Publication quality: DPI, vector formats and layout

Inches and dots per inch without guessing, vector export with embedded fonts, and multi-panel figures that survive review.

Size and DPI arithmetic

figsize is in inches and dpi is dots per inch, so pixel dimensions are simply the product. A single-column journal figure is about 3.5 inches wide; a slide is about 10. Set the physical size first, then the resolution.

fig, ax = plt.subplots(figsize=(3.5, 2.5))   # inches

fig.savefig("fig1.pdf")                       # vector: resolution is irrelevant
fig.savefig("fig1.png", dpi=600)              # 2100 x 1500 pixels
fig.savefig("fig1.tiff", dpi=300, pil_kwargs={"compression": "tiff_lzw"})

print(fig.get_size_inches())                  # confirm the physical size
# rule of thumb: line charts 300 dpi, raster images 600 dpi, always prefer vector
DestinationFormatTypical DPI
Journal or printPDF or EPSNot applicable (vector)
Word or PowerPointPNG or EMF300-600
Web pageSVG or PNG96-150
PosterPDFVector, sized in inches
Photo-like heatmapTIFF or PNG600

Vector output and fonts

import matplotlib as mpl

mpl.rcParams.update({
    "font.size": 8,
    "font.family": "sans-serif",
    "pdf.fonttype": 42,      # embed TrueType so text stays editable
    "ps.fonttype": 42,
    "axes.linewidth": 0.8,
    "axes.labelsize": 8,
    "legend.frameon": False,
    "savefig.dpi": 600,
    "savefig.bbox": "tight",
})
  • Type 42 embeds the font so the PDF renders identically everywhere and text remains selectable.
  • A PDF full of Type 3 fonts will be rejected by most publishers; check with the PDF property inspector.
  • Set font sizes relative to the final physical size, not the on-screen zoom level.
  • Keep the default font unless the venue requires one, and set it once in rcParams.

Multi-panel figures with labels

fig, axes = plt.subplots(1, 2, figsize=(7, 3), constrained_layout=True)

for label, ax in zip("ab", axes):
    ax.plot(x, np.sin(x))
    ax.text(-0.16, 1.06, label, transform=ax.transAxes,
            fontsize=11, fontweight="bold", va="top", ha="left")

fig.supxlabel("Time (s)", fontsize=9)
fig.savefig("figure1.pdf", bbox_inches="tight", pad_inches=0.02)
💡
Fix the physical width before you tune anything else. Resizing a finished figure in Word or LaTeX scales the fonts with it, and every carefully chosen size becomes wrong at once.

FAQ

PNG at 600 dpi or PDF?
Use PDF (or SVG) for anything containing lines and text, because it stays sharp at any size and keeps the text selectable. Use PNG only for photo-like or heavily rasterised content.
Why do the fonts look different in my final PDF?
The font was substituted because it was not embedded. Set pdf.fonttype = 42 and make sure the font is installed on the machine that produces the file.

Titles, legends, annotations and text Backends and environment setup

Last refreshed 2026-09-18.