def set_curve( self, prop ): """ Set point properties. The same properties are applied to all the point associated with this dataset. Curves are used to show the standard deviation, sdev. The sdev is drawn as an "error", err. >>> b.set_curve("err.color=red") >>> b.set_curve(["symbol.style", "square"]) >>> b.set_curve( { 'symbol.size' : '4' }) >>> p = ChipsCurve() >>> p.err.style = "cap" >>> b.set_curve(p) """ open_undo_block() self._restore_plot() if self.all_curves: for xx in self.all_curves: set_curve( xx, prop ) self.curve = get_curve( self.all_curves[0]) else: self.curve = prop close_undo_block()
def set_line( self, prop ): """ Set line properties. The same properties are applied to all the lines associated with this dataset. Lines are used to show the "limit" (min to max). >>> b.set_line("color=red") >>> b.set_line(["style", "dot"]) >>> b.set_line( { 'thickness' : '2' }) >>> l = ChipsLine() >>> l.color = "FFFF00" >>> b.set_line(l) """ open_undo_block() self._restore_plot() if self.all_lines: for xx in self.all_lines: set_line(xx, prop) self.line = get_line( self.all_lines[0] ) else: self.line = prop close_undo_block()
def set_point( self, prop ): """ Set point properties. The same properties are applied to all the point associated with this dataset. Points are used to show the mean value. >>> b.set_point("color=red") >>> b.set_point(["style", "square"]) >>> b.set_point( { 'size' : '4' }) >>> p = ChipsPoint() >>> p.fill = False >>> b.set_point(p) """ open_undo_block() self._restore_plot() if self.all_points: for xx in self.all_points: set_point( xx, prop ) self.point = get_point( self.all_points[0] ) else: self.point = prop close_undo_block()
def __init__(self, reverse=False): if len( self._get_all_object_name("Window")) != 1: raise NotImplementedError("Must have one and only one window") if len( self._get_all_object_name("Frame")) != 1: raise NotImplementedError("Must have one and only one frame") if len( self._get_all_object_name("Plot")) != 1: raise NotImplementedError("Must have one and only one plot") if len( self._get_all_object_name("Curve")) == 0: raise NotImplementedError("Must have at least one curve.") if len( self._get_all_object_name("Curve")) >= 7: print "Warning: Large number of curves found. This routine works best when there are fewer than 7 curves" open_undo_block() self._reverse = reverse self._get_current_curves() self._make_frame() self._make_drawing_area() self._background() self._draw() set_current_frame( self.orig_frm) close_undo_block()
def add_colorbar( self ): """ We now want to add a color bar to describe the Z axis. What we do is add an 2x2 image with values set to min/max of the Z axis (or in our case offsets); hide the image, and then create the colorbar Example: >>> lut.add_colorbar() """ if self.image: raise RuntimeError("Cannot set multiple colorbars") open_undo_block() self._set_lut_window() self._save_limits() # We set alpha to all 0 so we don't get an image flahsed on screen tmin = self.min_z if self.min_z is not None else 0 tmax = self.max_z if self.max_z is not None else 1 cmap = self.cmap if self.cmap else chips_usercmap1 add_image( tmin+np.arange(4)*((tmax-tmin)/3.0),2,2, "colormap={0} alpha=[0,0]".format(cmap)) # save the image name incase we want to change colormap self.image = self._get_current_object_name("Image") set_data_aspect_ratio('') hide_image() # then we reset alphas back to 1 so colorbar matches plotted data set_image("alpha=[1,1]") add_colorbar(1.075,0.5, """orientation=vertical ticklabel.angle=90 ticklabel.halign=center label.angle=180 label.valign=base stem=lutcolorbar""" ) self._restore_limits() self._restore_window() close_undo_block()
def _color_object( lutfile, reverse=False, invert=False, skip=0, rskip=0, plot_object="Curve", setter=set_curve, xform=_linear): """ Color all of a certain object type based on a color lookup table """ curves = _get_all_object_type_in_current_plot( plot_object) if len(curves) == 0: raise RuntimeError("No {}s found in the current plot.".format(plot_object.lower())) colors = _sample_from_lut( lutfile, len(curves)+skip+rskip, reverse=reverse, invert=invert, xform=xform) from pychips.advanced import open_undo_block, close_undo_block open_undo_block() for cc in zip( curves, colors[skip:] ): setter(cc[0], "*.color={}".format(cc[1])) close_undo_block()
def label(self, label_vals): """ Relabel the legend with new values """ if len(label_vals) != len(self.lgnd_lbls): raise RuntimeError("Number of labels does not match the number of curves") open_undo_block() old_frame = self._get_current_object_name("Frame") set_current_frame( self.frm ) for lbid,lbl in zip( self.lgnd_lbls, label_vals ): set_label_text( lbid, lbl ) set_current_frame( old_frame ) close_undo_block()
def update(self): """ Update the curve properties (symbole/line properties) after the legend has been created """ open_undo_block() old_frame = self._get_current_object_name("Frame") for usr,lgn,lpt in zip( self.usr_crvs, self.lgnd_crvs, self.lgnd_pnts): set_current_frame( self.orig_frm) cc = get_curve( usr ) set_current_frame( self.frm ) set_curve( lgn, cc ) set_curve( lgn, "symbol.style=none") pnt = self._get_point_properties( cc.symbol ) set_point( lpt, pnt ) set_current_frame( old_frame ) close_undo_block()
def clear(self): """ clear all plot elements associated with this object, only. The plot is retained. >>> b.clear() """ open_undo_block() self._restore_plot() if self.all_regions: for d in self.all_regions: delete_region(d) if self.all_lines: for d in self.all_lines: delete_line(d) if self.all_points: for d in self.all_points: delete_point(d) if self.all_curves: for d in self.all_curves: delete_curve(d) close_undo_block()
def set_curve( self, args ): """ Loop thru curves appling the style to each >>> lut.set_curve("symbol.style=circle") >>> lut.set_curve( ["symbol.size", "3"] ) >>> lut.set_curve( { "symbol.fill" : True } ) >>> cc = ChipsCurve() >>> cc.symbol.angle = 270 >>> lut.set_curve(cc) Users should not set the color parameters. """ open_undo_block() self._set_lut_window() for cc in self.curves: if cc: set_curve(cc, args) self._restore_window() close_undo_block()
def set_region( self, prop ): """ Set region properties. The same properties are applied to all the regions associated with this dataset. >>> b.set_region("*.color=red") >>> b.set_region(["fill.style", "userfill1"]) >>> b.set_region( { 'edge.style' : 'none' }) >>> r = ChipsRegion() >>> r.opacity = 1.0 >>> b.set_region(r) """ open_undo_block() self._restore_plot() if self.all_regions: for xx in self.all_regions: set_region( xx, prop ) self.region = get_region( self.all_regions[0] ) else: self.region = prop close_undo_block()
def replace_cmap( self,filename, reverse=False, invert=False ): """ This utility routine can be used to change the color map of and existing series plot. >>> lut.replace_cmap( "/soft/ciao/data/bb.lut") As with the init routine, the color map can be auto-located, reversed, or inverted. >>> lut.replace_cmap("16_colors") >>> lut.replace_cmap("heart", invert=True ) >>> lut.replace_cmap("standard", reverse=True ) The color map that is loaded must have the same number of colors as the original or an exception is raised. """ open_undo_block() self._set_lut_window() # save current window/frame/plot info if not self.curves: close_undo_block() raise RuntimeError("You can only replace a color map after it has been plotted") # consistency check that #colors == #curves assert len(self.hex_codes) == len( self.curves) rr,gg,bb = get_rgb_values( filename, reverse=reverse, invert=invert ) self.hex_codes = get_rgb_hexcodes( rr, gg, bb ) if len(rr) != self.num_colors: self._restore_window() close_undo_block() raise IOError("New lookup table must have same number of colors as previous table") self.filename = filename load_colormap( rr, gg, bb, self.cmap ) if self.image: set_image(self.image, "colormap={}".format(self.cmap)) nn = self.num_colors for ii in range(nn) : # Construct the color hex value mycol = self._get_color_code( ii) if self.curves[ii]: set_curve( self.curves[ii], "line.color={0} symbol.color={0}".format(mycol)) self._restore_window() close_undo_block()
def plot( self, xx, yy, zz, stem="lutpoint", zgrid=None, zmin=None, zmax=None, sizefn=lambda x: 1, thickfn=lambda x: 1 ): """ Plots the X, Y for each Z slice color coded by the LUT >>> x = np.random.rand(100) >>> y = np.random.rand(100) >>> z = np.arange(100) >>> lut.plot( x, y, z ) The ZZ values are split into an equal number of bins going from min(zz) to max(zz). The number of bins is equal to the number of colors in LUT. The zgrid can be explicitly input but must have the same number of grid points as the number of colors >>> zlo = np.arange(256) >>> zhi = zlo + 1 >>> zlo[0] = -999 >>> zhi[-1] = 999 >>> zgrid = zip(zlo,zhi) >>> plot(x, y, z, zgrid=zgrid) Note: The color bar tick labels will not correctly show the arbitrary zgrid values. A curve is created for each color. All the curves have a name that starts with the prefix "lutpoint" which can be changed using the 'stem' argument. >>> plot(x, y, z, stem="asoldata") >>> info() ... Curve [asoldata1] """ if self.curves: raise RuntimeError("The same object cannot be used to plot multiple series") # All commands in the routine are undone with a single undo() open_undo_block() nn = self.num_colors if not zgrid: # Determine the Z bins to plot; use linear/fixed bin widths self.min_z = min(zz) if zmin is None else zmin self.max_z = max(zz) if zmax is None else zmax dt = float(self.max_z - self.min_z)/(nn-1) tlo = self.min_z + dt* np.arange(nn) thi = tlo + dt thi[-1] = np.inf # make sure max value is always included (< vs <= below) else: # check zgrid to make sure is OK if len(zgrid) != self.num_colors: close_undo_block() raise ValueError("zgrid must have same number of elements as number of colors") if not all( [len(zgrid[i]) == 2 for i in range(nn)] ): close_undo_block() raise ValueError("zgrid must have 2 elements in each slot") try: tlo = np.array( [float(zgrid[i][0]) for i in range(nn) ]) thi = np.array( [float(zgrid[i][1]) for i in range(nn) ]) self.min_z = tlo[0] self.max_z = thi[-1] except: close_undo_block() raise ValueError("All elements of zgrid must be numbers") #We add a curve w/ no line/symbol just to get axes setup add_curve( xx, yy, "symbol.style=none line.style=none stem=delme") self._save_limits() delname = self._get_current_object_name("Curve") self.lut_win, self.lut_frame,self.lut_plot = self._get_window_info() all_curves = [] for ii in range(nn) : # Construct the color hex value mycol = self._get_color_code( ii ) # filter data in i-th range jj, = np.where( (zz >= tlo[ii]) & (zz < thi[ii])) if len(jj) == 0: all_curves.append(None) continue cc = ChipsCurve() cc.stem=stem cc.line.style=None cc.symbol.style="point" cc.symbol.color=mycol cc.line.color=mycol cc.symbol.size=sizefn(ii) cc.line.thickness=thickfn(ii) add_curve( np.array(xx)[jj], np.array(yy)[jj], cc ) all_curves.append( self._get_current_object_name("Curve") ) # save list of curves plotted self.curves = all_curves self.order = 1 # 1st color plotted on bottom # delete initial curve used to setup axes delete_curve(delname) close_undo_block()
def plot( self, qlo=0.25, qhi=0.75, limit=True, mean=True, sdev=False) : """ Box and whiskers plot The default is to plot the quartiles: data representing the 25%, 50% (median), and 75% of the values in each X bin with a line through the mean showing the min and max values. >>> b.plot() The quantiles can be changed >>> b.plot( qlo=0.33, qhi=0.67 ) >>> b.plot( qlo=0.05, qhi=0.95 ) The limit (min/max) line aka the whiskers can be disabled >>> b.plot( limit=False) and the mean value (point) can also be removed >>> b.plot( mean=False) """ open_undo_block() try: self.clear() except: #Window may have been deleted/closed/etc. pass # setup axes add_curve( self.xx, self.yy, "stem=delme line.style=none symbol.style=none") delete_curve(self._get_current_object_name("Curve")) # save plot info self.lut_win = self._get_current_object_name("Window") self.lut_frame = self._get_current_object_name("Frame") self.lut_plot = self._get_current_object_name("Plot") self.all_regions = [] self.all_points = [] self.all_lines = [] self.all_curves = [] self.qlo = qlo self.qhi = qhi self.limit = limit self.mean = mean self.sdev = sdev self.grid_regions = {} for g in self.grid: xlo = g[0] xhi = g[1] y0 = self.y0[g] if y0 is None: continue sz = len(y0) if 0 == sz: continue # TODO move this into the fill grid method? qlo and qhi # would need to move to different i/f q000=np.min(y0) q100=np.max(y0) q050=np.median(y0) qmid=np.mean(y0) qstd =np.std(y0) q033=y0[np.max([int(qlo*sz+0.5),0])] q066=y0[np.min([int(qhi*sz+0.5),sz-1])] xmid = (xhi+xlo)/2.0 self.grid_regions[g] = [] if q033 != q050: add_region( [xlo, xhi, xhi, xlo], [q033, q033, q050, q050], self.region ) self.all_regions.append( self._get_current_object_name("Region")) self.grid_regions[g].append(self._get_current_object_name("Region")) if q050 != q066: add_region( [xlo, xhi, xhi, xlo], [q050, q050, q066, q066], self.region ) self.all_regions.append( self._get_current_object_name("Region")) self.grid_regions[g].append(self._get_current_object_name("Region")) if True == mean: add_point( xmid, qmid, self.point ) self.all_points.append(self._get_current_object_name("Point")) if True == limit: add_line( xmid, q000, xmid, q100 ) self.all_lines.append(self._get_current_object_name("Line")) if True == sdev: add_curve( [xmid], [qmid], [qstd], self.curve ) self.all_curves.append(self._get_current_object_name("Curve")) close_undo_block()