diff --git a/altair_cartographic.ipynb b/altair_cartographic.ipynb index 0d546d1..057a7b3 100644 --- a/altair_cartographic.ipynb +++ b/altair_cartographic.ipynb @@ -239,23 +239,23 @@ "text/html": [ "\n", "\n", - "
\n", + "
\n", "" - ], - "text/plain": [ - "alt.Chart(...)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "alt.Chart(cars).mark_bar().encode(\n", " y='mean(Horsepower)',\n", @@ -730,7 +649,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.9" + "version": "3.13.11" } }, "nbformat": 4, diff --git a/altair_interaction.ipynb b/altair_interaction.ipynb index aea42d1..532f56c 100644 --- a/altair_interaction.ipynb +++ b/altair_interaction.ipynb @@ -55,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -79,7 +79,7 @@ "source": [ "Let's start with a basic selection: simply clicking a point to highlight it. Using the `cars` dataset, we'll start with a scatter plot of horsepower versus miles per gallon, with a color encoding for the number cylinders in the car engine.\n", "\n", - "In addition, we'll create a selection instance by calling `alt.selection_single()`, indicating we want a selection defined over a _single value_. By default, the selection uses a mouse click to determine the selected value. To register a selection with a chart, we must add it using the `.add_selection()` method.\n", + "In addition, we'll create a selection instance by calling `alt.selection_point(toggle=False)`, indicating we want a selection defined over a _single value_. By default, the selection uses a mouse click to determine the selected value. To register a selection with a chart, we must add it using the `.add_params()` method.\n", "\n", "Once our selection has been defined, we can use it as a parameter for _conditional encodings_, which apply a different encoding depending on whether a data record lies in or out of the selection. For example, consider the following code:\n", "\n", @@ -94,7 +94,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { @@ -102,23 +102,23 @@ "text/html": [ "\n", "\n", - "
\n", + "
\n", "\n", - " \n", - " \n", + " \n", + " \n", + " \n", " \n", " \n", "
\n", @@ -2658,7 +2658,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.13.9" + "version": "3.13.11" } }, "nbformat": 4, diff --git a/altair_marks_encoding.ipynb b/altair_marks_encoding.ipynb index 22a53d8..ec74a98 100644 --- a/altair_marks_encoding.ipynb +++ b/altair_marks_encoding.ipynb @@ -116,7 +116,7 @@ "id": "spJtZFQN0KCQ" }, "source": [ - "693 rows and 6 columns! Let's take a peek at the data content:" + "682 rows and 6 columns! Let's take a peek at the data content:" ] }, { @@ -482,7 +482,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 7, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -498,23 +498,23 @@ "text/html": [ "\n", "\n", - "
\n", + "
\n", " - - + + +
diff --git a/marimo/02_marks_encoding.py b/marimo/02_marks_encoding.py index fb2d831..1b3a90e 100644 --- a/marimo/02_marks_encoding.py +++ b/marimo/02_marks_encoding.py @@ -89,7 +89,7 @@ def _(data): @app.cell(hide_code=True) def _(mo): mo.md(r""" - 693 rows and 6 columns! Let's take a peek at the data content: + 682 rows and 6 columns! Let's take a peek at the data content: """) return @@ -1061,7 +1061,7 @@ def _(alt, dataNA): @app.cell(hide_code=True) def _(mo): mo.md(r""" - We can see a larger range of values in 1995, from just under 4 to just under 7. By 2005, both the overall fertility values and the variability have declined, centered around 2 children per familty. + We can see a larger range of values in 1955, from just under 4 to just under 7. By 2005, both the overall fertility values and the variability have declined, centered around 2 children per family. """) return diff --git a/marimo/03_data_transformation.py b/marimo/03_data_transformation.py index d675efd..0c478b1 100644 --- a/marimo/03_data_transformation.py +++ b/marimo/03_data_transformation.py @@ -55,7 +55,7 @@ def _(mo): mo.md(r""" We will be working with a table of data about motion pictures, taken from the [vega-datasets](https://vega.github.io/vega-datasets/) collection. The data includes variables such as the film name, director, genre, release date, ratings, and gross revenues. However, _be careful when working with this data_: the films are from unevenly sampled years, using data combined from multiple sources. If you dig in you will find issues with missing values and even some subtle errors! Nevertheless, the data should prove interesting to explore... - Let's retrieve the URL for the JSON data file from the datasets package, and then read the data into a Pandas data frame so that we can inspect its contents. + Let's read the JSON data file into a Pandas data frame from a URL so that we can inspect its contents. """) return diff --git a/marimo/04_scales_axes_legends.py b/marimo/04_scales_axes_legends.py index 67935dd..5894e2e 100644 --- a/marimo/04_scales_axes_legends.py +++ b/marimo/04_scales_axes_legends.py @@ -686,7 +686,7 @@ def _(alt, antibiotics): @app.cell(hide_code=True) def _(mo): mo.md(r""" - _Hmm... While the data are better segregated by genus, this cacapohony of colors doesn't seem particularly useful._ + _Hmm... While the data are better segregated by genus, this cacophony of colors doesn't seem particularly useful._ _If we look at some of the previous charts carefully, we can see that only a handful of bacteria have a genus shared with another bacteria: Salmonella, Staphylococcus, and Streptococcus. To focus our comparison, we might add colors only for these repeated genus values._ diff --git a/marimo/06_interaction.py b/marimo/06_interaction.py index 3ab4427..608f818 100644 --- a/marimo/06_interaction.py +++ b/marimo/06_interaction.py @@ -97,7 +97,7 @@ def _(mo): mo.md(r""" Let's start with a basic selection: simply clicking a point to highlight it. Using the `cars` dataset, we'll start with a scatter plot of horsepower versus miles per gallon, with a color encoding for the number cylinders in the car engine. - In addition, we'll create a selection instance by calling `alt.selection_single()`, indicating we want a selection defined over a _single value_. By default, the selection uses a mouse click to determine the selected value. To register a selection with a chart, we must add it using the `.add_params()` method. + In addition, we'll create a selection instance by calling `alt.selection_point(toggle=False)`, indicating we want a selection defined over a _single value_. By default, the selection uses a mouse click to determine the selected value. To register a selection with a chart, we must add it using the `.add_params()` method. Once our selection has been defined, we can use it as a parameter for _conditional encodings_, which apply a different encoding depending on whether a data record lies in or out of the selection. For example, consider the following code: @@ -122,11 +122,11 @@ def _(alt, cars): @app.cell(hide_code=True) def _(mo): mo.md(r""" - Of course, highlighting individual data points one-at-a-time is not particularly exciting! As we'll see, however, single value selections provide a useful building block for more powerful interactions. Moreover, single value selections are just one of the three selection types provided by Altair: + Of course, highlighting individual data points one-at-a-time is not particularly exciting! As we'll see, however, single value selections provide a useful building block for more powerful interactions. Moreover, single value selections are just one of the selection types provided by Altair: - - `selection_single` - select a single discrete value, by default on click events. - - `selection_multi` - select multiple discrete values. The first value is selected on mouse click and additional values toggled using shift-click. - - `selection_interval` - select a continuous range of values, initiated by mouse drag. + - `selection_point(toggle=False)` - select a single discrete value, by default on click events. + - `selection_point()` - select multiple discrete values. The first value is selected on mouse click and additional values toggled using shift-click. + - `selection_interval()` - select a continuous range of values, initiated by mouse drag. Let's compare each of these selection types side-by-side. To keep our code tidy we'll first define a function (`plot`) that generates a scatter plot specification just like the one above. We can pass a selection to the `plot` function to have it applied to the chart: """) @@ -250,7 +250,7 @@ def _(): @app.cell(hide_code=True) def _(mo): mo.md(r""" - Now let's create a `single` selection bound to a drop-down menu. + Now let's create a point selection bound to a drop-down menu. *Use the dynamic query menu below to explore the data. How do ratings vary by genre? How would you revise the code to filter `MPAA_Rating` (G, PG, PG-13, etc.) instead of `Major_Genre`?* """) @@ -284,8 +284,8 @@ def _(mo): Our construction above leverages multiple aspects of selections: - We give the selection a name (`'Select'`). This name is not required, but allows us to influence the label text of the generated dynamic query menu. (_What happens if you remove the name? Try it!_) - - We constrain the selection to a specific data field (`Major_Genre`). Earlier when we used a `single` selection, the selection mapped to individual data points. By limiting the selection to a specific field, we can select _all_ data points whose `Major_Genre` field value matches the single selected value. - - We initialize `init=...` the selection to a starting value. + - We constrain the selection to a specific data field (`Major_Genre`). Earlier when we used a point selection, it mapped to individual data points. By limiting the selection to a specific field, we can select _all_ data points whose `Major_Genre` field value matches the selected value. + - We set the initial selection state with `value=...`. - We `bind` the selection to an interface widget, in this case a drop-down menu via `binding_select`. - As before, we then use a conditional encoding to control the opacity channel. """) @@ -297,7 +297,7 @@ def _(mo): mo.md(r""" ### Binding Selections to Multiple Inputs - One selection instance can be bound to _multiple_ dynamic query widgets. Let's modify the example above to provide filters for _both_ `Major_Genre` and `MPAA_Rating`, using radio buttons instead of a menu. Our `single` selection is now defined over a single _pair_ of genre and MPAA rating values + One selection instance can be bound to _multiple_ dynamic query widgets. Let's modify the example above to provide filters for _both_ `Major_Genre` and `MPAA_Rating`, using radio buttons instead of a menu. Our point selection is now defined over a single _pair_ of genre and MPAA rating values. _Look for surprising conjunctions of genre and rating. Are there any G or PG-rated horror films?_ """) @@ -525,10 +525,10 @@ def _(mo): mo.md(r""" The example above adds three new layers to the scatter plot: a circular annotation, white text to provide a legible background, and black text showing a film title. In addition, this example uses two selections in tandem: - 1. A single selection (`hover`) that includes `nearest=True` to automatically select the nearest data point as the mouse moves. - 2. A multi selection (`click`) to create persistent selections via shift-click. + 1. A single-point selection (`hover`) that uses `toggle=False` and includes `nearest=True` to automatically select the nearest data point as the mouse moves. + 2. A multi-point selection (`click`) to create persistent selections via shift-click. - Both selections include the set `empty='none'` to indicate that no points should be included if a selection is empty. These selections are then combined into a single filter predicate — the logical _or_ of `hover` and `click` — to include points that reside in _either_ selection. We use this predicate to filter the new layers to show annotations and labels for selected points only. + Both selections include the setting `empty=False` to indicate that no points should be included if a selection is empty. These selections are then combined into a single filter predicate — the logical _or_ of `hover` and `click` — to include points that reside in _either_ selection. We use this predicate to filter the new layers to show annotations and labels for selected points only. """) return diff --git a/marimo/07_cartographic.py b/marimo/07_cartographic.py index ba92a48..dff8c30 100644 --- a/marimo/07_cartographic.py +++ b/marimo/07_cartographic.py @@ -381,7 +381,7 @@ def _(alt, zipcodes): @app.cell(hide_code=True) def _(mo): mo.md(r""" - _To zoom in on a specific digit, add a filter transform to limit the data shown! Try adding an [interactive selection](https://github.com/uwdata/visualization-curriculum/blob/master/altair_interaction.ipynb) to filter to a single digit and dynamically update the map. And be sure to use strings (\`'1'\`) instead of numbers (\`1\`) when filtering digit values!_ + _To zoom in on a specific digit, add a filter transform to limit the data shown! Try adding an [interactive selection](https://github.com/uwdata/visualization-curriculum/blob/master/altair_interaction.ipynb) to filter to a single digit and dynamically update the map. And be sure to use strings (`'1'`) instead of numbers (`1`) when filtering digit values!_ (This example is inspired by Ben Fry's classic [zipdecode](https://benfry.com/zipdecode/) visualization!) @@ -564,7 +564,7 @@ def _(mo): mo.md(r""" _Which U.S. airports have the highest number of outgoing routes?_ - Now that we can see the airports, which may wish to interact with them to better understand the structure of the air traffic network. We can add a `rule` mark layer to represent paths from `origin` airports to `destination` airports, which requires two `lookup` transforms to retrieve coordinates for each end point. In addition, we can use a `single` selection to filter these routes, such that only the routes originating at the currently selected airport are shown. + Now that we can see the airports, which may wish to interact with them to better understand the structure of the air traffic network. We can add a `rule` mark layer to represent paths from `origin` airports to `destination` airports, which requires two `lookup` transforms to retrieve coordinates for each end point. In addition, we can use a point selection to filter these routes, such that only the routes originating at the currently selected airport are shown. _Starting from the static map above, can you build an interactive version? Feel free to skip the code below to engage with the interactive map first, and think through how you might build it on your own!_ """) @@ -576,8 +576,8 @@ def _(airports, alt, flights, usa): # interactive selection for origin airport # select nearest airport to mouse cursor origin = alt.selection_point( - on='mouseover', nearest=True, - fields=['origin'], empty='none' + toggle=False, on='mouseover', nearest=True, + fields=['origin'], empty=False ) # shared data reference for lookup transforms diff --git a/marimo/08_debugging.py b/marimo/08_debugging.py index 2097bd7..cb36c0a 100644 --- a/marimo/08_debugging.py +++ b/marimo/08_debugging.py @@ -70,7 +70,7 @@ def _(mo): conda install -c conda-forge altair ``` - You can run command line commands from a code cell by prefixing it with `!`. For example, to install Altair and Vega Datasets with [Pip](https://pip.pypa.io/), you can run the following cell. + You can run command line commands from a code cell by prefixing it with `!`. For example, to install Altair with [Pip](https://pip.pypa.io/), you can run the following cell. """) return @@ -130,7 +130,7 @@ def _(): @app.cell(hide_code=True) def _(mo): mo.md(r""" - If you are not running the latest version, you can update it with `pip`. You can update Altair and Vega Datasets by running this command in your terminal. + If you are not running the latest version, you can update it with `pip`. You can update Altair by running this command in your terminal. ``` pip install -U altair @@ -213,7 +213,7 @@ def _(mo): mo.md(r""" ## Display Troubleshooting - If you are having issues with seeing a chart, make sure your setup is correct by following the [debugging instruction above](#Installation). If you are still having issues, follow the [instruction about debugging display issues in the Altair documentation](https://iliatimofeev.github.io/altair-viz.github.io/user_guide/troubleshooting.html). + If you are having issues with seeing a chart, make sure your setup is correct by following the [debugging instruction above](#Installation). If you are still having issues, follow the [instruction about debugging display issues in the Altair documentation](https://altair-viz.github.io/user_guide/troubleshooting.html). """) return @@ -223,7 +223,7 @@ def _(mo): mo.md(r""" ### Non Existent Fields - A common error is [accidentally using a field that does not exist](https://iliatimofeev.github.io/altair-viz.github.io/user_guide/troubleshooting.html#plot-displays-but-the-content-is-empty). + A common error is [accidentally using a field that does not exist](https://altair-viz.github.io/user_guide/troubleshooting.html#plot-displays-but-the-content-is-empty). """) return diff --git a/uv.lock b/uv.lock index dac6911..8ff4187 100644 --- a/uv.lock +++ b/uv.lock @@ -28,7 +28,7 @@ wheels = [ [[package]] name = "altair-tutorial" -version = "0.1.0" +version = "2.0.0" source = { virtual = "." } dependencies = [ { name = "altair" },