Releases: vega/altair
Version 5.5.0
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
signatur...
Version 5.4.1
What's Changed
Enhancements
- feat(typing): Generate
Literal
aliases inchannels
overload(s) by @dangotbanned in #3535 - feat(typing): Generate
Literal
(s) using"const"
by @dangotbanned in #3538
Bug Fixes
- fix: Raise informative error message if a non-existent column name is passed by @MarcoGorelli in #3533
- revert: Remove
sphinx
version constraint by @dangotbanned in #3541 - fix: Pass native dataframe to data transformers by @MarcoGorelli in #3550
- fix: Resolve
Then
copyTypeError
by @dangotbanned in #3553
Documentation
Other Changes
- ci: bump
ruff>=0.6.0
by @dangotbanned in #3539 - ci: Remove
m2r
frommypy.overrides
by @dangotbanned in #3540 - refactor: Simplify
SchemaBase.copy
by @dangotbanned in #3543 - fix(typing): Resolve misc type ignores in
schemapi.py
by @dangotbanned in #3545 - test: Rename test to more specific
chart_error_example__four_errors_hide_fourth
by @dangotbanned in #3546 - test: Shorten
test_chart_validation_errors
test ids by @dangotbanned in #3551 - refactor: Replace an indirect
SchemaBase
import by @dangotbanned in #3556 - test: Fix deprecation warning from
ipywidgets
by @dangotbanned in #3557
Full Changelog: v5.4.0...v5.4.1
Version 5.4.0
What's Changed
Enhancements
- Update Vega-Lite from version 5.17.0 to version 5.20.1; see Vega-Lite Release Notes. By @binste in #3479 and #3525
- Remove several dependencies to make the package more lightweight:
- feat: make pandas and NumPy optional dependencies, don't require PyArrow for plotting with Polars/Modin/cuDF by @MarcoGorelli in #3452
- Remove
toolz
dependency by @dangotbanned in #3426
- feat: Improve the syntax for conditions with multiple predicates. See the documentation of
alt.when
for examples by @dangotbanned in #3427 and #3492 - feat: Reimplement
alt.expr
as a class that is understood by IDEs by @dangotbanned in #3466 - feat: Support a wider range of iterables, i.e. many places in Altair now accept not only lists but
np.array
,pd.Series
,tuples
, etc. by @dangotbanned in #3501 - feat: Adds 4 new
carbon
themes, provide autocomplete for themes by @dangotbanned in #3516 - perf: Fix issues with
Chart|LayerChart.encode
, 1.32x speedup toinfer_encoding_types
by @dangotbanned in #3444
Various typing improvements:
- feat(typing): Adds public
altair.typing
module by @dangotbanned in #3515 - feat(typing):
@deprecated
versioning, IDE highlighting by @dangotbanned in #3455 - feat: Adds
ChartType
type and type guardis_chart_type
. Change PurePath to Path type hints by @dangotbanned in #3420 - feat(typing): adds
Map
alias forMapping[str, Any]
by @dangotbanned in #3458 - feat(typing): Ban
typing.Optional
import usingruff
by @dangotbanned in #3460 - feat(typing): Further simplify generated
Literal
aliases by @dangotbanned in #3469 - feat(typing): Fully annotate
api.py
by @dangotbanned in #3508
Bug Fixes
- fix(typing): Resolve
mypy==1.11.0
issues inplugin_registry
by @dangotbanned in #3487 - fix: solve mypy errors which are due to same object names in core.py and channels.py by @binste in #3414
- fix: remove remapped
ruff
rulePLR1701
by @dangotbanned in #3453 - fix(docs):
@utils.use_signature
formatting by @dangotbanned in #3450 - fix(typing): Ignore
[arg-type]
error in_deduplicate_enum_errors
by @dangotbanned in #3475 - fix: Restrict static & runtime top-level imports by @dangotbanned in #3482
- fix: Avoid
sphinx
error "Code Execution failed:NameError: name 'format_locale' is not defined" by @dangotbanned in #3503 - fix: replace deprecated
sphinx
default by @dangotbanned in #3512 - fix(ruff): Bump
ruff
, fixRUF031
by @dangotbanned in #3529
Documentation
- docs: Versioning policy by @dangotbanned in #3488
- docs: Add example of reordering stacked bars by @joelostblom in #3395
- docs: Add example of how to create polar bar charts by @joelostblom in #3428
- docs: Add example of cumulative line chart with facet by @dsmedia in #3440
- docs: Add example with hover path and search box by @dsmedia in #3459
- docs: Add example for Bar Chart with Highlighting on Hover and Selection on Click by @dangotbanned in #3485
- docs: Link to
Vega Theme Test
in user guide by @dangotbanned in #3528 - docs: Fix and improve
alt.Optional
doc by @dangotbanned in #3449 - docs: Fix camel case of fillOpacity channel by @timtroendle in #3465
- docs: Fix
CONTRIBUTING.md
phrasing by @dangotbanned in #3477 - docs: Reduce number of items in header to 4 by @binste in #3401
- docs: Link to project board for roadmap by @joelostblom in #3404
- docs: Use raw strings with escape sequences by @joelostblom in #3411
- docs: Update
hatch
guidance by @dangotbanned in #3461 - docs: Add
empty
as a explicitcondition
kwarg by @dangotbanned in #3490 - docs: Undoc deprecated functionality by @dangotbanned in #3509
- docs: Remove reference to
altair_saver
insave
by @dangotbanned in #3510 - docs: Update link to Altair Ally by @sebp in #3517
Maintenance
- chore: Remove CoC link in templates since it's displayed by default by @joelostblom in #3390
- chore: Update org name from altair-viz to vega by @binste in #3400
- build: pin upperlimit geopandas by @mattijn in #3421
- ci: remove again geopandas pin and disable flaky test by @binste in #3422
- ci: Remove references to archived altair_viewer and altair_saver in ci, docs, and tests. Uninstall anywidget and vl-convert-python during one test run by @binste in #3419
- ci: prepare for
numpy 2
by @dangotbanned in #3438 - ci: Add a Dependabot config to auto-update GitHub action versions by @kurtmckee in #3437
- ci: Update dependabot.yaml to include prefix by @mattijn in #3442
- ci: Bump the github-actions group with 2 updates by @dependabot in #3439
- chore: avoid pandas warning for
freq='H'
in test_utils.py by @MarcoGorelli in #3446 - refactor: Add
ruff
rules, improve type annotations, improve ci performance by @dangotbanned in #3431 - style: Remove outdated comments about the use of the former _Parameter protocol by @binste in #3448
- chore: fixup ruff-mypy CI job due to Ruff change by @MarcoGorelli in #3463
- refactor(typing): Reuse generated
Literal
aliases inapi
by @dangotbanned in #3464 - ci: remove
toolz
from[[tool.mypy.overrides]]
by @dangotbanned in #3474 - refactor: Simplify
SchemaBase
repr by @dangotbanned in #3472 - refactor: remove dead
_get_channels_mapping
code by @dangotbanned in #3467 - ci: bump
ruff>=0.5.3
forPLW1514
fix by @dangotbanned in #3484 - test: skip
ibis
test on unsupportedpython
version by @dangotbanned in #3486 - refactor(typing): reduce type ignores in
api.py
by @dangotbanned in #3480 - fix: remove unsupported
sphinx
theme option'footer_items'
by @dangotbanned in #3489 - refactor: Rename and move
is_undefined
,OneOrSeq
by @dangotbanned in #3491 - refactor(docs, ruff): Add
pydocstyle
rules by @dangotbanned in #3493 - ci: include optional dependencies for Polars backend in ibis-framework install by @MarcoGorelli in #3494
- ci: Add
python-version=="3.9"
to github action by @dangotbanned in #3498 - ci(ruff): Remove stale
docstring-code-format
comment by @dangotbanned in #3496 - ci: relax
numpy<=2.0.0
constraint by @dangotbanned in #3504 - refactor: replace archived
m2r
with updatedmistune
by @dangotbanned in #3506 - build: Add
ipykernel
optional dependency todev
group by @dangotbanned in #3507 - refactor(ruff): Organize imports w/ (
I001
,TID252
) rules by @dangotbanned in #3513 - ci: Bump
sphinx
,vl-convert-python
by @dangotbanned in #3527 - chore: Remove filterwarnings from tests for cross-version pandas compatibility by @MarcoGorelli in #3522
- ci(ruff): Enforce the default
C901
complexity by @dangotbanned in #3531 - refactor: Simplify unreachable compound chart cases by @dangotbanned in #3520
- feat: Adds
vega-themes.json
usingvl_convert
by @dangotbanned in #3523
New Contributors
- @dangotbanned made their first contribution in #3420
- @kurtmckee made their first contribution in #3437
- @dependabot made their first co...
Version 5.3.0
The Vega Project is happy to announce the release of version 5.3.0 of the Vega-Altair Python visualization library. This release has been 4 months in the making and includes enhancements, fixes, and documentation improvements from 11 contributors.
What's Changed
- Update Vega-Lite from version 5.16.3 to version 5.17.0; see Vega-Lite Release Notes
Enhancements
-
Add integration of VegaFusion and JupyterChart to enable scaling many interactive Vega-Altair charts to millions of rows. See VegaFusion Data Transformer for more information. Here is an example of histogram cross filtering with a 1 million row dataset.
vegafusion_widget.mov
-
Add
"browser"
renderer to support displaying Vega-Altair charts in an external web browser. See Browser Renderer for more information (#3379).browser_renderer.mov
-
Support opening charts in the Vega editor with
chart.open_editor()
(#3358)open_editor.mov
- Add
"jupyter"
renderer which uses JupyterChart for rendering (#3283). See Displaying Altair Charts for more information. - Add
embed_options
argument to JupyterChart to allow customization of Vega Embed options (#3304) - Add offline support for JupyterChart and the new
"jupyter"
renderer. See JupyterChart - Offline Usage for more information. - Add a new section to documentation on dashboards which have support for Altair (#3299)
- Support restrictive FIPS-compliant environment (#3291)
- Simplify type-hints to improve the readability of the function signature and docstring (#3307)
- Support installation of all optional dependencies via
python -m pip install altair[all]
andconda install altair-all -c conda-forge
(#3354) - Add privacy friendly web-analytics for the documentation (#3350)
- Additional gallery examples and documentation clarifications (#3233, #3266, #3276, #3282, #3298, #3299, #3323, #3334, #3324, #3340, #3350, #3353, #3357, #3362, #3363), including the following:
-
altair-ex-2024-03-12_10.16.49.mp4
Bug Fixes
- Fix error when
embed_options
areNone
(#3376) - Fix type hints for libraries such as Polars where Altair uses the dataframe interchange protocol (#3297)
- Fix anywidget deprecation warning (#3364)
- Fix handling of Date32 columns in arrow tables and Polars DataFrames (#3377)
Backward-Incompatible Changes
- Changed hash function from
md5
to a truncatedsha256
non-cryptograhic hash (#3291) - Updated
chart.show()
method to invoke the active renderer rather than depend onaltair_saver
(Which was never updated for use with Altair 5) (#3379).
New Contributors
- @franzhaas made their first contribution in #3278
- @ccravens made their first contribution in #3291
- @thomascamminady made their first contribution in #3323
- @d-trigo made their first contribution in #3350
- @RobinL made their first contribution in #3383
Release notes by pull requests
Click to view all 44 PRs merged in this release
- perf: Improve performance of
Chart.from_dict
by @RobinL in #3383 - feature: Add browser renderer to open charts in external browser and update chart.show() to display chart by @jonmmease in #3379
- fix: Don't error when embed_options are None by @jonmmease in #3376
- fix: Handle Date32 columns in Arrow tables and Polars DataFrames by @jonmmease in #3377
- fix: Support falling back to pandas when pyarrow is installed but too old by @jonmmease in #3387
- docs: Remove release notes and fully capture them in GitHub Releases by @binste in #3380
- Update save.py to use utf-8 instead of None per default by @franzhaas in #3278
- Consolidate governance documents in Vega Organization by @domoritz in #3277
- doc: histogram with gradient color by @mattijn in #3282
- Update for FIPS Compliance by @ccravens in #3291
- Docs: Fix link to project governance docs by @binste in #3298
- Fix type checker errors for libraries such as Polars where Altair uses dataframe interchange protocol by @binste in #3297
- Integrate VegaFusion into JupyterChart by @jonmmease in #3281
- Add "jupyter" renderer based on JupyterChart by @jonmmease in #3283
- Docs: Add section on displaying Altair charts in dashboards by @binste in #3299
- Validate version of vegafusion-python-embed by @jonmmease in #3303
- Add embed_options to JupyterChart and pass them through in "jupyter" renderer by @jonmmease in #3304
- Add offline support to JupyterChart and "jupyter" renderer by @jonmmease in #3305
- Type hints: Simplify to improve user experiences by @binste in #3307
- Adding missing interpolation methods to Line example by @thomascamminady in #3323
- Docs: Link to new section on Altair in Plotly docs by @binste in #3324
- Docs: Mark completed items in roadmap by @binste in #3326
- Docs: Mention Marimo in Dashboards section by @binste in #3334
- Relax type hint for 'indent' in to_json method by @binste in #3342
- MAINT: Reformat codebase with new style of ruff 0.3.0 by @binste in #3345
- Docs: Add another version of the 'Multiline Tooltip' exmaple which uses the standard tooltip by @binste in #3340
- Docs: Add privacy-friendly web analytics with plausible by @binste in #3346
- Docs: Modifying scale of "multiple interactions" example and adding legend adjustments by @d-trigo in #3350
- Add example of how to update titles based on a selection parameters by @joelostblom in #3353
- Add
all
dependency group by @jonmmease in #3354 - Add timeseries filtering example to illustrate subsetting of columns from selector values by @joelostblom in #3357
- Fix anywidget deprecation warning by @jonmmease in #3364
- Clarifications to the interactive docs by @joelostblom in #3362
- Open charts in the default browser with
open_editor
method by @joelostblom in #3358 - Change "mouse" to "pointer" everywhere by @joelostblom in #3363
- doc: update numpy-tooltip-images.rst by @mattijn in #3233
- Change a couple of more additional occurences of pointer over by @joelostblom in #3368
- [Doc] Fix Chart and MarkDef language by @ChiaLingWeng in #3266
- Add remaining changelog entries for 5.3 by @joelostblom in #3369
- Upgrade to Vega-Lite 5.17.0 by @binste in #3367
- Add a few 5.3 changelog entries by @jonmmease in #3372
- Add note about conda "all" installation and how to install without optional dependencies by @joelostblom in #3373
- Update README badges to reflect updated tool chain by @mattijn in #3374
- chore: Add templates for PRs and automated release notes by @joelostblom in https://github.com/altair-vi...
Version 5.2.0
What's Changed
- Update Vega-Lite from version 5.15.1 to version 5.16.3; see Vega-Lite Release Notes.
Enhancements
-
Support offline HTML export using vl-convert (#3251)
You now can use:
chart.save('chart.html', inline=True)
To create an HTML file with inline JavaScript dependencies. This enhancements takes advantage of HTML bundling support in
vl-convert
to replace the dependency onaltair_viewer
. Vega-Altair 5.2.0 expectsvl-convert-python
version 1.1.0 or higher for this enhancement.
-
Support saving charts as PDF files using the vl-convert export engine (#3244)
You now can use:
chart.save('chart.pdf')
To create an PDF representation of your chart. This enhancements takes advantage of PDF support in
vl-convert
to replace the dependency onaltair_saver
. Vega-Altair 5.2.0 expectsvl-convert-python
version 1.1.0 or higher for this enhancement.
-
Support converting charts to sharable Vega editor URLs with chart.to_url() (#3252)
You now can use:
chart.to_url()
To generate a Vega editor URL that opens the chart's specification in the online Vega editor. This enhancements takes advantage of lz-string URL-compatible compression in
vl-convert
. Vega-Altair 5.2.0 expectsvl-convert-python
version 1.1.0 or higher for this enhancement.Example:
import altair as alt from vega_datasets import data chart = alt.Chart(data.cars.url).mark_point().encode( x='Horsepower:Q', y='Miles_per_Gallon:Q', color='Origin:N' ) print(chart.to_url())
-
Pass
format_locale
andtime_format_locale
through to vl-convert to support locales in static image export (#3274)The preferred format of numbers, dates, and currencies varies by language and locale. Vega-Altair takes advantage of D3’s localization support to make it easy to configure the locale for your chart using the global
alt.renderers.set_embed_options
function. Vega-Altair 5.2.0 expectsvl-convert-python
version 1.1.0 or higher for this enhancement.See https://altair-viz.github.io/user_guide/customization.html#localization for more info (including the note with a caveat!).
-
Vega-Altair is now a typed package, with type annotations for all public functions and classes and some of the internal code
See #2951 for a full summary how we have implemented these. Type hints can help IDEs to provide a better development experience as well as static type checkers to catch potential errors before they appear at runtime.
Maintenance
- Vega-Altair now uses ruff for maintaining code quality & consistency (#3243)
- Vega-Altair is tested against Python 3.12 (#3235)
Bug Fixes
- None
Backward-Incompatible Changes
- None
New Contributors
- @ChiaLingWeng made their first contribution in #3218
Release Notes by Pull Request
Click to view all 31 PRs merged in this release
- Perform minor consistency cleanup by @joelostblom in #3215
- [Doc] Add integers to four digit year format example by @ChiaLingWeng in #3218
- Maint: Do not pass literal json to read_json in test by @binste in #3221
- Do not display search keyboard shortcut on home page by @joelostblom in #3220
- [Doc] Add Label Position Based on Condition Example by @ChiaLingWeng in #3226
- [Doc] Update UserGuide: Add Rotate Axis, Sort Legend Example, Citing Section by @ChiaLingWeng in #3217
- [Doc] Add Show Image Marks With Selection/Show Local Images Examples by @ChiaLingWeng in #3219
- [Doc] Add Reverse Scale and Update Example for Consistency by @ChiaLingWeng in #3228
- Correct the method-based syntax for a few more gallery examples by @joelostblom in #3005
- doc: update pandas to smallcase p by @mattijn in #3232
- Type hint api.py by @binste in #3143
- maint: change to ruff for formatting by @mattijn in #3243
- maint: GitHub action include
python-version
3.12 by @mattijn in #3235 - Support saving to PDF with VlConvert 1.0 by @jonmmease in #3244
- Support converting a Chart to a Vega editor URL by @jonmmease in #3252
- Type hint utils/save.py and utils/mimebundle.py by @binste in #3248
- docs: add range bar chart by @mattijn in #3250
- doc: barchart highlighting values beyond a single threshold by @mattijn in #3249
- Update image export error message with PDF format by @jonmmease in #3255
- Use vl-convert for offline html export by @jonmmease in #3251
- doc: add example interactive aggregation by @mattijn in #3260
- [Doc] Add Arrow Vector Example by @ChiaLingWeng in #3236
- [Doc] Add scatter plot with shaded area example by @ChiaLingWeng in #3256
- Make facet error more informative by @joelostblom in #3264
- Type hints: Infer types from vegalite schema for autogenerated code by @binste in #3208
- Fix broken JupyterWidget chart by pinning Vega by @jonmmease in #3269
- Type hints: Finish type hints and mark package as typed by @binste in #3272
- Update to Vega-Lite 5.16.3 by @jonmmease in #3273
- Pass locale info through to vl-convert, default to display embed options when not set by @jonmmease in #3274
- doc: add example, interval selection on a map by @mattijn in #3275
- doc: maintain colors by @mattijn in #3276
Full Changelog: v5.1.2...v5.2.0
Version 5.1.2
What's changed
-
Update Vega-Lite from version 5.14.1 to version 5.15.1; see Vega-Lite Release Notes.
-
Use Facet/Trellis/Repeat consistently in the documentation by @NickCrews in #3180
-
Add tutorial on numpy tooltip images by @joelostblom #3202
recording-2024-04-08_20.15.42.mp4
Bug Fixes
- Remove usage of deprecated Pandas parameter
convert_dtypes
by @binste in #3191 - Fix encoding type inference for boolean columns when pyarrow is installed by @jonmmease in #3210
Full Changelog: v5.1.1...v5.1.2
Version 5.1.1
What's Changed
- Fix doctest and run doctests in altair module by @jonmmease in #3175
- infer dtype pandas fallback by @jonmmease in #3179
Full Changelog: v5.1.0...v5.1.1
Version 5.1.0
What's Changed
- Update Vega-Lite from version 5.8.0 to version 5.14.1; see Vega-Lite Release Notes.
Enhancements
-
The
chart.transformed_data()
method was added to extract transformed chart dataFor example when having an Altair chart including aggregations:
import altair as alt from vega_datasets import data 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
Its now possible to call thechart.transformed_data
method to extract a pandas DataFrame containing the transformed data.chart.transformed_data()
This method is dependent on VegaFusion with the embed extras enabled.
-
Introduction of a new data transformer named
vegafusion
VegaFusion is an external project that provides efficient Rust implementations of most of Altair's data transformations. Using VegaFusion as Data Transformer it can overcome the Altair MaxRowsError by performing data-intensive aggregations in Python and pruning unused columns from the source dataset.
The data transformer can be enabled as such:
import altair as alt alt.data_transformers.enable("vegafusion") # default is "default"
DataTransformerRegistry.enable('vegafusion')
And one can now visualize a very large DataFrame as histogram where the binning is done within VegaFusion:
import pandas as pd import altair as alt # prepare dataframe with 1 million rows flights = pd.read_parquet( "https://vegafusion-datasets.s3.amazonaws.com/vega/flights_1m.parquet" ) delay_hist = alt.Chart(flights).mark_bar(tooltip=True).encode( alt.X("delay", bin=alt.Bin(maxbins=30)), alt.Y("count()") ) delay_hist
When thevegafusion
data transformer is active, data transformations will be pre-evaluated when displaying, saving and converting charts as dictionary or JSON.See a detailed overview on the VegaFusion Data Transformer in the documentation.
-
A
JupyterChart
class was added to support accessing params and selections from PythonThe
JupyterChart
class makes it possible to update charts after they have been displayed and access the state of interactions from Python.For example when having an Altair chart including a selection interval as brush:
import altair as alt from vega_datasets import data source = data.cars() brush = alt.selection_interval(name="interval", value={"x": [80, 160], "y": [15, 30]}) chart = alt.Chart(source).mark_point().encode( x='Horsepower:Q', y='Miles_per_Gallon:Q', color=alt.condition(brush, 'Cylinders:O', alt.value('grey')), ).add_params(brush) jchart = alt.JupyterChart(chart) jchart
It is now possible to return the defined interval selection within Python using theJupyterChart
jchart.selections.interval.value
{'Horsepower': [80, 160], 'Miles_per_Gallon': [15, 30]}
The selection dictionary may be converted into a pandas query to filter the source DataFrame:
filter = " and ".join([ f"{v[0]} <= `{k}` <= {v[1]}" for k, v in jchart.selections.interval.value.items() ]) source.query(filter)
Another possibility of the newJupyerChart
class is to useIPyWidgets
to control parameters in Altair. Here we use an ipywidgetIntSlider
to control the Altair parameter namedcutoff
.import pandas as pd import numpy as np from ipywidgets import IntSlider, link, VBox rand = np.random.RandomState(42) df = pd.DataFrame({ 'xval': range(100), 'yval': rand.randn(100).cumsum() }) cutoff = alt.param(name="cutoff", value=23) chart = alt.Chart(df).mark_point().encode( x='xval', y='yval', color=alt.condition( alt.datum.xval < cutoff, alt.value('red'), alt.value('blue') ) ).add_params( cutoff ) jchart = alt.JupyterChart(chart) slider = IntSlider(min=0, max=100, description='ipywidget') link((slider, "value"), (jchart.params, "cutoff")) VBox([slider, jchart])
TheJupyterChart
class is dependent on AnyWidget. See a detailed overview in the new documentation page on JupyterChart Interactivity.
-
Support for field encoding inference for objects that support the DataFrame Interchange Protocol
We are maturing support for objects build upon the DataFrame Interchange Protocol in Altair.
Given the following pandas DataFrame with an ordered categorical column-type:import altair as alt from vega_datasets import data # Clean Title column movies = data.movies() movies["Title"] = movies["Title"].astype(str) # Convert MPAA rating to an ordered categorical rating = movies["MPAA_Rating"].astype("category") rating = rating.cat.reorder_categories( ['Open', 'G', 'PG', 'PG-13', 'R', 'NC-17', 'Not Rated'] ).cat.as_ordered() movies["MPAA_Rating"] = rating # Build chart using pandas chart = alt.Chart(movies).mark_bar().encode( alt.X("MPAA_Rating"), alt.Y("count()") ) chart
We can convert the DataFrame to a PyArrow Table and observe that the types are now equally infered when rendering the chart.import pyarrow as pa # Build chart using PyArrow chart = alt.Chart(pa.Table.from_pandas(movies)).mark_bar().encode( alt.X("MPAA_Rating"), alt.Y("count()") ) chart
Vega-Altair support of the DataFrame Interchange Protocol is dependent on PyArrow.
-
A new transform method
transform_extent
is availableSee the following example how this transform can be used:
import pandas as pd import altair as alt df = pd.DataFrame( [ {"a": "A", "b": 28}, {"a": "B", "b": 55}, {"a": "C", "b": 43}, {"a": "D", "b": 91}, {"a": "E", "b": 81}, {"a": "F", "b": 53}, {"a": "G", "b": 19}, {"a": "H", "b": 87}, {"a": "I", "b": 52}, ] ) base = alt.Chart(df, title="A Simple Bar Chart with Lines at Extents").transform_extent( extent="b", param="b_extent" ) bars = base.mark_bar().encode(x="b", y="a") lower_extent_rule = base.mark_rule(stroke="firebrick").encode( x=alt.value(alt.expr("scale('x', b_extent[0])")) ) upper_extent_rule = base.mark_rule(stroke="firebrick").encode( x=alt.value(alt.expr("scale('x', b_extent[1])")) ) bars + lower_extent_rule + upper_extent_rule
-
It is now possible to add configurable pixels-per-inch (ppi) metadata to saved and displayed PNG images
import altair as alt from vega_datasets import data source = data.cars() chart = alt.Chart(source).mark_boxplot(extent="min-max").encode( alt.X("Miles_per_Gallon:Q").scale(zero=False), alt.Y("Origin:N"), ) chart.save("box.png", ppi=300)
alt.renderers.enable("png", ppi=144) # default ppi is 72 chart
Bug Fixes
- Don't call
len
on DataFrame Interchange Protocol objects (#3111)
Maintenance
- Add support for new referencing logic in version 4.18 of the jsonschema package
Backward-Incompatible Changes
- Drop support for Python 3.7 which is end-of-life (#3100)
- Hard dependencies: Increase minimum required pandas version to 0.25 (#3130)
- Soft dependencies: Increase minimum required vl-convert-python version to 0.13.0 and increase minimum required vegafusion version to 1.4.0 (#3163, #3160)
New Contributors
- @thomend made their first contribution in #3086
- @NickCrews made their first contribution in #3155
Release Notes by Pull Request
Click to view all 52 PRs m...
Version 5.0.1
What's Changed
- Be clearer about how vegafusion works by @joelostblom in #3052
- Use altairplot Sphinx directive of sphinxext_altair package by @binste in #3056
- Fix test command in README by @binste in #3058
- Remove extra files in site-packages from wheel by @jtilly in #3057
- Add validation of Vega-Lite schema itself by @binste in #3061
- Deprecate
.ref()
instead of removing it by @mattijn in #3063 - Update area.rst by @mattijn in #3064
- Documentation: Improve homepage by @binste in #3060
- TitleParam to Title in example gallery and sync scatterplot table by @joelostblom in #3066
- Fix bug in reconstructing layered charts with from_json/from_dict by @binste in #3068
Full Changelog: v5.0.0...v5.0.1
Version 5.0.0
What's Changed
- Update Vega-Lite from version 4.17.0 to version 5.8.0; see Vega-Lite Release Notes.
Enhancements
- As described in the release notes for Vega-Lite 5.0.0, the primary change in this release of Altair is the introduction of parameters. There are two types of parameters, selection parameters and variable parameters. Variable parameters are new to Altair, and while selections are not new, much of the old terminology has been deprecated. See Slider Cutoff for an application of variable parameters (#2528).
- Grouped bar charts and jitter are now supported using offset channels, see Grouped Bar Chart with xOffset and Strip Plot Jitter.
vl-convert
is now used as the default backend for saving Altair charts as svg and png files, which simplifies saving chart as it does not require external dependencies likealtair_saver
does (#2701). Currently,altair_saver
does not support Altair 5 and it is recommended to switch tovl-convert
. See PNG, SVG, and PDF format for more details.- Saving charts with HTML inline is now supported without having
altair_saver
installed (#2807). - The default chart width was changed from
400
to300
(#2785). - Ordered pandas categorical data are now automatically encoded as sorted ordinal data (#2522)
- The
Title
andImpute
aliases were added forTitleParams
andImputeParams
, respectively (#2732). - The documentation page has been revamped, both in terms of appearance and content.
- More informative autocompletion by removing deprecated methods (#2814) and for editors that rely on type hints (e.g. VS Code) we added support for completion in method chains (#2846) and extended keyword completion to cover additional methods (#2920).
- Substantially improved error handling. Both in terms of finding the more relevant error (#2842), and in terms of improving the formatting and clarity of the error messages (#2824, #2568, #2979, #3009).
- Include experimental support for the DataFrame Interchange Protocol (through
__dataframe__
attribute). This requirespyarrow>=11.0.0
(#2888). - Support data type inference for columns with special characters (#2905).
- Responsive width support using
width="container"
when saving charts to html or displaying them with the defaulthtml
renderer (#2867).
Grammar Changes
- Channel options can now be set via a more convenient method-based syntax in addition to the previous attribute-based syntax. For example, instead of
alt.X(..., bin=alt.Bin(...))
it is now recommend to usealt.X(...).bin(...)
) (#2795). See Method-Based Syntax for details. selection_single
andselection_multi
are now deprecated; useselection_point
instead. Similarly,type=point
should be used instead oftype=single
andtype=multi
.add_selection
is deprecated; useadd_params
instead.- The
selection
keyword argument must in many cases be replaced byparam
(e.g., when specifying a filter transform). - The
empty
keyword argument for a selection parameter should be specified asTrue
orFalse
instead ofall
ornone
, respectively. - The
init
keyword argument for a parameter is deprecated; usevalue
instead.
Bug Fixes
- Displaying a chart not longer changes the shorthand syntax of the stored spec (#2813).
- Fixed
disable_debug_mode
(#2851). - Fixed issue where the webdriver was not working with Firefox's geckodriver (#2466).
- Dynamically determine the jsonschema validator to avoid issues with recent jsonschema versions (#2812).
Backward-Incompatible Changes
- Colons in column names must now be escaped to remove any ambiguity with encoding types. You now need to write
"column\:name"
instead of"column:name"
(#2824). - Removed the Vega (v5) wrappers and deprecate rendering in Vega mode (save Chart as Vega format is still allowed) (#2829).
- Removed the Vega-Lite 3 and 4 wrappers (#2847).
- Removed the deprecated datasets.py (#3010).
- In regards to the grammar changes listed above, the old terminology will still work in many basic cases. On the other hand, if that old terminology gets used at a lower level, then it most likely will not work. For example, in the current version of Scatter Plot with Minimap, two instances of the key
param
are used in dictionaries to specify axis domains. Those used to beselection
, but that usage is not compatible with the current Vega-Lite schema. - Removed the
altair.sphinxext
module (#2792). Thealtair-plot
Sphinx directive is now part of the sphinxext-altair package.
Maintenance
- Vega-Altair now uses
hatch
for package management. - Vega-Altair now uses
ruff
for linting.
New Contributors
- @robna made their first contribution in #2559
- @tempdata73 made their first contribution in #2652
- @Ckend made their first contribution in #2667
- @brahn made their first contribution in #2681
- @jonmmease made their first contribution in #2701
- @hebarton5 made their first contribution in #2607
- @dwootton made their first contribution in #2719
- @johnmarkpittman made their first contribution in #2747
- @yanghung made their first contribution in #2621
- @daylinmorgan made their first contribution in #2686
- @xujiboy made their first contribution in #2615
- @Midnighter made their first contribution in #2466
- @dylancashman made their first contribution in #2925
- @dpoznik made their first contribution in #3001
- @m-charlton made their first contribution in #3026
- @nlafleur made their first contribution in #2867
- @kunalghosh made their first contribution in #3046
Release Notes by Pull Request
Click to view all 203 PRs merged in this release
- Add strict option to sphinx extension by @jtilly in #2551
- docs: correcting regression equations by @robna in #2559
- MAINT: Fix GH actions issues by @joelostblom in #2567
- WIP: update to Vega-Lite 5.2 by @ChristopherDavisUCI in #2528
- MAINT: Update actions' links to use https by @joelostblom in #2575
- DOCS: Clarify steps in the contributing guidelines by @joelostblom in #2569
- MAINT: Make sure that deprecation warnings are displayed by @joelostblom in #2577
- DOCS: Revamp docs for the 5.0 release by @joelostblom in #2566
- Pin selenium to avoid doctest breakage from deprecation by @joelostblom in #2624
- Remove broken Wikipedia donations chart by @palewire in #2625
- Tidy Falkensee case study by @palewire in #2626
- Tidy up U.S. Population by Age and Sex case study by @palewire in #2628
- Move bar chart with highlighted segment chart into the bar charts section by @palewire in #2630
- No need to say "Example" in the example headline by @palewire in #2631
- Isotype charts aren't case studies and should go in the other category by @palewire in #2632
- Top k charts aren't case studies and should go with other charts by @palewire in #2633
- Add pyramid pie chart to case studies by @palewire in #2635
- Move image tooltip example to interactive charts section by @palewire in #2636
- Move window rank technique to line charts section by @palewire in #2637
- Style fix to chart headline by @palewire in #2639
- Move scatter with histogram into scatter plots section by @palewire in #2641
- Clean up airport maps by @palewire in #2634
- Example of a line chart with a label annotating the final value by @palewire in #2623
- Update ranged_dot_plot.py by @palewire in #2642
- Tidy natural_disasters.py example by @palewire in #2643
- Create a new tables section by @palewire in #2646
- Tidy multiple_ma...