Skip to content
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

[Bug]: Widget blitting broken when saving as PDF #25075

Closed
QuLogic opened this issue Jan 25, 2023 · 2 comments · Fixed by #25085
Closed

[Bug]: Widget blitting broken when saving as PDF #25075

QuLogic opened this issue Jan 25, 2023 · 2 comments · Fixed by #25085

Comments

@QuLogic
Copy link
Member

QuLogic commented Jan 25, 2023

Bug summary

When running a test doc build for 3.7.0rc1, I build the PDF, which runs everything with the PDF backend. So either the PDF backend does not correctly mark itself as not supporting blitting, or the blitting is not turned off correctly in the button widgets.

Code for reproduction

make -C doc latexpdf

Actual outcome

/home/elliott/code/matplotlib-3.7.x/doc/users/next_whats_new/widget_button_styling.rst:8: WARNING: Exception occurred in plotting widget_button_styling-1
 from /home/elliott/code/matplotlib-3.7.x/doc/users/next_whats_new/widget_button_styling.rst:
Traceback (most recent call last):
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/sphinxext/plot_directive.py", line 615, in render_figures
    figman.canvas.figure.savefig(img.filename(fmt), dpi=dpi)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/figure.py", line 3328, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/backend_bases.py", line 2362, in print_figure
    result = print_method(
             ^^^^^^^^^^^^^
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/backend_bases.py", line 2228, in <lambda>
    print_method = functools.wraps(meth)(lambda *args, **kwargs: meth(
                                                                 ^^^^^
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/backends/backend_pdf.py", line 2815, in print_pdf
    self.figure.draw(renderer)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/artist.py", line 95, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
           ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/figure.py", line 3135, in draw
    DrawEvent("draw_event", self.canvas, renderer)._process()
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/backend_bases.py", line 1259, in _process
    self.canvas.callbacks.process(self.name, self)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/cbook/__init__.py", line 309, in process
    self.exception_handler(exc)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/cbook/__init__.py", line 96, in _exception_printer
    raise exc
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/cbook/__init__.py", line 304, in process
    func(*args, **kwargs)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/widgets.py", line 1706, in _clear
    self.ax.draw_artist(self._buttons)
  File "/home/elliott/code/matplotlib-3.7.x/lib/matplotlib/axes/_base.py", line 3076, in draw_artist
    a.draw(self.figure.canvas.get_renderer())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'FigureCanvasPdf' object has no attribute 'get_renderer'

Expected outcome

Docs build without warning.

Additional information

No response

Operating system

Fedora 37

Matplotlib Version

v3.7.x

Matplotlib Backend

PDF

Python version

3.11.1

Jupyter version

No response

Installation

git checkout

@QuLogic QuLogic added this to the v3.7.0 milestone Jan 25, 2023
@QuLogic QuLogic changed the title [Bug]: Widget blitting break for PDF backend [Bug]: Widget blitting broken on PDF backend Jan 25, 2023
@QuLogic QuLogic changed the title [Bug]: Widget blitting broken on PDF backend [Bug]: Widget blitting broken when saving as PDF Jan 25, 2023
@QuLogic
Copy link
Member Author

QuLogic commented Jan 25, 2023

Further investigation shows that this is not directly about the PDF backend. Rather, it occurs when changing to the PDF backend to save as a .pdf. If you start directly with the PDF backend, then the Widget will see that the canvas doesn't support blitting and disable it. So this might affect anything which uses blitting, depending on what they do.

@QuLogic
Copy link
Member Author

QuLogic commented Jan 25, 2023

Defining get_renderer like this seems to work:

diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py
index 7bd0afc456..d7adfdf53c 100644
--- a/lib/matplotlib/backends/backend_pdf.py
+++ b/lib/matplotlib/backends/backend_pdf.py
@@ -2796,6 +2796,12 @@ class FigureCanvasPdf(FigureCanvasBase):
     def get_default_filetype(self):
         return 'pdf'
 
+    def get_renderer(self):
+        if hasattr(self, '_renderer'):
+            return self._renderer
+        else:
+            raise ValueError('PDF must be saving to get a renderer')
+
     def print_pdf(self, filename, *,
                   bbox_inches_restore=None, metadata=None):
 
@@ -2808,12 +2814,15 @@ class FigureCanvasPdf(FigureCanvasBase):
             file = PdfFile(filename, metadata=metadata)
         try:
             file.newPage(width, height)
-            renderer = MixedModeRenderer(
+            self._renderer = MixedModeRenderer(
                 self.figure, width, height, dpi,
                 RendererPdf(file, dpi, height, width),
                 bbox_inches_restore=bbox_inches_restore)
-            self.figure.draw(renderer)
-            renderer.finalize()
+            try:
+                self.figure.draw(self._renderer)
+                self._renderer.finalize()
+            finally:
+                del self._renderer
             if not isinstance(filename, PdfPages):
                 file.finalize()
         finally:

Not sure if that's the best fix though.

tacaswell added a commit to tacaswell/matplotlib that referenced this issue Jan 25, 2023
Because we may switch the canvas to a different type (that may not
support blitting) when saving, check it `_clear` that the current canvas
is the canvas we expect when we update the blitting caches on the
draw_event callback.

Closes matplotlib#25075
ksunden pushed a commit to tacaswell/matplotlib that referenced this issue Feb 8, 2023
Because we may switch the canvas to a different type (that may not
support blitting) when saving, check it `_clear` that the current canvas
is the canvas we expect when we update the blitting caches on the
draw_event callback.

Closes matplotlib#25075
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.

1 participant