A slightly different approach to live plotting. I have a numerical
program that calls a status function every run through the main loop. It
allows the user to define a status function and pass it that function
(defaulting to just a one-line report on sys.err).
Using GTK idle slowed things down way too much, because GTK was always
idle, even though the number cruncher wasn't. GTK timeout didn't work
either. Using threads was too complicated and error prone, for no gain.
What I wanted was a meter that updated every second or so.
Here is my status function. It shows traces for the best score so far, and
the current score. If enough time has elapsed, it plots (thus scheduling
GTK events), otherwise no. So the gtk.events_pending() call near the end
is usually false.
It rescales the graph too, as required. You can ignore the "interrupted"
stuff -- that allows me to send a "stop" signal to the numerical routine,
saying "Ok, it looks to me like you've converged, stop now."
-Charles
···
----------
def my_status_func(*args, **kwargs):
""" Gather info from a running snob, and plot it.
It expects the final arg to be a dictionary with
the following keyword arguments:
fig -- the matplot figure for drawing to
ax -- the matplot axes in that figure
t1 -- a list of length 1, with timestamp of last refresh
iteratns -- sequence of all iteration #s to date (x axis)
currlens -- sequence of all current lengths to date
bestlens -- sequence of all best lenghts to date
All of these kwargs will be modified, at least sometimes.
"""
#global currlens, bestlens, iteratns, t
UPDATE_INTERVAL = 1 # how long in s to wait before updating graph
itr = args[0] + 1
max_itr = args[1]
cl = int (args[2][0] / N.log(2))
bl = int (args[3][0] / N.log(2))
#cl = int (curr[0] / N.log(2))
#bl = int (best[0] / N.log(2))
# Extract variables from kwargs
t1 = kwargs['t1']
iteratns = kwargs['iteratns']
currlens = kwargs['currlens']
bestlens = kwargs['bestlens']
iteratns.append (itr)
currlens.append (cl)
bestlens.append (bl)
if itr == 1:
print "Original length: ", cl
delta = time.time() - t1[0]
if (itr > 1) and ( (delta > UPDATE_INTERVAL) or (itr >= max_itr) ):
# matplot has trouble if we plot just a single data point
# so we wait for itr > 1
# if not ShowOn().get():
# ShowOn().set(True)
fig = kwargs['fig']
ax = kwargs['ax']
xlo, xhi = ax.get_xlim()
xlo = max ( 0, xlo) # Check bc original call is ignored
xhi = max (50, xhi) # Likewise
if itr > xhi:
xhi *= 2
ax.set_xlim ([xlo, xhi])
ax.set_ylim ( [ min(currlens), max(currlens) ] )
plot(iteratns, currlens, 'b',
iteratns, bestlens, 'r')
fig.draw() # schedule a refresh
t1[0] = time.time()
# Display any updates to the figure
while gtk.events_pending():
gtk.mainiteration() # if running in normal gtk thread
global interrupted
if interrupted:
return 1
return snob.default_status_func(*args)