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 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 - Adds
@alt.theme.register
decorator by @dangotbanned in #3526 - Adds
ThemeConfig
(TypedDict
) by @dangotbanned in #3536
Example of registering a custom theme
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")`
Example of instant feedback while you define a theme config through Pylance in VSCode
Enhancements
Olli Renderer
This release integrates the 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
Example of olli
renderer:
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
Expressions and Selections
Several improvements were made to Altair's expression and selection APIs:
- Generate
expr
method signatures, docs by @dangotbanned in #3600 - Support
&
,|
,~
on all...Predicate
classes by @dangotbanned in #3668 - Support
datetime.(date|datetime)
inExpression
(s) by @dangotbanned in #3654 - Support
datetime.(date|datetime)
as aSchemaBase
parameter by @dangotbanned in #3653 - Add missing
float
toIntoExpression
alias by @dangotbanned in #3611
Example of combining predicates within .transform_filter
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
Example of using Python datetime.date
for value
in alt.selection_interval()
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
Multiple predicates
and constraints
in Chart.transform_filter
- Support
Chart.transform_filter(*predicates, **constraints)
by @dangotbanned in #3664
Example of using keyword-argument constraints
to simplify filter compositions:
import altair as alt
from vega_datasets import data
source = data.population.url
chart = alt.Chart(source).mark_area().encode(
x="age:O",
y="sum(people):Q",
color="year:O"
).transform_filter(year=2000, sex=1)
chart
Bug Fixes
- Resolve multiple
@utils.use_signature
issues by @dangotbanned in #3565 - Relax
dict
annotations inchannels.py
by @dangotbanned in #3573 - Set charset=UTF-8 in HTML templates. by @davidgroves in #3604
- Replace unsafe
locals()
manipulation inChart.encode
by @dangotbanned in #3637 - Revise generated annotation order by @dangotbanned in #3655
- Resolve
alt.binding
signature/docstring issues by @dangotbanned in #3671 - Add missing
@skip_requires_pyarrow(requires_tzdata=True)
by @dangotbanned in #3674 - Don't materialise Ibis table to PyArrow if using vegafusion data transformer by @MarcoGorelli in #3566
mypy
1.12.0 errors by @dangotbanned in #3632- Resolve warnings in
test_api.py
by @dangotbanned in #3592
Documentation
Several new examples were added to the documentation
Example of using alt.when().then().otherwise()
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
Example of using luminance in an expression to dynamically colorize text
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
- Unstack area to render cumulative chart correctly by @joelostblom in #3558
- Change remote nick to
origin
and capitalize version commit by @joelostblom in #3559 - Update releasing notes to reflect that main branch is now protected by @binste in #3562
- Split interactive docs section into subpages by @joelostblom in #3561
- Update docs to use correct init value for
selection_point
by @jpn-- in #3584 - Add example with overlapping bars in a grouped bar chart by @mattijn in #3612
- Bar chart with labels coloured by measured luminance by @mattijn in #3614
- Adds example Calculate Residuals by @dangotbanned in #3625
- Adds Vega-Altair Theme Test by @dangotbanned in #3630
- adds info with step size/independent scale by @daylinmorgan in #3644
- Fix "Layered chart with Dual-Axis" (Method syntax) by @dangotbanned in #3660
- Fix inaccurate
selection_interval
signature by @dangotbanned in #3662 - Update
selection_point
signature by @dangotbanned in #3663 - Update "Ranged Dot Plot" example by @dangotbanned in #3665
- Promote
when-then-otherwise
in User Guide by @dangotbanned in #3544 - Add initial date range to interval selection example by @dsmedia in #3667
- Generate docstrings for
mark_
methods by @dangotbanned in #3675 - Make plausible web analytics public and add link to maintainer notes by @binste in #3571
- Reduce
SchemaValidationError
traceback length by @dangotbanned in #3530
Maintenance
- Drop support for Python 3.8 by @dangotbanned in #3647
- Add support Python 3.13 by @dangotbanned in #3591
- Improve
Then
annotations, autocompletion, docs by @dangotbanned in #3567 - Resolve
SIM910
lint indisplay.py
by @dangotbanned in #3613 - Add
typings/
to.gitignore
by @dangotbanned in #3560 - Adds
test-(slow|fast)
options by @dangotbanned in #3555 - Remove
channels
parameter ininfer_encoding_types
by @dangotbanned in #3564 - Add include patterns for
pyright
by @dangotbanned in #3583 - Fix support
pylance>=2024.9.1
by @dangotbanned in #3585 - Bump
typing_extensions
python to3.14
by @dangotbanned in #3593 - Future-proof Duration type error message test by @MarcoGorelli in #3606
- Use
breaking
,deprecation
labels in changelog by @dangotbanned in #3623 - Bump
vl-convert-python
to1.7.0
by @dangotbanned in #3633 - Add upper version bound on VegaFusion by @jonmmease in #3638
- Add untyped
vegafusion
tomypy
overrides by @dangotbanned in #3640 - Remove outdated
schemapi
comment by @dangotbanned in #3641 - Support generating
Union
aliases by @dangotbanned in #3656 - Moved
vl-convert-python
tosave
dependency group by @apoorvkh in #3609 - Simplify
channels.py
overloads by @dangotbanned in #3659 - Use more robust dtype comparisons, use Narwhals stable API in tests by @MarcoGorelli in #3670
- Use duckdb instead of ibis to test interchange-only support by @MarcoGorelli in #3672
- Resolve or ignore
pyright
-only warnings by @dangotbanned in #3676 - Add
pyarrow-stubs
todev
dependencies by @dangotbanned in #3679 - Prep for VegaFusion 2.0 by @jonmmease in #3680
- Replace unconditional
typing_extensions
imports by @dangotbanned in #3683 - VegaFusion 2 will support narwhals by @jonmmease in #3682
- Bump narwhals to v1.13.1 by @mattijn in #3690
- Distinct Olli renderer template by @mattijn in #3689
- Fix ci warning for pivot.rst by @mattijn in #3691
- Correct nested
expr
equivalence by @dangotbanned in #3624
Full Changelog: v5.4.1...v5.5.0