-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
interactive figure close with wxpython 4.1 causes freeze / crash (segfault?) #17769
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
Comments
I also tried the following setup: Install Winpython64-3.8.3.0dot.exe Error is the same |
Can also be reproduce with ipython (pip install ipython -> ipython-7.16.1.-py3-none-any.whl): %matplotlib wx closing figure by clicking on 'x' in upper right corner causes ipython to crash without error message. |
Hello there, I ran into the same problem when I've updated wxpython and matplotlib to the latest version. I wrote a very quick test script to run as I patch the matplotlib\backends\backend_wx.py code. It simply allows you to spawn the figure by invoking plt.figure, and close this via either pressing the "x" button in the top right corner, or by pressing the "close fig" button. It also shows "embedded" FigureCanvasses in wx.Frames don't give the same error. Copy and paste it into your editor, save and run.
After 2 hours of messing around, I came up with a fix which doesn't raise a segfault and doesn't give the error "C/C++ object already deleted" after spawning a new figure right after closing a previous one. Replace the FigureFrameWx._onClose method with this code (or just change the 2 lines marked with the "# !" comment...):
Note this function practically calls an equivalent to the "plt.close( )" (which actually calls Gcf.destroy), after the frame has been closed and destroyed (wx.CallAfter calls it after the EVT_CLOSE event is done). For some reason passing "self" yields the "C/C++ object not deleted" error, and you have to explicitly pass in the number of the figure/manager. I think this is because according to the "matplotlib/_pylab_helpers.py" code, function "destroy", FigureFrameWx doesn't contain an attribute named "_cidgcf", and just skips the "if" statement to run what's in "else". I hope this at least gives a start, I feel like this is an unstable fix and doesn't entirely clean the whole figure cache up. |
I can confirm, that with the following current versions the issue persists:
I can also confirm that with the code changes proposed by @johnabro the problem can not be reproduce. Thank you for the hint. I would appreciate if this issue could be resolved "officially" in one of the next releases. |
Can If the Wx objects don't have a What exactly do you mean by "doesn't entirely clean the whole figure cache up."? @lfriedri if you or @johnabro could open a PR with aversion of these changes we can definitely get them released. |
If believe "if self" was already included in the previous code. I made minimum changes.
Well I'm kind of speculating there: I'd assume there would be a reference stored in a list somewhere deep in the matplotlib backend. But the code snippet does call Gcf.destroy, which does destroy the matplotlib.figure.Figure object, not only the wxFrame. That's what I mean't with the figure cache. I'll first do some research into merging Github code... never really done this type of stuff. Thanks for the comment, appreciate your many contributions in general. |
I haven't read through the thread, but for wx objects |
Thank you for adding this topic the milestone. Unfortunately I can not provide a pull request, since I do not feel experienced enough to take the responsibility for the proposed code change. I feel quite experienced in python, however, I do not understand where the difference between wx.Frame.destroy(self) and self.destroy() should be (as self is a wx.Frame here...) |
I can confirm, that with the following current versions the issue persists: |
I can repro the freeze even without closing the window both with wxpy4.0.7 and 4.1, linux and windows; this occurs (at least) at the python console with interactive mode on. On Windows, opened windows are frozen; on Linux, they don't pop up at all. |
I've come across this problem which is a major issue for me as I use the wx backend from inside my Python Matlab clone PythonToolkit (https://pypi.org/project/PythonToolkit/) for interactive plotting. I'm reasonably experienced in using wxpython so I've had a look at the code in the location suggested by @johnabro above (which saved a lot of time finding the problem.) The figure references (actually FigureManagerWx classes) are stored in the Gcf class _pylab_helpers.py file and the problem seems to be that the figure is not being removed from here when closed via GUI, however It is when closed by plt.close() call. Changing the _onClose event handler to destroy the figureManager instance rather than the frame removes the figure number correctly when closed.
However the Gcf.destroy call also tries to close the Frame from the FigureManagerWx.destroy method, resulting in recursive calls to _onClose and Destroy. So I have removed it above so To make it work i had to also change FigureManagerWx.destroy method to just Destroy the frame and r
The program flow is now : I also needed to remove the Yield that should not be needed and also causes a crash (at least on my windows10 pc). I've left the original lines in but commented. I also needed to remove another yield (also causing a crash) in the FigureFrameWx.Destroy method again removing (commented below).
I believe this now works correctly both in my PTK environment and Ipython. |
@tohc1 Great! https://matplotlib.org/stable/devel/contributing.html#contributing-code is our guide to doing opening a PR and on a mechanical level GH's own docs are pretty good https://guides.github.com/introduction/flow/ If you need support please join the gitter room (https://gitter.im/matplotlib) as some of these things are most easily sorted out in a high-bandwdith channel! |
1) On figure window (FigureFrameWx) close - remove figure manager from from Gcf class previously Gcf.destroy was called with FigureFrameWx not FigureManagerWx instance so figure was not removed. 2) Destroy now done from FigureManagerWx.destroy() method to prevent multiple calls to the close event handler. 3) Remove unneeded wx mainloop yield calls that cause crash on windows form both FigureManagerWx.destroy and FigureFrameWx.Destroy
@tacaswell I've managed to create a PR for this issue which is now passing the automatic tests and seems to work correctly for me on windows10/linux mint. |
1) On figure window (FigureFrameWx) close - remove figure manager from from Gcf class previously Gcf.destroy was called with FigureFrameWx not FigureManagerWx instance so figure was not removed. 2) Destroy now done from FigureManagerWx.destroy() method to prevent multiple calls to the close event handler. 3) Remove unneeded wx mainloop yield calls that cause crash on windows form both FigureManagerWx.destroy and FigureFrameWx.Destroy
Bug report
Bug summary
In an interactive session with a wxpython PyShell, closing a matlotlib figure by clicking on the 'x' in upper right corner causes the python shell to freeze for a few seconds, then it exits without any error message.
Code for reproduction
open PyShell with
python ….\lib\site-packages\wx\py\PyShell.py
Then run:
Then close the figure by clicking on the 'x' in upper right corner.
Expected outcome
Figure closes and shell can be used for further commands.
Matplotlib version
print(matplotlib.get_backend())
): wxaggInstallation procedure:
Install Winpython64-3.8.3.0dot.exe
In winpython's command prompt:
pip install wxpython matplotlib
Further notes
Closing the figure with the following command avoids the error:
The text was updated successfully, but these errors were encountered: