def _hovmoller_plot(self, subplot, map_subplot, nomap_subplot, name, vmin, vmax, data, times, cmap, unit, title): if self.showmap: plt.subplot(subplot[map_subplot[0], map_subplot[1]]) else: plt.subplot(subplot[nomap_subplot[0], nomap_subplot[1]]) c = plt.pcolormesh( self.distance, times, data, cmap=cmap, shading='gouraud', # Smooth shading vmin=vmin, vmax=vmax) ax = plt.gca() ax.set_title(title, fontsize=14) # Set title of subplot ax.yaxis_date() ax.yaxis.grid(True) ax.set_facecolor('dimgray') plt.xlabel(gettext("Distance (km)")) plt.xlim([self.distance[0], self.distance[-1]]) divider = make_axes_locatable(plt.gca()) cax = divider.append_axes("right", size="5%", pad=0.05) bar = plt.colorbar(c, cax=cax) bar.set_label("%s (%s)" % (name, utils.mathtext(unit)))
def scale(args): """ Draws the variable scale that is placed over the map. Returns a BytesIO object. """ dataset_name = args.get("dataset") config = DatasetConfig(dataset_name) scale = args.get("scale") scale = [float(component) for component in scale.split(",")] variable = args.get("variable") variable = variable.split(",") if len(variable) > 1: variable_unit = config.variable[",".join(variable)].unit variable_name = config.variable[",".join(variable)].name else: variable_unit = config.variable[variable[0]].unit variable_name = config.variable[variable[0]].name cmap = colormap.find_colormap(variable_name) if len(variable) == 2: cmap = colormap.colormaps.get("speed") 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) if variable_name == "Potential Sub Surface Channel": bar.set_ticks([0, 1], True) bar.set_label("%s (%s)" % (variable_name.title(), utils.mathtext(variable_unit)), fontsize=12) # Increase tick font size bar.ax.tick_params(labelsize=12) buf = BytesIO() plt.savefig( buf, format="png", dpi="figure", transparent=False, bbox_inches="tight", pad_inches=0.05, ) plt.close(fig) buf.seek(0) # Move buffer back to beginning return buf
def scale(args): dataset_name = args.get('dataset') config = DatasetConfig(dataset_name) scale = args.get('scale') scale = [float(component) for component in scale.split(',')] variable = args.get('variable') variable = variable.split(',') with open_dataset(config) as dataset: if len(variable) > 1: variable_unit = config.variable[",".join(variable)].unit variable_name = config.variable[",".join(variable)].name else: variable_unit = config.variable[dataset.variables[ variable[0]]].unit variable_name = config.variable[dataset.variables[ variable[0]]].name cmap = colormap.find_colormap(variable_name) if len(variable) == 2: cmap = colormap.colormaps.get('speed') 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)), fontsize=12) # Increase tick font size bar.ax.tick_params(labelsize=12) buf = BytesIO() plt.savefig(buf, format='png', dpi='figure', transparent=False, bbox_inches='tight', pad_inches=0.05) plt.close(fig) buf.seek(0) # Move buffer back to beginning return buf
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 _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]]) if np.any([re.search(x, self.surface_data['name'], re.IGNORECASE) for x in [ "free surface", "surface height" ]]): ylim = plt.ylim() plt.ylim([min(ylim[0], -ylim[1]), max([-ylim[0], ylim[1]])]) ax.yaxis.grid(True) ax.axes.get_xaxis().set_visible(False)
def _transect_plot(self, values, depths, plotTitle, vmin, vmax, cmapLabel, unit, cmap): self.__fill_invalid_shift(values) dist = np.tile(self.transect_data['distance'], (values.shape[0], 1)) # Plot the data c = plt.pcolormesh( dist, depths.transpose(), values, cmap=cmap, shading='gouraud', # Smooth shading vmin=vmin, vmax=vmax) ax = plt.gca() ax.set_title(plotTitle, fontsize=14) # Set title of subplot ax.invert_yaxis() if self.depth_limit is None or (self.depth_limit is not None and self.linearthresh < self.depth_limit): plt.yscale('symlog', linthreshy=self.linearthresh) ax.yaxis.set_major_formatter(ScalarFormatter()) # Mask out the bottom plt.fill_between(self.bathymetry['x'], self.bathymetry['y'] * -1, plt.ylim()[0], facecolor='dimgray', hatch='xx') ax.set_facecolor('dimgray') plt.xlabel(gettext("Distance (km)")) plt.ylabel(gettext("Depth (m)")) plt.xlim([ self.transect_data['distance'][0], self.transect_data['distance'][-1] ]) # Tighten the y-limits if self.depth_limit: plt.ylim(self.depth_limit, 0) else: deep = np.amax(self.bathymetry['y'] * -1) l = 10**np.floor(np.log10(deep)) plt.ylim(np.ceil(deep / l) * l, 0) ticks = sorted( set(list(plt.yticks()[0]) + [self.linearthresh, plt.ylim()[0]])) if self.depth_limit is not None: ticks = [y for y in ticks if y <= self.depth_limit] plt.yticks(ticks) # Show the linear threshold plt.plot([ self.transect_data['distance'][0], self.transect_data['distance'][-1] ], [self.linearthresh, self.linearthresh], 'k:', alpha=1.0) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad=0.05) bar = plt.colorbar(c, cax=cax) # Append variable units to color scale label bar.set_label(cmapLabel + " (" + utils.mathtext(unit) + ")") if len(self.points) > 2: station_distances = [] current_dist = 0 d = VincentyDistance() for idx, p in enumerate(self.points): if idx == 0: station_distances.append(0) else: current_dist += d.measure(p, self.points[idx - 1]) station_distances.append(current_dist) ax2 = ax.twiny() ax2.set_xticks(station_distances) ax2.set_xlim([ self.transect_data['distance'][0], self.transect_data['distance'][-1] ]) ax2.tick_params('x', length=0, width=0, pad=-3, labelsize='xx-small', which='major') ax2.xaxis.set_major_formatter(StrMethodFormatter("$\u25bc$")) cax = make_axes_locatable(ax2).append_axes("right", size="5%", pad=0.05) bar2 = plt.colorbar(c, cax=cax) bar2.remove() return divider
def plot(self): v = set([]) for idx in self.observation_variable: v.add(self.observation_variable_names[idx]) for n in self.variable_names: v.add(n) numplots = len(v) fig, ax = self.setup_subplots(numplots) data = [] for o in self.observation: d = np.ma.MaskedArray(o['data']) d[np.where(d == '')] = np.ma.masked d = np.ma.masked_invalid(d.filled(np.nan).astype(np.float32)) data.append(d) ureg = pint.UnitRegistry() ax_idx = -1 axis_map = {} unit_map = {} for idx in self.observation_variable: ax_idx += 1 for d in data: if d.shape[1] == 1: style = '.' else: style = '-' ax[ax_idx].plot(d[idx, :, 1], d[idx, :, 0], style) ax[ax_idx].xaxis.set_label_position('top') ax[ax_idx].xaxis.set_ticks_position('top') ax[ax_idx].set_xlabel("%s (%s)" % ( self.observation_variable_names[idx], mathtext(self.observation_variable_units[idx]), )) axis_map[self.observation_variable_names[idx]] = ax[ax_idx] try: if "_" in self.observation_variable_units[idx]: u = self.observation_variable_units[idx].lower().split( "_", 1)[1] else: u = self.observation_variable_units[idx].lower() unit_map[ self.observation_variable_names[idx]] = ureg.parse_units(u) except: unit_map[ self.observation_variable_names[idx]] = ureg.dimensionless for k, v in list(unit_map.items()): if v == ureg.speed_of_light: unit_map[k] = ureg.celsius for idx, var in enumerate(self.variables): if axis_map.get(self.variable_names[idx]) is not None: axis = axis_map.get(self.variable_names[idx]) showlegend = True destunit = unit_map.get(self.variable_names[idx]) else: ax_idx += 1 axis = ax[ax_idx] showlegend = False try: destunit = ureg.parse_units( self.variable_units[idx].lower()) if destunit == ureg.speed_of_light: destunit = ureg.celsius except: destunit = ureg.dimensionless for j in range(0, self.data.shape[0]): try: u = ureg.parse_units(self.variable_units[idx].lower()) if u == ureg.speed_of_light: u = ureg.celsius quan = ureg.Quantity(self.data[j, idx, :], u) except: quan = ureg.Quantity(self.data[j, idx, :], ureg.dimensionless) axis.plot(quan.to(destunit).magnitude, self.depths[j, idx, :]) showlegend = showlegend or len(self.observation) > 1 if not showlegend: axis.xaxis.set_label_position('top') axis.xaxis.set_ticks_position('top') axis.set_xlabel("%s (%s)" % ( self.variable_names[idx], mathtext(self.variable_units[idx]), )) else: l = [] for j in [(gettext("Observed"), self.observation_times), (gettext("Modelled"), self.timestamps)]: for i, name in enumerate(self.names): if len(self.names) == 1: name = "" else: name = name + " " l.append("%s%s (%s)" % (name, j[0], format_datetime(j[1][i]))) leg = axis.legend(l, loc='best') for legobj in leg.legendHandles: legobj.set_linewidth(4.0) ax[0].invert_yaxis() ax[0].set_ylabel(gettext("Depth (m)")) if not self.plotTitle: if len(self.variables) > 0: plt.suptitle("\n".join( wrap( gettext( "Profile for %s, Observed at %s, Modelled at %s") % (", ".join(self.names), format_datetime(self.observation_time), format_datetime(self.timestamp)), 80))) else: plt.suptitle("\n".join( wrap( gettext("Profile for %s (%s)") % (", ".join(self.names), format_datetime(self.observation_time)), 80))) else: plt.suptitle(self.plotTitle, fontsize=15) fig.tight_layout() fig.subplots_adjust(top=0.85) return super(ObservationPlotter, self).plot()
def plot(self): figuresize = list(map(float, self.size.split("x"))) figuresize[1] *= len(self.points) * len(self.depth) fig, ax = plt.subplots(len(self.points) * len(self.depth), 1, sharex=True, figsize=figuresize, dpi=self.dpi) if len(self.points) * len(self.depth) == 1: ax = [ax] if self.data.shape[1] == 2: for idx, p in enumerate(self.points): magnitude = np.sqrt(self.data[idx, 0, :, :]**2 + self.data[idx, 1, :, :]**2) scale = np.mean(magnitude) if scale != 0: scale = np.round(scale, int(-np.floor(np.log10(scale)))) for idx2, d in enumerate(self.depth): datenums = date2num(self.timestamp) a = ax[idx * len(self.points) + idx2] q = a.quiver( datenums, [0] * len(self.timestamp), self.data[idx, 0, idx2, :], self.data[idx, 1, idx2, :], angles='uv', width=0.002, headwidth=0, headlength=0, headaxislength=0, ) a.axes.get_yaxis().set_visible(False) a.axes.get_xaxis().tick_bottom() a.xaxis_date() a.quiverkey( q, 0.1, 0.75, scale, "%.1g %s" % (scale, utils.mathtext(self.variable_units[0]))) dx = datenums[1] - datenums[0] a.set_xlim( [datenums[0] - dx / 2.0, datenums[-1] + dx / 2.0]) a.set_frame_on(False) a.axhline(0, color='grey', ls=':') if self.depth[idx2] == "bottom": depth = "Bottom" else: depth = "%d m" % np.round(self.data_depth[idx, 0, idx2, 0]) if self.plotTitle is None or self.plotTitle == "": a.set_title(gettext("%s at (%s)\n%s") % (self.vector_name(self.variable_names[0]), self.names[idx], depth), fontsize=15) else: a.set_title(self.plotTitle, fontsize=15) plt.setp(plt.gca().get_xticklabels(), rotation=30) fig.tight_layout() return super(StickPlotter, 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): # Create base figure fig = plt.figure(figsize=self.figuresize(), dpi=self.dpi) # Setup figure layout width = len(self.variables) if self.showmap: width += 1 # Horizontally scale the actual plots by 2x the size of # the location map width_ratios = [1] [width_ratios.append(2) for w in range(0, width - 1)] 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, subplot]) subplot += 1 utils.point_plot( np.array([ [x[0] for x in self.points], # Latitudes [x[1] for x in self.points] ])) # Longitudes is_y_label_plotted = False # Create a subplot for each variable selected # Each subplot has all points plotted for idx, v in enumerate(self.variables): plt.subplot(gs[:, subplot]) plt.plot(self.data[:, idx, :].transpose(), self.depths[:, idx, :].transpose()) current_axis = plt.gca() current_axis.xaxis.set_label_position('top') current_axis.xaxis.set_ticks_position('top') current_axis.invert_yaxis() current_axis.grid(True) current_axis.set_xlabel("%s (%s)" % (self.variable_names[idx], utils.mathtext(self.variable_units[idx])), fontsize=14) # Put y-axis label on left-most graph (but after the point location) if not is_y_label_plotted and (subplot == 0 or subplot == 1): current_axis.set_ylabel(gettext("Depth (m)"), fontsize=14) is_y_label_plotted = True if self.compare: xlim = np.abs(plt.gca().get_xlim()).max() plt.gca().set_xlim([-xlim, xlim]) subplot += 1 self.plot_legend(fig, self.names) if self.plotTitle is None or self.plotTitle == "": plt.suptitle("%s(%s)\n%s\n%s" % (gettext("Profile for "), \ ", ".join(self.names), \ ", ".join(self.variable_names), \ self.date_formatter(self.timestamp)), \ fontsize=15) else: plt.suptitle(self.plotTitle, fontsize=15) fig.tight_layout() fig.subplots_adjust(top=(0.8)) return super(ProfilePlotter, self).plot(fig)
def plot(self): if self.showmap: width = 2 width_ratios = [2, 7] else: width = 1 width_ratios = [1] numplots = len(self.variables) + len(self.buoyvariables) if "votemper" in self.variables and "sst" in self.buoyvariables: numplots -= 1 if self.latlon: numplots += 2 figuresize = list(map(float, self.size.split("x"))) figuresize[1] *= numplots fig = plt.figure(figsize=figuresize, dpi=self.dpi) gs = gridspec.GridSpec(numplots, width, width_ratios=width_ratios) if self.showmap: # Plot the path on a map if numplots > 1: plt.subplot(gs[:, 0]) else: plt.subplot(gs[0]) utils.path_plot(self.points[self.start:self.end].transpose(), False) # Plot observed if self.showmap: subplot = 1 subplot_inc = 2 else: subplot = 0 subplot_inc = 1 for j, v in enumerate(self.buoyvariables): ax = plt.subplot(gs[subplot]) subplot += subplot_inc ax.plot(self.times[self.start:self.end], self.data[j][self.start:self.end]) if v == 'sst' and 'votemper' in self.variables: i = self.variables.index('votemper') plt.plot(self.model_times, self.model_data[i]) legend = [self.name] if v == 'sst' and 'votemper' in self.variables: legend = legend + ["%s (Modelled)" % self.name] if 'votemper' in self.variables and v == 'sst': legend = [gettext("Observed"), gettext("Modelled")] if len(legend) > 1: leg = plt.legend(legend, loc='best') for legobj in leg.legendHandles: legobj.set_linewidth(4.0) if self.data_units[j] is not None: plt.ylabel( "%s (%s)" % (self.data_names[j], utils.mathtext(self.data_units[j]))) else: plt.ylabel(self.data_names[j]), plt.setp(ax.get_xticklabels(), rotation=30) for idx, v in enumerate(self.variables): if v == 'votemper' and 'sst' in self.buoyvariables: continue if np.isnan(self.model_data[idx]).all(): continue ax = plt.subplot(gs[subplot]) subplot += subplot_inc ax.plot(self.model_times, self.model_data[idx]) plt.ylabel("%s (%s)" % (self.variable_names[idx], utils.mathtext(self.variable_units[idx]))) plt.setp(ax.get_xticklabels(), rotation=30) # latlon if self.latlon: for j, label in enumerate([ gettext("Latitude (degrees)"), gettext("Longitude (degrees)") ]): plt.subplot(gs[subplot]) subplot += subplot_inc plt.plot(self.times[self.start:self.end], self.points[self.start:self.end, j]) plt.ylabel(label) plt.setp(plt.gca().get_xticklabels(), rotation=30) fig.suptitle( gettext("Drifter Plot (IMEI: %s, WMO: %s)") % (self.imei, self.wmo)) fig.tight_layout(pad=3, w_pad=4) return super(DrifterPlotter, self).plot(fig)
def plot(self): figuresize = list(map(float, self.size.split("x"))) fig = plt.figure(figsize=figuresize, dpi=self.dpi) width = len(self.variables) if self.showmap: width += 1 # Shift graphs to the right gs = gridspec.GridSpec(2, width) subplot = 0 # Render point location if self.showmap: plt.subplot(gs[0, subplot]) subplot += 1 utils.point_plot(np.array([self.latitude, self.longitude])) if len(self.ids) > 1: plt.legend(self.ids, loc='best') plot_label = "" giops_name = gettext("Model") if len(self.additional_model_names) > 0: giops_name = "GIOPS" for idx, v in enumerate(self.variables): plt.subplot(gs[:, subplot]) subplot += 1 handles = [] legend = [] for i in range(0, len(self.forecast_data)): if len(self.ids) > 1: id_label = self.ids[i] + " " else: id_label = "" form = '-' if self.observed_data[i, idx, :].count() < 3: form = 'o-' if self.error in ['climatology', 'observation']: if self.error == 'climatology': plot_label = gettext("Error wrt Climatology") handles.append( plt.plot( self.observed_data[i, idx, :] - self.climatology_data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, gettext("Observed"))) data = self.climatology_data else: plot_label = gettext("Error wrt Observation") data = self.observed_data handles.append( plt.plot( self.forecast_data[i, idx, :] - data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, giops_name)) for j, m in enumerate(self.additional_model_names): handles.append( plt.plot( self.additional_model_data[j, i, idx, :] - data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, m)) if self.error == 'observation' and self.climatology: handles.append( plt.plot( self.climatology_data[i, idx, :] - self.observed_data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, gettext("Climatology"))) lim = np.abs(plt.xlim()).max() plt.xlim([-lim, lim]) else: plot_label = gettext("Class 4") handles.append( plt.plot(self.observed_data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, gettext("Observed"))) handles.append( plt.plot(self.forecast_data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, giops_name)) for j, m in enumerate(self.additional_model_names): handles.append( plt.plot(self.additional_model_data[j, i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, m)) if self.climatology: handles.append( plt.plot(self.climatology_data[i, idx, :], self.depths[i], form)) legend.append("%s %s" % (id_label, gettext("Climatology"))) plt.xlim([np.floor(plt.xlim()[0]), np.ceil(plt.xlim()[1])]) plt.gca().xaxis.set_label_position('top') plt.gca().xaxis.set_ticks_position('top') plt.xlabel("%s (%s)" % (v, utils.mathtext(self.variable_units[idx])), fontsize=14) plt.gca().invert_yaxis() plt.ylabel(gettext("Depth (%s)") % utils.mathtext(self.depth_unit), fontsize=14) plt.grid(True) leg = fig.legend([x[0] for x in handles], legend, loc='lower left', bbox_to_anchor=(0.05, 0.05)) for legobj in leg.legendHandles: legobj.set_linewidth(4.0) names = [ "%s (%0.2f, %0.2f)" % x for x in zip(self.ids, self.latitude, self.longitude) ] plt.suptitle("%s\n%s" % ("\n".join(wrap(", ".join(names), 60)), plot_label), fontsize=15) fig.tight_layout(pad=3, w_pad=4) fig.subplots_adjust(top=0.85) return super(Class4Plotter, 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)
def plot(self): if self.showmap: width = 2 width_ratios = [3, 7] else: width = 1 width_ratios = [1] numplots = len(self.variables) + len(self.trackvariables) if "votemper" in self.variables and "sst" in self.trackvariables: numplots -= 1 if self.latlon: numplots += 2 figuresize = list(map(float, self.size.split("x"))) figuresize[1] *= numplots fig = plt.figure(figsize=figuresize, dpi=self.dpi) gs = gridspec.GridSpec(numplots, width, width_ratios=width_ratios) if self.showmap: # Plot the path on a map if numplots > 1: plt.subplot(gs[:, 0]) else: plt.subplot(gs[0]) utils.path_plot(self.points.transpose(), False) # Plot observed if self.showmap: subplot = 1 subplot_inc = 2 else: subplot = 0 subplot_inc = 1 for j, v in enumerate(self.trackvariables): ax = plt.subplot(gs[subplot]) subplot += subplot_inc # Is the depth changing? if len(np.unique(self.depth)) == 1: ax.plot(self.distances, self.data[j]) ax.set_xlim(self.distances[0], self.distances[-1]) ax.set_xlabel("Distance (km)") else: self.data[j, np.where(self.depth <= 0)] = np.nan RES = (50, 100) dd = np.empty((RES[0] + 1, RES[1] + 1)) dd[:, :] = np.nan x = np.linspace(0, max(self.distances), RES[1]) y = np.linspace(0, max(self.depth), RES[0]) di = np.digitize(self.distances, x) de = np.digitize(self.depth, y) co = np.array(list(zip(di, de))) dd[co[:, 1], co[:, 0]] = self.data[j] c = ax.pcolormesh(x, y, np.ma.masked_invalid(dd[:-1, :-1]), cmap=self.track_cmaps[j], shading='gouraud') ax.set_xlim(0, max(self.distances)) ax.invert_yaxis() ax.set_xlabel("Distance (km)") ax.set_ylim(max(self.depth), 0) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad="5%") bar = plt.colorbar(c, cax=cax) legend = [self.name] if len(legend) > 1: leg = plt.legend(legend, loc='best') for legobj in leg.legendHandles: legobj.set_linewidth(4.0) if len(np.unique(self.depth)) == 1: if self.data_units[j] is not None: ax.set_ylabel("%s (%s)" % (self.data_names[j], utils.mathtext(self.data_units[j]))) else: ax.set_ylabel(self.data_names[j]) else: if self.data_units[j] is not None: bar.set_label("%s (%s)" % (self.data_names[j], utils.mathtext(self.data_units[j]))) else: bar.set_label(self.data_names[j]) ax.set_ylabel("Depth (m)") for idx, v in enumerate(self.variables): if np.isnan(self.model_data[idx]).all(): continue ax = plt.subplot(gs[subplot]) subplot += subplot_inc if len(np.unique(self.depth)) > 1: mdist = np.linspace(0, self.model_dist[-1], 100) f = interp1d( self.model_dist, self.model_data[idx], assume_sorted=True, bounds_error=False, ) mdata = f(mdist) mdata = np.ma.masked_invalid(mdata) mdata = np.ma.masked_greater(mdata, mdata.fill_value) c = ax.pcolormesh( mdist, self.model_depths, mdata, cmap=self.cmaps[idx], shading='gouraud', ) ax.invert_yaxis() ax.set_ylim(max(self.depth), 0) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="5%", pad="5%") bar = plt.colorbar(c, cax=cax) else: ax.plot(self.model_dist, self.model_data[idx]) ax.set_xlim( self.model_dist[0], self.model_dist[-1], ) ax.set_xlabel("Distance (km)") if len(np.unique(self.depth)) > 1: ax.set_ylabel("Depth (m)") bar.set_label("%s (%s)" % (self.variable_names[idx], utils.mathtext(self.variable_units[idx]))) else: ax.set_ylabel("%s (%s)" % (self.variable_names[idx], utils.mathtext(self.variable_units[idx]))) plt.setp(ax.get_xticklabels(), rotation=30) # latlon if self.latlon: for j, label in enumerate([ gettext("Latitude (degrees)"), gettext("Longitude (degrees)") ]): plt.subplot(gs[subplot]) subplot += subplot_inc plt.plot(self.times, self.points[:, j]) plt.ylabel(label) plt.setp(plt.gca().get_xticklabels(), rotation=30) fig.suptitle( gettext("Track Plot (Observed %s - %s, Modelled %s - %s)") % (self.times[0].strftime("%Y-%m-%d"), self.times[-1].strftime("%Y-%m-%d"), self.model_times[0].strftime("%Y-%m-%d"), self.model_times[-1].strftime("%Y-%m-%d"))) fig.tight_layout(pad=3, w_pad=4) return super().plot(fig)
def scale(args): dataset_name = args.get('dataset') scale = args.get('scale') scale = [float(component) for component in scale.split(',')] variable = args.get('variable') anom = False if variable.endswith('_anom'): variable = variable[0:-5] anom = True 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)), fontsize=12) # Increase tick font size bar.ax.tick_params(labelsize=12) buf = BytesIO() plt.savefig(buf, format='png', dpi='figure', transparent=False, bbox_inches='tight', pad_inches=0.05) plt.close(fig) buf.seek(0) # Move buffer back to beginning return buf