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:

  1. Create a chart — returns a ChartResult with the Plotly figure

  2. Display 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

{chart_id}.html

Interactive HTML

Web display (Plotly)

{chart_id}.png

PNG (8×6”)

Static single format

{chart_id}_wide.png

PNG (12×6”)

Static wide format

{chart_id}.pdf

PDF (8×6”)

Publication (LaTeX)

{chart_id}_wide.pdf

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 generation

  • plotly — Interactive chart generation

  • kaleido — Plotly static export

  • pluggy — Plugin system

  • pandas-datareader — NBER recession data from FRED

  • fredapi — 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.