Revision: 7102
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7102&view=rev
Author: leejjoon
Date: 2009-05-14 06:27:58 +0000 (Thu, 14 May 2009)
Log Message:
-----------
An optional offset and bbox support in restore_bbox
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
trunk/matplotlib/src/_backend_agg.cpp
trunk/matplotlib/src/_backend_agg.h
Added Paths:
-----------
trunk/matplotlib/examples/animation/animation_blit_gtk2.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2009-05-14 04:00:38 UTC (rev 7101)
+++ trunk/matplotlib/CHANGELOG 2009-05-14 06:27:58 UTC (rev 7102)
@@ -1,4 +1,7 @@
======================================================================
+2009-05-13 An optional offset and bbox support in restore_bbox.
+ Add animation_blit_gtk2.py. -JJL
+
2009-05-13 psfrag in backend_ps now uses baseline-alignment
when preview.sty is used ((default is
bottom-alignment). Also, a small api imporvement
Added: trunk/matplotlib/examples/animation/animation_blit_gtk2.py
===================================================================
--- trunk/matplotlib/examples/animation/animation_blit_gtk2.py
(rev 0)
+++ trunk/matplotlib/examples/animation/animation_blit_gtk2.py 2009-05-14
06:27:58 UTC (rev 7102)
@@ -0,0 +1,167 @@
+#!/usr/bin/env python
+
+"""
+This example utlizes restore_region with optional bbox and xy
+arguments. The plot is continuously shifted to the left. Instead of
+drawing everything again, the plot is saved (copy_from_bbox) and
+restored with offset by the amount of the shift. And only newly
+exposed area is drawn. This technique may reduce drawing time for some cases.
+"""
+
+import time
+
+import gtk, gobject
+
+import matplotlib
+matplotlib.use('GTKAgg')
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+class UpdateLine(object):
+ def get_bg_bbox(self):
+
+ return self.ax.bbox.padded(-3)
+
+ def __init__(self, canvas, ax):
+ self.cnt = 0
+ self.canvas = canvas
+ self.ax = ax
+
+ self.prev_time = time.time()
+ self.start_time = self.prev_time
+ self.prev_pixel_offset = 0.
+
+
+ self.x0 = 0
+ self.phases = np.random.random_sample((20,)) * np.pi * 2
+ self.line, = ax.plot([], [], "-", animated=True, lw=2)
+
+ self.point, = ax.plot([], [], "ro", animated=True, lw=2)
+
+ self.ax.set_ylim(-1.1, 1.1)
+
+ self.background1 = None
+
+ cmap = plt.cm.jet
+ from itertools import cycle
+ self.color_cycle = cycle(cmap(np.arange(cmap.N)))
+
+
+ def save_bg(self):
+ self.background1 =
self.canvas.copy_from_bbox(self.ax.get_figure().bbox)
+
+ self.background2 = self.canvas.copy_from_bbox(self.get_bg_bbox())
+
+
+ def get_dx_data(self, dx_pixel):
+ tp = self.ax.transData.inverted().transform_point
+ x0, y0 = tp((0, 0))
+ x1, y1 = tp((dx_pixel, 0))
+ return (x1-x0)
+
+
+ def restore_background_shifted(self, dx_pixel):
+ """
+ restore bacground shifted by dx in data coordinate. This only
+ works if the data coordinate system is linear.
+ """
+
+ # restore the clean slate background
+ self.canvas.restore_region(self.background1)
+
+ # restore subregion (x1+dx, y1, x2, y2) of the second bg
+ # in a offset position (x1-dx, y1)
+ x1, y1, x2, y2 = self.background2.get_extents()
+ self.canvas.restore_region(self.background2,
+ bbox=(x1+dx_pixel, y1, x2, y2),
+ xy=(x1-dx_pixel, y1))
+
+ return dx_pixel
+
+ def on_draw(self, *args):
+ self.save_bg()
+ return False
+
+ def update_line(self, *args):
+
+ if self.background1 is None:
+ return True
+
+ cur_time = time.time()
+ pixel_offset = int((cur_time - self.start_time)*100.)
+ dx_pixel = pixel_offset - self.prev_pixel_offset
+ self.prev_pixel_offset = pixel_offset
+ dx_data = self.get_dx_data(dx_pixel) #cur_time - self.prev_time)
+
+ x0 = self.x0
+ self.x0 += dx_data
+ self.prev_time = cur_time
+
+ self.ax.set_xlim(self.x0-2, self.x0+0.1)
+
+
+ # restore background which will plot lines from previous plots
+ self.restore_background_shifted(dx_pixel) #x0, self.x0)
+ # This restores lines between [x0-2, x0]
+
+
+
+ self.line.set_color(self.color_cycle.next())
+
+ # now plot line segment within [x0, x0+dx_data],
+ # Note that we're only plotting a line between [x0, x0+dx_data].
+ xx = np.array([x0, self.x0])
+ self.line.set_xdata(xx)
+
+ # the for loop below could be improved by using collection.
+ [(self.line.set_ydata(np.sin(xx+p)),
+ self.ax.draw_artist(self.line)) \
+ for p in self.phases]
+
+ self.background2 = canvas.copy_from_bbox(self.get_bg_bbox())
+
+ self.point.set_xdata([self.x0])
+
+ [(self.point.set_ydata(np.sin([self.x0+p])),
+ self.ax.draw_artist(self.point)) \
+ for p in self.phases]
+
+
+ self.ax.draw_artist(self.ax.xaxis)
+ self.ax.draw_artist(self.ax.yaxis)
+
+ self.canvas.blit(self.ax.get_figure().bbox)
+
+
+ dt = (time.time()-tstart)
+ if dt>15:
+ # print the timing info and quit
+ print 'FPS:' , self.cnt/dt
+ gtk.main_quit()
+ raise SystemExit
+
+ self.cnt += 1
+ return True
+
+
+plt.rcParams["text.usetex"] = False
+fig = plt.figure()
+
+ax = fig.add_subplot(111)
+ax.xaxis.set_animated(True)
+ax.yaxis.set_animated(True)
+canvas = fig.canvas
+
+fig.subplots_adjust(left=0.2, bottom=0.2)
+canvas.draw()
+
+# for profiling
+tstart = time.time()
+
+ul = UpdateLine(canvas, ax)
+gobject.idle_add(ul.update_line)
+
+canvas.mpl_connect('draw_event', ul.on_draw)
+
+plt.show()
Modified: trunk/matplotlib/lib/matplotlib/backends/backend_agg.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2009-05-14
04:00:38 UTC (rev 7101)
+++ trunk/matplotlib/lib/matplotlib/backends/backend_agg.py 2009-05-14
06:27:58 UTC (rev 7102)
@@ -33,7 +33,7 @@
from matplotlib.ft2font import FT2Font, LOAD_FORCE_AUTOHINT
from matplotlib.mathtext import MathTextParser
from matplotlib.path import Path
-from matplotlib.transforms import Bbox
+from matplotlib.transforms import Bbox, BboxBase
from _backend_agg import RendererAgg as _RendererAgg
from matplotlib import _png
@@ -65,7 +65,6 @@
self.draw_quad_mesh = self._renderer.draw_quad_mesh
self.draw_image = self._renderer.draw_image
self.copy_from_bbox = self._renderer.copy_from_bbox
- self.restore_region = self._renderer.restore_region
self.tostring_rgba_minimized = self._renderer.tostring_rgba_minimized
self.mathtext_parser = MathTextParser('Agg')
@@ -239,7 +238,39 @@
# with the Agg backend
return True
+ def restore_region(self, region, bbox=None, xy=None):
+ """
+ restore the saved region. if bbox (instance of BboxBase, or
+ its extents) is given, only the region specified by the bbox
+ will be restored. *xy* (a tuple of two floasts) optionally
+ specify the new position (of the LLC of the originally region,
+ not the LLC of the bbox) that the region will be restored.
+ >>> region = renderer.copy_from_bbox()
+ >>> x1, y1, x2, y2 = region.get_extents()
+ >>> renderer.restore_region(region, bbox=(x1+dx, y1, x2, y2),
+ xy=(x1-dx, y1))
+
+ """
+ if bbox is not None or xy is not None:
+ if bbox is None:
+ x1, y1, x2, y2 = region.get_extents()
+ elif isinstance(bbox, BboxBase):
+ x1, y1, x2, y2 = bbox.extents
+ else:
+ x1, y1, x2, y2 = bbox
+
+ if xy is None:
+ ox, oy = x1, y1
+ else:
+ ox, oy = xy
+
+ self._renderer.restore_region2(region, x1, y1, x2, y2, ox, oy)
+
+ else:
+ self._renderer.restore_region(region)
+
+
def new_figure_manager(num, *args, **kwargs):
"""
Create a new figure manager instance
@@ -269,9 +300,9 @@
renderer = self.get_renderer()
return renderer.copy_from_bbox(bbox)
- def restore_region(self, region):
+ def restore_region(self, region, bbox=None, xy=None):
renderer = self.get_renderer()
- return renderer.restore_region(region)
+ return renderer.restore_region(region, bbox, xy)
def draw(self):
"""
@@ -334,3 +365,4 @@
renderer.width, renderer.height,
filename_or_obj, self.figure.dpi)
renderer.dpi = original_dpi
+
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp 2009-05-14 04:00:38 UTC (rev
7101)
+++ trunk/matplotlib/src/_backend_agg.cpp 2009-05-14 06:27:58 UTC (rev
7102)
@@ -104,6 +104,18 @@
return Py::Object();
}
+Py::Object BufferRegion::get_extents(const Py::Tuple &args) {
+ args.verify_length(0);
+
+ Py::Tuple extents(4);
+ extents[0] = Py::Int(rect.x1);
+ extents[1] = Py::Int(rect.y1);
+ extents[2] = Py::Int(rect.x2);
+ extents[3] = Py::Int(rect.y2);
+
+ return extents;
+}
+
Py::Object BufferRegion::to_string_argb(const Py::Tuple &args) {
// owned=true to prevent memory leak
Py_ssize_t length;
@@ -426,6 +438,49 @@
return Py::Object();
}
+// Restore the part of the saved region with offsets
+Py::Object
+RendererAgg::restore_region2(const Py::Tuple& args) {
+ //copy BufferRegion to buffer
+ args.verify_length(7);
+
+
+
+ int x(0),y(0), xx1(0),yy1(0), xx2(0), yy2(0);
+ try {
+ xx1 = Py::Int( args[1] );
+ yy1 = Py::Int( args[2] );
+ xx2 = Py::Int( args[3] );
+ yy2 = Py::Int( args[4] );
+ x = Py::Int( args[5] );
+ y = Py::Int( args[6] );
+ }
+ catch (Py::TypeError) {
+ throw Py::TypeError("Invalid input arguments to draw_text_image");
+ }
+
+
+ BufferRegion* region = static_cast<BufferRegion*>(args[0].ptr());
+
+ if (region->data==NULL)
+ throw Py::ValueError("Cannot restore_region from NULL data");
+
+ agg::rect_i rect(xx1-region->rect.x1, (yy1-region->rect.y1),
+ xx2-region->rect.x1, (yy2-region->rect.y1));
+
+
+ agg::rendering_buffer rbuf;
+ rbuf.attach(region->data,
+ region->width,
+ region->height,
+ region->stride);
+
+ rendererBase.copy_from(rbuf, &rect, x, y);
+
+ return Py::Object();
+}
+
+
bool RendererAgg::render_clippath(const Py::Object& clippath, const
agg::trans_affine& clippath_trans) {
typedef agg::conv_transform<PathIterator> transformed_path_t;
typedef agg::conv_curve<transformed_path_t> curve_t;
@@ -1717,6 +1772,9 @@
add_varargs_method("set_y", &BufferRegion::set_y,
"set_y(y)");
+ add_varargs_method("get_extents", &BufferRegion::get_extents,
+ "get_extents()");
+
add_varargs_method("to_string", &BufferRegion::to_string,
"to_string()");
add_varargs_method("to_string_argb", &BufferRegion::to_string_argb,
@@ -1759,6 +1817,8 @@
"copy_from_bbox(bbox)");
add_varargs_method("restore_region", &RendererAgg::restore_region,
"restore_region(region)");
+ add_varargs_method("restore_region2", &RendererAgg::restore_region2,
+ "restore_region(region, x1, y1, x2, y2, x3, y3)");
}
extern "C"
Modified: trunk/matplotlib/src/_backend_agg.h
===================================================================
--- trunk/matplotlib/src/_backend_agg.h 2009-05-14 04:00:38 UTC (rev 7101)
+++ trunk/matplotlib/src/_backend_agg.h 2009-05-14 06:27:58 UTC (rev 7102)
@@ -87,6 +87,8 @@
Py::Object set_x(const Py::Tuple &args);
Py::Object set_y(const Py::Tuple &args);
+ Py::Object get_extents(const Py::Tuple &args);
+
Py::Object to_string(const Py::Tuple &args);
Py::Object to_string_argb(const Py::Tuple &args);
static void init_type(void);
@@ -174,6 +176,7 @@
Py::Object copy_from_bbox(const Py::Tuple & args);
Py::Object restore_region(const Py::Tuple & args);
+ Py::Object restore_region2(const Py::Tuple & args);
virtual ~RendererAgg();
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
The NEW KODAK i700 Series Scanners deliver under ANY circumstances! Your
production scanning environment may not be a perfect world - but thanks to
Kodak, there's a perfect scanner to get the job done! With the NEW KODAK i700
Series Scanner you'll get full speed at 300 dpi even with all image
processing features enabled. http://p.sf.net/sfu/kodak-com
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins