On Jul 23, 2007, at 7:18 PM, Peter Wang wrote:
On Jul 19, 2007, at 10:42 PM, Ken McIvor wrote:

Code readability is also a concern to me -- the experience of reading mpl1.py suggests to me that newcomers might find traits a bit too "voodoo". I'm confident that the same thing could be achieved using Python properties to validate
attributes.

This is a true statement.  In fact, the first version of traits
basically used properties to implement a lot of the validation and
notification.  Eventually for power and speed, we moved to using a
metaclass with a C extension.

I think the code readability question comes down to "is it easier for
someone to learn some basic things about traits, or is it easier for
them to decipher the massive jumble of property setters and getters
I've wired up"?  I think that the amount of duplicated code that has
to written using simple python properties is non-trivial.

In retrospect, I should've been clearer about my objection to using traits in mpl1. I don't have any problem with enthought.traits in an abstract sense -- it seems like an excellent solution to the problems of attribute validation and change notification. My concerns regard building a backend rendering system that uses change notifications to maintain graphics state. I believe this approach makes the rendering system harder to understand and optimize.

Since my original comment about traits I have been working hard to put my money where my mouth is. Attached is an experimental rendering system with an alternative transform architecture that does not require attribute change notification. Please let me know what you think, everybody.

Ken
#!/usr/bin/env python

# Name: mpl1_displaypdf.py
# Purpose: Experimental rendering system using DisplayPDF's drawing model
# Author: Ken McIvor <[EMAIL PROTECTED]>
#
# Copyright 2007 Illinois Institute of Technology
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL ILLINOIS INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of Illinois Institute
# of Technology shall not be used in advertising or otherwise to promote
# the sale, use or other dealings in this Software without prior written
# authorization from Illinois Institute of Technology.
#
# Derived from code Copyright 2007 John D. Hunter and released under the
# license agreement for matplotlib 0.90.1

"""
An experimental rendering system inspired by John Hunter's mpl1.py.

This system uses a Renderer to draw series of Primitive plot objects on a
Canvas implementing some of DisplayPDFs' drawing model and graphics state. The
current transformation matrix is an affine transformation matrix are stored in
PDF's form:

                                a b 0
                                c d 0
                                e f 1

A Render uses the Canvas's DisplayPDF operations to draw Primitives on the
Canvas. The Renderer draws in units of 1/72 of an inch with a scaling
specified in dots-per-inch.

Primitives may be modified at any time and may be shared between Renderers. A
Canvas may have more than one Renderer associated with them. A Renderer may be
associated with more than one Canvas during its lifetime.

The Group primitives (Group, CanvasScaledGroup, and ScaledView) work like
matlab's 'hgtransform' plot objects.  The CanvasScaledGroup renderer works
like an mpl1 FigurePane.
"""


from matplotlib import agg
import numpy as npy


def affine_identity():
    """
    a b 0
    c d 0
    e f 1
    """
    affine = npy.zeros((3,3), npy.float_)
    affine[0,0] = affine[1,1,] = affine[2,2] = 1
    return affine


def affine_from_values(a, b, c, d, e, f):
    affine = npy.zeros((3,3), npy.float_)
    affine[:,0] = a, c, e
    affine[:,1] = b, d, f
    affine[2,2] = 1
    return affine


def affine_from_rotation(angle):
    return affine_rotate(affine_identity(), angle)


def affine_from_scale(sx, sy):
    return affine_scale(affine_identity(), sx, sy)


def affine_from_translation(tx, ty):
    return affine_translate(affine_identity(), tx, ty)


def affine_from_translation_scale(tx, ty, sx, sy):
    return affine_scale(affine_translate(affine_identity(), tx, ty), sx, sy)


def affine_concat(affine,other_affine):
    return npy.dot(other_affine, affine)


def affine_rotate(affine, theta):
    a = npy.cos(theta)
    b = npy.sin(theta)
    rotate = affine_from_values(a, b, -b, a, 0, 0)
    return affine_concat(affine, rotate)


def affine_scale(affine, sx, sy):
    result = affine.copy()
    result[0] *= sx
    result[1] *= sy
    return result


def affine_translate(affine, tx, ty):
    translate = affine_identity()
    translate[2,0] = tx
    translate[2,1] = ty
    return affine_concat(affine, translate)


def radians(degrees):
    return degrees*npy.pi/180


##############################################################################


def graphics_state_default():
    return {
        'antialiased': True,
        'ctm': affine_identity(),
        'fillcolor': (0.0, 0.0, 0.0, 1.0),
        'linewidth': 1.0,
        'strokecolor': (0.0, 0.0, 0.0, 1.0)
    }


class Canvas(object):
    default_dpi = 72

    def __init__(self, width, height, dpi=None):
        super(Canvas, self).__init__()
        self.graphics_state = graphics_state_default()
        self.graphics_state_stack = []
        self.ctm_changed = False

        self.width = int(width)
        self.height = int(height)

        if dpi is None:
            dpi = self.default_dpi
        self.device_scale = dpi / 72.0

        self.device_transform = self.canvas_make_device_transform()
        self.graphics_state['ctm'] = self.device_transform

    def clear(self):
        self.reset()
        self.canvas_clear()

    def reset(self):
        self.graphics_state = graphics_state_default()
        self.graphics_state_stack = []
        self.graphics_state['ctm'] = self.device_transform
        self.canvas_set_ctm()
        self.ctm_changed = False

    def resize(self, width, height, dpi=None):
        self.width = int(width)
        self.height = int(height)

        if dpi is not None:
            self.device_scale = dpi / 72.0

        self.device_transform = self.canvas_make_device_transform()
        self.graphics_state['ctm'] = self.device_transform
        self.ctm_changed = True

        self.canvas_resize()

    # CTM and graphics state

    def concat_ctm(self, transform):
        self.graphics_state['ctm'] = affine_concat(self.graphics_state['ctm'],
            transform)
        self.ctm_changed = True

    def restore_graphics_state(self):
        try:
            gstate = self.graphics_state_stack.pop()
        except IndexError:
            pass
        else:
            self.canvas_set_graphics_state(gstate)
            self.graphics_state = gstate
            self.ctm_changed = True

    def save_graphics_state(self):
        self.graphics_state_stack.append(self.graphics_state.copy())

    def update_graphics_style(self, style_dict):
        self.canvas_update_graphics_style(style_dict)
        self.graphics_state.update(style_dict)

    # public template method

    def show(self):
        raise NotImplementedError
        
    # private template methods

    def canvas_clear(self):
        raise NotImplementedError

    def canvas_make_device_transform(self):
        return affine_concat(
            # scale from 1/72" to device units
            affine_from_scale(self.device_scale, self.device_scale),
            # (0, 0) is usually device's (left, upper), so flip Y by default
            affine_from_values(1, 0, 0, -1, 0, self.height))

    def canvas_resize(self):
        raise NotImplementedError

    def canvas_set_ctm(self):
        raise NotImplementedError

    def canvas_set_graphics_state(self, other_gstate):
        raise NotImplementedError

    def canvas_update_graphics_style(self, style_dict):
        raise NotImplementedError

    def create_canvas_image(self, image):
        return None

    def create_canvas_path(self, path):
        return None

    def create_canvas_text(self, text):
        return None

    def draw_image(self, image):
        raise NotImplementedError

    def draw_path(self, path):
        raise NotImplementedError

    def draw_text(self, text):
        raise NotImplementedError


class PrimitiveContainer(object):
    def __init__(self):
        self.primitive_list = []

    def add(self, primitive):
        if primitive not in self.primitive_list:
            self.primitive_list.append(primitive)

    def clear(self):
        del self.primitive_list[:]

    def remove(self, primitive):
        try:
            self.primitive_list.remove(primitive)
        except ValueError:
            pass


class Renderer(PrimitiveContainer):
    def __init__(self, canvas):
        super(Renderer, self).__init__()        
        self.canvas = canvas

    def add(self, primitive):
        super(Renderer, self).add(primitive)
        canvas = self.canvas

        def get_canvas_primitives(primitive):
            cls = primitive.__class__
            if cls is Group or cls is CanvasScaledGroup or cls is ScaledView:
                for group_primitive in primitive.primitive_list:
                    get_canvas_primitives(group_primitive)
            elif isinstance(primitive, CanvasPrimitive):
                primitive.get_canvas_primitive(canvas)
        get_canvas_primitives(primitive)

    def clear(self):
        super(Renderer, self).clear()

    def render(self):
        self.canvas.reset()
        for primitive in self.primitive_list:
            self.render_primitive(primitive)

    def render_primitive(self, primitive):
        canvas = self.canvas
        cls = primitive.__class__
        style = primitive.style

        if cls is CanvasScaledGroup:
            transform = primitive.scaled_group_transform(canvas.width,
                canvas.height)
        else:
            transform = primitive.transform

        need_restore = False
        if style is not None or transform is not None:
            need_restore = True
            canvas.save_graphics_state()

            if style is not None:
                canvas.update_graphics_style(style.style_dict)

            if transform is not None:
                canvas.concat_ctm(transform)

        if cls is Group or cls is CanvasScaledGroup or cls is ScaledView:
            for group_primitive in primitive.primitive_list:
                self.render_primitive(group_primitive)
        else:
            if canvas.ctm_changed:
                canvas.canvas_set_ctm()
                canvas.ctm_changed = False

            if cls is Path:
                canvas.draw_path(primitive)
            elif cls is Text:
                canvas.draw_text(primitive)
            elif cls is Image:
                canvas.draw_image(primitive)

        if need_restore:
            canvas.restore_graphics_state()


class GraphicsStyle(object):
    def __init__(self, style_dict=None):
        super(GraphicsStyle, self).__init__()

        self.style_dict = {}
        if style_dict is not None:
            for key, value in style_dict.items():
                setattr(self, key, value)

    def copy(self):
        return GraphicsStyle(self.style_dict)

    # 'antialiased' attribute

    def get_antialiased(self):
        return self.style_dict.get('antialiased')

    def set_antialiased(self, antialiased):
        self.style_dict['antialiased'] = bool(antialiased)

    antialiased = property(get_antialiased, set_antialiased)

    # 'fillcolor' attribute

    def get_fillcolor(self):
        return self.style_dict.get('fillcolor')

    def set_fillcolor(self, fillcolor):
        # TODO: validate fillcolor and convert it to an RGBA tuple
        self.style_dict['fillcolor'] = fillcolor

    fillcolor = property(get_fillcolor, set_fillcolor)

    # 'linewidth' attribute 

    def get_linewidth(self):
        return self.style_dict.get('linewidth')

    def set_linewidth(self, linewidth):
        # TODO: validate linewidth
        self.style_dict['linewidth'] = linewidth

    linewidth = property(get_linewidth, set_linewidth)

    # 'strokecolor' attribute

    def get_strokecolor(self):
        return self.style_dict.get('strokecolor')

    def set_strokecolor(self, strokecolor):
        # TODO: validate strokecolor and convert it to an RGBA tuple
        self.style_dict['strokecolor'] = strokecolor

    strokecolor = property(get_strokecolor, set_strokecolor)


class Primitive(object):
    transform = None
    _copy_transform = True

    def __init__(self):
        super(Primitive, self).__init__()
        self.style = GraphicsStyle()

    def copy(self):
        clone = self.__class__()
        if self._copy_transform:
            clone.transform = self.transform
        clone.style = self.style.copy()
        return clone


class CanvasPrimitive(Primitive):
    def __init__(self):
        super(CanvasPrimitive, self).__init__()
        self.canvas_primitive_cache = {}

    def get_canvas_primitive(self, canvas):
        cache_id = canvas.__class__
        canvas_primitive_cache = self.canvas_primitive_cache        
        canvas_primitive = canvas_primitive_cache.get(cache_id)

        if cache_id in canvas_primitive_cache:
            canvas_primitive = canvas_primitive_cache[cache_id]
        else:
            canvas_primitive = canvas_primitive_cache[cache_id] = \
                self.create_canvas_primitive(canvas)

        if canvas_primitive is None:
            return self
        return canvas_primitive


class Path(CanvasPrimitive):
    MOVETO, LINETO, CLOSEPOLY = range(3)

    def __init__(self):
        super(Path, self).__init__()
        self._commands = []

    def get_commands(self):
        return self._commands

    def set_commands(self, commands):
        # TODO: validate commands 2-tuple
        self._commands = commands
        self.canvas_primitive_cache.clear()

    commands = property(get_commands, set_commands)

    def copy(self):
        clone = super(Path, self).copy()
        clone.commands[:] = self.commands
        return clone

    def create_canvas_primitive(self, canvas):
        return canvas.create_canvas_path(self)


class Image(CanvasPrimitive):
    def __init__(self):
        super(Image, self).__init__()
        raise NotImplementedError

    def copy(self):
        raise NotImplementedError


class Text(CanvasPrimitive):
    def __init__(self):
        super(Text, self).__init__()
        raise NotImplementedError

    def copy(self):
        raise NotImplementedError


class Group(Primitive, PrimitiveContainer):
    def __init__(self, transform=None):
        super(Group, self).__init__()
        if transform is not None:
            self.transform = transform

    def copy(self):
        clone = super(Group, self).copy()
        clone.primitive_list[:] = self.primitive_list
        return clone


class CanvasScaledGroup(Group):
    _copy_transform = False

    def __init__(self, lbwh=None):
        super(CanvasScaledGroup, self).__init__()

        if lbwh is None:
            self.lbwh = (0.0, 0.0, 1.0, 1.0)
        else:
            self.lbwh = lbwh

    def copy(self):
        clone = super(CanvasScaledGroup, self).copy()
        clone.lbwh = self.lbwh
        return clone

    def get_transform(self):
        return None
    transform = property(get_transform)

    def scaled_group_transform(self, width, height):
        l, b, w, h = self.lbwh
        ret = affine_from_translation_scale(l*width, b*height, w*width,
            h*height)
        return ret


class ScaledView(Group):
    _copy_transform = False

    def __init__(self, limits=None):
        super(ScaledView, self).__init__()

        if limits is None:
            self.xlim = (0., 1.)
            self.ylim = (0., 1.)
        else:
            self.xlim = limits[0]
            self.ylim = limits[1]

    def copy(self):
        clone = super(ScaledView, self).copy()
        clone.xlim = self.xlim
        clone.ylim = self.ylim
        return clone

    def get_transform(self):
        transform = affine_identity()

        xmin, xmax = self.xlim
        xscale = 1./(xmax-xmin)
        transform[0][0] = xscale
        transform[0][2] = -xmin*xscale

        ymin, ymax = self.ylim
        yscale = 1./(ymax-ymin)
        transform[1][1] = yscale
        transform[1][2] = -ymin*yscale

        transform = affine_from_values(xscale, 0, 0, yscale,
            -xmin*xscale, -ymin*yscale)

        return transform
    transform = property(get_transform)


##############################################################################

class CanvasAgg(Canvas):
    clear_color = agg.rgba8(128,128,128,255)

    def __init__(self, width, height, dpi=None):
        super(CanvasAgg, self).__init__(width, height, dpi)
        # buffer
        self.buf = None
        # rendering buffer
        self.rbuf = None
        # rendering buffer pixel format
        self.pf = None
        # renderer base
        self.rbase = None
        # antialiased renderers
        self.renderer = self.rasterizer = self.scanline = None
        # aliased renderers
        self.rendererbin = self.scanlinebin = None
        # agg CTM
        self.agg_affine = None
        # rgba8 fillcolor
        self.agg_fillcolor = None
        # rgba8 strokecolor
        self.agg_strokecolor = None

        # creates all of the agg rendering objects
        self.canvas_resize()

        # creates agg_affine
        self.canvas_set_ctm()

        # create the agg.rgba8 versions of fillcolor and strokecolor
        gstate = self.graphics_state

        if gstate['fillcolor'] is not None:
            color = [int(255*c) for c in gstate['fillcolor']]
            self.agg_fillcolor = agg.rgba8(*color)

        if gstate['strokecolor'] is not None:
            color = [int(255*c) for c in gstate['strokecolor']]
            self.agg_strokecolor = agg.rgba8(*color)

    def show(self):
        # we'll cheat a little and use pylab for display

        pix_width = int(self.width * self.device_scale)
        pix_height = int(self.height * self.device_scale)
        X = npy.fromstring(self.buf.to_string(), npy.uint8)
        X.shape = pix_height, pix_width, 4

        if 1:
            import pylab
            fig = pylab.figure()
            ax = fig.add_axes([0,0,1,1], xticks=[], yticks=[],
                              frameon=False, aspect='auto')
            ax.imshow(X, aspect='auto')
            pylab.show()

    def canvas_clear(self):
        self.rbase.clear_rgba8(self.clear_color)

    def canvas_resize(self):
        pix_width = int(self.width * self.device_scale)
        pix_height = int(self.height * self.device_scale)
        stride = pix_width * 4

        self.buf = buf = agg.buffer(pix_width, pix_height, stride)
        self.rbuf = rbuf = agg.rendering_buffer()
        rbuf.attachb(buf)

        self.pf = pf = agg.pixel_format_rgba(rbuf)
        self.rbase = rbase = agg.renderer_base_rgba(pf)
        rbase.clear_rgba8(self.clear_color)

        self.renderer =  agg.renderer_scanline_aa_solid_rgba(rbase);        
        self.rasterizer = agg.rasterizer_scanline_aa()
        self.scanline = agg.scanline_p8()
        self.trans = None

        self.rendererbin =  agg.renderer_scanline_bin_solid_rgba(rbase);
        self.scanlinebin = agg.scanline_bin()

    def canvas_set_ctm(self):
        ctm = self.graphics_state['ctm']
        a, c, e = ctm[:,0]
        b, d, f = ctm[:,1]
        self.agg_affine = agg.trans_affine(a, b, c, d, e, f)

    def canvas_set_graphics_state(self, gstate):
        mystate = self.graphics_state

        if gstate['fillcolor'] != mystate['fillcolor']:
            color = gstate['fillcolor']
            if color is None:
                self.agg_fillcolor = None
            else:
                color = tuple([int(255*c) for c in color])
                self.agg_fillcolor = agg.rgba8(*color)

        if gstate['strokecolor'] != mystate['strokecolor']:
            color = gstate['strokecolor']
            if color is None:
                self.agg_strokecolor = None
            else:
                color = tuple([int(255*c) for c in color])
                self.agg_strokecolor = agg.rgba8(*color)

    def canvas_update_graphics_style(self, style_dict):
        gstate = self.graphics_state

        if 'fillcolor' in style_dict:
            color = style_dict['fillcolor']
            if color is None:
                self.agg_fillcolor = None
            else:
                color = tuple([int(255*c) for c in color])
                self.agg_fillcolor = agg.rgba8(*color)

        if 'strokecolor' in style_dict:
            color = style_dict.get('strokecolor', gstate['strokecolor'])
            if color is None:
                self.agg_strokecolor = None
            else:
                color = tuple([int(255*c) for c in color])
                self.agg_strokecolor = agg.rgba8(*color)

    def create_canvas_path(self, path):
        agg_path = agg.path_storage()
        codes, verts = path.commands

        MOVETO = Path.MOVETO
        LINETO = Path.LINETO
        CLOSEPOLY = Path.CLOSEPOLY

        N = len(codes)
        for i in xrange(N):
            x, y = verts[i]
            code = codes[i]
            if code==MOVETO:
                agg_path.move_to(x, y)
            elif code==LINETO:
                agg_path.line_to(x, y)                
            elif code==CLOSEPOLY:
                agg_path.close_polygon()
        return agg_path

    def draw_path(self, path):
        agg_path = path.get_canvas_primitive(self)
        gstate = self.graphics_state

        if gstate['antialiased']:
            renderer = self.renderer
            scanline = self.scanline
            render_scanlines = agg.render_scanlines_rgba
        else:
            renderer = self.rendererbin
            scanline = self.scanlinebin
            render_scanlines = agg.render_scanlines_bin_rgba

        transpath = agg.conv_transform_path(agg_path, self.agg_affine)

        agg_strokecolor = self.agg_strokecolor
        if agg_strokecolor is None:
            renderer.color_rgba8(self.clear_color)
        else:
            renderer.color_rgba8(agg_strokecolor)

        if self.agg_fillcolor is not None:
            self.rasterizer.add_path(transpath)
            renderer.color_rgba8(self.agg_fillcolor)
            render_scanlines(self.rasterizer, scanline, renderer)

        if self.agg_strokecolor is not None:
            stroke = agg.conv_stroke_transpath(transpath)
            stroke.width(gstate['linewidth'])
            self.rasterizer.add_path(stroke)
            renderer.color_rgba8(self.agg_strokecolor)
            render_scanlines(self.rasterizer, scanline, renderer)


##############################################################################

def make_rectangle(lbwh, **kwds):
    path = Path()
    if kwds:
        path.style = GraphicsStyle(kwds)

    l,b,w,h = lbwh
    t = b+h
    r = l+w
    verts = npy.array([(l,b), (l,t), (r, t), (r, b), (0,0)], npy.float_)
    codes = Path.LINETO*npy.ones(5, npy.uint8)
    codes[0] = Path.MOVETO
    codes[-1] = Path.CLOSEPOLY
    path.commands = codes, verts
    return path


def polar_transform(X):
    'transform the numpy array with shape N,2'
    r = X[:,0]
    theta = X[:,1]
    x = r*npy.cos(theta)
    y = r*npy.sin(theta)
    return npy.array([x,y]).T


def make_line(x, y, model=None, **kwds):
    """
    The model is a function taking Nx2->Nx2. This is where a nonlinear
    transformation can be used.
    """
    path = Path()
    if kwds:
        path.style = GraphicsStyle(kwds)

    X = npy.array([x,y]).T
    numrows, numcols = X.shape

    codes = Path.LINETO*npy.ones(numrows, npy.uint8)
    codes[0] = Path.MOVETO

    if model is None:
        verts = X
    else:
        verts = model(X)

    path.commands = codes, verts    
    return path


# RGBA color tuples
BLUE   = (0.0, 0.0, 1.0, 1.0)
GREEN  = (0.0, 0.5, 0.0, 1.0)
RED    = (1.0, 0.0, 0.0, 1.0)
YELLOW = (1.0, 1.0, 0.0, 1.0)
WHITE  = (1.0, 1.0, 1.0, 1.0)

rect1 = make_rectangle([0, 0, 1, 1], strokecolor=None)
rect2 = make_rectangle([0.25,0.25,0.5,0.5], fillcolor=RED, strokecolor=None)

figure1 = CanvasScaledGroup((0.1, 0.1, 0.8, 0.8))
figure1.add(rect1)
figure1.add(rect2)

x1 = npy.arange(0, 10, 0.01)
y1 = npy.cos(2*npy.pi*x1)
line1 = make_line(x1, y1, linewidth=2, fillcolor=None, strokecolor=BLUE)
view1_limits = ((0, 10), (-1.1, 1.1))
view1 = ScaledView(view1_limits)
view1.add(line1)
figure2 = CanvasScaledGroup()
figure2.add(view1)

axes1 = Group(affine_from_translation_scale(0, 0, 0.5, 0.5))
axes1.add(rect1)
axes1.add(rect2)
figure3 = CanvasScaledGroup()
figure3.add(axes1)

axes2 = Group(affine_from_translation_scale(0.5, 0.5, 0.5, 0.5))
axes2.add(make_rectangle([0, 0, 1, 1], fillcolor=WHITE))
axes2.add(view1)
figure4 = CanvasScaledGroup()
figure4.add(axes2)

figure5 = CanvasScaledGroup((0.1, 0.1, 0.8, 0.8))
figure5.add(axes1)
figure5.add(axes2)

# John Hunter's example from the initial 'mpl1.py'
# first axes
ax_line1 = Group(affine_from_translation_scale(0.1, 0.1, 0.4, 0.4))
ax_line1.add(make_rectangle([0, 0, 1, 1], fillcolor=WHITE))
ax_line1.add(view1)
# second axes
r = npy.arange(0.0, 1.0, 0.01)
theta = r*4*npy.pi
line2_color = tuple([c/255. for c in (0xee, 0x8d, 0x18, 0xFF)])
line2 = make_line(r, theta, model=polar_transform, linewidth=2,
    fillcolor=None, strokecolor=line2_color)
view2_limits = ((-1.1, 1.1), (-1.1, 1.1))
view2 = ScaledView(view2_limits)
view2.add(line2)
ax_line2 = Group(affine_from_translation_scale(0.55, 0.55, 0.4, 0.4))
ax_line2_color = tuple([c/255. for c in (0xd5, 0xde, 0x9c, 0xFF)])
ax_line2.add(make_rectangle([0, 0, 1, 1], fillcolor=ax_line2_color))
ax_line2.add(view2)
# the figure
figure6 = CanvasScaledGroup()
figure6.add(ax_line1)
figure6.add(ax_line2)


##############################################################################

W, H, DPI = 600, 400, 72

# device scale test
if 0:
    canvas = CanvasAgg(W, H, DPI*2)
else:
    canvas = CanvasAgg(W, H, DPI)
renderer = Renderer(canvas)

# device transform test
if 0:
    renderer.add(
        make_rectangle([25, 25, 100, 100], strokecolor=None))            
    renderer.add(
        make_rectangle([75, 75, 50, 50], fillcolor=RED, strokecolor=None))
    renderer.render()

# path transform test
    if 1:
        renderer.add(
            make_rectangle([0, 0, 100, 100], 
                fillcolor=BLUE, strokecolor=None))
        xform_rect = make_rectangle([0, 0, 50, 50], fillcolor=GREEN,
            strokecolor=None)
        xform_rect.transform = affine_from_translation(25, 25)
        renderer.add(xform_rect)
        renderer.render()

        # Render.clear() test
        if 1:
            renderer.clear()
            renderer.add(
                make_rectangle([50, 50, 100, 100], strokecolor=None))            
            renderer.add(
                make_rectangle([100, 100, 50, 50], fillcolor=RED, 
                    strokecolor=None))
            renderer.render()

        # Canvas.clear() test
        if 0:
            canvas.clear()

# CanvasScaledGroup test
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure1) 
    renderer.render()

# CanvasScaledGroup/ScaledView test
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure2)
    renderer.render()

# CanvasScaledGroup/Group test
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure3)
    renderer.render()

# CanvasScaledGroup/Group/ScaledView test
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure4)
    renderer.render()

# CanvasScaledGroup with multiple Groups test
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure5)
    renderer.render()

# Canvas.resize() test
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure5)
    renderer.render()
    canvas.resize(W, H, DPI*1.5)
    canvas.clear()
    renderer.render()

# John Hunter's example from the initial 'mpl1.py'
if 0:
    canvas.clear()
    renderer.clear()
    renderer.add(figure6)
    renderer.render()

# rough benchmark
if 1:
    import time
    N = 100
    FIG = figure6

    # pre-create any CanvasPrimitives in the figure
    renderer.add(FIG)

    start = time.time()
    for i in xrange(N):
        canvas.clear()
        renderer.clear()
        renderer.add(FIG)
        renderer.render()
    elapsed = time.time() - start
    print 'Render: %0.3f elapsed, %0.4f avg, %0.2f FPS' % (elapsed,
        elapsed/N, N/elapsed)

    start = time.time()
    canvas.clear()
    renderer.clear()
    renderer.add(FIG)
    for i in xrange(N):
        canvas.clear()
        renderer.render()
    elapsed = time.time() - start
    print 'Redraw: %0.3f elapsed, %0.4f avg, %0.2f FPS' % (elapsed,
        elapsed/N, N/elapsed)

#canvas.show()
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Reply via email to