Skip to content

Instantly share code, notes, and snippets.

@CMCDragonkai
Last active February 12, 2023 13:22
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save CMCDragonkai/4e9464d9f32f5893d837f3de2c43daa4 to your computer and use it in GitHub Desktop.
Save CMCDragonkai/4e9464d9f32f5893d837f3de2c43daa4 to your computer and use it in GitHub Desktop.
Matplotlib Backends #matplotlib #python

Matplotlib Backends

Matplotlib is a plotting library. It relies on some backend to actually render the plots. The default backend is the agg backend. This backend only renders PNGs. On Jupyter notebooks the matplotlib backends are special as they are rendered to the browser. Generally you will not need to explicitly set the backend on a Jupyter notebook. This does introduce a discrepancy between code that runs in Jupyter and code that runs as a script natively in the Python interpreter. So you need to understand that the 2 environments are not the same and code that was written in Jupyter may not easily run inside the native Python interpreter.

To get backends that are interactive or integrate into your operating system GUI, you need to know what OS you're running and what kind of backends have been compiled into your matplotlib library. Different backends have different compatibility requirements, and some backends only work on Python 2 instead of Python 3.

There's no easy way to find out what backends are available to be used, instead you can only really find out either by trial and error, or if you have access to the compilation logs. (If you compiled it yourself, you should know).

However you can find out what backend the matplotlib library is currently set to and you can find out the string keys that point to different backends.

This will show you what the default backend of matplotlib has been set to. If you don't have any confounding environment variables nor a matplotlibrc file, then this should give back the string agg.

import matplotlib.pyplot as plt

print(plt.get_backend())

You can find out the current matplotlibrc file by doing:

import matplotlib as mpl

print(mpl.matplotlib_fname())

If you don't have a matplotlibrc file, it will show the default sample file.

The list of backend string keys can be acquired with:

import matplotlib.rcsetup as rcsetup

print(rcsetup.interactive_bk)
print(rcsetup.non_interactive_bk)
print(rcsetup.all_backends)

Once you know which backend you want to use. In my case, I have the Qt4Agg compiled into my matplotlib. (it was provided via matplotlib.override { enableQt = true; } in shell.nix). I can then try to switch to it. These are the ways to do this:

The first is to use it just before importing pyplot.

import matplotlib as mpl
mpl.use('Qt4Agg')
import matplotlib.pyplot as plt

plt.plot(range(20), range(20))
plt.show()

The second is to use an experimental function that allows you to switch backends, however this only works when switching from non-interactive to interactive and vice versa, not between interactive backends.

import matplotlib.pyplot as plt

plt.switch_backend('Qt4Agg')
plt.plot(range(20), range(20))
plt.show()

The third way to do this is to create a matplotlibrc file which contains:

backend: Qt4Agg

However this is not preferred, as it's better to be explicit in the code that uses the matplotlib library, and multiple projects may need to use different backends.

The fourth and best way is to use an environment variable:

MPLBACKEND=Qt4Agg python -c 'import matplotlib.pyplot as plt; print(plt.get_backend())'

This is because you may be working on multiple computers on the same codebase, then these computers may all support different backends. It is up to executor to tell matplotlib what backend use. You can easily script this into your development environment. When doing it this way, it is perfectly fine to use plt.switch_backend for switching to non-interactive backends to render plots onto disk. The only backend you're guaranteed to have is agg. You'll have to test any other backends.

If you are stuck on the agg backend, you cannot use plt.show(), however you can use plt.savefig:

import matplotlib.pyplot as plt

plt.plot(range(20), range(20))
plt.savefig('linear.png')

Remember the behaviour of not having the right backend is undefined. Sometimes it is a silent failure, other times you'll get something else break.

@agirman
Copy link

agirman commented May 22, 2019

When I use

matplotlib.use('Qt5Agg')
from matplotlib import pyplot as plt
THE CODE BODY
plt.show()

I always get the error

C:/Users/user/models/research/object_detection/object_detection_tutorial.py:162: UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.

It seems I got stuck on the agg backend. As you pointed, plt.savefig works.

However I still want to find a way to make plt.show() work and ready to get your suggestion.

@CMCDragonkai
Copy link
Author

Currently on NixOS, the default backend is now TkAgg so you don't need to override matplotlib anymore.

However this can still cause problems. So when using matplotlib non-interactively you can switch to it within a context.

import io
import numpy as np
import matplotlib.pyplot as plt

arr = np.array([1,2,3,4])

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(arr)
plt.show()
plt.close(fig)

backend_orig = plt.get_backend()
plt.switch_backend("agg")

buf = io.BytesIO()
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(arr)
plt.savefig(buf, format="png")
plt.close(fig)

plt.switch_backend(backend_orig)

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(arr)
plt.show()
plt.close(fig)

@tacaswell
Copy link

The default backend is the agg backend.

This is not quite true. Downstream packagers can set a default backend as part of their build process so the default will vary from system to system. Additional, the default the library now ships with is "find the best one" which will detect if you are headless (and go to Agg) and if not go through the GUI bindings until it finds one that imports.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment