def _match_error_to_data_set(x, ex): """ Inflates ex to match the dimensionality of x, "intelligently". x is assumed to be a 2D array. """ # Simplest case, ex is None or a number if not _fun.is_iterable(ex): # Just make a matched list of Nones if ex is None: ex = [ex] * len(x) # Make arrays of numbers if _fun.is_a_number(ex): value = ex # temporary storage ex = [] for n in range(len(x)): ex.append([value] * len(x[n])) # Otherwise, ex is iterable # Default behavior: If the elements are all numbers and the length matches # that of the first x-array, assume this is meant to match all the x # data sets if _fun.elements_are_numbers(ex) and len(ex) == len(x[0]): ex = [ex] * len(x) # The user may specify a list of some iterable and some not. Assume # in this case that at least the lists are the same length for n in range(len(x)): # do nothing to the None's # Inflate single numbers to match if _fun.is_a_number(ex[n]): ex[n] = [ex[n]] * len(x[n]) return ex
def execute_script(self, script, g={}): """ Runs a script, returning the result. Scripts are of the form: "3.0 + x/y - self[0] where x=3.0*c('my_column')+h('setting'); y=c(1)" "self" refers to the data object, giving access to everything, enabling complete control over the universe. c() and h() give quick reference to self.c() and self.h() to get columns and header lines Additionally, these scripts can see all of the numpy functions like sin, cos, sqrt, etc. Finally, if you would like access to additional globals, set self.extra_globals to the appropriate globals dictionary or add globals using insert_global(). Setting g=globals() will automatically insert your globals into this databox instance. There are a few shorthand scripts available as well. You can simply type a column name such as "my_column" or a column number like 2. However, I only added this functionality as a shortcut, and something like "2.0*a where a=F" will not work unless F is defined somehow. I figure since you're already writing a complicated script, you don't want to accidentally shortcut your way into using a column instead of a constant! Use "2.0*a where a=c('F')" instead. NOTE: You shouldn't try to use variables like 'c=...' or 'h=...' because they are already column and header functions! """ if self.debug: print "Generating column '"+str(name)+"' = "+str(script)+"..." # add any extra user-supplied global variables for the eventual eval() call. self.extra_globals.update(g) g = {} # clear out the existing dictionary # If the script is not a list of scripts, return the script value. # This is the termination of a recursive call. if not _fun.is_iterable(script): if script == None: return None # get the expression and variables [expression, v] = self._parse_script(script) # if there was a problem parsing the script if v == None: print "ERROR: Could not parse '"+script+"'" return None # otherwise, evaluate the script using python's eval command return eval(expression, v) # Otherwise, this is a list of scripts. Make the recursive call. output = [] for s in script: output.append(self.execute_script(s)) return output
def _match_data_sets(x,y): """ Makes sure everything is the same shape. "Intelligently". """ # Handle the None for x or y if x is None or len(x) == 0: # If x is none, y can be either [1,2] or [[1,2],[1,2]] if _fun.is_iterable(y[0]): # make an array of arrays to match x = [] for n in range(len(y)): x.append(list(range(len(y[n])))) else: x = list(range(len(y))) if y is None or len(y) == 0: # If y is none, x can be either [1,2] or [[1,2],[1,2]] if _fun.is_iterable(x[0]): # make an array of arrays to match y = [] for n in range(len(x)): y.append(list(range(len(x[n])))) else: y = list(range(len(x))) # At this point they should be matched, but may still be 1D # Default behavior: if all elements are numbers in both, assume they match if _fun.elements_are_numbers(x): x=[x] if _fun.elements_are_numbers(y): y=[y] # Make sure they are both lists (so append works!) if not type(x) == list: x = list(x) if not type(y) == list: y = list(y) # Make sure they're the same length while len(x) > len(y): y.append(y[-1]) while len(y) > len(x): x.append(x[-1]) # Second default behavior: shared array [1,2,3], [[1,2,1],[1,2,1]] or vis versa if _fun.elements_are_numbers(x) and not _fun.elements_are_numbers(y): x = [x]*len(y) if _fun.elements_are_numbers(y) and not _fun.elements_are_numbers(x): y = [y]*len(x) # Clean up any remaining Nones for n in range(len(x)): if x[n] is None: x[n] = list(range(len(y[n]))) if y[n] is None: y[n] = list(range(len(x[n]))) return x, y
def _match_data_sets(x, y): """ Makes sure everything is the same shape. "Intelligently". """ # Handle the None for x or y if x is None: # If x is none, y can be either [1,2] or [[1,2],[1,2]] if _fun.is_iterable(y[0]): # make an array of arrays to match x = [] for n in range(len(y)): x.append(list(range(len(y[n])))) else: x = list(range(len(y))) if y is None: # If x is none, y can be either [1,2] or [[1,2],[1,2]] if _fun.is_iterable(x[0]): # make an array of arrays to match y = [] for n in range(len(x)): y.append(list(range(len(x[n])))) else: y = list(range(len(x))) # At this point they should be matched, but may still be 1D # Default behavior: if all elements are numbers in both, assume they match if _fun.elements_are_numbers(x) and _fun.elements_are_numbers(y): x = [x] y = [y] # Second default behavior: shared array [1,2,3], [[1,2,1],[1,2,1]] or vis versa if _fun.elements_are_numbers(x) and not _fun.elements_are_numbers(y): x = [x] * len(y) if _fun.elements_are_numbers(y) and not _fun.elements_are_numbers(x): y = [y] * len(x) # Clean up any remaining Nones for n in range(len(x)): if x[n] is None: x[n] = list(range(len(y[n]))) if y[n] is None: y[n] = list(range(len(x[n]))) return x, y
def _match_error_to_data_set(x, ex): """ Inflates ex to match the dimensionality of x, "intelligently". x is assumed to be a 2D array. """ # Simplest case, ex is None or a number if not _fun.is_iterable(ex): # Just make a matched list of Nones if ex is None: ex = [ex]*len(x) # Make arrays of numbers if _fun.is_a_number(ex): value = ex # temporary storage ex = [] for n in range(len(x)): ex.append([value]*len(x[n])) # At this point, ex is iterable # Default behavior: If the elements are all numbers and the length matches # that of the first x-array, assume this is meant to match all the x # data sets if _fun.elements_are_numbers(ex) and len(ex) == len(x[0]): ex = [ex]*len(x) # Make sure it's a list (for appending) if not type(ex) == list: ex = list(ex) # The user may specify a list of some iterable and some not. # The list length may not match while len(ex) < len(x): ex.append(ex[-1]) # Now they are the same length for n in range(len(x)): # do nothing to the None's # Inflate single numbers to match if _fun.is_a_number(ex[n]): ex[n] = [ex[n]]*len(x[n]) return ex
def databoxes(ds, xscript=0, yscript=1, eyscript=None, exscript=None, plotter=xy_data, **kwargs): """ Plots the listed databox objects with the specified scripts. ds list of databoxes xscript script for x data yscript script for y data eyscript script for y error exscript script for x error plotter function used to do the plotting **kwargs are sent to plotter() """ if not _fun.is_iterable(ds): ds = [ds] if not kwargs.has_key('xlabel'): kwargs['xlabel'] = str(xscript) if not kwargs.has_key('ylabel'): kwargs['ylabel'] = str(yscript) # First make sure everything is a list of scripts (or None's) if not _fun.is_iterable(xscript): xscript = [xscript] if not _fun.is_iterable(yscript): yscript = [yscript] if not _fun.is_iterable(exscript): exscript = [exscript] if not _fun.is_iterable(eyscript): eyscript = [eyscript] # make sure exscript matches shape with xscript (and the same for y) if len(exscript) < len(xscript): for n in range(len(xscript) - 1): exscript.append(exscript[0]) if len(eyscript) < len(yscript): for n in range(len(yscript) - 1): eyscript.append(eyscript[0]) # Make xscript and exscript match in shape with yscript and eyscript if len(xscript) < len(yscript): for n in range(len(yscript) - 1): xscript.append(xscript[0]) exscript.append(exscript[0]) # check for the reverse possibility if len(yscript) < len(xscript): for n in range(len(xscript) - 1): yscript.append(yscript[0]) eyscript.append(eyscript[0]) # now check for None's (counting scripts) for n in range(len(xscript)): if xscript[n] == None and yscript[n] == None: print "Two None scripts? But why?" return if xscript[n] == None: if type(yscript[n]) == str: xscript[n] = 'range(len(' + yscript[n] + '))' else: xscript[n] = 'range(len(c(' + str(yscript[n]) + ')))' if yscript[n] == None: if type(xscript[n]) == str: yscript[n] = 'range(len(' + xscript[n] + '))' else: yscript[n] = 'range(len(c(' + str(xscript[n]) + ')))' xdatas = [] ydatas = [] exdatas = [] eydatas = [] labels = [] for d in ds: xdata = d(xscript) for n in range(len(xdata)): xdatas.append(xdata[n]) if len(xdata) > 1: labels.append(str(n) + ": " + _os.path.split(d.path)[-1]) else: labels.append(_os.path.split(d.path)[-1]) for y in d(yscript): ydatas.append(y) for x in d(exscript): exdatas.append(x) for y in d(eyscript): eydatas.append(y) if kwargs.has_key("label"): labels = kwargs.pop("label") plotter(xdatas, ydatas, eydatas, exdatas, label=labels, **kwargs)
def xy_data(xdata, ydata, eydata=None, exdata=None, label=None, xlabel='', ylabel='', \ title='', shell_history=1, xshift=0, yshift=0, xshift_every=1, yshift_every=1, \ coarsen=0, style=None, clear=True, axes=None, xscale='linear', yscale='linear', grid=False, \ legend='best', legend_max=20, autoformat=True, tall=False, draw=True, **kwargs): """ Plots specified data. xdata, ydata Arrays (or arrays of arrays) of data to plot eydata, exdata Arrays of x and y errorbar values label string or array of strings for the line labels xlabel='' label for the x-axis ylabel='' label for the y-axis title='' title for the axes; set to None to have nothing. shell_history=1 how many commands from the pyshell history to include with the title xshift=0, yshift=0 progressive shifts on the data, to make waterfall plots xshift_every=1 perform the progressive shift every 1 or n'th line. yshift_every=1 perform the progressive shift every 1 or n'th line. style style cycle object. clear=True if no axes are specified, clear the figure, otherwise clear just the axes. axes=None which axes to use, or "gca" for the current axes xscale,yscale 'linear' by default. Set either to 'log' for log axes grid=False Should we draw a grid on the axes? legend='best' where to place the legend (see pylab.legend()) Set this to None to ignore the legend. legend_max=20 number of legend entries before it's truncated with '...' autoformat=True Should we format the figure for printing? False Should the format be tall? draw=True whether or not to draw the plot after plotting **kwargs are sent to pylab.errorbar() """ _pylab.ioff() # make sure everything is at least iterable. if not _fun.is_iterable(xdata): xdata = [xdata] if not _fun.is_iterable(exdata): exdata = [exdata] if not _fun.is_iterable(ydata): ydata = [ydata] if not _fun.is_iterable(eydata): eydata = [eydata] # make sure at least xdata and ydata are 2-D if _fun.is_a_number(xdata[0]): xdata = [xdata] if _fun.is_a_number(ydata[0]): ydata = [ydata] # make sure the number of data sets agrees N = max(len(xdata), len(ydata)) for n in range(N - len(xdata)): xdata.append(xdata[0]) for n in range(N - len(ydata)): ydata.append(ydata[0]) for n in range(N - len(exdata)): exdata.append(exdata[0]) for n in range(N - len(eydata)): eydata.append(eydata[0]) # loop over each x and y data set, making sure None's are all converted # to counting arrays for n in range(N): # clean up the [None]'s if _fun.is_iterable(xdata[n]) and xdata[n][0] == None: xdata[n] = None if _fun.is_iterable(ydata[n]) and ydata[n][0] == None: ydata[n] = None if xdata[n] == None and ydata[n] == None: print "ERROR: " + str(n) + "'th data set is (None, None)." return if xdata[n] == None: xdata[n] = _n.arange(len(ydata[n])) if ydata[n] == None: ydata[n] = _n.arange(len(xdata[n])) # check that the labels is a list of strings of the same length if not _fun.is_iterable(label): label = [label] * N while len(label) < len(ydata): label.append(label[0]) # concatenate if necessary if len(label) > legend_max: label[legend_max - 2] = '...' for n in range(legend_max - 1, len(label) - 1): label[n] = "_nolegend_" # clear the figure? if clear and not axes: _pylab.gcf().clear() # axes cleared later # setup axes if axes == "gca" or axes == None: axes = _pylab.gca() # if we're clearing the axes if clear: axes.clear() # set the current axes _pylab.axes(axes) # now loop over the list of data in xdata and ydata for n in range(0, len(xdata)): # get the label if label: l = str(label[n]) else: l = str(n) # calculate the x an y progressive shifts dx = xshift * (n / xshift_every) dy = yshift * (n / yshift_every) # if we're supposed to coarsen the data, do so. x = _fun.coarsen_array(xdata[n], coarsen) y = _fun.coarsen_array(ydata[n], coarsen) ey = _fun.coarsen_array(eydata[n], coarsen, 'quadrature') ex = _fun.coarsen_array(exdata[n], coarsen, 'quadrature') # update the style if not style == None: kwargs.update(style.next()) axes.errorbar(x + dx, y + dy, label=l, yerr=ey, xerr=ex, **kwargs) _pylab.xscale(xscale) _pylab.yscale(yscale) if legend: axes.legend(loc=legend) axes.set_xlabel(xlabel) axes.set_ylabel(ylabel) # for some arguments there should be no title. if title in [None, False, 0]: axes.set_title('') # add the commands to the title else: title = str(title) history = _fun.get_shell_history() for n in range(0, min(shell_history, len(history))): title = title + "\n" + history[n].split('\n')[0].strip() title = title + '\nPlot created ' + _time.asctime() axes.set_title(title) if grid: _pylab.grid(True) if autoformat: _pt.format_figure(draw=False) _pt.auto_zoom(axes=axes, draw=False) # update the canvas if draw: _pylab.ion() _pylab.draw() _pylab.show() return axes
def databoxes(ds, xscript=0, yscript=1, eyscript=None, exscript=None, plotter=xy_data, **kwargs): """ Plots the listed databox objects with the specified scripts. ds list of databoxes xscript script for x data yscript script for y data eyscript script for y error exscript script for x error plotter function used to do the plotting **kwargs are sent to plotter() """ if not _fun.is_iterable(ds): ds = [ds] if not kwargs.has_key('xlabel'): kwargs['xlabel'] = str(xscript) if not kwargs.has_key('ylabel'): kwargs['ylabel'] = str(yscript) # First make sure everything is a list of scripts (or None's) if not _fun.is_iterable(xscript): xscript = [xscript] if not _fun.is_iterable(yscript): yscript = [yscript] if not _fun.is_iterable(exscript): exscript = [exscript] if not _fun.is_iterable(eyscript): eyscript = [eyscript] # make sure exscript matches shape with xscript (and the same for y) if len(exscript) < len(xscript): for n in range(len(xscript)-1): exscript.append(exscript[0]) if len(eyscript) < len(yscript): for n in range(len(yscript)-1): eyscript.append(eyscript[0]) # Make xscript and exscript match in shape with yscript and eyscript if len(xscript) < len(yscript): for n in range(len(yscript)-1): xscript.append(xscript[0]) exscript.append(exscript[0]) # check for the reverse possibility if len(yscript) < len(xscript): for n in range(len(xscript)-1): yscript.append(yscript[0]) eyscript.append(eyscript[0]) # now check for None's (counting scripts) for n in range(len(xscript)): if xscript[n] is None and yscript[n] is None: print "Two None scripts? But why?" return if xscript[n] is None: if type(yscript[n])==str: xscript[n] = 'range(len('+yscript[n]+'))' else: xscript[n] = 'range(len(c('+str(yscript[n])+')))' if yscript[n] is None: if type(xscript[n])==str: yscript[n] = 'range(len('+xscript[n]+'))' else: yscript[n] = 'range(len(c('+str(xscript[n])+')))' xdatas = [] ydatas = [] exdatas = [] eydatas = [] labels = [] for d in ds: xdata = d(xscript) for n in range(len(xdata)): xdatas.append(xdata[n]) if len(xdata)>1: labels.append(str(n)+": "+_os.path.split(d.path)[-1]) else: labels.append(_os.path.split(d.path)[-1]) for y in d(yscript): ydatas.append(y) for x in d(exscript): exdatas.append(x) for y in d(eyscript): eydatas.append(y) if kwargs.has_key("label"): labels = kwargs.pop("label") plotter(xdatas, ydatas, eydatas, exdatas, label=labels, **kwargs)
def xy_data(xdata, ydata, eydata=None, exdata=None, label=None, xlabel='', ylabel='', \ title='', shell_history=1, xshift=0, yshift=0, xshift_every=1, yshift_every=1, \ coarsen=0, style=None, clear=True, axes=None, xscale='linear', yscale='linear', grid=False, \ legend='best', legend_max=20, autoformat=True, tall=False, draw=True, **kwargs): """ Plots specified data. xdata, ydata Arrays (or arrays of arrays) of data to plot eydata, exdata Arrays of x and y errorbar values label string or array of strings for the line labels xlabel='' label for the x-axis ylabel='' label for the y-axis title='' title for the axes; set to None to have nothing. shell_history=1 how many commands from the pyshell history to include with the title xshift=0, yshift=0 progressive shifts on the data, to make waterfall plots xshift_every=1 perform the progressive shift every 1 or n'th line. yshift_every=1 perform the progressive shift every 1 or n'th line. style style cycle object. clear=True if no axes are specified, clear the figure, otherwise clear just the axes. axes=None which axes to use, or "gca" for the current axes xscale,yscale 'linear' by default. Set either to 'log' for log axes grid=False Should we draw a grid on the axes? legend='best' where to place the legend (see pylab.legend()) Set this to None to ignore the legend. legend_max=20 number of legend entries before it's truncated with '...' autoformat=True Should we format the figure for printing? False Should the format be tall? draw=True whether or not to draw the plot after plotting **kwargs are sent to pylab.errorbar() """ _pylab.ioff() # make sure everything is at least iterable. if not _fun.is_iterable(xdata): xdata = [xdata] if not _fun.is_iterable(exdata): exdata = [exdata] if not _fun.is_iterable(ydata): ydata = [ydata] if not _fun.is_iterable(eydata): eydata = [eydata] # make sure at least xdata and ydata are 2-D if _fun.is_a_number(xdata[0]): xdata = [xdata] if _fun.is_a_number(ydata[0]): ydata = [ydata] # make sure the number of data sets agrees N = max(len(xdata),len(ydata)) for n in range(N-len( xdata)): xdata.append( xdata[0]) for n in range(N-len( ydata)): ydata.append( ydata[0]) for n in range(N-len(exdata)): exdata.append(exdata[0]) for n in range(N-len(eydata)): eydata.append(eydata[0]) # loop over each x and y data set, making sure None's are all converted # to counting arrays for n in range(N): # clean up the [None]'s if _fun.is_iterable(xdata[n]) and xdata[n][0] is None: xdata[n] = None if _fun.is_iterable(ydata[n]) and ydata[n][0] is None: ydata[n] = None if xdata[n] is None and ydata[n] is None: print "ERROR: "+str(n)+"'th data set is (None, None)." return if xdata[n] is None: xdata[n] = _n.arange(len(ydata[n])) if ydata[n] is None: ydata[n] = _n.arange(len(xdata[n])) # check that the labels is a list of strings of the same length if not _fun.is_iterable(label): label = [label]*N while len(label) < len(ydata): label.append(label[0]) # concatenate if necessary if len(label) > legend_max: label[legend_max-2] = '...' for n in range(legend_max-1,len(label)-1): label[n] = "_nolegend_" # clear the figure? if clear and not axes: _pylab.gcf().clear() # axes cleared later # setup axes if axes=="gca" or axes is None: axes = _pylab.gca() # if we're clearing the axes if clear: axes.clear() # set the current axes _pylab.axes(axes) # now loop over the list of data in xdata and ydata for n in range(0,len(xdata)): # get the label if label: l = str(label[n]) else: l = str(n) # calculate the x an y progressive shifts dx = xshift*(n/xshift_every) dy = yshift*(n/yshift_every) # if we're supposed to coarsen the data, do so. x = _fun.coarsen_array(xdata[n], coarsen) y = _fun.coarsen_array(ydata[n], coarsen) ey = _fun.coarsen_array(eydata[n], coarsen, 'quadrature') ex = _fun.coarsen_array(exdata[n], coarsen, 'quadrature') # update the style if not style is None: kwargs.update(style.next()) axes.errorbar(x+dx, y+dy, label=l, yerr=ey, xerr=ex, **kwargs) _pylab.xscale(xscale) _pylab.yscale(yscale) if legend: axes.legend(loc=legend) axes.set_xlabel(xlabel) axes.set_ylabel(ylabel) # for some arguments there should be no title. if title in [None, False, 0]: axes.set_title('') # add the commands to the title else: title = str(title) history = _fun.get_shell_history() for n in range(0, min(shell_history, len(history))): title = title + "\n" + history[n].split('\n')[0].strip() title = title + '\nPlot created ' + _time.asctime() axes.set_title(title) if grid: _pylab.grid(True) if autoformat: _pt.format_figure(draw=False) _pt.auto_zoom(axes=axes, draw=False) # update the canvas if draw: _pylab.ion() _pylab.draw() _pylab.show() return axes
def xy_data(xdata, ydata, eydata=None, exdata=None, label=None, xlabel='', ylabel='', \ title='', shell_history=0, xshift=0, yshift=0, xshift_every=1, yshift_every=1, \ coarsen=0, style=None, clear=True, axes=None, xscale='linear', yscale='linear', grid=False, \ legend='best', legend_max=20, autoformat=True, autoformat_window=True, tall=False, draw=True, **kwargs): """ Plots specified data. Parameters ---------- xdata, ydata Arrays (or arrays of arrays) of data to plot eydata=None, exdata=None Arrays of x and y errorbar values label=None String or array of strings for the line labels xlabel='' Label for the x-axis ylabel='' Label for the y-axis title='' Title for the axes; set to None to have nothing. shell_history=0 How many commands from the pyshell history to include with the title xshift=0, yshift=0 Progressive shifts on the data, to make waterfall plots xshift_every=1 Perform the progressive shift every 1 or n'th line. yshift_every=1 perform the progressive shift every 1 or n'th line. style=None style cycle object. clear=True If no axes are specified (see below), clear the figure, otherwise clear just the axes. axes=None Which matplotlib axes to use, or "gca" for the current axes xscale='linear', yscale='linear' 'linear' or 'log' x and y axis scales. grid=False Should we draw a grid on the axes? legend='best' Where to place the legend (see pylab.legend() for options) Set this to None to ignore the legend. legend_max=20 Number of legend entries before it's truncated with '...' autoformat=True Should we format the figure for printing? autoformat_window=True Should we resize and reposition the window when autoformatting? tall=False Should the format be tall? draw=True Whether or not to draw the plot after plotting. See matplotlib's errorbar() function for additional optional keyword arguments. """ _pylab.ioff() # Make sure the dimensionality of the data sets matches xdata, ydata = _match_data_sets(xdata, ydata) exdata = _match_error_to_data_set(xdata, exdata) eydata = _match_error_to_data_set(ydata, eydata) # check that the labels is a list of strings of the same length if not _fun.is_iterable(label): label = [label] * len(xdata) while len(label) < len(ydata): label.append(label[0]) # concatenate if necessary if len(label) > legend_max: label[legend_max - 2] = '...' for n in range(legend_max - 1, len(label) - 1): label[n] = "_nolegend_" # clear the figure? if clear and not axes: _pylab.gcf().clear() # axes cleared later # setup axes if axes == "gca" or axes is None: axes = _pylab.gca() # if we're clearing the axes if clear: axes.clear() # set the current axes _pylab.axes(axes) # now loop over the list of data in xdata and ydata for n in range(0, len(xdata)): # get the label l = str(n) + ": " + str(label[n]) # calculate the x an y progressive shifts dx = xshift * (n / xshift_every) dy = yshift * (n / yshift_every) # if we're supposed to coarsen the data, do so. x = _fun.coarsen_array(xdata[n], coarsen) y = _fun.coarsen_array(ydata[n], coarsen) ey = _fun.coarsen_array(eydata[n], coarsen, 'quadrature') ex = _fun.coarsen_array(exdata[n], coarsen, 'quadrature') # update the style if not style is None: kwargs.update(next(style)) axes.errorbar(x + dx, y + dy, label=l, yerr=ey, xerr=ex, **kwargs) _pylab.xscale(xscale) _pylab.yscale(yscale) if legend: axes.legend(loc=legend) axes.set_xlabel(xlabel) axes.set_ylabel(ylabel) # for some arguments there should be no title. if title in [None, False, 0]: axes.set_title('') # add the commands to the title else: title = str(title) history = _fun.get_shell_history() for n in range(0, min(shell_history, len(history))): title = title + "\n" + history[n].split('\n')[0].strip() title = title + '\nPlot created ' + _time.asctime() axes.set_title(title) if grid: _pylab.grid(True) if autoformat: _pt.format_figure(draw=False, modify_geometry=autoformat_window) _pt.auto_zoom(axes=axes, draw=False) # update the canvas if draw: _pylab.ion() _pylab.draw() _pylab.show() return axes
def databoxes(ds, xscript=0, yscript=1, eyscript=None, exscript=None, g=None, plotter=xy_data, transpose=False, **kwargs): """ Plots the listed databox objects with the specified scripts. ds list of databoxes xscript script for x data yscript script for y data eyscript script for y error exscript script for x error plotter function used to do the plotting transpose applies databox.transpose() prior to plotting g optional dictionary of globals for the supplied scripts **kwargs are sent to plotter() """ if not _fun.is_iterable(ds): ds = [ds] if 'xlabel' not in kwargs: kwargs['xlabel'] = str(xscript) if 'ylabel' not in kwargs: kwargs['ylabel'] = str(yscript) # First make sure everything is a list of scripts (or None's) if not _fun.is_iterable(xscript): xscript = [xscript] if not _fun.is_iterable(yscript): yscript = [yscript] if not _fun.is_iterable(exscript): exscript = [exscript] if not _fun.is_iterable(eyscript): eyscript = [eyscript] # make sure exscript matches shape with xscript (and the same for y) if len(exscript) < len(xscript): for n in range(len(xscript) - 1): exscript.append(exscript[0]) if len(eyscript) < len(yscript): for n in range(len(yscript) - 1): eyscript.append(eyscript[0]) # Make xscript and exscript match in shape with yscript and eyscript if len(xscript) < len(yscript): for n in range(len(yscript) - 1): xscript.append(xscript[0]) exscript.append(exscript[0]) # check for the reverse possibility if len(yscript) < len(xscript): for n in range(len(xscript) - 1): yscript.append(yscript[0]) eyscript.append(eyscript[0]) # now check for None's (counting scripts) for n in range(len(xscript)): if xscript[n] is None and yscript[n] is None: print("Two None scripts? But why?") return if xscript[n] is None: if type(yscript[n]) == str: xscript[n] = 'range(len(' + yscript[n] + '))' else: xscript[n] = 'range(len(c(' + str(yscript[n]) + ')))' if yscript[n] is None: if type(xscript[n]) == str: yscript[n] = 'range(len(' + xscript[n] + '))' else: yscript[n] = 'range(len(c(' + str(xscript[n]) + ')))' xdatas = [] ydatas = [] exdatas = [] eydatas = [] labels = [] # Loop over all the data boxes for i in range(len(ds)): # Reset the default globals all_globals = dict(n=i, m=len(ds) - 1 - i) # Update them with the user-specified globals if not g == None: all_globals.update(g) # For ease of coding d = ds[i] # Take the transpose if necessary if transpose: d = d.transpose() # Generate the x-data; returns a list of outputs, one for each xscript xdata = d(xscript, all_globals) # Loop over each xdata, appending to the master list, and generating a label for n in range(len(xdata)): xdatas.append(xdata[n]) if len(xdata) > 1: labels.append(str(n) + ": " + _os.path.split(d.path)[-1]) else: labels.append(_os.path.split(d.path)[-1]) # Append the other data sets to their master lists for y in d(yscript, all_globals): ydatas.append(y) for x in d(exscript, all_globals): exdatas.append(x) for y in d(eyscript, all_globals): eydatas.append(y) if "label" in kwargs: labels = kwargs.pop("label") plotter(xdatas, ydatas, eydatas, exdatas, label=labels, **kwargs)
def databoxes(ds, xscript=0, yscript=1, eyscript=None, exscript=None, g=None, plotter=xy_data, transpose=False, **kwargs): """ Plots the listed databox objects with the specified scripts. ds list of databoxes xscript script for x data yscript script for y data eyscript script for y error exscript script for x error plotter function used to do the plotting transpose applies databox.transpose() prior to plotting g optional dictionary of globals for the supplied scripts **kwargs are sent to plotter() """ if not _fun.is_iterable(ds): ds = [ds] if 'xlabel' not in kwargs: kwargs['xlabel'] = str(xscript) if 'ylabel' not in kwargs: kwargs['ylabel'] = str(yscript) # First make sure everything is a list of scripts (or None's) if not _fun.is_iterable(xscript): xscript = [xscript] if not _fun.is_iterable(yscript): yscript = [yscript] if not _fun.is_iterable(exscript): exscript = [exscript] if not _fun.is_iterable(eyscript): eyscript = [eyscript] # make sure exscript matches shape with xscript (and the same for y) if len(exscript) < len(xscript): for n in range(len(xscript)-1): exscript.append(exscript[0]) if len(eyscript) < len(yscript): for n in range(len(yscript)-1): eyscript.append(eyscript[0]) # Make xscript and exscript match in shape with yscript and eyscript if len(xscript) < len(yscript): for n in range(len(yscript)-1): xscript.append(xscript[0]) exscript.append(exscript[0]) # check for the reverse possibility if len(yscript) < len(xscript): for n in range(len(xscript)-1): yscript.append(yscript[0]) eyscript.append(eyscript[0]) # now check for None's (counting scripts) for n in range(len(xscript)): if xscript[n] is None and yscript[n] is None: print("Two None scripts? But why?") return if xscript[n] is None: if type(yscript[n])==str: xscript[n] = 'range(len('+yscript[n]+'))' else: xscript[n] = 'range(len(c('+str(yscript[n])+')))' if yscript[n] is None: if type(xscript[n])==str: yscript[n] = 'range(len('+xscript[n]+'))' else: yscript[n] = 'range(len(c('+str(xscript[n])+')))' xdatas = [] ydatas = [] exdatas = [] eydatas = [] labels = [] # Loop over all the data boxes for i in range(len(ds)): # Reset the default globals all_globals = dict(n=i,m=len(ds)-1-i) # Update them with the user-specified globals if not g==None: all_globals.update(g) # For ease of coding d = ds[i] # Take the transpose if necessary if transpose: d = d.transpose() # Generate the x-data; returns a list of outputs, one for each xscript xdata = d(xscript, all_globals) # Loop over each xdata, appending to the master list, and generating a label for n in range(len(xdata)): xdatas.append(xdata[n]) if len(xdata)>1: labels.append(str(n)+": "+_os.path.split(d.path)[-1]) else: labels.append(_os.path.split(d.path)[-1]) # Append the other data sets to their master lists for y in d( yscript, all_globals): ydatas.append(y) for x in d(exscript, all_globals): exdatas.append(x) for y in d(eyscript, all_globals): eydatas.append(y) if "label" in kwargs: labels = kwargs.pop("label") plotter(xdatas, ydatas, eydatas, exdatas, label=labels, **kwargs)
def xy_data(xdata, ydata, eydata=None, exdata=None, label=None, xlabel='', ylabel='', \ title='', shell_history=0, xshift=0, yshift=0, xshift_every=1, yshift_every=1, \ coarsen=0, style=None, clear=True, axes=None, xscale='linear', yscale='linear', grid=False, \ legend='best', legend_max=20, autoformat=True, autoformat_window=True, tall=False, draw=True, **kwargs): """ Plots specified data. Parameters ---------- xdata, ydata Arrays (or arrays of arrays) of data to plot eydata=None, exdata=None Arrays of x and y errorbar values label=None String or array of strings for the line labels xlabel='' Label for the x-axis ylabel='' Label for the y-axis title='' Title for the axes; set to None to have nothing. shell_history=0 How many commands from the pyshell history to include with the title xshift=0, yshift=0 Progressive shifts on the data, to make waterfall plots xshift_every=1 Perform the progressive shift every 1 or n'th line. yshift_every=1 perform the progressive shift every 1 or n'th line. style=None style cycle object. clear=True If no axes are specified (see below), clear the figure, otherwise clear just the axes. axes=None Which matplotlib axes to use, or "gca" for the current axes xscale='linear', yscale='linear' 'linear' or 'log' x and y axis scales. grid=False Should we draw a grid on the axes? legend='best' Where to place the legend (see pylab.legend() for options) Set this to None to ignore the legend. legend_max=20 Number of legend entries before it's truncated with '...' autoformat=True Should we format the figure for printing? autoformat_window=True Should we resize and reposition the window when autoformatting? tall=False Should the format be tall? draw=True Whether or not to draw the plot after plotting. See matplotlib's errorbar() function for additional optional keyword arguments. """ _pylab.ioff() # Make sure the dimensionality of the data sets matches xdata, ydata = _match_data_sets(xdata, ydata) exdata = _match_error_to_data_set(xdata, exdata) eydata = _match_error_to_data_set(ydata, eydata) # check that the labels is a list of strings of the same length if not _fun.is_iterable(label): label = [label]*len(xdata) while len(label) < len(ydata): label.append(label[0]) # concatenate if necessary if len(label) > legend_max: label[legend_max-2] = '...' for n in range(legend_max-1,len(label)-1): label[n] = "_nolegend_" # clear the figure? if clear and not axes: _pylab.gcf().clear() # axes cleared later # setup axes if axes=="gca" or axes is None: axes = _pylab.gca() # if we're clearing the axes if clear: axes.clear() # set the current axes _pylab.axes(axes) # now loop over the list of data in xdata and ydata for n in range(0,len(xdata)): # get the label if label[n]=='_nolegend_': l = '_nolegend_' else: l = str(n)+": "+str(label[n]) # calculate the x an y progressive shifts dx = xshift*(n/xshift_every) dy = yshift*(n/yshift_every) # if we're supposed to coarsen the data, do so. x = _fun.coarsen_array(xdata[n], coarsen) y = _fun.coarsen_array(ydata[n], coarsen) ey = _fun.coarsen_array(eydata[n], coarsen, 'quadrature') ex = _fun.coarsen_array(exdata[n], coarsen, 'quadrature') # update the style if not style is None: kwargs.update(next(style)) axes.errorbar(x+dx, y+dy, label=l, yerr=ey, xerr=ex, **kwargs) _pylab.xscale(xscale) _pylab.yscale(yscale) if legend: axes.legend(loc=legend) axes.set_xlabel(xlabel) axes.set_ylabel(ylabel) # for some arguments there should be no title. if title in [None, False, 0]: axes.set_title('') # add the commands to the title else: title = str(title) history = _fun.get_shell_history() for n in range(0, min(shell_history, len(history))): title = title + "\n" + history[n].split('\n')[0].strip() title = title + '\nPlot created ' + _time.asctime() axes.set_title(title) if grid: _pylab.grid(True) if autoformat: _pt.format_figure(draw=False, modify_geometry=autoformat_window) _pt.auto_zoom(axes=axes, draw=False) # update the canvas if draw: _pylab.ion() _pylab.draw() _pylab.show() return axes
def _match_data_sets(x,y): """ Makes sure everything is the same shape. "Intelligently". """ # If x is a value, use this for the step size. dx = 1.0 if _fun.is_a_number(x): dx = x x = None # Handle the None for x or y if x is None or len(x) == 0: # If x is None, y can be either [1,2] or [[1,2],[1,2]] or [] if len(y) == 0: x = [] elif _fun.is_iterable(y[0]): # make an array of arrays to match x = [] for n in range(len(y)): x.append(list(dx*_n.array(range(len(y[n]))))) else: x = list(range(len(y))) # If y is a value, use this for the step size. dy = 1.0 if _fun.is_a_number(y): dy = y y = None if y is None or len(y) == 0: # If y is none, x can be either [1,2] or [[1,2],[1,2]] or [] if len(x) == 0: y = [] elif _fun.is_iterable(x[0]): # make an array of arrays to match y = [] for n in range(len(x)): y.append(list(dy*_n.array(range(len(x[n]))))) else: y = list(range(len(x))) # At this point they should be matched, but may still be 1D # Default behavior: if all elements are numbers in both, assume they match if _fun.elements_are_numbers(x): x=[x] if _fun.elements_are_numbers(y): y=[y] # Make sure they are both lists (so append works!) if not type(x) == list: x = list(x) if not type(y) == list: y = list(y) # Make sure they're the same length while len(x) > len(y): y.append(y[-1]) while len(y) > len(x): x.append(x[-1]) # Second default behavior: shared array [1,2,3], [[1,2,1],[1,2,1]] or vis versa if _fun.elements_are_numbers(x) and not _fun.elements_are_numbers(y): x = [x]*len(y) if _fun.elements_are_numbers(y) and not _fun.elements_are_numbers(x): y = [y]*len(x) # Clean up any remaining Nones for n in range(len(x)): if x[n] is None: x[n] = list(range(len(y[n]))) if y[n] is None: y[n] = list(range(len(x[n]))) return x, y
def execute_script(self, script, g={}): """ Runs a script, returning the result. Scripts are of the form: "3.0 + x/y - self[0] where x=3.0*c('my_column')+h('setting'); y=c(1)" "self" refers to the data object, giving access to everything, enabling complete control over the universe. c() and h() give quick reference to self.c() and self.h() to get columns and header lines Additionally, these scripts can see all of the numpy functions like sin, cos, sqrt, etc. Finally, if you would like access to additional globals, set self.extra_globals to the appropriate globals dictionary or add globals using insert_global(). Setting g=globals() will automatically insert your globals into this databox instance. There are a few shorthand scripts available as well. You can simply type a column name such as "my_column" or a column number like 2. However, I only added this functionality as a shortcut, and something like "2.0*a where a=F" will not work unless F is defined somehow. I figure since you're already writing a complicated script, you don't want to accidentally shortcut your way into using a column instead of a constant! Use "2.0*a where a=c('F')" instead. NOTE: You shouldn't try to use variables like 'c=...' or 'h=...' because they are already column and header functions! """ if self.debug: print "Generating column '" + str(name) + "' = " + str( script) + "..." # add any extra user-supplied global variables for the eventual eval() call. self.extra_globals.update(g) g = {} # clear out the existing dictionary # If the script is not a list of scripts, return the script value. # This is the termination of a recursive call. if not _fun.is_iterable(script): if script == None: return None # get the expression and variables [expression, v] = self._parse_script(script) # if there was a problem parsing the script if v == None: print "ERROR: Could not parse '" + script + "'" return None # otherwise, evaluate the script using python's eval command return eval(expression, v) # Otherwise, this is a list of scripts. Make the recursive call. output = [] for s in script: output.append(self.execute_script(s)) return output