From a675cfbe4d989dd82a45e74ccd7eb70b196a0749 Mon Sep 17 00:00:00 2001 From: dsmedia <63077097+dsmedia@users.noreply.github.com> Date: Sat, 8 Mar 2025 13:03:57 +0000 Subject: [PATCH 1/3] docs: Add documentation for initial interval selection date ranges This commit adds a new "Setting Initial Values" subsection to the "Interval Selections" documentation in `parameters.rst`. It explains how to use the `value` parameter with `datetime.date` and `datetime.datetime` objects to set an initial range for interval selections. This addresses issue #3643. --- doc/user_guide/interactions/parameters.rst | 55 ++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/doc/user_guide/interactions/parameters.rst b/doc/user_guide/interactions/parameters.rst index cf42d572b..43a2d8430 100644 --- a/doc/user_guide/interactions/parameters.rst +++ b/doc/user_guide/interactions/parameters.rst @@ -381,8 +381,57 @@ You can create such a selection using the :func:`selection_interval` function: As you click and drag on the plot, you'll find that your mouse creates a box that can be subsequently moved to change the selection. -The :func:`selection_interval` function takes a few additional arguments; for -example we can bind the interval to only the x-axis, and set it such that the +**Setting Initial Values** + +You can set initial values for an interval selection using the ``value`` parameter. +This lets you pre-select a region when the chart first renders: + +.. altair-plot:: + + import altair as alt + from vega_datasets import data + import datetime as dt + + source = data.sp500.url + + # Set initial date range for the selection + date_range = (dt.date(2007, 6, 30), dt.date(2009, 6, 30)) + interval = alt.selection_interval(encodings=['x'], value={'x': date_range}) + + alt.Chart(source).mark_area().encode( + x='date:T', + y='price:Q' + ).add_params( + interval + ).properties( + width=600, + height=300 + ) + +When working with datetime values, you can use Python's native ``datetime.date`` or +``datetime.datetime`` objects directly. Altair automatically handles the conversion of +these objects to the appropriate format for Vega-Lite. + +For numeric fields, you can similarly specify a range of values: + +.. altair-plot:: + + cars = data.cars.url + + # Set initial horsepower range + hp_range = (100, 200) + interval = alt.selection_interval(encodings=['x'], value={'x': hp_range}) + + alt.Chart(cars).mark_point().encode( + x='Horsepower:Q', + y='Miles_per_Gallon:Q', + color='Origin:N' + ).add_params( + interval + ) + +The :func:`selection_interval` function takes additional arguments to customize behavior. +For example, we can bind the interval to only the x-axis, and set it such that the empty selection contains none of the points: .. altair-plot:: @@ -399,7 +448,7 @@ rather than having to define separate selection objects:: color=alt.when(brush).then(...) size=alt.when(brush, empty=False).then(...) ... - + Point Selections ^^^^^^^^^^^^^^^^ A *point* selection allows you to select chart elements one at a time From 2e382e88d566a189b7a33737d0495535ba4af7e2 Mon Sep 17 00:00:00 2001 From: Daniel Sorid <63077097+dsmedia@users.noreply.github.com> Date: Tue, 11 Mar 2025 02:07:10 +0000 Subject: [PATCH 2/3] docs: improve flow --- doc/user_guide/interactions/parameters.rst | 201 +++++++++++++-------- 1 file changed, 128 insertions(+), 73 deletions(-) diff --git a/doc/user_guide/interactions/parameters.rst b/doc/user_guide/interactions/parameters.rst index 43a2d8430..b809e5389 100644 --- a/doc/user_guide/interactions/parameters.rst +++ b/doc/user_guide/interactions/parameters.rst @@ -46,7 +46,7 @@ we create a parameter with a default value of 0.1 using the ``value`` property: op_var = alt.param(value=0.1) -In order to use this variable in the chart specification, we explicitly add it to the chart using the :meth:`add_params` method, and we can then reference the variable within the chart specification. Here we set the opacity using our ``op_var`` parameter. +In order to use this variable in the chart specification, we explicitly add it to the chart using the :meth:`add_params` method, and we can then reference the variable within the chart specification. Here we set the opacity using our ``op_var`` parameter. The :meth:`add_params` method adds the parameter to the chart, making it available for use in encodings, conditions, and filters. .. altair-plot:: @@ -342,12 +342,15 @@ Selection Types ~~~~~~~~~~~~~~~ Now that we have seen the basics of how we can use a selection to interact with a chart, -let's take a more systematic look at some of the types of selection parameters available in Altair. -For simplicity, we'll use a common chart in all the following examples; a -simple heat-map based on the ``cars`` dataset. -For convenience, let's write a quick Python function that will take a selection -object and create a chart with the color of the chart elements linked to this -selection: +let's take a more systematic look at the types of selection parameters available in Altair. +There are two main types of selections you'll work with through mouse actions: + +1. **Interval selections**: Select ranges of data by clicking and dragging +2. **Point selections**: Select individual data points by clicking or hovering + +To demonstrate these selection types clearly, we'll use a consistent visualization +approach. The following helper function creates a heatmap from the ``cars`` dataset +where the color encoding responds to our selection: .. altair-plot:: :output: none @@ -366,111 +369,163 @@ selection: selector ) -Next we'll use this function to demonstrate the properties of various selections. - Interval Selections ^^^^^^^^^^^^^^^^^^^ -An *interval* selection allows you to select chart elements by clicking and dragging. -You can create such a selection using the :func:`selection_interval` function: +An *interval* selection allows you to select a range of data elements by clicking and dragging. +This is often referred to as a "brush" selection and is commonly used for filtering, +zooming, or highlighting ranges of data points. + +Basic Interval Selection +""""""""""""""""""""""" +The simplest interval selection is created with the :func:`selection_interval` function: .. altair-plot:: interval = alt.selection_interval() make_example(interval) -As you click and drag on the plot, you'll find that your mouse creates a box -that can be subsequently moved to change the selection. +As you click and drag on the plot, your mouse creates a selection region that can be +moved to change which data points are selected. + +Customizing Interval Behavior +"""""""""""""""""""""""""""" +The :func:`selection_interval` function accepts several arguments for customization. +For example, you can limit the selection to only the x-axis and set it so that +an empty selection contains no points: + +.. altair-plot:: + + interval_x = alt.selection_interval(encodings=['x'], empty=False) + make_example(interval_x) + +The ``empty=False`` argument can also be set inside :func:`when` to control +how individual conditions respond to empty selections. By default, `empty=True`, which means the selection predicate evaluates to true for *all* data points when the selection is empty. With `empty=False`, the predicate evaluates to false for all points when the selection is empty. This affects what happens when no data points are selected yet:: + + brush = alt.selection_interval() + + # Default behavior (empty=True): When nothing is selected, all points are gray + color=alt.when(brush).then("Origin:N").otherwise(alt.value("lightgray")) + + # Custom behavior (empty=False): When nothing is selected, points keep their category colors + color=alt.when(brush, empty=False).then(alt.value("steelblue")).otherwise("Origin:N") -**Setting Initial Values** +Setting Initial Values +""""""""""""""""""""" +When creating interactive visualizations, you often want to guide users by +starting with a pre-selected region rather than an empty selection. You can do this +using the ``value`` parameter of :func:`selection_interval`. -You can set initial values for an interval selection using the ``value`` parameter. -This lets you pre-select a region when the chart first renders: +Setting initial values is particularly useful when: + +- Creating a filtered overview-detail pattern where a detailed subset is shown +- Guiding viewer attention to a particular area of interest immediately +- Preserving selection states across different visualizations or user sessions + +Here's an example using time series data where we initially focus on a specific date range +containing the 2008 financial crisis: .. altair-plot:: import altair as alt from vega_datasets import data import datetime as dt - + source = data.sp500.url - - # Set initial date range for the selection + + # Define initial date range to select date_range = (dt.date(2007, 6, 30), dt.date(2009, 6, 30)) - interval = alt.selection_interval(encodings=['x'], value={'x': date_range}) - - alt.Chart(source).mark_area().encode( - x='date:T', - y='price:Q' - ).add_params( - interval - ).properties( - width=600, - height=300 + + # Create interval selection with initial value + brush = alt.selection_interval(encodings=['x'], + value={'x': date_range}) + + # Create base chart for both panels + base = alt.Chart(source, width=600, height=200).mark_area().encode( + x = 'date:T', + y = 'price:Q' + ) + + # Upper panel shows detailed view filtered by the brush + upper = base.encode( + alt.X('date:T').scale(domain=brush) ) - + + # Lower panel shows overview with the brush control + lower = base.properties( + height=60 + ).add_params(brush) + + # Combine the two charts + upper & lower + +This example demonstrates an "overview+detail" pattern - a common visualization technique +where one chart shows the complete dataset while another shows a detailed view of the +selected portion. + When working with datetime values, you can use Python's native ``datetime.date`` or ``datetime.datetime`` objects directly. Altair automatically handles the conversion of these objects to the appropriate format for Vega-Lite. -For numeric fields, you can similarly specify a range of values: - -.. altair-plot:: +The format of the ``value`` parameter depends on the encodings used in the selection: - cars = data.cars.url - - # Set initial horsepower range - hp_range = (100, 200) - interval = alt.selection_interval(encodings=['x'], value={'x': hp_range}) - - alt.Chart(cars).mark_point().encode( - x='Horsepower:Q', - y='Miles_per_Gallon:Q', - color='Origin:N' - ).add_params( - interval - ) +- For selections with `x` encoding: ``value={'x': [min, max]}`` +- For selections with `y` encoding: ``value={'y': [min, max]}`` +- For selections with both: ``value={'x': [xmin, xmax], 'y': [ymin, ymax]}`` -The :func:`selection_interval` function takes additional arguments to customize behavior. -For example, we can bind the interval to only the x-axis, and set it such that the -empty selection contains none of the points: +You can also use this feature with categorical data by specifying the categories to select. For example, to initially select only cars with 4 or 6 cylinders: .. altair-plot:: - interval_x = alt.selection_interval(encodings=['x'], empty=False) - make_example(interval_x) + cylinder_select = alt.selection_interval( + encodings=['x'], + value={"x": [4, 6]} # Select 4 and 6 cylinder cars + ) + make_example(cylinder_select) -The ``empty=False`` argument could instead be set inside :func:`when`, -to change the behavior of each condition when an empty selection is passed, -rather than having to define separate selection objects:: - brush = alt.selection_interval() - ... - color=alt.when(brush).then(...) - size=alt.when(brush, empty=False).then(...) - ... - Point Selections ^^^^^^^^^^^^^^^^ -A *point* selection allows you to select chart elements one at a time -via mouse actions. By default, points are selected on click: +A *point* selection allows you to select individual data elements one at a time. +Unlike interval selections which select ranges, point selections work with discrete +data points, making them ideal for interactive legends, tooltips, and highlighting +specific data points. + +Basic Point Selection +"""""""""""""""""""" +The simplest point selection is created with the :func:`selection_point` function. +By default, points are selected on click: .. altair-plot:: point = alt.selection_point() make_example(point) -By changing some arguments, we can select points when hovering over them rather than on -click. We can also set the ``nearest`` flag to ``True`` so that the nearest -point is highlighted: +Customizing Point Selection Behavior +""""""""""""""""""""""""""""""""""" +Point selections offer several customization options. For example, you can trigger +selection when hovering over points rather than clicking, and use the ``nearest`` flag +to ensure the closest point is selected: .. altair-plot:: point_nearest = alt.selection_point(on='pointerover', nearest=True) make_example(point_nearest) -Point selections also allow for multiple chart objects to be selected. -By default, chart elements can be added to and removed from the selection -by clicking on them while holding the *shift* key, you can try in the two charts above. +Point selections also support multi-selection. By default, you can add or remove +data points from your selection by holding the *shift* key while clicking. Try this +behavior in the examples above to see how it works. + +Setting Initial Values +"""""""""""""""""""""" +You can also set initial values for point selections using the ``value`` parameter. For point selections, the value is a dictionary specifying the initial selection based on fields or encodings. + +.. altair-plot:: + + point_initial = alt.selection_point( + fields=['Origin'], + value=[{'Origin': 'USA'}] # Initially select USA + ) + make_example(point_initial) Selection Targets ~~~~~~~~~~~~~~~~~ @@ -635,10 +690,10 @@ operands. Returning to our heatmap examples, we can construct a scenario where there are two people who can make an interval -selection in the same chart. The person Alex makes a selection box when the +selection in the same chart. The person Alex makes a selection region when the alt-key (macOS: option-key) is selected and Morgan can make a selection -box when the shift-key is selected. -We use :class:`BrushConfig` to give the selection box of Morgan a different +region when the shift-key is selected. +We use :class:`BrushConfig` to give the selection region of Morgan a different style. Now, we color the rectangles when they fall within Alex's or Morgan's selection @@ -677,7 +732,7 @@ With these operators, selections can be combined in arbitrary ways: For more information on how to fine-tune selections, including specifying other mouse and keystroke options, see the `Vega-Lite Selection documentation -`_. +`_. Also see :class:`BrushConfig` for information on how to customize the appearance of the brush. .. _polars.when: - https://docs.pola.rs/py-polars/html/reference/expressions/api/polars.when.html + https://docs.pola.rs/py-polars/html/reference/expressions/api/polars.when.html \ No newline at end of file From 9bdd801344a63c6319b3a5bc5c98deddead10f82 Mon Sep 17 00:00:00 2001 From: dangotbanned <125183946+dangotbanned@users.noreply.github.com> Date: Fri, 21 Mar 2025 19:10:55 +0000 Subject: [PATCH 3/3] ci: force rerun w/ `ruff==0.11.2` https://github.com/vega/altair/pull/3815#issuecomment-2741147309 https://github.com/vega/altair/actions/runs/13778777512/job/39119495592?pr=3815 --- doc/user_guide/interactions/parameters.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/user_guide/interactions/parameters.rst b/doc/user_guide/interactions/parameters.rst index b809e5389..8eaa99581 100644 --- a/doc/user_guide/interactions/parameters.rst +++ b/doc/user_guide/interactions/parameters.rst @@ -399,7 +399,12 @@ an empty selection contains no points: make_example(interval_x) The ``empty=False`` argument can also be set inside :func:`when` to control -how individual conditions respond to empty selections. By default, `empty=True`, which means the selection predicate evaluates to true for *all* data points when the selection is empty. With `empty=False`, the predicate evaluates to false for all points when the selection is empty. This affects what happens when no data points are selected yet:: +how individual conditions respond to empty selections. +By default, `empty=True`, which means the selection predicate evaluates to +true for *all* data points when the selection is empty. +With `empty=False`, the predicate evaluates to false for all points when +the selection is empty. +This affects what happens when no data points are selected yet:: brush = alt.selection_interval()