Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matplotlib picks a headless backend on Linux if Wayland is available but X11 isn't #18377

Closed
mstoeckl opened this issue Aug 30, 2020 · 1 comment · Fixed by #17396
Closed
Milestone

Comments

@mstoeckl
Copy link

Bug report

Bug summary

I've been running code using Matplotlib on a Linux computer using a Wayland compositor with X11 disabled. The environment variable DISPLAY is thus not present, although WAYLAND_DISPLAY (or WAYLAND_SOCKET) are. Matplotlib falls back to a headless backend (agg), even though a working display system (Qt5Agg) is available.

Code for reproduction

Any simple code that uses plt.show() should exhibit this behavior.

import matplotlib.pyplot as plt
import matplotlib
print(matplotlib.get_backend())
plt.plot([1,2],[3,4])
plt.show()

Actual outcome

No window appears, code prints "agg".

Expected outcome

Expect a window with the plot to appear, code prints "Qt5Agg"

Matplotlib version

  • Operating system: Linux
  • Matplotlib version: 3.3.1
  • Python version: 3.8.5
  • Wayland compositor: tested with Sway, or Weston
  • Installed via package manager

Current workaround:

To ensure that a GUI backend is selected, instead of a headless one:

diff -r /usr/lib/python3.8/site-packages/matplotlib/cbook/__init__.py ./cbook/__init__.py
74c74
<     if sys.platform.startswith("linux") and not os.environ.get("DISPLAY"):
---
>     if sys.platform.startswith("linux") and not os.environ.get("DISPLAY") and not os.environ.get("WAYLAND_DISPLAY") and not os.environ.get("WAYLAND_SOCKET"):

Why do I check for WAYAND_DISPLAY or WAYLAND_SOCKET to be set, instead of removing this line? It turns out that if these are unset, libwayland (and thus toolkits using it) will by default try to connect to the display "wayland-0". This behavior is horrible when one uses computers with multiple sessions, graphical and not, running, because a script run from an ssh connection might (or might not) lock up and accidentally display something on a monitor in another building.

To ensure that the Qt5Agg backend loads, remove the extra check for DISPLAY's presence. (The code dates back to 9bed016 and 5c222df, where apparently trying and failing to open a Qt4 window was fatal; maybe newer Qt versions let us use the standard try-except approach?)

diff -r /usr/lib/python3.8/site-packages/matplotlib/backends/backend_qt5.py backend_qt5.py
105,120d104
<             # check for DISPLAY env variable on X11 build of Qt
<             if QtCore.qVersion() >= "5.":
<                 try:
<                     importlib.import_module(
<                         # i.e. PyQt5.QtX11Extras or PySide2.QtX11Extras.
<                         f"{QtWidgets.__package__}.QtX11Extras")
<                     is_x11_build = True
<                 except ImportError:
<                     is_x11_build = False
<             else:
<                 is_x11_build = hasattr(QtGui, "QX11Info")
<             if is_x11_build:
<                 display = os.environ.get('DISPLAY')
<                 if display is None or not re.search(r':\d', display):
<                     raise RuntimeError('Invalid DISPLAY variable')
< 
@anntzer
Copy link
Contributor

anntzer commented Aug 30, 2020

maybe newer Qt versions let us use the standard try-except approach

No, Qt5 still aborts with an uncatchable qFatal().

Perhaps you may want to comment on #17396 too? Edit: I think #17396 now closes this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants