From: Charles T. <Cha...@in...> - 2003-11-03 00:28:39
|
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) |