# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/API/plotter.ipynb.

# %% auto 0
__all__ = ['effectsize_df_plotter']

# %% ../nbs/API/plotter.ipynb 4
import numpy as np
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
import pandas as pd
import warnings
import logging

# %% ../nbs/API/plotter.ipynb 5
# TODO refactor function name
def effectsize_df_plotter(effectsize_df, **plot_kwargs):
    """
    Custom function that creates an estimation plot from an EffectSizeDataFrame.
    Keywords
    --------
    Parameters
    ----------
    effectsize_df
        A `dabest` EffectSizeDataFrame object.
    plot_kwargs
        color_col=None
        raw_marker_size=6, es_marker_size=9,
        swarm_label=None, contrast_label=None, delta2_label=None,
        swarm_ylim=None, contrast_ylim=None, delta2_ylim=None,
        custom_palette=None, swarm_desat=0.5, halfviolin_desat=1,
        halfviolin_alpha=0.8,
        face_color = None,
        bar_label=None, bar_desat=0.8, bar_width = 0.5,bar_ylim = None,
        ci=None, ci_type='bca', err_color=None,
        float_contrast=True,
        show_pairs=True,
        show_delta2=True,
        group_summaries=None,
        group_summaries_offset=0.1,
        fig_size=None,
        dpi=100,
        ax=None,
        gridkey_rows=None,
        swarmplot_kwargs=None,
        violinplot_kwargs=None,
        slopegraph_kwargs=None,
        sankey_kwargs=None,
        reflines_kwargs=None,
        group_summary_kwargs=None,
        legend_kwargs=None,
        title=None, fontsize_title=16,
        fontsize_rawxlabel=12, fontsize_rawylabel=12,
        fontsize_contrastxlabel=12, fontsize_contrastylabel=12,
        fontsize_delta2label=12
    """
    from .misc_tools import merge_two_dicts
    from .plot_tools import (
        halfviolin,
        get_swarm_spans,
        error_bar,
        sankeydiag,
        swarmplot,
    )
    from ._stats_tools.effsize import (
        _compute_standardizers,
        _compute_hedges_correction_factor,
    )

    warnings.filterwarnings(
        "ignore", "This figure includes Axes that are not compatible with tight_layout"
    )

    # Have to disable logging of warning when get_legend_handles_labels()
    # tries to get from slopegraph.
    logging.disable(logging.WARNING)

    # Save rcParams that I will alter, so I can reset back.
    original_rcParams = {}
    _changed_rcParams = ["axes.grid"]
    for parameter in _changed_rcParams:
        original_rcParams[parameter] = plt.rcParams[parameter]

    plt.rcParams["axes.grid"] = False

    ytick_color = plt.rcParams["ytick.color"]
    face_color = plot_kwargs["face_color"]

    if plot_kwargs["face_color"] is None:
        face_color = "white"

    dabest_obj = effectsize_df.dabest_obj
    plot_data = effectsize_df._plot_data
    xvar = effectsize_df.xvar
    yvar = effectsize_df.yvar
    is_paired = effectsize_df.is_paired
    delta2 = effectsize_df.delta2
    mini_meta = effectsize_df.mini_meta
    effect_size = effectsize_df.effect_size
    proportional = effectsize_df.proportional

    all_plot_groups = dabest_obj._all_plot_groups
    idx = dabest_obj.idx

    if effect_size not in ["mean_diff", "delta_g"] or not delta2:
        show_delta2 = False
    else:
        show_delta2 = plot_kwargs["show_delta2"]

    if effect_size != "mean_diff" or not mini_meta:
        show_mini_meta = False
    else:
        show_mini_meta = plot_kwargs["show_mini_meta"]

    if show_delta2 and show_mini_meta:
        err0 = "`show_delta2` and `show_mini_meta` cannot be True at the same time."
        raise ValueError(err0)

    # Disable Gardner-Altman plotting if any of the idxs comprise of more than
    # two groups or if it is a delta-delta plot.
    float_contrast = plot_kwargs["float_contrast"]
    effect_size_type = effectsize_df.effect_size
    if len(idx) > 1 or len(idx[0]) > 2:
        float_contrast = False

    if effect_size_type in ["cliffs_delta"]:
        float_contrast = False

    if show_delta2 or show_mini_meta:
        float_contrast = False

    if not is_paired:
        show_pairs = False
    else:
        show_pairs = plot_kwargs["show_pairs"]

    # Set default kwargs first, then merge with user-dictated ones.
    # Swarmplot kwargs
    default_swarmplot_kwargs = {"size": plot_kwargs["raw_marker_size"]}
    if plot_kwargs["swarmplot_kwargs"] is None:
        swarmplot_kwargs = default_swarmplot_kwargs
    else:
        swarmplot_kwargs = merge_two_dicts(
            default_swarmplot_kwargs, plot_kwargs["swarmplot_kwargs"]
        )
    asymmetric_side = (
        "left"  # TODO: allow users to control side for swarms of swarmplot.
    )

    # Barplot kwargs
    default_barplot_kwargs = {"estimator": np.mean, "errorbar": plot_kwargs["ci"]}

    if plot_kwargs["barplot_kwargs"] is None:
        barplot_kwargs = default_barplot_kwargs
    else:
        barplot_kwargs = merge_two_dicts(
            default_barplot_kwargs, plot_kwargs["barplot_kwargs"]
        )

    # Sankey Diagram kwargs
    default_sankey_kwargs = {
        "width": 0.4,
        "align": "center",
        "sankey": True,
        "flow": True,
        "alpha": 0.4,
        "rightColor": False,
        "bar_width": 0.2,
    }
    if plot_kwargs["sankey_kwargs"] is None:
        sankey_kwargs = default_sankey_kwargs
    else:
        sankey_kwargs = merge_two_dicts(
            default_sankey_kwargs, plot_kwargs["sankey_kwargs"]
        )
    # We also need to extract the `sankey` and `flow` from the kwargs for plotter.py
    # to use for varying different kinds of paired proportional plots
    # We also don't want to pop the parameter from the kwargs
    sankey = sankey_kwargs["sankey"]
    flow = sankey_kwargs["flow"]

    # Violinplot kwargs.
    default_violinplot_kwargs = {
        "widths": 0.5,
        "vert": True,
        "showextrema": False,
        "showmedians": False,
    }
    if plot_kwargs["violinplot_kwargs"] is None:
        violinplot_kwargs = default_violinplot_kwargs
    else:
        violinplot_kwargs = merge_two_dicts(
            default_violinplot_kwargs, plot_kwargs["violinplot_kwargs"]
        )

    # Slopegraph kwargs.
    default_slopegraph_kwargs = {"linewidth": 1, "alpha": 0.5}
    if plot_kwargs["slopegraph_kwargs"] is None:
        slopegraph_kwargs = default_slopegraph_kwargs
    else:
        slopegraph_kwargs = merge_two_dicts(
            default_slopegraph_kwargs, plot_kwargs["slopegraph_kwargs"]
        )

    # Zero reference-line kwargs.
    default_reflines_kwargs = {
        "linestyle": "solid",
        "linewidth": 0.75,
        "zorder": 2,
        "color": ytick_color,
    }
    if plot_kwargs["reflines_kwargs"] is None:
        reflines_kwargs = default_reflines_kwargs
    else:
        reflines_kwargs = merge_two_dicts(
            default_reflines_kwargs, plot_kwargs["reflines_kwargs"]
        )

    # Legend kwargs.
    default_legend_kwargs = {"loc": "upper left", "frameon": False}
    if plot_kwargs["legend_kwargs"] is None:
        legend_kwargs = default_legend_kwargs
    else:
        legend_kwargs = merge_two_dicts(
            default_legend_kwargs, plot_kwargs["legend_kwargs"]
        )

    ################################################### GRIDKEY WIP - extracting arguments

    gridkey_rows = plot_kwargs["gridkey_rows"]
    gridkey_merge_pairs = plot_kwargs["gridkey_merge_pairs"]
    gridkey_show_Ns = plot_kwargs["gridkey_show_Ns"]
    gridkey_show_es = plot_kwargs["gridkey_show_es"]

    if gridkey_rows is None:
        gridkey_show_Ns = False
        gridkey_show_es = False

    ################################################### END GRIDKEY WIP - extracting arguments

    # Group summaries kwargs.
    gs_default = {"mean_sd", "median_quartiles", None}
    if plot_kwargs["group_summaries"] not in gs_default:
        raise ValueError(
            "group_summaries must be one of" " these: {}.".format(gs_default)
        )

    default_group_summary_kwargs = {"zorder": 3, "lw": 2, "alpha": 1}
    if plot_kwargs["group_summary_kwargs"] is None:
        group_summary_kwargs = default_group_summary_kwargs
    else:
        group_summary_kwargs = merge_two_dicts(
            default_group_summary_kwargs, plot_kwargs["group_summary_kwargs"]
        )

    # Create color palette that will be shared across subplots.
    color_col = plot_kwargs["color_col"]
    if color_col is None:
        color_groups = pd.unique(plot_data[xvar])
        bootstraps_color_by_group = True
    else:
        if color_col not in plot_data.columns:
            raise KeyError("``{}`` is not a column in the data.".format(color_col))
        color_groups = pd.unique(plot_data[color_col])
        bootstraps_color_by_group = False
    if show_pairs:
        bootstraps_color_by_group = False

    # Handle the color palette.
    names = color_groups
    n_groups = len(color_groups)
    custom_pal = plot_kwargs["custom_palette"]
    swarm_desat = plot_kwargs["swarm_desat"]
    bar_desat = plot_kwargs["bar_desat"]
    contrast_desat = plot_kwargs["halfviolin_desat"]

    if custom_pal is None:
        unsat_colors = sns.color_palette(n_colors=n_groups)
    else:
        if isinstance(custom_pal, dict):
            groups_in_palette = {
                k: v for k, v in custom_pal.items() if k in color_groups
            }

            names = groups_in_palette.keys()
            unsat_colors = groups_in_palette.values()

        elif isinstance(custom_pal, list):
            unsat_colors = custom_pal[0:n_groups]

        elif isinstance(custom_pal, str):
            # check it is in the list of matplotlib palettes.
            if custom_pal in plt.colormaps():
                unsat_colors = sns.color_palette(custom_pal, n_groups)
            else:
                err1 = "The specified `custom_palette` {}".format(custom_pal)
                err2 = " is not a matplotlib palette. Please check."
                raise ValueError(err1 + err2)

    if custom_pal is None and color_col is None:
        swarm_colors = [sns.desaturate(c, swarm_desat) for c in unsat_colors]
        plot_palette_raw = dict(zip(names.categories, swarm_colors))

        bar_color = [sns.desaturate(c, bar_desat) for c in unsat_colors]
        plot_palette_bar = dict(zip(names.categories, bar_color))

        contrast_colors = [sns.desaturate(c, contrast_desat) for c in unsat_colors]
        plot_palette_contrast = dict(zip(names.categories, contrast_colors))

        # For Sankey Diagram plot, no need to worry about the color, each bar will have the same two colors
        # default color palette will be set to "hls"
        plot_palette_sankey = None

    else:
        swarm_colors = [sns.desaturate(c, swarm_desat) for c in unsat_colors]
        plot_palette_raw = dict(zip(names, swarm_colors))

        bar_color = [sns.desaturate(c, bar_desat) for c in unsat_colors]
        plot_palette_bar = dict(zip(names, bar_color))

        contrast_colors = [sns.desaturate(c, contrast_desat) for c in unsat_colors]
        plot_palette_contrast = dict(zip(names, contrast_colors))

        plot_palette_sankey = custom_pal

    # Infer the figsize.
    fig_size = plot_kwargs["fig_size"]
    if fig_size is None:
        all_groups_count = np.sum([len(i) for i in dabest_obj.idx])
        # Increase the width for delta-delta graph
        if show_delta2 or show_mini_meta:
            all_groups_count += 2
        if is_paired and show_pairs and proportional is False:
            frac = 0.75
        else:
            frac = 1
        if float_contrast:
            height_inches = 4
            each_group_width_inches = 2.5 * frac
        else:
            height_inches = 6
            each_group_width_inches = 1.5 * frac

        width_inches = each_group_width_inches * all_groups_count
        fig_size = (width_inches, height_inches)

    # Initialise the figure.
    init_fig_kwargs = dict(figsize=fig_size, dpi=plot_kwargs["dpi"], tight_layout=True)

    width_ratios_ga = [2.5, 1]

    ###################### GRIDKEY HSPACE ALTERATION

    # Sets hspace for cummings plots if gridkey is shown.
    if gridkey_rows is not None:
        h_space_cummings = 0.1
    else:
        h_space_cummings = 0.3

    ###################### END GRIDKEY HSPACE ALTERATION

    if plot_kwargs["ax"] is not None:
        # New in v0.2.6.
        # Use inset axes to create the estimation plot inside a single axes.
        # Author: Adam L Nekimken. (PR #73)
        rawdata_axes = plot_kwargs["ax"]
        ax_position = rawdata_axes.get_position()  # [[x0, y0], [x1, y1]]

        fig = rawdata_axes.get_figure()
        fig.patch.set_facecolor(face_color)

        if float_contrast:
            axins = rawdata_axes.inset_axes(
                [1, 0, width_ratios_ga[1] / width_ratios_ga[0], 1]
            )
            rawdata_axes.set_position(  # [l, b, w, h]
                [
                    ax_position.x0,
                    ax_position.y0,
                    (ax_position.x1 - ax_position.x0)
                    * (width_ratios_ga[0] / sum(width_ratios_ga)),
                    (ax_position.y1 - ax_position.y0),
                ]
            )

            contrast_axes = axins

        else:
            axins = rawdata_axes.inset_axes([0, -1 - h_space_cummings, 1, 1])
            plot_height = (ax_position.y1 - ax_position.y0) / (2 + h_space_cummings)
            rawdata_axes.set_position(
                [
                    ax_position.x0,
                    ax_position.y0 + (1 + h_space_cummings) * plot_height,
                    (ax_position.x1 - ax_position.x0),
                    plot_height,
                ]
            )

        contrast_axes = axins
        rawdata_axes.contrast_axes = axins

    else:
        # Here, we hardcode some figure parameters.
        if float_contrast:
            fig, axx = plt.subplots(
                ncols=2,
                gridspec_kw={"width_ratios": width_ratios_ga, "wspace": 0},
                **init_fig_kwargs
            )
            fig.patch.set_facecolor(face_color)

        else:
            fig, axx = plt.subplots(
                nrows=2, gridspec_kw={"hspace": h_space_cummings}, **init_fig_kwargs
            )
            fig.patch.set_facecolor(face_color)

        # Title
        title = plot_kwargs["title"]
        fontsize_title = plot_kwargs["fontsize_title"]
        if title is not None:
            fig.suptitle(title, fontsize=fontsize_title)
        rawdata_axes = axx[0]
        contrast_axes = axx[1]
    rawdata_axes.set_frame_on(False)
    contrast_axes.set_frame_on(False)

    redraw_axes_kwargs = {
        "colors": ytick_color,
        "facecolors": ytick_color,
        "lw": 1,
        "zorder": 10,
        "clip_on": False,
    }

    swarm_ylim = plot_kwargs["swarm_ylim"]

    if swarm_ylim is not None:
        rawdata_axes.set_ylim(swarm_ylim)

    one_sankey = (
        False if is_paired is not None else None
    )  # Flag to indicate if only one sankey is plotted.
    two_col_sankey = (
        True if proportional and not one_sankey and sankey and not flow else False
    )

    if show_pairs:
        # Determine temp_idx based on is_paired and proportional conditions
        if is_paired == "baseline":
            idx_pairs = [
                (control, test)
                for i in idx
                for control, test in zip([i[0]] * (len(i) - 1), i[1:])
            ]
            temp_idx = idx if not proportional else idx_pairs
        else:
            idx_pairs = [
                (control, test) for i in idx for control, test in zip(i[:-1], i[1:])
            ]
            temp_idx = idx if not proportional else idx_pairs

        # Determine temp_all_plot_groups based on proportional condition
        plot_groups = [item for i in temp_idx for item in i]
        temp_all_plot_groups = all_plot_groups if not proportional else plot_groups

        if not proportional:
            # Plot the raw data as a slopegraph.
            # Pivot the long (melted) data.
            if color_col is None:
                pivot_values = [yvar]
            else:
                pivot_values = [yvar, color_col]
            pivoted_plot_data = pd.pivot(
                data=plot_data,
                index=dabest_obj.id_col,
                columns=xvar,
                values=pivot_values,
            )
            x_start = 0
            for ii, current_tuple in enumerate(temp_idx):
                current_pair = pivoted_plot_data.loc[
                    :, pd.MultiIndex.from_product([pivot_values, current_tuple])
                ].dropna()
                grp_count = len(current_tuple)
                # Iterate through the data for the current tuple.
                for ID, observation in current_pair.iterrows():
                    x_points = [t for t in range(x_start, x_start + grp_count)]
                    y_points = observation[yvar].tolist()

                    if color_col is None:
                        slopegraph_kwargs["color"] = ytick_color
                    else:
                        color_key = observation[color_col][0]
                        if isinstance(color_key, (str, np.int64, np.float64)):
                            slopegraph_kwargs["color"] = plot_palette_raw[color_key]
                            slopegraph_kwargs["label"] = color_key

                    rawdata_axes.plot(x_points, y_points, **slopegraph_kwargs)

                x_start = x_start + grp_count

            ##################### DELTA PTS ON CONTRAST PLOT WIP

            contrast_show_deltas = plot_kwargs["contrast_show_deltas"]

            if is_paired is None:
                contrast_show_deltas = False

            if contrast_show_deltas:
                delta_plot_data_temp = plot_data.copy()
                delta_id_col = dabest_obj.id_col
                if color_col is not None:
                    plot_palette_deltapts = plot_palette_raw
                    delta_plot_data = delta_plot_data_temp[
                        [xvar, yvar, delta_id_col, color_col]
                    ]
                    deltapts_args = {
                        "marker": "^",
                        "alpha": 0.5,
                    }

                else:
                    plot_palette_deltapts = "k"
                    delta_plot_data = delta_plot_data_temp[[xvar, yvar, delta_id_col]]
                    deltapts_args = {"marker": "^", "alpha": 0.5}

                final_deltas = pd.DataFrame()
                for i in idx:
                    for j in i:
                        if i.index(j) != 0:
                            temp_df_exp = delta_plot_data[
                                delta_plot_data[xvar].str.contains(j)
                            ].reset_index(drop=True)
                            if is_paired == "baseline":
                                temp_df_cont = delta_plot_data[
                                    delta_plot_data[xvar].str.contains(i[0])
                                ].reset_index(drop=True)
                            elif is_paired == "sequential":
                                temp_df_cont = delta_plot_data[
                                    delta_plot_data[xvar].str.contains(
                                        i[i.index(j) - 1]
                                    )
                                ].reset_index(drop=True)
                            delta_df = temp_df_exp.copy()
                            delta_df[yvar] = temp_df_exp[yvar] - temp_df_cont[yvar]
                            final_deltas = pd.concat([final_deltas, delta_df])

                # swarmplot() plots swarms based on current size of ax
                # Therefore, since the ax size for Gardner-Altman plot changes later on, there has to be decreased jitter
                # TODO: to make jitter value more accurate and not just a hardcoded eyeball value
                if float_contrast:
                    jitter = 0.6
                else:
                    jitter = 1

                # Plot the raw data as a swarmplot.
                deltapts_plot = swarmplot(
                    data=final_deltas,
                    x=xvar,
                    y=yvar,
                    ax=contrast_axes,
                    order=None,
                    hue=color_col,
                    palette=plot_palette_deltapts,
                    zorder=2,
                    size=3,
                    side="right",
                    jitter=jitter,
                    is_drop_gutter=True,
                    gutter_limit=1,
                    **deltapts_args
                )
                contrast_axes.legend().set_visible(False)

            ##################### DELTA PTS ON CONTRAST PLOT END

            # Set the tick labels, because the slopegraph plotting doesn't.
            rawdata_axes.set_xticks(np.arange(0, len(temp_all_plot_groups)))
            rawdata_axes.set_xticklabels(temp_all_plot_groups)

        else:
            # Plot the raw data as a set of Sankey Diagrams aligned like barplot.
            group_summaries = plot_kwargs["group_summaries"]
            if group_summaries is None:
                group_summaries = "mean_sd"
            err_color = plot_kwargs["err_color"]
            if err_color is None:
                err_color = "black"

            if show_pairs:
                sankey_control_group = []
                sankey_test_group = []
                # Design for Sankey Flow Diagram
                sankey_idx = (
                    [
                        (control, test)
                        for i in idx
                        for control, test in zip(i[:], (i[1:] + (i[0],)))
                    ]
                    if flow
                    else temp_idx
                )
                for i in sankey_idx:
                    sankey_control_group.append(i[0])
                    sankey_test_group.append(i[1])

            if len(temp_all_plot_groups) == 2:
                one_sankey = True
                sankey_control_group.pop()
                sankey_test_group.pop()  # Remove the last element from two lists

            # two_col_sankey = True if proportional == True and one_sankey == False and sankey == True and flow == False else False

            # Replace the paired proportional plot with sankey diagram
            sankeyplot = sankeydiag(
                plot_data,
                xvar=xvar,
                yvar=yvar,
                left_idx=sankey_control_group,
                right_idx=sankey_test_group,
                palette=plot_palette_sankey,
                ax=rawdata_axes,
                one_sankey=one_sankey,
                **sankey_kwargs
            )

    else:
        if not proportional:
            # Plot the raw data as a swarmplot.
            asymmetric_side = (
                plot_kwargs["swarm_side"] if plot_kwargs["swarm_side"] is not None else "right"
            )  # Default asymmetric side is right

            # swarmplot() plots swarms based on current size of ax
            # Therefore, since the ax size for mini_meta and show_delta changes later on, there has to be increased jitter
            # TODO: to make jitter value more accurate and not just a hardcoded eyeball value
            if show_mini_meta:
                jitter = 1.25
            elif show_delta2:
                jitter = 1.4
            else:
                jitter = 1

            if color_col is None: # Determine the use of hue
                rawdata_plot = swarmplot(
                    data=plot_data,
                    x=xvar,
                    y=yvar,
                    ax=rawdata_axes,
                    order=all_plot_groups,
                    hue=xvar,
                    palette=plot_palette_raw,
                    zorder=1,
                    side=asymmetric_side,
                    jitter=jitter,
                    is_drop_gutter=True,
                    gutter_limit=0.45,
                    **swarmplot_kwargs
                )
                rawdata_plot.legend().set_visible(False)
            else:
                rawdata_plot = swarmplot(
                    data=plot_data,
                    x=xvar,
                    y=yvar,
                    ax=rawdata_axes,
                    order=all_plot_groups,
                    hue=color_col,
                    palette=plot_palette_raw,
                    zorder=1,
                    side=asymmetric_side,
                    jitter=jitter,
                    is_drop_gutter=True,
                    gutter_limit=0.45,
                    **swarmplot_kwargs
                )
        else:
            # Plot the raw data as a barplot.
            bar1_df = pd.DataFrame(
                {xvar: all_plot_groups, "proportion": np.ones(len(all_plot_groups))}
            )
            bar1 = sns.barplot(
                data=bar1_df,
                x=xvar,
                y="proportion",
                ax=rawdata_axes,
                order=all_plot_groups,
                linewidth=2,
                facecolor=(1, 1, 1, 0),
                edgecolor=bar_color,
                zorder=1,
            )
            bar2 = sns.barplot(
                data=plot_data,
                x=xvar,
                y=yvar,
                ax=rawdata_axes,
                order=all_plot_groups,
                palette=plot_palette_bar,
                zorder=1,
                **barplot_kwargs
            )
            # adjust the width of bars
            bar_width = plot_kwargs["bar_width"]
            for bar in bar1.patches:
                x = bar.get_x()
                width = bar.get_width()
                centre = x + width / 2.0
                bar.set_x(centre - bar_width / 2.0)
                bar.set_width(bar_width)

        # Plot the gapped line summaries, if this is not a Cumming plot.
        # Also, we will not plot gapped lines for paired plots. For now.
        group_summaries = plot_kwargs["group_summaries"]
        if group_summaries is None:
            group_summaries = "mean_sd"

        if group_summaries is not None and not proportional:
            # Create list to gather xspans.
            xspans = []
            line_colors = []
            for jj, c in enumerate(rawdata_axes.collections):
                try:
                    if asymmetric_side == "right":
                        # currently offset is hardcoded with value of -0.2
                        x_max_span = -0.2
                    else:
                        _, x_max, _, _ = get_swarm_spans(c)
                        x_max_span = x_max - jj
                    xspans.append(x_max_span)
                except TypeError:
                    # we have got a None, so skip and move on.
                    pass

                if bootstraps_color_by_group:
                    line_colors.append(plot_palette_raw[all_plot_groups[jj]])

                # Break the loop since hue in Seaborn adds collections to axes and it will result in index out of range
                if jj >= n_groups - 1 and color_col is None:
                    break

            if len(line_colors) != len(all_plot_groups):
                line_colors = ytick_color

            error_bar(
                plot_data,
                x=xvar,
                y=yvar,
                # Hardcoded offset...
                offset=xspans + np.array(plot_kwargs["group_summaries_offset"]),
                line_color=line_colors,
                gap_width_percent=1.5,
                type=group_summaries,
                ax=rawdata_axes,
                method="gapped_lines",
                **group_summary_kwargs
            )

        if group_summaries is not None and proportional:
            err_color = plot_kwargs["err_color"]
            if err_color is None:
                err_color = "black"
            error_bar(
                plot_data,
                x=xvar,
                y=yvar,
                offset=0,
                line_color=err_color,
                gap_width_percent=1.5,
                type=group_summaries,
                ax=rawdata_axes,
                method="proportional_error_bar",
                **group_summary_kwargs
            )

    # Add the counts to the rawdata axes xticks.
    counts = plot_data.groupby(xvar).count()[yvar]
    ticks_with_counts = []
    ticks_loc = rawdata_axes.get_xticks()
    rawdata_axes.xaxis.set_major_locator(matplotlib.ticker.FixedLocator(ticks_loc))
    for xticklab in rawdata_axes.xaxis.get_ticklabels():
        t = xticklab.get_text()
        if t.rfind("\n") != -1:
            te = t[t.rfind("\n") + len("\n") :]
            N = str(counts.loc[te])
            te = t
        else:
            te = t
            N = str(counts.loc[te])

        ticks_with_counts.append("{}\nN = {}".format(te, N))

    if plot_kwargs["fontsize_rawxlabel"] is not None:
        fontsize_rawxlabel = plot_kwargs["fontsize_rawxlabel"]
    rawdata_axes.set_xticklabels(ticks_with_counts, fontsize=fontsize_rawxlabel)

    # Save the handles and labels for the legend.
    handles, labels = rawdata_axes.get_legend_handles_labels()
    legend_labels = [l for l in labels]
    legend_handles = [h for h in handles]
    if bootstraps_color_by_group is False:
        rawdata_axes.legend().set_visible(False)

    # Enforce the xtick of rawdata_axes to be 0 and 1 after drawing only one sankey
    if one_sankey:
        rawdata_axes.set_xticks([0, 1])

    # Plot effect sizes and bootstraps.
    # Take note of where the `control` groups are.
    if is_paired == "baseline" and show_pairs:
        if two_col_sankey:
            ticks_to_skip = []
            ticks_to_plot = np.arange(0, len(temp_all_plot_groups) / 2).tolist()
            ticks_to_start_twocol_sankey = np.cumsum([len(i) - 1 for i in idx]).tolist()
            ticks_to_start_twocol_sankey.pop()
            ticks_to_start_twocol_sankey.insert(0, 0)
        else:
            # ticks_to_skip = np.arange(0, len(temp_all_plot_groups), 2).tolist()
            # ticks_to_plot = np.arange(1, len(temp_all_plot_groups), 2).tolist()
            ticks_to_skip = np.cumsum([len(t) for t in idx])[:-1].tolist()
            ticks_to_skip.insert(0, 0)
            # Then obtain the ticks where we have to plot the effect sizes.
            ticks_to_plot = [
                t for t in range(0, len(all_plot_groups)) if t not in ticks_to_skip
            ]
            ticks_to_skip_contrast = np.cumsum([(len(t)) for t in idx])[:-1].tolist()
            ticks_to_skip_contrast.insert(0, 0)
    else:
        if two_col_sankey:
            ticks_to_skip = [len(sankey_control_group)]
            # Then obtain the ticks where we have to plot the effect sizes.
            ticks_to_plot = [
                t for t in range(0, len(temp_idx)) if t not in ticks_to_skip
            ]
            ticks_to_skip = []
            ticks_to_start_twocol_sankey = np.cumsum([len(i) - 1 for i in idx]).tolist()
            ticks_to_start_twocol_sankey.pop()
            ticks_to_start_twocol_sankey.insert(0, 0)
        else:
            ticks_to_skip = np.cumsum([len(t) for t in idx])[:-1].tolist()
            ticks_to_skip.insert(0, 0)
            # Then obtain the ticks where we have to plot the effect sizes.
            ticks_to_plot = [
                t for t in range(0, len(all_plot_groups)) if t not in ticks_to_skip
            ]

    # Plot the bootstraps, then the effect sizes and CIs.
    es_marker_size = plot_kwargs["es_marker_size"]
    halfviolin_alpha = plot_kwargs["halfviolin_alpha"]

    ci_type = plot_kwargs["ci_type"]

    results = effectsize_df.results
    contrast_xtick_labels = []

    for j, tick in enumerate(ticks_to_plot):
        current_group = results.test[j]
        current_control = results.control[j]
        current_bootstrap = results.bootstraps[j]
        current_effsize = results.difference[j]
        if ci_type == "bca":
            current_ci_low = results.bca_low[j]
            current_ci_high = results.bca_high[j]
        else:
            current_ci_low = results.pct_low[j]
            current_ci_high = results.pct_high[j]

        # Create the violinplot.
        # New in v0.2.6: drop negative infinities before plotting.
        v = contrast_axes.violinplot(
            current_bootstrap[~np.isinf(current_bootstrap)],
            positions=[tick],
            **violinplot_kwargs
        )
        # Turn the violinplot into half, and color it the same as the swarmplot.
        # Do this only if the color column is not specified.
        # Ideally, the alpha (transparency) fo the violin plot should be
        # less than one so the effect size and CIs are visible.
        if bootstraps_color_by_group:
            fc = plot_palette_contrast[current_group]
        else:
            fc = "grey"

        halfviolin(v, fill_color=fc, alpha=halfviolin_alpha)

        # Plot the effect size.
        contrast_axes.plot(
            [tick],
            current_effsize,
            marker="o",
            color=ytick_color,
            markersize=es_marker_size,
        )

        ################## SHOW ES ON CONTRAST PLOT WIP

        contrast_show_es = plot_kwargs["contrast_show_es"]
        es_sf = plot_kwargs["es_sf"]
        es_fontsize = plot_kwargs["es_fontsize"]

        if gridkey_show_es:
            contrast_show_es = False

        effsize_for_print = current_effsize

        printed_es = np.format_float_positional(
            effsize_for_print, precision=es_sf, sign=True, trim="k", min_digits=es_sf
        )
        if contrast_show_es:
            if effsize_for_print < 0:
                textoffset = 10
            else:
                textoffset = 15
            contrast_axes.annotate(
                text=printed_es,
                xy=(tick, effsize_for_print),
                xytext=(
                    -textoffset - len(printed_es) * es_fontsize / 2,
                    -es_fontsize / 2,
                ),
                textcoords="offset points",
                **{"fontsize": es_fontsize}
            )

        ################## SHOW ES ON CONTRAST PLOT END

        # Plot the confidence interval.
        contrast_axes.plot(
            [tick, tick],
            [current_ci_low, current_ci_high],
            linestyle="-",
            color=ytick_color,
            linewidth=group_summary_kwargs["lw"],
        )

        contrast_xtick_labels.append(
            "{}\nminus\n{}".format(current_group, current_control)
        )

    # Plot mini-meta violin
    if show_mini_meta or show_delta2:
        if show_mini_meta:
            mini_meta_delta = effectsize_df.mini_meta_delta
            data = mini_meta_delta.bootstraps_weighted_delta
            difference = mini_meta_delta.difference
            if ci_type == "bca":
                ci_low = mini_meta_delta.bca_low
                ci_high = mini_meta_delta.bca_high
            else:
                ci_low = mini_meta_delta.pct_low
                ci_high = mini_meta_delta.pct_high
        else:
            delta_delta = effectsize_df.delta_delta
            data = delta_delta.bootstraps_delta_delta
            difference = delta_delta.difference
            if ci_type == "bca":
                ci_low = delta_delta.bca_low
                ci_high = delta_delta.bca_high
            else:
                ci_low = delta_delta.pct_low
                ci_high = delta_delta.pct_high
        # Create the violinplot.
        # New in v0.2.6: drop negative infinities before plotting.
        position = max(rawdata_axes.get_xticks()) + 2
        v = contrast_axes.violinplot(
            data[~np.isinf(data)], positions=[position], **violinplot_kwargs
        )

        fc = "grey"

        halfviolin(v, fill_color=fc, alpha=halfviolin_alpha)

        # Plot the effect size.
        contrast_axes.plot(
            [position],
            difference,
            marker="o",
            color=ytick_color,
            markersize=es_marker_size,
        )
        # Plot the confidence interval.
        contrast_axes.plot(
            [position, position],
            [ci_low, ci_high],
            linestyle="-",
            color=ytick_color,
            linewidth=group_summary_kwargs["lw"],
        )
        if show_mini_meta:
            contrast_xtick_labels.extend(["", "Weighted delta"])
        elif effect_size == "delta_g":
            contrast_xtick_labels.extend(["", "deltas' g"])
        else:
            contrast_xtick_labels.extend(["", "delta-delta"])

    # Make sure the contrast_axes x-lims match the rawdata_axes xlims,
    # and add an extra violinplot tick for delta-delta plot.
    if show_delta2 is False and show_mini_meta is False:
        contrast_axes.set_xticks(rawdata_axes.get_xticks())
    else:
        temp = rawdata_axes.get_xticks()
        temp = np.append(temp, [max(temp) + 1, max(temp) + 2])
        contrast_axes.set_xticks(temp)

    if show_pairs:
        max_x = contrast_axes.get_xlim()[1]
        rawdata_axes.set_xlim(-0.375, max_x)

    if float_contrast:
        contrast_axes.set_xlim(0.5, 1.5)
    elif show_delta2 or show_mini_meta:
        # Increase the xlim of raw data by 2
        temp = rawdata_axes.get_xlim()
        if show_pairs:
            rawdata_axes.set_xlim(temp[0], temp[1] + 0.25)
        else:
            rawdata_axes.set_xlim(temp[0], temp[1] + 2)
        contrast_axes.set_xlim(rawdata_axes.get_xlim())
    else:
        contrast_axes.set_xlim(rawdata_axes.get_xlim())

    # Properly label the contrast ticks.
    for t in ticks_to_skip:
        contrast_xtick_labels.insert(t, "")

    if plot_kwargs["fontsize_contrastxlabel"] is not None:
        fontsize_contrastxlabel = plot_kwargs["fontsize_contrastxlabel"]

    contrast_axes.set_xticklabels(
        contrast_xtick_labels, fontsize=fontsize_contrastxlabel
    )

    if bootstraps_color_by_group is False:
        legend_labels_unique = np.unique(legend_labels)
        unique_idx = np.unique(legend_labels, return_index=True)[1]
        legend_handles_unique = (
            pd.Series(legend_handles, dtype="object").loc[unique_idx]
        ).tolist()

        if len(legend_handles_unique) > 0:
            if float_contrast:
                axes_with_legend = contrast_axes
                if show_pairs:
                    bta = (1.75, 1.02)
                else:
                    bta = (1.5, 1.02)
            else:
                axes_with_legend = rawdata_axes
                if show_pairs:
                    bta = (1.02, 1.0)
                else:
                    bta = (1.0, 1.0)
            leg = axes_with_legend.legend(
                legend_handles_unique,
                legend_labels_unique,
                bbox_to_anchor=bta,
                **legend_kwargs
            )
            if show_pairs:
                for line in leg.get_lines():
                    line.set_linewidth(3.0)

    og_ylim_raw = rawdata_axes.get_ylim()
    og_xlim_raw = rawdata_axes.get_xlim()

    if float_contrast:
        # For Gardner-Altman plots only.

        # Normalize ylims and despine the floating contrast axes.
        # Check that the effect size is within the swarm ylims.
        if effect_size_type in ["mean_diff", "cohens_d", "hedges_g", "cohens_h"]:
            control_group_summary = (
                plot_data.groupby(xvar)
                .mean(numeric_only=True)
                .loc[current_control, yvar]
            )
            test_group_summary = (
                plot_data.groupby(xvar).mean(numeric_only=True).loc[current_group, yvar]
            )
        elif effect_size_type == "median_diff":
            control_group_summary = (
                plot_data.groupby(xvar).median().loc[current_control, yvar]
            )
            test_group_summary = (
                plot_data.groupby(xvar).median().loc[current_group, yvar]
            )

        if swarm_ylim is None:
            swarm_ylim = rawdata_axes.get_ylim()

        _, contrast_xlim_max = contrast_axes.get_xlim()

        difference = float(results.difference[0])

        if effect_size_type in ["mean_diff", "median_diff"]:
            # Align 0 of contrast_axes to reference group mean of rawdata_axes.
            # If the effect size is positive, shift the contrast axis up.
            rawdata_ylims = np.array(rawdata_axes.get_ylim())
            if current_effsize > 0:
                rightmin, rightmax = rawdata_ylims - current_effsize
            # If the effect size is negative, shift the contrast axis down.
            elif current_effsize < 0:
                rightmin, rightmax = rawdata_ylims + current_effsize
            else:
                rightmin, rightmax = rawdata_ylims

            contrast_axes.set_ylim(rightmin, rightmax)

            og_ylim_contrast = rawdata_axes.get_ylim() - np.array(control_group_summary)

            contrast_axes.set_ylim(og_ylim_contrast)
            contrast_axes.set_xlim(contrast_xlim_max - 1, contrast_xlim_max)

        elif effect_size_type in ["cohens_d", "hedges_g", "cohens_h"]:
            if is_paired:
                which_std = 1
            else:
                which_std = 0
            temp_control = plot_data[plot_data[xvar] == current_control][yvar]
            temp_test = plot_data[plot_data[xvar] == current_group][yvar]

            stds = _compute_standardizers(temp_control, temp_test)
            if is_paired:
                pooled_sd = stds[1]
            else:
                pooled_sd = stds[0]

            if effect_size_type == "hedges_g":
                gby_count = plot_data.groupby(xvar).count()
                len_control = gby_count.loc[current_control, yvar]
                len_test = gby_count.loc[current_group, yvar]

                hg_correction_factor = _compute_hedges_correction_factor(
                    len_control, len_test
                )

                ylim_scale_factor = pooled_sd / hg_correction_factor

            elif effect_size_type == "cohens_h":
                ylim_scale_factor = (
                    np.mean(temp_test) - np.mean(temp_control)
                ) / difference

            else:
                ylim_scale_factor = pooled_sd

            scaled_ylim = (
                (rawdata_axes.get_ylim() - control_group_summary) / ylim_scale_factor
            ).tolist()

            contrast_axes.set_ylim(scaled_ylim)
            og_ylim_contrast = scaled_ylim

            contrast_axes.set_xlim(contrast_xlim_max - 1, contrast_xlim_max)

        if one_sankey is None:
            # Draw summary lines for control and test groups..
            for jj, axx in enumerate([rawdata_axes, contrast_axes]):
                # Draw effect size line.
                if jj == 0:
                    ref = control_group_summary
                    diff = test_group_summary
                    effsize_line_start = 1

                elif jj == 1:
                    ref = 0
                    diff = ref + difference
                    effsize_line_start = contrast_xlim_max - 1.1

                xlimlow, xlimhigh = axx.get_xlim()

                # Draw reference line.
                axx.hlines(
                    ref,  # y-coordinates
                    0,
                    xlimhigh,  # x-coordinates, start and end.
                    **reflines_kwargs
                )

                # Draw effect size line.
                axx.hlines(diff, effsize_line_start, xlimhigh, **reflines_kwargs)
        else:
            ref = 0
            diff = ref + difference
            effsize_line_start = contrast_xlim_max - 0.9
            xlimlow, xlimhigh = contrast_axes.get_xlim()
            # Draw reference line.
            contrast_axes.hlines(
                ref,  # y-coordinates
                effsize_line_start,
                xlimhigh,  # x-coordinates, start and end.
                **reflines_kwargs
            )

            # Draw effect size line.
            contrast_axes.hlines(diff, effsize_line_start, xlimhigh, **reflines_kwargs)
        rawdata_axes.set_xlim(og_xlim_raw)  # to align the axis
        # Despine appropriately.
        sns.despine(ax=rawdata_axes, bottom=True)
        sns.despine(ax=contrast_axes, left=True, right=False)

        # Insert break between the rawdata axes and the contrast axes
        # by re-drawing the x-spine.
        rawdata_axes.hlines(
            og_ylim_raw[0],  # yindex
            rawdata_axes.get_xlim()[0],
            1.3,  # xmin, xmax
            **redraw_axes_kwargs
        )
        rawdata_axes.set_ylim(og_ylim_raw)

        contrast_axes.hlines(
            contrast_axes.get_ylim()[0],
            contrast_xlim_max - 0.8,
            contrast_xlim_max,
            **redraw_axes_kwargs
        )

    else:
        # For Cumming Plots only.

        # Set custom contrast_ylim, if it was specified.
        if plot_kwargs["contrast_ylim"] is not None or (
            plot_kwargs["delta2_ylim"] is not None and show_delta2
        ):
            if plot_kwargs["contrast_ylim"] is not None:
                custom_contrast_ylim = plot_kwargs["contrast_ylim"]
                if plot_kwargs["delta2_ylim"] is not None and show_delta2:
                    custom_delta2_ylim = plot_kwargs["delta2_ylim"]
                    if custom_contrast_ylim != custom_delta2_ylim:
                        err1 = "Please check if `contrast_ylim` and `delta2_ylim` are assigned"
                        err2 = "with same values."
                        raise ValueError(err1 + err2)
            else:
                custom_delta2_ylim = plot_kwargs["delta2_ylim"]
                custom_contrast_ylim = custom_delta2_ylim

            if len(custom_contrast_ylim) != 2:
                err1 = "Please check `contrast_ylim` consists of "
                err2 = "exactly two numbers."
                raise ValueError(err1 + err2)

            if effect_size_type == "cliffs_delta":
                # Ensure the ylims for a cliffs_delta plot never exceed [-1, 1].
                l = plot_kwargs["contrast_ylim"][0]
                h = plot_kwargs["contrast_ylim"][1]
                low = -1 if l < -1 else l
                high = 1 if h > 1 else h
                contrast_axes.set_ylim(low, high)
            else:
                contrast_axes.set_ylim(custom_contrast_ylim)

        # If 0 lies within the ylim of the contrast axes,
        # draw a zero reference line.
        contrast_axes_ylim = contrast_axes.get_ylim()
        if contrast_axes_ylim[0] < contrast_axes_ylim[1]:
            contrast_ylim_low, contrast_ylim_high = contrast_axes_ylim
        else:
            contrast_ylim_high, contrast_ylim_low = contrast_axes_ylim
        if contrast_ylim_low < 0 < contrast_ylim_high:
            contrast_axes.axhline(y=0, **reflines_kwargs)

        if is_paired == "baseline" and show_pairs:
            if two_col_sankey:
                rightend_ticks_raw = np.array([len(i) - 2 for i in idx]) + np.array(
                    ticks_to_start_twocol_sankey
                )
            elif proportional and is_paired is not None:
                rightend_ticks_raw = np.array([len(i) - 1 for i in idx]) + np.array(
                    ticks_to_skip
                )
            else:
                rightend_ticks_raw = np.array(
                    [len(i) - 1 for i in temp_idx]
                ) + np.array(ticks_to_skip)
            for ax in [rawdata_axes]:
                sns.despine(ax=ax, bottom=True)

                ylim = ax.get_ylim()
                xlim = ax.get_xlim()
                redraw_axes_kwargs["y"] = ylim[0]

                if two_col_sankey:
                    for k, start_tick in enumerate(ticks_to_start_twocol_sankey):
                        end_tick = rightend_ticks_raw[k]
                        ax.hlines(xmin=start_tick, xmax=end_tick, **redraw_axes_kwargs)
                else:
                    for k, start_tick in enumerate(ticks_to_skip):
                        end_tick = rightend_ticks_raw[k]
                        ax.hlines(xmin=start_tick, xmax=end_tick, **redraw_axes_kwargs)
                ax.set_ylim(ylim)
                del redraw_axes_kwargs["y"]

            if not proportional:
                temp_length = [(len(i) - 1) for i in idx]
            else:
                temp_length = [(len(i) - 1) * 2 - 1 for i in idx]
            if two_col_sankey:
                rightend_ticks_contrast = np.array(
                    [len(i) - 2 for i in idx]
                ) + np.array(ticks_to_start_twocol_sankey)
            elif proportional and is_paired is not None:
                rightend_ticks_contrast = np.array(
                    [len(i) - 1 for i in idx]
                ) + np.array(ticks_to_skip)
            else:
                rightend_ticks_contrast = np.array(temp_length) + np.array(
                    ticks_to_skip_contrast
                )
            for ax in [contrast_axes]:
                sns.despine(ax=ax, bottom=True)

                ylim = ax.get_ylim()
                xlim = ax.get_xlim()
                redraw_axes_kwargs["y"] = ylim[0]

                if two_col_sankey:
                    for k, start_tick in enumerate(ticks_to_start_twocol_sankey):
                        end_tick = rightend_ticks_contrast[k]
                        ax.hlines(xmin=start_tick, xmax=end_tick, **redraw_axes_kwargs)
                else:
                    for k, start_tick in enumerate(ticks_to_skip_contrast):
                        end_tick = rightend_ticks_contrast[k]
                        ax.hlines(xmin=start_tick, xmax=end_tick, **redraw_axes_kwargs)

                ax.set_ylim(ylim)
                del redraw_axes_kwargs["y"]
        else:
            # Compute the end of each x-axes line.
            if two_col_sankey:
                rightend_ticks = np.array([len(i) - 2 for i in idx]) + np.array(
                    ticks_to_start_twocol_sankey
                )
            else:
                rightend_ticks = np.array([len(i) - 1 for i in idx]) + np.array(
                    ticks_to_skip
                )

            for ax in [rawdata_axes, contrast_axes]:
                sns.despine(ax=ax, bottom=True)

                ylim = ax.get_ylim()
                xlim = ax.get_xlim()
                redraw_axes_kwargs["y"] = ylim[0]

                if two_col_sankey:
                    for k, start_tick in enumerate(ticks_to_start_twocol_sankey):
                        end_tick = rightend_ticks[k]
                        ax.hlines(xmin=start_tick, xmax=end_tick, **redraw_axes_kwargs)
                else:
                    for k, start_tick in enumerate(ticks_to_skip):
                        end_tick = rightend_ticks[k]
                        ax.hlines(xmin=start_tick, xmax=end_tick, **redraw_axes_kwargs)

                ax.set_ylim(ylim)
                del redraw_axes_kwargs["y"]

    if show_delta2 or show_mini_meta:
        ylim = contrast_axes.get_ylim()
        redraw_axes_kwargs["y"] = ylim[0]
        x_ticks = contrast_axes.get_xticks()
        contrast_axes.hlines(xmin=x_ticks[-2], xmax=x_ticks[-1], **redraw_axes_kwargs)
        del redraw_axes_kwargs["y"]

    # Set raw axes y-label.
    swarm_label = plot_kwargs["swarm_label"]
    if swarm_label is None and yvar is None:
        swarm_label = "value"
    elif swarm_label is None and yvar is not None:
        swarm_label = yvar

    bar_label = plot_kwargs["bar_label"]
    if bar_label is None and effect_size_type != "cohens_h":
        bar_label = "proportion of success"
    elif bar_label is None and effect_size_type == "cohens_h":
        bar_label = "value"

    # Place contrast axes y-label.
    contrast_label_dict = {
        "mean_diff": "mean difference",
        "median_diff": "median difference",
        "cohens_d": "Cohen's d",
        "hedges_g": "Hedges' g",
        "cliffs_delta": "Cliff's delta",
        "cohens_h": "Cohen's h",
        "delta_g": "mean difference",
    }

    if proportional and effect_size_type != "cohens_h":
        default_contrast_label = "proportion difference"
    elif effect_size_type == "delta_g":
        default_contrast_label = "Hedges' g"
    else:
        default_contrast_label = contrast_label_dict[effectsize_df.effect_size]

    if plot_kwargs["contrast_label"] is None:
        if is_paired:
            contrast_label = "paired\n{}".format(default_contrast_label)
        else:
            contrast_label = default_contrast_label
        contrast_label = contrast_label.capitalize()
    else:
        contrast_label = plot_kwargs["contrast_label"]

    if plot_kwargs["fontsize_rawylabel"] is not None:
        fontsize_rawylabel = plot_kwargs["fontsize_rawylabel"]
    if plot_kwargs["fontsize_contrastylabel"] is not None:
        fontsize_contrastylabel = plot_kwargs["fontsize_contrastylabel"]
    if plot_kwargs["fontsize_delta2label"] is not None:
        fontsize_delta2label = plot_kwargs["fontsize_delta2label"]

    contrast_axes.set_ylabel(contrast_label, fontsize=fontsize_contrastylabel)
    if float_contrast:
        contrast_axes.yaxis.set_label_position("right")

    # Set the rawdata axes labels appropriately
    if not proportional:
        rawdata_axes.set_ylabel(swarm_label, fontsize=fontsize_rawylabel)
    else:
        rawdata_axes.set_ylabel(bar_label, fontsize=fontsize_rawylabel)
    rawdata_axes.set_xlabel("")

    # Because we turned the axes frame off, we also need to draw back
    # the y-spine for both axes.
    if not float_contrast:
        rawdata_axes.set_xlim(contrast_axes.get_xlim())
    og_xlim_raw = rawdata_axes.get_xlim()
    rawdata_axes.vlines(
        og_xlim_raw[0], og_ylim_raw[0], og_ylim_raw[1], **redraw_axes_kwargs
    )

    og_xlim_contrast = contrast_axes.get_xlim()

    if float_contrast:
        xpos = og_xlim_contrast[1]
    else:
        xpos = og_xlim_contrast[0]

    og_ylim_contrast = contrast_axes.get_ylim()
    contrast_axes.vlines(
        xpos, og_ylim_contrast[0], og_ylim_contrast[1], **redraw_axes_kwargs
    )

    if show_delta2:
        if plot_kwargs["delta2_label"] is not None:
            delta2_label = plot_kwargs["delta2_label"]
        elif effect_size == "mean_diff":
            delta2_label = "delta - delta"
        else:
            delta2_label = "deltas' g"
        delta2_axes = contrast_axes.twinx()
        delta2_axes.set_frame_on(False)
        delta2_axes.set_ylabel(delta2_label, fontsize=fontsize_delta2label)
        og_xlim_delta = contrast_axes.get_xlim()
        og_ylim_delta = contrast_axes.get_ylim()
        delta2_axes.set_ylim(og_ylim_delta)
        delta2_axes.vlines(
            og_xlim_delta[1], og_ylim_delta[0], og_ylim_delta[1], **redraw_axes_kwargs
        )

    ################################################### GRIDKEY MAIN CODE WIP

    # if gridkey_rows is None, skip everything here
    if gridkey_rows is not None:
        # Raise error if there are more than 2 items in any idx and gridkey_merge_pairs is True and is_paired is not None
        if gridkey_merge_pairs and is_paired is not None:
            for i in idx:
                if len(i) > 2:
                    warnings.warn(
                        "gridkey_merge_pairs=True only works if all idx in tuples have only two items. gridkey_merge_pairs has automatically been set to False"
                    )
                    gridkey_merge_pairs = False
                    break
        elif gridkey_merge_pairs and is_paired is None:
            warnings.warn(
                "gridkey_merge_pairs=True is only applicable for paired data."
            )
            gridkey_merge_pairs = False

        # Checks for gridkey_merge_pairs and is_paired; if both are true, "merges" the gridkey per pair
        if gridkey_merge_pairs and is_paired is not None:
            groups_for_gridkey = []
            for i in idx:
                groups_for_gridkey.append(i[1])
        else:
            groups_for_gridkey = all_plot_groups

        # raise errors if gridkey_rows is not a list, or if the list is empty
        if isinstance(gridkey_rows, list) is False:
            raise TypeError("gridkey_rows must be a list.")
        elif len(gridkey_rows) == 0:
            warnings.warn("gridkey_rows is an empty list.")

        # raise Warning if an item in gridkey_rows is not contained in any idx
        for i in gridkey_rows:
            in_idx = 0
            for j in groups_for_gridkey:
                if i in j:
                    in_idx += 1
            if in_idx == 0:
                if is_paired is not None:
                    warnings.warn(
                        i
                        + " is not in any idx. Please check. Alternatively, merging gridkey pairs may not be suitable for your data; try passing gridkey_merge_pairs=False."
                    )
                else:
                    warnings.warn(i + " is not in any idx. Please check.")

        # Populate table: checks if idx for each column contains rowlabel name
        # IF so, marks that element as present w black dot, or space if not present
        table_cellcols = []
        for i in gridkey_rows:
            thisrow = []
            for q in groups_for_gridkey:
                if str(i) in q:
                    thisrow.append("\u25CF")
                else:
                    thisrow.append("")
            table_cellcols.append(thisrow)

        # Adds a row for Ns with the Ns values
        if gridkey_show_Ns:
            gridkey_rows.append("Ns")
            list_of_Ns = []
            for i in groups_for_gridkey:
                list_of_Ns.append(str(counts.loc[i]))
            table_cellcols.append(list_of_Ns)

        # Adds a row for effectsizes with effectsize values
        if gridkey_show_es:
            gridkey_rows.append("\u0394")
            effsize_list = []
            results_list = results.test.to_list()

            # get the effect size, append + or -, 2 dec places
            for i in enumerate(groups_for_gridkey):
                if i[1] in results_list:
                    curr_esval = results.loc[results["test"] == i[1]][
                        "difference"
                    ].iloc[0]
                    curr_esval_str = np.format_float_positional(
                        curr_esval,
                        precision=es_sf,
                        sign=True,
                        trim="k",
                        min_digits=es_sf,
                    )
                    effsize_list.append(curr_esval_str)
                else:
                    effsize_list.append("-")

            table_cellcols.append(effsize_list)

        # If Gardner-Altman plot, plot on raw data and not contrast axes
        if float_contrast:
            axes_ploton = rawdata_axes
        else:
            axes_ploton = contrast_axes

        # Account for extended x axis in case of show_delta2 or show_mini_meta
        x_groups_for_width = len(groups_for_gridkey)
        if show_delta2 or show_mini_meta:
            x_groups_for_width += 2
        gridkey_width = len(groups_for_gridkey) / x_groups_for_width

        gridkey = axes_ploton.table(
            cellText=table_cellcols,
            rowLabels=gridkey_rows,
            cellLoc="center",
            bbox=[
                0,
                -len(gridkey_rows) * 0.1 - 0.05,
                gridkey_width,
                len(gridkey_rows) * 0.1,
            ],
            **{"alpha": 0.5}
        )

        # modifies row label cells
        for cell in gridkey._cells:
            if cell[1] == -1:
                gridkey._cells[cell].visible_edges = "open"
                gridkey._cells[cell].set_text_props(**{"ha": "right"})

        # turns off both x axes
        rawdata_axes.get_xaxis().set_visible(False)
        contrast_axes.get_xaxis().set_visible(False)

    ####################################################### END GRIDKEY MAIN CODE WIP

    # Make sure no stray ticks appear!
    rawdata_axes.xaxis.set_ticks_position("bottom")
    rawdata_axes.yaxis.set_ticks_position("left")
    contrast_axes.xaxis.set_ticks_position("bottom")
    if float_contrast is False:
        contrast_axes.yaxis.set_ticks_position("left")

    # Reset rcParams.
    for parameter in _changed_rcParams:
        plt.rcParams[parameter] = original_rcParams[parameter]

    # Return the figure.
    return fig

