A visual showcase of charts, maps, and tables styled with Attaviz.
Theme examples
These examples use Altair directly. Attaviz supplies the visual defaults while Altair supplies the chart specification. Native alt.Title(...) sets headings on these custom charts. For templates, pass title and subtitle directly; frame() adds publication footers and accessibility metadata to either kind of chart.
source = data.cars()alt.Chart( source, title=alt.Title("Cars with more horsepower travel fewer miles per gallon", subtitle="Relationship between engine power and mileage by origin", ),).mark_circle(size=80).encode( x=alt.X("Horsepower:Q"), y=alt.Y("Miles_per_Gallon:Q", title="Miles per gallon"), color=alt.Color("Origin:N", title="Origin"), tooltip=["Name:N","Horsepower:Q", alt.Tooltip("Miles_per_Gallon:Q", title="Miles per gallon"), ],).properties(width="container", height=380)
source = data.seattle_weather()alt.Chart( source, title=alt.Title("Seattle is warmest in July and August", subtitle="Average daily maximum temperature (°C) by month", ),).mark_rect().encode( x=alt.X("month(date):O", title="Month"), y=alt.Y("year(date):O", title="Year", axis=alt.Axis(grid=False)), color=alt.Color("mean(temp_max):Q", title="Average maximum temperature (°C)"),).properties(width="container", height=250)
source = data.movies()alt.Chart( source, title=alt.Title("Most movies rate between 5 and 8 on IMDb", subtitle="Number of movies by IMDb rating", ),).mark_bar().encode( x=alt.X("IMDB_Rating:Q", bin=alt.Bin(maxbins=30), title="IMDb rating"), y=alt.Y("count()", title="Number of movies"), color=alt.value(attaviz.CATEGORICAL[0]),).properties(width="container", height=300)
source = data.us_employment()alt.Chart( source, title=alt.Title("The United States lost jobs in most months of 2008 and 2009", subtitle="Monthly change in nonfarm payrolls (thousands), 2006–2015", ),).mark_bar().encode( x=alt.X("month:T", title=None), y=alt.Y("nonfarm_change:Q", title="Change (thousands)"), color=alt.Color("nonfarm_change:Q", scale=alt.Scale(range=attaviz.DIV_DEFAULT, domainMid=0), title="Change", ), tooltip=[ alt.Tooltip("month:T", title="Month"), alt.Tooltip("nonfarm_change:Q", title="Change (thousands)"), ],).properties(width="container", height=300)
source = pd.read_csv("data/wdi-indonesia-employment.csv")chart = alt.Chart(source).mark_area().encode( x=alt.X("year:O", title=None), y=alt.Y("share:Q", stack="normalize", title="Share of employment", axis=alt.Axis(format="%")), color=alt.Color("sector:N", title=None, legend=alt.Legend(labelExpr="upper(datum.label)"), ), tooltip=["year:O","sector:N", alt.Tooltip("share:Q", title="Share", format=".1f"), ],).properties( width="container", height=280, title=alt.Title("Services account for half of Indonesia's employment", subtitle="Modeled share of employment by sector, 2000–2024", ),)attaviz.frame( chart, description="Stacked area chart of Indonesia's employment by sector from 2000 to 2024; the services share rises from 38% to 50% while agriculture falls from 45% to 28%.", source="World Development Indicators",)
source = pd.read_csv("data/hci-range.csv")base = alt.Chart(source).encode( x=alt.X("year:O", title=None, axis=alt.Axis(labelAngle=0)),)band = base.mark_area(color=attaviz.CATEGORICAL[0], opacity=0.2).encode( y=alt.Y("lower:Q", title="Human Capital Index", scale=alt.Scale(zero=False)), y2="upper:Q",)estimate = base.mark_line(color=attaviz.CATEGORICAL_TEXT[0], point=True).encode( y="estimate:Q", tooltip=["country:N", "year:O", alt.Tooltip("estimate:Q", format=".3f")],)chart = (band + estimate).properties( width=190, height=150,).facet( facet=alt.Facet("country:N", title=None), columns=3,).properties( title=alt.Title("Human capital changed unevenly across Southeast Asia", subtitle="Human Capital Index estimate and uncertainty range, selected years", ),)attaviz.frame( chart, description="Lines with uncertainty bands showing the Human Capital Index for five Southeast Asian countries between 2010 and 2020.", source="World Bank Human Capital Index database",)
source = pd.read_csv("data/wdi-electricity-access-2010-2023.csv")base = alt.Chart(source).encode( x=alt.X("year:O", title=None, axis=alt.Axis(labelAngle=0, ticks=False)), y=alt.Y("access:Q", title="Population with electricity access", axis=alt.Axis(format="%"), scale=alt.Scale(zero=False)), color=alt.Color("country:N", legend=None),)lines = base.mark_line(strokeWidth=2)points = base.mark_circle(size=70)labels = base.transform_filter(alt.datum.year ==2010).mark_text(align="right", dx=-8).encode( text="country:N")chart = (lines + points + labels).properties( width="container", height=300, title=alt.Title("Cambodia made the largest gain in electricity access", subtitle="Share of population with access, 2010 and 2023", ),)attaviz.frame( chart, description="Slope chart of electricity access in five Southeast Asian countries from 2010 to 2023; Cambodia rose from 31% to 95%.", source="World Development Indicators",)
Formatting and captions
These examples use Attaviz helpers for captions, publication frames, and number formats.
Title, subtitle, and source
Set the title and subtitle on the chart, then apply frame() last. It adds the note, source, and byline below the chart, and stores the required description as accessibility metadata.
source = data.barley().groupby("site", as_index=False)["yield"].mean()chart = attaviz.bar( source, category="site", value="yield", title="Waseca had the highest barley yield", subtitle="Mean yield across varieties and years (bushels/acre)", width=600, height=300,)attaviz.frame( chart, description="Horizontal bars comparing mean barley yield at six sites; Waseca is highest.", source="Minnesota agricultural experiment stations, 1931–1932", note="Yields are averaged across varieties and years.", byline="Attaviz",)
source = data.gapminder().query("year == 2005").nlargest(5, "pop")alt.Chart( source, title=alt.Title("China and India have the largest populations", subtitle="Population, 2005, axis formatted with d3_number_format", ),).mark_bar().encode( x=alt.X("pop:Q", title="Population", axis=alt.Axis(format=attaviz.d3_number_format(decimals=0)), ), y=alt.Y("country:N", sort="-x", title=None), color=alt.value(attaviz.CATEGORICAL[0]),).properties(width="container", height=250)
source = data.gapminder().query("year == 2005").nlargest(5, "pop")alt.Chart( source, title=alt.Title("China and India have the largest populations", subtitle="Population, 2005, axis auto-scaled to K/M/B per tick", ),).mark_bar().encode( x=alt.X("pop:Q", title="Population", axis=alt.Axis(labelExpr=attaviz.vega_scale_labelExpr()), ), y=alt.Y("country:N", sort="-x", title=None), color=alt.value(attaviz.CATEGORICAL[0]), tooltip=alt.Tooltip("pop:Q", format=attaviz.d3_number_format(decimals=0))).properties(width="container", height=250)
Chart templates
These examples use Attaviz chart templates and composition helpers to handle common editorial decisions.
source = pd.read_csv("data/wdi-southeast-asia-2023.csv")chart = attaviz.bar( source, category="country", value="gdp", title="Indonesia has Southeast Asia's largest economy", subtitle="Current-price GDP, 2023", highlight="Indonesia", value_format="currency", currency="USD",)attaviz.frame( chart, description="Horizontal bars comparing GDP in five Southeast Asian economies; Indonesia is highlighted.", source="World Development Indicators", source_url="https://databank.worldbank.org/source/world-development-indicators",)
import geopandas as gpdcountries = gpd.read_file("data/southeast-asia.geojson")chart = attaviz.choropleth( countries, value="gdp_per_capita", label="country", value_label="GDP per capita (USD)", meaning="higher_is_better", classification="custom", breaks=[3_000, 5_000, 10_000, 20_000], value_format=",.0f", highlight="Indonesia", tooltip=["population"], title="Income levels vary widely across Southeast Asia", subtitle="GDP per capita, 2019 estimates", projection="mercator", width=700, height=450,)attaviz.frame( chart, description="A choropleth of 2019 GDP per capita estimates across eleven Southeast Asian economies; Indonesia is highlighted.", source="Natural Earth", source_url="https://www.naturalearthdata.com/", note="GDP per capita is calculated from Natural Earth's population and GDP estimates. Boundaries follow Natural Earth's de facto representation.",)
Continuous choropleth with missing data and annotation
Install attaviz[tables] to use the table helper. It returns a native Great Tables object with Attaviz styling; use Great Tables methods for column labels and formatting.
Counts and percentages
Format counts with thousands separators and fractions as percentages. Missing values display as N/A.
Build on the table above using Great Tables’ native methods. Group the numeric columns under a shared heading and attach a definition to the completion column.
from great_tables import loc( participation_table .tab_spanner(label="Program results", columns=["participants", "completion"]) .tab_footnote("Completion is the share of participants who finished the program.", locations=loc.column_labels(columns="completion"), ))
1 Completion is the share of participants who finished the program.
Wide table with subtle row striping
Keep related numeric measures together and use a light alternating background to help readers track rows across the table. Full labels wrap when needed.