import altair as alt
import pandas as pd
import attaviz
attaviz.enable()
data = pd.DataFrame({
"country": ["Indonesia", "Malaysia", "Philippines"],
"population": [280_000_000, 35_000_000, 117_000_000],
"income": [4900, 11800, 3800],
"life_expectancy": [71, 77, 70],
"region": ["Southeast Asia"] * 3,
"gdp": [1.4e12, 4e11, 4.4e11],
})
employment = pd.DataFrame({
"year": [2022, 2022, 2023, 2023],
"sector": ["Services", "Other", "Services", "Other"],
"share": [0.55, 0.45, 0.58, 0.42],
})
trend = pd.DataFrame({
"date": pd.to_datetime(["2023-01-01", "2023-04-01", "2023-07-01", "2023-10-01"]),
"value": [40, 48, 44, 60],
})Chart templates
Attaviz chart templates turn your data into publication-ready Altair charts. Enable the theme once before creating charts:
import attaviz
attaviz.enable()Templates copy their input and return ordinary Altair chart objects. Customize the returned chart with Altair when you need behavior outside these interfaces.
Working example data
The examples below use these illustrative observations:
Bar
attaviz.bar(
data,
*,
category,
value,
series=None,
title=None,
subtitle=None,
sort="descending",
labels=True,
highlight=None,
value_format="auto",
currency=None,
width="responsive",
height=None,
)bar() creates horizontal bars and you need to provide a non-empty pandas DataFrame as data, with category and numeric value columns specified. Each category must occur exactly once unless series is provided.
sortaccepts"ascending","descending","data", or a list of categories in the order you want.labelscontrols end labels.seriesis a column that splits each bar into stacked segments, one colored segment per value, with a legend. Each(category, series)pair must occur exactly once, and stacked values must be non-negative. Segment labels smaller than 8% of their category total are hidden so that they do not overflow narrow segments.highlightaccepts one category or a list of categories.heightdefaults to a value based on the category count.- Missing category or value rows are omitted with
UserWarning. - Duplicate keys, negative stacked values, zero stacked totals, unknown highlights, or invalid fields raise an error.
chart = attaviz.bar(
data,
category="country",
value="population",
title="Population by country",
highlight="Indonesia",
)
chartFor stacked bars, provide one row per category and segment. This example uses columns year, sector, and share:
chart = attaviz.bar(
employment,
category="year",
value="share",
series="sector",
sort="data",
title="Employment by sector in Indonesia",
value_format="percent",
)
chartLine
attaviz.line(
data,
*,
x,
y,
series=None,
title=None,
subtitle=None,
highlight=None,
end_labels=True,
points=False,
zero=False,
value_format="auto",
currency=None,
date_format="auto",
width="responsive",
height=None,
)x must be numeric or temporal and y must be numeric. Without series, each x value must be unique. With series, every (x, series) pair must be unique. Duplicate keys raise ValueError rather than being aggregated.
- Missing
yvalues create gaps. zero=Trueincludes zero in the y domain.highlightrequiresseriesand accepts one series or a list of series.- Up to five series use end labels by default, while larger charts use a legend.
end_labels=Falsealways uses a legend.points=Trueadds point marks.date_formataccepts"auto","day","month","month_year","year", or a D3 time-format string. For quarter and fiscal-year labels, use a custom Altair chart with preformatted ordinal strings;line()requires numeric or temporal x values. See date formatting.
chart = attaviz.line(
trend,
x="date",
y="value",
date_format=attaviz.d3_date_format("month_year"),
)
chartScatter
attaviz.scatter(
data,
*,
x,
y,
label=None,
series=None,
title=None,
subtitle=None,
highlight=None,
x_zero=False,
y_zero=False,
x_format="auto",
x_currency=None,
y_format="auto",
y_currency=None,
width="responsive",
height=None,
)x and y must name numeric columns. Each row is one observation and it may have duplicate coordinates.
labelidentifies observations in tooltips.seriesgroups observations by color.highlightrequireslabeland the selected observations render above muted points and receive direct labels.x_zeroandy_zeroindependently include zero in each axis domain.- Missing x or y rows are omitted with
UserWarning.
chart = attaviz.scatter(
data,
x="income",
y="life_expectancy",
label="country",
series="region",
highlight=["Indonesia", "Malaysia"],
)
chartNumber formats
Number-format arguments accept "auto", "integer", "decimal", "percent", "currency", or a D3 number-format string. For "currency", also pass currency with a currency code such as "USD". The currency code appears before each value, for example “USD 1.4T”. Passing currency with any other format raises an error.
attaviz.bar(
data,
category="country",
value="gdp",
value_format="currency",
currency="USD",
)See formatting examples for D3 strings in template arguments, axes, and tooltips. Percent formats expect fractions (0.456 becomes 45.6%).
Chart size
The default width="responsive" makes the chart fill the width of the page or notebook cell that contains it. For static exports such as PNG or SVG, pass a positive width and height in pixels so that the size is always the same.
Annotations and references
attaviz.add_annotation(
chart,
*,
x,
y,
text,
position="above",
offset=8,
marker=True,
)
attaviz.add_reference_line(chart, *, value, axis="y", label=None)
attaviz.add_reference_range(
chart,
*,
start,
end,
axis="y",
label=None,
)Annotations use data coordinates. position accepts "above", "below", "left", or "right"; offset is a non-negative pixel distance. Reference helpers require axis="x" or axis="y". Values outside the observed domain produce UserWarning, and a range with start > end raises ValueError.
The helpers compose with all three template outputs. A custom layered chart must have one unambiguous pair of in-memory x and y field encodings.
Add a band, a line, and an annotation
Add each helper to the returned chart, then apply the frame last. Temporal coordinates use pandas timestamps; numeric coordinates use numbers in the original data units.
chart = attaviz.line(trend, x="date", y="value", width=600, height=300)
chart = attaviz.add_reference_range(chart, start=45, end=55, axis="y")
chart = attaviz.add_reference_line(chart, value=50, axis="y", label="Target: 50")
chart = attaviz.add_annotation(
chart,
x=pd.Timestamp("2023-07-01"),
y=44,
text="Midyear dip",
position="below",
)
chartHover for custom Altair lines
Templates add their own hover behavior. Use add_hover() for a custom line chart:
attaviz.add_hover(
chart,
x,
*,
format=",.2f",
x_format=None,
rule_color=attaviz.GREY_400,
)The helper supports either one long-form chart with a color field or a layered wide-form chart with one y field per layer. It requires in-memory pandas data. format and x_format are D3 format strings. Unsupported chart shapes raise ValueError rather than producing an inaccurate tooltip.
observations = trend.assign(series="Observed")
lines = alt.Chart(observations).mark_line().encode(
x=alt.X("date:T", axis=alt.Axis(format=attaviz.d3_date_format("month_year"))),
y="value:Q",
color="series:N",
).properties(width=600, height=300)
attaviz.add_hover(
lines,
x="date",
format=attaviz.d3_number_format(decimals=0),
x_format=attaviz.d3_date_format("day", short=False),
)Publication frame
attaviz.frame(
chart,
*,
description,
source=None,
source_url=None,
note=None,
byline=None,
)Apply frame() last. The required non-empty description becomes Vega-Lite accessibility metadata and is not displayed as chart text. note, source, and byline render below the chart in that order. source_url requires source and is retained in usermeta for host integrations because native Vega-Lite titles do not support hyperlinks.
frame() changes a responsive chart to a fixed 600 px width. Vega-Lite cannot size a chart to its container when text is stacked below the chart. To use another width, pass width when you create the chart.