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