Plotting#
ChartBook includes a built-in plotting module that provides simple, consistent chart creation with automatic multi-format export. This module is designed to standardize chart styling across your organization while producing both interactive web charts and publication-ready static images.
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': './_output/gdp_growth.html',
# 'png': './_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 data requires a FRED API key. Set the FRED_API_KEY environment variable.
Get a free key at https://fred.stlouisfed.org/docs/api/api_key.html
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#
When you create a chart with chartbook.plotting, you can reference it in your chartbook.toml:
[charts.gdp_growth]
chart_name = "GDP Growth"
short_description_chart = "Quarterly GDP growth rate"
dataframe_id = "fred"
path_to_html_chart = "./_output/gdp_growth.html"
# Optional: indicate this was generated by chartbook.plotting
generated_by_chartbook_plotting = true
If path_to_html_chart is a directory (or omitted), chartbook will look for {chart_id}.html in the default output directory.
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#
The plotting module requires additional dependencies:
pip install "chartbook[plotting]"
This installs:
matplotlib— Static chart generationplotly— Interactive chart generationkaleido— Plotly static exportpluggy— Plugin systemfredapi— NBER recession data from FRED
Best Practices#
Use
.show()for exploration — Quick inline display without saving filesUse
.save()for production — Generates all formats with consistentchart_idAccess
.figurefor Plotly customization — Full Plotly API availableAccess
.mpl_axesfor fine control — Matplotlib API for complex annotationsSet global config early — Call
configure()at the start of your pipelineUse NBER recessions for time series — Provides economic context
Add source attribution — Include data sources for reproducibility
Keep titles concise — Detailed info goes in caption/note/source