def matrixplot(adata, var_names, groupby=None, use_raw=None, log=False, num_categories=7,
               figsize=None, dendrogram=False, gene_symbols=None, var_group_positions=None, var_group_labels=None,
               var_group_rotation=None, layer=None, standard_scale=None, swap_axes=False, show=None,
               save=None, **kwds):

    """\
    Creates a heatmap of the mean expression values per cluster of each var_names
    If groupby is not given, the matrixplot assumes that all data belongs to a single
    category.

    Parameters
    ----------
    {common_plot_args}
    standard_scale : {{'var', 'group'}}, optional (default: None)
        Whether or not to standardize that dimension between 0 and 1, meaning for each variable or group,
        subtract the minimum and divide each by its maximum.
    {show_save_ax}
    **kwds : keyword arguments
        Are passed to `matplotlib.pyplot.pcolor`.

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

    Examples
    --------
    >>> adata = sc.datasets.pbmc68k_reduced()
    >>> sc.pl.matrixplot(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
    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 groupby is None or len(categories) <= 1:
        # dendrogram can only be computed  between groupby categories
        dendrogram = False

    mean_obs = obs_tidy.groupby(level=0).mean()

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

    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 matrix
        if dendro_data['var_names_idx_ordered'] is not None:
            # reorder columns (usually genes) if needed. This only happens when
            # var_group_positions and var_group_labels is set
            mean_obs = mean_obs.iloc[:,dendro_data['var_names_idx_ordered']]

        # reorder rows (categories) to match the dendrogram order
        mean_obs = mean_obs.iloc[dendro_data['categories_idx_ordered'], :]

    colorbar_width = 0.2

    if not swap_axes:
        dendro_width = 0.8 if dendrogram else 0
        if figsize is None:
            height = len(categories) * 0.2 + 1  # +1 for labels
            heatmap_width = len(var_names) * 0.32
            width = heatmap_width + dendro_width + colorbar_width  # +1.6 to account for the colorbar and  + 1 to account for labels
        else:
            width, height = figsize
            heatmap_width = width - (dendro_width + colorbar_width)

        if var_group_positions is not None and len(var_group_positions) > 0:
            # add some space in case 'brackets' want to be plotted on top of the image
            height_ratios = [0.5, 10]
            height += 0.5
        else:
            height_ratios = [0, 10.5]

        # define a layout of 2 rows x 3 columns
        # first row is for 'brackets' (if no brackets needed, the height of this row is zero)
        # second row is for main content. This second row
        # is divided into three axes:
        #   first ax is for the main matrix figure
        #   second ax is for the dendrogram
        #   third ax is for the color bar legend
        fig = pl.figure(figsize=(width, height))
        axs = gridspec.GridSpec(nrows=2, ncols=3, wspace=0.02, hspace=0.04,
                                width_ratios=[heatmap_width, dendro_width, colorbar_width],
                                height_ratios=height_ratios)

        matrix_ax = fig.add_subplot(axs[1, 0])
        y_ticks = np.arange(mean_obs.shape[0]) + 0.5
        matrix_ax.set_yticks(y_ticks)
        matrix_ax.set_yticklabels([mean_obs.index[idx] for idx in range(mean_obs.shape[0])])

        if dendrogram:
            dendro_ax = fig.add_subplot(axs[1, 1], sharey=matrix_ax)
            _plot_dendrogram(dendro_ax, adata, groupby, dendrogram_key=dendrogram, ticks=y_ticks)

        pc = matrix_ax.pcolor(mean_obs, edgecolor='gray', **kwds)

        # invert y axis to show categories ordered from top to bottom
        matrix_ax.set_ylim(mean_obs.shape[0], 0)

        x_ticks = np.arange(mean_obs.shape[1]) + 0.5
        matrix_ax.set_xticks(x_ticks)
        matrix_ax.set_xticklabels([mean_obs.columns[idx] for idx in range(mean_obs.shape[1])], rotation=90)
        matrix_ax.tick_params(axis='both', labelsize='small')
        matrix_ax.grid(False)
        matrix_ax.set_xlim(-0.5, len(var_names) + 0.5)
        matrix_ax.set_ylabel(groupby)
        matrix_ax.set_xlim(0, mean_obs.shape[1])

        # plot group legends on top of matrix_ax (if given)
        if var_group_positions is not None and len(var_group_positions) > 0:
            gene_groups_ax = fig.add_subplot(axs[0, 0], sharex=matrix_ax)
            _plot_gene_groups_brackets(gene_groups_ax, group_positions=var_group_positions,
                                       group_labels=var_group_labels, rotation=var_group_rotation,
                                       left_adjustment=0.2, right_adjustment=0.8)

        # plot colorbar
        _plot_colorbar(pc, fig, axs[1, 2])
    else:
        dendro_height = 0.5 if dendrogram else 0
        if var_group_positions is not None and len(var_group_positions) > 0:
            # add some space in case 'color blocks' want to be plotted on the right of the image
            vargroups_width = 0.4
        else:
            vargroups_width = 0

        if figsize is None:
            heatmap_height = len(var_names) * 0.2
            height = dendro_height + heatmap_height + 1  # +1 for labels
            heatmap_width = len(categories) * 0.3
            width = heatmap_width + vargroups_width + colorbar_width
        else:
            width, height = figsize
            heatmap_width = width - (vargroups_width + colorbar_width)
            heatmap_height = height - dendro_height

        # define a layout of 2 rows x 3 columns
        # first row is for 'dendrogram' (if no dendrogram is plotted, the height of this row is zero)
        # second row is for main content. This row
        # is divided into three axes:
        #   first ax is for the main matrix figure
        #   second ax is for the groupby categories (eg. brackets)
        #   third ax is for the color bar legend
        fig = pl.figure(figsize=(width, height))
        axs = gridspec.GridSpec(nrows=2, ncols=3, wspace=0.05, hspace=0.005,
                                width_ratios=[heatmap_width, vargroups_width, colorbar_width],
                                height_ratios=[dendro_height, heatmap_height])

        mean_obs = mean_obs.T
        matrix_ax = fig.add_subplot(axs[1, 0])
        pc = matrix_ax.pcolor(mean_obs, edgecolor='gray', **kwds)
        y_ticks = np.arange(mean_obs.shape[0]) + 0.5
        matrix_ax.set_yticks(y_ticks)
        matrix_ax.set_yticklabels([mean_obs.index[idx] for idx in range(mean_obs.shape[0])])

        x_ticks = np.arange(mean_obs.shape[1]) + 0.5
        matrix_ax.set_xticks(x_ticks)
        matrix_ax.set_xticklabels([mean_obs.columns[idx] for idx in range(mean_obs.shape[1])], rotation=90)
        matrix_ax.tick_params(axis='both', labelsize='small')
        matrix_ax.grid(False)
        matrix_ax.set_xlim(0, len(categories))
        matrix_ax.set_xlabel(groupby)
        # invert y axis to show var_names ordered from top to bottom
        matrix_ax.set_ylim(mean_obs.shape[0], 0)

        if dendrogram:
            dendro_ax = fig.add_subplot(axs[0, 0], sharex=matrix_ax)
            _plot_dendrogram(dendro_ax, adata, groupby, dendrogram_key=dendrogram, ticks=x_ticks, orientation='top')

        # plot group legends on top of matrix_ax (if given)
        if var_group_positions is not None and len(var_group_positions) > 0:
            gene_groups_ax = fig.add_subplot(axs[1, 1], sharey=matrix_ax)
            _plot_gene_groups_brackets(gene_groups_ax, group_positions=var_group_positions,
                                       group_labels=var_group_labels, rotation=var_group_rotation,
                                       left_adjustment=0.2, right_adjustment=0.8, orientation='right')

        # plot colorbar
        _plot_colorbar(pc, fig, axs[1, 2])

    utils.savefig_or_show('matrixplot', show=show, save=save)
    return axs
\
    Creates a heatmap of the mean expression values per cluster of each var_names
    If groupby is not given, the matrixplot assumes that all data belongs to a single
    category.

    Parameters
    ----------
    {common_plot_args}
    standard_scale : {{'var', 'group'}}, optional (default: None)
        Whether or not to standardize that dimension between 0 and 1, meaning for each variable or group,
        subtract the minimum and divide each by its maximum.
    {show_save_ax}
    **kwds : keyword arguments
        Are passed to `matplotlib.pyplot.pcolor`.

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

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