Skip to content

In headless mode, matplotlib.use('tkagg') only errors after importing pyplot #13883

Closed
@shoyer

Description

@shoyer

Bug report

Bug summary

Calling matplotlib.use('tkagg') doesn't work in headless mode. That's fine and to be expected.

What is bizarre is that this only results in an error when this is called after matplotlib.pyplot is imported. This results in a surprising and challenge to debug situation if matplotlib.use('tkagg') is called multiple times (e.g., in separate files).

Code for reproduction

Here's a script that I'm running with matplotlib 3.0.2:

import os

# pretend to be in "headless" mode
os.environ.pop("DISPLAY", None)

# first module
import matplotlib
matplotlib.use('TkAgg')  # silently fails?
import matplotlib.pyplot

# in another imported module
import matplotlib
matplotlib.use('TkAgg')  # this is when matplotlib crashes!
import matplotlib.pyplot

Actual outcome

Traceback (most recent call last):
  File "/usr/local/google/home/shoyer/Downloads/use_tkagg_test.py", line 13, in <module>
    matplotlib.use('TkAgg')  # this is when matplotlib crashes!
  File "/usr/local/google/home/shoyer/miniconda3/envs/xarray-py37/lib/python3.7/site-packages/matplotlib/__init__.py", line 1391, in use
    switch_backend(name)
  File "/usr/local/google/home/shoyer/miniconda3/envs/xarray-py37/lib/python3.7/site-packages/matplotlib/pyplot.py", line 222, in switch_backend
    newbackend, required_framework, current_framework))
ImportError: Cannot load backend 'TkAgg' which requires the 'tk' interactive framework, as 'headless' is currently running

Expected outcome

It would be nice if matplotlib did any of these:

  1. Gave a clear error message when matplotlib.use() was called the first time.
  2. Gave a clear error message when matplotlib.pyplot is imported and an invalid backend is selected.
  3. Silently allowed setting an invalid backend with matplotlib.use() even after pyplot is imported.

Matplotlib version

  • Operating system:
  • Matplotlib version: 3.0.2
  • Matplotlib backend (print(matplotlib.get_backend())): NA
  • Python version: 3.7
  • Jupyter version (if applicable):
  • Other libraries:

As far as I can tell, the source of the problem is that matplotlib only actually validates backends if matplotlib.pyplot is imported:
https://github.com/matplotlib/matplotlib/blob/d9030efd40fe4300e775db22ba55845399f6668f/lib/matplotlib/__init__.py#L1281=L1283

It seems like one good way to avoid this would be to use a consistent codepath, whether or not matplotlib.pyplot has already been imported, e.g., by always calling matplotlib.pyplot.switch_backend(). Or maybe matplotlib.use() could do some basic validation, e.g., to verify that the backend is a valid choice.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions