# Vega-Altair: A Declarative Python Charting Library Built on Vega-Lite

> Vega-Altair turns pandas DataFrames into charts by emitting Vega-Lite JSON rather than drawing pixels. It is a strong fit for Jupyter users who want typed, reproducible figures, and a poor fit for anyone who needs a full imperative plotting API.

**vega/altair** — Declarative visualization library for Python

- Repository: https://github.com/vega/altair
- Website: https://altair-viz.github.io/
- Stars: 10,484 · Forks: 870
- Language: Python
- License: BSD-3-Clause
- Published: 2026-09-21 · Updated: 2026-09-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/vega-altair

## The problem Vega-Altair solves for Python users

Most Python plotting code mixes two jobs: deciding what the chart shows, and telling the renderer how to draw it. Vega-Altair separates them. You describe the mapping from columns to visual channels, and the library produces a Vega-Lite JSON specification that a renderer interprets. The README puts the goal plainly: "you can spend more time understanding your data and its meaning."

The audience is narrow but deep. It is people working in JupyterLab, Jupyter Notebook, Visual Studio Code, GitHub or nbviewer, where the native Vega-Lite renderer can display the output directly. It suits statistical work on pandas DataFrames more than bespoke illustration. If your chart is a scatter plot of two columns colored by a third, the code is three lines.

The declarative model has a cost. You are limited to what the Vega-Lite specification expresses. Anything outside that grammar means either composing existing marks or leaving the library.

## How the declarative grammar and Vega-Lite JSON pipeline work

A chart object is a description, not a drawing. `alt.Chart(cars)` binds a data source, `.mark_point()` picks the mark type, and `.encode()` maps fields to channels such as x, y and color. The result serializes to JSON, and the renderer does the rest.

The dependency list in pyproject.toml shows the machinery: `jinja2` for templating, `jsonschema>=3.0` for validating specifications, `packaging`, and `narwhals>=2.4.0` for DataFrame interchange. The README states that the internal Python API is auto-generated, which is why the API tracks the Vega-Lite specification closely and why the package is typed.

Interaction is part of the same grammar rather than a separate callback layer. The README's second example creates `alt.selection_interval()`, attaches it with `.add_params(brush)`, recolors points through `alt.when(brush).then(...).otherwise(...)`, and filters a second chart with `.transform_filter(brush)`. The two charts are combined with `points & bars`. No Python runs when the user drags the brush; the selection lives in the JSON spec.

## Installing Vega-Altair and building a first linked chart

Install from PyPI. The README gives this as the primary path, and the package requires Python 3.11 or newer according to pyproject.toml.

```bash
pip install altair
```

The conda equivalent is documented as well, using the conda-forge channel.

```bash
conda install altair -c conda-forge
```

With the package installed, the README's first example loads a bundled dataset through `altair.datasets` and encodes three channels. In a JupyterLab cell with the native Vega-Lite renderer, this returns an interactive scatter plot.

```python
import altair as alt

# load a simple dataset as a pandas DataFrame
from altair.datasets import data

cars = data.cars()

alt.Chart(cars).mark_point().encode(
    x="Horsepower",
    y="Miles_per_Gallon",
    color="Origin",
)
```

To add cross-filtering, the README defines a brush selection, applies it as a parameter on the points chart, and filters the bars chart with the same selection. The `&` operator places the two views side by side.

```python
import altair as alt
from altair.datasets import data

source = data.cars()

brush = alt.selection_interval()

points = 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
)

bars = alt.Chart(source).mark_bar().encode(
    x="count(Origin)",
    y="Origin",
    color="Origin",
).transform_filter(
    brush
)

points & bars
```

Dragging a rectangle over the scatter plot should gray out the unselected points and narrow the histogram to the matching rows. If nothing renders, the problem is usually the display front end, not the chart code, because the object itself is only a specification.

## Where Vega-Altair stops being the right tool

The grammar is the boundary. Marks that Vega-Lite does not define cannot be expressed, and the README does not document an escape hatch for arbitrary drawing. Work that depends on per-pixel control, custom raster compositing or a large library of imperative drawing primitives belongs in a different tool.

Export is a second constraint. The README lists PNG and SVG export as a feature, but pyproject.toml places `vl-convert-python>=1.9.0` in the optional `save` extra, not in the base dependencies. A bare `pip install altair` therefore does not give you the image export path. The README does not spell out which functions require that extra, so check the installation page before promising PNG output in a pipeline.

Large data is a third. The `all` extra pulls in `vegafusion>=2.0.3`, `pyarrow>=11` and `anywidget>=0.9.0`, which suggests that heavier data handling and certain interactive output modes are opt-in rather than default. The README does not state thresholds at which the default renderer becomes inadequate.

## Vega-Altair compared with an imperative plotting library

The clearest contrast is with an imperative library in the matplotlib style, where you create a figure, add axes, and call drawing methods that mutate a canvas. In that model the Python process owns the rendering, and the output is typically a static image.

Vega-Altair works the other way. Your Python code builds a JSON document, and a JavaScript renderer in the display environment draws it. That difference explains both the strengths and the limits. Selection and linked views come almost free, because the specification describes them. On the other hand, a static image file is not the natural output; it is a conversion step that depends on an optional package.

If your deliverable is a PNG attached to an email, the imperative model is simpler. If your deliverable is a notebook a colleague will open and explore, Vega-Altair's approach removes a lot of code.

## Maintenance, licensing and the cost of tracking Vega-Lite

The repository is not archived, and the last push was on 2026-09-18. Releases are frequent: 6.3.0 on 2026-09-15, 6.2.2 on 2026-06-23 and 6.2.1 on 2026-06-05. That cadence is a real cost as well as a signal. Because the Python API is auto-generated from the Vega-Lite specification, a Vega-Lite change can surface as an API change in Altair, and the release notes are the place to look before upgrading a pinned environment.

The licence is BSD-3-Clause, declared in pyproject.toml with `license-files = ["LICENSE"]`. The README also states that the project is not affiliated with Altair Engineering, Inc., which matters if you are searching for the commercial vendor of the same name. None of this is legal advice; read the LICENSE file for the actual terms.

The README asks academic users to cite the JOSS paper at doi 10.21105/joss.01057 and, additionally, the Vega-Lite paper. Bundle size is not documented in the README, so treat client-side weight as something to measure yourself if you ship exported HTML.

## Conclusion

Adopt Vega-Altair if your charts live in notebooks and you want a typed, declarative API that serializes to Vega-Lite JSON. Do not adopt it if you need a full imperative drawing layer for custom marks that Vega-Lite does not define, or if you cannot run Python 3.11 or newer. Before committing, verify that your target renderer (JupyterLab, VS Code, GitHub, nbviewer) handles the output, and check whether PNG or SVG export matters to you, because that path needs the save extra with vl-convert-python. The project is not archived, its last push was on 2026-09-18, and the current line is 6.3.0.

## FAQ

### How do I install Vega-Altair?

The README gives `pip install altair` as the primary method, with `conda install altair -c conda-forge` as the conda equivalent. The package requires Python 3.11 or newer according to pyproject.toml.

### How do I use Vega-Altair to make a chart?

Create an `alt.Chart` from a dataset, choose a mark such as `.mark_point()`, and map columns to channels with `.encode()`. The README's example encodes Horsepower, Miles_per_Gallon and Origin from the bundled cars dataset.

### What is the relationship between Vega-Altair and Vega?

Vega-Altair is built on the Vega-Lite JSON specification, and its internal Python API is auto-generated to stay in conformance with it. The README also asks users to cite the Vega-Lite paper in addition to the Altair paper.

## Sources

- [License: BSD-3-Clause](https://github.com/vega/altair/blob/main/LICENSE)
- [Project website](https://altair-viz.github.io/)
- [README](https://github.com/vega/altair/blob/main/README.md)
- [Releases](https://github.com/vega/altair/releases)
- [vega/altair on GitHub](https://github.com/vega/altair)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vega-altair
