Skip to content

Cairo in 2.2.0 not working for new backends #10763

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

Closed
2sn opened this issue Mar 12, 2018 · 27 comments · Fixed by #12637
Closed

Cairo in 2.2.0 not working for new backends #10763

2sn opened this issue Mar 12, 2018 · 27 comments · Fixed by #12637

Comments

@2sn
Copy link

2sn commented Mar 12, 2018

Bug report

The new Cairo backends do not produce plots

I tried the new Cairo backends, Qt4Cairo, Qt5Cairo, WXCairo, and TkCairo, but neither of them produced plots for me. (Fedora 27, compiled own python 3.6.4 from source, all extra packages installed from pip3).

Code for reproduction

matplotlibrc:

backend      : TkCairo
# all other lines commented out

code:

from matplotlib.pylab import *
plot([0,1])
show()

Actual outcome

Qt4Cairo, Qt5Cairo - frame but no plot, frame not updated
WXCairo, TkCairo - no frame

Just to be sure, GTK3Cairo makes a frame with a plot, all working fine.
Same for Qt5Agg, WXAgg, TkAgg all work as well

Qt4Agg is broken ("ModuleNotFoundError: No module named 'PyQt4'", there seems to be no such module on pip)

So it seems neither Cairo, WX, Tk, QT5 are broken by themselves, but the integration does not work smoothly, at least in my setup. I have no clue how to debug this.

Expected outcome

A plot.

Matplotlib version

  • Operating system: Fedora 27
  • Matplotlib version: 2.2.0
  • Matplotlib backend (see above)
  • Python version: 3.6.4
  • IPython: 6.2.1

python compiled from source, packages (current) from pip3

@QuLogic
Copy link
Member

QuLogic commented Mar 12, 2018

These all work fine for me, on Fedora 27 with matplotlib installed from the wheel and system Python.

Why are you building Python from source? Fedora 27 has 3.6.4 already.

@2sn
Copy link
Author

2sn commented Mar 14, 2018

Well, there is a new Fedora every other 6 months and until this release, the Python did tend not to be up to date. This way I can have system as closely as possible to the standard and install current packages from pip w/o affecting the system scripts.

@tacaswell
Copy link
Member

Qt4Agg is broken ("ModuleNotFoundError: No module named 'PyQt4'", there seems to be no such module on pip) <- this one is you do not have the right qt bindings installed.

So it seems neither Cairo, WX, Tk, QT5 are broken by themselves, but the integration does not work smoothly, at least in my setup. I have no clue how to debug this.

For historical reasons we have a mix of things we call 'backends'. There are a number of 'non-interactive' backend (Agg, Cairo, pdf, eps), a number of GUI specific base classes that deal with exposing what we need from the GUI frame works (QT5, QT4, Wx, Tk, Gtk) but don't make any contact with Matplotlib. These are then sub-classed into the 'interactive' backends and are matched up with one of the non-interactive backends (ex Qt5Agg) to give you a fully functioning GUI window. Previously we also had some backends with directly used the GUIs rendering (but they were extremely hard to maintain and were the source of a lot of inconsistencies).

@anntzer
Copy link
Contributor

anntzer commented Mar 18, 2018

I cannot reproduce the issue and have no idea where it could come from :/
I'm going to need a bit more info (print debugging?) to figure out at least what gets run and what doesn't...

@2sn
Copy link
Author

2sn commented Mar 23, 2018

My apologies. If you can let me know what extra info I can provide and how I will try that.

@anntzer
Copy link
Contributor

anntzer commented Mar 23, 2018

Do you have the same issue outside of IPython? (e.g., running a script file)

What happens with

import tkinter
from matplotlib.backends.backend_tkcairo import new_figure_manager, show

man = new_figure_manager(1)
man.canvas.figure.subplots()
man.show()
tkinter.mainloop()

?
(again, from a script, not IPython)

@2sn
Copy link
Author

2sn commented Mar 29, 2018

If I paste that script into IPython or python (with backend set to tkagg in matplotlibrc, though) it actually produces a plot, only if I change the backend in the matplotlibrc file and then try to make a plot with defaults the problems arise.

@2sn
Copy link
Author

2sn commented Mar 29, 2018

OK, if I run this just in python3

>>> from matplotlib.pylab import *
>>> plot([0,1])
>>> show()

the window does show up even if backend in matplotlibrc is set to TkCairo. (though I am not sure what it actually uses in that case ...

@anntzer
Copy link
Contributor

anntzer commented Mar 29, 2018

You can try to reproduce the bugs at #8798 (which only occur with the cairo backends), or print type(gcf().canvas).

@anntzer
Copy link
Contributor

anntzer commented May 19, 2018

Closing for lack of activity/reproducibility, but feel free to request a reopen with more information.

@anntzer anntzer closed this as completed May 19, 2018
@2sn
Copy link
Author

2sn commented May 20, 2018

GTK3Cairo now runs and produces plots

but TKCairo still does not produce plots

In [1]: plot([0,1])
Out[1]: [<matplotlib.lines.Line2D at 0x7f5a7b2ad198>]

(no plot or window)

In [2]: type(gcf().canvas)
Out[2]: matplotlib.backends.backend_tkcairo.FigureCanvasTkCairo

same for WXCairo

In [2]: type(gcf().canvas)
Out[2]: matplotlib.backends.backend_wxcairo.FigureCanvasWxCairo

and QT5Cairo produces only an empty window

In [2]: type(gcf().canvas)
Out[2]: matplotlib.backends.backend_qt5cairo.FigureCanvasQTCairo

This is particularly unfortunate as tk and wx are the default graphical interface libraries that ship with the python standard library. Ideally, these should work(!).

For #8798

from pylab import *
rcdefaults()
fig, axs = plt.subplots(1, 2)
axs[0].imshow(np.arange(4).reshape((2, 2)))
axs[1].imshow(np.arange(4).reshape((2, 2)), alpha=.5)
show()

I also get the second figure.

@anntzer anntzer reopened this May 20, 2018
@jenshnielsen
Copy link
Member

Both WXCairo, QT5Cairo and TKCairo works out of the box for me on Windows

I.e I get a plot out of and similar

>>> import matplotlib
>>> matplotlib.use('TkCairo')
>>> import matplotlib.pyplot as plt
>>> plt.plot(range(10))
[<matplotlib.lines.Line2D object at 0x0000027308C50358>]
>>> plt.show()
>>>

@2sn
Copy link
Author

2sn commented May 21, 2018

As before, I installed python from scratch on Fedora 28, including all system packages needed to compile the full standard library, then installed matplotlib and the backends from pip.

@jenshnielsen
Copy link
Member

Yes I am aware, this seems to be specific to your install/system

@2sn
Copy link
Author

2sn commented May 21, 2018

Even with GTK3Cairo I get an error message that does not make as much sense as it refers to Agg (see below). The figure was created using pyplot.figure().

--> 292         fig.show()

~/Python/lib/python3.6/site-packages/matplotlib/figure.py in show(self, warn)
    446                                  "Figure.show works only "
    447                                  "for figures managed by pyplot, normally "
--> 448                                  "created by pyplot.figure()." % err)
    449 
    450         if manager is not None:

AttributeError: 'FigureCanvasAgg' object has no attribute 'manager'
Figure.show works only for figures managed by pyplot, normally created by pyplot.figure().

@2sn
Copy link
Author

2sn commented May 21, 2018

This was a fresh install (Fedora 28, re-installed from scratch) relative to when I started the thread (Fedora 27).

@anntzer
Copy link
Contributor

anntzer commented May 21, 2018

What's the status outside of IPython (plain python), no (delete your) matplotlibrc, just do import matplotlib; matplotlib.use('XXXcairo'); from matplotlib import pyplot as plt; plt.plot(); plt.show()?

@2sn
Copy link
Author

2sn commented May 21, 2018

These seem to mostly work for all xxx. Except for gtk3 and wx the interactive mode plt.show(block=False) does not seem to work.

Is the issue with the matplotlibrc file or IPython?

OK, I restored the matplotlibrc and this still works

Python 3.6.5 (default, May 13 2018, 09:52:28) 
[GCC 8.1.1 20180502 (Red Hat 8.1.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib
>>> from matplotlib import pyplot as plt
>>> plt.plot([0,1])
[<matplotlib.lines.Line2D object at 0x7efdd61d47f0>]
>>> plt.show(block=False)
>>> type(plt.gcf().canvas)
<class 'matplotlib.backends.backend_tkcairo.FigureCanvasTkCairo'>

So the issue seems to be IPython? (still should look at interactive mode issue for gtk3 and wx). But much better. Just to be sure, I tried the same but with my ipython_config.py disabled; this does not fix it.

@2sn
Copy link
Author

2sn commented May 21, 2018

Some ore test with tkcairo. The issue seems to be that the interactive mode does not work with IPython. If I do a pause (plt.pause(0.01)) a plot may appear, even with plt.ion() this seems needed. But while the shell is interactive, plot is not (responsive).

@anntzer
Copy link
Contributor

anntzer commented May 21, 2018

Perhaps (disabling whatever you have in ipython_config.py) ipython --matplotlib=tk/--matplotlib=auto?

@2sn
Copy link
Author

2sn commented May 21, 2018

No, disabling ipython_config.py did not make a difference.

@nedclimaterisk
Copy link

I think I'm seeing pretty similar behaviour with Qt5Cairo from conda-forge:

image

@nedclimaterisk
Copy link

Also happens with QT4Cairo, and with cairocffi OR pycairo installed.

@anntzer
Copy link
Contributor

anntzer commented Oct 19, 2018

Actually, I can now repro this on a clean install (not clear what changed though), and I know where the problem is: it's IPython.core.pylabtools's backend2gui dict which contains no entries for qt{4,5}cairo (and I guess likewise for the other cairo-based backends.
Applying

diff --git i/IPython/core/pylabtools.py w/IPython/core/pylabtools.py
index 4423ed5d4..fe05e90d3 100644
--- i/IPython/core/pylabtools.py
+++ w/IPython/core/pylabtools.py
@@ -37,6 +37,8 @@
 backend2gui = dict(zip(backends.values(), backends.keys()))
 # Our tests expect backend2gui to just return 'qt'
 backend2gui['Qt4Agg'] = 'qt'
+backend2gui['Qt5Cairo'] = 'qt'
+backend2gui['Qt4Cairo'] = 'qt'
 # In the reverse mapping, there are a few extra valid matplotlib backends that
 # map to the same GUI support
 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'

against IPython master appears to fix the issue; however the better fix is likely for IPython to read the required_interactive_framework attribute that has been added to backends as of 3.0 (as that's much more robust to future changes and also works for third-party backends). In the meantime, I guess we could patch that dict ourselves; in fact that's already what I do in mplcairo: https://github.com/anntzer/mplcairo/blob/master/lib/mplcairo/base.py#L167...

@tacaswell @Carreau any preference on either solution?

@nedclimaterisk
Copy link

Yep, that makes interactive plotting work for me, however, the plots look pretty crap, which makes me thing it's still using Agg, somehow?

image

@anntzer
Copy link
Contributor

anntzer commented Oct 19, 2018

What does plt.gcf().canvas print for you?

@nedclimaterisk
Copy link

<matplotlib.backends.backend_qt5cairo.FigureCanvasQTCairo at 0x7f4e2bfc2c18>

guess it's right then. I'll try again with cffi

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

Successfully merging a pull request may close this issue.

6 participants