A Grammar of Graphics for Python providing a declarative approach to data visualization similar to R's ggplot2
—
Labels and annotations enhance plot clarity and communication by adding titles, axis labels, legends, and descriptive text. Plotnine provides comprehensive labeling functions for all plot elements, supporting custom formatting, positioning, and styling to create publication-ready and presentation-quality visualizations.
Core functions for setting plot titles, axis labels, and other text elements.
def labs(**kwargs):
"""
Set labels for plot elements comprehensively.
Universal labeling function that can set any plot label including
titles, axis labels, legend titles, and caption text.
Parameters:
- title: str, main plot title
- subtitle: str, plot subtitle (appears below title)
- caption: str, plot caption (appears at bottom)
- x: str, x-axis label
- y: str, y-axis label
- color/colour: str, color legend title
- fill: str, fill legend title
- size: str, size legend title
- shape: str, shape legend title
- alpha: str, alpha legend title
- linetype: str, linetype legend title
- **kwargs: any other aesthetic legend titles
Usage: Preferred method for setting multiple labels at once
"""
def ggtitle(title, subtitle=None):
"""
Set plot title and optional subtitle.
Parameters:
- title: str, main plot title
- subtitle: str, optional subtitle text
Equivalent to labs(title=title, subtitle=subtitle)
"""
def xlab(label):
"""
Set x-axis label.
Parameters:
- label: str, x-axis label text
Equivalent to labs(x=label)
"""
def ylab(label):
"""
Set y-axis label.
Parameters:
- label: str, y-axis label text
Equivalent to labs(y=label)
"""Functions for adding text, shapes, and other annotations directly to plots.
def annotate(geom, x=None, y=None, xmin=None, xmax=None, ymin=None, ymax=None,
xend=None, yend=None, **kwargs):
"""
Add annotations to plots using geometric objects.
Creates annotations without mapping to data variables, using fixed
coordinate positions and aesthetic values.
Parameters:
- geom: str, type of annotation ('point', 'text', 'segment', 'rect', etc.)
- x, y: float, position coordinates for point-like annotations
- xmin, xmax, ymin, ymax: float, rectangle bounds for 'rect' annotations
- xend, yend: float, end coordinates for 'segment' annotations
- **kwargs: aesthetic parameters (color, size, alpha, label, etc.)
Common geom types:
- 'text': text annotations
- 'point': point annotations
- 'segment': line segment annotations
- 'rect': rectangle annotations
- 'curve': curved line annotations
"""
def annotation_logticks(base=10, sides='bl', scaled=True, short=0.1, mid=0.2,
long=0.3, colour='black', size=0.5, linetype=1,
alpha=1, color=None, **kwargs):
"""
Add logarithmic tick marks to plots.
Adds small tick marks appropriate for logarithmic scales, with
different lengths for different orders of magnitude.
Parameters:
- base: float, logarithm base (usually 10)
- sides: str, which sides to add ticks ('t'=top, 'r'=right, 'b'=bottom, 'l'=left)
- scaled: bool, whether ticks should be scaled with plot
- short: float, length of short ticks (minor divisions)
- mid: float, length of medium ticks
- long: float, length of major ticks (powers of base)
- colour/color: str, tick color
- size: float, tick line width
- linetype: line type for ticks
- alpha: float, tick transparency
"""
def annotation_stripes(direction='horizontal', fill='grey90', colour='grey95',
alpha=1, color=None, **kwargs):
"""
Add background stripes to plots.
Creates alternating background stripes, useful for improving
readability of plots with many categories or time series.
Parameters:
- direction: str, stripe direction ('horizontal' or 'vertical')
- fill: str, stripe fill color
- colour/color: str, stripe border color
- alpha: float, stripe transparency
"""# Comprehensive labeling with labs()
ggplot(data, aes(x='income', y='happiness', color='country')) + \
geom_point() + \
labs(
title='Income vs Happiness by Country',
subtitle='Data from World Happiness Report 2020',
caption='Source: World Happiness Report',
x='GDP Per Capita (USD)',
y='Happiness Score (0-10)',
color='Country'
)
# Individual labeling functions
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
ggtitle('My Scatter Plot', 'With a subtitle') + \
xlab('X Variable (units)') + \
ylab('Y Variable (units)')# Custom legend titles for different aesthetics
ggplot(data, aes(x='x', y='y', color='group', size='value', shape='category')) + \
geom_point() + \
labs(
color='Treatment\nGroup', # Use \n for line breaks
size='Measurement\nValue',
shape='Sample\nType'
)
# Remove legend titles
ggplot(data, aes(x='x', y='y', color='group')) + \
geom_point() + \
labs(color=None) # or labs(color='')# Basic text annotation
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('text', x=5, y=10, label='Important Point',
color='red', size=12, fontweight='bold')
# Multiple text annotations
ggplot(data, aes(x='year', y='value')) + \
geom_line() + \
annotate('text', x=2010, y=50, label='Economic Crisis',
hjust=0, vjust=0) + \
annotate('text', x=2015, y=75, label='Recovery Period',
hjust=0, vjust=0, color='blue')
# Text with background box (using geom_label style)
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('label', x=5, y=10, label='Highlighted',
fill='yellow', color='black', alpha=0.8)# Point annotations
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('point', x=5, y=10, color='red', size=5, shape='diamond')
# Line segment annotations
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('segment', x=2, y=5, xend=8, yend=15,
color='red', size=1.2, linetype='dashed')
# Rectangle annotations (highlighting regions)
ggplot(data, aes(x='date', y='value')) + \
geom_line() + \
annotate('rect', xmin=as.Date('2020-01-01'), xmax=as.Date('2020-06-01'),
ymin=-Inf, ymax=Inf, alpha=0.2, fill='red') + \
annotate('text', x=as.Date('2020-03-15'), y=50,
label='Lockdown Period', hjust=0.5)# Mathematical expressions in labels
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
labs(
title='Population Growth Model',
x='Time (years)',
y='Population Size (N)',
subtitle=expression(N(t) == N[0] * e^{rt})
)
# Subscripts and superscripts in annotations
ggplot(chemistry_data, aes(x='pH', y='concentration')) + \
geom_point() + \
labs(
x='pH',
y=expression(paste('Concentration (mol L'^{-1}, ')'))
) + \
annotate('text', x=7, y=0.5,
label=expression(K[a] == 1.8 %*% 10^{-5}))# Multi-line labels using \n
ggplot(data, aes(x='treatment', y='response')) + \
geom_boxplot() + \
labs(
title='Treatment Response Analysis',
subtitle='Comparison across\nmultiple treatment groups',
x='Treatment\nCondition',
y='Response\nMeasurement'
)
# Rich text formatting (when supported)
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('text', x=5, y=10,
label='*Important* **finding**',
hjust=0, parse=True)# Annotations based on data
max_point = data.loc[data['y'].idxmax()]
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('point', x=max_point['x'], y=max_point['y'],
color='red', size=4) + \
annotate('text', x=max_point['x'], y=max_point['y'],
label=f'Max: {max_point["y"]:.1f}',
hjust=-0.1, vjust=0.5, color='red')
# Multiple annotations in a loop
for i, row in important_points.iterrows():
plot += annotate('text', x=row['x'], y=row['y'],
label=row['label'], color='blue')# Add log ticks to log-scaled plot
ggplot(data, aes(x='dose', y='response')) + \
geom_point() + \
scale_x_log10() + \
scale_y_log10() + \
annotation_logticks(sides='bl') + \
labs(
x='Dose (log scale)',
y='Response (log scale)'
)# Horizontal stripes for categorical data
ggplot(data, aes(x='value', y='category')) + \
annotation_stripes(direction='horizontal') + \
geom_point(size=3) + \
theme_minimal()
# Vertical stripes for time series
ggplot(time_data, aes(x='date', y='value')) + \
annotation_stripes(direction='vertical', alpha=0.1) + \
geom_line(size=1) + \
theme_minimal()# Curved annotations (arrows)
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('curve', x=2, y=3, xend=5, yend=8,
curvature=0.3, arrow=arrow(type='closed', length=unit(0.1, 'inches')),
color='red', size=1) + \
annotate('text', x=2, y=2.5, label='Trend direction', color='red')
# Combine multiple annotation types
ggplot(data, aes(x='year', y='gdp')) + \
geom_line(size=1) + \
# Highlight recession period
annotate('rect', xmin=2008, xmax=2009, ymin=-Inf, ymax=Inf,
alpha=0.2, fill='red') + \
# Add recession label
annotate('text', x=2008.5, y=max(data['gdp']) * 0.9,
label='Financial Crisis', hjust=0.5, color='red', fontweight='bold') + \
# Mark specific data point
annotate('point', x=2008, y=data.query('year == 2008')['gdp'].iloc[0],
color='red', size=4) + \
labs(
title='GDP Over Time',
subtitle='Highlighting the 2008 Financial Crisis',
x='Year',
y='GDP (Trillions USD)'
)# Control text alignment with hjust and vjust
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
# Left-aligned text
annotate('text', x=5, y=10, label='Left', hjust=0, vjust=0.5) + \
# Center-aligned text
annotate('text', x=5, y=8, label='Center', hjust=0.5, vjust=0.5) + \
# Right-aligned text
annotate('text', x=5, y=6, label='Right', hjust=1, vjust=0.5)
# Rotate text annotations
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
annotate('text', x=5, y=10, label='Rotated Text',
angle=45, hjust=0.5, vjust=0.5)# Ensure labels work well with theme
ggplot(data, aes(x='x', y='y', color='group')) + \
geom_point() + \
labs(
title='My Analysis',
subtitle='Important findings',
x='Predictor Variable',
y='Response Variable',
color='Group',
caption='Data source: My dataset'
) + \
theme_minimal() + \
theme(
plot_title=element_text(size=16, hjust=0.5),
plot_subtitle=element_text(size=12, hjust=0.5, color='gray50'),
plot_caption=element_text(size=8, hjust=1, color='gray50'),
axis_title=element_text(size=11),
legend_title=element_text(size=10)
)Install with Tessl CLI
npx tessl i tessl/pypi-plotnine