@@ -1438,6 +1438,181 @@ def splitfunc(x):
14381438 else : return X
14391439
14401440
1441+ def slopes (x ,y ):
1442+ """
1443+ SLOPES calculate the slope y'(x) Given data vectors X and Y SLOPES
1444+ calculates Y'(X), i.e the slope of a curve Y(X). The slope is
1445+ estimated using the slope obtained from that of a parabola through
1446+ any three consecutive points.
1447+
1448+ This method should be superior to that described in the appendix
1449+ of A CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russel
1450+ W. Stineman (Creative Computing July 1980) in at least one aspect:
1451+
1452+ Circles for interpolation demand a known aspect ratio between x-
1453+ and y-values. For many functions, however, the abscissa are given
1454+ in different dimensions, so an aspect ratio is completely
1455+ arbitrary.
1456+
1457+ The parabola method gives very similar results to the circle
1458+ method for most regular cases but behaves much better in special
1459+ cases
1460+
1461+ Norbert Nemec, Institute of Theoretical Physics, University or
1462+ Regensburg, April 2006 Norbert.Nemec at physik.uni-regensburg.de
1463+
1464+ (inspired by a original implementation by Halldor Bjornsson,
1465+ Icelandic Meteorological Office, March 2006 halldor at vedur.is)
1466+ """
1467+ # Cast key variables as float.
1468+ x = np .asarray (x , np .float_ )
1469+ y = np .asarray (y , np .float_ )
1470+
1471+ yp = np .zeros (y .shape , np .float_ )
1472+
1473+ dx = x [1 :] - x [:- 1 ]
1474+ dy = y [1 :] - y [:- 1 ]
1475+ dydx = dy / dx
1476+ yp [1 :- 1 ] = (dydx [:- 1 ] * dx [1 :] + dydx [1 :] * dx [:- 1 ])/ (dx [1 :] + dx [:- 1 ])
1477+ yp [0 ] = 2.0 * dy [0 ]/ dx [0 ] - yp [1 ]
1478+ yp [- 1 ] = 2.0 * dy [- 1 ]/ dx [- 1 ] - yp [- 2 ]
1479+ return yp
1480+
1481+
1482+ def stineman_interp (xi ,x ,y ,yp = None ):
1483+ """
1484+ STINEMAN_INTERP Well behaved data interpolation. Given data
1485+ vectors X and Y, the slope vector YP and a new abscissa vector XI
1486+ the function stineman_interp(xi,x,y,yp) uses Stineman
1487+ interpolation to calculate a vector YI corresponding to XI.
1488+
1489+ Here's an example that generates a coarse sine curve, then
1490+ interpolates over a finer abscissa:
1491+
1492+ x = linspace(0,2*pi,20); y = sin(x); yp = cos(x)
1493+ xi = linspace(0,2*pi,40);
1494+ yi = stineman_interp(xi,x,y,yp);
1495+ plot(x,y,'o',xi,yi)
1496+
1497+ The interpolation method is described in the article A
1498+ CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russell
1499+ W. Stineman. The article appeared in the July 1980 issue of
1500+ Creative Computing with a note from the editor stating that while
1501+ they were
1502+
1503+ not an academic journal but once in a while something serious
1504+ and original comes in adding that this was
1505+ "apparently a real solution" to a well known problem.
1506+
1507+ For yp=None, the routine automatically determines the slopes using
1508+ the "slopes" routine.
1509+
1510+ X is assumed to be sorted in increasing order
1511+
1512+ For values xi[j] < x[0] or xi[j] > x[-1], the routine tries a
1513+ extrapolation. The relevance of the data obtained from this, of
1514+ course, questionable...
1515+
1516+ original implementation by Halldor Bjornsson, Icelandic
1517+ Meteorolocial Office, March 2006 halldor at vedur.is
1518+
1519+ completely reworked and optimized for Python by Norbert Nemec,
1520+ Institute of Theoretical Physics, University or Regensburg, April
1521+ 2006 Norbert.Nemec at physik.uni-regensburg.de
1522+
1523+ """
1524+
1525+ # Cast key variables as float.
1526+ x = np .asarray (x , np .float_ )
1527+ y = np .asarray (y , np .float_ )
1528+ assert x .shape == y .shape
1529+ N = len (y )
1530+
1531+ if yp is None :
1532+ yp = slopes (x ,y )
1533+ else :
1534+ yp = np .asarray (yp , np .float_ )
1535+
1536+ xi = np .asarray (xi , np .float_ )
1537+ yi = np .zeros (xi .shape , np .float_ )
1538+
1539+ # calculate linear slopes
1540+ dx = x [1 :] - x [:- 1 ]
1541+ dy = y [1 :] - y [:- 1 ]
1542+ s = dy / dx #note length of s is N-1 so last element is #N-2
1543+
1544+ # find the segment each xi is in
1545+ # this line actually is the key to the efficiency of this implementation
1546+ idx = np .searchsorted (x [1 :- 1 ], xi )
1547+
1548+ # now we have generally: x[idx[j]] <= xi[j] <= x[idx[j]+1]
1549+ # except at the boundaries, where it may be that xi[j] < x[0] or xi[j] > x[-1]
1550+
1551+ # the y-values that would come out from a linear interpolation:
1552+ sidx = s .take (idx )
1553+ xidx = x .take (idx )
1554+ yidx = y .take (idx )
1555+ xidxp1 = x .take (idx + 1 )
1556+ yo = yidx + sidx * (xi - xidx )
1557+
1558+ # the difference that comes when using the slopes given in yp
1559+ dy1 = (yp .take (idx )- sidx ) * (xi - xidx ) # using the yp slope of the left point
1560+ dy2 = (yp .take (idx + 1 )- sidx ) * (xi - xidxp1 ) # using the yp slope of the right point
1561+
1562+ dy1dy2 = dy1 * dy2
1563+ # The following is optimized for Python. The solution actually
1564+ # does more calculations than necessary but exploiting the power
1565+ # of numpy, this is far more efficient than coding a loop by hand
1566+ # in Python
1567+ yi = yo + dy1dy2 * np .choose (np .array (np .sign (dy1dy2 ), np .int32 )+ 1 ,
1568+ ((2 * xi - xidx - xidxp1 )/ ((dy1 - dy2 )* (xidxp1 - xidx )),
1569+ 0.0 ,
1570+ 1 / (dy1 + dy2 ),))
1571+ return yi
1572+
1573+ def inside_poly (points , verts ):
1574+ """
1575+ points is a sequence of x,y points
1576+ verts is a sequence of x,y vertices of a poygon
1577+
1578+ return value is a sequence of indices into points for the points
1579+ that are inside the polygon
1580+ """
1581+ res , = np .nonzero (nxutils .points_inside_poly (points , verts ))
1582+ return res
1583+
1584+ def poly_below (ymin , xs , ys ):
1585+ """
1586+ given a arrays *xs* and *ys*, return the vertices of a polygon
1587+ that has a scalar lower bound *ymin* and an upper bound at the *ys*.
1588+
1589+ intended for use with Axes.fill, eg::
1590+
1591+ xv, yv = poly_below(0, x, y)
1592+ ax.fill(xv, yv)
1593+ """
1594+ return poly_between (xs , ys , xmin )
1595+
1596+
1597+ def poly_between (x , ylower , yupper ):
1598+ """
1599+ given a sequence of x, ylower and yupper, return the polygon that
1600+ fills the regions between them. ylower or yupper can be scalar or
1601+ iterable. If they are iterable, they must be equal in length to x
1602+
1603+ return value is x, y arrays for use with Axes.fill
1604+ """
1605+ Nx = len (x )
1606+ if not cbook .iterable (ylower ):
1607+ ylower = ylower * np .ones (Nx )
1608+
1609+ if not cbook .iterable (yupper ):
1610+ yupper = yupper * np .ones (Nx )
1611+
1612+ x = np .concatenate ( (x , x [::- 1 ]) )
1613+ y = np .concatenate ( (yupper , ylower [::- 1 ]) )
1614+ return x ,y
1615+
14411616### the following code was written and submitted by Fernando Perez
14421617### from the ipython numutils package under a BSD license
14431618# begin fperez functions
0 commit comments