def quantile_plot( ax: matplotlib.axes.Axes, x: np.ndarray, median: np.ndarray, lower: np.ndarray, upper: np.ndarray, shaded_kwargs: Dict[str, Any], line_kwargs: Dict[str, Any]) -> List[matplotlib.lines.Line2D]: """Create mean +- sd plot.""" ax.fill_between(x, lower, upper, **shaded_kwargs) return ax.plot(x, median, **line_kwargs)
def spm_plot(ax: matplotlib.axes.Axes, x: np.ndarray, spm_test: _SPM0Dinference, shaded_kwargs: Dict[str, Any], line_kwargs: Dict[str, Any]) -> List[matplotlib.lines.Line2D]: """Create SPM plot.""" ax.axhline(spm_test.zstar, ls='--', color='grey') ax.axhline(-spm_test.zstar, ls='--', color='grey') ax.fill_between(x, spm_test.zstar, spm_test.z, where=(spm_test.z > spm_test.zstar), **shaded_kwargs) ax.fill_between(x, -spm_test.zstar, spm_test.z, where=(spm_test.z < -spm_test.zstar), **shaded_kwargs) return ax.plot(x, spm_test.z, **line_kwargs)
def fill_under( ax: matplotlib.axes.Axes, x: List[float], y: List[float], between: Optional[Tuple[float, float]] = None, **kwargs, ) -> None: """Fill under a curve with fill limited by x-range in between""" where = None if between is None else is_in_range(x, between[0], between[1]) ax.fill_between(x, y, [0] * len(x), where=where, **kwargs)
def _plot_data(ax: mpl.axes.Axes, data: PlotData) -> Optional[List[mpl.lines.Line2D]]: x, y = None, None lines = None # Return line objects so we can add legends disp = data.display_attributes if isinstance(data, XYData) or isinstance(data, TimeSeries): x, y = (data.x, data.y) if isinstance(data, XYData) else (np.arange(len(data.timestamps)), data.values) if isinstance(disp, LinePlotAttributes): lines, = ax.plot(x, y, linestyle=disp.line_type, linewidth=disp.line_width, color=disp.color) if disp.marker is not None: # type: ignore ax.scatter(x, y, marker=disp.marker, c=disp.marker_color, s=disp.marker_size, zorder=100) elif isinstance(disp, ScatterPlotAttributes): lines = ax.scatter(x, y, marker=disp.marker, c=disp.marker_color, s=disp.marker_size, zorder=100) elif isinstance(disp, BarPlotAttributes): lines = ax.bar(x, y, color=disp.color) # type: ignore elif isinstance(disp, FilledLinePlotAttributes): x, y = np.nan_to_num(x), np.nan_to_num(y) pos_values = np.where(y > 0, y, 0) neg_values = np.where(y < 0, y, 0) ax.fill_between(x, pos_values, color=disp.positive_color, step='post', linewidth=0.0) ax.fill_between(x, neg_values, color=disp.negative_color, step='post', linewidth=0.0) else: raise Exception(f'unknown plot combination: {type(data)} {type(disp)}') # For scatter and filled line, xlim and ylim does not seem to get set automatically if isinstance(disp, ScatterPlotAttributes) or isinstance(disp, FilledLinePlotAttributes): xmin, xmax = _adjust_axis_limit(ax.get_xlim(), x) if not np.isnan(xmin) and not np.isnan(xmax): ax.set_xlim((xmin, xmax)) ymin, ymax = _adjust_axis_limit(ax.get_ylim(), y) if not np.isnan(ymin) and not np.isnan(ymax): ax.set_ylim((ymin, ymax)) elif isinstance(data, TradeSet) and isinstance(disp, ScatterPlotAttributes): lines = ax.scatter(np.arange(len(data.timestamps)), data.values, marker=disp.marker, c=disp.marker_color, s=disp.marker_size, zorder=100) elif isinstance(data, TradeBarSeries) and isinstance(disp, CandleStickPlotAttributes): draw_candlestick(ax, np.arange(len(data.timestamps)), data.o, data.h, data.l, data.c, data.v, data.vwap, colorup=disp.colorup, colordown=disp.colordown) elif isinstance(data, BucketedValues) and isinstance(disp, BoxPlotAttributes): draw_boxplot( ax, data.bucket_names, data.bucket_values, disp.proportional_widths, disp.notched, # type: ignore disp.show_outliers, disp.show_means, disp.show_all) # type: ignore elif isinstance(data, XYZData) and (isinstance(disp, SurfacePlotAttributes) or isinstance(disp, ContourPlotAttributes)): display_type: str = 'contour' if isinstance(disp, ContourPlotAttributes) else 'surface' draw_3d_plot(ax, data.x, data.y, data.z, display_type, disp.marker, disp.marker_size, disp.marker_color, disp.interpolation, disp.cmap) else: raise Exception(f'unknown plot combination: {type(data)} {type(disp)}') return lines
def fill_to_zenith( ax: matplotlib.axes.Axes, az: np.ndarray, alt: np.ndarray, alpha: float = 0.2, color: Optional[str] = None ) -> None: """Fill the region between a curve and zenith.""" ax.fill_between( np.radians(az), 90.0 - alt, np.zeros_like(az), alpha=alpha, color=color, linewidth=0, )
def fill_to_horizon( ax: matplotlib.axes.Axes, az: np.ndarray, alt: np.ndarray, alpha: float = 0.2, color=None ) -> None: """Fill the region between a curve and the horizon.""" az = az[alt >= 0] alt = alt[alt >= 0] ax.fill_between( np.radians(az), 90.0 - alt, 100*np.ones_like(az), alpha=alpha, color=color, linewidth=0, )
def err_plot(x, y, yerr=None, xerr=None, axis: mpl.axes.Axes = None, **mpl_args): """Plot graph with error bars. Decided weather to plot points with error bars or lines with shaded areas depending on the number of plotted points. Parameters ---------- x, y : array_like x and y coordinates of the data to plot. yerr, xerr : array_like, optional The corresponding error of the data. Has same shape `x` and `y`. axis : mpl.axes.Axes, optional `mpl.axes.Axes` object used for plotting. mpl_args : Arguments for plotting passed to `axis.errorbar` or `axis.plot`. """ axis = plt.gca() if axis is None else axis x = np.asarray(x) if x.size > 50: # continuous plot try: ecolor = mpl_args.pop('ecolor') except KeyError: # no color defined -> try color else default ecolor = mpl_args.get('color', None) try: fmt = mpl_args.pop('fmt') except KeyError: baseline, = axis.plot(x, y, **mpl_args) else: baseline, = axis.plot(x, y, fmt, **mpl_args) if ecolor is None: ecolor = baseline.get_color() if yerr is not None: axis.fill_between(x, y-yerr, y+yerr, color=ecolor, alpha=.3, zorder=1) if xerr is not None: axis.fill_betweenx(y, x-xerr, x+xerr, color=ecolor, alpha=.3, zorder=1) else: default_args = {'capsize': 2.5, 'elinewidth': .3} default_args.update(mpl_args) axis.errorbar(x, y, yerr=yerr, **default_args)
def plot_lookahead_final_acceptance_fractions( sampler_df: Union[pd.DataFrame, str], population_sizes: Union[np.ndarray, History], relative: bool = False, fill: bool = False, alpha: float = None, t_min: int = 0, title: str = "Composition of final acceptances", size: tuple = None, ax: mpl.axes.Axes = None): """Plot fraction of look-ahead samples in final acceptances, over generations. Parameters ---------- sampler_df: Dataframe or file as generated via `RedisEvalParallelSampler(log_file=...)`. population_sizes: The sizes of the populations of accepted particles. If a History is passed, those values are extracted automatically, otherwise should be for the same time values as `sampler_df`. relative: Whether to normalize the total evaluations for each generation to 1. fill: If True, instead of lines, filled areas are drawn that sum up to the totals. alpha: Alpha value for lines or areas. t_min: The minimum generation to show. E.g. a value of 1 omits the first generation. title: Plot title. size: The size of the plot in inches. ax: The axis object to use. Returns ------- ax: Axis of the generated plot. """ # process input if isinstance(sampler_df, str): sampler_df = pd.read_csv(sampler_df, sep=',') if alpha is None: alpha = 0.7 if fill else 1.0 # create figure if ax is None: fig, ax = plt.subplots() else: fig = ax.get_figure() # get numbers of final acceptances if isinstance(population_sizes, History): pop = population_sizes.get_all_populations() population_sizes = np.array( [pop.loc[pop.t == t, 'particles'] for t in sampler_df.t], dtype=float).flatten() # restrict to t >= 0 population_sizes = population_sizes[sampler_df.t >= t_min] sampler_df = sampler_df[sampler_df.t >= t_min] # extract variables t = sampler_df.t n_la_acc = sampler_df.n_lookahead_accepted # actual look-ahead acceptances cannot be more than requested n_la_acc = np.minimum(n_la_acc, population_sizes) # actual acceptances are the remaining ones, as these are always later n_act_acc = population_sizes - n_la_acc # normalize if relative: n_la_acc /= population_sizes n_act_acc /= population_sizes population_sizes /= population_sizes # plot if fill: ax.fill_between(t, n_la_acc, population_sizes, alpha=alpha, label="Actual") ax.fill_between(t, 0, n_la_acc, alpha=alpha, label="Look-ahead") else: ax.plot(t, population_sizes, linestyle='--', marker='o', color='black', alpha=alpha, label="Population size") ax.plot(t, n_act_acc, marker='o', alpha=alpha, label="Actual") ax.plot(t, n_la_acc, marker='o', alpha=alpha, label="Look-ahead") # prettify plot ax.legend() ax.set_title(title) ax.set_xlabel("Population index") ax.set_ylabel("Final acceptances") ax.set_ylim(bottom=0) # enforce integer ticks ax.xaxis.set_major_locator(MaxNLocator(integer=True)) if size is not None: fig.set_size_inches(size) return ax
def plot_lookahead_evaluations(sampler_df: Union[pd.DataFrame, str], relative: bool = False, fill: bool = False, alpha: float = None, t_min: int = 0, title: str = "Total evaluations", size: tuple = None, ax: mpl.axes.Axes = None): """Plot total vs look-ahead evaluations over the generations. Parameters ---------- sampler_df: Dataframe or file as generated via `RedisEvalParallelSampler(log_file=...)`. relative: Whether to normalize the total evaluations for each generation to 1. fill: If True, instead of lines, filled areas are drawn that sum up to the totals. alpha: Alpha value for lines or areas. t_min: The minimum generation to show. E.g. a value of 1 omits the first generation. title: Plot title. size: The size of the plot in inches. ax: The axis object to use. Returns ------- ax: Axis of the generated plot. """ # process input if isinstance(sampler_df, str): sampler_df = pd.read_csv(sampler_df, sep=',') if alpha is None: alpha = 0.7 if fill else 1.0 # create figure if ax is None: fig, ax = plt.subplots() else: fig = ax.get_figure() # restrict to t >= 0 sampler_df = sampler_df[sampler_df.t >= t_min] # extract variables t = sampler_df.t n_la = sampler_df.n_lookahead n_eval = sampler_df.n_evaluated n_act = n_eval - n_la # normalize if relative: n_la /= n_eval n_act /= n_eval n_eval /= n_eval # plot if fill: ax.fill_between(t, n_la, n_eval, alpha=alpha, label="Actual") ax.fill_between(t, 0, n_la, alpha=alpha, label="Look-ahead") else: ax.plot(t, n_eval, linestyle='--', marker='o', color='black', alpha=alpha, label="Total") ax.plot(t, n_act, marker='o', alpha=alpha, label="Actual") ax.plot(t, n_la, marker='o', alpha=alpha, label="Look-ahead") # prettify plot ax.legend() ax.set_title(title) ax.set_xlabel("Population index") ax.set_ylabel("Evaluations") ax.set_ylim(bottom=0) # enforce integer ticks ax.xaxis.set_major_locator(MaxNLocator(integer=True)) if size is not None: fig.set_size_inches(size) return ax
def plot( self, x_label: str = "Method 1", y_label: str = "Method 2", title: str = None, line_reference: bool = True, line_CI: bool = True, legend: bool = True, square: bool = False, ax: matplotlib.axes.Axes = None, point_kws: Optional[Dict] = None, color_regr: Optional[str] = None, alpha_regr: Optional[float] = None, ) -> matplotlib.axes.Axes: """Plot regression result Parameters ---------- x_label : str, optional The label which is added to the X-axis. (default: "Method 1") y_label : str, optional The label which is added to the Y-axis. (default: "Method 2") title : str, optional Title of the regression plot. If None is provided, no title will be plotted. line_reference : bool, optional If True, a grey reference line at y=x will be plotted in the plot (default: True) line_CI : bool, optional If True, dashed lines will be plotted at the boundaries of the confidence intervals. (default: False) legend : bool, optional If True, will provide a legend containing the computed regression equation. (default: True) square : bool, optional If True, set the Axes aspect to "equal" so each cell will be square-shaped. (default: True) ax : matplotlib.axes.Axes, optional matplotlib axis object, if not passed, uses gca() point_kws : Optional[Dict], optional Additional keywords to plt color_regr : Optional[str], optional color for regression line and CI area alpha_regr : Optional[float], optional alpha for regression CI area Returns ------------------ matplotlib.axes.Axes axes object with the plot """ ax = ax or plt.gca() # Set scatter plot keywords to defaults and apply override pkws = self.DEFAULT_POINT_KWS.copy() pkws.update(point_kws or {}) # Get regression parameters slope = self.result["slope"] intercept = self.result["intercept"] # plot individual points ax.scatter(self.method1, self.method2, **pkws) # plot reference line if line_reference: ax.plot( [0, 1], [0, 1], label="Reference", color="grey", linestyle="--", transform=ax.transAxes, ) # Compute x and y values xvals = np.array(ax.get_xlim()) yvals = xvals[:, None] * slope + intercept # Plot regression line 0 ax.plot( xvals, yvals[:, 0], label= f"{y_label} = {intercept[0]:.2f} + {slope[0]:.2f} * {x_label}", color=color_regr, linestyle="-", ) # Plot confidence region if yvals.shape[1] > 2: ax.fill_between( xvals, yvals[:, 1], yvals[:, 2], color=color_regr or self.DEFAULT_REGRESSION_KWS["color"], alpha=alpha_regr or self.DEFAULT_REGRESSION_KWS["alpha"], ) if line_CI: ax.plot(xvals, yvals[:, 1], linestyle="--") ax.plot(xvals, yvals[:, 2], linestyle="--") # Set axes labels ax.set( xlabel=x_label or "", ylabel=y_label or "", title=title or "", ) if legend: ax.legend(loc="upper left", frameon=False) if square: ax.set_aspect("equal") return ax
def mean_sd_plot(ax: matplotlib.axes.Axes, x: np.ndarray, mean: np.ndarray, sd: np.ndarray, shaded_kwargs: Dict[str, Any], line_kwargs: Dict[str, Any]) -> List[matplotlib.lines.Line2D]: """Create mean +- sd plot.""" ax.fill_between(x, mean - sd, mean + sd, **shaded_kwargs) return ax.plot(x, mean, **line_kwargs)
def plot( self, figsize: Tuple[float, float] = (15, 10), same_plot: bool = False, hide_cells: bool = False, perc: Tuple[float, float] = None, abs_prob_cmap: mcolors.ListedColormap = cm.viridis, cell_color: str = "black", lineage_color: str = "black", alpha: float = 0.8, lineage_alpha: float = 0.2, title: Optional[str] = None, size: int = 15, lw: float = 2, show_cbar: bool = True, margins: float = 0.015, xlabel: str = "pseudotime", ylabel: str = "expression", show_conf_int: bool = True, dpi: int = None, fig: mpl.figure.Figure = None, ax: mpl.axes.Axes = None, return_fig: bool = False, save: Optional[str] = None, ) -> Optional[mpl.figure.Figure]: """ Plot the smoothed gene expression. Parameters ---------- figsize Size of the figure. same_plot Whether to plot all trends in the same plot. hide_cells Whether to hide the cells. perc Percentile by which to clip the absorption probabilities./ abs_prob_cmap Colormap to use when coloring in the absorption probabilities. cell_color Color for the cells when not coloring absorption probabilities. lineage_color Color for the lineage. alpha Alpha channel for cells. lineage_alpha Alpha channel for lineage confidence intervals. title Title of the plot. size Size of the points. lw Line width for the smoothed values. show_cbar Whether to show colorbar. margins Margins around the plot. xlabel Label on the x-axis. ylabel Label on the y-axis. show_conf_int Whether to show the confidence interval. dpi Dots per inch. fig Figure to use, if `None`, create a new one. ax: :class:`matplotlib.axes.Axes` Ax to use, if `None`, create a new one. return_fig If `True`, return the figure object. save Filename where to save the plot. If `None`, just shows the plots. Returns ------- %(just_plots)s """ if fig is None or ax is None: fig, ax = plt.subplots(figsize=figsize, constrained_layout=True) if dpi is not None: fig.set_dpi(dpi) vmin, vmax = _minmax(self.w, perc) if not hide_cells: _ = ax.scatter( self.x_all.squeeze(), self.y_all.squeeze(), c=cell_color if same_plot or np.allclose(self.w_all, 1.0) else self.w_all.squeeze(), s=size, cmap=abs_prob_cmap, vmin=vmin, vmax=vmax, alpha=alpha, ) if title is None: title = f"{self._gene} @ {self._lineage}" _ = ax.plot(self.x_test, self.y_test, color=lineage_color, lw=lw, label=title) ax.set_title(title) ax.set_ylabel(ylabel) ax.set_xlabel(xlabel) ax.margins(margins) if show_conf_int and self.conf_int is not None: ax.fill_between( self.x_test.squeeze(), self.conf_int[:, 0], self.conf_int[:, 1], alpha=lineage_alpha, color=lineage_color, linestyle="--", ) if (show_cbar and not hide_cells and not same_plot and not np.allclose(self.w_all, 1)): norm = mcolors.Normalize(vmin=vmin, vmax=vmax) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="2.5%", pad=0.1) _ = mpl.colorbar.ColorbarBase(cax, norm=norm, cmap=abs_prob_cmap, label="absorption probability") if save is not None: save_fig(fig, save) if return_fig: return fig
def plot( self, figsize: Tuple[float, float] = (8, 5), same_plot: bool = False, hide_cells: bool = False, perc: Tuple[float, float] = None, abs_prob_cmap: mcolors.ListedColormap = cm.viridis, cell_color: str = "black", lineage_color: str = "black", alpha: float = 0.8, lineage_alpha: float = 0.2, title: Optional[str] = None, size: int = 15, lw: float = 2, cbar: bool = True, margins: float = 0.015, xlabel: str = "pseudotime", ylabel: str = "expression", conf_int: bool = True, lineage_probability: bool = False, lineage_probability_conf_int: Union[bool, float] = False, lineage_probability_color: Optional[str] = None, dpi: int = None, fig: mpl.figure.Figure = None, ax: mpl.axes.Axes = None, return_fig: bool = False, save: Optional[str] = None, **kwargs, ) -> Optional[mpl.figure.Figure]: """ Plot the smoothed gene expression. Parameters ---------- figsize Size of the figure. same_plot Whether to plot all trends in the same plot. hide_cells Whether to hide the cells. perc Percentile by which to clip the absorption probabilities. abs_prob_cmap Colormap to use when coloring in the absorption probabilities. cell_color Color for the cells when not coloring absorption probabilities. lineage_color Color for the lineage. alpha Alpha channel for cells. lineage_alpha Alpha channel for lineage confidence intervals. title Title of the plot. size Size of the points. lw Line width for the smoothed values. cbar Whether to show colorbar. margins Margins around the plot. xlabel Label on the x-axis. ylabel Label on the y-axis. conf_int Whether to show the confidence interval. lineage_probability Whether to show smoothed lineage probability as a dashed line. Note that this will require 1 additional model fit. lineage_probability_conf_int Whether to compute and show smoothed lineage probability confidence interval. If :paramref:`self` is :class:`cellrank.ul.models.GAMR`, it can also specify the confidence level, the default is `0.95`. Only used when ``show_lineage_probability=True``. lineage_probability_color Color to use when plotting the smoothed ``lineage_probability``. If `None`, it's the same as ``lineage_color``. Only used when ``show_lineage_probability=True``. dpi Dots per inch. fig Figure to use, if `None`, create a new one. ax: :class:`matplotlib.axes.Axes` Ax to use, if `None`, create a new one. return_fig If `True`, return the figure object. save Filename where to save the plot. If `None`, just shows the plots. **kwargs Keyword arguments for :meth:`matplotlib.axes.Axes.legend`, e.g. to disable the legend, specify ``loc=None``. Only available when ``show_lineage_probability=True``. Returns ------- %(just_plots)s """ if self.y_test is None: raise RuntimeError("Run `.predict()` first.") if fig is None or ax is None: fig, ax = plt.subplots(figsize=figsize, constrained_layout=True) if dpi is not None: fig.set_dpi(dpi) conf_int = conf_int and self.conf_int is not None hide_cells = (hide_cells or self.x_all is None or self.w_all is None or self.y_all is None) lineage_probability_color = (lineage_color if lineage_probability_color is None else lineage_probability_color) scaler = kwargs.pop( "scaler", self._create_scaler( lineage_probability, show_conf_int=conf_int, ), ) if lineage_probability: if ylabel in ("expression", self._gene): ylabel = f"scaled {ylabel}" vmin, vmax = None, None if not hide_cells: vmin, vmax = _minmax(self.w_all, perc) _ = ax.scatter( self.x_all.squeeze(), scaler(self.y_all.squeeze()), c=cell_color if same_plot or np.allclose(self.w_all, 1.0) else self.w_all.squeeze(), s=size, cmap=abs_prob_cmap, vmin=vmin, vmax=vmax, alpha=alpha, ) if title is None: title = (f"{self._gene} @ {self._lineage}" if self._lineage is not None else f"{self._gene}") ax.plot(self.x_test, scaler(self.y_test), color=lineage_color, lw=lw, label=title) if title is not None: ax.set_title(title) if ylabel is not None: ax.set_ylabel(ylabel) if xlabel is not None: ax.set_xlabel(xlabel) ax.margins(margins) if conf_int: ax.fill_between( self.x_test.squeeze(), scaler(self.conf_int[:, 0]), scaler(self.conf_int[:, 1]), alpha=lineage_alpha, color=lineage_color, linestyle="--", ) if (lineage_probability and not isinstance(self, FittedModel) and not np.allclose(self.w, 1.0)): from cellrank.pl._utils import _is_any_gam_mgcv model = deepcopy(self) model._y = self._reshape_and_retype(self.w).copy() model = model.fit() if not lineage_probability_conf_int: y = model.predict() elif _is_any_gam_mgcv(model): y = model.predict( level=lineage_probability_conf_int if isinstance( lineage_probability_conf_int, float) else 0.95) else: y = model.predict() model.confidence_interval() ax.fill_between( model.x_test.squeeze(), model.conf_int[:, 0], model.conf_int[:, 1], alpha=lineage_alpha, color=lineage_probability_color, linestyle="--", ) handle = ax.plot( model.x_test, y, color=lineage_probability_color, lw=lw, linestyle="--", zorder=-1, label="probability", ) if kwargs.get("loc", "best") is not None: ax.legend(handles=handle, **kwargs) if (cbar and not hide_cells and not same_plot and not np.allclose(self.w_all, 1.0)): norm = mcolors.Normalize(vmin=vmin, vmax=vmax) divider = make_axes_locatable(ax) cax = divider.append_axes("right", size="2%", pad=0.1) _ = mpl.colorbar.ColorbarBase( cax, norm=norm, cmap=abs_prob_cmap, ticks=np.linspace(norm.vmin, norm.vmax, 5), ) if save is not None: save_fig(fig, save) if return_fig: return fig