def get_scale(dataset, variable, depth, timestamp, projection, extent, interp, radius, neighbours): """ Calculates and returns the range (min, max values) of a selected variable, given the current map extents. """ x = np.linspace(extent[0], extent[2], 50) y = np.linspace(extent[1], extent[3], 50) xx, yy = np.meshgrid(x, y) dest = Proj(init=projection) lon, lat = dest(xx, yy, inverse=True) variables = variable.split(",") config = DatasetConfig(dataset) with open_dataset(config, variable=variables, timestamp=timestamp) as ds: d = ds.get_area(np.array([lat, lon]), depth, timestamp, variables[0], interp, radius, neighbours) if len(variables) > 1: d0 = d d1 = ds.get_area(np.array([lat, lon]), depth, timestamp, variables[1], interp, radius, neighbours) d = __magnitude(d0, d1) # Use your dot-product instead of exponents return normalize_scale(d, config.variable[",".join(variables)])
def __add_surface_plot(self, axis_divider): ax = axis_divider.append_axes("top", size="35%", pad=0.35) ax.plot(self.surface_data['distance'], self.surface_data['data'], color='r') ax.locator_params(nbins=3) ax.yaxis.tick_right() ax.yaxis.set_label_position("right") label = plt.ylabel(utils.mathtext(self.surface_data['unit'])) title = plt.title(self.surface_data['name'], y=1.1) plt.setp(title, size='smaller') plt.setp(label, size='smaller') plt.setp(ax.get_yticklabels(), size='x-small') plt.xlim([0, self.surface_data['distance'][-1]]) plt.ylim(utils.normalize_scale(self.surface_data['data'], self.surface_data['config'])) ax.yaxis.grid(True) ax.axes.get_xaxis().set_visible(False)
def get_scale(dataset, variable, depth, time, projection, extent, interp, radius, neighbours): x = np.linspace(extent[0], extent[2], 50) y = np.linspace(extent[1], extent[3], 50) xx, yy = np.meshgrid(x, y) dest = Proj(init=projection) lon, lat = dest(xx, yy, inverse=True) variables = variable.split(",") config = DatasetConfig(dataset) with open_dataset(config) as ds: timestamp = ds.timestamps[time] d = ds.get_area(np.array([lat, lon]), depth, time, variables[0], interp, radius, neighbours) if len(variables) > 1: d0 = d d1 = ds.get_area(np.array([lat, lon]), depth, time, variables[1], interp, radius, neighbours) d = np.sqrt(d0**2 + d1**2) return normalize_scale(d, config.variable[",".join(variables)])
def plot(self): gs, fig, velocity = self.gridSetup() # Plot the transect on a map if self.showmap: plt.subplot(gs[0, 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) # 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, data, name, cmapLabel, vmin, vmax, units, cmap): plt.subplot(subplots[map_subplot[0], map_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)) # Creates and places the plots def velocity_plot(): Row = 0 if self.showmap: Col = 1 else: Col = 0 if self.selected_velocity_plots[0] == 1: do_plot( gs, [Row, Col], self.transect_data['magnitude'], gettext("Magnitude") + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Magnitude"), vmin, vmax, self.transect_data['unit'], self.cmap) Row += 1 if self.selected_velocity_plots[1] == 1: do_plot( gs, [Row, Col], self.transect_data['parallel'], self.transect_data['name'] + " (" + gettext("Parallel") + ")" + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Parallel"), vmin, vmax, self.transect_data['unit'], self.cmap) Row += 1 if self.selected_velocity_plots[2] == 1: do_plot( gs, [Row, Col], self.transect_data['perpendicular'], self.transect_data['name'] + " (" + gettext("Perpendicular") + ")" + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Perpendicular"), vmin, vmax, self.transect_data['unit'], self.cmap) # Plot Transects # If in compare mode Type = ['magnitude', 'parallel', 'perpendicular'] 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 if self.showmap: Col = 1 else: Col = 0 do_plot( gs, [0, Col], self.transect_data['parallel'], self.transect_data['name'] + " (" + gettext("Parallel") + ")" + gettext(" for ") + self.date_formatter(self.timestamp), gettext("Parallel"), vmin, vmax, self.transect_data['unit'], self.cmap) Col += 1 do_plot( gs, [0, Col], self.transect_data['perpendicular'], self.transect_data['name'] + " (" + gettext("Perpendicular") + ")" + 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']) if self.showmap: Col = 1 else: Col = 0 do_plot( gs, [1, Col], self.compare['parallel'], self.transect_data['name'] + " (" + gettext("Parallel") + ")" + gettext(" for ") + self.date_formatter(self.compare['date']), gettext("Parallel"), vmin, vmax, self.transect_data['unit'], cmap) Col += 1 do_plot( gs, [1, Col], self.compare['perpendicular'], self.transect_data['name'] + " (" + gettext("Perpendicular") + ")" + gettext(" for ") + self.date_formatter(self.compare['date']), gettext("Perpendicular"), vmin, vmax, self.transect_data['unit'], cmap) else: vmin, vmax = utils.normalize_scale( self.transect_data['data'], self.dataset_config.variable[self.variables[0]]) # Render primary/Left Map if self.showmap: Col = 1 else: Col = 0 do_plot( gs, [0, Col], 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 = utils.normalize_scale( self.transect_data['compare_data'], self.compare_config.variable[",".join( self.compare['variables'])]) if self.showmap: Col = 1 else: Col = 0 do_plot( gs, [1, Col], 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) if self.showmap: Col = 1 else: Col = 0 do_plot( gs, [2, Col], 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 3 possible components if velocity: if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin = min(np.amin(self.transect_data['magnitude']), np.amin(self.transect_data['parallel']), np.amin(self.transect_data['perpendicular'])) vmax = max(np.amax(self.transect_data['magnitude']), np.amax(self.transect_data['parallel']), np.amin(self.transect_data['perpendicular'])) vmin = min(vmin, -vmax) vmax = max(vmax, -vmin) Row = 0 velocity_plot() # All other variables have 1 component else: if self.showmap: Col = 1 else: Col = 0 if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin, vmax = utils.normalize_scale( self.transect_data['data'], self.dataset_config.variable[self.variables[0]]) do_plot( gs, [0, Col], 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 if self.plotTitle is None or self.plotTitle == "": fig.suptitle("Transect Data for:\n%s" % (self.name), fontsize=15) else: fig.suptitle(self.plotTitle, 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)
def plot(self): if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin, vmax = utils.normalize_scale( self.data, self.dataset_config.variable[self.variables[0]]) if self.cmap is None: self.cmap = colormap.find_colormap(self.variable_name) datenum = matplotlib.dates.date2num(self.times) if self.depth == 'all': size = list(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: # Create base figure figure_size = self.figuresize figure_size[0] *= 1.5 if self.showmap else 1.0 fig = plt.figure(figsize=figure_size, dpi=self.dpi) # Setup figure layout width = 1 if self.showmap: width += 1 # Horizontally scale the actual plots by 2x the size of # the location map width_ratios = [1, 2] else: width_ratios = None # Create layout helper gs = gridspec.GridSpec(1, width, width_ratios=width_ratios) subplot = 0 # Render point location if self.showmap: plt.subplot(gs[0, 0]) subplot += 1 utils.point_plot( np.array([ [x[0] for x in self.points], # Latitudes [x[1] for x in self.points] ])) # Longitudes plt.subplot(gs[:, subplot]) plt.plot_date(datenum, np.squeeze(self.data), fmt='-', figure=fig, xdate=True) plt.ylabel( f"{self.variable_name.title()} ({utils.mathtext(self.variable_unit)})", fontsize=14) plt.ylim(vmin, vmax) # Title if self.plotTitle is None or self.plotTitle == "": wrapped_title = wrap( "%s%s at %s" % (self.variable_name.title(), self.depth_label, ", ".join(self.names)), 80) plt.title("\n".join(wrapped_title), fontsize=15) else: plt.title(self.plotTitle, fontsize=15) plt.gca().grid(True) fig.autofmt_xdate() self.plot_legend(fig, self.names) return super(TimeseriesPlotter, self).plot(fig)
def plot(self): def get_depth_label(depthValue, depthUnit): if depthValue == "bottom": return " at Bottom" return " at %s %s" % (depthValue, depthUnit) # Figure size figuresize = list(map(float, self.size.split("x"))) # Vertical scaling of figure figuresize[1] *= 1.5 if self.compare else 1 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 utils.path_plot(self.path_points, gs[:, 0]) # Calculate variable range if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin, vmax = utils.normalize_scale( self.data, self.dataset_config.variable[self.variables[0]]) 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.iso_timestamps, 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([ re.search(x, self.compare["variable_name"], re.IGNORECASE) for x in ["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 if self.plotTitle: fig.suptitle(gettext("Hovm\xf6ller Diagram(s) for:\n%s") % (self.name), fontsize=15) else: fig.suptitle(self.plotTitle, 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 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 = np.array([self.longitude[0, 0], self.longitude[-1, -1]]) y = np.array([self.latitude[0, 0], self.latitude[-1, -1]]) outRasterSRS = osr.SpatialReference() pts = self.plot_projection.transform_points( self.pc_projection, x, y) x = pts[:, 0] y = pts[:, 1] outRasterSRS.ImportFromProj4(self.plot_projection.proj4_init) 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(np.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", encoding="latin-1") as f: buf = f.read() os.remove(fname) return (buf, self.mime, self.filename.replace(".geotiff", ".tif")) # Figure size figuresize = list(map(float, self.size.split("x"))) fig, map_plot = basemap.load_map( self.plot_projection, self.plot_extent, figuresize, self.dpi, self.plot_res, ) ax = plt.gca() if self.scale: vmin = self.scale[0] vmax = self.scale[1] else: vmin, vmax = utils.normalize_scale( self.data, self.dataset_config.variable[f"{self.variables[0]}"]) c = map_plot.imshow( self.data, vmin=vmin, vmax=vmax, cmap=self.cmap, extent=self.plot_extent, transform=self.plot_projection, origin="lower", zorder=0, ) if len(self.quiver_data) == 2: qx, qy = self.quiver_data qx, qy = self.plot_projection.transform_vectors( self.pc_projection, self.quiver_longitude, self.quiver_latitude, qx, qy) pts = self.plot_projection.transform_points( self.pc_projection, self.quiver_longitude, self.quiver_latitude) x = pts[:, :, 0] y = pts[:, :, 1] qx = np.ma.masked_where(np.ma.getmask(self.quiver_data[0]), qx) qy = np.ma.masked_where(np.ma.getmask(self.quiver_data[1]), qy) if self.quiver["magnitude"] != "length": qx = qx / self.quiver_magnitude qy = qy / self.quiver_magnitude 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 = map_plot.quiver( x, y, qx, qy, self.quiver_magnitude, width=0.0035, headaxislength=4, headlength=4, scale=qscale, pivot="mid", cmap=qcmap, transform=self.plot_projection, ) else: q = map_plot.quiver( x, y, qx, qy, width=0.0025, headaxislength=4, headlength=4, scale=qscale, pivot="mid", transform=self.plot_projection, zorder=6, ) if self.quiver["magnitude"] == "length": unit_length = np.mean(self.quiver_magnitude) * 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, 0.65, 0.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 = map_plot.contour( self.longitude, self.latitude, self.bathymetry, linewidths=0.5, norm=FuncNorm((lambda x: np.log10(x), lambda x: 10**x), vmin=1, vmax=6000), cmap="Greys", levels=[100, 200, 500, 1000, 2000, 3000, 4000, 5000, 6000], transform=self.pc_projection, zorder=4, ) plt.clabel(cs, fontsize="x-large", 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() coords_transform = self.plot_projection.transform_points( self.pc_projection, coords[1], coords[0]) mx = coords_transform[:, 0] my = coords_transform[:, 1] map_coords = list(zip(mx, my)) polys.append(Polygon(map_coords)) paths = [] for poly in polys: paths.append(poly.get_path()) path = Path.make_compound_path(*paths) for ec, lw in zip(["w", "k"], [5, 3]): poly = PathPatch( path, fill=None, edgecolor=ec, linewidth=lw, transform=self.plot_projection, zorder=3, ) map_plot.add_patch(poly) if self.names is not None and len(self.names) > 1: for idx, name in enumerate(self.names): pts = self.plot_projection.transform_points( self.pc_projection, self.centroids[idx].x, self.centroids[idx].y) x = pts[:, 0] y = pts[:, 1] 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.dataset_config.variable[self.contour["variable"]], ) 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 = map_plot.contour( self.longitude, self.latitude, self.contour_data[0], linewidths=2, levels=levels, cmap=cmap, transform=self.pc_projection, zorder=5, ) else: hatches = [ "//", "xx", "\\\\", "--", "||", "..", "oo", "**" ] if len(levels) + 1 < len(hatches): hatches = hatches[0:len(levels) + 2] map_plot.contour( self.longitude, self.latitude, self.contour_data[0], linewidths=1, levels=levels, colors="k", transform=self.pc_projection, zorder=5, ) contours = map_plot.contourf( self.longitude, self.latitude, self.contour_data[0], colors=["none"], levels=levels, hatches=hatches, vmin=cmin, vmax=cmax, extend="both", transform=self.pc_projection, zorder=5, ) 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) title = self.plotTitle if self.plotTitle is None or self.plotTitle == "": 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()) axpos = map_plot.get_position() pos_x = axpos.x0 + axpos.width + 0.01 pos_y = axpos.y0 cax = fig.add_axes([pos_x, pos_y, 0.03, axpos.height]) bar = plt.colorbar(c, cax=cax) bar.set_label( "%s (%s)" % (self.variable_name.title(), utils.mathtext(self.variable_unit)), fontsize=14, ) if (self.quiver is not None and self.quiver["variable"] != "" and self.quiver["variable"] != "none" and self.quiver["magnitude"] == "color"): pos_x = axpos.x0 pos_y = axpos.y0 - 0.05 bax = fig.add_axes([pos_x, pos_y, axpos.width, 0.03]) qbar = plt.colorbar(q, orientation="horizontal", cax=bax) qbar.set_label( self.quiver_name.title() + " " + utils.mathtext(self.quiver_unit), fontsize=14, ) return super(MapPlotter, self).plot(fig)
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', encoding="latin-1") as f: buf = f.read() os.remove(fname) return (buf, self.mime, self.filename.replace(".geotiff", ".tif")) # Figure size figuresize = list(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.compare: 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 qx, qy, x, y = self.basemap.rotate_vector(qx, qy, self.quiver_longitude, self.quiver_latitude, returnxy=True) 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( x, y, qx, qy, quiver_mag, width=0.0035, headaxislength=4, headlength=4, scale=qscale, pivot='mid', cmap=qcmap, ) else: q = self.basemap.quiver( x, y, qx, qy, 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, linewidths=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 = list(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='#ffffff', linewidth=5) plt.gca().add_patch(poly) poly = PathPatch(path, fill=None, edgecolor='k', linewidth=2) 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) title = self.plotTitle if self.plotTitle is None or self.plotTitle == "": 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)), fontsize=14) 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), fontsize=14) fig.tight_layout(pad=3, w_pad=4) return super(MapPlotter, self).plot(fig)