Repository: highcharts-for-python/highcharts-stock (language: python)

Issue:
Add support for simplified `.from_csv()` API
Add support for simplified form of `.from_csv()` in line with highcharts-for-python/highcharts-core#105


Discussion / hints:

Fix patch:
diff --git a/CHANGES.rst b/CHANGES.rst
index 05d4178..700101a 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,29 @@
+
+Release 1.4.0
+=========================================
+
+* **MAJOR** performance gains in the ``.to_js_literal()`` method. Implementation seems to
+  improve performance by 50 - 90%.
+* *SIGNIFICANT* performance gains in the ``.to_json()`` method. Implementation seems to 
+  improve performance by 30 - 90%.
+* **ENHANCEMENT:** Significantly simplified use of the ``.from_pandas()`` method to support:
+
+  * creation of multiple series from one DataFrame in one method call
+  * creation of series without needing to specify a full property map
+  * support for creating series by DataFrame row, rather than just by DataFrame column
+
+* **ENHANCEMENT:** Added the ``.from_pandas_in_rows()`` method to support creation of
+  charts and series from simple two-dimensional DataFrames laid out in rows.
+* **ENHANCEMENT:** Added one-shot chart creation and rendering from Series objects.
+* **ENHANCEMENT:** Added one-shot chart creation using ``series`` and ``data``/``series_type`` keywords.
+* **ENHANCEMENT:** Added ``.convert_to()`` convenience method to Series objects.
+* **ENHANCEMENT:** Added ``CallbackFunction.from_python()`` method which converts a Python function
+  to its JavaScript equivalent using generative AI, with support for both OpenAI and Anthropic.
+* **BUGFIX:** Fixed instability issues in Jupyter Notebooks, both when operating as a Notebook (outside of 
+  Jupyter Lab) and when saved to a static HTML file.
+
+---------------------
+
 Release 1.3.0
 =========================================
 
diff --git a/README.rst b/README.rst
index a022f14..1328716 100644
--- a/README.rst
+++ b/README.rst
@@ -231,48 +231,53 @@ Hello World, and Basic Usage
 
   .. code-block:: python
 
+    # from a primitive array, using keyword arguments
+    my_chart = Chart(data = [[1, 23], [2, 34], [3, 45]], 
+                     series_type = 'line')
+
+    # from a primitive array, using the .from_array() method
+    my_chart = Chart.from_array([[1, 23], [2, 34], [3, 45]], 
+                                series_type = 'line')
+
+    # from a Numpy ndarray, using keyword arguments
+    my_chart = Chart(data = numpy_array, series_type = 'line')
+
+    # from a Numpy ndarray, using the .from_array() method
+    my_chart = Chart.from_array(data = numpy_array, series_type = 'line')
+
     # from a JavaScript file
-    my_chart = highcharts.Chart.from_js_literal('my_js_literal.js')
+    my_chart = Chart.from_js_literal('my_js_literal.js')
 
     # from a JSON file
-    my_chart = highcharts.Chart.from_json('my_json.json')
+    my_chart = Chart.from_json('my_json.json')
 
     # from a Python dict
-    my_chart = highcharts.Chart.from_dict(my_dict_obj)
+    my_chart = Chart.from_dict(my_dict_obj)
 
     # from a Pandas dataframe
-    my_chart = highcharts.Chart.from_pandas(df,
-                                            property_map = {
-                                                'x': 'transactionDate',
-                                                'y': 'invoiceAmt',
-                                                'id': 'id'
-                                            },
-                                            series_type = 'line')
+    my_chart = Chart.from_pandas(df)
 
     # from a PySpark dataframe
-    my_chart = highcharts.Chart.from_pyspark(df,
-                                             property_map = {
-                                                 'x': 'transactionDate',
-                                                 'y': 'invoiceAmt',
-                                                 'id': 'id'
-                                             },
-                                             series_type = 'line')
+    my_chart = Chart.from_pyspark(df,
+                                  property_map = {
+                                      'x': 'transactionDate',
+                                      'y': 'invoiceAmt',
+                                      'id': 'id'
+                                  },
+                                  series_type = 'line')
 
     # from a CSV
-    my_chart = highcharts.Chart.from_csv('/some_file_location/filename.csv'
-                                         column_property_map = {
-                                            'x': 0,
-                                            'y': 4,
-                                            'id': 14
-                                         },
-                                         series_type = 'line')
+    my_chart = Chart.from_csv('/some_file_location/filename.csv')
 
     # from a HighchartsOptions configuration object
-    my_chart = highcharts.Chart.from_options(my_options)
+    my_chart = Chart.from_options(my_options)
 
-    # from a Series configuration
-    my_chart = highcharts.Chart.from_series(my_series)
+    # from a Series configuration, using keyword arguments
+    my_chart = Chart(series = my_series)
 
+    # from a Series configuration, using .from_series()
+    my_chart = Chart.from_series(my_series)
+    
 
 3. Configure Global Settings (optional)
 =============================================
@@ -300,9 +305,10 @@ Hello World, and Basic Usage
 
   .. code-block:: python
 
-    from highcharts_stock.options.title import Title
-    from highcharts_stock.options.credits import Credits
+    from highcharts_core.options.title import Title
+    from highcharts_core.options.credits import Credits
 
+    # EXAMPLE 1.
     # Using dicts
     my_chart.title = {
         'align': 'center'
@@ -313,7 +319,7 @@ Hello World, and Basic Usage
 
     my_chart.credits = {
         'enabled': True,
-        'href': 'https://www.highcharts.com/',
+        'href': 'https://www.highchartspython.com/',
         'position': {
             'align': 'center',
             'vertical_align': 'bottom',
@@ -328,14 +334,19 @@ Hello World, and Basic Usage
         'text': 'Chris Modzelewski'
     }
 
+    # EXAMPLE 2.
     # Using direct objects
-    from highcharts_stock.options.title import Title
-    from highcharts_stock.options.credits import Credits
+    from highcharts_core.options.title import Title
+    from highcharts_core.options.credits import Credits
 
-    my_title = Title(text = 'The Title for My Chart', floating = True, align = 'center')
+    my_title = Title(text = 'The Title for My Chart',
+                     floating = True, 
+                     align = 'center')
     my_chart.options.title = my_title
 
-    my_credits = Credits(text = 'Chris Modzelewski', enabled = True, href = 'https://www.highcharts.com')
+    my_credits = Credits(text = 'Chris Modzelewski', 
+                         enabled = True, 
+                         href = 'https://www.highchartspython.com')
     my_chart.options.credits = my_credits
 
 
@@ -378,6 +389,13 @@ that will render the chart wherever it is you want it to go:
     my_image_bytes = my_chart.download_chart(filename = 'my_target_file.png',
                                              format = 'png')
 
+8. Render Your Chart in a Jupyter Notebook
+===============================================
+
+  .. code-block:: python
+
+    my_chart.display()
+
 --------------
 
 ***********************
diff --git a/docs/_static/highcharts-chart-anatomy.png b/docs/_static/highcharts-chart-anatomy.png
new file mode 100644
index 0000000..60ec37b
Binary files /dev/null and b/docs/_static/highcharts-chart-anatomy.png differ
diff --git a/docs/_static/tutorials/census-time-series-01.png b/docs/_static/tutorials/census-time-series-01.png
new file mode 100644
index 0000000..8b0d308
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-01.png differ
diff --git a/docs/_static/tutorials/census-time-series-02.png b/docs/_static/tutorials/census-time-series-02.png
new file mode 100644
index 0000000..19135f6
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-02.png differ
diff --git a/docs/_static/tutorials/census-time-series-03.png b/docs/_static/tutorials/census-time-series-03.png
new file mode 100644
index 0000000..c268ac3
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-03.png differ
diff --git a/docs/_static/tutorials/census-time-series-04.png b/docs/_static/tutorials/census-time-series-04.png
new file mode 100644
index 0000000..16ed17b
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-04.png differ
diff --git a/docs/_static/tutorials/census-time-series-05.png b/docs/_static/tutorials/census-time-series-05.png
new file mode 100644
index 0000000..98414fe
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-05.png differ
diff --git a/docs/_static/tutorials/census-time-series-06.png b/docs/_static/tutorials/census-time-series-06.png
new file mode 100644
index 0000000..07627cc
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-06.png differ
diff --git a/docs/_static/tutorials/census-time-series-07.png b/docs/_static/tutorials/census-time-series-07.png
new file mode 100644
index 0000000..73d7611
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-07.png differ
diff --git a/docs/_static/tutorials/census-time-series-08.png b/docs/_static/tutorials/census-time-series-08.png
new file mode 100644
index 0000000..0a1ea2d
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-08.png differ
diff --git a/docs/_static/tutorials/census-time-series-09.png b/docs/_static/tutorials/census-time-series-09.png
new file mode 100644
index 0000000..90c222c
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-09.png differ
diff --git a/docs/_static/tutorials/census-time-series-10.png b/docs/_static/tutorials/census-time-series-10.png
new file mode 100644
index 0000000..49ce258
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-10.png differ
diff --git a/docs/_static/tutorials/census-time-series-csv-01.png b/docs/_static/tutorials/census-time-series-csv-01.png
new file mode 100644
index 0000000..e444567
Binary files /dev/null and b/docs/_static/tutorials/census-time-series-csv-01.png differ
diff --git a/docs/_static/tutorials/raw-data-as-numpy.png b/docs/_static/tutorials/raw-data-as-numpy.png
new file mode 100644
index 0000000..542b285
Binary files /dev/null and b/docs/_static/tutorials/raw-data-as-numpy.png differ
diff --git a/docs/api.rst b/docs/api.rst
index 039f77f..3bbeb57 100644
--- a/docs/api.rst
+++ b/docs/api.rst
@@ -649,56 +649,88 @@ Core Components
     - :class:`DataPointAccessibility <highcharts_stock.options.series.data.accessibility.DataPointAccessibility>`
   * - :mod:`.options.series.data.arcdiagram <highcharts_stock.options.series.data.arcdiagram>`
     - :class:`ArcDiagramData <highcharts_stock.options.series.data.arcdiagram.ArcDiagramData>`
+      :class:`ArcDiagramDataCollection <highcharts_stock.options.series.data.arcidagram.ArcDiagramDataCollection>`
   * - :mod:`.options.series.data.bar <highcharts_stock.options.series.data.bar>`
     - :class:`BarData <highcharts_stock.options.series.data.bar.BarData>`
+      :class:`BarDataCollection <highcharts_stock.options.series.data.bar.BarDataCollection>`
       :class:`WaterfallData <highcharts_stock.options.series.data.bar.WaterfallData>`
+      :class:`WaterfallDataCollection <highcharts_stock.options.series.data.bar.WaterfallDataCollection>`
       :class:`WindBarbData <highcharts_stock.options.series.data.bar.WindBarbData>`
+      :class:`WindBarbDataCollection <highcharts_stock.options.series.data.bar.WindBarbDataCollection>`
       :class:`XRangeData <highcharts_stock.options.series.data.bar.XRangeData>`
+      :class:`XRangeDataCollection <highcharts_stock.options.series.data.bar.XRangeDataCollection>`
   * - :mod:`.options.series.data.base <highcharts_stock.options.series.data.base>`
     - :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`
   * - :mod:`.options.series.data.boxplot <highcharts_stock.options.series.data.boxplot>`
     - :class:`BoxPlotData <highcharts_stock.options.series.data.boxplot.BoxPlotData>`
+      :class:`BoxPlotDataCollection <highcharts_stock.options.series.data.boxplot.BoxPlotDataCollection>`
   * - :mod:`.options.series.data.bullet <highcharts_stock.options.series.data.bullet>`
     - :class:`BulletData <highcharts_stock.options.series.data.bullet.BulletData>`
+      :class:`BulletDataCollection <highcharts_stock.options.series.data.bullet.BulletDataCollection>`
   * - :mod:`.options.series.data.candlestick <highcharts_stock.options.series.data.candlestick>`
     - :class:`CandlestickData <highcharts_stock.options.series.data.candlestick.CandlestickData>`
   * - :mod:`.options.series.data.cartesian <highcharts_stock.options.series.data.cartesian>`
     - :class:`CartesianData <highcharts_stock.options.series.data.cartesian.CartesianData>`
+      :class:`CartesianDataCollection <highcharts_stock.options.series.data.cartesian.CartesianDataCollection>`
       :class:`Cartesian3DData <highcharts_stock.options.series.data.cartesian.Cartesian3DData>`
+      :class:`Cartesian3DDataCollection <highcharts_stock.options.series.data.cartesian.Cartesian3DDataCollection>`
       :class:`CartesianValueData <highcharts_stock.options.series.data.cartesian.CartesianValueData>`
+      :class:`CartesianValueDataCollection <highcharts_stock.options.series.data.cartesian.CartesianValueDataCollection>`
+  * - :mod:`.options.series.data.collections <highcharts_stock.options.series.data.collections>`
+    - :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
   * - :mod:`.options.series.data.connections <highcharts_stock.options.series.data.connections>`
     - :class:`ConnectionData <highcharts_stock.options.series.data.connections.ConnectionData>`
+      :class:`ConnectionDataCollection <highcharts_stock.options.series.data.connections.ConnectionDataCollection>`
       :class:`WeightedConnectionData <highcharts_stock.options.series.data.connections.WeightedConnectionData>`
+      :class:`WeightedConnectionDataCollection <highcharts_stock.options.series.data.connections.WeightedConnectionDataCollection>`
       :class:`OutgoingWeightedConnectionData <highcharts_stock.options.series.data.connections.OutgoingWeightedConnectionData>`
+      :class:`OutgoingWeightedConnectionDataCollection <highcharts_stock.options.series.data.connections.OutgoingWeightedConnectionDataCollection>`
       :class:`ConnectionBase <highcharts_stock.options.series.data.connections.ConnectionBase>`
   * - :mod:`.options.series.data.hlc <highcharts_stock.options.series.data.hlc>`
     - :class:`HLCData <highcharts_stock.options.series.data.hlc.HLCData>`
+      :class:`HLCDataCollection <highcharts_stock.options.series.data.hlc.HLCDataCollection>`
       :class:`OHLCData <highcharts_stock.options.series.data.hlc.OHLCData>`
+      :class:`OHLCDataCollection <highcharts_stock.options.series.data.hlc.OHLCDataCollection>`
   * - :mod:`.options.series.data.pie <highcharts_stock.options.series.data.pie>`
     - :class:`PieData <highcharts_stock.options.series.data.pie.PieData>`
+      :class:`PieDataCollection <highcharts_stock.options.series.data.pie.PieDataCollection>`
       :class:`VariablePieData <highcharts_stock.options.series.data.pie.VariablePieData>`
+      :class:`VariablePieDataCollection <highcharts_stock.options.series.data.pie.VariablePieDataCollection>`
   * - :mod:`.options.series.data.range <highcharts_stock.options.series.data.range>`
     - :class:`RangeData <highcharts_stock.options.series.data.range.RangeData>`
+      :class:`RangeDataCollection <highcharts_stock.options.series.data.range.RangeDataCollection>`
       :class:`ConnectedRangeData <highcharts_stock.options.series.data.range.ConnectedRangeData>`
+      :class:`ConnectedRangeDataCollection <highcharts_stock.options.series.data.range.ConnectedRangeDataCollection>`
   * - :mod:`.options.series.data.single_point <highcharts_stock.options.series.data.single_point>`
     - :class:`SinglePointData <highcharts_stock.options.series.data.single_point.SinglePointData>`
+      :class:`SinglePointDataCollection <highcharts_stock.options.series.data.single_point.SinglePointDataCollection>`
       :class:`SingleValueData <highcharts_stock.options.series.data.single_point.SingleValueData>`
+      :class:`SingleValueDataCollection <highcharts_stock.options.series.data.single_point.SingleValueDataCollection>`
       :class:`SingleXData <highcharts_stock.options.series.data.single_point.SingleXData>`
+      :class:`SingleXDataCollection <highcharts_stock.options.series.data.single_point.SingleXDataCollection>`
       :class:`LabeledSingleXData <highcharts_stock.options.series.data.single_point.LabeledSingleXData>`
+      :class:`LabeledSingleXDataCollection <highcharts_stock.options.series.data.single_point.LabeledSingleXDataCollection>`
       :class:`ConnectedSingleXData <highcharts_stock.options.series.data.single_point.ConnectedSingleXData>`
+      :class:`ConnectedSingleXDataCollection <highcharts_stock.options.series.data.single_point.ConnectedSingleXDataCollection>`
       :class:`SinglePointBase <highcharts_stock.options.series.data.single_point.SinglePointBase>`
   * - :mod:`.options.series.data.sunburst <highcharts_stock.options.series.data.sunburst>`
     - :class:`SunburstData <highcharts_stock.options.series.data.sunburst.SunburstData>`
+      :class:`SunburstDataCollection <highcharts_stock.options.series.data.sunburst.SunburstDataCollection>`
   * - :mod:`.options.series.data.treegraph <highcharts_stock.options.series.data.treegraph>`
     - :class:`TreegraphData <highcharts_stock.options.series.data.treegraph.TreegraphData>`
+      :class:`TreegraphDataCollection <highcharts_stock.options.series.data.treegraph.TreegraphDataCollection>`
   * - :mod:`.options.series.data.treemap <highcharts_stock.options.series.data.treemap>`
     - :class:`TreemapData <highcharts_stock.options.series.data.treemap.TreemapData>`
+      :class:`TreemapDataCollection <highcharts_stock.options.series.data.treemap.TreemapDataCollection>`
   * - :mod:`.options.series.data.vector <highcharts_stock.options.series.data.vector>`
     - :class:`VectorData <highcharts_stock.options.series.data.vector.VectorData>`
+      :class:`VectorDataCollection <highcharts_stock.options.series.data.vector.VectorDataCollection>`
   * - :mod:`.options.series.data.venn <highcharts_stock.options.series.data.venn>`
     - :class:`VennData <highcharts_stock.options.series.data.venn.VennData>`
+      :class:`VennDataCollection <highcharts_stock.options.series.data.venn.VennDataCollection>`
   * - :mod:`.options.series.data.wordcloud <highcharts_stock.options.series.data.wordcloud>`
     - :class:`WordcloudData <highcharts_stock.options.series.data.wordcloud.WordcloudData>`
+      :class:`WordcloudDataCollection <highcharts_stock.options.series.data.wordcloud.WordcloudDataCollection>`
   * - :mod:`.options.series.dependencywheel <highcharts_stock.options.series.dependencywheel>`
     - :class:`DependencyWheelSeries <highcharts_stock.options.series.dependencywheel.DependencyWheelSeries>`
   * - :mod:`.options.series.disparity_index <highcharts_stock.options.series.disparity_index>`
@@ -995,6 +1027,12 @@ need to familiarize yourself with these internals.
       :func:`validate_color() <highcharts_stock.utility_functions.validate_color>`
       :func:`to_camelCase() <highcharts_stock.utility_functions.to_camelCase>`
       :func:`parse_csv() <highcharts_stock.utility_functions.parse_csv>`
+  * - :mod:`.ai <highcharts_stock.ai>`
+    - :func:`convert_to_js() <highcharts_stock.ai.convert_to_js>`
+      :func:`openai_moderate() <highcharts_stock.ai.openai_moderate>`
+      :func:`openai_conversion() <highcharts_stock.ai.openai_conversion>`
+      :func:`anthropic_conversion() <highcharts_stock.ai.anthropic_conversion>`
+      :func:`get_source() <highcharts_stock.ai.get_source>`
 
 .. target-notes::
 
diff --git a/docs/api/options/series/data/arcdiagram.rst b/docs/api/options/series/data/arcdiagram.rst
index 9da3acc..bc85b85 100644
--- a/docs/api/options/series/data/arcdiagram.rst
+++ b/docs/api/options/series/data/arcdiagram.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.arcdiagram
+.. module:: highcharts_core.options.series.data.arcdiagram
 
 ********************************************************************************************************************
 class: :class:`ArcDiagramData <highcharts_stock.options.series.data.arcdiagram.ArcDiagramData>`
@@ -22,7 +22,27 @@ class: :class:`ArcDiagramData <highcharts_stock.options.series.data.arcdiagram.A
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: ArcDiagramData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+.. module:: highcharts_core.options.series.data.arcdiagram
+
+********************************************************************************************************************
+class: :class:`ArcDiagramDataCollection <highcharts_stock.options.series.data.arcdiagram.ArcDiagramDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: ArcDiagramDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: ArcDiagramDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/bar.rst b/docs/api/options/series/data/bar.rst
index 47cb399..384812c 100644
--- a/docs/api/options/series/data/bar.rst
+++ b/docs/api/options/series/data/bar.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.bar
+.. module:: highcharts_core.options.series.data.bar
 
 ********************************************************************************************************************
 class: :class:`BarData <highcharts_stock.options.series.data.bar.BarData>`
@@ -22,7 +22,25 @@ class: :class:`BarData <highcharts_stock.options.series.data.bar.BarData>`
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: BarData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`BarDataCollection <highcharts_stock.options.series.data.bar.BarDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: BarDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: BarDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -40,7 +58,25 @@ class: :class:`WaterfallData <highcharts_stock.options.series.data.bar.Waterfall
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: WaterfallData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+-----------------
+
+********************************************************************************************************************
+class: :class:`WaterfallDataCollection <highcharts_stock.options.series.data.bar.WaterfallDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: WaterfallDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: WaterfallDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -58,7 +94,25 @@ class: :class:`WindBarbData <highcharts_stock.options.series.data.bar.WindBarbDa
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: WindBarbData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+-----------------
+
+********************************************************************************************************************
+class: :class:`WindBarbDataCollection <highcharts_stock.options.series.data.bar.WindBarbDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: WindBarbDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: WindBarbDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -76,7 +130,25 @@ class: :class:`XRangeData <highcharts_stock.options.series.data.bar.XRangeData>`
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: XRangeData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+-----------------
+
+********************************************************************************************************************
+class: :class:`XRangeDataCollection <highcharts_stock.options.series.data.bar.XRangeDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: XRangeDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: XRangeDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/base.rst b/docs/api/options/series/data/base.rst
index 4328f6c..1a2f9dd 100644
--- a/docs/api/options/series/data/base.rst
+++ b/docs/api/options/series/data/base.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.base
+.. module:: highcharts_core.options.series.data.base
 
 ********************************************************************************************************************
 class: :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`
@@ -22,7 +22,7 @@ class: :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: DataBase
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/boxplot.rst b/docs/api/options/series/data/boxplot.rst
index 32d0aeb..95b1380 100644
--- a/docs/api/options/series/data/boxplot.rst
+++ b/docs/api/options/series/data/boxplot.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.boxplot
+.. module:: highcharts_core.options.series.data.boxplot
 
 ********************************************************************************************************************
 class: :class:`BoxPlotData <highcharts_stock.options.series.data.boxplot.BoxPlotData>`
@@ -22,7 +22,25 @@ class: :class:`BoxPlotData <highcharts_stock.options.series.data.boxplot.BoxPlot
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: BoxPlotData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`BoxPlotDataCollection <highcharts_stock.options.series.data.boxplot.BoxPlotDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: BoxPlotDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: BoxPlotDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/bullet.rst b/docs/api/options/series/data/bullet.rst
index 3957d1f..2ae5488 100644
--- a/docs/api/options/series/data/bullet.rst
+++ b/docs/api/options/series/data/bullet.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.bullet
+.. module:: highcharts_core.options.series.data.bullet
 
 ********************************************************************************************************************
 class: :class:`BulletData <highcharts_stock.options.series.data.bullet.BulletData>`
@@ -22,7 +22,25 @@ class: :class:`BulletData <highcharts_stock.options.series.data.bullet.BulletDat
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: BulletData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`BulletDataCollection <highcharts_stock.options.series.data.bullet.BulletDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: BulletDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: BulletDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/candlestick.rst b/docs/api/options/series/data/candlestick.rst
index 90957ed..3a0eeac 100644
--- a/docs/api/options/series/data/candlestick.rst
+++ b/docs/api/options/series/data/candlestick.rst
@@ -26,3 +26,23 @@ class: :class:`CandlestickData <highcharts_stock.options.series.data.candlestick
       :parts: -1
 
   |
+
+--------------
+
+.. module:: highcharts_stock.options.series.data.candlestick
+
+************************************************************************************************************************
+class: :class:`CandlestickDataCollection <highcharts_stock.options.series.data.candlestick.CandlestickDataCollection>`
+************************************************************************************************************************
+
+.. autoclass:: CandlestickDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: CandlestickDataCollection
+      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
diff --git a/docs/api/options/series/data/cartesian.rst b/docs/api/options/series/data/cartesian.rst
index ab6c3a3..6c224de 100644
--- a/docs/api/options/series/data/cartesian.rst
+++ b/docs/api/options/series/data/cartesian.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.cartesian
+.. module:: highcharts_core.options.series.data.cartesian
 
 ********************************************************************************************************************
 class: :class:`CartesianData <highcharts_stock.options.series.data.cartesian.CartesianData>`
@@ -22,7 +22,25 @@ class: :class:`CartesianData <highcharts_stock.options.series.data.cartesian.Car
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: CartesianData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`CartesianDataCollection <highcharts_stock.options.series.data.cartesian.CartesianDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: CartesianDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: CartesianDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -40,7 +58,25 @@ class: :class:`Cartesian3DData <highcharts_stock.options.series.data.cartesian.C
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: Cartesian3DData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`Cartesian3DDataCollection <highcharts_stock.options.series.data.cartesian.Cartesian3DDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: Cartesian3DDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: Cartesian3DDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -58,7 +94,25 @@ class: :class:`CartesianValueData <highcharts_stock.options.series.data.cartesia
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: CartesianValueData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`CartesianValueDataCollection <highcharts_stock.options.series.data.cartesian.CartesianValueDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: CartesianValueDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: CartesianValueDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/collections.rst b/docs/api/options/series/data/collections.rst
new file mode 100644
index 0000000..748505a
--- /dev/null
+++ b/docs/api/options/series/data/collections.rst
@@ -0,0 +1,28 @@
+##########################################################################################
+:mod:`.collections <highcharts_stock.options.series.data.collections>`
+##########################################################################################
+
+.. contents:: Module Contents
+  :local:
+  :depth: 3
+  :backlinks: entry
+
+--------------
+
+.. module:: highcharts_core.options.series.data.collections
+
+********************************************************************************************************************
+class: :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+********************************************************************************************************************
+
+.. autoclass:: DataPointCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: DataPointCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
diff --git a/docs/api/options/series/data/connections.rst b/docs/api/options/series/data/connections.rst
index 19c4022..fa4d2c9 100644
--- a/docs/api/options/series/data/connections.rst
+++ b/docs/api/options/series/data/connections.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.connections
+.. module:: highcharts_core.options.series.data.connections
 
 ********************************************************************************************************************
 class: :class:`ConnectionData <highcharts_stock.options.series.data.connections.ConnectionData>`
@@ -22,7 +22,25 @@ class: :class:`ConnectionData <highcharts_stock.options.series.data.connections.
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: ConnectionData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------
+
+********************************************************************************************************************
+class: :class:`ConnectionDataCollection <highcharts_stock.options.series.data.connections.ConnectionDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: ConnectionDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: ConnectionDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -40,7 +58,25 @@ class: :class:`WeightedConnectionData <highcharts_stock.options.series.data.conn
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: WeightedConnectionData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+----------------------
+
+********************************************************************************************************************
+class: :class:`WeightedConnectionDataCollection <highcharts_stock.options.series.data.connections.WeightedConnectionDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: WeightedConnectionDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: WeightedConnectionDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -58,7 +94,25 @@ class: :class:`OutgoingWeightedConnectionData <highcharts_stock.options.series.d
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: OutgoingWeightedConnectionData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------------------
+
+*************************************************************************************************************************************
+class: :class:`OutgoingWeightedConnectionDataCollection <highcharts_stock.options.series.data.connections.OutgoingWeightedConnectionDataCollection>`
+*************************************************************************************************************************************
+
+.. autoclass:: OutgoingWeightedConnectionDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: OutgoingWeightedConnectionDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -76,7 +130,7 @@ class: :class:`ConnectionBase <highcharts_stock.options.series.data.connections.
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: ConnectionBase
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/hlc.rst b/docs/api/options/series/data/hlc.rst
index dd7f7cb..4127e23 100644
--- a/docs/api/options/series/data/hlc.rst
+++ b/docs/api/options/series/data/hlc.rst
@@ -27,6 +27,26 @@ class: :class:`HLCData <highcharts_stock.options.series.data.hlc.HLCData>`
 
   |
 
+--------------
+
+.. module:: highcharts_stock.options.series.data.hlc
+
+********************************************************************************************************************
+class: :class:`HLCDataCollection <highcharts_stock.options.series.data.hlc.HLCDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: HLCDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: HLCDataCollection
+      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
 -----------------
 
 ********************************************************************************************************************
@@ -44,3 +64,21 @@ class: :class:`OHLCData <highcharts_stock.options.series.data.hlc.OHLCData>`
       :parts: -1
 
   |
+
+-----------------
+
+********************************************************************************************************************
+class: :class:`OHLCDataCollection <highcharts_stock.options.series.data.hlc.OHLCDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: OHLCDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: OHLCDataCollection
+      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
diff --git a/docs/api/options/series/data/index.rst b/docs/api/options/series/data/index.rst
index b7da936..271afaf 100644
--- a/docs/api/options/series/data/index.rst
+++ b/docs/api/options/series/data/index.rst
@@ -48,53 +48,85 @@ Sub-components
     - :class:`DataPointAccessibility <highcharts_stock.options.series.data.accessibility.DataPointAccessibility>`
   * - :mod:`.options.series.data.arcdiagram <highcharts_stock.options.series.data.arcdiagram>`
     - :class:`ArcDiagramData <highcharts_stock.options.series.data.arcdiagram.ArcDiagramData>`
+      :class:`ArcDiagramDataCollection <highcharts_stock.options.series.data.arcidagram.ArcDiagramDataCollection>`
   * - :mod:`.options.series.data.bar <highcharts_stock.options.series.data.bar>`
     - :class:`BarData <highcharts_stock.options.series.data.bar.BarData>`
+      :class:`BarDataCollection <highcharts_stock.options.series.data.bar.BarDataCollection>`
       :class:`WaterfallData <highcharts_stock.options.series.data.bar.WaterfallData>`
+      :class:`WaterfallDataCollection <highcharts_stock.options.series.data.bar.WaterfallDataCollection>`
       :class:`WindBarbData <highcharts_stock.options.series.data.bar.WindBarbData>`
+      :class:`WindBarbDataCollection <highcharts_stock.options.series.data.bar.WindBarbDataCollection>`
       :class:`XRangeData <highcharts_stock.options.series.data.bar.XRangeData>`
+      :class:`XRangeDataCollection <highcharts_stock.options.series.data.bar.XRangeDataCollection>`
   * - :mod:`.options.series.data.base <highcharts_stock.options.series.data.base>`
     - :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`
   * - :mod:`.options.series.data.boxplot <highcharts_stock.options.series.data.boxplot>`
     - :class:`BoxPlotData <highcharts_stock.options.series.data.boxplot.BoxPlotData>`
+      :class:`BoxPlotDataCollection <highcharts_stock.options.series.data.boxplot.BoxPlotDataCollection>`
   * - :mod:`.options.series.data.bullet <highcharts_stock.options.series.data.bullet>`
     - :class:`BulletData <highcharts_stock.options.series.data.bullet.BulletData>`
+      :class:`BulletDataCollection <highcharts_stock.options.series.data.bullet.BulletDataCollection>`
   * - :mod:`.options.series.data.candlestick <highcharts_stock.options.series.data.candlestick>`
     - :class:`CandlestickData <highcharts_stock.options.series.data.candlestick.CandlestickData>`
   * - :mod:`.options.series.data.cartesian <highcharts_stock.options.series.data.cartesian>`
     - :class:`CartesianData <highcharts_stock.options.series.data.cartesian.CartesianData>`
+      :class:`CartesianDataCollection <highcharts_stock.options.series.data.cartesian.CartesianDataCollection>`
       :class:`Cartesian3DData <highcharts_stock.options.series.data.cartesian.Cartesian3DData>`
+      :class:`Cartesian3DDataCollection <highcharts_stock.options.series.data.cartesian.Cartesian3DDataCollection>`
       :class:`CartesianValueData <highcharts_stock.options.series.data.cartesian.CartesianValueData>`
+      :class:`CartesianValueDataCollection <highcharts_stock.options.series.data.cartesian.CartesianValueDataCollection>`
+  * - :mod:`.options.series.data.collections <highcharts_stock.options.series.data.collections>`
+    - :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
   * - :mod:`.options.series.data.connections <highcharts_stock.options.series.data.connections>`
     - :class:`ConnectionData <highcharts_stock.options.series.data.connections.ConnectionData>`
+      :class:`ConnectionDataCollection <highcharts_stock.options.series.data.connections.ConnectionDataCollection>`
       :class:`WeightedConnectionData <highcharts_stock.options.series.data.connections.WeightedConnectionData>`
+      :class:`WeightedConnectionDataCollection <highcharts_stock.options.series.data.connections.WeightedConnectionDataCollection>`
       :class:`OutgoingWeightedConnectionData <highcharts_stock.options.series.data.connections.OutgoingWeightedConnectionData>`
+      :class:`OutgoingWeightedConnectionDataCollection <highcharts_stock.options.series.data.connections.OutgoingWeightedConnectionDataCollection>`
       :class:`ConnectionBase <highcharts_stock.options.series.data.connections.ConnectionBase>`
   * - :mod:`.options.series.data.hlc <highcharts_stock.options.series.data.hlc>`
     - :class:`HLCData <highcharts_stock.options.series.data.hlc.HLCData>`
+      :class:`HLCDataCollection <highcharts_stock.options.series.data.hlc.HLCDataCollection>`
       :class:`OHLCData <highcharts_stock.options.series.data.hlc.OHLCData>`
+      :class:`OHLCDataCollection <highcharts_stock.options.series.data.hlc.OHLCDataCollection>`
   * - :mod:`.options.series.data.pie <highcharts_stock.options.series.data.pie>`
     - :class:`PieData <highcharts_stock.options.series.data.pie.PieData>`
+      :class:`PieDataCollection <highcharts_stock.options.series.data.pie.PieDataCollection>`
       :class:`VariablePieData <highcharts_stock.options.series.data.pie.VariablePieData>`
+      :class:`VariablePieDataCollection <highcharts_stock.options.series.data.pie.VariablePieDataCollection>`
   * - :mod:`.options.series.data.range <highcharts_stock.options.series.data.range>`
     - :class:`RangeData <highcharts_stock.options.series.data.range.RangeData>`
+      :class:`RangeDataCollection <highcharts_stock.options.series.data.range.RangeDataCollection>`
       :class:`ConnectedRangeData <highcharts_stock.options.series.data.range.ConnectedRangeData>`
+      :class:`ConnectedRangeDataCollection <highcharts_stock.options.series.data.range.ConnectedRangeDataCollection>`
   * - :mod:`.options.series.data.single_point <highcharts_stock.options.series.data.single_point>`
     - :class:`SinglePointData <highcharts_stock.options.series.data.single_point.SinglePointData>`
+      :class:`SinglePointDataCollection <highcharts_stock.options.series.data.single_point.SinglePointDataCollection>`
       :class:`SingleValueData <highcharts_stock.options.series.data.single_point.SingleValueData>`
+      :class:`SingleValueDataCollection <highcharts_stock.options.series.data.single_point.SingleValueDataCollection>`
       :class:`SingleXData <highcharts_stock.options.series.data.single_point.SingleXData>`
+      :class:`SingleXDataCollection <highcharts_stock.options.series.data.single_point.SingleXDataCollection>`
       :class:`LabeledSingleXData <highcharts_stock.options.series.data.single_point.LabeledSingleXData>`
+      :class:`LabeledSingleXDataCollection <highcharts_stock.options.series.data.single_point.LabeledSingleXDataCollection>`
       :class:`ConnectedSingleXData <highcharts_stock.options.series.data.single_point.ConnectedSingleXData>`
+      :class:`ConnectedSingleXDataCollection <highcharts_stock.options.series.data.single_point.ConnectedSingleXDataCollection>`
       :class:`SinglePointBase <highcharts_stock.options.series.data.single_point.SinglePointBase>`
   * - :mod:`.options.series.data.sunburst <highcharts_stock.options.series.data.sunburst>`
     - :class:`SunburstData <highcharts_stock.options.series.data.sunburst.SunburstData>`
+      :class:`SunburstDataCollection <highcharts_stock.options.series.data.sunburst.SunburstDataCollection>`
   * - :mod:`.options.series.data.treegraph <highcharts_stock.options.series.data.treegraph>`
     - :class:`TreegraphData <highcharts_stock.options.series.data.treegraph.TreegraphData>`
+      :class:`TreegraphDataCollection <highcharts_stock.options.series.data.treegraph.TreegraphDataCollection>`
   * - :mod:`.options.series.data.treemap <highcharts_stock.options.series.data.treemap>`
     - :class:`TreemapData <highcharts_stock.options.series.data.treemap.TreemapData>`
+      :class:`TreemapDataCollection <highcharts_stock.options.series.data.treemap.TreemapDataCollection>`
   * - :mod:`.options.series.data.vector <highcharts_stock.options.series.data.vector>`
     - :class:`VectorData <highcharts_stock.options.series.data.vector.VectorData>`
+      :class:`VectorDataCollection <highcharts_stock.options.series.data.vector.VectorDataCollection>`
   * - :mod:`.options.series.data.venn <highcharts_stock.options.series.data.venn>`
     - :class:`VennData <highcharts_stock.options.series.data.venn.VennData>`
+      :class:`VennDataCollection <highcharts_stock.options.series.data.venn.VennDataCollection>`
   * - :mod:`.options.series.data.wordcloud <highcharts_stock.options.series.data.wordcloud>`
     - :class:`WordcloudData <highcharts_stock.options.series.data.wordcloud.WordcloudData>`
+      :class:`WordcloudDataCollection <highcharts_stock.options.series.data.wordcloud.WordcloudDataCollection>`
diff --git a/docs/api/options/series/data/pie.rst b/docs/api/options/series/data/pie.rst
index ce16d7d..6de63aa 100644
--- a/docs/api/options/series/data/pie.rst
+++ b/docs/api/options/series/data/pie.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.pie
+.. module:: highcharts_core.options.series.data.pie
 
 ********************************************************************************************************************
 class: :class:`PieData <highcharts_stock.options.series.data.pie.PieData>`
@@ -22,7 +22,25 @@ class: :class:`PieData <highcharts_stock.options.series.data.pie.PieData>`
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: PieData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+-----------------
+
+********************************************************************************************************************
+class: :class:`PieDataCollection <highcharts_stock.options.series.data.pie.PieDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: PieDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: PieDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -40,7 +58,25 @@ class: :class:`VariablePieData <highcharts_stock.options.series.data.pie.Variabl
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: VariablePieData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+-----------------
+
+********************************************************************************************************************
+class: :class:`VariablePieDataCollection <highcharts_stock.options.series.data.pie.VariablePieDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: VariablePieDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: VariablePieDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/range.rst b/docs/api/options/series/data/range.rst
index 43175cc..7e0b98a 100644
--- a/docs/api/options/series/data/range.rst
+++ b/docs/api/options/series/data/range.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.range
+.. module:: highcharts_core.options.series.data.range
 
 ********************************************************************************************************************
 class: :class:`RangeData <highcharts_stock.options.series.data.range.RangeData>`
@@ -22,7 +22,25 @@ class: :class:`RangeData <highcharts_stock.options.series.data.range.RangeData>`
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: RangeData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------
+
+********************************************************************************************************************
+class: :class:`RangeDataCollection <highcharts_stock.options.series.data.range.RangeDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: RangeDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: RangeDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -40,7 +58,25 @@ class: :class:`ConnectedRangeData <highcharts_stock.options.series.data.range.Co
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: ConnectedRangeData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------
+
+***********************************************************************************************************************
+class: :class:`ConnectedRangeDataCollection <highcharts_stock.options.series.data.range.ConnectedRangeDataCollection>`
+***********************************************************************************************************************
+
+.. autoclass:: ConnectedRangeDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: ConnectedRangeDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/single_point.rst b/docs/api/options/series/data/single_point.rst
index f8d1d09..c4a8552 100644
--- a/docs/api/options/series/data/single_point.rst
+++ b/docs/api/options/series/data/single_point.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.single_point
+.. module:: highcharts_core.options.series.data.single_point
 
 ********************************************************************************************************************
 class: :class:`SinglePointData <highcharts_stock.options.series.data.single_point.SinglePointData>`
@@ -22,7 +22,25 @@ class: :class:`SinglePointData <highcharts_stock.options.series.data.single_poin
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: SinglePointData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+-----------------------
+
+************************************************************************************************************************
+class: :class:`SinglePointDataCollection <highcharts_stock.options.series.data.single_point.SinglePointDataCollection>`
+************************************************************************************************************************
+
+.. autoclass:: SinglePointDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: SinglePointDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -40,7 +58,25 @@ class: :class:`SingleValueData <highcharts_stock.options.series.data.single_poin
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: SingleValueData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------------
+
+***********************************************************************************************************************
+class: :class:`SingleValueDataCollection <highcharts_stock.options.series.data.single_point.SingleValueDataCollection>`
+***********************************************************************************************************************
+
+.. autoclass:: SingleValueDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: SingleValueDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -58,7 +94,25 @@ class: :class:`SingleXData <highcharts_stock.options.series.data.single_point.Si
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: SingleXData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------
+
+********************************************************************************************************************
+class: :class:`SingleXDataCollection <highcharts_stock.options.series.data.single_point.SingleXDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: SingleXDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: SingleXDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -76,7 +130,25 @@ class: :class:`LabeledSingleXData <highcharts_stock.options.series.data.single_p
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: LabeledSingleXData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+---------------------
+
+********************************************************************************************************************
+class: :class:`LabeledSingleXDataCollection <highcharts_stock.options.series.data.single_point.LabeledSingleXDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: LabeledSingleXDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: LabeledSingleXDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -94,7 +166,25 @@ class: :class:`ConnectedSingleXData <highcharts_stock.options.series.data.single
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: ConnectedSingleXData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------------
+
+********************************************************************************************************************
+class: :class:`ConnectedSingleXDataCollection <highcharts_stock.options.series.data.single_point.ConnectedSingleXDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: ConnectedSingleXDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: ConnectedSingleXDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
@@ -112,7 +202,7 @@ class: :class:`SinglePointBase <highcharts_stock.options.series.data.single_poin
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: SinglePointBase
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/sunburst.rst b/docs/api/options/series/data/sunburst.rst
index d82ca68..3c57bc1 100644
--- a/docs/api/options/series/data/sunburst.rst
+++ b/docs/api/options/series/data/sunburst.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.sunburst
+.. module:: highcharts_core.options.series.data.sunburst
 
 ********************************************************************************************************************
 class: :class:`SunburstData <highcharts_stock.options.series.data.sunburst.SunburstData>`
@@ -22,7 +22,25 @@ class: :class:`SunburstData <highcharts_stock.options.series.data.sunburst.Sunbu
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: SunburstData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`SunburstDataCollection <highcharts_stock.options.series.data.sunburst.SunburstDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: SunburstDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: SunburstDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/treegraph.rst b/docs/api/options/series/data/treegraph.rst
index 235889f..338c619 100644
--- a/docs/api/options/series/data/treegraph.rst
+++ b/docs/api/options/series/data/treegraph.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.treegraph
+.. module:: highcharts_core.options.series.data.treegraph
 
 ********************************************************************************************************************
 class: :class:`TreegraphData <highcharts_stock.options.series.data.treegraph.TreegraphData>`
@@ -22,7 +22,25 @@ class: :class:`TreegraphData <highcharts_stock.options.series.data.treegraph.Tre
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: TreegraphData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`TreegraphDataCollection <highcharts_stock.options.series.data.treegraph.TreegraphDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: TreegraphDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: TreegraphDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/treemap.rst b/docs/api/options/series/data/treemap.rst
index b0c69c3..db5e169 100644
--- a/docs/api/options/series/data/treemap.rst
+++ b/docs/api/options/series/data/treemap.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.treemap
+.. module:: highcharts_core.options.series.data.treemap
 
 ********************************************************************************************************************
 class: :class:`TreemapData <highcharts_stock.options.series.data.treemap.TreemapData>`
@@ -22,7 +22,25 @@ class: :class:`TreemapData <highcharts_stock.options.series.data.treemap.Treemap
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: TreemapData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`TreemapDataCollection <highcharts_stock.options.series.data.treemap.TreemapDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: TreemapDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: TreemapDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/vector.rst b/docs/api/options/series/data/vector.rst
index fbc962b..91c63b8 100644
--- a/docs/api/options/series/data/vector.rst
+++ b/docs/api/options/series/data/vector.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.vector
+.. module:: highcharts_core.options.series.data.vector
 
 ********************************************************************************************************************
 class: :class:`VectorData <highcharts_stock.options.series.data.vector.VectorData>`
@@ -22,7 +22,25 @@ class: :class:`VectorData <highcharts_stock.options.series.data.vector.VectorDat
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: VectorData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`VectorDataCollection <highcharts_stock.options.series.data.vector.VectorDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: VectorDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: VectorDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/venn.rst b/docs/api/options/series/data/venn.rst
index 3b53c68..3b4f3c5 100644
--- a/docs/api/options/series/data/venn.rst
+++ b/docs/api/options/series/data/venn.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.venn
+.. module:: highcharts_core.options.series.data.venn
 
 ********************************************************************************************************************
 class: :class:`VennData <highcharts_stock.options.series.data.venn.VennData>`
@@ -22,7 +22,25 @@ class: :class:`VennData <highcharts_stock.options.series.data.venn.VennData>`
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: VennData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`VennDataCollection <highcharts_stock.options.series.data.venn.VennDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: VennDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: VennDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/options/series/data/wordcloud.rst b/docs/api/options/series/data/wordcloud.rst
index 460c7d7..f4989e1 100644
--- a/docs/api/options/series/data/wordcloud.rst
+++ b/docs/api/options/series/data/wordcloud.rst
@@ -9,7 +9,7 @@
 
 --------------
 
-.. module:: highcharts_stock.options.series.data.wordcloud
+.. module:: highcharts_core.options.series.data.wordcloud
 
 ********************************************************************************************************************
 class: :class:`WordcloudData <highcharts_stock.options.series.data.wordcloud.WordcloudData>`
@@ -22,7 +22,25 @@ class: :class:`WordcloudData <highcharts_stock.options.series.data.wordcloud.Wor
   .. collapse:: Class Inheritance
 
     .. inheritance-diagram:: WordcloudData
-      :top-classes: highcharts_stock.metaclasses.HighchartsMeta, highcharts_core.metaclasses.HighchartsMeta
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
+      :parts: -1
+
+  |
+
+--------------
+
+********************************************************************************************************************
+class: :class:`WordcloudDataCollection <highcharts_stock.options.series.data.wordcloud.WordcloudDataCollection>`
+********************************************************************************************************************
+
+.. autoclass:: WordcloudDataCollection
+  :members:
+  :inherited-members:
+
+  .. collapse:: Class Inheritance
+
+    .. inheritance-diagram:: WordcloudDataCollection
+      :top-classes: highcharts_core.metaclasses.HighchartsMeta
       :parts: -1
 
   |
diff --git a/docs/api/utility_classes/data_labels.rst b/docs/api/utility_classes/data_labels.rst
index b191778..6e42f06 100644
--- a/docs/api/utility_classes/data_labels.rst
+++ b/docs/api/utility_classes/data_labels.rst
@@ -30,7 +30,7 @@ class: :class:`DataLabel <highcharts_stock.utility_classes.data_labels.DataLabel
 -----------------
 
 ********************************************************************************************************************
-class: :class:`OrganizationDataLabel <highcharts_core.utility_classes.data_labels.OrganizationDataLabel>`
+class: :class:`OrganizationDataLabel <highcharts_stock.utility_classes.data_labels.OrganizationDataLabel>`
 ********************************************************************************************************************
 
 .. autoclass:: OrganizationDataLabel
@@ -48,7 +48,7 @@ class: :class:`OrganizationDataLabel <highcharts_core.utility_classes.data_label
 -----------------
 
 ********************************************************************************************************************
-class: :class:`SunburstDataLabel <highcharts_core.utility_classes.data_labels.SunburstDataLabel>`
+class: :class:`SunburstDataLabel <highcharts_stock.utility_classes.data_labels.SunburstDataLabel>`
 ********************************************************************************************************************
 
 .. autoclass:: SunburstDataLabel
diff --git a/docs/index.rst b/docs/index.rst
index a951f9d..ca3c4c7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -13,8 +13,6 @@ Highcharts Stock for Python
 
 **High-end time series data visualization for the Python ecosystem**
 
-.. include:: _unit_tests_code_coverage.rst
-
 .. toctree::
   :hidden:
   :maxdepth: 3
@@ -27,6 +25,7 @@ Highcharts Stock for Python
   FAQ <faq>
   Toolkit Components and Roadmap <toolkit>
   Using Highcharts Stock for Python <using>
+  Tutorials <tutorials>
   API Reference <api>
   Error Reference <errors>
   Getting Help <support>
@@ -47,6 +46,7 @@ Highcharts Stock for Python
     * Highcharts Core for Python 1.0 or higher,
     * Jupyter Notebook 6.4 or higher,
     * IPython 8.10 or higher,
+    * NumPy 1.19 or higher,
     * Pandas 1.3 or higher
     * PySpark 3.3 or higher
 
@@ -229,48 +229,54 @@ Hello World, and Basic Usage
 
   .. code-block:: python
 
+  .. code-block:: python
+
+    # from a primitive array, using keyword arguments
+    my_chart = Chart(data = [[1, 23], [2, 34], [3, 45]], 
+                     series_type = 'line')
+
+    # from a primitive array, using the .from_array() method
+    my_chart = Chart.from_array([[1, 23], [2, 34], [3, 45]], 
+                                series_type = 'line')
+
+    # from a Numpy ndarray, using keyword arguments
+    my_chart = Chart(data = numpy_array, series_type = 'line')
+
+    # from a Numpy ndarray, using the .from_array() method
+    my_chart = Chart.from_array(data = numpy_array, series_type = 'line')
+
     # from a JavaScript file
-    my_chart = highcharts.Chart.from_js_literal('my_js_literal.js')
+    my_chart = Chart.from_js_literal('my_js_literal.js')
 
     # from a JSON file
-    my_chart = highcharts.Chart.from_json('my_json.json')
+    my_chart = Chart.from_json('my_json.json')
 
     # from a Python dict
-    my_chart = highcharts.Chart.from_dict(my_dict_obj)
+    my_chart = Chart.from_dict(my_dict_obj)
 
     # from a Pandas dataframe
-    my_chart = highcharts.Chart.from_pandas(df,
-                                            property_map = {
-                                                'x': 'transactionDate',
-                                                'y': 'invoiceAmt',
-                                                'id': 'id'
-                                            },
-                                            series_type = 'line')
+    my_chart = Chart.from_pandas(df)
 
     # from a PySpark dataframe
-    my_chart = highcharts.Chart.from_pyspark(df,
-                                             property_map = {
-                                                 'x': 'transactionDate',
-                                                 'y': 'invoiceAmt',
-                                                 'id': 'id'
-                                             },
-                                             series_type = 'line')
+    my_chart = Chart.from_pyspark(df,
+                                  property_map = {
+                                      'x': 'transactionDate',
+                                      'y': 'invoiceAmt',
+                                      'id': 'id'
+                                  },
+                                  series_type = 'line')
 
     # from a CSV
-    my_chart = highcharts.Chart.from_csv('/some_file_location/filename.csv'
-                                         column_property_map = {
-                                            'x': 0,
-                                            'y': 4,
-                                            'id': 14
-                                         },
-                                         series_type = 'line')
+    my_chart = Chart.from_csv('/some_file_location/filename.csv')
 
     # from a HighchartsOptions configuration object
-    my_chart = highcharts.Chart.from_options(my_options)
+    my_chart = Chart.from_options(my_options)
 
-    # from a Series configuration
-    my_chart = highcharts.Chart.from_series(my_series)
+    # from a Series configuration, using keyword arguments
+    my_chart = Chart(series = my_series)
 
+    # from a Series configuration, using .from_series()
+    my_chart = Chart.from_series(my_series)
 
 3. Configure Global Settings (optional)
 =============================================
@@ -301,6 +307,7 @@ Hello World, and Basic Usage
     from highcharts_stock.options.title import Title
     from highcharts_stock.options.credits import Credits
 
+    # EXAMPLE 1.
     # Using dicts
     my_chart.title = {
         'align': 'center'
@@ -311,7 +318,7 @@ Hello World, and Basic Usage
 
     my_chart.credits = {
         'enabled': True,
-        'href': 'https://www.highcharts.com/',
+        'href': 'https://www.highchartspython.com/',
         'position': {
             'align': 'center',
             'vertical_align': 'bottom',
@@ -326,14 +333,19 @@ Hello World, and Basic Usage
         'text': 'Chris Modzelewski'
     }
 
+    # EXAMPLE 2.
     # Using direct objects
     from highcharts_stock.options.title import Title
     from highcharts_stock.options.credits import Credits
 
-    my_title = Title(text = 'The Title for My Chart', floating = True, align = 'center')
+    my_title = Title(text = 'The Title for My Chart',
+                     floating = True, 
+                     align = 'center')
     my_chart.options.title = my_title
 
-    my_credits = Credits(text = 'Chris Modzelewski', enabled = True, href = 'https://www.highcharts.com')
+    my_credits = Credits(text = 'Chris Modzelewski', 
+                         enabled = True, 
+                         href = 'https://www.highchartspython.com')
     my_chart.options.credits = my_credits
 
 
@@ -376,6 +388,13 @@ that will render the chart wherever it is you want it to go:
     my_image_bytes = my_chart.download_chart(filename = 'my_target_file.png',
                                              format = 'png')
 
+8. Render Your Chart in a Jupyter Notebook
+===============================================
+
+  .. code-block:: python
+
+    my_chart.display()
+
 --------------
 
 ***********************
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index b00eafa..a2a03dc 100644
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -76,7 +76,15 @@ Populating Series with Data
 
   .. tab:: w/ ``.from_array()``
 
-    .. include:: using/populating_series_data/_with_from_array.rst
+    .. tabs::
+      
+      .. tab:: Create a New Series
+
+        .. include:: using/populating_series_data/_new_from_array.rst
+
+      .. tab:: Update an Existing Series
+
+        .. include:: using/populating_series_data/_load_from_array.rst
 
   .. tab:: from CSV
 
@@ -127,6 +135,10 @@ Assembling Your Chart and Options
 
 .. tabs::
 
+  .. tabs:: Using Keyword Arguments
+
+    .. include:: using/assembling_your_chart/_using_kwargs.rst
+
   .. tab:: Using ``.add_series()``
 
     .. include:: using/assembling_your_chart/_using_add_series.rst
diff --git a/docs/tutorials.rst b/docs/tutorials.rst
new file mode 100644
index 0000000..00ba76e
--- /dev/null
+++ b/docs/tutorials.rst
@@ -0,0 +1,38 @@
+########################################
+Highcharts Core for Python: Tutorials
+########################################
+
+.. toctree::
+  :maxdepth: 2
+
+  Getting Started <tutorials/getting_started>
+  Using Highcharts Core for Python with Pandas <tutorials/pandas>
+  Using Highcharts Core for Python with CSVs <tutorials/csv>
+  Working with Data in Highcharts for Python <tutorials/data>
+  Working with Highcharts for Python Series Instances <tutorials/series>
+  Creating JavaScript Callback Functions <tutorials/callbacks>
+  Exporting Static Charts <tutorials/exporting>
+
+--------------------
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+.. tip::
+
+  You can find even more tutorials on the 
+  `Highcharts website <https://www.highcharts.com/blog/posts/python/>`__.
+
+Please use the table of contents to the left to find a tutorial that is 
+relevant to your needs. And if you would like us to prepare additional tutorials,
+please:
+
+  #. Check if it has 
+     `already been requested <https://github.com/highcharts-for-python/highcharts-core/issues?q=is%3Aissue+is%3Aopen+label%3Adocumentation+label%3Atutorial>`__
+  #. If it has, then please upvote it with a comment.
+  #. If the tutorial you would like to see hasn't been requested yet, then please 
+     `file a new request <https://github.com/highcharts-for-python/highcharts-core/issues/new/choose>`__ -
+     
\ No newline at end of file
diff --git a/docs/tutorials/_assembling_a_chart.rst b/docs/tutorials/_assembling_a_chart.rst
new file mode 100644
index 0000000..57af89f
--- /dev/null
+++ b/docs/tutorials/_assembling_a_chart.rst
@@ -0,0 +1,35 @@
+  .. code-block:: python
+
+    my_chart = Chart(data = my_iterable, series_type = 'line')
+
+This will create a :class:`Chart <highcharts_stock.chart.Chart>` instance
+with one :term:`series` of type ``line`` (represented as a 
+:class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` instance).
+
+Depending on how we've wrangled our data, we can similarly produce a chart
+from a :class:`pandas.DataFrame <pandas:pandas.DataFrame>`, 
+:class:`numpy.ndarray <numpy:numpy.ndarray>`, or Python :class:`dict <python:dict>`:
+
+  .. code-block:: python
+
+    # From a Pandas DataFrame
+
+    my_chart = Chart.from_pandas(df, series_type = 'line')
+
+    # From a Numpy ndarray
+
+    my_chart = Chart.from_array(data = as_ndarray, series_type = 'line')
+
+    # From a Python dict
+
+    my_chart = Chart(data = as_dict, series_type = 'line')
+
+All of these lines of code are equivalent, and should produce an identical
+``my_chart``.
+
+  .. seealso::
+  
+    * :doc:`Using Highcharts Core for Python with Pandas <pandas>`
+    * :doc:`Using Highcharts Core for Python with CSVs <csv>`
+    * :doc:`Working with Highcharts for Python Series Instances <series>`
+    * :doc:`Working with Data in the Highcharts for Python Toolkit <data>`
diff --git a/docs/tutorials/callbacks.rst b/docs/tutorials/callbacks.rst
new file mode 100644
index 0000000..b97510c
--- /dev/null
+++ b/docs/tutorials/callbacks.rst
@@ -0,0 +1,245 @@
+############################################
+Creating JavaScript Callback Functions
+############################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+Highcharts (JS) is known for how easy it is to configure and style
+beautiful, interactive data visualizations. One of the core tools
+it uses to achieve this is 
+:term:`callback functions <callback function>`.
+
+These can be used throughout your chart configuration, and let you
+write custom code that will do what you need it to do in specific
+situations. It is incredibly powerful!
+
+However, Highcharts (JS) is a *JavaScript* suite, and that means 
+that it only works with *JavaScript* callback functions. So if
+we're using **Highcharts for Python**, how do we create JavaScript
+:term:`callback functions <callback function>` that Highcharts (JS)
+will know how to leverage?
+
+The answer is simple: **Highcharts for Python** provides a special
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+class that you can use to create JavaScript 
+:term:`callback functions <callback function>`. When using this class,
+you can either:
+
+#. Write your own JavaScript function and the 
+   :class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+   class will serialize it to JavaScript when needed, or
+#. You can write a :term:`callback function` in *Python*, and rely on either 
+   `OpenAI <https://www.openai.com>`__'s GPT or `Anthropic <https://anthropic.com>`__'s
+   Claude generative AI model to suggest an equivalent JavaScript function.
+
+Because you're using **Highcharts for Python**, let's look at the AI-driven 
+approach first, because we already know how to write Python code. No JavaScript 
+needed!
+
+----------------------------
+
+********************************************************
+Creating Callback Functions using Generative AI
+********************************************************
+
+The 
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+class has a special helper class method called 
+:meth:`.from_python() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_python>`
+which can automatically create a 
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+instance containing the JavaScript function that you need.
+
+Here's how that works. Let's imagine a scenario where we want a custom tooltip formatter function 
+that customizes the content of each data point's tooltips. We can write that function in Python like
+so:
+
+  .. code-block:: python
+
+    def my_custom_formatter():
+        return f'The value for <b>{this.x}</b> is <b>{this.y}</b>.'
+
+Really pretty straightforward, right? Now we can produce its equivalent by passing 
+``my_custom_formatter`` as an argument to
+:meth:`.from_python() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_python>`:
+
+  .. code-block:: python
+
+    my_callback = CallbackFunction.from_python(my_custom_formatter)
+
+What the 
+:meth:`.from_python() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_python>`
+method call will do is:
+
+  #. It will take the *Python* function's source code, and pass it to the generative AI model of your 
+     choice. 
+  #. The AI will return a *JavaScript* function that the AI believes will do the same thing as your 
+     *Python* function.
+  #. And it will then load that *JavaScript* function into a new 
+     :class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+     instance.
+
+Now, when you use this 
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+instance in your chart configuration, it will get serialized to its approrpriate *JavaScript* source
+code form when appropriate, for example when calling 
+:meth:`Chart.display() <highcharts_stock.chart.Chart.display>` or 
+:meth:`Chart.to_js_literal() <highcharts_stock.chart.Chart.to_js_literal>`.
+
+Using Different Models
+===============================
+
+**Highcharts for Python** supports different models provided by `OpenAI <https://www.openai.com>`__
+and `Anthropic <https://anthropic.com>`__. 
+
+OpenAI's models in particular differ based on the *version* of GPT that the model supports, as
+well as the number of tokens that they allow (more tokens mean they can convert more complicated/longer
+function). Most typical callback functions should be converted reasonably reliably using 
+the default model ``gpt-3.5-turbo``, though others are available:
+
+* **OpenAI**
+
+  * ``'gpt-3.5-turbo'`` (default)
+  * ``'gpt-3.5-turbo-16k'``
+  * ``'gpt-4'``
+  * ``'gpt-4-32k'``
+
+* **Anthropic**
+
+  * ``'claude-instant-1'``
+  * ``'claude-2'``
+
+To use a different model, simply pass the ``model`` argument to the
+:meth:`.from_python() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_python>`
+method:
+
+  .. code-block:: python
+
+    my_callback = CallbackFunction.from_python(my_custom_formatter, model = "gpt-4")
+
+Authenticating with Your AI Provider
+==========================================
+
+  .. caution::
+
+    Because this relies on the outside APIs exposed by 
+    `OpenAI <https://www.openai.com/>`__ and `Anthropic <https://www.anthropic.com>`__,
+    if you wish to use one of their models you *must* supply your own API key.
+    These are paid services which they provide, and so you *will* be incurring
+    costs by using these generative AIs.
+
+To use one of the supported AI models, you *must* have a valid user/customer account with either
+`OpenAI <https://www.openai.com>`__ or `Anthropic <https://anthropic.com>`__. You must also have
+an API key to their respective platform that has permission to use the model you request. You can
+set your account up and get the relevant API key from each of the AI providers, respectively.
+
+When you have the API key, you can pass it in as an argument (``api_key``) to the 
+:meth:`.from_python() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_python>`
+method:
+
+  .. code-block:: python
+
+    my_callback = CallbackFunction.from_python(my_custom_formatter, api_key = "YOUR-API-KEY-GOES-HERE")
+
+However, if you do not supply an explicit ``api_key`` value, **Highcharts for Python** will look for
+the API key in your ``OPENAI_API_KEY`` or ``ANTHROPIC_API_KEY`` environment variables.
+
+.. tip::
+
+  **BEST PRACTICE:** Treat your API key as a highly-sensitive piece of information. It should never
+  be listed in your source code, or in your Jupyter Notebook. It should *only* be read from environment
+  variables, which in turn should get set with as few places where your API key is visible/available as
+  possible.
+
+Reviewing Your JavaScript Code
+===================================
+
+  .. warning::
+
+    Generating the JavaScript source code is *not* deterministic.
+    That means that it may not be correct, and we **STRONGLY** 
+    recommend reviewing it before using it in a production 
+    application.
+
+    Every single generative AI is known to have issues - whether 
+    "hallucinations", biases, or incoherence. We cannot stress
+    enough:
+
+    **DO NOT RELY ON AI-GENERATED CODE IN PRODUCTION WITHOUT HUMAN REVIEW.**
+
+    That being said, for "quick and dirty" EDA, fast prototyping, etc.
+    the functionality may be "good enough".
+
+Once you have created a
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+instance using the 
+:meth:`.from_python() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_python>`
+method, you can review the JavaScript source code that was generated by calling ``str()`` on your
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>` instance:
+
+  .. code-block::
+
+    print(str(my_callback))
+
+    # Output:
+    # function my_custom_formatter() { return 'The value for <b>' + this.x + '</b> is <b>' + this.y + '</b>.'; }
+
+We **STRONGLY** recommend reviewing the JavaScript source code that was generated before using it in 
+production. Even if you are not a JavaScript expert, since you know Python and you know what your function *should*
+be doing, you can probably follow along close-enough to make sure the JavaScript code "looks right".
+
+  .. tip::
+
+    **BEST PRACTICE:** Never let the AI generate JavaScript code based on *user-entered* Python code.
+
+    Doing so may introduce unintended security vulnerabilities into your application, and should be
+    considered *VERY* bad practice.
+
+-------------------------------------
+
+********************************************************
+Creating Callback Functions Directly
+********************************************************
+
+If you do not wish to use generative AI to create your :term:`callback functions <callback function>`,
+you can simply create 
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>` 
+instances directly. You can do this by:
+
+Instantiating the ``CallbackFunction`` Directly
+===================================================
+
+.. code-block:: python
+
+  my_callback = CallbackFunction(function_name = 'my_formatter',
+                                 arguments = None,
+                                 body = """return 'The value for <b>' + this.x + '</b> is <b>' + this.y + '</b>.';""")
+
+When instantiating the callback function directly, you supply the body of the function as a string to
+the ``body`` argument.  A best practice is to use Python's triple-quote syntax to make it easier to
+handle quotation marks *within* your JavaScript code.
+
+Using ``.from_js_literal()``
+=================================
+
+If you have your JavaScript function in a string, you can use the
+:meth:`CallbackFunction.from_js_literal() <highcharts_stock.utility_classes.javascript_functions.CallbackFunction.from_js_literal>` class method to create the callback function instance:
+
+  .. code-block:: python
+
+    callback_as_str = """function my_formatter() {
+       return 'The value for <b>' + this.x + '</b> is <b>' + this.y + '</b>.'; 
+    }"""
+
+    my_callback = CallbackFunction.from_js_literal(callback_as_str)
+
+----------
+
+And that's it! When your
+:class:`CallbackFunction <highcharts_stock.utility_classes.javascript_functions.CallbackFunction>`
+instances are used in your chart configuration, they will automatically be serialized to the 
+appropriate JavaScript syntax when needed.
\ No newline at end of file
diff --git a/docs/tutorials/csv.rst b/docs/tutorials/csv.rst
new file mode 100644
index 0000000..2c8eae6
--- /dev/null
+++ b/docs/tutorials/csv.rst
@@ -0,0 +1,471 @@
+########################################################
+Using Highcharts Core for Python with CSVs
+########################################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+CSV (Comma-Separated Value) is one of the most common formats for exchanging
+data files - both large and small. Because of its popularity, the 
+**Highcharts for Python Toolkit** is designed to work seamlessly with it.
+
+.. sidebar:: What Can Highcharts for Python do with CSVs?
+
+  The **Highcharts for Python Toolkit** is a *visualization* library. It is
+  not used to perform *arithmetical*, *algebraic*, *statistical*, or *matrix* 
+  calculations. It is exclusively concerned with visualizing data - and that
+  data is typically the product of calculations that are performed up-stream.
+
+  So given that focus, **Highcharts for Python** is designed to *read* data
+  that is contained in CSV files and load the data they contain into
+  appropriate **Highcharts for Python** classes, which can then be rendered
+  using Highcharts (JS).
+
+*********************************
+General Approach
+*********************************
+
+The **Highcharts for Python Toolkit** provides a number of standard methods
+that are used to interact with CSV files. These methods generally take the form:
+
+  * ``.from_csv(as_string_or_file)`` This is always a class method which produces one or more
+    instances, with data pulled from the CSV content found in ``as_string_or_file``.
+  * ``.from_csv_in_rows(as_string_or_file)`` This is always a class method which produces one
+    instance for every *row* in the CSV (``as_string_or_file``).
+  * ``.load_from_csv(as_string_or_file)`` This is an instance method which updates an instance
+    with data read from the ``as_string_or_file`` argument.
+
+.. tip::
+
+  All three of these standard methods are packaged to have batteries included.
+  This means that for simple use cases, you can simply pass a 
+  CSV to the method, and the method wlil attempt to determine the best way to 
+  deserialize the CSV into the appropriate  **Highcharts for Python** objects.
+
+  However, if you find that you need more fine-grained control, the methods
+  provide powerful tools to give you the control you need when you need it.
+
+These standard methods - with near-identical syntax - are available:
+
+  * On all :term:`series` classes (descended from 
+    :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`)
+  * On the :class:`Chart <highcharts_stock.chart.Chart>` class
+
+-------------------------------
+
+*****************************
+Preparing Your CSV Data
+*****************************
+
+So let's try a real-world example. Let's say you've got some annual population
+counts stored in a CSV file named ``'census-time-series.csv'`` that looks like this:
+
+  .. image:: /_static/tutorials/census-time-series-csv-01.png
+     :width: 100%
+     :alt: Rendering of the data contained in 'census-time-series.csv'
+
+The first column contains the names of geographic regions, while each of the subsequent
+columns contains the population counts for a given year. Now, let's say we wanted
+to visualize this data in various ways.
+
+------------------------------
+
+*********************************************
+Creating the Chart: ``Chart.from_csv()``
+*********************************************
+
+Relying on the Defaults
+===========================
+
+The simplest way to create a chart from a CSV file is to call 
+:class:`Chart.from_csv() <highcharts_stock.chart.Chart.from_csv>` like
+so:
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            wrapper_character = '"')
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-03.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv')
+
+As you can see, we haven't provided any more instructions besides telling it to
+generate a chart from the file ``'census-time-series.csv'``, and to interpret a single 
+quotation mark as a wrapper character. The result is a line chart, with one series for 
+each year, and one point for each region. 
+
+  .. tip::
+
+    Unless instructed otherwise, **Highcharts for Python** will default to using a
+    line chart. 
+
+Setting the Series Type
+==============================
+
+Why don't we switch it to a bar chart?
+
+.. code-block:: python
+        
+  my_chart = Chart.from_csv('census-time-series.csv', 
+                            series_type = 'bar',
+                            wrapper_character = '"')
+
+.. image:: /_static/tutorials/census-time-series-04.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'bar')
+
+Now the result is a little more readable, but still not great: After all, there are more than
+fifty geographic regions represented for each year, which makes the chart super crowded. 
+Besides, maybe we're only interested in a specific year: 2019. 
+
+Let's try focusing our chart.
+
+Basic Property Mapping
+==========================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'bar',
+                            property_column_map = {
+                                'x': 'Geographic Area',
+                                'y': '2019'
+                            })
+
+.. image:: /_static/tutorials/census-time-series-05.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'bar', property_column_map = {'x': 'Geographic Area', 'y': '2019'})
+
+Much better! We've now added a ``property_column_map`` argument to the ``.from_csv()`` method call. 
+This argument tells Highcharts for Python how to map columns in your data to properties in the 
+resulting chart. In this case, the keys ``'x'`` and ``'y'`` tell **Highcharts for Python** that you want to map the ``'Geographic Area'`` column to the resulting series' data points' 
+:meth:`.x <highcharts_stock.options.series.data.bar.BarData.x>`,
+and to map the ``'2019'`` column to the :meth:`.y <highcharts_stock.options.series.data.bar.BarData.y>` 
+properties, respectively.
+
+The net result is that ``my_chart`` contains one 
+:class:`BarSeries <highcharts_stock.options.series.bar.BarSeries>` whose 
+:meth:`.data <highcharts_stock.options.series.bar.BarSeries.data>` property contains a 
+:class:`BarDataCollection <highcharts_stock.options.series.data.bar.BarDataCollection>` instance populated
+with the data from the ``'Geographic Area'`` and ``'2019'`` columns in ``census-time-series.csv``.
+
+But maybe we actually want to compare a couple different years? Let's try that.
+
+  .. tip::
+
+    Not all CSV data contains a header row. If your CSV data does not contain a header row,
+    ``property_column_map`` accepts :class:`int <python:int>` values, which indicate the
+    index of the column that you want to map. So the method call above would be equivalent to:
+
+      .. code-block:: python
+
+        my_chart = Chart.from_csv('census-time-series.csv',
+                                  series_type = 'bar',
+                                  property_column_map = {
+                                      'x': 0,
+                                      'y': 10
+                                  })
+
+Property Mapping with Multiple Series
+========================================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'column',
+                            property_column_map = {
+                                'x': 'Geographic Area',
+                                'y': ['2017', '2018', '2019']
+                            })
+
+.. image:: /_static/tutorials/census-time-series-06.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'bar', property_column_map = {'x': 'Geographic Area', 'y': ['2017', '2018', '2019']})
+
+Now we're getting somewhere! We've added a list of column names to the ``'y'`` key in the ``property_column_map`` 
+argument. Each of those columns has now produced a *separate* 
+:class:`BarSeries <highcharts_stock.options.series.bar.BarSeries>` instance - but they're 
+all still sharing the ``'Geographic Area'`` column as their 
+:meth:`.x <highcharts_stock.options.series.data.bar.BarData.x>` value.
+
+  .. note::
+
+    You can supply multiple values to any property in the ``property_column_map``. The example
+    provided above is equivalent to:
+
+      .. code-block:: python
+
+        my_chart = Chart.from_csv('census-time-series.csv',
+                                     series_type = 'column',
+                                     property_column_map = {
+                                         'x': ['Geographic Area', 'Geographic Area', 'Geographic Area'],
+                                         'y': ['2017', '2018', '2019']
+                                     })
+
+    The only catch is that the ultimate number of values for each key must match. If there's
+    only one value, then it will get repeated for all of the others. But if there's a mismatch,
+    then **Highcharts for Python** will throw a 
+    :exc:`HighchartsCSVDeserializationError <highcharts_stock.errors.HighchartsCSVDeserializationError>`.
+
+But so far, we've only been using the ``'x'`` and ``'y'`` keys in our ``property_column_map``. What if we wanted to
+configure additional properties? Easy!
+
+Configuring Additional Properties
+=====================================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'bar',
+                            property_column_map = {
+                                'x': 'Geographic Area',
+                                'y': ['2017', '2018', '2019'],
+                                'id': 'some other column'
+                            })
+
+Now, our CSV is pretty simple does not contain a column named ``'some other column'`. But *if* it did,
+then it would use that column to set the :meth:`.id <highcharts_stock.options.series.data.bar.BarData.id>` property of each data point.
+
+  .. note::
+
+    You can supply any property you want to the ``property_map``. If the property is not
+    supported by the series type you've selected, then it will be ignored.
+
+But our chart is still looking a little basic - why don't we tweak some series configuration options?
+
+Configuring Series Options
+===============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'bar',
+                            property_column_map = {
+                                'x': 'Geographic Area',
+                                'y': ['2017', '2018', '2019'],
+                            },
+                            series_kwargs = {
+                                'point_padding': 5
+                            })
+
+.. image:: /_static/tutorials/census-time-series-07.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'bar', property_column_map = {'x': 'Geographic Area', 'y': ['2017', '2018', '2019'], 'id': 'Geographic Area'}, series_kwargs = {'point_padding': 0.25})
+
+As you can see, we supplied a new ``series_kwargs`` argument to the ``.from_csv()`` method call. This
+argument receives a :class:`dict <python:dict>` with keys that correspond to properties on the series. In
+this case, by supplying ``'point_padding'`` we have set the resulting 
+:meth:`BarSeries.point_padding <highcharts_stock.options.series.bar.BarSeries.point_padding>` property to a
+value of ``0.25`` - leading to a bit more spacing between the bars.
+
+But our chart is *still* a little basic - why don't we give it a reasonable title?
+
+Configuring Options
+=============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'bar',
+                            wrapper_character = '"',
+                            property_column_map = {
+                                'x': 'Geographic Area',
+                                'y': ['2017', '2018', '2019']
+                            },
+                            series_kwargs = {
+                                'point_padding': 5
+                            },
+                            options_kwargs = {
+                                'title': {
+                                  'text': 'This Is My Chart Title'
+                                }
+                            })
+
+.. image:: /_static/tutorials/census-time-series-08.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'bar', property_column_map = {'x': 'Geographic Area', 'y': ['2017', '2018', '2019'], 'id': 'Geographic Area'}, series_kwargs = {'point_padding': 0.25}, options_kwargs = {'title': {'text': 'This Is My Chart Title'}})
+
+As you can see, we've now given our chart a title. We did this by adding a new ``options_kwargs`` argument,
+which likewise takes a :class:`dict <python:dict>` with keys that correspond to properties on the chart's
+:class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>` configuration.`
+
+Now let's say we wanted our chart to render in an HTML ``<div>`` with an ``id`` of ``'my_target_div`` - 
+we can configure that in the same method call.
+
+Configuring Chart Settings
+==============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'bar',
+                            wrapper_character = '"',
+                            property_column_map = {
+                                'x': 'Geographic Area',
+                                'y': ['2017', '2018', '2019'],
+                            },
+                            series_kwargs = {
+                                'point_padding': 0.25
+                            },
+                            options_kwargs = {
+                                'title': {
+                                  'text': 'This Is My Chart Title'
+                                }
+                            },
+                            chart_kwargs = {
+                                'container': 'my_target_div'
+                            })
+
+While you can't really *see* the difference here, by adding the ``chart_kwargs`` argument to
+the method call, we now set the :meth:`.container <highcharts_stock.chart.Chart.container>` property
+on ``my_chart``.
+
+But maybe we want to do something a little different - like compare the change in population over time.
+Well, we can do that easily by visualizing each *row* of ``census-time-series.csv`` rather than each *column*.`
+
+Visualizing Data in Rows
+==============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'line',
+                            series_in_rows = True,
+                            wrapper_character = '"')
+
+.. image:: /_static/tutorials/census-time-series-09.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'line', series_in_rows = True)
+
+Okay, so here we removed some of the other arguments we'd been using to simplify the example. You'll see we've now
+added the ``series_in_rows`` argument, and set it to ``True``. This tells **Highcharts for Python** that we expect
+to produce one series for every *row* in ``census-time-series.csv``. 
+
+Because we have not specified a ``property_column_map``, the series 
+:meth:`.name <highcharts_stock.options.series.bar.BarSeries.name>` values are populated from the ``'Geographic Area'``
+column, while the data point :meth:`.x <highcharts_stock.options.series.data.bar.BarData.y>` values come from each additional column (e.g. ``'2010'``, ``'2011'``, ``'2012'``, etc.)
+
+  .. tip::
+
+    To simplify the code further, any class that supports the ``.from_csv()`` method also
+    supports the ``.from_csv_in_rows()`` method. The latter method is equivalent to passing
+    ``series_in_rows = True`` to ``.from_csv()``.
+
+    For more information, please see:
+
+      * :class:`Chart.from_csv_in_rows() <highcharts_stock.chart.Chart.from_csv_in_rows>`
+      * :class:`SeriesBase.from_csv_in_rows() <highcharts_stock.options.series.base.SeriesBase.from_csv_in_rows>`
+
+But maybe we don't want *all* geographic areas shown on the chart - maybe we only want to compare a few.
+
+Filtering Rows
+=======================
+
+.. code-block:: python
+
+  my_chart = Chart.from_csv('census-time-series.csv',
+                            series_type = 'line',
+                            series_in_rows = True,
+                            wrapper_character = '"',
+                            series_index = slice(7, 10))
+
+.. image:: /_static/tutorials/census-time-series-10.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_csv('census-time-series.csv', series_type = 'line', series_in_rows = True, series_index = slice(7, 10))
+
+What we did here is we added a ``series_index`` argument, which tells **Highcharts for Python** to only
+include the series found at that index in the resulting chart. In this case, we supplied a :func:`slice <python:slice>`
+object, which operates just like ``list_of_series[7:10]``. The result only returns those series between index 7 and 10.
+
+------------------------
+
+**********************************************************************
+Creating Series: ``.from_csv()`` and ``.from_csv_in_rows()``
+**********************************************************************
+
+All **Highcharts for Python** :term:`series` descend from the 
+:class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>` class. And they all
+therefore support the ``.from_csv()`` class method. 
+
+When called on a series class, it produces one or more series from the CSV supplied. 
+The method supports all of the same options
+as :class:`Chart.from_csv() <highcharts_stock.chart.Chart.from_csv>` *except for* ``options_kwargs`` and
+``chart_kwargs``. This is because the ``.from_csv()`` method on a series class is only responsible for
+creating series instances - not the chart itself.
+
+Creating Series from Columns
+==================================
+
+So let's say we wanted to create one series for each of the years in ``census-time-series.csv``. 
+We could do that like so:
+
+  .. code-block:: python
+
+    my_series = BarSeries.from_csv('census-time-series.csv')
+
+Unlike when calling :meth:`Chart.from_csv() <highcharts_stock.chart.Chart.from_csv>`, we
+did not have to specify a ``series_type`` - that's because the ``.from_csv()`` class method on a
+series class already knows the series type.
+
+In this case, ``my_series`` now contains ten separate :class:`BarSeries <highcharts_stock.options.series.bar.BarSeries>`
+instances, each corresponding to one of the year columns in ``census-time-series.csv``.
+
+But maybe we wanted to create our series from rows instead?
+
+Creating Series from Rows
+=================================
+
+.. code-block:: python
+
+  my_series = LineSeries.from_csv_in_rows('census-time-series.csv')
+
+This will produce one :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>`
+instance for each row in ``census-time-series.csv``, ultimately producing a 
+:class:`list <python:list>` of 57 
+:class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` instances.
+
+Now what if we don't need all 57, but instead only want the first five?
+
+Filtering Series Created from Rows
+======================================
+
+.. code-block:: python
+
+  my_series = LineSeries.from_csv_in_rows('census-time-series.csv', series_index = slice(0, 5))
+
+This will return the first five series in the list of 57.
+--------------------------
+
+***********************************************************
+Updating an Existing Series: ``.load_from_csv()``
+***********************************************************
+
+So far, we've only been creating new series and charts. But what if we want to update
+the data within an existing series? That's easy to do using the 
+:meth:`.load_from_csv() <highcharts_stock.options.series.base.SeriesBase.load_from_csv>` method.
+
+Let's say we take the first series returned in ``my_series`` up above, and we want to replace
+its data with the data from the *10th* series. We can do that by:
+
+  .. code-block:: python
+
+    my_series[0].load_from_csv('census-time-series.csv', 
+                               series_in_rows = True,
+                               series_index = 9)
+
+The ``series_in_rows`` argument tells the method to generate series per row, and then
+the ``series_index`` argument tells it to only use the 10th series generated.
+
+  .. caution::
+
+    While the :meth:`.load_from_csv() <highcharts_stock.options.series.base.SeriesBase.load_from_csv>`
+    method supports the same arguments as 
+    :meth:`.from_csv() <highcharts_stock.options.series.base.SeriesBase.from_csv>`, it expects that
+    the arguments supplied lead to an unambiguous *single* series. If they are ambiguous - meaning they
+    lead to multiple series generated from the CSV - then the method will throw a 
+    :exc:`HighchartsCSVDeserializationError <highcharts_stock.errors.HighchartsCSVDeserializationError>`
\ No newline at end of file
diff --git a/docs/tutorials/data.rst b/docs/tutorials/data.rst
new file mode 100644
index 0000000..b8525a5
--- /dev/null
+++ b/docs/tutorials/data.rst
@@ -0,0 +1,412 @@
+########################################################
+Using Highcharts Core for Python with Pandas
+########################################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+The **Highcharts for Python Toolkit** is a data *visualizaiton* library.
+That means that it is designed to let you visualize the data that you
+or your users are analyzing, rather than to do the analysis itself. But
+while there are better tools to actually crunch the numbers, 
+**Highcharts for Python** still has to work closely with your data in
+order to visualize it.
+
+When working with **Highcharts for Python**, it can be useful to
+understand:
+
+  #. How **Highcharts for Python** represents your data
+  #. How to load your data into a **Highcharts for Python** object
+  #. How to adjust your data in **Highcharts for Python**
+  #. How **Highcharts for Python** serializes your data for 
+     Highcharts (JS). 
+
+-------------------
+
+*************************************
+Highcharts for Python Data Model
+*************************************
+
+In broad brushstrokes, you can think of your **Highcharts for Python**
+chart as a tree. 
+
+.. list-table::
+  :widths: 30 70
+
+  * - .. image:: /_static/highcharts-chart-anatomy.png
+        :width: 100%
+        :alt: Diagram of chart structure: Chart > Options > Series Collection > Series > Data Collection > Data Point
+
+At the root of the tree is a 
+:class:`Chart <highcharts_stock.chart.Chart>`, and that chart contains 
+options (:class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>`). 
+Those options in turn contain a collection of :term:`series`,
+each of which can be thought of as one "line" of data in your visualization.
+
+Each series instance (descended from 
+:class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`)
+contains a :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>`
+property, which contains a set of :term:`data points <data point>`.
+
+Depending on your data and your configuration, this set of data points may 
+be represented as:
+
+  * a :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+    instance (or a descendent of it) which in turn contains your data values and related
+    configuration options
+  * an iterable of 
+    :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`-descended instances,
+    each of which contains the data value and configuration of an invidual :term:`data point`
+
+This model is relatively straightforward, but there is one important complexity: the 
+relationship between 
+:class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+instances and :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>` instances.
+
+:class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>` vs :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`
+=======================================================================================================================================================================================
+
+The :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>` 
+class stores your individual data points in a combination of three different list-like structures:
+
+  * as a :class:`numpy.ndarray <numpy:numpy.ndarray>` in the 
+    :meth:`.ndarray <highcharts_stock.options.series.data.collections.DataPointCollections.ndarray>` property
+  * as a :class:`list <python:list>` of 
+    :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>` instances in the 
+    :meth:`.data_points <highcharts_stock.options.series.data.collections.DataPointCollections.data_points>`
+    property
+  * as a :class:`list <python:list>` of primitives (e.g. numbers, strings, etc.) in the 
+    :meth:`.array <highcharts_stock.options.series.data.collections.DataPointCollections.array>`
+    property
+
+Why split it up like this? The purpose is to maximize performance within both
+**Highcharts for Python** and Highcharts (JS), while still minimizing outside dependencies.
+
+Highcharts (JS) supports data organized in primitive arrays. So it can easily visualize something
+like the following:
+
+  .. code-block:: python
+
+    [
+        [0, 12],
+        [1, 34],
+        [2, 56],
+        [3, 78],
+        [4, 90]
+    ]
+
+This way of representing your data gives you the fastest performance in Highcharts (JS),
+leading to lightening-fast rendering of your chart. And since it's just a simple list of
+numbers, **Highcharts for Python** doesn't have to apply any fancy logic to serialize it to
+:term:`JS literal notation <JavaScript Object Literal Notation>` - leading to fast 
+performance in Python as well.
+
+This is why the 
+:class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+separates the data that can be represented as a primitive array (stored in either 
+:meth:`.ndarray <highcharts_stock.options.series.data.collections.DataPointCollections.ndarray>` or
+:meth:`.array <highcharts_stock.options.series.data.collections.DataPointCollections.array>`), from 
+data point properties that need to be represented as a full Highcharts (JS) data point object
+(stored in 
+:meth:`.data_points <highcharts_stock.options.series.data.collections.DataPointCollections.data_points>`).
+
+And if you're familiar with `NumPy <https://www.numpy.org>`__, that looks *just* like
+a :class:`ndarray <numpy:numpy.ndarray>` - and for good reason! If you have 
+`NumPy <https://www.numpy.org>` installed, **Highcharts for Python** will leave your 
+:class:`ndarray <numpy:numpy.ndarray>` objects as-is to benefit from its vectorization 
+and performance.
+
+Internally, 
+:class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+instances will intelligently combine the information stored in these three different properties
+to serialize your data points. This is done as-appropriately, generating a list of renderable
+data points represented either as a primitive array, or as full objects, depending on the
+properties that have been configured.
+
+So do you have to worry to about this complexity? Not really! All of this happens under the
+hood in the **Highcharts for Python** code. You can simply load your data using the
+convenience methods available on your series instances
+:class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>` 
+or its descendents, or simply pass your data to the series 
+:class:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property.
+
+Let's see how this works in practice.
+
+------------------------
+
+*****************************************
+Loading Data into Highcharts for Python
+*****************************************
+
+Preparing Your Data
+===========================
+
+So let's try a real-world example. Let's say you've got some annual population
+counts stored in a CSV file named ``'census-time-series.csv'``. There are four
+different ways you can represent this data:
+
+  #. As-is in the CSV file. Meaning you don't do anything, just leave it
+     in the file as-is.
+  #. Loaded into a Python iterable (i.e. a :class:`list <python:list>` of
+     :class:`list <python:list>`, where each inner list represents a row from
+     the CSV). This might look something like this:
+
+       .. code-block:: python
+
+        raw_data = [
+            ['United States', 309321666, 311556874, 313830990, 315993715, 318301008, 320635163, 322941311, 324985539, 326687501, 328239523],
+            ['Northeast',  55380134, 55604223, 55775216, 55901806, 56006011, 56034684, 56042330, 56059240, 56046620, 55982803],
+            ['Midwest', 66974416, 67157800, 67336743, 67560379, 67745167, 67860583, 67987540, 68126781, 68236628, 68329004],
+            ...
+        ]
+
+  #. As a :class:`numpy.ndarray <numpy:numpy.ndarray>`, which might look like this:
+
+      .. list-table::
+        :widths: 30 70
+
+          - .. image:: /_static/tutorials/raw-data-as-numpy.png
+              :width: 100%
+              :alt: Rendering of the numpy.ndarray produced by np.genfromtext('census-time-series.csv', delimiter = ',', names = True)
+
+  #. As a :class:`pandas.DataFrame <pandas:pandas.DataFrame>`, which might look like this:
+
+      .. list-table::
+        :widths: 30 70
+
+        * - .. code-block:: python
+      
+              raw_data = pandas.read_csv('census-time-series.csv',
+                                         index_col = 0,
+                                         thousands = ',', 
+                                         delimiter = ',')
+
+        * - .. image:: /_static/tutorials/census-time-series-02.png
+              :width: 100%
+              :alt: Rendering of the Pandas DataFrame loaded from "census-time-series.csv"
+
+Now that we've got our data prepared, let's add it to a series or chart.
+
+Creating a Series/Chart with Data
+======================================
+
+.. note::
+
+  In this tutorial, we'll focus on assembling one or more :term:`series` of data, rather than
+  a complete chart. This is because chart's have many more configuration options, but 
+  fundamentally the data that they contain is stored within one or more series instances,
+  which themselves contain data points in a 
+  :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>` 
+  or an iterable of 
+  :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>` instances.
+
+So now that we have ``raw_data`` prepared, we can now load it into a series. There are four ways to do 
+this:
+
+  #. By passing it to the :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
+     of our series when instantiating the series:
+
+     .. code-block:: python
+
+      from highcharts_stock.options.series.area import LineSeries
+
+      my_series = LineSeries(data = raw_data)
+
+  #. By calling one of the "helper" methods:
+
+    .. code-block:: python
+
+      from highcharts_stock.options.series.area import LineSeries
+
+      # If my data is either a numpy.ndarray or Python iterable
+      my_series = LineSeries.from_array(raw_data)
+
+      # If my data is in a Pandas DataFrame
+      my_series = LineSeries.from_pandas(raw_data)
+
+      # If my data is in a CSV file
+      my_series = LineSeries.from_csv('census-time-series.csv')
+
+    .. seealso::
+
+      Depending on the arguments you supply to the helper methods, they
+      may produce *multiple* series for inclusion on your chart. For more
+      information, please see:
+
+        * :doc:`Using Highcharts for Python with Pandas <pandas>`
+        * :doc:`Using Highcharts for Python with CSVs <csv>`
+
+  #. By instantiating your *set* of data directly, and passing it to the
+     :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
+     of our series:
+
+       .. code-block:: python
+
+         from highcharts_stock.options.series.area import LineSeries
+         from highcharts_stock.options.series.data.cartesian import CartesianData
+
+         my_data = CartesianData.from_array(raw_data)
+
+         my_series = LineSeries(data = my_data)
+
+       .. seealso::
+
+       Depending on the arguments you supply to the helper methods, they
+       may produce *multiple* series for inclusion on your chart. For more
+       information, please see:
+
+         * :doc:`Using Highcharts for Python with Pandas <pandas>`
+         * :doc:`Using Highcharts for Python with CSVs <csv>`
+
+    #. By instantiating *individual* data points directly, and passing it to
+       the :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
+       of our series:
+
+       .. code-block:: python
+
+         from highcharts_stock.options.series.area import LineSeries
+         from highcharts_stock.options.series.data.cartesian import CartesianData
+
+         my_data = [CartesianData(x = record[0], y = record[1] for record in raw_data]
+
+         my_series = LineSeries(data = my_data)
+
+
+In all cases, the result is the same: a 
+:class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` instance (or a 
+:class:`list <python:list>` of 
+:class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` that contain your data.
+
+Now that your data has been loaded into your series, you can configure it as needed. 
+
+Configuring Your Data
+=========================================
+
+In most cases, you shouldn't have to worry about the internals of how **Highcharts for Python**
+stores your data. Depending on whether you supplied a primitive array, a 
+:class:`numpy.ndarray <numpy:numpy.ndarray>`, or data from a Pandas 
+:class:`DataFrame <pandas:pandas.DataFrame>`, your series' data will either be represented as
+a :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+or as a :class:`list <python:list>` of data point objects (descended from 
+:class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`).
+
+In all cases, you can easily set properties on your data via your series object itself. For
+example, let's say we wanted to configure the 
+:meth:`.target <highcharts_stock.options.series.bullet.BulletSeries>` values on data points
+in a :class:`BulletSeries <highcharts_stock.options.series.bullet.BulletSeries>` instance. We
+can do that easily by working at the *series* level:
+
+  .. code-block:: python
+
+    # EXAMPLE 1.
+    # Supplying one value per data point.
+
+    my_series.target = [1, 2, 3, 4, 5, 6]
+
+    # EXAMPLE 2.
+    # Supplying one value, which will be applied to ALL data points.
+
+    my_series.target = 2
+
+This propagation of data point properties extends to *all* data point properties. If a
+property of the same name exists on the series, it will be set on the *series*. But if
+it only exists on the data point, it will be propagated to the relevant data points.
+
+In some circumstances, you may want to set data point properties that have identically-named
+properties on the series. For example, data points and series both support the ``.id`` property.
+But you can set this property at the data point level in two ways:
+
+  #. If your data point is represented as a 
+     :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`,
+     you can simply set it as a sub-property of the series 
+     :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property:
+
+     .. code-block:: python
+
+       # EXAMPLE 1.
+       # Supplying one value per data point.
+       my_series.data.id = ['id1', 'id2', 'id3', 'id4', 'id5', 'id6']
+
+       # EXAMPLE 2.
+       # Supplying one value, which will be applied to ALL data points.
+
+       my_series.data.id = 'id2'
+
+    The :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+    will worry about proagating the relevant property / value to the individual data points as needed.
+
+  #. If you data points are represented as a :class:`list <python:list>` of 
+     :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`-descended objects, then you can
+     adjust them the same way you would adjust any member of a list:
+
+     .. code-block::
+    
+       id_list = ['id1', 'id2', 'id3', 'id4', 'id5', 'id6']
+       for index in range(len(series.data)):
+           series.data[index].id = id_list[index]
+
+    In this case, you are adjusting the data points directly, so you do need to make sure you are 
+    adjusting the exact properties you need to adjust in the exact right location.
+
+Updating Your Data
+========================
+
+You can also update your data after it has been loaded into your series. This is done by calling one
+of the ``.load_from_*`` series helper methods, which makes it possible to update your series' data
+just like when creating the series:
+
+  .. code-block:: python
+
+    # EXAMPLE 1.
+    # Updating the .data property
+
+    my_series.data = updated_data
+
+    # EXAMPLE 2.
+    # If my data is either a numpy.ndarray or Python iterable
+
+    my_series.load_from_array(updated_data)
+
+    # EXAMPLE 3.
+    # If my data is in a Pandas DataFrame
+
+    my_series.load_from_pandas(updated_data)
+
+    # EXAMPLE 4.
+    # If my data is in a CSV file
+
+    my_series.load_from_csv('updated-data.csv')
+
+---------------------------
+
+***************************************
+Serializing Your Data for Rendering
+***************************************
+
+While you shouldn't have to serialize your data directly using **Highcharts for Python**, it
+may be useful to understand how this process works.
+
+First, it's important to understand that Highcharts (JS) supports data represented in two different
+forms:
+
+  * as :term:`JavaScript literal objects <JavaScript Object Literal Notation>`, and
+  * as primitive arrays, which are basically collections of strings and numbers
+
+JS literal objects are the most flexible, because they allow you to take advantage of all of the
+different data point configuration options supported by Highcharts. However, primitive arrays
+perform much faster: Highcharts for Python generates them faster, there's less data to transfer on the wire, and Highcharts (JS) can render them faster.
+
+For this reason, **Highcharts for Python** will always try to serialize your data points to a 
+primitive array first. If the series type supports a primitive array, and there is no information configured
+on the data points that prevents it from being serialized as a primitive array, Highcharts for Python
+will default to that form of serialization.
+
+However, if there are special properties (not supported by primitive arrays) set on the data points, or if
+the series type is one that does not support primitive arrays, then Highcharts for Python will generate
+a JavaScript literal object instead.
+
+This logic all happens automatically whenever you call 
+:class:`.to_js_literal() <highcharts_stock.options.series.base.SeriesBase.to_js_literal>` on your series.
diff --git a/docs/tutorials/exporting.rst b/docs/tutorials/exporting.rst
new file mode 100644
index 0000000..be33da9
--- /dev/null
+++ b/docs/tutorials/exporting.rst
@@ -0,0 +1,161 @@
+#######################################################
+Exporting Static Charts with Highcharts for Python
+#######################################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+Highcharts (JS) and **Highcharts for Python** are designed to produce beautiful, powerful, highly-interactive
+data visualizations. However, there are moments when you or your users want to create a static chart for inclusion in
+presentations, documents, etc. Highcharts has you covered for that as well!
+
+------------
+
+**********************
+Client-side Exporting
+**********************
+
+Using **Highcharts for Python**, you can configure client-side export within the 
+:meth:`Chart.options <highcharts_stock.chart.Chart.options>` settings by configuring the 
+:meth:`options.exporting <highcharts_stock.options.HighchartsOptions.exporting>` 
+property. 
+
+In particular, you can apply configuration through an 
+:class:`Exporting <highcharts_stock.options.exporting.Exporting>` instance, which 
+lets you configure how your chart will support exporting from within the user's 
+browser when the chart is rendered. Here’s a quick example, assuming you have a 
+:meth:`Chart <highcharts_stock.chart.Chart>`` instance called ``my_chart``:
+
+  .. code-block:: python
+
+    from highcharts_stock.options.exporting import Exporting
+
+    exporting_options = Exporting(enabled = True,
+                                  filename = 'your-exported-chart',
+                                  show_table = True,
+                                  table_caption = "Your Chart's Caption Goes Here",
+                                  accessibility = {
+                                      'enabled': True
+                                  })
+    
+    exporting_options.buttons['contextButton'].menu_items = ['printChart', 'separator', 'downloadPNG']
+    
+    my_chart.options.exporting = exporting_options
+
+And that's it. With the code above you've now configured some basic logic that:
+
+  * Enables client-side export of the ``my_chart`` visualization.
+  * Gives an exported chart image a default filename of ``'your-exported-chart'`` (not 
+    including the file's extension).
+  * Makes sure that the exported or printed version of your chart includes the chart's 
+    underlying data table (thanks to the ``show_table`` property being set to ``True``), 
+    and
+  * Gives users the ability to either print the chart or download a PNG version of the chart, 
+    but nothing else (by setting the relevant buttons shown in the context menu).
+
+Highcharts Core supports client-side export to a number of formats, including:
+
+  * PNG
+  * JPEG
+  * SVG
+  * CSV
+  * Excel
+
+And you can also configure the client-side export to fall back to server-side export should it fail. 
+
+  .. seealso::
+    
+    * For more details on the extensive options, please see :mod:`highcharts_stock.options.exporting`
+
+---------
+
+**************************************
+Programmatic (Server-side) Export
+**************************************
+
+So now that your users can download a PNG image of your chart, maybe you want to create an image programmatically. **Highcharts for Python** makes that possible through an integration with the **Highcharts Export Server**. It's actually trivially easy to do since you can do it with just one method call in your Python code:
+
+  .. code-block:: python
+
+    # EXAMPLE 1.
+    # Download a PNG version of the chart in memory within your Python code.
+
+    my_png_image = my_chart.download_chart(format = 'png')
+
+    # EXAMPLE 2.
+    # Download a PNG version of the chart and save it the file "/images/my-chart-file.png"
+    my_png_image = my_chart.download_chart(
+        format = 'png',
+        filename = '/images/my-chart-file.png'
+    )
+
+The two examples shown above both download a PNG of your chart:
+
+  #. The first example keeps that PNG image in your Python code only, storing its binary data in the 
+     ``my_png_image`` variable. 
+  #. The second example not only stores its binary data in the ``my_png_image`` variable, but it *also* saves 
+     the PNG image to the file ``'/images/my-chart-file.png'``.
+
+The format argument is really the one doing the heavy lifting above. In the example above, it tells the method to generate a PNG image, but you can also create:
+
+  * ``'jpeg'`` 
+  * ``'pdf'``, and 
+  * ``'svg'
+
+And that's it! There's really nothing simpler.
+
+.. note::
+
+  Under the hood, this method defaults to calling the Highcharts Export Server that is maintained by 
+  `Highsoft <https://www.highcharts.com>`__ (creators of Highcharts Core (JS)). This publicly-available server 
+  is available to all licensees of Highcharts Core, and you are free to use it to generate downloadable 
+  versions of your data visualizations. 
+  
+  However, it is rate-limited and it does mean transmitting your chart's data across the wire. There are 
+  various situations in which this is inappropriate, which is why Highsoft allows you to configure and deploy 
+  your own Highcharts Export Server. And Highcharts for Python supports using your own custom Export Server 
+  for your programmatic chart exports.
+
+------------------------
+
+************************************
+Using a Custom Export Server
+************************************
+
+.. tip::
+
+  While deploying your own Highcharts Export Server is beyond the scope of this tutorial, we strongly recommend that 
+  you review the 
+  `Highcharts Export Server documentation <https://www.highcharts.com/docs/export-module/setting-up-the-server>`__
+
+If you have your own Highcharts Export Server, you can override **Highcharts for Python**'s default to 
+have your code rely on your own export server. While you can do this by creating an instance of 
+:class:`highcharts_stock.headless_export.ExportServer` with your custom configuration and passing it to the 
+:meth:`.download_chart() <highcharts_stock.chart.Chart.download_chart>` method in the ``server_instance`` 
+argument, it is far easier to simply set some environment variables wherever your Python code will be running:
+
+  * ``HIGHCHARTS_EXPORT_SERVER_DOMAIN`` is the environment variable that specifies the domain where the Highcharts 
+    Export Server exists. If this environment variable is not set, it will default to ``"export.highcharts.com"``, 
+    which is the Highsoft-provided export server.
+  * ``HIGHCHARTS_EXPORT_SERVER_PATH`` is the path at the domain where your Export Server is reachable. If this 
+    environment variable is not set, it will default to :obj:`None <python:None>` since there is no path when using the 
+    Highsoft-provided export server.
+  * ``HIGHCHARTS_EXPORT_SERVER_PORT`` is the port where your Export Server is reachable. If this environment variable 
+    is not set, it will default to :obj:`None <python:None>` since there is no need to specify a port when using the 
+    Highsoft-provided export server.
+
+In addition to the three environment variables above, the 
+:meth:`.download_chart() <highcharts_stock.chart.Chart.download_chart>` method also supports 
+three additional arguments which may prove useful:
+
+  * ``auth_user`` which is the user to supply to your custom Export Server using Basic authentication. This defaults to 
+    :obj:`None <python:None>` (since the default Highsoft-provided Export Server has no authentication).
+  * ``auth_password`` which is the password to supply to your custom Export Server using Basic authentication. This
+    :obj:`None <python:None>` (since the default Highsoft-provided Export Server has no authentication).
+  * ``timeout`` which is the number of seconds to wait before issuing a timeout error. The timeout check is passed if 
+    any bytes have been received on the socket in less than this number of seconds. It defaults to ``0.5``, but you may 
+    want to adjust this when using your own custom Export Server.
+
diff --git a/docs/tutorials/getting_started.rst b/docs/tutorials/getting_started.rst
new file mode 100644
index 0000000..7bac6c9
--- /dev/null
+++ b/docs/tutorials/getting_started.rst
@@ -0,0 +1,274 @@
+##############################################
+Highcharts Core for Python: Getting Started
+##############################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+We're so glad you want to use **Highcharts Core for Python**! This tutorial will help
+you get started, and give you a jumping off point to dive into all the great features
+of the Highcharts visualization suite. Before you really get going, we suggest you take
+a look at all of the great :doc:`visualization types <../visualizations>` you can create
+using **Highcharts for Python** and `Highcharts (JS) <https://www.highcharts.com>`__.
+
+***************************
+Installation
+***************************
+
+First things first, to use **Highcharts for Python** the first step is to install the
+library (likely to a virtual environment). That's pretty straightforward:
+
+.. include:: ../_installation.rst
+
+-------------------
+
+******************************************
+Importing Highcharts Core for Python
+******************************************
+
+Once you've installed **Highcharts Core for Python**, you can import it into your project
+in two different ways:
+
+.. include:: ../using/_importing.rst
+
+-------------------
+
+******************************************
+Wrangle Your Data
+******************************************
+
+Since you want to use **Highcharts Core for Python** to visualize some data, first
+you're going to have to wrangle the data into a form you can work with. How you do
+this really depends on the data you are working with and the other tools you are
+using in your tech stack.
+
+The **Highcharts for Python** toolkit works with most of the "usual suspects" in the
+Python ecosystem, including:
+
+  * `Pandas <https://pandas.pydata.org/>`__
+  * `Numpy <https://www.numpy.org/>`__
+  * `PySpark <https://spark.apache.org/docs/latest/api/python/index.html>`__
+  * CSV files
+  * JSON files
+  * Python :class:`dict <python:dict>` instances
+  * Python iterables (e.g. :class:`list <python:list>`, :class:`tuple <python:tuple>`, etc.)
+
+For the sake of simplicity, we'll work with Python iterables to show how you
+can quickly get started. Let's say we have a simple 2-dimensional set of x/y values 
+that we want to plot:
+
+  .. code-block:: python
+
+    my_iterable = [
+        [0, 123],
+        [1, 456],
+        [2, 789],
+        [3, 987],
+        [4, 654],
+        [5, 321]
+    ]
+
+That's all I need to wrangle my data! **Highcharts for Python** can work with 
+``my_iterable`` directly and easily, wherever data is referenced.
+
+.. tip::
+
+  Different Highcharts :term:`series` types support different structures of
+  iterable.
+
+  Please review the detailed :ref:`series documentation <series_documentation>` for
+  series type-specific details of relevant iterable/array structures.
+
+Alternatively, we can convert ``my_iterable`` into a 
+:class:`pandas.DataFrame <pandas:pandas.DataFrame>`, :class:`numpy.ndarray <numpy:numpy.ndarray>`,
+or Python :class:`dict <python:dict>`:
+
+  .. code-block:: python
+
+    # As a Pandas DataFrame
+    df = pandas.DataFrame(my_iterable, columns=['x', 'y'])
+
+    # As a Numpy ndarray
+    as_ndarray = numpy.as_ndarray(my_iterable)
+
+    # As a Python dict
+    as_dict = {'x': x[0], 'y': x[1] for x in my_iterable}
+
+Now, we can consider our data "wrangled" and ready for visualization.
+
+--------------------
+
+******************************************
+Assembling a Chart
+******************************************
+
+With our data wrangled, we can construct a chart with one line of code:
+
+.. include:: _assembling_a_chart.rst
+
+**********************************
+Configuring the Chart
+**********************************
+
+`Highcharts (JS) <https://www.highcharts.com>`__ sets the standard for
+data visualization because it supports a huge number of easy-to-understand
+configuration options. **Highcharts for Python** makes it easy to configure
+any of those options directly within Python.
+
+To do that, we can use the :meth:`Chart.options <highcharts_stock.chart.Chart.options>`
+property. Having assembled our chart following the instructions above, ``my_chart``
+already contains a :class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>`
+instance in the :meth:`Chart.options <highcharts_stock.chart.Chart.options>` property.
+You can access the :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>`
+we created at :meth:`Chart.options.series <highcharts_stock.options.HighchartsOptions.series>`,
+and you can set any other options you need on 
+:meth:`Chart.options <highcharts_stock.chart.Chart.options>`.
+
+For example, let's say we want to set the chart's title to "My First Chart". To do that,
+we can configure the 
+:meth:`Chart.options.title <highcharts_stock.options.HighchartsOptions.title>` property
+using either a :class:`Title <highcharts_stock.options.title.Title>` instance, or a
+:class:`dict <python:dict>`:
+
+  .. code-block:: python
+
+    # as a Title instance
+
+    from highcharts_stock.options.title import Title
+
+    my_chart.options.title = Title(text = 'My First Chart')
+
+    # as a dict
+
+    my_chart.options.title = {'text': 'My First Chart'}
+
+Either way, the chart's title will now be set to "My First Chart".
+
+  .. seealso::
+
+    * :doc:`Templating and Shared Options <templating>`
+    * :doc:`Creating JavaScript Callback Functions <callbacks>`
+
+----------------
+
+******************************************
+Rendering the Chart
+******************************************
+
+Once we've assembled and configured our chart, we can render it. How we want
+to render it depends on our exact needs. We can:
+
+  * Display the chart in a `Jupyter Notebook <https://www.jupyter.org>`__
+  * Save the chart as a static image
+  * Generate the JavaScript that will render the chart in your users'
+    web browser.
+
+Displaying in Jupyter Notebook / Jupyter Lab
+===============================================
+
+If you're using **Highcharts Core for Python** in a Jupyter Notebook or Jupyter Lab,
+you can display the chart right in your notebook. Doing so is super simple - just
+call the :meth:`.display() <highcharts_stock.chart.Chart.display>` method on 
+``my_chart``:
+
+  .. code-block:: python
+
+    my_chart.display()
+
+That's it! The chart will now render in the output of the cell.
+
+  .. seealso::
+
+    * :doc:`Using Highcharts Core for Python with Jupyter <jupyter>`
+
+Saving the Chart as a Static Image
+=======================================
+
+If you want to save the chart as a static image, you can do so by calling the
+:meth:`.download_chart() <highcharts_stock.chart.Chart.download_chart>` method:
+
+  .. code-block:: python
+
+    my_chart.download_chart(filename = 'my_chart.png')
+
+If you need it in a different format, you can specify the format using the
+``format`` parameter. Highcharts for Python supports PNG (the default),
+JPEG, PDF, and SVG. For example, to save the chart as a PDF, you can do:
+
+  .. code-block:: python
+
+    my_chart.download_chart(filename = 'my_chart.pdf', format = 'pdf')
+
+And that's it!
+
+  .. seealso::
+
+    * :doc:`Exporting Static Charts <exporting>`
+
+Rendering in the Web Browser
+================================
+
+If you want to render your chart in your user's web browser, then you can
+use **Highcharts for Python** to automatically generate the JavaScript code
+you will need. The best way to do this is to call the 
+:meth:`.to_js_literal() <highcharts_stock.chart.Chart.to_js_literal>` method
+on ``my_chart``.
+
+This will produce a string (or write to a file) containing the 
+:term:`JS literal <JavaScript Object Literal Notation>` form of your chart and
+its configuration. If the code contained in this string gets executed in your
+user's browser (within a set of ``<script></script>`` tags), it will render
+your chart.
+
+So the way to get the JS literal is very straightforward:
+
+  .. code-block:: python
+
+    # EXAMPLE 1. 
+    # Storing the JS literal in a string.
+
+    my_js_literal = my_chart.to_js_literal()
+
+    # EXAMPLE 2.
+    # Saving the JS literal to a file named
+    # "my-js-literal.js"
+
+    my_chart.to_js_literal('my-js-literal.js')
+
+Now the way to render this chart will ultimately depend on how your application
+is architected. We see three - typical - patterns employed:
+
+  #. If your Python code is responsible for preparing the client-side 
+     HTML + JavaScript, then you can include ``my_js_literal`` in your
+     template file. This pattern works for practically every Python web
+     framework, including `Django <https://www.djangoproject.com>`__,
+     and `Flask <https://flask.palletsprojects.com/en/3.0.x/>`__.
+  #. If your Python code exposes RESTful or GraphQL APIs that are 
+     consumed by your client-side application, then you can return the JS
+     literal object as a string via your API. This can then be evaluated
+     in your client-side application using JavaScript's ``new Function()``
+     feature.
+
+       .. caution::
+
+         **DO NOT USE JAVASCRIPT'S eval() FUNCTION**.
+         
+         It is deprecated, and for good reason:
+         
+         It represents a major security risk. When using ``new Function()``,
+         we recommend balancing the need for simplicity against the need for 
+         security. You can secure your code by applying whitelisting techniques,
+         sandboxing the scope of your ``new Function()`` context, adding 
+         additional layers of M2M signed encryption, or employing sanitization
+         techniques on the content of the JS literal returned by your API.
+
+         Which specific techniques make sense will depend on your application 
+         and your use case.
+
+  #. If the data in your front-end application is generated on a periodic / batch
+     basis, then you can save your JS literal to a static file (saved where 
+     consumable by your front-end application) and have your front-end application
+     simply load it as-needed.
\ No newline at end of file
diff --git a/docs/tutorials/pandas.rst b/docs/tutorials/pandas.rst
new file mode 100644
index 0000000..d6dc765
--- /dev/null
+++ b/docs/tutorials/pandas.rst
@@ -0,0 +1,498 @@
+########################################################
+Using Highcharts Core for Python with Pandas
+########################################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+`Pandas <https://pandas.pydata.org/>`__ is probably the single
+most popular library for data analysis in the Python ecosystem. Together
+with `NumPy <https://www.numpy.org>`__, it is ubquitous. And the 
+**Highcharts for Python Toolkit** is designed to natively integrate with 
+it.
+
+.. sidebar:: What Can Pandas Do in Highcharts?
+
+  The **Highcharts for Python Toolkit** is a *visualization* library. It is
+  not used to perform *arithmetical*, *algebraic*, *statistical*, or *matrix* 
+  calculations. It is exclusively concerned with visualizing data - and that
+  data is typically the product of calculations that are performed up-stream.
+
+  So given that focus, **Highcharts for Python** is designed to *read* data
+  that is contained in :class:`pandas.DataFrame <pandas:pandas.DataFrame>`
+  instances, or in :class:`numpy.ndarray <numpy:numpy.ndarray>` instances. The 
+  toolkit will take those instances and load the data they contain into
+  appropriate **Highcharts for Python** classes, and then support the
+  serialization of that data to 
+  :term:`JS literal notation <JavaScript Object Literal Notation>`.
+
+*********************************
+General Approach
+*********************************
+
+The **Highcharts for Python Toolkit** provides a number of standard methods
+that are used to interact with :class:`pandas.DataFrame <pandas:pandas.DataFrame>`
+instances. These methods generally take the form:
+
+  * ``.from_pandas(df)`` This is always a class method which produces one or more
+    instances, with data pulled from the ``df`` argument.
+  * ``.from_pandas_in_rows(df)`` This is always a class method which produces one
+    instance for every *row* in the :class:`DataFrame <pandas:pandas.DataFrame>` 
+    (``df``).
+  * ``.load_from_pandas(df)`` This is an instance method which updates an instance
+    with data read from the ``df`` argument.
+
+.. tip::
+
+  All three of these standard methods are packaged to have batteries included.
+  This means that for simple use cases, you can simply pass a 
+  :class:`pandas.DataFrame <pandas:pandas.DataFrame>` to the method, and the 
+  method wlil attempt to determine the optimum way to deserialize the 
+  :class:`DataFrame <pandas:pandas.DataFrame>` into the appropriate 
+  **Highcharts for Python** objects.
+
+  However, if you find that you need more fine-grained control, the methods
+  provide powerful tools to give you the control you need when you need it.
+
+These standard methods - with near-identical syntax - are available:
+
+  * On all :term:`series` classes (descended from 
+    :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`)
+  * On the :class:`Chart <highcharts_stock.chart.Chart>` class
+  * On the :class:`options.data.Data <highcharts_stock.options.data.Data>` 
+    class
+
+-------------------------------
+
+*****************************
+Preparing Your DataFrame
+*****************************
+
+  .. tip::
+  
+    While it is theoretically possible for **Highcharts for Python** to
+    work with a nested :class:`DataFrame <pandas:pandas.DataFrame>`, such
+    structures are generally considered an anti-pattern. We recommend 
+    keeping your :class:`DataFrame <pandas:pandas.DataFrame>` contents 
+    2-dimensional, organized into a single "flat" table of rows and 
+    columns.
+
+So let's try a real-world example. Let's say you've got some annual population
+counts stored in a CSV file named ``'census-time-series.csv'``. Using Pandas, you
+can construct a DataFrame from that CSV file very simply:
+
+  .. code-block:: python
+
+    df = pandas.read_csv('census-time-series.csv')
+
+This produces a simple 2-dimensional :class:`DataFrame <pandas:pandas.DataFrame>`.
+In our case, the resulting table looks like this:
+
+  .. image:: /_static/tutorials/census-time-series-01.png
+     :width: 100%
+     :alt: Rendering of the DataFrame produced by pandas.read_csv('census-time-series.csv')
+
+The first column contains the names of geographic regions, while each of the subsequent
+columns contains the population counts for a given year. However, you'll notice that the
+:class:`DataFrame <pandas:pandas.DataFrame>` index is not set. Unless told otherwise,
+**Highcharts for Python** will look for x-axis values in the index.
+
+Secondly, if you were to look under the hood, you'd see that the 
+:class:`DataFrame <pandas:pandas.DataFrame>` imported all of the numbers in our CSV as 
+strings (because of the presence of the comma), which is obviously a bit of a problem. So
+let's fix both of these issues:
+
+  .. code-block:: python
+
+    df = pandas.read_csv('census-time-series.csv', index_col = 0, thousands = ','))
+
+produces:
+
+  .. image:: /_static/tutorials/census-time-series-02.png
+     :width: 100%
+     :alt: Rendering of the DataFrame produced by pandas.read_csv('census-time-series.csv')
+
+Great! Now, let's say we wanted to visualize this data in various ways.
+
+------------------------------
+
+*********************************************
+Creating the Chart: ``Chart.from_pandas()``
+*********************************************
+
+Relying on the Defaults
+===========================
+
+The simplest way to create a chart from a :class:`DataFrame <pandas:pandas.DataFrame>`
+is to call :class:`Chart.from_pandas() <highcharts_stock.chart.Chart.from_pandas>` like
+so:
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df)
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-03.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df)
+
+As you can see, we haven't provided any more instructions besides telling it to
+generate a chart from ``df``. The result is a line chart, with one series for each year, and
+one point for each region. But because of the structure of our data file, this isn't a great chart:
+all the series are stacked on each other! So let's fix that.
+
+  .. tip::
+
+    Unless instructed otherwise, **Highcharts for Python** will default to using a
+    line chart. 
+
+Setting the Series Type
+==============================
+
+Why don't we switch it to a bar chart?
+
+.. list-table::
+  :widths: 30 70
+
+.. code-block:: python
+        
+  my_chart = Chart.from_pandas(df, series_type = 'bar')
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-04.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'bar')
+
+Now the result is a little more readable, but still not great: After all, there are more than
+fifty geographic regions represented for each year, which makes the chart super crowded. 
+Besides, maybe we're only interested in a specific year: 2019. 
+
+Let's try focusing our chart.
+
+Basic Property Mapping
+==========================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'bar',
+                               property_map = {
+                                   'x': 'Geographic Area',
+                                   'y': '2019'
+                               })
+
+.. image:: /_static/tutorials/census-time-series-05.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'bar', property_map = {'x': 'Geographic Area', 'y': '2019'})
+
+Much better! We've now added a ``property_map`` argument to the ``.from_pandas()`` method call. 
+This argument tells Highcharts for Python how to map columns in your 
+:class:`DataFrame <pandas:pandas.DataFrame>` to properties in the resulting chart. In this case,
+the keys ``'x'`` and ``'y'`` tell **Highcharts for Python** that you want to map the ``'Geographic Area'``
+column to the resulting series' data points' :meth:`.x <highcharts_stock.options.series.data.bar.BarData.x>`,
+and to map the ``'2019'`` column to the :meth:`.y <highcharts_stock.options.series.data.bar.BarData.y>` 
+properties, respectively.
+
+The net result is that ``my_chart`` contains one 
+:class:`BarSeries <highcharts_stock.options.series.bar.BarSeries>` whose 
+:meth:`.data <highcharts_stock.options.series.bar.BarSeries.data>` property contains a 
+:class:`BarDataCollection <highcharts_stock.options.series.data.bar.BarDataCollection>` instance populated
+with the data from the ``'Geographic Area'`` and ``'2019'`` columns in ``df`` - and even though 
+``'Geographic Area'`` is not technically a column, but instead is used as the index, 
+**Highcharts for Python** still uses it correctly.
+
+But maybe we actually want to compare a couple different years? Let's try that.
+
+Property Mapping with Multiple Series
+========================================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'column',
+                               property_map = {
+                                   'x': 'Geographic Area',
+                                   'y': ['2017', '2018', '2019']
+                               })
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-06.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'bar', property_map = {'x': 'Geographic Area', 'y': ['2017', '2018', '2019']})
+
+Now we're getting somewhere! First, we changed our series type to a :class:`ColumnSeries <highcharts_stock.options.series.bar.ColumnSeries>` to make it (a little) easier to read. Then we  added a list of column names to the ``'y'`` key in the ``property_map``  argument. Each of those columns has now produced a *separate* :class:`ColumnSeries <highcharts_stock.options.series.bar.ColumnSeries>` instance - but they're all still sharing the ``'Geographic Area'`` column as their :meth:`.x <highcharts_stock.options.series.data.bar.BarData.x>` value.
+
+  .. note::
+
+    You can supply multiple values to any property in the ``property_map``. The example
+    provided above is equivalent to:
+
+      .. code-block:: python
+
+        my_chart = Chart.from_pandas(df,
+                                     series_type = 'column',
+                                     property_map = {
+                                         'x': ['Geographic Area', 'Geographic Area', 'Geographic Area'],
+                                         'y': ['2017', '2018', '2019']
+                                     })
+
+    The only catch is that the ultimate number of values for each key must match. If there's
+    only one value, then it will get repeated for all of the others. But if there's a mismatch,
+    then **Highcharts for Python** will throw a 
+    :exc:`HighchartsPandasDeserializationError <highcharts_stock.errors.HighchartsPandasDeserializationError>`.
+
+But so far, we've only been using the ``'x'`` and ``'y'`` keys in our ``property_map``. What if we wanted to
+configure additional properties? Easy!
+
+Configuring Additional Properties
+=====================================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'column',
+                               property_map = {
+                                   'x': 'Geographic Area',
+                                   'y': ['2017', '2018', '2019'],
+                                   'id': 'some other column'
+                               })
+
+Now, our data frame is pretty simple does not contain a column named ``'some other column'`. But *if* it did,
+then it would use that column to set the :meth:`.id <highcharts_stock.options.series.data.bar.BarData.id>` property of each data point.
+
+  .. note::
+
+    You can supply any property you want to the ``property_map``. If the property is not
+    supported by the series type you've selected, then it will be ignored.
+
+But our chart is still looking a little basic - why don't we tweak some series configuration options?
+
+Configuring Series Options
+===============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'column',
+                               property_map = {
+                                   'x': 'Geographic Area',
+                                   'y': ['2017', '2018', '2019'],
+                               },
+                               series_kwargs = {
+                                   'point_padding': 5
+                               })
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-07.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'bar', property_map = {'x': 'Geographic Area', 'y': ['2017', '2018', '2019'], 'id': 'Geographic Area'}, series_kwargs = {'point_padding': 0.5})
+
+As you can see, we supplied a new ``series_kwargs`` argument to the ``.from_pandas()`` method call. This
+argument receives a :class:`dict <python:dict>` with keys that correspond to properties on the series. In
+this case, by supplying ``'point_padding'`` we have set the resulting 
+:meth:`ColumnSeries.point_padding <highcharts_stock.options.series.bar.ColumnSeries.point_padding>` property to a
+value of ``0.5`` - leading to a bit more spacing between the bars.
+
+But our chart is *still* a little basic - why don't we give it a reasonable title?
+
+Configuring Options
+=============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'column',
+                               property_map = {
+                                   'x': 'Geographic Area',
+                                   'y': ['2017', '2018', '2019'],
+                               },
+                               series_kwargs = {
+                                   'point_padding': 0.5
+                               },
+                               options_kwargs = {
+                                   'title': {
+                                       'text': 'This Is My Chart Title'
+                                   }
+                               })
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-08.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'bar', property_map = {'x': 'Geographic Area', 'y': ['2017', '2018', '2019'], 'id': 'Geographic Area'}, series_kwargs = {'point_padding': 0.25}, options_kwargs = {'title': {'text': 'This Is My Chart Title'}})
+
+As you can see, we've now given our chart a title. We did this by adding a new ``options_kwargs`` argument,
+which likewise takes a :class:`dict <python:dict>` with keys that correspond to properties on the chart's
+:class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>` configuration.`
+
+Now let's say we wanted our chart to render in an HTML ``<div>`` with an ``id`` of ``'my_target_div`` - 
+we can configure that in the same method call.
+
+Configuring Chart Settings
+==============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'bar',
+                               property_map = {
+                                   'x': 'Geographic Area',
+                                   'y': ['2017', '2018', '2019'],
+                                   'id': 'Geographic Area'
+                               },
+                               series_kwargs = {
+                                   'point_padding': 0.25
+                               },
+                               options_kwargs = {
+                                   'title': {
+                                       'text': 'This Is My Chart Title'
+                                   }
+                               },
+                               chart_kwargs = {
+                                   'container': 'my_target_div'
+                               })
+
+While you can't really *see* the difference here, by adding the ``chart_kwargs`` argument to
+the method call, we now set the :meth:`.container <highcharts_stock.chart.Chart.container>` property
+on ``my_chart``.
+
+But maybe we want to do something a little different - like compare the change in population over time.
+Well, we can do that easily by visualizing each *row* of ``df`` rather than each *column*.`
+
+Visualizing Data in Rows
+==============================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'line',
+                               series_in_rows = True)
+  my_chart.display()
+
+.. image:: /_static/tutorials/census-time-series-09.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'line', series_in_rows = True)
+
+Okay, so here we removed some of the other arguments we'd been using to simplify the example. You'll see we've now
+added the ``series_in_rows`` argument, and set it to ``True``. This tells **Highcharts for Python** that we expect
+to produce one series for every *row* in ``df``. Because we have not specified a ``property_map``, the series
+:meth:`.name <highcharts_stock.options.series.bar.BarSeries.name>` values are populated from the ``'Geographic Area'``
+column, while the data point :meth:`.x <highcharts_stock.options.series.data.bar.BarData.y>` values come from each additional column (e.g. ``'2010'``, ``'2011'``, ``'2012'``, etc.)
+
+  .. tip::
+
+    To simplify the code further, any class that supports the ``.from_pandas()`` method also
+    supports the ``.from_pandas_in_rows()`` method. The latter method is equivalent to passing
+    ``series_in_rows = True`` to ``.from_pandas()``.
+
+    For more information, please see:
+
+      * :class:`Chart.from_pandas_in_rows() <highcharts_stock.chart.Chart.from_pandas_in_rows>`
+      * :class:`SeriesBase.from_pandas_in_rows() <highcharts_stock.options.series.base.SeriesBase.from_pandas_in_rows>`
+
+But maybe we don't want *all* geographic areas shown on the chart - maybe we only want to compare a few.
+
+Filtering Rows
+=======================
+
+.. code-block:: python
+
+  my_chart = Chart.from_pandas(df,
+                               series_type = 'line',
+                               series_in_rows = True,
+                               series_index = slice(7, 10))
+
+.. image:: /_static/tutorials/census-time-series-10.png
+  :width: 100%
+  :alt: Rendering of the chart produced by Chart.from_pandas(df, series_type = 'line', series_in_rows = True, series_index = slice(7, 10))
+
+What we did here is we added a ``series_index`` argument, which tells **Highcharts for Python** to only
+include the series found at that index in the resulting chart. In this case, we supplied a :func:`slice <python:slice>`
+object, which operates just like ``list_of_series[7:10]``. The result only returns those series between index 7 and 10.
+
+------------------------
+
+**********************************************************************
+Creating Series: ``.from_pandas()`` and ``.from_pandas_in_rows()``
+**********************************************************************
+
+All **Highcharts for Python** :term:`series` descend from the 
+:class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>` class. And they all
+therefore support the ``.from_pandas()`` class method. 
+
+When called on a series class, it produces one or more series from the 
+:class:`DataFrame <pandas:pandas.DataFrame>` supplied. The method supports all of the same options
+as :class:`Chart.from_pandas() <highcharts_stock.chart.Chart.from_pandas>` *except for* ``options_kwargs`` and
+``chart_kwargs``. This is because the ``.from_pandas()`` method on a series class is only responsible for
+creating series instances - not the charts.
+
+Creating Series from Columns
+==================================
+
+So let's say we wanted to create one series for each of the years in ``df``. We could that like so:
+
+  .. code-block:: python
+
+    my_series = BarSeries.from_pandas(df)
+
+Unlike when calling :meth:`Chart.from_pandas() <highcharts_stock.chart.Chart.from_pandas>`, we
+did not have to specify a ``series_type`` - that's because the ``.from_pandas()`` class method on a
+series class already knows the series type!
+
+In this case, ``my_series`` now contains ten separate :class:`BarSeries <highcharts_stock.options.series.bar.BarSeries>`
+instances, each corresponding to one of the year columns in ``df``.
+
+But maybe we wanted to create our series from rows instead?
+
+Creating Series from Rows
+=================================
+
+.. code-block:: python
+
+  my_series = LineSeries.from_pandas_in_rows(df)
+
+This will produce one :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>`
+instance for each row in ``df``, ultimately producing a :class:`list <python:list>` of
+57 :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` instances.
+
+Now what if we don't need all 57, but instead only want the first five?
+
+Filtering Series Created from Rows
+======================================
+
+.. code-block:: python
+
+  my_series = LineSeries.from_pandas_in_rows(df, series_index = slice(0, 5))
+
+This will return the first five series in the list of 57.
+--------------------------
+
+***********************************************************
+Updating an Existing Series: ``.load_from_pandas()``
+***********************************************************
+
+So far, we've only been creating new series and charts. But what if we want to update
+the data within an existing series? That's easy to do using the 
+:meth:`.load_from_pandas() <highcharts_stock.options.series.base.SeriesBase.load_from_pandas>` method.
+
+Let's say we take the first series returned in ``my_series`` up above, and we want to replace
+its data with the data from the *10th* series. We can do that by:
+
+  .. code-block:: python
+
+    my_series[0].load_from_pandas(df, series_in_rows = True, series_index = 9)
+
+The ``series_in_rows`` argument tells the method to generate series per row, and then
+the ``series_index`` argument tells it to only use the 10th series generated.
+
+  .. caution::
+
+    While the :meth:`.load_from_pandas() <highcharts_stock.options.series.base.SeriesBase.load_from_pandas>`
+    method supports the same arguments as 
+    :meth:`.from_pandas() <highcharts_stock.options.series.base.SeriesBase.from_pandas>`, it expects that
+    the arguments supplied lead to an unambiguous *single* series. If they are ambiguous - meaning they
+    lead to multiple series generated from the :class:`DataFrame <pandas:pandas.DataFrame>` - then
+    the method will throw a 
+    :exc:`HighchartsPandasDeserializationError <highcharts_stock.errors.HighchartsPandasDeserializationError>`
\ No newline at end of file
diff --git a/docs/tutorials/series.rst b/docs/tutorials/series.rst
new file mode 100644
index 0000000..16ec4ce
--- /dev/null
+++ b/docs/tutorials/series.rst
@@ -0,0 +1,398 @@
+###################################################
+Working with Series in Highcharts for Python
+###################################################
+
+.. contents::
+  :depth: 2
+  :backlinks: entry
+
+-------------------
+
+**Highcharts for Python** (and Highcharts (JS), of course) are both built around
+the concept of :term:`data series <series>`. A data series can be thought of as
+a set of data points that describe the same "thing", and which represent how
+the data can be organized. Think: 
+  
+  * a single line on a line chart
+  * a set of columns all the same color on a column chart
+  * all of a pie or donut chart
+
+As a result, when you constructing your chart in **Highcharts for Python**,
+what you are really doing is constructing one or more :term:`series` that
+are then placed on a shared canvas, with shared axes, a shared legend, etc.
+
+  .. image:: /_static/highcharts-chart-anatomy.png
+    :width: 75
+    :align: right
+    :alt: Diagram showing the conceptual components of a Highcharts chart
+
+This tutorial is designed to help you understand how to manage series in your
+Highcharts visualizations using **Highcharts for Python**.
+
+----------------------------------
+
+*********************************
+How Series are Organized
+*********************************
+
+As the diagram above shows, Highcharts visualizations are configured
+within a :class:`Chart <highcharts_stock.chart.Chart>` object, which has
+the :meth:`.options <highcharts_stock.chart.Chart.options>` property where
+the chart's configuration "lives", represented as a 
+:class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>`
+instance.
+
+The :class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>` 
+configuration allows you to define *all* details of what gets displayed on
+the chart, how that content behaves, etc. The configuration options available in 
+:class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>` can be
+thought of as chart-level configurations: They configure or define things that apply to
+everything shown on the chart: the axes to display, the legend, the title, the settings shared
+across all of the series on the chart, etc.
+
+But within the :class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>`
+you will find the :meth:`.series <highcharts_stock.options.HighchartsOptions.series>`
+property. This is where you define the *specific* :term:`series` to render on your chart.
+
+This property gets one or more series instances, all of which are descended from
+:class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`. They descend from
+this single base series class because many of their properties are shared across all types
+of series. For example, whether the series is to render as a line or as a bar, all series will
+have an :meth:`.id <highcharts_stock.options.series.base.SeriesBase.id>` option.
+
+All visualizations supported by Highcharts have a corresponding series type, which means
+they all have their corresponding series class. To see this mapping, take a look at our
+:doc:`Supported Visualizations </visualizations>`.
+
+Each series type has its set of shared properties that derive from 
+:class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>, but specific series types 
+may have their own type-specific settings. For example, a 
+:class:`GaugeSeries <highcharts_stock.options.series.gauge.GaugeSeries>` will have options to
+configure the gauge's dial (:meth:`.dial <highcharts_stock.options.series.gauge.GaugeSeries.dial>`),
+overshot-handling (:meth:`.overshoot <highcharts_stock.options.series.gauge.GaugeSeries.overshoot>`),
+and pivot point (:meth:`.pivot <highcharts_stock.options.series.gauge.GaugeSeries.pivot>`) - settings
+which would be completely *irrelevant* for a 
+:class:`LineSeries <highcharts_stock.options.series.area.LineSeries>`, which does not have a dial,
+does not have a concept of overshooting the bounds of the dial, and does not have any pivot points.
+
+.. list-table::
+  :widths: 50 50
+  
+  * - .. figure:: ../../../_static/gauge-example.png
+        :alt: Gauge Example Chart
+        :align: center
+    - .. figure:: ../../../_static/line-example.png
+        :alt: Line Example Chart
+        :align: center
+
+And all series (technically, *almost* all) have a 
+:meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property, which contains the
+data that should be visualized in the series.
+
+.. sidebar:: Exceptions without Data
+
+  Certain types of visualiation - like 
+  :class:`BellCurveSeries <highcharts_stock.options.series.bellcurve.BellCurveSeries>`
+  do not receive their own data, but instead are tied to an underlying 
+  :meth:`.base_series <highcharts_stock.options.series.bellcurve.BellCurveSeries.base_series>`
+  whose data is used to shape their visualization.
+
+    .. figure:: ../../../_static/bellcurve-example.png
+      :alt: Bell Curve Example Chart
+      :align: center
+      :width: 35%
+
+So as you can see, series are pretty fundamental to your Highcharts visualizations: They are
+what actually gets visualized.
+
+So how do we start creating series using **Highcharts for Python**?
+
+---------------------------------------
+
+***************************************************
+Creating Series in Highcharts for Python
+***************************************************
+
+
+Of course, you can always construct your series using direct instantiation:
+
+  .. code-block:: python
+
+    from highcharts_stock.chart import Chart
+    from highcharts_stock.options import HighchartsOptions
+    from highcharts_stock.options.series.area import LineSeries
+
+    my_line_series = LineSeries(data = my_data, id = 'my_series_id123')
+    my_options = HighchartsOptions(series = [my_line_series])
+    my_chart = Chart(options = my_options)
+
+And there may be situations where there is the best way for you to construct your
+series, depending on how you are managing your full Highcharts for Python application.
+
+But there are much simpler / faster ways to rapidly create your chart/series:
+
+Assembling a Chart with Series at Once
+=========================================
+
+.. include:: _assembling_a_chart.rst
+
+Assembling Series Alone
+==========================
+
+You can create series similarly:
+
+  .. code-block:: python
+
+    from highcharts_stock.options.series.area import LineSeries
+
+    my_line_series = LineSeries(data = my_iterable)
+
+This will create a :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` 
+instance.
+
+Depending on how we've wrangled our data, we can similarly produce one or more
+series from a :class:`pandas.DataFrame <pandas:pandas.DataFrame>`, 
+:class:`numpy.ndarray <numpy:numpy.ndarray>`, or Python :class:`dict <python:dict>`:
+
+  .. code-block:: python
+
+    # From a Pandas DataFrame
+
+    my_series = LineSeries.from_pandas(df)
+
+    # From a Numpy ndarray
+
+    my_series = LineSeries.from_array(data = as_ndarray)
+
+    # From a CSV file
+
+    my_series = LineSeries.from_csv('my-data.csv')
+
+    # From a Python iterable
+
+    my_series = LineSeries.from_array(data = as_iterable)
+
+All of these lines of code are equivalent, and should produce an identical
+``my_series``. Depending on the arguments you supply to the helper methods,
+they may either produce *one* series instance or a :class:`list <python:list>`
+of series instances.
+
+Adding Series to a Chart
+===========================
+
+If you have created series on their own, you can add them to an existing
+:class:`Chart <highcharts_stock.chart.Chart>` very easily:
+
+  .. code-block:: python
+
+    # EXAMPLE 1.
+    # Adding one series
+
+    my_chart.add_series(my_series)
+
+    # EXAMPLE 2.
+    # Adding multiple series if they are in one iterable
+
+    my_chart.add_series(my_list_of_series)
+
+    # EXAMPLE 3.
+    # Adding multiple individual series
+    
+    my_chart.add_series(series1, series2, series3)
+
+Or you can also create a new chart *from* a list of series:
+
+  .. code-block:: python
+
+    # EXAMPLE 1.
+    # With one series
+
+    my_chart = Chart.from_series(my-series)
+
+    # EXAMPLE 2.
+    # With multiple series if they are in one iterable
+
+    my_chart = Chart.from_series(my_list_of_series)
+
+    # EXAMPLE 3.
+    # Adding multiple individual series
+    
+    my_chart = Chart.from_series(series1, series2, series3)
+
+.. tip::
+
+  The same :meth:`.add_series <highcharts_stock.chart.Chart.add_series>` and
+  :meth:`.from_series <highcharts_stock.chart.Chart.from_series>` helper methods
+  are also available on the
+  :class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>` class.
+
+So now that we've created a chart and a bunch of series, what else can we do?
+
+----------------------------
+
+*********************************
+Configuring Your Series
+*********************************
+
+You can configure the options available on each series very simply. Highcharts (JS) -
+and so **Highcharts for Python** - have a very extensive API, with lots of configuration
+options. 
+
+.. tip::
+    
+  We recommend reviewing the :doc:`API Reference </api>` to really explore
+  the options available for different series types.
+
+Updating Data Points
+=========================
+
+However, the most important configuration you will do is to manage the data points
+you wish to display in your series. You can do this by:
+
+  #. Passing data directly to the 
+     :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>`
+     property:
+
+     .. code-block:: python
+
+        my_series.data = updated_data
+
+  #. Using any of the helper methods provided on the series instance:
+
+     .. code-block:: python
+
+       # EXAMPLE 1.
+       # Updating data points from a new Pandas DataFrame
+
+       my_series.load_from_pandas(df)
+
+       # EXAMPLE 2.
+       # Updating data points from a new numpy.ndarray
+
+       my_series.load_from_array(as_ndarray)
+
+       # EXAMPLE 3.
+       # Updating data points from a new iterable.
+
+       my_series.load_from_array(as_iterable)
+
+       # EXAMPLE 4.
+       # Updating data points from a CSV file.
+
+       my_series.load_from_csv('my-updated-csv-file.csv')
+
+Updating Data Point Properties
+==================================
+
+In addition, all series instances make it easy to propagate information throughout your
+underlying data. When you try to set a property on your series object, **Highcharts for Python**
+will first see if it is a valid property on the series itself. But if it is not, then it will
+check whether it is a supported property on that series' *data*.
+
+So as an example, if we want to give our series an ID, we can simply call:
+
+  .. code-block:: python
+
+    my_series.id = 'my-updated-id-value'
+
+However, if we want to set a :class:`BulletSeries <highcharts_stock.options.series.bullet.BulletSeries>` data points' :meth:`.target <highcharts_stock.options.series.data.bullet.BulletData>` value, we can simply reference it on the series.
+For example, if our :class:`BulletSeries <highcharts_stock.options.series.bullet.BulletSeries>` contains three data points, we can set their targets easily using the series:
+
+  .. code-block:: python
+
+    my_bullet_series.target = [1, 2, 3]
+
+By passing an iterable (or a :class:`numpy.ndarray <numpy:numpy.ndarray>`), *all* of your data 
+points will get updated with the appropriate value. This makes it very easy to execute your data point 
+configurations by operating on the series, rather than working with *individual* data points - though if you want
+to work with *individual* data points, you can do so as well.
+
+.. seealso::
+
+  * :doc:`Working with Data in Highcharts for Python <data>`
+
+Converting Series Types
+===========================
+
+Every series type has its own type-specific set of configuration options. However, there may be
+times when you want to change how your data is to be visualized / rendered. **Highcharts for Python**
+provides a useful helper method for that, too. For example, if we want to convert our 
+:class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` to a 
+:class:`BarSeries <highcharts_stock.options.series.bar.BarSeries>`, we can do that by calling the
+:meth:`.convert_to <highcharts_stock.options.series.base.SeriesBase.convert_to>` method:
+
+  .. code-block:: python
+
+    # EXAMPLE 1
+    # Indicating the target type with a string label
+
+    my_series.convert_to(series_type = 'bar')
+
+    # EXAMPLE 2
+    # Indicating the target type with a SeriesBase class
+
+    my_series.convert_to(series_type = BarSeries)
+
+So now that we've constructed, configured, and adjusted our series, we can also render them
+easily.
+
+-----------------------
+
+***************************
+Rendering Series
+***************************
+
+Series can be rendered within the chart that they are a part of, simply by following
+the process to render the chart:
+
+Rendering a Series within a Chart
+=======================================
+
+  #. When in Jupyter Notebook/Lab, just execute the :meth:`.display() <highcharts_stock.chart.Chart.display>`
+     method.
+
+       .. code-block:: python
+
+         my_chart.display()
+
+  #. When rendering within a web application, or saving to a file for rendering in a separate application,
+     you can serialize your chart to :term:`JavaScript object literal notation`:
+
+       .. code-block:: python
+
+         as_js_literal = my_chart.to_js_literal()
+
+     which will produce the JavaScript code to render your complete chart.
+
+Rendering a Series Alone
+============================
+
+The *exact same* helper methods are available on your series as well. So if you have assembled your
+series as ``my_series``, you can take a shortcut to visualize it by calling:
+
+  .. code-block:: python
+
+    my_series.display()
+
+which will assemble a generic :class:`Chart <highcharts_stock.chart.Chart>` instance, include
+your series, and render it in Jupyter Notebook/Lab. 
+
+You can also produce a :class:`Chart <highcharts_stock.chart.Chart>` instance containing your 
+series in a single method call as well:
+
+  .. code-block:: python
+
+    my_chart = my_series.to_chart()
+
+And similarly:
+
+  .. code-block::
+
+    series_as_js_literal = my_series.to_js_literal()
+
+will produce the JS literal representation of your series, for use in a JavaScript application.
+
+------------
+
+Given all of this flexibliity, we hope you have a great time assembling 
+high-end visualizations and exploring **Highcharts for Python**!
\ No newline at end of file
diff --git a/docs/using.rst b/docs/using.rst
index 9dbb69b..05895e2 100644
--- a/docs/using.rst
+++ b/docs/using.rst
@@ -101,7 +101,7 @@ class in **Highcharts Stock for Python**. You can find the complete list in our
 comprehensive :doc:`Highcharts Stock for Python API Reference <api>`.
 
 These classes generally inherit from the
-:class:`HighchartsMeta <highcharts_core:highcharts_core.metaclasses.HighchartsMeta>` metaclass, which
+:class:`HighchartsMeta <highcharts_core:highcharts_stock.metaclasses.HighchartsMeta>` metaclass, which
 provides each class with a number of standard methods. These methods are the "workhorses"
 of **Highcharts for Python** and you will be relying heavily on them when using any of the
 libraries in the toolkit. Thankfully, their signatures and behavior is consistent - even 
@@ -386,97 +386,154 @@ As a result, `Highcharts (JS) <https://www.highcharts.com>`__ and
 **Highcharts for Python** both represent the data points in series as a list of data point
 objects in the ``data`` property within the series:
 
-.. list-table::
-  :widths: 50 50
-  :header-rows: 1
+    .. list-table::
+      :widths: 50 50
+      :header-rows: 1
 
-  * - Highcharts (JS)
-    - Highcharts for Python
-  * - .. code-block:: javascript
+      * - Highcharts (JS)
+        - Highcharts for Python
+      * - .. code-block:: javascript
 
-        // Example Series Object
-        // (for a Line series type):
-        {
-          data: [
+            // Example Series Object
+            // (for a Line series type):
             {
-              id: 'first-data-point',
-              x: 1,
-              y: 123,
-              // ...
-              // optional additional properties
-              // for styling/behavior go here
-              // ...
-            },
-            {
-              id: 'second-data-point',
-              x: 2,
-              y: 456,
-              // ...
-              // optional additional properties
-              // for styling/behavior go here
+              data: [
+                {
+                  id: 'first-data-point',
+                  x: 1,
+                  y: 123,
+                  // ...
+                  // optional additional properties
+                  // for styling/behavior go here
+                  // ...
+                },
+                {
+                  id: 'second-data-point',
+                  x: 2,
+                  y: 456,
+                  // ...
+                  // optional additional properties
+                  // for styling/behavior go here
+                  // ...
+                },
+                {
+                  id: 'third-data-point',
+                  x: 3,
+                  y: 789,
+                  // ...
+                  // optional additional properties
+                  // for styling/behavior go here
+                  // ...
+                }
+              ],
               // ...
-            },
+              // other Series properties go here
+              // to configure styling/behavior
+            }
+        - .. code-block:: python
+
+            # Corresponding LineSeries object
+            my_series = Series(data = [
+                CartesianData(id = 'first-data-point1',
+                              x = 1,
+                              y = 123),
+                CartesianData(id = 'second-data-point1',
+                              x = 2,
+                              y = 456),
+                CartesianData(id = 'third-data-point1',
+                              x = 3,
+                              y = 789),
+            ])
+
+  #. As a single :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+     object in the ``data`` property within the series, which in turn contains the 
+     individual data points.
+
+    .. list-table::
+      :widths: 50 50
+      :header-rows: 1
+
+      * - Highcharts (JS)
+        - Highcharts for Python
+      * - .. code-block:: javascript
+
+            // Example Series Object
+            // (for a Line series type):
             {
-              id: 'third-data-point',
-              x: 3,
-              y: 789,
-              // ...
-              // optional additional properties
-              // for styling/behavior go here
+              data: [
+                {
+                  name: 'first-data-point',
+                  x: 1,
+                  y: 123,
+                  // ...
+                  // optional additional properties
+                  // for styling/behavior go here
+                  // ...
+                },
+                {
+                  name: 'second-data-point',
+                  x: 2,
+                  y: 456,
+                  // ...
+                  // optional additional properties
+                  // for styling/behavior go here
+                  // ...
+                },
+                {
+                  name: 'third-data-point',
+                  x: 3,
+                  y: 789,
+                  // ...
+                  // optional additional properties
+                  // for styling/behavior go here
+                  // ...
+                }
+              ],
               // ...
+              // other Series properties go here
+              // to configure styling/behavior
             }
-          ],
-          // ...
-          // other Series properties go here
-          // to configure styling/behavior
-        }
-    - .. code-block:: python
-
-        # Corresponding LineSeries object
-        my_series = Series(data = [
-            CartesianData(id = 'first-data-point1',
-                          x = 1,
-                          y = 123),
-            CartesianData(id = 'second-data-point1',
-                          x = 2,
-                          y = 456),
-            CartesianData(id = 'third-data-point1',
-                          x = 3,
-                          y = 789),
-        ])
+        - .. code-block:: python
+
+            # EXAMPLE 1. Corresponding LineSeries object, with data as an
+            # numpy.ndarray.
+
+            my_series = Series(data = CartesianDataCollection(
+                ndarray = [
+                    [1, 123, 'first-data-point1'],
+                    [2, 456, 'second-data-point1'],
+                    [3, 789, 'third-data-point1'])
+            ])
+
+            # EXAMPLE 2. Corresponding LineSeries object, with data as a
+            # primitive array.
+
+            my_series = Series(data = CartesianDataCollection(
+                array = [
+                    [1, 123, 'first-data-point1'],
+                    [2, 456, 'second-data-point1'],
+                    [3, 789, 'third-data-point1'])
+                ]
+            ))
 
 As you can see, **Highcharts for Python** represents its data the same way that
 `Highcharts (JS) <https://www.highcharts.com>`__ does. That should be expected. 
 However, constructing tens, hundreds, or possibly thousands of data points 
 individually in your code would be a nightmare. For that reason, the 
-**Highcharts for Python Toolkit** provides a number of convenience methods to make it
-easier to populate your series.
-
-.. warning::
-
-  **PLEASE TAKE NOTE!**
-
-  **Highcharts Stock for Python** and
-  `Highcharts Stock <https://www.highcharts.com/products/stock/>`__ support 50
-  different :term:`technical indicators <technical indicator>`, which are visualizations
-  that are derived from *other* :term:`series` on your chart. 
-  
-  These technical indicators are a special kind of series. They do not have a ``.data`` 
-  property and thus cannot be given their own data points. Their data points are 
-  calculated automatically by
-  `Highcharts Stock <https://www.highcharts.com/products/stock/>`__ from the
-  related :term:`series` indicated in their
-  :meth:`.linked_to <highcharts_stock.options.series.base.IndicatorSeriesBase.linked_to>`
-  properties.
+**Highcharts for Python Toolkit** natively supports vectorized 
+:class:`numpy.ndarray <numpy:numpy.ndarray>` values, and automatically assembles data
+point collections for easy management/manipulation. In addition, the Toolkit 
+provides a number of convenience methods to make it easier to populate your 
+series.
 
 .. _populating_series_data:
 
 Populating Series Data
 ===========================
 
-Every single :term:`Series` class in **Highcharts Stock for Python** features several
-different methods to either instantiate data points directly, load data (to an existing
-series instance), or to create a new series instance with data already loaded.
+Every single :term:`Series` class in **Highcharts for Python** features several different
+methods to either instantiate data points directly, load data (to an existing series
+instance), or to create a new series instance with data already loaded.
 
 .. tabs::
 
@@ -502,18 +559,21 @@ series instance), or to create a new series instance with data already loaded.
 
     Data points all have the same standard **Highcharts for Python**
     :ref:`deserialization methods <deserialization_methods>`, so those make things very easy.
-    However, they also have a special data point-specific ``.from_array()`` deserialization method:
+    However, they also have a special data point-specific deserialization method:
 
-      .. collapse:: Method Signature
+      .. collapse:: Expand Method Signature
 
         .. method:: .from_array(cls, value)
           :classmethod:
           :noindex:
 
-          Creates a collection of data point instances, parsing the contents of ``value`` as an
-          array (iterable). This method is specifically used to parse data that is input to
+          Creates a 
+          :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+          instance if possible, or falls back to a collection of data point 
+          instances, parsing the contents of ``value`` as an array (iterable). This method 
+          is specifically used to parse data that is input to
           **Highcharts for Python** without property names, in an array-organized structure as
-          described in the `Highcharts <https://www.highcharts.com>`__ documentation.
+          described in the `Highcharts (JS) <https://www.highcharts.com>`__ documentation.
 
           .. seealso::
 
@@ -534,12 +594,37 @@ series instance), or to create a new series instance with data already loaded.
 
               my_series = LineSeries()
 
+              # EXAMPLE 1.
               # A simple array of numerical values which correspond to the Y value of the data
-              # point
+              # point, passed to the .from_array() method.
+
+              my_series = LineSeries.from_array([0, 5, 3, 5])
+
+              # EXAMPLE 2.
+              # A simple array of numerical values which correspond to the Y value of the data
+              # point, passed to the series data property.
+
               my_series.data = [0, 5, 3, 5]
 
+              # EXAMPLE 3.
+              # A simple array of numerical values which correspond to the Y value of the data
+              # point, updated in the series using the .load_from_array() method.
+
+              my_series.load_from_array([0, 5, 3, 5])
+
+              # EXAMPLE 4.
+              # An array containing 2-member arrays (corresponding to the X and Y values of the
+              # data point), passed to the .from_array() class method.
+              my_series = LineSeries.from_array([
+                  [0, 0],
+                  [1, 5],
+                  [2, 3],
+                  [3, 5]
+              ])
+
+              # EXAMPLE 5.
               # An array containing 2-member arrays (corresponding to the X and Y values of the
-              # data point)
+              # data point), passed to the series data property.
               my_series.data = [
                   [0, 0],
                   [1, 5],
@@ -547,7 +632,37 @@ series instance), or to create a new series instance with data already loaded.
                   [3, 5]
               ]
 
-              # An array of dict with named values
+              # EXAMPLE 6.
+              # An array of dict with named values, passed to the .from_array() class method.
+              my_series = LineSeries.from_array([
+                {
+                    'x': 0,
+                    'y': 0,
+                    'name': 'Point1',
+                    'color': '#00FF00'
+                },
+                {
+                    'x': 1,
+                    'y': 5,
+                    'name': 'Point2',
+                    'color': '#CCC'
+                },
+                {
+                    'x': 2,
+                    'y': 3,
+                    'name': 'Point3',
+                    'color': '#999'
+                },
+                {
+                    'x': 3,
+                    'y': 5,
+                    'name': 'Point4',
+                    'color': '#000'
+                }
+              ])
+
+              # EXAMPLE 6.
+              # An array of dict with named values, passed to the series data property.
               my_series.data = [
                 {
                     'x': 0,
@@ -575,6 +690,36 @@ series instance), or to create a new series instance with data already loaded.
                 }
               ]
 
+              # EXAMPLE 6.
+              # An array of dict with named values, passed to .load_from_array()
+              # method.
+              my_series.load_from_array([
+                {
+                    'x': 0,
+                    'y': 0,
+                    'name': 'Point1',
+                    'color': '#00FF00'
+                },
+                {
+                    'x': 1,
+                    'y': 5,
+                    'name': 'Point2',
+                    'color': '#CCC'
+                },
+                {
+                    'x': 2,
+                    'y': 3,
+                    'name': 'Point3',
+                    'color': '#999'
+                },
+                {
+                    'x': 3,
+                    'y': 5,
+                    'name': 'Point4',
+                    'color': '#000'
+                }
+              ])
+
           :param value: The value that should contain the data which will be converted into data
             point instances.
 
@@ -589,9 +734,11 @@ series instance), or to create a new series instance with data already loaded.
             :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`)
           :rtype: :class:`list <python:list>` of
             :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`-descendant
-            instances
+            instances or
+            :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
+            instance
 
-  .. tab:: Load to Existing Series
+  .. tab:: Update an Existing Series
 
     .. warning::
 
@@ -605,8 +752,13 @@ series instance), or to create a new series instance with data already loaded.
 
         * :doc:`Using Highcharts for Python <using>` > :ref:`Using Technical Indicators <using_technical_indicators>`
 
+
     .. tabs::
 
+      .. tab:: Using ``.load_from_array()``
+
+        .. include:: using/populating_series_data/_load_from_array.rst
+
       .. tab:: Using ``.load_from_csv()``
 
         .. include:: using/populating_series_data/_load_from_csv.rst
@@ -636,6 +788,10 @@ series instance), or to create a new series instance with data already loaded.
 
     .. tabs::
 
+      .. tab:: Using ``.from_array()``
+
+        .. include:: using/populating_series_data/_new_from_array.rst
+
       .. tab:: Using ``.from_csv()``
 
         .. include:: using/populating_series_data/_new_from_csv.rst
@@ -664,7 +820,7 @@ an instance of
 
     The :class:`HighchartsStockOptions <highcharts_stock.options.HighchartsStockOptions>`
     is a sub-class of the **Highcharts Core for Python**
-    :class:`HighchartsOptions <highcharts_core:highcharts_core.options.HighchartsOptions>` 
+    :class:`HighchartsOptions <highcharts_core:highcharts_stock.options.HighchartsOptions>` 
     class, and is fully backwards-compatible with it. 
     
     This means that you can use them interchangeably when using 
@@ -687,6 +843,10 @@ property. You can do this in several ways:
 
 .. tabs::
 
+  .. tab:: Using Keyword Arguments
+
+    .. include:: using/adding_series_to_charts/_using_kwargs.rst
+
   .. tab:: Using ``.options.series``
 
     .. include:: using/assembling_your_chart/_using_series_property.rst
@@ -760,14 +920,26 @@ will display the chart in full.
 
 .. warning::
 
-  The current version of **Highcharts Stock for Python** assumes that your web content
-  already has all the ``<script/>`` tags which include the
-  `Highcharts Core <https://www.highcharts.com/products/highcharts>`__ and
-  `Highcharts Stock <https://www.highcharts.com/products/stock>`__ modules your chart
-  relies on.
+  The :meth:`.to_js_literal() <highcharts_stock.chart.Chart.to_js_literal>` method 
+  assumes that your web content already has all the ``<script/>`` tags which include 
+  the `Highcharts (JS) <https://www.highcharts.com>`__ modules your chart relies on.
+
+  If you need to generate the required ``<script/>`` tags for your chart, you can do
+  so by calling:
+
+    .. code-block:: python
 
-  This is likely to change in a future version of **Highcharts Stock for Python**, where the
-  library will support the production of ``<script/>`` tags (see roadmap issue :issue:`4`).
+      # EXAMPLE 1.
+      # Get a list of <script/> tags.
+      list_of_script_tags = my_chart.get_script_tags()
+
+      # EXAMPLE 2.
+      # Get a string of <script/> tags.
+      script_tags_as_str = my_chart.get_script_tags(as_str = True)
+
+      # EXAMPLE 3.
+      # Get a list of the required Highcharts modules.
+      required_modules = my_chart.get_required_modules()
 
 For example:
 
@@ -793,7 +965,7 @@ application's HTML output (in an appropriate ``<script/>`` tag, of course).
 Rendering Highcharts for Python in Jupyter Labs or Jupyter Notebooks
 ======================================================================
 
-You can also render **Highcharts Stock for Python** visualizations inside your
+You can also render **Highcharts for Python** visualizations inside your
 `Jupyter <https://jupyter.org/>`_ notebook. This is as simple as executing a single
 :meth:`.display() <highcharts_stock.chart.Chart.display>` call on your
 :class:`Chart <highcharts_stock.chart.Chart>` instance:
@@ -897,6 +1069,7 @@ environment. The actual file itself is produced using a
 
     .. include:: using/download_visualizations/_using_custom.rst
 
+
 .. warning::
 
   As of Highcharts for Python v.1.1.0, the Highcharts :term:`Export Server` does not yet fully 
diff --git a/docs/using/assembling_your_chart/_using_kwargs.rst b/docs/using/assembling_your_chart/_using_kwargs.rst
new file mode 100644
index 0000000..0ad9c56
--- /dev/null
+++ b/docs/using/assembling_your_chart/_using_kwargs.rst
@@ -0,0 +1,23 @@
+  .. note::
+
+    The keyword pattern outlined below is supported by both the
+    :class:`Chart <highcharts_stock.chart.Chart>` and
+    :class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>`
+    classes
+
+.. code-block:: python
+
+  from highcharts_stock.chart import Chart
+  from highcharts_stock.options.series.area import LineSeries
+
+  # EXAMPLE 1. Indicating data and series_type.
+  my_chart = Chart(data = [[0, 1], [1, 2], [2, 3]],
+                   series_type = 'line')
+
+  # EXAMPLE 2. Supplying the Series instance(s) directly.
+  my_chart = Chart(series = LineSeries(data = [
+                                            [0, 1],
+                                            [1, 2],
+                                            [2, 3]
+                                      ]))
+  
\ No newline at end of file
diff --git a/docs/using/download_visualizations/_using_custom.rst b/docs/using/download_visualizations/_using_custom.rst
index 20ba143..6b45db8 100644
--- a/docs/using/download_visualizations/_using_custom.rst
+++ b/docs/using/download_visualizations/_using_custom.rst
@@ -1,20 +1,13 @@
 .. code-block:: python
 
   from highcharts_stock.chart import Chart
-  from highcharts_stock.options.series.area import LineSeries
   from highcharts_stock.headless_export import ExportServer
 
   custom_server = ExportServer(url = 'https://www.mydomain.dev/some_pathname_goes_here')
 
-  my_chart = Chart(container = 'target_div',
-                   options = {
-                       'series': [
-                           LineSeries(data = [0, 5, 3, 5])
-                       ]
-                   },
-                   variable_name = 'myChart',
-                   is_stock_chart = True)
-
+  my_chart = Chart(data = [0, 5, 3, 5],
+                   series_type = 'line')
+ 
   # Download a PNG version of the chart in memory within your Python code.
   my_png_image = my_chart.download_chart(format = 'png',
                                          server_instance = custom_server)
@@ -51,11 +44,12 @@
       be persisted. Defaults to :obj:`None <python:None>`.
     :type filename: Path-like or :obj:`None <python:None>`
 
-    :param server_instance: Provide an already-configured :class:`ExportServer`
+    :param server_instance: Provide an already-configured :class:`ExportServer <highcharts_stock.headless_export.ExportServer>`
       instance to use to programmatically produce the exported chart. Defaults to
       :obj:`None <python:None>`, which causes **Highcharts for Python** to instantiate
-      a new :class:`ExportServer` instance with all applicable defaults.
-    :type server_instance: :class:`ExportServer` or :obj:`None <python:None>`
+      a new :class:`ExportServer <highcharts_stock.headless_export.ExportServer>` instance with all applicable defaults.
+    :type server_instance: :class:`ExportServer <highcharts_stock.headless_export.ExportServer>`
+      or :obj:`None <python:None>`
 
     :param format: The format in which the exported chart should be returned. Defaults to
       ``'png'``.
@@ -118,7 +112,7 @@
 
     .. note::
 
-      All other keyword arguments are as per the :class:`ExportServer` constructor.
+      All other keyword arguments are as per the :class:`ExportServer <highcharts_stock.headless_export.ExportServer>` constructor.
 
     :returns: The exported chart image, either as a :class:`bytes <python:bytes>`
       binary object or as a base-64 encoded string (depending on the ``use_base64``
diff --git a/docs/using/download_visualizations/_using_highsoft.rst b/docs/using/download_visualizations/_using_highsoft.rst
index 3d5b11f..ec59c59 100644
--- a/docs/using/download_visualizations/_using_highsoft.rst
+++ b/docs/using/download_visualizations/_using_highsoft.rst
@@ -1,16 +1,9 @@
 .. code-block:: python
 
   from highcharts_stock.chart import Chart
-  from highcharts_stock.options.series.area import LineSeries
 
-  my_chart = Chart(container = 'target_div',
-                   options = {
-                       'series': [
-                           LineSeries(data = [0, 5, 3, 5])
-                       ]
-                   },
-                   variable_name = 'myChart',
-                   is_stock_chart = True)
+  my_chart = Chart(data = [0, 5, 3, 5],
+                   series_type = 'line')
 
   # Download a PNG version of the chart in memory within your Python code.
   my_png_image = my_chart.download_chart(format = 'png')
@@ -37,11 +30,11 @@
       be persisted. Defaults to :obj:`None <python:None>`.
     :type filename: Path-like or :obj:`None <python:None>`
 
-    :param server_instance: Provide an already-configured :class:`ExportServer`
+    :param server_instance: Provide an already-configured :class:`ExportServer <highcharts_stock.headless_export.ExportServer>`
       instance to use to programmatically produce the exported chart. Defaults to
       :obj:`None <python:None>`, which causes **Highcharts for Python** to instantiate
-      a new :class:`ExportServer` instance with all applicable defaults.
-    :type server_instance: :class:`ExportServer` or :obj:`None <python:None>`
+      a new :class:`ExportServer <highcharts_stock.headless_export.ExportServer>` instance with all applicable defaults.
+    :type server_instance: :class:`ExportServer <highcharts_stock.headless_export.ExportServer>` or :obj:`None <python:None>`
 
     :param format: The format in which the exported chart should be returned. Defaults to
       ``'png'``.
@@ -104,7 +97,7 @@
 
     .. note::
 
-      All other keyword arguments are as per the :class:`ExportServer` constructor.
+      All other keyword arguments are as per the :class:`ExportServer <highcharts_stock.headless_export.ExportServer>` constructor.
 
     :returns: The exported chart image, either as a :class:`bytes <python:bytes>`
       binary object or as a base-64 encoded string (depending on the ``use_base64``
diff --git a/docs/using/populating_series_data/_load_from_array.rst b/docs/using/populating_series_data/_load_from_array.rst
new file mode 100644
index 0000000..73e9109
--- /dev/null
+++ b/docs/using/populating_series_data/_load_from_array.rst
@@ -0,0 +1,85 @@
+.. code-block:: python
+
+  # EXAMPLE 1
+  # A simple array of numerical values which correspond to the Y value of the data
+  # point
+
+  my_series.load_from_array([0, 5, 3, 5])
+
+  # EXAMPLE 2
+  # An array containing 2-member arrays (corresponding to the X and Y values of the
+  # data point)
+
+  my_series.load_from_array([
+      [0, 0],
+      [1, 5],
+      [2, 3],
+      [3, 5]
+  ])
+
+  # EXAMPLE 3
+  # An array of dict with named values
+
+  my_series.load_from_array([
+    {
+        'x': 0,
+        'y': 0,
+        'name': 'Point1',
+        'color': '#00FF00'
+    },
+    {
+        'x': 1,
+        'y': 5,
+        'name': 'Point2',
+        'color': '#CCC'
+    },
+    {
+        'x': 2,
+        'y': 3,
+        'name': 'Point3',
+        'color': '#999'
+    },
+    {
+        'x': 3,
+        'y': 5,
+        'name': 'Point4',
+        'color': '#000'
+    }
+  ])
+
+  # EXAMPLE 5
+  # using a NumPy ndarray named "numpy_array"
+
+  my_series.load_from_array(numpy_array)
+
+.. collapse:: Method Signature
+
+  .. method:: load_from_array(cls, value)
+    :noindex:
+    :classmethod:
+
+    Update the :term:`series` instance's ``data`` property with data populated from
+    an array-like ``value``.
+
+    This method is specifically used to parse data that is input to
+    **Highcharts for Python** without property names, in an array-organized structure as
+    described in the `Highcharts JS <https://www.highcharts.com>`__ documentation.
+
+    .. seealso::
+
+      The specific structure of the expected array is highly dependent on the type of data
+      point that the series needs, which itself is dependent on the series type itself.
+
+      Please review the detailed :ref:`series documentation <series_documentation>` for
+      series type-specific details of relevant array structures.
+
+    :param value: The value that should contain the data which will be converted into data
+      point instances.
+
+      .. note::
+
+        If ``value`` is not an iterable, it will be converted into an iterable to be
+        further de-serialized correctly.
+
+    :type value: iterable
+
diff --git a/docs/using/populating_series_data/_load_from_csv.rst b/docs/using/populating_series_data/_load_from_csv.rst
index efb051e..f95fea6 100644
--- a/docs/using/populating_series_data/_load_from_csv.rst
+++ b/docs/using/populating_series_data/_load_from_csv.rst
@@ -1,6 +1,13 @@
 .. code-block:: python
 
   # Given a LineSeries named "my_series", and a CSV file named "updated-data.csv"
+
+  my_series.load_from_csv('updated-data.csv')
+
+  # For more precise control over how the CSV data is parsed, 
+  # you can supply a mapping of series properties to their CSV column
+  # either by index position *or* by column header name.
+
   my_series.load_from_csv('updated-data.csv',
                           property_column_map = {
                               'x': 0,
@@ -10,7 +17,7 @@
 
 .. collapse:: Method Signature
 
-  .. method:: .load_from_csv(self, as_string_or_file, property_column_map, has_header_row = True, delimiter = ',', null_text = 'None', wrapper_character = "'", line_terminator = '\r\n', wrap_all_strings = False, double_wrapper_character_when_nested = False, escape_character = '\\')
+  .. method:: .load_from_csv(self, as_string_or_file, property_column_map = None, has_header_row = True, delimiter = ',', null_text = 'None', wrapper_character = "'", line_terminator = '\r\n', wrap_all_strings = False, double_wrapper_character_when_nested = False, escape_character = '\\', series_in_rows = 'line', series_index = None, **kwargs)
     :noindex:
 
     Updates the series instance with a collection of data points (descending from
@@ -32,21 +39,40 @@
           .. code-block:: python
 
             my_series = LineSeries()
-            my_series.load_from_csv('some-csv-file.csv',
-                                    property_column_map = {
-                                        'x': 0,
-                                        'y': 3,
-                                        'id': 'id'
-                                    })
-
-        As the example above shows, data is loaded into the ``my_series`` instance from
-        the CSV file with a filename ``some-csv-file.csv``. The
-        :meth:`x <CartesianData.x>`
-        values for each data point will be taken from the first (index 0) column in the
-        CSV file. The :meth:`y <CartesianData.y>` values will be taken from the fourth
-        (index 3) column in the CSV file. And the :meth:`id <CartesianData.id>` values
-        will be taken from a column whose header row is labeled ``'id'`` (regardless of
-        its index).
+            
+            # Minimal code - will attempt to update the line series
+            # taking x-values from the first column, and y-values from
+            # the second column. If there are too many columns in the CSV,
+            # will throw an error.
+            my_series = my_series.from_csv('some-csv-file.csv')
+            
+            # More precise code - will attempt to update the line series
+            # mapping columns in the CSV file to properties on the series
+            # instance.
+            my_series = my_series.from_csv('some-csv-file.csv',
+                                            property_column_map = {
+                                                'x': 0,
+                                                'y': 3,
+                                                'id': 'id'
+                                            })
+
+        As the example above shows, data is loaded into the ``my_series`` instance
+        from the CSV file with a filename ``some-csv-file.csv``. Unless otherwise
+        specified, the :meth:`.x <CartesianData.x>` values for each data point will
+        be taken from the first (index 0) column in the CSV file, while the 
+        :meth:`.y <CartesianData.y>` values will be taken from the second column.
+        
+        If the CSV has more than 2 columns, then this will throw an
+        :exc:`HighchartsCSVDeserializationError` because the function is not certain
+        which columns to use to update the series. If this happens, you can precisely
+        specify which columns to use by providing a ``property_column_map`` argument, 
+        as shown in the second example. In that second example, the
+        :meth:`.x <CartesianData.x>` values for each data point will be taken from 
+        the first (index 0) column in the CSV file. The :meth:`.y <CartesianData.y>` 
+        values will be taken from the fourth (index 3) column in the CSV file. And 
+        the :meth:`.id <CartesianData.id>`
+        values will be taken from a column whose header row is labeled ``'id'``
+        (regardless of its index).
 
     :param as_string_or_file: The CSV data to load, either as a :class:`str <python:str>`
       or as the name of a file in the runtime envirnoment. If a file, data will be read
@@ -59,11 +85,12 @@
 
     :type as_string_or_file: :class:`str <python:str>` or Path-like
 
-    :param property_column_map: A :class:`dict <python:dict>` used to indicate which
-      data point property should be set to which CSV column. The keys in the
+    :param property_column_map: An optional :class:`dict <python:dict>` used to indicate 
+      which data point property should be set to which CSV column. The keys in the
       :class:`dict <python:dict>` should correspond to properties in the data point class,
       while the value can either be a numerical index (starting with 0) or a
-      :class:`str <python:str>` indicating the label for the CSV column.
+      :class:`str <python:str>` indicating the label for the CSV column. Defaults to 
+      :obj:`None <python:None>`.
 
       .. warning::
 
@@ -125,6 +152,28 @@
       Python's native escape character).
     :type escape_character: :class:`str <python:str>`
 
+    :param series_in_rows: if ``True``, will attempt a streamlined cartesian series
+      with x-values taken from column names, y-values taken from row values, and
+      the series name taken from the row index. Defaults to 
+      :obj:`False <python:False>`.
+    :type series_in_rows: :class:`bool <python:bool>`
+
+    :param series_index: if :obj:`None <python:None>`, will raise a 
+      :exc:`HighchartsCSVDeserializationError <highcharts_stock.errors.HighchartsCSVDeserializationError>`
+      if the CSV data contains more than one series and no ``property_column_map`` 
+      is provided. Otherwise, will update the instance with the series found 
+      in the CSV at the ``series_index`` value. Defaults to 
+      :obj:`None <python:None>`.
+
+        .. tip::
+
+          This argument is *ignored* if ``property_column_map`` is provided.
+
+    :type series_index: :class:`int <python:int>` or :obj:`None <python:None>`
+
+    :param **kwargs: Remaining keyword arguments will be attempted on the resulting
+      :term:`series` instance and the data points it contains.
+
     :returns: A collection of data points descended from
       :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>` as
       appropriate for the series class.
diff --git a/docs/using/populating_series_data/_load_from_pandas.rst b/docs/using/populating_series_data/_load_from_pandas.rst
index 9f195ea..67a5621 100644
--- a/docs/using/populating_series_data/_load_from_pandas.rst
+++ b/docs/using/populating_series_data/_load_from_pandas.rst
@@ -1,6 +1,14 @@
 .. code-block:: python
 
   # Given a LineSeries named "my_series", and a Pandas DataFrame variable named "df"
+  
+  # EXAMPLE 1. The minimum code required to update the series:
+
+  my_series.load_from_pandas(df)
+
+  # EXAMPLE 2. For more precise control over how the ``df`` is parsed, 
+  # you can supply a mapping of series properties to their dataframe column.
+
   my_series.load_from_pandas(df,
                              property_map = {
                                  'x': 'date',
@@ -8,28 +16,55 @@
                                  'id': 'id'
                              })
 
+  # EXAMPLE 3. For more precise control, specify the index of the
+  # Highcharts for Python series instance to use in updating your series' data.
+
+  my_series.load_from_pandas(df, series_index = 3)
+
+
 .. collapse:: Method Signature
 
-  .. method:: .load_from_pandas(self, df, property_map)
+  .. method:: .load_from_pandas(self, df, property_map = None, series_in_rows = False, series_index = None)
     :noindex:
 
     Replace the contents of the
     :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
     with data points populated from a `pandas <https://pandas.pydata.org/>`__
-    :class:`DataFrame <pandas:DataFrame>`.
+    :class:`DataFrame <pandas:pandas.DataFrame>`.
 
-    :param df: The :class:`DataFrame <pandas:DataFrame>` from which data should be
+    :param df: The :class:`DataFrame <pandas:pandas.DataFrame>` from which data should be
       loaded.
-    :type df: :class:`DataFrame <pandas:DataFrame>`
+    :type df: :class:`DataFrame <pandas:pandas.DataFrame>`
 
     :param property_map: A :class:`dict <python:dict>` used to indicate which
       data point property should be set to which column in ``df``. The keys in the
       :class:`dict <python:dict>` should correspond to properties in the data point
       class, while the value should indicate the label for the
-      :class:`DataFrame <pandas:DataFrame>` column.
+      :class:`DataFrame <pandas:pandas.DataFrame>` column.
     :type property_map: :class:`dict <python:dict>`
 
+    :param series_in_rows: if ``True``, will attempt a streamlined cartesian series
+      with x-values taken from column names, y-values taken from row values, and
+      the series name taken from the row index. Defaults to 
+      :obj:`False <python:False>`.
+    :type series_in_rows: :class:`bool <python:bool>`
+
+    :param series_index: If supplied, return the series that Highcharts for Python
+      generated from ``df`` at the ``series_index`` value. Defaults to 
+      :obj:`None <python:None>`, which returns all series generated from ``df``.
+
+      .. warning::
+
+        If :obj:`None <python:None>` and Highcharts for Python generates multiple
+        series, then a :exc:`HighchartsPandasDeserializationError` will be raised.
+
+    :type series_index: :class:`int <python:int>`, slice, or 
+      :obj:`None <python:None>`
+
     :raises HighchartsPandasDeserializationError: if ``property_map`` references
       a column that does not exist in the data frame
+    :raises HighchartsPandasDeserializationError: if ``series_index`` is 
+      :obj:`None <python:None>`, and it is ambiguous which series generated from
+      the dataframe should be used
     :raises HighchartsDependencyError: if `pandas <https://pandas.pydata.org/>`__ is
       not available in the runtime environment
diff --git a/docs/using/populating_series_data/_new_from_array.rst b/docs/using/populating_series_data/_new_from_array.rst
new file mode 100644
index 0000000..b904369
--- /dev/null
+++ b/docs/using/populating_series_data/_new_from_array.rst
@@ -0,0 +1,213 @@
+.. code-block:: python
+
+  from highcharts_stock.options.series.area import LineSeries
+  from highcharts_stock.options.series.data.cartesian import CartesianData
+  from highcharts_stock.options.series.data.cartesian import CartesianDataCollection
+
+  # Creating CartesianData instances from an array
+
+  # EXAMPLE 1
+  # A simple array of numerical values which correspond to the Y value of the data
+  # point
+
+  my_data = CartesianData.from_array([0, 5, 3, 5])
+
+  # EXAMPLE 2
+  # An array containing 2-member arrays (corresponding to the X and Y values of the
+  # data point)
+
+  my_data = CartesianData.from_array([
+      [0, 0],
+      [1, 5],
+      [2, 3],
+      [3, 5]
+  ])
+
+  # EXAMPLE 3
+  # An array of dict with named values
+
+  my_data = CartesianData.from_array([
+    {
+        'x': 0,
+        'y': 0,
+        'name': 'Point1',
+        'color': '#00FF00'
+    },
+    {
+        'x': 1,
+        'y': 5,
+        'name': 'Point2',
+        'color': '#CCC'
+    },
+    {
+        'x': 2,
+        'y': 3,
+        'name': 'Point3',
+        'color': '#999'
+    },
+    {
+        'x': 3,
+        'y': 5,
+        'name': 'Point4',
+        'color': '#000'
+    }
+  ])
+
+  # EXAMPLE 5
+  # using a NumPy ndarray named "numpy_array"
+
+  my_data = CartesianData.from_array(numpy_array)
+
+
+  my_series = LineSeries(data = my_data)
+
+  # Creating a CartesianDataCollection instance from an array
+
+  # EXAMPLE 1
+  # A simple array of numerical values which correspond to the Y value of the data
+  # point
+
+  my_data = CartesianDataCollection.from_array([0, 5, 3, 5])
+
+  # EXAMPLE 2
+  # An array containing 2-member arrays (corresponding to the X and Y values of the
+  # data point)
+
+  my_data = CartesianDataCollection.from_array([
+      [0, 0],
+      [1, 5],
+      [2, 3],
+      [3, 5]
+  ])
+
+  # EXAMPLE 3
+  # An array of dict with named values
+
+  my_data = CartesianDataCollection.from_array([
+    {
+        'x': 0,
+        'y': 0,
+        'name': 'Point1',
+        'color': '#00FF00'
+    },
+    {
+        'x': 1,
+        'y': 5,
+        'name': 'Point2',
+        'color': '#CCC'
+    },
+    {
+        'x': 2,
+        'y': 3,
+        'name': 'Point3',
+        'color': '#999'
+    },
+    {
+        'x': 3,
+        'y': 5,
+        'name': 'Point4',
+        'color': '#000'
+    }
+  ])
+
+  # EXAMPLE 5
+  # using a NumPy ndarray named "numpy_array"
+
+  my_data = CartesianDataCollection.from_array(numpy_array)
+
+  my_series = LineSeries(data = my_data)
+
+  # Creating CartesianData instances from an array
+
+  # EXAMPLE 1
+  # A simple array of numerical values which correspond to the Y value of the data
+  # point
+
+  my_series = LineSeries.from_array([0, 5, 3, 5])
+
+  # EXAMPLE 2
+  # An array containing 2-member arrays (corresponding to the X and Y values of the
+  # data point)
+
+  my_series = LineSeries.from_array([
+      [0, 0],
+      [1, 5],
+      [2, 3],
+      [3, 5]
+  ])
+
+  # EXAMPLE 3
+  # An array of dict with named values
+
+  my_series = LineSeries.from_array([
+    {
+        'x': 0,
+        'y': 0,
+        'name': 'Point1',
+        'color': '#00FF00'
+    },
+    {
+        'x': 1,
+        'y': 5,
+        'name': 'Point2',
+        'color': '#CCC'
+    },
+    {
+        'x': 2,
+        'y': 3,
+        'name': 'Point3',
+        'color': '#999'
+    },
+    {
+        'x': 3,
+        'y': 5,
+        'name': 'Point4',
+        'color': '#000'
+    }
+  ])
+
+  # EXAMPLE 5
+  # using a NumPy ndarray named "numpy_array"
+
+  my_series = LineSeries.from_array(numpy_array)
+
+.. collapse:: Method Signature
+
+  .. seealso::
+
+    * :meth:`SeriesBase.from_array() <highcharts_stock.options.series.base.SeriesBase.from_array>`
+    * :meth:`Chart.from_array() <highcharts_stock.chart.from_array>`
+
+  .. method:: from_array(cls, value)
+    :noindex:
+    :classmethod:
+
+    Creates a collection of data point instances, parsing the contents of ``value`` as an
+    array (iterable). This method is specifically used to parse data that is input to
+    **Highcharts for Python** without property names, in an array-organized structure as
+    described in the `Highcharts JS <https://www.highcharts.com>`__ documentation.
+
+    .. seealso::
+
+      The specific structure of the expected array is highly dependent on the type of data
+      point that the series needs, which itself is dependent on the series type itself.
+
+      Please review the detailed :ref:`series documentation <series_documentation>` for
+      series type-specific details of relevant array structures.
+
+    :param value: The value that should contain the data which will be converted into data
+      point instances.
+
+      .. note::
+
+        If ``value`` is not an iterable, it will be converted into an iterable to be
+        further de-serialized correctly.
+
+    :type value: iterable
+
+    :returns: Collection of :term:`data point` instances (descended from
+      :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`)
+    :rtype: `:class:`list <python:list>` of
+      :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`-descendant
+      instances, or 
+      :class:`DataPointCollection <highcharts_stock.options.series.data.collections.DataPointCollection>`
diff --git a/docs/using/populating_series_data/_new_from_csv.rst b/docs/using/populating_series_data/_new_from_csv.rst
index 976130c..25b898b 100644
--- a/docs/using/populating_series_data/_new_from_csv.rst
+++ b/docs/using/populating_series_data/_new_from_csv.rst
@@ -9,7 +9,15 @@
   from highcharts_stock.chart import Chart
   from highcharts_stock.options.series.area import LineSeries
 
-  # Create a new LineSeries instance from the CSV file "some-csv-file.csv".
+  # Create one or more LineSeries instances from the CSV file "some-csv-file.csv".
+
+  # EXAMPLE 1. The minimum code to produce one series for each
+  # column in the CSV file (excluding the first column):
+
+  my_series = LineSeries.from_csv('some-csv-file.csv')
+
+  # EXAMPLE 2. Produces ONE series with more precise configuration:
+
   my_series = LineSeries.from_csv('some-csv-file.csv',
                                   property_column_map = {
                                       'x': 0,
@@ -17,7 +25,25 @@
                                       'id': 'id'
                                   })
 
-  # Create a new LineSeries instance from the CSV file "some-csv-file.csv".
+  # EXAMPLE 3. Produces THREE series instances with 
+  # more precise configuration:
+
+  my_series = LineSeries.from_csv('some-csv-file.csv',
+                                  property_column_map = {
+                                      'x': 0,
+                                      'y': [3, 5, 8],
+                                      'id': 'id'
+                                  })
+
+  # Create a chart with one or more LineSeries instances from 
+  # the CSV file "some-csv-file.csv".
+
+  # EXAMPLE 1: The minimum code:
+
+  my_chart = Chart.from_csv('some-csv-file.csv', series_type = 'line')
+  
+  # EXAMPLE 2: For more precise configuration and *one* series:
+
   my_chart = Chart.from_csv('some-csv-file.csv',
                             property_column_map = {
                                 'x': 0,
@@ -25,29 +51,44 @@
                                 'id': 'id'
                             },
                             series_type = 'line')
+  
+  # EXAMPLE 3: For more precise configuration and *multiple* series:
+
+  my_chart = Chart.from_csv('some-csv-file.csv',
+                            property_column_map = {
+                                'x': 0,
+                                'y': [3, 5, 8],
+                                'id': 'id'
+                            },
+                            series_type = 'line')
 
 .. collapse:: Method Signature
 
   .. seealso::
 
     * :meth:`Chart.from_csv() <highcharts_stock.chart.Chart.from_csv>`
+    * :meth:`SeriesBase.from_csv_in_rows() <highcharts_stock.options.series.base.SeriesBase.from_csv_in_rows>`
 
-  .. method:: .from_csv(cls, as_string_or_file, property_column_map, series_kwargs = None, has_header_row = True, delimiter = ',', null_text = 'None', wrapper_character = "'", line_terminator = '\r\n', wrap_all_strings = False, double_wrapper_character_when_nested = False, escape_character = '\\')
+  .. method:: .from_csv(cls, as_string_or_file, property_column_map = None, series_kwargs = None, has_header_row = True, delimiter = ',', null_text = 'None', wrapper_character = "'", line_terminator = '\r\n', wrap_all_strings = False, double_wrapper_character_when_nested = False, escape_character = '\\', series_in_rows = False, series_index = None, **kwargs)
     :noindex:
     :classmethod:
 
-    Create a new :term:`series` instance with a
-    :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
-    populated from data in a CSV string or file.
+    Create one or more :term:`series` instances with
+    :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` populated from data in a CSV string 
+    or file.
 
       .. note::
 
-        For an example
-        :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>`, the
+        To produce one or more
+        :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` instances, the
         minimum code required would be:
 
           .. code-block:: python
 
+            # EXAMPLE 1. The minimum code:
+            my_series = LineSeries.from_csv('some-csv-file.csv')
+
+            # EXAMPLE 2. For more precise configuration and ONE series:
             my_series = LineSeries.from_csv('some-csv-file.csv',
                                             property_column_map = {
                                                 'x': 0,
@@ -55,14 +96,39 @@
                                                 'id': 'id'
                                             })
 
+            # EXAMPLE 3. For more precise configuration and MULTIPLE series:
+            my_series = LineSeries.from_csv('some-csv-file.csv',
+                                            property_column_map = {
+                                                'x': 0,
+                                                'y': [3, 5, 8],
+                                                'id': 'id'
+                                            })
+
         As the example above shows, data is loaded into the ``my_series`` instance
-        from the CSV file with a filename ``some-csv-file.csv``. The
-        :meth:`x <CartesianData.x>`
+        from the CSV file with a filename ``some-csv-file.csv``. 
+        
+        In EXAMPLE 1, the method will return one or more series where each series 
+        will default to having its :meth:`.x <CartesianData.x>` values taken from 
+        the first (index 0) column in the CSV, and one 
+        :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` 
+        instance will be created for each subsequent column (which will populate 
+        that series' :meth:`.y <CartesianData.y>` values.
+        
+        In EXAMPLE 2, the chart will contain one series, where the
+        :meth:`.x <CartesianData.x>`
         values for each data point will be taken from the first (index 0) column in
-        the CSV file. The :meth:`y <CartesianData.y>` values will be taken from the
-        fourth (index 3) column in the CSV file. And the :meth:`id <CartesianData.id>`
+        the CSV file. The :meth:`.y <CartesianData.y>` values will be taken from the
+        fourth (index 3) column in the CSV file. And the :meth:`.id <CartesianData.id>`
         values will be taken from a column whose header row is labeled ``'id'``
         (regardless of its index).
+        
+        In EXAMPLE 3, the chart will contain three series, all of which will have
+        :meth:`.x <CartesianData.x>` values taken from the first (index 0) column,
+        :meth:`.id <CartesianData.id>` values from the column whose header row is 
+        labeled ``'id'``, and whose :meth:`.y <CartesianData.y>` will be taken
+        from the fourth (index 3) column for the first series, the sixth (index 5)
+        column for the second series, and the ninth (index 8) column for the third
+        series.
 
     :param as_string_or_file: The CSV data to use to pouplate data. Accepts either
       the raw CSV data as a :class:`str <python:str>` or a path to a file in the
@@ -81,14 +147,45 @@
       class, while the value can either be a numerical index (starting with 0) or a
       :class:`str <python:str>` indicating the label for the CSV column.
 
+        .. note::
+        
+          If any of the values in ``property_column_map`` contain an iterable, then
+          one series will be produced for each item in the iterable. For example,
+          the following:
+          
+          .. code-block:: python
+          
+            {
+                'x': 0,
+                'y': [3, 5, 8]
+            }
+            
+          will return *three* series, each of which will have its 
+          :meth:`.x <CartesianData.x>` value populated from the first column 
+          (index 0), and whose :meth:`.y <CartesianData.y>`
+          values will be populated from the fourth, sixth, and ninth columns (indices 
+          3, 5, and 8), respectively.
+
+        .. warning::
+
+          If the ``property_column_map`` uses :class:`str <python:str>` values, the CSV
+          file *must* have a header row (this is expected, by default). If there is no
+          header row and a :class:`str <python:str>` value is found, a
+          :exc:`HighchartsCSVDeserializationError` will be raised.
+
+    :type property_column_map: :class:`dict <python:dict>`
+
+    :param series_type: Indicates the series type that should be created from the CSV
+      data. Defaults to ``'line'``.
+
       .. warning::
 
-        If the ``property_column_map`` uses :class:`str <python:str>` values, the CSV
-        file *must* have a header row (this is expected, by default). If there is no
-        header row and a :class:`str <python:str>` value is found, a
-        :exc:`HighchartsCSVDeserializationError` will be raised.
+        This argument is *not supported* when calling 
+        :meth:`.from_csv() <highcharts_stock.options.series.base.SeriesBase.from_csv>` on 
+        a :term:`series` instance. It is only supported when calling 
+        :meth:`Chart.from_csv() <highcharts_stock.chart.Chart.from_csv>`.
 
-    :type property_column_map: :class:`dict <python:dict>`
+    :type series_type: :class:`str <python:str>`
 
     :param has_header_row: If ``True``, indicates that the first row of
       ``as_string_or_file`` contains column labels, rather than actual data. Defaults
@@ -156,12 +253,29 @@
       Python's native escape character).
     :type escape_character: :class:`str <python:str>`
 
-    :returns: A :term:`series` instance (descended from
+    :param series_in_rows: if ``True``, will attempt a streamlined cartesian series
+      with x-values taken from column names, y-values taken from row values, and
+      the series name taken from the row index. Defaults to ``False``.
+    :type series_in_rows: :class:`bool <python:bool>`
+
+    :param series_index: if :obj:`None <python:None>`, will attempt to populate
+      the chart with multiple series from the CSV data. If an :class:`int <python:int>`
+      is supplied, will populate the chart only with the series found at 
+      ``series_index``.
+
+    :type series_index: :class:`int <python:int>`, slice, or 
+      :obj:`None <python:None>`
+
+    :param **kwargs: Remaining keyword arguments will be attempted on the resulting
+      :term:`series` instance and the data points it contains.
+
+    :returns: One or more :term:`series` instances (descended from
       :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`) with its
       :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
       populated from the CSV data in ``as_string_or_file``.
     :rtype: :class:`list <python:list>` of series instances (descended from
-      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`)
+      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`) or
+      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>` instance
 
     :raises HighchartsCSVDeserializationError: if ``property_column_map`` references
       CSV columns by their label, but the CSV data does not contain a header row
diff --git a/docs/using/populating_series_data/_new_from_pandas.rst b/docs/using/populating_series_data/_new_from_pandas.rst
index f2668cb..66bb96c 100644
--- a/docs/using/populating_series_data/_new_from_pandas.rst
+++ b/docs/using/populating_series_data/_new_from_pandas.rst
@@ -2,7 +2,7 @@
 
     The ``.from_pandas()`` method is available on all :term:`series` classes and on the
     :class:`Chart <highcharts_stock.chart.Chart>` class, allowing you to either assemble
-    a series or an entire chart from Pandas :class:`DataFrame <pandas:DataFrame>`
+    a series or an entire chart from Pandas :class:`DataFrame <pandas:pandas.DataFrame>`
     with only one method call.
 
 .. code-block:: python
@@ -12,14 +12,54 @@
   from highcharts_stock.options.series.area import LineSeries
 
   # Creating a Series from the DataFrame
+  
+  ## EXAMPLE 1. Minimum code required. Creates one or more series.
+
+  my_series = LineSeries.from_pandas(df)
+
+  ## EXAMPLE 2. More precise configuration. Creates ONE series.
+
+  my_series = LineSeries.from_pandas(df, series_index = 2)
+
+  ## EXAMPLE 3. More precise configuration. Creates ONE series.
+
   my_series = LineSeries.from_pandas(df,
                                      property_map = {
                                          'x': 'date',
                                          'y': 'value',
                                          'id': 'id'
                                      })
+  
+  ## EXAMPLE 4. More precise configuration. Creates THREE series.
 
+  my_series = LineSeries.from_pandas(df,
+                                     property_map = {
+                                         'x': 'date',
+                                         'y': ['value1', 'value2', 'value3'],
+                                         'id': 'id'
+                                     })
+
+  ## EXAMPLE 5. Minimum code required. Creates one or more series
+  ## from a dataframe where each row in the dataframe is a 
+  ## Highcharts series. The two lines of code below are equivalent.
+
+  my_series = LineSeries.from_pandas_in_rows(df)
+  
   # Creating a Chart with a lineSeries from the DataFrame.
+
+  ## EXAMPLE 1. Minimum code required. Populates the chart with
+  ## one or more series.
+
+  my_chart = Chart.from_pandas(df)
+
+  ## EXAMPLE 2. More precise configuration. Populates the chart with
+  ## one series.
+
+  my_chart = Chart.from_pandas(df, series_index = 2)
+
+  ## EXAMPLE 3. More precise configuration. Populates the chart with
+  ## ONE series.
+
   my_chart = Chart.from_pandas(df,
                                property_map = {
                                    'x': 'date',
@@ -27,6 +67,23 @@
                                    'id': 'id'
                                },
                                series_type = 'line')
+  
+  ## EXAMPLE 4. More precise configuration. Populates the chart with
+  ## THREE series.
+
+  my_chart = Chart.from_pandas(df,
+                               property_map = {
+                                   'x': 'date',
+                                   'y': ['value1', 'value2', 'value3'],
+                                   'id': 'id'
+                               },
+                               series_type = 'line')
+
+  ## EXAMPLE 5. Minimum code required. Creates a Chart populated
+  ## with series from a dataframe where each row in the dataframe
+  ## becomes a series on the chart.
+
+  my_chart = Chart.from_pandas_in_rows(df)
 
 
 .. collapse:: Method Signature
@@ -34,27 +91,61 @@
   .. seealso::
 
     * :meth:`Chart.from_pandas() <highcharts_stock.chart.Chart.from_pandas>`
+    * :meth:`Chart.from_pandas_in_rows() <highcharts_stock.chart.Chart.from_pandas_in_rows>`
+    * :meth:`SeriesBase.from_pandas_in_rows() <highcharts_stock.options.series.base.SeriesBase.from_pandas_in_rows>`
 
-  .. method:: .from_pandas(cls, df, property_map, series_kwargs = None)
+  .. method:: .from_pandas(cls, df, property_map = None, series_kwargs = None, series_in_rows = False, series_index = None, **kwargs)
     :noindex:
     :classmethod:
 
-    Create a :term:`series` instance whose
-    :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
-    is populated from a `pandas <https://pandas.pydata.org/>`__
-    :class:`DataFrame <pandas:DataFrame>`.
+    Create one or more :term:`series` instances whose
+    :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` properties
+    are populated from a `pandas <https://pandas.pydata.org/>`_
+    :class:`DataFrame <pandas:pandas.DataFrame>`.
 
-    :param df: The :class:`DataFrame <pandas:DataFrame>` from which data should be
+    :param df: The :class:`DataFrame <pandas:pandas.DataFrame>` from which data should be
       loaded.
-    :type df: :class:`DataFrame <pandas:DataFrame>`
+    :type df: :class:`DataFrame <pandas:pandas.DataFrame>`
 
-    :param property_map: A :class:`dict <python:dict>` used to indicate which
+    :param property_map: An optional :class:`dict <python:dict>` used to indicate which
       data point property should be set to which column in ``df``. The keys in the
       :class:`dict <python:dict>` should correspond to properties in the data point
       class, while the value should indicate the label for the
-      :class:`DataFrame <pandas:DataFrame>` column.
+      :class:`DataFrame <pandas:pandas.DataFrame>` column.
+
+        .. note::
+      
+          If any of the values in ``property_map`` contain an iterable, then
+          one series will be produced for each item in the iterable. For example,
+          the following:
+        
+            .. code-block:: python
+        
+              {
+                  'x': 'timestamp',
+                  'y': ['value1', 'value2', 'value3']
+              }
+          
+          will return *three* series, each of which will have its 
+          :meth:`.x <CartesianData.x>` value populated from the column
+          labeled ``'timestamp'``, and whose :meth:`.y <CartesianData.y>`
+          values will be populated from the columns labeled ``'value1'``,
+          ``'value2'``, and ``'value3'``, respectively.
+
     :type property_map: :class:`dict <python:dict>`
 
+    :param series_type: Indicates the series type that should be created from the CSV
+      data. Defaults to ``'line'``.
+
+      .. warning::
+
+        This argument is *not supported* when calling 
+        :meth:`.from_pandas() <highcharts_stock.options.series.base.SeriesBase.from_pandas>` on 
+        a :term:`series`. It is only supported when calling 
+        :meth:`Chart.from_csv() <highcharts_stock.chart.Chart.from_pandas>`.
+
+    :type series_type: :class:`str <python:str>`
+
     :param series_kwargs: An optional :class:`dict <python:dict>` containing keyword
       arguments that should be used when instantiating the series instance. Defaults
       to :obj:`None <python:None>`.
@@ -66,12 +157,30 @@
 
     :type series_kwargs: :class:`dict <python:dict>`
 
-    :returns: A :term:`series` instance (descended from
-      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`) with its
+    :param series_in_rows: if ``True``, will attempt a streamlined cartesian series
+      with x-values taken from column names, y-values taken from row values, and
+      the series name taken from the row index. Defaults to ``False``.
+      :obj:`False <python:False>`.
+    :type series_in_rows: :class:`bool <python:bool>`
+
+    :param series_index: If supplied, return the series that Highcharts for Python
+      generated from ``df`` at the ``series_index`` value. Defaults to 
+      :obj:`None <python:None>`, which returns all series generated from ``df``.
+
+    :type series_index: :class:`int <python:int>`, slice, or 
+      :obj:`None <python:None>`
+
+    :param **kwargs: Remaining keyword arguments will be attempted on the resulting
+      :term:`series` instance and the data points it contains.
+
+    :returns: One or more :term:`series` instances (descended from
+      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`) with the
       :meth:`.data <highcharts_stock.options.series.base.SeriesBase.data>` property
       populated from the data in ``df``.
     :rtype: :class:`list <python:list>` of series instances (descended from
-      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`)
+      :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`), or
+      a :class:`SeriesBase <highcharts_stock.options.series.base.SeriesBase>`-descended
+      instance
 
     :raises HighchartsPandasDeserializationError: if ``property_map`` references
       a column that does not exist in the data frame
diff --git a/docs/using/populating_series_data/_with_data_property.rst b/docs/using/populating_series_data/_with_data_property.rst
index 11fedfb..c264faa 100644
--- a/docs/using/populating_series_data/_with_data_property.rst
+++ b/docs/using/populating_series_data/_with_data_property.rst
@@ -2,12 +2,16 @@
 
   my_series = LineSeries()
 
+  # EXAMPLE 1
   # A simple array of numerical values which correspond to the Y value of the data
   # point
+
   my_series.data = [0, 5, 3, 5]
 
+  # EXAMPLE 2
   # An array containing 2-member arrays (corresponding to the X and Y values of the
   # data point)
+
   my_series.data = [
       [0, 0],
       [1, 5],
@@ -15,7 +19,9 @@
       [3, 5]
   ]
 
+  # EXAMPLE 3
   # An array of dict with named values
+  
   my_series.data = [
     {
         'x': 0,
@@ -42,15 +48,3 @@
         'color': '#000'
     }
   ]
-
-.. warning::
-
-  :term:`Technical indicators <technical indicator>` provided by
-  **Highcharts Stock for Python** do not support the ``.data`` property because
-  their data gets populated dynamically based on the series indicated in their
-  :meth:`.linked_to <highcharts_stock.options.series.base.IndicatorSeriesBase.linked_to>`
-  property.
-
-  .. seealso::
-
-    * :doc:`Using Highcharts Stock for Python </using>` > :ref:`Using Technical Indicators <using_technical_indicators>`
diff --git a/docs/using/populating_series_data/_with_from_array.rst b/docs/using/populating_series_data/_with_from_array.rst
deleted file mode 100644
index 7a2974c..0000000
--- a/docs/using/populating_series_data/_with_from_array.rst
+++ /dev/null
@@ -1,146 +0,0 @@
-.. code-block:: python
-
-  from highcharts_stock.options.series.area import LineSeries
-  from highcharts_stock.options.series.data import CartesianData
-
-  # A simple array of numerical values which correspond to the Y value of the data
-  # point
-  my_data = CartesianData.from_array([0, 5, 3, 5])
-
-  # An array containing 2-member arrays (corresponding to the X and Y values of the
-  # data point)
-  my_data = CartesianData.from_array([
-      [0, 0],
-      [1, 5],
-      [2, 3],
-      [3, 5]
-  ])
-
-  # An array of dict with named values
-  my_data = CartesianData.from_array([
-    {
-        'x': 0,
-        'y': 0,
-        'name': 'Point1',
-        'color': '#00FF00'
-    },
-    {
-        'x': 1,
-        'y': 5,
-        'name': 'Point2',
-        'color': '#CCC'
-    },
-    {
-        'x': 2,
-        'y': 3,
-        'name': 'Point3',
-        'color': '#999'
-    },
-    {
-        'x': 3,
-        'y': 5,
-        'name': 'Point4',
-        'color': '#000'
-    }
-  ])
-
-  my_series = LineSeries(data = my_data)
-
-.. collapse:: Method Signature
-
-  .. method:: from_array(cls, value)
-    :noindex:
-    :classmethod:
-
-    Creates a collection of data point instances, parsing the contents of ``value`` as an
-    array (iterable). This method is specifically used to parse data that is input to
-    **Highcharts for Python** without property names, in an array-organized structure as
-    described in the `Highcharts JS <https://www.highcharts.com>`__ documentation.
-
-    .. seealso::
-
-      The specific structure of the expected array is highly dependent on the type of data
-      point that the series needs, which itself is dependent on the series type itself.
-
-      Please review the detailed :ref:`series documentation <series_documentation>` for
-      series type-specific details of relevant array structures.
-
-    .. note::
-
-      An example of how this works for a simple
-      :class:`LineSeries <highcharts_stock.options.series.area.LineSeries>` (which uses
-      :class:`CartesianData <highcharts_stock.options.series.data.cartesian.CartesianData>`
-      data points) would be:
-
-      .. code-block:: python
-
-        my_series = LineSeries()
-
-        # A simple array of numerical values which correspond to the Y value of the data
-        # point
-        my_series.data = [0, 5, 3, 5]
-
-        # An array containing 2-member arrays (corresponding to the X and Y values of the
-        # data point)
-        my_series.data = [
-            [0, 0],
-            [1, 5],
-            [2, 3],
-            [3, 5]
-        ]
-
-        # An array of dict with named values
-        my_series.data = [
-          {
-              'x': 0,
-              'y': 0,
-              'name': 'Point1',
-              'color': '#00FF00'
-          },
-          {
-              'x': 1,
-              'y': 5,
-              'name': 'Point2',
-              'color': '#CCC'
-          },
-          {
-              'x': 2,
-              'y': 3,
-              'name': 'Point3',
-              'color': '#999'
-          },
-          {
-              'x': 3,
-              'y': 5,
-              'name': 'Point4',
-              'color': '#000'
-          }
-        ]
-
-    :param value: The value that should contain the data which will be converted into data
-      point instances.
-
-      .. note::
-
-        If ``value`` is not an iterable, it will be converted into an iterable to be
-        further de-serialized correctly.
-
-    :type value: iterable
-
-    :returns: Collection of :term:`data point` instances (descended from
-      :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`)
-    :rtype: :class:`list <python:list>` of
-      :class:`DataBase <highcharts_stock.options.series.data.base.DataBase>`-descendant
-      instances
-
-.. warning::
-
-  :term:`Technical indicators <technical indicator>` provided by
-  **Highcharts Stock for Python** do not support the ``.data`` property because
-  their data gets populated dynamically based on the series indicated in their
-  :meth:`.linked_to <highcharts_stock.options.series.base.IndicatorSeriesBase.linked_to>`
-  property.
-
-  .. seealso::
-
-    * :doc:`Using Highcharts Stock for Python </using>` > :ref:`Using Technical Indicators <using_technical_indicators>`
diff --git a/docs/using/rendering_your_visualizations/_as_jupyter.rst b/docs/using/rendering_your_visualizations/_as_jupyter.rst
index 87d8af4..af2a772 100644
--- a/docs/using/rendering_your_visualizations/_as_jupyter.rst
+++ b/docs/using/rendering_your_visualizations/_as_jupyter.rst
@@ -1,23 +1,15 @@
 .. code-block:: python
 
   from highcharts_stock.chart import Chart
-  from highcharts_stock.options.series.area import LineSeries
-  from highcharts_stock.global_options.shared_options import SharedStockOptions
-
-  my_chart = Chart(container = 'target_div',
-                   options = {
-                       'series': [
-                           LineSeries(data = [0, 5, 3, 5])
-                       ]
-                   },
-                   variable_name = 'myChart',
-                   is_stock_chart = True)
+  from highcharts_stock.global_options.shared_options import SharedOptions
+
+  my_chart = Chart(data = [0, 5, 3, 5], series_type = 'line')
 
   # Now this will render the contents of "my_chart" in your Jupyter Notebook
   my_chart.display()
 
   # You can also supply shared options to display to make sure that they are applied:
-  my_shared_options = SharedStockOptions()
+  my_shared_options = SharedOptions()
 
   # Now this will render the contents of "my_chart" in your Jupyter Notebook, but applying
   # your shared options
@@ -25,7 +17,7 @@
 
 .. collapse:: Method Signature
 
-  .. method:: display(self, global_options = None)
+  .. method:: display(self, global_options = None, container = None, retries = 5, interval = 1000)
     :noindex:
 
     Display the chart in `Jupyter Labs <https://jupyter.org/>`__ or
@@ -36,6 +28,31 @@
     :type global_options: :class:`SharedOptions <highcharts_stock.global_options.shared_options.SharedOptions>`
       or :obj:`None <python:None>`
 
+    :param container: The ID to apply to the HTML container when rendered in Jupyter Labs. Defaults to
+      :obj:`None <python:None>`, which applies the :meth:`.container <highcharts_stock.chart.Chart.container>`
+      property if set, and ``'highcharts_target_div'`` if not set.
+
+      .. note::
+
+        Highcharts for Python will append a 6-character random string to the value of ``container``
+        to ensure uniqueness of the chart's container when rendering in a Jupyter Notebook/Labs context. The
+        :class:`Chart <highcharts_stock.chart.Chart>` instance will retain the mapping between container and the
+        random string so long as the instance exists, thus allowing you to easily update the rendered chart by
+        calling the :meth:`.display() <highcharts_stock.chart.Chart.display>` method again.
+
+        If you wish to create a new chart from the instance that does not update the existing chart, then you can do
+        so by specifying a new ``container`` value.
+
+    :type container: :class:`str <python:str>` or :obj:`None <python:None>`
+
+    :param retries: The number of times to retry rendering the chart. Used to avoid race conditions with the 
+      Highcharts script. Defaults to 5.
+    :type retries: :class:`int <python:int>`
+
+    :param interval: The number of milliseconds to wait between retrying rendering the chart. Defaults to 1000 (1
+      second).
+    :type interval: :class:`int <python:int>`
+
     :raises HighchartsDependencyError: if
       `ipython <https://ipython.readthedocs.io/en/stable/>`__ is not available in the
       runtime environment
diff --git a/docs/using/rendering_your_visualizations/_as_web_content.rst b/docs/using/rendering_your_visualizations/_as_web_content.rst
index fcd5f84..20cffe0 100644
--- a/docs/using/rendering_your_visualizations/_as_web_content.rst
+++ b/docs/using/rendering_your_visualizations/_as_web_content.rst
@@ -1,42 +1,5 @@
 .. tabs::
 
-  .. tab:: as a Highcharts Stock Chart
-
-    .. code-block:: python
-
-      from highcharts_stock.chart import Chart
-      from highcharts_stock.options.series.hlc import HLCSeries
-
-      my_chart = Chart(container = 'target_div',
-                       options = {
-                           'series': [
-                               HLCSeries(data = [
-                                   [2, 0, 4],
-                                   [4, 2, 8],
-                                   [3, 9, 3]
-                               ])
-                           ]
-                       },
-                       variable_name = 'myChart',
-                       is_stock_chart = True)
-
-      as_js_literal = my_chart.to_js_literal()
-
-      # This will produce a string equivalent to:
-      #
-      # document.addEventListener('DOMContentLoaded', function() {
-      #   const myChart = Highcharts.stockChart('target_div', {
-      #      series: {
-      #          type: 'hlc',
-      #          data: [
-      #            [2, 0, 4],
-      #            [4, 2, 8],
-      #            [3, 9, 3]
-      #          ]
-      #      }
-      #   });
-      # });
-
   .. tab:: as a Highcharts JS Chart
 
     .. code-block:: python
@@ -44,13 +7,7 @@
       from highcharts_stock.chart import Chart
       from highcharts_stock.options.series.area import LineSeries
 
-      my_chart = Chart(container = 'target_div',
-                       options = {
-                           'series': [
-                               LineSeries(data = [0, 5, 3, 5])
-                           ]
-                       },
-                       variable_name = 'myChart')
+      my_chart = Chart(data = [0, 5, 3, 5], series_type = 'line')
 
       as_js_literal = my_chart.to_js_literal()
 
diff --git a/docs/using/shared_options/_with_dict.rst b/docs/using/shared_options/_with_dict.rst
index 267fa09..9ff2431 100644
--- a/docs/using/shared_options/_with_dict.rst
+++ b/docs/using/shared_options/_with_dict.rst
@@ -1,6 +1,6 @@
 If you are hoping to configure a simple set of options, one of the fastest ways to do
 so in your Python code is to instantiate your
-:class:`SharedStockOptions <highcharts_stock.global_options.shared_options.SharedStockOptions>`
+:class:`SharedOptions <highcharts_stock.global_options.shared_options.SharedOptions>`
 instance from a simple :class:`dict <python:dict>`:
 
   .. code-block:: python
@@ -14,12 +14,12 @@ instance from a simple :class:`dict <python:dict>`:
         }
     }
 
-    my_shared_options = SharedStockOptions.from_dict(as_dict)
+    my_shared_options = SharedOptions.from_dict(as_dict)
 
     js_code_snippet = my_shared_options.to_js_literal()
 
   .. tip::
 
     This method is particularly helpful and easy to maintain if you are only using a
-    *very* small subset of the `Highcharts <https://www.highcharts.com>`__
+    *very* small subset of the `Highcharts JS <https://www.highcharts.com>`__
     configuration options.
diff --git a/docs/using/shared_options/_with_js_literal.rst b/docs/using/shared_options/_with_js_literal.rst
index adf3825..adc3310 100644
--- a/docs/using/shared_options/_with_js_literal.rst
+++ b/docs/using/shared_options/_with_js_literal.rst
@@ -4,7 +4,7 @@
 
   We really like to use JS literals written as separate files in our codebase. It
   makes it super simple to instantiate a
-  :class:`SharedStockOptions <highcharts_stock.global_options.shared_options.SharedStockOptions>`
+  :class:`SharedOptions <highcharts_stock.global_options.shared_options.SharedOptions>`
   instance with one method call.
 
 Let's say you organize your files like so:
@@ -51,17 +51,17 @@ visualizations. This file might look something like this:
     :language: javascript
 
 Now with this file, you can easily create a
-:class:`SharedStockOptions <highcharts_stock.global_options.shared_options.SharedStockOptions>`
+:class:`SharedOptions <highcharts_stock.global_options.shared_options.SharedOptions>`
 instance by executing:
 
   .. code-block:: python
 
-    from highcharts_stock.highcharts import SharedStockOptions
+    from highcharts_stock.highcharts import SharedOptions
 
-    my_shared_options = SharedStockOptions.from_js_literal('../../project_resources/highcharts_config/shared_options.js')
+    my_shared_options = SharedOptions.from_js_literal('../../project_resources/highcharts_config/shared_options.js')
 
 And that's it! Now you have a
-:class:`SharedStockOptions <highcharts_stock.global_options.shared_options.SharedStockOptions>`
+:class:`SharedOptions <highcharts_stock.global_options.shared_options.SharedOptions>`
 instance that can be used to apply your configuration standards to all of your charts.
 You can do that by delivering its JavaScript output to your front-end by calling:
 
diff --git a/docs/using/shared_options/_with_json.rst b/docs/using/shared_options/_with_json.rst
index 6678a85..e1a3d3c 100644
--- a/docs/using/shared_options/_with_json.rst
+++ b/docs/using/shared_options/_with_json.rst
@@ -41,9 +41,9 @@ You can leverage shared options that read from
 
   .. code-block:: python
 
-    from highcharts_stock.highcharts import SharedStockOptions
+    from highcharts_stock.highcharts import SharedOptions
 
-    my_shared_options = SharedStockOptions.from_js_literal(
+    my_shared_options = SharedOptions.from_js_literal(
         '../../project_resources/highcharts_config/shared_options.json'
     )
 
diff --git a/docs/using/templates/_with_copy.rst b/docs/using/templates/_with_copy.rst
index 3d993bd..3676fbd 100644
--- a/docs/using/templates/_with_copy.rst
+++ b/docs/using/templates/_with_copy.rst
@@ -1,10 +1,10 @@
-If you have an existing **Highcharts Stock for Python** instance, you can copy its
+If you have an existing **Highcharts for Python** instance, you can copy its
 properties to another object using the ``.copy()`` method. You can therefore set up
 one chart, and then copy its properties to other chart objects with one method call.
 
   .. code-block:: python
 
-    type_1_chart = Chart.from_js_literal('../../project_resources/highcharts_config/hlc-template-01.js')
+    type_1_chart = Chart.from_js_literal('../../project_resources/highcharts_config/line-template-01.js')
     other_chart = type_1_chart.copy(other_chart, overwrite = True)
 
   .. tip::
@@ -19,7 +19,7 @@ one chart, and then copy its properties to other chart objects with one method c
 
         other_chart = Chart()
         other_chart.add_series(
-          HLCSeries.from_csv('../../project_resources/data_files/data-file-02.csv')
+          LineSeries.from_csv('../../project_resources/data_files/data-file-02.csv')
         )
 
         other_chart = type_1_chart.copy(other_chart,
diff --git a/docs/visualizations.rst b/docs/visualizations.rst
index cdb3a94..cb2c84f 100644
--- a/docs/visualizations.rst
+++ b/docs/visualizations.rst
@@ -51,89 +51,89 @@ to visualize your data.
             :alt: Arc Diagram Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.arcdiagram.ArcDiagramOptions`
+          :class:`highcharts_stock.options.plot_options.arcdiagram.ArcDiagramOptions`
 
-          :class:`highcharts_core.options.series.arcdiagram.ArcDiagramSeries`
+          :class:`highcharts_stock.options.series.arcdiagram.ArcDiagramSeries`
       * - **Area**
         - .. figure:: _static/area-example.png
             :alt: Area Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.area.AreaOptions`
+          :class:`highcharts_stock.options.plot_options.area.AreaOptions`
 
-          :class:`highcharts_core.options.series.area.AreaSeries`
+          :class:`highcharts_stock.options.series.area.AreaSeries`
       * - **Area Range**
         - .. figure:: _static/arearange-example.png
             :alt: Area Range Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.area.AreaRangeOptions`
+          :class:`highcharts_stock.options.plot_options.area.AreaRangeOptions`
 
-          :class:`highcharts_core.options.series.area.AreaRangeSeries`
+          :class:`highcharts_stock.options.series.area.AreaRangeSeries`
       * - **Area Spline**
         - .. figure:: _static/areaspline-example.png
             :alt: Area Spline Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.area.AreaSplineOptions`
+          :class:`highcharts_stock.options.plot_options.area.AreaSplineOptions`
 
-          :class:`highcharts_core.options.series.area.AreaSplineSeries`
+          :class:`highcharts_stock.options.series.area.AreaSplineSeries`
       * - **Area Spline Range**
         - .. figure:: _static/areasplinerange-example.png
             :alt: Area Spline Range Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.area.AreaSplineRangeOptions`
+          :class:`highcharts_stock.options.plot_options.area.AreaSplineRangeOptions`
 
-          :class:`highcharts_core.options.series.area.AreaSplineRangeSeries`
+          :class:`highcharts_stock.options.series.area.AreaSplineRangeSeries`
       * - **Bar**
         - .. figure:: _static/bar-example.png
             :alt: Bar Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.BarOptions`
+          :class:`highcharts_stock.options.plot_options.bar.BarOptions`
 
-          :class:`highcharts_core.options.series.bar.BarSeries`
+          :class:`highcharts_stock.options.series.bar.BarSeries`
       * - **Bell Curve**
         - .. figure:: _static/bellcurve-example.png
             :alt: BellCurve Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bellcurve.BellCurveOptions`
+          :class:`highcharts_stock.options.plot_options.bellcurve.BellCurveOptions`
 
-          :class:`highcharts_core.options.series.bellcurve.BellCurveSeries`
+          :class:`highcharts_stock.options.series.bellcurve.BellCurveSeries`
       * - **Box Plot**
         - .. figure:: _static/boxplot-example.png
             :alt: BoxPlot Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.boxplot.BoxPlotOptions`
+          :class:`highcharts_stock.options.plot_options.boxplot.BoxPlotOptions`
 
-          :class:`highcharts_core.options.series.boxplot.BoxPlotSeries`
+          :class:`highcharts_stock.options.series.boxplot.BoxPlotSeries`
       * - **Bubble**
         - .. figure:: _static/bubble-example.png
             :alt: Bubble Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bubble.BubbleOptions`
+          :class:`highcharts_stock.options.plot_options.bubble.BubbleOptions`
 
-          :class:`highcharts_core.options.series.bubble.BubbleSeries`
+          :class:`highcharts_stock.options.series.bubble.BubbleSeries`
       * - **Bullet**
         - .. figure:: _static/bullet-example.png
             :alt: Bullet Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bullet.BulletOptions`
+          :class:`highcharts_stock.options.plot_options.bullet.BulletOptions`
 
-          :class:`highcharts_core.options.series.bullet.BulletSeries`
+          :class:`highcharts_stock.options.series.bullet.BulletSeries`
       * - **Column**
         - .. figure:: _static/column-example.png
             :alt: Column Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.ColumnOptions`
+          :class:`highcharts_stock.options.plot_options.bar.ColumnOptions`
 
-          :class:`highcharts_core.options.series.bar.ColumnSeries`
+          :class:`highcharts_stock.options.series.bar.ColumnSeries`
       * - **Column Pyramid**
         - .. tabs::
 
@@ -155,9 +155,9 @@ to visualize your data.
                 :alt: Stacked and Inverted Column Pyramid Example Chart
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.ColumnPyramidOptions`
+          :class:`highcharts_stock.options.plot_options.bar.ColumnPyramidOptions`
 
-          :class:`highcharts_core.options.series.bar.ColumnPyramidSeries`
+          :class:`highcharts_stock.options.series.bar.ColumnPyramidSeries`
       * - **Column Range**
         - .. tabs::
 
@@ -173,73 +173,73 @@ to visualize your data.
                 :alt: Inverted Column Range Example Chart
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.ColumnRangeOptions`
+          :class:`highcharts_stock.options.plot_options.bar.ColumnRangeOptions`
 
-          :class:`highcharts_core.options.series.bar.ColumnRangeSeries`
+          :class:`highcharts_stock.options.series.bar.ColumnRangeSeries`
       * - **Dependency Wheel**
         - .. figure:: _static/dependencywheel-example.png
             :alt: DependencyWheel Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.dependencywheel.DependencyWheelOptions`
+          :class:`highcharts_stock.options.plot_options.dependencywheel.DependencyWheelOptions`
 
-          :class:`highcharts_core.options.series.dependencywheel.DependencyWheelSeries`
+          :class:`highcharts_stock.options.series.dependencywheel.DependencyWheelSeries`
       * - **Dumbbell**
         - .. figure:: _static/dumbbell-example.png
             :alt: Dumbbell Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.dumbbell.DumbbellOptions`
+          :class:`highcharts_stock.options.plot_options.dumbbell.DumbbellOptions`
 
-          :class:`highcharts_core.options.series.dumbbell.DumbbellSeries`
+          :class:`highcharts_stock.options.series.dumbbell.DumbbellSeries`
       * - **Error Bar**
         - .. figure:: _static/errorbar-example.png
             :alt: ErrorBar Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.boxplot.ErrorBarOptions`
+          :class:`highcharts_stock.options.plot_options.boxplot.ErrorBarOptions`
 
-          :class:`highcharts_core.options.series.boxplot.ErrorBarSeries`
+          :class:`highcharts_stock.options.series.boxplot.ErrorBarSeries`
       * - **Funnel**
         - .. figure:: _static/funnel-example.png
             :alt: Funnel Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.funnel.FunnelOptions`
+          :class:`highcharts_stock.options.plot_options.funnel.FunnelOptions`
 
-          :class:`highcharts_core.options.series.funnel.FunnelSeries`
+          :class:`highcharts_stock.options.series.funnel.FunnelSeries`
       * - **Funnel 3D**
         - .. figure:: _static/funnel_3d-example.png
             :alt: Funnel3D Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.funnel.Funnel3DOptions`
+          :class:`highcharts_stock.options.plot_options.funnel.Funnel3DOptions`
 
-          :class:`highcharts_core.options.series.funnel.Funnel3DSeries`
+          :class:`highcharts_stock.options.series.funnel.Funnel3DSeries`
       * - **Gauge**
         - .. figure:: _static/gauge-example.png
             :alt: Gauge Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.gauge.GaugeOptions`
+          :class:`highcharts_stock.options.plot_options.gauge.GaugeOptions`
 
-          :class:`highcharts_core.options.series.gauge.GaugeSeries`
+          :class:`highcharts_stock.options.series.gauge.GaugeSeries`
       * - **Heatmap**
         - .. figure:: _static/heatmap-example.png
             :alt: Heatmap Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.heatmap.HeatmapOptions`
+          :class:`highcharts_stock.options.plot_options.heatmap.HeatmapOptions`
 
-          :class:`highcharts_core.options.series.heatmap.HeatmapSeries`
+          :class:`highcharts_stock.options.series.heatmap.HeatmapSeries`
       * - **Histogram**
         - .. figure:: _static/histogram-example.png
             :alt: Histogram Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.histogram.HistogramOptions`
+          :class:`highcharts_stock.options.plot_options.histogram.HistogramOptions`
 
-          :class:`highcharts_core.options.series.histogram.HistogramSeries`
+          :class:`highcharts_stock.options.series.histogram.HistogramSeries`
       * - **Item**
         - .. tabs::
 
@@ -261,33 +261,33 @@ to visualize your data.
                 :alt: Item Example Chart with Symbols
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.item.ItemOptions`
+          :class:`highcharts_stock.options.plot_options.item.ItemOptions`
 
-          :class:`highcharts_core.options.series.item.ItemSeries`
+          :class:`highcharts_stock.options.series.item.ItemSeries`
       * - **Line**
         - .. figure:: _static/line-example.png
             :alt: Line Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.area.LineOptions`
+          :class:`highcharts_stock.options.plot_options.area.LineOptions`
 
-          :class:`highcharts_core.options.series.area.LineSeries`
+          :class:`highcharts_stock.options.series.area.LineSeries`
       * - **Lollipop**
         - .. figure:: _static/lollipop-example.png
             :alt: Lollipop Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.dumbbell.LollipopOptions`
+          :class:`highcharts_stock.options.plot_options.dumbbell.LollipopOptions`
 
-          :class:`highcharts_core.options.series.dumbbell.LollipopSeries`
+          :class:`highcharts_stock.options.series.dumbbell.LollipopSeries`
       * - **Network Graph**
         - .. figure:: _static/networkgraph-example.png
             :alt: Network Graph Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.networkgraph.NetworkGraphOptions`
+          :class:`highcharts_stock.options.plot_options.networkgraph.NetworkGraphOptions`
 
-          :class:`highcharts_core.options.series.networkgraph.NetworkGraphSeries`
+          :class:`highcharts_stock.options.series.networkgraph.NetworkGraphSeries`
       * - **Organization**
         - .. tabs::
 
@@ -303,9 +303,9 @@ to visualize your data.
                 :alt: Horizontal Organization Example Chart
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.organization.OrganizationOptions`
+          :class:`highcharts_stock.options.plot_options.organization.OrganizationOptions`
 
-          :class:`highcharts_core.options.series.organization.OrganizationSeries`
+          :class:`highcharts_stock.options.series.organization.OrganizationSeries`
       * - **Packed Bubble**
         - .. tabs::
 
@@ -321,25 +321,25 @@ to visualize your data.
                 :alt: Split Packed Bubble Example Chart
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.packedbubble.PackedBubbleOptions`
+          :class:`highcharts_stock.options.plot_options.packedbubble.PackedBubbleOptions`
 
-          :class:`highcharts_core.options.series.packedbubble.PackedBubbleSeries`
+          :class:`highcharts_stock.options.series.packedbubble.PackedBubbleSeries`
       * - **Pareto**
         - .. figure:: _static/pareto-example.png
             :alt: Pareto Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.pareto.ParetoOptions`
+          :class:`highcharts_stock.options.plot_options.pareto.ParetoOptions`
 
-          :class:`highcharts_core.options.series.pareto.ParetoSeries`
+          :class:`highcharts_stock.options.series.pareto.ParetoSeries`
       * - **Pictorial**
         - .. figure:: _static/pictorial-example.png
             :alt: Pictorial Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.pictorial.PictorialOptions`
+          :class:`highcharts_stock.options.plot_options.pictorial.PictorialOptions`
 
-          :class:`highcharts_core.options.series.pictorial.PictorialSeries`
+          :class:`highcharts_stock.options.series.pictorial.PictorialSeries`
       * - **Pie**
         - .. tabs::
 
@@ -355,33 +355,33 @@ to visualize your data.
                 :alt: Donut Example Chart
                 :align: center
 
-          :class:`highcharts_core.options.plot_options.pie.PieOptions`
+          :class:`highcharts_stock.options.plot_options.pie.PieOptions`
 
-          :class:`highcharts_core.options.series.pie.PieSeries`
+          :class:`highcharts_stock.options.series.pie.PieSeries`
       * - **Polygon**
         - .. figure:: _static/polygon-example.png
             :alt: Polygon Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.polygon.PolygonOptions`
+          :class:`highcharts_stock.options.plot_options.polygon.PolygonOptions`
 
-          :class:`highcharts_core.options.series.polygon.PolygonSeries`
+          :class:`highcharts_stock.options.series.polygon.PolygonSeries`
       * - **Pyramid**
         - .. figure:: _static/pyramid-example.png
             :alt: Pyramid Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.pyramid.PyramidOptions`
+          :class:`highcharts_stock.options.plot_options.pyramid.PyramidOptions`
 
-          :class:`highcharts_core.options.series.pyramid.PyramidSeries`
+          :class:`highcharts_stock.options.series.pyramid.PyramidSeries`
       * - **Pyramid 3D**
         - .. figure:: _static/pyramid_3d-example.png
             :alt: Pyramid 3D Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.pyramid.Pyramid3DOptions`
+          :class:`highcharts_stock.options.plot_options.pyramid.Pyramid3DOptions`
 
-          :class:`highcharts_core.options.series.pyramid.Pyramid3DSeries`
+          :class:`highcharts_stock.options.series.pyramid.Pyramid3DSeries`
       * - **Sankey**
         - .. tabs::
 
@@ -403,65 +403,65 @@ to visualize your data.
                 :alt: Sankey Example Chart with Outgoing Links
                 :align: center
 
-          :class:`highcharts_core.options.plot_options.sankey.SankeyOptions`
+          :class:`highcharts_stock.options.plot_options.sankey.SankeyOptions`
 
-          :class:`highcharts_core.options.series.sankey.SankeySeries`
+          :class:`highcharts_stock.options.series.sankey.SankeySeries`
       * - **Scatter**
         - .. figure:: _static/scatter-example.png
             :alt: Scatter Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.scatter.ScatterOptions`
+          :class:`highcharts_stock.options.plot_options.scatter.ScatterOptions`
 
-          :class:`highcharts_core.options.series.scatter.ScatterSeries`
+          :class:`highcharts_stock.options.series.scatter.ScatterSeries`
       * - **Scatter 3D**
         - .. figure:: _static/scatter_3d-example.png
             :alt: Scatter 3D Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.scatter.Scatter3DOptions`
+          :class:`highcharts_stock.options.plot_options.scatter.Scatter3DOptions`
 
-          :class:`highcharts_core.options.series.scatter.Scatter3DSeries`
+          :class:`highcharts_stock.options.series.scatter.Scatter3DSeries`
       * - **Solid Gauge**
         - .. figure:: _static/solidgauge-example.png
             :alt: SolidGauge Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.gauge.SolidGaugeOptions`
+          :class:`highcharts_stock.options.plot_options.gauge.SolidGaugeOptions`
 
-          :class:`highcharts_core.options.series.gauge.SolidGaugeSeries`
+          :class:`highcharts_stock.options.series.gauge.SolidGaugeSeries`
       * - **Spline**
         - .. figure:: _static/spline-example.png
             :alt: Spline Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.spline.SplineOptions`
+          :class:`highcharts_stock.options.plot_options.spline.SplineOptions`
 
-          :class:`highcharts_core.options.series.spline.SplineSeries`
+          :class:`highcharts_stock.options.series.spline.SplineSeries`
       * - **Stream Graph**
         - .. figure:: _static/streamgraph-example.png
             :alt: StreamGraph Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.area.StreamGraphOptions`
+          :class:`highcharts_stock.options.plot_options.area.StreamGraphOptions`
 
-          :class:`highcharts_core.options.series.area.StreamGraphSeries`
+          :class:`highcharts_stock.options.series.area.StreamGraphSeries`
       * - **Sunburst**
         - .. figure:: _static/sunburst-example.png
             :alt: Sunburst Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.sunburst.SunburstOptions`
+          :class:`highcharts_stock.options.plot_options.sunburst.SunburstOptions`
 
-          :class:`highcharts_core.options.series.sunburst.SunburstSeries`
+          :class:`highcharts_stock.options.series.sunburst.SunburstSeries`
       * - **Tilemap**
         - .. figure:: _static/tilemap-example.png
             :alt: Tilemap Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.heatmap.TilemapOptions`
+          :class:`highcharts_stock.options.plot_options.heatmap.TilemapOptions`
 
-          :class:`highcharts_core.options.series.heatmap.TilemapSeries`
+          :class:`highcharts_stock.options.series.heatmap.TilemapSeries`
       * - **Timeline**
         - .. tabs::
 
@@ -483,41 +483,41 @@ to visualize your data.
                 :alt: Timeline Example Chart with Datetime Axis
                 :align: center
 
-          :class:`highcharts_core.options.plot_options.timeline.TimelineOptions`
+          :class:`highcharts_stock.options.plot_options.timeline.TimelineOptions`
 
-          :class:`highcharts_core.options.series.timeline.TimelineSeries`
+          :class:`highcharts_stock.options.series.timeline.TimelineSeries`
       * - **Treegraph**
         - .. figure:: _static/treegraph-example.png
             :alt: Treegraph Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.treegraph.TreegraphOptions`
+          :class:`highcharts_stock.options.plot_options.treegraph.TreegraphOptions`
 
-          :class:`highcharts_core.options.series.treegraph.TreegraphSeries`
+          :class:`highcharts_stock.options.series.treegraph.TreegraphSeries`
       * - **Treemap**
         - .. figure:: _static/treemap-example.png
             :alt: Treemap Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.treemap.TreemapOptions`
+          :class:`highcharts_stock.options.plot_options.treemap.TreemapOptions`
 
-          :class:`highcharts_core.options.series.treemap.TreemapSeries`
+          :class:`highcharts_stock.options.series.treemap.TreemapSeries`
       * - **Variable Pie**
         - .. figure:: _static/variablepie-example.png
             :alt: VariablePie Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.pie.VariablePieOptions`
+          :class:`highcharts_stock.options.plot_options.pie.VariablePieOptions`
 
-          :class:`highcharts_core.options.series.pie.VariablePieSeries`
+          :class:`highcharts_stock.options.series.pie.VariablePieSeries`
       * - **Vector**
         - .. figure:: _static/vector-example.png
             :alt: Vector Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.vector.VectorOptions`
+          :class:`highcharts_stock.options.plot_options.vector.VectorOptions`
 
-          :class:`highcharts_core.options.series.vector.VectorSeries`
+          :class:`highcharts_stock.options.series.vector.VectorSeries`
       * - **Venn**
         - .. tabs::
 
@@ -533,9 +533,9 @@ to visualize your data.
                 :alt: Euler Example Chart
                 :align: center
 
-          :class:`highcharts_core.options.plot_options.venn.VennOptions`
+          :class:`highcharts_stock.options.plot_options.venn.VennOptions`
 
-          :class:`highcharts_core.options.series.venn.VennSeries`
+          :class:`highcharts_stock.options.series.venn.VennSeries`
       * - **Waterfall**
         - .. tabs::
 
@@ -557,25 +557,25 @@ to visualize your data.
                 :alt: Waterfall Example Chart
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.WaterfallOptions`
+          :class:`highcharts_stock.options.plot_options.bar.WaterfallOptions`
 
-          :class:`highcharts_core.options.series.bar.WaterfallSeries`
+          :class:`highcharts_stock.options.series.bar.WaterfallSeries`
       * - **Wind Barb**
         - .. figure:: _static/windbarb-example.png
             :alt: WindBarb Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.WindBarbOptions`
+          :class:`highcharts_stock.options.plot_options.bar.WindBarbOptions`
 
-          :class:`highcharts_core.options.series.bar.WindBarbSeries`
+          :class:`highcharts_stock.options.series.bar.WindBarbSeries`
       * - **Wordcloud**
         - .. figure:: _static/wordcloud-example.png
             :alt: Wordcloud Example Chart
             :width: 100%
 
-          :class:`highcharts_core.options.plot_options.wordcloud.WordcloudOptions`
+          :class:`highcharts_stock.options.plot_options.wordcloud.WordcloudOptions`
 
-          :class:`highcharts_core.options.series.wordcloud.WordcloudSeries`
+          :class:`highcharts_stock.options.series.wordcloud.WordcloudSeries`
       * - **X-Range**
         - .. tabs::
 
@@ -591,9 +591,9 @@ to visualize your data.
                 :alt: Inverted X-Range Example Chart
                 :width: 100%
 
-          :class:`highcharts_core.options.plot_options.bar.XRangeOptions`
+          :class:`highcharts_stock.options.plot_options.bar.XRangeOptions`
 
-          :class:`highcharts_core.options.series.bar.XRangeSeries`
+          :class:`highcharts_stock.options.series.bar.XRangeSeries`
 
   .. tab:: Stock
 
diff --git a/highcharts_stock/__version__.py b/highcharts_stock/__version__.py
index f94ba41..bdbb22b 100644
--- a/highcharts_stock/__version__.py
+++ b/highcharts_stock/__version__.py
@@ -1,1 +1,1 @@
-__version__ = '1.3.0'
\ No newline at end of file
+__version__ = '1.4.0'
\ No newline at end of file
diff --git a/highcharts_stock/ai.py b/highcharts_stock/ai.py
new file mode 100644
index 0000000..ae1d928
--- /dev/null
+++ b/highcharts_stock/ai.py
@@ -0,0 +1,1 @@
+from highcharts_core.ai import * # noqa: F401, F403
diff --git a/highcharts_stock/chart.py b/highcharts_stock/chart.py
index f827180..710cd3b 100644
--- a/highcharts_stock/chart.py
+++ b/highcharts_stock/chart.py
@@ -1,4 +1,5 @@
 from typing import Optional, List
+from collections import UserDict
 
 from validator_collection import validators, checkers
 
@@ -174,7 +175,8 @@ def _get_kwargs_from_dict(cls, as_dict):
 
     def to_js_literal(self,
                       filename = None,
-                      encoding = 'utf-8') -> Optional[str]:
+                      encoding = 'utf-8',
+                      careful_validation = False) -> Optional[str]:
         """Return the object represented as a :class:`str <python:str>` containing the
         JavaScript object literal.
 
@@ -186,6 +188,18 @@ def to_js_literal(self,
           to ``'utf-8'``.
         :type encoding: :class:`str <python:str>`
 
+        :param careful_validation: if ``True``, will carefully validate JavaScript values
+          along the way using the
+          `esprima-python <https://github.com/Kronuz/esprima-python>`__ library. Defaults
+          to ``False``.
+        
+          .. warning::
+        
+            Setting this value to ``True`` will significantly degrade serialization
+            performance, though it may prove useful for debugging purposes.
+
+        :type careful_validation: :class:`bool <python:bool>`
+
         .. note::
 
           If :meth:`variable_name <Chart.variable_name>` is set, will render a string as
@@ -207,7 +221,9 @@ def to_js_literal(self,
         as_dict = {}
         for key in untrimmed:
             item = untrimmed[key]
-            serialized = serialize_to_js_literal(item, encoding = encoding)
+            serialized = serialize_to_js_literal(item,
+                                                 encoding = encoding,
+                                                 careful_validation = careful_validation)
             if serialized is not None:
                 as_dict[key] = serialized
 
@@ -222,16 +238,20 @@ def to_js_literal(self,
 
         options_as_str = ''
         if self.options:
-            options_as_str = self.options.to_js_literal(encoding = encoding)
-            options_as_str = f"""{options_as_str}"""
+            options_as_str = "{}".format(
+                self.options.to_js_literal(encoding = encoding,
+                                           careful_validation = careful_validation)
+            )
         else:
             options_as_str = """{}"""
         signature_elements += 1
 
         callback_as_str = ''
         if self.callback:
-            callback_as_str = self.callback.to_js_literal(encoding = encoding)
-            callback_as_str = f"""{callback_as_str}"""
+            callback_as_str = "{}".format(
+                self.callback.to_js_literal(encoding = encoding,
+                                            careful_validation = careful_validation)
+            )
             signature_elements += 1
 
         signature = """Highcharts.chart("""
@@ -454,6 +474,111 @@ def add_indicator(self,
         series_list.append(indicator)
         self.options.series = series_list
 
+    @classmethod
+    def from_array(cls,
+                   value,
+                   series_type = 'line',
+                   series_kwargs = None,
+                   options_kwargs = None,
+                   chart_kwargs = None,
+                   is_stock_chart = False):
+        """Create a :class:`Chart <highcharts_core.chart.Chart>` instance with
+        one series populated from the array contained in ``value``.
+        
+        .. seealso::
+
+          The specific structure of the expected array is highly dependent on the type of data
+          point that the series needs, which itself is dependent on the series type itself.
+
+          Please review the detailed :ref:`series documentation <series_documentation>` for
+          series type-specific details of relevant array structures.
+
+        :param value: The array to use to populate the series data.
+        :type value: iterable
+        
+        :param series_type: Indicates the series type that should be created from the array
+          data. Defaults to ``'line'``.
+        :type series_type: :class:`str <python:str>`
+        
+        :param series_kwargs: An optional :class:`dict <python:dict>` containing keyword
+          arguments that should be used when instantiating the series instance. Defaults
+          to :obj:`None <python:None>`.
+
+          .. warning::
+
+            If ``series_kwargs`` contains a ``data`` key, its value will be *overwritten*.
+            The ``data`` value will be created from ``df`` instead.
+
+        :type series_kwargs: :class:`dict <python:dict>`
+
+        :param options_kwargs: An optional :class:`dict <python:dict>` containing keyword
+          arguments that should be used when instantiating the :class:`HighchartsOptions`
+          instance. Defaults to :obj:`None <python:None>`.
+
+          .. warning::
+
+            If ``options_kwargs`` contains a ``series`` key, the ``series`` value will be
+            *overwritten*. The ``series`` value will be created from the data in ``df``.
+
+        :type options_kwargs: :class:`dict <python:dict>` or :obj:`None <python:None>`
+
+        :param chart_kwargs: An optional :class:`dict <python:dict>` containing keyword
+          arguments that should be used when instantiating the :class:`Chart` instance.
+          Defaults to :obj:`None <python:None>`.
+
+          .. warning::
+
+            If ``chart_kwargs`` contains an ``options`` key, ``options`` will be
+            *overwritten*. The ``options`` value will be created from the
+            ``options_kwargs`` and the data in ``df`` instead.
+
+        :type chart_kwargs: :class:`dict <python:dict>` or :obj:`None <python:None>`
+
+        :param is_stock_chart: if ``True``, enforces the use of 
+          :class:`HighchartsStockOptions <highcharts_stock.options.HighchartsStockOptions>`.
+          If ``False``, applies 
+          :class:`HighchartsOptions <highcharts_stock.options.HighchartsOptions>`.
+          Defaults to ``False``.
+
+          .. note::
+
+            The value given to this argument will override any values specified in
+            ``chart_kwargs``.
+
+        :type is_stock_chart: :class:`bool <python:bool>`
+        
+        :returns: A :class:`Chart <highcharts_core.chart.Chart>` instance with its
+          data populated from the data in ``value``.
+        :rtype: :class:`Chart <highcharts_core.chart.Chart>`
+        
+        """
+        series_type = validators.string(series_type, allow_empty = False)
+        series_type = series_type.lower()
+        if series_type not in SERIES_CLASSES:
+            raise errors.HighchartsValueError(f'series_type expects a valid Highcharts '
+                                              f'series type. Received: {series_type}')
+
+        series_kwargs = validators.dict(series_kwargs, allow_empty = True) or {}
+        options_kwargs = validators.dict(options_kwargs, allow_empty = True) or {}
+        chart_kwargs = validators.dict(chart_kwargs, allow_empty = True) or {}
+
+        series_cls = SERIES_CLASSES.get(series_type, None)
+
+        series = series_cls.from_array(value, series_kwargs = series_kwargs)
+
+        options_kwargs['series'] = [series]
+        chart_kwargs['is_stock_chart'] = is_stock_chart
+
+        if is_stock_chart:
+            options = HighchartsStockOptions(**options_kwargs)
+        else:
+            options = HighchartsOptions(**options_kwargs)
+
+        instance = cls(**chart_kwargs)
+        instance.options = options
+
+        return instance
+
     @classmethod
     def from_series(cls, *series, kwargs = None):
         """Creates a new :class:`Chart <highcharts_core.chart.Chart>` instance populated
@@ -531,8 +656,8 @@ def _get_options_obj(series_type, options_kwargs):
     @classmethod
     def from_csv(cls,
                  as_string_or_file,
-                 property_column_map,
-                 series_type,
+                 property_column_map = None,
+                 series_type = 'line',
                  has_header_row = True,
                  series_kwargs = None,
                  options_kwargs = None,
@@ -544,7 +669,9 @@ def from_csv(cls,
                  wrap_all_strings = False,
                  double_wrapper_character_when_nested = False,
                  escape_character = "\\",
-                 is_stock_chart = False):
+                 is_stock_chart = False,
+                 series_in_rows = False,
+                 **kwargs):
         """Create a new :class:`Chart <highcharts_core.chart.Chart>` instance with
         data populated from a CSV string or file.
 
@@ -588,7 +715,8 @@ def from_csv(cls,
           data point property should be set to which CSV column. The keys in the
           :class:`dict <python:dict>` should correspond to properties in the data point
           class, while the value can either be a numerical index (starting with 0) or a
-          :class:`str <python:str>` indicating the label for the CSV column.
+          :class:`str <python:str>` indicating the label for the CSV column. Defaults to
+          :obj:`None <python:None>`.
 
           .. warning::
 
@@ -600,7 +728,7 @@ def from_csv(cls,
         :type property_column_map: :class:`dict <python:dict>`
 
         :param series_type: Indicates the series type that should be created from the CSV
-          data.
+          data. Defaults to ``'line'``.
         :type series_type: :class:`str <python:str>`
 
         :param has_header_row: If ``True``, indicates that the first row of
@@ -688,11 +816,19 @@ def from_csv(cls,
           wrapped in quotation marks. Defaults to ``\\\\`` (which is Python for ``'\\'``,
           which is Python's native escape character).
         :type escape_character: :class:`str <python:str>`
-
-        :param is_stock_chart: If ``True``, indicates that the chart should be
-          instantiated as a **Highcharts Stock for Python** chart. Defaults to ``False``.
+        
+        :param is_stock_chart: If ``True``, indicates that the chart should be instantiated
+          as a **Highcharts Stock for Python** chart. Defaults to ``False``.
         :type is_stock_chart: :class:`bool <python:bool>`
 
+        :param series_in_rows: if ``True``, will attempt a streamlined cartesian series
+          with x-values taken from column names, y-values taken from row values, and
+          the series name taken from the row index. Defaults to ``False``.
+        :type series_in_rows: :class:`bool <python:bool>`
+
+        :param **kwargs: Remaining keyword arguments will be attempted on the resulting
+          :term:`series` instance and the data points it contains.
+
         :returns: A :class:`Chart <highcharts_core.chart.Chart>` instance with its
           data populated from the CSV data.
         :rtype: :class:`Chart <highcharts_core.chart.Chart>`
@@ -701,25 +837,53 @@ def from_csv(cls,
           CSV columns by their label, but the CSV data does not contain a header row
 
         """
+        series_type = validators.string(series_type, allow_empty = False)
+        series_type = series_type.lower()
+        if series_type not in SERIES_CLASSES:
+            raise errors.HighchartsValueError(f'series_type expects a valid Highcharts '
+                                              f'series type. Received: {series_type}')
+
+        options_kwargs = validators.dict(options_kwargs, allow_empty = True) or {}
         chart_kwargs = validators.dict(chart_kwargs, allow_empty = True) or {}
 
-        options = cls._get_options_obj(series_type, options_kwargs)
+        chart_kwargs['is_stock_chart'] = bool(is_stock_chart)
 
         series_cls = SERIES_CLASSES.get(series_type, None)
 
-        series = series_cls.from_csv(as_string_or_file,
-                                     property_column_map,
-                                     has_header_row = has_header_row,
-                                     series_kwargs = series_kwargs,
-                                     delimiter = delimiter,
-                                     null_text = null_text,
-                                     wrapper_character = wrapper_character,
-                                     line_terminator = line_terminator,
-                                     wrap_all_strings = wrap_all_strings,
-                                     double_wrapper_character_when_nested = double_wrapper_character_when_nested,
-                                     escape_character = escape_character)
+        if series_in_rows:
+            series = series_cls.from_csv_in_rows(
+                as_string_or_file,
+                has_header_row = has_header_row,
+                series_kwargs = series_kwargs,
+                delimiter = delimiter,
+                null_text = null_text,
+                wrapper_character = wrapper_character,
+                line_terminator = line_terminator,
+                wrap_all_strings = wrap_all_strings,
+                double_wrapper_character_when_nested = double_wrapper_character_when_nested,
+                escape_character = escape_character,
+                **kwargs
+            )
+        else:
+            series = series_cls.from_csv(as_string_or_file,
+                                         property_column_map = property_column_map,
+                                         has_header_row = has_header_row,
+                                         series_kwargs = series_kwargs,
+                                         delimiter = delimiter,
+                                         null_text = null_text,
+                                         wrapper_character = wrapper_character,
+                                         line_terminator = line_terminator,
+                                         wrap_all_strings = wrap_all_strings,
+                                         double_wrapper_character_when_nested = double_wrapper_character_when_nested,
+                                         escape_character = escape_character,
+                                         **kwargs)
+
+        if not isinstance(series, list):
+            series = [series]
 
-        options.series = [series]
+        options_kwargs['series'] = series
+
+        options = cls._get_options_obj(series_type, options_kwargs)
 
         instance = cls(**chart_kwargs)
         instance.options = options
@@ -729,28 +893,32 @@ def from_csv(cls,
     @classmethod
     def from_pandas(cls,
                     df,
-                    property_map,
-                    series_type,
+                    property_map = None,
+                    series_type = 'line',
                     series_kwargs = None,
                     options_kwargs = None,
-                    chart_kwargs = None):
+                    chart_kwargs = None,
+                    series_in_rows = False,
+                    series_index = None,
+                    **kwargs):
         """Create a :class:`Chart <highcharts_core.chart.Chart>` instance whose
         data is populated from a `pandas <https://pandas.pydata.org/>`_
-        :class:`DataFrame <pandas:DataFrame>`.
+        :class:`DataFrame <pandas:pandas.DataFrame>`.
 
-        :param df: The :class:`DataFrame <pandas:DataFrame>` from which data should be
+        :param df: The :class:`DataFrame <pandas:pandas.DataFrame>` from which data should be
           loaded.
-        :type df: :class:`DataFrame <pandas:DataFrame>`
+        :type df: :class:`DataFrame <pandas:pandas.DataFrame>`
 
         :param property_map: A :class:`dict <python:dict>` used to indicate which
           data point property should be set to which column in ``df``. The keys in the
           :class:`dict <python:dict>` should correspond to properties in the data point
           class, while the value should indicate the label for the
-          :class:`DataFrame <pandas:DataFrame>` column.
-        :type property_map: :class:`dict <python:dict>`
+          :class:`DataFrame <pandas:pandas.DataFrame>` column. Defaults to 
+          :obj:`None <python:None>`.
+        :type property_map: :class:`dict <python:dict>` or :obj:`None <python:None>`
 
         :param series_type: Indicates the series type that should be created from the data
-          in ``df``.
+          in ``df``. Defaults to ``'line'``.
         :type series_type: :class:`str <python:str>`
 
         :param series_kwargs: An optional :class:`dict <python:dict>` containing keyword
@@ -786,6 +954,23 @@ def from_pandas(cls,
             ``options_kwargs`` and the data in ``df`` instead.
 
         :type chart_kwargs: :class:`dict <python:dict>` or :obj:`None <python:None>`
+        
+        :param series_in_rows: if ``True``, will attempt a streamlined cartesian series
+          with x-values taken from column names, y-values taken from row values, and
+          the series name taken from the row index. Defaults to 
+          :obj:`False <python:False>`.
+        :type series_in_rows: :class:`bool <python:bool>`
+
+        :param series_index: If supplied, generate the chart with the series that 
+          Highcharts for Python generated from ``df`` at the ``series_index`` position. 
+          Defaults to :obj:`None <python:None>`, which includes all series generated 
+          from ``df`` on the chart.
+
+        :type series_index: :class:`int <python:int>`, slice, or 
+          :obj:`None <python:None>`
+
+        :param **kwargs: Additional keyword arguments that are - in turn - propagated to 
+          the series created from the ``df``.
 
         :returns: A :class:`Chart <highcharts_core.chart.Chart>` instance with its
           data populated from the data in ``df``.
@@ -796,18 +981,50 @@ def from_pandas(cls,
         :raises HighchartsDependencyError: if `pandas <https://pandas.pydata.org/>`_ is
           not available in the runtime environment
         """
-        chart_kwargs = validators.dict(chart_kwargs, allow_empty = True) or {}
+        if not series_type:
+            raise errors.HighchartsValueError('series_type cannot be empty')
+        series_type = str(series_type).lower()
+        if series_type not in SERIES_CLASSES:
+            raise errors.HighchartsValueError(f'series_type expects a valid Highcharts '
+                                              f'series type. Received: {series_type}')
 
-        options = cls._get_options_obj(series_type, options_kwargs)
+        if not isinstance(options_kwargs, (dict, UserDict, type(None))):
+            raise errors.HighchartsValueError(f'options_kwarts expects a dict. '
+                                              f'Received: {options_kwargs.__class__.__name__}')
+        if not options_kwargs:
+            options_kwargs = {}
+
+        if not isinstance(chart_kwargs, (dict, UserDict, type(None))):
+            raise errors.HighchartsValueError(f'chart_kwargs expects a dict. '
+                                              f'Received: {chart_kwargs.__class__.__name__}')
+        if not chart_kwargs:
+            chart_kwargs = {}
+
+        if not isinstance(kwargs, (dict, UserDict, type(None))):
+            raise errors.HighchartsValueError(f'kwargs expects a dict. '
+                                              f'Received: {kwargs.__class__.__name__}')
+        if not kwargs:
+            kwargs = {}
 
         series_cls = SERIES_CLASSES.get(series_type, None)
 
-        series = series_cls.from_pandas(df,
-                                        property_map,
-                                        series_kwargs)
+        if series_in_rows:
+            series = series_cls.from_pandas_in_rows(df,
+                                                    series_kwargs = series_kwargs,
+                                                    series_index = series_index,
+                                                    **kwargs)
+        else:
+            series = series_cls.from_pandas(df,
+                                            property_map = property_map,
+                                            series_kwargs = series_kwargs,
+                                            series_index = series_index,
+                                            **kwargs)
 
-        options = HighchartsOptions(**options_kwargs)
-        options.series = [series]
+        if isinstance(series, series_cls):
+            series = [series]
+
+        options_kwargs['series'] = series
+        options = cls._get_options_obj(series_type, options_kwargs)
 
         instance = cls(**chart_kwargs)
         instance.options = options
diff --git a/highcharts_stock/global_options/shared_options.py b/highcharts_stock/global_options/shared_options.py
index faaac25..a1915d2 100644
--- a/highcharts_stock/global_options/shared_options.py
+++ b/highcharts_stock/global_options/shared_options.py
@@ -16,7 +16,8 @@ class SharedStockOptions(HighchartsStockOptions):
 
     def to_js_literal(self,
                       filename = None,
-                      encoding = 'utf-8') -> Optional[str]:
+                      encoding = 'utf-8',
+                      careful_validation = False) -> Optional[str]:
         """Return the object represented as a :class:`str <python:str>` containing the
         JavaScript object literal.
 
@@ -28,6 +29,18 @@ def to_js_literal(self,
           to ``'utf-8'``.
         :type encoding: :class:`str <python:str>`
 
+        :param careful_validation: if ``True``, will carefully validate JavaScript values
+          along the way using the
+          `esprima-python <https://github.com/Kronuz/esprima-python>`__ library. Defaults
+          to ``False``.
+        
+          .. warning::
+        
+            Setting this value to ``True`` will significantly degrade serialization
+            performance, though it may prove useful for debugging purposes.
+
+        :type careful_validation: :class:`bool <python:bool>`
+
         .. note::
 
           Returns a JavaScript string which applies the Highcharts global options. The
@@ -40,7 +53,8 @@ def to_js_literal(self,
         :rtype: :class:`str <python:str>`
         """
         prefix = 'Highcharts.setOptions('
-        options_body = super().to_js_literal(encoding = encoding)
+        options_body = super().to_js_literal(encoding = encoding,
+                                             careful_validation = careful_validation)
 
         as_str = prefix + options_body + ');'
 
diff --git a/highcharts_stock/options/series/arcdiagram.py b/highcharts_stock/options/series/arcdiagram.py
index 84e73a1..09725e4 100644
--- a/highcharts_stock/options/series/arcdiagram.py
+++ b/highcharts_stock/options/series/arcdiagram.py
@@ -8,8 +8,8 @@
 
 from highcharts_stock import errors
 from highcharts_stock.decorators import class_sensitive
-from highcharts_stock.options.series.data.arcdiagram import ArcDiagramData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.arcdiagram import ArcDiagramData, ArcDiagramDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 from highcharts_stock.utility_classes.nodes import NodeOptions
 
 
@@ -37,19 +37,22 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[ArcDiagramData]]:
+    def data(self) -> Optional[List[ArcDiagramData] | ArcDiagramDataCollection]:
         """The collection of data points for the series. Defaults to
         :obj:`None <python:None>`.
 
         :rtype: :class:`list <python:list>` of :class:`ArcDiagramData` or
-          :obj:`None <python:None>`
+          :class:`ArcDiagramDataCollection <highcharts_core.options.series.data.arcdiagram.ArcDiagramDataCollection>`
+          or :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
-    @class_sensitive(ArcDiagramData, force_iterable = True)
     def data(self, value):
-        self._data = value
+        if not is_ndarray(value) and not value:
+            self._data = None
+        else:
+            self._data = ArcDiagramData.from_array(value)
 
     @property
     def link_weight(self) -> Optional[int | float | Decimal]:
@@ -209,3 +212,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parent_as_dict[key]
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return ArcDiagramDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return ArcDiagramData
diff --git a/highcharts_stock/options/series/area.py b/highcharts_stock/options/series/area.py
index a8ff065..3f75866 100644
--- a/highcharts_stock/options/series/area.py
+++ b/highcharts_stock/options/series/area.py
@@ -3,9 +3,9 @@
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.area import AreaOptions, LineOptions
 
-from highcharts_stock.options.series.data.cartesian import CartesianData
-from highcharts_stock.options.series.data.range import RangeData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.cartesian import CartesianData, CartesianDataCollection
+from highcharts_stock.options.series.data.range import RangeData, RangeDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 
 class AreaSeries(SeriesBase, AreaOptions):
@@ -21,7 +21,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CartesianData]]:
+    def data(self) -> Optional[List[CartesianData] | CartesianDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -84,13 +84,14 @@ def data(self) -> Optional[List[CartesianData]]:
             A one-dimensional collection of :class:`CartesianData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianData` or
+          :class:`CartesianDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianData.from_array(value)
@@ -201,6 +202,23 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianData
 
 class AreaRangeSeries(AreaSeries):
     """Options to apply to an AreaRange series. The area range series
@@ -214,7 +232,7 @@ class AreaRangeSeries(AreaSeries):
     """
 
     @property
-    def data(self) -> Optional[List[RangeData]]:
+    def data(self) -> Optional[List[RangeData] | RangeDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -283,17 +301,36 @@ def data(self) -> Optional[List[RangeData]]:
             A one-dimensional collection of :class:`RangeData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`RangeData` or
+          :class:`RangeDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = RangeData.from_array(value)
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return RangeDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return RangeData
+
 
 class AreaSplineSeries(AreaSeries):
     """Options to apply to an AreaSpline series. The area spline series
diff --git a/highcharts_stock/options/series/bar.py b/highcharts_stock/options/series/bar.py
index 49bca05..8ad694c 100644
--- a/highcharts_stock/options/series/bar.py
+++ b/highcharts_stock/options/series/bar.py
@@ -1,12 +1,19 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.cartesian import CartesianData, Cartesian3DData
+from highcharts_stock.options.series.data.cartesian import (CartesianData,
+                                                            CartesianDataCollection,
+                                                            Cartesian3DData,
+                                                            Cartesian3DDataCollection)
 from highcharts_stock.options.series.data.bar import (BarData,
+                                                      BarDataCollection,
                                                       WaterfallData,
+                                                      WaterfallDataCollection,
                                                       WindBarbData,
-                                                      XRangeData)
-from highcharts_stock.options.series.data.range import RangeData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+                                                      WindBarbDataCollection,
+                                                      XRangeData,
+                                                      XRangeDataCollection)
+from highcharts_stock.options.series.data.range import RangeData, RangeDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.plot_options.bar import (BaseBarOptions,
                                                        BarOptions,
@@ -24,7 +31,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[BarData]]:
+    def data(self) -> Optional[List[BarData] | BarDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -87,13 +94,14 @@ def data(self) -> Optional[List[BarData]]:
             A one-dimensional collection of :class:`BarData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`BarData` or
+          :class:`BarDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = BarData.from_array(value)
@@ -216,6 +224,23 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return BarDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return BarData
 
 class BarSeries(BaseBarSeries, BarOptions):
     """Options to apply to a Bar series.
@@ -401,7 +426,7 @@ class ColumnPyramidSeries(ColumnSeries):
 
     """
     @property
-    def data(self) -> Optional[List[CartesianData]]:
+    def data(self) -> Optional[List[CartesianData] | CartesianDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -464,17 +489,35 @@ def data(self) -> Optional[List[CartesianData]]:
             A one-dimensional collection of :class:`CartesianData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianData` or
+          :class:`CartesianDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianData.from_array(value)
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianData
 
 class ColumnRangeSeries(ColumnSeries):
     """Options to apply to a Column Range series.
@@ -501,8 +544,9 @@ class ColumnRangeSeries(ColumnSeries):
           :align: center
 
     """
+
     @property
-    def data(self) -> Optional[List[RangeData]]:
+    def data(self) -> Optional[List[RangeData] | RangeDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -565,17 +609,35 @@ def data(self) -> Optional[List[RangeData]]:
             A one-dimensional collection of :class:`RangeData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`RangeData` or
+          :class:`RangeDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = RangeData.from_array(value)
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return RangeDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return RangeData
 
 class CylinderSeries(BarSeries):
     """Options to apply to a Cylinder series.
@@ -618,8 +680,9 @@ class VariwideSeries(BaseBarSeries):
           :align: center
 
     """
+
     @property
-    def data(self) -> Optional[List[Cartesian3DData]]:
+    def data(self) -> Optional[List[Cartesian3DData] | Cartesian3DDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -687,17 +750,36 @@ def data(self) -> Optional[List[Cartesian3DData]]:
             A one-dimensional collection of :class:`Cartesian3DData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`Cartesian3DData` or
+          :class:`Cartesian3DDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = Cartesian3DData.from_array(value)
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return Cartesian3DDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return Cartesian3DData
+
 
 class WaterfallSeries(ColumnSeries, WaterfallOptions):
     """Options to apply to a Waterfall series.
@@ -731,7 +813,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[WaterfallData]]:
+    def data(self) -> Optional[List[WaterfallData] | WaterfallDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -794,13 +876,14 @@ def data(self) -> Optional[List[WaterfallData]]:
             A one-dimensional collection of :class:`WaterfallData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`WaterfallData` or
+          :class:`WaterfallDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = WaterfallData.from_array(value)
@@ -930,6 +1013,23 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return WaterfallDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return WaterfallData
 
 class WindBarbSeries(BarSeries, WindBarbOptions):
     """Options to apply to a Wind Barb series.
@@ -948,7 +1048,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[WindBarbData]]:
+    def data(self) -> Optional[List[WindBarbData] | WindBarbDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -1013,13 +1113,14 @@ def data(self) -> Optional[List[WindBarbData]]:
             A one-dimensional collection of :class:`WindBarbData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`WindBarbData` or
+          :class:`WindBarbDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = WindBarbData.from_array(value)
@@ -1148,6 +1249,23 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return WindBarbDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return WindBarbData
 
 class XRangeSeries(BaseBarSeries, XRangeOptions):
     """Options to apply to an X-Range series.
@@ -1175,7 +1293,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[XRangeData]]:
+    def data(self) -> Optional[List[XRangeData] | XRangeDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -1184,13 +1302,14 @@ def data(self) -> Optional[List[XRangeData]]:
         :class:`dict <python:dict>` instances that can be coerced to :class:`XRangeData`.
 
         :rtype: :class:`list <python:list>` of :class:`XRangeData` or
+          :class:`XRangeDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = XRangeData.from_array(value)
@@ -1315,3 +1434,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return XRangeData
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return XRangeDataCollection
diff --git a/highcharts_stock/options/series/base.py b/highcharts_stock/options/series/base.py
index 93d9423..fdff80e 100644
--- a/highcharts_stock/options/series/base.py
+++ b/highcharts_stock/options/series/base.py
@@ -122,7 +122,65 @@ def get_indicator(self, indicator_name, indicator_kwargs = None):
 
 class SeriesBase(OriginalSeriesBase, IndicatorFactoryMixin):
     """Generic base class for specific series configurations."""
-    pass
+
+    def convert_to(self, series_type):
+        """Creates a new series of ``series_type`` from the current series.
+        
+        :param series_type: The series type that should be returned.
+        :type series_type: :class:`str <python:str>` or
+          :class:`SeriesBase <highcharts_core.options.series.base.SeriesBase>`-descended
+          
+        .. warning::
+        
+          This operation is *not* guaranteed to work converting between all series 
+          types. This is because some series types have different properties, different
+          logic / functionality for their properties, and may have entirely different
+          data requirements.
+          
+          In general, this method is expected to be *lossy* in nature, meaning that when
+          the series can be converted "close enough" the series will be converted. 
+          However, if the target ``series_type`` does not support certain properties set
+          on the original instance, then those settings will *not* be propagated to the 
+          new series.
+          
+          In certain cases, this method may raise an 
+          :exc:`HighchartsSeriesConversionError <highcharts_core.errors.HighchartsSeriesConversionError>`
+          if the method is unable to convert (even losing some data) the original into 
+          ``series_type``.
+        
+        :returns: A new series of ``series_type``, maintaining relevant properties and
+          data from the original instance.
+        :rtype: ``series_type``
+          :class:`SeriesBase <highcharts_core.options.series.base.SeriesBase>` descendant
+          
+        :raises HighchartsSeriesConversionError: if unable to convert (even after losing 
+          some data) the original instance into an instance of ``series_type``.
+        :raises HighchartsValueError: if ``series_type`` is not a recognized series type
+
+        """
+        from highcharts_stock.options.series.series_generator import SERIES_CLASSES
+        if isinstance(series_type, str):
+            series_type = series_type.lower()
+            if series_type not in SERIES_CLASSES:
+                raise errors.HighchartsValueError(f'series_type expects a valid Highcharts '
+                                                  f'series type. Received: {series_type}')
+            series_type_name = series_type
+            series_type = SERIES_CLASSES.get(series_type)
+        elif not issubclass(series_type, OriginalSeriesBase):
+            raise errors.HighchartsValueError(f'series_type expects a valid Highcharts '
+                                              f'series type. Received: {series_type}')
+        else:
+            series_type_name = series_type.__name__
+
+        as_js_literal = self.to_js_literal()
+        try:
+            target = series_type.from_js_literal(as_js_literal)
+        except (ValueError, TypeError):
+            raise errors.HighchartsSeriesConversionError(f'Unable to convert '
+                                                         f'{self.__class__.__name__} instance '
+                                                         f'to {series_type_name}')
+        
+        return target
 
 
 class IndicatorSeriesBase(SeriesOptions, IndicatorFactoryMixin):
diff --git a/highcharts_stock/options/series/bellcurve.py b/highcharts_stock/options/series/bellcurve.py
index ea5be7f..99a1597 100644
--- a/highcharts_stock/options/series/bellcurve.py
+++ b/highcharts_stock/options/series/bellcurve.py
@@ -184,3 +184,4 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parents_as_dict[key]
 
         return untrimmed
+
diff --git a/highcharts_stock/options/series/boxplot.py b/highcharts_stock/options/series/boxplot.py
index 0101d6a..c43cd80 100644
--- a/highcharts_stock/options/series/boxplot.py
+++ b/highcharts_stock/options/series/boxplot.py
@@ -1,8 +1,8 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.boxplot import BoxPlotData
-from highcharts_stock.options.series.data.range import RangeData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.boxplot import BoxPlotData, BoxPlotDataCollection
+from highcharts_stock.options.series.data.range import RangeData, RangeDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.bar import BarSeries
 from highcharts_stock.options.plot_options.boxplot import BoxPlotOptions
@@ -30,7 +30,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[BoxPlotData]]:
+    def data(self) -> Optional[List[BoxPlotData] | BoxPlotDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -105,13 +105,14 @@ def data(self) -> Optional[List[BoxPlotData]]:
             A one-dimensional collection of :class:`BoxPlotData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`BoxPlotData` or
+          :class:`BoxPlotDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = BoxPlotData.from_array(value)
@@ -250,6 +251,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return BoxPlotDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return BoxPlotData
+
 
 class ErrorBarSeries(BoxPlotSeries):
     """Options to configure an Error Bar series.
@@ -264,7 +283,7 @@ class ErrorBarSeries(BoxPlotSeries):
     """
 
     @property
-    def data(self) -> Optional[List[RangeData]]:
+    def data(self) -> Optional[List[RangeData] | RangeDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -333,13 +352,32 @@ def data(self) -> Optional[List[RangeData]]:
             A one-dimensional collection of :class:`RangeData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`RangeData` or
+          :class:`RangeDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = RangeData.from_array(value)
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return RangeDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return RangeData
diff --git a/highcharts_stock/options/series/bubble.py b/highcharts_stock/options/series/bubble.py
index 485c01a..ad94939 100644
--- a/highcharts_stock/options/series/bubble.py
+++ b/highcharts_stock/options/series/bubble.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.cartesian import Cartesian3DData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.cartesian import Cartesian3DData, Cartesian3DDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.bubble import BubbleOptions
@@ -25,7 +25,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[Cartesian3DData]]:
+    def data(self) -> Optional[List[Cartesian3DData] | Cartesian3DDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -93,13 +93,14 @@ def data(self) -> Optional[List[Cartesian3DData]]:
             A one-dimensional collection of :class:`Cartesian3DData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`Cartesian3DData` or
+          :class:`Cartesian3DDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = Cartesian3DData.from_array(value)
@@ -214,3 +215,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return Cartesian3DDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return Cartesian3DData
diff --git a/highcharts_stock/options/series/bullet.py b/highcharts_stock/options/series/bullet.py
index 38f0a39..a2f381e 100644
--- a/highcharts_stock/options/series/bullet.py
+++ b/highcharts_stock/options/series/bullet.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.bullet import BulletData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.bullet import BulletData, BulletDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.bar import BarSeries
 from highcharts_stock.options.plot_options.bullet import BulletOptions
@@ -24,7 +24,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[BulletData]]:
+    def data(self) -> Optional[List[BulletData] | BulletDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -93,13 +93,14 @@ def data(self) -> Optional[List[BulletData]]:
             A one-dimensional collection of :class:`BulletData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`BulletData` or
+          :class:`BulletDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = BulletData.from_array(value)
@@ -229,3 +230,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return BulletDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return BulletData
diff --git a/highcharts_stock/options/series/candlestick.py b/highcharts_stock/options/series/candlestick.py
index 07225ca..e5f40db 100644
--- a/highcharts_stock/options/series/candlestick.py
+++ b/highcharts_stock/options/series/candlestick.py
@@ -1,9 +1,9 @@
 from typing import Optional, List
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.candlestick import CandlestickOptions
-from highcharts_stock.options.series.data.candlestick import CandlestickData
+from highcharts_stock.options.series.data.candlestick import CandlestickData, CandlestickDataCollection
 
 
 class CandlestickSeries(SeriesBase, CandlestickOptions):
@@ -20,7 +20,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CandlestickData]]:
+    def data(self) -> Optional[List[CandlestickData] | CandlestickDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -81,13 +81,14 @@ def data(self) -> Optional[List[CandlestickData]]:
             coercable.
 
         :rtype: :class:`list <python:list>` of :class:`CandlestickData` or
+          :class:`CandlestickDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CandlestickData.from_array(value)
@@ -212,6 +213,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CandlestickDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CandlestickData
+
 
 class HollowCandlestickSeries(CandlestickSeries):
     """General options to apply to Hollow Candlestick series types. A candlestick chart is
diff --git a/highcharts_stock/options/series/data/candlestick.py b/highcharts_stock/options/series/data/candlestick.py
index b5c8161..481734e 100644
--- a/highcharts_stock/options/series/data/candlestick.py
+++ b/highcharts_stock/options/series/data/candlestick.py
@@ -1,4 +1,4 @@
-from highcharts_stock.options.series.data.hlc import OHLCData
+from highcharts_stock.options.series.data.hlc import OHLCData, OHLCDataCollection
 
 
 class CandlestickData(OHLCData):
@@ -6,4 +6,35 @@ class CandlestickData(OHLCData):
     :class:`CandlestickSeries <highcharts_core.options.series.candlestick.CandlestickSeries>`,
     featuring an x value, a high value, an open value, a low value, and a close value.
     """
-    pass
+
+    @classmethod
+    def from_ndarray(cls, value):
+        """Creates a collection of data points from a `NumPy <https://numpy.org>`__ 
+        :class:`ndarray <numpy:ndarray>` instance.
+        
+        :returns: A collection of data point values.
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+        """
+        return CandlestickDataCollection.from_ndarray(value)
+
+
+class CandlestickDataCollection(OHLCDataCollection):
+    """A collection of :class:`CandlestickData` objects.
+
+    .. note::
+    
+      When serializing to JS literals, if possible, the collection is serialized to a primitive
+      array to boost performance within Python *and* JavaScript. However, this may not always be
+      possible if data points have non-array-compliant properties configured (e.g. adjusting their 
+      style, names, identifiers, etc.). If serializing to a primitive array is not possible, the
+      results are serialized as JS literal objects.
+
+    """
+
+    @classmethod
+    def _get_data_point_class(cls):
+        """The Python class to use as the underlying data point within the Collection.
+        
+        :rtype: class object
+        """
+        return CandlestickData
diff --git a/highcharts_stock/options/series/data/collections.py b/highcharts_stock/options/series/data/collections.py
new file mode 100644
index 0000000..1c77748
--- /dev/null
+++ b/highcharts_stock/options/series/data/collections.py
@@ -0,0 +1,1 @@
+from highcharts_core.options.series.data.collections import *  # noqa: F401, F403
diff --git a/highcharts_stock/options/series/data/hlc.py b/highcharts_stock/options/series/data/hlc.py
index 950cd78..d9ee574 100644
--- a/highcharts_stock/options/series/data/hlc.py
+++ b/highcharts_stock/options/series/data/hlc.py
@@ -6,6 +6,7 @@
 from highcharts_stock import constants, errors
 from highcharts_stock.decorators import class_sensitive
 from highcharts_stock.options.series.data.base import DataBase
+from highcharts_stock.options.series.data.collections import DataPointCollection
 from highcharts_stock.options.plot_options.drag_drop import DragDropOptions
 from highcharts_stock.utility_classes.data_labels import DataLabel
 
@@ -183,7 +184,47 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         return untrimmed
 
     @classmethod
-    def from_array(cls, value):
+    def _get_supported_dimensions(cls) -> List[int]:
+        """Returns a list of the supported dimensions for the data point.
+        
+        :rtype: :class:`list <python:list>` of :class:`int <python:int>`
+        """
+        return [6, 5, 4, 3]
+
+    @classmethod
+    def from_ndarray(cls, value):
+        """Creates a collection of data points from a `NumPy <https://numpy.org>`__ 
+        :class:`ndarray <numpy:ndarray>` instance.
+        
+        :returns: A collection of data point values.
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+        """
+        return HLCDataCollection.from_ndarray(value)
+    
+    @classmethod
+    def _get_props_from_array(cls, length = None) -> List[str]:
+        """Returns a list of the property names that can be set using the
+        :meth:`.from_array() <highcharts_core.options.series.data.base.DataBase.from_array>`
+        method.
+        
+        :param length: The length of the array, which may determine the properties to 
+          parse. Defaults to :obj:`None <python:None>`, which returns the full list of 
+          properties.
+        :type length: :class:`int <python:int>` or :obj:`None <python:None>`
+        
+        :rtype: :class:`list <python:list>` of :class:`str <python:str>`
+        """
+        prop_list = {
+            None: ['x', 'open', 'high', 'low', 'close', 'name'],
+            6: ['x', 'open', 'high', 'low', 'close', 'name'],
+            5: ['x', 'open', 'high', 'low', 'close'],
+            4: ['x', 'high', 'low', 'close'],
+            3: ['high', 'low', 'close'],
+        }
+        return cls._get_props_from_array_helper(prop_list, length)
+
+    @classmethod
+    def from_list(cls, value):
         if not value:
             return []
         elif checkers.is_string(value):
@@ -245,15 +286,6 @@ def from_array(cls, value):
 
         return collection
 
-    def _get_props_from_array(self) -> List[str]:
-        """Returns a list of the property names that can be set using the
-        :meth:`.from_array() <highcharts_core.options.series.data.base.DataBase.from_array>`
-        method.
-        
-        :rtype: :class:`list <python:list>` of :class:`str <python:str>`
-        """
-        return ['x', 'high', 'low', 'close', 'name']
-
     def to_array(self, force_object = False) -> List | Dict:
         """Generate the array representation of the data point (the inversion 
         of 
@@ -303,6 +335,28 @@ def to_array(self, force_object = False) -> List | Dict:
         return [x, high, low, close]
 
 
+class HLCDataCollection(DataPointCollection):
+    """A collection of :class:`HLCData` objects.
+
+    .. note::
+    
+      When serializing to JS literals, if possible, the collection is serialized to a primitive
+      array to boost performance within Python *and* JavaScript. However, this may not always be
+      possible if data points have non-array-compliant properties configured (e.g. adjusting their 
+      style, names, identifiers, etc.). If serializing to a primitive array is not possible, the
+      results are serialized as JS literal objects.
+
+    """
+
+    @classmethod
+    def _get_data_point_class(cls):
+        """The Python class to use as the underlying data point within the Collection.
+        
+        :rtype: class object
+        """
+        return HLCData
+
+
 class OHLCData(HLCData):
     """Data point that can be visualized in a
     :class:`OHLCSeries <highcharts_stock.options.series.hlc.OHLCSeries>`,
@@ -381,7 +435,7 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         return untrimmed
 
     @classmethod
-    def from_array(cls, value):
+    def from_list(cls, value):
         if not value:
             return []
         elif checkers.is_string(value):
@@ -440,14 +494,44 @@ def from_array(cls, value):
 
         return collection
 
-    def _get_props_from_array(self) -> List[str]:
+    @classmethod
+    def _get_supported_dimensions(cls) -> List[int]:
+        """Returns a list of the supported dimensions for the data point.
+        
+        :rtype: :class:`list <python:list>` of :class:`int <python:int>`
+        """
+        return [6, 5, 4]
+
+    @classmethod
+    def from_ndarray(cls, value):
+        """Creates a collection of data points from a `NumPy <https://numpy.org>`__ 
+        :class:`ndarray <numpy:ndarray>` instance.
+        
+        :returns: A collection of data point values.
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+        """
+        return OHLCDataCollection.from_ndarray(value)
+
+    @classmethod
+    def _get_props_from_array(cls, length = None) -> List[str]:
         """Returns a list of the property names that can be set using the
         :meth:`.from_array() <highcharts_core.options.series.data.base.DataBase.from_array>`
         method.
         
+        :param length: The length of the array, which may determine the properties to 
+          parse. Defaults to :obj:`None <python:None>`, which returns the full list of 
+          properties.
+        :type length: :class:`int <python:int>` or :obj:`None <python:None>`
+        
         :rtype: :class:`list <python:list>` of :class:`str <python:str>`
         """
-        return ['x', 'open', 'high', 'low', 'close', 'name']
+        prop_list = {
+            None: ['x', 'open', 'high', 'low', 'close', 'name'],
+            6: ['x', 'open', 'high', 'low', 'close', 'name'],
+            5: ['x', 'open', 'high', 'low', 'close'],
+            4: ['x', 'high', 'low', 'close'],
+        }
+        return prop_list[length]
 
     def to_array(self, force_object = False) -> List | Dict:
         """Generate the array representation of the data point (the inversion 
@@ -501,3 +585,27 @@ def to_array(self, force_object = False) -> List | Dict:
             return [open, high, low, close]
 
         return [x, open, high, low, close]
+
+
+class OHLCDataCollection(HLCDataCollection):
+    """A collection of :class:`OHLCData` objects.
+
+    .. note::
+    
+      When serializing to JS literals, if possible, the collection is serialized to a primitive
+      array to boost performance within Python *and* JavaScript. However, this may not always be
+      possible if data points have non-array-compliant properties configured (e.g. adjusting their 
+      style, names, identifiers, etc.). If serializing to a primitive array is not possible, the
+      results are serialized as JS literal objects.
+
+    """
+
+    @classmethod
+    def _get_data_point_class(cls):
+        """The Python class to use as the underlying data point within the Collection.
+        
+        :rtype: class object
+        """
+        return OHLCData
+
+
diff --git a/highcharts_stock/options/series/dependencywheel.py b/highcharts_stock/options/series/dependencywheel.py
index a1a1d59..3cb91ff 100644
--- a/highcharts_stock/options/series/dependencywheel.py
+++ b/highcharts_stock/options/series/dependencywheel.py
@@ -1,8 +1,8 @@
 from typing import Optional, List
 
 from highcharts_stock.decorators import class_sensitive
-from highcharts_stock.options.series.data.connections import WeightedConnectionData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.connections import WeightedConnectionData, WeightedConnectionDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict,  is_ndarray
 from highcharts_stock.utility_classes.nodes import DependencyWheelNodeOptions
 
 from highcharts_stock.options.series.base import SeriesBase
@@ -29,7 +29,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[WeightedConnectionData]]:
+    def data(self) -> Optional[List[WeightedConnectionData] | WeightedConnectionDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -45,13 +45,14 @@ def data(self) -> Optional[List[WeightedConnectionData]]:
             :class:`WeightedConnectionData` instances.
 
         :rtype: :class:`list <python:list>` of :class:`WeightedConnectionData` or
+          :class:`WeightedConnectionDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = WeightedConnectionData.from_array(value)
@@ -190,3 +191,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed['nodes'] = self.nodes
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return WeightedConnectionDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return WeightedConnectionData
diff --git a/highcharts_stock/options/series/dumbbell.py b/highcharts_stock/options/series/dumbbell.py
index 54bf0e9..cecc19c 100644
--- a/highcharts_stock/options/series/dumbbell.py
+++ b/highcharts_stock/options/series/dumbbell.py
@@ -1,9 +1,9 @@
 from typing import Optional, List
 
 from highcharts_stock.decorators import class_sensitive
-from highcharts_stock.options.series.data.range import ConnectedRangeData
+from highcharts_stock.options.series.data.range import ConnectedRangeData, ConnectedRangeDataCollection
 from highcharts_stock.options.plot_options.drag_drop import HighLowDragDropOptions
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.plot_options.dumbbell import LollipopOptions, DumbbellOptions
 from highcharts_stock.options.series.base import SeriesBase
@@ -25,7 +25,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[ConnectedRangeData]]:
+    def data(self) -> Optional[List[ConnectedRangeData] | ConnectedRangeDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -94,13 +94,14 @@ def data(self) -> Optional[List[ConnectedRangeData]]:
             A one-dimensional collection of :class:`ConnectedRangeData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`ConnectedRangeData` or
+          :class:`ConnectedRangeDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = ConnectedRangeData.from_array(value)
@@ -235,6 +236,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return ConnectedRangeDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return ConnectedRangeData
+
 
 class LollipopSeries(DumbbellSeries, LollipopOptions):
     """Options to configure a Lollipop series.
diff --git a/highcharts_stock/options/series/funnel.py b/highcharts_stock/options/series/funnel.py
index 6d49d03..8f40262 100644
--- a/highcharts_stock/options/series/funnel.py
+++ b/highcharts_stock/options/series/funnel.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.single_point import SinglePointData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.single_point import SinglePointData, SinglePointDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.pie import PieSeries
 from highcharts_stock.options.plot_options.funnel import FunnelOptions, Funnel3DOptions
@@ -27,7 +27,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SinglePointData]]:
+    def data(self) -> Optional[List[SinglePointData] | SinglePointDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -51,13 +51,14 @@ def data(self) -> Optional[List[SinglePointData]]:
             A one-dimensional collection of :class:`SinglePointData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SinglePointData` or
+          :class:`SinglePointDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SinglePointData.from_array(value)
@@ -185,6 +186,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SinglePointDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SinglePointData
+
 
 class Funnel3DSeries(PieSeries, FunnelOptions):
     """Options to apply to a Variable Pie series.
@@ -207,7 +226,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SinglePointData]]:
+    def data(self) -> Optional[List[SinglePointData] | SinglePointDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -231,13 +250,14 @@ def data(self) -> Optional[List[SinglePointData]]:
             A one-dimensional collection of :class:`SinglePointData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SinglePointData` or
+          :class:`SinglePointDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SinglePointData.from_array(value)
@@ -369,3 +389,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parent_as_dict[key]
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SinglePointDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SinglePointData
diff --git a/highcharts_stock/options/series/gauge.py b/highcharts_stock/options/series/gauge.py
index 80e1985..f9e8bd9 100644
--- a/highcharts_stock/options/series/gauge.py
+++ b/highcharts_stock/options/series/gauge.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.single_point import SinglePointData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.single_point import SinglePointData, SinglePointDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.gauge import GaugeOptions, SolidGaugeOptions
@@ -23,7 +23,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SinglePointData]]:
+    def data(self) -> Optional[List[SinglePointData] | SinglePointDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -47,13 +47,14 @@ def data(self) -> Optional[List[SinglePointData]]:
             A one-dimensional collection of :class:`SinglePointData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SinglePointData` or
+          :class:`SinglePointDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SinglePointData.from_array(value)
@@ -164,6 +165,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SinglePointDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SinglePointData
+
 
 class SolidGaugeSeries(SeriesBase, SolidGaugeOptions):
     """Options to configure a Solid Gauge series.
@@ -181,7 +200,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SinglePointData]]:
+    def data(self) -> Optional[List[SinglePointData] | SinglePointDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -205,13 +224,14 @@ def data(self) -> Optional[List[SinglePointData]]:
             A one-dimensional collection of :class:`SinglePointData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SinglePointData` or
+          :class:`SinglePointData` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SinglePointData.from_array(value)
@@ -321,3 +341,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SinglePointDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SinglePointData
diff --git a/highcharts_stock/options/series/heatmap.py b/highcharts_stock/options/series/heatmap.py
index d6967d7..217fde4 100644
--- a/highcharts_stock/options/series/heatmap.py
+++ b/highcharts_stock/options/series/heatmap.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.cartesian import CartesianValueData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.cartesian import CartesianValueData, CartesianValueDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.heatmap import HeatmapOptions, TilemapOptions
@@ -27,7 +27,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CartesianValueData]]:
+    def data(self) -> Optional[List[CartesianValueData] | CartesianValueDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -95,13 +95,14 @@ def data(self) -> Optional[List[CartesianValueData]]:
             A one-dimensional collection of :class:`CartesianValueData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianValueData` or
+          :class:`CartesianValueDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianValueData.from_array(value)
@@ -214,6 +215,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianValueDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianValueData
+
 
 class TilemapSeries(HeatmapSeries, TilemapOptions):
     """General options to apply to all Tilemap series types.
diff --git a/highcharts_stock/options/series/hlc.py b/highcharts_stock/options/series/hlc.py
index 1639bf2..1282299 100644
--- a/highcharts_stock/options/series/hlc.py
+++ b/highcharts_stock/options/series/hlc.py
@@ -1,9 +1,12 @@
 from typing import Optional, List
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.hlc import HLCOptions, OHLCOptions
-from highcharts_stock.options.series.data.hlc import HLCData, OHLCData
+from highcharts_stock.options.series.data.hlc import (HLCData,
+                                                      HLCDataCollection,
+                                                      OHLCData,
+                                                      OHLCDataCollection)
 
 
 class HLCSeries(SeriesBase, HLCOptions):
@@ -20,7 +23,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[HLCData]]:
+    def data(self) -> Optional[List[HLCData] | HLCDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -123,13 +126,14 @@ def data(self) -> Optional[List[HLCData]]:
             coercable.
 
         :rtype: :class:`list <python:list>` of :class:`HLCData` or
+          :class:`HLCDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = HLCData.from_array(value)
@@ -253,6 +257,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return HLCDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return HLCData
+
 
 class OHLCSeries(SeriesBase, OHLCOptions):
     """General options to apply to a :term:`OHLC` series type. An OHLC chart is a
@@ -269,7 +291,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[OHLCData]]:
+    def data(self) -> Optional[List[OHLCData] | OHLCDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -352,13 +374,14 @@ def data(self) -> Optional[List[OHLCData]]:
             coercable.
 
         :rtype: :class:`list <python:list>` of :class:`OHLCData` or
+          :class:`OHLCDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = OHLCData.from_array(value)
@@ -481,3 +504,22 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls) or {}
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return OHLCDataCollection
+
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return OHLCData
+
diff --git a/highcharts_stock/options/series/item.py b/highcharts_stock/options/series/item.py
index 3533875..30fb97e 100644
--- a/highcharts_stock/options/series/item.py
+++ b/highcharts_stock/options/series/item.py
@@ -2,8 +2,8 @@
 
 from highcharts_stock.options.series.pie import PieSeries
 from highcharts_stock.options.plot_options.item import ItemOptions
-from highcharts_stock.options.series.data.single_point import SinglePointData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.single_point import SinglePointData, SinglePointDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 
 class ItemSeries(PieSeries, ItemOptions):
@@ -43,7 +43,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SinglePointData]]:
+    def data(self) -> Optional[List[SinglePointData] | SinglePointDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -67,13 +67,14 @@ def data(self) -> Optional[List[SinglePointData]]:
             A one-dimensional collection of :class:`SinglePointData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SinglePointData` or
+          :class:`SinglePointDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SinglePointData.from_array(value)
@@ -171,3 +172,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SinglePointDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SinglePointData
diff --git a/highcharts_stock/options/series/networkgraph.py b/highcharts_stock/options/series/networkgraph.py
index 2373ad8..ae10dd0 100644
--- a/highcharts_stock/options/series/networkgraph.py
+++ b/highcharts_stock/options/series/networkgraph.py
@@ -1,8 +1,8 @@
 from typing import Optional, List
 
 from highcharts_stock.decorators import class_sensitive
-from highcharts_stock.options.series.data.connections import ConnectionData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.connections import ConnectionData, ConnectionDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.networkgraph import NetworkGraphOptions
 
@@ -23,7 +23,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[ConnectionData]]:
+    def data(self) -> Optional[List[ConnectionData] | ConnectionDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -37,6 +37,7 @@ def data(self) -> Optional[List[ConnectionData]]:
             instances coercable to a :class:`ConnectionData` instance.
 
         :rtype: :class:`list <python:list>` of :class:`ConnectionData` or
+          :class:`ConnectionDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
@@ -150,3 +151,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return ConnectionDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return ConnectionData
diff --git a/highcharts_stock/options/series/organization.py b/highcharts_stock/options/series/organization.py
index fc8c763..3668901 100644
--- a/highcharts_stock/options/series/organization.py
+++ b/highcharts_stock/options/series/organization.py
@@ -1,9 +1,10 @@
 from typing import Optional, List
 
 from highcharts_stock.decorators import class_sensitive
-from highcharts_stock.options.series.data.connections import OutgoingWeightedConnectionData
+from highcharts_stock.options.series.data.connections import (OutgoingWeightedConnectionData,
+                                                              OutgoingWeightedConnectionDataCollection)
 from highcharts_stock.utility_classes.nodes import OrganizationNodeOptions
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.bar import BarSeries
 from highcharts_stock.options.plot_options.organization import OrganizationOptions
@@ -39,7 +40,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[OutgoingWeightedConnectionData]]:
+    def data(self) -> Optional[List[OutgoingWeightedConnectionData] | OutgoingWeightedConnectionDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -99,16 +100,17 @@ def data(self) -> Optional[List[OutgoingWeightedConnectionData]]:
 
           .. tab:: Object Collection
 
-            A one-dimensional collection of :class:`OrganizationData` objects.
+            A one-dimensional collection of :class:`OutgoingWeightedConnectionData` objects.
 
-        :rtype: :class:`list <python:list>` of :class:`OrganizationData` or
+        :rtype: :class:`list <python:list>` of :class:`OutgoingWeightedConnectionData` or
+          :class:`OutgoingWeightedConnectionDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = OutgoingWeightedConnectionData.from_array(value)
@@ -272,3 +274,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parents_as_dict[key]
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return OutgoingWeightedConnectionDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return OutgoingWeightedConnectionData
diff --git a/highcharts_stock/options/series/packedbubble.py b/highcharts_stock/options/series/packedbubble.py
index 6a6205e..e28497d 100644
--- a/highcharts_stock/options/series/packedbubble.py
+++ b/highcharts_stock/options/series/packedbubble.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.single_point import SingleValueData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.single_point import SingleValueData, SingleValueDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.networkgraph import NetworkGraphSeries
 from highcharts_stock.options.plot_options.packedbubble import PackedBubbleOptions
@@ -34,7 +34,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SingleValueData]]:
+    def data(self) -> Optional[List[SingleValueData] | SingleValueDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -59,13 +59,14 @@ def data(self) -> Optional[List[SingleValueData]]:
             A one-dimensional collection of :class:`SingleValueData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SingleValueData` or
+          :class:`SingleValueDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SingleValueData.from_array(value)
@@ -182,3 +183,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SingleValueDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SingleValueData
diff --git a/highcharts_stock/options/series/pictorial.py b/highcharts_stock/options/series/pictorial.py
index fb56b98..3aef1d5 100644
--- a/highcharts_stock/options/series/pictorial.py
+++ b/highcharts_stock/options/series/pictorial.py
@@ -1,9 +1,9 @@
 from typing import Optional, List
 
 from highcharts_stock.options.series.base import SeriesBase
-from highcharts_stock.options.series.data.cartesian import CartesianData
+from highcharts_stock.options.series.data.cartesian import CartesianData, CartesianDataCollection
 from highcharts_stock.options.plot_options.pictorial import PictorialOptions
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 from highcharts_stock.decorators import class_sensitive
 
 from highcharts_core.options.series.pictorial import PictorialPaths
@@ -29,7 +29,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CartesianData]]:
+    def data(self) -> Optional[List[CartesianData] | CartesianDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -92,13 +92,14 @@ def data(self) -> Optional[List[CartesianData]]:
             A one-dimensional collection of :class:`CartesianData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianData` or
+          :class:`CartesianDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianData.from_array(value)
@@ -235,3 +236,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parent_as_dict[key]
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianData
diff --git a/highcharts_stock/options/series/pie.py b/highcharts_stock/options/series/pie.py
index 0666830..2afe48f 100644
--- a/highcharts_stock/options/series/pie.py
+++ b/highcharts_stock/options/series/pie.py
@@ -1,7 +1,10 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.pie import PieData, VariablePieData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.pie import (PieData,
+                                                      PieDataCollection,
+                                                      VariablePieData,
+                                                      VariablePieDataCollection)
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.pie import PieOptions
@@ -33,7 +36,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[PieData]]:
+    def data(self) -> Optional[List[PieData] | PieDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -57,13 +60,14 @@ def data(self) -> Optional[List[PieData]]:
             A one-dimensional collection of :class:`PieData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`PieData` or
+          :class:`PieDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = PieData.from_array(value)
@@ -184,6 +188,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return PieDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return PieData
+
 
 class VariablePieSeries(PieSeries):
     """Options to apply to a Variable Pie series.
@@ -214,7 +236,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[VariablePieData]]:
+    def data(self) -> Optional[List[VariablePieData] | VariablePieDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -243,13 +265,14 @@ def data(self) -> Optional[List[VariablePieData]]:
             A one-dimensional collection of :class:`VariablePieData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`VariablePieData` or
+          :class:`VariablePieDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = VariablePieData.from_array(value)
@@ -360,3 +383,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parent_as_dict[key]
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return VariablePieDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return VariablePieData
diff --git a/highcharts_stock/options/series/polygon.py b/highcharts_stock/options/series/polygon.py
index d969393..1c15e2d 100644
--- a/highcharts_stock/options/series/polygon.py
+++ b/highcharts_stock/options/series/polygon.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.cartesian import CartesianData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.cartesian import CartesianData, CartesianDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.polygon import PolygonOptions
@@ -25,7 +25,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CartesianData]]:
+    def data(self) -> Optional[List[CartesianData] | CartesianDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -88,13 +88,14 @@ def data(self) -> Optional[List[CartesianData]]:
             A one-dimensional collection of :class:`CartesianData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianData` or
+          :class:`CartesianDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianData.from_array(value)
@@ -199,3 +200,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianData
diff --git a/highcharts_stock/options/series/pyramid.py b/highcharts_stock/options/series/pyramid.py
index 6aafc2e..d2f1cff 100644
--- a/highcharts_stock/options/series/pyramid.py
+++ b/highcharts_stock/options/series/pyramid.py
@@ -1,6 +1,6 @@
 from typing import Optional, List
-from highcharts_stock.options.series.data.single_point import SinglePointData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.single_point import SinglePointData, SinglePointDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.funnel import FunnelSeries
 from highcharts_stock.options.series.pie import PieSeries
@@ -41,7 +41,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SinglePointData]]:
+    def data(self) -> Optional[List[SinglePointData] | SinglePointDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -65,13 +65,14 @@ def data(self) -> Optional[List[SinglePointData]]:
             A one-dimensional collection of :class:`SinglePointData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`SinglePointData` or
+          :class:`SinglePointDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SinglePointData.from_array(value)
@@ -226,3 +227,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
             untrimmed[key] = parent_as_dict[key]
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SinglePointDataCollection
+    
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SinglePointData
diff --git a/highcharts_stock/options/series/sankey.py b/highcharts_stock/options/series/sankey.py
index 98d26a4..e6f78c3 100644
--- a/highcharts_stock/options/series/sankey.py
+++ b/highcharts_stock/options/series/sankey.py
@@ -1,7 +1,8 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.connections import OutgoingWeightedConnectionData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.connections import (OutgoingWeightedConnectionData,
+                                                              OutgoingWeightedConnectionDataCollection)
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.dependencywheel import DependencyWheelSeries
 from highcharts_stock.options.plot_options.sankey import SankeyOptions
@@ -39,7 +40,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[OutgoingWeightedConnectionData]]:
+    def data(self) -> Optional[List[OutgoingWeightedConnectionData] | OutgoingWeightedConnectionDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -55,13 +56,14 @@ def data(self) -> Optional[List[OutgoingWeightedConnectionData]]:
             :class:`OutgoingWeightedConnectionData` instances.
 
         :rtype: :class:`list <python:list>` of :class:`OutgoingWeightedConnectionData` or
+          :class:`OutgoingWeightedConnectionDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = OutgoingWeightedConnectionData.from_array(value)
@@ -184,3 +186,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed['nodes'] = self.nodes
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return OutgoingWeightedConnectionDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return OutgoingWeightedConnectionData
\ No newline at end of file
diff --git a/highcharts_stock/options/series/scatter.py b/highcharts_stock/options/series/scatter.py
index 0a1c671..ef3589b 100644
--- a/highcharts_stock/options/series/scatter.py
+++ b/highcharts_stock/options/series/scatter.py
@@ -1,7 +1,10 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.cartesian import CartesianData, Cartesian3DData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.cartesian import (CartesianData,
+                                                            CartesianDataCollection,
+                                                            Cartesian3DData,
+                                                            Cartesian3DDataCollection)
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.scatter import ScatterOptions
@@ -23,7 +26,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CartesianData]]:
+    def data(self) -> Optional[List[CartesianData] | CartesianDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -86,13 +89,13 @@ def data(self) -> Optional[List[CartesianData]]:
             A one-dimensional collection of :class:`CartesianData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianData` or
-          :obj:`None <python:None>`
+          :class:`CartesianDataCollection` or :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianData.from_array(value)
@@ -200,6 +203,24 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
 
         return untrimmed
 
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianData
+
 
 class Scatter3DSeries(ScatterSeries):
     """Options to configure a Scatter 3D series.
@@ -214,7 +235,7 @@ class Scatter3DSeries(ScatterSeries):
     """
 
     @property
-    def data(self) -> Optional[List[Cartesian3DData]]:
+    def data(self) -> Optional[List[Cartesian3DData] | Cartesian3DDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -277,13 +298,32 @@ def data(self) -> Optional[List[Cartesian3DData]]:
             A one-dimensional collection of :class:`Cartesian3DData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`Cartesian3DData` or
+          :class:`Cartesian3DDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = Cartesian3DData.from_array(value)
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return Cartesian3DDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return Cartesian3DData
diff --git a/highcharts_stock/options/series/spline.py b/highcharts_stock/options/series/spline.py
index 1b8025b..c9cbe18 100644
--- a/highcharts_stock/options/series/spline.py
+++ b/highcharts_stock/options/series/spline.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.cartesian import CartesianData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.cartesian import CartesianData, CartesianDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.spline import SplineOptions
@@ -23,7 +23,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[CartesianData]]:
+    def data(self) -> Optional[List[CartesianData] | CartesianDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -86,13 +86,14 @@ def data(self) -> Optional[List[CartesianData]]:
             A one-dimensional collection of :class:`CartesianData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`CartesianData` or
+          :class:`CartesianDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = CartesianData.from_array(value)
@@ -197,3 +198,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return CartesianDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return CartesianData
diff --git a/highcharts_stock/options/series/sunburst.py b/highcharts_stock/options/series/sunburst.py
index d95e1cb..f07f37e 100644
--- a/highcharts_stock/options/series/sunburst.py
+++ b/highcharts_stock/options/series/sunburst.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.sunburst import SunburstData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.sunburst import SunburstData, SunburstDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.sunburst import SunburstOptions
@@ -24,7 +24,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[SunburstData]]:
+    def data(self) -> Optional[List[SunburstData] | SunburstDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -39,13 +39,14 @@ def data(self) -> Optional[List[SunburstData]]:
             :class:`dict <python:dict>` instances coercable to :class:`SunburstData`
 
         :rtype: :class:`list <python:list>` of :class:`SunburstData` or
+          :class:`SunburstDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = SunburstData.from_array(value)
@@ -165,3 +166,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return SunburstDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return SunburstData
diff --git a/highcharts_stock/options/series/timeline.py b/highcharts_stock/options/series/timeline.py
index 31f5436..bd03cb3 100644
--- a/highcharts_stock/options/series/timeline.py
+++ b/highcharts_stock/options/series/timeline.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.single_point import LabeledSingleXData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.single_point import LabeledSingleXData, LabeledSingleXDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.timeline import TimelineOptions
@@ -38,7 +38,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[LabeledSingleXData]]:
+    def data(self) -> Optional[List[LabeledSingleXData] | LabeledSingleXDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -52,13 +52,14 @@ def data(self) -> Optional[List[LabeledSingleXData]]:
             A one-dimensional collection of :class:`LabeledSingleXData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`LabeledSingleXData` or
+          :class:`LabelSingleXDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = LabeledSingleXData.from_array(value)
@@ -166,3 +167,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return LabeledSingleXDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return LabeledSingleXData
diff --git a/highcharts_stock/options/series/treegraph.py b/highcharts_stock/options/series/treegraph.py
index 4d120a2..8b0d548 100644
--- a/highcharts_stock/options/series/treegraph.py
+++ b/highcharts_stock/options/series/treegraph.py
@@ -1,9 +1,9 @@
 from typing import Optional, List
 
 from highcharts_stock.options.series.base import SeriesBase
-from highcharts_stock.options.series.data.treegraph import TreegraphData
+from highcharts_stock.options.series.data.treegraph import TreegraphData, TreegraphDataCollection
 from highcharts_stock.options.plot_options.treegraph import TreegraphOptions
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 
 class TreegraphSeries(SeriesBase, TreegraphOptions):
@@ -22,7 +22,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[TreegraphData]]:
+    def data(self) -> Optional[List[TreegraphData] | TreegraphDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -51,13 +51,14 @@ def data(self) -> Optional[List[TreegraphData]]:
             :class:`dict <python:dict>` instances coercable to :class:`TreegraphData`
 
         :rtype: :class:`list <python:list>` of :class:`TreegraphData` or
+          :class:`TreegraphDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = TreegraphData.from_array(value)
@@ -137,3 +138,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls) or {}
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return TreegraphDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return TreegraphData
diff --git a/highcharts_stock/options/series/treemap.py b/highcharts_stock/options/series/treemap.py
index 77ee630..cd461ef 100644
--- a/highcharts_stock/options/series/treemap.py
+++ b/highcharts_stock/options/series/treemap.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.treemap import TreemapData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.treemap import TreemapData, TreemapDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.treemap import TreemapOptions
@@ -23,7 +23,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[TreemapData]]:
+    def data(self) -> Optional[List[TreemapData] | TreemapDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -38,13 +38,14 @@ def data(self) -> Optional[List[TreemapData]]:
             :class:`dict <python:dict>` instances coercable to :class:`TreemapData`
 
         :rtype: :class:`list <python:list>` of :class:`TreemapData` or
+          :class:`TreemapDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = TreemapData.from_array(value)
@@ -158,3 +159,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls) or {}
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return TreemapDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return TreemapData
diff --git a/highcharts_stock/options/series/vector.py b/highcharts_stock/options/series/vector.py
index 9417be4..328562e 100644
--- a/highcharts_stock/options/series/vector.py
+++ b/highcharts_stock/options/series/vector.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.vector import VectorData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.vector import VectorData, VectorDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.vector import VectorOptions
@@ -23,7 +23,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[VectorData]]:
+    def data(self) -> Optional[List[VectorData] | VectorDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -54,13 +54,14 @@ def data(self) -> Optional[List[VectorData]]:
             A one-dimensional collection of :class:`VectorData` objects.
 
         :rtype: :class:`list <python:list>` of :class:`VectorData` or
+          :class:`VectorDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = VectorData.from_array(value)
@@ -169,3 +170,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return VectorDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return VectorData
diff --git a/highcharts_stock/options/series/venn.py b/highcharts_stock/options/series/venn.py
index 9750b84..e5398b4 100644
--- a/highcharts_stock/options/series/venn.py
+++ b/highcharts_stock/options/series/venn.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.venn import VennData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.venn import VennData, VennDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.venn import VennOptions
 
@@ -35,7 +35,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[VennData]]:
+    def data(self) -> Optional[List[VennData] | VennData]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -50,13 +50,14 @@ def data(self) -> Optional[List[VennData]]:
             coercable to :class:`VennData`.
 
         :rtype: :class:`list <python:list>` of :class:`VennData` or
+          :class:`VennDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = VennData.from_array(value)
@@ -165,3 +166,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls)
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return VennDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return VennData
diff --git a/highcharts_stock/options/series/wordcloud.py b/highcharts_stock/options/series/wordcloud.py
index 929a58a..23f15ef 100644
--- a/highcharts_stock/options/series/wordcloud.py
+++ b/highcharts_stock/options/series/wordcloud.py
@@ -1,7 +1,7 @@
 from typing import Optional, List
 
-from highcharts_stock.options.series.data.wordcloud import WordcloudData
-from highcharts_stock.utility_functions import mro__to_untrimmed_dict
+from highcharts_stock.options.series.data.wordcloud import WordcloudData, WordcloudDataCollection
+from highcharts_stock.utility_functions import mro__to_untrimmed_dict, is_ndarray
 from highcharts_stock.options.series.base import SeriesBase
 from highcharts_stock.options.plot_options.wordcloud import WordcloudOptions
 
@@ -22,7 +22,7 @@ def __init__(self, **kwargs):
         super().__init__(**kwargs)
 
     @property
-    def data(self) -> Optional[List[WordcloudData]]:
+    def data(self) -> Optional[List[WordcloudData] | WordcloudDataCollection]:
         """Collection of data that represents the series. Defaults to
         :obj:`None <python:None>`.
 
@@ -37,13 +37,14 @@ def data(self) -> Optional[List[WordcloudData]]:
             coercable to :class:`WordcloudData`.
 
         :rtype: :class:`list <python:list>` of :class:`WordcloudData` or
+          :class:`WordcloudDataCollection` or
           :obj:`None <python:None>`
         """
         return self._data
 
     @data.setter
     def data(self, value):
-        if not value:
+        if not is_ndarray(value) and not value:
             self._data = None
         else:
             self._data = WordcloudData.from_array(value)
@@ -166,3 +167,21 @@ def _to_untrimmed_dict(self, in_cls = None) -> dict:
         untrimmed = mro__to_untrimmed_dict(self, in_cls = in_cls) or {}
 
         return untrimmed
+
+    @classmethod
+    def _data_collection_class(cls):
+        """Returns the class object used for the data collection.
+        
+        :rtype: :class:`DataPointCollection <highcharts_core.options.series.data.collections.DataPointCollection>`
+          descendent
+        """
+        return WordcloudDataCollection
+      
+    @classmethod
+    def _data_point_class(cls):
+        """Returns the class object used for individual data points.
+        
+        :rtype: :class:`DataBase <highcharts_core.options.series.data.base.DataBase>` 
+          descendent
+        """
+        return WordcloudData
diff --git a/pyproject.toml b/pyproject.toml
index e2b3d98..42194a1 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -59,7 +59,7 @@ classifiers = [
 
 requires-python = ">= 3.10"
 dependencies = [
-    "highcharts-core>=1.3.0",
+    "highcharts-core>=1.4.0",
     "esprima>=4.0.1",
     "validator-collection>=1.5.0",
     "requests>=2.31.0"
@@ -93,13 +93,19 @@ dev = [
     "IPython>=8.10.0",
     "pyspark>=3.3.0",
     "pandas>=1.3.3",
-    "orjson>=3.7.7"
+    "orjson>=3.7.7",
+    "anthropic>=0.3.11",
+    "dill>=0.3.7",
+    "openai>=0.28.0"
 ]
 soft = [
     "IPython>=8.10.0",
     "pyspark>=3.3.0",
     "pandas>=1.3.3",
-    "orjson>=3.7.7"
+    "orjson>=3.7.7",
+    "anthropic>=0.3.11",
+    "dill>=0.3.7",
+    "openai>=0.28.0"
 ]
 docs = [
     "Sphinx==6.1.3",
diff --git a/requirements.dev.txt b/requirements.dev.txt
index 76daf00..56c9d61 100644
--- a/requirements.dev.txt
+++ b/requirements.dev.txt
@@ -10,6 +10,8 @@ sphinx-toolbox==3.4.0
 sphinx-tabs==3.4.1
 tox==4.4.6
 requests==2.31.0
-urllib3==1.26.9
 validator-collection==1.5.0
-highcharts-core>=1.3.0
\ No newline at end of file
+anthropic==0.3.11
+dill==0.3.7
+openai==0.28.0
+highcharts-core>=1.4.0
\ No newline at end of file
diff --git a/requirements.travis.txt b/requirements.travis.txt
index 0510ae5..75b301f 100644
--- a/requirements.travis.txt
+++ b/requirements.travis.txt
@@ -12,6 +12,5 @@ sphinx-toolbox==3.4.0
 sphinx-tabs==3.4.1
 tox==4.4.6
 requests==2.31.0
-urllib3==1.26.9
 validator-collection==1.5.0
-highcharts-core>=1.3.0
\ No newline at end of file
+highcharts-core>=1.4.0
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index 2d05ab9..4f14775 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
 esprima==4.0.1
 requests==2.31.0
 validator-collection==1.5.0
-highcharts-core>=1.3.0
\ No newline at end of file
+highcharts-core>=1.4.0
\ No newline at end of file


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
index 6020b67..6236e17 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -40,6 +40,18 @@ def pytest_addoption(parser):
                      help=("pyspark: set to 'false' to disable tests of pyspark-related"
                            " functionality, or 'true' to enable those tests. Defaults to"
                            " 'false'"))
+    parser.addoption("--openai",
+                     action="store",
+                     default="none",
+                     help=("openai: The API key to use to authenticate against OpenAI."))
+    parser.addoption('--disable-ai',
+                     action='store',
+                     default='true',
+                     help=('disable-ai: set to "false" to enable tests of the AI'))
+    parser.addoption('--pandas',
+                     action = 'store',
+                     default = os.getenv('ENABLE_PANDAS', 'true'),
+                     help=('pandas: set to "false" to disable tests of pandas-related'))
 
 
 def pytest_runtest_makereport(item, call):
diff --git a/tests/fixtures.py b/tests/fixtures.py
index 9b09cdc..610eea8 100644
--- a/tests/fixtures.py
+++ b/tests/fixtures.py
@@ -13,6 +13,11 @@
 from collections import UserDict
 
 import pytest
+try:
+    import numpy as np
+    HAS_NUMPY = True
+except ImportError:
+    HAS_NUMPY = False
 
 from validator_collection import checkers, validators
 from highcharts_stock import constants
@@ -45,6 +50,17 @@ def run_pyspark_tests(request):
         return True
 
 
+@pytest.fixture
+def run_pandas_tests(request):
+    """Return the ``--pandas`` command-line option."""
+    value = request.config.getoption("--pandas")
+    value = value.lower()
+    if value in ['false', False, 0, 'no', 'no']:
+        return False
+    else:
+        return True
+
+
 @pytest.fixture
 def run_download_tests(request):
     """Return the ``--downloads`` command-line option."""
@@ -62,6 +78,31 @@ def input_files(request):
     return request.config.getoption("--inputs")
 
 
+@pytest.fixture
+def openai_api_key(request):
+    """Return the ``--openai`` command-line option."""
+    api_key = request.config.getoption("--openai")
+    if api_key == 'none':
+        api_key = None
+        
+    if not api_key:
+        api_key = os.getenv('OPENAI_API_KEY', None)
+    
+    return api_key
+
+
+@pytest.fixture
+def disable_ai(request):
+    """Return the ``--disable-ai`` command-line option."""
+    disable_ai = request.config.getoption("--disable-ai")
+    if disable_ai in ['false', False, 0, 'no', 'no', 'f', 'F']:
+        disable_ai = False
+    else:
+        disable_ai = True
+        
+    return disable_ai
+
+
 def check_input_file(input_directory, input_value):
     inputs = os.path.abspath(input_directory)
     if not os.path.exists(input_directory):
@@ -202,6 +243,8 @@ def does_kwarg_value_match_result(kwarg_value, result_value):
                 return False
 
         return True
+    elif HAS_NUMPY and isinstance(kwarg_value, np.ndarray):
+        return np.array_equal(kwarg_value, result_value)
     elif checkers.is_iterable(kwarg_value):
         print('- evaluating a KWARG value that is iterable')
         if hasattr(result_value, 'from_setter'):
@@ -254,6 +297,8 @@ def trim_expected(expected):
             trimmed_value = trim_expected(expected[key])
             if trimmed_value:
                 new_dict[key] = trimmed_value
+        elif HAS_NUMPY and isinstance(expected[key], np.ndarray):
+            new_dict[key] = expected[key]
         elif checkers.is_iterable(expected[key]):
             trimmed_value = []
             for item in expected[key]:
@@ -277,8 +322,8 @@ def compare_js_literals(original, new):
 
     counter = 0
     for char in original:
-        min_index = max(0, counter - 20)
-        max_index = min(counter + 20, len(original))
+        min_index = max(0, counter - 200)
+        max_index = min(counter + 200, len(original))
 
         if new[counter] != char:
             print(f'\nMISMATCH FOUND AT ORIGINAL CHARACTER: {counter}')
@@ -301,8 +346,10 @@ def Class__init__(cls, kwargs, error):
             #kwargs['type'] = result.type
         for key in kwargs_copy:
             print(f'CHECKING: {key}')
-            if kwargs.get(key) and isinstance(kwargs_copy[key],
-                                              str) and kwargs[key].startswith('function'):
+            if HAS_NUMPY and isinstance(kwargs.get(key, None), np.ndarray):
+                continue
+            elif kwargs.get(key) and isinstance(kwargs_copy[key],
+                                                str) and kwargs[key].startswith('function'):
                 continue
             if kwargs.get(key) and isinstance(kwargs_copy[key],
                                               str) and kwargs[key].startswith('class'):
@@ -365,6 +412,13 @@ def Class__to_untrimmed_dict(cls, kwargs, error):
             kwarg_value = kwargs_copy[key]
             result_value = result.get(key)
 
+            if HAS_NUMPY and isinstance(kwarg_value, np.ndarray):
+                assert isinstance(result_value, dict) is True
+                for key in result_value:
+                    key_value = result_value[key]
+                    assert isinstance(key_value, np.ndarray) is True
+                    assert len(key_value) == len(kwarg_value)
+                continue
             if kwargs.get(key) and isinstance(kwargs_copy[key],
                                               str) and kwargs[key].startswith('function'):
                 continue
@@ -596,7 +650,13 @@ def Class_from_dict(cls, kwargs, error):
                     result_value = getattr(instance, key)
                 print(kwarg_value)
                 print(result_value)
-                assert does_kwarg_value_match_result(kwarg_value, result_value)
+                if key == 'ndarray':
+                    assert isinstance(result_value, dict) is True
+                    for key in result_value:
+                        key_value = result_value[key]
+                        assert isinstance(key_value, np.ndarray) is True
+                else:
+                    assert does_kwarg_value_match_result(kwarg_value, result_value)
     else:
         with pytest.raises(error):
             instance = cls.from_dict(as_dict)
diff --git a/tests/input_files/chart_obj/01-expected.js b/tests/input_files/chart_obj/01-expected.js
index 568a3cc..040ce25 100644
--- a/tests/input_files/chart_obj/01-expected.js
+++ b/tests/input_files/chart_obj/01-expected.js
@@ -763,8 +763,8 @@ var someVariableName = Highcharts.stockChart('some-div-id',
       enabled: true,
       text: 'Button Label',
       theme: {
-          fill: '#fff',
-          stroke: '#ccc'
+          'fill': '#fff',
+          'stroke': '#ccc'
       },
       y: 0
     },
@@ -35950,46 +35950,6 @@ var someVariableName = Highcharts.stockChart('some-div-id',
       type: 'xrange'
     }
   },
-  rangeSelector: {
-    allButtonsEnabled: true,
-    buttonPosition: {
-      align: 'center',
-      x: 5,
-      y: 5
-    },
-    buttons: [
-      {
-        count: 1,
-        offsetMax: 0,
-        offsetMin: 0,
-        preserveDataGrouping: true,
-        text: 'Some Text Goes Here',
-        title: 'Button Title'
-      }
-    ],
-    buttonSpacing: 3,
-    dropdown: 'responsive',
-    enabled: true,
-    floating: false,
-    inputBoxBorderColor: '#ccc',
-    inputBoxHeight: 24,
-    inputDateFormat: '%b %e, %Y',
-    inputDateParser: function(param) { return true; },
-    inputEditDateFormat: '%b %e, %Y',
-    inputEnabled: true,
-    inputPosition: {
-      align: 'center',
-      x: 5,
-      y: 5
-    },
-    inputSpacing: 3,
-    inputStyle: 'some-value',
-    labelStyle: 'some-css-goes-here',
-    selected: 1,
-    verticalAlign: 'top',
-    x: 5,
-    y: 10
-  },
   responsive: {
     rules: [
       {
@@ -36010,226 +35970,6 @@ var someVariableName = Highcharts.stockChart('some-div-id',
       }
     ]
   },
-  scrollbar: {
-    barBackgroundColor: '#ccc',
-    barBorderColor: '#777',
-    barBorderRadius: 2,
-    barBorderWidth: 2,
-    buttonArrowColor: '#333',
-    buttonBackgroundColor: '#ccc',
-    buttonBorderColor: '#000',
-    buttonBorderRadius: 2,
-    buttonBorderWidth: 3,
-    enabled: true,
-    height: 120,
-    liveRedraw: false,
-    margin: 6,
-    minWidth: 8,
-    rifleColor: '#ccc',
-    showFull: false,
-    trackBackgroundColor: '#ccc',
-    trackBorderColor: '#fff',
-    trackBorderRadius: 0,
-    trackBorderWidth: 2,
-    zIndex: 3
-  },
-  stockTools: {
-    gui: {
-      buttons: [
-        'indicators',
-        'separator',
-        'simpleShapes',
-        'lines',
-        'crookedLines',
-        'measure',
-        'advanced',
-        'toggleAnnotations',
-        'separator',
-        'verticalLabels',
-        'flags',
-        'separator',
-        'zoomChange',
-        'fullScreen',
-        'typeChange',
-        'separator',
-        'currentPriceIndicator',
-        'saveChart'
-      ],
-      className: 'some-class-name',
-      definitions: {
-        advanced: {
-          items: [
-            'property1',
-            'property2'
-          ],
-          fibonacci: {
-            symbol: 'icon-name'
-          },
-          fibonacciTimeZones: {
-            symbol: 'icon-name'
-          },
-          parallelChannel: {
-            symbol: 'icon-name'
-          },
-          pitchfork: {
-            symbol: 'icon-name'
-          },
-          timeCycles: {
-            symbol: 'icon-name'
-          }
-        },
-        crookedLines: {
-          items: ['property1', 'property2'],
-          crooked3: {
-            symbol: 'icon-name'
-          },
-          crooked5: {
-            symbol: 'icon-name'
-          },
-          elliott3: {
-            symbol: 'icon-name'
-          },
-          elliott5: {
-            symbol: 'icon-name'
-          }
-        },
-        currentPriceIndicator: {
-          symbol: 'icon-name'
-        },
-        flags: {
-          items: ['property1', 'property2'],
-          flagCirclepin: {
-            symbol: 'icon-name'
-          },
-          flagDiamondpin: {
-            symbol: 'icon-name'
-          },
-          flagSimplepin: {
-            symbol: 'icon-name'
-          },
-          flagSquarepin: {
-            symbol: 'icon-name'
-          }
-        },
-        fullScreen: {
-          symbol: 'icon-name'
-        },
-        indicators: {
-          symbol: 'icon-name'
-        },
-        lines: {
-          items: ['proprety1', 'property2'],
-          arrowInfinityLine: {
-            symbol: 'icon-name'
-          },
-          arrowRay: {
-            symbol: 'icon-name'
-          },
-          arrowSegment: {
-            symbol: 'icon-name'
-          },
-          horizontalLine: {
-            symbol: 'icon-name'
-          },
-          line: {
-            symbol: 'icon-name'
-          },
-          ray: {
-            symbol: 'icon-name'
-          },
-          segment: {
-            symbol: 'icon-name'
-          },
-          verticalLine: {
-            symbol: 'icon-name'
-          }
-        },
-        measure: {
-          items: ['property1', 'property2'],
-          measureX: {
-            symbol: 'icon-name'
-          },
-          measureXY: {
-            symbol: 'icon-name'
-          },
-          measureY: {
-            symbol: 'icon-name'
-          }
-        },
-        saveChart: {
-          symbol: 'icon-name'
-        },
-        separator: {
-          symbol: 'icon-name'
-        },
-        simpleShapes: {
-          items: ['prop1', 'prop2'],
-          circle: {
-            symbol: 'icon-name'
-          },
-          ellipse: {
-            symbol: 'icon-name'
-          },
-          label: {
-            symbol: 'icon-name'
-          },
-          rectangle: {
-            symbol: 'icon-name'
-          }
-        },
-        toggleAnnotations: {
-          symbol: 'icon-name'
-        },
-        typeChange: {
-          items: ['prop1', 'prop2'],
-          typeCandlestick: {
-            symbol: 'icon-name'
-          },
-          typeHeikinAshi: {
-            symbol: 'icon-name'
-          },
-          typeHLC: {
-            symbol: 'icon-name'
-          },
-          typeHollowCandlestick: {
-            symbol: 'icon-name'
-          },
-          typeLine: {
-            symbol: 'icon-name'
-          },
-          typeOHLC: {
-            symbol: 'icon-name'
-          }
-        },
-        verticalLabels: {
-          items: ['prop1', 'prop2'],
-          verticalArrow: {
-            symbol: 'icon-name'
-          },
-          verticalCounter: {
-            symbol: 'icon-name'
-          },
-          verticalLabel: {
-            symbol: 'icon-name'
-          }
-        },
-        zoomChange: {
-          items: ['prop1', 'prop2'],
-          zoomX: {
-            symbol: 'icon-name'
-          },
-          zoomXY: {
-            symbol: 'icon-name'
-          },
-          zoomY: {
-            symbol: 'icon-name'
-          }
-        }
-      },
-      enabled: true,
-      toolbarClassName: 'some-class-name'
-    }
-  },
   subtitle: {
     align: 'left',
     floating: true,
diff --git a/tests/input_files/chart_obj/01-input.js b/tests/input_files/chart_obj/01-input.js
index d753d7e..44d34b0 100644
--- a/tests/input_files/chart_obj/01-input.js
+++ b/tests/input_files/chart_obj/01-input.js
@@ -765,8 +765,8 @@
         enabled: true,
         text: 'Button Label',
         theme: {
-            fill: '#fff',
-            stroke: '#ccc'
+            'fill': '#fff',
+            'stroke': '#ccc'
         },
         y: 0
       },
@@ -19411,7 +19411,6 @@
           enabled: true
         }
       },
-
       arcdiagram: {
         borderColor: '#fff',
         borderWidth: 2,
@@ -35952,46 +35951,6 @@
         type: 'xrange'
       }
     },
-    rangeSelector: {
-      allButtonsEnabled: true,
-      buttonPosition: {
-        align: 'center',
-        x: 5,
-        y: 5
-      },
-      buttons: [
-        {
-          count: 1,
-          offsetMax: 0,
-          offsetMin: 0,
-          preserveDataGrouping: true,
-          text: 'Some Text Goes Here',
-          title: 'Button Title'
-        }
-      ],
-      buttonSpacing: 3,
-      dropdown: 'responsive',
-      enabled: true,
-      floating: false,
-      inputBoxBorderColor: '#ccc',
-      inputBoxHeight: 24,
-      inputDateFormat: '%b %e, %Y',
-      inputDateParser: function(param) { return true; },
-      inputEditDateFormat: '%b %e, %Y',
-      inputEnabled: true,
-      inputPosition: {
-        align: 'center',
-        x: 5,
-        y: 5
-      },
-      inputSpacing: 3,
-      inputStyle: 'some-value',
-      labelStyle: 'some-css-goes-here',
-      selected: 1,
-      verticalAlign: 'top',
-      x: 5,
-      y: 10
-    },
     responsive: {
       rules: [
         {
@@ -36012,226 +35971,6 @@
         }
       ]
     },
-    scrollbar: {
-      barBackgroundColor: '#ccc',
-      barBorderColor: '#777',
-      barBorderRadius: 2,
-      barBorderWidth: 2,
-      buttonArrowColor: '#333',
-      buttonBackgroundColor: '#ccc',
-      buttonBorderColor: '#000',
-      buttonBorderRadius: 2,
-      buttonBorderWidth: 3,
-      enabled: true,
-      height: 120,
-      liveRedraw: false,
-      margin: 6,
-      minWidth: 8,
-      rifleColor: '#ccc',
-      showFull: false,
-      trackBackgroundColor: '#ccc',
-      trackBorderColor: '#fff',
-      trackBorderRadius: 0,
-      trackBorderWidth: 2,
-      zIndex: 3
-    },
-    stockTools: {
-      gui: {
-        buttons: [
-          'indicators',
-          'separator',
-          'simpleShapes',
-          'lines',
-          'crookedLines',
-          'measure',
-          'advanced',
-          'toggleAnnotations',
-          'separator',
-          'verticalLabels',
-          'flags',
-          'separator',
-          'zoomChange',
-          'fullScreen',
-          'typeChange',
-          'separator',
-          'currentPriceIndicator',
-          'saveChart'
-        ],
-        className: 'some-class-name',
-        definitions: {
-          advanced: {
-            items: [
-              'property1',
-              'property2'
-            ],
-            fibonacci: {
-              symbol: 'icon-name'
-            },
-            fibonacciTimeZones: {
-              symbol: 'icon-name'
-            },
-            parallelChannel: {
-              symbol: 'icon-name'
-            },
-            pitchfork: {
-              symbol: 'icon-name'
-            },
-            timeCycles: {
-              symbol: 'icon-name'
-            }
-          },
-          crookedLines: {
-            items: ['property1', 'property2'],
-            crooked3: {
-              symbol: 'icon-name'
-            },
-            crooked5: {
-              symbol: 'icon-name'
-            },
-            elliott3: {
-              symbol: 'icon-name'
-            },
-            elliott5: {
-              symbol: 'icon-name'
-            }
-          },
-          currentPriceIndicator: {
-            symbol: 'icon-name'
-          },
-          flags: {
-            items: ['property1', 'property2'],
-            flagCirclepin: {
-              symbol: 'icon-name'
-            },
-            flagDiamondpin: {
-              symbol: 'icon-name'
-            },
-            flagSimplepin: {
-              symbol: 'icon-name'
-            },
-            flagSquarepin: {
-              symbol: 'icon-name'
-            }
-          },
-          fullScreen: {
-            symbol: 'icon-name'
-          },
-          indicators: {
-            symbol: 'icon-name'
-          },
-          lines: {
-            items: ['proprety1', 'property2'],
-            arrowInfinityLine: {
-              symbol: 'icon-name'
-            },
-            arrowRay: {
-              symbol: 'icon-name'
-            },
-            arrowSegment: {
-              symbol: 'icon-name'
-            },
-            horizontalLine: {
-              symbol: 'icon-name'
-            },
-            line: {
-              symbol: 'icon-name'
-            },
-            ray: {
-              symbol: 'icon-name'
-            },
-            segment: {
-              symbol: 'icon-name'
-            },
-            verticalLine: {
-              symbol: 'icon-name'
-            }
-          },
-          measure: {
-            items: ['property1', 'property2'],
-            measureX: {
-              symbol: 'icon-name'
-            },
-            measureXY: {
-              symbol: 'icon-name'
-            },
-            measureY: {
-              symbol: 'icon-name'
-            }
-          },
-          saveChart: {
-            symbol: 'icon-name'
-          },
-          separator: {
-            symbol: 'icon-name'
-          },
-          simpleShapes: {
-            items: ['prop1', 'prop2'],
-            circle: {
-              symbol: 'icon-name'
-            },
-            ellipse: {
-              symbol: 'icon-name'
-            },
-            label: {
-              symbol: 'icon-name'
-            },
-            rectangle: {
-              symbol: 'icon-name'
-            }
-          },
-          toggleAnnotations: {
-            symbol: 'icon-name'
-          },
-          typeChange: {
-            items: ['prop1', 'prop2'],
-            typeCandlestick: {
-              symbol: 'icon-name'
-            },
-            typeHeikinAshi: {
-              symbol: 'icon-name'
-            },
-            typeHLC: {
-              symbol: 'icon-name'
-            },
-            typeHollowCandlestick: {
-              symbol: 'icon-name'
-            },
-            typeLine: {
-              symbol: 'icon-name'
-            },
-            typeOHLC: {
-              symbol: 'icon-name'
-            }
-          },
-          verticalLabels: {
-            items: ['prop1', 'prop2'],
-            verticalArrow: {
-              symbol: 'icon-name'
-            },
-            verticalCounter: {
-              symbol: 'icon-name'
-            },
-            verticalLabel: {
-              symbol: 'icon-name'
-            }
-          },
-          zoomChange: {
-            items: ['prop1', 'prop2'],
-            zoomX: {
-              symbol: 'icon-name'
-            },
-            zoomXY: {
-              symbol: 'icon-name'
-            },
-            zoomY: {
-              symbol: 'icon-name'
-            }
-          }
-        },
-        enabled: true,
-        toolbarClassName: 'some-class-name'
-      }
-    },
     subtitle: {
       align: 'left',
       floating: true,
@@ -36759,6 +36498,5 @@
       }
     ]
   },
-  variableName: 'someVariableName',
-  isStockChart: true
+  variableName: 'someVariableName'
 }
diff --git a/tests/input_files/global_options/shared_options/01-expected.js b/tests/input_files/global_options/shared_options/01-expected.js
index 0879b2e..3fdccda 100644
--- a/tests/input_files/global_options/shared_options/01-expected.js
+++ b/tests/input_files/global_options/shared_options/01-expected.js
@@ -762,8 +762,8 @@ Highcharts.setOptions({
       enabled: true,
       text: 'Button Label',
       theme: {
-          fill: '#fff',
-          stroke: '#ccc'
+          'fill': '#fff',
+          'stroke': '#ccc'
       },
       y: 0
     },
diff --git a/tests/input_files/navigation/navigation/01.js b/tests/input_files/navigation/navigation/01.js
index 0d94f96..48e679d 100644
--- a/tests/input_files/navigation/navigation/01.js
+++ b/tests/input_files/navigation/navigation/01.js
@@ -26,8 +26,8 @@
     enabled: true,
     text: 'Button Label',
     theme: {
-        fill: '#fff',
-        stroke: '#ccc'
+        'fill': '#fff',
+        'stroke': '#ccc'
     },
     y: 0
   },
diff --git a/tests/input_files/options/01.js b/tests/input_files/options/01.js
index b2ef027..5805f08 100644
--- a/tests/input_files/options/01.js
+++ b/tests/input_files/options/01.js
@@ -762,8 +762,8 @@
       enabled: true,
       text: 'Button Label',
       theme: {
-          fill: '#fff',
-          stroke: '#ccc'
+          'fill': '#fff',
+          'stroke': '#ccc'
       },
       y: 0
     },
diff --git a/tests/input_files/series/data/cartesian/05-expected.js b/tests/input_files/series/data/cartesian/05-expected.js
new file mode 100644
index 0000000..c0435a4
--- /dev/null
+++ b/tests/input_files/series/data/cartesian/05-expected.js
@@ -0,0 +1,1 @@
+[null,456]
\ No newline at end of file
diff --git a/tests/input_files/series/data/cartesian/05.js b/tests/input_files/series/data/cartesian/05-input.js
similarity index 100%
rename from tests/input_files/series/data/cartesian/05.js
rename to tests/input_files/series/data/cartesian/05-input.js
diff --git a/tests/input_files/series/data/collections/01-expected.js b/tests/input_files/series/data/collections/01-expected.js
new file mode 100644
index 0000000..7e2d2c4
--- /dev/null
+++ b/tests/input_files/series/data/collections/01-expected.js
@@ -0,0 +1,50 @@
+[
+    {
+        accessibility: {
+            description: 'Some description goes here',
+            enabled: true
+        },
+        className: 'some-class-name',
+        color: '#ccc',
+        colorIndex: 2,
+        custom: {
+            'some_key': 123,
+            'other_key': 456
+        },
+        description: 'Some description goes here',
+        events: {
+            click: function (event) { return true; },
+            drag: function (event) { return true; },
+            drop: function (event) { return true; },
+            mouseOut: function (event) { return true; }
+        },
+        id: 'some-id-goes-here',
+        labelrank: 3,
+        name: 'Some Name Goes here',
+        selected: false
+    },
+    {
+        accessibility: {
+            description: 'Some description goes here',
+            enabled: true
+        },
+        className: 'some-class-name',
+        color: '#ccc',
+        colorIndex: 2,
+        custom: {
+            'some_key': 123,
+            'other_key': 456
+        },
+        description: 'Some description goes here',
+        events: {
+            click: function (event) { return true; },
+            drag: function (event) { return true; },
+            drop: function (event) { return true; },
+            mouseOut: function (event) { return true; }
+        },
+        id: 'some-id-goes-here',
+        labelrank: 3,
+        name: 'Some Name Goes here',
+        selected: false
+    }
+]
\ No newline at end of file
diff --git a/tests/input_files/series/data/collections/01-input.js b/tests/input_files/series/data/collections/01-input.js
new file mode 100644
index 0000000..9f2a7bd
--- /dev/null
+++ b/tests/input_files/series/data/collections/01-input.js
@@ -0,0 +1,63 @@
+{
+    ndarray: [
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ],
+    dataPoints: [
+        {
+            accessibility: {
+                description: 'Some description goes here',
+                enabled: true
+            },
+            className: 'some-class-name',
+            color: '#ccc',
+            colorIndex: 2,
+            custom: {
+                'some_key': 123,
+                'other_key': 456
+            },
+            description: 'Some description goes here',
+            events: {
+                click: function (event) { return true; },
+                drag: function (event) { return true; },
+                drop: function (event) { return true; },
+                mouseOut: function (event) { return true; }
+            },
+            id: 'some-id-goes-here',
+            labelrank: 3,
+            name: 'Some Name Goes here',
+            selected: false
+        },
+        {
+            accessibility: {
+                description: 'Some description goes here',
+                enabled: true
+            },
+            className: 'some-class-name',
+            color: '#ccc',
+            colorIndex: 2,
+            custom: {
+                'some_key': 123,
+                'other_key': 456
+            },
+            description: 'Some description goes here',
+            events: {
+                click: function (event) { return true; },
+                drag: function (event) { return true; },
+                drop: function (event) { return true; },
+                mouseOut: function (event) { return true; }
+            },
+            id: 'some-id-goes-here',
+            labelrank: 3,
+            name: 'Some Name Goes here',
+            selected: false
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/input_files/series/data/collections/02-expected.js b/tests/input_files/series/data/collections/02-expected.js
new file mode 100644
index 0000000..e69de29
diff --git a/tests/input_files/series/data/collections/02-input.js b/tests/input_files/series/data/collections/02-input.js
new file mode 100644
index 0000000..73afc1b
--- /dev/null
+++ b/tests/input_files/series/data/collections/02-input.js
@@ -0,0 +1,13 @@
+{
+    ndarray: [
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ]
+}
\ No newline at end of file
diff --git a/tests/input_files/series/data/collections/03-expected.js b/tests/input_files/series/data/collections/03-expected.js
new file mode 100644
index 0000000..7e2d2c4
--- /dev/null
+++ b/tests/input_files/series/data/collections/03-expected.js
@@ -0,0 +1,50 @@
+[
+    {
+        accessibility: {
+            description: 'Some description goes here',
+            enabled: true
+        },
+        className: 'some-class-name',
+        color: '#ccc',
+        colorIndex: 2,
+        custom: {
+            'some_key': 123,
+            'other_key': 456
+        },
+        description: 'Some description goes here',
+        events: {
+            click: function (event) { return true; },
+            drag: function (event) { return true; },
+            drop: function (event) { return true; },
+            mouseOut: function (event) { return true; }
+        },
+        id: 'some-id-goes-here',
+        labelrank: 3,
+        name: 'Some Name Goes here',
+        selected: false
+    },
+    {
+        accessibility: {
+            description: 'Some description goes here',
+            enabled: true
+        },
+        className: 'some-class-name',
+        color: '#ccc',
+        colorIndex: 2,
+        custom: {
+            'some_key': 123,
+            'other_key': 456
+        },
+        description: 'Some description goes here',
+        events: {
+            click: function (event) { return true; },
+            drag: function (event) { return true; },
+            drop: function (event) { return true; },
+            mouseOut: function (event) { return true; }
+        },
+        id: 'some-id-goes-here',
+        labelrank: 3,
+        name: 'Some Name Goes here',
+        selected: false
+    }
+]
\ No newline at end of file
diff --git a/tests/input_files/series/data/collections/03-input.js b/tests/input_files/series/data/collections/03-input.js
new file mode 100644
index 0000000..1a0604e
--- /dev/null
+++ b/tests/input_files/series/data/collections/03-input.js
@@ -0,0 +1,56 @@
+{
+    array: [
+        [0.0, 15.0], 
+        [10.0, -50.0]
+    ],
+    dataPoints: [
+        {
+            accessibility: {
+                description: 'Some description goes here',
+                enabled: true
+            },
+            className: 'some-class-name',
+            color: '#ccc',
+            colorIndex: 2,
+            custom: {
+                'some_key': 123,
+                'other_key': 456
+            },
+            description: 'Some description goes here',
+            events: {
+                click: function (event) { return true; },
+                drag: function (event) { return true; },
+                drop: function (event) { return true; },
+                mouseOut: function (event) { return true; }
+            },
+            id: 'some-id-goes-here',
+            labelrank: 3,
+            name: 'Some Name Goes here',
+            selected: false
+        },
+        {
+            accessibility: {
+                description: 'Some description goes here',
+                enabled: true
+            },
+            className: 'some-class-name',
+            color: '#ccc',
+            colorIndex: 2,
+            custom: {
+                'some_key': 123,
+                'other_key': 456
+            },
+            description: 'Some description goes here',
+            events: {
+                click: function (event) { return true; },
+                drag: function (event) { return true; },
+                drop: function (event) { return true; },
+                mouseOut: function (event) { return true; }
+            },
+            id: 'some-id-goes-here',
+            labelrank: 3,
+            name: 'Some Name Goes here',
+            selected: false
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/input_files/series/data/collections/error-01.js b/tests/input_files/series/data/collections/error-01.js
new file mode 100644
index 0000000..f4dadab
--- /dev/null
+++ b/tests/input_files/series/data/collections/error-01.js
@@ -0,0 +1,60 @@
+{
+    ndarray: [
+        [0, 15], 
+        [10, -50], 
+        [20, -56.5], 
+        [30, -46.5], 
+        [40, -22.1],
+        [50, -2.5], 
+        [60, -27.7], 
+        [70, -55.7], 
+        [80, -76.5]
+    ],
+    dataPoints: [
+        {
+            accessibility: {
+                description: 'Some description goes here',
+                enabled: true
+            },
+            className: 'some-class-name',
+            color: '#ccc',
+            colorIndex: 2,
+            custom: 'invalid-value',
+            description: 'Some description goes here',
+            events: {
+                click: function (event) { return true; },
+                drag: function (event) { return true; },
+                drop: function (event) { return true; },
+                mouseOut: function (event) { return true; }
+            },
+            id: 'some-id-goes-here',
+            labelrank: 3,
+            name: 'Some Name Goes here',
+            selected: false
+        },
+        {
+            accessibility: {
+                description: 'Some description goes here',
+                enabled: true
+            },
+            className: 'some-class-name',
+            color: '#ccc',
+            colorIndex: 2,
+            custom: {
+                'some_key': 123,
+                'other_key': 456
+            },
+            description: 'Some description goes here',
+            events: {
+                click: function (event) { return true; },
+                drag: function (event) { return true; },
+                drop: function (event) { return true; },
+                mouseOut: function (event) { return true; }
+            },
+            id: 'some-id-goes-here',
+            labelrank: 3,
+            name: 'Some Name Goes here',
+            selected: false
+        }
+    ]
+}
\ No newline at end of file
diff --git a/tests/input_files/test-data-files/nst-est2019-01-reduced-to-two.csv b/tests/input_files/test-data-files/nst-est2019-01-reduced-to-two.csv
new file mode 100644
index 0000000..2811dbb
--- /dev/null
+++ b/tests/input_files/test-data-files/nst-est2019-01-reduced-to-two.csv
@@ -0,0 +1,58 @@
+Geographic Area,2010
+United States,"309,321,666"
+Northeast,"55,380,134"
+Midwest,"66,974,416"
+South,"114,866,680"
+West,"72,100,436"
+Alabama,"4,785,437"
+Alaska,"713,910"
+Arizona,"6,407,172"
+Arkansas,"2,921,964"
+California,"37,319,502"
+Colorado,"5,047,349"
+Connecticut,"3,579,114"
+Delaware,"899,593"
+District of Columbia,"605,226"
+Florida,"18,845,537"
+Georgia,"9,711,881"
+Hawaii,"1,363,963"
+Idaho,"1,570,746"
+Illinois,"12,840,503"
+Indiana,"6,490,432"
+Iowa,"3,050,745"
+Kansas,"2,858,190"
+Kentucky,"4,348,181"
+Louisiana,"4,544,532"
+Maine,"1,327,629"
+Maryland,"5,788,645"
+Massachusetts,"6,566,307"
+Michigan,"9,877,510"
+Minnesota,"5,310,828"
+Mississippi,"2,970,548"
+Missouri,"5,995,974"
+Montana,"990,697"
+Nebraska,"1,829,542"
+Nevada,"2,702,405"
+New Hampshire,"1,316,762"
+New Jersey,"8,799,446"
+New Mexico,"2,064,552"
+New York,"19,399,878"
+North Carolina,"9,574,323"
+North Dakota,"674,715"
+Ohio,"11,539,336"
+Oklahoma,"3,759,944"
+Oregon,"3,837,491"
+Pennsylvania,"12,711,160"
+Rhode Island,"1,053,959"
+South Carolina,"4,635,649"
+South Dakota,"816,166"
+Tennessee,"6,355,311"
+Texas,"25,241,971"
+Utah,"2,775,332"
+Vermont,"625,879"
+Virginia,"8,023,699"
+Washington,"6,742,830"
+West Virginia,"1,854,239"
+Wisconsin,"5,690,475"
+Wyoming,"564,487"
+Puerto Rico,"3,721,525"
\ No newline at end of file
diff --git a/tests/input_files/test-data-files/nst-est2019-01-removed-column.csv b/tests/input_files/test-data-files/nst-est2019-01-removed-column.csv
new file mode 100644
index 0000000..87a18db
--- /dev/null
+++ b/tests/input_files/test-data-files/nst-est2019-01-removed-column.csv
@@ -0,0 +1,58 @@
+2010,2011,2012,2013,2014,2015,2016,2017,2018,2019
+"309,321,666","311,556,874","313,830,990","315,993,715","318,301,008","320,635,163","322,941,311","324,985,539","326,687,501","328,239,523"
+"55,380,134","55,604,223","55,775,216","55,901,806","56,006,011","56,034,684","56,042,330","56,059,240","56,046,620","55,982,803"
+"66,974,416","67,157,800","67,336,743","67,560,379","67,745,167","67,860,583","67,987,540","68,126,781","68,236,628","68,329,004"
+"114,866,680","116,006,522","117,241,208","118,364,400","119,624,037","120,997,341","122,351,760","123,542,189","124,569,433","125,580,448"
+"72,100,436","72,788,329","73,477,823","74,167,130","74,925,793","75,742,555","76,559,681","77,257,329","77,834,820","78,347,268"
+"4,785,437","4,799,069","4,815,588","4,830,081","4,841,799","4,852,347","4,863,525","4,874,486","4,887,681","4,903,185"
+"713,910","722,128","730,443","737,068","736,283","737,498","741,456","739,700","735,139","731,545"
+"6,407,172","6,472,643","6,554,978","6,632,764","6,730,413","6,829,676","6,941,072","7,044,008","7,158,024","7,278,717"
+"2,921,964","2,940,667","2,952,164","2,959,400","2,967,392","2,978,048","2,989,918","3,001,345","3,009,733","3,017,804"
+"37,319,502","37,638,369","37,948,800","38,260,787","38,596,972","38,918,045","39,167,117","39,358,497","39,461,588","39,512,223"
+"5,047,349","5,121,108","5,192,647","5,269,035","5,350,101","5,450,623","5,539,215","5,611,885","5,691,287","5,758,736"
+"3,579,114","3,588,283","3,594,547","3,594,841","3,594,524","3,587,122","3,578,141","3,573,297","3,571,520","3,565,287"
+"899,593","907,381","915,179","923,576","932,487","941,252","948,921","956,823","965,479","973,764"
+"605,226","619,800","634,924","650,581","662,328","675,400","685,815","694,906","701,547","705,749"
+"18,845,537","19,053,237","19,297,822","19,545,621","19,845,911","20,209,042","20,613,477","20,963,613","21,244,317","21,477,737"
+"9,711,881","9,802,431","9,901,430","9,972,479","10,067,278","10,178,447","10,301,890","10,410,330","10,511,131","10,617,423"
+"1,363,963","1,379,329","1,394,804","1,408,243","1,414,538","1,422,052","1,427,559","1,424,393","1,420,593","1,415,872"
+"1,570,746","1,583,910","1,595,324","1,611,206","1,631,112","1,651,059","1,682,380","1,717,715","1,750,536","1,787,065"
+"12,840,503","12,867,454","12,882,510","12,895,129","12,884,493","12,858,913","12,820,527","12,778,828","12,723,071","12,671,821"
+"6,490,432","6,516,528","6,537,703","6,568,713","6,593,644","6,608,422","6,634,304","6,658,078","6,695,497","6,732,219"
+"3,050,745","3,066,336","3,076,190","3,092,997","3,109,350","3,120,960","3,131,371","3,141,550","3,148,618","3,155,070"
+"2,858,190","2,869,225","2,885,257","2,893,212","2,900,475","2,909,011","2,910,844","2,908,718","2,911,359","2,913,314"
+"4,348,181","4,369,821","4,386,346","4,404,659","4,414,349","4,425,976","4,438,182","4,452,268","4,461,153","4,467,673"
+"4,544,532","4,575,625","4,600,972","4,624,527","4,644,013","4,664,628","4,678,135","4,670,560","4,659,690","4,648,794"
+"1,327,629","1,328,284","1,327,729","1,328,009","1,330,513","1,328,262","1,331,317","1,334,612","1,339,057","1,344,212"
+"5,788,645","5,839,419","5,886,992","5,923,188","5,957,283","5,985,562","6,003,323","6,023,868","6,035,802","6,045,680"
+"6,566,307","6,613,583","6,663,005","6,713,315","6,762,596","6,794,228","6,823,608","6,859,789","6,882,635","6,892,503"
+"9,877,510","9,882,412","9,897,145","9,913,065","9,929,848","9,931,715","9,950,571","9,973,114","9,984,072","9,986,857"
+"5,310,828","5,346,143","5,376,643","5,413,479","5,451,079","5,482,032","5,522,744","5,566,230","5,606,249","5,639,632"
+"2,970,548","2,978,731","2,983,816","2,988,711","2,990,468","2,988,471","2,987,938","2,988,510","2,981,020","2,976,149"
+"5,995,974","6,010,275","6,024,367","6,040,715","6,056,202","6,071,732","6,087,135","6,106,670","6,121,623","6,137,428"
+"990,697","997,316","1,003,783","1,013,569","1,021,869","1,030,475","1,040,859","1,052,482","1,060,665","1,068,778"
+"1,829,542","1,840,672","1,853,303","1,865,279","1,879,321","1,891,277","1,905,616","1,915,947","1,925,614","1,934,408"
+"2,702,405","2,712,730","2,743,996","2,775,970","2,817,628","2,866,939","2,917,563","2,969,905","3,027,341","3,080,156"
+"1,316,762","1,320,202","1,324,232","1,326,622","1,333,341","1,336,350","1,342,307","1,348,787","1,353,465","1,359,711"
+"8,799,446","8,828,117","8,844,942","8,856,972","8,864,525","8,867,949","8,870,827","8,885,525","8,886,025","8,882,190"
+"2,064,552","2,080,450","2,087,309","2,092,273","2,089,568","2,089,291","2,091,630","2,091,784","2,092,741","2,096,829"
+"19,399,878","19,499,241","19,572,932","19,624,447","19,651,049","19,654,666","19,633,428","19,589,572","19,530,351","19,453,561"
+"9,574,323","9,657,592","9,749,476","9,843,336","9,932,887","10,031,646","10,154,788","10,268,233","10,381,615","10,488,084"
+"674,715","685,225","701,176","722,036","737,401","754,066","754,434","754,942","758,080","762,062"
+"11,539,336","11,544,663","11,548,923","11,576,684","11,602,700","11,617,527","11,634,370","11,659,650","11,676,341","11,689,100"
+"3,759,944","3,788,379","3,818,814","3,853,214","3,878,187","3,909,500","3,926,331","3,931,316","3,940,235","3,956,971"
+"3,837,491","3,872,036","3,899,001","3,922,468","3,963,244","4,015,792","4,089,976","4,143,625","4,181,886","4,217,737"
+"12,711,160","12,745,815","12,767,118","12,776,309","12,788,313","12,784,826","12,782,275","12,787,641","12,800,922","12,801,989"
+"1,053,959","1,053,649","1,054,621","1,055,081","1,055,936","1,056,065","1,056,770","1,055,673","1,058,287","1,059,361"
+"4,635,649","4,671,994","4,717,354","4,764,080","4,823,617","4,891,938","4,957,968","5,021,268","5,084,156","5,148,714"
+"816,166","823,579","833,566","842,316","849,129","853,988","862,996","872,868","878,698","884,659"
+"6,355,311","6,399,291","6,453,898","6,494,340","6,541,223","6,591,170","6,646,010","6,708,799","6,771,631","6,829,174"
+"25,241,971","25,645,629","26,084,481","26,480,266","26,964,333","27,470,056","27,914,410","28,295,273","28,628,666","28,995,881"
+"2,775,332","2,814,384","2,853,375","2,897,640","2,936,879","2,981,835","3,041,868","3,101,042","3,153,550","3,205,958"
+"625,879","627,049","626,090","626,210","625,214","625,216","623,657","624,344","624,358","623,989"
+"8,023,699","8,101,155","8,185,080","8,252,427","8,310,993","8,361,808","8,410,106","8,463,587","8,501,286","8,535,519"
+"6,742,830","6,826,627","6,897,058","6,963,985","7,054,655","7,163,657","7,294,771","7,423,362","7,523,869","7,614,893"
+"1,854,239","1,856,301","1,856,872","1,853,914","1,849,489","1,842,050","1,831,023","1,817,004","1,804,291","1,792,147"
+"5,690,475","5,705,288","5,719,960","5,736,754","5,751,525","5,760,940","5,772,628","5,790,186","5,807,406","5,822,434"
+"564,487","567,299","576,305","582,122","582,531","585,613","584,215","578,931","577,601","578,759"
+"3,721,525","3,678,732","3,634,488","3,593,077","3,534,874","3,473,232","3,406,672","3,325,286","3,193,354","3,193,694"
\ No newline at end of file
diff --git a/tests/input_files/test-data-files/nst-est2019-01.csv b/tests/input_files/test-data-files/nst-est2019-01.csv
index ffb9349..34c6996 100644
--- a/tests/input_files/test-data-files/nst-est2019-01.csv
+++ b/tests/input_files/test-data-files/nst-est2019-01.csv
@@ -4,61 +4,55 @@ Northeast,"55,380,134","55,604,223","55,775,216","55,901,806","56,006,011","56,0
 Midwest,"66,974,416","67,157,800","67,336,743","67,560,379","67,745,167","67,860,583","67,987,540","68,126,781","68,236,628","68,329,004"
 South,"114,866,680","116,006,522","117,241,208","118,364,400","119,624,037","120,997,341","122,351,760","123,542,189","124,569,433","125,580,448"
 West,"72,100,436","72,788,329","73,477,823","74,167,130","74,925,793","75,742,555","76,559,681","77,257,329","77,834,820","78,347,268"
-.Alabama,"4,785,437","4,799,069","4,815,588","4,830,081","4,841,799","4,852,347","4,863,525","4,874,486","4,887,681","4,903,185"
-.Alaska,"713,910","722,128","730,443","737,068","736,283","737,498","741,456","739,700","735,139","731,545"
-.Arizona,"6,407,172","6,472,643","6,554,978","6,632,764","6,730,413","6,829,676","6,941,072","7,044,008","7,158,024","7,278,717"
-.Arkansas,"2,921,964","2,940,667","2,952,164","2,959,400","2,967,392","2,978,048","2,989,918","3,001,345","3,009,733","3,017,804"
-.California,"37,319,502","37,638,369","37,948,800","38,260,787","38,596,972","38,918,045","39,167,117","39,358,497","39,461,588","39,512,223"
-.Colorado,"5,047,349","5,121,108","5,192,647","5,269,035","5,350,101","5,450,623","5,539,215","5,611,885","5,691,287","5,758,736"
-.Connecticut,"3,579,114","3,588,283","3,594,547","3,594,841","3,594,524","3,587,122","3,578,141","3,573,297","3,571,520","3,565,287"
-.Delaware,"899,593","907,381","915,179","923,576","932,487","941,252","948,921","956,823","965,479","973,764"
-.District of Columbia,"605,226","619,800","634,924","650,581","662,328","675,400","685,815","694,906","701,547","705,749"
-.Florida,"18,845,537","19,053,237","19,297,822","19,545,621","19,845,911","20,209,042","20,613,477","20,963,613","21,244,317","21,477,737"
-.Georgia,"9,711,881","9,802,431","9,901,430","9,972,479","10,067,278","10,178,447","10,301,890","10,410,330","10,511,131","10,617,423"
-.Hawaii,"1,363,963","1,379,329","1,394,804","1,408,243","1,414,538","1,422,052","1,427,559","1,424,393","1,420,593","1,415,872"
-.Idaho,"1,570,746","1,583,910","1,595,324","1,611,206","1,631,112","1,651,059","1,682,380","1,717,715","1,750,536","1,787,065"
-.Illinois,"12,840,503","12,867,454","12,882,510","12,895,129","12,884,493","12,858,913","12,820,527","12,778,828","12,723,071","12,671,821"
-.Indiana,"6,490,432","6,516,528","6,537,703","6,568,713","6,593,644","6,608,422","6,634,304","6,658,078","6,695,497","6,732,219"
-.Iowa,"3,050,745","3,066,336","3,076,190","3,092,997","3,109,350","3,120,960","3,131,371","3,141,550","3,148,618","3,155,070"
-.Kansas,"2,858,190","2,869,225","2,885,257","2,893,212","2,900,475","2,909,011","2,910,844","2,908,718","2,911,359","2,913,314"
-.Kentucky,"4,348,181","4,369,821","4,386,346","4,404,659","4,414,349","4,425,976","4,438,182","4,452,268","4,461,153","4,467,673"
-.Louisiana,"4,544,532","4,575,625","4,600,972","4,624,527","4,644,013","4,664,628","4,678,135","4,670,560","4,659,690","4,648,794"
-.Maine,"1,327,629","1,328,284","1,327,729","1,328,009","1,330,513","1,328,262","1,331,317","1,334,612","1,339,057","1,344,212"
-.Maryland,"5,788,645","5,839,419","5,886,992","5,923,188","5,957,283","5,985,562","6,003,323","6,023,868","6,035,802","6,045,680"
-.Massachusetts,"6,566,307","6,613,583","6,663,005","6,713,315","6,762,596","6,794,228","6,823,608","6,859,789","6,882,635","6,892,503"
-.Michigan,"9,877,510","9,882,412","9,897,145","9,913,065","9,929,848","9,931,715","9,950,571","9,973,114","9,984,072","9,986,857"
-.Minnesota,"5,310,828","5,346,143","5,376,643","5,413,479","5,451,079","5,482,032","5,522,744","5,566,230","5,606,249","5,639,632"
-.Mississippi,"2,970,548","2,978,731","2,983,816","2,988,711","2,990,468","2,988,471","2,987,938","2,988,510","2,981,020","2,976,149"
-.Missouri,"5,995,974","6,010,275","6,024,367","6,040,715","6,056,202","6,071,732","6,087,135","6,106,670","6,121,623","6,137,428"
-.Montana,"990,697","997,316","1,003,783","1,013,569","1,021,869","1,030,475","1,040,859","1,052,482","1,060,665","1,068,778"
-.Nebraska,"1,829,542","1,840,672","1,853,303","1,865,279","1,879,321","1,891,277","1,905,616","1,915,947","1,925,614","1,934,408"
-.Nevada,"2,702,405","2,712,730","2,743,996","2,775,970","2,817,628","2,866,939","2,917,563","2,969,905","3,027,341","3,080,156"
-.New Hampshire,"1,316,762","1,320,202","1,324,232","1,326,622","1,333,341","1,336,350","1,342,307","1,348,787","1,353,465","1,359,711"
-.New Jersey,"8,799,446","8,828,117","8,844,942","8,856,972","8,864,525","8,867,949","8,870,827","8,885,525","8,886,025","8,882,190"
-.New Mexico,"2,064,552","2,080,450","2,087,309","2,092,273","2,089,568","2,089,291","2,091,630","2,091,784","2,092,741","2,096,829"
-.New York,"19,399,878","19,499,241","19,572,932","19,624,447","19,651,049","19,654,666","19,633,428","19,589,572","19,530,351","19,453,561"
-.North Carolina,"9,574,323","9,657,592","9,749,476","9,843,336","9,932,887","10,031,646","10,154,788","10,268,233","10,381,615","10,488,084"
-.North Dakota,"674,715","685,225","701,176","722,036","737,401","754,066","754,434","754,942","758,080","762,062"
-.Ohio,"11,539,336","11,544,663","11,548,923","11,576,684","11,602,700","11,617,527","11,634,370","11,659,650","11,676,341","11,689,100"
-.Oklahoma,"3,759,944","3,788,379","3,818,814","3,853,214","3,878,187","3,909,500","3,926,331","3,931,316","3,940,235","3,956,971"
-.Oregon,"3,837,491","3,872,036","3,899,001","3,922,468","3,963,244","4,015,792","4,089,976","4,143,625","4,181,886","4,217,737"
-.Pennsylvania,"12,711,160","12,745,815","12,767,118","12,776,309","12,788,313","12,784,826","12,782,275","12,787,641","12,800,922","12,801,989"
-.Rhode Island,"1,053,959","1,053,649","1,054,621","1,055,081","1,055,936","1,056,065","1,056,770","1,055,673","1,058,287","1,059,361"
-.South Carolina,"4,635,649","4,671,994","4,717,354","4,764,080","4,823,617","4,891,938","4,957,968","5,021,268","5,084,156","5,148,714"
-.South Dakota,"816,166","823,579","833,566","842,316","849,129","853,988","862,996","872,868","878,698","884,659"
-.Tennessee,"6,355,311","6,399,291","6,453,898","6,494,340","6,541,223","6,591,170","6,646,010","6,708,799","6,771,631","6,829,174"
-.Texas,"25,241,971","25,645,629","26,084,481","26,480,266","26,964,333","27,470,056","27,914,410","28,295,273","28,628,666","28,995,881"
-.Utah,"2,775,332","2,814,384","2,853,375","2,897,640","2,936,879","2,981,835","3,041,868","3,101,042","3,153,550","3,205,958"
-.Vermont,"625,879","627,049","626,090","626,210","625,214","625,216","623,657","624,344","624,358","623,989"
-.Virginia,"8,023,699","8,101,155","8,185,080","8,252,427","8,310,993","8,361,808","8,410,106","8,463,587","8,501,286","8,535,519"
-.Washington,"6,742,830","6,826,627","6,897,058","6,963,985","7,054,655","7,163,657","7,294,771","7,423,362","7,523,869","7,614,893"
-.West Virginia,"1,854,239","1,856,301","1,856,872","1,853,914","1,849,489","1,842,050","1,831,023","1,817,004","1,804,291","1,792,147"
-.Wisconsin,"5,690,475","5,705,288","5,719,960","5,736,754","5,751,525","5,760,940","5,772,628","5,790,186","5,807,406","5,822,434"
-.Wyoming,"564,487","567,299","576,305","582,122","582,531","585,613","584,215","578,931","577,601","578,759"
-,,,,,,,,,,
-Puerto Rico,"3,721,525","3,678,732","3,634,488","3,593,077","3,534,874","3,473,232","3,406,672","3,325,286","3,193,354","3,193,694"
-"Note: The estimates are based on the 2010 Census and reflect changes to the April 1, 2010 population due to the Count Question Resolution program and geographic program revisions. See Geographic Terms and Definitions at http://www.census.gov/programs-surveys/popest/guidance-geographies/terms-and-definitions.html for a list of the states that are included in each region.  All geographic boundaries for the 2019 population estimates series except statistical area delineations are as of January 1, 2019.  For population estimates methodology statements, see http://www.census.gov/programs-surveys/popest/technical-documentation/methodology.html.",,,,,,,,,,
-Suggested Citation:,,,,,,,,,,
-"Table 1. Annual Estimates of the Resident Population for the United States, Regions, States, and Puerto Rico: April 1, 2010 to July 1, 2019 (NST-EST2019-01)",,,,,,,,,,
-"Source: U.S. Census Bureau, Population Division",,,,,,,,,,
-Release Date: December 2019,,,,,,,,,,
+Alabama,"4,785,437","4,799,069","4,815,588","4,830,081","4,841,799","4,852,347","4,863,525","4,874,486","4,887,681","4,903,185"
+Alaska,"713,910","722,128","730,443","737,068","736,283","737,498","741,456","739,700","735,139","731,545"
+Arizona,"6,407,172","6,472,643","6,554,978","6,632,764","6,730,413","6,829,676","6,941,072","7,044,008","7,158,024","7,278,717"
+Arkansas,"2,921,964","2,940,667","2,952,164","2,959,400","2,967,392","2,978,048","2,989,918","3,001,345","3,009,733","3,017,804"
+California,"37,319,502","37,638,369","37,948,800","38,260,787","38,596,972","38,918,045","39,167,117","39,358,497","39,461,588","39,512,223"
+Colorado,"5,047,349","5,121,108","5,192,647","5,269,035","5,350,101","5,450,623","5,539,215","5,611,885","5,691,287","5,758,736"
+Connecticut,"3,579,114","3,588,283","3,594,547","3,594,841","3,594,524","3,587,122","3,578,141","3,573,297","3,571,520","3,565,287"
+Delaware,"899,593","907,381","915,179","923,576","932,487","941,252","948,921","956,823","965,479","973,764"
+District of Columbia,"605,226","619,800","634,924","650,581","662,328","675,400","685,815","694,906","701,547","705,749"
+Florida,"18,845,537","19,053,237","19,297,822","19,545,621","19,845,911","20,209,042","20,613,477","20,963,613","21,244,317","21,477,737"
+Georgia,"9,711,881","9,802,431","9,901,430","9,972,479","10,067,278","10,178,447","10,301,890","10,410,330","10,511,131","10,617,423"
+Hawaii,"1,363,963","1,379,329","1,394,804","1,408,243","1,414,538","1,422,052","1,427,559","1,424,393","1,420,593","1,415,872"
+Idaho,"1,570,746","1,583,910","1,595,324","1,611,206","1,631,112","1,651,059","1,682,380","1,717,715","1,750,536","1,787,065"
+Illinois,"12,840,503","12,867,454","12,882,510","12,895,129","12,884,493","12,858,913","12,820,527","12,778,828","12,723,071","12,671,821"
+Indiana,"6,490,432","6,516,528","6,537,703","6,568,713","6,593,644","6,608,422","6,634,304","6,658,078","6,695,497","6,732,219"
+Iowa,"3,050,745","3,066,336","3,076,190","3,092,997","3,109,350","3,120,960","3,131,371","3,141,550","3,148,618","3,155,070"
+Kansas,"2,858,190","2,869,225","2,885,257","2,893,212","2,900,475","2,909,011","2,910,844","2,908,718","2,911,359","2,913,314"
+Kentucky,"4,348,181","4,369,821","4,386,346","4,404,659","4,414,349","4,425,976","4,438,182","4,452,268","4,461,153","4,467,673"
+Louisiana,"4,544,532","4,575,625","4,600,972","4,624,527","4,644,013","4,664,628","4,678,135","4,670,560","4,659,690","4,648,794"
+Maine,"1,327,629","1,328,284","1,327,729","1,328,009","1,330,513","1,328,262","1,331,317","1,334,612","1,339,057","1,344,212"
+Maryland,"5,788,645","5,839,419","5,886,992","5,923,188","5,957,283","5,985,562","6,003,323","6,023,868","6,035,802","6,045,680"
+Massachusetts,"6,566,307","6,613,583","6,663,005","6,713,315","6,762,596","6,794,228","6,823,608","6,859,789","6,882,635","6,892,503"
+Michigan,"9,877,510","9,882,412","9,897,145","9,913,065","9,929,848","9,931,715","9,950,571","9,973,114","9,984,072","9,986,857"
+Minnesota,"5,310,828","5,346,143","5,376,643","5,413,479","5,451,079","5,482,032","5,522,744","5,566,230","5,606,249","5,639,632"
+Mississippi,"2,970,548","2,978,731","2,983,816","2,988,711","2,990,468","2,988,471","2,987,938","2,988,510","2,981,020","2,976,149"
+Missouri,"5,995,974","6,010,275","6,024,367","6,040,715","6,056,202","6,071,732","6,087,135","6,106,670","6,121,623","6,137,428"
+Montana,"990,697","997,316","1,003,783","1,013,569","1,021,869","1,030,475","1,040,859","1,052,482","1,060,665","1,068,778"
+Nebraska,"1,829,542","1,840,672","1,853,303","1,865,279","1,879,321","1,891,277","1,905,616","1,915,947","1,925,614","1,934,408"
+Nevada,"2,702,405","2,712,730","2,743,996","2,775,970","2,817,628","2,866,939","2,917,563","2,969,905","3,027,341","3,080,156"
+New Hampshire,"1,316,762","1,320,202","1,324,232","1,326,622","1,333,341","1,336,350","1,342,307","1,348,787","1,353,465","1,359,711"
+New Jersey,"8,799,446","8,828,117","8,844,942","8,856,972","8,864,525","8,867,949","8,870,827","8,885,525","8,886,025","8,882,190"
+New Mexico,"2,064,552","2,080,450","2,087,309","2,092,273","2,089,568","2,089,291","2,091,630","2,091,784","2,092,741","2,096,829"
+New York,"19,399,878","19,499,241","19,572,932","19,624,447","19,651,049","19,654,666","19,633,428","19,589,572","19,530,351","19,453,561"
+North Carolina,"9,574,323","9,657,592","9,749,476","9,843,336","9,932,887","10,031,646","10,154,788","10,268,233","10,381,615","10,488,084"
+North Dakota,"674,715","685,225","701,176","722,036","737,401","754,066","754,434","754,942","758,080","762,062"
+Ohio,"11,539,336","11,544,663","11,548,923","11,576,684","11,602,700","11,617,527","11,634,370","11,659,650","11,676,341","11,689,100"
+Oklahoma,"3,759,944","3,788,379","3,818,814","3,853,214","3,878,187","3,909,500","3,926,331","3,931,316","3,940,235","3,956,971"
+Oregon,"3,837,491","3,872,036","3,899,001","3,922,468","3,963,244","4,015,792","4,089,976","4,143,625","4,181,886","4,217,737"
+Pennsylvania,"12,711,160","12,745,815","12,767,118","12,776,309","12,788,313","12,784,826","12,782,275","12,787,641","12,800,922","12,801,989"
+Rhode Island,"1,053,959","1,053,649","1,054,621","1,055,081","1,055,936","1,056,065","1,056,770","1,055,673","1,058,287","1,059,361"
+South Carolina,"4,635,649","4,671,994","4,717,354","4,764,080","4,823,617","4,891,938","4,957,968","5,021,268","5,084,156","5,148,714"
+South Dakota,"816,166","823,579","833,566","842,316","849,129","853,988","862,996","872,868","878,698","884,659"
+Tennessee,"6,355,311","6,399,291","6,453,898","6,494,340","6,541,223","6,591,170","6,646,010","6,708,799","6,771,631","6,829,174"
+Texas,"25,241,971","25,645,629","26,084,481","26,480,266","26,964,333","27,470,056","27,914,410","28,295,273","28,628,666","28,995,881"
+Utah,"2,775,332","2,814,384","2,853,375","2,897,640","2,936,879","2,981,835","3,041,868","3,101,042","3,153,550","3,205,958"
+Vermont,"625,879","627,049","626,090","626,210","625,214","625,216","623,657","624,344","624,358","623,989"
+Virginia,"8,023,699","8,101,155","8,185,080","8,252,427","8,310,993","8,361,808","8,410,106","8,463,587","8,501,286","8,535,519"
+Washington,"6,742,830","6,826,627","6,897,058","6,963,985","7,054,655","7,163,657","7,294,771","7,423,362","7,523,869","7,614,893"
+West Virginia,"1,854,239","1,856,301","1,856,872","1,853,914","1,849,489","1,842,050","1,831,023","1,817,004","1,804,291","1,792,147"
+Wisconsin,"5,690,475","5,705,288","5,719,960","5,736,754","5,751,525","5,760,940","5,772,628","5,790,186","5,807,406","5,822,434"
+Wyoming,"564,487","567,299","576,305","582,122","582,531","585,613","584,215","578,931","577,601","578,759"
+Puerto Rico,"3,721,525","3,678,732","3,634,488","3,593,077","3,534,874","3,473,232","3,406,672","3,325,286","3,193,354","3,193,694"
\ No newline at end of file
diff --git a/tests/input_files/utility_classes/buttons/01.js b/tests/input_files/utility_classes/buttons/01.js
index d5a9aaf..000b3c1 100644
--- a/tests/input_files/utility_classes/buttons/01.js
+++ b/tests/input_files/utility_classes/buttons/01.js
@@ -2,8 +2,8 @@
     enabled: true,
     text: 'Button Label',
     theme: {
-        fill: '#fff',
-        stroke: '#ccc'
+        'fill': '#fff',
+        'stroke': '#ccc'
     },
     y: 0
 }
diff --git a/tests/input_files/utility_classes/buttons/02.js b/tests/input_files/utility_classes/buttons/02.js
index 748ea23..431f694 100644
--- a/tests/input_files/utility_classes/buttons/02.js
+++ b/tests/input_files/utility_classes/buttons/02.js
@@ -8,8 +8,8 @@
     symbolFill: '#ccc',
     text: 'Button Label',
     theme: {
-        fill: '#fff',
-        stroke: '#ccc'
+        'fill': '#fff',
+        'stroke': '#ccc'
     },
     titleKey: 'somevalue',
     x: 10,
diff --git a/tests/options/series/data/test_cartesian.py b/tests/options/series/data/test_cartesian.py
index 0d01fd7..2e4422e 100644
--- a/tests/options/series/data/test_cartesian.py
+++ b/tests/options/series/data/test_cartesian.py
@@ -11,7 +11,7 @@
 from highcharts_stock import errors
 from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
     Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
-    Class_from_js_literal
+    Class_from_js_literal, Class_from_js_literal_with_expected
 
 STANDARD_PARAMS = [
     ({}, None),
@@ -746,6 +746,21 @@ def test_CartesianData_from_js_literal(input_files, filename, as_file, error):
     Class_from_js_literal(cls, input_files, filename, as_file, error)
 
 
+@pytest.mark.parametrize('input_filename, expected_filename, as_file, error', [
+    ('series/data/cartesian/05-input.js',
+     'series/data/cartesian/05-expected.js',
+     False,
+     None),
+])
+def test_Cartesian3DData_from_js_literal_expected(input_files, input_filename, expected_filename, as_file, error):
+    Class_from_js_literal_with_expected(cls2,
+                                        input_files,
+                                        input_filename,
+                                        expected_filename,
+                                        as_file,
+                                        error)
+
+
 ## NEXT CLASS
 
 STANDARD_PARAMS_2 = [
@@ -1007,7 +1022,6 @@ def test_Cartesian3DData_to_dict(kwargs, error):
 
 
 @pytest.mark.parametrize('filename, as_file, error', [
-    ('series/data/cartesian/05.js', False, None),
     ('series/data/cartesian/06.js', False, None),
 
     ('series/data/cartesian/error-05.js',
@@ -1018,7 +1032,6 @@ def test_Cartesian3DData_to_dict(kwargs, error):
       TypeError,
       ValueError)),
 
-    ('series/data/cartesian/05.js', True, None),
     ('series/data/cartesian/06.js', True, None),
 
     ('series/data/cartesian/error-05.js',
diff --git a/tests/options/series/data/test_collections.py b/tests/options/series/data/test_collections.py
new file mode 100644
index 0000000..8d63316
--- /dev/null
+++ b/tests/options/series/data/test_collections.py
@@ -0,0 +1,467 @@
+"""Tests for ``highcharts.no_data``."""
+
+import pytest
+try:
+    import numpy as np
+    HAS_NUMPY = True
+except ImportError:
+    HAS_NUMPY = False
+
+from json.decoder import JSONDecodeError
+
+from validator_collection import checkers
+
+from highcharts_stock.options.series.data.collections import DataPointCollection as cls
+from highcharts_stock.options.series.data.base import DataBase
+from highcharts_stock import errors
+from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
+    Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
+    Class_from_js_literal_with_expected
+
+
+class NonAbstractDataBase(DataBase):
+
+    @classmethod
+    def from_array(cls, value):
+        pass
+
+
+class RequiringJSObject(NonAbstractDataBase):
+    def _to_untrimmed_dict(self):
+        return {'someKey': 123}
+
+
+STANDARD_PARAMS = [
+    ({}, None),
+    ({
+        'data_points': [{
+            'accessibility': {
+                'description': 'Some description goes here',
+                'enabled': True
+            },
+            'className': 'some-class-name',
+            'color': '#ccc',
+            'colorIndex': 2,
+            'custom': {
+                'some_key': 123,
+                'other_key': 456
+            },
+            'description': 'Some description goes here',
+            'events': {
+                'click': """function(event) { return true; }""",
+                'drag': """function(event) { return true; }""",
+                'drop': """function(event) { return true; }""",
+                'mouseOut': """function(event) { return true; }"""
+            },
+            'id': 'some-id-goes-here',
+            'labelrank': 3,
+            'name': 'Some Name Goes here',
+            'selected': False
+        }]
+    }, None),
+    ({
+        'ndarray': np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3]
+    }, None if HAS_NUMPY else ValueError),
+    ({
+        'ndarray': np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3],
+        'data_points': [{
+            'accessibility': {
+                'description': 'Some description goes here',
+                'enabled': True
+            },
+            'className': 'some-class-name',
+            'color': '#ccc',
+            'colorIndex': 2,
+            'custom': {
+                'some_key': 123,
+                'other_key': 456
+            },
+            'description': 'Some description goes here',
+            'events': {
+                'click': """function(event) { return true; }""",
+                'drag': """function(event) { return true; }""",
+                'drop': """function(event) { return true; }""",
+                'mouseOut': """function(event) { return true; }"""
+            },
+            'id': 'some-id-goes-here',
+            'labelrank': 3,
+            'name': 'Some Name Goes here',
+            'selected': False
+        }]
+    }, None if HAS_NUMPY else ValueError),
+]
+
+
+@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)
+def test__init__(kwargs, error):
+    Class__init__(cls, kwargs, error)
+
+
+@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)
+def test__to_untrimmed_dict(kwargs, error):
+    Class__to_untrimmed_dict(cls, kwargs, error)
+
+
+@pytest.mark.parametrize('kwargs, error',  STANDARD_PARAMS)
+def test_from_dict(kwargs, error):
+    Class_from_dict(cls, kwargs, error)
+
+
+@pytest.mark.parametrize('kwargs, error',  STANDARD_PARAMS)
+def test_to_dict(kwargs, error):
+    Class_to_dict(cls, kwargs, error)
+
+
+@pytest.mark.parametrize('input_filename, expected_filename, as_file, error', [
+    ('series/data/collections/01-input.js',
+     'series/data/collections/01-expected.js',
+     False,
+     None if HAS_NUMPY else ValueError),
+
+    ('series/data/collections/02-input.js',
+     'series/data/collections/02-expected.js',
+     False,
+     None if HAS_NUMPY else ValueError),
+
+    ('series/data/collections/03-input.js',
+     'series/data/collections/03-expected.js',
+     False,
+     None),
+])
+def test_from_js_literal(input_files, input_filename, expected_filename, as_file, error):
+    Class_from_js_literal_with_expected(cls,
+                                        input_files,
+                                        input_filename,
+                                        expected_filename,
+                                        as_file,
+                                        error)
+
+if HAS_NUMPY:
+    @pytest.mark.parametrize('value, expected_shape, has_data_points, error', [
+        (np.asarray([
+            [0.0, 15.0], 
+            [10.0, -50.0], 
+            [20.0, -56.5], 
+            [30.0, -46.5], 
+            [40.0, -22.1],
+            [50.0, -2.5], 
+            [60.0, -27.7], 
+            [70.0, -55.7], 
+            [80.0, -76.5]
+        ]), (9, 2), False, None),
+        
+        ('Not an Array', None, False, ValueError),
+    ])
+    def test_from_ndarray(value, expected_shape, has_data_points, error):
+        if not error:
+            result = cls.from_ndarray(value)
+            assert result is not None
+            assert result.ndarray is not None
+            assert isinstance(result.ndarray, dict) is True
+            for key in result.ndarray:
+                key_value = result.ndarray[key]
+                assert isinstance(key_value, np.ndarray) is True
+                assert len(key_value) == expected_shape[0]
+            if has_data_points:
+                assert result.data_points is not None
+        else:
+            with pytest.raises(error):
+                result = cls.from_ndarray(value)
+            
+
+@pytest.mark.parametrize('value, expected_shape, has_ndarray, has_data_points, error', [
+    (np.asarray([
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ]) if HAS_NUMPY else [
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ], (9, 2), True, False, None),
+    ([
+        {
+            'id': 'some-value'
+        },
+        {
+            'id': 'some other value'
+        },
+    ], (9, 2), False, True, None),
+    
+    ('Not an Array', None, True, False, ValueError),
+])
+def test_from_array(value, expected_shape, has_ndarray, has_data_points, error):
+    if has_ndarray is False and has_data_points is False:
+        raise AssertionError('Test is invalid. has_ndarray or has_data_points must be '
+                             'True. Both were supplied as False.')
+    if not error:
+        result = cls.from_array(value)
+        assert result is not None
+        if has_ndarray:
+            if HAS_NUMPY:
+                assert result.ndarray is not None
+                assert isinstance(result.ndarray, dict) is True
+                for key in result.ndarray:
+                    key_value = result.ndarray[key]
+                    assert isinstance(key_value, np.ndarray) is True
+                    assert len(key_value) == expected_shape[0]
+            else:
+                assert result.array is not None or result.data_points is not None
+                if result.array:
+                    assert len(result.array) == expected_shape[0]
+                else:
+                    assert len(result.data_points) == expected_shape[0]
+        if has_data_points:
+            assert result.data_points is not None
+    else:
+        with pytest.raises(error):
+            result = cls.from_array(value)
+            
+
+@pytest.mark.parametrize('value, kwargs, expects_objects, error', [
+    (np.asarray([
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ]) if HAS_NUMPY else [
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ], {}, False, None),
+    ([
+        {
+            'id': 'some-value'
+        },
+        {
+            'id': 'some other value'
+        },
+    ], {}, True, None),
+    (np.asarray([
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ]) if HAS_NUMPY else [
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ], {'force_object': True}, True, None),
+    ([
+        {
+            'id': 'some-value'
+        },
+        {
+            'id': 'some other value'
+        },
+    ], {'force_ndarray': True}, False, None if HAS_NUMPY else ValueError),
+    
+])
+def test_to_array(value, kwargs, expects_objects, error):
+    if not error:
+        obj = cls.from_array(value)
+        result = obj.to_array(**kwargs)
+        assert result is not None
+        assert isinstance(result, list) is True
+        # assert len(result) == len(value)
+        if expects_objects:
+            for item in result:
+                assert isinstance(item, DataBase) is True
+                
+
+@pytest.mark.parametrize('kwargs, name, expected, error', [
+    ({}, 'ndarray', None, None),
+    ({}, 'data_points', None, None),
+    ({
+        'ndarray': np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3]
+    }, 'ndarray', np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3], None if HAS_NUMPY else ValueError),
+    ({
+        'ndarray': np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3]
+     },
+     'data_points',
+     None, 
+     None if HAS_NUMPY else ValueError),
+    ({
+        'ndarray': np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3],
+        'data_points': {
+            'accessibility': {
+                'description': 'Some description goes here',
+                'enabled': True
+            },
+            'className': 'some-class-name',
+            'color': '#ccc',
+            'colorIndex': 2,
+            'custom': {
+                'some_key': 123,
+                'other_key': 456
+            },
+            'description': 'Some description goes here',
+            'events': {
+                'click': """function(event) { return true; }""",
+                'drag': """function(event) { return true; }""",
+                'drop': """function(event) { return true; }""",
+                'mouseOut': """function(event) { return true; }"""
+            },
+            'id': 'some-id-goes-here',
+            'labelrank': 3,
+            'name': 'Some Name Goes here',
+            'selected': False
+        }
+    },
+     'ndarray',
+     np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3],
+     None if HAS_NUMPY else ValueError),
+    ({
+        'data_points': {
+            'accessibility': {
+                'description': 'Some description goes here',
+                'enabled': True
+            },
+            'className': 'some-class-name',
+            'color': '#ccc',
+            'colorIndex': 2,
+            'custom': {
+                'some_key': 123,
+                'other_key': 456
+            },
+            'description': 'Some description goes here',
+            'events': {
+                'click': """function(event) { return true; }""",
+                'drag': """function(event) { return true; }""",
+                'drop': """function(event) { return true; }""",
+                'mouseOut': """function(event) { return true; }"""
+            },
+            'id': 'some-id-goes-here',
+            'labelrank': 3,
+            'name': 'Some Name Goes here',
+            'selected': False
+        }
+    }, 'color', np.asarray(['#ccc']) if HAS_NUMPY else ['#ccc'], None),
+])
+def test__getattr__(kwargs, name, expected, error):
+    if not error:
+        obj = cls(**kwargs)
+        result = getattr(obj, name)
+        if name == 'ndarray':
+            if expected is None:
+                assert result is None
+            else:
+                print(type(result))
+                assert isinstance(result, dict) is True
+        elif not checkers.is_type(result, 'ndarray'):
+            assert checkers.are_equivalent(result, expected) is True
+        elif HAS_NUMPY:
+            assert np.array_equiv(result, expected) is True
+    else:
+        with pytest.raises(error):
+            obj = cls(**kwargs)
+            result = getattr(obj, name)
+            
+
+@pytest.mark.parametrize('name, value, expected, error', [
+    ('ndarray', 
+     np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3], 
+     np.array([1, 2, 3]) if HAS_NUMPY else [1, 2, 3], 
+     None if HAS_NUMPY else ValueError),
+    ('data_points', {
+            'accessibility': {
+                'description': 'Some description goes here',
+                'enabled': True
+            },
+            'className': 'some-class-name',
+            'color': '#ccc',
+            'colorIndex': 2,
+            'custom': {
+                'some_key': 123,
+                'other_key': 456
+            },
+            'description': 'Some description goes here',
+            'events': {
+                'click': """function(event) { return true; }""",
+                'drag': """function(event) { return true; }""",
+                'drop': """function(event) { return true; }""",
+                'mouseOut': """function(event) { return true; }"""
+            },
+            'id': 'some-id-goes-here',
+            'labelrank': 3,
+            'name': 'Some Name Goes here',
+            'selected': False
+        }, [DataBase(**{
+            'accessibility': {
+                'description': 'Some description goes here',
+                'enabled': True
+            },
+            'className': 'some-class-name',
+            'color': '#ccc',
+            'colorIndex': 2,
+            'custom': {
+                'some_key': 123,
+                'other_key': 456
+            },
+            'description': 'Some description goes here',
+            'events': {
+                'click': """function(event) { return true; }""",
+                'drag': """function(event) { return true; }""",
+                'drop': """function(event) { return true; }""",
+                'mouseOut': """function(event) { return true; }"""
+            },
+            'id': 'some-id-goes-here',
+            'labelrank': 3,
+            'name': 'Some Name Goes here',
+            'selected': False
+        })], None),
+])
+def test__setattr__(name, value, expected, error):
+    if not error:
+        obj = cls()
+        setattr(obj, name, value)
+        result = getattr(obj, name)
+        if name == 'ndarray':
+            if expected is None:
+                assert result is None
+            else:
+                assert isinstance(result, dict) is True
+        elif not checkers.is_type(result, 'ndarray') and name == 'data_points':
+            assert len(result) == len(expected)
+        elif not checkers.is_type(result, 'ndarray'):
+            assert checkers.are_equivalent(result, expected) is True
+        else:
+            assert np.array_equiv(result, expected) is True
+    else:
+        with pytest.raises(error):
+            obj = cls()
+            setattr(obj, name, value)
diff --git a/tests/options/series/test_area.py b/tests/options/series/test_area.py
index 41804c7..79b20af 100644
--- a/tests/options/series/test_area.py
+++ b/tests/options/series/test_area.py
@@ -14,7 +14,7 @@
 from highcharts_stock import errors
 from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
     Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
-    Class_from_js_literal
+    Class_from_js_literal, run_pandas_tests
 
 STANDARD_PARAMS = [
     ({}, None),
@@ -1394,6 +1394,44 @@ def test_AreaSeries_to_dict(kwargs, error):
 def test_AreaSeries_from_js_literal(input_files, filename, as_file, error):
     Class_from_js_literal(cls, input_files, filename, as_file, error)
 
+
+@pytest.mark.parametrize('filename, target_type, as_cls, error', [
+    ('series/area/01.js', 'line', False, None),
+    ('series/area/02.js', 'line', False, None),
+    ('series/area/03.js', 'line', False, None),
+
+    ('series/area/01.js', 'line', True, None),
+    ('series/area/02.js', 'line', True, None),
+    ('series/area/03.js', 'line', True, None),
+
+    ('series/area/01.js', 'not a series type', False, ValueError),
+    ('series/area/01.js', 123, False, ValueError),
+
+])
+def test_convert_to(input_files, filename, target_type, as_cls, error):
+    input_file = check_input_file(input_files, filename)
+    if not error:
+        from highcharts_stock.options.series.series_generator import SERIES_CLASSES
+
+        original = cls.from_js_literal(input_file)
+
+        if isinstance(target_type, str):
+            target_type_cls = SERIES_CLASSES.get(target_type)
+            target_type_name = target_type
+        else:
+            target_type_cls = target_type
+            target_type_name = target_type.__name__
+
+        if as_cls:
+            target_type = target_type_cls
+        else:
+            target_type = target_type_name
+        
+        converted = original.convert_to(target_type)
+        assert converted is not None
+        assert isinstance(converted, cls)
+        assert isinstance(converted, target_type_cls)
+
 #### NEXT CLASS
 
 STANDARD_PARAMS_2 = [
@@ -1736,7 +1774,7 @@ def test_AreaSeries_from_js_literal(input_files, filename, as_file, error):
               'symbol': 'circle',
               'width': 48
             },
-            'name': 'some category'
+            'x': 'some category'
           },
           {
             'dataLabels': {
@@ -2730,6 +2768,353 @@ def test_LineSeries_from_js_literal(input_files, filename, as_file, error):
     Class_from_js_literal(cls5, input_files, filename, as_file, error)
 
 
+@pytest.mark.parametrize('filename, error', [
+    ('test-data-files/nst-est2019-01.csv', None),
+])
+def test_LineSeries_from_pandas_in_rows(run_pandas_tests, input_files, filename, error):
+    if not run_pandas_tests:
+        return
+
+    import pandas
+    
+    input_file = check_input_file(input_files, filename)
+    df = pandas.read_csv(input_file, header = 0, thousands = ',')
+    df.index = df['Geographic Area']
+    df = df.drop(columns = ['Geographic Area'])
+    print(df)
+    
+    if not error:
+        result = cls5.from_pandas_in_rows(df)
+        assert result is not None
+        assert isinstance(result, list)
+        assert len(result) == len(df)
+        for series in result:
+            assert isinstance(series, cls5)
+            assert series.data is not None
+            assert len(series.data) == len(df.columns)
+    else:
+        with pytest.raises(error):
+            result = cls5.from_pandas_in_rows(df)
+
+
+def prep_df(df):
+    df.index = df['Geographic Area']
+    df = df.drop(columns = ['Geographic Area'])
+    
+    return df
+
+
+def reduce_to_two_columns(df):
+    df = df[['Geographic Area', '2010']]
+    
+    return df
+
+
+@pytest.mark.parametrize('filename, kwargs, pre_test_df_func, expected_series, expected_data_points, error', [
+    # SCENARIO 0: Series in Rows
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'series_in_rows': True
+     },
+     prep_df,
+     57,
+     10,
+     None),
+    
+    # SCENARIO 1a: Has Property Map, Single Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'property_map': {
+             'name': 'Geographic Area',
+         },
+         'series_in_rows': False
+     },
+     None,
+     1,
+     57,
+     None),
+
+    # SCENARIO 1b: Has Property Map, Multiple Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'property_map': {
+             'x': ['Geographic Area', '2010']
+         },
+         'series_in_rows': False
+     },
+     None,
+     2,
+     57,
+     None),
+    
+    # SCENARIO 2a: Single Property in KWARGS
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     None,
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3a: Exact Match on Column Count
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     reduce_to_two_columns,
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3b: Multiple Series, Multipled Columns
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     prep_df,
+     10,
+     57,
+     None),
+
+    # SCENARIO 4: Mismatched Columns
+    # NOTE: On SeriesBase, this will actually return one series per column.
+    # This is because SeriesBase supports 1D arrays.
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     None,
+     11,
+     57,
+     TypeError),
+    
+])
+def test_LineSeries_from_pandas(run_pandas_tests,
+                                input_files, 
+                                filename, 
+                                kwargs, 
+                                pre_test_df_func, 
+                                expected_series, 
+                                expected_data_points, 
+                                error):
+    if not run_pandas_tests:
+        return
+
+    import pandas
+
+    input_file = check_input_file(input_files, filename)
+    df = pandas.read_csv(input_file, header = 0, thousands = ',')
+    if pre_test_df_func:
+        df = pre_test_df_func(df)
+    print(df)
+
+    if not error:
+        result = cls5.from_pandas(df, **kwargs)
+        assert result is not None
+        if expected_series > 1:
+            assert isinstance(result, list)
+            assert len(result) == expected_series
+            for series in result:
+                assert isinstance(series, cls)
+                assert series.data is not None
+                assert len(series.data) == expected_data_points
+        else:
+            assert isinstance(result, cls)
+            assert result.data is not None
+            assert len(result.data) == len(df)
+    else:
+        with pytest.raises(error):
+            result = cls5.from_pandas(df, **kwargs)
+
+
+@pytest.mark.parametrize('kwargs, error', [
+    ({
+        'as_string_or_file': "'Date','HeadCount'\r\n'01/01/2023','2'\r\n'01/02/2023','4'\r\n'01/03/2023','8'",
+        'property_column_map': {'x': 'Date', 'y': 'HeadCount', 'id': 'Date'}
+     }, None),
+    ({
+        'as_string_or_file': "Date,HeadCount\r\n01/01/2023,2\r\n01/02/2023,4\r\n01/03/2023,8",
+        'property_column_map': {'x': 'Date', 'y': 'HeadCount', 'id': 'Date'}
+     }, None),
+
+])
+def test_bugfix32_LineSeries_from_csv(kwargs, error):
+    if not error:
+        result = cls5.from_csv(**kwargs)
+        assert result is not None
+        assert isinstance(result, cls5) is True
+        assert result.data is not None
+        for item in result.data:
+            assert item.x is not None or item.name is not None
+            assert item.y is not None
+            assert item.id is not None
+
+
+@pytest.mark.parametrize('filename, expected_series, expected_data_points, error', [
+    ('test-data-files/nst-est2019-01.csv', 57, 10, None),
+])
+def test_LineSeries_from_csv_in_rows(input_files, filename, expected_series, expected_data_points, error):
+    input_file = check_input_file(input_files, filename)
+    if not error:
+        result = cls5.from_csv_in_rows(input_file,
+                                       wrapper_character = '"')
+        assert result is not None
+        assert isinstance(result, list)
+        assert len(result) == expected_series
+        for series in result:
+            assert isinstance(series, cls5)
+            assert series.data is not None
+            assert len(series.data) == expected_data_points
+    else:
+        with pytest.raises(error):
+            result = cls5.from_pandas_in_rows(input_file)
+
+
+@pytest.mark.parametrize('filename, property_map, kwargs, expected_series, expected_data_points, error', [
+    ('test-data-files/nst-est2019-01.csv', 
+     {}, 
+     {
+         'wrapper_character': '"'
+     },
+     10,
+     57,
+     None),
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'name': 'Geographic Area',
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     {
+         'wrapper_character': '"'
+     },
+     1,
+     57,
+     None),
+
+    # SCENARIO 0: Series in Rows
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     {
+         'wrapper_character': '"',
+         'series_in_rows': True
+     },
+     57,
+     10,
+     None),
+    
+    # SCENARIO 1a: Has Property Map, Single Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'name': 'Geographic Area'
+     },
+     {
+         'wrapper_character': '"',
+         'series_in_rows': False
+     },
+     1,
+     57,
+     None),
+
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     {
+         'wrapper_character': '"'
+     },
+     1,
+     57,
+     None),
+
+    # SCENARIO 1b: Has Property Map, Multiple Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'x': ['Geographic Area', '2010']
+     },
+     {
+         'series_in_rows': False,
+         'wrapper_character': '"'
+          },
+     2,
+     57,
+     None),
+    
+    # SCENARIO 2a: Single Property in KWARGS
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     {
+         'wrapper_character': '"',
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3a: Exact Match on Column Count
+    ('test-data-files/nst-est2019-01-reduced-to-two.csv',
+     {},
+     {
+         'wrapper_character': '"'
+     },
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3b: Multiple Series, Multipled Columns
+    ('test-data-files/nst-est2019-01-removed-column.csv',
+     {},
+     {
+         'wrapper_character': '"'
+     },
+     9,
+     57,
+     None),
+
+    # SCENARIO 4: Mismatched Columns
+    # NOTE: On SeriesBase, this will actually return one series per column.
+    # This is because SeriesBase supports 1D arrays.
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     {
+         'wrapper_character': '"'
+     },
+     10,
+     57,
+     None),
+    
+])
+def test_LineSeries_from_csv(input_files, filename, property_map, kwargs, expected_series, expected_data_points, error):
+    input_file = check_input_file(input_files, filename)
+    
+    if not error:
+        result = cls5.from_csv(input_file,
+                               property_column_map = property_map,
+                               **kwargs)
+        assert result is not None
+        if isinstance(result, list):
+            assert len(result) == expected_series
+            for series in result:
+                assert isinstance(series, cls5)
+                assert series.data is not None
+                assert len(series.data) == expected_data_points
+        else:
+            assert isinstance(result, cls5)
+            assert result.data is not None
+            for item in result.data:
+                for key in property_map:
+                    if key == 'x':
+                        x_value = getattr(item, 'x', None)
+                        if x_value is None:
+                            assert getattr(item, 'name', None) is not None
+                    else:
+                        assert getattr(item, key, None) is not None
+
+    else:
+        with pytest.raises(error):
+            result = cls5.from_csv(input_file, 
+                                   property_column_map = property_map,
+                                   **kwargs)
+
+
 #### NEXT CLASS
 
 @pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)
diff --git a/tests/options/series/test_bar.py b/tests/options/series/test_bar.py
index 742f67c..f35559c 100644
--- a/tests/options/series/test_bar.py
+++ b/tests/options/series/test_bar.py
@@ -1,8 +1,10 @@
 """Tests for ``highcharts.no_data``."""
 
 import pytest
+import numpy as np
 
 from json.decoder import JSONDecodeError
+from validator_collection import checkers
 
 from highcharts_stock.options.series.bar import BaseBarSeries as cls
 from highcharts_stock.options.series.bar import BarSeries as cls2
@@ -15,6 +17,8 @@
 from highcharts_stock.options.series.bar import WindBarbSeries as cls9
 from highcharts_stock.options.series.bar import XRangeSeries as cls10
 from highcharts_stock import errors
+
+
 from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
     Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
     Class_from_js_literal
@@ -904,6 +908,89 @@ def test_BarSeries_from_js_literal(input_files, filename, as_file, error):
     Class_from_js_literal(cls2, input_files, filename, as_file, error)
 
 
+@pytest.mark.parametrize('kwargs, name, expected, error', [
+    ({'data': [[1, 2], [3, 4], [5, 6]]},
+     'data', 
+     cls2._data_point_class().from_array([[1, 2], [3, 4], [5, 6]]),
+     None),
+    ({'data': np.asarray([[1, 2], [3, 4], [5, 6]])},
+     'data',
+     cls2._data_collection_class().from_ndarray(np.asarray([[1, 2], [3, 4], [5, 6]])),
+     None),
+    ({'data': [[1, 2], [3, 4], [5, 6]]},
+     'x', 
+     np.asarray([1, 3, 5]),
+     None),
+    ({'data': [[1, 2], [3, 4], [5, 6]]},
+     'y', 
+     np.asarray([2, 4, 6]),
+     None),
+    ({'data': np.asarray([[1, 2], [3, 4], [5, 6]])},
+     'x', 
+     np.asarray([1, 3, 5]),
+     None),
+    ({'data': np.asarray([[1, 2], [3, 4], [5, 6]])},
+     'y', 
+     np.asarray([2, 4, 6]),
+     None),
+])
+def test_BarSeries__getattr__(kwargs, name, expected, error):
+    if not error:
+        obj = cls2(**kwargs)
+        result = getattr(obj, name)
+        if not checkers.is_type(expected, 'ndarray'):
+            assert result == expected
+        else:
+            assert np.array_equiv(result, expected) is True
+    else:
+        with pytest.raises(error):
+            obj = cls(**kwargs)
+            result = getattr(obj, name)
+
+
+@pytest.mark.parametrize('name, value, expected, error', [
+    ('data',
+     [[1, 2], [3, 4], [5, 6]],
+     cls2._data_point_class().from_array([[1, 2], [3, 4], [5, 6]]),
+     None),
+    ('data', 
+     np.asarray([[1, 2], [3, 4], [5, 6]]),
+     cls2._data_collection_class().from_ndarray(np.asarray([[1, 2], [3, 4], [5, 6]])),
+     None),
+    ('x',
+     [1, 3, 5],
+     np.asarray([1, 3, 5]),
+     None),
+    ('y',
+     [2, 4, 6],
+     np.asarray([2, 4, 6]),
+     None),
+    ('x',
+     np.asarray([1, 3, 5]),
+     np.asarray([1, 3, 5]),
+     None),
+    ('y',
+     np.asarray([2, 4, 6]),
+     np.asarray([2, 4, 6]),
+     None),
+])
+def test_BarSeries__setattr__(name, value, expected, error):
+    if not error:
+        obj = cls()
+        setattr(obj, name, value)
+        result = getattr(obj, name)
+        if not checkers.is_type(expected, 'ndarray') and name == 'data_points':
+            assert len(result) == len(expected)
+        elif not checkers.is_type(expected, 'ndarray'):
+            assert result == expected
+        else:
+            assert np.array_equiv(result, expected) is True
+    else:
+        with pytest.raises(error):
+            obj = cls()
+            setattr(obj, name, value)
+
+
 # NEXT CLASS!
 
 @pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)
diff --git a/tests/options/series/test_base.py b/tests/options/series/test_base.py
index d6c381d..34348e5 100644
--- a/tests/options/series/test_base.py
+++ b/tests/options/series/test_base.py
@@ -9,6 +9,8 @@
 from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
     Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
     Class_from_js_literal
+    
+from validator_collection import checkers
 
 STANDARD_PARAMS = [
     ({}, None),
@@ -655,3 +657,54 @@ def test_to_dict(kwargs, error):
 ])
 def test_from_js_literal(input_files, filename, as_file, error):
     Class_from_js_literal(cls, input_files, filename, as_file, error)
+
+
+@pytest.mark.parametrize('kwargs, error', STANDARD_PARAMS)
+def test_to_chart(kwargs, error):
+    if not error:
+        instance = cls(**kwargs)
+        chart = instance.to_chart()
+        assert chart is not None
+        assert checkers.is_type(chart, 'Chart')
+    else:
+        with pytest.raises(error):
+            instance = cls(**kwargs)
+            chart = instance.to_chart()
+
+
+@pytest.mark.parametrize('filename, target_type, as_cls, error', [
+    ('series/base/01.js', 'line', False, None),
+    ('series/base/02.js', 'line', False, None),
+    ('series/base/03.js', 'line', False, None),
+
+    ('series/base/01.js', 'line', True, None),
+    ('series/base/02.js', 'line', True, None),
+    ('series/base/03.js', 'line', True, None),
+
+    ('series/base/01.js', 'not a series type', False, ValueError),
+    ('series/base/01.js', 123, False, ValueError),
+])
+def test_convert_to(input_files, filename, target_type, as_cls, error):
+    input_file = check_input_file(input_files, filename)
+    if not error:
+        from highcharts_stock.options.series.base import SeriesBase
+        from highcharts_stock.options.series.series_generator import SERIES_CLASSES
+
+        original = cls.from_js_literal(input_file)
+
+        if isinstance(target_type, str):
+            target_type_cls = SERIES_CLASSES.get(target_type)
+            target_type_name = target_type
+        else:
+            target_type_cls = target_type
+            target_type_name = target_type.__name__
+
+        if as_cls:
+            target_type = target_type_cls
+        else:
+            target_type = target_type_name
+        
+        converted = original.convert_to(target_type)
+        assert converted is not None
+        assert isinstance(converted, SeriesBase)
+        assert isinstance(converted, target_type_cls)
\ No newline at end of file
diff --git a/tests/test_chart.py b/tests/test_chart.py
index 4bca83a..9802006 100644
--- a/tests/test_chart.py
+++ b/tests/test_chart.py
@@ -1,6 +1,11 @@
 """Tests for ``highcharts.no_data``."""
 
 import pytest
+try:
+    import numpy as np
+    HAS_NUMPY = True
+except ImportError:
+    HAS_NUMPY = False
 
 from json.decoder import JSONDecodeError
 
@@ -8,7 +13,7 @@
 from highcharts_stock import errors
 from tests.fixtures import input_files, check_input_file, to_camelCase, to_js_dict, \
     Class__init__, Class__to_untrimmed_dict, Class_from_dict, Class_to_dict, \
-    Class_from_js_literal, Class_from_js_literal_with_expected
+    Class_from_js_literal, Class_from_js_literal_with_expected, run_pandas_tests
 
 STANDARD_PARAMS = [
     ({}, None),
@@ -52,3 +57,421 @@ def test_from_js_literal(input_files, input_filename, expected_filename, as_file
                                         expected_filename,
                                         as_file,
                                         error)
+
+
+@pytest.mark.parametrize('kwargs, expected_series, expected_data_points, error', [
+    ({}, 0, [], None),
+
+    ({
+        'series': [
+            {
+                'data': [[1, 2], [3, 4]],
+                'type': 'line'
+            }
+        ]
+    }, 1, [(0, 2)], None),
+    ({
+        'series': {
+            'data': [[1, 2], [3, 4]],
+            'type': 'line'
+        }
+    }, 1, [(0, 2)], None),
+    
+    ({
+        'data': [[1, 2], [3, 4]],
+        'series_type': 'line'
+    }, 1, [(0, 2)], None),
+
+    ({
+        'data': [[1, 2], [3, 4]],
+    }, 1, [(0, 2)], errors.HighchartsValueError),
+
+])
+def test_issue90_one_shot_creation(kwargs, expected_series, expected_data_points, error):
+    if not error:
+        result = cls(**kwargs)
+        assert result is not None
+        if kwargs:
+            assert getattr(result, 'options') is not None
+            assert getattr(result.options, 'series') is not None
+            assert len(result.options.series) == expected_series
+            for item in expected_data_points:
+                assert len(result.options.series[item[0]].data) == item[1]
+    else:
+        with pytest.raises(error):
+            result = cls(**kwargs)
+            
+
+@pytest.mark.parametrize('filename, error', [
+    ('test-data-files/nst-est2019-01.csv', None),
+])
+def test_from_pandas_in_rows(run_pandas_tests, input_files, filename, error):
+    if not run_pandas_tests:
+        return
+
+    import pandas
+    
+    input_file = check_input_file(input_files, filename)
+    df = pandas.read_csv(input_file, header = 0, thousands = ',')
+    df.index = df['Geographic Area']
+    df = df.drop(columns = ['Geographic Area'])
+    print(df)
+    
+    if not error:
+        result = cls.from_pandas_in_rows(df)
+        assert result is not None
+        assert isinstance(result, cls)
+        assert len(result.options.series) == len(df)
+        for series in result.options.series:
+            assert series.data is not None
+            assert len(series.data) == len(df.columns)
+    else:
+        with pytest.raises(error):
+            result = cls.from_pandas_in_rows(df)
+
+
+def prep_df(df):
+    df.index = df['Geographic Area']
+    df = df.drop(columns = ['Geographic Area'])
+    
+    return df
+
+
+def reduce_to_two_columns(df):
+    df = df[['Geographic Area', '2010']]
+    
+    return df
+
+
+@pytest.mark.parametrize('filename, kwargs, pre_test_df_func, expected_series, expected_data_points, error', [
+    # SCENARIO 0: Series in Rows
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'series_in_rows': True
+     },
+     prep_df,
+     57,
+     10,
+     None),
+    
+    # SCENARIO 1a: Has Property Map, Single Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'property_map': {
+             'name': 'Geographic Area',
+         },
+         'series_in_rows': False
+     },
+     None,
+     1,
+     57,
+     None),
+
+    # SCENARIO 1b: Has Property Map, Multiple Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'property_map': {
+             'x': ['Geographic Area', '2010']
+         },
+         'series_in_rows': False
+     },
+     None,
+     2,
+     57,
+     None),
+    
+    # SCENARIO 2a: Single Property in KWARGS
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     None,
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3a: Exact Match on Column Count
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     reduce_to_two_columns,
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3b: Multiple Series, Multipled Columns
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     prep_df,
+     10,
+     57,
+     None),
+
+    # SCENARIO 4: Mismatched Columns
+    # NOTE: On SeriesBase, this will actually return one series per column.
+    # This is because SeriesBase supports 1D arrays.
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     None,
+     11,
+     57,
+     TypeError),
+    
+])
+def test_from_pandas(run_pandas_tests,
+                     input_files,
+                     filename,
+                     kwargs,
+                     pre_test_df_func,
+                     expected_series,
+                     expected_data_points,
+                     error):
+    if not run_pandas_tests:
+        return
+
+    import pandas
+
+    input_file = check_input_file(input_files, filename)
+    df = pandas.read_csv(input_file, header = 0, thousands = ',')
+    if pre_test_df_func:
+        df = pre_test_df_func(df)
+    print(df)
+
+    if not error:
+        result = cls.from_pandas(df, **kwargs)
+        assert result is not None
+        assert isinstance(result, cls)
+        assert len(result.options.series) == expected_series
+        for series in result.options.series:
+            assert series.data is not None
+            assert len(series.data) == expected_data_points
+    else:
+        with pytest.raises(error):
+            result = cls.from_pandas(df, **kwargs)
+
+
+@pytest.mark.parametrize('filename, expected_series, expected_data_points, error', [
+    ('test-data-files/nst-est2019-01.csv', 57, 10, None),
+])
+def test_from_csv_in_rows(input_files, filename, expected_series, expected_data_points, error):
+    input_file = check_input_file(input_files, filename)
+    if not error:
+        result = cls.from_csv_in_rows(input_file,
+                                      wrapper_character = '"')
+        assert result is not None
+        assert isinstance(result, cls)
+        assert result.options is not None
+        assert result.options.series is not None
+        assert isinstance(result.options.series, list)
+        assert len(result.options.series) == expected_series
+        for series in result.options.series:
+            assert series.data is not None
+            assert len(series.data) == expected_data_points
+    else:
+        with pytest.raises(error):
+            result = cls.from_pandas_in_rows(input_file)
+
+
+@pytest.mark.parametrize('filename, property_map, kwargs, expected_series, expected_data_points, error', [
+    ('test-data-files/nst-est2019-01.csv', 
+     {}, 
+     {
+         'wrapper_character': '"'
+     },
+     10,
+     57,
+     None),
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'name': 'Geographic Area',
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     {
+         'wrapper_character': '"'
+     },
+     1,
+     57,
+     None),
+
+    # SCENARIO 0: Series in Rows
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     {
+         'wrapper_character': '"',
+         'series_in_rows': True
+     },
+     57,
+     10,
+     None),
+    
+    # SCENARIO 1a: Has Property Map, Single Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'name': 'Geographic Area'
+     },
+     {
+         'wrapper_character': '"',
+         'series_in_rows': False
+     },
+     1,
+     57,
+     None),
+
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     {
+         'wrapper_character': '"'
+     },
+     1,
+     57,
+     None),
+
+    # SCENARIO 1b: Has Property Map, Multiple Series
+    ('test-data-files/nst-est2019-01.csv',
+     {
+         'x': ['Geographic Area', '2010']
+     },
+     {
+         'series_in_rows': False,
+         'wrapper_character': '"'
+          },
+     2,
+     57,
+     None),
+    
+    # SCENARIO 2a: Single Property in KWARGS
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     {
+         'wrapper_character': '"',
+         'x': 'Geographic Area',
+         'y': '2010'
+     },
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3a: Exact Match on Column Count
+    ('test-data-files/nst-est2019-01-reduced-to-two.csv',
+     {},
+     {
+         'wrapper_character': '"'
+     },
+     1,
+     57,
+     None),
+    
+    # SCENARIO 3b: Multiple Series, Multipled Columns
+    ('test-data-files/nst-est2019-01-removed-column.csv',
+     {},
+     {
+         'wrapper_character': '"'
+     },
+     9,
+     57,
+     None),
+
+    # SCENARIO 4: Mismatched Columns
+    # NOTE: On SeriesBase, this will actually return one series per column.
+    # This is because SeriesBase supports 1D arrays.
+    ('test-data-files/nst-est2019-01.csv',
+     {},
+     {
+         'wrapper_character': '"'
+     },
+     10,
+     57,
+     None),
+    
+])
+def test_from_csv(input_files, filename, property_map, kwargs, expected_series, expected_data_points, error):
+    input_file = check_input_file(input_files, filename)
+    
+    if not error:
+        result = cls.from_csv(input_file,
+                              property_column_map = property_map,
+                              **kwargs)
+        assert result is not None
+        assert isinstance(result, cls)
+        assert result.options is not None
+        assert result.options.series is not None
+        if isinstance(result.options.series, list):
+            assert len(result.options.series) == expected_series
+            for series in result.options.series:
+                assert series.data is not None
+                assert len(series.data) == expected_data_points
+    else:
+        with pytest.raises(error):
+            result = cls.from_csv(input_file,
+                                  property_column_map = property_map,
+                                  **kwargs)
+
+
+@pytest.mark.parametrize('value, expected_shape, has_ndarray, has_data_points, error', [
+    (np.asarray([
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ]) if HAS_NUMPY else [
+        [0.0, 15.0], 
+        [10.0, -50.0], 
+        [20.0, -56.5], 
+        [30.0, -46.5], 
+        [40.0, -22.1],
+        [50.0, -2.5], 
+        [60.0, -27.7], 
+        [70.0, -55.7], 
+        [80.0, -76.5]
+    ], (9, 2), True, False, None),
+    ([
+        {
+            'id': 'some-value'
+        },
+        {
+            'id': 'some other value'
+        },
+    ], (2, 2), False, True, None),
+    
+    ('Not an Array', None, True, False, ValueError),
+])
+def test_from_array(value, expected_shape, has_ndarray, has_data_points, error):
+    if has_ndarray is False and has_data_points is False:
+        raise AssertionError('Test is invalid. has_ndarray or has_data_points must be '
+                             'True. Both were supplied as False.')
+    if not error:
+        result = cls.from_array(value)
+        assert result is not None
+        assert result.options.series is not None
+        assert len(result.options.series) == 1
+        assert result.options.series[0].data is not None
+
+        if has_ndarray:
+            data = result.options.series[0].data
+            if HAS_NUMPY:
+                assert data.ndarray is not None
+                assert isinstance(data.ndarray, dict) is True
+                for key in data.ndarray:
+                    assert data.ndarray[key] is not None
+                    assert isinstance(data.ndarray[key], np.ndarray) is True
+                    assert data.ndarray[key].shape[0] == expected_shape[0]
+            else:
+                assert data.array is not None or data.data_points is not None
+                if data.array:
+                    assert len(data.array) == expected_shape[0]
+                else:
+                    assert len(data.data_points) == expected_shape[0]
+        if has_data_points:
+            assert len(result.options.series[0].data) == expected_shape[0]
+    else:
+        with pytest.raises(error):
+            result = cls.from_array(value)
diff --git a/tests/test_utility_functions.py b/tests/test_utility_functions.py
index a3a034b..3db4080 100644
--- a/tests/test_utility_functions.py
+++ b/tests/test_utility_functions.py
@@ -1,7 +1,143 @@
 """Unit tests for ``highcharts/utility_functions``"""
 
 import pytest
-
 from abc import ABC, abstractmethod
 
-from highcharts_stock import utility_functions
+try:
+    import numpy as np
+    HAS_NUMPY = True
+except ImportError:
+    HAS_NUMPY = False
+
+from validator_collection import checkers
+
+from highcharts_stock import utility_functions, constants
+
+
+@pytest.mark.parametrize('kwargs, expected_column_names, expected_records, error', [
+    ({
+        'csv_data': "Date,Header\r\n01/01/2023,2\r\n01/02/2023,4\r\n01/03/2023,8"
+     }, ['Date', 'HeadCount'], 3, None),
+])
+def test_parse_csv(kwargs, expected_column_names, expected_records, error):
+    if not error:
+        columns, records_as_dicts = utility_functions.parse_csv(**kwargs)
+        assert columns is not None
+        assert len(columns) == len(expected_column_names)
+        
+        assert records_as_dicts is not None
+        assert len(records_as_dicts) == expected_records
+    else:
+        with pytest.raises(error):
+            result = utility_functions.parse_csv(**kwargs)
+            
+
+@pytest.mark.parametrize('camelCase, expected, error', [
+    ('camelCase', 'camel_case', None),
+    ('camelCaseURL', 'camel_case_url', None),
+    ('camel123Case', 'camel123_case', None),
+])
+def test_to_snake_case(camelCase, expected, error):
+    if not error:
+        result = utility_functions.to_snake_case(camelCase)
+        assert result == expected
+    else:
+        with pytest.raises(error):
+            result = utility_functions.to_snake_case(camelCase)
+
+
+if HAS_NUMPY:
+    @pytest.mark.parametrize('value, expected_dtype, error', [
+        ([1, 2, 3], [np.int32, np.int64], None),
+        ([43934, np.nan, 65165, 81827, 112143, 142383, 171533, 165174, 155157, 161454, 154610], np.float64, None),
+        ([{'test': 123}, {'test': 456}], np.dtype('O'), None),
+
+    ])
+    def test_to_ndarray(value, expected_dtype, error):
+        if not error:
+            result = utility_functions.to_ndarray(value)
+            assert isinstance(result, np.ndarray)
+            assert result.shape[0] == len(value)
+            if isinstance(expected_dtype, list):
+                assert result.dtype in expected_dtype
+            else:
+                assert result.dtype == expected_dtype
+        else:
+            with pytest.raises(error):
+                result = utility_functions.to_ndarray(value)
+
+
+    @pytest.mark.parametrize('as_ndarray, force_enforced_null, error', [
+        (np.asarray([1, 2, 3]), False, None),
+        (np.asarray([43934, np.nan, 65165, 81827, 112143, 142383, 171533, 165174, 155157, 161454, 154610]), False, None),
+        (np.asarray([{'test': 123}, {'test': 456}]), False, None),
+        (np.asarray([1, 2, np.nan, 4, 5, 6]), False, None),
+
+        (np.asarray([1, 2, 3]), True, None),
+        (np.asarray([43934, np.nan, 65165, 81827, 112143, 142383, 171533, 165174, 155157, 161454, 154610]), True, None),
+        (np.asarray([{'test': 123}, {'test': 456}]), True, None),
+        (np.asarray([1, 2, np.nan, 4, 5, 6]), True, None),
+    ])
+    def test_from_ndarray(as_ndarray, force_enforced_null, error):
+        if not error:
+            print(as_ndarray.dtype)
+            result = utility_functions.from_ndarray(as_ndarray, 
+                                                    force_enforced_null = force_enforced_null)
+            assert isinstance(result, list)
+            assert len(result) == as_ndarray.shape[0]
+            for item in result:
+                if checkers.is_numeric(item):
+                    continue
+                if isinstance(item, dict):
+                    continue
+                if force_enforced_null:
+                    assert isinstance(item, constants.EnforcedNullType)
+                else:
+                    assert item is None
+
+    @pytest.mark.parametrize('array, index, expected, error', [
+        (np.asarray([[1, 2, 3], [4, 5, 6]]), 1, np.asarray([2, 5]), None),
+        (np.asarray([[1, 2, 3], [4, 5, 6]]), 4, np.full((2, 1), np.nan), None),
+    ])
+    def test_get_ndarray_slice(array, index, expected, error):
+        if not error:
+            result = utility_functions.get_ndarray_slice(array, index)
+            print(f'Expected:\n{expected}')
+            print(f'Result:\n{result}')
+            assert np.array_equal(expected, result, equal_nan = True)
+        else:
+            with pytest.raises(error):
+                result = utility_functions.get_ndarray_slice(array, index)
+
+
+    @pytest.mark.parametrize('value, members, error', [
+        (1, 5, None),
+        #(np.asarray([1, 2, 3]), 5, None),
+        (np.asarray([[1, 2, 3], [4, 5, 6]]), 5, None),
+    ])
+    def test_lengthen_array(value, members, error):
+        if not error:
+            result = utility_functions.lengthen_array(value, members)
+            assert isinstance(result, np.ndarray) is True
+            assert result.shape[0] == members
+            if isinstance(value, int):
+                expected = np.full((members, 1), value)
+                assert np.allclose(result, expected, atol = 1e-15, equal_nan = True)
+        else:
+            with pytest.raises(error):
+                result = utility_functions.lengthen_array(value, members)
+
+
+    @pytest.mark.parametrize('value, expected, error', [
+        (np.asarray([[1, 2, 3], [4, 5, 6]]), True, None),
+        ([1, 2, 3], True, None),
+        ([[1, 2, 3], [4, 5, 6]], True, None),
+        ('not an array', False, None),
+    ])
+    def test_is_arraylike(value, expected, error):
+        if not error:
+            result = utility_functions.is_arraylike(value)
+            assert result is expected
+        else:
+            with pytest.raises(error):
+                result = utility_functions.is_arraylike(value)
\ No newline at end of file
diff --git a/tests/utility_classes/test_buttons.py b/tests/utility_classes/test_buttons.py
index b656b6e..460d618 100644
--- a/tests/utility_classes/test_buttons.py
+++ b/tests/utility_classes/test_buttons.py
@@ -20,6 +20,8 @@
       'text': 'Button Label',
       'theme': {
           'fill': '#fff',
+          'padding': None,
+          'states': None,
           'stroke': '#ccc'
       },
       'y': 0
@@ -81,6 +83,8 @@ def test_ButtonConfiguration_from_js_literal(input_files, filename, as_file, err
       'text': 'Button Label',
       'theme': {
           'fill': '#fff',
+          'padding': None,
+          'states': None,
           'stroke': '#ccc'
       },
       'title_key': 'somevalue',