From: Manuel M. <mm...@as...> - 2006-10-13 07:16:09
|
Hallo, sorry to bother you again. I recognized that I introduced an error in my last patch :-( sym = None starlike = False # to be API compatible if sym is None and not (verts is None): ^^^^^^^^^^^ This, of cause, makes no sense. The correct line reads: if marker is None and not (verts is None): ^^^^^^^^^^^^^^ I've attached a patch... I apologize again ... Manuel Manuel Metz wrote: > John Hunter wrote: >>>>>>>>>>>>> "Manuel" == Manuel Metz <mm...@as...> writes: >>> Manuel> There is a subtle but essential difference ;-) : for i in >>> Manuel> xrange(1,len(r), 2 ) ^^^ , i.e. every second value gets >>> Manuel> rescaled. But there is probably a more "pythonic" way to >>> Manuel> do that: >>> >>> Manuel> r = 1.0/math.sqrt(math.pi) # unit area r = asarray( >>> Manuel> [r,0.5*r]*self.numsides ) >>> >>> Manuel> I'm not aware of a better way to do this with numerix :-( >>> >>> Oops, sorry I missed that. I think what you want is then >>> >>> scale = 0.5/math.sqrt(math.pi) >>> r = scale*ones(self.numsides*2) >>> r[1::2] *= 0.5 >>> > > I've fixed that - and I've learned something ! > >>> OK, if I could make a few more suggestions (I feel like a customer at >>> a restaurant where every time the waiter brings me a cup of coffee I >>> ask "just one more thing"...) >>> >>> + old_ymin,old_ymax = self.get_ylim() >>> >>> The matplotlib style guidelines are >>> >>> UpperCase : classes >>> lower_underscore : functions and methods >>> lower or lowerUpper : variables or attributes >>> >>> For shortish variable names, I prefer >>> >>> oldymin, oldymax = self.get_ylim() > > Ah - there are three lines that I touched for only one reason: the line > indention was done with a "tab" instead of "spaces". When I recognised > this in my text editor, I changed it to space-indention. That's the only > reason for these patched lines. > >>> + if isinstance(marker, str) or isinstance(marker, unicode): >>> + # the standard way to define symbols using a string > character >>> + sym = syms.get(marker) >>> >>> + if isinstance(marker, tuple) or isinstance(marker, list): >>> + # accept marker to be: >>> + # (numsides, style, [angle]) >>> >>> + if isinstance(marker[0], int) or isinstance(marker[0], > long): >>> + # (numsides, style, [angle]) >>> >>> Here you should use "duck typing" not "type checking" (google "duck >>> typing"). matplotlib.cbook provides several duck typing functions, eg >>> is_stringlike, iterable and is_numlike. Take a look at is_numlike >>> >>> def is_numlike(obj): >>> try: obj+1 >>> except TypeError: return False >>> else: return True >>> >>> Ie, if it acts like a number (you can add one to it) then we'll treat >>> it as a number. This allows users to provide other integer like >>> classes which are not ints or longs. Everytime you use isinstance, >>> take a 2nd look. There may be a better way. >>> >>> I'll await your updated patch :-) > > I've fixed that too - and learned even more ;-) Thanks ! > > Patch against latest revision is attached. > > Manuel > > > > ------------------------------------------------------------------------ > > Index: axes.py > =================================================================== > --- axes.py (revision 2811) > +++ axes.py (working copy) > @@ -14,8 +14,9 @@ > from artist import Artist, setp > from axis import XAxis, YAxis > from cbook import iterable, is_string_like, flatten, enumerate, \ > - allequal, dict_delall, popd, popall, silent_list > -from collections import RegularPolyCollection, PolyCollection, LineCollection, QuadMesh > + allequal, dict_delall, popd, popall, silent_list, is_numlike > +from collections import RegularPolyCollection, PolyCollection, LineCollection, QuadMesh, \ > + StarPolygonCollection > from colors import colorConverter, normalize, Colormap, \ > LinearSegmentedColormap, looks_like_color, is_color_like > import cm > @@ -1211,7 +1212,7 @@ > if xmax is None and hasattr(xmin,'__len__'): > xmin,xmax = xmin > > - old_xmin,old_xmax = self.get_xlim() > + old_xmin,old_xmax = self.get_xlim() > if xmin is None: xmin = old_xmin > if xmax is None: xmax = old_xmax > > @@ -1223,7 +1224,7 @@ > xmin -= 1e-38 > xmax += 1e-38 > > - self.viewLim.intervalx().set_bounds(xmin, xmax) > + self.viewLim.intervalx().set_bounds(xmin, xmax) > if emit: self._send_xlim_event() > return xmin, xmax > > @@ -1324,7 +1325,7 @@ > if ymax is None and hasattr(ymin,'__len__'): > ymin,ymax = ymin > > - old_ymin,old_ymax = self.get_ylim() > + old_ymin,old_ymax = self.get_ylim() > if ymin is None: ymin = old_ymin > if ymax is None: ymax = old_ymax > > @@ -3100,10 +3101,9 @@ > 'h' : hexagon > '8' : octagon > > + If marker is None and verts is not None, verts is a sequence > + of (x,y) vertices for a custom scatter symbol. > > - if marker is None and verts is not None, verts is a sequence > - of (x,y) vertices for a custom scatter symbol. The > - > s is a size argument in points squared. > > Any or all of x, y, s, and c may be masked arrays, in which > @@ -3171,26 +3171,74 @@ > if faceted: edgecolors = None > else: edgecolors = 'None' > > - sym = syms.get(marker) > - if sym is None and verts is None: > - raise ValueError('Unknown marker symbol to scatter') > - > + sym = None > + starlike = False > + > + # to be API compatible > + if sym is None and not (verts is None): > + marker = (verts, 0) > + verts = None > + > + if is_string_like(marker): > + # the standard way to define symbols using a string character > + sym = syms.get(marker) > + if sym is None and verts is None: > + raise ValueError('Unknown marker symbol to scatter') > + numsides, rotation = syms[marker] > + > + elif iterable(marker): > + # accept marker to be: > + # (numsides, style, [angle]) > + # or > + # (verts[], style, [angle]) > + > + if len(marker)<2 or len(marker)>3: > + raise ValueError('Cannot create markersymbol from marker') > + > + if is_numlike(marker[0]): > + # (numsides, style, [angle]) > + > + if len(marker)==2: > + numsides, rotation = marker[0], math.pi/4. > + elif len(marker)==3: > + numsides, rotation = marker[0], marker[2] > + sym = True > + > + if marker[1]==1: > + # starlike symbol, everthing else is interpreted as solid symbol > + starlike = True > + > + else: > + verts = asarray(marker[0]) > + > if sym is not None: > - numsides, rotation = syms[marker] > - collection = RegularPolyCollection( > - self.figure.dpi, > - numsides, rotation, scales, > - facecolors = colors, > - edgecolors = edgecolors, > - linewidths = linewidths, > - offsets = zip(x,y), > - transOffset = self.transData, > - ) > + if not starlike: > + collection = RegularPolyCollection( > + self.figure.dpi, > + numsides, rotation, scales, > + facecolors = colors, > + edgecolors = edgecolors, > + linewidths = linewidths, > + offsets = zip(x,y), > + transOffset = self.transData, > + ) > + else: > + collection = StarPolygonCollection( > + self.figure.dpi, > + numsides, rotation, scales, > + facecolors = colors, > + edgecolors = edgecolors, > + linewidths = linewidths, > + offsets = zip(x,y), > + transOffset = self.transData, > + ) > else: > - verts = asarray(verts) > - # hmm, the scaling is whacked -- how do we want to scale with custom verts? > + # rescale verts > + rescale = sqrt(max(verts[:,0]**2+verts[:,1]**2)) > + verts /= rescale > + > scales = asarray(scales) > - #scales = sqrt(scales * self.figure.dpi.get() / 72.) > + scales = sqrt(scales * self.figure.dpi.get() / 72.) > if len(scales)==1: > verts = [scales[0]*verts] > else: > Index: collections.py > =================================================================== > --- collections.py (revision 2811) > +++ collections.py (working copy) > @@ -15,7 +15,7 @@ > from cbook import is_string_like, iterable > from colors import colorConverter > from cm import ScalarMappable > -from numerix import arange, sin, cos, pi, asarray, sqrt, array, newaxis > +from numerix import arange, sin, cos, pi, asarray, sqrt, array, newaxis, ones > from transforms import identity_transform > > class Collection(Artist): > @@ -293,7 +293,7 @@ > * dpi is the figure dpi instance, and is required to do the > area scaling. > > - * numsides: the number of sides of the polygon > + * numsides: the number of sides of the polygon > > * sizes gives the area of the circle circumscribing the > regular polygon in points^2 > @@ -374,6 +374,43 @@ > raise NotImplementedError('Vertices in data coordinates are calculated\n' > + 'only with offsets and only if _transOffset == dataTrans.') > > +class StarPolygonCollection(RegularPolyCollection): > + def __init__(self, > + dpi, > + numsides, > + rotation = 0 , > + sizes = (1,), > + **kwargs): > + """ > + Draw a regular star like Polygone with numsides. > + > + * dpi is the figure dpi instance, and is required to do the > + area scaling. > + > + * numsides: the number of sides of the polygon > + > + * sizes gives the area of the circle circumscribing the > + regular polygon in points^2 > + > + * rotation is the rotation of the polygon in radians > + > + kwargs: See PatchCollection for more details > + > + * offsets are a sequence of x,y tuples that give the centers of > + the polygon in data coordinates > + > + * transOffset is the Transformation instance used to > + transform the centers onto the canvas. > + """ > + RegularPolyCollection.__init__(self, dpi, numsides, rotation, sizes, **kwargs) > + > + def _update_verts(self): > + scale = 1.0/math.sqrt(math.pi) > + r = scale*ones(self.numsides*2) > + r[1::2] *= 0.5 > + theta = (2.*math.pi/(2*self.numsides))*arange(2*self.numsides) + self.rotation > + self._verts = zip( r*sin(theta), r*cos(theta) ) > + > class LineCollection(Collection, ScalarMappable): > """ > All parameters must be sequences. The property of the ith line > > > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------- > Using Tomcat but need to do more? Need to support web services, security? > Get stuff done quickly with pre-integrated technology to make your job easier > Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo > http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642 > > > ------------------------------------------------------------------------ > > _______________________________________________ > Matplotlib-devel mailing list > Mat...@li... > https://lists.sourceforge.net/lists/listinfo/matplotlib-devel -- --------------------------------------- Manuel Metz ............ Stw@AIfA Argelander Institut fuer Astronomie Auf dem Huegel 71 (room 3.06) D - 53121 Bonn E-Mail: mm...@as... Web: www.astro.uni-bonn.de/~mmetz Phone: (+49) 228 / 73-3660 Fax: (+49) 228 / 73-3672 --------------------------------------- |