def subplot_data(fig: matplotlib.figure.Figure, subplot_params: tuple, timestamps: list, data: np.array, x_label: str, y_label: str, event_timestamps: list = None, data_label: str = None, fontsize: int = 30, event_annotation_color='g') -> None: '''Plots a given time series data on a subplot. Keyword arguments: fig -- matplotlib figure handle subplot_params -- a tuple with three subplot parameters: number of rows, number of columns, and the number of the current subplot timestamps -- a list of timestamps (plotted over the x-axis) data -- a one-dimensional numpy array of data items (plotted over the y-axis) x_label -- x axis label y_label -- y axis label event_timestamps -- optional list of timestamps for data annotation; the annotations are plotted as lines at the given timestamps (default None, in which case there are no annotations) data_label -- optional label for the plotted data; if a label is given, a legend is added to the plot (default None) fontsize -- fontsize for the x and y axes labels (default 30) event_annotation_color -- color of event annotation lines (default 'g') ''' fig.add_subplot(*subplot_params) # we plot the data if data_label: plt.plot(timestamps, data, label=data_label) else: plt.plot(timestamps, data) # we add event annotations to the plot if there are any events if event_timestamps is not None and len(event_timestamps) > 0: plt.plot([event_timestamps, event_timestamps], [np.nanmin(data), np.nanmax(data)], event_annotation_color) plt.xlabel(x_label, fontsize=fontsize) plt.ylabel(y_label, fontsize=fontsize) # we add a legend only if a data label is assigned if data_label: plt.legend()
def hfss_plot_convergences_report(convergence_t: pd.core.frame.DataFrame, convergence_f: pd.core.frame.DataFrame, fig: mpl.figure.Figure = None, _display=True): """Plot convergence frequency vs. pass number if fig is None. Plot delta frequency and solved elements vs. pass number. Plot delta frequency vs. solved elements. Args: convergence_t (pandas.core.frame.DataFrame): Convergence vs pass number of the eigenemode freqs. convergence_f (pandas.core.frame.DataFrame): Convergence vs pass number of the eigenemode freqs. fig (matplotlib.figure.Figure, optional): A mpl figure. Defaults to None. _display (bool, optional): Display the plot? Defaults to True. """ if fig is None: fig = plt.figure(figsize=(11, 3.)) # Grid spec and axes; height_ratios=[4, 1], wspace=0.5 gs = mpl.gridspec.GridSpec(1, 3, width_ratios=[1.2, 1.5, 1]) axs = [fig.add_subplot(gs[i]) for i in range(3)] ax0t = axs[1].twinx() plot_convergence_f_vspass(axs[0], convergence_f) plot_convergence_max_df(axs[1], convergence_t.iloc[:, 1]) plot_convergence_solved_elem(ax0t, convergence_t.iloc[:, 0]) plot_convergence_maxdf_vs_sol(axs[2], convergence_t.iloc[:, 1], convergence_t.iloc[:, 0]) fig.tight_layout(w_pad=0.1) # pad=0.0, w_pad=0.1, h_pad=1.0)
def setup_ax(fig: matplotlib.figure.Figure, pos: tuple[int, int, int] = (1, 1, 1), ) -> matplotlib.axes.Axes: ''' Args - fig: matplotlib.figure.Figure - pos: 3-tuple of int, axes position (nrows, ncols, index) Returns: matplotlib.axes.Axes ''' ax = fig.add_subplot(*pos, projection=ccrs.PlateCarree()) # draw land (better version of cfeature.LAND) # land = cfeature.NaturalEarthFeature( # category='physical', name='land', scale='10m', # edgecolor='face', facecolor=cfeature.COLORS['land'], zorder=-1) ax.add_feature(cfeature.LAND) # draw borders of countries (better version of cfeature.BORDERS) countries = cfeature.NaturalEarthFeature( category='cultural', name='admin_0_boundary_lines_land', scale='10m', edgecolor='black', facecolor='none') ax.add_feature(countries) # draw coastline (better version of cfeature.COASTLINE) coastline = cfeature.NaturalEarthFeature( category='physical', name='coastline', scale='10m', edgecolor='black', facecolor='none') ax.add_feature(coastline) # draw lakes (better version of cfeature.LAKES) lakes = cfeature.NaturalEarthFeature( category='physical', name='lakes', scale='10m', edgecolor='face', facecolor=cfeature.COLORS['water']) ax.add_feature(lakes) # draw ocean (better version of cfeature.OCEAN) ocean = cfeature.NaturalEarthFeature( category='physical', name='ocean', scale='50m', edgecolor='face', facecolor=cfeature.COLORS['water'], zorder=-1) ax.add_feature(ocean) # draw rivers (better version of cfeature.RIVERS) rivers = cfeature.NaturalEarthFeature( category='physical', name='rivers_lake_centerlines', scale='10m', edgecolor=cfeature.COLORS['water'], facecolor='none') ax.add_feature(rivers) # draw borders of states/provinces internal to a country states_provinces = cfeature.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lines', scale='50m', edgecolor='gray', facecolor='none') ax.add_feature(states_provinces) ax.set_aspect('equal') gridliner = ax.gridlines(draw_labels=True) gridliner.top_labels = False gridliner.right_labels = False return ax
def plot_convergences(self, convergence_t: pd.DataFrame = None, convergence_f: pd.DataFrame = None, fig: mpl.figure.Figure = None, _display: bool = True): """Creates 3 plots, useful to determin the convergence achieved by the renderer: * convergence frequency vs. pass number if fig is None. * delta frequency and solved elements vs. pass number. * delta frequency vs. solved elements. Args: convergence_t (pd.DataFrame): Convergence vs pass number of the eigenemode freqs. convergence_f (pd.DataFrame): Convergence vs pass number of the eigenemode freqs. fig (matplotlib.figure.Figure, optional): A mpl figure. Defaults to None. _display (bool, optional): Display the plot? Defaults to True. """ if convergence_t is None: convergence_t = self.convergence_t if convergence_f is None: convergence_f = self.convergence_f if fig is None: fig = plt.figure(figsize=(11, 3.)) # Grid spec and axes; height_ratios=[4, 1], wspace=0.5 gspec = mpl.gridspec.GridSpec(1, 3, width_ratios=[1.2, 1.5, 1]) axs = [fig.add_subplot(gspec[i]) for i in range(3)] ax0t = axs[1].twinx() plot_convergence_f_vspass(axs[0], convergence_f) plot_convergence_max_df(axs[1], convergence_t.iloc[:, 1]) plot_convergence_solved_elem(ax0t, convergence_t.iloc[:, 0]) plot_convergence_maxdf_vs_sol(axs[2], convergence_t.iloc[:, 1], convergence_t.iloc[:, 0]) fig.tight_layout(w_pad=0.1) # pad=0.0, w_pad=0.1, h_pad=1.0)
def plot_avg_decay_data(t_sol: Union[np.ndarray, List[np.array]], list_sim_data: List[np.array], list_exp_data: List[np.array] = None, state_labels: List[str] = None, concentration: Conc = None, atol: float = A_TOL, colors: Union[str, Tuple[ColorMap, ColorMap]] = 'rk', fig: mpl.figure.Figure = None, title: str = '') -> None: ''' Plot the list of simulated and experimental data (optional) against time in t_sol. If concentration is given, the legend will show the concentrations. colors is a string with two chars. The first is the sim color, the second the exp data color. ''' num_plots = len(list_sim_data) num_rows = 3 num_cols = int(np.ceil(num_plots / 3)) # optional lists default to list of None list_exp_data = list_exp_data or [None] * num_plots state_labels = state_labels or [''] * num_plots list_t_sim = t_sol if len( t_sol) == num_plots else [t_sol] * num_plots # type: List[np.array] if concentration: conc_str = '_' + str(concentration.S_conc) + 'S_' + str( concentration.A_conc) + 'A' # state_labels = [label+conc_str for label in state_labels] else: conc_str = '' sim_color = colors[0] exp_color = colors[1] exp_size = 2 # marker size exp_marker = '.' if fig is None: fig = plt.figure() fig.suptitle(title + '. Time in ms.') list_axes = fig.get_axes() # type: List if not list_axes: for num in range(num_plots): fig.add_subplot(num_rows, num_cols, num + 1) list_axes = fig.get_axes() for sim_data, t_sim, exp_data, state_label, axes\ in zip(list_sim_data, list_t_sim, list_exp_data, state_labels, list_axes): if state_label: axes.set_title( state_label.replace('_', ' '), { 'horizontalalignment': 'center', 'verticalalignment': 'center', 'fontweight': 'bold', 'fontsize': 10 }) if sim_data is None or np.isnan(sim_data).any() or not np.any( sim_data > 0): continue # no exp data: either a GS or simply no exp data available if exp_data is 0 or exp_data is None: # nonposy='clip': clip non positive values to a very small positive number axes.semilogy(t_sim * 1000, sim_data, color=sim_color, label=state_label + conc_str) axes.axis('tight') axes.set_xlim(left=t_sim[0] * 1000.0) # add some white space above and below margin_factor = np.array([0.7, 1.3]) axes.set_ylim(*np.array(axes.get_ylim()) * margin_factor) if axes.set_ylim()[0] < atol: axes.set_ylim(bottom=atol) # don't show noise below atol # detect when the simulation goes above and below atol above = sim_data > atol change_indices = np.where(np.roll(above, 1) != above)[0] # make sure change_indices[-1] happens when the population is going BELOW atol if change_indices.size > 1 and sim_data[ change_indices[-1]] < atol: # pragma: no cover # last time it changes max_index = change_indices[-1] # show simData until it falls below atol axes.set_xlim(right=t_sim[max_index] * 1000) min_y = min(*axes.get_ylim()) max_y = max(*axes.get_ylim()) axes.set_ylim(bottom=min_y, top=max_y) else: # exp data available sim_handle, = axes.semilogy(t_sim * 1000, sim_data, color=sim_color, label=state_label + conc_str, zorder=10) # convert exp_data time to ms exp_handle, = axes.semilogy(exp_data[:, 0] * 1000, exp_data[:, 1] * np.max(sim_data), color=exp_color, marker=exp_marker, linewidth=0, markersize=exp_size, zorder=1) axes.axis('tight') axes.set_ylim(top=axes.get_ylim()[1] * 1.2) # add some white space on top tmin = min(exp_data[-1, 0], t_sim[0]) axes.set_xlim(left=tmin * 1000.0, right=exp_data[-1, 0] * 1000) # don't show beyond expData if conc_str: list_axes[0].legend(loc="best", fontsize='small') curr_handles, curr_labels = list_axes[0].get_legend_handles_labels() new_labels = [ label.replace(state_labels[0] + '_', '').replace('_', ', ') for label in curr_labels ] list_axes[0].legend(curr_handles, new_labels, markerscale=5, loc="best", fontsize='small') fig.subplots_adjust(top=0.918, bottom=0.041, left=0.034, right=0.99, hspace=0.275, wspace=0.12)
def subplot_data_lists(fig: matplotlib.figure.Figure, subplot_params: tuple, timestamps: list, data: np.array, x_label: str, y_label: str, event_timestamps: list = None, data_labels: list = None, data_colors: list = None, fontsize: int = 30, event_annotation_color='g') -> None: '''Plots multiple time series on a single subplot. Keyword arguments: fig -- matplotlib figure handle subplot_params -- a tuple with three subplot parameters: number of rows, number of columns, and the number of the current subplot timestamps -- a list of timestamps (plotted over the x-axis) data -- a 2D numpy array of time series (plotted over the y-axis), where each column represents a single time series x_label -- x axis label y_label -- y axis label event_timestamps -- optional list of timestamps for data annotation; the annotations are plotted as green lines at the given timestamps (default None, in which case there are no annotations) data_labels -- a list of optional labels for the plotted data, where the size of the list should match the number of columns in "data"; if this parameter is passed, a legend is added to the plot (default None) data_colors -- a list of optional colors for the plotted data, where the size of the list should match the number of columns in "data" fontsize -- fontsize for the x and y axes labels (default 30) event_annotation_color -- color of event annotation lines (default 'g') ''' if data_labels: try: assert data.shape[1] == len(data_labels) except AssertionError: print( 'The length of data_labels should match the number of columns in data' ) return if data_colors: try: assert data.shape[1] == len(data_colors) except AssertionError: print( 'The length of data_colors should match the number of columns in data' ) return fig.add_subplot(*subplot_params) # we plot the data if data_labels and data_colors: for i in range(data.shape[1]): plt.plot(timestamps, data[:, i], label=data_labels[i], color=data_colors[i]) elif data_labels: for i in range(data.shape[1]): plt.plot(timestamps, data[:, i], label=data_labels[i]) elif data_colors: for i in range(data.shape[1]): plt.plot(timestamps, data[:, i], color=data_colors[i]) else: for i in range(data.shape[1]): plt.plot(timestamps, data[:, i]) # we add event annotations to the plot if there are any events if event_timestamps is not None and len(event_timestamps) > 0: plt.plot([event_timestamps, event_timestamps], [np.nanmin(data), np.nanmax(data)], event_annotation_color) plt.xlabel(x_label, fontsize=fontsize) plt.ylabel(y_label, fontsize=fontsize) # we add a legend only if a data label is assigned if data_labels: plt.legend()