Skip to content

MatplotlibThemes

H.P. Gansevoort edited this page Sep 12, 2026 · 7 revisions

Matplotlib Themes

These themes give a chart the matplotlib look in pure .NET, with no other changes needed. No Python runtime is required.

The two themes mimic matplotlib's visual style: the pre-2.0 classic look and the modern v2.0+ default. MatPlotLibNet renders both entirely on its own.


Theme.MatplotlibClassic — the pre-2.0 look

This theme uses a white background, the bgrcmyk 7-color cycle, DejaVu Sans at 12pt, and a grid that is hidden by default. The grid is hidden because matplotlib ships with plt.grid(False); users turn it on themselves.

using MatPlotLibNet;
using MatPlotLibNet.Styling;

double[] x = [0, 1, 2, 3, 4, 5];
double[] y1 = [0, 1, 4, 9, 16, 25];
double[] y2 = [0, 2, 4, 6,  8, 10];

Plt.Create()
    .WithTheme(Theme.MatplotlibClassic)
    .WithTitle("Classic matplotlib look")
    .Plot(x, y1, s => s.Label = "Quadratic")
    .Plot(x, y2, s => s.Label = "Linear")
    .WithLegend()
    .Save("classic.svg");

Color cycle — bgrcmyk

# Hex Name
0 #0000FF blue
1 #008000 green
2 #FF0000 red
3 #00BFBF cyan
4 #BF00BF magenta
5 #BFBF00 yellow
6 #000000 black

At a glance

Property Value
Background #FFFFFF (white)
Axes background #FFFFFF (white)
Foreground text #000000 (pure black)
Font family DejaVu Sans, Bitstream Vera Sans, sans-serif
Font size 12.0pt
Grid hidden by default (Visible = false)
Cycle length 7 colors

Theme.MatplotlibV2 — the modern default

This theme uses a white background, soft-black #262626 text, the modern tab10 10-color cycle, DejaVu Sans at 10pt, and a grid that is hidden by default. Matplotlib v2 softened pure black to this soft black on purpose.

Plt.Create()
    .WithTheme(Theme.MatplotlibV2)
    .WithTitle("Modern matplotlib look")
    .Plot(x, y1, s => s.Label = "Quadratic")
    .Plot(x, y2, s => s.Label = "Linear")
    .WithLegend()
    .Save("v2.svg");

Color cycle — tab10

# Hex Name
0 #1f77b4 blue
1 #ff7f0e orange
2 #2ca02c green
3 #d62728 red
4 #9467bd purple
5 #8c564b brown
6 #e377c2 pink
7 #7f7f7f gray
8 #bcbd22 olive
9 #17becf cyan

At a glance

Property Value
Background #FFFFFF (white)
Axes background #FFFFFF (white)
Foreground text #262626 (soft black)
Font family DejaVu Sans, sans-serif
Font size 10.0pt
Grid hidden by default (Visible = false)
Cycle length 10 colors

Opting into a grid

Both themes ship with the grid off, matching matplotlib's plt.grid(False) default.

Plt.Create()
    .WithTheme(Theme.MatplotlibV2)
    .AddSubPlot(1, 1, 1, ax => ax
        .Plot(x, y)
        .ShowGrid(true))                           // simple toggle
    .Save("v2_with_grid.svg");

Or override the theme grid via ThemeBuilder:

var v2WithGrid = Theme.CreateFrom(Theme.MatplotlibV2)
    .WithGrid(g => g with { Visible = true, Color = Color.FromHex("#B0B0B0") })
    .Build();

Comparison

Aspect MatplotlibClassic MatplotlibV2 Theme.Default
Era mimicked matplotlib < 2.0 matplotlib 2.0+ none specifically
Cycle bgrcmyk (7) tab10 (10) tab10 (10)
Foreground text pure black soft black #262626 pure black
Font size 12pt 10pt 13pt (default)
Grid default off off on
Use case retro / classic modern Jupyter look MatPlotLibNet's own default

Theme.Default already uses tab10. Choose MatplotlibV2 when you want the full matplotlib look: it has a different font stack, soft-black text, and a grid that is hidden by default.


Community Themes

There are six community themes. Each has its own palette, font, size, and grid defaults. Applying one visibly changes the chart; no other API calls are needed.

Theme Palette Font Size Grid
Theme.Grayscale grayscale cycle (no hues) default default default
Theme.Paper default serif 11pt off
Theme.Presentation default bold 16pt default
Theme.Poster default bold 20pt on, 1.5 linewidth
Theme.GitHub GitHub brand palette default default #E1E4E8
Theme.Minimal default default 11pt off

Use them the same way: Plt.Create().WithTheme(Theme.Paper)…. Contract tests check that each theme produces byte-distinct output, so a theme that collapses back to Default fails CI.


Pixel-verified against matplotlib

Every chart with a matplotlib equivalent is verified against a pinned matplotlib (3.10.8) reference PNG under both themes. The fidelity suite runs 146 tests (73 fixtures × 2 themes):

# regenerate reference PNGs (developers only — not run in CI)
pip install -r tools/mpl_reference/requirements.txt
python tools/mpl_reference/generate.py --all --style both

# run the dual-theme fidelity tests
dotnet run --project Tst/MatPlotLibNet.Fidelity/MatPlotLibNet.Fidelity.Tests.csproj

Each test renders one MatPlotLibNet figure, exports to PNG via the SkiaSharp backend, and compares against the matplotlib reference using three metrics: RMS pixel error, block SSIM, and MaxColorDeltaE (CIE ΔE*76 across the 5 dominant colours). Failures emit a 3-panel side-by-side diff PNG (reference | actual | abs-difference heatmap) under bin/Debug/net10.0/fidelity-failures/{theme}_{name}.diff.png.

Coverage: the 73 fixtures are 12 core fixtures (line, scatter, bar, hist, pie, box, violin, heatmap, contour, polar, candlestick, errorbar), 45 Phase 5 fixtures (XY, grid, field, polar, categorical, distribution, 3D, financial, special), 15 Phase 6 fixtures (pandas_ta technical indicators), and 1 composition fixture (a multi-subplot suptitle, mathtext labels, and a mathtext legend).

The v2 fixtures use plt.style.context('default'), which is matplotlib's modern default (tab10 cycle, DejaVu Sans 10pt, soft-black #262626 foreground). This is the look that Theme.MatplotlibV2 reproduces.


Implementation notes

An internal MatplotlibThemeFactory builds both themes through a shared Build(...) helper, so the two themes differ only where they have to: color cycle, font size, and foreground text. The font stack is a record struct (MatplotlibFontStack). It has named fields with value equality; it is not a positional tuple.


See also

Clone this wiki locally