def stacked_violin(adata, var_names, groupby=None, log=False, use_raw=None, num_categories=7,
                   figsize=None,  dendrogram=False, gene_symbols=None,
                   var_group_positions=None, var_group_labels=None, standard_scale=None,
                   var_group_rotation=None, layer=None, stripplot=False, jitter=False, size=1,
                   scale='width', order=None, swap_axes=False, show=None, save=None,
                   row_palette='muted', **kwds):
    """\
    Stacked violin plots.

    Makes a compact image composed of individual violin plots (from `seaborn.violinplot`)
    stacked on top of each other. Useful to visualize gene expression per cluster.

    Wraps `seaborn.violinplot` for :class:`~anndata.AnnData`.

    Parameters
    ----------
    {common_plot_args}
    stripplot : `bool` optional (default: `True`)
        Add a stripplot on top of the violin plot.
        See `seaborn.stripplot`.
    jitter : `float` or `bool`, optional (default: `True`)
        Add jitter to the stripplot (only when stripplot is True)
        See `seaborn.stripplot`.
    size : int, optional (default: 1)
        Size of the jitter points.
    order : list of str, optional (default: `True`)
        Order in which to show the categories.
    scale : {{'area', 'count', 'width'}}, optional (default: 'width')
        The method used to scale the width of each violin. If 'area', each
        violin will have the same area. If 'count', the width of the violins
        will be scaled by the number of observations in that bin. If 'width',
        each violin will have the same width.
    row_palette: `str` (default: `muted`)
        The row palette determines the colors to use in each of the stacked violin plots. The value
        should be a valid seaborn palette name or a valic matplotlib colormap
        (see https://seaborn.pydata.org/generated/seaborn.color_palette.html). Alternatively,
        a single color name or hex value can be passed. E.g. 'red' or '#cc33ff'
    standard_scale : {{'var', 'obs'}}, optional (default: None)
        Whether or not to standardize that dimension between 0 and 1, meaning for each variable or observation,
        subtract the minimum and divide each by its maximum.
    swap_axes: `bool`, optional (default: `False`)
         By default, the x axis contains `var_names` (e.g. genes) and the y axis the `groupby` categories.
         By setting `swap_axes` then x are the `groupby` categories and y the `var_names`. When swapping
         axes var_group_positions are no longer used
    {show_save_ax}
    **kwds : keyword arguments
        Are passed to `seaborn.violinplot`.

    Returns
    -------
    List of :class:`~matplotlib.axes.Axes`

    Examples
    -------
    >>> adata = sc.datasets.pbmc68k_reduced()
    >>> sc.pl.stacked_violin(adata, ['C1QA', 'PSAP', 'CD79A', 'CD79B', 'CST3', 'LYZ'],
    ...                      groupby='bulk_labels', dendrogram=True)

    """
    if use_raw is None and adata.raw is not None: use_raw = True
    has_var_groups = True if var_group_positions is not None and len(var_group_positions) > 0 else False
    if isinstance(var_names, str):
        var_names = [var_names]
    categories, obs_tidy = _prepare_dataframe(adata, var_names, groupby, use_raw, log, num_categories,
                                              gene_symbols=gene_symbols, layer=layer)

    if standard_scale == 'obs':
        obs_tidy = obs_tidy.sub(obs_tidy.min(1), axis=0)
        obs_tidy = obs_tidy.div(obs_tidy.max(1), axis=0).fillna(0)
    elif standard_scale == 'var':
        obs_tidy -= obs_tidy.min(0)
        obs_tidy = (obs_tidy / obs_tidy.max(0)).fillna(0)
    elif standard_scale is None:
        pass
    else:
        logg.warn('Unknown type for standard_scale, ignored')


    if 'color' in kwds:
        row_palette = kwds['color']
        # remove color from kwds in case is set to avoid an error caused by
        # double parameters
        del (kwds['color'])
    if 'linewidth' not in kwds:
        # for the tiny violin plots used, is best
        # to use a thin lindwidth.
        kwds['linewidth'] = 0.5
    if groupby is None or len(categories) <= 1:
        # dendrogram can only be computed  between groupby categories
        dendrogram = False

    if dendrogram:
        dendro_data = _reorder_categories_after_dendrogram(adata, groupby, dendrogram,
                                                           var_names=var_names,
                                                           var_group_labels=var_group_labels,
                                                           var_group_positions=var_group_positions)

        var_group_labels = dendro_data['var_group_labels']
        var_group_positions = dendro_data['var_group_positions']

        # reorder obs_tidy
        if dendro_data['var_names_idx_ordered'] is not None:
            obs_tidy = obs_tidy.iloc[:, dendro_data['var_names_idx_ordered']]
            var_names = [var_names[x] for x in dendro_data['var_names_idx_ordered']]

        obs_tidy.index = obs_tidy.index.reorder_categories(
            [categories[x] for x in dendro_data['categories_idx_ordered']], ordered=True)
        categories = [categories[x] for x in dendro_data['categories_idx_ordered']]

    global count
    count = 0

    def rename_cols_to_int(value):
        global count
        count += 1
        return count

    # All columns should have a unique name, otherwise the
    # pd.melt object that is passed to seaborn will merge non-unique columns.
    # Here, I simply rename the columns using a count from 1..n using the
    # mapping function `rename_cols_to_int` to solve the problem.
    obs_tidy.rename(rename_cols_to_int, axis='columns', inplace=True)

    if not swap_axes:
        # plot image in which x = var_names and y = groupby categories

        dendro_width = 1.4 if dendrogram else 0

        if figsize is None:
            height = len(categories) * 0.2 + 3
            width = len(var_names) * 0.2 + 1 + dendro_width
        else:
            width, height = figsize

        num_rows = len(categories)
        height_ratios = None
        if has_var_groups:
            # add some space in case 'brackets' want to be plotted on top of the image
            num_rows += 2  # +2 to add the row for the brackets and a spacer
            height_ratios = [0.2, 0.05] + [float(height) / len(categories)] * len(categories)
            categories = [None, None] + list(categories)
        fig = pl.figure(figsize=(width, height))

        # define a layout of nrows = len(categories) rows x 2 columns
        # each row is one violin plot. Second column is reserved for dendrogram (if any)
        # if var_group_positions is defined, a new row is added
        axs = gridspec.GridSpec(nrows=num_rows, ncols=2, height_ratios=height_ratios,
                                width_ratios=[width, dendro_width], wspace=0.08)
        axs_list = []
        if dendrogram:
            first_plot_idx = 1 if has_var_groups else 0
            dendro_ax = fig.add_subplot(axs[first_plot_idx:, 1])
            _plot_dendrogram(dendro_ax, adata, groupby, dendrogram_key=dendrogram)
            axs_list.append(dendro_ax)
        ax0 = None
        if is_color_like(row_palette):
            row_colors = [row_palette] * len(categories)
        else:
            row_colors = sns.color_palette(row_palette, n_colors=len(categories))
        for idx in range(num_rows)[::-1]:  # iterate in reverse to start on the bottom plot
                                           # this facilitates adding the brackets plot (if
                                           # needed) by sharing the x axis with a previous
                                           # violing plot.
            category = categories[idx]
            if has_var_groups and idx <= 1:
                # if var_group_positions is given, axs[0] and axs[1] are the location for the
                # brackets and a spacer (axs[1])
                if idx == 0:
                    brackets_ax = fig.add_subplot(axs[0], sharex=ax0)
                    _plot_gene_groups_brackets(brackets_ax, group_positions=var_group_positions,
                                               group_labels=var_group_labels,
                                               rotation=var_group_rotation)

                continue

            df = pd.melt(obs_tidy[obs_tidy.index == category], value_vars=obs_tidy.columns)
            if ax0 is None:
                ax = fig.add_subplot(axs[idx, 0])
                ax0 = ax

            else:
                ax = fig.add_subplot(axs[idx, 0])

            axs_list.append(ax)

            ax = sns.violinplot('variable', y='value', data=df, inner=None, order=order,
                                orient='vertical', scale=scale, ax=ax, color=row_colors[idx], **kwds)

            if stripplot:
                ax = sns.stripplot('variable', y='value', data=df, order=order,
                                   jitter=jitter, color='black', size=size, ax=ax)

            # remove the grids because in such a compact plot are unnecessary
            ax.grid(False)

            ax.tick_params(axis='y', left=False, right=True, labelright=True,
                           labelleft=False, labelsize='x-small', length=1, pad=1)

            ax.set_ylabel(category, rotation=0, fontsize='small', labelpad=8, ha='right', va='center')
            ax.set_xlabel('')
            if log:
                ax.set_yscale('log')

            if idx < num_rows - 1:
                # remove the xticks labels except for the last processed plot (first from bottom-up).
                # Because the plots share the x axis it is redundant and less compact to plot the
                # axis ticks and labels for each plot
                ax.set_xticklabels([])
                ax.tick_params(axis='x', bottom=False, top=False, labeltop=False, labelbottom=False)
            else:
                ax.set_xticklabels(var_names)

        ax0.tick_params(axis='x', labelrotation=90, labelsize='small')

    else:
        # plot image in which x = group by and y = var_names
        dendro_height = 3 if dendrogram else 0
        vargroups_width = 0.45 if has_var_groups else 0
        if figsize is None:
            height = len(var_names) * 0.3 + dendro_height
            width = len(categories) * 0.4 + vargroups_width
        else:
            width, height = figsize

        fig = pl.figure(figsize=(width, height))

        # define a layout of nrows = var_names x 1 columns
        # if plot dendrogram a row is added
        # each row is one violin plot.
        num_rows = len(var_names) + 1 # +1 to account for dendrogram
        height_ratios = [dendro_height] + ([1] * len(var_names))

        axs = gridspec.GridSpec(nrows=num_rows, ncols=2,
                                height_ratios=height_ratios, wspace=0.2,
                                width_ratios=[width - vargroups_width, vargroups_width])

        axs_list = []
        if dendrogram:
            dendro_ax = fig.add_subplot(axs[0])
            _plot_dendrogram(dendro_ax, adata, groupby, orientation='top', dendrogram_key=dendrogram)
            axs_list.append(dendro_ax)
        first_ax = None
        if is_color_like(row_palette):
            row_colors = [row_palette] * len(var_names)
        else:
            row_colors = sns.color_palette(row_palette, n_colors=len(var_names))
        for idx, y in enumerate(obs_tidy.columns):
            ax_idx = idx + 1  # +1 to account that idx 0 is the dendrogram
            if first_ax is None:
                ax = fig.add_subplot(axs[ax_idx, 0])
                first_ax = ax
            else:
                ax = fig.add_subplot(axs[ax_idx, 0])
            axs_list.append(ax)
            ax = sns.violinplot(x=obs_tidy.index, y=y, data=obs_tidy, inner=None, order=order,
                                orient='vertical', scale=scale, ax=ax, color=row_colors[idx], **kwds)
            if stripplot:
                ax = sns.stripplot(x=obs_tidy.index, y=y, data=obs_tidy, order=order,
                                   jitter=jitter, color='black', size=size, ax=ax)

            ax.set_ylabel(var_names[idx], rotation=0, fontsize='small', labelpad=8, ha='right', va='center')
            # remove the grids because in such a compact plot are unnecessary
            ax.grid(False)
            ax.tick_params(axis='y', right=True, labelright=True, left=False,
                           labelleft=False, labelrotation=0, labelsize='x-small')
            ax.tick_params(axis='x', labelsize='small')

            # remove the xticks labels except for the last processed plot (first from bottom-up).
            # Because the plots share the x axis it is redundant and less compact to plot the
            # axis for each plot
            if idx < len(var_names) - 1:
                ax.tick_params(labelbottom=False, labeltop=False, bottom=False, top=False)
                ax.set_xlabel('')
            if log:
                ax.set_yscale('log')

            if max([len(x) for x in categories]) > 1:
                ax.tick_params(axis='x', labelrotation=90)

        if has_var_groups:
            start = 1 if dendrogram else 0
            gene_groups_ax = fig.add_subplot(axs[start:, 1])
            arr = []
            for idx, pos in enumerate(var_group_positions):
                arr += [idx] * (pos[1]+1 - pos[0])
            _plot_gene_groups_brackets(gene_groups_ax, var_group_positions, var_group_labels,
                                       left_adjustment=0.3, right_adjustment=0.7, orientation='right')
            gene_groups_ax.set_ylim(len(var_names), 0)
            axs_list.append(gene_groups_ax)

    # remove the spacing between subplots
    pl.subplots_adjust(wspace=0, hspace=0)

    utils.savefig_or_show('stacked_violin', show=show, save=save)

    return axs_list
\
    Stacked violin plots.

    Makes a compact image composed of individual violin plots (from `seaborn.violinplot`)
    stacked on top of each other. Useful to visualize gene expression per cluster.

    Wraps `seaborn.violinplot` for :class:`~anndata.AnnData`.

    Parameters
    ----------
    {common_plot_args}
    stripplot : `bool` optional (default: `True`)
        Add a stripplot on top of the violin plot.
        See `seaborn.stripplot`.
    jitter : `float` or `bool`, optional (default: `True`)
        Add jitter to the stripplot (only when stripplot is True)
        See `seaborn.stripplot`.
    size : int, optional (default: 1)
        Size of the jitter points.
    order : list of str, optional (default: `True`)
        Order in which to show the categories.
    scale : {{'area', 'count', 'width'}}, optional (default: 'width')
        The method used to scale the width of each violin. If 'area', each
        violin will have the same area. If 'count', the width of the violins
        will be scaled by the number of observations in that bin. If 'width',
        each violin will have the same width.
    row_palette: `str` (default: `muted`)
        The row palette determines the colors to use in each of the stacked violin plots. The value
        should be a valid seaborn palette name or a valic matplotlib colormap
        (see https://seaborn.pydata.org/generated/seaborn.color_palette.html). Alternatively,
        a single color name or hex value can be passed. E.g. 'red' or '#cc33ff'
    standard_scale : {{'var', 'obs'}}, optional (default: None)
        Whether or not to standardize that dimension between 0 and 1, meaning for each variable or observation,
        subtract the minimum and divide each by its maximum.
    swap_axes: `bool`, optional (default: `False`)
         By default, the x axis contains `var_names` (e.g. genes) and the y axis the `groupby` categories.
         By setting `swap_axes` then x are the `groupby` categories and y the `var_names`. When swapping
         axes var_group_positions are no longer used
    {show_save_ax}
    **kwds : keyword arguments
        Are passed to `seaborn.violinplot`.

    Returns
    -------
    List of :class:`~matplotlib.axes.Axes`

    Examples
    -------
    >>> adata = sc.datasets.pbmc68k_reduced()
    >>> sc.pl.stacked_violin(adata, ['C1QA', 'PSAP', 'CD79A', 'CD79B', 'CST3', 'LYZ'],
    ...                      groupby='bulk_labels', dendrogram=True)