A Grammar of Graphics for Python providing a declarative approach to data visualization similar to R's ggplot2
—
Coordinate systems transform the positioning of geometric objects and control how data is mapped to the plot space. They enable specialized visualizations like flipped axes, fixed aspect ratios, polar coordinates, and transformed scales. Plotnine provides coordinate system functions that work seamlessly with all geometric objects and scales.
Fundamental coordinate transformations for standard and specialized plot layouts.
def coord_cartesian(xlim=None, ylim=None, expand=True):
"""
Standard Cartesian coordinate system (default).
Linear mapping between data coordinates and plot coordinates with
optional zoom functionality that doesn't affect statistical computations.
Parameters:
- xlim: tuple, x-axis limits for zooming (min, max)
- ylim: tuple, y-axis limits for zooming (min, max)
- expand: bool, whether to expand limits to include data
Note: This coordinate system preserves distances and angles.
"""
def coord_flip(xlim=None, ylim=None, expand=True):
"""
Flipped coordinate system (swap x and y axes).
Exchanges the x and y coordinates, effectively rotating the plot 90 degrees.
Useful for horizontal bar charts, box plots, and making long labels readable.
Parameters:
- xlim: tuple, limits for original x-axis (becomes y-axis after flip)
- ylim: tuple, limits for original y-axis (becomes x-axis after flip)
- expand: bool, whether to expand limits
Note: After flipping, 'x' aesthetics control vertical position and
'y' aesthetics control horizontal position.
"""
def coord_fixed(ratio=1, xlim=None, ylim=None, expand=True):
"""
Fixed aspect ratio coordinate system.
Maintains a fixed relationship between units on the x and y axes,
ensuring specific aspect ratios are preserved.
Parameters:
- ratio: float, aspect ratio (y/x). ratio=1 makes axes equal,
ratio=2 makes y-axis twice as long as x-axis
- xlim: tuple, x-axis limits
- ylim: tuple, y-axis limits
- expand: bool, whether to expand limits
Usage: Essential for maps, scatter plots where distances matter,
and any visualization where proportional relationships are important.
"""
def coord_equal(xlim=None, ylim=None, expand=True, ratio=1):
"""
Equal scale coordinate system (alias for coord_fixed with ratio=1).
Ensures that one unit on the x-axis is the same length as one unit
on the y-axis. Identical to coord_fixed(ratio=1).
Parameters:
- xlim: tuple, x-axis limits
- ylim: tuple, y-axis limits
- expand: bool, whether to expand limits
- ratio: float, aspect ratio (kept for compatibility, default=1)
"""
def coord_trans(x=None, y=None, xlim=None, ylim=None, expand=True):
"""
Transformed coordinate system.
Applies transformations to the coordinate axes, allowing for
non-linear mappings of data to plot space.
Parameters:
- x: str or transformer, transformation for x-axis
('identity', 'log10', 'sqrt', 'reverse', etc.)
- y: str or transformer, transformation for y-axis
- xlim: tuple, x-axis limits (in transformed space)
- ylim: tuple, y-axis limits (in transformed space)
- expand: bool, whether to expand limits
Common transformations:
- 'log10': logarithmic transformation
- 'sqrt': square root transformation
- 'reverse': reverse the axis direction
- 'identity': no transformation (default)
"""# Default coordinate system (usually not specified explicitly)
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
coord_cartesian()
# Zoom in on specific region without affecting statistics
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
geom_smooth(method='lm') + \
coord_cartesian(xlim=(2, 8), ylim=(0, 10))# Horizontal bar chart
ggplot(data, aes(x='category', y='value')) + \
geom_col() + \
coord_flip()
# Horizontal box plots
ggplot(data, aes(x='group', y='measurement')) + \
geom_boxplot() + \
coord_flip()
# Better label readability
ggplot(data, aes(x='long_category_names', y='count')) + \
geom_col() + \
coord_flip() + \
theme(axis_text_y=element_text(hjust=1))# Equal axes for scatter plots where distance matters
ggplot(data, aes(x='width', y='height')) + \
geom_point() + \
coord_equal()
# Geographic data (approximate equal projection)
ggplot(map_data, aes(x='longitude', y='latitude')) + \
geom_polygon(aes(group='group'), fill='lightblue', color='black') + \
coord_fixed(ratio=1.3) # Adjust for latitude distortion
# Custom aspect ratio
ggplot(data, aes(x='time', y='price')) + \
geom_line() + \
coord_fixed(ratio=0.5) # Make x-axis twice as long as y-axis# Log-scale coordinates
ggplot(data, aes(x='dose', y='response')) + \
geom_point() + \
geom_smooth() + \
coord_trans(x='log10', y='log10')
# Square root transformation for count data
ggplot(data, aes(x='x', y='count')) + \
geom_point() + \
coord_trans(y='sqrt')
# Reverse one axis
ggplot(data, aes(x='year', y='rank')) + \
geom_line() + \
coord_trans(y='reverse') # Lower ranks (1, 2, 3) at top# Flipped coordinates with free scales in facets
ggplot(data, aes(x='category', y='value')) + \
geom_col() + \
facet_wrap('group', scales='free_y') + \
coord_flip() + \
theme(axis_text_x=element_text(angle=0))
# Fixed aspect ratio with custom scales
ggplot(spatial_data, aes(x='x', y='y', color='elevation')) + \
geom_point() + \
scale_color_gradient(low='blue', high='red') + \
coord_equal() + \
theme_void()
# Transformed coordinates with statistical layers
ggplot(data, aes(x='income', y='health_outcome')) + \
geom_point(alpha=0.6) + \
geom_smooth(method='lm', se=True) + \
coord_trans(x='log10') + \
scale_x_continuous(breaks=[1000, 10000, 100000],
labels=['1K', '10K', '100K'])# Correlation matrix with equal axes
correlation_data = data.corr().reset_index().melt(id_vars='index')
ggplot(correlation_data, aes(x='index', y='variable', fill='value')) + \
geom_tile() + \
scale_fill_gradient2(low='blue', high='red', mid='white') + \
coord_equal() + \
theme(axis_text_x=element_text(angle=45))
# Time series with custom aspect ratio for trend visibility
ggplot(time_data, aes(x='date', y='value')) + \
geom_line() + \
coord_fixed(ratio=30) # Emphasize changes over time
# Rank plots with reversed y-axis
ggplot(ranking_data, aes(x='year', y='rank', color='country')) + \
geom_line(size=1) + \
geom_point(size=2) + \
coord_trans(y='reverse') + \
scale_y_continuous(breaks=range(1, 11))# World map with appropriate projection approximation
ggplot(world_data, aes(x='long', y='lat')) + \
geom_polygon(aes(group='group'), fill='lightgray', color='white') + \
coord_fixed(ratio=1.3) + \
theme_void()
# Regional map with equal coordinates
ggplot(region_data, aes(x='longitude', y='latitude')) + \
geom_point(aes(size='population', color='category')) + \
coord_equal() + \
theme_minimal()# Dose-response curves with log transformation
ggplot(dose_data, aes(x='dose', y='response', color='treatment')) + \
geom_point() + \
geom_smooth(method='lm', se=False) + \
coord_trans(x='log10') + \
scale_x_continuous(trans='log10',
breaks=[0.1, 1, 10, 100],
labels=['0.1', '1', '10', '100'])
# Growth curves with log y-axis
ggplot(growth_data, aes(x='time', y='size', color='condition')) + \
geom_line() + \
coord_trans(y='log10') + \
labs(y='Size (log scale)')# Combining zoom with transformations
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
coord_trans(x='sqrt', xlim=(1, 25), ylim=(0, 100))
# Multiple coordinate adjustments for complex layouts
ggplot(data, aes(x='category', y='value')) + \
geom_boxplot() + \
facet_wrap('treatment') + \
coord_flip() + \
theme(strip_text_x=element_text(angle=0))# Scale transformation (affects statistics)
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
geom_smooth(method='lm') + \
scale_x_log10() # Statistics computed on log-transformed data
# Coordinate transformation (affects display only)
ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
geom_smooth(method='lm') + \
coord_trans(x='log10') # Statistics computed on original data, display transformed# Fixed aspect ratios may require plot size adjustments
plot = ggplot(data, aes(x='x', y='y')) + \
geom_point() + \
coord_equal()
# Save with appropriate dimensions
plot.save('equal_aspect.png', width=8, height=8) # Square for equal aspect# Cartesian zoom (doesn't affect data range for statistics)
coord_cartesian(xlim=(0, 10))
# Scale limits (removes data outside range before statistics)
scale_x_continuous(limits=(0, 10))
# Coordinate transformation limits (applied after transformation)
coord_trans(x='log10', xlim=(0, 2)) # Limits on log10-transformed valuesInstall with Tessl CLI
npx tessl i tessl/pypi-plotnine