# 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">

### 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