Revision: 6423
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6423&view=rev
Author: jdh2358
Date: 2008-11-20 18:58:54 +0000 (Thu, 20 Nov 2008)
Log Message:
-----------
added some helper functions for poly collections and masked regions
Modified Paths:
--------------
trunk/matplotlib/CHANGELOG
trunk/matplotlib/lib/matplotlib/collections.py
trunk/matplotlib/lib/matplotlib/mlab.py
trunk/matplotlib/src/_backend_agg.cpp
Added Paths:
-----------
trunk/matplotlib/examples/api/filled_masked_regions.py
Modified: trunk/matplotlib/CHANGELOG
===================================================================
--- trunk/matplotlib/CHANGELOG 2008-11-20 15:46:46 UTC (rev 6422)
+++ trunk/matplotlib/CHANGELOG 2008-11-20 18:58:54 UTC (rev 6423)
@@ -1,3 +1,11 @@
+2008-11-20 Added some static helper methods
+ BrokenHBarCollection.span_masked and
+ PolyCollection.fill_between_masked for visualizing
+ non-masked regions. In the longer term, the better
+ solution will be to fix the relevant classes and functions
+ to handle masked data, so this may be a temporary solution
+ - JDH
+
2008-11-12 Add x_isdata and y_isdata attributes to Artist instances,
and use them to determine whether either or both
coordinates are used when updating dataLim. This is
Added: trunk/matplotlib/examples/api/filled_masked_regions.py
===================================================================
--- trunk/matplotlib/examples/api/filled_masked_regions.py
(rev 0)
+++ trunk/matplotlib/examples/api/filled_masked_regions.py 2008-11-20
18:58:54 UTC (rev 6423)
@@ -0,0 +1,45 @@
+"""
+Illustrate some helper functions for shading regions where a logical
+mask is True
+"""
+import numpy as np
+import matplotlib.pyplot as plt
+import matplotlib.collections as collections
+
+
+t = np.arange(0.0, 2, 0.01)
+s = np.sin(2*np.pi*t)
+
+fig = plt.figure()
+ax = fig.add_subplot(111)
+ax.set_title('using fill_between_masked')
+ax.plot(t, s, '-')
+ax.axhline(0, color='black', lw=2)
+
+collection = collections.PolyCollection.fill_between_masked(t, s, s>=0,
yboundary=0, color='green', alpha=0.5)
+ax.add_collection(collection)
+
+collection = collections.PolyCollection.fill_between_masked(t, s, s<=0,
yboundary=0, color='red', alpha=0.5)
+ax.add_collection(collection)
+
+
+fig = plt.figure()
+ax = fig.add_subplot(111)
+ax.set_title('using span_masked')
+ax.plot(t, s, '-')
+ax.axhline(0, color='black', lw=2)
+
+collection = collections.BrokenBarHCollection.span_masked(t, s>0, ymin=0,
ymax=1, facecolor='green', alpha=0.5)
+ax.add_collection(collection)
+
+collection = collections.BrokenBarHCollection.span_masked(t, s<0, ymin=-1,
ymax=0, facecolor='red', alpha=0.5)
+ax.add_collection(collection)
+
+
+
+plt.show()
+
+
+
+
+
Modified: trunk/matplotlib/lib/matplotlib/collections.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/collections.py 2008-11-20 15:46:46 UTC
(rev 6422)
+++ trunk/matplotlib/lib/matplotlib/collections.py 2008-11-20 18:58:54 UTC
(rev 6423)
@@ -19,6 +19,7 @@
import matplotlib.artist as artist
import matplotlib.backend_bases as backend_bases
import matplotlib.path as mpath
+import matplotlib.mlab as mlab
class Collection(artist.Artist, cm.ScalarMappable):
"""
@@ -234,7 +235,7 @@
self._urls = [None,]
else:
self._urls = urls
-
+
def get_urls(self): return self._urls
def set_offsets(self, offsets):
@@ -671,6 +672,49 @@
for x in self._sizes]
return Collection.draw(self, renderer)
+
+ @staticmethod
+ def fill_between_masked(x, y, mask, yboundary=0, **kwargs):
+ """
+ Create a :class:`PolyCollection` filling the regions between *y*
+ and *yboundary7* where ``mask==True``
+
+
+ *x*
+ an N length np array of the x data
+
+ *y*
+ an N length np array of the y data
+
+ *mask*
+ an N length numpy boolean array
+
+ *yboundary*
+ a scalar to fill between *y* and the boundary
+
+ *kwargs*
+ keyword args passed on to the :class:`PolyCollection`
+
+ """
+ polys = []
+ for ind0, ind1 in mlab.contiguous_regions(mask):
+ theseverts = []
+ xslice = x[ind0:ind1]
+ yslice = y[ind0:ind1]
+ N = len(xslice)
+ X = np.zeros((2*N+2, 2), np.float)
+ X[0] = xslice[0], yboundary
+ X[N+1] = xslice[-1], yboundary
+ X[1:N+1,0] = xslice
+ X[1:N+1,1] = yslice
+ X[N+2:,0] = xslice[::-1]
+ X[N+2:,1] = yboundary
+
+ polys.append(X)
+
+ collection = PolyCollection(polys, **kwargs)
+ return collection
+
class BrokenBarHCollection(PolyCollection):
"""
A collection of horizontal bars spanning *yrange* with a sequence of
@@ -692,6 +736,25 @@
PolyCollection.__init__(self, verts, **kwargs)
__init__.__doc__ = cbook.dedent(__init__.__doc__) % artist.kwdocd
+
+ @staticmethod
+ def span_masked(x, mask, ymin, ymax, **kwargs):
+ """
+ Create a BrokenBarHCollection to plot horizontal bars from
+ over the regions in *x* where *mask* is True. The bars range
+ on the y-axis from *ymin* to *ymax*
+
+ A :class:`BrokenBarHCollection` is returned.
+ **kwargs are passed on to the collection
+ """
+ xranges = []
+ for ind0, ind1 in mlab.contiguous_regions(mask):
+ xslice = x[ind0:ind1]
+ xranges.append((xslice[0], xslice[-1]-xslice[0]))
+
+ collection = BrokenBarHCollection(xranges, [ymin, ymax-ymin], **kwargs)
+ return collection
+
class RegularPolyCollection(Collection):
"""Draw a collection of regular polygons with *numsides*."""
_path_generator = mpath.Path.unit_regular_polygon
Modified: trunk/matplotlib/lib/matplotlib/mlab.py
===================================================================
--- trunk/matplotlib/lib/matplotlib/mlab.py 2008-11-20 15:46:46 UTC (rev
6422)
+++ trunk/matplotlib/lib/matplotlib/mlab.py 2008-11-20 18:58:54 UTC (rev
6423)
@@ -159,7 +159,7 @@
import csv, warnings, copy, os
import numpy as np
-
+ma = np.ma
from matplotlib import verbose
import matplotlib.nxutils as nxutils
@@ -247,7 +247,7 @@
#The checks for if y is x are so that we can use the same function to
#implement the core of psd(), csd(), and spectrogram() without doing
#extra calculations. We return the unaveraged Pxy, freqs, and t.
-
+
#Make sure we're dealing with a numpy array. If y and x were the same
#object to start with, keep them that way
same_data = y is x
@@ -309,7 +309,7 @@
Pxy /= (np.abs(windowVals)**2).sum()
t = 1./Fs * (ind + NFFT / 2.)
freqs = float(Fs) / pad_to * np.arange(numFreqs)
-
+
return Pxy, freqs, t
#Split out these keyword docs so that they can be used elsewhere
@@ -2104,7 +2104,8 @@
def csv2rec(fname, comments='#', skiprows=0, checkrows=0, delimiter=',',
- converterd=None, names=None, missing='', missingd=None):
+ converterd=None, names=None, missing='', missingd=None,
+ use_mrecords=True):
"""
Load data from comma/space/tab delimited file in *fname* into a
numpy record array and return the record array.
@@ -2139,9 +2140,11 @@
be masked, e.g. '0000-00-00' or 'unused'
- *missing*: a string whose value signals a missing field regardless of
- the column it appears in, e.g. 'unused'
+ the column it appears in
- If no rows are found, *None* is returned -- see :file:`examples/loadrec.py`
+ - *use_mrecords*: if True, return an mrecords.fromrecords record array if
any of the data are missing
+
+ If no rows are found, *None* is returned -- see
:file:`examples/loadrec.py`
"""
if converterd is None:
@@ -2338,7 +2341,8 @@
if not len(rows):
return None
- if np.any(rowmasks):
+
+ if use_mrecords and np.any(rowmasks):
try: from numpy.ma import mrecords
except ImportError:
raise RuntimeError('numpy 1.05 or later is required for masked
array support')
@@ -2938,19 +2942,25 @@
xv, yv = poly_below(0, x, y)
ax.fill(xv, yv)
"""
- xs = np.asarray(xs)
- ys = np.asarray(ys)
+ if ma.isMaskedArray(xs) or ma.isMaskedArray(ys):
+ nx = ma
+ else:
+ nx = np
+
+ xs = nx.asarray(xs)
+ ys = nx.asarray(ys)
Nx = len(xs)
Ny = len(ys)
assert(Nx==Ny)
- x = xmin*np.ones(2*Nx)
- y = np.ones(2*Nx)
+ x = xmin*nx.ones(2*Nx)
+ y = nx.ones(2*Nx)
x[:Nx] = xs
y[:Nx] = ys
y[Nx:] = ys[::-1]
return x, y
+
def poly_between(x, ylower, yupper):
"""
Given a sequence of *x*, *ylower* and *yupper*, return the polygon
@@ -2961,17 +2971,23 @@
Return value is *x*, *y* arrays for use with
:meth:`matplotlib.axes.Axes.fill`.
"""
+ if ma.isMaskedArray(ylower) or ma.isMaskedArray(yupper) or
ma.isMaskedArray(x):
+ nx = ma
+ else:
+ nx = np
+
Nx = len(x)
if not cbook.iterable(ylower):
- ylower = ylower*np.ones(Nx)
+ ylower = ylower*nx.ones(Nx)
if not cbook.iterable(yupper):
- yupper = yupper*np.ones(Nx)
+ yupper = yupper*nx.ones(Nx)
- x = np.concatenate( (x, x[::-1]) )
- y = np.concatenate( (yupper, ylower[::-1]) )
+ x = nx.concatenate( (x, x[::-1]) )
+ y = nx.concatenate( (yupper, ylower[::-1]) )
return x,y
+
def is_closed_polygon(X):
"""
Tests whether first and last object in a sequence are the same. These are
@@ -2980,6 +2996,28 @@
"""
return np.all(X[0] == X[-1])
+
+def contiguous_regions(mask):
+ """
+ return a list of (ind0, ind1) such that mask[ind0:ind1].all() is
+ True and we cover all such regions
+
+ TODO: this is a pure python implementation which probably has a much
faster numpy impl
+ """
+
+ in_region = None
+ boundaries = []
+ for i, val in enumerate(mask):
+ if in_region is None and val:
+ in_region = i
+ elif in_region is not None and not val:
+ boundaries.append((in_region, i))
+ in_region = None
+
+ if in_region is not None:
+ boundaries.append((in_region, i+1))
+ return boundaries
+
##################################################
# Vector and path length geometry calculations
##################################################
Modified: trunk/matplotlib/src/_backend_agg.cpp
===================================================================
--- trunk/matplotlib/src/_backend_agg.cpp 2008-11-20 15:46:46 UTC (rev
6422)
+++ trunk/matplotlib/src/_backend_agg.cpp 2008-11-20 18:58:54 UTC (rev
6423)
@@ -385,7 +385,8 @@
if (!py_convert_bbox(box_obj.ptr(), l, b, r, t))
throw Py::TypeError("Invalid bbox provided to copy_from_bbox");
- agg::rect_i rect((int)l, height - (int)t, (int)r, height - (int)b);
+ // std::cout << l << " " << b << " " << r << " " << t << " " << (height -
(int)b) << " " << height - (int)t << std::endl;
+ agg::rect_i rect((int)l, height - (int)b, (int)r, height - (int)t);
BufferRegion* reg = NULL;
try {
@@ -419,9 +420,11 @@
BufferRegion* region = static_cast<BufferRegion*>(args[0].ptr());
if (region->data==NULL)
- return Py::Object();
- //throw Py::ValueError("Cannot restore_region from NULL data");
+ throw Py::ValueError("Cannot restore_region from NULL data");
+ //return Py::Object();
+ //std::cout << "restoring " << region->width << " " << region->height << " "
<< region->stride << " " << region->rect.x1 << " " << region->rect.y1 <<
std::endl;
+
agg::rendering_buffer rbuf;
rbuf.attach(region->data,
region->width,
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Matplotlib-checkins mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins