182

How can I save Python plots at very high quality?

That is, when I keep zooming in on the object saved in a PDF file, why isn't there any blurring?

Also, what would be the best mode to save it in?

png, eps? Or some other? I can't do pdf, because there is a hidden number that happens that mess with Latexmk compilation.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dustin
  • 4,309
  • 12
  • 57
  • 79

5 Answers5

224

If you are using Matplotlib and are trying to get good figures in a LaTeX document, save as an EPS. Specifically, try something like this after running the commands to plot the image:

plt.savefig('destination_path.eps', format='eps')

I have found that EPS files work best and the dpi parameter is what really makes them look good in a document.

To specify the orientation of the figure before saving, simply call the following before the plt.savefig call, but after creating the plot (assuming you have plotted using an axes with the name ax):

ax.view_init(elev=elevation_angle, azim=azimuthal_angle)

Where elevation_angle is a number (in degrees) specifying the polar angle (down from vertical z axis) and the azimuthal_angle specifies the azimuthal angle (around the z axis).

I find that it is easiest to determine these values by first plotting the image and then rotating it and watching the current values of the angles appear towards the bottom of the window just below the actual plot. Keep in mind that the x, y, z, positions appear by default, but they are replaced with the two angles when you start to click+drag+rotate the image.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
spencerlyon2
  • 9,476
  • 4
  • 30
  • 39
  • 1
    @spencerlon2 what if I want to change the orientation of the figure before saving? – dustin Apr 24 '13 at 05:01
  • 23
    Why do we need the DPI parameter? Isn't the eps a vector format? – mkvoya Dec 27 '18 at 16:39
  • 3
    Good point - DPI is not needed for vector formats like svg, pdf, eps – spencerlyon2 Mar 12 '19 at 13:32
  • 3
    You can omit `format='eps'` if you like to. In this case the format is inferred from the filename. – timgeb Aug 11 '19 at 15:58
  • @mkvoya I think with higher `dpi`, the image can be magnified a lot more. – zyy Nov 17 '20 at 17:52
  • `dpi` is important if the exported plot contains raster elements (images) in addition to vector art. To elaborate, a lower `dpi` export will contain pixelated raster elements such as embedded images. – PPR Oct 08 '21 at 22:22
116

Just to add my results, also using Matplotlib.

.eps made all my text bold and removed transparency. .svg gave me high-resolution pictures that actually looked like my graph.

import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# Do the plot code
fig.savefig('myimage.svg', format='svg', dpi=1200)

I used 1200 dpi because a lot of scientific journals require images in 1200 / 600 / 300 dpi, depending on what the image is of. Convert to desired dpi and format in GIMP or Inkscape.

Obviously the dpi doesn't matter since .svg are vector graphics and have "infinite resolution".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
grofte
  • 1,839
  • 1
  • 16
  • 15
  • 4
    The DPI matters a great deal when we use `imshow(..)` somewhere on the figure. These bitmaps get rasterised down as they get embedded into the SVG. With the default DPI, the results are even worse than what we see on the screen, definitely unsuitable for publications. – Evgeni Sergeev Mar 12 '17 at 11:28
  • 2
    I also highly recommend Scour (https://github.com/scour-project/scour) to reduce the file size of your svg. On the most aggressive setting I can get reduce my file size to 50% of the original - 5% if I use the .svgz compressed format. – grofte Jan 14 '20 at 12:36
  • 1
    Actually dpi = 1200 works with png as well! Amazing, thanks a million :) – Dmitrij Celov May 06 '22 at 08:42
11

Okay, I found spencerlyon2's answer working. However, in case anybody would find himself/herself not knowing what to do with that one line, I had to do it this way:

beingsaved = plt.figure()

# Some scatter plots
plt.scatter(X_1_x, X_1_y)
plt.scatter(X_2_x, X_2_y)

beingsaved.savefig('destination_path.eps', format='eps', dpi=1000)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jonatán Iván
  • 111
  • 1
  • 4
11

You can save to a figure that is 1920x1080 (or 1080p) using:

fig = plt.figure(figsize=(19.20,10.80))

You can also go much higher or lower. The above solutions work well for printing, but these days you want the created image to go into a PNG/JPG or appear in a wide screen format.

Eamonn Kenny
  • 1,926
  • 18
  • 20
  • 2
    You should probably add that this is because (usually) the default value for dpi is 100 and figsize is given in inches. So 19.2 inches with 100 dots per inch gives you 1920 dots in that dimension =D – grofte Dec 10 '21 at 09:30
  • note that the text isn't scaled up when you make the `figsize` large, which means that when showing the image at a scale less than 100% the text might be unreadable. It is better to set the `figsize` (close) to the actual size in your document and then set the `dpi` higher to increase the resolution of the text and images. – hugovdberg Dec 16 '22 at 10:44
9

In case you are working with seaborn plots, instead of Matplotlib, you can save a .png image like this:

Let's suppose you have a matrix object (either Pandas or NumPy), and you want to take a heatmap:

import seaborn as sb

image = sb.heatmap(matrix)   # This gets you the heatmap
image.figure.savefig("C:/Your/Path/ ... /your_image.png")   # This saves it

This code is compatible with the latest version of Seaborn. Other code around Stack Overflow worked only for previous versions.

Another way I like is this. I set the size of the next image as follows:

plt.subplots(figsize=(15,15))

And then later I plot the output in the console, from which I can copy-paste it where I want. (Since Seaborn is built on top of Matplotlib, there will not be any problem.)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Leevo
  • 1,683
  • 2
  • 17
  • 34