Matplotlib — Publication-Quality Figures in Python

Matplotlib gives you exact control over every element of a figure, which is what journal specifications demand. Verbose, unlovely defaults, and still the standard.

Category Figures
Pricing Free
Rating ★★★★☆ (4/5)

What Matplotlib is

Matplotlib is the foundational plotting library for Python. Nearly every other Python visualisation tool — Seaborn, pandas’ plotting methods, much of scikit-learn’s diagnostic output — is built on top of it, which means learning Matplotlib is learning the layer underneath most of the ecosystem.

The property that makes it the publication standard is control. Every element of a figure is an object you can address: the axis spine, the tick label, the legend frame, the width of a specific line. That is why its defaults look dated and its code is verbose — it is not optimised for a quick look at your data, it is optimised for producing exactly the figure someone specified. Journal figure requirements are exactly that kind of specification: 3.5 inches wide, 8-point sans-serif labels, 300 dpi, vector format, no transparency. Matplotlib is the most direct route from that list to a compliant file.

Why researchers use it

  • Exact dimensional control — set the figure to your journal’s column width in inches, and what you get is that width, not something scaled to approximately it.
  • Vector output — PDF, EPS, and SVG that stay sharp at any zoom and satisfy submission requirements without a resolution conversation.
  • A style file makes consistency automatic — an .mplstyle applied across a project means every figure in your paper shares fonts, colours, and line weights without repeating the setup.
  • It is scriptable, so figures regenerate — the data changes, you re-run, and the figure updates. No re-drawing, no stale panel three.
  • AnimationsFuncAnimation produces convergence plots and simulation videos for talks, covered in the animation tutorial.

Where it fits in a research workflow

Matplotlib is the last computational step before a figure becomes a document. Upstream is your analysis in Jupyter or a script; downstream is a .pdf referenced from LaTeX or dropped into a Quarto manuscript, where re-rendering regenerates it from the data.

The pattern worth adopting deliberately is the two-layer one: generate the data layer in Matplotlib — axes, series, labels, everything driven by numbers — and if annotation or layout work remains, export SVG and finish in Inkscape. Keeping the data layer scripted means the figure updates when the data does; keeping the design layer separate means you are not encoding arrow positions in Python. Where it hands off entirely: Plotly when readers should explore the data rather than read it, and RStudio with ggplot2 if your analysis is in R.

Getting started

An afternoon to a compliant figure, and one habit that saves the rest of the project.

  1. Write an .mplstyle file before your second figure. Font family, sizes, line widths, and a fixed colour cycle in one file, applied with plt.style.use(). This is the difference between a coherent paper and eight figures that disagree with each other.
  2. Set the figure size in inches to your target column width and the font size to the journal’s caption size. Getting these right at generation time avoids the scaling that ruins text legibility.
  3. Save as PDF or SVG rather than PNG. Vector output is what journals want and what survives being resized.
  4. The step people skip: check your colour choices against colour-vision deficiency. Roughly one in twelve men cannot distinguish a red-green pair, and the default rainbow colormaps are actively bad. Use a perceptually uniform colormap and an accessible categorical palette; it costs one line and it is the most common reviewable flaw in scientific figures.

Matplotlib vs the alternatives

AlternativeDoes it betterPick it if
SeabornAttractive statistical plots in far less codeYou want a good default quickly, not exact control
PlotlyInteraction — hover, zoom, rotateThe figure is for a web supplement or a dashboard
ggplot2 in RStudioA more coherent grammar and better defaultsYour analysis is in R
InkscapeHand-placed annotation and final layoutThe figure is a diagram, not a plot of data

Seaborn is not really a competitor — it produces Matplotlib figures you can then adjust with Matplotlib. Using both is the normal answer.

Cost, licensing, and your data

Free and open source under a BSD-style licence, developed by a community under the NumFOCUS umbrella with two decades of continuous development. Nothing to buy, no account, nothing leaves your machine.

The consideration that matters is longevity, and it is a strength: figures generated by a script are reproducible in a way figures drawn by hand are not, and Matplotlib’s API has been stable enough that decade-old plotting code still largely runs. Pin the version in your project environment anyway — default styling has changed across major releases, so a figure regenerated years later can differ subtly from the published one even when the data and code are identical.

The honest review

Strengths. Nothing else gives you this degree of control over a scientific figure, and control is precisely what publication requires. Combined with a style file, it turns “make eight figures that look like they belong to the same paper” from an act of discipline into a property of the setup. And because figures are generated from code, a reviewer’s request for a different subset is a re-run rather than an afternoon.

Limitations. The defaults are unattractive and the API is genuinely awkward — two overlapping interfaces (pyplot and the object-oriented one) that tutorials mix freely, and a verbosity that makes simple plots longer than they should be. Getting a figure to look good rather than merely correct takes real effort, which is why Seaborn exists. Interactive output is weak. And the learning curve is front-loaded in an unhelpful way: the concepts you need for publication-quality output are not the ones the beginner tutorials teach.

Verdict. Adopt it if you publish figures from Python data — there is no real alternative for camera-ready output. Skip it for exploratory plotting, where Seaborn’s defaults save you time, and for interactive work, where Plotly is built for the job. The condition that flips the answer is the destination: print journal, Matplotlib; web supplement, Plotly.

When NOT to use this Do not use a rainbow colormap, and do not encode your only distinction in red versus green. Roughly one reader in twelve cannot reliably tell those apart, jet-style colormaps distort perceived magnitude even for readers who can, and both problems survive peer review far too often. Use a perceptually uniform colormap for continuous data and a colour-vision-safe palette for categories — and check that the figure still works in greyscale, because someone will print it.

Common questions

Is Matplotlib free?

Yes — free and open source under a BSD-style licence, community-maintained under NumFOCUS, with no paid tier.

How do I make Matplotlib figures publication-ready?

Set the figure size in inches to your journal’s column width, set font sizes to match the caption size, export as PDF or SVG rather than PNG, and use a colour-vision-safe palette. Put all of it in an .mplstyle file so it applies to every figure automatically — the publication-quality walkthrough covers the details.

Matplotlib or Seaborn?

Both. Seaborn produces Matplotlib figures with better defaults and much less code, so use it to generate the plot and Matplotlib to adjust it for publication. They are layers, not alternatives.