8000 [Bug]: blocking_input · Issue #21548 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content
[Bug]: blocking_input  #21548
Closed
Closed
@misc-coder

Description

@misc-coder

Bug summary

** Updated after looking into figure.py.

In blocking_input.py (called by ginput()), the following breaks when a figure is created outside of pyplot. In the Figure class init, FigureCanvasBase(self) is called and this sets the canvas. The FigureCanvasBase init sets the figure.canvas.manager attribute to None, so the combination of these two if statements doesn't produce the expected outcome.

blocking_input.py:

        if hasattr(self.fig.canvas, "manager"):
            # Ensure that the figure is shown, if we are managing it.
            self.fig.show()

This causes figure.show() to return an attribute error.

        if self.canvas.manager is None:
            raise AttributeError(
                "Figure.show works only for figures managed by pyplot, "
                "normally created by pyplot.figure()")

Code for reproduction

import wx
from matplotlib.figure import Figure
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas

class GraphFrame(wx.Frame):
    def __init__(self):
        super().__init__(parent=None, title='Graph Frame')
        panel = wx.Panel(self)

        my_sizer = wx.BoxSizer(wx.VERTICAL)

        # Create figure and canvas, add canvas to sizer.
        self._figure = Figure()
        my_canvas = FigureCanvas(self, wx.ID_ANY, self._figure)
        my_sizer.Add(my_canvas, 1, wx.LEFT | wx.TOP | wx.GROW)

        # Add subplot to figure, and plot to axis.
        self._axis = self._figure.add_subplot()
        self._axis.plot([1,2,3])

        # Add a button to trigger ginput.
        my_btn = wx.Button(panel, label='Select Point')
        my_btn.Bind(wx.EVT_BUTTON, self.on_press)
        my_sizer.Add(my_btn, 0, wx.TOP | wx.CENTER, 5)

        # Add a button to delete the manager attribute from canvas.
        my_other_btn = wx.Button(panel, label='Delete canvas manager')
        my_other_btn.Bind(wx.EVT_BUTTON, self.delete_canvas_manager)
        my_sizer.Add(my_other_btn, 0, wx.TOP | wx.CENTER, 5)

        panel.SetSizer(my_sizer)
        panel.Fit()
        self.Show()
        self.Fit()

    def delete_canvas_manager(self, event):
        print("Canvas  has attribute manager returns: ", hasattr(self._figure.canvas, "manager"))
        del self._figure.canvas.__dict__["manager"]
        print("Canvas manager attribute deleted.")
        print("Canvas  has attribute manager returns: ", hasattr(self._figure.canvas, "manager"))
        print("Try selecting a point again.")

    def on_press(self, event):
        try:
            selection = self._figure.ginput()
            print("User selection ({}, {})".format(selection[0][0], selection[0][1]))
        except AttributeError as e:
            print("User selection unsuccessful: ", e)

if __name__ == '__main__':
    app = wx.App()
    frame = GraphFrame()
    app.MainLoop()

Actual outcome

  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/figure.py", line 3075, in ginput
    return blocking_mouse_input(n=n, timeout=timeout,
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/blocking_input.py", line 266, in __call__
    super().__call__(n=n, timeout=timeout)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/blocking_input.py", line 88, in __call__
    self.fig.show()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/matplotlib/figure.py", line 2333, in show
    raise AttributeError(
AttributeError: Figure.show works only for figures managed by pyplot, normally created by pyplot.figure()

Expected outcome

The expected outcome is for blocking_input to skip the call to show figure. Modifying the attribute check in blocking_input.py to the following gives the expected result. In the example, deleting the manager attribute from the class dict also works.

        if hasattr(self.fig.canvas, "manager"):
            # Ensure that the figure is shown, if we are managing it.
            if self.fig.canvas.manager is not None:
                self.fig.show()

Operating system

OS/X

Matplotlib Version

3.4.3

Matplotlib Backend

MacOSX

Python version

3.9.6

Jupyter version

No response

Other libraries

No response

Installation

pip

Conda channel

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0