FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

pgf backend no longer supports fig.draw · Issue #18407 · matplotlib/matplotlib · GitHub

Repository navigation

pgf backend no longer supports fig.draw #18407

Closed

Description

Bug report

Because of the cleanups in #15977, the pgf backend no longer supports fig.draw(fig.canvas.get_renderer()) to trigger a draw.

If this is not supposed to be a bug and is the correct expected behavior, is there a cleaner way to trigger a draw without using fig.savefig?

Bug summary

Code for reproduction

import numpy as np
import matplotlib.pyplot as plt

plt.switch_backend('pgf')  # Switching to the PGF backend
fig, ax = plt.subplots(figsize=(6, 3.0), ncols=2, nrows=1,
                       constrained_layout=True, sharey=True)
fig.set_constrained_layout_pads(wspace=0.03)

ax[0].plot(np.arange(4), 'r', label=r'Really longgggg label 1')
ax[1].plot(np.arange(5), 'b', label=r'Really longgggg label 2')
(leg_h0, leg_lab0) = ax[0].get_legend_handles_labels()
(leg_h1, leg_lab1) = ax[1].get_legend_handles_labels()

# add a legend to one of the axes to make space at the top of the figure
leg0 = ax[0].legend(leg_h0, leg_lab0, loc='lower center',
                    bbox_to_anchor=(0.5, 1.07))

leg0.set_in_layout(True)  # force to steal space from top of the figure
# ------------------------------------------------------
# Trigger a draw (required for constrained_layout to work)
# fig.canvas.draw()   # Doesn't work since pgf is a non-interactive backend
fig.draw(fig.canvas.get_renderer())  # used to work before #15977
# ------------------------------------------------------
# Thanks constrained_layout, your work is done! turning you off now
fig.set_constrained_layout(False)

# Remove legend from axes and add a figure legend
# which includes entries from both axes
leg0.remove() 
fig_leg = fig.legend(*zip(leg_h0, leg_h1), *zip(leg_lab0, leg_lab1),
                     loc='lower center', ncol=2, columnspacing=5,
                     bbox_to_anchor=(0.5, 0.85))
fig.savefig('test.png', dpi=200)

Actual outcome

Traceback (most recent call last):
  File "test.py", line 22, in <module>
    fig.draw(fig.canvas.get_renderer())  # works!
  File "---\Miniconda3\lib\site-packages\matplotlib\artist.py", line 41, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "---\Miniconda3\lib\site-packages\matplotlib\figure.py", line 1862, in draw
    self.patch.draw(renderer)
  File "---\Miniconda3\lib\site-packages\matplotlib\artist.py", line 41, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "---\Miniconda3\lib\site-packages\matplotlib\patches.py", line 587, in draw
    draw_path(tpath, affine,
  File "---\Miniconda3\lib\site-packages\matplotlib\backends\backend_pgf.py", line 475, in draw_path
    writeln(self.fh, r"\begin{pgfscope}")
  File "---\Miniconda3\lib\site-packages\matplotlib\backends\backend_pgf.py", line 129, in writeln
    fh.write(line)
AttributeError: 'NoneType' object has no attribute 'write'

Expected outcome

Matplotlib version

  • Operating system: Windows 10
  • Matplotlib version: 3.3.1
  • Matplotlib backend (print(matplotlib.get_backend())): pgf
  • Python version: 3.8.5
  • Jupyter version (if applicable):
  • Other libraries:

Activity

  1. added this to the v3.3.2 milestone on Sep 4, 2020
  2. added
    Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.
    on Sep 4, 2020
  3. anntzer commented on Sep 4, 2020

    Contributor

    Looks like something like

    diff --git i/lib/matplotlib/backends/backend_pgf.py w/lib/matplotlib/backends/backend_pgf.py
    index 4474aa32a..561ae9c7c 100644
    --- i/lib/matplotlib/backends/backend_pgf.py
    +++ w/lib/matplotlib/backends/backend_pgf.py
    @@ -968,7 +968,13 @@ class FigureCanvasPgf(FigureCanvasBase):
                 self._print_png_to_fh(file, *args, **kwargs)
     
         def get_renderer(self):
    -        return RendererPgf(self.figure, None)
    +        renderer = RendererPgf(self.figure, None)
    +        dd = renderer._draw_disabled()
    +        dd.__enter__()
    +        # This renderer is permanently disabled.  Store a reference to the
    +        # context manager, to prevent it from being auto-closed.
    +        renderer._dd = dd
    +        return renderer
     
     
     FigureManagerPgf = FigureManagerBase

    works (note that the old behavior was indeed to return an always-dummy renderer here).

    On the other hand(s)

    • I think fig.canvas.draw() is the canonical way to trigger a draw? (fig.draw(renderer) is in a sense an implementation detail...)
    • I think we can just delete get_renderer() and rely on backend_bases' handling?
  4. tacaswell commented on Sep 4, 2020

    Member

    @anntzer is about 2 steps ahead of me (as normal),

    I think a better solution is to add a draw method to backend_pgf.FigureCanvas that does the dummy draw (enough to update constrained layout) like we expect. Currently it does not define draw at all which gets the default no-op implementation and runs counter to what we have been saying everywhere of "do fig.canvas.draw() to force updates".

    For short term fixes, either do what @anntzer is suggesting in your code or do the save with a BytesIO object as the filename.

  5. anntzer commented on Sep 4, 2020

    Contributor

    I have not looked carefully but what's wrong with just inheriting FigureCanvasBase.draw?

  6. tacaswell commented on Sep 4, 2020

    Member

    It is a no-op

    def draw(self, *args, **kwargs):
    """Render the `.Figure`."""
    def draw_idle(self, *args, **kwargs):

  7. anntzer commented on Sep 4, 2020

    Contributor

    Woops. But I guess the same problem exists for the other non-interactive backends, so I guess we could just change the base class implementation to do a fig.draw(renderer) using a draw-disabled renderer? fixing all non-interactive backends at once...

  8. tacaswell commented on Sep 4, 2020

    Member

    Agg draws itself (and then calls super()) so that complicates things.

  9. anntzer commented on Sep 4, 2020

    Contributor

    Ah, that's annoying. We should still try to at least keep pdf/ps/svg/pgf consistent, even if by copy-pasting the same draw() implementation.

  10. tacaswell commented on Sep 4, 2020

    Member

    I'll have a PR soon.

  11. modified the milestones: v3.3.2, v3.4.0 on Sep 4, 2020
  12. added a commit that references this issue on Sep 4, 2020
    4ae1ae3
  13. added 2 commits that reference this issue on Sep 23, 2020
    e7f01a4
    2898a9c
  14. added a commit that references this issue on Oct 16, 2020
    600ac18
  15. added 4 commits that reference this issue on Jan 22, 2021
    48bff43
    7131cbe
    4c0656d
    7211646
  16. added 2 commits that reference this issue on Feb 11, 2021
    a35df3f
    b7ccfb6
  17. added a commit that references this issue on Mar 8, 2021
    3e7d216
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL