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
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
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
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
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
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
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
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
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
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
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
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
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
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" )
More chart types
Small multiples
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
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
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
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
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
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
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
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
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
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
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" ,
),
)