class Line2D(Artist): """ A line - the line can have both a solid linestyle connecting all the vertices, and a marker at each vertex. Additionally, the drawing of the solid line is influenced by the drawstyle, eg one can create "stepped" lines in various styles. """ lineStyles = _lineStyles = { # hidden names deprecated '-' : '_draw_solid', '--' : '_draw_dashed', '-.' : '_draw_dash_dot', ':' : '_draw_dotted', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', } _drawStyles_l = { 'default': '_draw_lines', 'steps-mid': '_draw_steps_mid', 'steps-pre': '_draw_steps_pre', 'steps-post': '_draw_steps_post', } _drawStyles_s = { 'steps': '_draw_steps_pre', } drawStyles = {} drawStyles.update(_drawStyles_l) drawStyles.update(_drawStyles_s) # Need a list ordered with long names first: drawStyleKeys = _drawStyles_l.keys() + _drawStyles_s.keys() # Referenced here to maintain API. These are defined in # MarkerStyle markers = MarkerStyle.markers filled_markers = MarkerStyle.filled_markers fillStyles = MarkerStyle.fillstyles zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') def __str__(self): if self._label != "": return "Line2D(%s)" % (self._label) elif hasattr(self, '_x') and len(self._x) > 3: return "Line2D((%g,%g),(%g,%g),...,(%g,%g))"\ %(self._x[0],self._y[0],self._x[0],self._y[0],self._x[-1],self._y[-1]) elif hasattr(self, '_x'): return "Line2D(%s)"\ %(",".join(["(%g,%g)"%(x,y) for x,y in zip(self._x,self._y)])) else: return "Line2D()" def __init__( self, xdata, ydata, linewidth=None, # all Nones default to rc linestyle=None, color=None, marker=None, markersize=None, markeredgewidth=None, markeredgecolor=None, markerfacecolor=None, markerfacecoloralt='none', fillstyle='full', antialiased=None, dash_capstyle=None, solid_capstyle=None, dash_joinstyle=None, solid_joinstyle=None, pickradius=5, drawstyle=None, markevery=None, **kwargs): """ Create a :class:`~matplotlib.lines.Line2D` instance with *x* and *y* data in sequences *xdata*, *ydata*. The kwargs are :class:`~matplotlib.lines.Line2D` properties: %(Line2D)s See :meth:`set_linestyle` for a decription of the line styles, :meth:`set_marker` for a description of the markers, and :meth:`set_drawstyle` for a description of the draw styles. """ Artist.__init__(self) #convert sequences to numpy arrays if not iterable(xdata): raise RuntimeError('xdata must be a sequence') if not iterable(ydata): raise RuntimeError('ydata must be a sequence') if linewidth is None: linewidth = rcParams['lines.linewidth'] if linestyle is None: linestyle = rcParams['lines.linestyle'] if marker is None: marker = rcParams['lines.marker'] if color is None: color = rcParams['lines.color'] if markersize is None: markersize = rcParams['lines.markersize'] if antialiased is None: antialiased = rcParams['lines.antialiased'] if dash_capstyle is None: dash_capstyle = rcParams['lines.dash_capstyle'] if dash_joinstyle is None: dash_joinstyle = rcParams['lines.dash_joinstyle'] if solid_capstyle is None: solid_capstyle = rcParams['lines.solid_capstyle'] if solid_joinstyle is None: solid_joinstyle = rcParams['lines.solid_joinstyle'] if drawstyle is None: drawstyle = 'default' self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) self.set_linestyle(linestyle) self.set_drawstyle(drawstyle) self.set_linewidth(linewidth) self.set_color(color) self._marker = MarkerStyle() self.set_marker(marker) self.set_markevery(markevery) self.set_antialiased(antialiased) self.set_markersize(markersize) self._dashSeq = None self.set_markerfacecolor(markerfacecolor) self.set_markerfacecoloralt(markerfacecoloralt) self.set_markeredgecolor(markeredgecolor) self.set_markeredgewidth(markeredgewidth) self.set_fillstyle(fillstyle) self.verticalOffset = None # update kwargs before updating data to give the caller a # chance to init axes (and hence unit support) self.update(kwargs) self.pickradius = pickradius self.ind_offset = 0 if is_numlike(self._picker): self.pickradius = self._picker self._xorig = np.asarray([]) self._yorig = np.asarray([]) self._invalidx = True self._invalidy = True self.set_data(xdata, ydata) def contains(self, mouseevent): """ Test whether the mouse event occurred on the line. The pick radius determines the precision of the location test (usually within five points of the value). Use :meth:`~matplotlib.lines.Line2D.get_pickradius` or :meth:`~matplotlib.lines.Line2D.set_pickradius` to view or modify it. Returns *True* if any values are within the radius along with ``{'ind': pointlist}``, where *pointlist* is the set of points within the radius. TODO: sort returned indices by distance """ if callable(self._contains): return self._contains(self, mouseevent) if not is_numlike(self.pickradius): raise ValueError, "pick radius should be a distance" # Make sure we have data to plot if self._invalidy or self._invalidx: self.recache() if len(self._xy) == 0: return False, {} # Convert points to pixels if self._transformed_path is None: self._transform_path() path, affine = self._transformed_path.get_transformed_path_and_affine() path = affine.transform_path(path) xy = path.vertices xt = xy[:, 0] yt = xy[:, 1] # Convert pick radius from points to pixels if self.figure == None: warning.warn('no figure set when check if mouse is on line') pixels = self.pickradius else: pixels = self.figure.dpi / 72. * self.pickradius # Check for collision if self._linestyle in ['None', None]: # If no line, return the nearby point(s) d = (xt - mouseevent.x)**2 + (yt - mouseevent.y)**2 ind, = np.nonzero(np.less_equal(d, pixels**2)) else: # If line, return the nearby segment(s) ind = segment_hits(mouseevent.x, mouseevent.y, xt, yt, pixels) ind += self.ind_offset # Debugging message if False and self._label != u'': print "Checking line", self._label, "at", mouseevent.x, mouseevent.y print 'xt', xt print 'yt', yt #print 'dx,dy', (xt-mouseevent.x)**2., (yt-mouseevent.y)**2. print 'ind', ind # Return the point(s) within radius return len(ind) > 0, dict(ind=ind) def get_pickradius(self): 'return the pick radius used for containment tests' return self.pickradius def set_pickradius(self, d): """Sets the pick radius used for containment tests ACCEPTS: float distance in points """ self.pickradius = d def get_fillstyle(self): """ return the marker fillstyle """ return self._marker.get_fillstyle() def set_fillstyle(self, fs): """ Set the marker fill style; 'full' means fill the whole marker. The other options are for half filled markers ACCEPTS: ['full' | 'left' | 'right' | 'bottom' | 'top'] """ self._marker.set_fillstyle(fs) def set_markevery(self, every): """ Set the markevery property to subsample the plot when using markers. Eg if ``markevery=5``, every 5-th marker will be plotted. *every* can be None Every point will be plotted an integer N Every N-th marker will be plotted starting with marker 0 A length-2 tuple of integers every=(start, N) will start at point start and plot every N-th marker ACCEPTS: None | integer | (startind, stride) """ self._markevery = every def get_markevery(self): 'return the markevery setting' return self._markevery def set_picker(self, p): """Sets the event picker details for the line. ACCEPTS: float distance in points or callable pick function ``fn(artist, event)`` """ if callable(p): self._contains = p else: self.pickradius = p self._picker = p def get_window_extent(self, renderer): bbox = Bbox.unit() bbox.update_from_data_xy(self.get_transform().transform( self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker: ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 bbox = bbox.padded(ms) return bbox def set_axes(self, ax): Artist.set_axes(self, ax) if ax.xaxis is not None: self._xcid = ax.xaxis.callbacks.connect('units', self.recache_always) if ax.yaxis is not None: self._ycid = ax.yaxis.callbacks.connect('units', self.recache_always) set_axes.__doc__ = Artist.set_axes.__doc__ def set_data(self, *args): """ Set the x and y data ACCEPTS: 2D array (rows are x, y) or two 1D arrays """ if len(args) == 1: x, y = args[0] else: x, y = args self.set_xdata(x) self.set_ydata(y) def recache_always(self): self.recache(always=True) def recache(self, always=False): if always or self._invalidx: xconv = self.convert_xunits(self._xorig) if ma.isMaskedArray(self._xorig): x = ma.asarray(xconv, np.float_) else: x = np.asarray(xconv, np.float_) x = x.ravel() else: x = self._x if always or self._invalidy: yconv = self.convert_yunits(self._yorig) if ma.isMaskedArray(self._yorig): y = ma.asarray(yconv, np.float_) else: y = np.asarray(yconv, np.float_) y = y.ravel() else: y = self._y if len(x) == 1 and len(y) > 1: x = x * np.ones(y.shape, np.float_) if len(y) == 1 and len(x) > 1: y = y * np.ones(x.shape, np.float_) if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') x = x.reshape((len(x), 1)) y = y.reshape((len(y), 1)) if ma.isMaskedArray(x) or ma.isMaskedArray(y): self._xy = ma.concatenate((x, y), 1) else: self._xy = np.concatenate((x, y), 1) self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view self._subslice = False if (self.axes and len(x) > 100 and self._is_sorted(x) and self.axes.name == 'rectilinear' and self.axes.get_xscale() == 'linear' and self._markevery is None): self._subslice = True if hasattr(self, '_path'): interpolation_steps = self._path._interpolation_steps else: interpolation_steps = 1 self._path = Path(self._xy, None, interpolation_steps) self._transformed_path = None self._invalidx = False self._invalidy = False def _transform_path(self, subslice=None): # Masked arrays are now handled by the Path class itself if subslice is not None: _path = Path(self._xy[subslice, :]) else: _path = self._path self._transformed_path = TransformedPath(_path, self.get_transform()) def set_transform(self, t): """ set the Transformation instance used by this artist ACCEPTS: a :class:`matplotlib.transforms.Transform` instance """ Artist.set_transform(self, t) self._invalidx = True self._invalidy = True def _is_sorted(self, x): "return true if x is sorted" if len(x) < 2: return 1 return np.alltrue(x[1:] - x[0:-1] >= 0) @allow_rasterization def draw(self, renderer): if self._invalidy or self._invalidx: self.recache() self.ind_offset = 0 # Needed for contains() method. if self._subslice and self.axes: # Need to handle monotonically decreasing case also... x0, x1 = self.axes.get_xbound() i0, = self._x.searchsorted([x0], 'left') i1, = self._x.searchsorted([x1], 'right') subslice = slice(max(i0 - 1, 0), i1 + 1) self.ind_offset = subslice.start self._transform_path(subslice) if self._transformed_path is None: self._transform_path() if not self.get_visible(): return renderer.open_group('line2d', self.get_gid()) gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self._color) gc.set_antialiased(self._antialiased) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) if self.is_dashed(): cap = self._dashcapstyle join = self._dashjoinstyle else: cap = self._solidcapstyle join = self._solidjoinstyle gc.set_joinstyle(join) gc.set_capstyle(cap) gc.set_snap(self.get_snap()) funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') if funcname != '_draw_nothing': tpath, affine = self._transformed_path.get_transformed_path_and_affine( ) if len(tpath.vertices): self._lineFunc = getattr(self, funcname) funcname = self.drawStyles.get(self._drawstyle, '_draw_lines') drawFunc = getattr(self, funcname) drawFunc(renderer, gc, tpath, affine.frozen()) if self._marker: gc = renderer.new_gc() self._set_gc_clip(gc) rgbFace = self._get_rgb_face() rgbFaceAlt = self._get_rgb_face(alt=True) edgecolor = self.get_markeredgecolor() if is_string_like(edgecolor) and edgecolor.lower() == 'none': gc.set_linewidth(0) gc.set_foreground(rgbFace) else: gc.set_foreground(edgecolor) gc.set_linewidth(self._markeredgewidth) gc.set_alpha(self._alpha) marker = self._marker tpath, affine = self._transformed_path.get_transformed_points_and_affine( ) if len(tpath.vertices): # subsample the markers if markevery is not None markevery = self.get_markevery() if markevery is not None: if iterable(markevery): startind, stride = markevery else: startind, stride = 0, markevery if tpath.codes is not None: codes = tpath.codes[startind::stride] else: codes = None vertices = tpath.vertices[startind::stride] subsampled = Path(vertices, codes) else: subsampled = tpath snap = marker.get_snap_threshold() if type(snap) == float: snap = renderer.points_to_pixels(self._markersize) >= snap gc.set_snap(snap) gc.set_joinstyle(marker.get_joinstyle()) gc.set_capstyle(marker.get_capstyle()) marker_path = marker.get_path() marker_trans = marker.get_transform() w = renderer.points_to_pixels(self._markersize) if marker.get_marker() != ',': # Don't scale for pixels, and don't stroke them marker_trans = marker_trans.scale(w) else: gc.set_linewidth(0) renderer.draw_markers(gc, marker_path, marker_trans, subsampled, affine.frozen(), rgbFace) alt_marker_path = marker.get_alt_path() if alt_marker_path: alt_marker_trans = marker.get_alt_transform() alt_marker_trans = alt_marker_trans.scale(w) renderer.draw_markers(gc, alt_marker_path, alt_marker_trans, subsampled, affine.frozen(), rgbFaceAlt) gc.restore() gc.restore() renderer.close_group('line2d') def get_antialiased(self): return self._antialiased def get_color(self): return self._color def get_drawstyle(self): return self._drawstyle def get_linestyle(self): return self._linestyle def get_linewidth(self): return self._linewidth def get_marker(self): return self._marker.get_marker() def get_markeredgecolor(self): if (is_string_like(self._markeredgecolor) and self._markeredgecolor == 'auto'): if self._marker.get_marker() in ('.', ','): return self._color if self._marker.is_filled(): return 'k' # Bad hard-wired default... else: return self._color return self._markeredgecolor def get_markeredgewidth(self): return self._markeredgewidth def _get_markerfacecolor(self, alt=False): if alt: fc = self._markerfacecoloralt else: fc = self._markerfacecolor if (fc is None or (is_string_like(fc) and fc.lower() == 'none')): return fc elif (is_string_like(fc) and fc.lower() == 'auto'): return self._color else: return fc def get_markerfacecolor(self): return self._get_markerfacecolor(alt=False) def get_markerfacecoloralt(self): return self._get_markerfacecolor(alt=True) def get_markersize(self): return self._markersize def get_data(self, orig=True): """ Return the xdata, ydata. If *orig* is *True*, return the original data """ return self.get_xdata(orig=orig), self.get_ydata(orig=orig) def get_xdata(self, orig=True): """ Return the xdata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._xorig if self._invalidx: self.recache() return self._x def get_ydata(self, orig=True): """ Return the ydata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._yorig if self._invalidy: self.recache() return self._y def get_path(self): """ Return the :class:`~matplotlib.path.Path` object associated with this line. """ if self._invalidy or self._invalidx: self.recache() return self._path def get_xydata(self): """ Return the *xy* data as a Nx2 numpy array. """ if self._invalidy or self._invalidx: self.recache() return self._xy def set_antialiased(self, b): """ True if line should be drawin with antialiased rendering ACCEPTS: [True | False] """ self._antialiased = b def set_color(self, color): """ Set the color of the line ACCEPTS: any matplotlib color """ self._color = color def set_drawstyle(self, drawstyle): """ Set the drawstyle of the plot 'default' connects the points with lines. The steps variants produce step-plots. 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. ACCEPTS: [ 'default' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' ] """ self._drawstyle = drawstyle def set_linewidth(self, w): """ Set the line width in points ACCEPTS: float value in points """ self._linewidth = w def set_linestyle(self, linestyle): """ Set the linestyle of the line (also accepts drawstyles) ================ ================= linestyle description ================ ================= ``'-'`` solid ``'--'`` dashed ``'-.'`` dash_dot ``':'`` dotted ``'None'`` draw nothing ``' '`` draw nothing ``''`` draw nothing ================ ================= 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. .. seealso:: :meth:`set_drawstyle` To set the drawing style (stepping) of the plot. ACCEPTS: [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'None'`` | ``' '`` | ``''`` ] and any drawstyle in combination with a linestyle, e.g. ``'steps--'``. """ for ds in self.drawStyleKeys: # long names are first in the list if linestyle.startswith(ds): self.set_drawstyle(ds) if len(linestyle) > len(ds): linestyle = linestyle[len(ds):] else: linestyle = '-' break if linestyle not in self._lineStyles: if linestyle in ls_mapper: linestyle = ls_mapper[linestyle] else: verbose.report('Unrecognized line style %s, %s' % (linestyle, type(linestyle))) if linestyle in [' ', '']: linestyle = 'None' self._linestyle = linestyle @docstring.dedent_interpd def set_marker(self, marker): """ Set the line marker %(MarkerTable)s %(MarkerAccepts)s """ self._marker.set_marker(marker) def set_markeredgecolor(self, ec): """ Set the marker edge color ACCEPTS: any matplotlib color """ if ec is None: ec = 'auto' self._markeredgecolor = ec def set_markeredgewidth(self, ew): """ Set the marker edge width in points ACCEPTS: float value in points """ if ew is None: ew = rcParams['lines.markeredgewidth'] self._markeredgewidth = ew def set_markerfacecolor(self, fc): """ Set the marker face color. ACCEPTS: any matplotlib color """ if fc is None: fc = 'auto' self._markerfacecolor = fc def set_markerfacecoloralt(self, fc): """ Set the alternate marker face color. ACCEPTS: any matplotlib color """ if fc is None: fc = 'auto' self._markerfacecoloralt = fc def set_markersize(self, sz): """ Set the marker size in points ACCEPTS: float """ self._markersize = sz def set_xdata(self, x): """ Set the data np.array for x ACCEPTS: 1D array """ self._xorig = x self._invalidx = True def set_ydata(self, y): """ Set the data np.array for y ACCEPTS: 1D array """ self._yorig = y self._invalidy = True def set_dashes(self, seq): """ Set the dash sequence, sequence of dashes with on off ink in points. If seq is empty or if seq = (None, None), the linestyle will be set to solid. ACCEPTS: sequence of on/off ink in points """ if seq == (None, None) or len(seq) == 0: self.set_linestyle('-') else: self.set_linestyle('--') self._dashSeq = seq # TODO: offset ignored for now def _draw_lines(self, renderer, gc, path, trans): self._lineFunc(renderer, gc, path, trans) def _draw_steps_pre(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2 * len(vertices) - 1, 2), np.float_) steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_steps_post(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2 * len(vertices) - 1, 2), np.float_) steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_steps_mid(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2 * len(vertices), 2), np.float_) steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[0, 0] = vertices[0, 0] steps[-1, 0] = vertices[-1, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle('solid') renderer.draw_path(gc, path, trans) def _draw_dashed(self, renderer, gc, path, trans): gc.set_linestyle('dashed') if self._dashSeq is not None: gc.set_dashes(0, self._dashSeq) renderer.draw_path(gc, path, trans) def _draw_dash_dot(self, renderer, gc, path, trans): gc.set_linestyle('dashdot') renderer.draw_path(gc, path, trans) def _draw_dotted(self, renderer, gc, path, trans): gc.set_linestyle('dotted') renderer.draw_path(gc, path, trans) def update_from(self, other): 'copy properties from other to self' Artist.update_from(self, other) self._linestyle = other._linestyle self._linewidth = other._linewidth self._color = other._color self._markersize = other._markersize self._markerfacecolor = other._markerfacecolor self._markerfacecoloralt = other._markerfacecoloralt self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth self._dashSeq = other._dashSeq self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle self._solidcapstyle = other._solidcapstyle self._solidjoinstyle = other._solidjoinstyle self._linestyle = other._linestyle self._marker = MarkerStyle(other._marker.get_marker(), other._marker.get_fillstyle()) self._drawstyle = other._drawstyle def _get_rgb_face(self, alt=False): facecolor = self._get_markerfacecolor(alt=alt) if is_string_like(facecolor) and facecolor.lower() == 'none': rgbFace = None else: rgbFace = colorConverter.to_rgb(facecolor) return rgbFace # some aliases.... def set_aa(self, val): 'alias for set_antialiased' self.set_antialiased(val) def set_c(self, val): 'alias for set_color' self.set_color(val) def set_ls(self, val): 'alias for set_linestyle' self.set_linestyle(val) def set_lw(self, val): 'alias for set_linewidth' self.set_linewidth(val) def set_mec(self, val): 'alias for set_markeredgecolor' self.set_markeredgecolor(val) def set_mew(self, val): 'alias for set_markeredgewidth' self.set_markeredgewidth(val) def set_mfc(self, val): 'alias for set_markerfacecolor' self.set_markerfacecolor(val) def set_mfcalt(self, val): 'alias for set_markerfacecoloralt' self.set_markerfacecoloralt(val) def set_ms(self, val): 'alias for set_markersize' self.set_markersize(val) def get_aa(self): 'alias for get_antialiased' return self.get_antialiased() def get_c(self): 'alias for get_color' return self.get_color() def get_ls(self): 'alias for get_linestyle' return self.get_linestyle() def get_lw(self): 'alias for get_linewidth' return self.get_linewidth() def get_mec(self): 'alias for get_markeredgecolor' return self.get_markeredgecolor() def get_mew(self): 'alias for get_markeredgewidth' return self.get_markeredgewidth() def get_mfc(self): 'alias for get_markerfacecolor' return self.get_markerfacecolor() def get_mfcalt(self, alt=False): 'alias for get_markerfacecoloralt' return self.get_markerfacecoloralt() def get_ms(self): 'alias for get_markersize' return self.get_markersize() def set_dash_joinstyle(self, s): """ Set the join style for dashed linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_dash_joinstyle passed "%s";\n' % (s, ) + 'valid joinstyles are %s' % (self.validJoin, )) self._dashjoinstyle = s def set_solid_joinstyle(self, s): """ Set the join style for solid linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_solid_joinstyle passed "%s";\n' % (s, ) + 'valid joinstyles are %s' % (self.validJoin, )) self._solidjoinstyle = s def get_dash_joinstyle(self): """ Get the join style for dashed linestyles """ return self._dashjoinstyle def get_solid_joinstyle(self): """ Get the join style for solid linestyles """ return self._solidjoinstyle def set_dash_capstyle(self, s): """ Set the cap style for dashed linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_dash_capstyle passed "%s";\n' % (s, ) + 'valid capstyles are %s' % (self.validCap, )) self._dashcapstyle = s def set_solid_capstyle(self, s): """ Set the cap style for solid linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_solid_capstyle passed "%s";\n' % (s, ) + 'valid capstyles are %s' % (self.validCap, )) self._solidcapstyle = s def get_dash_capstyle(self): """ Get the cap style for dashed linestyles """ return self._dashcapstyle def get_solid_capstyle(self): """ Get the cap style for solid linestyles """ return self._solidcapstyle def is_dashed(self): 'return True if line is dashstyle' return self._linestyle in ('--', '-.', ':')
class Line2D(Artist): """ A line - the line can have both a solid linestyle connecting all the vertices, and a marker at each vertex. Additionally, the drawing of the solid line is influenced by the drawstyle, eg one can create "stepped" lines in various styles. """ lineStyles = _lineStyles = { # hidden names deprecated '-' : '_draw_solid', '--' : '_draw_dashed', '-.' : '_draw_dash_dot', ':' : '_draw_dotted', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', } _drawStyles_l = { 'default' : '_draw_lines', 'steps-mid' : '_draw_steps_mid', 'steps-pre' : '_draw_steps_pre', 'steps-post' : '_draw_steps_post', } _drawStyles_s = { 'steps' : '_draw_steps_pre', } drawStyles = {} drawStyles.update(_drawStyles_l) drawStyles.update(_drawStyles_s) # Need a list ordered with long names first: drawStyleKeys = _drawStyles_l.keys() + _drawStyles_s.keys() # Referenced here to maintain API. These are defined in # MarkerStyle markers = MarkerStyle.markers filled_markers = MarkerStyle.filled_markers fillStyles = MarkerStyle.fillstyles zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') def __str__(self): if self._label != "": return "Line2D(%s)"%(self._label) elif hasattr(self, '_x') and len(self._x) > 3: return "Line2D((%g,%g),(%g,%g),...,(%g,%g))"\ %(self._x[0],self._y[0],self._x[0],self._y[0],self._x[-1],self._y[-1]) elif hasattr(self, '_x'): return "Line2D(%s)"\ %(",".join(["(%g,%g)"%(x,y) for x,y in zip(self._x,self._y)])) else: return "Line2D()" def __init__(self, xdata, ydata, linewidth = None, # all Nones default to rc linestyle = None, color = None, marker = None, markersize = None, markeredgewidth = None, markeredgecolor = None, markerfacecolor = None, markerfacecoloralt = 'none', fillstyle = 'full', antialiased = None, dash_capstyle = None, solid_capstyle = None, dash_joinstyle = None, solid_joinstyle = None, pickradius = 5, drawstyle = None, markevery = None, **kwargs ): """ Create a :class:`~matplotlib.lines.Line2D` instance with *x* and *y* data in sequences *xdata*, *ydata*. The kwargs are :class:`~matplotlib.lines.Line2D` properties: %(Line2D)s See :meth:`set_linestyle` for a decription of the line styles, :meth:`set_marker` for a description of the markers, and :meth:`set_drawstyle` for a description of the draw styles. """ Artist.__init__(self) #convert sequences to numpy arrays if not iterable(xdata): raise RuntimeError('xdata must be a sequence') if not iterable(ydata): raise RuntimeError('ydata must be a sequence') if linewidth is None : linewidth=rcParams['lines.linewidth'] if linestyle is None : linestyle=rcParams['lines.linestyle'] if marker is None : marker=rcParams['lines.marker'] if color is None : color=rcParams['lines.color'] if markersize is None : markersize=rcParams['lines.markersize'] if antialiased is None : antialiased=rcParams['lines.antialiased'] if dash_capstyle is None : dash_capstyle=rcParams['lines.dash_capstyle'] if dash_joinstyle is None : dash_joinstyle=rcParams['lines.dash_joinstyle'] if solid_capstyle is None : solid_capstyle=rcParams['lines.solid_capstyle'] if solid_joinstyle is None : solid_joinstyle=rcParams['lines.solid_joinstyle'] if drawstyle is None : drawstyle='default' self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) self.set_linestyle(linestyle) self.set_drawstyle(drawstyle) self.set_linewidth(linewidth) self.set_color(color) self._marker = MarkerStyle() self.set_marker(marker) self.set_markevery(markevery) self.set_antialiased(antialiased) self.set_markersize(markersize) self._dashSeq = None self.set_markerfacecolor(markerfacecolor) self.set_markerfacecoloralt(markerfacecoloralt) self.set_markeredgecolor(markeredgecolor) self.set_markeredgewidth(markeredgewidth) self.set_fillstyle(fillstyle) self.verticalOffset = None # update kwargs before updating data to give the caller a # chance to init axes (and hence unit support) self.update(kwargs) self.pickradius = pickradius self.ind_offset = 0 if is_numlike(self._picker): self.pickradius = self._picker self._xorig = np.asarray([]) self._yorig = np.asarray([]) self._invalidx = True self._invalidy = True self.set_data(xdata, ydata) def contains(self, mouseevent): """ Test whether the mouse event occurred on the line. The pick radius determines the precision of the location test (usually within five points of the value). Use :meth:`~matplotlib.lines.Line2D.get_pickradius` or :meth:`~matplotlib.lines.Line2D.set_pickradius` to view or modify it. Returns *True* if any values are within the radius along with ``{'ind': pointlist}``, where *pointlist* is the set of points within the radius. TODO: sort returned indices by distance """ if callable(self._contains): return self._contains(self,mouseevent) if not is_numlike(self.pickradius): raise ValueError("pick radius should be a distance") # Make sure we have data to plot if self._invalidy or self._invalidx: self.recache() if len(self._xy)==0: return False,{} # Convert points to pixels if self._transformed_path is None: self._transform_path() path, affine = self._transformed_path.get_transformed_path_and_affine() path = affine.transform_path(path) xy = path.vertices xt = xy[:, 0] yt = xy[:, 1] # Convert pick radius from points to pixels if self.figure == None: warning.warn('no figure set when check if mouse is on line') pixels = self.pickradius else: pixels = self.figure.dpi/72. * self.pickradius # the math involved in checking for containment (here and inside of segment_hits) assumes # that it is OK to overflow. In case the application has set the error flags such that # an exception is raised on overflow, we temporarily set the appropriate error flags here # and set them back when we are finished. olderrflags = np.seterr(all='ignore') try: # Check for collision if self._linestyle in ['None',None]: # If no line, return the nearby point(s) d = (xt-mouseevent.x)**2 + (yt-mouseevent.y)**2 ind, = np.nonzero(np.less_equal(d, pixels**2)) else: # If line, return the nearby segment(s) ind = segment_hits(mouseevent.x,mouseevent.y,xt,yt,pixels) finally: np.seterr(**olderrflags) ind += self.ind_offset # Debugging message if False and self._label != '': print("Checking line",self._label,"at",mouseevent.x,mouseevent.y) print('xt', xt) print('yt', yt) #print 'dx,dy', (xt-mouseevent.x)**2., (yt-mouseevent.y)**2. print('ind',ind) # Return the point(s) within radius return len(ind)>0,dict(ind=ind) def get_pickradius(self): 'return the pick radius used for containment tests' return self.pickradius def set_pickradius(self,d): """Sets the pick radius used for containment tests ACCEPTS: float distance in points """ self.pickradius = d def get_fillstyle(self): """ return the marker fillstyle """ return self._marker.get_fillstyle() def set_fillstyle(self, fs): """ Set the marker fill style; 'full' means fill the whole marker. 'none' means no filling; other options are for half-filled markers. ACCEPTS: ['full' | 'left' | 'right' | 'bottom' | 'top' | 'none'] """ self._marker.set_fillstyle(fs) def set_markevery(self, every): """ Set the markevery property to subsample the plot when using markers. Eg if ``markevery=5``, every 5-th marker will be plotted. *every* can be None Every point will be plotted an integer N Every N-th marker will be plotted starting with marker 0 A length-2 tuple of integers every=(start, N) will start at point start and plot every N-th marker ACCEPTS: None | integer | (startind, stride) """ self._markevery = every def get_markevery(self): 'return the markevery setting' return self._markevery def set_picker(self,p): """Sets the event picker details for the line. ACCEPTS: float distance in points or callable pick function ``fn(artist, event)`` """ if callable(p): self._contains = p else: self.pickradius = p self._picker = p def get_window_extent(self, renderer): bbox = Bbox.unit() bbox.update_from_data_xy(self.get_transform().transform(self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker: ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 bbox = bbox.padded(ms) return bbox def set_axes(self, ax): Artist.set_axes(self, ax) if ax.xaxis is not None: self._xcid = ax.xaxis.callbacks.connect('units', self.recache_always) if ax.yaxis is not None: self._ycid = ax.yaxis.callbacks.connect('units', self.recache_always) set_axes.__doc__ = Artist.set_axes.__doc__ def set_data(self, *args): """ Set the x and y data ACCEPTS: 2D array (rows are x, y) or two 1D arrays """ if len(args)==1: x, y = args[0] else: x, y = args self.set_xdata(x) self.set_ydata(y) def recache_always(self): self.recache(always=True) def recache(self, always=False): if always or self._invalidx: xconv = self.convert_xunits(self._xorig) if ma.isMaskedArray(self._xorig): x = ma.asarray(xconv, np.float_) else: x = np.asarray(xconv, np.float_) x = x.ravel() else: x = self._x if always or self._invalidy: yconv = self.convert_yunits(self._yorig) if ma.isMaskedArray(self._yorig): y = ma.asarray(yconv, np.float_) else: y = np.asarray(yconv, np.float_) y = y.ravel() else: y = self._y if len(x)==1 and len(y)>1: x = x * np.ones(y.shape, np.float_) if len(y)==1 and len(x)>1: y = y * np.ones(x.shape, np.float_) if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') x = x.reshape((len(x), 1)) y = y.reshape((len(y), 1)) if ma.isMaskedArray(x) or ma.isMaskedArray(y): self._xy = ma.concatenate((x, y), 1) else: self._xy = np.concatenate((x, y), 1) self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view self._subslice = False if (self.axes and len(x) > 100 and self._is_sorted(x) and self.axes.name == 'rectilinear' and self.axes.get_xscale() == 'linear' and self._markevery is None): self._subslice = True if hasattr(self, '_path'): interpolation_steps = self._path._interpolation_steps else: interpolation_steps = 1 self._path = Path(self._xy, None, interpolation_steps) self._transformed_path = None self._invalidx = False self._invalidy = False def _transform_path(self, subslice=None): # Masked arrays are now handled by the Path class itself if subslice is not None: _path = Path(self._xy[subslice,:]) else: _path = self._path self._transformed_path = TransformedPath(_path, self.get_transform()) def set_transform(self, t): """ set the Transformation instance used by this artist ACCEPTS: a :class:`matplotlib.transforms.Transform` instance """ Artist.set_transform(self, t) self._invalidx = True self._invalidy = True def _is_sorted(self, x): "return true if x is sorted" if len(x)<2: return 1 return np.alltrue(x[1:]-x[0:-1]>=0) @allow_rasterization def draw(self, renderer): if self._invalidy or self._invalidx: self.recache() self.ind_offset = 0 # Needed for contains() method. if self._subslice and self.axes: # Need to handle monotonically decreasing case also... x0, x1 = self.axes.get_xbound() i0, = self._x.searchsorted([x0], 'left') i1, = self._x.searchsorted([x1], 'right') subslice = slice(max(i0-1, 0), i1+1) self.ind_offset = subslice.start self._transform_path(subslice) if self._transformed_path is None: self._transform_path() if not self.get_visible(): return renderer.open_group('line2d', self.get_gid()) gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self._color) gc.set_antialiased(self._antialiased) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) if self.is_dashed(): cap = self._dashcapstyle join = self._dashjoinstyle else: cap = self._solidcapstyle join = self._solidjoinstyle gc.set_joinstyle(join) gc.set_capstyle(cap) gc.set_snap(self.get_snap()) funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') if funcname != '_draw_nothing': tpath, affine = self._transformed_path.get_transformed_path_and_affine() if len(tpath.vertices): self._lineFunc = getattr(self, funcname) funcname = self.drawStyles.get(self._drawstyle, '_draw_lines') drawFunc = getattr(self, funcname) drawFunc(renderer, gc, tpath, affine.frozen()) if self._marker: gc = renderer.new_gc() self._set_gc_clip(gc) rgbFace = self._get_rgb_face() rgbFaceAlt = self._get_rgb_face(alt=True) edgecolor = self.get_markeredgecolor() if is_string_like(edgecolor) and edgecolor.lower() == 'none': gc.set_linewidth(0) gc.set_foreground(rgbFace) else: gc.set_foreground(edgecolor) gc.set_linewidth(self._markeredgewidth) gc.set_alpha(self._alpha) marker = self._marker tpath, affine = self._transformed_path.get_transformed_points_and_affine() if len(tpath.vertices): # subsample the markers if markevery is not None markevery = self.get_markevery() if markevery is not None: if iterable(markevery): startind, stride = markevery else: startind, stride = 0, markevery if tpath.codes is not None: codes = tpath.codes[startind::stride] else: codes = None vertices = tpath.vertices[startind::stride] subsampled = Path(vertices, codes) else: subsampled = tpath snap = marker.get_snap_threshold() if type(snap) == float: snap = renderer.points_to_pixels(self._markersize) >= snap gc.set_snap(snap) gc.set_joinstyle(marker.get_joinstyle()) gc.set_capstyle(marker.get_capstyle()) marker_path = marker.get_path() marker_trans = marker.get_transform() w = renderer.points_to_pixels(self._markersize) if marker.get_marker() != ',': # Don't scale for pixels, and don't stroke them marker_trans = marker_trans.scale(w) else: gc.set_linewidth(0) renderer.draw_markers( gc, marker_path, marker_trans, subsampled, affine.frozen(), rgbFace) alt_marker_path = marker.get_alt_path() if alt_marker_path: alt_marker_trans = marker.get_alt_transform() alt_marker_trans = alt_marker_trans.scale(w) renderer.draw_markers( gc, alt_marker_path, alt_marker_trans, subsampled, affine.frozen(), rgbFaceAlt) gc.restore() gc.restore() renderer.close_group('line2d') def get_antialiased(self): return self._antialiased def get_color(self): return self._color def get_drawstyle(self): return self._drawstyle def get_linestyle(self): return self._linestyle def get_linewidth(self): return self._linewidth def get_marker(self): return self._marker.get_marker() def get_markeredgecolor(self): mec = self._markeredgecolor if (is_string_like(mec) and mec == 'auto'): if self._marker.get_marker() in ('.', ','): return self._color if self._marker.is_filled() and self.get_fillstyle() != 'none': return 'k' # Bad hard-wired default... else: return self._color else: return mec def get_markeredgewidth(self): return self._markeredgewidth def _get_markerfacecolor(self, alt=False): if alt: fc = self._markerfacecoloralt else: fc = self._markerfacecolor if (is_string_like(fc) and fc.lower() == 'auto'): if self.get_fillstyle() == 'none': return 'none' else: return self._color else: return fc def get_markerfacecolor(self): return self._get_markerfacecolor(alt=False) def get_markerfacecoloralt(self): return self._get_markerfacecolor(alt=True) def get_markersize(self): return self._markersize def get_data(self, orig=True): """ Return the xdata, ydata. If *orig* is *True*, return the original data """ return self.get_xdata(orig=orig), self.get_ydata(orig=orig) def get_xdata(self, orig=True): """ Return the xdata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._xorig if self._invalidx: self.recache() return self._x def get_ydata(self, orig=True): """ Return the ydata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._yorig if self._invalidy: self.recache() return self._y def get_path(self): """ Return the :class:`~matplotlib.path.Path` object associated with this line. """ if self._invalidy or self._invalidx: self.recache() return self._path def get_xydata(self): """ Return the *xy* data as a Nx2 numpy array. """ if self._invalidy or self._invalidx: self.recache() return self._xy def set_antialiased(self, b): """ True if line should be drawin with antialiased rendering ACCEPTS: [True | False] """ self._antialiased = b def set_color(self, color): """ Set the color of the line ACCEPTS: any matplotlib color """ self._color = color def set_drawstyle(self, drawstyle): """ Set the drawstyle of the plot 'default' connects the points with lines. The steps variants produce step-plots. 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. ACCEPTS: [ 'default' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' ] """ self._drawstyle = drawstyle def set_linewidth(self, w): """ Set the line width in points ACCEPTS: float value in points """ self._linewidth = w def set_linestyle(self, linestyle): """ Set the linestyle of the line (also accepts drawstyles) ================ ================= linestyle description ================ ================= ``'-'`` solid ``'--'`` dashed ``'-.'`` dash_dot ``':'`` dotted ``'None'`` draw nothing ``' '`` draw nothing ``''`` draw nothing ================ ================= 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. .. seealso:: :meth:`set_drawstyle` To set the drawing style (stepping) of the plot. ACCEPTS: [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'None'`` | ``' '`` | ``''`` ] and any drawstyle in combination with a linestyle, e.g. ``'steps--'``. """ for ds in self.drawStyleKeys: # long names are first in the list if linestyle.startswith(ds): self.set_drawstyle(ds) if len(linestyle) > len(ds): linestyle = linestyle[len(ds):] else: linestyle = '-' break if linestyle not in self._lineStyles: if linestyle in ls_mapper: linestyle = ls_mapper[linestyle] else: verbose.report('Unrecognized line style %s, %s' % (linestyle, type(linestyle))) if linestyle in [' ','']: linestyle = 'None' self._linestyle = linestyle @docstring.dedent_interpd def set_marker(self, marker): """ Set the line marker %(MarkerTable)s %(MarkerAccepts)s """ self._marker.set_marker(marker) def set_markeredgecolor(self, ec): """ Set the marker edge color ACCEPTS: any matplotlib color """ if ec is None : ec = 'auto' self._markeredgecolor = ec def set_markeredgewidth(self, ew): """ Set the marker edge width in points ACCEPTS: float value in points """ if ew is None : ew = rcParams['lines.markeredgewidth'] self._markeredgewidth = ew def set_markerfacecolor(self, fc): """ Set the marker face color. ACCEPTS: any matplotlib color """ if fc is None: fc = 'auto' self._markerfacecolor = fc def set_markerfacecoloralt(self, fc): """ Set the alternate marker face color. ACCEPTS: any matplotlib color """ if fc is None: fc = 'auto' self._markerfacecoloralt = fc def set_markersize(self, sz): """ Set the marker size in points ACCEPTS: float """ self._markersize = sz def set_xdata(self, x): """ Set the data np.array for x ACCEPTS: 1D array """ self._xorig = x self._invalidx = True def set_ydata(self, y): """ Set the data np.array for y ACCEPTS: 1D array """ self._yorig = y self._invalidy = True def set_dashes(self, seq): """ Set the dash sequence, sequence of dashes with on off ink in points. If seq is empty or if seq = (None, None), the linestyle will be set to solid. ACCEPTS: sequence of on/off ink in points """ if seq == (None, None) or len(seq)==0: self.set_linestyle('-') else: self.set_linestyle('--') self._dashSeq = seq # TODO: offset ignored for now def _draw_lines(self, renderer, gc, path, trans): self._lineFunc(renderer, gc, path, trans) def _draw_steps_pre(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_steps_post(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_steps_mid(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices), 2), np.float_) steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[0, 0] = vertices[0, 0] steps[-1, 0] = vertices[-1, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle('solid') renderer.draw_path(gc, path, trans) def _draw_dashed(self, renderer, gc, path, trans): gc.set_linestyle('dashed') if self._dashSeq is not None: gc.set_dashes(0, self._dashSeq) renderer.draw_path(gc, path, trans) def _draw_dash_dot(self, renderer, gc, path, trans): gc.set_linestyle('dashdot') renderer.draw_path(gc, path, trans) def _draw_dotted(self, renderer, gc, path, trans): gc.set_linestyle('dotted') renderer.draw_path(gc, path, trans) def update_from(self, other): 'copy properties from other to self' Artist.update_from(self, other) self._linestyle = other._linestyle self._linewidth = other._linewidth self._color = other._color self._markersize = other._markersize self._markerfacecolor = other._markerfacecolor self._markerfacecoloralt = other._markerfacecoloralt self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth self._dashSeq = other._dashSeq self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle self._solidcapstyle = other._solidcapstyle self._solidjoinstyle = other._solidjoinstyle self._linestyle = other._linestyle self._marker = MarkerStyle(other._marker.get_marker(), other._marker.get_fillstyle()) self._drawstyle = other._drawstyle def _get_rgb_face(self, alt=False): facecolor = self._get_markerfacecolor(alt=alt) if is_string_like(facecolor) and facecolor.lower()=='none': rgbFace = None else: rgbFace = colorConverter.to_rgb(facecolor) return rgbFace # some aliases.... def set_aa(self, val): 'alias for set_antialiased' self.set_antialiased(val) def set_c(self, val): 'alias for set_color' self.set_color(val) def set_ls(self, val): 'alias for set_linestyle' self.set_linestyle(val) def set_lw(self, val): 'alias for set_linewidth' self.set_linewidth(val) def set_mec(self, val): 'alias for set_markeredgecolor' self.set_markeredgecolor(val) def set_mew(self, val): 'alias for set_markeredgewidth' self.set_markeredgewidth(val) def set_mfc(self, val): 'alias for set_markerfacecolor' self.set_markerfacecolor(val) def set_mfcalt(self, val): 'alias for set_markerfacecoloralt' self.set_markerfacecoloralt(val) def set_ms(self, val): 'alias for set_markersize' self.set_markersize(val) def get_aa(self): 'alias for get_antialiased' return self.get_antialiased() def get_c(self): 'alias for get_color' return self.get_color() def get_ls(self): 'alias for get_linestyle' return self.get_linestyle() def get_lw(self): 'alias for get_linewidth' return self.get_linewidth() def get_mec(self): 'alias for get_markeredgecolor' return self.get_markeredgecolor() def get_mew(self): 'alias for get_markeredgewidth' return self.get_markeredgewidth() def get_mfc(self): 'alias for get_markerfacecolor' return self.get_markerfacecolor() def get_mfcalt(self, alt=False): 'alias for get_markerfacecoloralt' return self.get_markerfacecoloralt() def get_ms(self): 'alias for get_markersize' return self.get_markersize() def set_dash_joinstyle(self, s): """ Set the join style for dashed linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._dashjoinstyle = s def set_solid_joinstyle(self, s): """ Set the join style for solid linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_solid_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._solidjoinstyle = s def get_dash_joinstyle(self): """ Get the join style for dashed linestyles """ return self._dashjoinstyle def get_solid_joinstyle(self): """ Get the join style for solid linestyles """ return self._solidjoinstyle def set_dash_capstyle(self, s): """ Set the cap style for dashed linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._dashcapstyle = s def set_solid_capstyle(self, s): """ Set the cap style for solid linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._solidcapstyle = s def get_dash_capstyle(self): """ Get the cap style for dashed linestyles """ return self._dashcapstyle def get_solid_capstyle(self): """ Get the cap style for solid linestyles """ return self._solidcapstyle def is_dashed(self): 'return True if line is dashstyle' return self._linestyle in ('--', '-.', ':')
class Line2D(Artist): """ A line - the line can have both a solid linestyle connecting all the vertices, and a marker at each vertex. Additionally, the drawing of the solid line is influenced by the drawstyle, eg one can create "stepped" lines in various styles. """ lineStyles = _lineStyles = { # hidden names deprecated '-' : '_draw_solid', '--' : '_draw_dashed', '-.' : '_draw_dash_dot', ':' : '_draw_dotted', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', } _drawStyles_l = { 'default' : '_draw_lines', 'steps-mid' : '_draw_steps_mid', 'steps-pre' : '_draw_steps_pre', 'steps-post' : '_draw_steps_post', } _drawStyles_s = { 'steps' : '_draw_steps_pre', } drawStyles = {} drawStyles.update(_drawStyles_l) drawStyles.update(_drawStyles_s) markers = _markers = { # hidden names deprecated '.' : '_draw_point', ',' : '_draw_pixel', 'o' : '_draw_circle', 'v' : '_draw_triangle_down', '^' : '_draw_triangle_up', '<' : '_draw_triangle_left', '>' : '_draw_triangle_right', '1' : '_draw_tri_down', '2' : '_draw_tri_up', '3' : '_draw_tri_left', '4' : '_draw_tri_right', 's' : '_draw_square', 'p' : '_draw_pentagon', '*' : '_draw_star', 'h' : '_draw_hexagon1', 'H' : '_draw_hexagon2', '+' : '_draw_plus', 'x' : '_draw_x', 'D' : '_draw_diamond', 'd' : '_draw_thin_diamond', '|' : '_draw_vline', '_' : '_draw_hline', TICKLEFT : '_draw_tickleft', TICKRIGHT : '_draw_tickright', TICKUP : '_draw_tickup', TICKDOWN : '_draw_tickdown', CARETLEFT : '_draw_caretleft', CARETRIGHT : '_draw_caretright', CARETUP : '_draw_caretup', CARETDOWN : '_draw_caretdown', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', } filled_markers = ('o', '^', 'v', '<', '>', 's', 'd', 'D', 'h', 'H', 'p', '*') zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') def __str__(self): if self._label != "": return "Line2D(%s)"%(self._label) elif hasattr(self, '_x') and len(self._x) > 3: return "Line2D((%g,%g),(%g,%g),...,(%g,%g))"\ %(self._x[0],self._y[0],self._x[0],self._y[0],self._x[-1],self._y[-1]) elif hasattr(self, '_x'): return "Line2D(%s)"\ %(",".join(["(%g,%g)"%(x,y) for x,y in zip(self._x,self._y)])) else: return "Line2D()" def __init__(self, xdata, ydata, linewidth = None, # all Nones default to rc linestyle = None, color = None, marker = None, markersize = None, markeredgewidth = None, markeredgecolor = None, markerfacecolor = None, antialiased = None, dash_capstyle = None, solid_capstyle = None, dash_joinstyle = None, solid_joinstyle = None, pickradius = 5, drawstyle = None, **kwargs ): """ Create a :class:`~matplotlib.lines.Line2D` instance with *x* and *y* data in sequences *xdata*, *ydata*. The kwargs are :class:`~matplotlib.lines.Line2D` properties: %(Line2D)s See :meth:`set_linestyle` for a decription of the line styles, :meth:`set_marker` for a description of the markers, and :meth:`set_drawstyle` for a description of the draw styles. """ Artist.__init__(self) #convert sequences to numpy arrays if not iterable(xdata): raise RuntimeError('xdata must be a sequence') if not iterable(ydata): raise RuntimeError('ydata must be a sequence') if linewidth is None : linewidth=rcParams['lines.linewidth'] if linestyle is None : linestyle=rcParams['lines.linestyle'] if marker is None : marker=rcParams['lines.marker'] if color is None : color=rcParams['lines.color'] if markersize is None : markersize=rcParams['lines.markersize'] if antialiased is None : antialiased=rcParams['lines.antialiased'] if dash_capstyle is None : dash_capstyle=rcParams['lines.dash_capstyle'] if dash_joinstyle is None : dash_joinstyle=rcParams['lines.dash_joinstyle'] if solid_capstyle is None : solid_capstyle=rcParams['lines.solid_capstyle'] if solid_joinstyle is None : solid_joinstyle=rcParams['lines.solid_joinstyle'] if drawstyle is None : drawstyle='default' self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) self.set_linestyle(linestyle) self.set_drawstyle(drawstyle) self.set_linewidth(linewidth) self.set_color(color) self.set_marker(marker) self.set_antialiased(antialiased) self.set_markersize(markersize) self._dashSeq = None self.set_markerfacecolor(markerfacecolor) self.set_markeredgecolor(markeredgecolor) self.set_markeredgewidth(markeredgewidth) self._point_size_reduction = 0.5 self.verticalOffset = None # update kwargs before updating data to give the caller a # chance to init axes (and hence unit support) self.update(kwargs) self.pickradius = pickradius if is_numlike(self._picker): self.pickradius = self._picker self._xorig = np.asarray([]) self._yorig = np.asarray([]) self._invalid = True self.set_data(xdata, ydata) def contains(self, mouseevent): """ Test whether the mouse event occurred on the line. The pick radius determines the precision of the location test (usually within five points of the value). Use :meth:`~matplotlib.lines.Line2D.get_pickradius` or :meth:`~matplotlib.lines.Line2D.set_pickradius` to view or modify it. Returns *True* if any values are within the radius along with ``{'ind': pointlist}``, where *pointlist* is the set of points within the radius. TODO: sort returned indices by distance """ if callable(self._contains): return self._contains(self,mouseevent) if not is_numlike(self.pickradius): raise ValueError,"pick radius should be a distance" # Make sure we have data to plot if self._invalid: self.recache() if len(self._xy)==0: return False,{} # Convert points to pixels path, affine = self._transformed_path.get_transformed_path_and_affine() path = affine.transform_path(path) xy = path.vertices xt = xy[:, 0] yt = xy[:, 1] # Convert pick radius from points to pixels if self.figure == None: warning.warn('no figure set when check if mouse is on line') pixels = self.pickradius else: pixels = self.figure.dpi/72. * self.pickradius # Check for collision if self._linestyle in ['None',None]: # If no line, return the nearby point(s) d = (xt-mouseevent.x)**2 + (yt-mouseevent.y)**2 ind, = np.nonzero(np.less_equal(d, pixels**2)) else: # If line, return the nearby segment(s) ind = segment_hits(mouseevent.x,mouseevent.y,xt,yt,pixels) # Debugging message if False and self._label != u'': print "Checking line",self._label,"at",mouseevent.x,mouseevent.y print 'xt', xt print 'yt', yt #print 'dx,dy', (xt-mouseevent.x)**2., (yt-mouseevent.y)**2. print 'ind',ind # Return the point(s) within radius return len(ind)>0,dict(ind=ind) def get_pickradius(self): 'return the pick radius used for containment tests' return self.pickradius def set_pickradius(self,d): """Sets the pick radius used for containment tests ACCEPTS: float distance in points """ self.pickradius = d def set_picker(self,p): """Sets the event picker details for the line. ACCEPTS: float distance in points or callable pick function ``fn(artist, event)`` """ if callable(p): self._contains = p else: self.pickradius = p self._picker = p def get_window_extent(self, renderer): bbox = Bbox.unit() bbox.update_from_data_xy(self.get_transform().transform(self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker is not None: ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 bbox = bbox.padded(ms) return bbox def set_axes(self, ax): Artist.set_axes(self, ax) if ax.xaxis is not None: self._xcid = ax.xaxis.callbacks.connect('units', self.recache) if ax.yaxis is not None: self._ycid = ax.yaxis.callbacks.connect('units', self.recache) set_axes.__doc__ = Artist.set_axes.__doc__ def set_data(self, *args): """ Set the x and y data ACCEPTS: 2D array """ if len(args)==1: x, y = args[0] else: x, y = args not_masked = 0 if not ma.isMaskedArray(x): x = np.asarray(x) not_masked += 1 if not ma.isMaskedArray(y): y = np.asarray(y) not_masked += 1 if (not_masked < 2 or (x is not self._xorig and (x.shape != self._xorig.shape or np.any(x != self._xorig))) or (y is not self._yorig and (y.shape != self._yorig.shape or np.any(y != self._yorig)))): self._xorig = x self._yorig = y self._invalid = True def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units if ma.isMaskedArray(self._xorig) or ma.isMaskedArray(self._yorig): x = ma.asarray(self.convert_xunits(self._xorig), float) y = ma.asarray(self.convert_yunits(self._yorig), float) x = ma.ravel(x) y = ma.ravel(y) else: x = np.asarray(self.convert_xunits(self._xorig), float) y = np.asarray(self.convert_yunits(self._yorig), float) x = np.ravel(x) y = np.ravel(y) if len(x)==1 and len(y)>1: x = x * np.ones(y.shape, float) if len(y)==1 and len(x)>1: y = y * np.ones(x.shape, float) if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') x = x.reshape((len(x), 1)) y = y.reshape((len(y), 1)) if ma.isMaskedArray(x) or ma.isMaskedArray(y): self._xy = ma.concatenate((x, y), 1) else: self._xy = np.concatenate((x, y), 1) self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view # Masked arrays are now handled by the Path class itself self._path = Path(self._xy) self._transformed_path = TransformedPath(self._path, self.get_transform()) self._invalid = False def set_transform(self, t): """ set the Transformation instance used by this artist ACCEPTS: a :class:`matplotlib.transforms.Transform` instance """ Artist.set_transform(self, t) self._invalid = True # self._transformed_path = TransformedPath(self._path, self.get_transform()) def _is_sorted(self, x): "return true if x is sorted" if len(x)<2: return 1 return np.alltrue(x[1:]-x[0:-1]>=0) def draw(self, renderer): if self._invalid: self.recache() renderer.open_group('line2d') if not self._visible: return gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self._color) gc.set_antialiased(self._antialiased) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) if self.is_dashed(): cap = self._dashcapstyle join = self._dashjoinstyle else: cap = self._solidcapstyle join = self._solidjoinstyle gc.set_joinstyle(join) gc.set_capstyle(cap) gc.set_snap(self.get_snap()) funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') if funcname != '_draw_nothing': tpath, affine = self._transformed_path.get_transformed_path_and_affine() if len(tpath.vertices): self._lineFunc = getattr(self, funcname) funcname = self.drawStyles.get(self._drawstyle, '_draw_lines') drawFunc = getattr(self, funcname) drawFunc(renderer, gc, tpath, affine.frozen()) if self._marker is not None: gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self.get_markeredgecolor()) gc.set_linewidth(self._markeredgewidth) gc.set_alpha(self._alpha) funcname = self._markers.get(self._marker, '_draw_nothing') if funcname != '_draw_nothing': tpath, affine = self._transformed_path.get_transformed_points_and_affine() if len(tpath.vertices): markerFunc = getattr(self, funcname) markerFunc(renderer, gc, tpath, affine.frozen()) renderer.close_group('line2d') def get_antialiased(self): return self._antialiased def get_color(self): return self._color def get_drawstyle(self): return self._drawstyle def get_linestyle(self): return self._linestyle def get_linewidth(self): return self._linewidth def get_marker(self): return self._marker def get_markeredgecolor(self): if (is_string_like(self._markeredgecolor) and self._markeredgecolor == 'auto'): if self._marker in self.filled_markers: return 'k' else: return self._color else: return self._markeredgecolor return self._markeredgecolor def get_markeredgewidth(self): return self._markeredgewidth def get_markerfacecolor(self): if (self._markerfacecolor is None or (is_string_like(self._markerfacecolor) and self._markerfacecolor.lower()=='none') ): return self._markerfacecolor elif (is_string_like(self._markerfacecolor) and self._markerfacecolor.lower() == 'auto'): return self._color else: return self._markerfacecolor def get_markersize(self): return self._markersize def get_data(self, orig=True): """ Return the xdata, ydata. If *orig* is *True*, return the original data """ return self.get_xdata(orig=orig), self.get_ydata(orig=orig) def get_xdata(self, orig=True): """ Return the xdata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._xorig if self._invalid: self.recache() return self._x def get_ydata(self, orig=True): """ Return the ydata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._yorig if self._invalid: self.recache() return self._y def get_path(self): """ Return the :class:`~matplotlib.path.Path` object associated with this line. """ if self._invalid: self.recache() return self._path def get_xydata(self): """ Return the *xy* data as a Nx2 numpy array. """ if self._invalid: self.recache() return self._xy def set_antialiased(self, b): """ True if line should be drawin with antialiased rendering ACCEPTS: [True | False] """ self._antialiased = b def set_color(self, color): """ Set the color of the line ACCEPTS: any matplotlib color """ self._color = color def set_drawstyle(self, drawstyle): """ Set the drawstyle of the plot 'default' connects the points with lines. The steps variants produce step-plots. 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. ACCEPTS: [ 'default' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' ] """ self._drawstyle = drawstyle def set_linewidth(self, w): """ Set the line width in points ACCEPTS: float value in points """ self._linewidth = w def set_linestyle(self, linestyle): """ Set the linestyle of the line (also accepts drawstyles) ================ ================= linestyle description ================ ================= '-' solid '--' dashed '-.' dash_dot ':' dotted 'None' draw nothing ' ' draw nothing '' draw nothing ================ ================= 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. .. seealso:: :meth:`set_drawstyle` ACCEPTS: [ '-' | '--' | '-.' | ':' | 'None' | ' ' | '' ] and any drawstyle in combination with a linestyle, e.g. 'steps--'. """ # handle long drawstyle names before short ones ! for ds in flatten([k.keys() for k in (self._drawStyles_l, self._drawStyles_s)], is_string_like): if linestyle.startswith(ds): self.set_drawstyle(ds) if len(linestyle) > len(ds): linestyle = linestyle[len(ds):] else: linestyle = '-' if linestyle not in self._lineStyles: if linestyle in ls_mapper: linestyle = ls_mapper[linestyle] else: verbose.report('Unrecognized line style %s, %s' % (linestyle, type(linestyle))) if linestyle in [' ','']: linestyle = 'None' self._linestyle = linestyle def set_marker(self, marker): """ Set the line marker ========== ========================== marker description ========== ========================== '.' point ',' pixel 'o' circle 'v' triangle_down '^' triangle_up '<' triangle_left '>' triangle_right '1' tri_down '2' tri_up '3' tri_left '4' tri_right 's' square 'p' pentagon '*' star 'h' hexagon1 'H' hexagon2 '+' plus 'x' x 'D' diamond 'd' thin_diamond '|' vline '_' hline TICKLEFT tickleft TICKRIGHT tickright TICKUP tickup TICKDOWN tickdown CARETLEFT caretleft CARETRIGHT caretright CARETUP caretup CARETDOWN caretdown 'None' nothing ' ' nothing '' nothing ========== ========================== ACCEPTS: [ '+' | '*' | ',' | '.' | '1' | '2' | '3' | '4' | '<' | '>' | 'D' | 'H' | '^' | '_' | 'd' | 'h' | 'o' | 'p' | 's' | 'v' | 'x' | '|' | TICKUP | TICKDOWN | TICKLEFT | TICKRIGHT | 'None' | ' ' | '' ] """ if marker not in self._markers: verbose.report('Unrecognized marker style %s, %s' % (marker, type(marker))) if marker in [' ','']: marker = 'None' self._marker = marker self._markerFunc = self._markers[marker] def set_markeredgecolor(self, ec): """ Set the marker edge color ACCEPTS: any matplotlib color """ if ec is None : ec = 'auto' self._markeredgecolor = ec def set_markeredgewidth(self, ew): """ Set the marker edge width in points ACCEPTS: float value in points """ if ew is None : ew = rcParams['lines.markeredgewidth'] self._markeredgewidth = ew def set_markerfacecolor(self, fc): """ Set the marker face color ACCEPTS: any matplotlib color """ if fc is None : fc = 'auto' self._markerfacecolor = fc def set_markersize(self, sz): """ Set the marker size in points ACCEPTS: float """ self._markersize = sz def set_xdata(self, x): """ Set the data np.array for x ACCEPTS: 1D array """ x = np.asarray(x) self.set_data(x, self._yorig) def set_ydata(self, y): """ Set the data np.array for y ACCEPTS: 1D array """ y = np.asarray(y) self.set_data(self._xorig, y) def set_dashes(self, seq): """ Set the dash sequence, sequence of dashes with on off ink in points. If seq is empty or if seq = (None, None), the linestyle will be set to solid. ACCEPTS: sequence of on/off ink in points """ if seq == (None, None) or len(seq)==0: self.set_linestyle('-') else: self.set_linestyle('--') self._dashSeq = seq # TODO: offset ignored for now def _draw_lines(self, renderer, gc, path, trans): self._lineFunc(renderer, gc, path, trans) def _draw_steps_pre(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_steps_post(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_steps_mid(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices), 2), np.float_) steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[0, 0] = vertices[0, 0] steps[-1, 0] = vertices[-1, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] path = Path(steps) path = path.transformed(self.get_transform()) self._lineFunc(renderer, gc, path, IdentityTransform()) def _draw_nothing(self, *args, **kwargs): pass def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle('solid') renderer.draw_path(gc, path, trans) def _draw_dashed(self, renderer, gc, path, trans): gc.set_linestyle('dashed') if self._dashSeq is not None: gc.set_dashes(0, self._dashSeq) renderer.draw_path(gc, path, trans) def _draw_dash_dot(self, renderer, gc, path, trans): gc.set_linestyle('dashdot') renderer.draw_path(gc, path, trans) def _draw_dotted(self, renderer, gc, path, trans): gc.set_linestyle('dotted') renderer.draw_path(gc, path, trans) def _draw_point(self, renderer, gc, path, path_trans): w = renderer.points_to_pixels(self._markersize) * \ self._point_size_reduction * 0.5 gc.set_snap(renderer.points_to_pixels(self._markersize) > 3.0) rgbFace = self._get_rgb_face() transform = Affine2D().scale(w) renderer.draw_markers( gc, Path.unit_circle(), transform, path, path_trans, rgbFace) _draw_pixel_transform = Affine2D().translate(-0.5, -0.5) def _draw_pixel(self, renderer, gc, path, path_trans): rgbFace = self._get_rgb_face() gc.set_snap(False) renderer.draw_markers(gc, Path.unit_rectangle(), self._draw_pixel_transform, path, path_trans, rgbFace) def _draw_circle(self, renderer, gc, path, path_trans): w = renderer.points_to_pixels(self._markersize) * 0.5 gc.set_snap(renderer.points_to_pixels(self._markersize) > 3.0) rgbFace = self._get_rgb_face() transform = Affine2D().scale(w, w) renderer.draw_markers( gc, Path.unit_circle(), transform, path, path_trans, rgbFace) _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]]) def _draw_triangle_up(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_down(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, -offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_left(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset).rotate_deg(90) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_right(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset).rotate_deg(-90) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_square(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 2.0) side = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_diamond(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) side = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_thin_diamond(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5) \ .rotate_deg(45).scale(offset * 0.6, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_pentagon(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(5), transform, path, path_trans, rgbFace) def _draw_star(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() _starpath = Path.unit_regular_star(5, innerCircle=0.381966) renderer.draw_markers(gc, _starpath, transform, path, path_trans, rgbFace) def _draw_hexagon1(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, path_trans, rgbFace) def _draw_hexagon2(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(30) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, path_trans, rgbFace) _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) def _draw_vline(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._line_marker_path, transform, path, path_trans) def _draw_hline(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._line_marker_path, transform, path, path_trans) _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) def _draw_tickleft(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(-offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, path_trans) def _draw_tickright(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, path_trans) _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) def _draw_tickup(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, path_trans) def _draw_tickdown(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 1.0) offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, -offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, path_trans) _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) def _draw_plus(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._plus_path, transform, path, path_trans) _tri_path = Path([[0.0, 0.0], [0.0, -1.0], [0.0, 0.0], [0.8, 0.5], [0.0, 0.0], [-0.8, 0.5]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) def _draw_tri_down(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_up(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(180) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_left(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_right(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 5.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(270) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) def _draw_caretdown(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretup(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(180) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretleft(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(270) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretright(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) _x_path = Path([[-1.0, -1.0], [1.0, 1.0], [-1.0, 1.0], [1.0, -1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) def _draw_x(self, renderer, gc, path, path_trans): gc.set_snap(renderer.points_to_pixels(self._markersize) >= 3.0) offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._x_path, transform, path, path_trans) def update_from(self, other): 'copy properties from other to self' Artist.update_from(self, other) self._linestyle = other._linestyle self._linewidth = other._linewidth self._color = other._color self._markersize = other._markersize self._markerfacecolor = other._markerfacecolor self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth self._dashSeq = other._dashSeq self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle self._solidcapstyle = other._solidcapstyle self._solidjoinstyle = other._solidjoinstyle self._linestyle = other._linestyle self._marker = other._marker self._drawstyle = other._drawstyle def _get_rgb_face(self): facecolor = self.get_markerfacecolor() if is_string_like(facecolor) and facecolor.lower()=='none': rgbFace = None else: rgbFace = colorConverter.to_rgb(facecolor) return rgbFace # some aliases.... def set_aa(self, val): 'alias for set_antialiased' self.set_antialiased(val) def set_c(self, val): 'alias for set_color' self.set_color(val) def set_ls(self, val): 'alias for set_linestyle' self.set_linestyle(val) def set_lw(self, val): 'alias for set_linewidth' self.set_linewidth(val) def set_mec(self, val): 'alias for set_markeredgecolor' self.set_markeredgecolor(val) def set_mew(self, val): 'alias for set_markeredgewidth' self.set_markeredgewidth(val) def set_mfc(self, val): 'alias for set_markerfacecolor' self.set_markerfacecolor(val) def set_ms(self, val): 'alias for set_markersize' self.set_markersize(val) def get_aa(self): 'alias for get_antialiased' return self.get_antialiased() def get_c(self): 'alias for get_color' return self.get_color() def get_ls(self): 'alias for get_linestyle' return self.get_linestyle() def get_lw(self): 'alias for get_linewidth' return self.get_linewidth() def get_mec(self): 'alias for get_markeredgecolor' return self.get_markeredgecolor() def get_mew(self): 'alias for get_markeredgewidth' return self.get_markeredgewidth() def get_mfc(self): 'alias for get_markerfacecolor' return self.get_markerfacecolor() def get_ms(self): 'alias for get_markersize' return self.get_markersize() def set_dash_joinstyle(self, s): """ Set the join style for dashed linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._dashjoinstyle = s def set_solid_joinstyle(self, s): """ Set the join style for solid linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_solid_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._solidjoinstyle = s def get_dash_joinstyle(self): """ Get the join style for dashed linestyles """ return self._dashjoinstyle def get_solid_joinstyle(self): """ Get the join style for solid linestyles """ return self._solidjoinstyle def set_dash_capstyle(self, s): """ Set the cap style for dashed linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._dashcapstyle = s def set_solid_capstyle(self, s): """ Set the cap style for solid linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._solidcapstyle = s def get_dash_capstyle(self): """ Get the cap style for dashed linestyles """ return self._dashcapstyle def get_solid_capstyle(self): """ Get the cap style for solid linestyles """ return self._solidcapstyle def is_dashed(self): 'return True if line is dashstyle' return self._linestyle in ('--', '-.', ':')
class Line2D(Artist): lineStyles = _lineStyles = { # hidden names deprecated '-' : '_draw_solid', '--' : '_draw_dashed', '-.' : '_draw_dash_dot', ':' : '_draw_dotted', 'steps' : '_draw_steps_pre', 'steps-mid' : '_draw_steps_mid', 'steps-pre' : '_draw_steps_pre', 'steps-post' : '_draw_steps_post', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', } markers = _markers = { # hidden names deprecated '.' : '_draw_point', ',' : '_draw_pixel', 'o' : '_draw_circle', 'v' : '_draw_triangle_down', '^' : '_draw_triangle_up', '<' : '_draw_triangle_left', '>' : '_draw_triangle_right', '1' : '_draw_tri_down', '2' : '_draw_tri_up', '3' : '_draw_tri_left', '4' : '_draw_tri_right', 's' : '_draw_square', 'p' : '_draw_pentagon', 'h' : '_draw_hexagon1', 'H' : '_draw_hexagon2', '+' : '_draw_plus', 'x' : '_draw_x', 'D' : '_draw_diamond', 'd' : '_draw_thin_diamond', '|' : '_draw_vline', '_' : '_draw_hline', TICKLEFT : '_draw_tickleft', TICKRIGHT : '_draw_tickright', TICKUP : '_draw_tickup', TICKDOWN : '_draw_tickdown', CARETLEFT : '_draw_caretleft', CARETRIGHT : '_draw_caretright', CARETUP : '_draw_caretup', CARETDOWN : '_draw_caretdown', 'None' : '_draw_nothing', ' ' : '_draw_nothing', '' : '_draw_nothing', } filled_markers = ('o', '^', 'v', '<', '>', 's', 'd', 'D', 'h', 'H', 'p') zorder = 2 validCap = ('butt', 'round', 'projecting') validJoin = ('miter', 'round', 'bevel') def __str__(self): if self._label != "": return "Line2D(%s)"%(self._label) elif hasattr(self, '_x') and len(self._x) > 3: return "Line2D((%g,%g),(%g,%g),...,(%g,%g))"\ %(self._x[0],self._y[0],self._x[0],self._y[0],self._x[-1],self._y[-1]) elif hasattr(self, '_x'): return "Line2D(%s)"\ %(",".join(["(%g,%g)"%(x,y) for x,y in zip(self._x,self._y)])) else: return "Line2D()" def __init__(self, xdata, ydata, linewidth = None, # all Nones default to rc linestyle = None, color = None, marker = None, markersize = None, markeredgewidth = None, markeredgecolor = None, markerfacecolor = None, antialiased = None, dash_capstyle = None, solid_capstyle = None, dash_joinstyle = None, solid_joinstyle = None, pickradius = 5, **kwargs ): """ Create a :class:`~matplotlib.lines.Line2D` instance with *x* and *y* data in sequences *xdata*, *ydata*. The kwargs are Line2D properties: %(Line2D)s """ Artist.__init__(self) #convert sequences to numpy arrays if not iterable(xdata): raise RuntimeError('xdata must be a sequence') if not iterable(ydata): raise RuntimeError('ydata must be a sequence') if linewidth is None : linewidth=rcParams['lines.linewidth'] if linestyle is None : linestyle=rcParams['lines.linestyle'] if marker is None : marker=rcParams['lines.marker'] if color is None : color=rcParams['lines.color'] if markersize is None : markersize=rcParams['lines.markersize'] if antialiased is None : antialiased=rcParams['lines.antialiased'] if dash_capstyle is None : dash_capstyle=rcParams['lines.dash_capstyle'] if dash_joinstyle is None : dash_joinstyle=rcParams['lines.dash_joinstyle'] if solid_capstyle is None : solid_capstyle=rcParams['lines.solid_capstyle'] if solid_joinstyle is None : solid_joinstyle=rcParams['lines.solid_joinstyle'] self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) self.set_linestyle(linestyle) self.set_linewidth(linewidth) self.set_color(color) self.set_marker(marker) self.set_antialiased(antialiased) self.set_markersize(markersize) self._dashSeq = None self.set_markerfacecolor(markerfacecolor) self.set_markeredgecolor(markeredgecolor) self.set_markeredgewidth(markeredgewidth) self._point_size_reduction = 0.5 self.verticalOffset = None # update kwargs before updating data to give the caller a # chance to init axes (and hence unit support) self.update(kwargs) self.pickradius = pickradius if is_numlike(self._picker): self.pickradius = self._picker self._xorig = np.asarray([]) self._yorig = np.asarray([]) self._invalid = True self.set_data(xdata, ydata) def contains(self, mouseevent): """ Test whether the mouse event occurred on the line. The pick radius determines the precision of the location test (usually within five points of the value). Use :meth:`~matplotlib.lines.Line2D.get_pickradius`/:meth:`~matplotlib.lines.Line2D.set_pickradius` to view or modify it. Returns *True* if any values are within the radius along with ``{'ind': pointlist}``, where *pointlist* is the set of points within the radius. TODO: sort returned indices by distance """ if callable(self._contains): return self._contains(self,mouseevent) if not is_numlike(self.pickradius): raise ValueError,"pick radius should be a distance" # Make sure we have data to plot if self._invalid: self.recache() if len(self._xy)==0: return False,{} # Convert points to pixels path, affine = self._transformed_path.get_transformed_path_and_affine() path = affine.transform_path(path) xy = path.vertices xt = xy[:, 0] yt = xy[:, 1] # Convert pick radius from points to pixels if self.figure == None: warning.warn('no figure set when check if mouse is on line') pixels = self.pickradius else: pixels = self.figure.dpi/72. * self.pickradius # Check for collision if self._linestyle in ['None',None]: # If no line, return the nearby point(s) d = (xt-mouseevent.x)**2 + (yt-mouseevent.y)**2 ind, = np.nonzero(np.less_equal(d, pixels**2)) else: # If line, return the nearby segment(s) ind = segment_hits(mouseevent.x,mouseevent.y,xt,yt,pixels) # Debugging message if False and self._label != u'': print "Checking line",self._label,"at",mouseevent.x,mouseevent.y print 'xt', xt print 'yt', yt #print 'dx,dy', (xt-mouseevent.x)**2., (yt-mouseevent.y)**2. print 'ind',ind # Return the point(s) within radius return len(ind)>0,dict(ind=ind) def get_pickradius(self): 'return the pick radius used for containment tests' return self.pickradius def set_pickradius(self,d): """Sets the pick radius used for containment tests Accepts: float distance in points. """ self.pickradius = d def set_picker(self,p): """Sets the event picker details for the line. Accepts: float distance in points or callable pick function fn(artist,event) """ if callable(p): self._contains = p else: self.pickradius = p self._picker = p def get_window_extent(self, renderer): bbox = Bbox.unit() bbox.update_from_data_xy(self.get_transform().transform(self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker is not None: ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 bbox = bbox.padded(ms) return bbox def set_axes(self, ax): Artist.set_axes(self, ax) if ax.xaxis is not None: self._xcid = ax.xaxis.callbacks.connect('units', self.recache) if ax.yaxis is not None: self._ycid = ax.yaxis.callbacks.connect('units', self.recache) def set_data(self, *args): """ Set the x and y data ACCEPTS: (np.array xdata, np.array ydata) """ if len(args)==1: x, y = args[0] else: x, y = args not_masked = 0 if not ma.isMaskedArray(x): x = np.asarray(x) not_masked += 1 if not ma.isMaskedArray(y): y = np.asarray(y) not_masked += 1 if (not_masked < 2 or (x is not self._xorig and (x.shape != self._xorig.shape or np.any(x != self._xorig))) or (y is not self._yorig and (y.shape != self._yorig.shape or np.any(y != self._yorig)))): self._xorig = x self._yorig = y self._invalid = True def recache(self): #if self.axes is None: print 'recache no axes' #else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units if ma.isMaskedArray(self._xorig) or ma.isMaskedArray(self._yorig): x = ma.asarray(self.convert_xunits(self._xorig), float) y = ma.asarray(self.convert_yunits(self._yorig), float) x = ma.ravel(x) y = ma.ravel(y) else: x = np.asarray(self.convert_xunits(self._xorig), float) y = np.asarray(self.convert_yunits(self._yorig), float) x = np.ravel(x) y = np.ravel(y) if len(x)==1 and len(y)>1: x = x * np.ones(y.shape, float) if len(y)==1 and len(x)>1: y = y * np.ones(x.shape, float) if len(x) != len(y): raise RuntimeError('xdata and ydata must be the same length') x = x.reshape((len(x), 1)) y = y.reshape((len(y), 1)) if ma.isMaskedArray(x) or ma.isMaskedArray(y): self._xy = ma.concatenate((x, y), 1) else: self._xy = np.concatenate((x, y), 1) self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view # Masked arrays are now handled by the Path class itself self._path = Path(self._xy) self._transformed_path = TransformedPath(self._path, self.get_transform()) self._invalid = False def set_transform(self, t): """ set the Transformation instance used by this artist ACCEPTS: a matplotlib.transforms.Transform instance """ Artist.set_transform(self, t) self._invalid = True # self._transformed_path = TransformedPath(self._path, self.get_transform()) def _is_sorted(self, x): "return true if x is sorted" if len(x)<2: return 1 return np.alltrue(x[1:]-x[0:-1]>=0) def draw(self, renderer): if self._invalid: self.recache() renderer.open_group('line2d') if not self._visible: return gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self._color) gc.set_antialiased(self._antialiased) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) if self.is_dashed(): cap = self._dashcapstyle join = self._dashjoinstyle else: cap = self._solidcapstyle join = self._solidjoinstyle gc.set_joinstyle(join) gc.set_capstyle(cap) funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') if funcname != '_draw_nothing': tpath, affine = self._transformed_path.get_transformed_path_and_affine() lineFunc = getattr(self, funcname) lineFunc(renderer, gc, tpath, affine.frozen()) if self._marker is not None: gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self.get_markeredgecolor()) gc.set_linewidth(self._markeredgewidth) gc.set_alpha(self._alpha) funcname = self._markers.get(self._marker, '_draw_nothing') if funcname != '_draw_nothing': tpath, affine = self._transformed_path.get_transformed_points_and_affine() markerFunc = getattr(self, funcname) markerFunc(renderer, gc, tpath, affine.frozen()) renderer.close_group('line2d') def get_antialiased(self): return self._antialiased def get_color(self): return self._color def get_linestyle(self): return self._linestyle def get_linewidth(self): return self._linewidth def get_marker(self): return self._marker def get_markeredgecolor(self): if (is_string_like(self._markeredgecolor) and self._markeredgecolor == 'auto'): if self._marker in self.filled_markers: return 'k' else: return self._color else: return self._markeredgecolor return self._markeredgecolor def get_markeredgewidth(self): return self._markeredgewidth def get_markerfacecolor(self): if (self._markerfacecolor is None or (is_string_like(self._markerfacecolor) and self._markerfacecolor.lower()=='none') ): return self._markerfacecolor elif (is_string_like(self._markerfacecolor) and self._markerfacecolor.lower() == 'auto'): return self._color else: return self._markerfacecolor def get_markersize(self): return self._markersize def get_data(self, orig=True): """ Return the xdata, ydata. If *orig* is *True*, return the original data """ return self.get_xdata(orig=orig), self.get_ydata(orig=orig) def get_xdata(self, orig=True): """ Return the xdata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._xorig if self._invalid: self.recache() return self._x def get_ydata(self, orig=True): """ Return the ydata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._yorig if self._invalid: self.recache() return self._y def get_path(self): """ Return the :class:`~matplotlib.path.Path` object associated with this line. """ if self._invalid: self.recache() return self._path def get_xydata(self): """ Return the *xy* data as a Nx2 numpy array. """ if self._invalid: self.recache() return self._xy def set_antialiased(self, b): """ True if line should be drawin with antialiased rendering ACCEPTS: [True | False] """ self._antialiased = b def set_color(self, color): """ Set the color of the line ACCEPTS: any matplotlib color """ self._color = color def set_linewidth(self, w): """ Set the line width in points ACCEPTS: float value in points """ self._linewidth = w def set_linestyle(self, linestyle): """ Set the linestyle of the line 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' | 'None' | ' ' | '' ] """ if linestyle not in self._lineStyles: if ls_mapper.has_key(linestyle): linestyle = ls_mapper[linestyle] else: verbose.report('Unrecognized line style %s, %s' % (linestyle, type(linestyle))) if linestyle in [' ','']: linestyle = 'None' self._linestyle = linestyle self._lineFunc = self._lineStyles[linestyle] def set_marker(self, marker): """ Set the line marker ACCEPTS: [ '+' | ',' | '.' | '1' | '2' | '3' | '4' | '<' | '>' | 'D' | 'H' | '^' | '_' | 'd' | 'h' | 'o' | 'p' | 's' | 'v' | 'x' | '|' | TICKUP | TICKDOWN | TICKLEFT | TICKRIGHT | 'None' | ' ' | '' ] """ if marker not in self._markers: verbose.report('Unrecognized marker style %s, %s' % (marker, type(marker))) if marker in [' ','']: marker = 'None' self._marker = marker self._markerFunc = self._markers[marker] def set_markeredgecolor(self, ec): """ Set the marker edge color ACCEPTS: any matplotlib color """ if ec is None : ec = 'auto' self._markeredgecolor = ec def set_markeredgewidth(self, ew): """ Set the marker edge width in points ACCEPTS: float value in points """ if ew is None : ew = rcParams['lines.markeredgewidth'] self._markeredgewidth = ew def set_markerfacecolor(self, fc): """ Set the marker face color ACCEPTS: any matplotlib color """ if fc is None : fc = 'auto' self._markerfacecolor = fc def set_markersize(self, sz): """ Set the marker size in points ACCEPTS: float """ self._markersize = sz def set_xdata(self, x): """ Set the data np.array for x ACCEPTS: np.array """ x = np.asarray(x) self.set_data(x, self._yorig) def set_ydata(self, y): """ Set the data np.array for y ACCEPTS: np.array """ y = np.asarray(y) self.set_data(self._xorig, y) def set_dashes(self, seq): """ Set the dash sequence, sequence of dashes with on off ink in points. If seq is empty or if seq = (None, None), the linestyle will be set to solid. ACCEPTS: sequence of on/off ink in points """ if seq == (None, None) or len(seq)==0: self.set_linestyle('-') else: self.set_linestyle('--') self._dashSeq = seq # TODO: offset ignored for now def _draw_nothing(self, *args, **kwargs): pass def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle('solid') renderer.draw_path(gc, path, trans) def _draw_steps_pre(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] path = Path(steps) self._draw_solid(renderer, gc, path, trans) def _draw_steps_post(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices)-1, 2), np.float_) steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] path = Path(steps) self._draw_solid(renderer, gc, path, trans) def _draw_steps_mid(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2*len(vertices), 2), np.float_) steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[0, 0] = vertices[0, 0] steps[-1, 0] = vertices[-1, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] path = Path(steps) self._draw_solid(renderer, gc, path, trans) def _draw_dashed(self, renderer, gc, path, trans): gc.set_linestyle('dashed') if self._dashSeq is not None: gc.set_dashes(0, self._dashSeq) renderer.draw_path(gc, path, trans) def _draw_dash_dot(self, renderer, gc, path, trans): gc.set_linestyle('dashdot') renderer.draw_path(gc, path, trans) def _draw_dotted(self, renderer, gc, path, trans): gc.set_linestyle('dotted') renderer.draw_path(gc, path, trans) def _draw_point(self, renderer, gc, path, path_trans): w = renderer.points_to_pixels(self._markersize) * \ self._point_size_reduction * 0.5 rgbFace = self._get_rgb_face() transform = Affine2D().scale(w) renderer.draw_markers( gc, Path.unit_circle(), transform, path, path_trans, rgbFace) _draw_pixel_transform = Affine2D().translate(-0.5, -0.5) def _draw_pixel(self, renderer, gc, path, path_trans): rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), self._draw_pixel_transform, path, path_trans, rgbFace) def _draw_circle(self, renderer, gc, path, path_trans): w = renderer.points_to_pixels(self._markersize) * 0.5 rgbFace = self._get_rgb_face() transform = Affine2D().scale(w, w) renderer.draw_markers( gc, Path.unit_circle(), transform, path, path_trans, rgbFace) _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]]) def _draw_triangle_up(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_down(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, -offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_left(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset).rotate_deg(90) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_right(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset).rotate_deg(-90) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_square(self, renderer, gc, path, path_trans): side = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_diamond(self, renderer, gc, path, path_trans): side = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_thin_diamond(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5) \ .rotate_deg(45).scale(offset * 0.6, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_pentagon(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(5), transform, path, path_trans, rgbFace) def _draw_hexagon1(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, path_trans, rgbFace) def _draw_hexagon2(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(30) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, path_trans, rgbFace) _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) def _draw_vline(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._line_marker_path, transform, path, path_trans) def _draw_hline(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._line_marker_path, transform, path, path_trans) _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) def _draw_tickleft(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(-offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, path_trans) def _draw_tickright(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, path_trans) _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) def _draw_tickup(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, path_trans) def _draw_tickdown(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, -offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, path_trans) _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) def _draw_plus(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._plus_path, transform, path, path_trans) _tri_path = Path([[0.0, 0.0], [0.0, -1.0], [0.0, 0.0], [0.8, 0.5], [0.0, 0.0], [-0.8, 0.5]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) def _draw_tri_down(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_up(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(180) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_left(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_right(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(270) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) def _draw_caretdown(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretup(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(180) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretleft(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(270) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretright(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) _x_path = Path([[-1.0, -1.0], [1.0, 1.0], [-1.0, 1.0], [1.0, -1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO]) def _draw_x(self, renderer, gc, path, path_trans): offset = 0.5*renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._x_path, transform, path, path_trans) def update_from(self, other): 'copy properties from other to self' Artist.update_from(self, other) self._linestyle = other._linestyle self._linewidth = other._linewidth self._color = other._color self._markersize = other._markersize self._markerfacecolor = other._markerfacecolor self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth self._dashSeq = other._dashSeq self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle self._solidcapstyle = other._solidcapstyle self._solidjoinstyle = other._solidjoinstyle self._linestyle = other._linestyle self._marker = other._marker def _get_rgb_face(self): facecolor = self.get_markerfacecolor() if is_string_like(facecolor) and facecolor.lower()=='none': rgbFace = None else: rgbFace = colorConverter.to_rgb(facecolor) return rgbFace # some aliases.... def set_aa(self, val): 'alias for set_antialiased' self.set_antialiased(val) def set_c(self, val): 'alias for set_color' self.set_color(val) def set_ls(self, val): 'alias for set_linestyle' self.set_linestyle(val) def set_lw(self, val): 'alias for set_linewidth' self.set_linewidth(val) def set_mec(self, val): 'alias for set_markeredgecolor' self.set_markeredgecolor(val) def set_mew(self, val): 'alias for set_markeredgewidth' self.set_markeredgewidth(val) def set_mfc(self, val): 'alias for set_markerfacecolor' self.set_markerfacecolor(val) def set_ms(self, val): 'alias for set_markersize' self.set_markersize(val) def get_aa(self): 'alias for get_antialiased' return self.get_antialiased() def get_c(self): 'alias for get_color' return self.get_color() def get_ls(self): 'alias for get_linestyle' return self.get_linestyle() def get_lw(self): 'alias for get_linewidth' return self.get_linewidth() def get_mec(self): 'alias for get_markeredgecolor' return self.get_markeredgecolor() def get_mew(self): 'alias for get_markeredgewidth' return self.get_markeredgewidth() def get_mfc(self): 'alias for get_markerfacecolor' return self.get_markerfacecolor() def get_ms(self): 'alias for get_markersize' return self.get_markersize() def set_dash_joinstyle(self, s): """ Set the join style for dashed linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._dashjoinstyle = s def set_solid_joinstyle(self, s): """ Set the join style for solid linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_solid_joinstyle passed "%s";\n' % (s,) + 'valid joinstyles are %s' % (self.validJoin,)) self._solidjoinstyle = s def get_dash_joinstyle(self): """ Get the join style for dashed linestyles """ return self._dashjoinstyle def get_solid_joinstyle(self): """ Get the join style for solid linestyles """ return self._solidjoinstyle def set_dash_capstyle(self, s): """ Set the cap style for dashed linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._dashcapstyle = s def set_solid_capstyle(self, s): """ Set the cap style for solid linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) + 'valid capstyles are %s' % (self.validCap,)) self._solidcapstyle = s def get_dash_capstyle(self): """ Get the cap style for dashed linestyles """ return self._dashcapstyle def get_solid_capstyle(self): """ Get the cap style for solid linestyles """ return self._solidcapstyle def is_dashed(self): 'return True if line is dashstyle' return self._linestyle in ('--', '-.', ':')
class Line2D(Artist): lineStyles = _lineStyles = { # hidden names deprecated "-": "_draw_solid", "--": "_draw_dashed", "-.": "_draw_dash_dot", ":": "_draw_dotted", "steps": "_draw_steps_pre", "steps-mid": "_draw_steps_mid", "steps-pre": "_draw_steps_pre", "steps-post": "_draw_steps_post", "None": "_draw_nothing", " ": "_draw_nothing", "": "_draw_nothing", } markers = _markers = { # hidden names deprecated ".": "_draw_point", ",": "_draw_pixel", "o": "_draw_circle", "v": "_draw_triangle_down", "^": "_draw_triangle_up", "<": "_draw_triangle_left", ">": "_draw_triangle_right", "1": "_draw_tri_down", "2": "_draw_tri_up", "3": "_draw_tri_left", "4": "_draw_tri_right", "s": "_draw_square", "p": "_draw_pentagon", "h": "_draw_hexagon1", "H": "_draw_hexagon2", "+": "_draw_plus", "x": "_draw_x", "D": "_draw_diamond", "d": "_draw_thin_diamond", "|": "_draw_vline", "_": "_draw_hline", TICKLEFT: "_draw_tickleft", TICKRIGHT: "_draw_tickright", TICKUP: "_draw_tickup", TICKDOWN: "_draw_tickdown", CARETLEFT: "_draw_caretleft", CARETRIGHT: "_draw_caretright", CARETUP: "_draw_caretup", CARETDOWN: "_draw_caretdown", "None": "_draw_nothing", " ": "_draw_nothing", "": "_draw_nothing", } filled_markers = ("o", "^", "v", "<", ">", "s", "d", "D", "h", "H", "p") zorder = 2 validCap = ("butt", "round", "projecting") validJoin = ("miter", "round", "bevel") def __str__(self): if self._label != "": return "Line2D(%s)" % (self._label) elif hasattr(self, "_x") and len(self._x) > 3: return "Line2D((%g,%g),(%g,%g),...,(%g,%g))" % ( self._x[0], self._y[0], self._x[0], self._y[0], self._x[-1], self._y[-1], ) elif hasattr(self, "_x"): return "Line2D(%s)" % (",".join(["(%g,%g)" % (x, y) for x, y in zip(self._x, self._y)])) else: return "Line2D()" def __init__( self, xdata, ydata, linewidth=None, # all Nones default to rc linestyle=None, color=None, marker=None, markersize=None, markeredgewidth=None, markeredgecolor=None, markerfacecolor=None, antialiased=None, dash_capstyle=None, solid_capstyle=None, dash_joinstyle=None, solid_joinstyle=None, pickradius=5, **kwargs ): """ Create a :class:`~matplotlib.lines.Line2D` instance with *x* and *y* data in sequences *xdata*, *ydata*. The kwargs are Line2D properties: %(Line2D)s """ Artist.__init__(self) # convert sequences to numpy arrays if not iterable(xdata): raise RuntimeError("xdata must be a sequence") if not iterable(ydata): raise RuntimeError("ydata must be a sequence") if linewidth is None: linewidth = rcParams["lines.linewidth"] if linestyle is None: linestyle = rcParams["lines.linestyle"] if marker is None: marker = rcParams["lines.marker"] if color is None: color = rcParams["lines.color"] if markersize is None: markersize = rcParams["lines.markersize"] if antialiased is None: antialiased = rcParams["lines.antialiased"] if dash_capstyle is None: dash_capstyle = rcParams["lines.dash_capstyle"] if dash_joinstyle is None: dash_joinstyle = rcParams["lines.dash_joinstyle"] if solid_capstyle is None: solid_capstyle = rcParams["lines.solid_capstyle"] if solid_joinstyle is None: solid_joinstyle = rcParams["lines.solid_joinstyle"] self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) self.set_linestyle(linestyle) self.set_linewidth(linewidth) self.set_color(color) self.set_marker(marker) self.set_antialiased(antialiased) self.set_markersize(markersize) self._dashSeq = None self.set_markerfacecolor(markerfacecolor) self.set_markeredgecolor(markeredgecolor) self.set_markeredgewidth(markeredgewidth) self._point_size_reduction = 0.5 self.verticalOffset = None # update kwargs before updating data to give the caller a # chance to init axes (and hence unit support) self.update(kwargs) self.pickradius = pickradius if is_numlike(self._picker): self.pickradius = self._picker self._xorig = np.asarray([]) self._yorig = np.asarray([]) self._invalid = True self.set_data(xdata, ydata) def contains(self, mouseevent): """ Test whether the mouse event occurred on the line. The pick radius determines the precision of the location test (usually within five points of the value). Use :meth:`~matplotlib.lines.Line2D.get_pickradius`/:meth:`~matplotlib.lines.Line2D.set_pickradius` to view or modify it. Returns *True* if any values are within the radius along with ``{'ind': pointlist}``, where *pointlist* is the set of points within the radius. TODO: sort returned indices by distance """ if callable(self._contains): return self._contains(self, mouseevent) if not is_numlike(self.pickradius): raise ValueError, "pick radius should be a distance" # Make sure we have data to plot if self._invalid: self.recache() if len(self._xy) == 0: return False, {} # Convert points to pixels path, affine = self._transformed_path.get_transformed_path_and_affine() path = affine.transform_path(path) xy = path.vertices xt = xy[:, 0] yt = xy[:, 1] # Convert pick radius from points to pixels if self.figure == None: warning.warn("no figure set when check if mouse is on line") pixels = self.pickradius else: pixels = self.figure.dpi / 72.0 * self.pickradius # Check for collision if self._linestyle in ["None", None]: # If no line, return the nearby point(s) d = (xt - mouseevent.x) ** 2 + (yt - mouseevent.y) ** 2 ind, = np.nonzero(np.less_equal(d, pixels ** 2)) else: # If line, return the nearby segment(s) ind = segment_hits(mouseevent.x, mouseevent.y, xt, yt, pixels) # Debugging message if False and self._label != u"": print "Checking line", self._label, "at", mouseevent.x, mouseevent.y print "xt", xt print "yt", yt # print 'dx,dy', (xt-mouseevent.x)**2., (yt-mouseevent.y)**2. print "ind", ind # Return the point(s) within radius return len(ind) > 0, dict(ind=ind) def get_pickradius(self): "return the pick radius used for containment tests" return self.pickradius def set_pickradius(self, d): """Sets the pick radius used for containment tests Accepts: float distance in points. """ self.pickradius = d def set_picker(self, p): """Sets the event picker details for the line. Accepts: float distance in points or callable pick function fn(artist,event) """ if callable(p): self._contains = p else: self.pickradius = p self._picker = p def get_window_extent(self, renderer): bbox = Bbox.unit() bbox.update_from_data_xy(self.get_transform().transform(self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker is not None: ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 bbox = bbox.padded(ms) return bbox def set_axes(self, ax): Artist.set_axes(self, ax) if ax.xaxis is not None: self._xcid = ax.xaxis.callbacks.connect("units", self.recache) if ax.yaxis is not None: self._ycid = ax.yaxis.callbacks.connect("units", self.recache) def set_data(self, *args): """ Set the x and y data ACCEPTS: (np.array xdata, np.array ydata) """ if len(args) == 1: x, y = args[0] else: x, y = args not_masked = 0 if not ma.isMaskedArray(x): x = np.asarray(x) not_masked += 1 if not ma.isMaskedArray(y): y = np.asarray(y) not_masked += 1 if ( not_masked < 2 or (x is not self._xorig and (x.shape != self._xorig.shape or np.any(x != self._xorig))) or (y is not self._yorig and (y.shape != self._yorig.shape or np.any(y != self._yorig))) ): self._xorig = x self._yorig = y self._invalid = True def recache(self): # if self.axes is None: print 'recache no axes' # else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units if ma.isMaskedArray(self._xorig) or ma.isMaskedArray(self._yorig): x = ma.asarray(self.convert_xunits(self._xorig), float) y = ma.asarray(self.convert_yunits(self._yorig), float) x = ma.ravel(x) y = ma.ravel(y) else: x = np.asarray(self.convert_xunits(self._xorig), float) y = np.asarray(self.convert_yunits(self._yorig), float) x = np.ravel(x) y = np.ravel(y) if len(x) == 1 and len(y) > 1: x = x * np.ones(y.shape, float) if len(y) == 1 and len(x) > 1: y = y * np.ones(x.shape, float) if len(x) != len(y): raise RuntimeError("xdata and ydata must be the same length") x = x.reshape((len(x), 1)) y = y.reshape((len(y), 1)) if ma.isMaskedArray(x) or ma.isMaskedArray(y): self._xy = ma.concatenate((x, y), 1) else: self._xy = np.concatenate((x, y), 1) self._x = self._xy[:, 0] # just a view self._y = self._xy[:, 1] # just a view # Masked arrays are now handled by the Path class itself self._path = Path(self._xy) self._transformed_path = TransformedPath(self._path, self.get_transform()) self._invalid = False def set_transform(self, t): """ set the Transformation instance used by this artist ACCEPTS: a matplotlib.transforms.Transform instance """ Artist.set_transform(self, t) self._invalid = True # self._transformed_path = TransformedPath(self._path, self.get_transform()) def _is_sorted(self, x): "return true if x is sorted" if len(x) < 2: return 1 return np.alltrue(x[1:] - x[0:-1] >= 0) def draw(self, renderer): if self._invalid: self.recache() renderer.open_group("line2d") if not self._visible: return gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self._color) gc.set_antialiased(self._antialiased) gc.set_linewidth(self._linewidth) gc.set_alpha(self._alpha) if self.is_dashed(): cap = self._dashcapstyle join = self._dashjoinstyle else: cap = self._solidcapstyle join = self._solidjoinstyle gc.set_joinstyle(join) gc.set_capstyle(cap) funcname = self._lineStyles.get(self._linestyle, "_draw_nothing") if funcname != "_draw_nothing": tpath, affine = self._transformed_path.get_transformed_path_and_affine() lineFunc = getattr(self, funcname) lineFunc(renderer, gc, tpath, affine.frozen()) if self._marker is not None: gc = renderer.new_gc() self._set_gc_clip(gc) gc.set_foreground(self.get_markeredgecolor()) gc.set_linewidth(self._markeredgewidth) gc.set_alpha(self._alpha) funcname = self._markers.get(self._marker, "_draw_nothing") if funcname != "_draw_nothing": tpath, affine = self._transformed_path.get_transformed_points_and_affine() markerFunc = getattr(self, funcname) markerFunc(renderer, gc, tpath, affine.frozen()) renderer.close_group("line2d") def get_antialiased(self): return self._antialiased def get_color(self): return self._color def get_linestyle(self): return self._linestyle def get_linewidth(self): return self._linewidth def get_marker(self): return self._marker def get_markeredgecolor(self): if is_string_like(self._markeredgecolor) and self._markeredgecolor == "auto": if self._marker in self.filled_markers: return "k" else: return self._color else: return self._markeredgecolor return self._markeredgecolor def get_markeredgewidth(self): return self._markeredgewidth def get_markerfacecolor(self): if self._markerfacecolor is None or ( is_string_like(self._markerfacecolor) and self._markerfacecolor.lower() == "none" ): return self._markerfacecolor elif is_string_like(self._markerfacecolor) and self._markerfacecolor.lower() == "auto": return self._color else: return self._markerfacecolor def get_markersize(self): return self._markersize def get_data(self, orig=True): """ Return the xdata, ydata. If *orig* is *True*, return the original data """ return self.get_xdata(orig=orig), self.get_ydata(orig=orig) def get_xdata(self, orig=True): """ Return the xdata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._xorig if self._invalid: self.recache() return self._x def get_ydata(self, orig=True): """ Return the ydata. If *orig* is *True*, return the original data, else the processed data. """ if orig: return self._yorig if self._invalid: self.recache() return self._y def get_path(self): """ Return the :class:`~matplotlib.path.Path` object associated with this line. """ if self._invalid: self.recache() return self._path def get_xydata(self): """ Return the *xy* data as a Nx2 numpy array. """ if self._invalid: self.recache() return self._xy def set_antialiased(self, b): """ True if line should be drawin with antialiased rendering ACCEPTS: [True | False] """ self._antialiased = b def set_color(self, color): """ Set the color of the line ACCEPTS: any matplotlib color """ self._color = color def set_linewidth(self, w): """ Set the line width in points ACCEPTS: float value in points """ self._linewidth = w def set_linestyle(self, linestyle): """ Set the linestyle of the line 'steps' is equivalent to 'steps-pre' and is maintained for backward-compatibility. ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' | 'None' | ' ' | '' ] """ if linestyle not in self._lineStyles: if ls_mapper.has_key(linestyle): linestyle = ls_mapper[linestyle] else: verbose.report("Unrecognized line style %s, %s" % (linestyle, type(linestyle))) if linestyle in [" ", ""]: linestyle = "None" self._linestyle = linestyle self._lineFunc = self._lineStyles[linestyle] def set_marker(self, marker): """ Set the line marker ACCEPTS: [ '+' | ',' | '.' | '1' | '2' | '3' | '4' | '<' | '>' | 'D' | 'H' | '^' | '_' | 'd' | 'h' | 'o' | 'p' | 's' | 'v' | 'x' | '|' | TICKUP | TICKDOWN | TICKLEFT | TICKRIGHT | 'None' | ' ' | '' ] """ if marker not in self._markers: verbose.report("Unrecognized marker style %s, %s" % (marker, type(marker))) if marker in [" ", ""]: marker = "None" self._marker = marker self._markerFunc = self._markers[marker] def set_markeredgecolor(self, ec): """ Set the marker edge color ACCEPTS: any matplotlib color """ if ec is None: ec = "auto" self._markeredgecolor = ec def set_markeredgewidth(self, ew): """ Set the marker edge width in points ACCEPTS: float value in points """ if ew is None: ew = rcParams["lines.markeredgewidth"] self._markeredgewidth = ew def set_markerfacecolor(self, fc): """ Set the marker face color ACCEPTS: any matplotlib color """ if fc is None: fc = "auto" self._markerfacecolor = fc def set_markersize(self, sz): """ Set the marker size in points ACCEPTS: float """ self._markersize = sz def set_xdata(self, x): """ Set the data np.array for x ACCEPTS: np.array """ x = np.asarray(x) self.set_data(x, self._yorig) def set_ydata(self, y): """ Set the data np.array for y ACCEPTS: np.array """ y = np.asarray(y) self.set_data(self._xorig, y) def set_dashes(self, seq): """ Set the dash sequence, sequence of dashes with on off ink in points. If seq is empty or if seq = (None, None), the linestyle will be set to solid. ACCEPTS: sequence of on/off ink in points """ if seq == (None, None) or len(seq) == 0: self.set_linestyle("-") else: self.set_linestyle("--") self._dashSeq = seq # TODO: offset ignored for now def _draw_nothing(self, *args, **kwargs): pass def _draw_solid(self, renderer, gc, path, trans): gc.set_linestyle("solid") renderer.draw_path(gc, path, trans) def _draw_steps_pre(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2 * len(vertices) - 1, 2), np.float_) steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] path = Path(steps) self._draw_solid(renderer, gc, path, trans) def _draw_steps_post(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2 * len(vertices) - 1, 2), np.float_) steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] path = Path(steps) self._draw_solid(renderer, gc, path, trans) def _draw_steps_mid(self, renderer, gc, path, trans): vertices = self._xy steps = ma.zeros((2 * len(vertices), 2), np.float_) steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) steps[0, 0] = vertices[0, 0] steps[-1, 0] = vertices[-1, 0] steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] path = Path(steps) self._draw_solid(renderer, gc, path, trans) def _draw_dashed(self, renderer, gc, path, trans): gc.set_linestyle("dashed") if self._dashSeq is not None: gc.set_dashes(0, self._dashSeq) renderer.draw_path(gc, path, trans) def _draw_dash_dot(self, renderer, gc, path, trans): gc.set_linestyle("dashdot") renderer.draw_path(gc, path, trans) def _draw_dotted(self, renderer, gc, path, trans): gc.set_linestyle("dotted") renderer.draw_path(gc, path, trans) def _draw_point(self, renderer, gc, path, path_trans): w = renderer.points_to_pixels(self._markersize) * self._point_size_reduction * 0.5 rgbFace = self._get_rgb_face() transform = Affine2D().scale(w) renderer.draw_markers(gc, Path.unit_circle(), transform, path, path_trans, rgbFace) _draw_pixel_transform = Affine2D().translate(-0.5, -0.5) def _draw_pixel(self, renderer, gc, path, path_trans): rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), self._draw_pixel_transform, path, path_trans, rgbFace) def _draw_circle(self, renderer, gc, path, path_trans): w = renderer.points_to_pixels(self._markersize) * 0.5 rgbFace = self._get_rgb_face() transform = Affine2D().scale(w, w) renderer.draw_markers(gc, Path.unit_circle(), transform, path, path_trans, rgbFace) _triangle_path = Path([[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]]) def _draw_triangle_up(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_down(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, -offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_left(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset).rotate_deg(90) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_triangle_right(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset, offset).rotate_deg(-90) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, self._triangle_path, transform, path, path_trans, rgbFace) def _draw_square(self, renderer, gc, path, path_trans): side = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_diamond(self, renderer, gc, path, path_trans): side = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45).scale(side) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_thin_diamond(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45).scale(offset * 0.6, offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_rectangle(), transform, path, path_trans, rgbFace) def _draw_pentagon(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(5), transform, path, path_trans, rgbFace) def _draw_hexagon1(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, path_trans, rgbFace) def _draw_hexagon2(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(30) rgbFace = self._get_rgb_face() renderer.draw_markers(gc, Path.unit_regular_polygon(6), transform, path, path_trans, rgbFace) _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) def _draw_vline(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._line_marker_path, transform, path, path_trans) def _draw_hline(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._line_marker_path, transform, path, path_trans) _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) def _draw_tickleft(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(-offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, path_trans) def _draw_tickright(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(offset, 1.0) renderer.draw_markers(gc, self._tickhoriz_path, marker_transform, path, path_trans) _tickvert_path = Path([[-0.0, 0.0], [-0.0, 1.0]]) def _draw_tickup(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, path_trans) def _draw_tickdown(self, renderer, gc, path, path_trans): offset = renderer.points_to_pixels(self._markersize) marker_transform = Affine2D().scale(1.0, -offset) renderer.draw_markers(gc, self._tickvert_path, marker_transform, path, path_trans) _plus_path = Path( [[-1.0, 0.0], [1.0, 0.0], [0.0, -1.0], [0.0, 1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO] ) def _draw_plus(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._plus_path, transform, path, path_trans) _tri_path = Path( [[0.0, 0.0], [0.0, -1.0], [0.0, 0.0], [0.8, 0.5], [0.0, 0.0], [-0.8, 0.5]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO], ) def _draw_tri_down(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_up(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(180) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_left(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) def _draw_tri_right(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(270) renderer.draw_markers(gc, self._tri_path, transform, path, path_trans) _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) def _draw_caretdown(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretup(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(180) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretleft(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(270) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) def _draw_caretright(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset).rotate_deg(90) renderer.draw_markers(gc, self._caret_path, transform, path, path_trans) _x_path = Path( [[-1.0, -1.0], [1.0, 1.0], [-1.0, 1.0], [1.0, -1.0]], [Path.MOVETO, Path.LINETO, Path.MOVETO, Path.LINETO] ) def _draw_x(self, renderer, gc, path, path_trans): offset = 0.5 * renderer.points_to_pixels(self._markersize) transform = Affine2D().scale(offset) renderer.draw_markers(gc, self._x_path, transform, path, path_trans) def update_from(self, other): "copy properties from other to self" Artist.update_from(self, other) self._linestyle = other._linestyle self._linewidth = other._linewidth self._color = other._color self._markersize = other._markersize self._markerfacecolor = other._markerfacecolor self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth self._dashSeq = other._dashSeq self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle self._solidcapstyle = other._solidcapstyle self._solidjoinstyle = other._solidjoinstyle self._linestyle = other._linestyle self._marker = other._marker def _get_rgb_face(self): facecolor = self.get_markerfacecolor() if is_string_like(facecolor) and facecolor.lower() == "none": rgbFace = None else: rgbFace = colorConverter.to_rgb(facecolor) return rgbFace # some aliases.... def set_aa(self, val): "alias for set_antialiased" self.set_antialiased(val) def set_c(self, val): "alias for set_color" self.set_color(val) def set_ls(self, val): "alias for set_linestyle" self.set_linestyle(val) def set_lw(self, val): "alias for set_linewidth" self.set_linewidth(val) def set_mec(self, val): "alias for set_markeredgecolor" self.set_markeredgecolor(val) def set_mew(self, val): "alias for set_markeredgewidth" self.set_markeredgewidth(val) def set_mfc(self, val): "alias for set_markerfacecolor" self.set_markerfacecolor(val) def set_ms(self, val): "alias for set_markersize" self.set_markersize(val) def get_aa(self): "alias for get_antialiased" return self.get_antialiased() def get_c(self): "alias for get_color" return self.get_color() def get_ls(self): "alias for get_linestyle" return self.get_linestyle() def get_lw(self): "alias for get_linewidth" return self.get_linewidth() def get_mec(self): "alias for get_markeredgecolor" return self.get_markeredgecolor() def get_mew(self): "alias for get_markeredgewidth" return self.get_markeredgewidth() def get_mfc(self): "alias for get_markerfacecolor" return self.get_markerfacecolor() def get_ms(self): "alias for get_markersize" return self.get_markersize() def set_dash_joinstyle(self, s): """ Set the join style for dashed linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) + "valid joinstyles are %s" % (self.validJoin,)) self._dashjoinstyle = s def set_solid_joinstyle(self, s): """ Set the join style for solid linestyles ACCEPTS: ['miter' | 'round' | 'bevel'] """ s = s.lower() if s not in self.validJoin: raise ValueError( 'set_solid_joinstyle passed "%s";\n' % (s,) + "valid joinstyles are %s" % (self.validJoin,) ) self._solidjoinstyle = s def get_dash_joinstyle(self): """ Get the join style for dashed linestyles """ return self._dashjoinstyle def get_solid_joinstyle(self): """ Get the join style for solid linestyles """ return self._solidjoinstyle def set_dash_capstyle(self, s): """ Set the cap style for dashed linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) + "valid capstyles are %s" % (self.validCap,)) self._dashcapstyle = s def set_solid_capstyle(self, s): """ Set the cap style for solid linestyles ACCEPTS: ['butt' | 'round' | 'projecting'] """ s = s.lower() if s not in self.validCap: raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) + "valid capstyles are %s" % (self.validCap,)) self._solidcapstyle = s def get_dash_capstyle(self): """ Get the cap style for dashed linestyles """ return self._dashcapstyle def get_solid_capstyle(self): """ Get the cap style for solid linestyles """ return self._solidcapstyle def is_dashed(self): "return True if line is dashstyle" return self._linestyle in ("--", "-.", ":")