diff --git a/docs/utils.md b/docs/utils.md
index 21b41ee..6dff76d 100644
--- a/docs/utils.md
+++ b/docs/utils.md
@@ -243,3 +243,24 @@ from mapboxgl.utils import create_numeric_stops, height_map
height_stops = create_numeric_stops([0, 50, 100, 500, 1500], 0, 150000)
height = height_map(117, height_stops)
```
+
+## step_map
+Return a color or numeric value with a 'step'-type expression from given color_stops or numeric_stops; for use with 'step' expression type (color_function_type, radius_function_type, height_function_type).
+
+### Params
+**step_map**(_lookup, step_stops, default='rgb(122,122,122)'_)
+
+Parameter | Description
+--|--
+lookup | value maybe be numeric for interpolated values or string for categorical stops
+step_stops | height ramp stops generated from `create_numeric_stops`, or custom list of numeric or categorical stops with paired heights
+default | default value (color or numeric) used for values below the minimum color or numeric break
+
+### Usage
+```python
+from mapboxgl.utils import create_color_stops, step_map
+
+# assign color with a step function
+color_stops = create_color_stops([0, 50, 100, 500, 1500], colors='YlOrRd')
+color = step_map(73, color_stops, 'white')
+```
diff --git a/docs/viz.md b/docs/viz.md
index a4e8b36..dea386b 100644
--- a/docs/viz.md
+++ b/docs/viz.md
@@ -102,6 +102,19 @@ Generate stops array for use with match expression in mapbox template.
Determines if features are defined as vector source based on MapViz arguments.
+## class ExpressionsMixin
+
+The `ExpressionsMixin` class is a parent class of the various `mapboxgl-jupyter` visualizations supporting validations of the combinations of viz settings and selected expression types before rendering the map. `CircleViz`, `GraduatedCircleViz`, `HeatmapViz`, `ChoroplethViz`, and `LinestringViz` inherit from this mixin class.
+
+### Methods
+**validate_function_types**(_self_)
+Raise an error if color_function_type, radius_function_type, or height_function_type do not match the allowed values (one of `interpolate`, `match`, `identity`, or `step`.)
+
+**validate_legend_settings**(_self_)
+Warning if the property function_type for the legend property is `identity` and `self.legend = True`. Legend will not display with `identity`.
+Also raises an error if `legend_gradient` is True and color_function_type is one of `identity` or `step`.
+
+
## class CircleViz
The `CircleViz` class handles the creation of a circle map and is built on top of the `MapViz` class.
@@ -114,8 +127,8 @@ Parameter | Description
data | name of GeoJson file or object or JSON join-data
color_property | property to determine circle color
color_stops | property to determine circle color
-color_default | color of circle to use if no lookup value matches the property value. Only used for the **match** color_function_type.
-color_function_type | property to determine `type` used by Mapbox to assign color. One of 'interpolate' or 'match'. Default is interpolate
+color_default | color of circle to use if no lookup value matches the property value. Only used for the **match** or **step** color_function_type.
+color_function_type | property to determine `type` used by Mapbox to assign color. One of 'interpolate', 'match', 'identity' or 'step'. Default is interpolate
stroke_color | color of circle outline stroke
stroke_width | width (in pixels) of circle outline stroke
@@ -233,12 +246,12 @@ Parameter | Description
data | name of GeoJson file or object or JSON join-data
color_property | property to determine circle color.
color_stops | property to determine circle color.
-color_default | color of the circle to use if no lookup value matches the property value. Only used for the **match** color_function_type.
-color_function_type | property to determine `type` used by Mapbox to assign color. One of "interpolate" or "match". Default is interpolate.
+color_default | color of the circle to use if no lookup value matches the property value. Only used for the **match** or **step** color_function_type.
+color_function_type | property to determine `type` used by Mapbox to assign color. One of "interpolate", "match", "identity" or "step". Default is interpolate.
radius_property | property to determine circle radius.
radius_stops | property to determine circle radius.
-radius_default | radius of the circle to use if no lookup value matches the property value. Only used for the **match** radius_function_type.
-radius_function_type | property to determine `type` used by Mapbox to assign radius size. One of "interpolate" or "match". Default is interpolate.
+radius_default | radius of the circle to use if no lookup value matches the property value. Only used for the **match** or **step** radius_function_type.
+radius_function_type | property to determine `type` used by Mapbox to assign radius size. One of "interpolate", "match", "identity" or "step". Default is interpolate.
stroke_color | Color of stroke outline on circles
stroke_width | Width of stroke outline on circles
@@ -368,7 +381,7 @@ data | can be either GeoJSON (containing polygon features) or JSON for data-join
label_property | property to use for marker label | 'density'
color_property | property to determine fill color | 'density'
color_stops | property to determine fill color | [[0, 'red'], [0.5, 'blue'], [1, 'green']]
-color_default | property to determine default fill color in match lookups | '#F0F0F0'
+color_default | property to determine default fill color in match lookups and step lookups | '#F0F0F0'
color_function_type | property to determine type of expression used by Mapbox to assign color | 'interpolate'
line_color | property to determine choropleth border line color | '#FFFFFF'
line_stroke | property to determine choropleth border line stroke (one of solid (-), dashed (--), dotted (:), dash dot (-.)) | 'solid' or '-'
diff --git a/examples/data/state_colors.geojson b/examples/data/state_colors.geojson
new file mode 100644
index 0000000..790ab8c
--- /dev/null
+++ b/examples/data/state_colors.geojson
@@ -0,0 +1,97 @@
+{
+ "type": "FeatureCollection",
+ "features": [
+ {
+ "type": "Feature",
+ "id": "49",
+ "properties": {
+ "name": "Utah",
+ "density": 34.3,
+ "color": "gold",
+ "height": 100000
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [-112.164359, 41.995232],
+ [-111.047063, 42.000709],
+ [-111.047063, 40.998429],
+ [-109.04798, 40.998429],
+ [-109.053457, 39.125316],
+ [-109.058934, 38.27639],
+ [-109.042503, 38.166851],
+ [-109.042503, 37.000263],
+ [-110.499369, 37.00574],
+ [-114.048427, 37.000263],
+ [-114.04295, 41.995232],
+ [-112.164359, 41.995232]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "08",
+ "properties": {
+ "name": "Colorado",
+ "density": 49.33,
+ "color": "skyblue",
+ "height": 300000
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [-107.919731, 41.003906],
+ [-105.728954, 40.998429],
+ [-104.053011, 41.003906],
+ [-102.053927, 41.003906],
+ [-102.053927, 40.001626],
+ [-102.042974, 36.994786],
+ [-103.001438, 37.000263],
+ [-104.337812, 36.994786],
+ [-106.868158, 36.994786],
+ [-107.421329, 37.000263],
+ [-109.042503, 37.000263],
+ [-109.042503, 38.166851],
+ [-109.058934, 38.27639],
+ [-109.053457, 39.125316],
+ [-109.04798, 40.998429],
+ [-107.919731, 41.003906]
+ ]
+ ]
+ }
+ },
+ {
+ "type": "Feature",
+ "id": "56",
+ "properties": {
+ "name": "Wyoming",
+ "density": 5.851,
+ "color": "orange",
+ "height": 200000
+ },
+ "geometry": {
+ "type": "Polygon",
+ "coordinates": [
+ [
+ [-109.080842, 45.002073],
+ [-105.91517, 45.002073],
+ [-104.058488, 44.996596],
+ [-104.053011, 43.002989],
+ [-104.053011, 41.003906],
+ [-105.728954, 40.998429],
+ [-107.919731, 41.003906],
+ [-109.04798, 40.998429],
+ [-111.047063, 40.998429],
+ [-111.047063, 42.000709],
+ [-111.047063, 44.476286],
+ [-111.05254, 45.002073],
+ [-109.080842, 45.002073]
+ ]
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/notebooks/identity_example.ipynb b/examples/notebooks/identity_example.ipynb
new file mode 100644
index 0000000..8f0d78d
--- /dev/null
+++ b/examples/notebooks/identity_example.ipynb
@@ -0,0 +1,663 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "True\n"
+ ]
+ },
+ {
+ "data": {
+ "text/html": [
+ ""
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "from mapboxgl.viz import *\n",
+ "viz = ChoroplethViz('../data/state_colors.geojson', \n",
+ " access_token=os.getenv('MAPBOX_ACCESS_TOKEN'),\n",
+ " center=(-96, 42), \n",
+ " zoom=3,\n",
+ " color_function_type='identity',\n",
+ " height_function_type='identity',\n",
+ " pitch=60,\n",
+ " height='200px',\n",
+ " legend=False)\n",
+ "viz.show()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.6.1"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/mapboxgl/errors.py b/mapboxgl/errors.py
index 435b274..48d7a36 100644
--- a/mapboxgl/errors.py
+++ b/mapboxgl/errors.py
@@ -2,10 +2,6 @@ class TokenError(ValueError):
pass
-class ValueError(ValueError):
- pass
-
-
class SourceDataError(ValueError):
pass
@@ -15,4 +11,8 @@ class LegendError(ValueError):
class DateConversionError(ValueError):
+ pass
+
+
+class ExpressionTypeError(ValueError):
pass
\ No newline at end of file
diff --git a/mapboxgl/templates/choropleth.html b/mapboxgl/templates/choropleth.html
index 7f9c0dd..fcfc702 100644
--- a/mapboxgl/templates/choropleth.html
+++ b/mapboxgl/templates/choropleth.html
@@ -13,13 +13,13 @@
{% if extrudeChoropleth %}
{% if colorStops and colorProperty and heightProperty %}
{% if colorProperty != heightProperty and extrudeChoropleth %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }} vs. {{ heightProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }} vs. {{ heightProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% else %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% endif %}
{% endif %}
{% else %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% endif %}
{% endif %}
diff --git a/mapboxgl/templates/circle.html b/mapboxgl/templates/circle.html
index 594cbee..cda799e 100644
--- a/mapboxgl/templates/circle.html
+++ b/mapboxgl/templates/circle.html
@@ -11,7 +11,7 @@
{% if showLegend %}
{% if colorStops and colorProperty %}
- calcColorLegend({{ colorStops }} , "{{ colorProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% endif %}
{% endif %}
diff --git a/mapboxgl/templates/clustered_circle.html b/mapboxgl/templates/clustered_circle.html
index f139985..107026d 100644
--- a/mapboxgl/templates/clustered_circle.html
+++ b/mapboxgl/templates/clustered_circle.html
@@ -10,7 +10,7 @@
{% block legend %}
{% if showLegend %}
- calcColorLegend({{ colorStops }}, "Point Density");
+ calcColorLegend({{ colorStops }}, "Point Density", "interpolate", "{{ defaultColor }}");
{% endif %}
{% endblock legend %}
@@ -85,7 +85,7 @@
"circle-color": ["case",
["boolean", ["feature-state", "hover"], false],
"{{ highlightColor }}",
- "{{ colorDefault }}"],
+ "{{ defaultColor }}"],
"circle-radius" : generateInterpolateExpression( 'zoom', [[0, {{ radiusDefault }} ], [22,10 * {{ radiusDefault }}]]),
"circle-stroke-color": ["case",
["boolean", ["feature-state", "hover"], false],
diff --git a/mapboxgl/templates/graduated_circle.html b/mapboxgl/templates/graduated_circle.html
index 429af2e..46dd9e4 100644
--- a/mapboxgl/templates/graduated_circle.html
+++ b/mapboxgl/templates/graduated_circle.html
@@ -13,7 +13,7 @@
{% if colorStops and colorProperty and radiusProperty %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% endif %}
diff --git a/mapboxgl/templates/linestring.html b/mapboxgl/templates/linestring.html
index 42fe980..63293cb 100644
--- a/mapboxgl/templates/linestring.html
+++ b/mapboxgl/templates/linestring.html
@@ -5,12 +5,12 @@
{% if showLegend %}
{% if colorStops and colorProperty and widthProperty %}
{% if colorProperty != widthProperty %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }} vs. {{ widthProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }} vs. {{ widthProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% else %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% endif %}
{% elif colorStops and colorProperty %}
- calcColorLegend({{ colorStops }}, "{{ colorProperty }}");
+ calcColorLegend({{ colorStops }}, "{{ colorProperty }}", "{{ colorType }}", "{{ defaultColor }}");
{% endif %}
{% endif %}
diff --git a/mapboxgl/templates/main.html b/mapboxgl/templates/main.html
index 0dfc844..d6943b3 100644
--- a/mapboxgl/templates/main.html
+++ b/mapboxgl/templates/main.html
@@ -14,9 +14,10 @@