def common_plotting_settings(plot: plt.Axes, plot_def: PlotDef,
                             xaxis_title: str,
                             yaxis_title: str) -> Optional[mpl.legend.Legend]:
    """Common settings for plots.

    Args:
        plot: a pyplot plot object
        plot_def: a `PlotDef` that defines properties of the plot
        xaxis_title: label for x-axis
        yaxis_title: label for y-axis
    """
    plot.set_xlabel(xaxis_title)
    plot.set_ylabel(yaxis_title)
    if plot_def.title:
        plot.set_title(plot_def.title)
    plot.grid(True)

    # get handles and labels for the legend
    handles, labels = plot.get_legend_handles_labels()
    # remove the errorbars from the legend if they are there
    handles = [(h[0] if isinstance(h, tuple) else h) for h in handles]

    if plot_def.legend_pos == "inside":
        return plot.legend(handles, labels)
    if plot_def.legend_pos == "outside":
        return plot.legend(handles,
                           labels,
                           loc="upper left",
                           bbox_to_anchor=(1, plot_def.legend_yanchor))
    return None
Beispiel #2
0
def plot_2E(ax: plt.Axes,
            bin_edges_human: np.ndarray = np.array(
                [-1000, -90, -60, -30, -4, -2, 0, 2, 4, 30, 60, 1000]),
            bin_edges_model: np.ndarray = np.linspace(-160, 100, 40)):
    Δ, p_human, p_model = [], [], []
    for pid in DataExp1.pids:
        data = DataExp1(pid)
        model = data.build_model(models.BayesianIdealObserver)
        df = model.predict(model.fit())
        δ = np.stack([
            np.log(df[s]) - np.log(np.sum(df.loc[:, df.columns != s], axis=1))
            for s in data.structures
        ])
        Δ += list(δ.T.flatten())
        p_model += list(
            data.cross_validate(models.ChoiceModel4Param).to_numpy().flatten())
        p_human += list(
            np.array([data.df['choice'] == s
                      for s in Exp1.structures]).T.flatten())
    df = pd.DataFrame({'Δ': Δ, 'p_human': p_human, 'p_model': p_model})
    x_human, y_human, yerr_human, x_model, y_model, yerr_model = [], [], [], [], [], []
    df['bin'] = pd.cut(df['Δ'], bin_edges_human, labels=False)
    for i in range(len(bin_edges_human) - 1):
        _df = df[df['bin'] == i]
        x_human.append(_df['Δ'].mean())
        y_human.append(_df['p_human'].mean())
        yerr_human.append(_df['p_human'].sem())
    df['bin'] = pd.cut(df['Δ'], bin_edges_model, labels=False)
    for i in range(len(bin_edges_model) - 1):
        _df = df[df['bin'] == i]
        x_model.append(_df['Δ'].mean())
        y_model.append(_df['p_model'].mean())
        yerr_model.append(_df['p_model'].sem())
    ax.errorbar(x_human,
                y_human,
                yerr_human,
                label='Human ± sem',
                color=colors['decision_human'],
                fmt='.',
                capsize=2,
                ms=2,
                capthick=0.5,
                zorder=1)
    ax.plot(x_model,
            y_model,
            color=colors['decision_model'],
            label='Model',
            ms=1,
            zorder=0)
    ax.set_xlabel(r'logit( $P_\mathregular{ideal}$($S\,|\,\bf{X}$) )')
    ax.set_ylabel(r'$P($choice=$S\,|\,\bf{X}$)')
    ax.set_ylim(0, 1)
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles[::-1],
              labels[::-1],
              loc='upper left',
              handler_map={ErrorbarContainer: HandlerErrorbar(yerr_size=0.25)})
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    plt.tight_layout()
Beispiel #3
0
def plot_stacked_activities(dict_states: Dict[str, np.ndarray],
                            time_axis: np.ndarray = None,
                            ax: plt.Axes = None,
                            step: str = 'post',
                            **kwargs) -> None:
    """Plot the stacked household states during time.

    Attributes:
        dict_states: A dictionary where keys are the names of the activities
            or states and the values are ndarray of size = n_steps and
            values are the number of residents in this states/activity
        time_axis: The datetime axis to plot
        ax: an ax on which to plot the activities
        kwargs: any other keywork argument from `ax.stackplot
            <https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.stackplot.html#matplotlib.pyplot.stackplot>`_

    """
    # Creates a time axis
    if time_axis is None:
        # Creates an ax of the length of states
        time_axis = np.arange(len(dict_states[list(dict_states.keys())[0]]))

    ax.stackplot(time_axis,
                 dict_states.values(),
                 labels=dict_states.keys(),
                 step='post',
                 **kwargs)
    # Reverse the legend, in the same way as they are stacked
    handles, lab = ax.get_legend_handles_labels()
    ax.legend(handles[::-1], lab[::-1])
 def add_legend(self, ax: plt.Axes):
     """ ax: The current axis. Use `not-OAA-derived` for now so the legend is plotted in the bottom right of the whole figure."""
     handles, labels = ax.get_legend_handles_labels()
     logger.debug(labels)
     by_label = dict(zip(labels, handles))
     logger.debug(by_label)
     plt.legend(by_label.values(),
                by_label.keys(),
                loc='lower right',
                framealpha=1,
                facecolor=self.legend_facecolor,
                title=self.label_legend_title)
Beispiel #5
0
def _make_distance_over_time_plot_legend(
    plotter: CustomCILinePlotter,
    fig: plt.Figure,
    ax: plt.Axes,
    hue_col: str,
    style_col: str,
) -> None:
    """Add legend to distance over time plot."""
    plotter.add_legend_data(ax)
    handles, labels = ax.get_legend_handles_labels()
    if hue_col == style_col:
        # Only one key, so legend can fit into one row.
        ncol = len(handles)
    else:
        # Different keys. Legend needs two rows.

        # Make number of columns large enough to fit hue and style each in one row.
        n_hue = len(plotter.lower[hue_col].dtype.categories)
        n_style = len(plotter.lower[style_col].dtype.categories)
        ncol = max(n_hue, n_style)

        # Delete subtitles
        del handles[0], labels[0]  # delete hue subtitle
        del handles[n_hue], labels[n_hue]  # delete style subtitle

        # Pad the smaller row, if they're different length, so its entries are centered
        if n_hue > n_style:
            larger_handles, larger_labels = handles[:n_hue], labels[:n_hue]
            smaller_handles, smaller_labels = handles[n_hue:], labels[n_hue:]
        else:
            larger_handles, larger_labels = handles[n_hue:], labels[n_hue:]
            smaller_handles, smaller_labels = handles[:n_hue], labels[:n_hue]

        delta = len(larger_handles) - len(smaller_handles)
        pad_start = delta // 2 + (delta % 2)
        pad_end = delta // 2
        empty = mpatches.Patch(color="white")
        smaller_handles = [empty] * pad_start + smaller_handles + [empty
                                                                   ] * pad_end
        smaller_labels = [""] * pad_start + smaller_labels + [""] * pad_end

        # Reassemble. Note that matplotlib fills column by column, so we zip to "transpose".
        handles = list(itertools.chain(*zip(larger_handles, smaller_handles)))
        labels = list(itertools.chain(*zip(larger_labels, smaller_labels)))

    outside_legend(
        handles=handles,
        labels=labels,
        ncol=ncol,
        fig=fig,
        ax=ax,
    )
def plot_3B(ax: plt.Axes):
    data = pool(DataExp2)
    data.plot_stacked_bar(ax)
    n = len(ExpConfig.glo_exp2)
    y_human, y1, y2 = np.zeros(n), np.zeros(n), np.zeros(n)
    for pid in DataExp2.pids:
        data = DataExp2(pid)
        y_human += data.plot_line_human()[0]
        m1 = data.load_model(
            models.ChoiceModel4Param,
            DataExp1(pid).build_model(models.ChoiceModel4Param).fit())
        y1 += data.plot_line_model(m1.predict(m1.fit()))
        y2 += data.plot_line_model(
            data.cross_validate(models.ChoiceModel4Param))
    y_human, y1, y2 = y_human / len(DataExp2.pids), y1 / len(
        DataExp2.pids), y2 / len(DataExp2.pids)
    err = [np.sqrt(p * (1 - p) / len(DataExp2.pids) / 20) for p in y_human]
    ax.errorbar(DataExp2.x,
                y_human,
                err,
                label='Human $\pm$ sem',
                color=colors['decision_human'],
                capsize=5,
                capthick=1,
                lw=1,
                ms=3,
                fmt='o',
                zorder=3)
    ax.plot(DataExp2.x,
            y1,
            'o--',
            label='Transfer model',
            color=colors['decision_transfer'],
            lw=1,
            ms=3,
            zorder=2)
    ax.plot(DataExp2.x,
            y2,
            'o-',
            label='Fitted model',
            color=colors['decision_model'],
            lw=1,
            ms=3,
            zorder=2)
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles[::-1],
              labels[::-1],
              loc='upper right',
              handler_map={ErrorbarContainer: HandlerErrorbar(yerr_size=0.35)})
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    plt.tight_layout()
Beispiel #7
0
def _legend_with_triplot_fix(ax: plt.Axes, **kwargs):
    """Add legend for triplot with fix that avoids duplicate labels.

    Parameters
    ----------
    ax : plt.Axes
        Matplotlib axes to apply legend to.
    **kwargs
        Extra keyword arguments passed to `ax.legend`.
    """
    handles, labels = ax.get_legend_handles_labels()
    # reverse to avoid blank line color
    by_label = dict(zip(reversed(labels), reversed(handles)))
    ax.legend(by_label.values(), by_label.keys(), **kwargs)
Beispiel #8
0
def legend_last_to_first(ax: plt.Axes, **kwargs):
    """Move the last element of the legend to first.

    Parameters
    ----------
    ax : matplotlib.axes.Axes
        Matplotlib axes to create a legend on.
    kwargs : dict
        Arguments passed to :py:obj:`matplotlib.axes.Axes.legend`.

    """
    if ax.get_legend() is None:
        ax.legend()
    handles, labels = ax.get_legend_handles_labels()
    handles.insert(0, handles.pop())
    labels.insert(0, labels.pop())
    ax.legend(handles, labels, **kwargs)
Beispiel #9
0
 def legend(
     self,
     gmeq: Eq,
     axes: Axes,
     do_legend: bool,
     do_half: bool,
     do_ray_slowness: bool = False,
 ) -> None:
     """Construct and place a legend."""
     if not do_legend:
         return
     handles, labels = axes.get_legend_handles_labels()
     if gmeq.eta_ >= 1:
         loc_ = ("center right" if do_half else
                 "upper left" if do_ray_slowness else "lower left")
     else:
         loc_ = ("upper right" if do_half else
                 "upper left" if do_ray_slowness else "lower left")
     axes.legend(handles[::-1], labels[::-1], loc=loc_)
Beispiel #10
0
def plot_appliance_consumptions(consumptions: np.ndarray,
                                appliances_dict: AppliancesDict,
                                time_axis: np.ndarray = None,
                                differentiative_factor: str = 'type',
                                labels_list: List[Any] = None,
                                ax: plt.Axes = None,
                                **kwargs) -> None:
    """Plot the consumption of the appliances.

    Args:
        consumptions: A ndarray of size = (n_steps, n_appliances) and
            values are the consumption of each appliance
        appliances_dict: The dictionary of appliances from simulator
        time_axis: The datetime axis to plot
        differentiative_factor: The key in the appliance_dict that
            should be used to differentiate the appiances
            ex: ('type', 'name', 'related_activity')
        labels_list: Optional list of the labels to be plotted
            Usefull for choosing an order
        ax: an ax on which to plot the activities

    """
    # Finds all the attributes or uses the ones given
    attributes_list = (np.unique(appliances_dict[differentiative_factor])
                       if labels_list is None else labels_list)
    # Sum up consumption mapping these appliances
    consumptions_to_plot = [
        np.sum(
            consumptions[:,
                         appliances_dict[differentiative_factor] == attribute],
            axis=-1) for attribute in attributes_list
    ]
    if time_axis is None:
        # Creates an ax of the length of states
        time_axis = np.arange(len(consumptions))

    ax.stackplot(time_axis,
                 *consumptions_to_plot,
                 labels=attributes_list,
                 step='post')
    # Reverse the legend, in the same way as they are stacked
    handles, lab = ax.get_legend_handles_labels()
    ax.legend(handles[::-1], lab[::-1])
Beispiel #11
0
def plot_stack_states(states: States,
                      labels: StateLabels,
                      ax: plt.Axes = None,
                      **kwargs) -> Any:
    """Plot the stacked states.

    Args:
        states: the states to be stacked in the plot
        labels: the labels of the different states values in
            the states array
        ax: An optional ax object on which to plot the labels
        **kwargs: any arguments passed to 'plt.stackplot'

    Returns:
        fig, ax: a matplotlib figure and ax objects
    """
    # stack plot with an hourhly axis
    if ax is None:
        fig = plt.figure(figsize=(16, 9))
        ax = fig.add_subplot(1, 1, 1)
        need_return = True
    else:
        need_return = False
    # stack the states for the stack plot
    stacked_states = np.apply_along_axis(np.bincount,
                                         0,
                                         np.array(states, int),
                                         minlength=np.max(states) + 1)
    ax.stackplot(
        np.arange(0, states.shape[1]),  # Create an x axis
        stacked_states,
        labels=labels)
    handles, lab = ax.get_legend_handles_labels()
    # Reverse the legend, so they follow the states order
    ax.legend(handles[::-1], lab[::-1], loc='right')

    if need_return:
        return fig, ax
    def plot(self, ax: plt.Axes):
        utils.format_axes(ax)
        with_both_bounds = np.logical_and(np.isfinite(self.sed_lower), np.isfinite(self.sed_upper))
        E_mean = np.sqrt(self.E_left * self.E_right)
        E_err_left = E_mean - self.E_left
        E_err_right = self.E_right - E_mean

        # check if the same data has already been plotted and listed on legend
        label = str(self)
        _, legend_texts = ax.get_legend_handles_labels()
        for legend_text in legend_texts:
            if label == legend_text:
                return

        fmt = self.marker
        ax.errorbar(
            E_mean[with_both_bounds],
            self.sed_mean[with_both_bounds],
            xerr=[E_err_left[with_both_bounds], E_err_right[with_both_bounds]],
            yerr=(
                (self.sed_mean - self.sed_lower)[with_both_bounds],
                (self.sed_upper - self.sed_mean)[with_both_bounds],
            ),
            fmt=fmt,
            color=self.color,
            label=label,
        )
        with_upper_bound = np.logical_not(with_both_bounds)
        ax.errorbar(
            E_mean[with_upper_bound],
            self.sed_upper[with_upper_bound],
            xerr=[E_err_left[with_upper_bound], E_err_right[with_upper_bound]],
            yerr=self.sed_upper[with_upper_bound] / 2,
            uplims=True,
            fmt=fmt,
            color=self.color,
        )
Beispiel #13
0
def _unfolded_fit(
    eigs: ndarray,
    unfolded: ndarray,
    title: str = "Unfolding Fit",
    mode: PlotMode = "block",
    outfile: Path = None,
    fig: Figure = None,
    axes: Axes = None,
) -> PlotResult:
    """Plot the unfolding fit against the step function.

    Parameters
    ----------
    unfolded: ndarray
        The unfolded eigenvalues to plot.

    title: string
        The plot title string

    mode: "block" (default) | "noblock" | "save" | "return"
        If "block", call plot.plot() and display plot in a blocking fashion.
        If "noblock", attempt to generate plot in nonblocking fashion.
        If "save", save plot to pathlib Path specified in `outfile` argument
        If "return", return (fig, axes), the matplotlib figure and axes object
        for modification.

    outfile: Path
        If mode="save", save generated plot to Path specified in `outfile` argument.
        Intermediate directories will be created if needed.

    kind: "scatter" (default) | "line"
        Whether to use a scatterplot or line plot.

    fig: Figure
        If provided with `axes`, configure plotting with the provided `fig`
        object instead of creating a new figure. Useful for creating subplots.

    axes: Axes
        If provided with `fig`, plot to the provided `axes` object. Useful for
        creating subplots.


    Returns
    -------
    (fig, axes): (Figure, Axes)
        The handles to the matplotlib objects, only if `mode` is "return".
    """
    _configure_sbn_style()
    # cmap = plt.cm.cividis
    cmap = plt.cm.gist_heat
    fig, axes = _setup_plotting(fig, axes)
    N = len(unfolded)
    step_vals = np.arange(0, N)
    df_line = pd.DataFrame({"Step Function": step_vals, "Unfolded λ": unfolded})
    # df_scatter = pd.DataFrame({"Step Function": steps, "Outlier": np.abs(unfolded)})
    sbn.lineplot(data=df_line, ax=axes)
    mean = np.mean(np.abs(unfolded))

    # 0 is left of cmap, color_max is right of cmap
    color = (5 * np.abs(unfolded) / mean) ** 2
    size = (10 * (np.abs(unfolded) - mean) / mean) ** 2
    inlier = np.abs(unfolded - step_vals) < 5
    color[inlier] = color.min()
    min_size = 0.5
    size[inlier] = min_size
    size[size < 1] = min_size
    axes.scatter(
        x=step_vals,
        y=unfolded,
        s=size,  # size of points
        c=color,  # color of points
        cmap=cmap,  # should be color blind safe
        marker="o",
        # color="red",
        edgecolors="white",
        linewidths=0.1,
        label="Outlier",
        alpha=0.4,
    )
    # plt.setp(ax_scatter, label="Outlier")
    axes.set(title=title, xlabel="Eigenvalue Index", ylabel="Unfolded Value")
    handles, labels = axes.get_legend_handles_labels()
    line_handles, line_labels = handles[:-1], labels[:-1]
    # axes.legend(line_handles, line_labels)
    cmap_handles = [Rectangle((0, 0), 1, 1)]
    # seems you only need a handler map for legend element that need a custom handler
    handler_map = dict(zip(cmap_handles, [HandlerColormap(cmap, num_stripes=16)]))
    labels = [line_labels[0], line_labels[1], "Inlier / Outlier"]
    axes.legend(
        handles=line_handles + cmap_handles,
        labels=labels,
        handler_map=handler_map,
        fontsize=12,
    ).set_visible(True)
    return _handle_plot_mode(mode, fig, axes, outfile)
def plot_3C(ax: plt.Axes,
            bin_edges_human: np.ndarray = np.array(
                [-1000, -4.5, -3, -1.5, 0, 1.5, 3, 4.5, 1000]),
            bin_edges_model: np.ndarray = np.array(
                [-1000, -4.5, -3, -1.5, 0, 1.5, 3, 4.5, 1000])):
    Δ, p_human, p1, p2 = [], [], [], []
    for pid in DataExp2.pids:
        data = DataExp2(pid)
        model = data.build_model(models.BayesianIdealObserver)
        df = model.predict(model.fit())
        Δ += list(np.log(df['C']) - np.log(df['H']))
        model = data.load_model(
            models.ChoiceModel4Param,
            DataExp1(pid).build_model(models.ChoiceModel4Param).fit())
        p1 += list(model.predict(model.fit())['C'])
        p2 += list(data.cross_validate(models.ChoiceModel4Param)['C'])
        p_human += list((data.df['choice'] == 'C') * 1.0)
    df = pd.DataFrame({'Δ': Δ, 'p_human': p_human, 'p1': p1, 'p2': p2})
    x_human, y_human, yerr_human, x_model, y1, yerr1, y2, yerr2 = [], [], [], [], [], [], [], []
    df['bin'] = pd.cut(df['Δ'], bin_edges_human, labels=False)
    for i in range(len(bin_edges_human) - 1):
        _df = df[df['bin'] == i]
        x_human.append(_df['Δ'].mean())
        y_human.append(_df['p_human'].mean())
        yerr_human.append(_df['p_human'].sem())
    df['bin'] = pd.cut(df['Δ'], bin_edges_model, labels=False)
    for i in range(len(bin_edges_model) - 1):
        _df = df[df['bin'] == i]
        x_model.append(_df['Δ'].mean())
        y1.append(_df['p1'].mean())
        yerr1.append(_df['p1'].sem())
        y2.append(_df['p2'].mean())
        yerr2.append(_df['p2'].sem())
    ax.errorbar(x_human,
                y_human,
                yerr_human,
                label='Human $\pm$ sem',
                color=colors['decision_human'],
                fmt='.',
                capsize=2,
                ms=2,
                capthick=0.5,
                zorder=1)
    ax.plot(x_model,
            y1,
            '--',
            color=colors['decision_transfer'],
            label='Transfer model',
            ms=1,
            zorder=0)
    ax.plot(x_model,
            y2,
            '-',
            color=colors['decision_model'],
            label='Fitted model',
            ms=1,
            zorder=0)
    ax.set_xlabel(r'logit( $P_\mathregular{ideal}(S=C\,|\,\bf{X}$) )')
    ax.set_ylabel(r'$P$(choice=$C\,|\,\bf{X}$)')
    ax.set_ylim(0, 1)
    handles, labels = ax.get_legend_handles_labels()
    ax.legend(handles[::-1],
              labels[::-1],
              loc='lower right',
              handler_map={ErrorbarContainer: HandlerErrorbar(yerr_size=0.25)})
    ax.spines['right'].set_visible(False)
    ax.spines['top'].set_visible(False)
    plt.tight_layout()
Beispiel #15
0
def decorate_axes(
    ax: plt.Axes,
    catalogue: VelociraptorCatalogue,
    comment: Union[str, None] = None,
    legend_loc: str = "upper left",
    redshift_loc: str = "lower right",
    comment_loc: str = "lower left",
) -> None:
    """
    Decorates the axes with information about the redshift and
    scale-factor.
    """

    markerfirst = "right" not in legend_loc

    if len(ax.get_legend_handles_labels()[0]):
        # Only create the legend if we have handles available to plot,
        # otherwise we get a warning from matplotlib printed to the
        # console.
        legend = ax.legend(loc=legend_loc, markerfirst=markerfirst)
        fontsize = legend.get_texts()[0].get_fontsize()
    else:
        fontsize = None

    label_switch = {
        redshift_loc: f"$z={catalogue.z:2.3f}$\n$a={catalogue.a:2.3f}$",
        comment_loc: comment,
    }

    distance_from_edge = 0.025

    for loc, label in label_switch.items():
        if label is not None:
            # First need to parse the 'loc' string
            try:
                va, ha = loc.split(" ")
            except ValueError:
                if loc == "right":
                    ha = "right"
                    va = "center"
                elif loc == "center":
                    ha = "center"
                    va = "center"

            if va == "lower":
                y = distance_from_edge
                va = "bottom"
            elif va == "upper":
                y = 1.0 - distance_from_edge
                va = "top"
            elif va == "center":
                y = 0.5
            else:
                raise AttributeError(
                    f"Unknown location string {loc}. Choose e.g. lower right")

            if ha == "left":
                x = distance_from_edge
            elif ha == "right":
                x = 1.0 - distance_from_edge
            elif ha == "center":
                x = 0.5

            ax.text(
                x,
                y,
                label,
                ha=ha,
                va=va,
                transform=ax.transAxes,
                multialignment=ha,
                fontsize=fontsize,
            )

    return