From e7bab33eca2b2f69158fa4aa31aab7a8b102aadf Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 21 Aug 2020 19:44:30 +0200 Subject: [PATCH] Safely import pyplot if a GUI framework is already running. `configure_subplots` now needs to import `pyplot` (because that's how we can spin up a new figure as needed), but when relying on embedding we could well reach that point with an already running interactive framework, pyplot never imported, and an incompatible rcParams["backend"] (which had not been read yet). For example, run `examples/user_interfaces/embedding_in_tk_sgskip.py` with a non-tk backend set in your matplotlibrc: clicking on the the configure_subplots button triggers a "cannot load backend 'foo' which requires the 'foo' interactive framework, as 'bar' is currently running". Instead, use a helper to safely import pyplot when another interactive framework may already be running. The list of frameworks that `_get_running_interactive_framework` returns is fixed, so we can just hardcode the mapping. (We are going to ignore the user-set `rcParams["backend"]` anyways.) --- lib/matplotlib/backend_bases.py | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 5c3d9097162b..fe8cc66913cc 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -85,6 +85,30 @@ } +def _safe_pyplot_import(): + """ + Import and return ``pyplot``, correctly setting the backend if one is + already forced. + """ + try: + import matplotlib.pyplot as plt + except ImportError: # Likely due to a framework mismatch. + current_framework = cbook._get_running_interactive_framework() + if current_framework is None: + raise # No, something else went wrong, likely with the install... + backend_mapping = {'qt5': 'qt5agg', + 'qt4': 'qt4agg', + 'gtk3': 'gtk3agg', + 'wx': 'wxagg', + 'tk': 'tkagg', + 'macosx': 'macosx', + 'headless': 'agg'} + backend = backend_mapping[current_framework] + rcParams["backend"] = mpl.rcParamsOrig["backend"] = backend + import matplotlib.pyplot as plt # Now this should succeed. + return plt + + def register_backend(format, backend, description=None): """ Register a backend for saving to a given file format. @@ -3269,7 +3293,7 @@ def _update_view(self): self.canvas.draw_idle() def configure_subplots(self, *args): - from matplotlib import pyplot as plt + plt = _safe_pyplot_import() tool = plt.subplot_tool(self.canvas.figure) tool.figure.canvas.manager.show()