Skip to content

Commit

Permalink
Image transform doc-strings.
Browse files Browse the repository at this point in the history
  • Loading branch information
bjlittle committed Oct 11, 2012
1 parent ee7065f commit 762fe51
Showing 1 changed file with 183 additions and 15 deletions.
198 changes: 183 additions & 15 deletions lib/cartopy/img_transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
#
# You should have received a copy of the GNU Lesser General Public License
# along with cartopy. If not, see <http://www.gnu.org/licenses/>.
"""
This module contains generic functionality to support Cartopy image transformations.
"""

import matplotlib.image
import numpy
Expand All @@ -24,27 +27,85 @@


def stack(*one_dim_arrays):
"""Stack the given arrays into an array of (m, n) where m is the len of each array and n is the number of arrays given."""
"""
XXX Not used external to this module. Only used within the module
XXX by functions that are not used themselves. DELETE ME?
Stack the given N :class:`numpy.ndarray`'s of similar shape M into a
single :class:`numpy.ndarray` of shape (M, N,).
Also see, :func:`~cartopy.img_transform.unpack`.
Args:
* one_dim_arrays:
One or more :class:`~numpy.ndarray` instance of the same shape.
Returns:
A :class:`~numpy.ndarray` instance of shape (M, N).
"""

# Ensure all arrays are of the same shape.
first = one_dim_arrays[0]
first_shape = first.shape
assert all([arr.shape == first_shape for arr in one_dim_arrays])

# Concatenate all the arrays together into one stacked array.
arrs = list(one_dim_arrays)
for arr in arrs:
arr.shape = first_shape + (1,)
r = numpy.concatenate(arrs, axis= -1)

# Undo the shape change to the original arrays.
for arr in arrs:
arr.shape = first_shape
return r


def unpack(vals):
"""opposite of stack."""
return [vals[..., i] for i in xrange(vals.shape[-1])]
def unpack(data):
"""
XXX Not used! DELETE ME?
Unpack the :class:`~numpy.ndarray` of shape (..., M) into M separate :class:`~numpy.ndarray`'s.
Also see, :func:`~cartopy.img_transform.stack`.
Args:
* data:
The :class:`~numpy.ndarray` to be unpacked.
Returns:
A list of M :class:`~numpy.ndarray`'s.
"""

return [data[..., i] for i in xrange(data.shape[-1])]


def ll_to_cart(lonslats):
"""
XXX Not used! DELETE ME!
Converts longitude and latitude coordinate data into Cartesian coordinate data.
Args:
* lonslats:
A :class:`~numpy.ndarray` instance of shape (M, 2) containing M coordinate
data values in longitude, latitude coordinate order.
Returns:
A single :class:`~numpy.ndarray` of shape (M, 3) containing M
Cartesian coordinate data values in x, y, z order.
"""

# Unpack into longitude and latitude values.
lons, lats = unpack(lonslats)

# Convert to Cartesian coordinates.
# XXX Should be done using crs.Geocentric
x = numpy.sin(numpy.deg2rad(90 - lats)) * numpy.cos(numpy.deg2rad(lons))
y = numpy.sin(numpy.deg2rad(90 - lats)) * numpy.sin(numpy.deg2rad(lons))
Expand All @@ -54,37 +115,68 @@ def ll_to_cart(lonslats):

def mesh_projection(projection, nx, ny, x_extents=[None, None], y_extents=[None, None]):
"""
Returns coords in the projection which span the entire projection range evenly.
Returns:
Returns sample points in the given projection which span the entire projection range evenly.
The range of the x-direction and y-direction sample points will be within the bounds
of the projection or specified extents.
Args:
xs, ys, extent
The return value is native coordinate system.
* projection:
A :class:`~cartopy.crs.Projection` instance.
* nx:
The number of sample points in the projection x-direction.
* ny:
The number of sample points in the projection y-direction.
Kwargs:
* x_extents:
The (lower, upper) x-direction extent of the projection.
Defaults to the :attribute:`~cartopy.crs.Projection.x_limits`.
* y_extents:
The (lower, upper) y-direction extent of the projection.
Defaults to the :attribute:`~cartopy.crs.Projection.y_limits`.
Returns:
A tuple of x-direction sample points :class:`numpy.ndarray` of shape (nx, ny),
y-direction sample points :class:`numpy.ndarray` of shape (nx, ny),
and the extent of the projection range as (x-lower, x-upper, y-lower, y-upper).
"""

# Establish the x-direction and y-direction extents.
x_lower = x_extents[0] or projection.x_limits[0]
x_upper = x_extents[1] or projection.x_limits[1]
y_lower = y_extents[0] or projection.y_limits[0]
y_upper = y_extents[1] or projection.y_limits[1]

# Calculate evenly spaced sample points spanning the extent - excluding endpoint.
x, xstep = numpy.linspace(x_lower, x_upper, nx, retstep=True, endpoint=False)
y, ystep = numpy.linspace(y_lower, y_upper, ny, retstep=True, endpoint=False)

# Offset the sample points to be within the extent range.
x += 0.5 * xstep
y += 0.5 * ystep

# Generate the x-direction and y-direction meshgrids.
x, y = numpy.meshgrid(x, y)
return x, y, [x_lower, x_upper, y_lower, y_upper]


def projection_coords(projection, nx, ny):
"""
XXX Not used and wrong! DELETE ME!
Returns coords in the projection which span the entire projection range evenly.
The return value is (natives, latslons, xyzs) for convenience.
"""

x = numpy.linspace(projection.x_limits[0], projection.x_limits[1], nx).reshape(1, -1)
y = numpy.linspace(projection.y_limits[0], projection.y_limits[1], ny).reshape(-1, 1)
x, y = numpy.meshgrid(x, y)
Expand All @@ -97,27 +189,72 @@ def projection_coords(projection, nx, ny):


def get_img_coords_and_nxy(fname, projection):
img = matplotlib.image.imread(fname)
"""
XXX Not used! DELETE ME!
ny, nx = img.shape[:-1]
"""

img = matplotlib.image.imread(fname)
ny, nx = img.shape[:-1]
_, _, xyz = projection_coords(projection, nx, ny)

return img, xyz, nx, ny


def warp_img(fname, target_proj, source_proj=None, target_res=(400, 200)):
"""
XXX Not used! DELETE ME!
"""

if source_proj is None:
source_proj = ccrs.PlateCarree()

raise NotImplementedError('Not yet implemented.')


def warp_array(array, target_proj, source_proj=None, target_res=(400, 200), source_extent=None, target_extent=None):
# source_extent is in source coordinates
"""
Regrid the data array from the source projection to the target projection.
Also see, :function:`~cartopy.img_transform.regrid`.
Args:
* array:
The :class:`numpy.ndarray` of data to be regridded to the target projection.
* target_proj:
The target :class:`~cartopy.crs.Projection` instance for the data.
Kwargs:
* source_proj:
The source :class:`~cartopy.crs.Projection' instance of the data.
Defaults to a :class:`~cartopy.crs.PlateCarree` projection.
* target_res:
The (nx, yx) resolution of the target projection. Where nx defaults to
400 sample points, and yx defaults to 200 sample points.
* source_extent:
The (x-lower, x-upper, y-lower, y-upper) extent in native
source projection coordinates.
* target_extent:
The (x-lower, x-upper, y-lower, y-upper) extent in native
target projection coordinates.
Returns:
A tuple of the regridded :class:`numpy.ndarray` in the target projection and
the (x-lower, x-upper, y-lower, y-upper) target projection extent.
"""

# source_extent is in source coordinates.
if source_extent is None:
source_extent = [None] * 4
# target_extent is in target coordinates
# target_extent is in target coordinates.
if target_extent is None:
target_extent = [None] * 4

Expand All @@ -134,7 +271,7 @@ def warp_array(array, target_proj, source_proj=None, target_res=(400, 200), sour
source_native_xy = mesh_projection(source_proj, nx, ny,
x_extents=source_x_extents, y_extents=source_y_extents)

# xxx take into account the extents of the original to determine target_extents?
# XXX Take into account the extents of the original to determine target_extents?
target_native_x, target_native_y, extent = mesh_projection(target_proj, target_res[0], target_res[1],
x_extents=target_x_extents, y_extents=target_y_extents)

Expand All @@ -146,6 +283,37 @@ def warp_array(array, target_proj, source_proj=None, target_res=(400, 200), sour

def regrid(array, source_x_coords, source_y_coords, source_cs, target_proj,
target_x_points, target_y_points):
"""
Regrid the data array from the source projection to the target projection.
Args:
* array:
The :class:`numpy.ndarray` of data to be regridded to the target projection.
* source_x_coords:
A 2-dimensional source projection :class:`numpy.ndarray` of x-direction sample points.
* source_y_coords:
A 2-dimensional source projection :class:`numpy.ndarray` of y-direction sample points.
* source_cs:
The source :class:`~cartopy.crs.Projection` instance.
* target_cs:
The target :class:`~cartopy.crs.Projection` instance.
* target_x_points:
A 2-dimensional target projection :class:`numpy.ndarray` of x-direction sample points.
* target_y_points:
A 2-dimensional target projection :class:`numpy.ndarray` of y-direction sample points.
Returns:
The data array regridded in the target projection.
"""

# n.b. source_cs is actually a projection (the coord system of the
# source coordinates), but not necessarily the native projection of
# the source array (i.e. you can provide a warped image with lat lon
Expand Down

0 comments on commit 762fe51

Please sign in to comment.