docs: def plot_pseudosection_type2(dataobj, column, **kwargs):
      """Create a pseudosection plot of type 2.
  
      For a given measurement data set, create plots that graphically show
      the data in a 2D color plot. Hereby, x and y coordinates in the plot
      are determined by the current dipole (x-axis) and voltage dipole
      (y-axis) of the corresponding measurement configurations.
  
      This type of rawdata plot can plot any type of measurement
      configurations, i.e., it is not restricted to certain types of
      configurations such as Dipole-dipole or Wenner configurations. However,
      spatial inferences cannot be made from the plots for all configuration
      types.
  
      Coordinates are generated by separately sorting the dipoles
      (current/voltage) along the first electrode, and then subsequently
      sorting by the difference (skip) between both electrodes.
  
      Note that this type of raw data plot does not take into account the
      real electrode spacing of the measurement setup.
  
      Type 2 plots can show normal and reciprocal data at the same time.
      Hereby the upper left triangle of the plot area usually contains normal
      data, and the lower right triangle contains the corresponding
      reciprocal data. Therefore a quick assessment of normal-reciprocal
      differences can be made by visually comparing the symmetry on the 1:1
      line going from the lower left corner to the upper right corner.
  
      Note that this interpretation usually only holds for Dipole-Dipole data
      (and the related Wenner configurations).
  
      Parameters
      ----------
  
      dataobj: ERT container|pandas.DataFrame
          Container or DataFrame with data to plot
      column: string
          Column key to plot
      ax: matplotlib.Axes object, optional
          axes object to plot to. If not provided, a new figure and axes
          object will be created and returned
      nocb: bool, optional
          if set to False, don't plot the colorbar
      cblabel: string, optional
          label for the colorbar
      cbmin: float, optional
          colorbar minimum
      cbmax: float, optional
          colorbar maximum
      xlabel: string, optional
          xlabel for the plot
      ylabel: string, optional
          ylabel for the plot
      do_not_saturate: bool, optional
          if set to True, then values outside the colorbar range will not
          saturate with the respective limit colors. Instead, values lower
          than the CB are colored "cyan" and vaues above the CB limit are
          colored "red"
      log10: bool, optional
          if set to True, plot the log10 values of the provided data
  
      Returns
      -------
      fig:
          figure object
      ax:
          axes object
      cb:
          colorbar object
  
      Examples
      --------
  
      You can just supply a pandas.DataFrame to the plot function:
  
      .. plot::
          :include-source:
  
          import numpy as np
          configs = np.array((
              (1, 2, 4, 3),
              (1, 2, 5, 4),
              (1, 2, 6, 5),
              (2, 3, 5, 4),
              (2, 3, 6, 5),
              (3, 4, 6, 5),
          ))
          measurements = np.random.random(configs.shape[0])
          import pandas as pd
          df = pd.DataFrame(configs, columns=['a', 'b', 'm', 'n'])
          df['measurements'] = measurements
  
          from reda.plotters.pseudoplots import plot_pseudosection_type2
          fig, ax, cb = plot_pseudosection_type2(
             dataobj=df,
             column='measurements',
          )
  
      You can also supply axes to plot to:
  
      .. plot::
          :include-source:
  
          import numpy as np
          configs = np.array((
              (1, 2, 4, 3),
              (1, 2, 5, 4),
              (1, 2, 6, 5),
              (2, 3, 5, 4),
              (2, 3, 6, 5),
              (3, 4, 6, 5),
          ))
          measurements = np.random.random(configs.shape[0])
          measurements2 = np.random.random(configs.shape[0])
  
          import pandas as pd
          df = pd.DataFrame(configs, columns=['a', 'b', 'm', 'n'])
          df['measurements'] = measurements
          df['measurements2'] = measurements2
  
          from reda.plotters.pseudoplots import plot_pseudosection_type2
  
          fig, axes = plt.subplots(1, 2)
  
          plot_pseudosection_type2(
              df,
              column='measurements',
              ax=axes[0],
              cblabel='this label',
              xlabel='xlabel',
              ylabel='ylabel',
          )
          plot_pseudosection_type2(
              df,
              column='measurements2',
              ax=axes[1],
              cblabel='measurement 2',
              xlabel='xlabel',
              ylabel='ylabel',
          )
          fig.tight_layout()
  
      >>> from reda.testing.containers import ERTContainer_nr
      >>> import reda.plotters.pseudoplots as ps
      >>> fig, axes, cb = ps.plot_pseudosection_type2(ERTContainer_nr, 'r')
  
      """
      if isinstance(dataobj, pd.DataFrame):
          df = dataobj
      else:
          df = dataobj.data
  
      c = df[['a', 'b', 'm', 'n']].values
  
      AB_ids = _get_unique_identifiers(c[:, 0:2])
      MN_ids = _get_unique_identifiers(c[:, 2:4])
  
      ab_sorted = np.sort(c[:, 0:2], axis=1)
      mn_sorted = np.sort(c[:, 2:4], axis=1)
  
      AB_coords = [
          AB_ids[x] for x in
          (ab_sorted[:, 0] * 1e5 + ab_sorted[:, 1]).astype(int)
      ]
      MN_coords = [
          MN_ids[x] for x in
          (mn_sorted[:, 0] * 1e5 + mn_sorted[:, 1]).astype(int)
      ]
  
      # check for duplicate positions
      ABMN_coords = np.vstack((AB_coords, MN_coords)).T.copy()
      _, counts = np.unique(
          ABMN_coords.view(
              ABMN_coords.dtype.descr * 2
          ),
          return_counts=True,
      )
      # import IPython
      # IPython.embed()
      # exit()
      if np.any(counts > 1):
          print('found duplicate coordinates!')
          # duplicate_configs = np.where(counts > 1)[0]
          # print('duplicate configs:')
          # print('A B M N')
          # for i in duplicate_configs:
          #     print(c[i, :])
  
      # prepare matrix
      plot_values = np.squeeze(df[column].values)
  
      if kwargs.get('log10', False):
          plot_values = np.log10(plot_values)
  
      C = np.zeros((len(MN_ids.items()), len(AB_ids))) * np.nan
      C[MN_coords, AB_coords] = plot_values
  
      # for display purposes, reverse the first dimension
      C = C[::-1, :]
  
      ax = kwargs.get('ax', None)
      if ax is None:
          fig, ax = plt.subplots(1, 1, figsize=(15 / 2.54, 10 / 2.54))
      fig = ax.get_figure()
  
      cmap = mpl.cm.get_cmap('viridis')
      if kwargs.get('do_not_saturate', False):
          cmap.set_over(
              color='r'
          )
          cmap.set_under(
              color='c'
          )
      im = ax.matshow(
          C,
          interpolation='none',
          cmap=cmap,
          aspect='auto',
          vmin=kwargs.get('cbmin', None),
          vmax=kwargs.get('cbmax', None),
          extent=[
              0, max(AB_coords),
              0, max(MN_coords),
          ],
      )
  
      max_xy = max((max(AB_coords), max(MN_coords)))
      ax.plot(
          (0, max_xy),
          (0, max_xy),
          '-',
          color='k',
          linewidth=1.0,
      )
  
      cb = None
      if not kwargs.get('nocb', False):
          cb = fig.colorbar(im, ax=ax)
          cb.set_label(
              kwargs.get('cblabel', units.get_label(column))
          )
  
      ax.set_xlabel(
          kwargs.get('xlabel', 'current dipoles')
      )
      ax.set_ylabel(
          kwargs.get('ylabel', 'voltage dipoles')
      )
  
      return fig, ax, cb