docs: def correlation(df, cm=cm.PuOr_r, vmin=None, vmax=None, labels=None, show_scatter=False):
      """
      Generate a column-wise correlation plot from the provided data.
  
      The columns of the supplied dataframes will be correlated (using `analysis.correlation`) to
      generate a Pearson correlation plot heatmap. Scatter plots of correlated samples can also be generated over
      the redundant half of the plot to give a visual indication of the protein distribution.
  
      :param df: `pandas.DataFrame`
      :param cm: Matplotlib colormap (default cm.PuOr_r)
      :param vmin: Minimum value for colormap normalization
      :param vmax: Maximum value for colormap normalization
      :param labels: Index column to retrieve labels from
      :param show_scatter: Show overlaid scatter plots for each sample in lower-left half. Note that this is slow for large numbers of samples.
      :return: `matplotlib.Figure` generated Figure.
      """
  
  
      data = analysis.correlation(df)
  
      if labels:
          for axis in (0,1):
              data.sort_index(level=labels, axis=axis, inplace=True)
  
      data = data.values
  
      # Plot the distributions
      fig = plt.figure(figsize=(10,10))
      ax = fig.add_subplot(1,1,1)
  
      if vmin is None:
          vmin = np.nanmin(data)
  
      if vmax is None:
          vmax = np.nanmax(data)
  
      n_dims = data.shape[0]
  
      # If showing scatter plots, set the inlay portion to np.nan
      if show_scatter:
          # Get the triangle, other values will be zeroed
          idx = np.tril_indices(n_dims)
          data[idx] = np.nan
  
      cm.set_bad('w', 1.)
      i = ax.imshow(data, cmap=cm, vmin=vmin, vmax=vmax, interpolation='none')
      fig.colorbar(i)
      fig.axes[0].grid('off')
  
      if show_scatter:
          figo = mpl.figure.Figure(figsize=(n_dims, n_dims), dpi=300)
          # Create a dummy Agg canvas so we don't have to display/output this intermediate
          canvas = FigureCanvasAgg(figo)
  
          for x in range(0, n_dims):
              for y in range(x, n_dims):
  
                  ax = figo.add_subplot(n_dims, n_dims, y*n_dims+x+1)
  
                  if x != y:
                      xd = df.values[:, x]
                      yd = df.values[:, y]
                      ax.scatter(xd, yd, lw=0, s=5, c='k', alpha=0.2)
  
                  ax.grid('off')
                  ax.axis('off')
  
  
          figo.subplots_adjust(left=0, bottom=0, right=1, top=1, wspace=0, hspace=0)
          raw = BytesIO()
          figo.savefig(raw, format='png', bbox_inches=0, transparent=True)
          del figo
  
          raw.seek(0)
          img = mplimg.imread(raw)
          ax2 = fig.add_axes(fig.axes[0].get_position(), label='image', zorder=1)
          ax2.axis('off')
          ax2.imshow(img)
  
      if labels:
          # Build labels from the supplied axis
          labels = [
              df.columns.get_level_values(l)
              for l in labels
          ]
          labels = [" ".join([str(s) for s in l]) for l in zip(*labels) ]
  
          fig.axes[0].set_xticks(range(n_dims))
          fig.axes[0].set_xticklabels(labels, rotation=45)
  
          fig.axes[0].set_yticks(range(n_dims))
          fig.axes[0].set_yticklabels(labels)
  
      return fig