From: Axel K. <A.K...@gm...> - 2004-12-18 15:00:52
|
Hello, I have the following small problem when terminating a matplotlib script. Basically I do the following (interactive set to False): from pylab import * plot([1,2,3]) savefig('bla.ps') Now, this script does produce the PS file but then terminates with the error message: >Fatal Python error: PyEval_RestoreThread: NULL tstate >This application has requested the Runtime to terminate it in an unusual way. >Please contact the application's support team for more information. I know that I could use the PS backend which avoids this problem, but I want to be flexible and either generate a PS file or some screen output and so I keep the default backend. Since the script actually does what it should do the question is somewhat aesthetical: How can I avoid this error message ? Many thanks, Axel Kowald |
From: John H. <jdh...@ac...> - 2004-12-18 16:18:28
|
>>>>> "Axel" == Axel Kowald <A.K...@gm...> writes: Axel> Hello, I have the following small problem when terminating a Axel> matplotlib script. Basically I do the following Axel> (interactive set to False): from pylab import * Axel> plot([1,2,3]) savefig('bla.ps') Axel> Now, this script does produce the PS file but then Axel> terminates with the error message: >> Fatal Python error: PyEval_RestoreThread: NULL tstate This >> application has requested the Runtime to terminate it in an Axel> unusual way. >> Please contact the application's support team for more >> information. This error has cropped up before in other contexts, always on win32, and I think a common cause is when you import the tk backend but do not start the tk mainloop (which is what show does), which is what I suspect you are doing since this is the default backend on win32. My guess is the bug will go away if you call "show" at the end of the script, but then you'll get the GUI window in addition to the ps file. I'm not sure if there is a fix for this. Basically, you want to create postscript output using the tk backend without having the tk window popup. Perhaps Todd has some ideas about what to do with tk internals to avoid this problem, but I don't know offhand. I'll try and take a look next week when I have access to a win32 box. Does the minimal script, which does nothing but "import pylab" replicate the problem? Do you know that you can run the script with -dPS from the shell to switch the backend? Then you'll get the PS, no GUI popup, no error, and you won't have to alter your script. You can also place an rc file in the directory where the script resides and make PS the default backend. When you want to switch to GUI mode, you can replace the backend parameter with TkAgg again. But you'll need the show in that case. If you get any additional information from some of the tests suggested above, let me know, because as I said this PyEval_RestoreThread has popped up in many contexts, including multiple calls to show or not calling it at all. I would like to fix these problems if possible so that it "just works". See related threads http://sourceforge.net/mailarchive/message.php?msg_id=10271482 http://sourceforge.net/mailarchive/message.php?msg_id=10114470 JDH |
From: Axel K. <A.K...@gm...> - 2004-12-20 10:31:37
|
Hi John, > >> Fatal Python error: PyEval_RestoreThread: NULL tstate This > >> application has requested the Runtime to terminate it in an > Axel> unusual way. > >> Please contact the application's support team for more > >> information. > >This error has cropped up before in other contexts, always on win32, >and I think a common cause is when you import the tk backend but do >not start the tk mainloop (which is what show does), which is what I >suspect you are doing since this is the default backend on win32. > Yes, that's exactly what's happening. I'm using winXP with matplotlib 0.65 and Activestate Python 2.3.2 >Does the >minimal script, which does nothing but "import pylab" replicate the >problem? > > > This replictes the problem: #!/usr/bin/env python from pylab import * rcParams['interactive'] = False plot([1,2,3]) savefig('bla.ps') >Do you know that you can run the script with -dPS from the shell to >switch the backend? > This is not really appropriate for me, since I read some user input and decide then (after the script is running) if I produce screen output or only a PS file :-( If you or anyone else finds a solution, please let me know. Many thanks, Axel |
From: John H. <jdh...@ac...> - 2004-12-20 19:15:16
|
>>>>> "Axel" == Axel Kowald <A.K...@gm...> writes: Axel> This is not really appropriate for me, since I read some Axel> user input and decide then (after the script is running) if Axel> I produce screen output or only a PS file :-( Axel> If you or anyone else finds a solution, please let me know. So this has nothing to do with the ps save. The core problem is exposed by from pylab import * plot([1,2,3]) with interactive false and no call to show. I traced the source of the error message to binding the destroy event to the window. Apparently the destroy is being called but the window is never shown. By moving the destroy binding into the figure manager show method, all appears to be fixed. Todd, you may want to look over this but I think it's sound Axel, try replacing the FigureManagerTkAgg code in site-packages/matplotlib/backends/backend_tkagg.py with the following class FigureManagerTkAgg(FigureManagerBase): """ Public attributes canvas : The FigureCanvas instance num : The Figure number toolbar : The tk.Toolbar window : The tk.Window """ def __init__(self, canvas, num, window): FigureManagerBase.__init__(self, canvas, num) self.window = window self.window.withdraw() self.window.wm_title("Figure %d" % num) self.canvas = canvas self._num = num t1,t2,w,h = canvas.figure.bbox.get_bounds() w, h = int(w), int(h) self.window.minsize(int(w*3/4),int(h*3/4)) if matplotlib.rcParams['toolbar']=='classic': self.toolbar = NavigationToolbar( canvas, self ) elif matplotlib.rcParams['toolbar']=='toolbar2': self.toolbar = NavigationToolbar2TkAgg( canvas, self.window ) else: self.toolbar = None if self.toolbar is not None: self.toolbar.update() self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) self._shown = False def resize(self, event): width, height = event.width, event.height self.toolbar.configure(width=width) # , height=height) def show(self): def destroy(*args): self.window = None Gcf.destroy(self._num) if not self._shown: self.window.bind("<Destroy>", destroy) _focus = windowing.FocusManager() self.window.deiconify() self.canvas.draw() self._shown = True def add_subplot(self, *args, **kwargs): a = FigureManagerBase.add_subplot(self, *args, **kwargs) if self.toolbar is not None: self.toolbar.update() return a def add_axes(self, rect, **kwargs): a = FigureManagerBase.add_axes(self, rect, **kwargs) if self.toolbar is not None: self.toolbar.update() return a def set_current_axes(self, a): if a not in self.axes.values(): error_msg_tkpaint('Axes is not in current figure') FigureManagerBase.set_current_axes(self, a) def destroy(self, *args): if Gcf.get_num_fig_managers()==0 and not matplotlib.is_interactive(): if self.window is not None: self.window.quit() if self.window is not None: self.window.destroy() self.window = None |
From: Todd M. <jm...@st...> - 2004-12-20 20:02:16
|
Hi John, I looked over the diffs and they look fine; your analysis sounds plausible to me. I'll try to reproduce the problem using the test script and see if your fix removes it. If so, I'll go ahead and commit the changes. Todd On Mon, 2004-12-20 at 13:12 -0600, John Hunter wrote: > >>>>> "Axel" == Axel Kowald <A.K...@gm...> writes: > Axel> This is not really appropriate for me, since I read some > Axel> user input and decide then (after the script is running) if > Axel> I produce screen output or only a PS file :-( > > Axel> If you or anyone else finds a solution, please let me know. > > So this has nothing to do with the ps save. The core problem is > exposed by > > from pylab import * > plot([1,2,3]) > > with interactive false and no call to show. I traced the source of > the error message to binding the destroy event to the window. > Apparently the destroy is being called but the window is never shown. > By moving the destroy binding into the figure manager show method, all > appears to be fixed. Todd, you may want to look over this but I think > it's sound > > Axel, try replacing the FigureManagerTkAgg code in > site-packages/matplotlib/backends/backend_tkagg.py with the following > > class FigureManagerTkAgg(FigureManagerBase): > """ > Public attributes > > canvas : The FigureCanvas instance > num : The Figure number > toolbar : The tk.Toolbar > window : The tk.Window > """ > def __init__(self, canvas, num, window): > FigureManagerBase.__init__(self, canvas, num) > self.window = window > self.window.withdraw() > self.window.wm_title("Figure %d" % num) > self.canvas = canvas > self._num = num > t1,t2,w,h = canvas.figure.bbox.get_bounds() > w, h = int(w), int(h) > self.window.minsize(int(w*3/4),int(h*3/4)) > if matplotlib.rcParams['toolbar']=='classic': > self.toolbar = NavigationToolbar( canvas, self ) > elif matplotlib.rcParams['toolbar']=='toolbar2': > self.toolbar = NavigationToolbar2TkAgg( canvas, self.window ) > else: > self.toolbar = None > if self.toolbar is not None: > self.toolbar.update() > self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) > self._shown = False > > def resize(self, event): > width, height = event.width, event.height > self.toolbar.configure(width=width) # , height=height) > > def show(self): > def destroy(*args): > self.window = None > Gcf.destroy(self._num) > if not self._shown: self.window.bind("<Destroy>", destroy) > > _focus = windowing.FocusManager() > self.window.deiconify() > self.canvas.draw() > self._shown = True > > def add_subplot(self, *args, **kwargs): > a = FigureManagerBase.add_subplot(self, *args, **kwargs) > if self.toolbar is not None: > self.toolbar.update() > return a > > def add_axes(self, rect, **kwargs): > a = FigureManagerBase.add_axes(self, rect, **kwargs) > if self.toolbar is not None: > self.toolbar.update() > return a > > def set_current_axes(self, a): > if a not in self.axes.values(): > error_msg_tkpaint('Axes is not in current figure') > FigureManagerBase.set_current_axes(self, a) > > def destroy(self, *args): > if Gcf.get_num_fig_managers()==0 and not matplotlib.is_interactive(): > if self.window is not None: > self.window.quit() > if self.window is not None: > self.window.destroy() > self.window = None > > > > ------------------------------------------------------- > SF email is sponsored by - The IT Product Guide > Read honest & candid reviews on hundreds of IT Products from real users. > Discover which products truly live up to the hype. Start reading now. > http://productguide.itmanagersjournal.com/ > _______________________________________________ > Matplotlib-users mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-users |
From: Axel K. <A.K...@gm...> - 2004-12-22 12:16:33
|
Hello John, >Axel, try replacing the FigureManagerTkAgg code in >site-packages/matplotlib/backends/backend_tkagg.py with the following > > > Perfect. Problem solved ! Best wishes and a merry Christmas, Axel |