attaviz logo attaviz logo attaviz
  • Quick start
  • Gallery
  • Reference
    • Theme
    • Chart factories
    • Maps
    • Color palettes
    • Formatting & helpers

On this page

  • Theme examples
    • Bar chart
    • Line chart
    • Line chart with hover
    • Scatter plot
    • Area chart
    • Heatmap
  • Opinionated factories
    • Opinionated bar with highlight and publication frame
    • Opinionated line with annotation and reference
    • Opinionated scatter with highlight and reference range
  • More theme and utility examples
    • Histogram
    • Diverging color scale
    • Faceted small multiples
    • Title, subtitle, and caption
    • Formatted axis labels
  • More chart types
    • Small multiples
    • Dumbbell chart
    • Stacked area
    • Grouped bar
    • Line chart with uncertainty band
    • Bubble scatterplot
    • Slope chart
  • Maps
    • Choropleth map
    • Continuous choropleth with missing data and annotation
    • Quantile change choropleth
    • Point map
  • Formatting utility
    • Auto-scaled with vega_scale_labelExpr
  • Edit this page
  • Report an issue

Gallery

A visual showcase of common chart types with the WBG theme enabled.

Theme examples

These examples use Altair directly. Attaviz supplies the visual defaults while Altair supplies the chart specification.

Bar chart

  • Output
  • Code
Show code
source = data.barley()

alt.Chart(
    source,
    title=alt.Title(
        "Barley Yield by Site",
        subtitle="Mean yield across varieties and years (bushels/acre)",
    ),
).mark_bar().encode(
    x=alt.X("mean(yield):Q", title="Mean Yield"),
    y=alt.Y("site:N", title="Site", sort="-x"),
    color=alt.value(attaviz.CATEGORICAL[0]),
).properties(width="container", height=300)

Line chart

  • Output
  • Code
Show code
source = data.stocks()

alt.Chart(
    source,
    title=alt.Title(
        "Stock Prices 2000–2010", subtitle="Monthly closing price by company"
    ),
).mark_line().encode(
    x=alt.X("date:T", title=None),
    y=alt.Y("price:Q", title="Price (USD)"),
    color=alt.Color("symbol:N", title="Symbol"),
).properties(width="container", height=350)

Line chart with hover

  • Output
  • Code
Show code
source = data.stocks()

lines = (
    alt.Chart(
        source,
        title=alt.Title(
            "Stock Prices 2000–2010", subtitle="Hover to compare companies at a date"
        ),
    )
    .mark_line()
    .encode(
        x=alt.X("date:T", title=None),
        y=alt.Y("price:Q", title="Price (USD)"),
        color=alt.Color("symbol:N", title="Symbol"),
    )
    .properties(width="container", height=350)
)

attaviz.add_hover(lines, x="date", format="$.2f")

Scatter plot

  • Output
  • Code
Show code
source = data.cars()

alt.Chart(
    source,
    title=alt.Title(
        "Horsepower vs. Fuel Efficiency",
        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)

Area chart

  • Output
  • Code
Show code
source = data.iowa_electricity()

alt.Chart(
    source,
    title=alt.Title(
        "Iowa Electricity Generation", subtitle="Net generation by source (GWh)"
    ),
).mark_area().encode(
    x=alt.X("year:T", title=None),
    y=alt.Y("net_generation:Q", title="Net Generation (GWh)"),
    color=alt.Color("source:N", title="Source"),
).properties(width="container", height=350)

Heatmap

  • Output
  • Code
Show code
source = data.seattle_weather()

alt.Chart(
    source,
    title=alt.Title(
        "Seattle Monthly Max Temperatures",
        subtitle="Average daily maximum temperature (°F) 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="Avg Max Temp (°F)"),
).properties(width="container", height=250)

Opinionated factories

These examples use Attaviz factories and composition helpers to handle common editorial decisions.

Opinionated bar with highlight and publication frame

  • Output
  • Code
Show code
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",
)

Opinionated line with annotation and reference

  • Output
  • Code
Show code
source = data.stocks().query("symbol in ['AAPL', 'MSFT', 'GOOG']")

chart = attaviz.line(
    source,
    x="date",
    y="price",
    series="symbol",
    title="Technology stocks followed different paths",
    subtitle="Monthly closing price, 2000–2010",
    highlight="AAPL",
    width="responsive",
)

chart = attaviz.add_reference_line(
    chart,
    value=500,
    axis="y",
    label="500",
)

attaviz.add_annotation(
    chart,
    x=pd.Timestamp("2007-12-01"),
    y=198.08,
    text="Apple approached 200",
    position="above",
)

Opinionated scatter with highlight and reference range

  • Output
  • Code
Show code
source = data.cars().dropna(subset=["Horsepower", "Miles_per_Gallon", "Name"])

chart = attaviz.scatter(
    source,
    x="Horsepower",
    y="Miles_per_Gallon",
    label="Name",
    series="Origin",
    highlight="honda civic",
    title="More powerful cars tend to use more fuel",
    subtitle="Horsepower and fuel economy",
)

attaviz.add_reference_range(
    chart,
    start=25,
    end=35,
    axis="y",
    label="25–35 mpg",
)

More theme and utility examples

Histogram

  • Output
  • Code
Show code
source = data.movies()

alt.Chart(
    source,
    title=alt.Title(
        "Distribution of IMDB Ratings",
        subtitle="Histogram of movie ratings from the IMDB database",
    ),
).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)

Diverging color scale

  • Output
  • Code
Show code
source = data.us_employment()

alt.Chart(
    source,
    title=alt.Title(
        "US Nonfarm Employment Change",
        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)

Faceted small multiples

  • Output
  • Code
Show code
source = data.iris()

alt.Chart(
    source,
).mark_circle(size=60).encode(
    x=alt.X("sepalLength:Q", title="Sepal Length"),
    y=alt.Y("petalLength:Q", title="Petal Length"),
    color=alt.Color("species:N", title="Species"),
).properties(
    width=200,
    height=200,
).facet(
    column=alt.Column("species:N", title=None),
).properties(
    title=alt.Title(
        "Iris Measurements by Species", subtitle="Sepal vs. petal dimensions"
    )
)

Title, subtitle, and caption

  • Output
  • Code
Show code
source = data.barley()

chart = (
    alt.Chart(
        source,
        title=alt.Title(
            "Barley Yield by Site",
            subtitle="Mean yield across varieties and years (bushels/acre)",
        ),
    )
    .mark_bar()
    .encode(
        x=alt.X("mean(yield):Q", title="Mean Yield"),
        y=alt.Y("site:N", sort="-x", title=None),
        color=alt.value(attaviz.CATEGORICAL[0]),
    )
    .properties(width="container", height=300)
)

attaviz.add_caption(chart, "Source: Minnesota agricultural experiment stations, 1931–1932")

Formatted axis labels

  • Output
  • Code
Show code
source = data.gapminder().query("year == 2005").nlargest(5, "pop")

alt.Chart(
    source,
    title=alt.Title(
        "Most Populous Countries",
        subtitle="Axis formatted via 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)

More chart types

Small multiples

  • Output
  • Code
Show code
countries = ["Afghanistan", "China", "India", "Indonesia", "Nigeria", "United States"]
source = data.gapminder()
source = source[source["country"].isin(countries)]

base = alt.Chart().encode(
    x=alt.X("year:Q", title=None, axis=alt.Axis(format="d", tickCount=3)),
    y=alt.Y("life_expect:Q", title=None, scale=alt.Scale(zero=False)),
    color=alt.value(attaviz.CATEGORICAL[0]),
)
latest = base.transform_filter(alt.datum.year == 2005)

alt.layer(
    base.mark_line(),
    latest.mark_point(filled=True, size=40),
    latest.mark_text(align="left", dx=6).encode(text=alt.Text("life_expect:Q", format=".0f")),
    data=source,
).properties(width=170, height=110).facet(
    facet=alt.Facet("country:N", title=None, sort=countries),
    columns=3,
).properties(
    title=alt.Title(
        "Life expectancy rose across countries",
        subtitle="Life expectancy at birth, 1955–2005",
    )
)

Dumbbell chart

  • Output
  • Code
Show code
countries = ["Afghanistan", "China", "India", "Indonesia", "Nigeria", "United States"]
points = data.gapminder()
points = points[
    points["country"].isin(countries) & points["year"].isin([1955, 2005])
]
source = points.pivot(index="country", columns="year", values="life_expect").reset_index()
source = source.rename(columns={1955: "start", 2005: "end"})
order = source.assign(change=source["end"] - source["start"]).sort_values(
    "change", ascending=False
)["country"].tolist()

y = alt.Y("country:N", sort=order, title=None)
connector = alt.Chart(source).mark_rule(color=attaviz.REFERENCE, strokeWidth=2).encode(
    x="start:Q", x2="end:Q", y=y
)
dots = alt.Chart(points).mark_circle(size=90, opacity=1).encode(
    x=alt.X("life_expect:Q", title="Life expectancy at birth (years)"),
    y=y,
    color=alt.Color(
        "year:N",
        scale=alt.Scale(range=[attaviz.GREY_300, attaviz.CATEGORICAL[0]]),
        legend=alt.Legend(title=None, labelExpr="upper(datum.label)"),
    ),
    tooltip=["country:N", "year:N", alt.Tooltip("life_expect:Q", format=".1f")],
)

(connector + dots).properties(
    width="container",
    height=260,
    title=alt.Title(
        "Life expectancy increased across countries",
        subtitle="Years at birth, 1955 and 2005, sorted by change",
    ),
)

Stacked area

  • Output
  • Code
Show code
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.add_caption(chart, "Source: World Development Indicators")

Grouped bar

  • Output
  • Code
Show code
source = pd.read_csv("data/wdi-electricity-access-2022.csv")

alt.Chart(source).mark_bar().encode(
    x=alt.X("access:Q", title=None, axis=alt.Axis(format="%"), scale=alt.Scale(domain=[0, 1])),
    y=alt.Y("country:N", title=None),
    yOffset=alt.YOffset("area:N", sort=["Urban", "Rural"]),
    color=alt.Color(
        "area:N",
        scale=alt.Scale(
            domain=["Urban", "Rural"],
            range=[attaviz.URBANIZATION["urban"], attaviz.URBANIZATION["rural"]],
        ),
        legend=alt.Legend(title=None, labelExpr="upper(datum.label)"),
    ),
    tooltip=["country:N", "area:N", alt.Tooltip("access:Q", format=".0%")],
).properties(
    width="container",
    height=alt.Step(12),
    title=alt.Title(
        "Rural electricity access still trails in some countries",
        subtitle="Share of population with access to electricity, 2022",
    ),
)

Line chart with uncertainty band

  • Output
  • Code
Show code
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.add_caption(chart, "Source: World Bank Human Capital Index database")

Bubble scatterplot

  • Output
  • Code
Show code
source = pd.read_csv("data/wdi-southeast-asia-2023.csv")

alt.Chart(source).mark_circle(opacity=0.75, stroke="white", strokeWidth=1).encode(
    x=alt.X("gdp_per_capita:Q", title="GDP per capita (USD)", axis=alt.Axis(format="~s")),
    y=alt.Y("life_expectancy:Q", title="Life expectancy (years)", scale=alt.Scale(zero=False)),
    size=alt.Size(
        "population:Q",
        title="Population",
        scale=alt.Scale(range=[80, 1_200]),
        legend=alt.Legend(orient="right", direction="vertical"),
    ),
    color=alt.Color(
        "income_group:N",
        legend=alt.Legend(title=None, labelExpr="upper(datum.label)"),
    ),
    tooltip=[
        "country:N",
        "income_group:N",
        alt.Tooltip("gdp_per_capita:Q", title="GDP per capita", format=",.0f"),
        alt.Tooltip("life_expectancy:Q", title="Life expectancy", format=".1f"),
        alt.Tooltip("population:Q", title="Population", format=",.0f"),
    ],
).properties(
    width="container",
    height=320,
    title=alt.Title(
        "Higher incomes are associated with longer lives",
        subtitle="Bubble size represents population, 2023",
    ),
)

Slope chart

  • Output
  • Code
Show code
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 == 2023).mark_text(align="left", dx=8).encode(
    text="country:N"
)

chart = (lines + points + labels).properties(
    width="container",
    height=300,
    title=alt.Title(
        "Electricity access expanded across Southeast Asia",
        subtitle="Share of population with access, 2010 and 2023",
    ),
)

attaviz.add_caption(chart, "Source: World Development Indicators")

Maps

Map factories handle geometry validation, projection, missing values, classification, legends, and tooltips.

Choropleth map

  • Output
  • Code
Show code
import geopandas as gpd

countries = 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

  • Output
  • Code
Show code
continuous_countries = countries.copy()
continuous_countries.loc[
    continuous_countries["country"] == "Brunei", "gdp_per_capita"
] = None

chart = attaviz.choropleth(
    continuous_countries,
    value="gdp_per_capita",
    label="country",
    value_label="GDP per capita (USD)",
    value_format=",.0f",
    title="Missing values remain visible",
    subtitle="Continuous scale with Brunei shown as no data",
    projection="mercator",
    width=700,
    height=450,
)

attaviz.add_map_annotation(
    chart,
    longitude=106.8,
    latitude=-6.2,
    text="Jakarta",
)

Quantile change choropleth

  • Output
  • Code
Show code
change_countries = countries.assign(
    relative_income_change=(
        countries["gdp_per_capita"] / countries["gdp_per_capita"].median() - 1
    )
)

attaviz.choropleth(
    change_countries,
    value="relative_income_change",
    label="country",
    value_label="Difference from regional median",
    meaning="change",
    classification="quantile",
    classes=3,
    value_format="percent",
    title="Income differs across the region",
    subtitle="Difference from the regional median, grouped into three quantiles",
    projection="mercator",
    width=700,
    height=450,
)

Point map

  • Output
  • Code
Show code
capitals = pd.DataFrame(
    {
        "city": ["Bangkok", "Hanoi", "Jakarta", "Kuala Lumpur", "Manila", "Phnom Penh"],
        "country": ["Thailand", "Viet Nam", "Indonesia", "Malaysia", "Philippines", "Cambodia"],
        "longitude": [100.5018, 105.8342, 106.8456, 101.6869, 120.9842, 104.9282],
        "latitude": [13.7563, 21.0278, -6.2088, 3.1390, 14.5995, 11.5564],
    }
)

base = alt.Chart(countries).mark_geoshape(
    fill=attaviz.NO_DATA,
    stroke="white",
    strokeWidth=0.5,
    tooltip=None,
)

points = alt.Chart(capitals).mark_circle(
    size=45,
    color=attaviz.CATEGORICAL[0],
).encode(
    longitude="longitude:Q",
    latitude="latitude:Q",
    tooltip=[
        alt.Tooltip("city:N", title="City"),
        alt.Tooltip("country:N", title="Country"),
    ],
)

(base + points).project(type="mercator").properties(
    width=600,
    height=360,
    title=alt.Title(
        "Selected Southeast Asian capitals",
        subtitle="Capital-city locations over local gallery boundaries",
    ),
)

Formatting utility

Auto-scaled with vega_scale_labelExpr

  • Output
  • Code
Show code
source = data.gapminder().query("year == 2005").nlargest(5, "pop")

alt.Chart(
    source,
    title=alt.Title(
        "Most Populous Countries",
        subtitle="Raw values, 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)
  • Edit this page
  • Report an issue