Hi all, I think I have finally found a nice way to implement step-plots with different linestyles. The way this is done required some re-writing of lines.py, but I think it is done in a consistent manner:
A new property *drawstyle* is introduced. By default this just connects the datapoints by a straight line. It can be set to "steps-***" to create step-plots. So, the important point is that "steps-***" is no longer a linestyle and thus it is possible to set the linestyle independently. Additionally one can set a combined line- and drawstyle, e.g. linestyle='steps-mid:'. The drawstyle property has the advantage, that one can add other ways to draw the data naturally, for example one can think of a drawstyle "bspline" that connects data-points using a spline, or something like a moving-mean plot. The patch is applied and also an example and its output. If there are no objections, I will commit the patch soon. Any comments ??? Manuel
Index: lines.py
===================================================================
--- lines.py (revision 6115)
+++ lines.py (working copy)
@@ -11,7 +11,8 @@
from matplotlib import verbose
import artist
from artist import Artist
-from cbook import iterable, is_string_like, is_numlike, ls_mapper, dedent
+from cbook import iterable, is_string_like, is_numlike, ls_mapper, dedent,\
+flatten
from colors import colorConverter
from path import Path
from transforms import Affine2D, Bbox, TransformedPath, IdentityTransform
@@ -76,14 +77,24 @@
'--' : '_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',
}
+
+ _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',
@@ -155,6 +166,7 @@
dash_joinstyle = None,
solid_joinstyle = None,
pickradius = 5,
+ drawstyle = None,
**kwargs
):
"""
@@ -185,6 +197,8 @@
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)
@@ -192,6 +206,7 @@
self.set_linestyle(linestyle)
+ self.set_drawstyle(drawstyle)
self.set_linewidth(linewidth)
self.set_color(color)
self.set_marker(marker)
@@ -423,8 +438,10 @@
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())
+ 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()
@@ -442,6 +459,7 @@
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
@@ -543,6 +561,18 @@
"""
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
@@ -558,8 +588,20 @@
'steps' is equivalent to 'steps-pre' and is maintained for
backward-compatibility.
- ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'steps-pre' | 'steps-mid' | 'steps-post' | 'None' | ' ' | '' ]
+ 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 ls_mapper.has_key(linestyle):
linestyle = ls_mapper[linestyle]
@@ -569,7 +611,6 @@
if linestyle in [' ','']:
linestyle = 'None'
self._linestyle = linestyle
- self._lineFunc = self._lineStyles[linestyle]
def set_marker(self, marker):
"""
@@ -660,15 +701,10 @@
self.set_linestyle('--')
self._dashSeq = seq # TODO: offset ignored for now
- def _draw_nothing(self, *args, **kwargs):
- pass
+ def _draw_lines(self, renderer, gc, path, trans):
+ self._lineFunc(renderer, gc, path, trans)
- 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_)
@@ -678,9 +714,8 @@
path = Path(steps)
path = path.transformed(self.get_transform())
- self._draw_solid(renderer, gc, path, IdentityTransform())
+ 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_)
@@ -690,9 +725,8 @@
path = Path(steps)
path = path.transformed(self.get_transform())
- self._draw_solid(renderer, gc, path, IdentityTransform())
+ 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_)
@@ -705,9 +739,16 @@
path = Path(steps)
path = path.transformed(self.get_transform())
- self._draw_solid(renderer, gc, path, IdentityTransform())
+ 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:
@@ -990,6 +1031,7 @@
self._linestyle = other._linestyle
self._marker = other._marker
+ self._drawstyle = other._drawstyle
def _get_rgb_face(self):
@@ -1239,6 +1281,7 @@
lineStyles = Line2D._lineStyles
lineMarkers = Line2D._markers
+drawStyles = Line2D.drawStyles
artist.kwdocd['Line2D'] = artist.kwdoc(Line2D)
<<inline: steps.png>>
import pylab from numpy import * x = arange(10) pylab.plot(x,x,linestyle='steps', label='solid') pylab.plot(x,x+2,linestyle='steps-pre--', label='dashed') pylab.plot(x,x+4,linestyle='steps-mid:', label='dotted') pylab.plot(x,x+6,linestyle='steps-post-.', label='dash-dotted') pylab.legend(loc='upper left') pylab.xlim(-0.5,9.5) pylab.show()
------------------------------------------------------------------------- This SF.Net email is sponsored by the Moblin Your Move Developer's challenge Build the coolest Linux based applications with Moblin SDK & win great prizes Grand prize is a trip for two to an Open Source event anywhere in the world http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________ Matplotlib-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/matplotlib-devel
