[Matplotlib-users] Figures piling up in Tkinter GUI (1.2.0rc2)

2012-11-01 Thread Hans Bering
Hello everybody,

I'm building a small Tkinter GUI using matplotlib, in which I have to  
change/update plots quite often depending on user input (with different  
contents & sizes, in different places in the GUI, etc.; but always only  
one figure at a time).

As a first resort, I regenerated the figures with plt.figure(...) whenever  
necessary; unfortunately, the program happily accumulated memory with  
every new figure until the computer would no longer cooperate in a timely  
fashion. The following minimal script should demonstrate the tendency:

--- start of script ---

import math
 from Tkinter import Tk, Button
import Tkconstants
 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
 from matplotlib.figure import Figure
 from matplotlib import pyplot as plt

def replot():
 global globalCanvas, globalFigure, plotShift

 # any variety of clean-up calls
 if globalFigure is not None:
 plt.close()
 globalCanvas.get_tk_widget().destroy()
 globalFigure.clf()

 globalFigure = Figure(dpi=120, figsize=(4, 4))

 globalCanvas = FigureCanvasTkAgg(globalFigure, master=root)
 globalCanvas.get_tk_widget().grid(row=0, column=1)

 xVals = xrange(100)
 ax = globalFigure.add_subplot(111)
 ax.plot(xVals, [math.sin(x + plotShift) for x in xVals])
 plotShift += 10

# MAIN
globalCanvas = None
globalFigure = None
plotShift = 0 # just to see the plot change

root = Tk()

draw_button = Button(root, text="Replot", command=replot)
draw_button.grid(row=0, column=0, sticky=Tkconstants.N)

root.mainloop()

--- end of script ---


I have tried various clean-up calls, but the effect (of memory piling up)  
is always the same. Using objgraph (http://mg.pov.lt/objgraph/), I took a  
look at object counts by adding the following snippet at the end of the  
"replot" call:

--- start of insertion ---

 import gc
 import objgraph
 gc.collect()
 print "---"
 for c in ('FigureCanvasTkAgg', 'Figure'):
 print "{}\t{}".format(len(objgraph.by_type(c)), c)

--- end of insertion ---

The output shows that the total number of both Figures and  
FigureCanvasTkAggs increases constantly (i.e., one each after the first  
call, then two each, etc.), whereas I had expected that old ones get  
released, and that the count remains at one each.

Now I am wondering if I am missing some detail, e.g., some other clean-up  
procedure? Or should this work & could be a memory leak in matplotlib or  
Tkinter? And/or is this approach (of generating a new figure every time)  
not recommended in the first place? I tried reusing the figure, but some  
aspects like changing the layout in the GUI and applying new size and dpi  
then proved tricky in their own ways.

Many thanks in advance,
Hans

--
Everyone hates slow websites. So do we.
Make your web apps faster with AppDynamics
Download AppDynamics Lite for free today:
http://p.sf.net/sfu/appdyn_sfd2d_oct
___
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users


Re: [Matplotlib-users] Figures piling up in Tkinter GUI

2012-11-05 Thread Hans Bering
On Fri, 02 Nov 2012 16:45:22 +0100,  
 wrote:

> Message: 5
> Date: Fri, 2 Nov 2012 12:01:35 +0100
> From: Vlastimil Brom 
> Subject: Re: [Matplotlib-users] Figures piling up in Tkinter GUI
>   (1.2.0rc2)
> To: matplotlib-users@lists.sourceforge.net
> Message-ID:
>   
> Content-Type: text/plain; charset=ISO-8859-1
> 2012/11/1 Hans Bering :
>> Hello everybody,
>>
>> I'm building a small Tkinter GUI using matplotlib, in which I have to
>> change/update plots quite often depending on user input (with different
>> contents & sizes, in different places in the GUI, etc.; but always only
>> one figure at a time).
>>
>> As a first resort, I regenerated the figures with plt.figure(...)  
>> whenever necessary; unfortunately, the program happily accumulated  
>> memory with
>> every new figure until the computer would no longer cooperate in a  
>> timely fashion. The following minimal script should demonstrate the  
>> tendency:
>>
> ...
>
> Hi,
> I'd recommend to use an embedded plot and only clear and replace its
> content [...]
> I only roughly adapted that source to use your function and the memory
> usage appears to be more effective (although there is some increase
> too - as displayed in Process Explorer). Would some variation of the
> following work for you?

[...]

Hi Vlastimil,

thanks for your effort; I had tried the approach of clearing & replacing  
the plot myself, too. Unfortunately, that approach has a different  
problem: Because of the figure's size, I have to present it with  
scrollbars, and clearing & reusing the plot does not seem to work when  
resizing & scrolling the plot. I had posted that problem as a question at  
Stackoverflow (as http://stackoverflow.com/questions/13197469 ), since I  
hoped it might be "easier"; i.e., just a misunderstanding on my part of  
how to wire together the scrollbars/canvas/figure. Please note that, while  
I also use plt.figure(...) in the post at Stackoverflow, the effect  
remains the same when using Figure(...) and ax.plot(...).

So basically I'm stuck between a rock and a hard place - I can either have  
the memory issue reported previously; or the plot won't behave properly  
with scrolling+resizing.

I am wondering: Should repeatedly creating Figures in a Tkinter GUI work,  
and could this be a Matplotlib bug worth mentioning on some bug tracker?

Thanks & Regards
Hans

--
LogMeIn Central: Instant, anywhere, Remote PC access and management.
Stay in control, update software, and manage PCs from one command center
Diagnose problems and improve visibility into emerging IT issues
Automate, monitor and manage. Do more in less time with Central
http://p.sf.net/sfu/logmein12331_d2d
___
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users


[Matplotlib-users] "bad screen distance" tkinter error with German locale

2011-06-30 Thread hans . bering
Hi,

sorry if this has already been addressed. I did a search on the archives, but 
even though that turned up lots of hits, none of them seemed to be related to 
the issue.

The following very simple example will reliably crash in Python 2.7.[0-2] with 
matplotlib 1.0.1 under a 64 bit German Windows (and probably also on other 
machines where you can set an equivalent locale):

---

import matplotlib

from pylab import arange,sin,pi
t = arange(0.0, 2.0, 0.01)
s = sin(2*pi*t)

import locale
# the locale setting in the next line makes pyplot.plot crash
# have to use "deu_deu" instead of "de_DE" on German Windows 
locale.setlocale(locale.LC_ALL, 'deu_deu')
print "locale =", locale.getlocale(locale.LC_NUMERIC)

print "will plot ..."
matplotlib.pyplot.plot(t, s, linewidth=1.0)
# doesn't get this far with German locale
print "will show ..."
matplotlib.pyplot.show() 

---

The program crashes in pyplot.plot(). The stacktrace is:

---

Traceback (most recent call last):
  File "C:\[...]\badScreenSizeMPL.py", line 14, in 
matplotlib.pyplot.plot(t, s, linewidth=1.0)
  File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 2279, in plot
ax = gca()
  File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 593, in gca
ax =  gcf().gca(**kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 292, in gcf
return figure()
  File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 270, in figure
**kwargs)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", 
line 82, in new_figure_manager
figManager = FigureManagerTkAgg(canvas, num, window)
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", 
line 400, in __init__
self.toolbar = NavigationToolbar2TkAgg( canvas, self.window )
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", 
line 667, in __init__
NavigationToolbar2.__init__(self, canvas)
  File "C:\Python27\lib\site-packages\matplotlib\backend_bases.py", line 2310, 
in __init__
self._init_toolbar()
  File "C:\Python27\lib\site-packages\matplotlib\backends\backend_tkagg.py", 
line 711, in _init_toolbar
borderwidth=2)
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 2466, in __init__
Widget.__init__(self, master, 'frame', cnf, {}, extra)
  File "C:\Python27\lib\lib-tk\Tkinter.py", line 1977, in __init__
(widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: bad screen distance "640.0"
Fatal Python error: PyEval_RestoreThread: NULL tstate

---

The reason appears to be that at some point Tkinter tries to parse the string 
"640.0" as a number, which does not work in a locale where the decimal marker 
is, e.g., the comma (as in German). If you comment out the locale setting (or 
set it to "C"), the example works.

The float value of 640.0 seems to emerge from the following piece of code in 
"backend_tkagg.py".

---

class NavigationToolbar2TkAgg(NavigationToolbar2, Tk.Frame):

   [...]

def _init_toolbar(self):
xmin, xmax = self.canvas.figure.bbox.intervalx
height, width = 50, xmax-xmin
Tk.Frame.__init__(self, master=self.window,
  width=width, height=height,
  borderwidth=2)

---

Through the initialization by difference, "width" is a 'numpy.float64'; 
changing the assignment of "height, width" to

   height, width = 50, int(xmax-xmin)

makes the example program run through without problems.

One the one hand, I guess this should be fixed in the depths of Tkinter (where 
apparently a number type gets stringified just to be parsed again as a number). 
One the other hand, it would be very simple fix in the TkAgg backend, and it 
seems sensible to make the width an int. (Perhaps even the intervals in 
intervalx should already be ints?)

I would like to point out that, even though this might sound like a contrived 
problem, it can easily occur where machines are set up with different 
languages; we had a tool run on an English Windows, but we got the stack trace 
from above when we moved that tool to a German Windows which we believed to be 
set up in just the same way as the original Windows. It took us a day to figure 
out what the reason behind the cryptic Tkinter error was.

Kind regards,
H.


--
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security 
threats, fraudulent activity, and more. Splunk takes this data and makes 
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
___
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users


Re: [Matplotlib-users] "bad screen distance" tkinter error with German locale

2011-07-01 Thread hans . bering

Hi,

thanks for the very quick response & fix. We were surprised, too, that we 
hadn't found more about this problem. We were put on the right track by this 
related report: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=395867 - 
Thanks also for the link to the other report. I'll see if I can come up with a 
nice example and submit it there.

Cheers
HB

> On 06/30/2011 01:10 PM, Michael Droettboom wrote:
> > I'm surprised this bug (which really lies in Tkinter) isn't more widely
> > known -- searching the Python bug tracker revealed nothing.  It would be
> > great to follow-up there (with a standalone Tkinter-crashing example) if
> > you're so inclined.
> I did find this bug, which seems to be related.
> 
> http://bugs.python.org/issue10647
> 
> Mike

--
All of the data generated in your IT infrastructure is seriously valuable.
Why? It contains a definitive record of application performance, security 
threats, fraudulent activity, and more. Splunk takes this data and makes 
sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-d2d-c2
___
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users


Re: [Matplotlib-users] adding scrollbars to plot embedded in tk

2011-09-05 Thread Hans Bering
Hi Matt,

a possible workaround seems to be to embed the figure's canvas in a second  
Tk canvas using canvas.create_window(...). The second (embedding) canvas  
handles the appropriate resizing & scrolling. I have attached a script  
below to demonstrate. Unfortunately, scrolling is rather sluggish, but it  
seems to work - the plot is not resized, and you can scroll around to  
different areas. Does that help?

Cheers
Hans

On Wed, 31 Aug 2011 22:19:26 +0200, Benjamin Root  wrote:

> On Wed, Aug 31, 2011 at 2:55 PM, Matthew Hemke  wrote:
>
>> I have a plot canvas added to a tk interface (python 2.7.2, matplotlib
>> 1.0.1) according to the recipe here:
>>
>>
>> http://matplotlib.sourceforge.net/examples/user_interfaces/embedding_in_tk.html
>>
>> When the window containing the plot is resized the plot shrinks, often
>> leading to REALLY ugly, unreadable plots.
>>
>> I tried adding scrollbars to the canvas returned by get_tk_widget() and
>> they connect as expected (using the yview method). Then, I set a  
>> scrollarea
>> config option for the canvas.
>>
>> Everything seems to be working just like a tkinter canvas, but then when
>> the window is resized, the plot still resizes and the scrollbars never
>> activate. I was hoping the plot wouldn't resize and the scrollbars would
>> activate to allow the user to scroll to see the appropriate part of the
>> plot, while still keeping the plot looking pretty.
>>
>> Is there a way (besides editing backend_tkagg.py self.resize method)  
>> that
>> would allow the scrollbars to work properly?
>>
>> If my question isn't clear, I can mock up some code, but it may be a bit
>> lengthy, so if anyone can steer me in a better direction that would be
>> great.
>>
>> Thanks,
>>
>> -Matt
>>

--- start of script ---

 from Tkinter import Tk, Frame, Canvas, Scrollbar
 from Tkconstants import NSEW, HORIZONTAL, EW, NS, ALL

 from matplotlib import pyplot as plt
 from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg

def doLargePlot():
 from numpy.random import randn

 matrix = randn(100, 100)
 plt.pcolor(matrix)

def getScrollingCanvas(frame):
 """
 Adds a new canvas with scroll bars to the argument frame
 NB: uses grid layout
 @return: the newly created canvas
 """

 frame.grid(sticky=NSEW)
 frame.rowconfigure(0, weight=1)
 frame.columnconfigure(0, weight=1)

 canvas = Canvas(frame)
 canvas.grid(row=0, column=0, sticky=NSEW)

 xScrollbar = Scrollbar(frame, orient=HORIZONTAL)
 yScrollbar = Scrollbar(frame)

 xScrollbar.grid(row=1, column=0, sticky=EW)
 yScrollbar.grid(row=0, column=1, sticky=NS)

 canvas.config(xscrollcommand=xScrollbar.set)
 xScrollbar.config(command=canvas.xview)
 canvas.config(yscrollcommand=yScrollbar.set)
 yScrollbar.config(command=canvas.yview)

 return canvas

if __name__ == "__main__":

 root = Tk()
 root.rowconfigure(0, weight=1)
 root.columnconfigure(0, weight=1)

 frame = Frame(root)

 scrollC = getScrollingCanvas(frame)

 # use more dpi for bigger plot
 #figure = plt.figure(dpi=200)
 figure = plt.figure()

 mplCanvas = FigureCanvasTkAgg(figure, scrollC)
 canvas = mplCanvas.get_tk_widget()
 canvas.grid(sticky=NSEW)

 scrollC.create_window(0, 0, window=canvas)
 scrollC.config(scrollregion=scrollC.bbox(ALL))
 doLargePlot()

 root.mainloop()

--- end of script ---


--
Special Offer -- Download ArcSight Logger for FREE!
Finally, a world-class log management solution at an even better 
price-free! And you'll get a free "Love Thy Logs" t-shirt when you
download Logger. Secure your free ArcSight Logger TODAY!
http://p.sf.net/sfu/arcsisghtdev2dev
___
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users