Menu

Tutorial10 min read

Export High-Resolution Figures from Matplotlib: Complete Guide

By Francesco Villasmunta
Export High-Resolution Figures from Matplotlib: Complete Guide

Your figure looks great in Jupyter - but the journal says it is too low resolution. Sound familiar? Getting matplotlib to export high-quality figures requires understanding DPI, file formats, and layout tricks.

This guide covers everything with live, editable code you can test right here.

What You Will Learn

0.Live Code Lab: High-Res Export

1.Understanding DPI

2.Format Comparison

3.Avoiding Clipped Labels

4.Multi-Format Export Workflow

5.Export Checklist

0. Live Code Lab: High-Res Export

This code demonstrates the complete high-resolution export workflow - setting rcParams, using constrained_layout, and calling savefig with the right parameters. Edit the code and run it to see results instantly.

Live Code Editor
Code EditorPython
Loading editor...
Live Preview

Preparing preview

Running once automatically on first load

Learn by Experimenting

This is a safe playground for learning! Try changing:

  • Colors: Modify color values to see different palettes
  • Numbers: Adjust sizes, positions, or data ranges
  • Labels: Update titles, axis names, or legends

Edit the code, run it, then open the full data visualization tool to continue with your own dataset.

1. Understanding DPI

DPI stands for dots per inch. It controls how many pixels are generated per inch of figure width. The formula is simple:

pixels = figure_width_inches x DPI

A 5-inch figure at 300 DPI produces a 1500-pixel-wide image.

72 DPI

Default for screen display. Fine for presentations and Jupyter views. Never for print.

300 DPI

Minimum for print publications. Good for photographs and color images.

600-1200 DPI

Required for line art and graphs. Most Nature/Science journals expect this range.

2. Format Comparison

FormatTypeBest ForDPI Matters?
.pngRasterPhotos, web, slidesYes, set 300+
.pdfVectorLine art, graphs, chartsNo (infinite)
.svgVectorWeb, editable graphicsNo (infinite)
.tiffRasterJournals requiring TIFFYes, set 600+
.epsVectorLegacy journal systemsNo (infinite)

Quick Rule

Graphs and charts? Always use PDF or SVG (vector). Photos/micrographs? Use PNG or TIFF at 300+ DPI. Never upscale a low-res image.

3. Avoiding Clipped Labels

The most common matplotlib export problem: axis labels or titles get cut off because the saved image does not include the full figure area. There are two solutions:

Option 1: bbox_inches

fig.savefig("fig.png", bbox_inches="tight")

Automatically expands the bounding box to include all elements. Works 90% of the time. This is your go-to solution.

Option 2: constrained_layout

fig, ax = plt.subplots(constrained_layout=True)

Better for multi-panel figures. Automatically adjusts spacing between subplots. More reliable than tight_layout for complex layouts.

Warning

Do not use both tight_layout() and constrained_layout=True on the same figure. They conflict. Pick one or the other.

4. Multi-Format Export Workflow

See the same data at 3 different DPI values side by side. This helps you understand why DPI matters and how to choose the right value for your use case.

Live Code Editor
Code EditorPython
Loading editor...
Live Preview

Preparing preview

Running once automatically on first load

Learn by Experimenting

This is a safe playground for learning! Try changing:

  • Colors: Modify color values to see different palettes
  • Numbers: Adjust sizes, positions, or data ranges
  • Labels: Update titles, axis names, or legends

Edit the code, run it, then open the full data visualization tool to continue with your own dataset.

5. Export Checklist

Set figure size in inches to match journal column width

Use constrained_layout=True or bbox_inches='tight'

Export graphs/charts as PDF or SVG (vector)

Export photos/micrographs as PNG/TIFF at 300-600 DPI

Check that all text is 7+ pt at the final printed size

Verify fonts are embedded (open PDF in viewer to check)

Test colorblind accessibility (no red-green only encoding)

Do not upscale low-res images - regenerate from code

Chart gallery

High-res export templates

Each gallery chart exports at publication quality by default.

Browse all chart types →
Scatter plot of height vs weight colored by gender with regression line
Statisticalmatplotlib, seaborn
From the chart galleryCorrelation analysis between metrics

Scatterplot

Displays values for two variables as points on a Cartesian coordinate system.

Sample code / prompt

import matplotlib.pyplot as plt
import numpy as np
from scipy import stats
import pandas as pd

# Generate sample data
np.random.seed(42)
n_samples = 200
height = np.random.normal(170, 8, n_samples)
weight = height * 0.6 + np.random.normal(0, 8, n_samples) - 50
Multi-line graph showing temperature trends for 3 cities over a year
Time Seriesmatplotlib, seaborn
From the chart galleryStock price tracking over time

Line Graph

Displays data points connected by straight line segments to show trends over time.

Sample code / prompt

import matplotlib.pyplot as plt
import numpy as np

# Generate temperature data for 3 major US cities over 12 months
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
nyc = [30, 32, 40, 52, 65, 75, 82, 81, 74, 63, 50, 38]
miami = [65, 66, 70, 76, 82, 87, 90, 90, 87, 80, 72, 66]
chicago = [25, 27, 35, 48, 62, 72, 80, 79, 71, 60, 45, 32]

# Create figure with enhanced styling
Bar chart comparing average scores across 5 groups with error bars
Comparisonmatplotlib, seaborn
From the chart galleryComparing performance across categories

Bar Chart

Compares categorical data using rectangular bars with heights proportional to values.

Sample code / prompt

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import stats

# Generate performance scores for 5 treatment groups
np.random.seed(42)
groups = ['Control', 'Treatment A', 'Treatment B', 'Treatment C', 'Treatment D']
n_samples = 30
Histogram showing age distribution with 20 bins and KDE overlay
Distributionmatplotlib, seaborn
From the chart galleryAnalyzing age demographics

Histogram

Displays the distribution of numerical data by grouping values into bins.

Sample code / prompt

import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde, skewnorm

# Generate age data with slight right skew
np.random.seed(42)
ages = skewnorm.rvs(a=2, loc=42, scale=15, size=500)
ages = np.clip(ages, 18, 80)  # Clip to realistic range

fig, ax = plt.subplots(figsize=(12, 7))

Frequently Asked Questions

What DPI should I use for journal figures?
Most journals require 300 DPI minimum for raster images (PNG, TIFF). Nature and Science recommend 600-1200 DPI for line art. For vector formats like PDF and SVG, DPI does not apply since they scale infinitely without quality loss.
Why are my matplotlib labels getting clipped when I export?
Use bbox_inches='tight' in your savefig() call. This tells matplotlib to recalculate the bounding box to include all labels and annotations. Alternatively, use plt.tight_layout() or fig.set_layout_engine('constrained') before saving.
Should I export as PNG, PDF, or SVG for my paper?
Use PDF or SVG for vector graphics (line plots, bar charts) - they stay sharp at any zoom level and journals prefer them. Use PNG or TIFF at 600 DPI for raster images (heatmaps, photographs). Avoid JPEG for scientific figures since lossy compression introduces artifacts.
How do I set the exact figure size in inches for a journal column width?
Use fig, ax = plt.subplots(figsize=(width_inches, height_inches)). For a single-column Nature figure, use figsize=(3.5, 2.5). For a double-column figure, use figsize=(7.2, 4.5). Always check your target journal's specific requirements.
Why does my exported figure look different from the Jupyter notebook preview?
Jupyter renders at screen resolution (72 DPI) while savefig() uses your specified DPI. The font sizes, line widths, and overall proportions can shift. Always preview the saved file at 100% zoom to verify. Set DPI consistently: fig.savefig('plot.png', dpi=300, bbox_inches='tight').

Skip the DPI Headaches

Plotivy exports publication-ready figures at 600 DPI by default. Upload your data, pick a journal style, and download in one click.

Start Free
Tags:#matplotlib#export#dpi#publication figures#python#savefig

Found this helpful? Share it with your network.

FV
Francesco Villasmunta

Experimental Physicist & Photonics Researcher

Hands-on experience in silicon photonics, semiconductor fabrication (DRIE/ICP-RIE), optical simulation, and data-driven analysis. Built Plotivy to help researchers focus on discoveries instead of data struggles.

More about the author

Visualize your own data

Apply the techniques from this article to your own datasets. Upload CSV, Excel, or paste data directly.

Start Analyzing - Free