
Plotnine
- 1 installs
- 3.2k repo stars
- Updated August 4, 2026
- brycewang-stanford/awesome-agent-skills-for-empirical-research
plotnine is a skill that is a reference for creating static, publication-quality Python figures using the grammar of graphics (ggplot2 syntax).
About
This skill is a reference for creating static, publication-quality figures with plotnine, a Python implementation of the grammar of graphics using ggplot2 syntax. A developer uses it for geoms, aesthetics, scales, coordinates, facets, and themes when static output is needed or coming from an R ggplot2 background. It matters for producing print-ready charts for reports and papers.
- Static plotnine visualization using ggplot2 grammar-of-graphics syntax
- Covers geoms, aesthetics, scales, coordinates, facets, and themes
- Produces publication-quality static figures saved to PNG
Plotnine by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,803 of 2,064 Data Science & ML skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
plotnine capabilities & compatibility
- Capabilities
- data visualization · static charts
- Use cases
- data analysis
- Pricing
- Free
What plotnine says it does
plotnine static visualization library for Python, implementing the grammar of graphics (ggplot2 syntax).
Prefer over plotly when static output is needed.
npx skills add https://github.com/brycewang-stanford/awesome-agent-skills-for-empirical-research --skill plotnineAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 3.2k |
| Last updated | August 4, 2026 |
| Repository | brycewang-stanford/awesome-agent-skills-for-empirical-research ↗ |
What it does
Create static, publication-quality figures with plotnine using ggplot2-style grammar-of-graphics syntax.
Who is it for?
Static publication-quality figures with ggplot2-style syntax for print or reports.
Skip if: Interactive charts (use plotly) or maps (use geopandas).
When should I use this skill?
When creating static publication-quality figures with grammar-of-graphics syntax.
What you get
A static plotnine figure saved as an image for a report.
- A static plotnine figure saved as an image file
By the numbers
- 7 common geoms listed
- 6 reference files
Files
Plotnine Skill
plotnine static visualization library for Python, implementing the grammar of graphics (ggplot2 syntax). Covers geoms (point, line, bar, histogram, boxplot, smooth), aesthetics, scales, coordinates, facets, and themes. Use when creating static publication-quality figures with ggplot2-style syntax, producing charts for print or reports, or working with an R ggplot2 background. Prefer over plotly when static output is needed.
Quick reference for creating data visualizations with plotnine, a Python implementation of the grammar of graphics (ggplot2).
What is Plotnine?
plotnine is a data visualization library based on the grammar of graphics:
- Declarative: Describe what you want, not how to draw it
- Layered: Build plots by adding components with
+ - ggplot2 compatible: Nearly identical syntax to R's ggplot2
- Publication-ready: Themes and customization for polished output
How to Use This Skill
Reference File Structure
| File | Purpose | When to Read |
|---|---|---|
quickstart.md | Installation, imports, basic syntax | Starting out |
geoms.md | Geometric objects (points, lines, bars) | Choosing chart types |
aesthetics.md | Mapping data to visual properties | Customizing appearance |
scales-coords.md | Scales, coordinates, positions | Axis/color control |
facets-themes.md | Multi-panel plots and styling | Layout and themes |
gotchas.md | Common errors and best practices | Debugging |
Quick Decision Trees
"I need to create a plot"
What kind of plot?
├─ Scatter plot (geom_point) → ./references/geoms.md
├─ Line plot (geom_line) → ./references/geoms.md
├─ Bar chart (geom_bar, geom_col) → ./references/geoms.md
├─ Histogram (geom_histogram) → ./references/geoms.md
├─ Box plot (geom_boxplot) → ./references/geoms.md
└─ Other geoms → ./references/geoms.md"I need to customize appearance"
What to customize?
├─ Colors, sizes, shapes → ./references/aesthetics.md
├─ Axis limits/labels → ./references/scales-coords.md
├─ Color palettes → ./references/scales-coords.md
├─ Overall theme → ./references/facets-themes.md
├─ Title/labels → ./references/facets-themes.md
└─ Multiple panels (faceting) → ./references/facets-themes.md"Something isn't working"
Common issues?
├─ Plot not showing → ./references/quickstart.md
├─ Column not found → ./references/gotchas.md
├─ Color not applying → ./references/aesthetics.md
├─ Unexpected grouping → ./references/gotchas.md
└─ Syntax errors → ./references/gotchas.mdFile-First Execution in Research Workflows
Important: In data research pipelines (see CLAUDE.md), all visualizations are generated through script files in scripts/stage8_analysis/, not interactively. This ensures auditability and reproducibility.
The pattern: 1. Write plot code to scripts/stage8_analysis/{step}_{plot-name}.py 2. Execute via Bash with automatic output capture wrapper script 3. Validation results get automatically embedded in scripts as comments 4. If failed, create versioned copy for fixes
Closely read agent_reference/SCRIPT_EXECUTION_REFERENCE.md for the mandatory file-first execution protocol covering complete code file writing, output capture, and file versioning rules.
See:
agent_reference/WORKFLOW_PHASE4_ANALYSIS.md— Stage 8 (Analysis & Visualization)
The examples below show plotnine syntax. In research workflows, wrap them in scripts following the file-first pattern.
---
Quick Reference
Basic Plot Pattern
from plotnine import ggplot, aes, geom_point
(
ggplot(df, aes(x="col_x", y="col_y"))
+ geom_point()
)Essential Imports
from plotnine import * # All components
from plotnine.data import mtcars # Built-in datasetsCommon Geoms
| Geom | Use Case |
|---|---|
geom_point() | Scatter plots |
geom_line() | Line plots |
geom_bar() | Count bars |
geom_col() | Value bars |
geom_histogram() | Distributions |
geom_boxplot() | Box plots |
geom_smooth() | Trend lines |
Common Aesthetics
| Aesthetic | Controls |
|---|---|
x, y | Position |
color | Point/line color |
fill | Area fill color |
size | Point/line size |
shape | Point shape |
alpha | Transparency |
Saving Plots
p = ggplot(df, aes("x", "y")) + geom_point()
p.save("plot.png", width=10, height=8, dpi=300)Topic Index
| Topic | Reference File |
|---|---|
| Installation | ./references/quickstart.md |
| Basic syntax | ./references/quickstart.md |
| Chart types | ./references/geoms.md |
| Data mapping | ./references/aesthetics.md |
| Color/shape values | ./references/aesthetics.md |
| Axis scales | ./references/scales-coords.md |
| Color scales | ./references/scales-coords.md |
| Coordinates | ./references/scales-coords.md |
| Faceting | ./references/facets-themes.md |
| Themes | ./references/facets-themes.md |
| Labels/titles | ./references/facets-themes.md |
| Common errors | ./references/gotchas.md |
| Best practices | ./references/gotchas.md |
Citation
When this library is used as a primary analytical tool, include in the report's Software & Tools references:
Kibirige, H. et al. plotnine: Grammar of graphics for Python [Computer software]. https://plotnine.org/
Cite when: plotnine is the primary visualization library producing figures included in the report. Do not cite when: Only used for quick exploratory plots not included in deliverables.
Aesthetics
Aesthetics map data columns to visual properties using aes().
The aes() Function
aes(x="column_x", y="column_y", color="column_color")Placement
In ggplot() - applies to all layers:
ggplot(df, aes("x", "y", color="group")) + geom_point() + geom_line()*In geom_()** - applies to that layer only:
ggplot(df, aes("x", "y")) + geom_point(aes(color="group"))Variable vs. Literal Values
Variable Mapping (inside aes)
Maps a column to the aesthetic:
# Color varies by "species" column
aes(color="species")Literal Value (outside aes)
Sets a fixed value:
# All points are blue
geom_point(color="blue")Common Mistake
# WRONG: looks for column named "blue"
aes(color="blue")
# CORRECT: fixed color
geom_point(color="blue")
# CORRECT: map to column
aes(color="species")Core Aesthetics
| Aesthetic | Description | Applies to |
|---|---|---|
x | X position | All |
y | Y position | All |
color | Outline/point color | Points, lines |
fill | Fill color | Bars, areas, polygons |
size | Size | Points, lines |
shape | Point shape | Points |
alpha | Transparency | All |
linetype | Line pattern | Lines |
group | Grouping (no legend) | Lines, paths |
Color vs. Fill
- color: Outline of shapes, color of points and lines
- fill: Interior of shapes
# Points use color
geom_point(aes(color="group"))
# Bars use fill (and optionally color for outline)
geom_bar(aes(fill="group"))
# Both
geom_bar(aes(fill="group"), color="black")Grouping
Use group to connect or group data without creating a legend:
# Multiple lines without color distinction
ggplot(df, aes("x", "y", group="id")) + geom_line()Computed Aesthetics
after_stat()
Access computed statistics:
# Density scaled to max 1
geom_density(aes(y=after_stat("scaled")))
# Histogram with density instead of count
geom_histogram(aes(y=after_stat("density")))after_scale()
Access scaled values:
# Lighter fill color
geom_bar(aes(fill="group", alpha=after_scale("fill")))Aesthetic Specifications
Colors
Named colors, hex codes, or RGB:
color="red"
color="steelblue"
color="#FF5733"Shapes
Note: plotnine uses matplotlib marker codes, not ggplot2's 0-25 integer system. Common markers: 'o' (circle), 's' (square), '^' (triangle up), 'D' (diamond), 'v' (triangle down), '+' (plus), 'x' (cross). The ggplot2 integer codes below may work for some shapes but matplotlib string markers are preferred.
Integer codes (0-25) or names:
| Code | Name |
|---|---|
| 0 | square open |
| 1 | circle open |
| 2 | triangle open |
| 15 | square |
| 16 | circle |
| 17 | triangle |
| 19 | circle (default) |
| 21 | circle filled |
geom_point(shape=17) # triangles
geom_point(shape="triangle")Linetypes
Integer codes or names:
| Code | Name |
|---|---|
| 0 | blank |
| 1 | solid |
| 2 | dashed |
| 3 | dotted |
| 4 | dotdash |
| 5 | longdash |
| 6 | twodash |
geom_line(linetype="dashed")
geom_line(linetype=2)Sizes
Numeric values (in mm for most geoms):
geom_point(size=3)
geom_line(size=1.5)Alpha (Transparency)
Values from 0 (invisible) to 1 (opaque):
geom_point(alpha=0.5)factor() for Discrete Mapping
Convert continuous to discrete:
# Treat numeric as categorical
aes(color="factor(cyl)")reorder() for Ordering
Order categories by another variable:
# Order bars by count
aes(x="reorder(category, -count)", y="count")Multiple Aesthetics Example
(
ggplot(df, aes(
x="x",
y="y",
color="group",
size="value",
shape="type",
alpha="confidence"
))
+ geom_point()
)Facets & Themes
Faceting
Create multiple panels (small multiples) from data subsets.
facet_wrap()
Wrap panels into rows/columns:
# Single variable
facet_wrap("variable")
# Control layout
facet_wrap("variable", ncol=3)
facet_wrap("variable", nrow=2)
# Free scales
facet_wrap("variable", scales="free")
facet_wrap("variable", scales="free_x")
facet_wrap("variable", scales="free_y")facet_grid()
Grid layout with row and column variables:
# Rows by one variable, columns by another
facet_grid("row_var ~ col_var")
# Only rows
facet_grid("row_var ~ .")
# Only columns
facet_grid(". ~ col_var")
# Free scales
facet_grid("row ~ col", scales="free")Facet Labels
# Show variable name and value
facet_wrap("var", labeller=label_both)
# Custom labels
facet_wrap("var", labeller=labeller(var={"A": "Group A", "B": "Group B"}))Labeller Options
| Function | Result |
|---|---|
label_value | Value only (default) |
label_both | Variable: Value |
label_context | Smart context |
Labels & Titles
labs()
Set multiple labels:
labs(
title="Main Title",
subtitle="Subtitle",
caption="Data source: ...",
x="X Axis Label",
y="Y Axis Label",
color="Legend Title",
fill="Fill Legend"
)Individual Functions
ggtitle("Title")
xlab("X Label")
ylab("Y Label")Themes
Premade Themes
| Theme | Description |
|---|---|
theme_gray() | Default gray background |
theme_bw() | Black and white |
theme_minimal() | Minimal, no background |
theme_classic() | Classic, axes only |
theme_light() | Light gray lines |
theme_dark() | Dark background |
theme_void() | Nothing (maps, etc.) |
theme_538() | FiveThirtyEight style |
theme_tufte() | Tufte minimal ink |
theme_xkcd() | XKCD comic style |
ggplot(df, aes("x", "y")) + geom_point() + theme_minimal()Theme Base Parameters
theme_minimal(base_size=14, base_family="Arial")Custom Themes
theme()
Modify individual elements:
theme(
axis_text=element_text(size=12),
axis_title=element_text(size=14, weight="bold"),
legend_position="bottom",
panel_grid_major=element_line(color="gray", size=0.5),
panel_background=element_rect(fill="white")
)Element Functions
| Function | For |
|---|---|
element_text() | Text styling |
element_line() | Lines and borders |
element_rect() | Rectangles (backgrounds) |
element_blank() | Remove element |
element_text()
element_text(
size=12,
color="black",
family="Arial",
weight="bold", # normal, bold
style="italic", # normal, italic
angle=45,
hjust=0.5, # horizontal alignment
vjust=0.5 # vertical alignment
)element_line()
element_line(
color="gray",
size=0.5,
linetype="dashed"
)element_rect()
element_rect(
fill="white",
color="black",
size=1
)element_blank()
Remove an element:
theme(panel_grid_minor=element_blank())Common Theme Modifications
Legend Position
theme(legend_position="bottom") # bottom, top, left, right
theme(legend_position="none") # remove legend
theme(legend_position=(0.8, 0.2)) # coordinates (0-1)Remove Grid Lines
theme(
panel_grid_major=element_blank(),
panel_grid_minor=element_blank()
)Rotate Axis Labels
theme(axis_text_x=element_text(angle=45, hjust=1))Transparent Background
theme(
panel_background=element_rect(fill="transparent"),
plot_background=element_rect(fill="transparent")
)Figure Size
theme(figure_size=(10, 6)) # width, height in inchesDPI
theme(dpi=300)Themeable Elements
Axis
| Element | Description |
|---|---|
axis_title | Both axis titles |
axis_title_x | X axis title |
axis_title_y | Y axis title |
axis_text | Both tick labels |
axis_text_x | X tick labels |
axis_text_y | Y tick labels |
axis_ticks | Tick marks |
axis_line | Axis lines |
Panel
| Element | Description |
|---|---|
panel_background | Panel background |
panel_border | Panel border |
panel_grid_major | Major grid lines |
panel_grid_minor | Minor grid lines |
panel_spacing | Space between panels |
Legend
| Element | Description |
|---|---|
legend_position | Position |
legend_title | Legend title |
legend_text | Legend labels |
legend_background | Background |
legend_key | Key background |
Plot
| Element | Description |
|---|---|
plot_title | Main title |
plot_subtitle | Subtitle |
plot_caption | Caption |
plot_background | Overall background |
plot_margin | Margins |
Strip (Facet Labels)
| Element | Description |
|---|---|
strip_text | Facet label text |
strip_text_x | Top strip text |
strip_text_y | Right strip text |
strip_background | Strip background |
Combining Themes
(
ggplot(df, aes("x", "y"))
+ geom_point()
+ theme_minimal()
+ theme(
axis_text=element_text(size=12),
legend_position="bottom"
)
)Set Default Theme
from plotnine import theme_set, theme_minimal
theme_set(theme_minimal())Geoms (Geometric Objects)
Geoms determine how data is visually represented. Each geom has required and optional aesthetics.
Geoms by Use Case
Points & Scatter
| Geom | Description | Required aes |
|---|---|---|
geom_point() | Scatter plot | x, y |
geom_jitter() | Jittered points | x, y |
geom_count() | Count overlapping points | x, y |
# Basic scatter
ggplot(df, aes("x", "y")) + geom_point()
# With jitter for overplotting
ggplot(df, aes("x", "y")) + geom_jitter(width=0.2)Lines & Paths
| Geom | Description | Required aes |
|---|---|---|
geom_line() | Connect points (ordered by x) | x, y |
geom_path() | Connect points (data order) | x, y |
geom_step() | Step line | x, y |
geom_segment() | Line segment | x, y, xend, yend |
# Line plot
ggplot(df, aes("date", "value")) + geom_line()
# Grouped lines
ggplot(df, aes("date", "value", color="group")) + geom_line()Bars
| Geom | Description | Required aes |
|---|---|---|
geom_bar() | Bar heights from counts | x |
geom_col() | Bar heights from values | x, y |
# Count occurrences
ggplot(df, aes(x="category")) + geom_bar()
# Use existing values
ggplot(df, aes(x="category", y="value")) + geom_col()
# Stacked bars
ggplot(df, aes("category", fill="group")) + geom_bar()
# Dodged (side-by-side)
ggplot(df, aes("category", fill="group")) + geom_bar(position="dodge")Distributions
| Geom | Description | Required aes |
|---|---|---|
geom_histogram() | Histogram | x |
geom_density() | Density curve | x |
geom_freqpoly() | Frequency polygon | x |
# Histogram
ggplot(df, aes(x="value")) + geom_histogram(bins=30)
# Density
ggplot(df, aes(x="value")) + geom_density()
# Overlaid densities
ggplot(df, aes(x="value", fill="group")) + geom_density(alpha=0.5)Box & Violin
| Geom | Description | Required aes |
|---|---|---|
geom_boxplot() | Box-and-whisker | x, y |
geom_violin() | Violin plot | x, y |
# Boxplot by group
ggplot(df, aes("category", "value")) + geom_boxplot()
# Violin plot
ggplot(df, aes("category", "value")) + geom_violin()Area & Ribbon
| Geom | Description | Required aes |
|---|---|---|
geom_area() | Area under line | x, y |
geom_ribbon() | Ribbon with ymin/ymax | x, ymin, ymax |
# Stacked area
ggplot(df, aes("date", "value", fill="group")) + geom_area()
# Confidence band
ggplot(df, aes("x", ymin="lower", ymax="upper")) + geom_ribbon(alpha=0.3)Smoothing & Trends
| Geom | Description | Required aes |
|---|---|---|
geom_smooth() | Smoothed conditional mean | x, y |
# Default: method="auto" (loess for n<1000, glm otherwise)
ggplot(df, aes("x", "y")) + geom_point() + geom_smooth()
# Linear regression
ggplot(df, aes("x", "y")) + geom_point() + geom_smooth(method="lm")
# Without confidence interval
ggplot(df, aes("x", "y")) + geom_smooth(se=False)Error Bars
| Geom | Description | Required aes |
|---|---|---|
geom_errorbar() | Vertical error bars | x, ymin, ymax |
geom_errorbarh() | Horizontal error bars | y, xmin, xmax |
geom_pointrange() | Point with range | x, y, ymin, ymax |
geom_linerange() | Vertical line | x, ymin, ymax |
# Error bars
ggplot(df, aes("category", "mean", ymin="lower", ymax="upper")) + geom_errorbar()
# Point with range
ggplot(df, aes("category", "mean", ymin="lower", ymax="upper")) + geom_pointrange()Text & Labels
| Geom | Description | Required aes |
|---|---|---|
geom_text() | Text labels | x, y, label |
geom_label() | Text with background | x, y, label |
# Add labels
ggplot(df, aes("x", "y", label="name")) + geom_point() + geom_text()
# Adjust position
ggplot(df, aes("x", "y", label="name")) + geom_text(nudge_y=0.5)Reference Lines
| Geom | Description | Parameters |
|---|---|---|
geom_hline() | Horizontal line | yintercept |
geom_vline() | Vertical line | xintercept |
geom_abline() | Line by slope/intercept | slope, intercept |
# Add reference lines
(
ggplot(df, aes("x", "y"))
+ geom_point()
+ geom_hline(yintercept=0, linetype="dashed")
+ geom_vline(xintercept=5, color="red")
)2D Density
| Geom | Description | Required aes |
|---|---|---|
geom_bin_2d() | 2D histogram | x, y |
geom_density_2d() | 2D density contours | x, y |
# 2D bins (heatmap)
ggplot(df, aes("x", "y")) + geom_bin_2d()
# Density contours
ggplot(df, aes("x", "y")) + geom_density_2d()Tiles & Raster
| Geom | Description | Required aes |
|---|---|---|
geom_tile() | Rectangle by center | x, y |
geom_rect() | Rectangle by corners | xmin, xmax, ymin, ymax |
geom_raster() | Fast tiles (equal size) | x, y |
# Heatmap
ggplot(df, aes("x", "y", fill="value")) + geom_tile()Common Geom Parameters
| Parameter | Description | Example |
|---|---|---|
color | Outline color | color="blue" |
fill | Fill color | fill="red" |
alpha | Transparency (0-1) | alpha=0.5 |
size | Size | size=2 |
linetype | Line style | linetype="dashed" |
position | Position adjustment | position="dodge" |
Position Adjustments
Use position parameter to handle overlapping:
| Position | Description |
|---|---|
"identity" | No adjustment (default) |
"dodge" | Side by side |
"stack" | Stack on top |
"fill" | Stack and normalize to 100% |
"jitter" | Random noise |
# Dodged bars
geom_bar(position="dodge")
# Stacked area
geom_area(position="stack")
# Custom jitter
geom_point(position=position_jitter(width=0.2, height=0))Gotchas & Best Practices
Common Errors
Column Name Issues
Error: KeyError or "column not found"
Cause: Column names must be strings in aes().
# WRONG
aes(x=column_name, y=other)
# CORRECT
aes(x="column_name", y="other")Literal vs. Mapped Color
Problem: All points same color when expecting variation.
# WRONG: looks for column named "blue"
aes(color="blue")
# CORRECT: fixed color (outside aes)
geom_point(color="blue")
# CORRECT: mapped to column
aes(color="species")Missing Required Aesthetic
Error: PlotnineError: geom_*() requires the following missing aesthetics: ...
Fix: Add required aesthetics to aes().
# geom_point needs x and y
ggplot(df, aes(x="col1", y="col2")) + geom_point()Plus at End of Line
Error: SyntaxError
Cause: Python doesn't allow + at line end without continuation.
# WRONG
ggplot(df, aes("x", "y")) +
geom_point()
# CORRECT: use parentheses
(
ggplot(df, aes("x", "y"))
+ geom_point()
)Data Type Mismatch
Problem: Unexpected plot behavior or errors.
# If "year" is numeric but should be categorical
aes(x="factor(year)")
# Or convert in pandas first
df["year"] = df["year"].astype(str)Grouped Data Not Connecting
Problem: geom_line() draws separate segments.
Fix: Add group aesthetic.
# Multiple lines by group
aes(x="x", y="y", group="id")
# Or use color (implicitly groups)
aes(x="x", y="y", color="id")ggplot2 Differences
String Column Names
R uses bare names; Python uses strings:
# R
aes(x = column, y = other)# Python
aes(x="column", y="other")Formula Syntax in Facets
# plotnine uses string formula
facet_grid("row ~ col")
# Not R's bare formula
# facet_grid(row ~ col) # WRONGfactor() Syntax
# In aes string
aes(color="factor(cyl)")Some Functions Missing
Not all ggplot2 functions exist. Check API reference for alternatives.
plotnine vs ggplot2 Divergences
These gotchas catch R ggplot2 users who translate code directly to plotnine.
`stat_summary` requires a callable, not a string:
In R ggplot2, stat_summary(fun="mean") accepts a string function name. In plotnine, the fun_y, fun_ymin, and fun_ymax parameters require a Python callable — not a string.
import numpy as np
# WRONG: R-style string name
stat_summary(fun_y="mean") # Error
# CORRECT: Python callable
stat_summary(fun_y=np.mean)
stat_summary(fun_y=np.mean, fun_ymin=np.min, fun_ymax=np.max)`guide=False` is deprecated in scale functions:
In R ggplot2, guide=FALSE or guide="none" inside a scale function removes that scale's legend entry. In recent plotnine versions, guide=False inside scale functions is deprecated. Use theme(legend_position="none") to remove all legends, or guides(color=None) to remove a specific scale's legend.
# WRONG: deprecated in recent plotnine
scale_color_brewer(guide=False)
# CORRECT: remove all legends
theme(legend_position="none")
# CORRECT: remove specific scale legend
guides(color=None)R color names are not valid:
Named colors from R like "gray40", "grey80", "steelblue1" are not recognized by plotnine/matplotlib. Use hex codes or matplotlib named colors.
# WRONG: R-style color names
geom_point(color="gray40") # Not recognized
geom_point(color="steelblue1") # Not recognized
# CORRECT: hex codes
geom_point(color="#666666")
# CORRECT: matplotlib named colors
geom_point(color="steelblue")
geom_point(color="gray")`guide_colorbar()` parameters differ from R:
The parameter names and behavior of guide_colorbar() differ between R ggplot2 and plotnine. Always check the plotnine docs for exact parameter names rather than copying R code directly.
Performance Tips
Large Datasets
1. Sample data for exploration:
ggplot(df.sample(1000), aes(...))2. Use `geom_bin_2d()` instead of geom_point() for millions of points.
3. Reduce DPI during development:
theme(dpi=72)Memory
Save plots explicitly and close:
p = ggplot(...) + geom_point()
p.save("plot.png")
del pBest Practices
Choosing Geoms
| Data | Geom |
|---|---|
| x: continuous, y: continuous | geom_point(), geom_smooth() |
| x: discrete, y: continuous | geom_boxplot(), geom_violin() |
| x: continuous (distribution) | geom_histogram(), geom_density() |
| x: discrete (counts) | geom_bar() |
| x: continuous, y: continuous (time) | geom_line() |
Color vs. Fill
- Points, lines: use
color - Bars, areas, polygons: use
fill(andcolorfor outline)
# Points
geom_point(aes(color="group"))
# Bars
geom_bar(aes(fill="group"))Layer Order
Later layers draw on top:
(
ggplot(df, aes("x", "y"))
+ geom_point(color="gray") # Bottom
+ geom_smooth(color="red") # Top
)Consistent Styling
Create reusable theme:
my_theme = (
theme_minimal()
+ theme(
axis_text=element_text(size=12),
plot_title=element_text(size=16, weight="bold")
)
)
# Apply to plots
ggplot(...) + geom_point() + my_themeReadable Code
# Good: clear structure
(
ggplot(df, aes("x", "y", color="group"))
+ geom_point(size=2)
+ geom_smooth(method="lm")
+ scale_color_brewer(palette="Set1")
+ labs(title="My Plot", x="X Label", y="Y Label")
+ theme_minimal()
)Debugging
Check Data
print(df.head())
print(df.dtypes)
print(df["column"].unique())Simplify Plot
Start minimal, add layers one at a time:
# Start here
ggplot(df, aes("x", "y")) + geom_point()
# Then add
+ geom_smooth()
# Then add
+ facet_wrap("group")Print Intermediate
p = ggplot(df, aes("x", "y"))
print(p) # Shows structure
p + geom_point()Quick Fixes
| Problem | Fix |
|---|---|
| Plot not showing | Add .draw() or ensure last expression |
| Legend unwanted | + theme(legend_position="none") or + guides(color=None) |
| Axis labels overlapping | + theme(axis_text_x=element_text(angle=45)) |
| Too many legend items | Filter data or use scale_*_manual() |
| Bars not stacking | Check position="stack" |
| Points hidden | Add alpha=0.5 or position_jitter() |
| Wrong colors | Check color vs fill |
| Facets same scale | Use scales="free" |
Quickstart
Installation
pip install plotnine
# or
conda install -c conda-forge plotnineBasic Imports
# Import everything (common approach)
from plotnine import *
# Or import specific components
from plotnine import ggplot, aes, geom_point, geom_line, theme_minimalBuilt-in Datasets
from plotnine.data import mtcars, diamonds, mpg, economics, faithfulBasic Plot Anatomy
Every plot follows this pattern:
(
ggplot(data, aes(x="column_x", y="column_y")) # Data + aesthetics
+ geom_point() # Geometry layer
)Key Components
| Component | Purpose |
|---|---|
ggplot() | Initialize plot with data |
aes() | Map columns to visual properties |
geom_*() | Define how to represent data |
+ | Add layers/components |
Minimal Example
from plotnine import ggplot, aes, geom_point
from plotnine.data import mtcars
(
ggplot(mtcars, aes(x="wt", y="mpg"))
+ geom_point()
)Adding Layers
Layers are added with +:
(
ggplot(mtcars, aes("wt", "mpg"))
+ geom_point()
+ geom_smooth(method="lm")
)Multi-line Syntax
Use parentheses to span multiple lines:
p = (
ggplot(df, aes("x", "y"))
+ geom_point()
+ theme_minimal()
)Displaying Plots
In Jupyter/IPython
The plot displays automatically as the last expression:
ggplot(df, aes("x", "y")) + geom_point()In Scripts
Assign to variable and call .draw():
p = ggplot(df, aes("x", "y")) + geom_point()
p.draw()Saving Plots
p = ggplot(df, aes("x", "y")) + geom_point()
# Basic save
p.save("plot.png")
# With options
p.save("plot.png", width=10, height=8, dpi=300)
# Different formats
p.save("plot.pdf")
p.save("plot.svg")Save Parameters
| Parameter | Description |
|---|---|
filename | Output path |
width | Width in inches |
height | Height in inches |
dpi | Resolution (default 100) |
format | Override file extension |
DataFrame Requirements
plotnine works with:
- Pandas DataFrame (primary)
- Polars DataFrame (supported)
Column names are passed as strings:
# Correct
aes(x="column_name", y="other_column")
# Wrong
aes(x=column_name, y=other_column)Quick Examples
Scatter with Color
(
ggplot(mtcars, aes("wt", "mpg", color="factor(cyl)"))
+ geom_point()
)Line Plot
(
ggplot(economics, aes("date", "unemploy"))
+ geom_line()
)Bar Chart
(
ggplot(mtcars, aes(x="factor(cyl)"))
+ geom_bar()
)Histogram
(
ggplot(diamonds, aes(x="price"))
+ geom_histogram(bins=30)
)Next Steps
- Geoms - Chart types
- Aesthetics - Visual mappings
- Scales & Coords - Axis control
- Facets & Themes - Layout and styling
Scales, Coordinates & Positions
Scales Overview
Scales control how data values map to visual properties.
Scale Naming Convention
scale_<aesthetic>_<type>()Examples: scale_x_continuous(), scale_color_brewer(), scale_fill_manual()
Position Scales
Continuous
| Scale | Description |
|---|---|
scale_x_continuous() | Continuous x-axis |
scale_y_continuous() | Continuous y-axis |
scale_x_log10() | Log10 x-axis |
scale_y_log10() | Log10 y-axis |
scale_x_sqrt() | Square root x |
scale_x_reverse() | Reverse direction |
# Custom breaks and labels
scale_x_continuous(breaks=[0, 5, 10], labels=["Low", "Mid", "High"])
# Limit range
scale_x_continuous(limits=(0, 100))
# Format labels
scale_y_continuous(labels=lambda x: f"${x:,.0f}")Discrete
| Scale | Description |
|---|---|
scale_x_discrete() | Categorical x-axis |
scale_y_discrete() | Categorical y-axis |
# Reorder categories
scale_x_discrete(limits=["C", "B", "A"])DateTime
| Scale | Description |
|---|---|
scale_x_datetime() | Date/time x-axis |
scale_x_date() | Date x-axis |
scale_x_datetime(date_labels="%Y-%m")Color & Fill Scales
Discrete Colors
| Scale | Description |
|---|---|
scale_color_brewer() | ColorBrewer palettes |
scale_fill_brewer() | ColorBrewer fills |
scale_color_manual() | Custom colors |
scale_fill_manual() | Custom fills |
scale_color_hue() | Default hue-based |
# ColorBrewer palette
scale_color_brewer(palette="Set1")
scale_fill_brewer(palette="Blues")
# Manual colors
scale_color_manual(values=["red", "blue", "green"])
scale_fill_manual(values={"A": "#FF0000", "B": "#00FF00"})ColorBrewer Palettes
| Type | Palettes |
|---|---|
| Sequential | Blues, Greens, Oranges, Reds, Purples, Greys |
| Diverging | RdBu, RdYlBu, BrBG, PiYG, PRGn, RdYlGn |
| Qualitative | Set1, Set2, Set3, Pastel1, Dark2, Paired |
Continuous Colors
| Scale | Description |
|---|---|
scale_color_gradient() | Two-color gradient |
scale_color_gradient2() | Diverging gradient |
scale_color_gradientn() | Multi-color gradient |
scale_color_distiller() | ColorBrewer continuous |
scale_color_cmap() | Matplotlib colormap |
# Two-color gradient
scale_color_gradient(low="white", high="red")
# Diverging with midpoint
scale_color_gradient2(low="blue", mid="white", high="red", midpoint=0)
# Matplotlib colormap
scale_color_cmap(cmap_name="viridis")Grey Scale
scale_color_grey()
scale_fill_grey(start=0.2, end=0.8)Other Scales
Size
scale_size(range=(1, 10))
scale_size_area(max_size=10) # Area proportional to valueShape
scale_shape_manual(values=[16, 17, 18])Alpha
scale_alpha(range=(0.2, 1))Linetype
scale_linetype_manual(values=["solid", "dashed", "dotted"])Axis Limits
Quick Methods
xlim(0, 100)
ylim(-10, 10)
lims(x=(0, 100), y=(-10, 10))Via Scales
scale_x_continuous(limits=(0, 100))Coordinate Limits (Zoom)
# Zooms without removing data
coord_cartesian(xlim=(0, 100))Difference: limits in scales removes data outside range; coord_cartesian just zooms.
Coordinates
coord_cartesian()
Default Cartesian coordinates:
coord_cartesian(xlim=(0, 10), ylim=(0, 100))coord_fixed()
Fixed aspect ratio:
coord_fixed(ratio=1) # Square plotcoord_flip()
Swap x and y axes:
# Horizontal bar chart
ggplot(df, aes("category", "value")) + geom_col() + coord_flip()coord_trans()
Transform coordinates:
coord_trans(x="log10", y="sqrt")Position Adjustments
Used to handle overlapping elements.
| Position | Use |
|---|---|
position_identity() | No adjustment |
position_dodge() | Side by side |
position_dodge2() | Side by side (preserve width) |
position_stack() | Stack vertically |
position_fill() | Stack to 100% |
position_jitter() | Random noise |
position_jitterdodge() | Both |
position_nudge() | Fixed offset |
# Dodge with custom width
geom_bar(position=position_dodge(width=0.8))
# Jitter with control
geom_point(position=position_jitter(width=0.2, height=0))
# Nudge labels
geom_text(position=position_nudge(y=0.5))Guides (Legends)
Modify Legend
# Legend title
scale_color_brewer(name="Category", palette="Set1")
# Remove all legends
theme(legend_position="none")
# Remove legend for a specific scale
guides(color=None)
# Customize legend
guides(color=guide_legend(title="My Title", nrow=2))Note:guide=Falseinside scale functions (e.g.,scale_color_brewer(guide=False))
is deprecated in recent plotnine versions. Use theme(legend_position="none") to removeall legends, or guides(color=None) for a specific scale.guide_legend()
guide_legend(
title="Title",
nrow=2,
ncol=1,
reverse=True
)guide_colorbar()
For continuous color scales:
guide_colorbar(
title="Value",
barwidth=10,
barheight=100
)Note: The parameter names and behavior of guide_colorbar() differ betweenR ggplot2 and plotnine. Always check the plotnine docs for exact parameter names
rather than copying R code directly.
Common Patterns
Percentage Y-Axis
scale_y_continuous(labels=lambda x: f"{x:.0%}")Currency Format
scale_y_continuous(labels=lambda x: f"${x:,.0f}")Scientific Notation
scale_y_continuous(labels=lambda x: f"{x:.2e}")Date Formatting
scale_x_datetime(date_labels="%b %Y") # "Jan 2024"Reverse Axis
scale_y_reverse()Related skills
FAQ
When should I use plotnine over plotly?
Prefer plotnine over plotly when static output is needed; use plotly when interactivity is required.
How are plots saved?
Use p.save with width, height, and dpi, for example p.save('plot.png', width=10, height=8, dpi=300).