code: def critical_difference_diagram(
      ranks: Union[dict, Series],
      sig_matrix: DataFrame,
      *,
      ax: SubplotBase = None,
      label_fmt_left: str = "{label} ({rank:.2g})",
      label_fmt_right: str = "({rank:.2g}) {label}",
      label_props: dict = None,
      marker_props: dict = None,
      elbow_props: dict = None,
      crossbar_props: dict = None,
      color_palette: Union[Dict[str, str], List] = {},
      text_h_margin: float = 0.01,
  ) -> Dict[str, list]:
      """Plot a Critical Difference diagram from ranks and post-hoc results.
  
      The diagram arranges the average ranks of multiple groups on the x axis
      in order to facilitate performance comparisons between them. The groups
      that could not be statistically deemed as different are linked by a
      horizontal crossbar [1]_, [2]_.
  
      ::
  
                        rank markers
           X axis ---------O----O-------------------O-O------------O---------
                           |----|                   | |            |
                           |    |                   |---crossbar---|
                  clf1 ----|    |                   | |            |---- clf3
                  clf2 ---------|                   | |----------------- clf4
                                                    |------------------- clf5
                      |____|
                  text_h_margin
  
      In the drawing above, the two crossbars indicate that clf1 and clf2 cannot
      be statistically differentiated, the same occurring between clf3, clf4 and
      clf5. However, clf1 and clf2 are each significantly lower ranked than clf3,
      clf4 and clf5.
  
      Parameters
      ----------
      ranks : dict or Series
          Indicates the rank value for each sample or estimator (as keys or index).
  
      sig_matrix : DataFrame
          The corresponding p-value matrix outputted by post-hoc tests, with
          indices matching the labels in the ranks argument.
  
      ax : matplotlib.SubplotBase, optional
          The object in which the plot will be built. Gets the current Axes
          by default (if None is passed).
  
      label_fmt_left : str, optional
          The format string to apply to the labels on the left side. The keywords
          label and rank can be used to specify the sample/estimator name and
          rank value, respectively, by default '{label} ({rank:.2g})'.
  
      label_fmt_right : str, optional
          The same, but for the labels on the right side of the plot.
          By default '({rank:.2g}) {label}'.
  
      label_props : dict, optional
          Parameters to be passed to pyplot.text() when creating the labels,
          by default None.
  
      marker_props : dict, optional
          Parameters to be passed to pyplot.scatter() when plotting the rank
          markers on the axis, by default None.
  
      elbow_props : dict, optional
          Parameters to be passed to pyplot.plot() when creating the elbow lines,
          by default None.
  
      crossbar_props : dict, optional
          Parameters to be passed to pyplot.plot() when creating the crossbars
          that indicate lack of statistically significant difference. By default
          None.
  
      text_h_margin : float, optional
          Space between the text labels and the nearest vertical line of an
          elbow, by default 0.01.
      color_palette: dict, optional
          Parameters to be passed when you need specific colors for each category
  
      Returns
      -------
      dict[str, list[matplotlib.Artist]]
          Lists of Artists created.
  
      Examples
      --------
      See the :doc:`/tutorial`.
  
      References
      ----------
      .. [1] Demšar, J. (2006). Statistical comparisons of classifiers over multiple
              data sets. The Journal of Machine learning research, 7, 1-30.
  
      .. [2] https://mirkobunse.github.io/CriticalDifferenceDiagrams.jl/stable/
      """
      ## check color_palette consistency
      if len(color_palette) == 0:
          pass
      elif isinstance(color_palette, Dict) and (
          (len(set(ranks.keys()) & set(color_palette.keys())))
          == len(ranks)
      ):
          pass
      elif isinstance(color_palette, List) and (
          len(ranks) <= len(color_palette)
      ):
          pass
      else:
          raise ValueError(
              "color_palette keys are not consistent, or list size too small"
          )
  
      elbow_props = elbow_props or {}
      marker_props = {"zorder": 3, **(marker_props or {})}
      label_props = {"va": "center", **(label_props or {})}
      crossbar_props = {
          "color": "k",
          "zorder": 3,
          "linewidth": 2,
          **(crossbar_props or {}),
      }
  
      ax = ax or pyplot.gca()
      ax.yaxis.set_visible(False)
      ax.spines["right"].set_visible(False)
      ax.spines["left"].set_visible(False)
      ax.spines["bottom"].set_visible(False)
      ax.xaxis.set_ticks_position("top")
      ax.spines["top"].set_position("zero")
  
      # lists of artists to be returned
      markers = []
      elbows = []
      labels = []
      crossbars = []
  
      # True if pairwise comparison is NOT significant
      adj_matrix = DataFrame(
          1 - sign_array(sig_matrix),
          index=sig_matrix.index,
          columns=sig_matrix.columns,
          dtype=bool,
      )
  
      ranks = Series(ranks)  # Standardize if ranks is dict
      points_left, points_right = np.array_split(ranks.sort_values(), 2)
  
      # Sets of points under the same crossbar
      crossbar_sets = _find_maximal_cliques(adj_matrix)
  
      # Sort by lowest rank and filter single-valued sets
      crossbar_sets = sorted(
          (x for x in crossbar_sets if len(x) > 1),
          key=lambda x: ranks[list(x)].min(),
      )
  
      # Create stacking of crossbars: for each level, try to fit the crossbar,
      # so that it does not intersect with any other in the level. If it does not
      # fit in any level, create a new level for it.
      crossbar_levels: list[list[set]] = []
      for bar in crossbar_sets:
          for level, bars_in_level in enumerate(crossbar_levels):
              if not any(
                  bool(bar & bar_in_lvl) for bar_in_lvl in bars_in_level
              ):
                  ypos = -level - 1
                  bars_in_level.append(bar)
                  break
          else:
              ypos = -len(crossbar_levels) - 1
              crossbar_levels.append([bar])
  
          crossbars.append(
              ax.plot(
                  # Adding a separate line between each pair enables showing a
                  # marker over each elbow with crossbar_props={'marker': 'o'}.
                  [ranks[i] for i in bar],
                  [ypos] * len(bar),
                  **crossbar_props,
              )
          )
  
      lowest_crossbar_ypos = -len(crossbar_levels)
  
      def plot_items(
          points, xpos, label_fmt, color_palette, label_props
      ):
          """Plot each marker + elbow + label."""
          ypos = lowest_crossbar_ypos - 1
          for idx, (label, rank) in enumerate(points.items()):
              if len(color_palette) == 0:
                  elbow, *_ = ax.plot(
                      [xpos, rank, rank],
                      [ypos, ypos, 0],
                      **elbow_props,
                  )
              else:
                  elbow, *_ = ax.plot(
                      [xpos, rank, rank],
                      [ypos, ypos, 0],
                      c=color_palette[label]
                      if isinstance(color_palette, Dict)
                      else color_palette[idx],
                      **elbow_props,
                  )
  
              elbows.append(elbow)
              curr_color = elbow.get_color()
              markers.append(
                  ax.scatter(
                      rank, 0, **{"color": curr_color, **marker_props}
                  )
              )
              labels.append(
                  ax.text(
                      xpos,
                      ypos,
                      label_fmt.format(label=label, rank=rank),
                      **{"color": curr_color, **label_props},
                  )
              )
              ypos -= 1
  
      plot_items(
          points_left,
          xpos=points_left.iloc[0] - text_h_margin,
          label_fmt=label_fmt_left,
          color_palette=color_palette,
          label_props={
              "ha": "right",
              **label_props,
          },
      )
      plot_items(
          points_right[::-1],
          xpos=points_right.iloc[-1] + text_h_margin,
          label_fmt=label_fmt_right,
          color_palette=color_palette,
          label_props={"ha": "left", **label_props},
      )
  
      return {
          "markers": markers,
          "elbows": elbows,
          "labels": labels,
          "crossbars": crossbars,
      }
  
file_path: scikit-posthocs/scikit_posthocs/_plotting.py
imports: from typing import Union, List, Tuple, Dict, Set
  import numpy
  from matplotlib import colors
  from matplotlib.axes import SubplotBase
  from matplotlib.colorbar import ColorbarBase, Colorbar
  from matplotlib.colors import ListedColormap
  from matplotlib import pyplot
  from pandas import DataFrame, Series
  from seaborn import heatmap
label_desc: Use image node_id 6 for calling a global function with example usage: critical_difference_diagram(ranks, sig_matrix) and returns: dict