custom symbol patch

There is a subtle but essential difference :wink: : for i in

    > xrange(1,len(r), 2 ) ^^^ , i.e. every second value gets
    > rescaled. But there is probably a more "pythonic" way to
    > do that:

    > r = 1.0/math.sqrt(math.pi) # unit area r = asarray(
    > [r,0.5*r]*self.numsides )

    > I'm not aware of a better way to do this with numerix :frowning:

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

    > The patch against the latest svn revision (2810) is
    > attached.

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()

+ 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 :slight_smile:

JDH

John Hunter wrote:

    > There is a subtle but essential difference :wink: : for i in
    > xrange(1,len(r), 2 ) ^^^ , i.e. every second value gets
    > rescaled. But there is probably a more "pythonic" way to
    > do that:

    > r = 1.0/math.sqrt(math.pi) # unit area r = asarray(
    > [r,0.5*r]*self.numsides )

    > I'm not aware of a better way to do this with numerix :frowning:

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 :slight_smile:

I've fixed that too - and learned even more :wink: Thanks !

Patch against latest revision is attached.

Manuel

custom_symbol.c.patch (7.8 KB)

John Hunter wrote:

>
> > There is a subtle but essential difference :wink: : for i in
> > xrange(1,len(r), 2 ) ^^^ , i.e. every second value gets
> > rescaled. But there is probably a more "pythonic" way to
> > do that:
>
> > r = 1.0/math.sqrt(math.pi) # unit area r = asarray(
> > [r,0.5*r]*self.numsides )
>
> > I'm not aware of a better way to do this with numerix :frowning:
>
> 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 :slight_smile:

I've fixed that too - and learned even more :wink: Thanks !

Patch against latest revision is attached.

Manuel

custom_symbol.c.patch (7.8 KB)

Hallo,

sorry to bother you again. I recognized that I introduced an error in my
last patch :frowning:

        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:

axes.patch (398 Bytes)

···

John Hunter wrote:

    > There is a subtle but essential difference :wink: : for i in
    > xrange(1,len(r), 2 ) ^^^ , i.e. every second value gets
    > rescaled. But there is probably a more "pythonic" way to
    > do that:

    > r = 1.0/math.sqrt(math.pi) # unit area r = asarray(
    > [r,0.5*r]*self.numsides )

    > I'm not aware of a better way to do this with numerix :frowning:

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 :slight_smile:

I've fixed that too - and learned even more :wink: 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
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

--
---------------------------------------
  Manuel Metz ............ Stw@...468...
  Argelander Institut fuer Astronomie
  Auf dem Huegel 71 (room 3.06)
  D - 53121 Bonn

  E-Mail: mmetz@...459...
  Web: www.astro.uni-bonn.de/~mmetz
  Phone: (+49) 228 / 73-3660
  Fax: (+49) 228 / 73-3672
---------------------------------------