plotting directly using the renderer

Hello everyone,
Hello John,

as you advised in a Mail some days ago concerning a fastplot-command I wrote
a polygon_factory and it worked quite well (In large parts taken from
Line2D). See the code attached.
What I now want to ask you is:
Would it be good to write this object-oriented (propably yes, so one gets
rid of all those tiny funktions _make_...(size))? One drawback which comes
into my mind is: How should this class be used within fastplot()? Initialize
an instance each time you plot a single point? Wouldn't this slow down
everything a bit (or am I overestimating the time-scales)?
On the otherhand using a class would look very 'tidy'.

Thanks for your suggestion.
Bye,
Martin

···

#--------------------------------------------------------------------

""" A routine which uses blitting so that it is possible to plot
    seperate markers faster than usual.
"""

from pylab import *
import time # for profiling

#--------------------------------------------------------------------
from matplotlib.lines import Line2D
from matplotlib.transforms import identity_transform, lbwh_to_bbox
from Numeric import pi

def _make_point(size):
    size *= .5
    if size <= 0.5:
        return _make_pixel()
    elif size <= 2:
        return _make_hexagon1(size, point=True)
    else:
        return _make_circle(size, point=True)

def _make_pixel():
    return ((-0.5, -0.5),
            (-0.5, 0.5),
            ( 0.5, 0.5),
            ( 0.5, -0.5))

def _make_circle(size, point=False):
    if point:
        size *= .5
    N = 50.0
    r = size/2.0
    rads = (2*pi/N)*arange(N)
    xs = r*cos(rads)
    ys = r*sin(rads)
    verts = [(xs[0], ys[0])]
    for x, y in zip(xs[1:], ys[1:]):
        verts.append((x, y))
    return tuple(verts)

def _make_triangle_up(size):
    return (( 0, size),
            (-size, -size),
            ( size, -size))

def _make_triangle_down(size):
    return ((-size, size),
            ( size, size),
            ( 0, -size))

def _make_triangle_left(size):
    return ((-size, 0),
            ( size, -size),
            ( size, size))

def _make_triangle_right(size):
    return (( size, 0),
            (-size, -size),
            (-size, size))

def _make_tri_down(size):
    size1 = size*0.8
    size2 = size*0.5
    return ((-size1, size2),
            ( 0, 0),
            ( size1, size2),
            ( 0, 0)
            ( 0, -size)
            ( 0, 0))

def _make_tri_up(size):
    size1 = size*0.8
    size2 = size*0.5
    return ((-size1, -size2),
            ( 0, 0),
            ( size1, -size2),
            ( 0, 0),
            ( 0, size),
            ( 0, 0))

def _make_tri_left(size):
    size1 = size*0.8
    size2 = size*0.5
    return ((size2, -size1),
            ( 0, 0),
            (size2, size1),
            ( 0, 0),
            (-size, 0),
            ( 0, 0))

def _make_tri_right(size):
    size1 = size*0.8
    size2 = size*0.5
    return ((-size2, -size1),
            ( 0, 0),
            (-size2, size1),
            ( 0, 0),
            ( size, 0),
            ( 0, 0))

def _make_square(size):
    return ((-size, -size),
            (-size, size),
            ( size, size),
            ( size, -size))

def _make_diamond(size):
    return (( size, 0),
            ( 0, -size),
            (-size, 0),
            ( 0, size))

def _make_thin_diamond(size):
    xsize = 0.6*size
    return (( xsize, 0),
            ( 0, -size),
            (-xsize, 0),
            ( 0, size))

def _make_pentagon(size):
    sizeX1 = size*0.95
    sizeY1 = size*0.31
    sizeX2 = size*0.59
    sizeY2 = size*0.81
    return (( 0, size),
            (-sizeX1, sizeY1),
            (-sizeX2, -sizeY2),
            ( sizeX2, -sizeY2),
            ( sizeX1, sizeY1))

def _make_hexagon1(size, point=False):
    if point:
        size *= .5
    sizeX1 = size*0.87
    sizeY1 = size*0.5
    return (( 0, size),
            (-sizeX1, sizeY1),
            (-sizeX1, -sizeY1),
            ( 0, -size),
            ( sizeX1, -sizeY1),
            ( sizeX1, sizeY1))

def _make_hexagon2(size):
    sizeX1 = size*0.5
    sizeY1 = size*0.87
    return (( size, 0),
            ( sizeX1, sizeY1),
            (-sizeX1, sizeY1),
            ( -size, 0),
            (-sizeX1, -sizeY1),
            ( sizeX1, -sizeY1))

def _make_plus(size):
    return ((-size, -size),
            ( size, size),
            ( 0, 0),
            ( size, -size),
            (-size, size),
            ( 0, 0))

def _make_x(size):
    return ((-size, 0),
            ( size, 0),
            ( 0, 0),
            ( 0, -size),
            ( 0, size),
            ( 0, 0))

def _make_vline(size):
    return ((0, -size),
            (0, size))

def _make_hline(size):
    return ((-size, 0),
            ( size, 0))

markerd = {
        '.' : _make_point,
        ',' : _make_pixel,
        'o' : _make_circle,
        'v' : _make_triangle_down,
        '^' : _make_triangle_up,
        '<' : _make_triangle_left,
        '>' : _make_triangle_right,
        '1' : _make_tri_down,
        '2' : _make_tri_up,
        '3' : _make_tri_left,
        '4' : _make_tri_right,
        's' : _make_square,
        'p' : _make_pentagon,
        'h' : _make_hexagon1,
        'H' : _make_hexagon2,
        '+' : _make_plus,
        'x' : _make_x,
        'D' : _make_diamond,
        'd' : _make_thin_diamond,
        '|' : _make_vline,
        '_' : _make_hline
        }

def polygon_factory(ax, marker, size, args, **kwargs):
    """ This function creates a Polygon-instance having a shape
        according to the given marker. This instance is located at
        the position specified by the args (containing two
        floats x and y).
    """
    func = markerd[marker]
    renderer = ax.get_renderer_cache()
    verts = func(size = 1.0*renderer.points_to_pixels(int(size)))
    trans = identity_transform()
    trans.set_offset( (args[0], args[1]), ax.transData)
    poly = Polygon( verts, transform=trans, **kwargs )
    poly.set_clip_box(ax.bbox)
    return poly

def fastplot_points(*args, **kwargs):
    """This program tries to enable a routine 'fastplot' using
       JDH's method of reblitting only a small region around
       the new object.

         Notice: args have to be (x, y) and not ([x], [y])
         like for plot().
         You can select the markers with the keyword marker = 'h'
         for example.
         To change their color use
           facecolor = 'g' or fc = 'g'
         and
           edgecolor = 'b' or ec = 'b' respectivly.
         To vary their size use either ms = 4.5 or markersize = 4.5.
         For a change of the markeredgewidth use
           markeredgewith, mew, linewidth or lw
         (If more of them are given they are respected in this order)
         Also all other kwargs can be used (antialiased, alpha, ...)
      """
    ax = gca()
    trans = identity_transform()
    trans.set_offset(args, ax.transData)

    marker = kwargs.pop('marker', 'o') # which marker is desired
                                        # (default:'o')?
    msize = kwargs.pop('markersize', kwargs.pop('ms', 6))
                                        # filter out the desired size
                                        # (If both kwargsare given
                                        # 'markersize' is prefered.)
    lw = kwargs.pop('markeredgewidth',
           kwargs.pop('mew',
            kwargs.pop('linewidth',
             kwargs.pop('lw', .5))))
                                        # filter out the desired
    kwargs.update({'lw':lw}) # edgewidth
        
    p = polygon_factory(ax, marker, msize, args, **kwargs)

    p.set_clip_box(ax.bbox)
    l,b,w,h = p.get_window_extent().get_bounds()
    pad = 3
    bbox = lbwh_to_bbox(l-pad, b-pad, w+2*pad, h+2*pad)
    ax.draw_artist(p)
    ax.figure.canvas.blit(bbox)
    
#-------------------------------------------------------------------
n=300
phi=2.0*pi*arange(n)/n
x=cos(phi)
y=sin(phi)

ion()
figure(1)
subplot(111, autoscale_on=False)
tstart = time.time()
title('point by point with blitting')
axis([-1,1,-1,1])
axis('scaled')
for i in xrange(n): # plot all data step by step
    fastplot_points( x[i], y[i],marker='o', fc = 'b')
tend = time.time()
t_fast = tend - tstart
close(1)
ioff()

print " It took %6.2f s."%(t_fast)

#-------------------------------------------------------------------

--
5 GB Mailbox, 50 FreeSMS http://www.gmx.net/de/go/promail
+++ GMX - die erste Adresse f�r Mail, Message, More +++