From 762fe5116c249a975a7fe85c9f05dbd88d093456 Mon Sep 17 00:00:00 2001 From: Bill Little Date: Thu, 11 Oct 2012 16:20:42 +0100 Subject: [PATCH] Image transform doc-strings. --- lib/cartopy/img_transform.py | 198 ++++++++++++++++++++++++++++++++--- 1 file changed, 183 insertions(+), 15 deletions(-) diff --git a/lib/cartopy/img_transform.py b/lib/cartopy/img_transform.py index 0aacf6cc4..68b1ee073 100644 --- a/lib/cartopy/img_transform.py +++ b/lib/cartopy/img_transform.py @@ -14,7 +14,10 @@ # # You should have received a copy of the GNU Lesser General Public License # along with cartopy. If not, see . +""" +This module contains generic functionality to support Cartopy image transformations. +""" import matplotlib.image import numpy @@ -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)) @@ -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) @@ -97,16 +189,24 @@ 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() @@ -114,10 +214,47 @@ def warp_img(fname, target_proj, source_proj=None, target_res=(400, 200)): 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 @@ -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) @@ -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