Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a93ddb7

Browse files
committed
Add some documentation for ExtremeFinder.
Let's try to figure out how this whole thing is constructed :) At least that's my understanding.
1 parent a00fdf1 commit a93ddb7

File tree

3 files changed

+82
-50
lines changed

3 files changed

+82
-50
lines changed

lib/mpl_toolkits/axisartist/angle_helper.py

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -335,26 +335,49 @@ def __call__(self, direction, factor, values): # hour
335335

336336

337337
class ExtremeFinderCycle(ExtremeFinderSimple):
338-
"""
339-
When there is a cycle, e.g., longitude goes from 0-360.
340-
"""
338+
# docstring inherited
339+
341340
def __init__(self, nx, ny,
342341
lon_cycle=360., lat_cycle=None,
343342
lon_minmax=None, lat_minmax=(-90, 90)):
343+
"""
344+
This subclass handles the case where one or both coordinates should be
345+
taken modulo 360, or be restricted to not exceed a specific range.
346+
347+
Parameters
348+
----------
349+
nx, ny : int
350+
The number of samples in each direction.
351+
352+
lon_cycle, lat_cycle : 360 or None
353+
If not None, values in the corresponding direction are taken modulo
354+
*lon_cycle* or *lat_cycle*; in theory this can be any number but
355+
the implementation actually assumes that it is 360 (if not None);
356+
other values give nonsensical results.
357+
358+
This is done by "unwrapping" the transformed grid coordinates so
359+
that jumps are less than a half-cycle; then normalizing the span to
360+
no more than a full cycle.
361+
362+
For example, if values are in the union of the [0, 2] and
363+
[358, 360] intervals (typically, angles measured modulo 360), the
364+
values in the second interval are normalized to [-2, 0] instead so
365+
that the values now cover [-2, 2]. If values are in a range of
366+
[5, 1000], this gets normalized to normalized to [5, 365].
367+
368+
lon_minmax, lat_minmax : (float, float) or None
369+
If not None, the computed bounding box is clipped to the given
370+
range in the corresponding direction.
371+
"""
344372
self.nx, self.ny = nx, ny
345373
self.lon_cycle, self.lat_cycle = lon_cycle, lat_cycle
346374
self.lon_minmax = lon_minmax
347375
self.lat_minmax = lat_minmax
348376

349377
def __call__(self, transform_xy, x1, y1, x2, y2):
350-
"""
351-
get extreme values.
352-
353-
x1, y1, x2, y2 in image coordinates (0-based)
354-
nx, ny : number of divisions in each axis
355-
"""
356-
x_, y_ = np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny)
357-
x, y = np.meshgrid(x_, y_)
378+
# docstring inherited
379+
x, y = np.meshgrid(
380+
np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny))
358381
lon, lat = transform_xy(np.ravel(x), np.ravel(y))
359382

360383
# iron out jumps, but algorithm should be improved.
@@ -374,13 +397,6 @@ def __call__(self, transform_xy, x1, y1, x2, y2):
374397
lon_min, lon_max = np.nanmin(lon), np.nanmax(lon)
375398
lat_min, lat_max = np.nanmin(lat), np.nanmax(lat)
376399

377-
lon_min, lon_max, lat_min, lat_max = \
378-
self._adjust_extremes(lon_min, lon_max, lat_min, lat_max)
379-
380-
return lon_min, lon_max, lat_min, lat_max
381-
382-
def _adjust_extremes(self, lon_min, lon_max, lat_min, lat_max):
383-
384400
lon_min, lon_max, lat_min, lat_max = \
385401
self._add_pad(lon_min, lon_max, lat_min, lat_max)
386402

lib/mpl_toolkits/axisartist/floating_axes.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,16 +143,21 @@ def get_line(self, axes):
143143

144144

145145
class ExtremeFinderFixed(ExtremeFinderSimple):
146-
def __init__(self, extremes):
147-
self._extremes = extremes
146+
# docstring inherited
148147

149-
def __call__(self, transform_xy, x1, y1, x2, y2):
148+
def __init__(self, extremes):
150149
"""
151-
get extreme values.
150+
This subclass always returns the same bounding box.
152151
153-
x1, y1, x2, y2 in image coordinates (0-based)
154-
nx, ny : number of division in each axis
152+
Parameters
153+
----------
154+
extremes : (float, float, float, float)
155+
The bounding box always returned by this helper.
155156
"""
157+
self._extremes = extremes
158+
159+
def __call__(self, transform_xy, x1, y1, x2, y2):
160+
# docstring inherited
156161
return self._extremes
157162

158163

lib/mpl_toolkits/axisartist/grid_finder.py

Lines changed: 37 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,50 @@ def _deprecate_factor_none(factor):
1616
return factor
1717

1818

19-
# extremes finder
2019
class ExtremeFinderSimple:
21-
def __init__(self, nx, ny):
22-
self.nx, self.ny = nx, ny
20+
"""
21+
A helper class to figure out the range of grid lines that need to be drawn.
22+
"""
2323

24-
def __call__(self, transform_xy, x1, y1, x2, y2):
24+
def __init__(self, nx, ny):
2525
"""
26-
get extreme values.
27-
28-
x1, y1, x2, y2 in image coordinates (0-based)
29-
nx, ny : number of division in each axis
26+
Parameters
27+
----------
28+
nx, ny : int
29+
The number of samples in each direction.
3030
"""
31-
x_, y_ = np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny)
32-
x, y = np.meshgrid(x_, y_)
33-
lon, lat = transform_xy(np.ravel(x), np.ravel(y))
34-
35-
lon_min, lon_max = lon.min(), lon.max()
36-
lat_min, lat_max = lat.min(), lat.max()
31+
self.nx = nx
32+
self.ny = ny
3733

38-
return self._add_pad(lon_min, lon_max, lat_min, lat_max)
39-
40-
def _add_pad(self, lon_min, lon_max, lat_min, lat_max):
34+
def __call__(self, transform_xy, x1, y1, x2, y2):
4135
"""
42-
A small amount of padding is added because the current clipping
43-
algorithms seems to fail when the gridline ends at the bbox boundary.
36+
Compute an approximation of the bounding box obtained by applying
37+
*transform_xy* to the box delimited by ``(x1, y1, x2, y2)``.
38+
39+
The intended use is to have ``(x1, y1, x2, y2)`` in axes coordinates,
40+
and have *transform_xy* be the transform from axes coordinates to data
41+
coordinates; this method then returns the range of data coordinates
42+
that span the actual axes.
43+
44+
The computation is done by sampling ``nx * ny`` equispaced points in
45+
the ``(x1, y1, x2, y2)`` box and finding the resulting points with
46+
extremal coordinates; then adding some padding to take into account the
47+
finite sampling.
48+
49+
As each sampling step covers a relative range of *1/nx* or *1/ny*,
50+
the padding is computed by expanding the span covered by the extremal
51+
coordinates by these fractions.
4452
"""
45-
dlon = (lon_max - lon_min) / self.nx
46-
dlat = (lat_max - lat_min) / self.ny
47-
48-
lon_min, lon_max = lon_min - dlon, lon_max + dlon
49-
lat_min, lat_max = lat_min - dlat, lat_max + dlat
50-
51-
return lon_min, lon_max, lat_min, lat_max
53+
x, y = np.meshgrid(
54+
np.linspace(x1, x2, self.nx), np.linspace(y1, y2, self.ny))
55+
xt, yt = transform_xy(np.ravel(x), np.ravel(y))
56+
return self._add_pad(xt.min(), xt.max(), yt.min(), yt.max())
57+
58+
def _add_pad(self, x_min, x_max, y_min, y_max):
59+
"""Perform the padding mentioned in `__call__`."""
60+
dx = (x_max - x_min) / self.nx
61+
dy = (y_max - y_min) / self.ny
62+
return x_min - dx, x_max + dx, y_min - dy, y_max + dy
5263

5364

5465
class GridFinder:

0 commit comments

Comments
 (0)