diff --git a/run.py b/run.py index 854a0e452526abb0742e72c9a3c6162ff03a6287..79492b0f92f5c32eb75c4e3443778336a6192656 100644 --- a/run.py +++ b/run.py @@ -34,9 +34,7 @@ def main(parser_args): create_new_bootstraps=False, plot_list=["PlotMonthlySummary", "PlotStationMap", "PlotClimatologicalSkillScore", "PlotCompetitiveSkillScore", "PlotBootstrapSkillScore", "PlotConditionalQuantiles", - "PlotAvailability", "PlotAvailabilityHistogram"], - - + "PlotAvailabilityHistogram"], ) PreProcessing() diff --git a/src/plotting/postprocessing_plotting.py b/src/plotting/postprocessing_plotting.py index a4e7173bebc7d25bc276251b66cd8beae2d6d2bd..5c72b47585ccde6017f2f7769f9e09258d3943ca 100644 --- a/src/plotting/postprocessing_plotting.py +++ b/src/plotting/postprocessing_plotting.py @@ -27,10 +27,22 @@ logging.getLogger('matplotlib').setLevel(logging.WARNING) class AbstractPlotClass: - def __init__(self, plot_folder, plot_name, resolution=500): + def __init__(self, plot_folder, plot_name, resolution=500, rc_params=None): + if rc_params is None: + rc_params = {'axes.labelsize': 'large', + 'xtick.labelsize': 'large', + 'ytick.labelsize': 'large', + 'legend.fontsize': 'large', + 'axes.titlesize': 'large', + } self.plot_folder = plot_folder self.plot_name = plot_name self.resolution = resolution + self.rc_params = rc_params + self._update_rc_params() + + def _update_rc_params(self): + plt.rcParams.update(self.rc_params) def _plot(self, *args): raise NotImplementedError @@ -67,7 +79,7 @@ class PlotMonthlySummary(AbstractPlotClass): in data_path with name monthly_summary_box_plot.pdf and 500dpi resolution. """ def __init__(self, stations: List, data_path: str, name: str, target_var: str, window_lead_time: int = None, - plot_folder: str = "."): + plot_folder: str = ".", target_var_unit: str = 'ppb'): """ Sets attributes and create plot :param stations: all stations to plot @@ -77,13 +89,14 @@ class PlotMonthlySummary(AbstractPlotClass): :param window_lead_time: lead time to plot, if window_lead_time is higher than the available lead time or not given the maximum lead time from data is used. (default None -> use maximum lead time from data). :param plot_folder: path to save the plot (default: current directory) + :param target_var_unit: unit of target var for plot legend """ super().__init__(plot_folder, "monthly_summary_box_plot") self._data_path = data_path self._data_name = name self._data = self._prepare_data(stations) self._window_lead_time = self._get_window_lead_time(window_lead_time) - self._plot(target_var) + self._plot(target_var, target_var_unit) self._save() def _prepare_data(self, stations: List) -> xr.DataArray: @@ -128,7 +141,7 @@ class PlotMonthlySummary(AbstractPlotClass): window_lead_time = ahead_steps return min(ahead_steps, window_lead_time) - def _plot(self, target_var: str): + def _plot(self, target_var: str, target_var_unit: str): """ Main plot function that creates a monthly grouped box plot over all stations but with separate boxes for each lead time step. @@ -140,9 +153,15 @@ class PlotMonthlySummary(AbstractPlotClass): ax = sns.boxplot(x='index', y='values', hue='ahead', data=data.compute(), whis=1., palette=color_palette, flierprops={'marker': '.', 'markersize': 1}, showmeans=True, meanprops={'markersize': 1, 'markeredgecolor': 'k'}) - ax.set(xlabel='month', ylabel=f'{target_var}') + ylabel = self._spell_out_chemical_concentrations(target_var) + ax.set(xlabel='month', ylabel=f'{ylabel} (in {target_var_unit})') plt.tight_layout() + @staticmethod + def _spell_out_chemical_concentrations(short_name: str): + short2long = {'o3': 'ozone', 'no': 'nitrogen oxide', 'no2': 'nitrogen dioxide', 'nox': 'nitrogen dioxides'} + return f"{short2long[short_name]} concentration" + @TimeTrackingWrapper class PlotStationMap(AbstractPlotClass): @@ -477,7 +496,7 @@ class PlotClimatologicalSkillScore(AbstractPlotClass): name skill_score_clim_{extra_name_tag}{model_setup}.pdf and resolution of 500dpi. """ def __init__(self, data: Dict, plot_folder: str = ".", score_only: bool = True, extra_name_tag: str = "", - model_setup: str = ""): + model_setup: str = "", font_size_all_terms: int = 22): """ Sets attributes and create plot :param data: dictionary with station names as keys and 2D xarrays as values, consist on axis ahead and terms. @@ -485,8 +504,10 @@ class PlotClimatologicalSkillScore(AbstractPlotClass): :param score_only: if true plot only scores of CASE I to IV, otherwise plot all single terms (default True) :param extra_name_tag: additional tag that can be included in the plot name (default "") :param model_setup: architecture type to specify plot name (default "CNN") + :param font_size_all_terms: font size for summary plot containing all terms and skill scores """ super().__init__(plot_folder, f"skill_score_clim_{extra_name_tag}{model_setup}") + self.font_size_all_terms = font_size_all_terms self._labels = None self._data = self._prepare_data(data, score_only) self._plot(score_only) @@ -522,12 +543,23 @@ class PlotClimatologicalSkillScore(AbstractPlotClass): fig, ax = plt.subplots() if not score_only: fig.set_size_inches(11.7, 8.27) + ax.tick_params(labelsize=self.font_size_all_terms) + plt.xticks(fontsize=self.font_size_all_terms, rotation=45) + sns.boxplot(x="terms", y="data", hue="ahead", data=self._data, ax=ax, whis=1., palette="Blues_d", showmeans=True, meanprops={"markersize": 1, "markeredgecolor": "k"}, flierprops={"marker": "."}) ax.axhline(y=0, color="grey", linewidth=.5) - ax.set(ylabel=f"{self._label_add(score_only)}skill score", xlabel="", title="summary of all stations") handles, _ = ax.get_legend_handles_labels() - ax.legend(handles, self._labels) + if not score_only: + ax.set_xlabel("") + ax.set_ylabel(f"{self._label_add(score_only)}skill score", fontsize=self.font_size_all_terms) + ax.set_title("summary of all stations", fontsize=self.font_size_all_terms) + ax.legend(handles, self._labels, fontsize=self.font_size_all_terms, loc='lower left') + + else: + ax.legend(handles, self._labels) + ax.set(ylabel=f"{self._label_add(score_only)}skill score", xlabel="", title="summary of all stations") + plt.tight_layout() @@ -643,6 +675,7 @@ class PlotBootstrapSkillScore(AbstractPlotClass): sns.boxplot(x=self._x_name, y="data", hue="ahead", data=self._data, ax=ax, whis=1., palette="Blues_d", showmeans=True, meanprops={"markersize": 1, "markeredgecolor": "k"}, flierprops={"marker": "."}) ax.axhline(y=0, color="grey", linewidth=.5) + plt.xticks(rotation=45) ax.set(ylabel=f"skill score", xlabel="", title="summary of all stations") handles, _ = ax.get_legend_handles_labels() ax.legend(handles, self._labels) @@ -969,7 +1002,8 @@ class PlotAvailabilityHistogram(AbstractPlotClass): plot_dataset.plot.step(color=colors[subset], ax=axes, label=subset) plt.fill_between(plot_dataset.coords[self.temporal_dim].values, plot_dataset.values, color=colors[subset]) - lgd = fig.legend(loc="upper right", ncol=len(self.dataset_time_interval)) + lgd = fig.legend(loc="upper right", ncol=len(self.dataset_time_interval), + facecolor='white', framealpha=1, edgecolor='black') for lgd_line in lgd.get_lines(): lgd_line.set_linewidth(4.0) plt.gca().xaxis.set_major_locator(mdates.YearLocator())