Matplotlib can be a powerful tool for Python-based plotting, but if you’ve ever generated your plots inline within a Jupyter notebook you probably noticed that the default resolution of the rendered plot images is pretty low, which can leave your plots looking blurry/grainy and hard to read. This can be troublesome, particularly if you are planning to share your notebook or export it to another format.

In this post, I’ll share two ways to change default settings so that matplotlib plots come out with better resolution both inline and when exported (for example, with nbconvert).

Okay, first things first, let’s do our initial imports and setup. We can import pyplot and give our notebook magic command to inline matplotlib figures:

import matplotlib.pyplot as plt
%matplotlib inline

Here is the code for the test data set I used to generate the plots in this post:

import numpy as np
x = np.linspace(0,10,100)
y = 2*x + 2.

And here is the default plot outcome:

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y(x)")

png

Pretty blurry…

Solution 1. Change the default dpi settings in matplotlib

By default the plots rendered in our notebooks are png format with a relatively low resolution. Although this first solution isn’t necessarily Jupyter notebook specific, we use the following commands to increase the default pixel density used for our matplotlib plots via matplotlib’s rcParams.:

plt.rcParams['figure.dpi'] = 300
plt.rcParams['savefig.dpi'] = 300

I like 300 (i.e., 300 dpi), but you can adjust to your liking; for reference, I think the default dpi is 78. Note that figure.dpi will increase the pixel for inlined renderings while savefig.dpi is needed if you plan to export the notebook (e.g., using nbconvert) with its plots.

Now let’s see the new plot with updated resolution:

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y(x)")

png Much clearer! (However, Jupyter has the quirk of increasing the image size too when you increase the figure dpi. I’m not sure why or how to alter this behavior without explicitly setting figure size via rcParams).

Seaborn version

If you are seaborn user, you can achieve similar results by with the following:

import seaborn as sns
sns.set(rc={"figure.dpi":300, 'savefig.dpi':300})
sns.set_context('notebook')
sns.set_style("ticks")

And the plot for comparison:

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y(x)")

png

Solution 2. Change the default image format to a vector format

As noted in the previous section, the default format for the plots rendered in our notebooks is png with a relatively low resolution. With the first solution, we improved resolution by simply increasing matplotlib’s default pixel density. In this case, we will avoid the pixel density issue altogether by switching the default format of plot renderings to a re-scalable vector format - I learned this trick from this blog post. We can add the following commands after our pyplot import and inline magic to change the default format (or even have the notebook store plots in multiple image formats):

from IPython.display import set_matplotlib_formats
set_matplotlib_formats('svg')

The first line imports the special function we need from the IPython.display module and in the second line we set the image format we want the notebook use for matplotlib plots; I chose svg here, but you could also try other vector formats such pdf. Here is the resulting plot:

plt.plot(x, y)
plt.xlabel("x")
plt.ylabel("y(x)")

svg
Much nicer than the default!

I should note that we could also do the above with matplotlib’s rcParams, for example by using:

plt.rcParams['figure.format'] = 'svg'

However, the set_matplotlib_formats function is a little more powerful within the Jupyter notebook setting, as you can also tell the notebook to render matplotlib plots in multiple formats; e.g.:

from IPython.display import set_matplotlib_formats
set_matplotlib_formats('svg', 'pdf')

which could be useful if you want to export the notebook itself to different formats (like markdown to share on the web and pdf to send to a colleague).

Update 06/04/2020: Although you can get beautifully crisp and clear plots, I’ve found that in some cases switching the inline render format of plots to svg can cause the notebook to lag, so much so that it was noticeably bogging down one of my exploratory analysis notebooks; in that particular case, much of my data was overlapped anyways, so using svg probably wasn’t best way to go regardless. Anyways, this may be something to keep in mind when deciding what solution is best for your case. As an alternative, I’ve gotten good results so far by using the retina format (instead of svg) with a default plot resolution of 100 dpi. So, something like

import seaborn as sns
sns.set(rc={"figure.dpi":100, 'savefig.dpi':300})
sns.set_context('notebook')
sns.set_style("ticks")
from IPython.display import set_matplotlib_formats
set_matplotlib_formats('retina')

yields nice looking inline plots that are much cleaner and crisper than normal png, without so much notebook lag. This also doesn’t alter the inline plot image size as much as when you just set the figure.dpi to something like 300 with the default png format.

Well, that’s it. Thanks for stopping by, and I hope these tips help you get nicer looking matplotlib plots inline and on export from your Jupyter notebooks.

Like this content? You can follow this blog and get updated about new post via its RSS/Atom Feed.

Until next time – Blake