Repository: ladybug-tools/honeybee-vtk (language: python)

Issue:
Refactor package
 - [x] [refactor index](https://github.com/ladybug-tools/honeybee-vtk/pull/11#discussion_r562164542)
 - [x] [Remove duplication in file_writers module](https://github.com/ladybug-tools/honeybee-vtk/pull/11#discussion_r562151764)
 - [ ] [Style vtkjs_helpper](https://github.com/ladybug-tools/honeybee-vtk/pull/11#discussion_r562199630)
 - [ ] [Alternative method for grouping](https://github.com/ladybug-tools/honeybee-vtk/pull/19#discussion_r563092700)
 - [x] Refactor to make documentation look right
 - [ ] [General refactoring direction](https://github.com/ladybug-tools/honeybee-vtk/pull/19#pullrequestreview-574838455)


Discussion / hints:

Fix patch:
diff --git a/README.md b/README.md
index f14659d5..fbe5b34f 100644
--- a/README.md
+++ b/README.md
@@ -16,32 +16,35 @@ import honeybee_vtk
 ```
 ## Usage
 ```console
-honeybee-vtk translate --help
-
 Usage: honeybee-vtk translate [OPTIONS] HBJSON_FILE
 
   Translate a HBJSON file to several VTK, XML, or HTML file.
 
   The output file is either a zipped file that contains all the generated
-  VTK/XML files  or an HTML file.
+  VTK/XML files or an HTML file.
 
-Args:
-    hbjson-file: Path to input HBJSON file.
+  Args:
+      hbjson-file: Path to input HBJSON file.
 
 Options:
-  -n, --name TEXT                 Name of the output file. If not provided, the name of input HBJSON file will be used.
+  -n, --name TEXT                 Name of the output file. If not provided,
+                                  the name of input HBJSON file will be used.
 
   -f, --folder DIRECTORY          Path to target folder.  [default: .]
-  
-  -t, --file-type [vtk|xml|html]  Switch between VTK, XML, and HTML formats. Default is HTML.  [default: html]
+  -t, --file-type [vtk|xml|html]  Switch between VTK, XML, and HTML formats.
+                                  Default is HTML.  [default: html]
 
-  -eg, --include-grids            Export grids.  [default: False]
-  
-  -ev, --include-vectors          Export normals for apertures and grid sensors.  [default: False]
+  -ig, --include-grids            Export grids.  [default: False]
+  -is, --include-sensors [vectors|points]
+                                  Export sensors as either arrows or color-
+                                  grouped points.
 
-  -ep, --include-points           Export points colored based on the direction of normal for apertures and grid sensors.  [default: False]
+  -in, --include-normals [vectors|points]
+                                  Export aperture normals as either arrows or
+                                  color-grouped points.
 
-  -sh, --show-html, --show        Open the generated HTML file in a browser. [default: False]
+  -sh, --show-html, --show        Open the generated HTML file in a browser.
+                                  [default: False]
 
   --help                          Show this message and exit.
 ```
@@ -49,7 +52,7 @@ Options:
 Viewing an [HBJSON](tests/assets/gridbased.hbjson) generated from a model that ships with Ladybug Tools. You can send this HTML to someone and they will be able to open the see the same model.
 
 ```console
-honeybee-vtk translate "path to hbjson file" --include-grids --include-vectors --show
+honeybee-vtk translate "path to hbjson file" --include-grids --include-sensors="vectors" --show
 ```
 
 ![](/images/honeybee-vtk-vectors.gif)
@@ -57,7 +60,7 @@ honeybee-vtk translate "path to hbjson file" --include-grids --include-vectors -
 Exporting points colored based on the direction of the normals for apertures and grid sensors. This is useful for models with very high number of sensors or apertures.
 
 ```console
-honeybee-vtk translate "path to hbjson file" --include-grids --include-points --show
+honeybee-vtk translate "path to hbjson file" --include-grids --include-sensors="points" --include-normals="points" --show
 ```
 
 ![](/images/honeybee-vtk-points.gif)
diff --git a/honeybee_vtk/cli.py b/honeybee_vtk/cli.py
index a290d32c..eb850add 100644
--- a/honeybee_vtk/cli.py
+++ b/honeybee_vtk/cli.py
@@ -1,4 +1,5 @@
-"""Honeybee VTK command line interface."""
+"""honeybee-vtk command line interface."""
+
 import sys
 import pathlib
 
@@ -31,29 +32,29 @@ def main():
     show_default=True
 )
 @click.option(
-    '--include-grids', '-eg', is_flag=True, default=False,
+    '--include-grids', '-ig', is_flag=True, default=False,
     help='Export grids.', show_default=True
 )
 @click.option(
-    '--include-vectors', '-ev', is_flag=True, default=False,
-    help='Export normals for apertures and grid sensors.', show_default=True
+    '--include-sensors', '-is', type=click.Choice(['vectors', 'points']),
+    help='Export sensors as either arrows or color-grouped points.', show_default=True
 )
 @click.option(
-    '--include-points', '-ep', is_flag=True, default=False,
-    help='Export points colored based on the direction of normal for apertures' 
-    ' and grid sensors.', show_default=True
+    '--include-normals', '-in', type=click.Choice(['vectors', 'points']),
+    help='Export aperture normals as either arrows or color-grouped points.',
+    show_default=True
 )
 @click.option(
     '--show-html', '--show', '-sh', is_flag=True, default=False,
-    help='Open the generated HTML file in a browser', show_default=True
+    help='Open the generated HTML file in a browser.', show_default=True
 )
 def translate_recipe(
-        hbjson_file, name, folder, file_type, include_grids, include_vectors,
-        include_points, show_html
+        hbjson_file, name, folder, file_type, include_grids, include_sensors,
+        include_normals, show_html
     ):
     """Translate a HBJSON file to several VTK, XML, or HTML file.
 
-    The output file is either a zipped file that contains all the generated VTK/XML files 
+    The output file is either a zipped file that contains all the generated VTK/XML files
     or an HTML file.
 
     \b
@@ -64,12 +65,16 @@ def translate_recipe(
 
     folder = pathlib.Path(folder)
     folder.mkdir(exist_ok=True)
+    if not include_normals:
+        include_normals = False
+    if not include_sensors:
+        include_sensors = False
 
     try:
         output_file = writer(
             hbjson_file, target_folder=folder, file_name=name,
-            include_grids=include_grids, include_vectors=include_vectors,
-            include_points=include_points, writer=file_type, open_html=show_html
+            include_grids=include_grids, include_sensors=include_sensors,
+            include_normals=include_normals, writer=file_type, open_html=show_html
         )
     except Exception as e:
         raise ClickException(f'Translation to VTK failed:\n{e}')
diff --git a/honeybee_vtk/file_writers.py b/honeybee_vtk/file_writers.py
index 400f01bc..97b094b1 100644
--- a/honeybee_vtk/file_writers.py
+++ b/honeybee_vtk/file_writers.py
@@ -6,17 +6,92 @@
 import tempfile
 import webbrowser
 import pathlib
+import warnings
 
 from zipfile import ZipFile
 from honeybee.typing import clean_string
 from .hbjson import check_grid, read_hbjson, group_by_face_type
-from .writers import write_polydata, _write_grids, _write_vectors, _write_points
+from .writers import _write_grids, _write_sensors, _write_normals, write_polydata
 from .index import write_index_json
 from .vtkjs_helper import convert_directory_to_zip_file, add_data_to_viewer
 
 
+def _write(hbjson, temp_folder, vtk_writer, vtk_extension, include_grids,
+           include_sensors, include_normals):
+    """Write files to temp folder get the names of files/folders being written.
+
+    Args:
+        hbjson: A dictionary.
+        temp_folder: Path to the temp folder as a text string.
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
+            acceptable values for the corresponding vtk_writer values;
+            '.vtk', '.vtp', ''.
+            Please note that the vtk_extension value is a an empty string with no spaces
+            in the case of vtk_writer having the value of 'html'.
+        include_grids: A bool.
+        include_sensors: Bool value of False or a value from 'vectors' or 'points.'
+        include_normals: Bool value of False or a value from 'vectors' or 'points.'
+
+    Returns:
+        A list of text strings for file names.
+    """
+
+    # Get points and face_types from HBJSON
+    points, hb_types = read_hbjson(hbjson)
+
+    # Get points grouped for each Honeybee face_type
+    grouped_points = group_by_face_type(points, hb_types)
+
+    # Write VTK files based on Honeybee face_type and Honeybee object type
+    for hb_type in grouped_points:
+        write_polydata(grouped_points[hb_type], hb_type, vtk_writer, vtk_extension,
+                       temp_folder)
+
+    # Names of VTK files to be written
+    file_names = list(grouped_points.keys())
+
+    # write grid points to a vtk file if grids are found in HBJSON
+    if include_grids or include_sensors:
+ 
+        # If grids are there in HBJSON
+        grids = check_grid(hbjson)
+        if grids:
+
+            # If grids are requested
+            if include_grids:
+                grid_file_names = _write_grids(
+                    grids, vtk_writer, vtk_extension, temp_folder, include_sensors)
+                file_names.extend(grid_file_names)
+
+            # If sensors are requested
+            if include_sensors:
+                sensor_file_names = _write_sensors(
+                    include_sensors, grids, vtk_writer, vtk_extension, temp_folder)
+                file_names.extend(sensor_file_names)
+        else:
+            warnings.warn(
+                'Grids are not found in HBJSON. include_grids and include_sensors will'
+                ' be ignored.')
+
+    # Write normals if they are requested
+    if include_normals:
+        if 'Aperture' in hb_types:
+            normal_file_names = _write_normals(
+                include_normals, hb_types, grouped_points, vtk_writer, vtk_extension,
+                temp_folder)
+            file_names.extend(normal_file_names)
+        else:
+            warnings.warn(
+                'Apertures are not found in HBJSON. include_normals will be ignored.')
+
+    return file_names
+
+
 def write_files(hbjson, file_path, file_name, target_folder, include_grids,
-                include_vectors, include_points, vtk_writer, vtk_extension):
+                include_sensors, include_normals, vtk_writer, vtk_extension):
     """
     Write a .zip of VTK/VTP files.
 
@@ -30,11 +105,14 @@ def write_files(hbjson, file_path, file_name, target_folder, include_grids,
             will be written to the current folder if not provided.
         include_grids: A boolean. Defaults to True. Grids will not be extracted from
             HBJSON if set to False.
-        include_vectors: A boolean. Defaults to True. Vector arrows will not be created
-            if set to False.
-        include_points: A boolean. Defaults to False. If set to True, sensor points
-            color-grouped based on their vector direction will be exported instead of
-            arrows for the vectors.
+        include_sensors: A text string to indicate whether to show sensor directions as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to False.
+        include_normals: A text string to indicate whether to show face normals as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to False. Currently, this function
+            only exports normals for the apertures. Other face types will be supported
+            in future.
         vtk_writer: A vtk object. Acceptable values are following;
             vtk.vtkXMLPolyDataWriter() and vtk.vtkPolyDataWriter() to write XML and
             VTK files respectively.
@@ -49,42 +127,9 @@ def write_files(hbjson, file_path, file_name, target_folder, include_grids,
     # Create a temp folder
     temp_folder = tempfile.mkdtemp()
 
-    # Get points and face_types from HBJSON
-    points, hb_types = read_hbjson(hbjson)
-
-    # Get points grouped for each Honeybee face_type
-    grouped_points = group_by_face_type(points, hb_types)
-
-    # Write VTK files based on Honeybee face_type and Honeybee object type
-    for hb_type in grouped_points:
-        write_polydata(grouped_points[hb_type], hb_type, vtk_writer, vtk_extension,
-                       temp_folder)
-
-    # Names of VTK files to be written
-    file_names = list(grouped_points.keys())
-
-    # write grid points to a vtk file if grids are found in HBJSON
-    grids = check_grid(hbjson)
-
-    # If grids are there in HBJSON and they are requested
-    if grids and include_grids:
-        grid_file_names = _write_grids(
-            grids, vtk_writer, vtk_extension, temp_folder, include_points)
-        file_names.extend(grid_file_names)
-
-    # Write vectors if they are requested
-    if include_vectors:
-        vector_file_names = _write_vectors(
-            hb_types, grouped_points, grids, include_grids, vtk_writer, vtk_extension,
-            temp_folder)
-        file_names.extend(vector_file_names)
-    
-    # Write color-grouped points if they are requested
-    if include_points:
-        point_file_names = _write_points(
-            hb_types, grouped_points, grids, include_grids, vtk_writer, vtk_extension,
-            temp_folder)
-        file_names.extend(point_file_names)
+    file_names = _write(
+        hbjson, temp_folder, vtk_writer, vtk_extension, include_grids, include_sensors,
+        include_normals)
 
     # Use the name of HBJSON if file name is not provided
     if not file_name:
@@ -124,8 +169,8 @@ def write_files(hbjson, file_path, file_name, target_folder, include_grids,
     return target_zip_file
 
 
-def write_html(hbjson, file_path, file_name, target_folder, include_grids,
-               include_vectors, include_points, open_html):
+def write_html(hbjson, file_path, file_name, target_folder, open_html, include_grids,
+               include_sensors, include_normals):
     """Write an HTML file with VTK objects embedded into it.
 
     Args:
@@ -136,15 +181,24 @@ def write_html(hbjson, file_path, file_name, target_folder, include_grids,
             file name for the .zip file.
         target_folder: A text string to a folder to write the output file. The file
             will be written to the current folder if not provided.
-        include_grids: A boolean. Defaults to True. Grids will not be extracted from
-            HBJSON if set to False.
-        include_vectors: A boolean. Defaults to True. Vector arrows will not be created
-            if set to False.
-        include_points: A boolean. Defaults to False. If set to True, sensor points
-            color-grouped based on their vector direction will be exported instead of
-            arrows for the vectors.
-        open_html: A boolean. If set to False, it will not open the generated HTML
-            in a web browser.
+        writer: A text string to indicate the VTK writer. Acceptable values are
+            'vtk', 'xml', and 'html'. Defaults to 'html'.
+        open_html: A boolean. If set to True, it will open the generated HTML
+            in a web browser when 'html' is provided as value in the writer argument.
+            Defaults to False.
+        include_grids: A boolean. Grids will be exported if the value is True. Here, a
+            grid is exported as base-geometry, grid mesh, or sensorpoints in that order
+            of preference. So if a Sensorgrid object in HBJSON has base-geometry, then
+            that object will be exported as base geometry, eventhough it also might have
+            mesh and sensors.
+        include_sensors: A text string to indicate whether to show sensor directions as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to False.
+        include_normals: A text string to indicate whether to show face normals as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to False. Currently, this function
+            only exports normals for the apertures. Other face types will be supported
+            in future.
 
     Returns:
         A text string containing the path to the HTML file with VTK objects embedded.
@@ -163,42 +217,9 @@ def write_html(hbjson, file_path, file_name, target_folder, include_grids,
     vtk_writer = vtk.vtkJSONDataSetWriter()
     vtk_extension = ""
 
-    # Get points and face_types from HBJSON
-    points, hb_types = read_hbjson(hbjson)
-
-    # Get points grouped for each Honeybee face_type
-    grouped_points = group_by_face_type(points, hb_types)
-
-    # Write VTK files based on Honeybee face_type and Honeybee object type
-    for hb_type in grouped_points:
-        write_polydata(grouped_points[hb_type], hb_type, vtk_writer, vtk_extension,
-                       temp_folder)
-
-    # Names of VTK files to be written
-    file_names = list(grouped_points.keys())
-
-    # write grid points to a vtk file if grids are found in HBJSON
-    grids = check_grid(hbjson)
-
-    # If grids are there in HBJSON and they are requested
-    if grids and include_grids:
-        grid_file_names = _write_grids(
-            grids, vtk_writer, vtk_extension, temp_folder, include_points)
-        file_names.extend(grid_file_names)
-
-    # Write vectors if they are requested
-    if include_vectors:
-        vector_file_names = _write_vectors(
-            hb_types, grouped_points, grids, include_grids, vtk_writer, vtk_extension,
-            temp_folder)
-        file_names.extend(vector_file_names)
-    
-    # Write color-grouped points if they are requested
-    if include_points:
-        point_file_names = _write_points(
-            hb_types, grouped_points, grids, include_grids, vtk_writer, vtk_extension,
-            temp_folder)
-        file_names.extend(point_file_names)
+    file_names = _write(
+        hbjson, temp_folder, vtk_writer, vtk_extension, include_grids, include_sensors,
+        include_normals)
 
     # Write index.json
     write_index_json(temp_folder, file_names)
diff --git a/honeybee_vtk/hbjson.py b/honeybee_vtk/hbjson.py
index 4caf9cdc..a15506cc 100644
--- a/honeybee_vtk/hbjson.py
+++ b/honeybee_vtk/hbjson.py
@@ -5,7 +5,7 @@
 from typing import List, Tuple, Dict
 
 
-def read_rooms(rooms: List) -> Tuple[List[List], List[str]]:
+def get_rooms(rooms: List) -> Tuple[List[List], List[str]]:
     """Read rooms in HBJSON.
 
     Args:
@@ -126,7 +126,7 @@ def read_hbjson(hbjson: Dict) -> Tuple[List[List], List[str]]:
             hb_types.extend(types)
     
     if 'rooms' in hbjson:
-        pts, types = read_rooms(hbjson['rooms'])
+        pts, types = get_rooms(hbjson['rooms'])
         points.extend(pts)
         hb_types.extend(types)
 
diff --git a/honeybee_vtk/index.py b/honeybee_vtk/index.py
index ac0bdbcd..9f4105f5 100644
--- a/honeybee_vtk/index.py
+++ b/honeybee_vtk/index.py
@@ -1,4 +1,4 @@
-"""Write index.json to color vtk datasets."""
+"""Write index.json to color vtk datasets for Paraview Glance."""
 
 import os
 import json
@@ -6,12 +6,12 @@
 
 # Scarlet colors in decimal
 layer_colors = {
-    'Wall': [0.858, 0.713, 0.560],
-    'Aperture': [0.858, 0.988, 1],
-    'Door': [0.776, 0.847, 0.686],
-    'Shade': [0.937, 0.643, 0.545],
-    'Floor': [0.031, 0.572, 0.647],
-    'RoofCeiling': [0.407, 0.325, 0.411],
+    'Wall': [0.901, 0.705, 0.235],
+    'Aperture': [0.250, 0.705, 1],
+    'Door': [0.627, 0.588, 0.392],
+    'Shade': [0.470, 0.294, 0.745],
+    'Floor': [1, 0.501, 0.501],
+    'RoofCeiling': [0.501, 0.078, 0.078],
     'Grid base': [0.925, 0.250, 0.403],
     'Grid mesh': [0.925, 0.250, 0.403],
     'Grid points': [1, 1, 1],
@@ -22,8 +22,9 @@
     'Aperture points': [1, 1, 1],
     'Grid base points': [1, 1, 1],
     'Grid mesh points': [1, 1, 1],
-    'AirBoundary': [0.109, 0.227, 0.074],
-    'Context': [0.925, 0.305, 0.125]
+    'Grid sensor points': [1, 1, 1],
+    'Aperture normals': [1, 1, 1],
+    'AirBoundary': [1, 1, 0.784],
 }
 
 index_template = {
diff --git a/honeybee_vtk/vtkjs_helper.py b/honeybee_vtk/vtkjs_helper.py
index 69146c20..eecd6530 100644
--- a/honeybee_vtk/vtkjs_helper.py
+++ b/honeybee_vtk/vtkjs_helper.py
@@ -1,5 +1,6 @@
 """This module helps in embedding vtkjs data in Paraview Glance HTML. This module is
-originally developed by Kitware and can be found at the following link."""
+originally developed by Kitware and can be found at the following link.
+https://github.com/Kitware/VTK/blob/master/Web/Python/vtkmodules/web/vtkjs_helper.py"""
 
 import base64
 import json
diff --git a/honeybee_vtk/writer.py b/honeybee_vtk/writer.py
index 9d0163ba..9bab8c99 100644
--- a/honeybee_vtk/writer.py
+++ b/honeybee_vtk/writer.py
@@ -1,4 +1,4 @@
-"""Write either an HTML or a .zip of VTk or XML files from a valid HBJSON."""
+"""Write either an HTML or a .zip of VTK or XML files from a valid HBJSON."""
 
 import os
 import json
@@ -8,8 +8,9 @@
 from .file_writers import write_files, write_html
 
 
-def writer(file_path, *, file_name=None, target_folder=None, include_grids=False,
-           include_vectors=False, include_points=False, writer='html', open_html=False):
+def writer(file_path, *, file_name=None, target_folder=None, writer='html',
+           open_html=False, include_grids=False, include_sensors=None,
+           include_normals=None):
     """Read a valid HBJSON and either write an HTML or a .zip of VTK files.
 
     Args:
@@ -19,23 +20,39 @@ def writer(file_path, *, file_name=None, target_folder=None, include_grids=False
             file name for the .zip file.
         target_folder: A text string to a folder to write the output file. The file
             will be written to the current folder if not provided.
-        include_grids: A boolean. Defaults to False. Grids will not be extracted from
-            HBJSON if set to False.
-        include_vectors: A boolean. Defaults to False. Vector arrows will not be created
-            if set to False.
-        include_points: A boolean. Defaults to False. If set to True, sensor points
-            color-grouped based on their vector direction will be exported instead of
-            arrows for the vectors.
         writer: A text string to indicate the VTK writer. Acceptable values are
             'vtk', 'xml', and 'html'. Defaults to 'html'.
         open_html: A boolean. If set to True, it will open the generated HTML
             in a web browser when 'html' is provided as value in the writer argument.
             Defaults to False.
+        include_grids: A boolean. Grids will be exported if the value is True. Here, a
+            grid is exported as base-geometry, grid mesh, or sensorpoints in that order
+            of preference. So if a Sensorgrid object in HBJSON has base-geometry, then
+            that object will be exported as base geometry, eventhough it also might have
+            mesh and sensors.
+        include_sensors: A text string to indicate whether to show sensor directions as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to None.
+        include_normals: A text string to indicate whether to show face normals as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to None. Currently, this function
+            only exports normals for the apertures. Other face types will be supported
+            in future.
 
     Returns:
         A text string containing the path to the output file.
     """
 
+    # Validate include_sensors
+    if include_sensors and include_sensors.lower() not in ['vectors', 'points']:
+        raise ValueError('The value for include_sensors can be either "vectors"'
+                         ' or "points".')
+
+    # Validate include_normals
+    if include_normals and include_normals.lower() not in ['vectors', 'points']:
+        raise ValueError('The value for include_normals can be either "vectors"'
+                         ' or "points".')
+
     # Check if path to HBJSON is fine
     if not os.path.isfile(file_path):
         raise FileNotFoundError(f'The path is not a valid path:{file_path}')
@@ -57,35 +74,27 @@ def writer(file_path, *, file_name=None, target_folder=None, include_grids=False
         os.makedirs(target_folder, exist_ok=True)
 
     # Validate and set writer and extension
-    writer_error = 'The value for writer can be "html", vtk" or "xml" only.'
-
-    # Write files
-    if isinstance(writer, str):
-
-        if include_vectors:
-            include_points = False
-
-        if writer.lower() == 'html':
-            return write_html(
-                hbjson, file_path, file_name, target_folder, include_grids,
-                include_vectors, include_points, open_html)
-
-        elif writer.lower() == 'xml':
-            vtk_writer = vtk.vtkXMLPolyDataWriter()
-            vtk_extension = '.vtp'
-            return write_files(
-                hbjson, file_path, file_name, target_folder, include_grids,
-                include_vectors, include_points, vtk_writer, vtk_extension)
-
-        elif writer.lower() == 'vtk':
-            vtk_writer = vtk.vtkPolyDataWriter()
-            vtk_extension = '.vtk'
-            return write_files(
-                hbjson, file_path, file_name, target_folder, include_grids,
-                include_vectors, include_points, vtk_writer, vtk_extension)
-
-        else:
-            raise ValueError(writer_error)
-
+    if writer.lower() not in ['vtk', 'xml', 'html']:
+        raise ValueError('The value for writer can be "html", "vtk" or "xml" only.')
     else:
-        raise ValueError(writer_error)
+        writer_val = writer
+
+    if writer_val.lower() == 'html':
+        return write_html(
+            hbjson, file_path, file_name, target_folder, open_html, include_grids,
+            include_sensors, include_normals)
+
+    elif writer_val.lower() == 'xml':
+        vtk_writer = vtk.vtkXMLPolyDataWriter()
+        vtk_extension = '.vtp'
+        return write_files(
+            hbjson, file_path, file_name, target_folder, include_grids,
+            include_sensors, include_normals, vtk_writer, vtk_extension)
+
+    elif writer_val.lower() == 'vtk':
+        vtk_writer = vtk.vtkPolyDataWriter()
+        vtk_extension = '.vtk'
+        return write_files(
+            hbjson, file_path, file_name, target_folder, include_grids,
+            include_sensors, include_normals, vtk_writer, vtk_extension)
+
diff --git a/honeybee_vtk/writers.py b/honeybee_vtk/writers.py
index dbb5c019..98dd0f8a 100644
--- a/honeybee_vtk/writers.py
+++ b/honeybee_vtk/writers.py
@@ -1,10 +1,11 @@
-"""A collection of helper functions to write VTK objects to file."""
+"""A collection of functions to write VTK objects to file."""
+
 
-import vtk
 import os
 
 from typing import List
-from .to_vtk import create_polygons, create_points, create_arrows, create_color_grouped_points
+from .to_vtk import create_polygons, create_points, create_arrows, \
+    create_color_grouped_points
 from .helper import get_end_point, get_vector_at_center, get_point3d, get_vector3d
 from .hbjson import get_grid_base, get_grid_mesh, get_grid_points
 
@@ -14,22 +15,27 @@ def write_polydata(
     """Write VTK Polydata to a file.
 
     Args:
-        grouped_points: A dictionary with Honeybee type as keys and list of 
-        lists of Point3Ds for geometry that belongs to that Honeybee type. 
+        grouped_points: A dictionary with Honeybee type as keys and list of
+        lists of Point3Ds for geometry that belongs to that Honeybee type.
         An example would be;
-        {
-        'Wall': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]],
-        'Aperture': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]]
-        }
+
+        .. code-block:: python
+
+            {
+            'Wall': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]],
+            'Aperture': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]]
+            }
+
         file_name: A text string for the the file name to be written.
-        vtk_writer: A text string to indicate the VTK writer. Acceptable values are
-            'vtk', 'xml', and 'html'. Defaults to 'html'.
-        vtk_extension: A text string for the file extension to be used. Following are 
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
             acceptable values for the corresponding vtk_writer values;
             '.vtk', '.vtp', ''.
             Please note that the vtk_extension value is a an empty string with no spaces
             in the case of vtk_writer having the value of 'html'.
-        target_folder: A text string to a folder to write the output vtk file. 
+        target_folder: A text string to a folder to write the output vtk file.
 
     Returns:
         A text string containing the path to the file.
@@ -47,23 +53,24 @@ def write_polydata(
 
 
 def write_points(
-        points: List[List], vectors: List[List], vtk_writer, vtk_extension,
-        target_folder, file_name='Grid points'):
+        points: List[List], vectors: List[List], *, file_name, target_folder,
+        vtk_writer, vtk_extension):
     """Write VTK points to a file.
 
     Args:
         points : A list of lists. Here, each list has X, Y, and Z coordinates of a point.
         vectors: A list of lists. Here, each list has X, Y, and Z components of a vector.
-        vtk_writer: A text string to indicate the VTK writer. Acceptable values are
-            'vtk', 'xml', and 'html'. Defaults to 'html'.
-        vtk_extension: A text string for the file extension to be used. Following are 
+        file_name: A text string to be used as a file name.
+        target_folder: A text string to a folder to write the output vtk file.
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
             acceptable values for the corresponding vtk_writer values;
             '.vtk', '.vtp', ''.
             Please note that the vtk_extension value is a an empty string with no spaces
             in the case of vtk_writer having the value of 'html'.
-        target_folder: A text string to a folder to write the output vtk file. 
-        file_name: A text string to be used as a file name. Defaults to "grid points."
-
+        
     Returns:
         A text string containing the path to the file.
     """
@@ -81,9 +88,8 @@ def write_points(
     return file_name
 
 
-def write_arrows(
-    start_points, vectors, file_name, target_folder, vtk_writer=vtk.vtkPolyDataWriter(),
-        vtk_extension='.vtk'):
+def write_arrows(start_points, vectors, *, file_name, target_folder, vtk_writer,
+                 vtk_extension):
     """Write VTK arrows to a file.
 
     Args:
@@ -92,9 +98,10 @@ def write_arrows(
         file_name: A text string to be used as the file name.
         target_folder: A text string to a folder to write the output file. The file
             will be written to the current folder if not provided.
-        vtk_writer: A text string to indicate the VTK writer. Acceptable values are
-            'vtk', 'xml', and 'html'. Defaults to 'html'.
-        vtk_extension: A text string for the file extension to be used. Following are 
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
             acceptable values for the corresponding vtk_writer values;
             '.vtk', '.vtp', ''.
             Please note that the vtk_extension value is a an empty string with no spaces
@@ -107,18 +114,18 @@ def write_arrows(
         get_end_point(point, vector)
         for point, vector in zip(start_points, vectors)]
 
-    file_name = file_name + ' vectors' + vtk_extension
+    file_name = file_name + vtk_extension
     face_vector_polydata = create_arrows(start_points, end_points, vectors)
     writer = vtk_writer
     file_name = os.path.join(target_folder, file_name)
     writer.SetFileName(file_name)
     writer.SetInputConnection(face_vector_polydata.GetOutputPort())
     writer.Write()
-    
+
     return file_name
 
 
-def _write_grids(grids, vtk_writer, vtk_extension, target_folder, include_points):
+def _write_grids(grids, vtk_writer, vtk_extension, target_folder, include_sensors):
     """
     Write HBJSON Sensorgrid objects to file.
 
@@ -129,17 +136,18 @@ def _write_grids(grids, vtk_writer, vtk_extension, target_folder, include_points
             'base_geometry' as a key.
             A list of HBJSON sensorgrids that have neither 'mesh' nor 'base_geometry'
             as keys.
-        vtk_writer: A text string to indicate the VTK writer. Acceptable values are
-            'vtk', 'xml', and 'html'. Defaults to 'html'.
-        vtk_extension: A text string for the file extension to be used. Following are 
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
             acceptable values for the corresponding vtk_writer values;
             '.vtk', '.vtp', ''.
             Please note that the vtk_extension value is a an empty string with no spaces
             in the case of vtk_writer having the value of 'html'.
         target_folder: A text string to a folder to write the output vtk file.
-        include_points: A boolean. Defaults to False. If set to True, sensor points
-            color-grouped based on their vector direction will be exported instead of
-            arrows for the vectors.
+        include_sensors: A text string to indicate whether to show sensor directions as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to False.
 
     Returns:
         A list of strings for file names.
@@ -161,44 +169,32 @@ def _write_grids(grids, vtk_writer, vtk_extension, target_folder, include_points
         grid_file_names.append('Grid mesh')
 
     # If only grid points are found
-    if grids[2] and not include_points:
+    if grids[2] and include_sensors != 'points':
         start_points = get_grid_points(grids[2])[0]
         vectors = None
-        write_points(start_points, vectors, vtk_writer, vtk_extension, target_folder)
+        write_points(start_points, vectors, 'Grid points', target_folder, vtk_writer,
+                     vtk_extension)
         grid_file_names.append('Grid points')
 
     return grid_file_names
 
 
-def _write_vectors(hb_types, grouped_points, grids, include_grids, vtk_writer,
-                   vtk_extension, target_folder):
+def _write_sensors(include_sensors, grids, vtk_writer, vtk_extension, target_folder):
     """
-    Write vectors to file.
+    Write points that are color-grouped based on the direction of vectors.
 
     Args:
-        hb_types: A list of text strings. Each text string represents either the
-            Honeybee face type or the Honeybee face object for each list of Point3Ds
-            in points.
-        grouped_points: A dictionary with Honeybee type as keys and list of lists of
-            Point3Ds for geometry that belongs to that Honeybee type. An example would
-            be;
-
-            .. code-block:: python
-                {
-                'Wall': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]],
-                'Aperture': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]]
-                }
-                
+        include_sensors: Bool value of False or a value from 'vectors' or 'points.'
         grids: A of following three lists.
             A list of HBJSON sensorgrids that have 'base_geometry' as a key.
             A list of HBJSON sensorgrids that have 'mesh' as a key and does not have
             'base_geometry' as a key.
             A list of HBJSON sensorgrids that have neither 'mesh' nor 'base_geometry'
             as keys.
-        include_grids: A boolean. Grids will be included if the value is True.
-        vtk_writer: A text string to indicate the VTK writer. Acceptable values are
-            'vtk', 'xml', and 'html'. Defaults to 'html'.
-        vtk_extension: A text string for the file extension to be used. Following are 
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
             acceptable values for the corresponding vtk_writer values;
             '.vtk', '.vtp', ''.
             Please note that the vtk_extension value is a an empty string with no spaces
@@ -208,123 +204,109 @@ def _write_vectors(hb_types, grouped_points, grids, include_grids, vtk_writer,
     Returns:
         A list of strings for file names.
     """
-    vector_file_names = []
-
-    # If Aperture objects are there in HBJSON
-    if 'Aperture' in hb_types:
-        # Create face normals
-        start_points, vectors = get_vector_at_center(
-            grouped_points['Aperture'])
-        write_arrows(start_points, vectors, 'Aperture', target_folder, vtk_writer,
-                     vtk_extension)
-        vector_file_names.append('Aperture vectors')
-
-    # If grids are found in HBJSON
-    if grids and include_grids:
-
-        # If base_geometry is found in any of the grids
-        if grids[0]:
-            grid_points, grid_vectors = get_grid_points(grids[0])
-            start_points = get_point3d(grid_points)
-            vectors = get_vector3d(grid_vectors)
-            write_arrows(start_points, vectors, 'Grid base', target_folder, vtk_writer,
-                         vtk_extension)
-            vector_file_names.append('Grid base vectors')
-
-        # If mesh is found in any of the grids
-        if grids[1]:
-            mesh_points = get_grid_mesh(grids[1])[0]
-            start_points, vectors = get_vector_at_center(mesh_points)
-            write_arrows(start_points, vectors, 'Grid mesh', target_folder, vtk_writer,
-                         vtk_extension)
-            vector_file_names.append('Grid mesh vectors')
-        
-        # If only grid points and vectors are there in the grids
-        if grids[2]:
-            grid_points, grid_vectors = get_grid_points(grids[2])
-            start_points = get_point3d(grid_points)
-            vectors = get_vector3d(grid_vectors)
-            write_arrows(start_points, vectors, 'Grid points', target_folder, vtk_writer,
-                         vtk_extension)
-            vector_file_names.append('Grid points vectors')
-
-    return vector_file_names
+    if include_sensors == 'vectors':
+        sensor_writer = write_arrows
+        layer_name_extension = 'vectors'
+    else:
+        sensor_writer = write_points
+        layer_name_extension = 'points'
 
+    sensor_file_names = []
 
-def _write_points(hb_types, grouped_points, grids, include_grids, vtk_writer,
-                  vtk_extension, target_folder):
+    # If base_geometry is found in any of the grids
+    if grids[0]:
+        grid_points, grid_vectors = get_grid_points(grids[0])
+        start_points = get_point3d(grid_points)
+        vectors = get_vector3d(grid_vectors)
+        layer_name = 'Grid base ' + layer_name_extension
+        sensor_writer(
+            start_points, vectors, file_name=layer_name, target_folder=target_folder,
+            vtk_writer=vtk_writer, vtk_extension=vtk_extension)
+        sensor_file_names.append(layer_name)
+
+    # If mesh is found in any of the grids
+    if grids[1]:
+        mesh_points = get_grid_mesh(grids[1])[0]
+        start_points, vectors = get_vector_at_center(mesh_points)
+        layer_name = 'Grid mesh ' + layer_name_extension
+        sensor_writer(
+            start_points, vectors, file_name=layer_name, target_folder=target_folder,
+            vtk_writer=vtk_writer, vtk_extension=vtk_extension)
+        sensor_file_names.append(layer_name)
+
+    # If only grid points and vectors are there in the grids
+    if grids[2]:
+        grid_points, grid_vectors = get_grid_points(grids[2])
+        start_points = get_point3d(grid_points)
+        vectors = get_vector3d(grid_vectors)
+        if layer_name_extension == 'points':
+            layer_name = 'Grid points'
+        else:
+            layer_name = 'Grid points ' + layer_name_extension
+        sensor_writer(
+            start_points, vectors, file_name=layer_name, target_folder=target_folder,
+            vtk_writer=vtk_writer, vtk_extension=vtk_extension)
+
+    return sensor_file_names
+
+
+def _write_normals(include_normals, hb_types, grouped_points, vtk_writer, vtk_extension,
+                   target_folder):
     """
-    Write points that are color-grouped based on the direction of vectors.
+    Write face normals as either arrows or color-grouped points.
+
+    Currently, this function only writes face normals for apertures.
 
     Args:
+        include_normals: A text string to indicate whether to show face normals as
+            vectors or points colored based on directions. Acceptable values are;
+            'vectors' and 'points.' Defaults to False. Currently, this function
+            only exports normals for the apertures. Other face types will be supported
+            in future.
         hb_types: A list of text strings. Each text string represents either the
             Honeybee face type or the Honeybee face object for each list of Point3Ds
             in points.
         grouped_points: A dictionary with Honeybee type as keys and list of lists of
             Point3Ds for geometry that belongs to that Honeybee type. An example would
             be;
+
             .. code-block:: python
+
                 {
                 'Wall': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]],
                 'Aperture': [[Point1, Point2, Point3], [Point4, Point5, Point6, Point7]]
                 }
-        grids: A of following three lists.
-            A list of HBJSON sensorgrids that have 'base_geometry' as a key.
-            A list of HBJSON sensorgrids that have 'mesh' as a key and does not have
-            'base_geometry' as a key.
-            A list of HBJSON sensorgrids that have neither 'mesh' nor 'base_geometry'
-            as keys.
-        include_grids: A boolean. Grids will be included if the value is True.
-        vtk_writer: A text string to indicate the VTK writer. Acceptable values are
-            'vtk', 'xml', and 'html'. Defaults to 'html'.
-        vtk_extension: A text string for the file extension to be used. Following are 
+                
+        vtk_writer: A vtk object. Acceptable values are following;
+            vtk.vtkXMLPolyDataWriter(), vtk.vtkPolyDataWriter(), and
+            vtk.vtkJSONDataSetWriter() to write XML, VTK, and HTML files respectively.
+        vtk_extension: A text string for the file extension to be used. Following are
             acceptable values for the corresponding vtk_writer values;
             '.vtk', '.vtp', ''.
             Please note that the vtk_extension value is a an empty string with no spaces
             in the case of vtk_writer having the value of 'html'.
-        target_folder: A text string to a folder to write the output vtk file. 
+        target_folder: A text string to a folder to write the output vtk file.
 
     Returns:
         A list of strings for file names.
     """
-    point_file_names = []
-
-    # If Aperture objects are there in HBJSON
-    if 'Aperture' in hb_types:
-        # Create face normals
-        start_points, vectors = get_vector_at_center(
-            grouped_points['Aperture'])
-        write_points(start_points, vectors, vtk_writer, vtk_extension, target_folder,
-                     'Aperture points')
-        point_file_names.append('Aperture points')
-
-    # If grids are found in HBJSON
-    if grids and include_grids:
-
-        # If base_geometry is found in any of the grids
-        if grids[0]:
-            grid_points, grid_vectors = get_grid_points(grids[0])
-            start_points = get_point3d(grid_points)
-            vectors = get_vector3d(grid_vectors)
-            write_points(start_points, vectors, vtk_writer, vtk_extension, target_folder,
-                         'Grid base points')
-            point_file_names.append('Grid base points')
-
-        # If mesh is found in any of the grids
-        if grids[1]:
-            mesh_points = get_grid_mesh(grids[1])[0]
-            start_points, vectors = get_vector_at_center(mesh_points)
-            write_points(start_points, vectors, vtk_writer, vtk_extension, target_folder,
-                         'Grid mesh points')
-            point_file_names.append('Grid mesh points')
-        
-        # If only grid points and vectors are there in the grids
-        if grids[2]:
-            grid_points, grid_vectors = get_grid_points(grids[2])
-            start_points = get_point3d(grid_points)
-            vectors = get_vector3d(grid_vectors)
-            write_points(start_points, vectors, vtk_writer, vtk_extension, target_folder,
-                         'Grid points')
-            point_file_names.append('Grid points')
-
-    return point_file_names
+    normal_file_names = []
+
+    # Create face normals
+    start_points, vectors = get_vector_at_center(grouped_points['Aperture'])
+
+    if include_normals == 'vectors':
+        write_arrows(
+            start_points, vectors, file_name='Aperture vectors',
+            target_folder=target_folder, vtk_writer=vtk_writer,
+            vtk_extension=vtk_extension)
+        normal_file_names.append('Aperture vectors')
+
+    elif include_normals == 'points':
+        write_points(
+            start_points, vectors, file_name='Aperture points',
+            target_folder=target_folder, vtk_writer=vtk_writer,
+            vtk_extension=vtk_extension)
+        normal_file_names.append('Aperture points')
+
+    return normal_file_names
diff --git a/requirements.txt b/requirements.txt
index 5fe1a618..104b1c31 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@
-ladybug-geometry==1.23.0
-honeybee-core==1.41.11
+honeybee-core==1.42.1
 vtk==9.0.1
 click==7.1.2


Test patch:
diff --git a/tests/write_test.py b/tests/write_test.py
index 3a7eb99e..1f69fa8d 100644
--- a/tests/write_test.py
+++ b/tests/write_test.py
@@ -13,20 +13,20 @@ def test_write():
     assert len(zip_file.namelist()) == 6
 
 
-def test_write_no_grids():
+def test_write_grids():
     file_path = './tests/assets/unnamed.hbjson'
     # Write without grids
-    zip_path = writer(file_path, include_grids=False, include_vectors=True, writer='vtk',
+    zip_path = writer(file_path, include_grids=True, writer='vtk',
                       target_folder='./tests/assets/temp')
     assert os.path.isfile(zip_path)
     zip_file = zipfile.ZipFile(zip_path)
-    assert len(zip_file.namelist()) == 7
+    assert len(zip_file.namelist()) == 8
 
 
-def test_write_no_vectors():
+def test_write_vectors():
     file_path = './tests/assets/unnamed.hbjson'
     # Write without vectors
-    zip_path = writer(file_path, include_grids=True, include_vectors=False, writer='vtk',
+    zip_path = writer(file_path, include_sensors='vectors', writer='vtk',
                       target_folder='./tests/assets/temp')
     assert os.path.isfile(zip_path)
     zip_file = zipfile.ZipFile(zip_path)
@@ -36,8 +36,7 @@ def test_write_no_vectors():
 def test_write_no_grids_no_vectors():
     file_path = './tests/assets/unnamed.hbjson'
     # Write without grids & vectors
-    zip_path = writer(file_path, include_grids=False, include_vectors=False,
-                      writer='vtk', target_folder='./tests/assets/temp')
+    zip_path = writer(file_path, writer='vtk', target_folder='./tests/assets/temp')
     assert os.path.isfile(zip_path)
     zip_file = zipfile.ZipFile(zip_path)
     assert len(zip_file.namelist()) == 6