From: Benny Brown Date: May 21, 2009 10:05:21 AM PDT To: "James P. Crutchfield" Subject: One-D Map tool Reply-To: brown@cse.ucdavis.edu Hi Jim, Here's the OO version of the one-d map tool. Works fine in iPython, will open multiple windows, but you can't interact with the figures until you quit the program. This is the matplotlib "bug". Once you quit the program, you can interact with the figures normally. If run directly from the terminal, you can interact with the first figure produced. Subsequent figures, however, will not let you interact with them (they produce correct plots, though). Benny # OneDTool.py # try importing modules, catch exceptions if a module isn't installed try: import sys import matplotlib.pyplot as plt import numpy as np import OneDMapClasses as odm except ImportError, msg: print 'Error importing modules:', msg sys.exit() # Create a dictionary of map choices with pointers to their classes. # Note that only references to the classes are stored below and no objects # are actually created until the main loop. maps = { '1' : ['Logistic Map: f(x)=r*x*(1-x)', odm.LogisticMap], '2' : ['Cosine Map: f(x)=r*cos(x)', odm.CosineMap], } mapList = maps.keys() # convenient for looping in order mapList.sort() # dictionaries do not necessarily automatically sort, even if # items are entered in correct order, so we have to manually sort mapChoice = None # main loop... while mapChoice != '0': # prompt user for map choice print '\nOne Dimensional Map Bifurcation Tool' print 'Maps available:' for item in mapList: print item, '-', maps[item][0] # get choice from user mapChoice = raw_input('Enter choice (%s-%s) or 0 to quit): ' % (mapList[0], mapList[-1])) # check if user wants to quit if mapChoice == '0': print 'Exiting bifurcation tool...' break # break out of main loop # else check if valid choice elif mapChoice not in mapList: print '\n-->Invalid choice! Please try again...' continue # skip to beginning of main loop to try again # this is where we actually create a map object OneDMap = maps[mapChoice][1]() # get initial condition from user while True: ic = raw_input('Enter initial condition (leave blank for default of %0.2f): ' \ % OneDMap.defaults[0]).strip() if ic != '': # something was entered try: OneDMap.ic = float(ic) # try saving value to the map object break # break out of loop if valid ic except ValueError: # catch non-numerical input print 'Invalid number... try again' else: # user wants default break # default value is already set, so jump out of loop, go to next prompt # get lower parameter limit while True: rLow = raw_input('Enter lower limit of r (leave blank for default of %0.2f): ' \ % OneDMap.defaults[1]).strip() if rLow != '': # something was entered try: OneDMap.rLow = float(rLow) # try saving value to the map object break # break out of loop if valid ic except ValueError: # catch non-numerical input print 'Invalid number... try again' else: # user wants default break # default value is already set, so jump out of loop, go to next prompt # get upper parameter limit while True: rHi = raw_input('Enter upper limit of r (leave blank for default of %0.2f): ' \ % OneDMap.defaults[2]).strip() if rHi != '': # something was entered try: OneDMap.rHi = float(rHi) # try saving value to the map object break # break out of loop if valid ic except ValueError: # catch non-numerical input print 'Invalid number... try again' else: # user wants default break # default value is already set, so jump out of loop, go to next prompt # now compute and plot the bifurcation diagram OneDMap.plotBifn() # delete object before creating a new one del OneDMap ## end main loop ## # OneDMaps.py # import in a try-except statement in case a module is not installed try: import numpy as np import matplotlib.pyplot as plt except ImportError, msg: # catch any import exceptions, print error message print 'Error importing modules:', msg class OneDimMap(): """ Base class for all map classes. This provides methods common to all map classes. """ def __init__(self): """Constructor for the OneDMap base class.""" # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.0, 0.0, 1.0] self.resetVals() # set map values to defaults self.mapStr = 'One Dimensional Map f(x) = x' # place holder for map string def __repr__(self): """String representation of map.""" return self.mapStr # defined in __init__ def func(self, x): """Returns f(x). This is a place holder for all map classes.""" return x # in this case, f(x) = x def iterate(self, num_its): """Iterates the map num_its times and saves the state.""" for n in xrange(num_its): self.state = self.func(self.state) # compute the maps's function # state of last iteration is saved in self.state def plotBifn(self): """Generate and display a bifurcation plot of the map.""" plt.figure() # Title for plot plt.title(self.mapStr + ', bifurcation diagram for r in [%g,%g]' \ % (self.rLow,self.rHi)) # Label axes plt.xlabel('Control parameter r') plt.ylabel('{X(n)}') # The iterates we'll throw away nTransients = 200 # This sets how much the attractor is filled in nIterates = 250 # This sets how dense the bifurcation diagram will be nSteps = 400 # Sweep the control parameter over the desired range rInc = (self.rHi-self.rLow)/float(nSteps) for self.r in np.arange(self.rLow, self.rHi, rInc): # Set the initial condition to the reference value self.state = self.ic # Throw away the transient iterations self.iterate(nTransients) # Now store the next batch of iterates rsweep = np.repeat(self.r, nIterates)   # array of parameter values x = [ ]        # The iterates for i in xrange(nIterates): self.iterate(1) x.append( self.state ) plt.plot(rsweep, x, 'k,') # Plot the list of (r,x) pairs as pixels plt.show() def resetVals(self): """Set map values to their respective defaults.""" # set default values for state and parameters/limits self.ic = self.defaults[0] self.state = self.defaults[0] self.r = self.defaults[1] self.rLow = self.defaults[1] self.rHi = self.defaults[2] ## end class OneDMap ## class LogisticMap(OneDimMap): """The logistic map class.""" def __init__(self): """Constructor for a LogisticMap object.""" OneDimMap.__init__(self) # invoke constructor of base class # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.3, 0.0, 4.0] self.resetVals() # descriptive string of map self.mapStr = 'Logistic Map: f(x) = r*x*(1-x)' def func(self, x): """Computes the logistic map.""" return self.r * self.state * (1.0 - self.state) ## end class LogisticMap ## class CosineMap(OneDimMap): """The cosine map class.""" def __init__(self): """Constructor for a CosineMap object.""" OneDimMap.__init__(self) # invoke constructor of base class # list of defaults in this order: [ ic, r low, r high ] self.defaults = [0.3, -5.0, 5.0] self.resetVals() # descriptive string of map self.mapStr = 'Cosine Map: f(x)=r*cos(x)' def func(self, x): """Computes the cosine map.""" return self.r * np.cos(self.state) ## end class CosineMap ##