| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Using mpl.use('Qt5Agg') works as expected on my hi-dpi mac for resizing and dragging the window around. Using mpl.use('Qt5Cairo') works as expected on my hi-dpi mac, except redraws are quite slow, so moving or resizing are quite laggy compared to Qt5Agg. I just used a randomish bit of test code that happened to have a small pcolor in it: import matplotlib as mpl
mpl.use('Qt5Cairo')
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
values = np.random.rand(290,20)
values[:26, :] = np.NaN
values[ [57, 239, 253], :] = np.nan
values = np.ma.masked_invalid(values)
h, w = values.shape
#h=262, w=20
fig, ax = plt.subplots(figsize=(9,7))
#fig, ax = plt.subplots()
y = np.arange(0, 290.5)
x = np.arange(0, 20.5)
pcm = ax.pcolormesh(x, y, values)
fig.colorbar(pcm)
plt.xticks(np.arange(w), list('PNIYLKCVFWABCDEFGHIJ'))
plt.show()EDIT: Bumping the 290x20 pcolor up to 290x290 made Qt5Cairo completely unusable; It took about 60 seconds to even finish the first render. Qt5Agg was fine. |
Sorry, something went wrong.
|
The current (pure-python) cairo backend implementation is not optimized for speed at all (and again, it is not the real point of this PR :-)). You can play with #8787 if you want to improve the performance a bit, but really the way to do this is to write it in C(++)... which I did :) |
Sorry, something went wrong.
|
Great! Just wanted you to know that it worked, but wasn't blazingly fast. and of course that you didn't seem to break Qt5Agg for me at least, including the DPI support. I'll spend a bit of time w/ the actual code to make sure I follow the changes and post a proper review soon. |
Sorry, something went wrong.
There was a problem hiding this comment.
This was fine on my machine. But I don't embed GUIs etc...
Sorry, something went wrong.
| surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) | ||
| self._renderer.set_ctx_from_surface(surface) | ||
| self._renderer.set_width_height(width, height) | ||
| self.figure.draw(self._renderer) |
There was a problem hiding this comment.
Doesn't this result in a double-draw (once from the canvas draw method and once from here)?
Sorry, something went wrong.
There was a problem hiding this comment.
Indeed, this implementation is slighlty inefficient, because it was essentially copied from the implementation in gtk3cairo, which can only do a meaningful draw at the time of paintEvent (on_draw_event, for gtk3) (as that passes in a native draw context).
Here, best (and implemented in mplcairo) would be to check whether the current renderer already has an internal canvas of the correct size, and, if so, to blit it directly. Keeping that on my todo.
Sorry, something went wrong.
|
I'm a little hesitant to merge this if @anntzer is busy in the next week and it breaks a lot of things.... |
Sorry, something went wrong.
|
I am comfortable enough with this part of the code to not be worried about this. |
Sorry, something went wrong.
|
Not sure if it's really an argument but you should in general feel free to revert my PRs if they break stuff and I don't have the bandwidth to take care of the breakage. |
Sorry, something went wrong.
There was a problem hiding this comment.
@tacaswell 's changes look good.
Sorry, something went wrong.
|
Thanks for helping me getting this in! 😃 |
Sorry, something went wrong.
|
The super(FigureCanvasAgg, self).draw() in FigureCanvasAgg breaks the current WxAgg backend implementation. It may break other things as well. The draw() method in FigureCanvasWxAgg calls FigureCanvasAgg.draw(). Replacing FigureCanvasAgg.draw(self) with self.figure.draw(self.get_renderer()) in backend_wxagg.FigureCanvasWxAgg.draw does fix things for me and seems the right thing anyway. I'm not sure about side effects, though. But if ever there was code to call FigureCanvasAgg.draw, then things would fail as super finds the wrong method. The inheritance for the wx backends: class FigureCanvasWxAgg(FigureCanvasAgg, FigureCanvasWx) class FigureCanvasWx(FigureCanvasBase, wx.Panel) class FigureCanvasAgg(FigureCanvasBase) Without multiple inheritance, would the super class of FigureCanvasAgg not be the FigureCanvasBase? So super usually would not find the GUI class, right? I'm not familiar with the other backends (and also not yet really with the wx ones). Would FigureCanvasAgg.draw() ever be called if the derived classes use figure.draw(renderer)? |
Sorry, something went wrong.
|
Can confirm the issue. In the meantime the following patch seems to work diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py
index 775107a08..85531d956 100644
--- a/lib/matplotlib/backends/backend_wx.py
+++ b/lib/matplotlib/backends/backend_wx.py
@@ -721,7 +721,9 @@ class FigureCanvasWx(FigureCanvasBase, wx.Panel):
previously defined renderer if none is specified.
"""
DEBUG_MSG("draw()", 1, self)
- self.renderer = RendererWx(self.bitmap, self.figure.dpi)
+ from .backend_wxagg import FigureCanvasWxAgg
+ if not isinstance(self, FigureCanvasWxAgg):
+ self.renderer = RendererWx(self.bitmap, self.figure.dpi)
self.figure.draw(self.renderer)
self._isDrawn = True
self.gui_repaint(drawDC=drawDC)
diff --git a/lib/matplotlib/backends/backend_wxagg.py b/lib/matplotlib/backends/backend_wxagg.py
index 8383f50cd..482002cbd 100644
--- a/lib/matplotlib/backends/backend_wxagg.py
+++ b/lib/matplotlib/backends/backend_wxagg.py
@@ -37,16 +37,11 @@ class FigureCanvasWxAgg(FigureCanvasAgg, FigureCanvasWx):
size.
"""
- def draw(self, drawDC=None):
- """
- Render the figure using agg.
- """
- DEBUG_MSG("draw()", 1, self)
- FigureCanvasAgg.draw(self)
-
+ def gui_repaint(self, drawDC=None, origin='WXAgg'):
self.bitmap = _convert_agg_to_wx_bitmap(self.get_renderer(), None)
self._isDrawn = True
- self.gui_repaint(drawDC=drawDC, origin='WXAgg')
+ super(FigureCanvasWxAgg, self).gui_repaint(
+ drawDC=drawDC, origin=origin)
def blit(self, bbox=None):
"""
Note that the slightly ugly instance check in FigureCanvasWx.draw can be removed once the Wx backend is likewise removed. PS: I think this warrants a release critical issue. @DietmarSchwertberger can you open it? |
Sorry, something went wrong.
|
Wouldn't it be better to implement a get_renderer() method for the FigureCanvasWx instead of using the instance check? This here is not exactly peformance-optimized, but should actually behave the same as before: class FigureCanvasWx:
def get_renderer(self):
self.renderer = RendererWx(self.bitmap, self.figure.dpi)
return self.renderer
def draw(self, drawDC=None):
self.figure.draw( self.get_renderer() )
self._isDrawn = True
self.gui_repaint(drawDC=drawDC)
Later this year, I would like give it a try whether the FigureCanvasWx code could be used to render to a MetaFileDC. Having direct WMF/EMF export again would be nice on Windows. As of now, for rendering to a bitmap and then pasting to the screen, I agree that it does not have an added value. |
Sorry, something went wrong.
|
Regarding my question from above whether FigureCanvasAgg.draw() would be called at all. I had a look at QTAgg. |
Sorry, something went wrong.
|
The draw chain seems like pretty-standard OO style. I think it helps make supporting multiple rasterization backends (Agg, cairo, native, ...) under each GUI framework easier. |
Sorry, something went wrong.
|
Regarding the first point: |
Sorry, something went wrong.
|
The RendererWx seems to call standard wx.DC Draw methods. So it should be possible to render to a MetaFileDC. The point is to get high quality vector graphics. I would not place bitmap images in e.g. datasheets for publication. So Bitmap or Pillow do not help here. (At the moment the only way is to convert SVG graphics, which is working better with the recent Inkscape releases.) |
Sorry, something went wrong.
|
(fwiw it may be ultimately possible to generate emf/wmf files with the cairo backend as well via https://cairographics.org/manual/cairo-Win32-Surfaces.html + https://msdn.microsoft.com/en-us/library/windows/desktop/ms535284(v=vs.85).aspx) (but that'll wait for mplcairo to be a bit more settled first...) |
Sorry, something went wrong.
|
We used to have a dedicated emf backend, but it broke and was removed in 2013 (#2026). I think there exists a third-party EMF backend, but google is failing me. |
Sorry, something went wrong.
|
I did use the EMF backend a long time ago and did even use it after removal, but it did not clip the lines IIRC. I did not find anything else at that time and so I switched to SVG->Inkscape->WMF... By default Cairo-Win32-Surfaces seem to be 'raster surface type', even though for printing there seems to be a vector surface. Given the availability of wx vs. Cairo binaries on Windows, a WxEMF would be nicer. This is not high-priority, though, as I only create datasheets once or twice a year and often I need to post-process them anyway... |
Sorry, something went wrong.
|
Back to the failure we have on master, which of the proposed solutions do we want to go with? We are now over a week late on our target for 2.2rc1 so I'm happy with any solution that un-breaks the master branch, we can iterate as needed later. |
Sorry, something went wrong.
|
I would suggest to take Antony's code with my modification for get_renderer. |
Sorry, something went wrong.
|
Update: with the merged Cairo PR, the super(FigureCanvasAgg, self).draw() is a no-op as it calls the empty implementation from FigureCanvasBase. |
Sorry, something went wrong.
|
@DietmarSchwertberger We never write to master directly, everything must go through PRs with usually two other devs accepting the PR (the second one committing it). See https://matplotlib.org/devel/coding_guide.html#pr-review-guidelines (although I guess this is not explicitly written there...). |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
PR Summary
The stripped down (but sufficient) version of #8771. API docs and adding an entry to the backends tutorial are missing but will wait for #10203 to be merged first. Edit: docs added.
The idea is simply to move the parts of the code that were in Qt5Agg but are really only dependent on the GUI toolkit, but not on the renderer, to the base Qt5 classes (so that Qt5Cairo can share them). Note that there is some minimal testing via test_backends_interactive.
[The wxcairo and tkcairo backends PR will follow after this one is merged in order to not to conflict on rcsetup.py.]
[may be worth keeping qt5cairo "private" ("_qt5cairo")]
PR Checklist