def plot(self, axis=None, **kwargs): """Plot centroids scatter points over earth. Parameters ---------- axis : matplotlib.axes._subplots.AxesSubplot, optional axis to use kwargs : optional arguments for scatter matplotlib function Returns ------- axis : matplotlib.axes._subplots.AxesSubplot """ if self.meta and not self.coord.size: self.set_meta_to_lat_lon() pad = np.abs(u_coord.get_resolution(self.lat, self.lon)).min() proj_data, _ = u_plot.get_transformation(self.crs) proj_plot = proj_data if isinstance(proj_data, ccrs.PlateCarree): # use different projections for plot and data to shift the central lon in the plot xmin, ymin, xmax, ymax = u_coord.latlon_bounds(self.lat, self.lon, buffer=pad) proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax)) else: xmin, ymin, xmax, ymax = (self.lon.min() - pad, self.lat.min() - pad, self.lon.max() + pad, self.lat.max() + pad) if not axis: _, axis = u_plot.make_map(proj=proj_plot) axis.set_extent((xmin, xmax, ymin, ymax), crs=proj_data) u_plot.add_shapes(axis) axis.scatter(self.lon, self.lat, transform=proj_data, **kwargs) return axis
def plot_raster(self, res=None, raster_res=None, save_tiff=None, raster_f=lambda x: np.log10((np.fmax(x+1, 1))), label='value (log10)', scheduler=None, axis=None, **kwargs): """ Generate raster from points geometry and plot it using log10 scale: np.log10((np.fmax(raster+1, 1))). Parameters: res (float, optional): resolution of current data in units of latitude and longitude, approximated if not provided. raster_res (float, optional): desired resolution of the raster save_tiff (str, optional): file name to save the raster in tiff format, if provided raster_f (lambda function): transformation to use to data. Default: log10 adding 1. label (str): colorbar label scheduler (str): used for dask map_partitions. “threads”, “synchronous” or “processes” axis (matplotlib.axes._subplots.AxesSubplot, optional): axis to use kwargs (optional): arguments for imshow matplotlib function Returns: matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot """ if self.meta and self.meta['height']*self.meta['width'] == len(self): raster = self.value.values.reshape((self.meta['height'], self.meta['width'])) # check raster starts by upper left corner if self.latitude.values[0] < self.latitude.values[-1]: raster = np.flip(raster, axis=0) if self.longitude.values[0] > self.longitude.values[-1]: LOGGER.error('Points are not ordered according to meta raster.') raise ValueError else: raster, meta = co.points_to_raster(self, ['value'], res, raster_res, scheduler) raster = raster.reshape((meta['height'], meta['width'])) # save tiff if save_tiff is not None: ras_tiff = rasterio.open(save_tiff, 'w', driver='GTiff', \ height=meta['height'], width=meta['width'], count=1, \ dtype=np.float32, crs=self.crs, transform=meta['transform']) ras_tiff.write(raster.astype(np.float32), 1) ras_tiff.close() # make plot crs_epsg, _ = u_plot.get_transformation(self.crs) xmin, ymin, xmax, ymax = self.longitude.min(), self.latitude.min(), \ self.longitude.max(), self.latitude.max() if not axis: _, axis = u_plot.make_map(proj=crs_epsg) cbar_ax = make_axes_locatable(axis).append_axes('right', size="6.5%", \ pad=0.1, axes_class=plt.Axes) axis.set_extent([max(xmin, crs_epsg.x_limits[0]), \ min(xmax, crs_epsg.x_limits[1]), max(ymin, crs_epsg.y_limits[0]), \ min(ymax, crs_epsg.y_limits[1])], crs_epsg) u_plot.add_shapes(axis) imag = axis.imshow(raster_f(raster), **kwargs, origin='upper', extent=[xmin, xmax, ymin, ymax], transform=crs_epsg) plt.colorbar(imag, cax=cbar_ax, label=label) plt.draw() return axis
def plot_raster(self, res=None, raster_res=None, save_tiff=None, raster_f=lambda x: np.log10((np.fmax(x+1, 1))), label='value (log10)', **kwargs): """ Generate raster from points geometry and plot it using log10 scale: np.log10((np.fmax(raster+1, 1))). Parameters: res (float, optional): resolution of current data in units of latitude and longitude, approximated if not provided. raster_res (float, optional): desired resolution of the raster save_tiff (str, optional): file name to save the raster in tiff format, if provided raster_f (lambda function): transformation to use to data. Default: log10 adding 1. label (str): colorbar label kwargs (optional): arguments for imshow matplotlib function Returns: matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot """ if not 'geometry' in self.columns: self.set_geometry_points() crs_epsg, crs_unit = self._get_transformation() if not res: res= min(get_resolution(self.latitude.values, self.longitude.values)) if not raster_res: raster_res = res LOGGER.info('Raster from resolution %s%s to %s%s.', res, crs_unit, raster_res, crs_unit) exp_poly = self[['value']].set_geometry(self.buffer(res/2).envelope) # construct raster xmin, ymin, xmax, ymax = self.total_bounds rows, cols, ras_trans = points_to_raster((xmin, ymin, xmax, ymax), raster_res) raster = rasterize([(x, val) for (x, val) in zip(exp_poly.geometry, exp_poly.value)], out_shape=(rows, cols), transform=ras_trans, fill=0, all_touched=True, dtype=rasterio.float32, ) # save tiff if save_tiff is not None: ras_tiff = rasterio.open(save_tiff, 'w', driver='GTiff', \ height=raster.shape[0], width=raster.shape[1], count=1, \ dtype=np.float32, crs=self.crs, transform=ras_trans) ras_tiff.write(raster.astype(np.float32), 1) ras_tiff.close() # make plot fig, axis = u_plot.make_map(proj=crs_epsg) cbar_ax = fig.add_axes([0.99, 0.238, 0.03, 0.525]) fig.subplots_adjust(hspace=0, wspace=0) axis[0, 0].set_extent([max(xmin, crs_epsg.x_limits[0]), min(xmax, crs_epsg.x_limits[1]), max(ymin, crs_epsg.y_limits[0]), min(ymax, crs_epsg.y_limits[1])], crs_epsg) u_plot.add_shapes(axis[0, 0]) imag = axis[0, 0].imshow(raster_f(raster), **kwargs, origin='upper', extent=[xmin, xmax, ymin, ymax], transform=crs_epsg) plt.colorbar(imag, cax=cbar_ax, label=label) plt.draw() posn = axis[0, 0].get_position() cbar_ax.set_position([posn.x0 + posn.width + 0.01, posn.y0, 0.04, posn.height]) return fig, axis
def plot(self, axis=None, **kwargs): """Plot centroids scatter points over earth. Parameters: axis (matplotlib.axes._subplots.AxesSubplot, optional): axis to use kwargs (optional): arguments for scatter matplotlib function Returns: matplotlib.axes._subplots.AxesSubplot """ if not axis: _, axis = u_plot.make_map() u_plot.add_shapes(axis) if self.meta and not self.coord.size: self.set_meta_to_lat_lon() axis.scatter(self.lon, self.lat, **kwargs) return axis
def plot(self, **kwargs): """ Plot centroids scatter points over earth. Parameters: kwargs (optional): arguments for scatter matplotlib function Returns: matplotlib.figure.Figure, matplotlib.axes._subplots.AxesSubplot """ if 's' not in kwargs: kwargs['s'] = 1 fig, axis = u_plot.make_map() axis = axis[0][0] u_plot.add_shapes(axis) if self.meta and not self.coord.size: self.set_meta_to_lat_lon() axis.scatter(self.lon, self.lat, **kwargs) return fig, axis
def plot(self, **kwargs): """ Plot centroids points over earth. Parameters: kwargs (optional): arguments for scatter matplotlib function Returns: matplotlib.figure.Figure, matplotlib.axes._subplots.AxesSubplot """ if 's' not in kwargs: kwargs['s'] = 1 fig, axis = u_plot.make_map() axis = axis[0][0] u_plot.add_shapes(axis) axis.set_title(self.tag.join_file_names()) axis.scatter(self.lon, self.lat, **kwargs) return fig, axis
def plot_raster(self, res=None, raster_res=None, save_tiff=None, raster_f=lambda x: np.log10((np.fmax(x + 1, 1))), label='value (log10)', scheduler=None, axis=None, figsize=(9, 13), **kwargs): """Generate raster from points geometry and plot it using log10 scale: np.log10((np.fmax(raster+1, 1))). Parameters: res (float, optional): resolution of current data in units of latitude and longitude, approximated if not provided. raster_res (float, optional): desired resolution of the raster save_tiff (str, optional): file name to save the raster in tiff format, if provided raster_f (lambda function): transformation to use to data. Default: log10 adding 1. label (str): colorbar label scheduler (str): used for dask map_partitions. “threads”, “synchronous” or “processes” axis (matplotlib.axes._subplots.AxesSubplot, optional): axis to use figsize (tuple, optional): figure size for plt.subplots kwargs (optional): arguments for imshow matplotlib function Returns: matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot """ if self.meta and self.meta.get('height', 0) * self.meta.get( 'height', 0) == len(self.gdf): raster = self.gdf.value.values.reshape( (self.meta['height'], self.meta['width'])) # check raster starts by upper left corner if self.gdf.latitude.values[0] < self.gdf.latitude.values[-1]: raster = np.flip(raster, axis=0) if self.gdf.longitude.values[0] > self.gdf.longitude.values[-1]: LOGGER.error( 'Points are not ordered according to meta raster.') raise ValueError else: raster, meta = u_coord.points_to_raster(self.gdf, ['value'], res, raster_res, scheduler) raster = raster.reshape((meta['height'], meta['width'])) # save tiff if save_tiff is not None: with rasterio.open(save_tiff, 'w', driver='GTiff', height=meta['height'], width=meta['width'], count=1, dtype=np.float32, crs=self.crs, transform=meta['transform']) as ras_tiff: ras_tiff.write(raster.astype(np.float32), 1) # make plot proj_data, _ = u_plot.get_transformation(self.crs) proj_plot = proj_data if isinstance(proj_data, ccrs.PlateCarree): # use different projections for plot and data to shift the central lon in the plot xmin, ymin, xmax, ymax = u_coord.latlon_bounds( self.gdf.latitude.values, self.gdf.longitude.values) proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax)) else: xmin, ymin, xmax, ymax = (self.gdf.longitude.min(), self.gdf.latitude.min(), self.gdf.longitude.max(), self.gdf.latitude.max()) if not axis: _, axis = u_plot.make_map(proj=proj_plot, figsize=figsize) cbar_ax = make_axes_locatable(axis).append_axes('right', size="6.5%", pad=0.1, axes_class=plt.Axes) axis.set_extent((xmin, xmax, ymin, ymax), crs=proj_data) u_plot.add_shapes(axis) imag = axis.imshow(raster_f(raster), **kwargs, origin='upper', extent=(xmin, xmax, ymin, ymax), transform=proj_data) plt.colorbar(imag, cax=cbar_ax, label=label) plt.draw() return axis
def video_direct_impact(exp, if_set, haz_list, file_name='', writer=animation.PillowWriter(bitrate=500), imp_thresh=0, args_exp=dict(), args_imp=dict()): """ Computes and generates video of accumulated impact per input events over exposure. Parameters: exp (Exposures): exposures instance, constant during all video if_set (ImpactFuncSet): impact functions haz_list (list(Hazard)): every Hazard contains an event; all hazards use the same centroids file_name (str, optional): file name to save video, if provided writer = (matplotlib.animation.*, optional): video writer. Default: pillow with bitrate=500 imp_thresh (float): represent damages greater than threshold args_exp (optional): arguments for scatter (points) or hexbin (raster) matplotlib function used in exposures args_imp (optional): arguments for scatter (points) or hexbin (raster) matplotlib function used in impact Returns: list(Impact) """ imp_list = [] exp_list = [] imp_arr = np.zeros(len(exp)) for i_time, _ in enumerate(haz_list): imp_tmp = Impact() imp_tmp.calc(exp, if_set, haz_list[i_time]) imp_arr = np.maximum(imp_arr, imp_tmp.eai_exp) # remove not impacted exposures save_exp = imp_arr > imp_thresh imp_tmp.coord_exp = imp_tmp.coord_exp[save_exp, :] imp_tmp.eai_exp = imp_arr[save_exp] imp_list.append(imp_tmp) exp_list.append(~save_exp) v_lim = [np.array([haz.intensity.min() for haz in haz_list]).min(), np.array([haz.intensity.max() for haz in haz_list]).max()] if 'vmin' not in args_exp: args_exp['vmin'] = exp.value.values.min() if 'vmin' not in args_imp: args_imp['vmin'] = np.array([imp.eai_exp.min() for imp in imp_list if imp.eai_exp.size]).min() if 'vmax' not in args_exp: args_exp['vmax'] = exp.value.values.max() if 'vmax' not in args_imp: args_imp['vmax'] = np.array([imp.eai_exp.max() for imp in imp_list if imp.eai_exp.size]).max() if 'cmap' not in args_exp: args_exp['cmap'] = 'winter_r' if 'cmap' not in args_imp: args_imp['cmap'] = 'autumn_r' plot_raster = False if exp.meta: plot_raster = True def run(i_time): haz_list[i_time].plot_intensity(1, axis=axis, cmap='Greys', vmin=v_lim[0], vmax=v_lim[1], alpha=0.8) if plot_raster: exp.plot_hexbin(axis=axis, mask=exp_list[i_time], ignore_zero=True, pop_name=False, **args_exp) if imp_list[i_time].coord_exp.size: imp_list[i_time].plot_hexbin_eai_exposure(axis=axis, pop_name=False, **args_imp) fig.delaxes(fig.axes[1]) else: exp.plot_scatter(axis=axis, mask=exp_list[i_time], ignore_zero=True, pop_name=False, **args_exp) if imp_list[i_time].coord_exp.size: imp_list[i_time].plot_scatter_eai_exposure(axis=axis, pop_name=False, **args_imp) fig.delaxes(fig.axes[1]) fig.delaxes(fig.axes[1]) fig.delaxes(fig.axes[1]) axis.set_xlim(haz_list[-1].centroids.lon.min(), haz_list[-1].centroids.lon.max()) axis.set_ylim(haz_list[-1].centroids.lat.min(), haz_list[-1].centroids.lat.max()) axis.set_title(haz_list[i_time].event_name[0]) pbar.update() if file_name: LOGGER.info('Generating video %s', file_name) fig, axis = u_plot.make_map() ani = animation.FuncAnimation(fig, run, frames=len(haz_list), interval=500, blit=False) pbar = tqdm(total=len(haz_list)) ani.save(file_name, writer=writer) pbar.close() return imp_list
def video_intensity(track_name, tracks, centroids, file_name=None, writer=animation.PillowWriter(bitrate=500), figsize=(9, 13), adapt_fontsize=True, **kwargs): """ Generate video of TC wind fields node by node and returns its corresponding TropCyclone instances and track pieces. Parameters ---------- track_name : str name of the track contained in tracks to record tracks : climada.hazard.TCTracks tropical cyclone tracks centroids : climada.hazard.Centroids centroids where wind fields are mapped file_name : str, optional file name to save video (including full path and file extension) writer : matplotlib.animation.*, optional video writer. Default is pillow with bitrate=500 figsize : tuple, optional figure size for plt.subplots adapt_fontsize : bool, optional If set to true, the size of the fonts will be adapted to the size of the figure. Otherwise the default matplotlib font size is used. Default is True. kwargs : optional arguments for pcolormesh matplotlib function used in event plots Returns ------- tc_list, tc_coord : list(TropCyclone), list(np.array) Raises ------ ValueError """ # initialization track = tracks.get_track(track_name) if not track: raise ValueError('%s not found in track data.' % track_name) idx_plt = np.argwhere( (track.lon.values < centroids.total_bounds[2] + 1) & (centroids.total_bounds[0] - 1 < track.lon.values) & (track.lat.values < centroids.total_bounds[3] + 1) & (centroids.total_bounds[1] - 1 < track.lat.values)).reshape(-1) tc_list = [] tr_coord = {'lat': [], 'lon': []} for node in range(idx_plt.size - 2): tr_piece = track.sel( time=slice(track.time.values[idx_plt[node]], track.time.values[ idx_plt[node + 2]])) tr_piece.attrs['n_nodes'] = 2 # plot only one node tr_sel = TCTracks() tr_sel.append(tr_piece) tr_coord['lat'].append(tr_sel.data[0].lat.values[:-1]) tr_coord['lon'].append(tr_sel.data[0].lon.values[:-1]) tc_tmp = TropCyclone() tc_tmp.set_from_tracks(tr_sel, centroids) tc_tmp.event_name = [ track.name + ' ' + time.strftime( "%d %h %Y %H:%M", time.gmtime(tr_sel.data[0].time[1].values.astype(int) / 1000000000)) ] tc_list.append(tc_tmp) if 'cmap' not in kwargs: kwargs['cmap'] = 'Greys' if 'vmin' not in kwargs: kwargs['vmin'] = np.array([tc_.intensity.min() for tc_ in tc_list]).min() if 'vmax' not in kwargs: kwargs['vmax'] = np.array([tc_.intensity.max() for tc_ in tc_list]).max() def run(node): tc_list[node].plot_intensity(1, axis=axis, **kwargs) axis.plot(tr_coord['lon'][node], tr_coord['lat'][node], 'k') axis.set_title(tc_list[node].event_name[0]) pbar.update() if file_name: LOGGER.info('Generating video %s', file_name) fig, axis, fontsize = u_plot.make_map( figsize=figsize, adapt_fontsize=adapt_fontsize) pbar = tqdm(total=idx_plt.size - 2) ani = animation.FuncAnimation(fig, run, frames=idx_plt.size - 2, interval=500, blit=False) fig.tight_layout() ani.save(file_name, writer=writer) pbar.close() return tc_list, tr_coord
def video_intensity(track_name, tracks, centroids, file_name=None, writer=animation.PillowWriter(bitrate=500), **kwargs): """Generate video of TC wind fields node by node and returns its corresponding TropCyclone instances and track pieces. Parameters: track_name (str): name of the track contained in tracks to record tracks (TCTracks): tracks centroids (Centroids): centroids where wind fields are mapped file_name (str, optional): file name to save video, if provided writer = (matplotlib.animation.*, optional): video writer. Default: pillow with bitrate=500 kwargs (optional): arguments for pcolormesh matplotlib function used in event plots Returns: list(TropCyclone), list(np.array) Raises: ValueError """ # initialization track = tracks.get_track(track_name) if not track: LOGGER.error('%s not found in track data.', track_name) raise ValueError idx_plt = np.argwhere( (track.lon.values < centroids.total_bounds[2] + 1) & (centroids.total_bounds[0] - 1 < track.lon.values) & (track.lat.values < centroids.total_bounds[3] + 1) & (centroids.total_bounds[1] - 1 < track.lat.values)).reshape(-1) tc_list = [] tr_coord = {'lat': [], 'lon': []} for node in range(idx_plt.size - 2): tr_piece = track.sel( time=slice(track.time.values[idx_plt[node]], track.time.values[ idx_plt[node + 2]])) tr_piece.attrs['n_nodes'] = 2 # plot only one node tr_sel = TCTracks() tr_sel.append(tr_piece) tr_coord['lat'].append(tr_sel.data[0].lat.values[:-1]) tr_coord['lon'].append(tr_sel.data[0].lon.values[:-1]) tc_tmp = TropCyclone() tc_tmp.set_from_tracks(tr_sel, centroids) tc_tmp.event_name = [ track.name + ' ' + time.strftime( "%d %h %Y %H:%M", time.gmtime(tr_sel.data[0].time[1].values.astype(int) / 1000000000)) ] tc_list.append(tc_tmp) if 'cmap' not in kwargs: kwargs['cmap'] = 'Greys' if 'vmin' not in kwargs: kwargs['vmin'] = np.array([tc_.intensity.min() for tc_ in tc_list]).min() if 'vmax' not in kwargs: kwargs['vmax'] = np.array([tc_.intensity.max() for tc_ in tc_list]).max() def run(node): tc_list[node].plot_intensity(1, axis=axis, **kwargs) axis.plot(tr_coord['lon'][node], tr_coord['lat'][node], 'k') axis.set_title(tc_list[node].event_name[0]) pbar.update() if file_name: LOGGER.info('Generating video %s', file_name) fig, axis = u_plot.make_map() pbar = tqdm(total=idx_plt.size - 2) ani = animation.FuncAnimation(fig, run, frames=idx_plt.size - 2, interval=500, blit=False) ani.save(file_name, writer=writer) pbar.close() return tc_list, tr_coord
def _plot_warn( self, run_datetime, thresholds, decision_level, decision_dict, polygon_file, polygon_file_crs, title, proj=ccrs.PlateCarree(), figsize=(9, 13), adapt_fontsize=True, ): """plotting the warning level of each warning region based on thresholds""" # select hazard with run_datetime # pylint: disable=protected-access if run_datetime is None: run_datetime = self.run_datetime[0] haz_ind = np.argwhere(np.isin(self.run_datetime, run_datetime))[0][0] kwargs = dict() kwargs["cmap"] = CMAP_WARNPROB kwargs["s"] = 5 kwargs["marker"] = "," kwargs["norm"] = BoundaryNorm(np.linspace(0, 1, 11), CMAP_WARNPROB.N, clip=True) # Generate each subplot fig, axis, _fontsize = u_plot.make_map(1, proj=proj, figsize=figsize, adapt_fontsize=adapt_fontsize) if isinstance(axis, np.ndarray): axis = axis[0] tit = title fig.set_size_inches(9, 8) # add warning regions shp = shapereader.Reader(polygon_file) transformer = pyproj.Transformer.from_crs(polygon_file_crs, self._impact[haz_ind].crs, always_xy=True) # checking the decision dict and define the corresponding functions if not (isinstance(decision_dict["probability_aggregation"], float) & isinstance(decision_dict["area_aggregation"], float)): ValueError(" If decision_level is 'exposure_point'," + "parameters probability_aggregation and " + "area_aggregation of " + "Forecast.plot_warn_map() must both be " + "floats between [0..1]. Which each " + "specify quantiles.") decision_dict_functions = decision_dict.copy() for aggregation in decision_dict: if isinstance(decision_dict[aggregation], float): decision_dict_functions[aggregation] = np.percentile elif decision_dict[aggregation] == "sum": decision_dict_functions[aggregation] = np.sum elif decision_dict[aggregation] == "mean": decision_dict_functions[aggregation] = np.mean else: raise ValueError("Parameter area_aggregation of " + "Forecast.plot_warn_map() must eiter be " + "a float between [0..1], which " + "specifys a quantile. or 'sum' or 'mean'.") for geometry, _ in zip(shp.geometries(), shp.records()): geom2 = shapely.ops.transform(transformer.transform, geometry) in_geom = u_coord.coord_on_land( lat=self._impact[haz_ind].coord_exp[:, 0], lon=self._impact[haz_ind].coord_exp[:, 1], land_geom=geom2, ) if not in_geom.any(): continue # decide warning level warn_level = 0 for ind_i, warn_thres_i in enumerate(thresholds): if decision_level == "exposure_point": # decision at each grid_point probabilities = np.squeeze( np.asarray((self._impact[haz_ind].imp_mat >= warn_thres_i).sum(axis=0) / self._impact[haz_ind].event_id.size)) # quantiles over probability area = (probabilities[in_geom] >= decision_dict["probability_aggregation"]).sum() # quantiles over area if area >= (in_geom.sum() * decision_dict["area_aggregation"]): warn_level = ind_i + 1 elif decision_level == "polygon": # aggregation over area if isinstance(decision_dict["area_aggregation"], float): value_per_member = decision_dict_functions[ "area_aggregation"]( self._impact[haz_ind].imp_mat[:, in_geom].todense( ), decision_dict["area_aggregation"], axis=1, ) else: value_per_member = decision_dict_functions[ "area_aggregation"](self._impact[haz_ind]. imp_mat[:, in_geom].todense(), axis=1) # aggregation over members/probability if isinstance(decision_dict["probability_aggregation"], float): value_per_region = decision_dict_functions[ "probability_aggregation"]( value_per_member, decision_dict["probability_aggregation"]) else: value_per_region = decision_dict_functions[ "probability_aggregation"](value_per_member) # warn level decision if value_per_region >= warn_thres_i: warn_level = ind_i + 1 else: raise ValueError( "Parameter decision_level of " + "Forecast.plot_warn_map() must eiter be " + "'exposure_point' or 'polygon'.") # plot warn_region with specific color (dependent on warning level) axis.add_geometries( [geom2], crs=ccrs.PlateCarree(), facecolor=COLORS_WARN[warn_level, :], edgecolor="gray", ) # Create legend in this axis hazard_levels = [ "1: Minimal or no hazard", "2: Moderate hazard", "3: Significant hazard", "4: Severe hazard", "5: Very severe hazard", ] legend_elements = [ Patch(facecolor=COLORS_WARN[n, :], edgecolor="gray", label=hazard_level) for n, hazard_level in enumerate(hazard_levels) ] axis.legend( handles=legend_elements, loc="upper center", framealpha=0.5, bbox_to_anchor=(0.5, -0.02), ncol=3, ) title_position = { "model_text": [0.02, 0.91], "explain_text": [0.02, 0.87], "event_day": [0.98, 0.91], "run_start": [0.98, 0.87], } left_right = { "model_text": "left", "explain_text": "left", "event_day": "right", "run_start": "right", } color = { "model_text": "k", "explain_text": "k", "event_day": "r", "run_start": "k", } for t_i in tit: plt.figtext( title_position[t_i][0], title_position[t_i][1], tit[t_i], fontsize="xx-large", color=color[t_i], ha=left_right[t_i], ) extent = u_plot._get_borders(self._impact[haz_ind].coord_exp) axis.set_extent((extent), ccrs.PlateCarree()) fig.tight_layout() return fig, axis
def _plot_exc_prob( self, run_datetime, threshold, title, cbar_label, proj=ccrs.PlateCarree(), polygon_file=None, polygon_file_crs="epsg:4326", mask=None, figsize=(9, 13), adapt_fontsize=True, ): """plot the probability of reaching a threshold""" # select hazard with run_datetime # pylint: disable=protected-access if run_datetime is None: run_datetime = self.run_datetime[0] haz_ind = np.argwhere(np.isin(self.run_datetime, run_datetime))[0][0] extend = "neither" value = np.squeeze( np.asarray( (self._impact[haz_ind].imp_mat > threshold).sum(axis=0) / self._impact[haz_ind].event_id.size)) if mask is not None: value[np.invert(mask)] = np.nan coord = self._impact[haz_ind].coord_exp # Generate array of values used in each subplot array_sub = value shapes = True if not polygon_file: shapes = False var_name = cbar_label geo_coord = coord num_im, list_arr = u_plot._get_collection_arrays(array_sub) list_tit = to_list(num_im, title, "title") list_name = to_list(num_im, var_name, "var_name") list_coord = to_list(num_im, geo_coord, "geo_coord") kwargs = dict() kwargs["cmap"] = CMAP_WARNPROB kwargs["s"] = 5 kwargs["marker"] = "," kwargs["norm"] = BoundaryNorm(np.linspace(0, 1, 11), CMAP_WARNPROB.N, clip=True) # Generate each subplot fig, axis_sub, _fontsize = u_plot.make_map( num_im, proj=proj, figsize=figsize, adapt_fontsize=adapt_fontsize) if not isinstance(axis_sub, np.ndarray): axis_sub = np.array([[axis_sub]]) fig.set_size_inches(9, 8) for array_im, axis, tit, name, coord in zip(list_arr, axis_sub.flatten(), list_tit, list_name, list_coord): if coord.shape[0] != array_im.size: raise ValueError("Size mismatch in input array: %s != %s." % (coord.shape[0], array_im.size)) hex_bin = axis.scatter(coord[:, 1], coord[:, 0], c=array_im, transform=ccrs.PlateCarree(), **kwargs) if shapes: # add warning regions shp = shapereader.Reader(polygon_file) transformer = pyproj.Transformer.from_crs( polygon_file_crs, self._impact[haz_ind].crs, always_xy=True) for geometry, _ in zip(shp.geometries(), shp.records()): geom2 = shapely.ops.transform(transformer.transform, geometry) axis.add_geometries( [geom2], crs=ccrs.PlateCarree(), facecolor="none", edgecolor="gray", ) # Create colorbar in this axis cbax = make_axes_locatable(axis).append_axes("bottom", size="6.5%", pad=0.3, axes_class=plt.Axes) cbar = plt.colorbar(hex_bin, cax=cbax, orientation="horizontal", extend=extend) cbar.set_label(name) title_position = { "model_text": [0.02, 0.94], "explain_text": [0.02, 0.9], "event_day": [0.98, 0.94], "run_start": [0.98, 0.9], } left_right = { "model_text": "left", "explain_text": "left", "event_day": "right", "run_start": "right", } color = { "model_text": "k", "explain_text": "k", "event_day": "r", "run_start": "k", } for t_i in tit: plt.figtext( title_position[t_i][0], title_position[t_i][1], tit[t_i], fontsize="xx-large", color=color[t_i], ha=left_right[t_i], ) extent = u_plot._get_borders(coord) axis.set_extent((extent), ccrs.PlateCarree()) fig.tight_layout() return fig, axis_sub
def _plot_imp_map( self, run_datetime, title, cbar_label, polygon_file=None, polygon_file_crs="epsg:4326", proj=ccrs.PlateCarree(), figsize=(9, 13), adapt_fontsize=True, ): # select hazard with run_datetime # pylint: disable=protected-access if run_datetime is None: run_datetime = self.run_datetime[0] haz_ind = np.argwhere(np.isin(self.run_datetime, run_datetime))[0][0] # tryout new plot with right projection extend = "neither" value = self._impact[haz_ind].eai_exp # value[np.invert(mask)] = np.nan coord = self._impact[haz_ind].coord_exp # Generate array of values used in each subplot array_sub = value shapes = True if not polygon_file: shapes = False var_name = cbar_label geo_coord = coord num_im, list_arr = u_plot._get_collection_arrays(array_sub) list_tit = to_list(num_im, title, "title") list_name = to_list(num_im, var_name, "var_name") list_coord = to_list(num_im, geo_coord, "geo_coord") kwargs = dict() kwargs["cmap"] = CMAP_IMPACT kwargs["s"] = 5 kwargs["marker"] = "," kwargs["norm"] = BoundaryNorm( np.append( np.append([0], [10**x for x in np.arange(0, 2.9, 2.9 / 9)]), [10**x for x in np.arange(3, 7, 4 / 90)], ), CMAP_IMPACT.N, clip=True, ) # Generate each subplot fig, axis_sub, _fontsize = u_plot.make_map( num_im, proj=proj, figsize=figsize, adapt_fontsize=adapt_fontsize) if not isinstance(axis_sub, np.ndarray): axis_sub = np.array([[axis_sub]]) fig.set_size_inches(9, 8) for array_im, axis, tit, name, coord in zip(list_arr, axis_sub.flatten(), list_tit, list_name, list_coord): if coord.shape[0] != array_im.size: raise ValueError("Size mismatch in input array: %s != %s." % (coord.shape[0], array_im.size)) # Binned image with coastlines extent = u_plot._get_borders(coord) axis.set_extent((extent), ccrs.PlateCarree()) hex_bin = axis.scatter(coord[:, 1], coord[:, 0], c=array_im, transform=ccrs.PlateCarree(), **kwargs) if shapes: # add warning regions shp = shapereader.Reader(polygon_file) transformer = pyproj.Transformer.from_crs( polygon_file_crs, self._impact[haz_ind].crs, always_xy=True) for geometry, _ in zip(shp.geometries(), shp.records()): geom2 = shapely.ops.transform(transformer.transform, geometry) axis.add_geometries( [geom2], crs=ccrs.PlateCarree(), facecolor="none", edgecolor="gray", ) else: # add country boundaries u_plot.add_shapes(axis) # Create colorbar in this axis cbax = make_axes_locatable(axis).append_axes("bottom", size="6.5%", pad=0.3, axes_class=plt.Axes) cbar = plt.colorbar(hex_bin, cax=cbax, orientation="horizontal", extend=extend) cbar.set_label(name) cbar.formatter.set_scientific(False) cbar.set_ticks([0, 1000, 10000, 100000, 1000000]) cbar.set_ticklabels( ["0", "1 000", "10 000", "100 000", "1 000 000"]) title_position = { "model_text": [0.02, 0.85], "explain_text": [0.02, 0.81], "event_day": [0.98, 0.85], "run_start": [0.98, 0.81], } left_right = { "model_text": "left", "explain_text": "left", "event_day": "right", "run_start": "right", } color = { "model_text": "k", "explain_text": "k", "event_day": "r", "run_start": "k", } for t_i in tit: plt.figtext( title_position[t_i][0], title_position[t_i][1], tit[t_i], fontsize="xx-large", color=color[t_i], ha=left_right[t_i], ) fig.tight_layout() fig.subplots_adjust(top=0.8) return fig, axis_sub
def _plot_exc_prob(self, run_datetime, threshold, title, cbar_label, proj=ccrs.PlateCarree(), polygon_file=None, polygon_file_crs='epsg:4326', mask=None, figsize=(9, 13)): """ plot the probability of reaching a threshold """ # select hazard with run_datetime if run_datetime is None: run_datetime = self.run_datetime[0] haz_ind = np.argwhere(np.isin(self.run_datetime, run_datetime))[0][0] extend = 'neither' value = np.squeeze( np.asarray( (self._impact[haz_ind].imp_mat > threshold).sum(axis=0) / self._impact[haz_ind].event_id.size)) if mask is not None: value[np.invert(mask)] = np.nan coord = self._impact[haz_ind].coord_exp # Generate array of values used in each subplot array_sub = value shapes = True if not polygon_file: shapes = False var_name = cbar_label geo_coord = coord num_im, list_arr = u_plot._get_collection_arrays(array_sub) list_tit = to_list(num_im, title, 'title') list_name = to_list(num_im, var_name, 'var_name') list_coord = to_list(num_im, geo_coord, 'geo_coord') kwargs = dict() kwargs['cmap'] = CMAP_WARNPROB kwargs['s'] = 5 kwargs['marker'] = ',' kwargs['norm'] = BoundaryNorm(np.linspace(0, 1, 11), CMAP_WARNPROB.N, clip=True) # Generate each subplot fig, axis_sub = u_plot.make_map(num_im, proj=proj, figsize=figsize) if not isinstance(axis_sub, np.ndarray): axis_sub = np.array([[axis_sub]]) fig.set_size_inches(9, 8) for array_im, axis, tit, name, coord in zip(list_arr, axis_sub.flatten(), list_tit, list_name, list_coord): if coord.shape[0] != array_im.size: raise ValueError("Size mismatch in input array: %s != %s." % \ (coord.shape[0], array_im.size)) hex_bin = axis.scatter(coord[:, 1], coord[:, 0], c=array_im, \ transform=ccrs.PlateCarree(), **kwargs) if shapes: # add warning regions shp = shapereader.Reader(polygon_file) transformer = pyproj.Transformer.from_crs( polygon_file_crs, self._impact[haz_ind].crs, always_xy=True) for geometry, _ in zip(shp.geometries(), shp.records()): geom2 = shapely.ops.transform(transformer.transform, geometry) axis.add_geometries([geom2], crs=ccrs.PlateCarree(), facecolor='', \ edgecolor='gray') # Create colorbar in this axis cbax = make_axes_locatable(axis).append_axes('bottom', size="6.5%", \ pad=0.3, axes_class=plt.Axes) cbar = plt.colorbar(hex_bin, cax=cbax, orientation='horizontal', extend=extend) cbar.set_label(name) title_position = { 'model_text': [0.02, 0.94], 'explain_text': [0.02, 0.9], 'event_day': [0.98, 0.94], 'run_start': [0.98, 0.9] } left_right = { 'model_text': 'left', 'explain_text': 'left', 'event_day': 'right', 'run_start': 'right' } color = { 'model_text': 'k', 'explain_text': 'k', 'event_day': 'r', 'run_start': 'k' } for t_i in tit: plt.figtext(title_position[t_i][0], title_position[t_i][1], tit[t_i], fontsize='xx-large', color=color[t_i], ha=left_right[t_i]) extent = u_plot._get_borders(coord) axis.set_extent((extent), ccrs.PlateCarree()) return fig, axis_sub
def plot_raster(self, res=None, raster_res=None, save_tiff=None, raster_f=lambda x: np.log10((np.fmax(x + 1, 1))), label='value (log10)', scheduler=None, axis=None, figsize=(9, 13), fill=True, adapt_fontsize=True, **kwargs): """Generate raster from points geometry and plot it using log10 scale: np.log10((np.fmax(raster+1, 1))). Parameters ---------- res : float, optional resolution of current data in units of latitude and longitude, approximated if not provided. raster_res : float, optional desired resolution of the raster save_tiff : str, optional file name to save the raster in tiff format, if provided raster_f : lambda function transformation to use to data. Default: log10 adding 1. label : str colorbar label scheduler : str used for dask map_partitions. “threads”, “synchronous” or “processes” axis : matplotlib.axes._subplots.AxesSubplot, optional axis to use figsize : tuple, optional figure size for plt.subplots fill : bool, optional If false, the areas with no data will be plotted in white. If True, the areas with missing values are filled as 0s. The default is True. adapt_fontsize : bool, optional If set to true, the size of the fonts will be adapted to the size of the figure. Otherwise the default matplotlib font size is used. Default is True. kwargs : optional arguments for imshow matplotlib function Returns ------- matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot """ if self.meta and self.meta.get('height', 0) * self.meta.get( 'height', 0) == len(self.gdf): raster = self.gdf.value.values.reshape( (self.meta['height'], self.meta['width'])) # check raster starts by upper left corner if self.gdf.latitude.values[0] < self.gdf.latitude.values[-1]: raster = np.flip(raster, axis=0) if self.gdf.longitude.values[0] > self.gdf.longitude.values[-1]: raise ValueError( 'Points are not ordered according to meta raster.') else: raster, meta = u_coord.points_to_raster(self.gdf, ['value'], res, raster_res, scheduler) raster = raster.reshape((meta['height'], meta['width'])) # save tiff if save_tiff is not None: with rasterio.open(save_tiff, 'w', driver='GTiff', height=meta['height'], width=meta['width'], count=1, dtype=np.float32, crs=self.crs, transform=meta['transform']) as ras_tiff: ras_tiff.write(raster.astype(np.float32), 1) # make plot proj_data, _ = u_plot.get_transformation(self.crs) proj_plot = proj_data if isinstance(proj_data, ccrs.PlateCarree): # use different projections for plot and data to shift the central lon in the plot xmin, ymin, xmax, ymax = u_coord.latlon_bounds( self.gdf.latitude.values, self.gdf.longitude.values) proj_plot = ccrs.PlateCarree(central_longitude=0.5 * (xmin + xmax)) else: xmin, ymin, xmax, ymax = (self.gdf.longitude.min(), self.gdf.latitude.min(), self.gdf.longitude.max(), self.gdf.latitude.max()) if not axis: _, axis, fontsize = u_plot.make_map(proj=proj_plot, figsize=figsize, adapt_fontsize=adapt_fontsize) else: fontsize = None cbar_ax = make_axes_locatable(axis).append_axes('right', size="6.5%", pad=0.1, axes_class=plt.Axes) axis.set_extent((xmin, xmax, ymin, ymax), crs=proj_data) u_plot.add_shapes(axis) if not fill: raster = np.where(raster == 0, np.nan, raster) raster_f = lambda x: np.log10((np.maximum(x + 1, 1))) if 'cmap' not in kwargs: kwargs['cmap'] = CMAP_RASTER imag = axis.imshow(raster_f(raster), **kwargs, origin='upper', extent=(xmin, xmax, ymin, ymax), transform=proj_data) cbar = plt.colorbar(imag, cax=cbar_ax, label=label) plt.colorbar(imag, cax=cbar_ax, label=label) plt.tight_layout() plt.draw() if fontsize: cbar.ax.tick_params(labelsize=fontsize) cbar.ax.yaxis.get_offset_text().set_fontsize(fontsize) for item in [axis.title, cbar.ax.xaxis.label, cbar.ax.yaxis.label]: item.set_fontsize(fontsize) return axis