From: <lee...@us...> - 2008-12-18 15:38:43
|
Revision: 6664 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6664&view=rev Author: leejjoon Date: 2008-12-18 15:38:33 +0000 (Thu, 18 Dec 2008) Log Message: ----------- add new arrow style (a line + filled triangles) Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py trunk/matplotlib/lib/matplotlib/bezier.py trunk/matplotlib/lib/matplotlib/patches.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008-12-18 13:47:19 UTC (rev 6663) +++ trunk/matplotlib/CHANGELOG 2008-12-18 15:38:33 UTC (rev 6664) @@ -1,3 +1,5 @@ +2008-12-18 add new arrow style, a line + filled triangles. -JJL + 2008-12-18 Fix bug where a line with NULL data limits prevents subsequent data limits from calculating correctly - MGD Modified: trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008-12-18 13:47:19 UTC (rev 6663) +++ trunk/matplotlib/examples/pylab_examples/fancyarrow_demo.py 2008-12-18 15:38:33 UTC (rev 6664) @@ -3,23 +3,26 @@ styles = mpatches.ArrowStyle.get_styles() -figheight = (len(styles)+.5) -fig1 = plt.figure(1, (4, figheight)) -fontsize = 0.3 * fig1.dpi +ncol=2 +nrow = len(styles) // ncol + 1 +figheight = (nrow+0.5) +fig1 = plt.figure(1, (4.*ncol/1.5, figheight/1.5)) +fontsize = 0.2 * 70 ax = fig1.add_axes([0, 0, 1, 1], frameon=False, aspect=1.) -ax.set_xlim(0, 4) +ax.set_xlim(0, 4*ncol) ax.set_ylim(0, figheight) for i, (stylename, styleclass) in enumerate(sorted(styles.items())): - y = (float(len(styles)) -0.25 - i) # /figheight - p = mpatches.Circle((3.2, y), 0.2, fc="w") + x = 3.2 + (i//nrow)*4 + y = (figheight - 0.7 - i%nrow) # /figheight + p = mpatches.Circle((x, y), 0.2, fc="w") ax.add_patch(p) - ax.annotate(stylename, (3.2, y), - (2., y), + ax.annotate(stylename, (x, y), + (x-1.2, y), #xycoords="figure fraction", textcoords="figure fraction", ha="right", va="center", size=fontsize, Modified: trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py 2008-12-18 13:47:19 UTC (rev 6663) +++ trunk/matplotlib/examples/pylab_examples/fancybox_demo2.py 2008-12-18 15:38:33 UTC (rev 6664) @@ -4,8 +4,8 @@ styles = mpatch.BoxStyle.get_styles() figheight = (len(styles)+.5) -fig1 = plt.figure(1, (4, figheight)) -fontsize = 0.4 * fig1.dpi +fig1 = plt.figure(1, (4/1.5, figheight/1.5)) +fontsize = 0.3 * 72 for i, (stylename, styleclass) in enumerate(styles.items()): fig1.text(0.5, (float(len(styles)) - 0.5 - i)/figheight, stylename, @@ -15,3 +15,4 @@ bbox=dict(boxstyle=stylename, fc="w", ec="k")) plt.draw() plt.show() + Modified: trunk/matplotlib/lib/matplotlib/bezier.py =================================================================== --- trunk/matplotlib/lib/matplotlib/bezier.py 2008-12-18 13:47:19 UTC (rev 6663) +++ trunk/matplotlib/lib/matplotlib/bezier.py 2008-12-18 15:38:33 UTC (rev 6664) @@ -468,6 +468,38 @@ +def make_path_regular(p): + """ + fill in the codes if None. + """ + c = p.codes + if c is None: + c = np.empty(p.vertices.shape, "i") + c.fill(Path.LINETO) + c[0] = Path.MOVETO + + return Path(p.vertices, c) + else: + return p + +def concatenate_paths(paths): + """ + concatenate list of paths into a single path. + """ + + vertices = [] + codes = [] + for p in paths: + p = make_path_regular(p) + vertices.append(p.vertices) + codes.append(p.codes) + + _path = Path(np.concatenate(vertices), + np.concatenate(codes)) + return _path + + + if 0: path = Path([(0, 0), (1, 0), (2, 2)], [Path.MOVETO, Path.CURVE3, Path.CURVE3]) @@ -476,3 +508,4 @@ ax = gca() + Modified: trunk/matplotlib/lib/matplotlib/patches.py =================================================================== --- trunk/matplotlib/lib/matplotlib/patches.py 2008-12-18 13:47:19 UTC (rev 6663) +++ trunk/matplotlib/lib/matplotlib/patches.py 2008-12-18 15:38:33 UTC (rev 6664) @@ -2176,6 +2176,7 @@ from matplotlib.bezier import get_intersection, inside_circle, get_parallels from matplotlib.bezier import make_wedged_bezier2 from matplotlib.bezier import split_path_inout, get_cos_sin +from matplotlib.bezier import make_path_regular, concatenate_paths class ConnectionStyle(_Style): @@ -2627,12 +2628,15 @@ def transmute(self, path, mutation_size, linewidth): """ The transmute method is a very core of the ArrowStyle - class and must be overriden in the subclasses. It receives the - path object along which the arrow will be drawn, and the - mutation_size, with which the amount arrow head and etc. will - be scaled. It returns a Path instance. The linewidth may be - used to adjust the the path so that it does not pass beyond - the given points. + class and must be overriden in the subclasses. It receives + the path object along which the arrow will be drawn, and + the mutation_size, with which the amount arrow head and + etc. will be scaled. The linewidth may be used to adjust + the the path so that it does not pass beyond the given + points. It returns a tuple of a Path instance and a + boolean. The boolean value indicate whether the path can + be filled or not. The return value can also be a list of paths + and list of booleans of a same length. """ raise NotImplementedError('Derived must override') @@ -2646,6 +2650,8 @@ and take care of the aspect ratio. """ + path = make_path_regular(path) + if aspect_ratio is not None: # Squeeze the given height by the aspect_ratio @@ -2654,12 +2660,19 @@ vertices[:,1] = vertices[:,1] / aspect_ratio path_shrinked = Path(vertices, codes) # call transmute method with squeezed height. - path_mutated, closed = self.transmute(path_shrinked, linewidth, - mutation_size) - vertices, codes = path_mutated.vertices, path_mutated.codes - # Restore the height - vertices[:,1] = vertices[:,1] * aspect_ratio - return Path(vertices, codes), closed + path_mutated, fillable = self.transmute(path_shrinked, + linewidth, + mutation_size) + if cbook.iterable(fillable): + path_list = [] + for p in zip(path_mutated): + v, c = p.vertices, p.codes + # Restore the height + v[:,1] = v[:,1] * aspect_ratio + path_list.append(Path(v, c)) + return path_list, fillable + else: + return path_mutated, fillable else: return self.transmute(path, mutation_size, linewidth) @@ -2669,21 +2682,24 @@ """ A simple arrow which will work with any path instance. The returned path is simply concatenation of the original path + at - most two paths representing the arrow at the begin point and the - at the end point. The returned path is not closed and only meant - to be stroked. + most two paths representing the arrow head at the begin point and the + at the end point. The arrow heads can be either open or closed. """ def __init__(self, beginarrow=None, endarrow=None, + fillbegin=False, fillend=False, head_length=.2, head_width=.1): """ The arrows are drawn if *beginarrow* and/or *endarrow* are - true. *head_length* and *head_width* determines the size of - the arrow relative to the *mutation scale*. + true. *head_length* and *head_width* determines the size + of the arrow relative to the *mutation scale*. The + arrowhead at the begin (or end) is closed if fillbegin (or + fillend) is True. """ self.beginarrow, self.endarrow = beginarrow, endarrow self.head_length, self.head_width = \ head_length, head_width + self.fillbegin, self.fillend = fillbegin, fillend super(ArrowStyle._Curve, self).__init__() @@ -2783,18 +2799,35 @@ # this simple code will not work if ddx, ddy is greater than # separation bettern vertices. - vertices = np.concatenate([verticesA + [(x0+ddxA, y0+ddyA)], - path.vertices[1:-1], - [(x3+ddxB, y3+ddyB)] + verticesB]) - codes = np.concatenate([codesA, - path.codes, - codesB]) + _path = [Path(np.concatenate([[(x0+ddxA, y0+ddyA)], + path.vertices[1:-1], + [(x3+ddxB, y3+ddyB)]]), + path.codes)] + _fillable = [False] + + if self.beginarrow: + if self.fillbegin: + p = np.concatenate([verticesA, [verticesA[0], verticesA[0]], ]) + c = np.concatenate([codesA, [Path.LINETO, Path.CLOSEPOLY]]) + _path.append(Path(p, c)) + _fillable.append(True) + else: + _path.append(Path(verticesA, codesA)) + _fillable.append(False) + + if self.endarrow: + if self.fillend: + _fillable.append(True) + p = np.concatenate([verticesB, [verticesB[0], verticesB[0]], ]) + c = np.concatenate([codesB, [Path.LINETO, Path.CLOSEPOLY]]) + _path.append(Path(p, c)) + else: + _fillable.append(False) + _path.append(Path(verticesB, codesB)) + + return _path, _fillable - p = Path(vertices, codes) - return p, False - - class Curve(_Curve): """ A simple curve without any arrow head. @@ -2872,6 +2905,73 @@ _style_list["<->"] = CurveAB + + class CurveFilledA(_Curve): + """ + An arrow with filled triangle head at the begin. + """ + + def __init__(self, head_length=.4, head_width=.2): + """ + *head_length* + length of the arrow head + + *head_width* + width of the arrow head + """ + + super(ArrowStyle.CurveFilledA, self).__init__( \ + beginarrow=True, endarrow=False, + fillbegin=True, fillend=False, + head_length=head_length, head_width=head_width ) + + _style_list["<|-"] = CurveFilledA + + + class CurveFilledB(_Curve): + """ + An arrow with filled triangle head at the end. + """ + + def __init__(self, head_length=.4, head_width=.2): + """ + *head_length* + length of the arrow head + + *head_width* + width of the arrow head + """ + + super(ArrowStyle.CurveFilledB, self).__init__( \ + beginarrow=False, endarrow=True, + fillbegin=False, fillend=True, + head_length=head_length, head_width=head_width ) + + _style_list["-|>"] = CurveFilledB + + + class CurveFilledAB(_Curve): + """ + An arrow with filled triangle heads both at the begin and the end point. + """ + + def __init__(self, head_length=.4, head_width=.2): + """ + *head_length* + length of the arrow head + + *head_width* + width of the arrow head + """ + + super(ArrowStyle.CurveFilledAB, self).__init__( \ + beginarrow=True, endarrow=True, + fillbegin=True, fillend=True, + head_length=head_length, head_width=head_width ) + + _style_list["<|-|>"] = CurveFilledAB + + class _Bracket(_Base): def __init__(self, bracketA=None, bracketB=None, @@ -3201,6 +3301,7 @@ + class FancyArrowPatch(Patch): """ A fancy arrow patch. It draws an arrow using the :class:ArrowStyle. @@ -3423,9 +3524,14 @@ get_path_in_displaycoord() medthod to retrieve the arrow path in the disaply coord. """ - _path = self.get_path_in_displaycoord() + _path, fillable = self.get_path_in_displaycoord() + + if cbook.iterable(fillable): + _path = concatenate_paths(_path) + return self.get_transform().inverted().transform_path(_path) + def get_path_in_displaycoord(self): """ Return the mutated path of the arrow in the display coord @@ -3445,16 +3551,16 @@ - _path, closed = self.get_arrowstyle()(_path, - self.get_mutation_scale(), - self.get_linewidth(), - self.get_mutation_aspect() - ) + _path, fillable = self.get_arrowstyle()(_path, + self.get_mutation_scale(), + self.get_linewidth(), + self.get_mutation_aspect() + ) - if not closed: - self.fill = False + #if not fillable: + # self.fill = False - return _path + return _path, fillable @@ -3463,12 +3569,7 @@ #renderer.open_group('patch') gc = renderer.new_gc() - fill_orig = self.fill - path = self.get_path_in_displaycoord() - affine = transforms.IdentityTransform() - - if cbook.is_string_like(self._edgecolor) and self._edgecolor.lower()=='none': gc.set_linewidth(0) else: @@ -3494,8 +3595,22 @@ gc.set_hatch(self._hatch ) - renderer.draw_path(gc, path, affine, rgbFace) + path, fillable = self.get_path_in_displaycoord() - self.fill = fill_orig + if not cbook.iterable(fillable): + path = [path] + fillable = [fillable] + - #renderer.close_group('patch') + affine = transforms.IdentityTransform() + + renderer.open_group('patch', self.get_gid()) + + for p, f in zip(path, fillable): + if f: + renderer.draw_path(gc, p, affine, rgbFace) + else: + renderer.draw_path(gc, p, affine, None) + + + renderer.close_group('patch') This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |