Plotting#
chartbook.plotting creates charts with one call and exports them in every format a pipeline needs — interactive HTML for the generated site, static PNG and PDF for papers and slides — with consistent styling across your organization.
Every chart type below appears with live output in the ChartBook Plotting Gallery.
Overview#
The plotting module follows a two-step workflow:
Create a chart — returns a
ChartResultwith the Plotly figureDisplay or Save — call
.show()to display inline, or.save(chart_id)to export files
When saving, the module generates 5 output files for each chart:
File |
Format |
Purpose |
|---|---|---|
|
Interactive HTML |
Web display (Plotly) |
|
PNG (8×6”) |
Static single format |
|
PNG (12×6”) |
Static wide format |
|
PDF (8×6”) |
Publication (LaTeX) |
|
PDF (12×6”) |
Publication wide |
Quick Start#
import chartbook
import pandas as pd
# Create sample data
df = pd.DataFrame({
'date': pd.date_range('2020-01-01', periods=12, freq='ME'),
'gdp': [100, 102, 101, 105, 108, 110, 112, 115, 114, 118, 120, 122],
'cpi': [2.1, 2.2, 2.3, 2.2, 2.4, 2.5, 2.6, 2.5, 2.7, 2.8, 2.9, 3.0],
})
# Create a line chart and display inline
chartbook.plotting.line(df, x="date", y="gdp", title="GDP Growth").show()
# Create and save to files
result = chartbook.plotting.line(
df,
x="date",
y=["gdp", "cpi"],
title="Economic Indicators",
)
result.save(chart_id="gdp_growth")
print(result.paths)
# {'html': Path('_output/gdp_growth.html'),
# 'png': Path('_output/gdp_growth.png'), ...}
ChartResult Object#
All chart functions return a ChartResult object that provides access to the underlying figures and saving functionality:
result = chartbook.plotting.line(df, x="date", y="value")
# Display inline (Jupyter, interactive environments)
result.show()
# Access the Plotly figure for customization
fig = result.figure
fig.update_layout(title_font_size=24)
result.show()
# Access matplotlib objects for fine-grained control
ax = result.mpl_axes
ax.axhline(y=100, color='red', linestyle='--', label='Target')
ax.legend()
fig = result.mpl_figure
fig.suptitle("Custom Title", fontsize=16)
# Save to files
result.save(chart_id="my_chart")
# Access saved paths
result.html_path # Path to HTML file
result.png_path # Path to PNG file
result.png_wide_path # Path to wide PNG
result.pdf_path # Path to PDF file
result.pdf_wide_path # Path to wide PDF
# Get all paths as dict
result.paths # {'html': Path(...), 'png': Path(...), ...}
# Chart metadata
result.chart_id # "my_chart"
result.chart_type # "line"
result.output_dir # Path("./_output")
Method Chaining#
The .save() method returns the result for convenient chaining:
# One-liner: create, save, and get paths
paths = chartbook.plotting.line(df, x="date", y="value").save("gdp").paths
Chart Types#
Line Chart#
chartbook.plotting.line(
df,
x="date",
y=["series1", "series2"], # Multiple series supported
title="My Line Chart",
y_title="Value",
nber_recessions=True, # Add recession shading
).save("my_line")
Bar Chart#
chartbook.plotting.bar(
df,
x="category",
y=["value1", "value2"],
stacked=True, # Stack bars instead of grouping
title="Sales by Category",
).save("my_bar")
Scatter Plot#
chartbook.plotting.scatter(
df,
x="x_var",
y="y_var",
size="magnitude", # Size points by column
color_by="category", # Color by category
regression_line=True, # Add trend line
).save("my_scatter")
Pie Chart#
chartbook.plotting.pie(
df,
names="category",
values="amount",
title="Distribution",
).save("my_pie")
Area Chart#
chartbook.plotting.area(
df,
x="date",
y=["a", "b", "c"],
stacked=True,
title="Stacked Area",
).save("my_area")
Dual-Axis Chart#
Combine two chart types with independent y-axes:
chartbook.plotting.dual(
df,
x="date",
left_y="gdp",
right_y="interest_rate",
left_type="bar", # "line", "bar", "scatter", "area"
right_type="line",
left_y_title="GDP (Billions)",
right_y_title="Interest Rate (%)",
).save("gdp_vs_rate")
Overlays#
NBER Recession Shading#
Add NBER recession bars to time series charts:
chartbook.plotting.line(
df,
x="date",
y="value",
nber_recessions=True,
).show()
Note
NBER recession shading is fetched from FRED’s public USREC series via
pandas-datareader (installed with
chartbook) — no API key needed. Fetching requires network access.
Horizontal Lines#
chartbook.plotting.line(
df,
x="date",
y="value",
hlines=[
{"y": 100, "color": "red", "dash": "dash", "label": "Target"},
{"y": 0, "color": "gray", "dash": "solid"},
],
).show()
Shaded Regions#
Highlight specific time periods:
chartbook.plotting.line(
df,
x="date",
y="value",
shaded_regions=[
{
"x0": "2020-03-01",
"x1": "2020-06-01",
"color": "red",
"alpha": 0.2,
"label": "COVID Period",
},
],
).save("with_regions")
Bands (Fill Between)#
Fill between two y-columns (e.g., confidence intervals, target ranges):
chartbook.plotting.line(
df,
x="date",
y="value",
bands=[
{
"y_upper": "upper_bound",
"y_lower": "lower_bound",
"color": "blue",
"alpha": 0.2,
},
],
).save("with_band")
Configuration#
Global Settings#
Configure defaults that apply to all charts:
chartbook.plotting.configure(
default_output_dir="./_charts",
nber_recessions=False,
figure_size_single=(8, 6),
figure_size_wide=(12, 6),
matplotlib_style="chartbook",
plotly_template="plotly_white",
)
Matplotlib Style#
Set the matplotlib stylesheet:
# Use built-in chartbook style
chartbook.plotting.set_style("chartbook")
# Use a built-in matplotlib style
chartbook.plotting.set_style("seaborn-v0_8-whitegrid")
# Use a custom .mplstyle file
chartbook.plotting.set_style("./my_custom_style.mplstyle")
Annotations#
Add title, caption, note, and source to any chart:
chartbook.plotting.line(
df,
x="date",
y="value",
title="GDP Growth Over Time",
caption="Quarterly data, seasonally adjusted",
note="Preliminary data for Q4 2024",
source="Bureau of Economic Analysis",
).save("annotated")
Axis Formatting#
chartbook.plotting.line(
df,
x="date",
y="rate",
x_title="Date",
y_title="Rate (%)",
y_tickformat=".1%", # Format as percentage
y_range=(0, 10), # Set axis range
).save("formatted")
Advanced Usage: Accessing Raw Figures#
For fine-grained control, access the underlying plotting library objects:
Plotly Figure#
result = chartbook.plotting.line(df, x="date", y="value")
# Get the Plotly figure
fig = result.figure
# Customize with Plotly API
fig.update_layout(
title_font_size=24,
legend=dict(orientation="h", yanchor="bottom", y=1.02),
)
fig.update_traces(line=dict(width=3))
# Display the customized chart
result.show()
Matplotlib Figure and Axes#
result = chartbook.plotting.line(df, x="date", y="value")
# Access matplotlib objects (lazily created)
ax = result.mpl_axes
fig = result.mpl_figure
# Customize with matplotlib API
ax.axhline(y=100, color='red', linestyle='--', linewidth=2, label='Target')
ax.fill_between(df['date'], 90, 110, alpha=0.1, color='green')
ax.legend(loc='upper left')
fig.suptitle("My Custom Chart", fontsize=16, fontweight='bold')
# Save the chart (matplotlib customizations apply to static formats)
result.save("custom_chart")
Integration with chartbook.toml#
.save(chart_id="gdp_growth") writes gdp_growth.html (and the static variants) into the output directory. Reference that HTML file from the chart’s manifest entry, and the generated site embeds it:
[charts.gdp_growth]
name = "GDP Growth"
description = "Quarterly GDP growth rate"
dataframe = "fred"
path = "./_output/gdp_growth.html"
docs = "Quarterly real GDP growth, seasonally adjusted."
See Documenting a Pipeline for the manifest side.
Plugin System#
The plotting module uses pluggy for extensibility. Third-party packages can provide custom backends:
# In third-party package's pyproject.toml
[project.entry-points.chartbook_plotting]
altair = "mypackage.backend:AltairBackend"
See the API reference for details on implementing custom backends.
Dependencies#
Everything the plotting module needs ships with pip install chartbook:
matplotlib— Static chart generationplotly— Interactive chart generationkaleido— Plotly static exportpluggy— Plugin systempandas-datareader— NBER recession data from FREDfredapi— FRED API client, available for pipeline code
Workflow notes#
Use .show() while exploring and .save() when the chart is ready for the pipeline — the interactive and static outputs stay in sync because both render from the same data and config. If you call configure(), do it once at the top of your chart script so every chart picks up the same defaults.