|
From: <md...@us...> - 2007-09-19 16:18:56
|
Revision: 3858
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=3858&view=rev
Author: mdboom
Date: 2007-09-19 09:18:51 -0700 (Wed, 19 Sep 2007)
Log Message:
-----------
Got steps_demo.py working
Modified Paths:
--------------
branches/transforms/lib/matplotlib/backend_bases.py
branches/transforms/lib/matplotlib/lines.py
branches/transforms/lib/matplotlib/path.py
branches/transforms/lib/matplotlib/transforms.py
branches/transforms/src/_backend_agg.cpp
branches/transforms/src/_backend_agg.h
Modified: branches/transforms/lib/matplotlib/backend_bases.py
===================================================================
--- branches/transforms/lib/matplotlib/backend_bases.py 2007-09-19 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/backend_bases.py 2007-09-19 16:18:51 UTC (rev 3858)
@@ -40,7 +40,7 @@
def _get_cached_native_path(self, path):
native_path = self._native_paths.get(path)
if native_path is None:
- # print "CACHE MISS", path
+ print "CACHE MISS", path
native_path = self.convert_to_native_path(path)
self._native_paths[path] = native_path
return native_path
Modified: branches/transforms/lib/matplotlib/lines.py
===================================================================
--- branches/transforms/lib/matplotlib/lines.py 2007-09-19 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/lines.py 2007-09-19 16:18:51 UTC (rev 3858)
@@ -25,53 +25,6 @@
(TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN,
CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = range(8)
-def unmasked_index_ranges(mask, compressed = True):
- '''
- Calculate the good data ranges in a masked 1-D npy.array, based on mask.
-
- Returns Nx2 npy.array with each row the start and stop indices
- for slices of the compressed npy.array corresponding to each of N
- uninterrupted runs of unmasked values.
- If optional argument compressed is False, it returns the
- start and stop indices into the original npy.array, not the
- compressed npy.array.
- Returns None if there are no unmasked values.
-
- Example:
-
- y = ma.array(npy.arange(5), mask = [0,0,1,0,0])
- #ii = unmasked_index_ranges(y.mask())
- ii = unmasked_index_ranges(ma.getmask(y))
- # returns [[0,2,] [2,4,]]
-
- y.compressed().filled()[ii[1,0]:ii[1,1]]
- # returns npy.array [3,4,]
- # (The 'filled()' method converts the masked npy.array to a numerix npy.array.)
-
- #i0, i1 = unmasked_index_ranges(y.mask(), compressed=False)
- i0, i1 = unmasked_index_ranges(ma.getmask(y), compressed=False)
- # returns [[0,3,] [2,5,]]
-
- y.filled()[ii[1,0]:ii[1,1]]
- # returns npy.array [3,4,]
-
- '''
- m = npy.concatenate(((1,), mask, (1,)))
- indices = npy.arange(len(mask) + 1)
- mdif = m[1:] - m[:-1]
- i0 = npy.compress(mdif == -1, indices)
- i1 = npy.compress(mdif == 1, indices)
- assert len(i0) == len(i1)
- if len(i1) == 0:
- return None
- if not compressed:
- return npy.concatenate((i0[:, npy.newaxis], i1[:, npy.newaxis]), axis=1)
- seglengths = i1 - i0
- breakpoints = npy.cumsum(seglengths)
- ic0 = npy.concatenate(((0,), breakpoints[:-1]))
- ic1 = breakpoints
- return npy.concatenate((ic0[:, npy.newaxis], ic1[:, npy.newaxis]), axis=1)
-
def segment_hits(cx,cy,x,y,radius):
"""Determine if any line segments are within radius of a point. Returns
the list of line segments that are within that radius.
@@ -117,7 +70,7 @@
'--' : '_draw_dashed',
'-.' : '_draw_dash_dot',
':' : '_draw_dotted',
- 'steps': '_draw_solid',
+ 'steps': '_draw_steps',
'None' : '_draw_nothing',
' ' : '_draw_nothing',
'' : '_draw_nothing',
@@ -394,6 +347,8 @@
self._yorig = y
self.recache()
+ _masked_array_to_path_code_mapping = npy.array(
+ [Path.LINETO, Path.IGNORE, Path.MOVETO], Path.code_type)
def recache(self):
#if self.axes is None: print 'recache no axes'
#else: print 'recache units', self.axes.xaxis.units, self.axes.yaxis.units
@@ -411,36 +366,28 @@
if len(x) != len(y):
raise RuntimeError('xdata and ydata must be the same length')
- # MGDTODO: Deal with segments
+ self._xy = npy.vstack((npy.asarray(x, npy.float_),
+ npy.asarray(y, npy.float_))).transpose()
+ self._x = self._xy[:, 0] # just a view
+ self._y = self._xy[:, 1] # just a view
+ self._logcache = None
+
mx = ma.getmask(x)
my = ma.getmask(y)
mask = ma.mask_or(mx, my)
+ codes = None
if mask is not ma.nomask:
- x = ma.masked_array(x, mask=mask).compressed()
- y = ma.masked_array(y, mask=mask).compressed()
- self._segments = unmasked_index_ranges(mask)
- else:
- self._segments = None
-
- self._xy = npy.vstack((npy.asarray(x, npy.float_),
- npy.asarray(y, npy.float_))).transpose()
- self._x = self._xy[:, 0]
- self._y = self._xy[:, 1]
- self._logcache = None
+ m = npy.concatenate(((1,), mask, (1,)))
+ mdif = m[1:] - m[:-1]
+ mdif = npy.maximum((mdif[:-1] * -2), mask)
+ codes = npy.take(
+ self._masked_array_to_path_code_mapping,
+ mdif)
+ self._path = Path(self._xy, codes, closed=False)
+ # MGDTODO: If _draw_steps is removed, remove the following line also
+ self._step_path = None
- if self._linestyle == 'steps':
- siz=len(xt)
- if siz<2: return
- xt, yt = self._x, self._y
- xt2=npy.ones((2*siz,), xt.dtype)
- xt2[0:-1:2], xt2[1:-1:2], xt2[-1] = xt, xt[1:], xt[-1]
- yt2=npy.ones((2*siz,), yt.dtype)
- yt2[0:-1:2], yt2[1::2] = yt, yt
- self._path = Path(npy.vstack((xt2, yt2)).transpose(), closed=False)
- else:
- self._path = Path(self._xy, closed=False)
-
def _is_sorted(self, x):
"return true if x is sorted"
if len(x)<2: return 1
@@ -507,14 +454,7 @@
funcname = self._lineStyles.get(self._linestyle, '_draw_nothing')
lineFunc = getattr(self, funcname)
-
- # MGDTODO: Deal with self._segments
- if self._segments is not None:
- for ii in self._segments:
- lineFunc(renderer, gc, xt[ii[0]:ii[1]], yt[ii[0]:ii[1]])
-
- else:
- lineFunc(renderer, gc, self._path)
+ lineFunc(renderer, gc, self._path)
# MGDTODO: Deal with markers
if self._marker is not None:
@@ -709,7 +649,29 @@
def _draw_nothing(self, renderer, gc, path):
pass
-
+
+ def _draw_steps(self, renderer, gc, path):
+ # We generate the step function path on-the-fly, and then cache it.
+ # The cache may be later invalidated when the data changes
+ # (in self.recache())
+
+ # MGDTODO: Untested -- using pylab.step doesn't actually trigger
+ # this code -- the path is "stepped" before even getting to this
+ # class. Perhaps this should be removed here, since it is not as
+ # powerful as what is in axes.step() anyway.
+ if self._step_path is None:
+ vertices = self._path.vertices
+ codes = self._path.codes
+ siz = len(vertices)
+ if siz<2: return
+ new_vertices = npy.zeros((2*siz, 2), vertices.dtype)
+ new_vertices[0:-1:2, 0], new_vertices[1:-1:2, 0], newvertices[-1, 0] = vertices[:, 0], vertices[1:, 0], vertices[-1, 0]
+ new_vertices[0:-1:2, 1], new_vertices[1::2, 1] = vertices[:, 1], vertices[:, 1]
+ self._step_path = Path(new_vertices, closed=False)
+ gc.set_linestyle('solid')
+ renderer.draw_path(gc, self._step_path, self.get_transform())
+
+
def _draw_solid(self, renderer, gc, path):
gc.set_linestyle('solid')
renderer.draw_path(gc, path, self.get_transform())
Modified: branches/transforms/lib/matplotlib/path.py
===================================================================
--- branches/transforms/lib/matplotlib/path.py 2007-09-19 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/path.py 2007-09-19 16:18:51 UTC (rev 3858)
@@ -1,10 +1,10 @@
import numpy as npy
-VALIDATE_PATHS = True
+DEBUG = True
class Path(object):
# Path codes
- STOP = 0
+ IGNORE = 0 # 1 vertex
MOVETO = 1 # 1 vertex
LINETO = 2 # 1 vertex
CURVE3 = 3 # 2 vertices
@@ -18,7 +18,7 @@
UBSPLINE = 8
####
- NUM_VERTICES = [0, 1, 1, 2, 3, 0]
+ NUM_VERTICES = [1, 1, 1, 2, 3, 0]
code_type = npy.uint8
@@ -43,7 +43,7 @@
assert self._codes.ndim == 1
- if VALIDATE_PATHS:
+ if DEBUG:
i = 0
NUM_VERTICES = self.NUM_VERTICES
for code in codes:
Modified: branches/transforms/lib/matplotlib/transforms.py
===================================================================
--- branches/transforms/lib/matplotlib/transforms.py 2007-09-19 13:28:11 UTC (rev 3857)
+++ branches/transforms/lib/matplotlib/transforms.py 2007-09-19 16:18:51 UTC (rev 3858)
@@ -32,18 +32,6 @@
for child in children:
getattr(self, child)._parents.add(self)
self._children = children
-
- # MGDTODO: decide whether we need this in-place updating and
- # remove if not
-# def replace_child(self, index, child):
-# children = self._children
-# getattr(self, children[index])._parents.remove(self)
-# setattr(self, children[index], child)
-# # We have to reset children in case two or more
-# # of the children are the same
-# for child in children:
-# getattr(self, child)._parents.add(self)
-# self.invalidate()
class BboxBase(TransformNode):
'''
@@ -327,53 +315,7 @@
if self._points is None:
self._points = self.transform(self.bbox.get_points())
return self._points
-
-# MGDTODO: This code probably works, but I don't think it's a good idea
-# (from a code clarity perspective)
-# class BlendedBbox(BboxBase):
-# def __init__(self, bbox_x, bbox_y):
-# assert isinstance(bbox_x, BboxBase)
-# assert isinstance(bbox_y, BboxBase)
-
-# BboxBase.__init__(self)
-# self._x = bbox_x
-# self._y = bbox_y
-# self.set_children(['_x', '_y'])
-# self._points = None
-
-# def __repr__(self):
-# return "TransformedBbox(%s, %s)" % (self.bbox, self.transform)
-# __str__ = __repr__
-# def _do_invalidation(self):
-# self._points = None
-
-# def get_points(self):
-# if self._points is None:
-# # MGDTODO: Optimize
-# if self._x == self._y:
-# self._points = self._x.get_points()
-# else:
-# x_points = self._x.get_points()
-# y_points = self._y.get_points()
-# self._points = npy.array(
-# [[x_points[0,0], y_points[0,1]],
-# [x_points[1,0], y_points[1,1]]],
-# npy.float_)
-# return self._points
-
-# def _set_intervalx(self, pair):
-# # MGDTODO: Optimize
-# bbox = Bbox([[pair[0], 0.0], [pair[1], 0.0]])
-# self.replace_child(0, bbox)
-# intervalx = property(BboxBase._get_intervalx, _set_intervalx)
-
-# def _set_intervaly(self, pair):
-# # MGDTODO: Optimize
-# bbox = Bbox([[0.0, pair[0]], [0.0, pair[1]]])
-# self.replace_child(1, bbox)
-# intervaly = property(BboxBase._get_intervaly, _set_intervaly)
-
class Transform(TransformNode):
def __init__(self):
TransformNode.__init__(self)
@@ -746,7 +688,6 @@
self._mtx = affine._mtx
return self._mtx
-# MGDTODO: There's probably a better place for this
def nonsingular(vmin, vmax, expander=0.001, tiny=1e-15, increasing=True):
'''
Ensure the endpoints of a range are not too close together.
Modified: branches/transforms/src/_backend_agg.cpp
===================================================================
--- branches/transforms/src/_backend_agg.cpp 2007-09-19 13:28:11 UTC (rev 3857)
+++ branches/transforms/src/_backend_agg.cpp 2007-09-19 16:18:51 UTC (rev 3858)
@@ -634,6 +634,9 @@
if (num_vertices) {
for (size_t j=0; j<num_vertices; ++j)
GET_NEXT_VERTEX(x, y);
+ if (code_i == IGNORE)
+ continue;
+
trans.transform(&x, &y);
if (face.first) {
@@ -860,6 +863,10 @@
for (size_t i = 0; i < N; ++i) {
switch (*(unsigned char*)(code_i)) {
+ case IGNORE:
+ GET_NEXT_VERTEX(x0, y0);
+ _VERBOSE("IGNORE");
+ break;
case MOVETO:
GET_NEXT_VERTEX(x0, y0);
move_to(x0, y0);
Modified: branches/transforms/src/_backend_agg.h
===================================================================
--- branches/transforms/src/_backend_agg.h 2007-09-19 13:28:11 UTC (rev 3857)
+++ branches/transforms/src/_backend_agg.h 2007-09-19 16:18:51 UTC (rev 3858)
@@ -40,14 +40,14 @@
#include "agg_vcgen_markers_term.h"
// These are copied directly from path.py, and must be kept in sync
-#define STOP 0
+#define IGNORE 0
#define MOVETO 1
#define LINETO 2
#define CURVE3 3
#define CURVE4 4
#define CLOSEPOLY 5
-const size_t NUM_VERTICES[] = { 0, 1, 1, 2, 3, 0 };
+const size_t NUM_VERTICES[] = { 1, 1, 1, 2, 3, 0 };
typedef agg::pixfmt_rgba32 pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|