def test_array_dims(self): # Source data source_nx = 100 source_ny = 100 source_x = np.linspace(-180.0, 180.0, source_nx).astype(np.float64) source_y = np.linspace(-90, 90.0, source_ny).astype(np.float64) source_x, source_y = np.meshgrid(source_x, source_y) data = np.arange(source_nx * source_ny, dtype=np.int32).reshape(source_ny, source_nx) source_cs = ccrs.Geodetic() # Target grid target_nx = 23 target_ny = 45 target_proj = ccrs.PlateCarree() target_x, target_y, extent = im_trans.mesh_projection( target_proj, target_nx, target_ny) # Perform regrid new_array = im_trans.regrid(data, source_x, source_y, source_cs, target_proj, target_x, target_y) # Check dimensions of return array self.assertEqual(new_array.shape, target_x.shape) self.assertEqual(new_array.shape, target_y.shape) self.assertEqual(new_array.shape, (target_ny, target_nx))
def test_griding_data_outside_projection(): # Data which exists outside the standard projection e.g. [0, 360] rather # than [-180, 180]. target_prj = ccrs.PlateCarree() # create 3 data points lats = np.array([65, 10, -45]) lons = np.array([120, 180, 240]) data = np.array([1, 2, 3]) data_trans = ccrs.Geodetic() target_x, target_y, extent = img_trans.mesh_projection(target_prj, 8, 4) image = img_trans.regrid(data, lons, lats, data_trans, target_prj, target_x, target_y, mask_extrapolated=True) # The expected image. n.b. on a map the data is reversed in the y axis. expected = np.array( [[3, 3, 3, 3, 3, 3, 3, 3], [3, 3, 3, 3, 3, 1, 2, 2], [2, 2, 3, 1, 1, 1, 1, 2], [1, 1, 1, 1, 1, 1, 1, 1]], dtype=np.float64) expected_mask = np.array( [[True, True, True, True, True, True, True, True], [False, False, True, True, True, True, False, False], [False, False, True, True, True, True, False, False], [True, True, True, True, True, True, True, True]]) assert_array_equal([-180, 180, -90, 90], extent) assert_array_equal(expected, image) assert_array_equal(expected_mask, image.mask)
def test_gridding_data_outside_projection(): # Data which exists outside the standard projection e.g. [0, 360] rather # than [-180, 180]. target_prj = ccrs.PlateCarree() # create 3 data points lats = np.array([65, 10, -45]) lons = np.array([120, 180, 240]) data = np.array([1, 2, 3]) data_trans = ccrs.Geodetic() target_x, target_y, extent = img_trans.mesh_projection(target_prj, 8, 4) image = img_trans.regrid(data, lons, lats, data_trans, target_prj, target_x, target_y, mask_extrapolated=True) # The expected image. n.b. on a map the data is reversed in the y axis. expected = np.array([[3, 3, 3, 3, 3, 2, 2, 2], [3, 3, 3, 3, 1, 1, 2, 2], [3, 3, 3, 3, 1, 1, 1, 2], [3, 3, 3, 1, 1, 1, 1, 1]], dtype=np.float64) expected_mask = np.array( [[True, True, True, True, True, True, True, True], [False, False, True, True, True, True, False, False], [False, False, True, True, True, True, False, False], [True, True, True, True, True, True, True, True]]) assert_array_equal([-180, 180, -90, 90], extent) assert_array_equal(expected, image) assert_array_equal(expected_mask, image.mask)
def data(self, da, projection): """""" # Reproject the data if projection and (da[self.xname].ndim == 2): projection = getattr(cartopy.crs, projection)() # Set the central longitude (if applicable) if self.c_lon: try: projection = projection.__class__(central_longitude=self.c_lon) except: pass # TODO: Need to detect and add cyclic point insertion x, y = img_transform.mesh_projection(projection, nx=self.nx, ny=self.ny)[:2] field = img_transform.regrid(da.to_masked_array(), da[self.xname].values, da[self.yname].values, self.ref_crs, projection, x, y) plt.gcf().add_subplot(self.subplot, projection=projection) # Subsample the data and plot on grid coords else: # NOTE: Assume here that dims are (y, x); I don't think auto-transpose happens in mpl so should be # obvious from figure if this assumption is wrong da = da[slice(None, None, max(1, da.shape[0] / self.ny)), slice(None, None, max(1, da.shape[1] / self.nx))] x = da[self.xname] y = da[self.yname] field = da.to_masked_array() plt.gcf().add_subplot(self.subplot) return x, y, field
def test_array_dims(self): # Source data source_nx = 100 source_ny = 100 source_x = np.linspace(-180.0, 180.0, source_nx).astype(np.float64) source_y = np.linspace(-90, 90.0, source_ny).astype(np.float64) source_x, source_y = np.meshgrid(source_x, source_y) data = np.arange(source_nx * source_ny, dtype=np.int32).reshape(source_ny, source_nx) source_cs = ccrs.Geodetic() # Target grid target_nx = 23 target_ny = 45 target_proj = ccrs.PlateCarree() target_x, target_y, extent = im_trans.mesh_projection(target_proj, target_nx, target_ny) # Perform regrid new_array = im_trans.regrid(data, source_x, source_y, source_cs, target_proj, target_x, target_y) # Check dimensions of return array self.assertEqual(new_array.shape, target_x.shape) self.assertEqual(new_array.shape, target_y.shape) self.assertEqual(new_array.shape, (target_ny, target_nx))
def test_regrid_image(): # Source data fname = os.path.join(config["repo_data_dir"], 'raster', 'natural_earth', '50-natural-earth-1-downsampled.png') nx = 720 ny = 360 source_proj = ccrs.PlateCarree() source_x, source_y, _ = im_trans.mesh_projection(source_proj, nx, ny) data = plt.imread(fname) # Flip vertically to match source_x/source_y orientation data = data[::-1] # Target grid target_nx = 300 target_ny = 300 target_proj = ccrs.InterruptedGoodeHomolosine(emphasis='land') target_x, target_y, target_extent = im_trans.mesh_projection( target_proj, target_nx, target_ny) # Perform regrid new_array = im_trans.regrid(data, source_x, source_y, source_proj, target_proj, target_x, target_y) # Plot fig = plt.figure(figsize=(10, 10)) gs = mpl.gridspec.GridSpec(nrows=4, ncols=1, hspace=1.5, wspace=0.5) # Set up axes and title ax = fig.add_subplot(gs[0], projection=target_proj) ax.imshow(new_array, origin='lower', extent=target_extent) ax.coastlines() # Plot each color slice (tests masking) cmaps = {'red': 'Reds', 'green': 'Greens', 'blue': 'Blues'} for i, color in enumerate(['red', 'green', 'blue']): ax = fig.add_subplot(gs[i + 1], projection=target_proj) ax.imshow(new_array[:, :, i], extent=target_extent, origin='lower', cmap=cmaps[color]) ax.coastlines() # Tighten up layout gs.tight_layout(fig) return fig
def test_regrid_image(): # Source data fname = os.path.join(config["repo_data_dir"], 'raster', 'natural_earth', '50-natural-earth-1-downsampled.png') nx = 720 ny = 360 source_proj = ccrs.PlateCarree() source_x, source_y, _ = im_trans.mesh_projection(source_proj, nx, ny) data = plt.imread(fname) # Flip vertically to match source_x/source_y orientation data = data[::-1] # Target grid target_nx = 300 target_ny = 300 target_proj = ccrs.InterruptedGoodeHomolosine() target_x, target_y, target_extent = im_trans.mesh_projection(target_proj, target_nx, target_ny) # Perform regrid new_array = im_trans.regrid(data, source_x, source_y, source_proj, target_proj, target_x, target_y) # Plot fig = plt.figure(figsize=(10, 10)) gs = matplotlib.gridspec.GridSpec(nrows=4, ncols=1, hspace=1.5, wspace=0.5) # Set up axes and title ax = plt.subplot(gs[0], frameon=False, projection=target_proj) plt.imshow(new_array, origin='lower', extent=target_extent) ax.coastlines() # Plot each colour slice (tests masking) cmaps = {'red': 'Reds', 'green': 'Greens', 'blue': 'Blues'} for i, colour in enumerate(['red', 'green', 'blue']): ax = plt.subplot(gs[i + 1], frameon=False, projection=target_proj) ax.set_title(colour) plt.imshow(new_array[:, :, i], extent=target_extent, origin='lower', cmap=cmaps[colour]) ax.coastlines() # Tighten up layout gs.tight_layout(plt.gcf())
def test_griding_data(): target_prj = ccrs.PlateCarree() # create 3 data points lats = np.array([45, 20, -45]) lons = np.array([-90, 90, 0]) data = np.array([1, 2, 3]) data_trans = ccrs.Geodetic() target_x, target_y, extent = img_trans.mesh_projection(target_prj, 8, 4) image = img_trans.regrid(data, lons, lats, data_trans, target_prj, target_x, target_y) # The expected image. n.b. on a map the data is reversed in the y axis. expected = np.array( [[3., 3., 3., 3., 3., 3., 3., 3.], [1., 1., 3., 3., 3., 2., 2., 2.], [1., 1., 1., 1., 2., 2., 2., 2.], [1., 1., 1., 1., 1., 2., 2., 1.]], dtype=np.float64) assert_array_equal([-180, 180, -90, 90], extent) assert_array_equal(expected, image)
def test_mesh_projection_extent(xmin, xmax, ymin, ymax): proj = ccrs.PlateCarree() nx = 4 ny = 2 target_x, target_y, extent = img_trans.mesh_projection( proj, nx, ny, x_extents=(xmin, xmax), y_extents=(ymin, ymax)) if xmin is None: xmin = proj.x_limits[0] if xmax is None: xmax = proj.x_limits[1] if ymin is None: ymin = proj.y_limits[0] if ymax is None: ymax = proj.y_limits[1] assert_array_equal(extent, [xmin, xmax, ymin, ymax]) assert_array_equal(np.diff(target_x, axis=1), (xmax - xmin) / nx) assert_array_equal(np.diff(target_y, axis=0), (ymax - ymin) / ny)
def test_griding_data(): target_prj = ccrs.PlateCarree() # create 3 data points lats = np.array([45, 20, -45]) lons = np.array([-90, 90, 0]) data = np.array([1, 2, 3]) data_trans = ccrs.Geodetic() target_x, target_y, extent = img_trans.mesh_projection(target_prj, 8, 4) image = img_trans.regrid(data, lons, lats, data_trans, target_prj, target_x, target_y) # The expected image. n.b. on a map the data is reversed in the y axis. expected = np.array([[3., 3., 3., 3., 3., 3., 3., 3.], [1., 1., 3., 3., 3., 2., 2., 2.], [1., 1., 1., 1., 2., 2., 2., 2.], [1., 1., 1., 1., 1., 2., 2., 1.]], dtype=np.float64) assert_array_equal([-180, 180, -90, 90], extent) assert_array_equal(expected, image)
def __init__(self, data_xx: Optional[Any] = None, data_yy: Optional[Any] = None, src_lon: Optional[Any] = None, src_lat: Optional[Any] = None, dest_lon: Optional[Any] = None, dest_lat: Optional[Any] = None, extent: Optional[Any] = None, dest_crs: Optional[Any] = None, source_crs: Optional[Any] = None, fig: Optional[Any] = None, image_res: Optional[tuple] = (400, 400), extend_x: Optional[Any] = True, extend_y: Optional[Any] = True, average: Optional[Any] = False, smooth_radius: Optional[Any] = None, min_hits: Optional[Any] = 1, missing: Optional[float] = -9999.): from os import linesep as newline import warnings import numpy as np import cartopy.img_transform as cimgt import matplotlib.pyplot as plt #local functions from ._find_nearest import _find_nearest from .lat_lon_extend import lat_lon_extend #check specification of destination grid if (dest_lon is not None) and (dest_lat is not None): #destination lat/lon are provided by user, use those dest_lon = np.asarray(dest_lon) dest_lat = np.asarray(dest_lat) elif (dest_crs is not None): #we are projecting data onto an image, get destination grid from Cartopy delete_dummy_fig = False if fig is None: dummy_fig = plt.figure() delete_dummy_fig = True else: dummy_fig = fig dummy_ax = dummy_fig.add_axes([0., 0., 1., 1.], projection=dest_crs) if extent is not None: dummy_ax.set_extent(extent) dummy_ax.outline_patch.set_linewidth(0) #No axes contour line if extent is not None: #get corners of image in data space transform_data_to_axes = dummy_ax.transData + dummy_ax.transAxes.inverted( ) transform_axes_to_data = transform_data_to_axes.inverted() pts = ((0., 0.), (1., 1.)) pt1, pt2 = transform_axes_to_data.transform(pts) #get regular grid of pts in projected figure units of dest_lon and dest_lat are in dataspace # W-E S-NE see explanation below dest_lon, dest_lat, extent = cimgt.mesh_projection( dest_crs, int(image_res[0]), int(image_res[1]), x_extents=[pt1[0], pt2[0]], y_extents=[pt1[1], pt2[1]]) else: #use default extent for this projection dest_lon, dest_lat, extent = cimgt.mesh_projection( dest_crs, int(image_res[0]), int(image_res[1])) #Image returned by Cartopy is of shape (ny,nx) so that nx corresponds to S-N # with orientation # S #E W # N ...go figure... # #For the result to work with imshow origin=upper + extent obtained from get_extent, We want # N #E W # S # #the following transformation does that. dest_lon = np.rot90(np.transpose(dest_lon)) dest_lat = np.rot90(np.transpose(dest_lat)) ##took me a long while to figure the nx,ny -> ny,nx + transpose/rotation above ##lets keep debugging code around for a little while... #print('before') #print(dest_lon.shape) #print(dest_lat.shape) #print('0,0', dest_lon[0,0] , dest_lat[0,0]) #print('0,n', dest_lon[0,-1], dest_lat[0,-1]) #print('m,0', dest_lon[-1,0], dest_lat[-1,0]) #print('m,n', dest_lon[-1,-1] ,dest_lat[-1,-1]) #print('after') #print(dest_lon.shape) #print(dest_lat.shape) #print('0,0', dest_lon[0,0] , dest_lat[0,0]) #print('0,n', dest_lon[0,-1], dest_lat[0,-1]) #print('m,0', dest_lon[-1,0], dest_lat[-1,0]) #print('m,n', dest_lon[-1,-1] ,dest_lat[-1,-1]) else: raise ValueError( ' The lat/lon of the destination grid must be specified using:' + newline + ' - Directly through the use of the "dest_lat" and "dest_lon" keywords ' + newline + ' - By specifying "dest_crs" and the "extent" keywords of a figure being' + newline + ' generated') #check specification of input grid if (src_lon is not None) and (src_lat is not None): #source grid provided by user, use it pass elif (data_xx is not None) and (data_yy is not None): #old way of providing same info, use those and write a deprecation message src_lon = data_xx src_lat = data_yy warnings.warn( 'The keywords "data_xx" and "data_yy" are deprecated. ' + newline + 'Use keywords "src_lon" and "src_lat" instead ', DeprecationWarning) else: raise ValueError( ' The lat/lon of the source data mush be provided through the "src_lon" and "src_lat" keywords.' ) #insure input coords are numpy arrays np_xx = np.asarray(src_lon) np_yy = np.asarray(src_lat) #only necessary for plotting border # borders make no sense for continuous grids such as global grids # set either extend_x or extend_y = False to skip computation of borders if extend_x and extend_y: #get lat/lon at the border of the domain Note the half dist in the call to lat_lon_extend border_lat2d = np.zeros(np.asarray(np_yy.shape) + 2) border_lon2d = np.zeros(np.asarray(np_xx.shape) + 2) #center contains data lat/lon border_lat2d[1:-1, 1:-1] = np_yy border_lon2d[1:-1, 1:-1] = np_xx #extend left side border_lon2d[1:-1, 0], border_lat2d[1:-1, 0] = lat_lon_extend(np_xx[:, 1], np_yy[:, 1], np_xx[:, 0], np_yy[:, 0], half_dist=True) #extend right side border_lon2d[1:-1, -1], border_lat2d[1:-1, -1] = lat_lon_extend(np_xx[:, -2], np_yy[:, -2], np_xx[:, -1], np_yy[:, -1], half_dist=True) #extend top border_lon2d[0, :], border_lat2d[0, :] = lat_lon_extend( border_lon2d[2, :], border_lat2d[2, :], border_lon2d[1, :], border_lat2d[1, :], half_dist=True) #extend bottom border_lon2d[-1, :], border_lat2d[-1, :] = lat_lon_extend( border_lon2d[-3, :], border_lat2d[-3, :], border_lon2d[-2, :], border_lat2d[-2, :], half_dist=True) #we are only interested in the extended values left = np.flip(border_lon2d[1:-1, 0].flatten()) top = border_lon2d[0, :].flatten() right = border_lon2d[1:-1, -1].flatten() bottom = np.flip(border_lon2d[-1, :]).flatten() border_lons = np.concatenate([ left, top, right, bottom, np.array(left[0], ndmin=1) ]) #last entry is first for a complete polygon left = np.flip(border_lat2d[1:-1, 0].flatten()) top = border_lat2d[0, :].flatten() right = border_lat2d[1:-1, -1].flatten() bottom = np.flip(border_lat2d[-1, :]).flatten() border_lats = np.concatenate( [left, top, right, bottom, np.array(left[0], ndmin=1)]) else: border_lats = None border_lons = None #find proj_ind using _find_nearest if smooth_radius is not None: #when using a smoothing radius, the tree will be used in project_data kdtree, dest_xyz = _find_nearest(src_lon, src_lat, dest_lon, dest_lat, smooth_radius=smooth_radius, extend_x=False, extend_y=False, missing=missing, source_crs=source_crs, dest_crs=dest_crs) elif average: #reverse order since we will likely encounter need multiple data pts per destination grid tile proj_ind = _find_nearest(dest_lon, dest_lat, src_lon, src_lat, extend_x=False, extend_y=False, missing=missing, source_crs=source_crs, dest_crs=dest_crs) else: #regular nearest neighbor search proj_ind = _find_nearest(src_lon, src_lat, dest_lon, dest_lat, extend_x=extend_x, extend_y=extend_y, missing=missing, source_crs=source_crs, dest_crs=dest_crs) #save needed data #data needed for projecting data self.data_shape = np_xx.shape self.dest_shape = dest_lon.shape self.min_hits = min_hits self.missing = missing if smooth_radius is not None: #crs space in meters self.smooth_radius_m = smooth_radius * 1e3 self.kdtree = kdtree self.dest_xyz = dest_xyz self.average = True #uses the averaging mechanism during smoothing self.destLon = dest_lon #need those in project_data when smoothing self.destLat = dest_lat else: self.smooth_radius_m = None self.proj_ind = proj_ind self.average = average #data needed for plotting border self.border_lons = border_lons self.border_lats = border_lats #cleanup if dest_crs: dummy_ax.remove() if delete_dummy_fig: plt.close(dummy_fig)
def load_data(self): width_scale = 1.25 height_scale = 1.25 if self.projection == "EPSG:32661": # north pole projection near_pole, covers_pole = self.pole_proximity(self.points[0]) blat = min(self.bounds[0], self.bounds[2]) blat = 5 * np.floor(blat / 5) if self.centroid[0] > 80 or near_pole or covers_pole: self.plot_projection = ccrs.Stereographic( central_latitude=self.centroid[0], central_longitude=self.centroid[1], ) width_scale = 1.5 else: self.plot_projection = ccrs.LambertConformal( central_latitude=self.centroid[0], central_longitude=self.centroid[1], ) elif self.projection == "EPSG:3031": # south pole projection near_pole, covers_pole = self.pole_proximity(self.points[0]) blat = max(self.bounds[0], self.bounds[2]) blat = 5 * np.ceil(blat / 5) # is centerered close to the south pole if ((self.centroid[0] < -80 or self.bounds[1] < -80 or self.bounds[3] < -80) or covers_pole) or near_pole: self.plot_projection = ccrs.Stereographic( central_latitude=self.centroid[0], central_longitude=self.centroid[1], ) width_scale = 1.5 else: self.plot_projection = ccrs.LambertConformal( central_latitude=self.centroid[0], central_longitude=self.centroid[1], ) elif abs(self.centroid[1] - self.bounds[1]) > 90: if abs(self.bounds[3] - self.bounds[1]) > 360: raise ClientError( gettext( "You have requested an area that exceeds the width \ of the world. Thinking big is good but plots need to \ be less than 360 deg wide.")) self.plot_projection = ccrs.Mercator( central_longitude=self.centroid[1]) else: self.plot_projection = ccrs.LambertConformal( central_latitude=self.centroid[0], central_longitude=self.centroid[1]) proj_bounds = self.plot_projection.transform_points( self.pc_projection, np.array([self.bounds[1], self.bounds[3]]), np.array([self.bounds[0], self.bounds[2]]), ) proj_size = np.diff(proj_bounds, axis=0) width = proj_size[0][0] * width_scale height = proj_size[0][1] * height_scale aspect_ratio = height / width if aspect_ratio < 1: gridx = 500 gridy = int(500 * aspect_ratio) else: gridy = 500 gridx = int(500 / aspect_ratio) self.plot_res = basemap.get_resolution(height, width) x_grid, y_grid, self.plot_extent = cimg_transform.mesh_projection( self.plot_projection, gridx, gridy, x_extents=(-width / 2, width / 2), y_extents=(-height / 2, height / 2), ) latlon_grid = self.pc_projection.transform_points( self.plot_projection, x_grid, y_grid) self.longitude = latlon_grid[:, :, 0] self.latitude = latlon_grid[:, :, 1] variables_to_load = self.variables[:] # we don't want to change self,variables so copy it if self.__load_quiver(): variables_to_load.append(self.quiver["variable"]) with open_dataset(self.dataset_config, variable=variables_to_load, timestamp=self.time) as dataset: self.variable_unit = self.get_variable_units( dataset, self.variables)[0] self.variable_name = self.get_variable_names( dataset, self.variables)[0] if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) if self.depth == "bottom": depth_value_map = "Bottom" else: self.depth = np.clip(int(self.depth), 0, len(dataset.depths) - 1) depth_value = dataset.depths[self.depth] depth_value_map = depth_value data = [] var = dataset.variables[self.variables[0]] if self.filetype in ["csv", "odv", "txt"]: d, depth_value_map = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, self.variables[0], self.interp, self.radius, self.neighbours, return_depth=True, ) else: d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, self.variables[0], self.interp, self.radius, self.neighbours, ) data.append(d) if self.filetype not in ["csv", "odv", "txt"]: if len(var.dimensions) == 3: self.depth_label = "" elif self.depth == "bottom": self.depth_label = " at Bottom" else: self.depth_label = (" at " + str(int(np.round(depth_value_map))) + " m") self.data = data[0] quiver_data = [] # Store the quiver data on the same grid as the main variable. This # will only be used for CSV export. quiver_data_fullgrid = [] if self.__load_quiver(): var = dataset.variables[self.quiver["variable"]] quiver_unit = self.dataset_config.variable[var].unit quiver_name = self.dataset_config.variable[var].name quiver_x_var = self.dataset_config.variable[ var].east_vector_component quiver_y_var = self.dataset_config.variable[ var].north_vector_component quiver_x, quiver_y, _ = cimg_transform.mesh_projection( self.plot_projection, 50, 50, self.plot_extent[:2], self.plot_extent[2:], ) quiver_coords = self.pc_projection.transform_points( self.plot_projection, quiver_x, quiver_y) quiver_lon = quiver_coords[:, :, 0] quiver_lat = quiver_coords[:, :, 1] x_vals = dataset.get_area( np.array([quiver_lat, quiver_lon]), self.depth, self.time, quiver_x_var, self.interp, self.radius, self.neighbours, ) quiver_data.append(x_vals) y_vals = dataset.get_area( np.array([quiver_lat, quiver_lon]), self.depth, self.time, quiver_y_var, self.interp, self.radius, self.neighbours, ) quiver_data.append(y_vals) mag_data = dataset.get_area( np.array([quiver_lat, quiver_lon]), self.depth, self.time, self.quiver["variable"], self.interp, self.radius, self.neighbours, ) self.quiver_magnitude = mag_data # Get the quiver data on the same grid as the main # variable. x_vals = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, quiver_x_var, self.interp, self.radius, self.neighbours, ) quiver_data_fullgrid.append(x_vals) y_vals = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, quiver_y_var, self.interp, self.radius, self.neighbours, ) quiver_data_fullgrid.append(y_vals) self.quiver_name = self.get_variable_names( dataset, [self.quiver["variable"]])[0] self.quiver_longitude = quiver_lon self.quiver_latitude = quiver_lat self.quiver_unit = quiver_unit self.quiver_data = quiver_data self.quiver_data_fullgrid = quiver_data_fullgrid if all([ dataset.variables[v].is_surface_only() for v in variables_to_load ]): self.depth = 0 contour_data = [] if (self.contour is not None and self.contour["variable"] != "" and self.contour["variable"] != "none"): d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, self.contour["variable"], self.interp, self.radius, self.neighbours, ) vc = self.dataset_config.variable[self.contour["variable"]] contour_unit = vc.unit contour_name = vc.name contour_data.append(d) self.contour_unit = contour_unit self.contour_name = contour_name self.contour_data = contour_data self.timestamp = dataset.nc_data.timestamp_to_iso_8601(self.time) if self.compare: self.variable_name += " Difference" compare_config = DatasetConfig(self.compare["dataset"]) with open_dataset( compare_config, variable=self.compare["variables"], timestamp=self.compare["time"], ) as dataset: data = [] for v in self.compare["variables"]: var = dataset.variables[v] d = dataset.get_area( np.array([self.latitude, self.longitude]), self.compare["depth"], self.compare["time"], v, self.interp, self.radius, self.neighbours, ) data.append(d) data = data[0] self.data -= data # Load bathymetry data self.bathymetry = overlays.bathymetry(self.latitude, self.longitude, blur=2) if self.depth != "bottom" and self.depth != 0: if quiver_data: quiver_bathymetry = overlays.bathymetry(quiver_lat, quiver_lon) self.data[np.where( self.bathymetry < depth_value_map)] = np.ma.masked for d in self.quiver_data: d[np.where(quiver_bathymetry < depth_value)] = np.ma.masked for d in self.contour_data: d[np.where(self.bathymetry < depth_value_map)] = np.ma.masked else: mask = maskoceans(self.longitude, self.latitude, self.data, True, "h", 1.25).mask self.data[~mask] = np.ma.masked for d in self.quiver_data: mask = maskoceans(self.quiver_longitude, self.quiver_latitude, d).mask d[~mask] = np.ma.masked for d in contour_data: mask = maskoceans(self.longitude, self.latitude, d).mask d[~mask] = np.ma.masked if self.area and self.filetype in ["csv", "odv", "txt", "geotiff"]: area_polys = [] for a in self.area: rings = [LinearRing(p) for p in a["polygons"]] innerrings = [LinearRing(p) for p in a["innerrings"]] polygons = [] for r in rings: inners = [] for ir in innerrings: if r.contains(ir): inners.append(ir) polygons.append(Poly(r, inners)) area_polys.append(MultiPolygon(polygons)) points = [ Point(p) for p in zip(self.latitude.ravel(), self.longitude.ravel()) ] indicies = [] for a in area_polys: indicies.append( np.where( list(map(lambda p, poly=a: poly.contains(p), points)))[0]) indicies = np.unique(np.array(indicies).ravel()) newmask = np.ones(self.data.shape, dtype=bool) newmask[np.unravel_index(indicies, newmask.shape)] = False self.data.mask |= newmask self.depth_value_map = depth_value_map