# Release 5.5.0 The Vega-Altair team is pleased to announce the release of version 5.5.0. This version introduces several exciting new features and enhancements including a revamped theme system, a new renderer optimized for screen readers, and numerous type system updates that improve auto-completion and make it easier to integrate Altair into larger typed programs. This release adds Python 3.13 and removes Python 3.8 support. It also includes a variety of documentation improvements and a range of important bug fixes. Thanks to our maintainers (@binste, @dangotbanned, @joelostblom, @mattijn, and @jonmmease), returning contributors (@MarcoGorelli, @daylinmorgan, and @dsmedia), and first time contributors (@jpn--, @davidgroves, and @apoorvkh) for these improvements. ## What's Changed ### Deprecation #### alt.themes This release deprecates the `alt.themes` `ThemeRegistry` object and replaces it with an improved theme API in the new `alt.theme` module. See the updated [Chart Themes](https://altair-viz.github.io/user_guide/customization.html#chart-themes) documentation for more information: > [!NOTE] > Usage of the legacy `alt.themes` registry will be supported until version 6, but will now display a warning on first use. * Refactor `alt.themes` -> `alt.theme` by @dangotbanned in [#3618](https://github.com/vega/altair/pull/3618) * Adds `@register_theme` decorator by @dangotbanned in [#3526](https://github.com/vega/altair/pull/3526) * Adds `ThemeConfig` (`TypedDict`) by @dangotbanned in [#3536](https://github.com/vega/altair/pull/3536) ##### Example of registering a custom theme ```python= import altair as alt import pandas as pd data = pd.DataFrame({'x': [5, 3, 6, 7, 2], 'y': ['A', 'B', 'C', 'D', 'E']}) @alt.theme.register("my_little_theme", enable=True) def custom_theme(): return alt.theme.ThemeConfig( config={ "bar":{"color":"black"} } ) chart = alt.Chart(data).mark_bar().encode( x='x', y='y', ) chart # enable default using `alt.theme.enable("default")` ``` <img src="https://hackmd.io/_uploads/rJ2miY1XJl.png" width="200"> ##### Example of instant feedback while you define a theme config through Pylance in VSCode <img src="https://hackmd.io/_uploads/SJ8Qi917Jx.gif" width="450"> ### Enhancements #### Olli Renderer This release integrates the [Olli](https://vis.csail.mit.edu/pubs/olli/) project to provide a chart renderer that augments chart visualizations with a keyboard-navigable structure accessible to screen readers. * Add 'olli' renderer to generate accessible text structures for screen reader users by @binste in [#3580](https://github.com/vega/altair/pull/3580) ##### Example of `olli` renderer: ```python= import altair as alt from vega_datasets import data alt.renderers.enable("olli") cars = data.cars.url chart = alt.Chart(cars).mark_bar().encode( y='Cylinders:O', x='mean_acc:Q' ).transform_aggregate( mean_acc='mean(Acceleration)', groupby=["Cylinders"] ) chart ``` <img src="https://hackmd.io/_uploads/H1Cr9dJ7kl.png" width="555"> #### Expressions and Selections Several improvements were made to Altair's [expression](https://altair-viz.github.io/user_guide/interactions/expressions.html) and [selection](https://altair-viz.github.io/user_guide/interactions.html#selections-capturing-chart-interactions) APIs: * Generate `expr` method signatures, docs by @dangotbanned in [#3600](https://github.com/vega/altair/pull/3600) * Support `&`, `|`, `~` on all `...Predicate` classes by @dangotbanned in [#3668](https://github.com/vega/altair/pull/3668) * Support `datetime.(date|datetime)` in `Expression`(s) by @dangotbanned in [#3654](https://github.com/vega/altair/pull/3654) * Support `datetime.(date|datetime)` as a `SchemaBase` parameter by @dangotbanned in [#3653](https://github.com/vega/altair/pull/3653) * Add missing `float` to `IntoExpression` alias by @dangotbanned in [#3611](https://github.com/vega/altair/pull/3611) ##### Example of combining predicates within `.transform_filter` ```python= import altair as alt from vega_datasets import data source = data.population.url chart = alt.Chart(source).mark_line().encode( x="age:O", y="sum(people):Q", color="year:O" ).transform_filter( ~alt.FieldRangePredicate(field='year', range=[1900, 1960]) & (alt.datum.age <= 70) ) chart ``` <img src="https://hackmd.io/_uploads/B1e5TuJQyx.png" width="350"> ##### Example of using Python `datetime.date` for `value` in `alt.selection_interval()` ```python= import datetime import altair as alt from vega_datasets import data source = data.unemployment_across_industries.url dt_values = [datetime.date(2005, 1, 1), datetime.date(2009, 1, 1)] brush = alt.selection_interval( encodings=['x'], value={"x": dt_values} ) base = alt.Chart(source).mark_area( color='goldenrod', opacity=0.3 ).encode( x='yearmonth(date):T', y='sum(count):Q', ) background = base.add_params(brush) selected = base.transform_filter(brush).mark_area(color='goldenrod') background + selected ``` <img src="https://hackmd.io/_uploads/Sy29et1XJl.png" width="350"> #### Multiple `predicates` and `constraints` in `Chart.transform_filter` * Support `Chart.transform_filter(*predicates, **constraints)` by @dangotbanned in [#3664](https://github.com/vega/altair/pull/3664) ##### Example of using keyword-argument `constraints` to simplify filter compositions: ```python= import altair as alt from vega_datasets import data source = data.population.url chart = alt.Chart(source).mark_line().encode( x="age:O", y="sum(people):Q", color="year:O" ).transform_filter(year=2000, sex=1) chart ``` <img src="https://hackmd.io/_uploads/rJvgGtkXJx.png" width="400"> ![image](https://hackmd.io/_uploads/SJNufFk71g.png) ### Bug Fixes * Resolve multiple `@utils.use_signature` issues by @dangotbanned in [#3565](https://github.com/vega/altair/pull/3565) * Relax `dict` annotations in `channels.py` by @dangotbanned in [#3573](https://github.com/vega/altair/pull/3573) * Set charset=UTF-8 in HTML templates. by @davidgroves in [#3604](https://github.com/vega/altair/pull/3604) * Replace unsafe `locals()` manipulation in `Chart.encode` by @dangotbanned in [#3637](https://github.com/vega/altair/pull/3637) * Revise generated annotation order by @dangotbanned in [#3655](https://github.com/vega/altair/pull/3655) * Resolve `alt.binding` signature/docstring issues by @dangotbanned in [#3671](https://github.com/vega/altair/pull/3671) * Add missing `@skip_requires_pyarrow(requires_tzdata=True)` by @dangotbanned in [#3674](https://github.com/vega/altair/pull/3674) * Don't materialise Ibis table to PyArrow if using vegafusion data transformer by @MarcoGorelli in [#3566](https://github.com/vega/altair/pull/3566) * `mypy` 1.12.0 errors by @dangotbanned in [#3632](https://github.com/vega/altair/pull/3632) * Resolve warnings in `test_api.py` by @dangotbanned in [#3592](https://github.com/vega/altair/pull/3592) ### Documentation * Unstack area to render cumulative chart correctly by @joelostblom in [#3558](https://github.com/vega/altair/pull/3558) * Change remote nick to `origin` and capitalize version commit by @joelostblom in [#3559](https://github.com/vega/altair/pull/3559) * Update releasing notes to reflect that main branch is now protected by @binste in [#3562](https://github.com/vega/altair/pull/3562) * Split interactive docs section into subpages by @joelostblom in [#3561](https://github.com/vega/altair/pull/3561) * Update docs to use correct init value for `selection_point` by @jpn-- in [#3584](https://github.com/vega/altair/pull/3584) * Add example with overlapping bars in a grouped bar chart by @mattijn in [#3612](https://github.com/vega/altair/pull/3612) * Bar chart with labels coloured by measured luminance by @mattijn in [#3614](https://github.com/vega/altair/pull/3614) * Adds example Calculate Residuals by @dangotbanned in [#3625](https://github.com/vega/altair/pull/3625) * Adds Vega-Altair Theme Test by @dangotbanned in [#3630](https://github.com/vega/altair/pull/3630) * adds info with step size/independent scale by @daylinmorgan in [#3644](https://github.com/vega/altair/pull/3644) * Fix "Layered chart with Dual-Axis" (Method syntax) by @dangotbanned in [#3660](https://github.com/vega/altair/pull/3660) * Fix inaccurate `selection_interval` signature by @dangotbanned in [#3662](https://github.com/vega/altair/pull/3662) * Update `selection_point` signature by @dangotbanned in [#3663](https://github.com/vega/altair/pull/3663) * Update "Ranged Dot Plot" example by @dangotbanned in [#3665](https://github.com/vega/altair/pull/3665) * Promote `when-then-otherwise` in User Guide by @dangotbanned in [#3544](https://github.com/vega/altair/pull/3544) * Add initial date range to interval selection example by @dsmedia in [#3667](https://github.com/vega/altair/pull/3667) * Generate docstrings for `mark_` methods by @dangotbanned in [#3675](https://github.com/vega/altair/pull/3675) * Make plausible web analytics public and add link to maintainer notes by @binste in [#3571](https://github.com/vega/altair/pull/3571) * Reduce `SchemaValidationError` traceback length by @dangotbanned in [#3530](https://github.com/vega/altair/pull/3530) ##### Example of using `alt.when().then().otherwise()` ```python= import altair as alt from vega_datasets import data source = data.cars() brush = alt.selection_interval() chart = alt.Chart(source).mark_point().encode( x='Horsepower', y='Miles_per_Gallon', color=alt.when(brush).then("Origin").otherwise(alt.value("lightgray")) ).add_params( brush ) chart ``` <img src="https://hackmd.io/_uploads/BJA2tFk7kx.png" width="350"> ##### Example of using luminance in an expression to dynamically colorize text ```python= import altair as alt from vega_datasets import data source = data.barley() base = alt.Chart(source).encode( x=alt.X('sum(yield):Q').stack('zero'), y=alt.Y('site:O').sort('-x'), text=alt.Text('sum(yield):Q', format='.0f') ) bars = base.mark_bar( tooltip=alt.expr("luminance(scale('color', datum.sum_yield))") ).encode( color='sum(yield):Q' ) text = base.mark_text( align='right', dx=-3, color=alt.expr("luminance(scale('color', datum.sum_yield)) > 0.5 ? 'black' : 'white'") ) bars + text ``` <img src="https://hackmd.io/_uploads/r1-ydtkXJg.png" width="300"> ### Maintenance * Drop support for Python `3.8` by @dangotbanned in [#3647](https://github.com/vega/altair/pull/3647) * Add support Python 3.13 by @dangotbanned in [#3591](https://github.com/vega/altair/pull/3591) * Improve `Then` annotations, autocompletion, docs by @dangotbanned in [#3567](https://github.com/vega/altair/pull/3567) * Resolve `SIM910` lint in `display.py` by @dangotbanned in [#3613](https://github.com/vega/altair/pull/3613) * Add `typings/` to `.gitignore` by @dangotbanned in [#3560](https://github.com/vega/altair/pull/3560) * Adds `test-(slow|fast)` options by @dangotbanned in [#3555](https://github.com/vega/altair/pull/3555) * Remove `channels` parameter in `infer_encoding_types` by @dangotbanned in [#3564](https://github.com/vega/altair/pull/3564) * Add include patterns for `pyright` by @dangotbanned in [#3583](https://github.com/vega/altair/pull/3583) * Fix support `pylance>=2024.9.1` by @dangotbanned in [#3585](https://github.com/vega/altair/pull/3585) * Bump `typing_extensions` python to `3.14` by @dangotbanned in [#3593](https://github.com/vega/altair/pull/3593) * Future-proof Duration type error message test by @MarcoGorelli in [#3606](https://github.com/vega/altair/pull/3606) * Use `breaking`, `deprecation` labels in changelog by @dangotbanned in [#3623](https://github.com/vega/altair/pull/3623) * Bump `vl-convert-python` to `1.7.0` by @dangotbanned in [#3633](https://github.com/vega/altair/pull/3633) * Add upper version bound on VegaFusion by @jonmmease in [#3638](https://github.com/vega/altair/pull/3638) * Add untyped `vegafusion` to `mypy` overrides by @dangotbanned in [#3640](https://github.com/vega/altair/pull/3640) * Remove outdated `schemapi` comment by @dangotbanned in [#3641](https://github.com/vega/altair/pull/3641) * Support generating `Union` aliases by @dangotbanned in [#3656](https://github.com/vega/altair/pull/3656) * Moved `vl-convert-python` to `save` dependency group by @apoorvkh in [#3609](https://github.com/vega/altair/pull/3609) * Simplify `channels.py` overloads by @dangotbanned in [#3659](https://github.com/vega/altair/pull/3659) * Use more robust dtype comparisons, use Narwhals stable API in tests by @MarcoGorelli in [#3670](https://github.com/vega/altair/pull/3670) * Use duckdb instead of ibis to test interchange-only support by @MarcoGorelli in [#3672](https://github.com/vega/altair/pull/3672) * Resolve or ignore `pyright`-only warnings by @dangotbanned in [#3676](https://github.com/vega/altair/pull/3676) * Add `pyarrow-stubs` to `dev` dependencies by @dangotbanned in [#3679](https://github.com/vega/altair/pull/3679) * Prep for VegaFusion 2.0 by @jonmmease in [#3680](https://github.com/vega/altair/pull/3680) * Replace unconditional `typing_extensions` imports by @dangotbanned in [#3683](https://github.com/vega/altair/pull/3683) * VegaFusion 2 will support narwhals by @jonmmease in [#3682](https://github.com/vega/altair/pull/3682) * Bump narwhals to v1.13.1 by @mattijn in [#3690](https://github.com/vega/altair/pull/3690) * Distinct Olli renderer template by @mattijn in [#3689](https://github.com/vega/altair/pull/3689) * Fix ci warning for pivot.rst by @mattijn in [#3691](https://github.com/vega/altair/pull/3691) * Correct nested `expr` equivalence by @dangotbanned in [#3624](https://github.com/vega/altair/pull/3624) **Full Changelog**: https://github.com/vega/altair/compare/v5.4.1...v5.5.0