def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as dataset: latvar, lonvar = utils.get_latlon_vars(dataset) if self.depth: if self.depth == 'bottom': self.depth_value = 'Bottom' self.depth_unit = '' else: self.depth = np.clip(int(self.depth), 0, len(dataset.depths) - 1) self.depth_value = np.round(dataset.depths[self.depth]) self.depth_unit = "m" else: self.depth_value = 0 self.depth_unit = "m" self.fix_startend_times(dataset) time = range(self.starttime, self.endtime + 1) if len(self.variables) > 1: v = [] for name in self.variables: pts, distance, t, value = dataset.get_path( self.points, self.depth, time, name ) v.append(value ** 2) value = np.sqrt(np.ma.sum(v, axis=0)) else: pts, distance, t, value = dataset.get_path( self.points, self.depth, time, self.variables[0] ) self.path_points = pts self.distance = distance variable_names = self.get_variable_names(dataset, self.variables) variable_units = self.get_variable_units(dataset, self.variables) scale_factors = self.get_variable_scale_factors(dataset, self.variables) self.variable_unit, self.data = self.kelvin_to_celsius( variable_units[0], value ) self.data = np.multiply(self.data, scale_factors[0]) self.variable_name = variable_names[0] self.data = self.data.transpose() if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) self.times = dataset.timestamps[self.starttime:self.endtime + 1]
def scale(args): dataset_name = args.get('dataset') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] variable = args.get('variable') if variable.endswith('_anom'): variable = variable[0:-5] anom = True else: anom = False variable = variable.split(',') with open_dataset(get_dataset_url(dataset_name)) as dataset: variable_unit = get_variable_unit(dataset_name, dataset.variables[variable[0]]) variable_name = get_variable_name(dataset_name, dataset.variables[variable[0]]) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" if anom: cmap = colormap.colormaps['anomaly'] variable_name = gettext("%s Anomaly") % variable_name else: cmap = colormap.find_colormap(variable_name) if len(variable) == 2: if not anom: cmap = colormap.colormaps.get('speed') variable_name = re.sub( r"(?i)( x | y |zonal |meridional |northward |eastward )", " ", variable_name) variable_name = re.sub(r" +", " ", variable_name) fig = plt.figure(figsize=(2, 5), dpi=75) ax = fig.add_axes([0.05, 0.05, 0.25, 0.9]) norm = matplotlib.colors.Normalize(vmin=scale[0], vmax=scale[1]) formatter = ScalarFormatter() formatter.set_powerlimits((-3, 4)) bar = ColorbarBase(ax, cmap=cmap, norm=norm, orientation='vertical', format=formatter) bar.set_label("%s (%s)" % (variable_name.title(), utils.mathtext(variable_unit))) buf = StringIO() try: plt.savefig(buf, format='png', dpi='figure', transparent=False, bbox_inches='tight', pad_inches=0.05) plt.close(fig) return buf.getvalue() finally: buf.close()
def scale(args): dataset_name = args.get('dataset') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] variable = args.get('variable') if variable.endswith('_anom'): variable = variable[0:-5] anom = True else: anom = False variable = variable.split(',') with open_dataset(get_dataset_url(dataset_name)) as dataset: variable_unit = get_variable_unit(dataset_name, dataset.variables[variable[0]]) variable_name = get_variable_name(dataset_name, dataset.variables[variable[0]]) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" if anom: cmap = colormap.colormaps['anomaly'] variable_name = gettext("%s Anomaly") % variable_name else: cmap = colormap.find_colormap(variable_name) if len(variable) == 2: if not anom: cmap = colormap.colormaps.get('speed') variable_name = re.sub( r"(?i)( x | y |zonal |meridional |northward |eastward )", " ", variable_name) variable_name = re.sub(r" +", " ", variable_name) fig = plt.figure(figsize=(2, 5), dpi=75) ax = fig.add_axes([0.05, 0.05, 0.25, 0.9]) norm = matplotlib.colors.Normalize(vmin=scale[0], vmax=scale[1]) formatter = ScalarFormatter() formatter.set_powerlimits((-3, 4)) bar = ColorbarBase(ax, cmap=cmap, norm=norm, orientation='vertical', format=formatter) bar.set_label("%s (%s)" % (variable_name.title(), utils.mathtext(variable_unit))) buf = StringIO() try: plt.savefig(buf, format='png', dpi='figure', transparent=False, bbox_inches='tight', pad_inches=0.05) plt.close(fig) return buf.getvalue() finally: buf.close()
def plot(self): def get_depth_label(depthValue, depthUnit): if depthValue == 'bottom': return " at Bottom" return " at %s %s" % (depthValue, depthUnit) # Figure size figuresize = map(float, self.size.split("x")) figuresize[ 1] *= 1.5 if self.compare else 1 # Vertical scaling of figure fig = plt.figure(figsize=figuresize, dpi=self.dpi) if self.showmap: width = 2 # 2 columns width_ratios = [2, 7] else: width = 1 # 1 column width_ratios = [1] # Setup grid (rows, columns, column/row ratios) depending on view mode if self.compare: # Don't show a difference plot if variables are different if self.compare['variables'][0] == self.variables[0]: gs = gridspec.GridSpec(3, width, width_ratios=width_ratios, height_ratios=[1, 1, 1]) else: gs = gridspec.GridSpec(2, width, width_ratios=width_ratios, height_ratios=[1, 1]) else: gs = gridspec.GridSpec(1, width, width_ratios=width_ratios) if self.showmap: # Plot the path on a map plt.subplot(gs[:, 0]) utils.path_plot(self.path_points) # Calculate variable range if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = np.amin(self.data) vmax = np.amax(self.data) if np.any( map( lambda x: re.search(x, self.variable_name, re. IGNORECASE), ["velocity", "surface height", "wind"])): vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) if len(self.variables) > 1: vmin = 0 # Render self._hovmoller_plot( gs, [0, 1], [0, 0], gettext(self.variable_name), vmin, vmax, self.data, self.times, self.cmap, self.variable_unit, gettext(self.variable_name) + gettext(get_depth_label(self.depth_value, self.depth_unit))) # If in compare mode if self.compare: # Calculate variable range if self.compare['scale']: vmin = self.compare['scale'][0] vmax = self.compare['scale'][1] else: vmin = np.amin(self.compare['data']) vmax = np.amax(self.compare['data']) if np.any( map( lambda x: re.search(x, self.compare['variable_name'], re.IGNORECASE), ["velocity", "surface height", "wind"])): vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) if len(self.compare['variables']) > 1: vmin = 0 self._hovmoller_plot( gs, [1, 1], [1, 0], gettext(self.compare['variable_name']), vmin, vmax, self.compare['data'], self.compare['times'], self.compare['colormap'], self.compare['variable_unit'], gettext(self.compare['variable_name']) + gettext( get_depth_label(self.compare['depth'], self.compare['depth_unit']))) # Difference plot if self.compare['variables'][0] == self.variables[0]: data_difference = self.data - self.compare['data'] vmin = np.amin(data_difference) vmax = np.amax(data_difference) self._hovmoller_plot( gs, [2, 1], [2, 0], gettext(self.compare['variable_name']), vmin, vmax, data_difference, self.compare['times'], colormap.find_colormap("anomaly"), self.compare['variable_unit'], gettext(self.compare['variable_name']) + gettext(" Difference") + gettext( get_depth_label(self.compare['depth'], self.compare['depth_unit']))) # Image title fig.suptitle(gettext(u"Hovm\xf6ller Diagram(s) for:\n%s") % (self.name), fontsize=15) # Subplot padding fig.tight_layout(pad=0, w_pad=4, h_pad=2) fig.subplots_adjust(top=0.9 if self.compare else 0.85) return super(HovmollerPlotter, self).plot(fig)
def load_data(self): if self.projection == 'EPSG:32661': blat = min(self.bounds[0], self.bounds[2]) blat = 5 * np.floor(blat / 5) self.basemap = basemap.load_map('npstere', (blat, 0), None, None) elif self.projection == 'EPSG:3031': blat = max(self.bounds[0], self.bounds[2]) blat = 5 * np.ceil(blat / 5) self.basemap = basemap.load_map('spstere', (blat, 180), None, None) else: distance = VincentyDistance() height = distance.measure( (self.bounds[0], self.centroid[1]), (self.bounds[2], self.centroid[1])) * 1000 * 1.25 width = distance.measure( (self.centroid[0], self.bounds[1]), (self.centroid[0], self.bounds[3])) * 1000 * 1.25 self.basemap = basemap.load_map('lcc', self.centroid, height, width) if self.basemap.aspect < 1: gridx = 500 gridy = int(500 * self.basemap.aspect) else: gridy = 500 gridx = int(500 / self.basemap.aspect) self.longitude, self.latitude = self.basemap.makegrid(gridx, gridy) with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) self.time = np.clip(self.time, 0, len(dataset.timestamps) - 1) self.variable_unit = self.get_variable_units( dataset, self.variables)[0] self.variable_name = self.get_variable_names( dataset, self.variables)[0] scale_factor = self.get_variable_scale_factors( dataset, self.variables)[0] if self.cmap is None: if len(self.variables) == 1: self.cmap = colormap.find_colormap(self.variable_name) else: self.cmap = colormap.colormaps.get('speed') if len(self.variables) == 2: self.variable_name = self.vector_name(self.variable_name) if self.depth == 'bottom': depth_value = 'Bottom' else: self.depth = np.clip(int(self.depth), 0, len(dataset.depths) - 1) depth_value = dataset.depths[self.depth] data = [] allvars = [] for v in self.variables: var = dataset.variables[v] allvars.append(v) if self.filetype in ['csv', 'odv', 'txt']: d, depth_value = dataset.get_area(np.array( [self.latitude, self.longitude]), self.depth, self.time, v, return_depth=True) else: d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v) d = np.multiply(d, scale_factor) self.variable_unit, d = self.kelvin_to_celsius( self.variable_unit, d) 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))) + " m" if len(data) == 2: data[0] = np.sqrt(data[0]**2 + data[1]**2) self.data = data[0] quiver_data = [] if self.quiver is not None and \ self.quiver['variable'] != '' and \ self.quiver['variable'] != 'none': for v in self.quiver['variable'].split(','): allvars.append(v) var = dataset.variables[v] quiver_unit = get_variable_unit(self.dataset_name, var) quiver_name = get_variable_name(self.dataset_name, var) quiver_lon, quiver_lat = self.basemap.makegrid(50, 50) d = dataset.get_area(np.array([quiver_lat, quiver_lon]), self.depth, self.time, v) quiver_data.append(d) self.quiver_name = self.vector_name(quiver_name) self.quiver_longitude = quiver_lon self.quiver_latitude = quiver_lat self.quiver_unit = quiver_unit self.quiver_data = quiver_data if all( map(lambda v: len(dataset.variables[v].dimensions) == 3, allvars)): 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']) contour_unit = get_variable_unit( self.dataset_name, dataset.variables[self.contour['variable']]) contour_name = get_variable_name( self.dataset_name, dataset.variables[self.contour['variable']]) contour_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.contour['variable']]) contour_unit, d = self.kelvin_to_celsius(contour_unit, d) d = np.multiply(d, contour_factor) contour_data.append(d) self.contour_unit = contour_unit self.contour_name = contour_name self.contour_data = contour_data self.timestamp = dataset.timestamps[self.time] if self.variables != self.variables_anom: self.variable_name += " Anomaly" with open_dataset(get_dataset_climatology( self.dataset_name)) as dataset: data = [] for v in self.variables: var = dataset.variables[v] d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.timestamp.month - 1, v) data.append(d) if len(data) == 2: data = np.sqrt(data[0]**2 + data[1]**2) else: data = data[0] u, data = self.kelvin_to_celsius( dataset.variables[self.variables[0]].unit, data) self.data -= data # Load bathymetry data self.bathymetry = overlays.bathymetry(self.basemap, self.latitude, self.longitude, blur=2) if self.depth != 'bottom' and self.depth != 0: if len(quiver_data) > 0: quiver_bathymetry = overlays.bathymetry( self.basemap, quiver_lat, quiver_lon) self.data[np.where(self.bathymetry < depth_value)] = 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)] = np.ma.masked else: mask = maskoceans(self.longitude, self.latitude, self.data).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(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 = depth_value
def plot(self): if self.filetype == 'geotiff': f, fname = tempfile.mkstemp() os.close(f) driver = gdal.GetDriverByName('GTiff') outRaster = driver.Create(fname, self.latitude.shape[1], self.longitude.shape[0], 1, gdal.GDT_Float64) x = [self.longitude[0, 0], self.longitude[-1, -1]] y = [self.latitude[0, 0], self.latitude[-1, -1]] outRasterSRS = osr.SpatialReference() x, y = self.basemap(x, y) outRasterSRS.ImportFromProj4(self.basemap.proj4string) pixelWidth = (x[-1] - x[0]) / self.longitude.shape[0] pixelHeight = (y[-1] - y[0]) / self.latitude.shape[0] outRaster.SetGeoTransform( (x[0], pixelWidth, 0, y[0], 0, pixelHeight)) outband = outRaster.GetRasterBand(1) d = self.data.astype("Float64") ndv = d.fill_value outband.WriteArray(d.filled(ndv)) outband.SetNoDataValue(ndv) outRaster.SetProjection(outRasterSRS.ExportToWkt()) outband.FlushCache() outRaster = None with open(fname, 'r') as f: buf = f.read() os.remove(fname) return (buf, self.mime, self.filename.replace(".geotiff", ".tif")) # Figure size figuresize = map(float, self.size.split("x")) fig = plt.figure(figsize=figuresize, dpi=self.dpi) ax = plt.gca() if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = np.amin(self.data) vmax = np.amax(self.data) if self.variables != self.variables_anom: vmax = max(abs(vmax), abs(vmin)) vmin = -vmax c = self.basemap.imshow(self.data, vmin=vmin, vmax=vmax, cmap=self.cmap) if len(self.quiver_data) == 2: qx, qy = self.quiver_data quiver_mag = np.sqrt(qx**2 + qy**2) if self.quiver['magnitude'] != 'length': qx = qx / quiver_mag qy = qy / quiver_mag qscale = 50 else: qscale = None if self.quiver['magnitude'] == 'color': if self.quiver['colormap'] is None or \ self.quiver['colormap'] == 'default': qcmap = colormap.colormaps.get('speed') else: qcmap = colormap.colormaps.get(self.quiver['colormap']) q = self.basemap.quiver( self.quiver_longitude, self.quiver_latitude, qx, qy, quiver_mag, latlon=True, width=0.0035, headaxislength=4, headlength=4, scale=qscale, pivot='mid', cmap=qcmap, ) else: q = self.basemap.quiver( self.quiver_longitude, self.quiver_latitude, qx, qy, latlon=True, width=0.0025, headaxislength=4, headlength=4, scale=qscale, pivot='mid', ) if self.quiver['magnitude'] == 'length': unit_length = np.mean(quiver_mag) * 2 unit_length = np.round(unit_length, -int(np.floor(np.log10(unit_length)))) if unit_length >= 1: unit_length = int(unit_length) plt.quiverkey(q, .65, .01, unit_length, self.quiver_name.title() + " " + str(unit_length) + " " + utils.mathtext(self.quiver_unit), coordinates='figure', labelpos='E') if self.show_bathymetry: # Plot bathymetry on top cs = self.basemap.contour( self.longitude, self.latitude, self.bathymetry, latlon=True, lineweight=0.5, norm=LogNorm(vmin=1, vmax=6000), cmap=mcolors.LinearSegmentedColormap.from_list( 'transparent_gray', [(0, 0, 0, 0.5), (0, 0, 0, 0.1)]), levels=[100, 200, 500, 1000, 2000, 3000, 4000, 5000, 6000]) plt.clabel(cs, fontsize='xx-small', fmt='%1.0fm') if self.area and self.show_area: for a in self.area: polys = [] for co in a['polygons'] + a['innerrings']: coords = np.array(co).transpose() mx, my = self.basemap(coords[1], coords[0]) map_coords = zip(mx, my) polys.append(Polygon(map_coords)) paths = [] for poly in polys: paths.append(poly.get_path()) path = concatenate_paths(paths) poly = PathPatch(path, fill=None, edgecolor='k', linewidth=1) plt.gca().add_patch(poly) if self.names is not None and len(self.names) > 1: for idx, name in enumerate(self.names): x, y = self.basemap(self.centroids[idx].y, self.centroids[idx].x) plt.annotate( xy=(x, y), s=name, ha='center', va='center', size=12, # weight='bold' ) if len(self.contour_data) > 0: if (self.contour_data[0].min() != self.contour_data[0].max()): cmin, cmax = utils.normalize_scale(self.contour_data[0], self.contour_name, self.contour_unit) levels = None if self.contour.get('levels') is not None and \ self.contour['levels'] != 'auto' and \ self.contour['levels'] != '': try: levels = list( set([ float(xx) for xx in self.contour['levels'].split(",") if xx.strip() ])) levels.sort() except ValueError: pass if levels is None: levels = np.linspace(cmin, cmax, 5) cmap = self.contour['colormap'] if cmap is not None: cmap = colormap.colormaps.get(cmap) if cmap is None: cmap = colormap.find_colormap(self.contour_name) if not self.contour.get('hatch'): contours = self.basemap.contour(self.longitude, self.latitude, self.contour_data[0], latlon=True, linewidths=2, levels=levels, cmap=cmap) else: hatches = [ '//', 'xx', '\\\\', '--', '||', '..', 'oo', '**' ] if len(levels) + 1 < len(hatches): hatches = hatches[0:len(levels) + 2] self.basemap.contour(self.longitude, self.latitude, self.contour_data[0], latlon=True, linewidths=1, levels=levels, colors='k') contours = self.basemap.contourf(self.longitude, self.latitude, self.contour_data[0], latlon=True, colors=['none'], levels=levels, hatches=hatches, vmin=cmin, vmax=cmax, extend='both') if self.contour['legend']: handles, l = contours.legend_elements() labels = [] for i, lab in enumerate(l): if self.contour.get('hatch'): if self.contour_unit == 'fraction': if i == 0: labels.append( "$x \\leq {0: .0f}\\%$".format( levels[i] * 100)) elif i == len(levels): labels.append("$x > {0: .0f}\\%$".format( levels[i - 1] * 100)) else: labels.append( "${0:.0f}\\% < x \\leq {1:.0f}\\%$". format(levels[i - 1] * 100, levels[i] * 100)) else: if i == 0: labels.append("$x \\leq %.3g$" % levels[i]) elif i == len(levels): labels.append("$x > %.3g$" % levels[i - 1]) else: labels.append("$%.3g < x \\leq %.3g$" % (levels[i - 1], levels[i])) else: if self.contour_unit == 'fraction': labels.append("{0:.0%}".format(levels[i])) else: labels.append( "%.3g %s" % (levels[i], utils.mathtext(self.contour_unit))) ax = plt.gca() if self.contour_unit != 'fraction' and not \ self.contour.get('hatch'): contour_title = "%s (%s)" % (self.contour_name, utils.mathtext( self.contour_unit)) else: contour_title = self.contour_name leg = ax.legend(handles[::-1], labels[::-1], loc='lower left', fontsize='medium', frameon=True, framealpha=0.75, title=contour_title) leg.get_title().set_fontsize('medium') if not self.contour.get('hatch'): for legobj in leg.legendHandles: legobj.set_linewidth(3) # Map Info self.basemap.drawmapboundary(fill_color=(0.3, 0.3, 0.3), zorder=-1) self.basemap.drawcoastlines(linewidth=0.5) self.basemap.fillcontinents(color='grey', lake_color='dimgrey') def find_lines(values): if np.amax(values) - np.amin(values) < 1: return [values.mean()] elif np.amax(values) - np.amin(values) < 25: return np.round( np.arange(np.amin(values), np.amax(values), round(np.amax(values) - np.amin(values)) / 5)) else: return np.arange(round(np.amin(values), -1), round(np.amax(values), -1), 5) parallels = find_lines(self.latitude) meridians = find_lines(self.longitude) self.basemap.drawparallels(parallels, labels=[1, 0, 0, 0], color=(0, 0, 0, 0.5)) self.basemap.drawmeridians(meridians, labels=[0, 0, 0, 1], color=(0, 0, 0, 0.5), latmax=85) area_title = "\n".join(wrap(", ".join(self.names), 60)) + "\n" title = "%s %s %s, %s" % (area_title, self.variable_name.title(), self.depth_label, self.date_formatter(self.timestamp)) plt.title(title.strip()) ax = plt.gca() divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) bar = plt.colorbar(c, cax=cax) bar.set_label( "%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit))) if self.quiver is not None and \ self.quiver['variable'] != '' and \ self.quiver['variable'] != 'none' and \ self.quiver['magnitude'] == 'color': bax = divider.append_axes("bottom", size="5%", pad=0.35) qbar = plt.colorbar(q, orientation='horizontal', cax=bax) qbar.set_label(self.quiver_name.title() + " " + utils.mathtext(self.quiver_unit)) fig.tight_layout(pad=3, w_pad=4) return super(MapPlotter, self).plot(fig)
def load_data(self): distance = VincentyDistance() height = distance.measure( (self.bounds[0], self.centroid[1]), (self.bounds[2], self.centroid[1])) * 1000 * 1.25 width = distance.measure( (self.centroid[0], self.bounds[1]), (self.centroid[0], self.bounds[3])) * 1000 * 1.25 if self.projection == 'EPSG:32661': 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.basemap = basemap.load_map( 'npstere', self.centroid, height, width, min(self.bounds[0], self.bounds[2])) else: self.basemap = basemap.load_map('lcc', self.centroid, height, width) elif self.projection == 'EPSG:3031': near_pole, covers_pole = self.pole_proximity(self.points[0]) blat = max(self.bounds[0], self.bounds[2]) blat = 5 * np.ceil(blat / 5) if ((self.centroid[0] < -80 or self.bounds[1] < -80 or self.bounds[3] < -80) or covers_pole): # is centerered close to the south pole self.basemap = basemap.load_map('spstere', (blat, 180), height, width) else: self.basemap = basemap.load_map( 'lcc', self.centroid, height, width, max(self.bounds[0], self.bounds[2])) elif abs(self.centroid[1] - self.bounds[1]) > 90: height_bounds = [self.bounds[0], self.bounds[2]] width_bounds = [self.bounds[1], self.bounds[3]] height_buffer = (abs(height_bounds[1] - height_bounds[0])) * 0.1 width_buffer = (abs(width_bounds[0] - width_bounds[1])) * 0.1 if abs(width_bounds[1] - width_bounds[0]) > 360: raise ClientError( gettext( "You have requested an area that exceads the width of the world. \ Thinking big is good but plots need to be less the 360 deg wide." )) if height_bounds[1] < 0: height_bounds[1] = height_bounds[1] + height_buffer else: height_bounds[1] = height_bounds[1] + height_buffer if height_bounds[0] < 0: height_bounds[0] = height_bounds[0] - height_buffer else: height_bounds[0] = height_bounds[0] - height_buffer new_width_bounds = [] new_width_bounds.append(width_bounds[0] - width_buffer) new_width_bounds.append(width_bounds[1] + width_buffer) if abs(new_width_bounds[1] - new_width_bounds[0]) > 360: width_buffer = np.floor( (360 - abs(width_bounds[1] - width_bounds[0])) / 2) new_width_bounds[0] = width_bounds[0] - width_buffer new_width_bounds[1] = width_bounds[1] + width_buffer if new_width_bounds[0] < -360: new_width_bounds[0] = -360 if new_width_bounds[1] > 720: new_width_bounds[1] = 720 self.basemap = basemap.load_map( 'merc', self.centroid, (height_bounds[0], height_bounds[1]), (new_width_bounds[0], new_width_bounds[1])) else: self.basemap = basemap.load_map('lcc', self.centroid, height, width) if self.basemap.aspect < 1: gridx = 500 gridy = int(500 * self.basemap.aspect) else: gridy = 500 gridx = int(500 / self.basemap.aspect) self.longitude, self.latitude = self.basemap.makegrid(gridx, gridy) with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) self.time = np.clip(self.time, 0, len(dataset.timestamps) - 1) self.variable_unit = self.get_variable_units( dataset, self.variables)[0] self.variable_name = self.get_variable_names( dataset, self.variables)[0] scale_factor = self.get_variable_scale_factors( dataset, self.variables)[0] if self.cmap is None: if len(self.variables) == 1: self.cmap = colormap.find_colormap(self.variable_name) else: self.cmap = colormap.colormaps.get('speed') if len(self.variables) == 2: self.variable_name = self.vector_name(self.variable_name) if self.depth == 'bottom': depth_value = 'Bottom' else: self.depth = np.clip(int(self.depth), 0, len(dataset.depths) - 1) depth_value = dataset.depths[self.depth] data = [] allvars = [] for v in self.variables: var = dataset.variables[v] allvars.append(v) if self.filetype in ['csv', 'odv', 'txt']: d, depth_value = dataset.get_area(np.array( [self.latitude, self.longitude]), self.depth, self.time, v, self.interp, self.radius, self.neighbours, return_depth=True) else: d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v, self.interp, self.radius, self.neighbours) d = np.multiply(d, scale_factor) self.variable_unit, d = self.kelvin_to_celsius( self.variable_unit, d) 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))) + " m" if len(data) == 2: data[0] = np.sqrt(data[0]**2 + data[1]**2) 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.quiver is not None and \ self.quiver['variable'] != '' and \ self.quiver['variable'] != 'none': for v in self.quiver['variable'].split(','): allvars.append(v) var = dataset.variables[v] quiver_unit = get_variable_unit(self.dataset_name, var) quiver_name = get_variable_name(self.dataset_name, var) quiver_lon, quiver_lat = self.basemap.makegrid(50, 50) d = dataset.get_area( np.array([quiver_lat, quiver_lon]), self.depth, self.time, v, self.interp, self.radius, self.neighbours, ) quiver_data.append(d) # Get the quiver data on the same grid as the main # variable. d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v, self.interp, self.radius, self.neighbours, ) quiver_data_fullgrid.append(d) self.quiver_name = self.vector_name(quiver_name) 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( map(lambda v: len(dataset.variables[v].dimensions) == 3, allvars)): 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, ) contour_unit = get_variable_unit( self.dataset_name, dataset.variables[self.contour['variable']]) contour_name = get_variable_name( self.dataset_name, dataset.variables[self.contour['variable']]) contour_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.contour['variable']]) contour_unit, d = self.kelvin_to_celsius(contour_unit, d) d = np.multiply(d, contour_factor) contour_data.append(d) self.contour_unit = contour_unit self.contour_name = contour_name self.contour_data = contour_data self.timestamp = dataset.timestamps[self.time] if self.compare: self.variable_name += " Difference" with open_dataset(get_dataset_url( self.compare['dataset'])) 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) if len(data) == 2: data = np.sqrt(data[0]**2 + data[1]**2) else: data = data[0] u, data = self.kelvin_to_celsius( dataset.variables[self.compare['variables'][0]].unit, data) self.data -= data # Load bathymetry data self.bathymetry = overlays.bathymetry(self.basemap, self.latitude, self.longitude, blur=2) if self.depth != 'bottom' and self.depth != 0: if len(quiver_data) > 0: quiver_bathymetry = overlays.bathymetry( self.basemap, quiver_lat, quiver_lon) self.data[np.where(self.bathymetry < depth_value)] = 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)] = np.ma.masked else: mask = maskoceans(self.longitude, self.latitude, self.data).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(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 = depth_value
def plot(self): if len(self.variables) > 1: self.variable_name = self.vector_name(self.variable_name) if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = 0 vmax = self.data.max() if self.cmap is None: self.cmap = colormap.colormaps.get('speed') else: if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = self.data.min() vmax = self.data.max() if self.variable_unit == "fraction": vmin = 0 vmax = 1 elif np.any( map( lambda x: re. search(x, self.variable_name, re.IGNORECASE), [ "free surface", "surface height", "velocity", "wind" ])): vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) datenum = matplotlib.dates.date2num(self.times) if self.depth == 'all': size = map(float, self.size.split("x")) numpoints = len(self.points) figuresize = (size[0], size[1] * numpoints) fig, ax = plt.subplots(numpoints, 1, sharex=True, figsize=figuresize, dpi=self.dpi) if not isinstance(ax, np.ndarray): ax = [ax] for idx, p in enumerate(self.points): d = self.data[idx, 0, :] dlim = np.ma.flatnotmasked_edges(d[0, :]) maxdepth = self.depths[dlim[1]].max() mindepth = self.depths[dlim[0]].min() c = ax[idx].pcolormesh(datenum, self.depths[:dlim[1] + 1], d[:, :dlim[1] + 1].transpose(), shading='gouraud', cmap=self.cmap, vmin=vmin, vmax=vmax) ax[idx].invert_yaxis() if maxdepth > LINEAR: ax[idx].set_yscale('symlog', linthreshy=LINEAR) ax[idx].yaxis.set_major_formatter(ScalarFormatter()) if maxdepth > LINEAR: l = 10**np.floor(np.log10(maxdepth)) ax[idx].set_ylim(np.ceil(maxdepth / l) * l, mindepth) ax[idx].set_yticks( list(ax[idx].get_yticks()) + [maxdepth, LINEAR]) else: ax[idx].set_ylim(maxdepth, mindepth) ax[idx].set_ylabel("Depth (%s)" % utils.mathtext(self.depth_unit)) ax[idx].xaxis_date() ax[idx].set_xlim(datenum[0], datenum[-1]) divider = make_axes_locatable(ax[idx]) cax = divider.append_axes("right", size="5%", pad=0.05) bar = plt.colorbar(c, cax=cax) bar.set_label("%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit))) ax[idx].set_title("%s%s at %s" % (self.variable_name.title(), self.depth_label, self.names[idx])) plt.setp(ax[idx].get_xticklabels(), rotation=30) fig.autofmt_xdate() else: fig = plt.figure(figsize=self.figuresize(), dpi=self.dpi) wrapped_title = wrap( "%s%s at %s" % (self.variable_name.title(), self.depth_label, ", ".join(self.names)), 80) plt.title("\n".join(wrapped_title)) plt.plot_date(datenum, self.data[:, 0, :].transpose(), '-', figure=fig) plt.ylabel("%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit))) plt.ylim(vmin, vmax) plt.gca().xaxis.grid(True) plt.gca().yaxis.grid(True) fig.autofmt_xdate() self.plot_legend(fig, self.names) return super(TimeseriesPlotter, self).plot(fig)
def load_data(self): if self.projection == 'EPSG:32661': blat = min(self.bounds[0], self.bounds[2]) blat = 5 * np.floor(blat / 5) self.basemap = basemap.load_map('npstere', (blat, 0), None, None) elif self.projection == 'EPSG:3031': blat = max(self.bounds[0], self.bounds[2]) blat = 5 * np.ceil(blat / 5) self.basemap = basemap.load_map('spstere', (blat, 180), None, None) else: distance = VincentyDistance() height = distance.measure( (self.bounds[0], self.centroid[1]), (self.bounds[2], self.centroid[1]) ) * 1000 * 1.25 width = distance.measure( (self.centroid[0], self.bounds[1]), (self.centroid[0], self.bounds[3]) ) * 1000 * 1.25 self.basemap = basemap.load_map( 'lcc', self.centroid, height, width ) if self.basemap.aspect < 1: gridx = 500 gridy = int(500 * self.basemap.aspect) else: gridy = 500 gridx = int(500 / self.basemap.aspect) self.longitude, self.latitude = self.basemap.makegrid(gridx, gridy) with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) self.time = np.clip(self.time, 0, len(dataset.timestamps) - 1) self.variable_unit = self.get_variable_units( dataset, self.variables )[0] self.variable_name = self.get_variable_names( dataset, self.variables )[0] scale_factor = self.get_variable_scale_factors( dataset, self.variables )[0] if self.cmap is None: if len(self.variables) == 1: self.cmap = colormap.find_colormap(self.variable_name) else: self.cmap = colormap.colormaps.get('speed') if len(self.variables) == 2: self.variable_name = self.vector_name(self.variable_name) if self.depth == 'bottom': depth_value = 'Bottom' else: self.depth = np.clip( int(self.depth), 0, len(dataset.depths) - 1) depth_value = dataset.depths[self.depth] data = [] allvars = [] for v in self.variables: var = dataset.variables[v] allvars.append(v) if self.filetype in ['csv', 'odv', 'txt']: d, depth_value = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v, return_depth=True ) else: d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.time, v ) d = np.multiply(d, scale_factor) self.variable_unit, d = self.kelvin_to_celsius( self.variable_unit, d) 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))) + " m" if len(data) == 2: data[0] = np.sqrt(data[0] ** 2 + data[1] ** 2) self.data = data[0] quiver_data = [] if self.quiver is not None and \ self.quiver['variable'] != '' and \ self.quiver['variable'] != 'none': for v in self.quiver['variable'].split(','): allvars.append(v) var = dataset.variables[v] quiver_unit = get_variable_unit(self.dataset_name, var) quiver_name = get_variable_name(self.dataset_name, var) quiver_lon, quiver_lat = self.basemap.makegrid(50, 50) d = dataset.get_area( np.array([quiver_lat, quiver_lon]), self.depth, self.time, v ) quiver_data.append(d) self.quiver_name = self.vector_name(quiver_name) self.quiver_longitude = quiver_lon self.quiver_latitude = quiver_lat self.quiver_unit = quiver_unit self.quiver_data = quiver_data if all(map(lambda v: len(dataset.variables[v].dimensions) == 3, allvars)): 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'] ) contour_unit = get_variable_unit( self.dataset_name, dataset.variables[self.contour['variable']]) contour_name = get_variable_name( self.dataset_name, dataset.variables[self.contour['variable']]) contour_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.contour['variable']]) contour_unit, d = self.kelvin_to_celsius(contour_unit, d) d = np.multiply(d, contour_factor) contour_data.append(d) self.contour_unit = contour_unit self.contour_name = contour_name self.contour_data = contour_data self.timestamp = dataset.timestamps[self.time] if self.variables != self.variables_anom: self.variable_name += " Anomaly" with open_dataset( get_dataset_climatology(self.dataset_name) ) as dataset: data = [] for v in self.variables: var = dataset.variables[v] d = dataset.get_area( np.array([self.latitude, self.longitude]), self.depth, self.timestamp.month - 1, v ) data.append(d) if len(data) == 2: data = np.sqrt(data[0] ** 2 + data[1] ** 2) else: data = data[0] u, data = self.kelvin_to_celsius( dataset.variables[self.variables[0]].unit, data) self.data -= data # Load bathymetry data self.bathymetry = overlays.bathymetry( self.basemap, self.latitude, self.longitude, blur=2 ) if self.depth != 'bottom' and self.depth != 0: if len(quiver_data) > 0: quiver_bathymetry = overlays.bathymetry( self.basemap, quiver_lat, quiver_lon) self.data[np.where(self.bathymetry < depth_value)] = 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)] = np.ma.masked else: mask = maskoceans(self.longitude, self.latitude, self.data).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( 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 = depth_value
def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) time = np.clip(self.time, 0, len(dataset.timestamps) - 1) for idx, v in enumerate(self.variables): var = dataset.variables[v] if not (set(var.dimensions) & set(dataset.depth_dimensions)): for potential in dataset.variables: if potential in self.variables: continue pot = dataset.variables[potential] if (set(pot.dimensions) & set(dataset.depth_dimensions)): if len(pot.dimensions) > 3: self.variables[idx] = potential.key value = parallel = perpendicular = None variable_names = self.get_variable_names(dataset, self.variables) variable_units = self.get_variable_units(dataset, self.variables) scale_factors = self.get_variable_scale_factors( dataset, self.variables) # Load data sent from primary/Left Map if len(self.variables) > 1: # Only velocity has 2 variables v = [] for name in self.variables: v.append(dataset.variables[name]) distances, times, lat, lon, bearings = geo.path_to_points( self.points, 100) transect_pts, distance, x, dep = dataset.get_path_profile( self.points, time, self.variables[0], 100) transect_pts, distance, y, dep = dataset.get_path_profile( self.points, time, self.variables[1], 100) # Calculate vector components x = np.multiply(x, scale_factors[0]) y = np.multiply(y, scale_factors[1]) r = np.radians(np.subtract(90, bearings)) theta = np.arctan2(y, x) - r mag = np.sqrt(x**2 + y**2) parallel = mag * np.cos(theta) perpendicular = mag * np.sin(theta) else: # Get data for one variable transect_pts, distance, value, dep = dataset.get_path_profile( self.points, time, self.variables[0]) value = np.multiply(value, scale_factors[0]) # Get variable units and convert to Celsius if needed variable_units[0], value = self.kelvin_to_celsius( variable_units[0], value) if len(self.variables) == 2: variable_names[0] = self.vector_name(variable_names[0]) # If a colourmap has not been manually specified by the # Navigator... if self.cmap is None: self.cmap = colormap.find_colormap(variable_names[0]) self.timestamp = dataset.timestamps[int(time)] self.depth = dep self.depth_unit = "m" self.transect_data = { "points": transect_pts, "distance": distance, "data": value, "name": variable_names[0], "unit": variable_units[0], "parallel": parallel, "perpendicular": perpendicular, } if self.surface is not None: surface_pts, surface_dist, t, surface_value = \ dataset.get_path( self.points, 0, time, self.surface, ) surface_unit = get_variable_unit( self.dataset_name, dataset.variables[self.surface]) surface_name = get_variable_name( self.dataset_name, dataset.variables[self.surface]) surface_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.surface]) surface_value = np.multiply(surface_value, surface_factor) surface_unit, surface_value = self.kelvin_to_celsius( surface_unit, surface_value) self.surface_data = { "points": surface_pts, "distance": surface_dist, "data": surface_value, "name": surface_name, "unit": surface_unit } # Load data sent from Right Map (if in compare mode) if self.compare: def interpolate_depths(data, depth_in, depth_out): output = [] for i in range(0, depth_in.shape[0]): f = interp1d( depth_in[i], data[:, i], bounds_error=False, assume_sorted=True, ) output.append( f(depth_out[i].view(np.ma.MaskedArray).filled())) return np.ma.masked_invalid(output).transpose() with open_dataset(get_dataset_url( self.compare['dataset'])) as dataset: # Get and format date self.compare['date'] = np.clip(self.compare['time'], 0, len(dataset.timestamps) - 1) self.compare['date'] = dataset.timestamps[int( self.compare['date'])] # 1 variable if len(self.compare['variables']) == 1: # Get and store the "nicely formatted" string for the variable name self.compare['name'] = self.get_variable_names( dataset, self.compare['variables'])[0] # Find correct colourmap if (self.compare['colormap'] == 'default'): self.compare['colormap'] = colormap.find_colormap( self.compare['name']) else: self.compare['colormap'] = colormap.find_colormap( self.compare['colormap']) climate_points, climate_distance, climate_data, cdep = \ dataset.get_path_profile(self.points, self.compare['time'], self.compare['variables'][0]) # Get variable units and convert to Celsius if needed self.compare['unit'], climate_data = self.kelvin_to_celsius( dataset.variables[self.compare['variables'][0]].unit, climate_data) self.__fill_invalid_shift(climate_data) if (self.depth.shape != cdep.shape) or \ (self.depth != cdep).any(): # Need to interpolate the depths climate_data = interpolate_depths( climate_data, cdep, self.depth) if self.transect_data['data'] is None: self.transect_data['parallel'] -= climate_data self.transect_data['perpendicular'] -= climate_data else: self.transect_data['compare_data'] = climate_data # Velocity variables else: # Get and store the "nicely formatted" string for the variable name self.compare['name'] = self.get_variable_names( dataset, self.compare['variables'])[0] climate_pts, climate_distance, climate_x, cdep = \ dataset.get_path_profile( self.points, self.compare['time'], self.compare['variables'][0], 100 ) climate_pts, climate_distance, climate_y, cdep = \ dataset.get_path_profile( self.points, self.compare['time'], self.compare['variables'][0], 100 ) climate_distances, ctimes, clat, clon, bearings = \ geo.path_to_points(self.points, 100) r = np.radians(np.subtract(90, bearings)) theta = np.arctan2(climate_y, climate_x) - r mag = np.sqrt(climate_x**2 + climate_y**2) if np.all(self.depth != cdep): theta = interpolate_depths(theta, cdep, self.depth) self.__fill_invalid_shift(theta) mag = interpolate_depths(mag, cdep, self.depth) self.__fill_invalid_shift(mag) self.compare['parallel'] = mag * np.cos(theta) self.compare['perpendicular'] = mag * np.sin(theta) """ if self.transect_data['parallel'] is None: self.transect_data['data'] -= mag else: self.transect_data['parallel'] -= climate_parallel self.transect_data['perpendicular'] -= climate_perpendicular """ # Bathymetry with Dataset(app.config['BATHYMETRY_FILE'], 'r') as dataset: bath_x, bath_y = bathymetry(dataset.variables['y'], dataset.variables['x'], dataset.variables['z'], self.points) self.bathymetry = {'x': bath_x, 'y': bath_y}
def plot(self): if len(self.variables) > 1: self.variable_name = self.vector_name(self.variable_name) if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = 0 vmax = self.data.max() if self.cmap is None: self.cmap = colormap.colormaps.get('speed') else: if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = self.data.min() vmax = self.data.max() if self.variable_unit == "fraction": vmin = 0 vmax = 1 elif np.any(map(lambda x: re.search(x, self.variable_name, re.IGNORECASE), [ "free surface", "surface height", "velocity", "wind" ])): vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) datenum = matplotlib.dates.date2num(self.times) if self.depth == 'all': size = map(float, self.size.split("x")) numpoints = len(self.points) figuresize = (size[0], size[1] * numpoints) fig, ax = plt.subplots( numpoints, 1, sharex=True, figsize=figuresize, dpi=self.dpi) if not isinstance(ax, np.ndarray): ax = [ax] for idx, p in enumerate(self.points): d = self.data[idx, 0, :] dlim = np.ma.flatnotmasked_edges(d[0, :]) maxdepth = self.depths[dlim[1]].max() mindepth = self.depths[dlim[0]].min() c = ax[idx].pcolormesh( datenum, self.depths[:dlim[1] + 1], d[ :, :dlim[1] + 1].transpose(), shading='gouraud', cmap=self.cmap, vmin=vmin, vmax=vmax) ax[idx].invert_yaxis() if maxdepth > LINEAR: ax[idx].set_yscale('symlog', linthreshy=LINEAR) ax[idx].yaxis.set_major_formatter(ScalarFormatter()) if maxdepth > LINEAR: l = 10 ** np.floor(np.log10(maxdepth)) ax[idx].set_ylim(np.ceil(maxdepth / l) * l, mindepth) ax[idx].set_yticks( list(ax[idx].get_yticks()) + [maxdepth, LINEAR]) else: ax[idx].set_ylim(maxdepth, mindepth) ax[idx].set_ylabel("Depth (%s)" % utils.mathtext(self.depth_unit)) ax[idx].xaxis_date() ax[idx].set_xlim(datenum[0], datenum[-1]) divider = make_axes_locatable(ax[idx]) cax = divider.append_axes("right", size="5%", pad=0.05) bar = plt.colorbar(c, cax=cax) bar.set_label("%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit))) ax[idx].set_title( "%s%s at %s" % ( self.variable_name.title(), self.depth_label, self.names[idx])) plt.setp(ax[idx].get_xticklabels(), rotation=30) fig.autofmt_xdate() else: fig = plt.figure(figsize=self.figuresize(), dpi=self.dpi) wrapped_title = wrap( "%s%s at %s" % ( self.variable_name.title(), self.depth_label, ", ".join(self.names) ), 80) plt.title("\n".join(wrapped_title)) plt.plot_date( datenum, self.data[:, 0, :].transpose(), '-', figure=fig) plt.ylabel("%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit))) plt.ylim(vmin, vmax) plt.gca().xaxis.grid(True) plt.gca().yaxis.grid(True) fig.autofmt_xdate() self.plot_legend(fig, self.names) return super(TimeseriesPlotter, self).plot(fig)
def load_data(self): with open_dataset(get_dataset_url(self.dataset_name)) as dataset: if self.time < 0: self.time += len(dataset.timestamps) time = np.clip(self.time, 0, len(dataset.timestamps) - 1) for idx, v in enumerate(self.variables): var = dataset.variables[v] if not (set(var.dimensions) & set(dataset.depth_dimensions)): for potential in dataset.variables: if potential in self.variables: continue pot = dataset.variables[potential] if (set(pot.dimensions) & set(dataset.depth_dimensions)): if len(pot.shape) > 3: self.variables[idx] = potential self.variables_anom[idx] = potential value = parallel = perpendicular = None variable_names = self.get_variable_names(dataset, self.variables) variable_units = self.get_variable_units(dataset, self.variables) scale_factors = self.get_variable_scale_factors(dataset, self.variables) if len(self.variables) > 1: v = [] for name in self.variables: v.append(dataset.variables[name]) distances, times, lat, lon, bearings = geo.path_to_points( self.points, 100 ) transect_pts, distance, x, dep = dataset.get_path_profile( self.points, time, self.variables[0], 100) transect_pts, distance, y, dep = dataset.get_path_profile( self.points, time, self.variables[1], 100) x = np.multiply(x, scale_factors[0]) y = np.multiply(y, scale_factors[1]) r = np.radians(np.subtract(90, bearings)) theta = np.arctan2(y, x) - r mag = np.sqrt(x ** 2 + y ** 2) parallel = mag * np.cos(theta) perpendicular = mag * np.sin(theta) else: transect_pts, distance, value, dep = dataset.get_path_profile( self.points, time, self.variables[0]) value = np.multiply(value, scale_factors[0]) variable_units[0], value = self.kelvin_to_celsius( variable_units[0], value ) if len(self.variables) == 2: variable_names[0] = self.vector_name(variable_names[0]) if self.cmap is None: self.cmap = colormap.find_colormap(variable_names[0]) self.timestamp = dataset.timestamps[int(time)] self.depth = dep self.depth_unit = "m" self.transect_data = { "points": transect_pts, "distance": distance, "data": value, "name": variable_names[0], "unit": variable_units[0], "parallel": parallel, "perpendicular": perpendicular, } if self.surface is not None: surface_pts, surface_dist, t, surface_value = \ dataset.get_path( self.points, 0, time, self.surface, ) surface_unit = get_variable_unit( self.dataset_name, dataset.variables[self.surface] ) surface_name = get_variable_name( self.dataset_name, dataset.variables[self.surface] ) surface_factor = get_variable_scale_factor( self.dataset_name, dataset.variables[self.surface] ) surface_value = np.multiply(surface_value, surface_factor) surface_unit, surface_value = self.kelvin_to_celsius( surface_unit, surface_value ) self.surface_data = { "points": surface_pts, "distance": surface_dist, "data": surface_value, "name": surface_name, "unit": surface_unit } if self.variables != self.variables_anom: with open_dataset( get_dataset_climatology(self.dataset_name) ) as dataset: if self.variables[0] in dataset.variables: if len(self.variables) == 1: climate_points, climate_distance, climate_data = \ dataset.get_path_profile(self.points, self.timestamp.month - 1, self.variables[0]) u, climate_data = self.kelvin_to_celsius( dataset.variables[self.variables[0]].unit, climate_data ) self.transect_data['data'] -= - climate_data else: climate_pts, climate_distance, climate_x, cdep = \ dataset.get_path_profile( self.points, self.timestamp.month - 1, self.variables[0], 100 ) climate_pts, climate_distance, climate_y, cdep = \ dataset.get_path_profile( self.points, self.timestamp.month - 1, self.variables[0], 100 ) climate_distances, ctimes, clat, clon, bearings = \ geo.path_to_points(self.points, 100) r = np.radians(np.subtract(90, bearings)) theta = np.arctan2(y, x) - r mag = np.sqrt(x ** 2 + y ** 2) climate_parallel = mag * np.cos(theta) climate_perpendicular = mag * np.sin(theta) self.transect_data['parallel'] -= climate_parallel self.transect_data[ 'perpendicular'] -= climate_perpendicular # Bathymetry with Dataset(app.config['BATHYMETRY_FILE'], 'r') as dataset: bath_x, bath_y = bathymetry( dataset.variables['y'], dataset.variables['x'], dataset.variables['z'], self.points) self.bathymetry = { 'x': bath_x, 'y': bath_y }
def plot(projection, x, y, z, args): lat, lon = get_latlon_coords(projection, x, y, z) if len(lat.shape) == 1: lat, lon = np.meshgrid(lat, lon) dataset_name = args.get('dataset') variable = args.get('variable') if variable.endswith('_anom'): variable = variable[0:-5] anom = True else: anom = False variable = variable.split(',') depth = args.get('depth') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] data = [] with open_dataset(get_dataset_url(dataset_name)) as dataset: if args.get('time') is None or (type(args.get('time')) == str and len(args.get('time')) == 0): time = -1 else: time = int(args.get('time')) t_len = len(dataset.timestamps) while time >= t_len: time -= t_len while time < 0: time += len(dataset.timestamps) timestamp = dataset.timestamps[time] for v in variable: data.append(dataset.get_area( np.array([lat, lon]), depth, time, v )) variable_name = get_variable_name(dataset_name, dataset.variables[variable[0]]) variable_unit = get_variable_unit(dataset_name, dataset.variables[variable[0]]) scale_factor = get_variable_scale_factor( dataset_name, dataset.variables[variable[0]] ) if anom: cmap = colormap.colormaps['anomaly'] else: cmap = colormap.find_colormap(variable_name) if depth != 'bottom': depthm = dataset.depths[depth] else: depthm = 0 if scale_factor != 1.0: for idx, val in enumerate(data): data[idx] = np.multiply(val, scale_factor) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" for idx, val in enumerate(data): data[idx] = np.add(val, -273.15) if len(data) == 1: data = data[0] if len(data) == 2: data = np.sqrt(data[0] ** 2 + data[1] ** 2) if not anom: cmap = colormap.colormaps.get('speed') if anom: with open_dataset(get_dataset_climatology(dataset_name)) as dataset: a = dataset.get_area( np.array([lat, lon]), depth, timestamp.month - 1, v ) data = data - a f, fname = tempfile.mkstemp() os.close(f) data = data.transpose() xpx = x * 256 ypx = y * 256 with Dataset(ETOPO_FILE % (projection, z), 'r') as dataset: bathymetry = dataset["z"][ypx:(ypx + 256), xpx:(xpx + 256)] bathymetry = gaussian_filter(bathymetry, 0.5) data[np.where(bathymetry > -depthm)] = np.ma.masked sm = matplotlib.cm.ScalarMappable( matplotlib.colors.Normalize(vmin=scale[0], vmax=scale[1]), cmap=cmap) img = sm.to_rgba(np.squeeze(data)) im = Image.fromarray((img * 255.0).astype(np.uint8)) im.save(fname, format='png', optimize=True) with open(fname, 'r') as f: buf = f.read() os.remove(fname) return buf
def load_data(self): """ Calculates and returns the depth, depth-value, and depth unit from a given dataset Args: depth: Stored depth information (self.depth or self.compare['depth']) clip_length: How many depth values to clip (usually len(dataset.depths) - 1) dataset: Opened dataset Returns: (depth, depth_value, depth_unit) """ def find_depth(depth, clip_length, dataset): depth_value = 0 depth_unit = "m" if depth: if depth == 'bottom': depth_value = 'Bottom' depth_unit = '' return (depth, depth_value, depth_unit) else: depth = np.clip(int(depth), 0, clip_length) depth_value = np.round(dataset.depths[depth]) depth_unit = "m" return (depth, depth_value, depth_unit) return (depth, depth_value, depth_unit) # Load left/Main Map with open_dataset(get_dataset_url(self.dataset_name)) as dataset: latvar, lonvar = utils.get_latlon_vars(dataset) self.depth, self.depth_value, self.depth_unit = find_depth( self.depth, len(dataset.depths) - 1, dataset) self.fix_startend_times(dataset, self.starttime, self.endtime) time = range(self.starttime, self.endtime + 1) if len(self.variables) > 1: v = [] for name in self.variables: self.path_points, self.distance, t, value = dataset.get_path( self.points, self.depth, time, name) v.append(value**2) value = np.sqrt(np.ma.sum(v, axis=0)) self.variable_name = self.get_variable_names( dataset, self.variables)[0] self.variable_name = self.vector_name(self.variable_name) else: self.path_points, self.distance, t, value = dataset.get_path( self.points, self.depth, time, self.variables[0]) self.variable_name = self.get_variable_names( dataset, self.variables)[0] variable_units = self.get_variable_units(dataset, self.variables) scale_factors = self.get_variable_scale_factors( dataset, self.variables) self.variable_unit, self.data = self.kelvin_to_celsius( variable_units[0], value) self.times = dataset.timestamps[self.starttime:self.endtime + 1] self.data = np.multiply(self.data, scale_factors[0]) self.data = self.data.transpose() # Get colourmap if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) # Load data sent from Right Map (if in compare mode) if self.compare: with open_dataset(get_dataset_url( self.compare['dataset'])) as dataset: latvar, lonvar = utils.get_latlon_vars(dataset) self.compare['depth'], self.compare[ 'depth_value'], self.compare['depth_unit'] = find_depth( self.compare['depth'], len(dataset.depths) - 1, dataset) self.fix_startend_times(dataset, self.compare['starttime'], self.compare['endtime']) time = range(self.compare['starttime'], self.compare['endtime'] + 1) if len(self.compare['variables']) > 1: v = [] for name in self.compare['variables']: path, distance, t, value = dataset.get_path( self.points, self.compare['depth'], time, name) v.append(value**2) value = np.sqrt(np.ma.sum(v, axis=0)) self.compare['variable_name'] = self.get_variable_names( dataset, self.compare['variables'])[0] self.compare['variable_name'] = self.vector_name( self.compare['variable_name']) else: path, distance, t, value = dataset.get_path( self.points, self.compare['depth'], time, self.compare['variables'][0]) self.compare['variable_name'] = self.get_variable_names( dataset, self.compare['variables'])[0] # Colourmap if (self.compare['colormap'] == 'default'): self.compare['colormap'] = colormap.find_colormap( self.compare['variable_name']) else: self.compare['colormap'] = colormap.find_colormap( self.compare['colormap']) variable_units = self.get_variable_units( dataset, self.compare['variables']) scale_factors = self.get_variable_scale_factors( dataset, self.compare['variables']) self.compare['variable_unit'], self.compare[ 'data'] = self.kelvin_to_celsius(variable_units[0], value) self.compare['times'] = dataset.timestamps[ self.compare['starttime']:self.compare['endtime'] + 1] self.compare['data'] = np.multiply(self.compare['data'], scale_factors[0]) self.compare['data'] = self.compare['data'].transpose() # Comparison over different time ranges makes no sense if self.starttime != self.compare['starttime'] or\ self.endtime != self.compare['endtime']: raise ClientError( gettext( "Please ensure the Start Time and End Time for the Left and Right maps are identical." ))
def plot(self): if self.filetype == 'geotiff': f, fname = tempfile.mkstemp() os.close(f) driver = gdal.GetDriverByName('GTiff') outRaster = driver.Create(fname, self.latitude.shape[1], self.longitude.shape[0], 1, gdal.GDT_Float64) x = [self.longitude[0, 0], self.longitude[-1, -1]] y = [self.latitude[0, 0], self.latitude[-1, -1]] outRasterSRS = osr.SpatialReference() x, y = self.basemap(x, y) outRasterSRS.ImportFromProj4(self.basemap.proj4string) pixelWidth = (x[-1] - x[0]) / self.longitude.shape[0] pixelHeight = (y[-1] - y[0]) / self.latitude.shape[0] outRaster.SetGeoTransform((x[0], pixelWidth, 0, y[0], 0, pixelHeight)) outband = outRaster.GetRasterBand(1) d = self.data.astype("Float64") ndv = d.fill_value outband.WriteArray(d.filled(ndv)) outband.SetNoDataValue(ndv) outRaster.SetProjection(outRasterSRS.ExportToWkt()) outband.FlushCache() outRaster = None with open(fname, 'r') as f: buf = f.read() os.remove(fname) return (buf, self.mime, self.filename.replace(".geotiff", ".tif")) # Figure size figuresize = map(float, self.size.split("x")) fig = plt.figure(figsize=figuresize, dpi=self.dpi) ax = plt.gca() if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = np.amin(self.data) vmax = np.amax(self.data) if self.variables != self.variables_anom: vmax = max(abs(vmax), abs(vmin)) vmin = -vmax c = self.basemap.imshow( self.data, vmin=vmin, vmax=vmax, cmap=self.cmap) if len(self.quiver_data) == 2: qx, qy = self.quiver_data quiver_mag = np.sqrt(qx ** 2 + qy ** 2) if self.quiver['magnitude'] != 'length': qx = qx / quiver_mag qy = qy / quiver_mag qscale = 50 else: qscale = None if self.quiver['magnitude'] == 'color': if self.quiver['colormap'] is None or \ self.quiver['colormap'] == 'default': qcmap = colormap.colormaps.get('speed') else: qcmap = colormap.colormaps.get(self.quiver['colormap']) q = self.basemap.quiver( self.quiver_longitude, self.quiver_latitude, qx, qy, quiver_mag, latlon=True, width=0.0035, headaxislength=4, headlength=4, scale=qscale, pivot='mid', cmap=qcmap, ) else: q = self.basemap.quiver( self.quiver_longitude, self.quiver_latitude, qx, qy, latlon=True, width=0.0025, headaxislength=4, headlength=4, scale=qscale, pivot='mid', ) if self.quiver['magnitude'] == 'length': unit_length = np.mean(quiver_mag) * 2 unit_length = np.round(unit_length, -int(np.floor(np.log10(unit_length)))) if unit_length >= 1: unit_length = int(unit_length) plt.quiverkey(q, .65, .01, unit_length, self.quiver_name.title() + " " + str(unit_length) + " " + utils.mathtext(self.quiver_unit), coordinates='figure', labelpos='E') if self.show_bathymetry: # Plot bathymetry on top cs = self.basemap.contour( self.longitude, self.latitude, self.bathymetry, latlon=True, lineweight=0.5, norm=LogNorm(vmin=1, vmax=6000), cmap=mcolors.LinearSegmentedColormap.from_list( 'transparent_gray', [(0, 0, 0, 0.5), (0, 0, 0, 0.1)] ), levels=[100, 200, 500, 1000, 2000, 3000, 4000, 5000, 6000]) plt.clabel(cs, fontsize='xx-small', fmt='%1.0fm') if self.area and self.show_area: for a in self.area: polys = [] for co in a['polygons'] + a['innerrings']: coords = np.array(co).transpose() mx, my = self.basemap(coords[1], coords[0]) map_coords = zip(mx, my) polys.append(Polygon(map_coords)) paths = [] for poly in polys: paths.append(poly.get_path()) path = concatenate_paths(paths) poly = PathPatch(path, fill=None, edgecolor='k', linewidth=1 ) plt.gca().add_patch(poly) if self.names is not None and len(self.names) > 1: for idx, name in enumerate(self.names): x, y = self.basemap( self.centroids[idx].y, self.centroids[idx].x) plt.annotate( xy=(x, y), s=name, ha='center', va='center', size=12, # weight='bold' ) if len(self.contour_data) > 0: if (self.contour_data[0].min() != self.contour_data[0].max()): cmin, cmax = utils.normalize_scale( self.contour_data[0], self.contour_name, self.contour_unit ) levels = None if self.contour.get('levels') is not None and \ self.contour['levels'] != 'auto' and \ self.contour['levels'] != '': try: levels = list( set( [float(xx) for xx in self.contour['levels'].split(",") if xx.strip()] ) ) levels.sort() except ValueError: pass if levels is None: levels = np.linspace(cmin, cmax, 5) cmap = self.contour['colormap'] if cmap is not None: cmap = colormap.colormaps.get(cmap) if cmap is None: cmap = colormap.find_colormap(self.contour_name) if not self.contour.get('hatch'): contours = self.basemap.contour( self.longitude, self.latitude, self.contour_data[ 0], latlon=True, linewidths=2, levels=levels, cmap=cmap) else: hatches = [ '//', 'xx', '\\\\', '--', '||', '..', 'oo', '**' ] if len(levels) + 1 < len(hatches): hatches = hatches[0:len(levels) + 2] self.basemap.contour( self.longitude, self.latitude, self.contour_data[ 0], latlon=True, linewidths=1, levels=levels, colors='k') contours = self.basemap.contourf( self.longitude, self.latitude, self.contour_data[0], latlon=True, colors=['none'], levels=levels, hatches=hatches, vmin=cmin, vmax=cmax, extend='both') if self.contour['legend']: handles, l = contours.legend_elements() labels = [] for i, lab in enumerate(l): if self.contour.get('hatch'): if self.contour_unit == 'fraction': if i == 0: labels.append("$x \\leq {0: .0f}\\%$". format(levels[i] * 100)) elif i == len(levels): labels.append("$x > {0: .0f}\\%$". format(levels[i - 1] * 100)) else: labels.append( "${0:.0f}\\% < x \\leq {1:.0f}\\%$". format(levels[i - 1] * 100, levels[i] * 100)) else: if i == 0: labels.append("$x \\leq %.3g$" % levels[i]) elif i == len(levels): labels.append("$x > %.3g$" % levels[i - 1]) else: labels.append("$%.3g < x \\leq %.3g$" % (levels[i - 1], levels[i])) else: if self.contour_unit == 'fraction': labels.append("{0:.0%}".format(levels[i])) else: labels.append("%.3g %s" % ( levels[i], utils.mathtext(self.contour_unit) )) ax = plt.gca() if self.contour_unit != 'fraction' and not \ self.contour.get('hatch'): contour_title = "%s (%s)" % ( self.contour_name, utils.mathtext( self.contour_unit) ) else: contour_title = self.contour_name leg = ax.legend(handles[::-1], labels[::-1], loc='lower left', fontsize='medium', frameon=True, framealpha=0.75, title=contour_title) leg.get_title().set_fontsize('medium') if not self.contour.get('hatch'): for legobj in leg.legendHandles: legobj.set_linewidth(3) # Map Info self.basemap.drawmapboundary(fill_color=(0.3, 0.3, 0.3), zorder=-1) self.basemap.drawcoastlines(linewidth=0.5) self.basemap.fillcontinents(color='grey', lake_color='dimgrey') def find_lines(values): if np.amax(values) - np.amin(values) < 1: return [values.mean()] elif np.amax(values) - np.amin(values) < 25: return np.round( np.arange( np.amin(values), np.amax(values), round( np.amax(values) - np.amin(values)) / 5 ) ) else: return np.arange( round(np.amin(values), -1), round(np.amax(values), -1), 5 ) parallels = find_lines(self.latitude) meridians = find_lines(self.longitude) self.basemap.drawparallels( parallels, labels=[1, 0, 0, 0], color=(0, 0, 0, 0.5)) self.basemap.drawmeridians( meridians, labels=[0, 0, 0, 1], color=(0, 0, 0, 0.5), latmax=85) area_title = "\n".join( wrap(", ".join(self.names), 60) ) + "\n" title = "%s %s %s, %s" % ( area_title, self.variable_name.title(), self.depth_label, self.date_formatter(self.timestamp) ) plt.title(title.strip()) ax = plt.gca() divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) bar = plt.colorbar(c, cax=cax) bar.set_label("%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit))) if self.quiver is not None and \ self.quiver['variable'] != '' and \ self.quiver['variable'] != 'none' and \ self.quiver['magnitude'] == 'color': bax = divider.append_axes("bottom", size="5%", pad=0.35) qbar = plt.colorbar(q, orientation='horizontal', cax=bax) qbar.set_label( self.quiver_name.title() + " " + utils.mathtext(self.quiver_unit)) fig.tight_layout(pad=3, w_pad=4) return super(MapPlotter, self).plot(fig)
def plot(projection, x, y, z, args): lat, lon = get_latlon_coords(projection, x, y, z) if len(lat.shape) == 1: lat, lon = np.meshgrid(lat, lon) dataset_name = args.get('dataset') variable = args.get('variable') if variable.endswith('_anom'): variable = variable[0:-5] anom = True else: anom = False variable = variable.split(',') depth = args.get('depth') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] data = [] with open_dataset(get_dataset_url(dataset_name)) as dataset: if args.get('time') is None or (type(args.get('time')) == str and len(args.get('time')) == 0): time = -1 else: time = int(args.get('time')) t_len = len(dataset.timestamps) while time >= t_len: time -= t_len while time < 0: time += len(dataset.timestamps) timestamp = dataset.timestamps[time] for v in variable: data.append(dataset.get_area(np.array([lat, lon]), depth, time, v)) variable_name = get_variable_name(dataset_name, dataset.variables[variable[0]]) variable_unit = get_variable_unit(dataset_name, dataset.variables[variable[0]]) scale_factor = get_variable_scale_factor( dataset_name, dataset.variables[variable[0]]) if anom: cmap = colormap.colormaps['anomaly'] else: cmap = colormap.find_colormap(variable_name) if depth != 'bottom': depthm = dataset.depths[depth] else: depthm = 0 if scale_factor != 1.0: for idx, val in enumerate(data): data[idx] = np.multiply(val, scale_factor) if variable_unit.startswith("Kelvin"): variable_unit = "Celsius" for idx, val in enumerate(data): data[idx] = np.add(val, -273.15) if len(data) == 1: data = data[0] if len(data) == 2: data = np.sqrt(data[0]**2 + data[1]**2) if not anom: cmap = colormap.colormaps.get('speed') if anom: with open_dataset(get_dataset_climatology(dataset_name)) as dataset: a = dataset.get_area(np.array([lat, lon]), depth, timestamp.month - 1, v) data = data - a f, fname = tempfile.mkstemp() os.close(f) data = data.transpose() xpx = x * 256 ypx = y * 256 with Dataset(ETOPO_FILE % (projection, z), 'r') as dataset: bathymetry = dataset["z"][ypx:(ypx + 256), xpx:(xpx + 256)] bathymetry = gaussian_filter(bathymetry, 0.5) data[np.where(bathymetry > -depthm)] = np.ma.masked sm = matplotlib.cm.ScalarMappable(matplotlib.colors.Normalize( vmin=scale[0], vmax=scale[1]), cmap=cmap) img = sm.to_rgba(np.squeeze(data)) im = Image.fromarray((img * 255.0).astype(np.uint8)) im.save(fname, format='png', optimize=True) with open(fname, 'r') as f: buf = f.read() os.remove(fname) return buf
def plot(self): # velocity has 2 variable components (parallel, perpendicular) velocity = len(self.variables) == 2 or \ self.compare and len(self.compare['variables']) == 2 # Setup grid if self.showmap: width = 2 # 2 columns if velocity: if self.compare: width_ratios = [1, 1] else: width_ratios = [2, 7] else: width_ratios = [2, 7] else: if velocity: width = 2 width_ratios = [1, 1] else: width = 1 # 1 column width_ratios = [1] # Setup grid (rows, columns, column/row ratios) depending on view mode figuresize = map(float, self.size.split("x")) if self.compare: figuresize[1] *= len( self.variables) * 3 # Vertical scaling of figure if velocity: figuresize[0] *= 1.25 # Horizontal scaling of figure gs = gridspec.GridSpec(4, width, width_ratios=width_ratios, height_ratios=[1, 1, 1, 1, 1]) else: gs = gridspec.GridSpec(3, width, width_ratios=width_ratios, height_ratios=[1, 1, 1]) else: figuresize[1] *= len(self.variables) * 1.5 if velocity: figuresize[0] *= 1.35 gs = gridspec.GridSpec(2, width, width_ratios=width_ratios, height_ratios=[1, 1]) else: gs = gridspec.GridSpec(1, width, width_ratios=width_ratios) fig = plt.figure(figsize=figuresize, dpi=self.dpi) # Plot the transect on a map if self.showmap: plt.subplot(gs[:, 0]) utils.path_plot(self.transect_data['points']) """ Args: subplots: a GridSpec object (gs) map_subplot: Row number (Note: don't use consecutive rows to allow for expanding figure height) nomap_subplot: Row index of subplot location when "Show Location" is toggled off (consecutive works here) data: Data to be plotted name: subplot title cmapLabel: label for colourmap legend vmin: minimum value for a variable (grabbed from the lowest value of some data) vmax: maxmimum value for a variable (grabbed from the highest value of some data)onstrate a networked Ope units: units for variable (PSU, Celsius, etc) cmap: colormap for variable """ def do_plot(subplots, map_subplot, nomap_subplot, data, name, cmapLabel, vmin, vmax, units, cmap): if self.showmap: plt.subplot(subplots[map_subplot[0], map_subplot[1]]) else: plt.subplot(subplots[nomap_subplot[0], nomap_subplot[1]]) divider = self._transect_plot(data, self.depth, name, vmin, vmax, cmapLabel, units, cmap) if self.surface: self._surface_plot(divider) """ Finds and returns the correct min/max values for the variable scale Args: scale: scale for the left or Right Map (self.scale or self.compare['scale]) data: transect_data Returns: (min, max) """ def find_minmax(scale, data): if scale: return (scale[0], scale[1]) else: return (np.amin(data), np.amax(data)) # Plot Transects # If in compare mode if self.compare: # Velocity has 2 components if velocity: if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = min(np.amin(self.transect_data['parallel']), np.amin(self.transect_data['perpendicular'])) vmax = max(np.amax(self.transect_data['parallel']), np.amin(self.transect_data['perpendicular'])) vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) # Get colormap for variable do_plot( gs, [0, 0], [0, 0], self.transect_data['parallel'], gettext("Parallel Velocity") + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Parallel"), vmin, vmax, self.transect_data['unit'], self.cmap) do_plot( gs, [0, 1], [0, 1], self.transect_data['perpendicular'], gettext("Perpendicular Velocity") + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Perpendicular"), vmin, vmax, self.transect_data['unit'], self.cmap) if len(self.compare['variables']) == 2: if self.compare['scale']: vmin = self.compare['scale'][0] vmax = self.compare['scale'][1] else: vmin = min(np.amin(self.compare['parallel']), np.amin(self.compare['perpendicular'])) vmax = max(np.amax(self.compare['parallel']), np.amin(self.compare['perpendicular'])) vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) # Get colormap for variable cmap = colormap.find_colormap(self.compare['colormap']) do_plot( gs, [1, 0], [1, 0], self.compare['parallel'], gettext("Parallel Velocity") + gettext(" for ") + self.date_formatter(self.compare['date']), gettext("Parallel"), vmin, vmax, self.transect_data['unit'], cmap) do_plot( gs, [1, 1], [1, 1], self.compare['perpendicular'], gettext("Perpendicular Velocity") + gettext(" for ") + self.date_formatter(self.compare['date']), gettext("Perpendicular"), vmin, vmax, self.transect_data['unit'], cmap) else: # Get range min/max vmin, vmax = find_minmax(self.scale, self.transect_data['data']) if re.search("velocity", self.transect_data['name'], re.IGNORECASE): vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) # Render primary/Left Map do_plot( gs, [0, 1], [0, 0], self.transect_data['data'], self.transect_data['name'] + gettext(" for ") + self.date_formatter(self.timestamp), self.transect_data['name'], vmin, vmax, self.transect_data['unit'], self.cmap) # Render Right Map vmin, vmax = find_minmax(self.compare['scale'], self.transect_data['compare_data']) do_plot( gs, [1, 1], [1, 0], self.transect_data['compare_data'], self.compare['name'] + gettext(" for ") + self.date_formatter(self.compare['date']), self.compare['name'], vmin, vmax, self.compare['unit'], self.compare['colormap']) # Show a difference plot if both variables and datasets are the same if self.variables[0] == self.compare['variables'][0]: self.transect_data['difference'] = self.transect_data['data'] - \ self.transect_data['compare_data'] # Calculate variable range if self.compare['scale_diff'] is not None: vmin = self.compare['scale_diff'][0] vmax = self.compare['scale_diff'][1] else: vmin, vmax = find_minmax( self.compare['scale_diff'], self.transect_data['difference']) vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) do_plot( gs, [2, 1], [2, 0], self.transect_data['difference'], self.transect_data['name'] + gettext(" Difference"), self.transect_data['name'], vmin, vmax, self.transect_data[ 'unit'], # Since both variables are the same doesn't matter which view we reference colormap.find_colormap( self.compare['colormap_diff'] ) # Colormap for difference graphs ) # Not comparing else: # Velocity has 2 components if velocity: if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = min(np.amin(self.transect_data['parallel']), np.amin(self.transect_data['perpendicular'])) vmax = max(np.amax(self.transect_data['parallel']), np.amin(self.transect_data['perpendicular'])) vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) do_plot( gs, [0, 1], [0, 0], self.transect_data['parallel'], gettext("Parallel Velocity") + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Parallel"), vmin, vmax, self.transect_data['unit'], self.cmap) do_plot( gs, [1, 1], [0, 1], self.transect_data['perpendicular'], gettext("Perpendicular Velocity") + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Perpendicular"), vmin, vmax, self.transect_data['unit'], self.cmap) # All other variables have 1 component else: if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = np.amin(self.transect_data['data']) vmax = np.amax(self.transect_data['data']) if re.search("velocity", self.transect_data['name'], re.IGNORECASE): vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) do_plot( gs, [0, 1], [0, 0], self.transect_data['data'], self.transect_data['name'] + " for " + self.date_formatter(self.timestamp), self.transect_data['name'], vmin, vmax, self.transect_data['unit'], self.cmap) # Figure title fig.suptitle("Transect Data for:\n%s" % (self.name), fontsize=15) # Subplot padding fig.tight_layout(pad=2, w_pad=2, h_pad=2) fig.subplots_adjust(top=0.90 if self.compare else 0.85) return super(TransectPlotter, self).plot(fig)