diff --git a/cartoframes/viz/constants.py b/cartoframes/viz/constants.py index 1301e5f6d..5d81ee530 100644 --- a/cartoframes/viz/constants.py +++ b/cartoframes/viz/constants.py @@ -2,7 +2,7 @@ CARTO_VL_DEV = '/dist/carto-vl.js' CARTO_VL_URL = 'https://libs.cartocdn.com/carto-vl/{}/carto-vl.min.js'.format(CARTO_VL_VERSION) -AIRSHIP_VERSION = 'cartoframes' +AIRSHIP_VERSION = 'v2.2.0-rc.2' AIRSHIP_COMPONENTS_DEV = '/packages/components/dist/airship.js' AIRSHIP_BRIDGE_DEV = '/packages/bridge/dist/asbridge.js' AIRSHIP_MODULE_DEV = '/packages/components/dist/airship/airship.esm.js' @@ -67,4 +67,19 @@ 'time-series' ] +FORMULA_OPERATIONS_VIEWPORT = { + 'count': 'viewportCount', + 'avg': 'viewportAvg', + 'min': 'viewportMin', + 'max': 'viewportMax', + 'sum': 'viewportSum' +} + +FORMULA_OPERATIONS_GLOBAL = { + 'count': 'globalCount', + 'avg': 'globalAvg', + 'min': 'globalMin', + 'max': 'globalMax', + 'sum': 'globalSum' +} THEMES = ['dark', 'light'] diff --git a/cartoframes/viz/widget.py b/cartoframes/viz/widget.py index 15736bdfa..9d95047ca 100644 --- a/cartoframes/viz/widget.py +++ b/cartoframes/viz/widget.py @@ -11,7 +11,6 @@ class Widget(): data (dict): The widget definition for a layer. It contains the information to render a widget: `type`: 'default', 'formula', time-series', 'animation', 'category', 'histogram' `value`: A constant value or a CARTO VL expression - `options`: Options for the widget, this varies depending on the widget The widget also can display text information: `title`, `description` and `footer`. Example: @@ -94,4 +93,6 @@ def _get_options_from_data(self, data): for key, value in data.items(): if key not in attributes: options[key] = value + + options['read_only'] = data.get('read_only', False) return options diff --git a/cartoframes/viz/widget_list.py b/cartoframes/viz/widget_list.py index 9e3c7310e..2c177faa8 100644 --- a/cartoframes/viz/widget_list.py +++ b/cartoframes/viz/widget_list.py @@ -4,24 +4,26 @@ class WidgetList(object): - """List + """WidgetList Args: widgets (dict, list, Widget): The list of widgets for a layer. Example: - .. code:: - from cartoframes.viz import Widget - - WidgetList([{ - type: 'formula', - value: 'viewportSum($amount)' - title: '...', - description: '...', - footer: '...' - }, { - 'type': 'default', - 'value': '"Custom Info"', - }]) + + .. code::python + + from cartoframes.viz import Widget + + WidgetList([{ + type: 'formula', + value: 'viewportSum($amount)' + title: '...', + description: '...', + footer: '...' + }, { + 'type': 'default', + 'value': '"Custom Info"', + }]) """ def __init__(self, widgets=None): diff --git a/cartoframes/viz/widgets/__init__.py b/cartoframes/viz/widgets/__init__.py index 7380698c9..3421999b1 100644 --- a/cartoframes/viz/widgets/__init__.py +++ b/cartoframes/viz/widgets/__init__.py @@ -1,5 +1,5 @@ """ -Widget functions to generate widgets faster. +Widget helpers to generate widgets faster. """ from __future__ import absolute_import diff --git a/cartoframes/viz/widgets/animation_widget.py b/cartoframes/viz/widgets/animation_widget.py index 482d42703..d1ebb8c35 100644 --- a/cartoframes/viz/widgets/animation_widget.py +++ b/cartoframes/viz/widgets/animation_widget.py @@ -4,6 +4,42 @@ def animation_widget(**kwargs): + """Helper function for quickly creating an animated widget. + + The animation widget includes an animation status bar as well as controls to play or pause animated data. + The `filter` property of your map's style, applied to either a date or numeric field, drives both + the animation and the widget. Only **one** animation can be controlled per layer. + To learn more about creating animations visit: + - https://carto.com/developers/carto-vl/guides/animated-visualizations. + + Args: + title (str, optional): Title of widget. + description (str, optional): Description text widget placed under widget title. + footer (str, optional): Footer text placed on the widget bottom + + Returns: + cartoframes.viz.Widget: Widget with type='animation' + + Example: + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import animation_widget + + Map( + Layer( + 'seattle_collisions', + 'filter: animation($incdate, 20, fade(0.5,0.5))', + widgets=[ + animation_widget( + title='Collision Date', + description= 'Play, pause, or select the range of the animation' + )] + ) + ) + """ + data = kwargs data['type'] = 'animation' return Widget(data) diff --git a/cartoframes/viz/widgets/category_widget.py b/cartoframes/viz/widgets/category_widget.py index 32da3a03c..1e4945842 100644 --- a/cartoframes/viz/widgets/category_widget.py +++ b/cartoframes/viz/widgets/category_widget.py @@ -4,7 +4,42 @@ def category_widget(value, **kwargs): + """Helper function for quickly creating a category widget. + + Args: + value (str): Column name of the category value + title (str, optional): Title of widget. + description (str, optional): Description text widget placed under widget title. + footer (str, optional): Footer text placed on the widget bottom + read_only (boolean, optional): Interactively filter a category by selecting it in the widget. + Set to "False" by default. + + Returns: + cartoframes.viz.Widget: Widget with type='category' + + Example: + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import category_widget + + Map( + Layer( + 'seattle_collisions', + widgets=[ + category_widget( + 'collisiontype', + title='Type of Collision', + description='Select a category to filter', + ) + ] + ) + ) + """ + data = kwargs data['type'] = 'category' data['value'] = value + data['read_only'] = kwargs.get('read_only', False) return Widget(data) diff --git a/cartoframes/viz/widgets/default_widget.py b/cartoframes/viz/widgets/default_widget.py index f9969ca23..58f3dbfa5 100644 --- a/cartoframes/viz/widgets/default_widget.py +++ b/cartoframes/viz/widgets/default_widget.py @@ -4,6 +4,38 @@ def default_widget(**kwargs): + """Helper function for quickly creating a default widget. + + The default widget is a general purpose widget that can be used to provide additional information about your map. + + Args: + title (str, optional): Title of widget. + description (str, optional): Description text widget placed under widget title. + footer (str, optional): Footer text placed on the widget bottom + + Returns: + cartoframes.viz.Widget: Widget with type='default' + + Example: + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import default_widget + + Map( + Layer( + 'seattle_collisions', + widgets=[ + default_widget( + title='Road Collisions in 2018', + description='An analysis of collisions in Seattle, WA', + footer='Data source: City of Seattle' + )] + ) + ) + """ + data = kwargs data['type'] = 'default' return Widget(data) diff --git a/cartoframes/viz/widgets/formula_widget.py b/cartoframes/viz/widgets/formula_widget.py index 3ffc90cb2..bedb13ac4 100644 --- a/cartoframes/viz/widgets/formula_widget.py +++ b/cartoframes/viz/widgets/formula_widget.py @@ -1,11 +1,95 @@ from __future__ import absolute_import from ..widget import Widget +from ..constants import FORMULA_OPERATIONS_VIEWPORT, FORMULA_OPERATIONS_GLOBAL -def formula_widget(value, **kwargs): +def formula_widget(value, operation=None, **kwargs): + """Helper function for quickly creating a formula widget. + + Formula widgets calculate aggregated values ('Avg', 'Max', 'Min', 'Sum') from numeric columns + or counts of features ('Count') in a dataset. + + A formula widget's aggregations can be calculated on 'global' or 'viewport' based values. + If you want the values in a formula widget to update on zoom and/or pan, use viewport based aggregations. + + Args: + value (str): Column name of the numeric value + operation (str): attribute for widget's aggregated value ('count', 'avg', 'max', 'min', 'sum') + title (str, optional): Title of widget. + description (str, optional): Description text widget placed under widget title. + footer (str, optional): Footer text placed on the widget bottom + is_global (boolean, optional): Account for calculations based on the entire dataset ('global') vs. + the default of 'viewport' features. + + Returns: + cartoframes.viz.Widget: Widget with type='formula' + + Example: + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import formula_widget + + Map( + Layer( + 'seattle_collisions', + widgets=[ + formula_widget( + 'count', + title='Number of Collisions', + description='Zoom and/or pan the map to update count', + footer='collisions in this view' + ) + ] + ) + ) + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import formula_widget + + Map( + Layer( + 'seattle_collisions', + widgets=[ + formula_widget( + 'pedcount', + 'sum', + is_global=True, + title='Total Number of Pedestrians', + description='involved over all collisions', + footer='pedestrians' + ) + ] + ) + ) + """ + data = kwargs data['type'] = 'formula' - data['value'] = value + is_global = kwargs.get('is_global', False) + data['value'] = get_value_expression(operation, value, is_global) return Widget(data) + + +def get_formula_operation(operation, is_global): + if is_global: + return FORMULA_OPERATIONS_GLOBAL.get(operation) + else: + return FORMULA_OPERATIONS_VIEWPORT.get(operation) + + +def get_value_expression(operation, value, is_global): + if value == 'count': + formula_operation = get_formula_operation(value, is_global) + return formula_operation + '()' + else: + if operation: + formula_operation = get_formula_operation(operation, is_global) + return formula_operation + '($' + value + ')' + else: + return '$' + value diff --git a/cartoframes/viz/widgets/histogram_widget.py b/cartoframes/viz/widgets/histogram_widget.py index 83e83e8de..0c5c10bdf 100644 --- a/cartoframes/viz/widgets/histogram_widget.py +++ b/cartoframes/viz/widgets/histogram_widget.py @@ -4,7 +4,49 @@ def histogram_widget(value, **kwargs): + """Helper function for quickly creating a histogram widget. + + Histogram widgets display the distribution of a numeric attribute, in buckets, to group + ranges of values in your data. + By default, you can hover over each bar to see each bucket's values and count, and also + filter your map's data within a given range + + Args: + value (str): Column name of the numeric or date value + title (str, optional): Title of widget. + description (str, optional): Description text widget placed under widget title. + footer (str, optional): Footer text placed on the widget bottom + buckets (number, optional): Number of histogram buckets. Set to 20 by default. + read_only (boolean, optional): Interactively filter a range of numeric values by selecting them in the widget. + Set to "False" by default. + + Returns: + cartoframes.viz.Widget: Widget with type='histogram' + + Example: + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import histogram_widget + + Map( + Layer( + 'seattle_collisions', + widgets=[ + histogram_widget( + 'vehcount', + title='Number of Vehicles Involved', + description='Select a range of values to filter', + buckets=9 + ) + ] + ) + ) + """ + data = kwargs data['type'] = 'histogram' data['value'] = value + data['read_only'] = kwargs.get('read_only', False) return Widget(data) diff --git a/cartoframes/viz/widgets/time_series_widget.py b/cartoframes/viz/widgets/time_series_widget.py index f8d91b4b3..7bfb18ccb 100644 --- a/cartoframes/viz/widgets/time_series_widget.py +++ b/cartoframes/viz/widgets/time_series_widget.py @@ -4,7 +4,47 @@ def time_series_widget(value, **kwargs): + """Helper function for quickly creating a time series widget. + + The time series widget enables you to display animated data (by aggregation) over a specified date or numeric field. + Time series widgets provide a status bar of the animation, controls to play or pause, and the ability to filter on + a range of values. + + Args: + value (str): Column name of the numeric or date value + title (str, optional): Title of widget. + description (str, optional): Description text widget placed under widget title. + footer (str, optional): Footer text placed on the widget bottom + buckets (number, optional): Number of histogram buckets. Set to 20 by default. + read_only (boolean, optional): Interactively filter a range of numeric values by selecting them in the widget. + Set to "False" by default. + + Returns: + cartoframes.viz.Widget: Widget with type='time-series' + + Example: + + .. code:: + + from cartoframes.viz import Map, Layer + from cartoframes.viz.widgets import time_series_widget + + Map( + Layer( + 'seattle_collisions', + 'filter: animation($incdate, 20, fade(0.5,0.5))', + widgets=[ + time_series_widget( + value='incdate', + title='Number of Collisions by Date', + description= 'Play, pause, or select a range for the animation', + buckets=10 + )] + ) + ) + """ data = kwargs data['type'] = 'time-series' data['value'] = value + data['read_only'] = kwargs.get('read_only', False) return Widget(data) diff --git a/docs/developer-center/guides/09-Widgets-Part-1.md b/docs/developer-center/guides/09-Widgets-Part-1.md new file mode 100644 index 000000000..95d9e20f1 --- /dev/null +++ b/docs/developer-center/guides/09-Widgets-Part-1.md @@ -0,0 +1,154 @@ +## Widgets - Part 1 + +In CARTOframes it is possible to to add interactive widgets for viewing your map data. Widgets are added to your visualization and do not modify your original data. They allow you to **explore** your map using filters or adding animations, among others. + +We use Airship components for the widget's UI and Airship Bridge to connect the widget behaviour with the map. All the widgets accept the following parameters to display widget information: `title`, `description` and `footer`. + +There are a variety of widgets available to embed with your map. Widgets can be standalone, combined inside of one layer, or across multiple layers. There are two ways to add widgets (from `cartoframes.viz.widgets`): + +1. Using the `Widget` class and passing a dict +2. Using a widget helper + +For simplicity, in this guide we're going to create widgets using helper methods: + +```py +from cartoframes.viz import Map, Layer +from cartoframes.viz.widgets import formula_widget + +Map( + Layer('spend_data', + widgets=[ + formula_widget('amount', 'avg', title="Avg Amount", description="Some description", footer="data source") + ] + ) +) +``` + +The following types of widgets are currently supported: + +### Default Widgets + +The default widget is a general purpose widget that can be used to provide additional information about your map. + +```py +from cartoframes.viz import Map, Layer +from cartoframes.viz.widgets import default_widget + +Map( + Layer( + 'seattle_collisions', + widgets=[ + default_widget( + title='Road Collisions in 2018', + description='An analysis of collisions in Seattle, WA', + footer='Data source: City of Seattle' + )] + ) +) +``` + +![Default Widget](../../img/guides/widgets/default-widget.png) + +### Formula Widgets + +The Formula Widget calculates aggregated values from numeric columns. The operations supported are: avg, max, min, sum and count. By default, only the data visible in the viewport is used. In order to use all the data in the dataset, it is necessary to set `is_global` to `True`. + +- Viewport Count: `formula_widget('count')` +- Global Count: `formula_widget('count', is_global=True)` +- Viewport Average: `formula_widget('$numeric_value', 'avg')` +- Global Average: `formula_widget('$numeric_value', 'avg', is_global=True)` +- Viewport Max: `formula_widget('$numeric_value', 'max')` +- Global Max: `formula_widget('$numeric_value', 'max', is_global=True)` +- Viewport Min: `formula_widget('$numeric_value', 'min')` +- Global Min: `formula_widget('$numeric_value', 'min', is_global=True)` +- Viewport Sum: `formula_widget('$numeric_value', 'sum')` +- Global Sum: `formula_widget('$numeric_value', 'sum', is_global=True)` + +```py +from cartoframes.viz.widgets import formula_widget + +Map( + Layer( + 'seattle_collisions', + widgets=[ + formula_widget( + 'count', + title='Number of Collisions', + description='Zoom and/or pan the map to update count', + footer='collisions in this view' + ) + ] + ) +) +``` + +![Formula Viewport Widget](../../img/guides/widgets/formula-viewport-widget.gif) + +```py +from cartoframes.viz.widgets import formula_widget + +Map( + Layer( + 'seattle_collisions', + widgets=[ + formula_widget( + 'pedcount', + 'sum', + is_global=True, + title='Total Number of Pedestrians', + description='involved over all collisions', + footer='pedestrians' + ) + ] + ) +) +``` + +![Formula Global Widget](../../img/guides/widgets/formula-global-widget.gif) + +### Category Widgets + +These widgets allows you to aggregate the data and create categories. Category widgets group features from string columns into aggregated categories based on their occurence in your current map view with their associated count. As you zoom or pan the map, the category widget updates. By default, you can also select a category to filter your map's data. + +```py +from cartoframes.viz.widgets import category_widget + +Map( + Layer( + 'seattle_collisions', + widgets=[ + category_widget( + 'collisiontype', + title='Type of Collision', + description='Select a category to filter', + ) + ] + ) +) +``` + +![Category Widget](../../img/guides/widgets/category-widget.gif) + +### Histogram Widgets + +Histogram widgets display the distribution of a numeric attribute, in buckets, to group ranges of values in your data. By default, you can hover over each bar to see each bucket's values and count, and also filter your map's data within a given range. + +```py +from cartoframes.viz.widgets import histogram_widget + +Map( + Layer( + 'seattle_collisions', + widgets=[ + histogram_widget( + 'vehcount', + title='Number of Vehicles Involved', + description='Select a range of values to filter', + buckets=9 + ) + ] + ) +) +``` + +![Histogram Widget](../../img/guides/widgets/histogram-widget.gif) diff --git a/docs/developer-center/guides/09-Widgets-Part-2.md b/docs/developer-center/guides/09-Widgets-Part-2.md new file mode 100644 index 000000000..4575d1edd --- /dev/null +++ b/docs/developer-center/guides/09-Widgets-Part-2.md @@ -0,0 +1,116 @@ +## Widgets - Part 2 + +In CARTOframes it is possible to to add interactive widgets for viewing your map data. Widgets are added to your visualization and do not modify your original data. They allow you to **explore** your map using filters or adding animations, among others. + +This is the continuation of the [Widgets Part 1]({{ site.url }}/developers/cartoframes/guides/widgets-part-1/) + +### Animation Controls Widget + +This widget makes possible to control the animation present in the visualization. Only **one** animation can be controled. To add an animation, it is currently needed to understand how to create [Animated visualizations](https://carto.com/developers/carto-vl/guides/animated-visualizations/). + +The animation widget will get the animation expression from the `filter` property: + +```py +from cartoframes.viz.widgets import animation_widget + +Map( + Layer( + 'seattle_collisions', + 'filter: animation($incdate, 20, fade(0.5,0.5))', + widgets=[ + animation_widget( + title='Collision Date', + description= 'Play, pause, or select the range of the animation' + )] + ) +) +``` + +![Animation Widget](../../img/guides/widgets/animation-widget.gif) + +### Animation Widget and Style Properties + +As mentioned above, the animation widget gets the animation expression from the `filter` property: + +```py +from cartoframes.auth import set_default_context +from cartoframes.viz import Map, Layer +from cartoframes.viz.widgets import animation_widget + +Map( + Layer( + 'seattle_collisions', + 'filter: animation($incdate, 30, fade(1, 1))', + widgets=[animation_widget()] + ) +) +``` + +However, if you want to animate the features by another property, for example, by `width`, you have to provide this information to the widget throught the `prop` parameter: + +```py +from cartoframes.auth import set_default_context +from cartoframes.viz import Map, Layer +from cartoframes.viz.widgets import animation_widget + +Map( + Layer( + 'seattle_collisions', + 'width: animation(linear($incdate), 20,fade(1, 1)) * ramp(linear($personcount, 2, 5), [5, 20])', + widgets=[animation_widget(prop='width')] + ) +) +``` + +![Animation by Property Widget](../../img/guides/widgets/animation-property-widget.gif) + +### Time-Series Widget + +The time series widget enables you to display animated data (by aggregation) over a specified date or numeric field. Time series widgets provide a status bar of the animation, controls to play or pause, and the ability to filter on a range of values. + +```py +from cartoframes.viz.widgets import time_series_widget + +Map( + Layer( + 'seattle_collisions', + 'filter: animation($incdate, 20, fade(0.5,0.5))', + widgets=[ + time_series_widget( + value='incdate', + title='Number of Collisions by Date', + description= 'Play, pause, or select a range for the animation', + buckets=10 + )] + ) +) +``` + +![Time Series Widget](../../img/guides/widgets/time-series-widget.gif) + +### Combine multiple widgets + +It is possible to combine widgets on your map. The map below, uses a formula widget to count the number of pedestrian involved collisions with the address type of where the collision occured. You can filter a category and the formula widget will update to relflect the values of that category in the current map view. + +```py +from cartoframes.viz.widgets import category_widget, formula_widget + +Map( + Layer( + 'seattle_collisions', + widgets=[ + formula_widget( + 'pedcount', + 'sum', + is_global=True, + title='Total Number of Pedestrians', + description='involved over all collisions', + footer='pedestrians' + ), + category_widget('addrtype') + ] + ) +) +``` + +![Combined Widgets](../../img/guides/widgets/combine-widgets.gif) diff --git a/docs/developer-center/guides/08-Publishing.md b/docs/developer-center/guides/10-Publishing.md similarity index 100% rename from docs/developer-center/guides/08-Publishing.md rename to docs/developer-center/guides/10-Publishing.md diff --git a/docs/developer-center/guides/09-Spatial-Analysis.md b/docs/developer-center/guides/11-Spatial-Analysis.md similarity index 100% rename from docs/developer-center/guides/09-Spatial-Analysis.md rename to docs/developer-center/guides/11-Spatial-Analysis.md diff --git a/docs/developer-center/img/guides/widgets/animation-property-widget.gif b/docs/developer-center/img/guides/widgets/animation-property-widget.gif new file mode 100644 index 000000000..0be9c8332 Binary files /dev/null and b/docs/developer-center/img/guides/widgets/animation-property-widget.gif differ diff --git a/docs/developer-center/img/guides/widgets/animation-widget.gif b/docs/developer-center/img/guides/widgets/animation-widget.gif new file mode 100644 index 000000000..860bb4d03 Binary files /dev/null and b/docs/developer-center/img/guides/widgets/animation-widget.gif differ diff --git a/docs/developer-center/img/guides/widgets/category-widget.gif b/docs/developer-center/img/guides/widgets/category-widget.gif new file mode 100644 index 000000000..5b96ee58d Binary files /dev/null and b/docs/developer-center/img/guides/widgets/category-widget.gif differ diff --git a/docs/developer-center/img/guides/widgets/combine-widgets.gif b/docs/developer-center/img/guides/widgets/combine-widgets.gif new file mode 100644 index 000000000..a49ec8341 Binary files /dev/null and b/docs/developer-center/img/guides/widgets/combine-widgets.gif differ diff --git a/docs/developer-center/img/guides/widgets/default-widget.png b/docs/developer-center/img/guides/widgets/default-widget.png new file mode 100644 index 000000000..d88ce0df9 Binary files /dev/null and b/docs/developer-center/img/guides/widgets/default-widget.png differ diff --git a/docs/developer-center/img/guides/widgets/formula-global-widget.gif b/docs/developer-center/img/guides/widgets/formula-global-widget.gif new file mode 100644 index 000000000..eb8d6146e Binary files /dev/null and b/docs/developer-center/img/guides/widgets/formula-global-widget.gif differ diff --git a/docs/developer-center/img/guides/widgets/formula-viewport-widget.gif b/docs/developer-center/img/guides/widgets/formula-viewport-widget.gif new file mode 100644 index 000000000..4f44735de Binary files /dev/null and b/docs/developer-center/img/guides/widgets/formula-viewport-widget.gif differ diff --git a/docs/developer-center/img/guides/widgets/histogram-widget.gif b/docs/developer-center/img/guides/widgets/histogram-widget.gif new file mode 100644 index 000000000..6a9f8501d Binary files /dev/null and b/docs/developer-center/img/guides/widgets/histogram-widget.gif differ diff --git a/docs/developer-center/img/guides/widgets/time-series-widget.gif b/docs/developer-center/img/guides/widgets/time-series-widget.gif new file mode 100644 index 000000000..9973f84ad Binary files /dev/null and b/docs/developer-center/img/guides/widgets/time-series-widget.gif differ diff --git a/docs/maps.rst b/docs/maps.rst index 86dc6d300..e01bf68b7 100644 --- a/docs/maps.rst +++ b/docs/maps.rst @@ -32,6 +32,13 @@ Helper Functions :noindex: :members: +Widget Functions +^^^^^^^^^^^^^^^^ + +.. automodule:: cartoframes.viz.widgets + :noindex: + :members: + Vector Layers ^^^^^^^^^^^^^ diff --git a/examples/03_visualizations/03_widgets_part_1.ipynb b/examples/03_visualizations/03_widgets_part_1.ipynb new file mode 100644 index 000000000..d1c09afc4 --- /dev/null +++ b/examples/03_visualizations/03_widgets_part_1.ipynb @@ -0,0 +1,5025 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Widgets in CARTOframes\n", + "\n", + "Widgets allow you to explore, filter, and animate your map's data in CARTOframes.\n", + "\n", + "There are a variety of widgets available to embed with your map. Widgets can be standalone, combined inside of one layer, or across multiple layers. There are two ways to add widgets (from `cartoframes.viz.widgets`):\n", + "\n", + "1. Using the `Widget` class and passing a dict\n", + "2. Using a widget helper\n", + "\n", + "Click on the links below to go to a description and example of each method and available widgets in CARTOframes.\n", + "\n", + "## Widgets: Part 1\n", + "\n", + "- [Default Widget](#Default-Widget)\n", + "\n", + "- [Formula Widget](#Formula-Widget)\n", + "\n", + "- [Category Widget](#Category-Widget)\n", + "\n", + "- [Histogram Widget](#Histogram-Widget)\n", + "\n", + "\n", + "## Widgets: Part 2, Taking it Further\n", + "\n", + "- [Animation Widget](./04_widgets_part_2.ipynb#Animation-Widget)\n", + "\n", + "- [Time Series Widget](./04_widgets_part_2.ipynb#Time-Series-Widget)\n", + "\n", + "- [Combining Widgets](./04_widgets_part_2.ipynb#Combining-Widgets)\n", + "\n", + "- [Animation Widget and Style Properties](./04_widgets_part_2.ipynb#Animation-Widget-and-Style-Properties)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from cartoframes.auth import set_default_credentials\n", + "from cartoframes.viz import Map, Layer\n", + "\n", + "set_default_credentials('cartovl')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Default Widget\n", + "The default widget is a general purpose widget that can be used to provide additional information about your map. \n", + "\n", + "#### Parameters: \n", + "* **`type`** (string): widget type\n", + "* **`title`** (string,optional): widget's title \n", + "* **`description`** (string,optional): widget's description\n", + "* **`footer`** (string,optional): widget's footer\n", + "\n", + "In the example below, the default widget is used to provide general information for a map of Seattle road collisions.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Add a default widget\n", + "\n", + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[{\n", + " 'type': 'default',\n", + " 'title': 'Road Collisions in 2018',\n", + " 'description': 'An analysis of collisions in Seattle, WA',\n", + " 'footer': 'Data source: City of Seattle'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "from cartoframes.viz.widgets import default_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[\n", + " default_widget(\n", + " title='Road Collisions in 2018',\n", + " description='An analysis of collisions in Seattle, WA',\n", + " footer='Data source: City of Seattle'\n", + " )]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Formula Widget\n", + "\n", + "Formula widgets calculate aggregated values (`Avg`, `Max`, `Min`, `Sum`) from numeric columns or counts of features (`Count`) in a dataset. A formula widget's aggregations can be calculated on `global` or `viewport` based values. If you want the values in a formula widget to update on zoom and/or pan, use viewport based aggregations. \n", + "\n", + "#### Parameters:\n", + "* **`type`** (string): widget type\n", + "* **`value`** (string): attribute for widget's aggregation\n", + "* **`title`** (string,optional): widget's title \n", + "* **`description`** (string,optional): widget's description\n", + "* **`footer`** (string,optional): widget's footer\n", + "* **`is_global`** (boolean,optional): only applicable to the `formula_widget` helper method to account for calculations based on the entire dataset vs. the default of `viewport` features.\n", + "\n", + "In the example below, the formula widget is used to count the number of collisions in the map's current viewport. Since the aggregations are viewport based, the count of collisions will update any time the map is zoomed or panned." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Add a formula count widget\n", + "\n", + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[{\n", + " 'type': 'formula',\n", + " 'value': 'viewportCount()',\n", + " 'title': 'Number of Collisions',\n", + " 'description': 'Zoom and/or pan the map to update count',\n", + " 'footer': 'collisions in this view'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "from cartoframes.viz.widgets import formula_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[\n", + " formula_widget(\n", + " 'count',\n", + " title='Number of Collisions',\n", + " description='Zoom and/or pan the map to update count',\n", + " footer='collisions in this view'\n", + " )\n", + " ]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Add a formula widget based on a value in the data\n", + "\n", + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[{\n", + " 'type': 'formula',\n", + " 'value': 'globalSUM($pedcount)',\n", + " 'title': 'Total Number of Pedestrians',\n", + " 'description': 'involved over all collisions',\n", + " 'footer': 'pedestrians'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[\n", + " formula_widget(\n", + " 'pedcount',\n", + " 'sum',\n", + " is_global=True,\n", + " title='Total Number of Pedestrians',\n", + " description='involved over all collisions',\n", + " footer='pedestrians'\n", + " )\n", + " ]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Category Widget\n", + "\n", + "Category widgets group features from string columns into aggregated categories based on their occurence in your current map view with their associated count. As you zoom or pan the map, the category widget updates. By default, you can also select a category to filter your map's data.\n", + "\n", + "#### Parameters:\n", + "* **`type`** (string): widget type\n", + "* **`value`** (string): category attribute\n", + "* **`title (string, optional)`**: title text\n", + "* **`description (string, optional)`**: description text\n", + "* **`footer (string, optional)`**: footer text\n", + "* **`read_only (boolean, optional)`**: interactively filter a category by selecting it in the widget. Set to \"False\" by default." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Add a category widget\n", + "\n", + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[{\n", + " 'type': 'category',\n", + " 'value': 'collisiontype',\n", + " 'title': 'Type of Collision',\n", + " 'description': 'Select a category to filter',\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "\n", + "from cartoframes.viz.widgets import category_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[\n", + " category_widget(\n", + " 'collisiontype',\n", + " title='Type of Collision',\n", + " description='Select a category to filter',\n", + " )\n", + " ]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Histogram Widget\n", + "\n", + "Histogram widgets display the distribution of a numeric attribute, in buckets, to group ranges of values in your data. By default, you can hover over each bar to see each bucket's values and count, and also filter your map's data within a given range.\n", + "\n", + "#### Parameters:\n", + "* **`type`** (string): widget type\n", + "* **`value`** (string): numeric attribute\n", + "* **`title (string, optional)`**: title text\n", + "* **`description (string, optional)`**: description text\n", + "* **`footer (string, optional)`**: footer text\n", + "* **`buckets`** (number,optional): number of histogram buckets\n", + "* **`read_only (boolean, optional)`**: interactively filter a range of numeric values by selecting them in the widget. Set to \"False\" by default.\n", + "\n", + "In the example below, the number of vehicles involved in each collision are grouped over 9 buckets." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[{\n", + " 'type': 'histogram',\n", + " 'value': 'vehcount',\n", + " 'title': 'Number of Vehicles Involved',\n", + " 'description': 'Select a range of values to filter'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "\n", + "from cartoframes.viz.widgets import histogram_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[\n", + " histogram_widget(\n", + " 'vehcount',\n", + " title='Number of Vehicles Involved',\n", + " description='Select a range of values to filter',\n", + " buckets=9\n", + " )\n", + " ]\n", + " )\n", + ")" + ] + } + ], + "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.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/03_visualizations/04_widgets_part_2.ipynb b/examples/03_visualizations/04_widgets_part_2.ipynb new file mode 100644 index 000000000..99bc4e52d --- /dev/null +++ b/examples/03_visualizations/04_widgets_part_2.ipynb @@ -0,0 +1,5025 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Widgets in CARTOframes\n", + "\n", + "Widgets allow you to explore, filter, and animate your map's data in CARTOframes.\n", + "\n", + "There are a variety of widgets available to embed with your map. Widgets can be standalone, combined inside of one layer, or across multiple layers. There are two ways to add widgets (from `cartoframes.viz.widgets`):\n", + "\n", + "1. Using the `Widget` class and passing a dict\n", + "2. Using a widget helper\n", + "\n", + "Click on the links below to go to a description and example of each method and available widgets in CARTOframes.\n", + "\n", + "## Widgets: Part 1\n", + "\n", + "- [Default Widget](./03_widgets_part_1.ipynb#Default-Widget)\n", + "\n", + "- [Formula Widget](./03_widgets_part_1.ipynb#Formula-Widget)\n", + "\n", + "- [Category Widget](./03_widgets_part_1.ipynb#Category-Widget)\n", + "\n", + "- [Histogram Widget](./03_widgets_part_1.ipynb#Histogram-Widget)\n", + "\n", + "\n", + "## Widgets: Part 2, Taking it Further\n", + "\n", + "- [Animation Widget](#Animation-Widget)\n", + "\n", + "- [Time Series Widget](#Time-Series-Widget)\n", + "\n", + "- [Combining Widgets](#Combining-Widgets)\n", + "\n", + "- [Animation Widget and Style Properties](#Animation-Widget-and-Style-Properties)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from cartoframes.auth import set_default_credentials\n", + "from cartoframes.viz import Map, Layer\n", + "\n", + "set_default_credentials('cartovl')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Animation Widget\n", + "\n", + "The animation widget includes an animation status bar as well as controls to play or pause animated data. The `filter` property of your map's style, applied to either a date or numeric field, drives both the animation and the widget. Only **one** animation can be controlled per layer. To learn more about creating animations visit: [Animated visualizations](https://carto.com/developers/carto-vl/guides/animated-visualizations/).\n", + "\n", + "#### Parameters:\n", + "\n", + "* **`type`** (string): widget type\n", + "* **`title`** (string, optional): title text\n", + "* **`description`** (string, optional): description text\n", + "* **`footer`** (string, optional): footer text\n", + "\n", + "In the example below, collisions are animated by the date they occured. The animation can be controlled via the widget.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Add an animation widget\n", + "\n", + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'filter: animation($incdate, 20, fade(0.5,0.5))',\n", + " widgets=[{\n", + " 'type': 'animation'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "from cartoframes.viz.widgets import animation_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'filter: animation($incdate, 20, fade(0.5,0.5))',\n", + " widgets=[\n", + " animation_widget(\n", + " title='Collision Date',\n", + " description= 'Play, pause, or select the range of the animation'\n", + " )]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Time Series Widget\n", + "\n", + "The time series widget enables you to display animated data (by aggregation) over a specified date or numeric field. Time series widgets provide a status bar of the animation, controls to play or pause, and the ability to filter on a range of values.\n", + "\n", + "#### Parameters:\n", + "* **`type`** (string): widget type\n", + "* **`value`** (string): date or numeric field \n", + "* **`title`** (string, optional): title text\n", + "* **`description`** (string, optional): description text\n", + "* **`footer`** (string, optional): footer text\n", + "* **`buckets`** (number, optional): the number of time series buckets\n", + "\n", + "In the example below, collisions are animated by the date they occured. The number of incidents over time are shown in the time series widget. The animation can be controlled and date ranges filtered via the widget." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'filter: animation($incdate, 20, fade(0.5,0.5))',\n", + " widgets=[{\n", + " 'type': 'time-series'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "from cartoframes.viz.widgets import time_series_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'filter: animation($incdate, 20, fade(0.5,0.5))',\n", + " widgets=[\n", + " time_series_widget(\n", + " value='incdate',\n", + " title='Number of Collisions by Date',\n", + " description= 'Play, pause, or select a range for the animation',\n", + " buckets=10\n", + " )]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Combining Widgets\n", + "\n", + "It is possible to combine widgets on your map. The map below, uses a formula widget to count the number of pedestrian involved collisions with the address type of where the collision occured. You can filter a category and the formula widget will update to relflect the values of that category in the current map view." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Combine a category and formula widget\n", + "\n", + "from cartoframes.viz.widgets import category_widget, formula_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[\n", + " formula_widget(\n", + " 'pedcount',\n", + " 'sum',\n", + " is_global=True,\n", + " title='Total Number of Pedestrians',\n", + " description='involved over all collisions',\n", + " footer='pedestrians'\n", + " ),\n", + " category_widget('addrtype')\n", + " ]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Animation Widget and Style Properties\n", + "\n", + "As mentioned above, the animation widget gets the animation expression from the `filter` property:\n", + "\n", + "```py\n", + "from cartoframes.auth import set_default_context\n", + "from cartoframes.viz import Map, Layer\n", + "from cartoframes.viz.widgets import animation_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'filter: animation($incdate, 30, fade(1, 1))',\n", + " widgets=[animation_widget()]\n", + " )\n", + ")\n", + "```\n", + "\n", + "However, if you want to animate the features by another property, for example, by `width`, you have to provide this information to the widget throught the `prop` parameter:\n", + "\n", + "```py\n", + "from cartoframes.auth import set_default_context\n", + "from cartoframes.viz import Map, Layer\n", + "from cartoframes.viz.widgets import animation_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'width: animation(linear($incdate), 20,fade(1, 1)) * ramp(linear($personcount, 2, 5), [5, 20])',\n", + " widgets=[animation_widget(prop='width')]\n", + " )\n", + ")\n", + "```\n", + "\n", + "The map below displays two variables: the date and time a collision occured as well as the number of people involved in each incident by width. The animation widget is set to read from the `width` property of the style." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Add an animation widget\n", + "# Animate by width property\n", + "\n", + "# Using a dict\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'width: animation(linear($incdate), 20,fade(1, 1)) * ramp(linear($personcount, 2, 5), [5, 20])',\n", + " widgets=[{\n", + " 'type': 'animation',\n", + " 'prop': 'width'\n", + " }]\n", + " )\n", + ")\n", + "\n", + "# Using a helper method\n", + "from cartoframes.viz.widgets import animation_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " 'width: animation(linear($incdate), 20, fade(1,1)) * ramp(linear($personcount, 2, 5), [5, 20])',\n", + " widgets=[animation_widget(prop='width')]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Combine an animation and category widget\n", + "\n", + "from cartoframes.viz.widgets import animation_widget, category_widget\n", + "\n", + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " '''\n", + " color: ramp($addrtype, Bold)\n", + " strokeWidth: 0\n", + " width: animation(linear($incdate), 20,fade(1, 1)) * ramp(linear($personcount, 2, 5), [5, 20])\n", + " ''',\n", + " widgets=[\n", + " animation_widget(prop='width'),\n", + " category_widget('addrtype')\n", + " ]\n", + " )\n", + ")" + ] + }, + { + "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.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/06_advanced/visualize-temperatures.ipynb b/examples/06_advanced/visualize-temperatures.ipynb new file mode 100644 index 000000000..3249c50fe --- /dev/null +++ b/examples/06_advanced/visualize-temperatures.ipynb @@ -0,0 +1,1153 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "from cartoframes.auth import set_default_credentials\n", + "from cartoframes.viz import Map, Layer, Legend, Widget, basemaps\n", + "\n", + "set_default_credentials('cartovl')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " Issued: 7/17/19 | Source: NOAA Weather Predicition Center\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Map ([\n", + " Layer(\n", + " 'maxhi_20190717_72',\n", + " '''\n", + " color: ramp(linear($value,globalMIN($value),globalMAX($value)),[turquoise, yellow, red])\n", + " filter: animation(linear($value,globalMIN($value),globalMAX($value)), 20, fade(0.1, hold))\n", + " strokeWidth: 0\n", + " width: 5\n", + " ''',\n", + " legend={\n", + " 'type':'color-continuous-polygon',\n", + " 'title': 'Max Heat Index for July 20, 2019',\n", + " 'description': 'Degrees (°F)',\n", + " 'footer': 'Issued: 7/17/19 | Source: NOAA Weather Predicition Center'\n", + " },\n", + " widgets=[\n", + " Widget(\n", + " 'formula',\n", + " value='viewportMAX($value)',\n", + " title='Max Degrees (°F)',\n", + " ),\n", + " Widget('time-series', value='value', title='Animation by Temperature'),\n", + " \n", + " ],\n", + " ),\n", + " Layer(\n", + " 'state_bounds',\n", + " 'color: rgba(200,200,200,0.8)',\n", + " 'width: 2'\n", + " ),\n", + " ],\n", + " basemap=basemaps.darkmatter,\n", + " viewport={'zoom': 2, 'lat': 37.572586, 'lng': -110.638529},\n", + " )" + ] + }, + { + "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.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/_debug/widgets_animation.ipynb b/examples/_debug/widgets_animation.ipynb index 53dd44c59..be223f744 100644 --- a/examples/_debug/widgets_animation.ipynb +++ b/examples/_debug/widgets_animation.ipynb @@ -979,13 +979,6 @@ " )\n", ")" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/examples/_debug/widgets_animation_width.ipynb b/examples/_debug/widgets_animation_width.ipynb index bdfa5b455..ee0175911 100644 --- a/examples/_debug/widgets_animation_width.ipynb +++ b/examples/_debug/widgets_animation_width.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -14,7 +14,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -951,7 +951,7 @@ "" ] }, - "execution_count": 2, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } @@ -972,8 +972,7 @@ " }, {\n", " 'type': 'category',\n", " 'value': 'addrtype',\n", - " 'title': 'Address type',\n", - " 'read_only': False\n", + " 'title': 'Address type'\n", " }]\n", " )\n", ")" @@ -981,7 +980,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "metadata": {}, "outputs": [ { diff --git a/examples/_debug/widgets_review.ipynb b/examples/_debug/widgets_review.ipynb new file mode 100644 index 000000000..d86b9ff8c --- /dev/null +++ b/examples/_debug/widgets_review.ipynb @@ -0,0 +1,5085 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "from cartoframes.auth import set_default_context\n", + "from cartoframes.viz import Map, Layer, Widget\n", + "\n", + "set_default_context('https://cartovl.carto.com/')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Custom Animation" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " '''\n", + " @duration: 30\n", + " filter: animation($incdate, @duration, fade(0.5, 0.5))\n", + " strokeWidth: 0\n", + " ''',\n", + " widgets=[Widget('time-series', value='incdate', title='Seattle Collisions', buckets=10)]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Default Animation" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "scrolled": true + }, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Map(\n", + " Layer(\n", + " 'seattle_collisions',\n", + " widgets=[Widget('time-series', value='incdate', title='Seattle Collisions')]\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from cartoframes.auth import set_default_context\n", + "from cartoframes.viz import Map, Layer, Legend, Widget, basemaps\n", + "\n", + "set_default_context('https://cartovl.carto.com/')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " Data: City of New York\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Map(\n", + " Layer(\n", + " 'select * from mnmappluto where numfloors > 2 and yearbuilt >= 1900',\n", + " '''\n", + " color: ramp(linear($numfloors), ag_sunset)\n", + " filter: animation(linear($yearbuilt), 20, fade(0.1, hold))\n", + " strokeWidth: 0\n", + " ''',\n", + " legend={\n", + " 'type':'color-continuous-polygon',\n", + " 'title': 'Manhattan Development (1900-2013)',\n", + " 'description': 'Number of Floors',\n", + " 'footer': 'Data: City of New York'\n", + " },\n", + " widgets=[\n", + " Widget('time-series', value='yearbuilt', title='Year Built'),\n", + " Widget(\n", + " 'histogram',\n", + " value='numfloors',\n", + " title='Number of Floors',\n", + " buckets=10,\n", + " options={'read_only': True}\n", + " )\n", + " ],\n", + " ),\n", + " viewport={'zoom': 12.54, 'lat': 40.730950, 'lng': -73.995281},\n", + " basemap=basemaps.darkmatter\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 122, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'id': '90032aa3-1992-44f5-b8e6-cc7c66f1f9eb',\n", + " 'url': 'https://cartovl.carto.com/kuviz/90032aa3-1992-44f5-b8e6-cc7c66f1f9eb',\n", + " 'name': '3 Day Heat Index',\n", + " 'privacy': 'public'}" + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tmap= Map (\n", + " [\n", + " Layer(\n", + " 'maxhi_20190717_72',\n", + " '''\n", + " color: ramp(linear($value,globalMIN($value),globalMAX($value)),[turquoise, yellow, red])\n", + " filter: animation(linear($value,globalMIN($value),globalMAX($value)), 20, fade(0.1, hold))\n", + " strokeWidth: 0\n", + " width: 5\n", + " ''',\n", + " legend={\n", + " 'type':'color-continuous-polygon',\n", + " 'title': 'Max Heat Index for July 20, 2019',\n", + " 'description': 'Degrees (°F)',\n", + " 'footer': 'Issued: 7/17/19 | Source: NOAA Weather Predicition Center'\n", + " },\n", + " widgets=[\n", + " Widget(\n", + " 'formula',\n", + " value='viewportMAX($value)',\n", + " title='Max Degrees (°F)',\n", + " ),\n", + " Widget('time-series', value='value', title='Animation by Temperature'),\n", + " \n", + " ],\n", + " ),\n", + " Layer(\n", + " 'state_bounds',\n", + " 'color: rgba(200,200,200,0.8)',\n", + " 'width: 2'\n", + " ),\n", + " ],\n", + " \n", + " viewport={'zoom': 2, 'lat': 37.572586, 'lng': -96.638529},\n", + " )\n", + "\n", + "\n", + "tmap.publish('3 Day Heat Index')\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 117, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " Issued: 7/17/19 | Source: NOAA Weather Predicition Center\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 117, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "\n", + "Map (\n", + " [\n", + " Layer(\n", + " 'maxhi_20190717_72',\n", + " '''\n", + " color: ramp(linear($value,globalMIN($value),globalMAX($value)),[turquoise, yellow, red])\n", + " filter: animation(linear($value,globalMIN($value),globalMAX($value)), 20, fade(0.1, hold))\n", + " strokeWidth: 0\n", + " width: 6\n", + " ''',\n", + " legend={\n", + " 'type':'color-continuous-polygon',\n", + " 'title': 'Max Heat Index for July 20, 2019',\n", + " 'description': 'Degrees (°F)',\n", + " 'footer': 'Issued: 7/17/19 | Source: NOAA Weather Predicition Center'\n", + " },\n", + " widgets=[\n", + " Widget(\n", + " 'formula',\n", + " value='viewportMAX($value)',\n", + " title='Max Degrees (°F)',\n", + " ),\n", + " Widget('time-series', value='value', title='Animation by Temperature'),\n", + " \n", + " ],\n", + " ),\n", + " Layer(\n", + " 'state_bounds',\n", + " 'color: rgba(200,200,200,0.8)',\n", + " 'width: 2'\n", + " ),\n", + " ],\n", + " \n", + " viewport={'zoom': 2, 'lat': 37.572586, 'lng': -96.638529},\n", + " )\n", + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "note to self\n", + "- add footer to widgets\n", + "\n", + "- adding opacity to all features via a filter breaks animation widget\n", + "filter: animation(linear($time), 20, fade(0,hold))+0.01\n", + "\n", + "Map (\n", + " Layer(\n", + " 'all_week',\n", + " '''\n", + " //color: ramp(linear($mag),[turquoise, yellow, red])\n", + " filter: animation(linear($time), 20, fade(1,1))\n", + " //strokeWidth: 0\n", + " ''',\n", + " widgets=[\n", + " Widget('time-series', value='mag', title='Animation by Temperature'),\n", + " \n", + " ],\n", + " ),\n", + ")\n", + "\n", + "- add use case to helper api ticket\n", + "color_continuous_layer(\n", + " 'all_week',\n", + " 'mag',\n", + " '''\n", + " filter: filter: animation(linear($time), 30, fade(0,hold))\n", + " ''',\n", + " ),\n", + "\n", + "\n", + "- add ticket to add widgets to helper methods\n", + "\n", + "- hover on histogram not showing values\n", + "\n", + "- Extra widget white space when description and/or title is empty\n", + "\n", + "- popup and hover not working \n", + "\n", + "\n", + "from cartoframes.viz.helpers import color_category_layer, color_bins_layer, color_continuous_layer, \\\n", + " size_category_layer, size_bins_layer, size_continuous_layer\n", + "Map(\n", + " \n", + " color_continuous_layer(\n", + " 'maxhi_20190717_72',\n", + " 'value',\n", + " ),\n", + " widgets=[\n", + " \n", + " Widget(\n", + " 'histogram',\n", + " value='value',\n", + " title='Number of Floors',\n", + " buckets=10,\n", + " options={'read_only': True},\n", + " ),\n", + " ],\n", + " )\n" + ] + }, + { + "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.7.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/_debug/widgets_time_series.ipynb b/examples/_debug/widgets_time_series.ipynb index e777b1372..db748210d 100644 --- a/examples/_debug/widgets_time_series.ipynb +++ b/examples/_debug/widgets_time_series.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -21,7 +21,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 9, "metadata": { "scrolled": false }, @@ -948,7 +948,7 @@ "" ] }, - "execution_count": 2, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } @@ -976,8 +976,10 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, + "execution_count": 10, + "metadata": { + "scrolled": true + }, "outputs": [ { "data": { @@ -1901,7 +1903,7 @@ "" ] }, - "execution_count": 3, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } @@ -1915,6 +1917,1048 @@ ")" ] }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + " CARTOframes\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " Data: City of New York\n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + "\n", + " \n", + " There is a \n", + " from the CARTO VL library:\n", + " \n", + " :\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + " \n", + " StackTrace\n", + " \n", + " \n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\">\n", + "\n", + "" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 13, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from cartoframes.viz import basemaps\n", + "\n", + "Map(\n", + " Layer(\n", + " 'select * from mnmappluto where numfloors > 2 and yearbuilt >= 1900',\n", + " '''\n", + " color: ramp(linear($numfloors), ag_sunset)\n", + " filter: animation(linear($yearbuilt), 20, fade(0.1, hold))\n", + " strokeWidth: 0\n", + " ''',\n", + " legend={\n", + " 'type':'color-continuous-polygon',\n", + " 'title': 'Manhattan Development (1900-2013)',\n", + " 'description': 'Number of Floors',\n", + " 'footer': 'Data: City of New York'\n", + " },\n", + " widgets=[\n", + " Widget('time-series', value='yearbuilt', title='Year Built'),\n", + " Widget(\n", + " 'histogram',\n", + " value='numfloors',\n", + " title='Number of Floors',\n", + " buckets=10,\n", + " options={'read_only': True}\n", + " )\n", + " ],\n", + " ),\n", + " viewport={'zoom': 12.54, 'lat': 40.730950, 'lng': -73.995281},\n", + " basemap=basemaps.darkmatter\n", + ")" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/test/viz/test_widget.py b/test/viz/test_widget.py index 60ee4403c..403d865b1 100644 --- a/test/viz/test_widget.py +++ b/test/viz/test_widget.py @@ -42,7 +42,7 @@ def test_widget_info(self): 'has_bridge': False, 'prop': '', 'variable_name': 'vb6dbcf', - 'options': {} + 'options': {'readOnly': False} }) def test_wrong_input(self): @@ -73,7 +73,7 @@ def test_animation_widget(self): 'has_bridge': True, 'prop': 'filter', 'variable_name': '', - 'options': {} + 'options': {'readOnly': False} }) def test_animation_widget_prop(self): @@ -92,5 +92,5 @@ def test_animation_widget_prop(self): 'has_bridge': True, 'prop': 'width', 'variable_name': '', - 'options': {} + 'options': {'readOnly': False} }) diff --git a/test/viz/test_widget_list.py b/test/viz/test_widget_list.py index 3cb2107b6..b7cfcb85e 100644 --- a/test/viz/test_widget_list.py +++ b/test/viz/test_widget_list.py @@ -86,7 +86,7 @@ def test_widget_list_get_widgets_info(self): 'footer': '[footer]', 'has_bridge': False, 'variable_name': 'vb6dbcf', - 'options': {} + 'options': {'readOnly': False} }, { 'type': 'default', 'title': '"Custom Info"', @@ -96,5 +96,5 @@ def test_widget_list_get_widgets_info(self): 'footer': '', 'has_bridge': False, 'variable_name': '', - 'options': {} + 'options': {'readOnly': False} }]) diff --git a/test/viz/widgets/test_category_widget.py b/test/viz/widgets/test_category_widget.py index 271e69fd1..999be25b1 100644 --- a/test/viz/widgets/test_category_widget.py +++ b/test/viz/widgets/test_category_widget.py @@ -14,3 +14,4 @@ def test_factory(self): self.assertEqual(widget_info.get('type'), 'category') self.assertEqual(widget_info.get('value'), '$value') self.assertEqual(widget_info.get('title'), 'Category Widget') + self.assertEqual(widget_info.get('options').get('readOnly'), False) diff --git a/test/viz/widgets/test_formula_widget.py b/test/viz/widgets/test_formula_widget.py index f1cee32f1..18ae857c4 100644 --- a/test/viz/widgets/test_formula_widget.py +++ b/test/viz/widgets/test_formula_widget.py @@ -8,9 +8,33 @@ def test_widgets(self): self.assertNotEqual(widgets.formula_widget, None) def test_factory(self): - "should create a formula widget" - widget = widgets.formula_widget('$value', title='Formula Widget') + "should create a default formula widget" + widget = widgets.formula_widget('value', title='Formula Widget') widget_info = widget.get_info() self.assertEqual(widget_info.get('type'), 'formula') self.assertEqual(widget_info.get('value'), '$value') self.assertEqual(widget_info.get('title'), 'Formula Widget') + + def test_count_formula_viewport(self): + "should create a formula widget to count viewport features" + widget = widgets.formula_widget('count') + widget_info = widget.get_info() + self.assertEqual(widget_info.get('value'), 'viewportCount()') + + def test_count_formula_global(self): + "should create a formula widget to count global features" + widget = widgets.formula_widget('count', is_global=True) + widget_info = widget.get_info() + self.assertEqual(widget_info.get('value'), 'globalCount()') + + def test_formula_viewport(self): + "should create a formula widget to get a viewport operation" + widget = widgets.formula_widget('value', 'avg') + widget_info = widget.get_info() + self.assertEqual(widget_info.get('value'), 'viewportAvg($value)') + + def test_formula_global(self): + "should create a formula widget to get a global operation" + widget = widgets.formula_widget('value', 'avg', is_global=True) + widget_info = widget.get_info() + self.assertEqual(widget_info.get('value'), 'globalAvg($value)') diff --git a/test/viz/widgets/test_histogram_widget.py b/test/viz/widgets/test_histogram_widget.py index dbaea4618..c0a4e4d6a 100644 --- a/test/viz/widgets/test_histogram_widget.py +++ b/test/viz/widgets/test_histogram_widget.py @@ -14,3 +14,4 @@ def test_factory(self): self.assertEqual(widget_info.get('type'), 'histogram') self.assertEqual(widget_info.get('value'), '$value') self.assertEqual(widget_info.get('title'), 'Histogram Widget') + self.assertEqual(widget_info.get('options').get('readOnly'), False) diff --git a/test/viz/widgets/test_time_series_widget.py b/test/viz/widgets/test_time_series_widget.py index ba7904ea7..ffcf719a6 100644 --- a/test/viz/widgets/test_time_series_widget.py +++ b/test/viz/widgets/test_time_series_widget.py @@ -14,3 +14,4 @@ def test_factory(self): self.assertEqual(widget_info.get('type'), 'time-series') self.assertEqual(widget_info.get('value'), '$value') self.assertEqual(widget_info.get('title'), 'Time Series Widget') + self.assertEqual(widget_info.get('options').get('readOnly'), False)
There is a \n", + " from the CARTO VL library: