Skip to content

Commit a65066d

Browse files
committed
Use qhull for delaunay triangulation
1 parent b35ad23 commit a65066d

File tree

13 files changed

+807
-1514
lines changed

13 files changed

+807
-1514
lines changed

CHANGELOG

+24-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1+
2013-11-28 Added qhull extension module to perform Delaunay triangulation more
2+
robustly than before. It is used by tri.Triangulation (and hence
3+
all pyplot.tri* methods) and mlab.griddata. Deprecated
4+
matplotlib.delaunay module. - IMT
5+
16
2013-10-27 Added get_rlabel_position and set_rlabel_position methods to
2-
PolarAxes to control angular position of radial tick labels.
3-
7+
PolarAxes to control angular position of radial tick labels.
8+
49
2013-10-06 Add stride-based functions to mlab for easy creation of 2D arrays
510
with less memory.
611

@@ -27,16 +32,16 @@
2732
and matplotlib.units.Registry.
2833

2934
2013-06-26 Refactored the axes module: the axes module is now a folder,
30-
containing the following submodule:
31-
- _subplots.py, containing all the subplots helper methods
32-
- _base.py, containing several private methods and a new
33-
_AxesBase class. This _AxesBase class contains all the methods
34-
that are not directly linked to plots of the "old" Axes
35-
- _axes.py contains the Axes class. This class now inherits from
36-
_AxesBase: it contains all "plotting" methods and labelling
37-
methods.
38-
This refactoring should not affect the API. Only private methods
39-
are not importable from the axes module anymore.
35+
containing the following submodule:
36+
- _subplots.py, containing all the subplots helper methods
37+
- _base.py, containing several private methods and a new
38+
_AxesBase class. This _AxesBase class contains all the methods
39+
that are not directly linked to plots of the "old" Axes
40+
- _axes.py contains the Axes class. This class now inherits from
41+
_AxesBase: it contains all "plotting" methods and labelling
42+
methods.
43+
This refactoring should not affect the API. Only private methods
44+
are not importable from the axes module anymore.
4045

4146
2013-05-18 Added support for arbitrary rasterization resolutions to the
4247
SVG backend. Previously the resolution was hard coded to 72
@@ -52,22 +57,21 @@
5257

5358
2013-04-25 Changed all instances of:
5459

55-
from matplotlib import MatplotlibDeprecationWarning as mplDeprecation
56-
to:
57-
58-
from cbook import mplDeprecation
60+
from matplotlib import MatplotlibDeprecationWarning as mplDeprecation
61+
to:
5962

60-
and removed the import into the matplotlib namespace in __init__.py
61-
Thomas Caswell
63+
from cbook import mplDeprecation
6264

65+
and removed the import into the matplotlib namespace in __init__.py
66+
Thomas Caswell
6367

6468
2013-04-15 Added 'axes.xmargin' and 'axes.ymargin' to rpParams to set default
65-
margins on auto-scaleing. - TAC
69+
margins on auto-scaleing. - TAC
6670

6771
2013-04-16 Added patheffect support for Line2D objects. -JJL
6872

6973
2013-03-19 Added support for passing `linestyle` kwarg to `step` so all `plot`
70-
kwargs are passed to the underlying `plot` call. -TAC
74+
kwargs are passed to the underlying `plot` call. -TAC
7175

7276
2013-02-25 Added classes CubicTriInterpolator, UniformTriRefiner, TriAnalyzer
7377
to matplotlib.tri module. - GBy

MANIFEST.in

+1-3
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,5 @@ recursive-include LICENSE *
1414
recursive-include examples *
1515
recursive-include doc *
1616
recursive-include src *.cpp *.c *.h *.m
17-
recursive-include CXX *.cxx *.hxx *.c *.h
18-
recursive-include agg24 *
1917
recursive-include lib *
20-
recursive-include ttconv *.cpp *.h
18+
recursive-include extern *

examples/pylab_examples/griddata_demo.py

+12-26
Original file line numberDiff line numberDiff line change
@@ -6,36 +6,22 @@
66
#npts = int(raw_input('enter # of random points to plot:'))
77
seed(0)
88
npts = 200
9-
x = uniform(-2,2,npts)
10-
y = uniform(-2,2,npts)
11-
z = x*np.exp(-x**2-y**2)
9+
x = uniform(-2, 2, npts)
10+
y = uniform(-2, 2, npts)
11+
z = x*np.exp(-x**2 - y**2)
1212
# define grid.
13-
xi = np.linspace(-2.1,2.1,100)
14-
yi = np.linspace(-2.1,2.1,200)
13+
xi = np.linspace(-2.1, 2.1, 100)
14+
yi = np.linspace(-2.1, 2.1, 200)
1515
# grid the data.
16-
zi = griddata(x,y,z,xi,yi,interp='linear')
16+
zi = griddata(x, y, z, xi, yi, interp='linear')
1717
# contour the gridded data, plotting dots at the nonuniform data points.
18-
CS = plt.contour(xi,yi,zi,15,linewidths=0.5,colors='k')
19-
CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.rainbow,
18+
CS = plt.contour(xi, yi, zi, 15, linewidths=0.5, colors='k')
19+
CS = plt.contourf(xi, yi, zi, 15, cmap=plt.cm.rainbow,
2020
vmax=abs(zi).max(), vmin=-abs(zi).max())
21-
plt.colorbar() # draw colorbar
21+
plt.colorbar() # draw colorbar
2222
# plot data points.
23-
plt.scatter(x,y,marker='o',c='b',s=5,zorder=10)
24-
plt.xlim(-2,2)
25-
plt.ylim(-2,2)
23+
plt.scatter(x, y, marker='o', c='b', s=5, zorder=10)
24+
plt.xlim(-2, 2)
25+
plt.ylim(-2, 2)
2626
plt.title('griddata test (%d points)' % npts)
2727
plt.show()
28-
29-
# test case that scikits.delaunay fails on, but natgrid passes..
30-
#data = np.array([[-1, -1], [-1, 0], [-1, 1],
31-
# [ 0, -1], [ 0, 0], [ 0, 1],
32-
# [ 1, -1 - np.finfo(np.float_).eps], [ 1, 0], [ 1, 1],
33-
# ])
34-
#x = data[:,0]
35-
#y = data[:,1]
36-
#z = x*np.exp(-x**2-y**2)
37-
## define grid.
38-
#xi = np.linspace(-1.1,1.1,100)
39-
#yi = np.linspace(-1.1,1.1,100)
40-
## grid the data.
41-
#zi = griddata(x,y,z,xi,yi)

lib/matplotlib/delaunay/triangulate.py

+5
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

1212
from matplotlib._delaunay import delaunay
1313
from .interpolate import LinearInterpolator, NNInterpolator
14+
from matplotlib.cbook import warn_deprecated
15+
warn_deprecated('1.4',
16+
name='matplotlib.delaunay',
17+
alternative='matplotlib.tri.Triangulation',
18+
obj_type='module')
1419

1520
__all__ = ['Triangulation', 'DuplicatePointWarning']
1621

lib/matplotlib/mlab.py

+123-116
Original file line numberDiff line numberDiff line change
@@ -3356,124 +3356,131 @@ def newfunc(val, mask, mval):
33563356
if opened:
33573357
fh.close()
33583358

3359-
def griddata(x,y,z,xi,yi,interp='nn'):
3360-
"""
3361-
``zi = griddata(x,y,z,xi,yi)`` fits a surface of the form *z* =
3362-
*f*(*x*, *y*) to the data in the (usually) nonuniformly spaced
3363-
vectors (*x*, *y*, *z*). :func:`griddata` interpolates this
3364-
surface at the points specified by (*xi*, *yi*) to produce
3365-
*zi*. *xi* and *yi* must describe a regular grid, can be either 1D
3366-
or 2D, but must be monotonically increasing.
3367-
3368-
A masked array is returned if any grid points are outside convex
3369-
hull defined by input data (no extrapolation is done).
3370-
3371-
If interp keyword is set to '`nn`' (default),
3372-
uses natural neighbor interpolation based on Delaunay
3373-
triangulation. By default, this algorithm is provided by the
3374-
:mod:`matplotlib.delaunay` package, written by Robert Kern. The
3375-
triangulation algorithm in this package is known to fail on some
3376-
nearly pathological cases. For this reason, a separate toolkit
3377-
(:mod:`mpl_tookits.natgrid`) has been created that provides a more
3378-
robust algorithm fof triangulation and interpolation. This
3379-
toolkit is based on the NCAR natgrid library, which contains code
3380-
that is not redistributable under a BSD-compatible license. When
3381-
installed, this function will use the :mod:`mpl_toolkits.natgrid`
3382-
algorithm, otherwise it will use the built-in
3383-
:mod:`matplotlib.delaunay` package.
3384-
3385-
If the interp keyword is set to '`linear`', then linear interpolation
3386-
is used instead of natural neighbor. In this case, the output grid
3387-
is assumed to be regular with a constant grid spacing in both the x and
3388-
y directions. For regular grids with nonconstant grid spacing, you
3389-
must use natural neighbor interpolation. Linear interpolation is only valid if
3390-
:mod:`matplotlib.delaunay` package is used - :mod:`mpl_tookits.natgrid`
3391-
only provides natural neighbor interpolation.
3392-
3393-
The natgrid matplotlib toolkit can be downloaded from
3394-
http://sourceforge.net/project/showfiles.php?group_id=80706&package_id=142792
3395-
"""
3396-
try:
3397-
from mpl_toolkits.natgrid import _natgrid, __version__
3398-
_use_natgrid = True
3399-
except ImportError:
3400-
import matplotlib.delaunay as delaunay
3401-
from matplotlib.delaunay import __version__
3402-
_use_natgrid = False
3403-
if not griddata._reported:
3404-
if _use_natgrid:
3405-
verbose.report('using natgrid version %s' % __version__)
3406-
else:
3407-
verbose.report('using delaunay version %s' % __version__)
3408-
griddata._reported = True
3359+
3360+
def griddata(x, y, z, xi, yi, interp='nn'):
3361+
"""Interpolates from a nonuniformly spaced grid to some other
3362+
grid.
3363+
3364+
Fits a surface of the form z = f(`x`, `y`) to the data in the
3365+
(usually) nonuniformly spaced vectors (`x`, `y`, `z`), then
3366+
interpolates this surface at the points specified by
3367+
(`xi`, `yi`) to produce `zi`.
3368+
3369+
Parameters
3370+
----------
3371+
x, y, z : 1d array_like
3372+
Coordinates of grid points to interpolate from.
3373+
xi, yi : 1d or 2d array_like
3374+
Coordinates of grid points to interpolate to.
3375+
interp : string key from {'nn', 'linear'}
3376+
Interpolation algorithm, either 'nn' for natural neighbor, or
3377+
'linear' for linear interpolation.
3378+
3379+
Returns
3380+
-------
3381+
2d float array
3382+
Array of values interpolated at (`xi`, `yi`) points. Array
3383+
will be masked is any of (`xi`, `yi`) are outside the convex
3384+
hull of (`x`, `y`).
3385+
3386+
Notes
3387+
-----
3388+
If `interp` is 'nn' (the default), uses natural neighbor
3389+
interpolation based on Delaunay triangulation. This option is
3390+
only available if the mpl_toolkits.natgrid module is installed.
3391+
This can be downloaded from https://github.com/matplotlib/natgrid.
3392+
The (`xi`, `yi`) grid must be regular and monotonically increasing
3393+
in this case.
3394+
3395+
If `interp` is 'linear', linear interpolation is used via
3396+
matplotlib.tri.LinearTriInterpolator.
3397+
3398+
Instead of using `griddata`, more flexible functionality and other
3399+
interpolation options are available using a
3400+
matplotlib.tri.Triangulation and a matplotlib.tri.TriInterpolator.
3401+
"""
3402+
# Check input arguments.
3403+
x = np.asanyarray(x, dtype=np.float64)
3404+
y = np.asanyarray(y, dtype=np.float64)
3405+
z = np.asanyarray(z, dtype=np.float64)
3406+
if x.shape != y.shape or x.shape != z.shape or x.ndim != 1:
3407+
raise ValueError("x, y and z must be equal-length 1-D arrays")
3408+
3409+
xi = np.asanyarray(xi, dtype=np.float64)
3410+
yi = np.asanyarray(yi, dtype=np.float64)
34093411
if xi.ndim != yi.ndim:
3410-
raise TypeError("inputs xi and yi must have same number of dimensions (1 or 2)")
3411-
if xi.ndim != 1 and xi.ndim != 2:
3412-
raise TypeError("inputs xi and yi must be 1D or 2D.")
3413-
if not len(x)==len(y)==len(z):
3414-
raise TypeError("inputs x,y,z must all be 1D arrays of the same length")
3415-
# remove masked points.
3416-
if hasattr(z,'mask'):
3417-
# make sure mask is not a scalar boolean array.
3418-
if z.mask.ndim:
3419-
x = x.compress(z.mask == False)
3420-
y = y.compress(z.mask == False)
3421-
z = z.compressed()
3422-
if _use_natgrid: # use natgrid toolkit if available.
3423-
if interp != 'nn':
3424-
raise ValueError("only natural neighor interpolation"
3425-
" allowed when using natgrid toolkit in griddata.")
3412+
raise ValueError("xi and yi must be arrays with the same number of "
3413+
"dimensions (1 or 2)")
3414+
if xi.ndim == 2 and xi.shape != yi.shape:
3415+
raise ValueError("if xi and yi are 2D arrays, they must have the same "
3416+
"shape")
3417+
if xi.ndim == 1:
3418+
xi, yi = np.meshgrid(xi, yi)
3419+
3420+
if interp == 'nn':
3421+
use_nn_interpolation = True
3422+
elif interp == 'linear':
3423+
use_nn_interpolation = False
3424+
else:
3425+
raise ValueError("interp keyword must be one of 'linear' (for linear "
3426+
"interpolation) or 'nn' (for natural neighbor "
3427+
"interpolation). Default is 'nn'.")
3428+
3429+
# Remove masked points.
3430+
mask = np.ma.getmask(z)
3431+
if not (mask is np.ma.nomask):
3432+
x = x.compress(~mask)
3433+
y = y.compress(~mask)
3434+
z = z.compressed()
3435+
3436+
if use_nn_interpolation:
3437+
try:
3438+
from mpl_toolkits.natgrid import _natgrid
3439+
except ImportError:
3440+
raise RuntimeError("To use interp='nn' (Natural Neighbor "
3441+
"interpolation) in griddata, natgrid must be installed. "
3442+
"Either install it from http://sourceforge.net/projects/"
3443+
"matplotlib/files/matplotlib-toolkits, or use interp='linear' "
3444+
"instead.")
3445+
34263446
if xi.ndim == 2:
3427-
xi = xi[0,:]
3428-
yi = yi[:,0]
3429-
# override default natgrid internal parameters.
3430-
_natgrid.seti('ext',0)
3431-
_natgrid.setr('nul',np.nan)
3432-
# cast input arrays to doubles (this makes a copy)
3433-
x = x.astype(np.float)
3434-
y = y.astype(np.float)
3435-
z = z.astype(np.float)
3436-
xo = xi.astype(np.float)
3437-
yo = yi.astype(np.float)
3438-
if min(xo[1:]-xo[0:-1]) < 0 or min(yo[1:]-yo[0:-1]) < 0:
3439-
raise ValueError('output grid defined by xi,yi must be monotone increasing')
3440-
# allocate array for output (buffer will be overwritten by nagridd)
3441-
zo = np.empty((yo.shape[0],xo.shape[0]), np.float)
3442-
_natgrid.natgridd(x,y,z,xo,yo,zo)
3443-
else: # use Robert Kern's delaunay package from scikits (default)
3444-
if xi.ndim != yi.ndim:
3445-
raise TypeError("inputs xi and yi must have same number of dimensions (1 or 2)")
3446-
if xi.ndim != 1 and xi.ndim != 2:
3447-
raise TypeError("inputs xi and yi must be 1D or 2D.")
3448-
if xi.ndim == 1:
3449-
xi,yi = np.meshgrid(xi,yi)
3450-
# triangulate data
3451-
tri = delaunay.Triangulation(x,y)
3452-
# interpolate data
3453-
if interp == 'nn':
3454-
interp = tri.nn_interpolator(z)
3455-
zo = interp(xi,yi)
3456-
elif interp == 'linear':
3457-
# make sure grid has constant dx, dy
3458-
dx = xi[0,1:]-xi[0,0:-1]
3459-
dy = yi[1:,0]-yi[0:-1,0]
3460-
epsx = np.finfo(xi.dtype).resolution
3461-
epsy = np.finfo(yi.dtype).resolution
3462-
if dx.max()-dx.min() > epsx or dy.max()-dy.min() > epsy:
3463-
raise ValueError("output grid must have constant spacing"
3464-
" when using interp='linear'")
3465-
interp = tri.linear_interpolator(z)
3466-
zo = interp[yi.min():yi.max():complex(0,yi.shape[0]),
3467-
xi.min():xi.max():complex(0,xi.shape[1])]
3468-
else:
3469-
raise ValueError("interp keyword must be one of"
3470-
" 'linear' (for linear interpolation) or 'nn'"
3471-
" (for natural neighbor interpolation). Default is 'nn'.")
3472-
# mask points on grid outside convex hull of input data.
3473-
if np.any(np.isnan(zo)):
3474-
zo = np.ma.masked_where(np.isnan(zo),zo)
3475-
return zo
3476-
griddata._reported = False
3447+
# natgrid expects 1D xi and yi arrays.
3448+
xi = xi[0, :]
3449+
yi = yi[:, 0]
3450+
3451+
# Override default natgrid internal parameters.
3452+
_natgrid.seti('ext', 0)
3453+
_natgrid.setr('nul', np.nan)
3454+
3455+
if np.min(np.diff(xi)) < 0 or np.min(np.diff(yi)) < 0:
3456+
raise ValueError("Output grid defined by xi,yi must be monotone "
3457+
"increasing")
3458+
3459+
# Allocate array for output (buffer will be overwritten by natgridd)
3460+
zi = np.empty((yi.shape[0], xi.shape[0]), np.float64)
3461+
3462+
# Natgrid requires each array to be contiguous rather than e.g. a view
3463+
# that is a non-contiguous slice of another array. Use numpy.require
3464+
# to deal with this, which will copy if necessary.
3465+
x = np.require(x, requirements=['C'])
3466+
y = np.require(y, requirements=['C'])
3467+
z = np.require(z, requirements=['C'])
3468+
xi = np.require(xi, requirements=['C'])
3469+
yi = np.require(yi, requirements=['C'])
3470+
_natgrid.natgridd(x, y, z, xi, yi, zi)
3471+
3472+
# Mask points on grid outside convex hull of input data.
3473+
if np.any(np.isnan(zi)):
3474+
zi = np.ma.masked_where(np.isnan(zi), zi)
3475+
return zi
3476+
else:
3477+
# Linear interpolation performed using a matplotlib.tri.Triangulation
3478+
# and a matplotlib.tri.LinearTriInterpolator.
3479+
from .tri import Triangulation, LinearTriInterpolator
3480+
triang = Triangulation(x, y)
3481+
interpolator = LinearTriInterpolator(triang, z)
3482+
return interpolator(xi, yi)
3483+
34773484

34783485
##################################################
34793486
# Linear interpolation algorithms
Binary file not shown.

0 commit comments

Comments
 (0)