def plot_3E(ax: plt.Axes):
    sns.set_palette(sns.color_palette(['white']))
    L = []
    for pid in DataExp2.pids:
        data = DataExp2(pid)
        m1 = data.load_model(
            models.ChoiceModel4Param,
            DataExp1(pid).build_model(models.ChoiceModel4Param).fit())
        df = data.cross_validate(models.ChoiceModel4Param)
        df['choice'] = data.df['choice']
        L.append(
            m1.fit().log_likelihood -
            np.log(df.apply(lambda row: row[row['choice']], axis=1)).sum())
    sns.boxplot(data=L, fliersize=0, ax=ax, linewidth=0.5, width=0.2)
    sns.scatterplot(x=np.linspace(-0.09, 0.09, 12),
                    y=L,
                    fc='white',
                    ec=sns_edge_color('white'),
                    ax=ax,
                    s=5,
                    linewidth=0.5,
                    zorder=11,
                    clip_on=False,
                    legend=False)
    # sns.stripplot(data=L, jitter=True, ax=ax, size=2.5, linewidth=0.5, zorder=10, clip_on=False)
    ax.axhline(0, 0, 1, color='k', zorder=1)
    ax.set_xlim(-0.2, 0.2)
    ax.set_ylabel(r'$\mathcal{L}$(transfer) - $\mathcal{L}$(fitted)')
    ax.set_xticks([])
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    ax.spines['bottom'].set_visible(False)
    plt.tight_layout()
Example #2
0
    def draw_LX_bounds(self, ax: plt.Axes, redshifts_on: bool = True):
        self.hconv = 0.70 / self.h

        ax.axhspan(self.bins[0][0] * 1e44 * self.hconv**2,
                   self.bins[-1][1] * 1e44 * self.hconv**2,
                   facecolor='lime',
                   linewidth=0,
                   alpha=0.2)
        ax.axhline(self.bins[0][0] * 1e44 * self.hconv**2,
                   color='lime',
                   linewidth=1,
                   alpha=0.1)

        for i, (luminosity_min, luminosity_max, redshift_min,
                redshift_max) in enumerate(self.bins):

            ax.axhline(luminosity_max * 1e44 * self.hconv**2,
                       color='lime',
                       linewidth=1,
                       alpha=0.1)

            # Print redshift bounds once every 2 bins to avoid clutter.
            if i % 2 == 0 and redshifts_on:
                ax.text(10**ax.get_xlim()[0],
                        10**(0.5 * np.log10(luminosity_min * luminosity_max)) *
                        1e44 * self.hconv**2,
                        f"$z$ = {redshift_min:.3f} - {redshift_max:.3f}",
                        horizontalalignment='left',
                        verticalalignment='center',
                        color='k',
                        alpha=0.3)
Example #3
0
def ma_plot(filename: str,
            *,
            count_col: str = DESEQ2_BASE_MEAN,
            padj_col: str = DESEQ2_PADJ,
            lfc_col: str = DESEQ2_LOG2_CHANGE,
            color_col: str = None,
            color: str = palette.gray(shade=30),
            accent_color: str = palette.red(),
            threshold: float = 0.05,
            use_threshold: bool = True,
            ax: plt.Axes = None,
            decorations: bool = True,
            **kwargs):
    data = pd.read_csv(filename)
    _validate(data, count_col, padj_col, lfc_col)
    if color_col is None:
        color_col = f"clr{np.random.randint(10000, 90000)}"
        data[color_col] = color
        if use_threshold:
            data.loc[data[padj_col] < threshold, color_col] = accent_color

    if ax is None:
        _, ax = plt.subplots()

    ax.scatter(data[count_col], data[lfc_col], color=data[color_col], **kwargs)

    if decorations:
        ax.axhline(0, ls="--", color=palette.black())
        ax.set_ylabel("Log$_2$ Fold Change")
        ax.set_xlabel("Average Normalized Counts")
Example #4
0
 def _plot_image(self, axis: plt.Axes=None, title: str=''):
     plt.ioff()
     if axis is None:
         fig, axis = plt.subplots()
     axis.imshow(self.array, cmap=get_dicom_cmap())
     axis.axhline(self.positions['vertical']*self.array.shape[0], color='r')  # y
     axis.axvline(self.positions['horizontal']*self.array.shape[1], color='r')  # x
     _remove_ticklabels(axis)
     axis.set_title(title)
Example #5
0
 def _plot_image(self, axis: plt.Axes=None, title: str=''):
     plt.ioff()
     if axis is None:
         fig, axis = plt.subplots()
     axis.imshow(self.image.array, cmap=get_dicom_cmap())
     axis.axhline(self.positions['horizontal']*self.image.array.shape[0], color='r')  # y
     axis.axvline(self.positions['vertical']*self.image.array.shape[1], color='r')  # x
     _remove_ticklabels(axis)
     axis.set_title(title)
Example #6
0
def mirror(spec_top: MsmsSpectrum,
           spec_bottom: MsmsSpectrum,
           color_ions: bool = True,
           annotate_ions: bool = True,
           ax: plt.Axes = None):
    """
    Mirror plot two MS/MS spectra.

    Parameters
    ----------
    spec_top : MsmsSpectrum
        The spectrum to be plotted on the top.
    spec_bottom : MsmsSpectrum
        The spectrum to be plotted on the bottom.
    color_ions : bool, optional
        Flag indicating whether or not to color annotated fragment ions. The
        default is True.
    annotate_ions : bool, optional
        Flag indicating whether or not to annotate fragment ions. The default
        is True.
    ax : plt.Axes, optional
        Axes instance on which to plot the spectrum. If None the current Axes
        instance is used.

    Returns
    -------
    plt.Axes
        The matplotlib Axes instance on which the spectra are plotted.
    """
    if ax is None:
        ax = plt.gca()

    # Top spectrum.
    spectrum(spec_top, color_ions, annotate_ions, False, ax)
    # Mirrored bottom spectrum.
    spectrum(spec_bottom, color_ions, annotate_ions, True, ax)

    ax.axhline(0, color='#9E9E9E', zorder=10)

    # Update axes so that both spectra fit.
    min_mz = max([
        0,
        math.floor(spec_top.mz[0] / 100 - 1) * 100,
        math.floor(spec_bottom.mz[0] / 100 - 1) * 100
    ])
    max_mz = max([
        math.ceil(spec_top.mz[-1] / 100 + 1) * 100,
        math.ceil(spec_bottom.mz[-1] / 100 + 1) * 100
    ])
    ax.set_xlim(min_mz, max_mz)
    ax.yaxis.set_major_formatter(
        mticker.FuncFormatter(lambda x, pos: f'{abs(x):.0%}'))
    ax.set_ylim(-1.15 if annotate_ions else -1.05,
                1.15 if annotate_ions else 1.05)

    return ax
Example #7
0
def entropy_vs_coupling(
    ax: plt.Axes,
    int_coupling: Union[list, np.ndarray],
    int_entropy: Union[list, np.ndarray],
    int_peaks: Optional[Union[list, np.ndarray]] = None,
    fit_coupling: Union[list, np.ndarray] = None,
    fit_entropy: Union[list, np.ndarray] = None,
    peak_diff_coupling: Optional[Union[list, np.ndarray]] = None,
    peak_diff: Optional[Union[list, np.ndarray]] = None,
) -> plt.Axes:
    """
    Plots fit and integrated entropy vs coupling gate

    Args:
        ax ():
        int_coupling ():
        int_entropy ():
        int_peaks (): Optional pass in to also plot the peak of integrated entropy as dotted line
        fit_coupling ():
        fit_entropy ():
        peak_diff_coupling:  x axis for peak - final
        peak_diff:  peak entropy - final entropy
    Returns:

    """
    ax.set_title('Entropy vs Coupling Gate')
    ax.set_xlabel('Coupling Gate (mV)')
    ax.set_ylabel('Entropy (kB)')

    line = ax.plot(int_coupling,
                   int_entropy,
                   marker='.',
                   label='From integration')[0]
    if int_peaks is not None:
        color = line.get_color()
        ax.plot(int_coupling,
                int_peaks,
                marker='.',
                linestyle='--',
                color=color,
                label='Peak from integration')
        ax.axhline(y=np.log(3), color='black', linestyle=':')
        if peak_diff_coupling is not None and peak_diff is not None:
            ax.plot(peak_diff_coupling,
                    peak_diff,
                    marker='x',
                    linestyle=':',
                    color='C3',
                    label='Peak - Final')

    ax.plot(fit_coupling, fit_entropy, marker='+', label='From dN/dT fit')
    ax.axhline(y=np.log(2), color='black', linestyle=':')

    ax.set_ylim(0, 1.5)
    ax.legend()
    return ax
Example #8
0
def measureTau(abf: pyabf.ABF,
               sweep: int,
               epoch: int = 3,
               percentile: float = .05,
               ax: plt.Axes = None):

    abf.setSweep(sweep)

    # use epoch table to determine puff times
    puffTimeStart = abf.sweepEpochs.p1s[epoch] / abf.sampleRate
    puffTimeEnd = abf.sweepEpochs.p2s[epoch] / abf.sampleRate

    # calculate baseline level
    baselineStart = puffTimeStart - .1
    baselineEnd = puffTimeStart
    baselineMean = getMean(abf, baselineStart, baselineEnd)

    # find antipeak
    antipeakIndex = getAntiPeakIndex(abf.sweepY, abf.sampleRate, puffTimeStart,
                                     puffTimeStart + .5)
    antipeakLevel = abf.sweepY[antipeakIndex]

    # find portion of curve to fit
    curveIndex1, curveIndex2 = getCurveIndexes(abf.sweepY, antipeakIndex,
                                               baselineMean, percentile)
    curveYs = -abf.sweepY[curveIndex1:curveIndex2]
    curveXs = np.arange(len(curveYs)) / abf.sampleRate

    try:
        p0 = (500, 15, 0)  # start with values near those we expect
        params, cv = scipy.optimize.curve_fit(monoExp, curveXs, curveYs, p0)
    except:
        print(f"FIT FAILED (sweep {sweep})")
        return None
    m, t, b = params
    curveYsIdeal = monoExp(curveXs, m, t, b)
    tauMS = 1000 / t
    if (tauMS < 0):
        return None

    if ax:
        yPad = abs(antipeakLevel - baselineMean) * .1
        ax.plot(abf.sweepX, abf.sweepY, alpha=.5)
        ax.grid(alpha=.5, ls='--')
        ax.axhline(baselineMean, ls='--', color='k')
        ax.plot(abf.sweepX[curveIndex1:curveIndex2], -curveYsIdeal, color='k')
        ax.set(title=f"first sweep tau = {tauMS:.02f} ms")
        ax.axis([
            baselineStart - .1, baselineStart + 1, antipeakLevel - yPad,
            baselineMean + yPad
        ])
        ax.axvspan(puffTimeEnd, puffTimeEnd + .5, color='g', alpha=.1)
        ax.axvspan(puffTimeEnd + .5, puffTimeEnd + .6, color='m', alpha=.1)

    return tauMS
Example #9
0
def _plot_2d(ax: plt.Axes, xlabel: str, ylabel: str, x: np.ndarray,
             y: np.ndarray, xlim, ylim, plot_kw):
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.axhline(0, c='k')
    ax.axvline(0, c='k')
    if xlim:
        ax.set_xlim(xlim)
    if ylim:
        ax.set_ylim(ylim)
    ax.plot(x, y, **plot_kw)
Example #10
0
 def _plot_flatness(self, direction: str, axis: plt.Axes=None):
     plt.ioff()
     if axis is None:
         fig, axis = plt.subplots()
     data = self.flatness[direction.lower()]
     axis.set_title(direction.capitalize() + " Flatness")
     axis.plot(data['profile'].values)
     _remove_ticklabels(axis)
     axis.axhline(data['profile max'], color='r')
     axis.axhline(data['profile min'], color='r')
     axis.axvline(data['profile left'], color='g', linestyle='-.')
     axis.axvline(data['profile right'], color='g', linestyle='-.')
Example #11
0
 def _plot_flatness(self, direction: str, axis: plt.Axes=None):
     plt.ioff()
     if axis is None:
         fig, axis = plt.subplots()
     data = self.flatness[direction.lower()]
     axis.set_title(direction.capitalize() + " Flatness")
     axis.plot(data['profile'].values)
     _remove_ticklabels(axis)
     axis.axhline(data['profile max'], color='r')
     axis.axhline(data['profile min'], color='r')
     axis.axvline(data['profile left'], color='g', linestyle='-.')
     axis.axvline(data['profile right'], color='g', linestyle='-.')
Example #12
0
def integrated_entropy(ax: plt.Axes, xs: List[np.ndarray],
                       datas: List[np.ndarray], labels: list) -> plt.Axes:
    """Plots integrated entropy vs gate voltage in real mV"""

    ax.set_xlabel('Sweep gate (mV)')
    ax.set_ylabel('Entropy (kB)')

    for x, data, label in zip(xs, datas, labels):
        ax.plot(x, data, label=label)

    for v in np.log(2), np.log(3):
        ax.axhline(v, linestyle=':', color='black')

    leg = ax.legend()
    ax.get_legend().set_title('Gamma/T')
    return ax
Example #13
0
def plot_fits(fits: xr.Dataset, offset: float = 0., ax: plt.Axes = None, **kwargs) -> None:
    """Plot the fitted curves."""
    if ax is None:
        ax = plt.gca()
    kwargs.setdefault("xlim", [0, fits["x"][-1].item()])
    kwargs.setdefault("marker", "o")
    kwargs.setdefault("fillstyle", "none")
    kwargs.setdefault("ls", "none")
    fits["yobs"].plot.line(ax=ax, **kwargs)
    ax.plot(fits["x"], fits["ycalc"])
    diff = fits["y"] - fits["ycalc"]
    shift = offset + fits["y"].min() - diff.max()
    diff += shift
    ax.axhline(shift, ls='--', alpha=0.5, color="black")
    ax.plot(fits["x"], diff)
    return
Example #14
0
 def _plot_image(self, axis: plt.Axes=None, title: str=''):
     plt.ioff()
     if axis is None:
         fig, axis = plt.subplots()
     axis.imshow(self.image.array, cmap=get_dicom_cmap())
     # show vertical/axial profiles
     left_profile = self.positions['vertical left']
     right_profile = self.positions['vertical right']
     axis.axvline(left_profile, color='b')
     axis.axvline(right_profile, color='b')
     # show horizontal/transverse profiles
     bottom_profile = self.positions['horizontal bottom']
     top_profile = self.positions['horizontal top']
     axis.axhline(bottom_profile, color='b')
     axis.axhline(top_profile, color='b')
     _remove_ticklabels(axis)
     axis.set_title(title)
Example #15
0
def scatter_peaks_no_peaks(
    top_eco: pd.DataFrame,
    top_naked: pd.DataFrame,
    non_top_eco: pd.DataFrame,
    non_top_naked: pd.DataFrame,
    ax: plt.Axes = None,
):
    if not ax:
        _, ax = plt.subplots(figsize=(12, 12))
    ax.set_xlabel("Chromatin")
    ax.set_ylabel("Naked")
    ax.scatter(
        non_top_eco,
        non_top_naked,
        alpha=0.2,
        label="All Points",
    )
    ax.scatter(top_eco, top_naked, label="Open ATAC")

    ax.axvline(non_top_eco.mean(), color="C0")
    ax.axvline(top_eco.mean(), color="C1")
    ax.axhline(non_top_naked.mean(), color="C0")
    ax.axhline(top_naked.mean(), color="C1")

    ax.legend(
        loc="upper right",
        frameon=False,
        shadow=False,
    )
    # We concatenate the two DFs to a single one so that the dropna() call will
    # "synced" between the two different rows
    top = pd.DataFrame({"chrom": top_eco, "naked": top_naked}).dropna(axis=0)
    all_ = pd.DataFrame({
        "chrom": non_top_eco,
        "naked": non_top_naked
    }).dropna(axis=0)
    r_top, _ = scipy.stats.pearsonr(top.loc[:, "chrom"], top.loc[:, "naked"])
    r_all, _ = scipy.stats.pearsonr(all_.loc[:, "chrom"], all_.loc[:, "naked"])
    ax.text(0.01,
            0.8,
            f"R (top) = {r_top} \nR (rest) = {r_all}",
            transform=ax.transAxes)
    return ax
def add_sh_order_lines(ax: plt.Axes,
                       order=None,
                       args_dict=None,
                       x_flag=True,
                       y_flag=True):
    if args_dict is None:
        args_dict = {}
    from src.utils.sphere import sh

    if order is None:
        order = sh.i2nm(np.floor(ax.get_xlim()[1]))[0]

    n = np.arange(order)
    m = n
    locs = sh.nm2i(n, m) + 0.5
    for loc in locs:
        if x_flag:
            ax.axvline(loc, color='red', **args_dict)
        if y_flag:
            ax.axhline(loc, color='red', **args_dict)
Example #17
0
def add_milestone_lines(
    ax: plt.Axes,
    milestones: List[Dict[str, Union[str, int]]],
    min_value: float,
    max_value: float,
    delta: float,
) -> plt.Axes:
    """Add the lines for the milestones the user reached.

    :param ax: The axis to draw the milestones into.
    :param milestones: The milestones to consider. Each must have a threshold and color.
    :param min_value: The minimum value to determine if a milestone should be included.
    :param max_value: The maximum value to determine if a milestone should be inlcuded.
    :param delta: Determines how "far away" milestone lines are still included.
    """
    for milestone in milestones:
        if max_value + delta >= milestone["threshold"] >= min_value - delta:
            ax.axhline(y=milestone["threshold"],
                       color=milestone["color"],
                       zorder=-1)
    return ax
Example #18
0
 def _plot_image(self, axis: plt.Axes = None, title: str = ''):
     plt.ioff()
     if axis is None:
         fig, axis = plt.subplots()
     axis.imshow(self.image.array, cmap=get_dicom_cmap())
     #show horizontal profiles
     left_profile = (
         self.positions['horizontal'] -
         self.widths['horizontal'] / 2) * self.image.array.shape[0]
     right_profile = (
         self.positions['horizontal'] +
         self.widths['horizontal'] / 2) * self.image.array.shape[0]
     axis.axhline(left_profile, color='r')  # X
     axis.axhline(right_profile, color='r')  # X
     #show vertical profiles
     bottom_profile = (
         self.positions['vertical'] -
         self.widths['vertical'] / 2) * self.image.array.shape[1]
     top_profile = (self.positions['vertical'] +
                    self.widths['vertical'] / 2) * self.image.array.shape[1]
     axis.axvline(bottom_profile, color='r')  # Y
     axis.axvline(top_profile, color='r')  # Y
     _remove_ticklabels(axis)
     axis.set_title(title)
Example #19
0
def add_contacts_to_plot(qc_frame: pd.DataFrame, axis: pyplot.Axes) -> None:
    if "OWC" in qc_frame:
        owc = qc_frame["OWC"].values[
            0]  # OWC is assumed constant in the dataframe
        axis.axhline(owc, color="black", linestyle="--", linewidth=1)
        axis.annotate(f"OWC={owc:g}", (0, owc))
    if "GOC" in qc_frame:
        goc = qc_frame["GOC"].values[0]
        axis.axhline(goc, color="black", linestyle="--", linewidth=1)
        axis.annotate(f"GOC={goc:g}", (0, goc))
    if "GWC" in qc_frame:
        gwc = qc_frame["GWC"].values[0]
        axis.axhline(gwc, color="black", linestyle="--", linewidth=1)
        axis.annotate(f"GWC={gwc:g}", (0, gwc))
Example #20
0
def draw_curve(plot_type: str,
               ax: plt.Axes,
               data: pd.DataFrame,
               x_grid: Union[list, np.ndarray, to.Tensor],
               x_label: Optional[Union[str, Sequence[str]]] = None,
               y_label: Optional[str] = None,
               curve_label: Optional[str] = None,
               area_label: Optional[str] = None,
               vline_level: Optional[float] = None,
               vline_label: str = 'approx. solved',
               title: Optional[str] = None,
               show_legend: bool = True,
               legend_kwargs: dict = None,
               plot_kwargs: dict = None) -> plt.Figure:
    """
    Create a box or violin plot for a list of data arrays or a pandas DataFrame.
    The plot is neither shown nor saved.

    .. note::
        If you want to have a tight layout, it is best to pass axes of a figure with `tight_layout=True` or
        `constrained_layout=True`.

        If you want to order the 4th element to the 2nd position in terms of colors use
        .. code-block:: python

            palette.insert(1, palette.pop(3))

    :param plot_type: tye of categorical plot, pass box or violin
    :param ax: axis of the figure to plot on
    :param data: pandas DataFrame containing the columns `mean`, `std`, `min`, and `max` depending on the `plot_type`
    :param x_grid: values to plot the data over, e.g. time
    :param x_label: labels for the categories on the x-axis, if `data` is not given as a `DataFrame`
    :param y_label: label for the y-axis, pass `None` to set no label
    :param curve_label: label of the (1-dim) curve
    :param area_label: label of the (transparent) area
    :param vline_level: if not `None` (default) add a vertical line at the given level
    :param vline_label: label for the vertical line
    :param show_legend: if `True` the legend is shown, useful when handling multiple subplots
    :param title: title displayed above the figure, set to None to suppress the title
    :param legend_kwargs: keyword arguments forwarded to pyplot's `legend()` function, e.g. `loc='best'`
    :param plot_kwargs: keyword arguments forwarded to seaborn's `boxplot()` or `violinplot()` function
    :return: handle to the resulting figure
    """
    plot_type = plot_type.lower()
    if plot_type not in ['mean_std', 'min_mean_max']:
        raise pyrado.ValueErr(given=plot_type,
                              eq_constraint='mean_std or min_mean_max')
    if not isinstance(data, pd.DataFrame):
        raise pyrado.TypeErr(given=data, expected_type=pd.DataFrame)
    if x_label is not None and not isinstance(x_label, str):
        raise pyrado.TypeErr(given=x_label, expected_type=str)
    if y_label is not None and not isinstance(y_label, str):
        raise pyrado.TypeErr(given=y_label, expected_type=str)

    # Set defaults which can be overwritten by passing plot_kwargs
    plot_kwargs = merge_dicts([dict(alpha=0.3), plot_kwargs])
    legend_kwargs = dict() if legend_kwargs is None else legend_kwargs
    # palette = sns.color_palette() if palette is None else palette

    # Preprocess
    if isinstance(x_grid, list):
        x_grid = np.array(x_grid)
    elif isinstance(x_grid, to.Tensor):
        x_grid = x_grid.detach().cpu().numpy()

    # Plot
    if plot_type == 'mean_std':
        if not ('mean' in data.columns and 'std' in data.columns):
            raise pyrado.KeyErr(keys="'mean' and 'std'", container=data)
        num_stds = 2
        if area_label is None:
            area_label = rf'$\pm {num_stds}$ std'
        ax.fill_between(x_grid,
                        data['mean'] - num_stds * data['std'],
                        data['mean'] + num_stds * data['std'],
                        label=area_label,
                        **plot_kwargs)

    elif plot_type == 'min_mean_max':
        if not ('mean' in data.columns and 'min' in data.columns
                and 'max' in data.columns):
            raise pyrado.KeyErr(keys="'mean' and 'min' and 'max'",
                                container=data)
        if area_label is None:
            area_label = r'min \& max'
        ax.fill_between(x_grid,
                        data['min'],
                        data['max'],
                        label=area_label,
                        **plot_kwargs)

    # plot mean last for proper z-ordering
    plot_kwargs['alpha'] = 1
    ax.plot(x_grid, data['mean'], label=curve_label, **plot_kwargs)

    # Postprocess
    if vline_level is not None:
        # Add dashed line to mark a threshold
        ax.axhline(vline_level, c='k', ls='--', lw=1., label=vline_label)

    if x_label is None:
        ax.get_xaxis().set_ticks([])

    if y_label is not None:
        ax.set_ylabel(y_label)

    if show_legend:
        ax.legend(**legend_kwargs)

    if title is not None:
        ax.set_title(title)

    return plt.gcf()
Example #21
0
def plot_heatmap(
    dataset: netCDF4.Dataset,
    ax: plt.Axes = None,
    color: str = "charge",
    residues: list = None,
    zerobased: bool = False,
):
    """Plot the states, or the charges as colored blocks

    Parameters
    ----------
    dataset - netCDF$.Dataset containing Protons information.
    ax - matplotlib Axes object
    color - 'charge', 'state', 'taut' , color by charge, by state, or charge and shade by tautomer
    residues - list, residues to plot
    zerobased - bool default False - use zero based labeling for states.

    Returns
    -------
    ax - plt.Axes
    """
    # Convert to array, and make sure types are int
    if ax is None:
        ax = plt.gca()

    if zerobased:
        label_offset = 0
    else:
        label_offset = 1

    if color == "charge":
        vmin = -2
        vmax = 2
        center = 0
        cmap = sns.diverging_palette(
            25, 244, l=60, s=95, sep=80, center="light", as_cmap=True
        )
        ticks = np.arange(vmin, vmax + 1)
        boundaries = np.arange(vmin - 0.5, vmax + 1.5)
        cbar_kws = {"ticks": ticks, "boundaries": boundaries, "label": color.title()}

    elif color == "state":
        vmin = 0 + label_offset
        vmax = label_offset + np.amax(dataset["Protons/Titration/state"][:, :])
        ticks = np.arange(vmin, vmax + 1)
        boundaries = np.arange(vmin - 0.5, vmax + 1.5)
        cbar_kws = {"ticks": ticks, "boundaries": boundaries, "label": color.title()}
        center = None
        cmap = "Accent"

    else:
        raise ValueError("color argument should be 'charge', or 'state'.")

    to_plot = None
    if residues is None:
        if color == "charge":
            to_plot = charge_taut_trace(dataset)[0][:, :]
        elif color == "state":
            titration_states = dataset["Protons/Titration/state"][:, :]
            to_plot = titration_states + label_offset

    else:
        if isinstance(residues, int):
            residues = [residues]
        residues = np.asarray(residues).astype(np.int)
        if color == "charge":
            to_plot = charge_taut_trace(dataset)[0][:, residues]
        elif color == "state":
            to_plot = dataset["Protons/Titration/state"][:, residues] + label_offset

    ax = sns.heatmap(
        to_plot.T,
        ax=ax,
        vmin=vmin,
        vmax=vmax,
        center=center,
        xticklabels=int(np.floor(to_plot.shape[0] / 7)) - 1,
        yticklabels=int(np.floor(to_plot.shape[1] / 4)) - 1,
        cmap=cmap,
        cbar_kws=cbar_kws,
        edgecolor="None",
        snap=True,
    )

    for residue in range(to_plot.T.shape[1]):
        ax.axhline(residue, lw=0.4, c="w")

    ax.set_ylabel("Residue")
    ax.set_xlabel("Update")
    return ax
Example #22
0
def draw_categorical(
    plot_type: str,
    ax: plt.Axes,
    data: Union[list, np.ndarray, to.Tensor, pd.DataFrame],
    x_label: Optional[Union[str, Sequence[str]]],
    y_label: Optional[str],
    vline_level: float = None,
    vline_label: str = "approx. solved",
    palette=None,
    title: str = None,
    show_legend: bool = True,
    legend_kwargs: dict = None,
    plot_kwargs: dict = None,
) -> plt.Figure:
    """
    Create a box or violin plot for a list of data arrays or a pandas DataFrame.
    The plot is neither shown nor saved.

    If you want to order the 4th element to the 2nd position in terms of colors use

    .. code-block:: python

        palette.insert(1, palette.pop(3))

    .. note::
        If you want to have a tight layout, it is best to pass axes of a figure with `tight_layout=True` or
        `constrained_layout=True`.

    :param plot_type: tye of categorical plot, pass box or violin
    :param ax: axis of the figure to plot on
    :param data: list of data sets to plot as separate boxes
    :param x_label: labels for the categories on the x-axis, if `data` is not given as a `DataFrame`
    :param y_label: label for the y-axis, pass `None` to set no label
    :param vline_level: if not `None` (default) add a vertical line at the given level
    :param vline_label: label for the vertical line
    :param palette: seaborn color palette, pass `None` to use the default palette
    :param show_legend: if `True` the legend is shown, useful when handling multiple subplots
    :param title: title displayed above the figure, set to None to suppress the title
    :param legend_kwargs: keyword arguments forwarded to pyplot's `legend()` function, e.g. `loc='best'`
    :param plot_kwargs: keyword arguments forwarded to seaborn's `boxplot()` or `violinplot()` function
    :return: handle to the resulting figure
    """
    plot_type = plot_type.lower()
    if plot_type not in ["box", "violin"]:
        raise pyrado.ValueErr(given=plot_type, eq_constraint="box or violin")
    if not isinstance(data, (list, to.Tensor, np.ndarray, pd.DataFrame)):
        raise pyrado.TypeErr(
            given=data,
            expected_type=[list, to.Tensor, np.ndarray, pd.DataFrame])

    # Set defaults which can be overwritten
    plot_kwargs = merge_dicts([dict(alpha=1),
                               plot_kwargs])  # by default no transparency
    alpha = plot_kwargs.pop(
        "alpha")  # can't pass the to the seaborn plotting functions
    legend_kwargs = dict() if legend_kwargs is None else legend_kwargs
    palette = sns.color_palette() if palette is None else palette

    # Preprocess
    if isinstance(data, pd.DataFrame):
        df = data
    else:
        if isinstance(data, list):
            data = np.array(data)
        elif isinstance(data, to.Tensor):
            data = data.detach().cpu().numpy()
        if x_label is not None and not len(x_label) == data.shape[1]:
            raise pyrado.ShapeErr(given=data, expected_match=x_label)
        df = pd.DataFrame(data, columns=x_label)

    if data.shape[0] < data.shape[1]:
        print_cbt(
            f"Less data samples {data.shape[0]} then data dimensions {data.shape[1]}",
            "y",
            bright=True)

    # Plot
    if plot_type == "box":
        ax = sns.boxplot(data=df, ax=ax, **plot_kwargs)

    elif plot_type == "violin":
        plot_kwargs = merge_dicts([
            dict(alpha=0.3, scale="count", inner="box", bw=0.3, cut=0),
            plot_kwargs
        ])
        ax = sns.violinplot(data=df, ax=ax, palette=palette, **plot_kwargs)

        # Plot larger circles for medians (need to memorize the limits)
        medians = df.median().to_numpy()
        left, right = ax.get_xlim()
        locs = ax.get_xticks()
        ax.scatter(locs,
                   medians,
                   marker="o",
                   s=30,
                   zorder=3,
                   color="white",
                   edgecolors="black")
        ax.set_xlim((left, right))

    # Postprocess
    if alpha < 1 and plot_type == "box":
        for patch in ax.artists:
            r, g, b, a = patch.get_facecolor()
            patch.set_facecolor((r, g, b, alpha))
    elif alpha < 1 and plot_type == "violin":
        for violin in ax.collections[::2]:
            violin.set_alpha(alpha)

    if vline_level is not None:
        # Add dashed line to mark a threshold
        ax.axhline(vline_level, c="k", ls="--", lw=1.0, label=vline_label)

    if x_label is None:
        ax.get_xaxis().set_ticks([])

    if y_label is not None:
        ax.set_ylabel(y_label)

    if show_legend:
        ax.legend(**legend_kwargs)

    if title is not None:
        ax.set_title(title)

    return plt.gcf()
Example #23
0
def plot_tautomer_heatmap(
    dataset: netCDF4.Dataset,
    ax: plt.Axes = None,
    residues: list = None,
    zerobased: bool = False,
):
    """Plot the charge of residues on a blue-red (negative-positive) scale, and add different shades for different tautomers.

    Parameters
    ----------
    dataset - netCDF4 dataset containing protons data
    ax - matplotlib Axes object
    residues - list, residues to plot
    zerobased - bool default False - use zero based labeling for states.

    Returns
    -------
    plt.Axes

    """
    # Convert to array, and make sure types are int
    if ax is None:
        ax = plt.gca()

    if zerobased:
        label_offset = 0
    else:
        label_offset = 1

    # color charges, and add shade for tautomers
    vmin = -2
    vmax = 2
    center = 0
    cmap = sns.diverging_palette(
        25, 244, l=60, s=95, sep=80, center="light", as_cmap=True
    )
    ticks = np.arange(vmin, vmax + 1)
    boundaries = np.arange(vmin - 0.5, vmax + 1.5)
    cbar_kws = {"ticks": ticks, "boundaries": boundaries, "label": "Charge"}

    taut_vmin = 0 + label_offset
    taut_vmax = label_offset + np.amax(dataset["Protons/Titration/state"][:, :])
    taut_ticks = np.arange(taut_vmin, taut_vmax + 1)
    taut_boundaries = np.arange(taut_vmin - 0.5, taut_vmax + 1.5)
    taut_cbar_kws = {"boundaries": taut_boundaries}

    taut_center = None
    taut_cmap = "Greys"

    to_plot = None
    if residues is None:
        to_plot, taut_to_plot = charge_taut_trace(dataset)

    else:
        if isinstance(residues, int):
            residues = [residues]
        residues = np.asarray(residues).astype(np.int)
        charges, tauts = charge_taut_trace(dataset)
        to_plot = charges[:, residues]
        taut_to_plot = tauts[:, residues]

    mesh = ax.pcolor(to_plot.T, cmap=cmap, vmin=vmin, vmax=vmax, snap=True, alpha=1.0)
    plt.colorbar(mesh, ax=ax, **cbar_kws)
    taut_mesh = ax.pcolor(
        taut_to_plot.T,
        cmap=taut_cmap,
        vmin=taut_vmin,
        vmax=taut_vmax,
        alpha=0.1,
        snap=True,
    )

    for residue in range(to_plot.T.shape[0]):
        ax.axhline(residue, lw=0.4, c="w")

    ax.set_ylabel("Residue")
    ax.set_xlabel("Update")

    return ax
Example #24
0
def add_geodesic_grid(ax: plt.Axes, manifold: Stereographic, line_width=0.1):
    import math
    # define geodesic grid parameters
    N_EVALS_PER_GEODESIC = 10000
    STYLE = "--"
    COLOR = "gray"
    LINE_WIDTH = line_width

    # get manifold properties
    K = manifold.k.item()
    R = manifold.radius.item()

    # get maximal numerical distance to origin on manifold
    if K < 0:
        # create point on R
        r = torch.tensor((R, 0.0), dtype=manifold.dtype)
        # project point on R into valid range (epsilon border)
        r = manifold.projx(r)
        # determine distance from origin
        max_dist_0 = manifold.dist0(r).item()
    else:
        max_dist_0 = math.pi * R
    # adjust line interval for spherical geometry
    circumference = 2 * math.pi * R

    # determine reasonable number of geodesics
    # choose the grid interval size always as if we'd be in spherical
    # geometry, such that the grid interpolates smoothly and evenly
    # divides the sphere circumference
    n_geodesics_per_circumference = 4 * 6  # multiple of 4!
    n_geodesics_per_quadrant = n_geodesics_per_circumference // 2
    grid_interval_size = circumference / n_geodesics_per_circumference
    if K < 0:
        n_geodesics_per_quadrant = int(max_dist_0 / grid_interval_size)

    # create time evaluation array for geodesics
    if K < 0:
        min_t = -1.2 * max_dist_0
    else:
        min_t = -circumference / 2.0
    t = torch.linspace(min_t, -min_t, N_EVALS_PER_GEODESIC)[:, None]

    # define a function to plot the geodesics
    def plot_geodesic(gv):
        ax.plot(*gv.t().numpy(), STYLE, color=COLOR, linewidth=LINE_WIDTH)

    # define geodesic directions
    u_x = torch.tensor((0.0, 1.0))
    u_y = torch.tensor((1.0, 0.0))

    # add origin x/y-crosshair
    o = torch.tensor((0.0, 0.0))
    if K < 0:
        x_geodesic = manifold.geodesic_unit(t, o, u_x)
        y_geodesic = manifold.geodesic_unit(t, o, u_y)
        plot_geodesic(x_geodesic)
        plot_geodesic(y_geodesic)
    else:
        # add the crosshair manually for the sproj of sphere
        # because the lines tend to get thicker if plotted
        # as done for K<0
        ax.axvline(0, linestyle=STYLE, color=COLOR, linewidth=LINE_WIDTH)
        ax.axhline(0, linestyle=STYLE, color=COLOR, linewidth=LINE_WIDTH)

    # add geodesics per quadrant
    for i in range(1, n_geodesics_per_quadrant):
        i = torch.as_tensor(float(i))
        # determine start of geodesic on x/y-crosshair
        x = manifold.geodesic_unit(i * grid_interval_size, o, u_y)
        y = manifold.geodesic_unit(i * grid_interval_size, o, u_x)

        # compute point on geodesics
        x_geodesic = manifold.geodesic_unit(t, x, u_x)
        y_geodesic = manifold.geodesic_unit(t, y, u_y)

        # plot geodesics
        plot_geodesic(x_geodesic)
        plot_geodesic(y_geodesic)
        if K < 0:
            plot_geodesic(-x_geodesic)
            plot_geodesic(-y_geodesic)
Example #25
0
def plot_rt(fig: plt.Figure, target_df: pd.DataFrame, ax: plt.Axes,
            county_name: str) -> None:
    above = [1, 0, 0]
    middle = [1, 1, 1]
    below = [0, 0, 0]
    cmap = ListedColormap(np.r_[np.linspace(below, middle, 25),
                                np.linspace(middle, above, 25)])
    color_mapped = lambda y: np.clip(y, .5, 1.5) - .5
    target_df = target_df.loc[(
        target_df.index.get_level_values('name') == county_name)]
    start_dt = pd.to_datetime(
        target_df['Rt'].index.get_level_values('Date').min())
    index = pd.to_datetime(target_df['Rt'].index.get_level_values('Date'))
    values = target_df['Rt'].values
    # Plot dots and line
    ax.plot(index, values, c='k', zorder=1, alpha=.25)
    ax.scatter(index,
               values,
               s=40,
               lw=.5,
               c=cmap(color_mapped(values)),
               edgecolors='k',
               zorder=2)
    # Aesthetically, extrapolate credible interval by 1 day either side
    lowfn = interp1d(date2num(index),
                     target_df['90_CrI_LB'].values,
                     bounds_error=False,
                     fill_value='extrapolate')
    highfn = interp1d(date2num(index),
                      target_df['90_CrI_UB'].values,
                      bounds_error=False,
                      fill_value='extrapolate')
    extended = pd.date_range(start=start_dt - pd.Timedelta(days=3),
                             end=index[-1] + pd.Timedelta(days=1))
    ax.fill_between(extended,
                    lowfn(date2num(extended)),
                    highfn(date2num(extended)),
                    color='k',
                    alpha=.1,
                    lw=0,
                    zorder=3)
    ax.axhline(1.0, c='k', lw=1, label='$R_t=1.0$', alpha=.25)
    ax.set_title(f'{county_name}',
                 loc='left',
                 fontsize=20,
                 fontweight=0,
                 color='#375A97')
    # Formatting
    ax.xaxis.set_major_locator(mdates.MonthLocator())
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%b'))
    ax.xaxis.set_minor_locator(mdates.DayLocator())
    ax.yaxis.set_major_locator(ticker.MultipleLocator(1))
    ax.yaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.1f}"))
    ax.yaxis.tick_right()
    ax.spines['left'].set_visible(False)
    ax.spines['bottom'].set_visible(False)
    ax.spines['right'].set_visible(False)
    ax.margins(0)
    ax.grid(which='major', axis='y', c='k', alpha=.1, zorder=-2)
    ax.margins(0)
    ax.set_ylim(0.0, 5.0)
    ax.set_xlim(
        start_dt - pd.Timedelta(days=3),
        target_df.index.get_level_values('Date')[-1] + pd.Timedelta(days=1))
    ax.xaxis.set_major_locator(mdates.WeekdayLocator())
    ax.xaxis.set_major_formatter(mdates.DateFormatter('%b %d'))
    fig.set_facecolor('w')
Example #26
0
 def _draw_truth_offdiag(ax: plt.Axes, truth_x, truth_y, **kwargs):
     ax.axvline(truth_x, **kwargs)
     ax.axhline(truth_y, **kwargs)
Example #27
0
File: plot.py Project: whynot-s/evo
def error_array(ax: plt.Axes,
                err_array: ListOrArray,
                x_array: typing.Optional[ListOrArray] = None,
                statistics: typing.Optional[typing.Dict[str, float]] = None,
                threshold: float = None,
                cumulative: bool = False,
                color: str = 'grey',
                name: str = "error",
                title: str = "",
                xlabel: str = "index",
                ylabel: typing.Optional[str] = None,
                subplot_arg: int = 111,
                linestyle: str = "-",
                marker: typing.Optional[str] = None):
    """
    high-level function for plotting raw error values of a metric
    :param fig: matplotlib axes
    :param err_array: an nx1 array of values
    :param x_array: an nx1 array of x-axis values
    :param statistics: optional dictionary of {metrics.StatisticsType.value: value}
    :param threshold: optional value for horizontal threshold line
    :param cumulative: set to True for cumulative plot
    :param name: optional name of the value array
    :param title: optional plot title
    :param xlabel: optional x-axis label
    :param ylabel: optional y-axis label
    :param subplot_arg: optional matplotlib subplot ID if used as subplot
    :param linestyle: matplotlib linestyle
    :param marker: optional matplotlib marker style for points
    """
    if cumulative:
        if x_array is not None:
            ax.plot(x_array,
                    np.cumsum(err_array),
                    linestyle=linestyle,
                    marker=marker,
                    color=color,
                    label=name)
        else:
            ax.plot(np.cumsum(err_array),
                    linestyle=linestyle,
                    marker=marker,
                    color=color,
                    label=name)
    else:
        if x_array is not None:
            ax.plot(x_array,
                    err_array,
                    linestyle=linestyle,
                    marker=marker,
                    color=color,
                    label=name)
        else:
            ax.plot(err_array,
                    linestyle=linestyle,
                    marker=marker,
                    color=color,
                    label=name)
    if statistics is not None:
        for stat_name, value in statistics.items():
            color = next(ax._get_lines.prop_cycler)['color']
            if stat_name == "std" and "mean" in statistics:
                mean, std = statistics["mean"], statistics["std"]
                ax.axhspan(mean - std / 2,
                           mean + std / 2,
                           color=color,
                           alpha=0.5,
                           label=stat_name)
            else:
                ax.axhline(y=value,
                           color=color,
                           linewidth=2.0,
                           label=stat_name)
    if threshold is not None:
        ax.axhline(y=threshold,
                   color='red',
                   linestyle='dashed',
                   linewidth=2.0,
                   label="threshold")
    plt.ylabel(ylabel if ylabel else name)
    plt.xlabel(xlabel)
    plt.title(title)
    plt.legend(frameon=True)
Example #28
0
def plot_heatmap(
    dataset: netCDF4.Dataset,
    ax: plt.Axes = None,
    color: str = "charge",
    residues: list = None,
    zerobased: bool = False,
):
    """Plot the states, or the charges as colored blocks

    Parameters
    ----------
    dataset - netCDF$.Dataset containing Protons information.
    ax - matplotlib Axes object
    color - 'charge', 'state', 'taut' , color by charge, by state, or charge and shade by tautomer
    residues - list, residues to plot
    zerobased - bool default False - use zero based labeling for states.

    Returns
    -------
    ax - plt.Axes
    """
    # Convert to array, and make sure types are int
    if ax is None:
        ax = plt.gca()

    if zerobased:
        label_offset = 0
    else:
        label_offset = 1

    if color == "charge":
        vmin = -2
        vmax = 2
        center = 0
        cmap = sns.diverging_palette(25,
                                     244,
                                     l=60,
                                     s=95,
                                     sep=80,
                                     center="light",
                                     as_cmap=True)
        ticks = np.arange(vmin, vmax + 1)
        boundaries = np.arange(vmin - 0.5, vmax + 1.5)
        cbar_kws = {
            "ticks": ticks,
            "boundaries": boundaries,
            "label": color.title()
        }

    elif color == "state":
        vmin = 0 + label_offset
        vmax = label_offset + np.amax(dataset["Protons/Titration/state"][:, :])
        ticks = np.arange(vmin, vmax + 1)
        boundaries = np.arange(vmin - 0.5, vmax + 1.5)
        cbar_kws = {
            "ticks": ticks,
            "boundaries": boundaries,
            "label": color.title()
        }
        center = None
        cmap = "Accent"

    else:
        raise ValueError("color argument should be 'charge', or 'state'.")

    to_plot = None
    if residues is None:
        if color == "charge":
            to_plot = charge_taut_trace(dataset)[0][:, :]
        elif color == "state":
            titration_states = dataset["Protons/Titration/state"][:, :]
            to_plot = titration_states + label_offset

    else:
        if isinstance(residues, int):
            residues = [residues]
        residues = np.asarray(residues).astype(np.int)
        if color == "charge":
            to_plot = charge_taut_trace(dataset)[0][:, residues]
        elif color == "state":
            to_plot = dataset[
                "Protons/Titration/state"][:, residues] + label_offset

    ax = sns.heatmap(
        to_plot.T,
        ax=ax,
        vmin=vmin,
        vmax=vmax,
        center=center,
        xticklabels=int(np.floor(to_plot.shape[0] / 7)) - 1,
        yticklabels=int(np.floor(to_plot.shape[1] / 4)) - 1,
        cmap=cmap,
        cbar_kws=cbar_kws,
        edgecolor="None",
        snap=True,
    )

    for residue in range(to_plot.T.shape[1]):
        ax.axhline(residue, lw=0.4, c="w")

    ax.set_ylabel("Residue")
    ax.set_xlabel("Update")
    return ax
Example #29
0
def plot_tautomer_heatmap(
    dataset: netCDF4.Dataset,
    ax: plt.Axes = None,
    residues: list = None,
    zerobased: bool = False,
):
    """Plot the charge of residues on a blue-red (negative-positive) scale, and add different shades for different tautomers.

    Parameters
    ----------
    dataset - netCDF4 dataset containing protons data
    ax - matplotlib Axes object
    residues - list, residues to plot
    zerobased - bool default False - use zero based labeling for states.

    Returns
    -------
    plt.Axes

    """
    # Convert to array, and make sure types are int
    if ax is None:
        ax = plt.gca()

    if zerobased:
        label_offset = 0
    else:
        label_offset = 1

    # color charges, and add shade for tautomers
    vmin = -2
    vmax = 2
    center = 0
    cmap = sns.diverging_palette(25,
                                 244,
                                 l=60,
                                 s=95,
                                 sep=80,
                                 center="light",
                                 as_cmap=True)
    ticks = np.arange(vmin, vmax + 1)
    boundaries = np.arange(vmin - 0.5, vmax + 1.5)
    cbar_kws = {"ticks": ticks, "boundaries": boundaries, "label": "Charge"}

    taut_vmin = 0 + label_offset
    taut_vmax = label_offset + np.amax(
        dataset["Protons/Titration/state"][:, :])
    taut_ticks = np.arange(taut_vmin, taut_vmax + 1)
    taut_boundaries = np.arange(taut_vmin - 0.5, taut_vmax + 1.5)
    taut_cbar_kws = {"boundaries": taut_boundaries}

    taut_center = None
    taut_cmap = "Greys"

    to_plot = None
    if residues is None:
        to_plot, taut_to_plot = charge_taut_trace(dataset)

    else:
        if isinstance(residues, int):
            residues = [residues]
        residues = np.asarray(residues).astype(np.int)
        charges, tauts = charge_taut_trace(dataset)
        to_plot = charges[:, residues]
        taut_to_plot = tauts[:, residues]

    mesh = ax.pcolor(to_plot.T,
                     cmap=cmap,
                     vmin=vmin,
                     vmax=vmax,
                     snap=True,
                     alpha=1.0)
    plt.colorbar(mesh, ax=ax, **cbar_kws)
    taut_mesh = ax.pcolor(
        taut_to_plot.T,
        cmap=taut_cmap,
        vmin=taut_vmin,
        vmax=taut_vmax,
        alpha=0.1,
        snap=True,
    )

    for residue in range(to_plot.T.shape[0]):
        ax.axhline(residue, lw=0.4, c="w")

    ax.set_ylabel("Residue")
    ax.set_xlabel("Update")

    return ax
Example #30
0
def render_violinplot(
    ax: plt.Axes,
    data: [Sequence[list], Sequence[np.ndarray]],
    x_labels: Sequence[str],
    y_label: str,
    vline_level: float = None,
    vline_label: str = 'approx. solved',
    alpha: float = 0.7,
    show_inner_quartiles: bool = False,
    show_legend: bool = True,
    legend_loc: str = 'best',
    title: str = None,
    use_seaborn: bool = False,
) -> plt.Figure:
    """
    Create a violin plot for a list of data arrays. Every entry results in one column of the violin plot.
    The plot is neither shown nor saved.

    .. note::
        If you want to have a tight layout, it is best to pass axes of a figure with `tight_layout=True` or
        `constrained_layout=True`.

    :param ax: axis of the figure to plot on
    :param data: list of data sets to plot as separate violins
    :param x_labels: labels for the categories on the x-axis
    :param y_label: label for the y-axis
    :param vline_level: if not `None` (default) add a vertical line at the given level
    :param vline_label: label for the vertical line
    :param alpha: transparency (alpha-value) for violin body (including the border lines)
    :param show_inner_quartiles: display the 1st and 3rd quartile with a thick line
    :param show_legend: flag if the legend entry should be printed, set to `True` when using multiple subplots
    :param legend_loc: location of the legend, ignored if `show_legend = False`
    :param title: title displayed above the figure, set to None to suppress the title
    :return: handle to the resulting figure
    """
    if use_seaborn:
        # Plot the data
        import seaborn as sns
        import pandas as pd
        df = pd.DataFrame(data, x_labels).T
        ax = sns.violinplot(data=df,
                            scale='count',
                            inner='stick',
                            bw=0.3,
                            cut=0)  # cut controls the max7min values

        medians = np.zeros(len(data))
        for i in range(len(data)):
            medians[i] = np.median(data[i])

        x_grid = np.arange(0, len(medians))
        ax.scatter(x_grid,
                   medians,
                   marker='o',
                   s=50,
                   zorder=3,
                   color='white',
                   edgecolors='black')

    else:
        # Plot the data
        violin = ax.violinplot(data,
                               showmeans=False,
                               showmedians=False,
                               showextrema=False)

        # Set custom color scheme
        for pc in violin['bodies']:
            pc.set_facecolor('#b11226')
            pc.set_edgecolor('black')
            pc.set_alpha(alpha)

        # Set axis style
        ax.set_xticks(np.arange(1, len(x_labels) + 1))
        ax.set_xticklabels(x_labels)

        quartiles_up, medians, quartiles_lo = np.zeros(len(data)), np.zeros(
            len(data)), np.zeros(len(data))
        data_mins, data_maxs = np.zeros(len(data)), np.zeros(len(data))
        for i in range(len(data)):
            quartiles_up[i], medians[i], quartiles_lo[i] = np.percentile(
                data[i], [25, 50, 75])
            data_mins[i], data_maxs[i] = min(data[i]), max(data[i])

        x_grid = np.arange(1, len(medians) + 1)
        ax.scatter(x_grid,
                   medians,
                   marker='o',
                   s=50,
                   zorder=3,
                   color='white',
                   edgecolors='black')
        ax.vlines(x_grid,
                  data_mins,
                  data_maxs,
                  color='k',
                  linestyle='-',
                  lw=1,
                  alpha=alpha)
        if show_inner_quartiles:
            ax.vlines(x_grid,
                      quartiles_up,
                      quartiles_lo,
                      color='k',
                      linestyle='-',
                      lw=5)

    # Add dashed line to mark the approx solved threshold
    if vline_level is not None:
        ax.axhline(vline_level, c='k', ls='--', lw=1.0, label=vline_label)

    ax.set_ylabel(y_label)
    if show_legend:
        ax.legend(loc=legend_loc)
    if title is not None:
        ax.set_title(title)
    return plt.gcf()
Example #31
0
def render_boxplot(
    ax: plt.Axes,
    data: [Sequence[list], Sequence[np.ndarray]],
    x_labels: Sequence[str],
    y_label: str,
    vline_level: float = None,
    vline_label: str = 'approx. solved',
    alpha: float = 1.,
    colorize: bool = False,
    show_fliers: bool = False,
    show_legend: bool = True,
    legend_loc: str = 'best',
    title: str = None,
) -> plt.Figure:
    """
    Create a box plot for a list of data arrays. Every entry results in one column of the box plot.
    The plot is neither shown nor saved.

    .. note::
        If you want to have a tight layout, it is best to pass axes of a figure with `tight_layout=True` or
        `constrained_layout=True`.

    :param ax: axis of the figure to plot on
    :param data: list of data sets to plot as separate boxes
    :param x_labels: labels for the categories on the x-axis
    :param y_label: label for the y-axis
    :param vline_level: if not `None` (default) add a vertical line at the given level
    :param vline_label: label for the vertical line
    :param alpha: transparency (alpha-value) for boxes (including the border lines)
    :param colorize: colorize the core of the boxes
    :param show_fliers: show outliers (more the 1.5 of the inter quartial range) as circles
    :param show_legend: flag if the legend entry should be printed, set to True when using multiple subplots
    :param legend_loc: location of the legend, ignored if `show_legend = False`
    :param title: title displayed above the figure, set to None to suppress the title
    :return: handle to the resulting figure
    """
    medianprops = dict(linewidth=1., color='firebrick')
    meanprops = dict(marker='D',
                     markeredgecolor='black',
                     markerfacecolor='purple')
    boxprops = dict(linewidth=1.)
    whiskerprops = dict(linewidth=1.)
    capprops = dict(linewidth=1.)

    # Plot the data
    box = ax.boxplot(
        data,
        boxprops=boxprops,
        whiskerprops=whiskerprops,
        capprops=capprops,
        meanprops=meanprops,
        meanline=False,
        showmeans=False,
        medianprops=medianprops,
        showfliers=show_fliers,
        notch=False,
        patch_artist=colorize,  # necessary to colorize the boxes
        labels=x_labels,
        widths=0.7)

    if colorize:
        for i, patch in enumerate(box['boxes']):
            patch.set_facecolorf(f'C{i%10}')
            patch.set_alpha(alpha)

    # Add dashed line to mark the approx solved threshold
    if vline_level is not None:
        ax.axhline(vline_level, c='k', ls='--', lw=1., label=vline_label)

    ax.set_ylabel(y_label)
    if show_legend:
        ax.legend(loc=legend_loc)
    if title is not None:
        ax.set_title(title)
    return plt.gcf()
Example #32
0
    def overlay_entropy_profiles(self,
                                 axes: plt.Axes = None,
                                 r_units: str = 'r500',
                                 k_units: str = 'K500adi',
                                 vkb05_line: bool = True,
                                 color: str = 'k',
                                 alpha: float = 1.,
                                 markersize: float = 1,
                                 linewidth: float = 0.5) -> None:

        stand_alone = False
        if axes is None:
            stand_alone = True
            fig, axes = plt.subplots()
            axes.loglog()
            axes.set_xlabel(f'$r$ [{r_units}]')
            axes.set_ylabel(f'$K$ [${k_units}$]')
            axes.axvline(1, linestyle=':', color=color, alpha=alpha)

        # Set-up entropy data
        fields = [
            'K_500', 'K_1000', 'K_1500', 'K_2500', 'K_0p15r500', 'K_30kpc'
        ]
        K_stat = dict()
        if k_units == 'K500adi':
            K_conv = 1 / getattr(self, 'K_500_adi')
            axes.axhline(1, linestyle=':', color=color, alpha=alpha)
        elif k_units == 'keVcm^2':
            K_conv = np.ones_like(getattr(self, 'K_500_adi'))
            axes.fill_between(np.array(axes.get_xlim()),
                              y1=np.nanmin(self.K_500_adi),
                              y2=np.nanmax(self.K_500_adi),
                              facecolor='k',
                              alpha=0.3)
        else:
            raise ValueError("Conversion unit unknown.")
        for field in fields:
            data = np.multiply(getattr(self, field), K_conv)
            K_stat[field] = (np.nanpercentile(data,
                                              16), np.nanpercentile(data, 50),
                             np.nanpercentile(data, 84))
            K_stat[field.replace('K',
                                 'num')] = np.count_nonzero(~np.isnan(data))

        # Set-up radial distance data
        r_stat = dict()
        if r_units == 'r500':
            r_conv = 1 / getattr(self, 'r_500')
        elif r_units == 'r2500':
            r_conv = 1 / getattr(self, 'r_2500')
        elif r_units == 'kpc':
            r_conv = np.ones_like(getattr(self, 'r_2500'))
        else:
            raise ValueError("Conversion unit unknown.")
        for field in ['r_500', 'r_1000', 'r_1500', 'r_2500']:
            data = np.multiply(getattr(self, field), r_conv)
            if k_units == 'K500adi':
                data[np.isnan(self.K_500_adi)] = np.nan
            r_stat[field] = (np.nanpercentile(data,
                                              16), np.nanpercentile(data, 50),
                             np.nanpercentile(data, 84))
            r_stat[field.replace('r',
                                 'num')] = np.count_nonzero(~np.isnan(data))
        data = np.multiply(getattr(self, 'r_500') * 0.15, r_conv)
        if k_units == 'K500adi':
            data[np.isnan(self.K_500_adi)] = np.nan
        r_stat['r_0p15r500'] = (np.nanpercentile(data, 16),
                                np.nanpercentile(data, 50),
                                np.nanpercentile(data, 84))
        r_stat['num_0p15r500'] = np.count_nonzero(~np.isnan(data))
        data = np.multiply(
            np.ones_like(getattr(self, 'r_2500')) * 30 * unyt.kpc, r_conv)
        if k_units == 'K500adi':
            data[np.isnan(self.K_500_adi)] = np.nan
        r_stat['r_30kpc'] = (np.nanpercentile(data,
                                              16), np.nanpercentile(data, 50),
                             np.nanpercentile(data, 84))
        r_stat['num_30kpc'] = np.count_nonzero(~np.isnan(data))

        for suffix in [
                '_500', '_1000', '_1500', '_2500', '_0p15r500', '_30kpc'
        ]:
            x_low, x, x_hi = r_stat['r' + suffix]
            y_low, y, y_hi = K_stat['K' + suffix]
            num_objects = f"{r_stat['num' + suffix]}, {K_stat['num' + suffix]}"
            point_label = f"r{suffix:.<17s} Num(x,y) = {num_objects}"
            if stand_alone:
                axes.scatter(x, y, label=point_label, s=markersize)
                axes.errorbar(x,
                              y,
                              yerr=[[y_hi - y], [y - y_low]],
                              xerr=[[x_hi - x], [x - x_low]],
                              ls='none',
                              ms=markersize,
                              lw=linewidth)
            else:
                axes.scatter(x, y, color=color, alpha=alpha, s=markersize)
                axes.errorbar(x,
                              y,
                              yerr=[[y_hi - y], [y - y_low]],
                              xerr=[[x_hi - x], [x - x_low]],
                              ls='none',
                              ecolor=color,
                              alpha=alpha,
                              ms=markersize,
                              lw=linewidth)

        if vkb05_line:
            if r_units == 'r500' and k_units == 'K500adi':
                r = np.linspace(*axes.get_xlim(), 31)
                k = 1.40 * r**1.1 / self.hconv
                axes.plot(r, k, linestyle='--', color=color, alpha=alpha)
            else:
                print((
                    "The VKB05 adiabatic threshold should be plotted only when both "
                    "axes are in scaled units, since the line is calibrated on an NFW "
                    "profile with self-similar halos with an average concentration of "
                    "c_500 ~ 4.2 for the objects in the Sun et al. (2009) sample."
                ))

        if k_units == 'K500adi':
            r_r500, S_S500_50, S_S500_10, S_S500_90 = self.get_shortcut()

            plt.fill_between(r_r500,
                             S_S500_10,
                             S_S500_90,
                             color='grey',
                             alpha=0.5,
                             linewidth=0)
            plt.plot(r_r500, S_S500_50, c='k')

        if stand_alone:
            plt.legend()
            plt.show()
Example #33
0
def plot_triple_data(
    ax: plt.Axes,
    lab_values: ty.List[ty.List[str]],
    lab_names: ty.Tuple[str, str, str, str],
    f_mean: np.ndarray,
    f_min: np.ndarray,
    f_max: np.ndarray,
    f_std: np.ndarray,
    outer_label: str = None,
    outer_value: str = None,
    mean_all: float = None,
    max_all: float = None,
    min_all: float = None,
    min_lower_limit: float = 0,
    hypa_labels: ty.Dict[str, ty.Dict[str, str]] = None,
):
    """Plot groups of groups of columns

    f_mean.shape (x, y, z)

    z groups of (groups of columns)
    y groups of columns
    x columns per group

        example of (3, 4, 2) shape
    ^
    |                   x x
    |x                  xxx xx   x
    |xxx xx             xxx xx  xx  x
    |xxx xxx x   x x    xxx xxx xxx x x
    |xxx xxx xxx xxx    xxx xxx xxx xxx
    |xxx xxx xxx xxx    xxx xxx xxx xxx
    .----------------------------------->
    """
    logg = logging.getLogger(f"c.{__name__}.plot_triple_data")
    logg.setLevel("INFO")
    logg.debug("Start plot_triple_data")
    logg.debug(f"f_mean.shape: {f_mean.shape}")
    logg.debug(f"outer_value: {outer_value} outer_label {outer_label}")
    logg.debug(f"lab_names: {lab_names}")
    logg.debug(f"lab_values: {lab_values}")
    logg.debug(f"hypa_labels: {hypa_labels}")

    if outer_label is not None and outer_value is not None:
        if hypa_labels is not None:
            lab_values_disp = []
            for il, this_lab_values in enumerate(lab_values):
                this_lab_name = lab_names[il]
                new_disp_values = []
                for this_lab_value in this_lab_values:

                    # if I know how to translate
                    if this_lab_name in hypa_labels:
                        disp_lab_value = hypa_labels[this_lab_name][
                            this_lab_value]
                        logg.debug(f"disp_lab_value: {disp_lab_value}")

                    # use the current available label, no translation
                    else:
                        disp_lab_value = this_lab_value

                    new_disp_values.append(disp_lab_value)

                lab_values_disp.append(new_disp_values)

            # translate the outer label if you have the translation available
            if outer_label in hypa_labels:
                outer_value_disp = hypa_labels[outer_label][outer_value]
            else:
                outer_value_disp = outer_value

        else:
            lab_values_disp = lab_values
            outer_value_disp = outer_value
    logg.debug(f"lab_values_disp: {lab_values_disp}")
    logg.debug(f"outer_value_disp: {outer_value_disp}")

    title = ""
    if outer_label is not None and outer_value is not None:
        title += f"{outer_label}"
        # title += f": \\textbf{{{outer_value_disp}}}"
        title += f": $\\bf{{{outer_value_disp}}}$"
        title += "\n"
    title += f"{lab_names[0]}"
    title += f": {lab_values_disp[0]}"
    title += "\n"
    title += f" grouped by {lab_names[1]}"
    title += f": {lab_values_disp[1]}"
    title += "\n"
    title += f" grouped by {lab_names[2]}"
    title += f": {lab_values_disp[2]}"
    ax.set_title(title, fontsize=14)

    lab_fontsize = 14
    ax.set_ylabel("F-score (min/mean/max and std-dev)", fontsize=lab_fontsize)
    ax.set_xlabel(f"{lab_names[1]} ({lab_names[2]})", fontsize=lab_fontsize)

    f_dim = f_mean.shape

    # the width of each super group
    width_outer_group = 0.9

    # scale the available space by 0.8 to leave space between subgroups
    width_inner_group = width_outer_group * 0.8 / f_dim[1]

    # the columns are side by side
    width_inner_col = width_inner_group / f_dim[0]

    # where the z super groups of columns start
    x_outer_pos = np.arange(f_dim[2])

    # where the y sub groups start
    x_inner_pos = np.arange(f_dim[1]) * width_outer_group / f_dim[1]

    # where to put the ticks for each subgroup
    x_inner_ticks = x_inner_pos + (width_inner_group / 2)

    # all the ticks and the relative labels
    all_x_ticks = np.array([])
    all_xticklabels = []

    # if there are too many groups of columns draw less info
    too_many_groups = f_dim[1] * f_dim[2] > 12

    if not too_many_groups:
        err_capsize = 5
        std_capsize = 3
        std_capthick = 4
        xticklabels_rot = 0
        xticklabels_ha = "center"
    else:
        err_capsize = 3
        std_capsize = 2
        std_capthick = 3
        xticklabels_rot = 30
        xticklabels_ha = "right"

    # for each super group
    for iz in range(f_dim[2]):

        # where this group starts
        shift_group = x_outer_pos[iz]

        # where to put the ticks
        this_ticks = x_inner_ticks + shift_group
        all_x_ticks = np.hstack((all_x_ticks, this_ticks))
        this_labels = [
            f"{vy} ({lab_values_disp[2][iz]})" for vy in lab_values_disp[1]
        ]
        all_xticklabels.extend(this_labels)

        # reset the cycler
        cc = cycler(color=[
            "#1f77b4",
            "#ff7f0e",
            "#2ca02c",
            "#d62728",
            "#9467bd",
            "#8c564b",
            "#e377c2",
            "#7f7f7f",
            "#bcbd22",
            "#17becf",
        ])

        ax.set_prop_cycle(cc)

        # for each column
        for ix in range(f_dim[0]):

            # how much this batch of y columns must be shifted
            shift_col = width_inner_col * ix
            x_col = x_inner_pos + shift_col + shift_group

            # extract the values of the y columns in this batch
            y_f = f_mean[ix, :, iz]

            # only put the label for the first z slice
            the_label = lab_values_disp[0][ix] if iz == 0 else None

            # plot the bars
            ax.bar(
                x=x_col,
                height=y_f,
                width=width_inner_col,
                label=the_label,
                align="edge",
                capsize=err_capsize,
            )

            # compute the relative min/max
            y_min = y_f - f_min[ix, :, iz]
            y_max = f_max[ix, :, iz] - y_f
            y_err = np.vstack((y_min, y_max))
            ax.errorbar(
                x=x_col + width_inner_col / 2,
                y=y_f,
                yerr=y_err,
                linestyle="None",
                capsize=err_capsize,
                ecolor="k",
            )

            # get the standard deviation
            y_std = f_std[ix, :, iz]
            ax.errorbar(
                x_col + width_inner_col / 2,
                y_f,
                yerr=y_std,
                linestyle="None",
                capsize=std_capsize,
                capthick=std_capthick,
                ecolor="b",
            )

    if min_all is not None and min_all < min_lower_limit:
        # logg.debug(f"Resettin min_all: {min_all} to min_lower_limit")
        min_all = min_lower_limit

    if max_all is not None and min_all is not None:
        ax.set_ylim(top=max_all * 1.01, bottom=min_all * 0.99)
    elif max_all is not None:
        ax.set_ylim(top=max_all * 1.01)
    elif min_all is not None:
        ax.set_ylim(bottom=min_all * 0.99)

    if mean_all is not None:
        ax.axhline(mean_all)

        bottom, top = ax.get_ylim()
        mean_rescaled = ((mean_all - bottom) / (top - bottom)) * 1.01
        ax.annotate(
            text=f"{mean_all:.03f}",
            xy=(0.005, mean_rescaled),
            xycoords="axes fraction",
            fontsize=13,
        )

    ax.set_xticks(all_x_ticks)
    ax.set_xticklabels(
        labels=all_xticklabels,
        rotation=xticklabels_rot,
        horizontalalignment=xticklabels_ha,
    )
    ax.legend(title=f"{lab_names[0]}", title_fontsize=lab_fontsize)