diff --git a/altair/vegalite/v2/examples/multiple_interactions.py b/altair/vegalite/v2/examples/multiple_interactions.py new file mode 100644 index 000000000..495a4b5fe --- /dev/null +++ b/altair/vegalite/v2/examples/multiple_interactions.py @@ -0,0 +1,90 @@ +""" +Multiple Interations +==================== +This example shows how multiple user inputs can be layered onto a chart. The four inputs have functionality as follows: + +* Dropdown: Filters the movies by genre +* Radio Buttons: Highlights certain films by Worldwide Gross +* Mouse Drag and Scroll: Zooms the x and y scales to allow for panning. + + + +""" +# category: interactive charts +import altair as alt +from vega_datasets import data + + +movies = alt.UrlData(data.movies.url, format=alt.DataFormat(parse={"Release_Date":"date"})) + +ratings = ['G', 'NC-17', 'PG', 'PG-13', 'R'] + +genres = ['Action', 'Adventure', 'Black Comedy', 'Comedy', + 'Concert/Performance', 'Documentary', 'Drama', 'Horror', 'Musical', + 'Romantic Comedy', 'Thriller/Suspense', 'Western'] + +base = alt.Chart(movies, width=200, height=200).mark_point(filled=True).transform_calculate( + Rounded_IMDB_Rating = "floor(datum.IMDB_Rating)", + Hundred_Million_Production = "datum.Production_Budget > 100000000.0 ? 100 : 10", + Release_Year = "year(datum.Release_Date)" +).transform_filter( + alt.datum.IMDB_Rating > 0 +).transform_filter( + alt.FieldOneOfPredicate(field='MPAA_Rating', oneOf=ratings) +).encode( + x=alt.X('Worldwide_Gross:Q', scale=alt.Scale(domain=(100000,10**9), clamp=True)), + y='IMDB_Rating:Q', + tooltip="Title:N" +) + +# A slider filter +year_slider = alt.binding_range(min=1969, max=2018, step=1) +slider_selection = alt.selection_single(bind=year_slider, fields=['Release_Year'], name="Release Year_") + + +filter_year = base.add_selection( + slider_selection +).transform_filter( + slider_selection +).properties(title="Slider Filtering") + +# A dropdown filter +genre_dropdown = alt.binding_select(options=genres) +genre_select = alt.selection_single(fields=['Major_Genre'], bind=genre_dropdown, name="Genre") + +filter_genres = base.add_selection( + genre_select +).transform_filter( + genre_select +).properties(title="Dropdown Filtering") + +#color changing marks +rating_radio = alt.binding_radio(options=ratings) + +rating_select = alt.selection_single(fields=['MPAA_Rating'], bind=rating_radio, name="Rating") +rating_color_condition = alt.condition(rating_select, + alt.Color('MPAA_Rating:N', legend=None), + alt.value('lightgray')) + +highlight_ratings = base.add_selection( + rating_select +).encode( + color=rating_color_condition +).properties(title="Radio Button Highlighting") + +# Boolean selection for format changes +input_checkbox = alt.binding_checkbox() +checkbox_selection = alt.selection_single(bind=input_checkbox, name="Big Budget Films") + +size_checkbox_condition = alt.condition(checkbox_selection, + alt.SizeValue(25), + alt.Size('Hundred_Million_Production:Q') + ) + +budget_sizing = base.add_selection( + checkbox_selection +).encode( + size=size_checkbox_condition +).properties(title="Checkbox Formatting") + +( filter_year | filter_genres) & (highlight_ratings | budget_sizing ) \ No newline at end of file diff --git a/doc/case_studies/exploring-weather.rst b/doc/case_studies/exploring-weather.rst index dddb0d821..2af2d9fd8 100644 --- a/doc/case_studies/exploring-weather.rst +++ b/doc/case_studies/exploring-weather.rst @@ -221,7 +221,7 @@ by weather type: And now we can vertically concatenate this histogram to the points plot above, and add a brush selection tool such that the histogram reflects the content of the selection (for more information on selections, see -:ref:`user-guide-selections`): +:ref:`user-guide-interactions`): .. altair-plot:: diff --git a/doc/index.rst b/doc/index.rst index f4b656bc9..ed104f5e4 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -39,7 +39,7 @@ beautiful and effective visualizations with a minimal amount of code. user_guide/encoding user_guide/marks user_guide/transform - user_guide/selections + user_guide/interactions user_guide/configuration user_guide/compound_charts user_guide/saving_charts diff --git a/doc/user_guide/selections.rst b/doc/user_guide/interactions.rst similarity index 65% rename from doc/user_guide/selections.rst rename to doc/user_guide/interactions.rst index cde370271..98951a7b2 100644 --- a/doc/user_guide/selections.rst +++ b/doc/user_guide/interactions.rst @@ -1,19 +1,31 @@ .. currentmodule:: altair -.. _user-guide-selections: +.. _user-guide-interactions: + +Bindings, Selections, Conditions: Making Charts Interactive +=========================================================== -Selections: Building Blocks of Interactions -------------------------------------------- One of the unique features of Altair, inherited from Vega-Lite, is a -declarative grammar of not just visualization, but *interaction*. The -core concept of this grammar is the *selection* object. +declarative grammar of not just visualization, but *interaction*. There are three +core concepts of this grammar: + +- the :func:`selection` object which captures interactions from the mouse or through other inputs to effect the chart. Inputs can either be events like moust clicks or drags. Inputs can also be elemnts like a drop-down, radio button or slider. Selections can be used alone but if you want to have change any element of your chart you will need to connect them to a *condition*. +- the :func:`condition` function takes the selection input and changes an element of the chart based on that input. +- the ``bind`` property of a selection which establishes a two-way binding between the selection and an input element of your chart. + +Interactive charts can use one or more of these elements to create rich interactivity between the viewer and the data. + + +Selections: Building Blocks of Interactions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Selections in Altair come in a few flavors, and they can be *bound* to particular charts or sub-charts in your visualization, then referenced in other parts of the visualization. Example: Linked-Brush Scatter-Plot -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ As a motivation, let's create a simple chart and then add some selections to it. Here is a simple scatter-plot created from the ``cars`` dataset: @@ -55,6 +67,9 @@ property: The result above is a chart that allows you to click and drag to create a selection region, and to move this region once the region is created. +Conditions: Making the chart respond +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + This is neat, but the selection doesn't actually *do* anything yet. To use this selection, we need to reference it in some way within the chart. Here, we will use the :func:`condition` function to create @@ -308,10 +323,102 @@ cylinders: By fine-tuning the behavior of selections in this way, they can be used to create a wide variety of linked interactive chart types. +Binding: Adding Data Driven Inputs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +With an understanding of the selection types and conditions, you can now add data-driven input elements to the charts using the :class:`bind`. As specified by `Vega-lite binding `_, selections can be bound two-ways: + +1. Single selections can be bound directly to an input elements. *For example, a radio button.* +2. Interval selections which can be bound to scale. *for example, zooming in on a map.* + +Input Element Binding +^^^^^^^^^^^^^^^^^^^^^ +With single selections, an input element can be added to the chart to establish a binding between the input and the selection. + +For instance, using our example from above a dropdown can be used to highlight cars from a specific ``origin`` : + +.. altair-plot:: + + input_dropdown = alt.binding_select(options=['Europe','Japan','USA']) + selection = alt.selection_single(fields=['Origin'], bind=input_dropdown, name='Country of ') + color = alt.condition(selection, + alt.Color('Origin:N', legend=None), + alt.value('lightgray')) + + alt.Chart(cars).mark_point().encode( + x='Horsepower:Q', + y='Miles_per_Gallon:Q', + color=color, + tooltip='Name:N' + ).add_selection( + selection + ) + + + + +The above example shows all three elements at work. The :input_dropdown: is :bind: to the :selection: which is called from the :condition: encoded through the data. + +The following are the input elements supported in vega-lite: + + +========================= =========================================================================== =============================================== +Input Element Description Example +========================= =========================================================================== =============================================== +:class:`binding_checkbox` Renders as checkboxes allowing for multiple selections of items. :ref:`gallery_multiple_interactions` +:class:`binding_radio` Radio buttons that force only a single selection :ref:`gallery_multiple_interactions` +:class:`binding_select` Drop down box for selecting a single item from a list :ref:`gallery_multiple_interactions` +:class:`binding_range` Shown as a slider to allow for selection along a scale. :ref:`gallery_us_population_over_time` +========================= =========================================================================== =============================================== + + +Bindings and input elements can also be used to filter data on the client side. Reducing noise in the chart and allowing the user to see just certain selected elements: + +.. altair-plot:: + + input_dropdown = alt.binding_select(options=['Europe','Japan','USA']) + selection = alt.selection_single(fields=['Origin'], bind=input_dropdown, name='Country of ') + color = alt.condition(selection, + alt.Color('Origin:N', legend=None), + alt.value('lightgray')) + + alt.Chart(cars).mark_point().encode( + x='Horsepower:Q', + y='Miles_per_Gallon:Q', + color='Origin:N', + tooltip='Name:N' + ).add_selection( + selection + ).transform_filter( + selection + ) + + +Scale Binding +^^^^^^^^^^^^^ +With interval selections, the bind property can be set to the value of :"scales":. In these cases, the binding will automatically respond to the panning and zooming along the chart: + +.. altair-plot:: + + selection = alt.selection_interval(bind="scales") + color = alt.condition(selection, + alt.Color('Origin:N', legend=None), + alt.value('lightgray')) + + alt.Chart(cars).mark_point().encode( + x='Horsepower:Q', + y='Miles_per_Gallon:Q', + color='Origin:N', + tooltip='Name:N' + ).add_selection( + selection + ) + + + Further Examples ~~~~~~~~~~~~~~~~ -Now that you understand the basics of Altair selections, you might wish to look +Now that you understand the basics of Altair selections and bindings, you might wish to look through the :ref:`gallery-category-Interactive Charts` section of the example gallery for ideas about how they can be applied to more interesting charts.