Backend switching#9795
Conversation
4fae022 to
33aa68c
Compare
|
This looks really cool. But, I'm on MacOS so its not working for me yet. If I do import matplotlib
print(matplotlib.get_backend())
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
plt.scatter([1, 2], [0,2])
print(matplotlib.get_backend())
plt.show()I get a Qt5Agg GUI and If I do import matplotlib
print(matplotlib.get_backend())
import matplotlib.pyplot as plt
matplotlib.use('Qt5Agg')
plt.scatter([1, 2], [0,2])
print(matplotlib.get_backend())
plt.show()I get: but, I get the macOS GUI (Toolbar on the bottom instead of top, and I can close with command-w). So either I am not understanding how to test this or MacOS needs work. Happy to help make this work on MacOS... |
|
That's because I forgot to actually update the backend when doing Right now what needs to be done for OSX is a way to detect whether the OSX event loop is already running (see _get_current_event_loop for examples), so that having an OSX event loop running prevents starting another event loop. |
|
Confirmed, the snippet above now works as advertized! |
|
BTW, looking at event-loops and such would be a longer term project for me if I were to help. @dopplershift would probably be much better suited. |
9ff786e to
c689eac
Compare
c689eac to
307c1ec
Compare
307c1ec to
6725bf4
Compare
8a08283 to
c745e17
Compare
f865c09 to
1083c3c
Compare
|
I just tried on your machine and it worked for me... Can you check what's happening at INFO log level, especially during the call to matplotlib.backends.pylab_setup? |
|
@anntzer is this still active? Sorry if I was supposed to get back to you on some of it - looks like it'll be an ugly rebase, but they are probably all your changes anyways 😉 |
|
I'll probably wait until the rest of the mpl3 transition settles down a bit before revisiting this. |
|
Some version of this should go in for 3.0 to make life easier for conda-forge. |
|
Frankly, I wouldn't say no to some progress on merging my 61 other currently open PRs rather than seeing them bitrot one after another like this one. |
This is the followup to #9551 (backend loading refactor), and includes it (so it would make sense for #9551 to be merged first).
This PR removes the ambiguous behavior of
matplotlib.use, which was, up to now, documented as follows:Instead, matplotlib.use now works just fine as long as an event loop has not started yet (i.e. an interactive window popped up), or when switching to a noninteractive backend, or to an interactive backend compatible with the current event loop (e.g. gtk3agg -> gtk3cairo); in all other cases, an exception is raised. This means, for example, that one can write
from matplotlib import pyplot as plt; plt.rcParams["backend"] = "foo"; ...instead of having to do a separate import of matplotlib.Moreover, it is now possible to set rcParams["backend"] to a list of candidate backends; they will simply be tested one at a time until one succeeds. If pyplot is already loaded, the value in rcParams["backend"] is immediately replaced by the successful candidate. If pyplot is not loaded yet, rcParams["backend"] will keep hold of the list of candidates until pyplot is loaded. This is a documented change of behavior (users should import pyplot to force backend resolution). (Alternatively the list could be shoved into a new, separate rcParam, but little would be gained because rcParams["backend"] would then hold an incorrect value until backend resolution). Another change of behavior is that the matplotlib.backends.backend global variable has been removed, again in favor of rcParams["backend"] as single truth point: it was too difficult to properly keep matplotlib.backends.backend in sync, especially at import time when that module may not have been imported yet.
(Exception: I don't have a Mac available to figure out the relevant fixes for the OSX backend, but hopefully another contributor can help here. See _get_current_event_loop.)
Edit: Now also working on OSX, see comment below.
A major advantage of such a scheme is that we can now just ship a default matplotlibrc which lists all buitin backends in preference order (
backend: osx, qt5agg, qt4agg, gtk3agg, ...). Currently, this list is evaluated at build time (by testing which GUI toolkit is importable), which causes two major problems: 1) the import of the GUI toolkits need to happen in separate processes, which means that setup.py relies on multiprocessing(!); for example, this appears to confuse conda-build (see comment in ci/conda_recipe/meta.yaml); 2) the built list is useless anyways unless 1) the end user is doing the build, rather than a central packager (the end user may have a different list of installed GUI toolkits...) and 2) the end user never adds or removes a new GUI toolkit. Here, I can instead completely strip out the relevant part of setupext.py, greatly simplifying it.The backend_fallback rcParam likewise becomes obsolete, although this PR does not remove it (this rcParam can easily go through a normal deprecation route).
I also removed the interactive backends API docs because the shimming (to allow them to be imported in a headless buildbot) was insufficient to support this PR's implementation. Proposed fix at #9708 (comment). (But note that they were incomplete anyways...)
Closes #3679, #6739, #8613, #9017 (comment); sort-of #3466 (which is perhaps more a doc issue...).
Some comments to try clarifying the implementation:
use(...); rcdefaults()working: this implies thatuse(...)must overwrite the default backend (in rcParamsDefault, and likewise rcParamsOrig), to a single fixed value.