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.themeby @dangotbanned in #3618 - Adds
@alt.theme.registerdecorator 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
exprmethod signatures, docs by @dangotbanned in #3600 - Support
&,|,~on all...Predicateclasses by @dangotbanned in #3668 - Support
datetime.(date|datetime)inExpression(s) by @dangotbanned in #3654 - Support
datetime.(date|datetime)as aSchemaBaseparameter by @dangotbanned in #3653 - Add missing
floattoIntoExpressionalias 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)
)
chartExample 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_signatureissues by @dangotbanned in #3565 - Relax
dictannotations inchannels.pyby @dangotbanned in #3573 - Set charset=UTF-8 in HTML templates. by @davidgroves in #3604
- Replace unsafe
locals()manipulation inChart.encodeby @dangotbanned in #3637 - Revise generated annotation order by @dangotbanned in #3655
- Resolve
alt.bindingsignature/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
mypy1.12.0 errors by @dangotbanned in #3632- Resolve warnings in
test_api.pyby @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
originand 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_pointby @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_intervalsignature by @dangotbanned in #3662 - Update
selection_pointsignature by @dangotbanned in #3663 - Update "Ranged Dot Plot" example by @dangotbanned in #3665
- Promote
when-then-otherwisein 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
SchemaValidationErrortraceback 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
Thenannotations, autocompletion, docs by @dangotbanned in #3567 - Resolve
SIM910lint indisplay.pyby @dangotbanned in #3613 - Add
typings/to.gitignoreby @dangotbanned in #3560 - Adds
test-(slow|fast)options by @dangotbanned in #3555 - Remove
channelsparameter ininfer_encoding_typesby @dangotbanned in #3564 - Add include patterns for
pyrightby @dangotbanned in #3583 - Fix support
pylance>=2024.9.1by @dangotbanned in #3585 - Bump
typing_extensionspython to3.14by @dangotbanned in #3593 - Future-proof Duration type error message test by @MarcoGorelli in #3606
- Use
breaking,deprecationlabels in changelog by @dangotbanned in #3623 - Bump
vl-convert-pythonto1.7.0by @dangotbanned in #3633 - Add upper version bound on VegaFusion by @jonmmease in #3638
- Add untyped
vegafusiontomypyoverrides by @dangotbanned in #3640 - Remove outdated
schemapicomment by @dangotbanned in #3641 - Support generating
Unionaliases by @dangotbanned in #3656 - Moved
vl-convert-pythontosavedependency group by @apoorvkh in #3609 - Simplify
channels.pyoverloads 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-stubstodevdependencies by @dangotbanned in #3679 - Prep for VegaFusion 2.0 by @jonmmease in #3680
- Replace unconditional
typing_extensionsimports 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
exprequivalence by @dangotbanned in #3624
Full Changelog: v5.4.1...v5.5.0