Revision: 4521
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=4521&view=rev
Author: mdboom
Date: 2007-11-30 07:06:56 -0800 (Fri, 30 Nov 2007)
Log Message:
-----------
Get Gtk backend working.
Modified Paths:
--------------
branches/transforms/lib/matplotlib/axis.py
branches/transforms/lib/matplotlib/backends/backend_gdk.py
branches/transforms/lib/matplotlib/path.py
branches/transforms/src/_path.cpp
Modified: branches/transforms/lib/matplotlib/axis.py
===================================================================
--- branches/transforms/lib/matplotlib/axis.py 2007-11-30 14:43:11 UTC (rev
4520)
+++ branches/transforms/lib/matplotlib/axis.py 2007-11-30 15:06:56 UTC (rev
4521)
@@ -87,7 +87,7 @@
self._size = size
self._padPixels = self.figure.dpi * self._pad * (1/72.0)
-
+
self.tick1line = self._get_tick1line()
self.tick2line = self._get_tick2line()
self.gridline = self._get_gridline()
@@ -97,7 +97,7 @@
self.label2 = self._get_text2()
self.update_position(loc)
-
+
self.gridOn = gridOn
self.tick1On = tick1On
self.tick2On = tick2On
@@ -114,7 +114,7 @@
#self.tick2line.set_clip_path(clippath, transform)
self.gridline.set_clip_path(clippath, transform)
set_clip_path.__doc__ = Artist.set_clip_path.__doc__
-
+
def contains(self, mouseevent):
"""Test whether the mouse event occured in the Tick marks.
@@ -189,7 +189,7 @@
"""
self.label1.set_text(s)
set_label = set_label1
-
+
def set_label2(self, s):
"""
Set the text of ticklabel2
@@ -209,7 +209,7 @@
def set_view_interval(self, vmin, vmax, ignore=False):
raise NotImplementedError('Derived must override')
-
+
class XTick(Tick):
"""
Contains all the Artists needed to make an x tick - the tick line,
@@ -223,7 +223,7 @@
# x in data coords, y in axes coords
#t = Text(
trans, vert, horiz =
self.axes.get_xaxis_text1_transform(self._padPixels)
-
+
t = TextWithDash(
x=0, y=0,
fontproperties=FontProperties(size=rcParams['xtick.labelsize']),
@@ -320,10 +320,10 @@
else:
Vmin, Vmax = self.get_view_interval()
self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax)
-
+
def get_minpos(self):
return self.axes.dataLim.minposx
-
+
def get_data_interval(self):
'return the Interval instance for this axis data limits'
return self.axes.dataLim.intervalx
@@ -428,7 +428,7 @@
self._loc = loc
-
+
def get_view_interval(self):
'return the Interval instance for this axis view limits'
return self.axes.viewLim.intervaly
@@ -439,10 +439,10 @@
else:
Vmin, Vmax = self.get_view_interval()
self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax)
-
+
def get_minpos(self):
return self.axes.dataLim.minposy
-
+
def get_data_interval(self):
'return the Interval instance for this axis data limits'
return self.axes.dataLim.intervaly
@@ -465,7 +465,7 @@
"""
LABELPAD = 5
OFFSETTEXTPAD = 3
-
+
def __str__(self):
return str(self.__class__).split('.')[-1] \
+ "(%d,%d)"%self.axes.transAxes.xy_tup((0,0))
@@ -493,23 +493,23 @@
self.majorTicks = []
self.minorTicks = []
self.pickradius = pickradius
-
+
self.cla()
self.set_scale('linear')
-
+
def get_transform(self):
return self._scale.get_transform()
def get_scale(self):
return self._scale.name
-
+
def set_scale(self, value, **kwargs):
self._scale = scale_factory(value, self, **kwargs)
self._scale.set_default_locators_and_formatters(self)
def limit_range_for_scale(self, vmin, vmax):
return self._scale.limit_range_for_scale(vmin, vmax, self.get_minpos())
-
+
def get_children(self):
children = [self.label]
majorticks = self.get_major_ticks()
@@ -547,7 +547,7 @@
self.minorTicks.extend([self._get_tick(major=False)])
self._lastNumMajorTicks = 1
self._lastNumMinorTicks = 1
-
+
self.converter = None
self.units = None
self.set_units(None)
@@ -555,17 +555,17 @@
def set_clip_path(self, clippath, transform=None):
Artist.set_clip_path(self, clippath, transform)
majorticks = self.get_major_ticks()
- minorticks = self.get_minor_ticks()
+ minorticks = self.get_minor_ticks()
for child in self.majorTicks + self.minorTicks:
child.set_clip_path(clippath, transform)
-
+
def get_view_interval(self):
'return the Interval instance for this axis view limits'
raise NotImplementedError('Derived must override')
def set_view_interval(self, vmin, vmax, ignore=False):
raise NotImplementedError('Derived must override')
-
+
def get_data_interval(self):
'return the Interval instance for this axis data limits'
raise NotImplementedError('Derived must override')
@@ -573,7 +573,7 @@
def set_data_interval(self):
'Set the axis data limits'
raise NotImplementedError('Derived must override')
-
+
def _set_artist_props(self, a):
if a is None: return
a.set_figure(self.figure)
@@ -774,7 +774,7 @@
for i in range(numticks - len(self.majorTicks)):
tick = self._get_tick(major=True)
self.majorTicks.append(tick)
-
+
if self._lastNumMajorTicks < numticks:
protoTick = self.majorTicks[0]
for i in range(self._lastNumMajorTicks, len(self.majorTicks)):
@@ -798,7 +798,7 @@
for i in range(numticks - len(self.minorTicks)):
tick = self._get_tick(major=False)
self.minorTicks.append(tick)
-
+
if self._lastNumMinorTicks < numticks:
protoTick = self.minorTicks[0]
for i in range(self._lastNumMinorTicks, len(self.minorTicks)):
@@ -1039,7 +1039,7 @@
class XAxis(Axis):
__name__ = 'xaxis'
axis_name = 'x'
-
+
def contains(self,mouseevent):
"""Test whether the mouse event occured in the x axis.
"""
@@ -1120,7 +1120,7 @@
bbox = Bbox.union(bboxes)
bottom = bbox.y0
self.label.set_position( (x, bottom -
self.LABELPAD*self.figure.dpi / 72.0))
-
+
else:
if not len(bboxes2):
top = self.axes.bbox.ymax
@@ -1141,7 +1141,7 @@
bbox = Bbox.union(bboxes)
bottom = bbox.y0
self.offsetText.set_position((x,
bottom-self.OFFSETTEXTPAD*self.figure.dpi/72.0))
-
+
def set_ticks_position(self, position):
"""
Set the ticks position (top, bottom, both, default or none)
@@ -1224,10 +1224,10 @@
else:
Vmin, Vmax = self.get_view_interval()
self.axes.viewLim.intervalx = min(vmin, Vmin), max(vmax, Vmax)
-
+
def get_minpos(self):
return self.axes.dataLim.minposx
-
+
def get_data_interval(self):
'return the Interval instance for this axis data limits'
return self.axes.dataLim.intervalx
@@ -1244,7 +1244,7 @@
class YAxis(Axis):
__name__ = 'yaxis'
axis_name = 'y'
-
+
def contains(self,mouseevent):
"""Test whether the mouse event occurred in the y axis.
@@ -1331,7 +1331,7 @@
left = bbox.x0
self.label.set_position( (left-self.LABELPAD*self.figure.dpi/72.0,
y))
-
+
else:
if not len(bboxes2):
right = self.axes.bbox.xmax
@@ -1349,7 +1349,7 @@
x,y = self.offsetText.get_position()
top = self.axes.bbox.ymax
self.offsetText.set_position((x,
top+self.OFFSETTEXTPAD*self.figure.dpi/72.0))
-
+
def set_offset_position(self, position):
assert position == 'left' or position == 'right'
@@ -1445,10 +1445,10 @@
else:
Vmin, Vmax = self.get_view_interval()
self.axes.viewLim.intervaly = min(vmin, Vmin), max(vmax, Vmax)
-
+
def get_minpos(self):
return self.axes.dataLim.minposy
-
+
def get_data_interval(self):
'return the Interval instance for this axis data limits'
return self.axes.dataLim.intervaly
Modified: branches/transforms/lib/matplotlib/backends/backend_gdk.py
===================================================================
--- branches/transforms/lib/matplotlib/backends/backend_gdk.py 2007-11-30
14:43:11 UTC (rev 4520)
+++ branches/transforms/lib/matplotlib/backends/backend_gdk.py 2007-11-30
15:06:56 UTC (rev 4521)
@@ -25,7 +25,7 @@
from matplotlib.cbook import is_string_like, enumerate
from matplotlib.figure import Figure
from matplotlib.mathtext import MathTextParser
-
+from matplotlib.transforms import Affine2D
from matplotlib.backends._backend_gdk import pixbuf_get_pixels_array
@@ -81,23 +81,25 @@
"""
self.width, self.height = width, height
- def draw_arc(self, gc, rgbFace, x, y, width, height, angle1, angle2,
rotation):
- x, y = int(x-0.5*width), self.height-int(y+0.5*height)
- w, h = int(width)+1, int(height)+1
- a1, a2 = int(angle1*64), int(angle2*64)
+ def draw_path(self, gc, path, transform, rgbFace=None):
+ transform = transform + Affine2D(). \
+ scale(1.0, -1.0).translate(0, self.height)
+ polygons = path.to_polygons(transform)
+ for polygon in polygons:
+ # draw_polygon won't take an arbitrary sequence -- it must be a
list
+ # of tuples
+ polygon = [(int(round(x)), int(round(y))) for x, y in polygon]
+ if rgbFace is not None:
+ saveColor = gc.gdkGC.foreground
+ gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace)
+ self.gdkDrawable.draw_polygon(gc.gdkGC, True, polygon)
+ gc.gdkGC.foreground = saveColor
+ if gc.gdkGC.line_width > 0:
+ self.gdkDrawable.draw_lines(gc.gdkGC, polygon)
- if rgbFace:
- saveColor = gc.gdkGC.foreground
- gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace)
- self.gdkDrawable.draw_arc(gc.gdkGC, True, x, y, w, h, a1, a2)
- gc.gdkGC.foreground = saveColor
- if gc.gdkGC.line_width > 0:
- self.gdkDrawable.draw_arc(gc.gdkGC, False, x, y, w, h, a1, a2)
-
-
- def draw_image(self, x, y, im, bbox):
+ def draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None):
if bbox != None:
- l,b,w,h = bbox.get_bounds()
+ l,b,w,h = bbox.bounds
#rectangle = (int(l), self.height-int(b+h),
# int(w), int(h))
# set clip rect?
@@ -135,48 +137,6 @@
im.flipud_out()
- def draw_line(self, gc, x1, y1, x2, y2):
- if gc.gdkGC.line_width > 0:
- self.gdkDrawable.draw_line(gc.gdkGC, int(x1), self.height-int(y1),
- int(x2), self.height-int(y2))
-
-
- def draw_lines(self, gc, x, y, transform=None):
- if gc.gdkGC.line_width > 0:
- x = x.astype(npy.int16)
- y = self.height - y.astype(npy.int16)
- self.gdkDrawable.draw_lines(gc.gdkGC, zip(x,y))
-
-
- def draw_point(self, gc, x, y):
- self.gdkDrawable.draw_point(gc.gdkGC, int(x), self.height-int(y))
-
-
- def draw_polygon(self, gc, rgbFace, points):
- points = [(int(x), self.height-int(y)) for x,y in points]
- if rgbFace:
- saveColor = gc.gdkGC.foreground
- gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace)
- self.gdkDrawable.draw_polygon(gc.gdkGC, True, points)
- gc.gdkGC.foreground = saveColor
- if gc.gdkGC.line_width > 0:
- self.gdkDrawable.draw_polygon(gc.gdkGC, False, points)
-
-
- def draw_rectangle(self, gc, rgbFace, x, y, width, height):
- x, y = int(x), self.height-int(y+height)
- #x, y = int(x), self.height-int(math.ceil(y+height))
- w, h = int(math.ceil(width)), int(math.ceil(height))
-
- if rgbFace:
- saveColor = gc.gdkGC.foreground
- gc.gdkGC.foreground = gc.rgb_to_gdk_color(rgbFace)
- self.gdkDrawable.draw_rectangle(gc.gdkGC, True, x, y, w, h)
- gc.gdkGC.foreground = saveColor
- if gc.gdkGC.line_width > 0:
- self.gdkDrawable.draw_rectangle(gc.gdkGC, False, x, y, w, h)
-
-
def draw_text(self, gc, x, y, s, prop, angle, ismath):
x, y = int(x), int(y)
@@ -200,7 +160,7 @@
def _draw_mathtext(self, gc, x, y, s, prop, angle):
ox, oy, width, height, descent, font_image, used_characters = \
- self.mathtext_parser.parse(s, self.dpi.get(), prop)
+ self.mathtext_parser.parse(s, self.dpi, prop)
if angle==90:
width, height = height, width
@@ -213,7 +173,7 @@
# a numpixels by num fonts array
Xall = npy.zeros((N,1), npy.uint8)
-
+
image_str = font_image.as_str()
Xall[:,0] = npy.fromstring(image_str, npy.uint8)
@@ -310,12 +270,12 @@
# two (not one) layouts are created for every text item s (then they
# are cached) - why?
- key = self.dpi.get(), s, hash(prop)
+ key = self.dpi, s, hash(prop)
value = self.layoutd.get(key)
if value != None:
return value
- size = prop.get_size_in_points() * self.dpi.get() / 96.0
+ size = prop.get_size_in_points() * self.dpi / 96.0
size = round(size)
font_str = '%s, %s %i' % (prop.get_name(), prop.get_style(), size,)
@@ -341,7 +301,7 @@
def get_text_width_height_descent(self, s, prop, ismath):
if ismath:
ox, oy, width, height, descent, font_image, used_characters = \
- self.mathtext_parser.parse(s, self.dpi.get(), prop)
+ self.mathtext_parser.parse(s, self.dpi, prop)
return width, height, descent
layout, inkRect, logicalRect = self._get_pango_layout(s, prop)
@@ -386,9 +346,9 @@
return an allocated gtk.gdk.Color
"""
try:
- return self._cached[rgb]
+ return self._cached[tuple(rgb)]
except KeyError:
- color = self._cached[rgb] = \
+ color = self._cached[tuple(rgb)] = \
self._cmap.alloc_color(
int(rgb[0]*65535),int(rgb[1]*65535),int(rgb[2]*65535))
return color
@@ -404,14 +364,15 @@
def set_clip_rectangle(self, rectangle):
GraphicsContextBase.set_clip_rectangle(self, rectangle)
- l,b,w,h = rectangle
+ if rectangle is None:
+ return
+ l,b,w,h = rectangle.bounds
rectangle = (int(l), self.renderer.height-int(b+h)+1,
int(w), int(h))
#rectangle = (int(l), self.renderer.height-int(b+h),
# int(w+1), int(h+2))
self.gdkGC.set_clip_rectangle(rectangle)
-
def set_dashes(self, dash_offset, dash_list):
GraphicsContextBase.set_dashes(self, dash_offset, dash_list)
@@ -486,7 +447,7 @@
def print_png(self, filename, *args, **kwargs):
return self._print_image(filename, 'png')
-
+
def _print_image(self, filename, format, *args, **kwargs):
width, height = self.get_width_height()
pixmap = gtk.gdk.Pixmap (None, width, height, depth=24)
@@ -500,4 +461,6 @@
0, 0, 0, 0, width, height)
pixbuf.save(filename, format)
-
+
+ def get_default_filetype(self):
+ return 'png'
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py 2007-11-30 14:43:11 UTC (rev
4520)
+++ branches/transforms/lib/matplotlib/path.py 2007-11-30 15:06:56 UTC (rev
4521)
@@ -12,7 +12,7 @@
from matplotlib._path import point_in_path, get_path_extents, \
point_in_path_collection, get_path_collection_extents, \
- path_in_path, path_intersects_path
+ path_in_path, path_intersects_path, convert_path_to_polygons
from matplotlib.cbook import simple_linear_interpolation
KAPPA = 4.0 * (npy.sqrt(2) - 1) / 3.0
@@ -210,19 +210,17 @@
If transform is not None, the path will be transformed before
performing the test.
"""
- if transform is None:
- from transforms import IdentityTransform
- transform = IdentityTransform()
- return point_in_path(point[0], point[1], self, transform.frozen())
+ if transform is not None:
+ transform = transform.frozen()
+ return point_in_path(point[0], point[1], self, transform)
def contains_path(self, path, transform=None):
"""
Returns True if this path completely contains the given path.
"""
- if transform is None:
- from transforms import IdentityTransform
- transform = IdentityTransform()
- return path_in_path(self, IdentityTransform(), path, transform)
+ if transform is not None:
+ transform = transform.frozen()
+ return path_in_path(self, None, path, transform)
def get_extents(self, transform=None):
"""
@@ -232,9 +230,9 @@
algorithm will take into account the curves and deal with
control points appropriately.
"""
- from transforms import Affine2D, Bbox
- if transform is None:
- transform = Affine2D()
+ from transforms import Bbox
+ if transform is not None:
+ transform = transform.frozen()
return Bbox(get_path_extents(self, transform))
def intersects_path(self, other):
@@ -267,6 +265,23 @@
new_codes = None
return Path(vertices, new_codes)
+ def to_polygons(self, transform=None):
+ """
+ Convert this path to a list of polygons. Each polygon is an
+ Nx2 array of vertices. In other words, each polygon has no
+ "move to" instructions or curves.
+ """
+ if transform is not None:
+ transform = transform.frozen()
+ # Deal with the common and simple case
+ if self.codes is None:
+ if len(self.vertices):
+ return [transform.transform(self.vertices)]
+ return []
+ # Deal with the case where there are curves and/or multiple
+ # subpaths (using extension code)
+ return convert_path_to_polygons(self, transform)
+
_unit_rectangle = None
[EMAIL PROTECTED]
def unit_rectangle(cls):
Modified: branches/transforms/src/_path.cpp
===================================================================
--- branches/transforms/src/_path.cpp 2007-11-30 14:43:11 UTC (rev 4520)
+++ branches/transforms/src/_path.cpp 2007-11-30 15:06:56 UTC (rev 4521)
@@ -48,6 +48,8 @@
"count_bboxes_overlapping_bbox(bbox, bboxes)");
add_varargs_method("path_intersects_path",
&_path_module::path_intersects_path,
"path_intersects_path(p1, p2)");
+ add_varargs_method("convert_path_to_polygons",
&_path_module::convert_path_to_polygons,
+ "convert_path_to_polygons(path, trans)");
initialize("Helper functions for paths");
}
@@ -66,6 +68,7 @@
Py::Object affine_transform(const Py::Tuple& args);
Py::Object count_bboxes_overlapping_bbox(const Py::Tuple& args);
Py::Object path_intersects_path(const Py::Tuple& args);
+ Py::Object convert_path_to_polygons(const Py::Tuple& args);
};
//
@@ -137,7 +140,7 @@
code = path.vertex(&x, &y);
// The following cases denote the beginning on a new subpath
- if (code == agg::path_cmd_stop ||
+ if (code == agg::path_cmd_stop ||
(code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly)
{
x = sx;
@@ -234,7 +237,7 @@
double x = Py::Float(args[0]);
double y = Py::Float(args[1]);
PathIterator path(args[2]);
- agg::trans_affine trans = py_to_agg_transformation_matrix(args[3]);
+ agg::trans_affine trans = py_to_agg_transformation_matrix(args[3], false);
if (::point_in_path(x, y, path, trans))
return Py::Int(1);
@@ -623,9 +626,9 @@
args.verify_length(4);
PathIterator a(args[0]);
- agg::trans_affine atrans = py_to_agg_transformation_matrix(args[1]);
+ agg::trans_affine atrans = py_to_agg_transformation_matrix(args[1], false);
PathIterator b(args[2]);
- agg::trans_affine btrans = py_to_agg_transformation_matrix(args[3]);
+ agg::trans_affine btrans = py_to_agg_transformation_matrix(args[3], false);
return Py::Int(::path_in_path(a, atrans, b, btrans));
}
@@ -1091,6 +1094,68 @@
return Py::Int(1);
}
+void _add_polygon(Py::List& polygons, const std::vector<double>& polygon) {
+ if (polygon.size() == 0)
+ return;
+ npy_intp polygon_dims[] = { polygon.size() / 2, 2, 0 };
+ double* polygon_data = new double[polygon.size()];
+ memcpy(polygon_data, &polygon[0], polygon.size() * sizeof(double));
+ PyArrayObject* polygon_array = NULL;
+ polygon_array = (PyArrayObject*)PyArray_SimpleNewFromData
+ (2, polygon_dims, PyArray_DOUBLE, polygon_data);
+ if (!polygon_array)
+ {
+ delete[] polygon_data;
+ throw Py::RuntimeError("Error creating polygon array");
+ }
+ polygons.append(Py::Object((PyObject*)polygon_array));
+}
+
+Py::Object _path_module::convert_path_to_polygons(const Py::Tuple& args)
+{
+ typedef agg::conv_transform<PathIterator> transformed_path_t;
+ typedef agg::conv_curve<transformed_path_t> curve_t;
+
+ typedef std::vector<double> vertices_t;
+
+ args.verify_length(2);
+
+ PathIterator path(args[0]);
+ agg::trans_affine trans = py_to_agg_transformation_matrix(args[1], false);
+
+ transformed_path_t tpath(path, trans);
+ curve_t curve(tpath);
+
+ Py::List polygons;
+ vertices_t polygon;
+ double x, y;
+ unsigned code;
+
+ while ((code = curve.vertex(&x, &y)) != agg::path_cmd_stop)
+ {
+ if ((code & agg::path_cmd_end_poly) == agg::path_cmd_end_poly) {
+ if (polygon.size() >= 2)
+ {
+ polygon.push_back(polygon[0]);
+ polygon.push_back(polygon[1]);
+ _add_polygon(polygons, polygon);
+ }
+ polygon.clear();
+ } else {
+ if (code == agg::path_cmd_move_to) {
+ _add_polygon(polygons, polygon);
+ polygon.clear();
+ }
+ polygon.push_back(x);
+ polygon.push_back(y);
+ }
+ }
+
+ _add_polygon(polygons, polygon);
+
+ return polygons;
+}
+
extern "C"
DL_EXPORT(void)
init_path(void)
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
SF.Net email is sponsored by: The Future of Linux Business White Paper
from Novell. From the desktop to the data center, Linux is going
mainstream. Let it simplify your IT future.
http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins