# if pyplot is not already imported, do not import it. Doing
They say that simply
from matplotlib import pyplot
can trigger setting the default backend.
This is somewhat frustrating for people who use interactive sessions.
Running the code
from matplotlib import pyplot
import matplotlib
matplotlib.use("WxAgg")
all at once will work in ipython (from the terminal). But running it one line at a time, won't.
This is somewhat strange.
Now that things like __getattr__ exist, would be possible to further delay setting the default backend?
The issue arises when you want to build an application, and other people's code might be imported before yours. You are then at their mercy to not set the backend (implicitly!) before you set yours.
Proposed solution
No solution. I'm sure there is some strange historic thing I'm missing.
Honestly, you created a great API with pyplot. People use it to get colormaps, and for all sorts of things.
The fact that pyplot triggers the backend creation is documented, and so is
the fact that this causes side-effects.
EDIT: At least, we used to extensively document this... I was about to post
a bunch of links from the docs talking about this, but now I can't find the
relevant information. The best I can get is
https://matplotlib.org/stable/users/explain/interactive.html
That being said, work is ongoing to defer the backend initialization to
later points in the figure lifetime. Perhaps you can help with that effort?
On Wed, Mar 30, 2022 at 11:29 PM Mark Harfouche ***@***.***> wrote:
Problem
It seems that simply importing pyplot can have serious effects on what
backends are chosen, and how they interact with one and other.
In
https://github.com/matplotlib/matplotlib/blob/da9533d507c1f06ceee5078c9cbbd99897809d31/lib/matplotlib/__init__.py#L1137
They say that simply
from matplotlib import pyplot
can trigger setting the default backend.
This is somewhat frustrating for people who use interactive sessions.
Running the code
from matplotlib import pyplot
import matplotlib
matplotlib.use("WxAgg")
all at once will work in ipython (from the terminal). But running it one
line at a time, won't.
This is somewhat strange.
Now that things like __getattr__ exist, would be possible to further
delay setting the default backend?
The issue arises when you want to build an application, and other people's
code might be imported before yours. You are then at their mercy to not set
the backend (implicitly!) before you set yours.
Proposed solution
No solution. I'm sure there is some strange historic thing I'm missing.
Honestly, you created a great API with pyplot. People use it to get
colormaps, and for all sorts of things.
XREF: DeepLabCut/DeepLabCut#1730
<DeepLabCut/DeepLabCut#1730>
—
Reply to this email directly, view it on GitHub
<#22739>, or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACHF6CHT52IKVM6YRCD2RTVCULZXANCNFSM5SD7ZBWA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
ok, understood. I didn't know if patches would be welcome that would defer that.
Is there an API that application developers can use that is independent of the chosen backend? That is, they would specify their own handles/backend name and matplotlib will forcibly use that?
General question: Is there a reason that we need global exclusive backend state and cannot have a per-figure backend setting?
I don't know - is it really worth the trouble to allow multiple GUI backends to run at the same time? I could see us allowing one GUI to be closed and a different one opened after the GUI is closed, but I'm not sure its a good idea for one python process to have multiple GUI frameworks running at the same time?
Is there a reason that we need global exclusive backend state and cannot have a per-figure backend setting?
You cannot have e.g. both qt and tk running as they'll fight over https://docs.python.org/3/c-api/veryhigh.html#c.PyOS_InputHook. You could allow e.g. qtcairo + qtagg or any interactive backend + any noninteractive backend, but I'm not sure it's worth the engineering...
# if pyplot is not already imported, do not import it. Doing
# so may trigger a `plt.switch_backend` to the _default_ backend
# before we get a chance to change to the one the user just requested
plt=sys.modules.get('matplotlib.pyplot')
# if pyplot is imported, then try to change backends
ifpltisnotNone:
try:
# we need this import check here to re-raise if the
# user does not have the libraries to support their
# chosen backend installed.
plt.switch_backend(name)
exceptImportError:
ifforce:
raise
# if we have not imported pyplot, then we can set the rcParam
# value which will be respected when the user finally imports
# pyplot
else:
rcParams['backend'] =backend
This code is saying "if the user explicitly called mpl.use(...) then make sure right now that is something we can actually do. That comment needs to be adjusted now that #22005 is merged.
I am morbidly curious why it was going wrong before but I do think it is fixed.
I'm not entirely sure. It is kinda hard to compile matplotlib and backporting the patch wasn't super easy.
Where are you trying to backport it to?
If you can compile skimage, I would also expect Matplotlib to compile "out of the box" as well...
Is there an API that application developers can use that is independent of the chosen backend? That is, they would specify their own handles/backend name and matplotlib will forcibly use that?
You might be interested in my book, "Interactive Applications using Matplotlib". It is a little out of date now (published almost 7 years ago!), but many of the principles are still true. In it, it describes how to embed a figure as a widget in an existing GUI application. It also shows how to embed GUI widgets into a regular matplotlib figure window.
Furthermore, it also talks about some of the GUI-agnostic widgets that are available so that you can have an application that'll work in just about any interactive environment.
$ ipython
Python 3.9.9 (main, Dec 29 2021, 07:47:36)
Type 'copyright', 'credits' or 'license' for more information
IPython 8.1.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from matplotlib import pyplot
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
Input In [1], in <cell line: 1>()
----> 1 from matplotlib import pyplot
File ~/git/matplotlib/lib/matplotlib/__init__.py:208, in <module>
203 if parse_version(module.__version__) < parse_version(minver):
204 raise ImportError(f"Matplotlib requires {modname}>={minver}; "
205 f"you have {module.__version__}")
--> 208 _check_versions()
211 # The decorator ensures this always returns the same handler (and it is only
212 # attached once).
213 @functools.lru_cache()
214 def _ensure_handler():
File ~/git/matplotlib/lib/matplotlib/__init__.py:193, in _check_versions()
189 def _check_versions():
190
191 # Quickfix to ensure Microsoft Visual C++ redistributable
192 # DLLs are loaded before importing kiwisolver
--> 193 from . import ft2font
195 for modname, minver in [
196 ("cycler", "0.10"),
197 ("dateutil", "2.7"),
(...)
200 ("pyparsing", "2.2.1"),
201 ]:
202 module = importlib.import_module(modname)
ImportError: /home/mark/git/matplotlib/lib/matplotlib/ft2font.cpython-39-x86_64-linux-gnu.so: undefined symbol: FT_Load_Glyph
Kinda just as hard as I expected it to be (i.e. not to work on the first try).
The link provided on anaconda installed successfully.
Finally, it does resolve the problem of allowing you to select the WxAgg backend.
I then uninstalled it, and reinstalled the version from conda-forge, and it seems to work!
Oh, that makes sense 😞 . We build our own freetype pinned to a very old version (so the tests will pass because every version of freetype moves the text around a tiny bit) but conda provides a newer one. I suspect at runtime you ended up with crossed libraries....
I will not claim to understand what the wheel is doing under the hood to make it work though!
Activity
WeatherGod commented on Mar 31, 2022
hmaarrfk commented on Mar 31, 2022
ok, understood. I didn't know if patches would be welcome that would defer that.
Is there an API that application developers can use that is independent of the chosen backend? That is, they would specify their own handles/backend name and matplotlib will forcibly use that?
timhoffm commented on Mar 31, 2022
Deferring backed selection has been implemented in #22005, but is not yet released.
I'm not the backend expert here, but I'm not aware of a reasonably simple way to do this.
General question: Is there a reason that we need global exclusive backend state and cannot have a per-figure backend setting?
jklymak commented on Mar 31, 2022
I don't know - is it really worth the trouble to allow multiple GUI backends to run at the same time? I could see us allowing one GUI to be closed and a different one opened after the GUI is closed, but I'm not sure its a good idea for one python process to have multiple GUI frameworks running at the same time?
We probably should revisit the roadmap for https://github.com/matplotlib/mpl-gui
hmaarrfk commented on Mar 31, 2022
Well... I feel like it might be address in the next release.
#22005
hmaarrfk commented on Mar 31, 2022
Can't wait!
timhoffm commented on Mar 31, 2022
@hmaarrfk does #22005 address your needs? If so we can close this issue.
hmaarrfk commented on Mar 31, 2022
I'm not entirely sure. It is kinda hard to compile matplotlib and backporting the patch wasn't super easy.
There still seems to be eager code in:
https://github.com/matplotlib/matplotlib/blob/main/lib/matplotlib/pyplot.py#L2246
so i really wnat to have the time to test before saying it is fixed.
hmaarrfk commented on Mar 31, 2022
The comment I referred to in the init file seems suspicious now too.
anntzer commented on Mar 31, 2022
You cannot have e.g. both qt and tk running as they'll fight over https://docs.python.org/3/c-api/veryhigh.html#c.PyOS_InputHook. You could allow e.g. qtcairo + qtagg or any interactive backend + any noninteractive backend, but I'm not sure it's worth the engineering...
timhoffm commented on Mar 31, 2022
I can if I have different processes 😝
tacaswell commented on Mar 31, 2022
matplotlib/lib/matplotlib/pyplot.py
Lines 2246 to 2250 in d8ede1a
says:
then set the backend to "automatic" and let the later machinery sort out detecting which one is running and doing the correct selection then.
tacaswell commented on Mar 31, 2022
matplotlib/lib/matplotlib/__init__.py
Lines 1137 to 1155 in da9533d
This code is saying "if the user explicitly called mpl.use(...) then make sure right now that is something we can actually do. That comment needs to be adjusted now that #22005 is merged.
I am morbidly curious why it was going wrong before but I do think it is fixed.
Where are you trying to backport it to?
If you can compile skimage, I would also expect Matplotlib to compile "out of the box" as well...
tacaswell commented on Apr 1, 2022
And thank to #22733 which just got merged
will now get you nightlies!
ianhi commented on Apr 1, 2022
Slight correction to that install command. To get everything to work properly with dependencies you need to run:
hmaarrfk commented on Apr 1, 2022
Touchée .
I guess I'm using conda for most environment management.
It becomes a pain to remove matplotlib-core and replace it with matplotlib
I'll give it a try in a few hours.
WeatherGod commented on Apr 1, 2022
You might be interested in my book, "Interactive Applications using Matplotlib". It is a little out of date now (published almost 7 years ago!), but many of the principles are still true. In it, it describes how to embed a figure as a widget in an existing GUI application. It also shows how to embed GUI widgets into a regular matplotlib figure window.
Furthermore, it also talks about some of the GUI-agnostic widgets that are available so that you can have an application that'll work in just about any interactive environment.
hmaarrfk commented on Apr 1, 2022
I'm not going to say I can't get it to compile from source, but I am going to say that for my conda environment, I tried:
and it resulted in:
$ ipython Python 3.9.9 (main, Dec 29 2021, 07:47:36) Type 'copyright', 'credits' or 'license' for more information IPython 8.1.1 -- An enhanced Interactive Python. Type '?' for help. In [1]: from matplotlib import pyplot --------------------------------------------------------------------------- ImportError Traceback (most recent call last) Input In [1], in <cell line: 1>() ----> 1 from matplotlib import pyplot File ~/git/matplotlib/lib/matplotlib/__init__.py:208, in <module> 203 if parse_version(module.__version__) < parse_version(minver): 204 raise ImportError(f"Matplotlib requires {modname}>={minver}; " 205 f"you have {module.__version__}") --> 208 _check_versions() 211 # The decorator ensures this always returns the same handler (and it is only 212 # attached once). 213 @functools.lru_cache() 214 def _ensure_handler(): File ~/git/matplotlib/lib/matplotlib/__init__.py:193, in _check_versions() 189 def _check_versions(): 190 191 # Quickfix to ensure Microsoft Visual C++ redistributable 192 # DLLs are loaded before importing kiwisolver --> 193 from . import ft2font 195 for modname, minver in [ 196 ("cycler", "0.10"), 197 ("dateutil", "2.7"), (...) 200 ("pyparsing", "2.2.1"), 201 ]: 202 module = importlib.import_module(modname) ImportError: /home/mark/git/matplotlib/lib/matplotlib/ft2font.cpython-39-x86_64-linux-gnu.so: undefined symbol: FT_Load_GlyphKinda just as hard as I expected it to be (i.e. not to work on the first try).
The link provided on anaconda installed successfully.
Finally, it does resolve the problem of allowing you to select the WxAgg backend.
I then uninstalled it, and reinstalled the version from conda-forge, and it seems to work!
Thanks all!
tacaswell commented on Apr 1, 2022
Oh, that makes sense 😞 . We build our own freetype pinned to a very old version (so the tests will pass because every version of freetype moves the text around a tiny bit) but conda provides a newer one. I suspect at runtime you ended up with crossed libraries....
I will not claim to understand what the wheel is doing under the hood to make it work though!
hmaarrfk commented on Apr 1, 2022
@tacaswell thank you for the hint about freetype. using a slightly modified build script from conda-forge
https://github.com/conda-forge/matplotlib-feedstock/blob/main/recipe/build_base.sh
it does indeed import.
Time for me to sleep. Goodnight