class_docstr: Plotting object allows for visualization of absolute group bias metrics and
  relative disparities calculated by Aequitas Group(), Bias(), and Fairness()
  class instances.
docstr: Create treemap based on a single bias disparity metric across attribute
  groups.
  
  Adapted from https://plot.ly/python/treemaps/,
  https://gist.github.com/gVallverdu/0b446d0061a785c808dbe79262a37eea,
  and https://fcpython.com/visualisation/python-treemaps-squarify-matplotlib
  
  :param disparity_table: a disparity table. Output of bias.get_disparity or
      fairness.get_fairness function.
  :param group_metric: the metric to plot. Must be a column in the
      disparity_table.
  :param attribute_name: which attribute to plot group_metric across.
  :param color_mapping: matplotlib colormapping for treemap value boxes.
  :param ax: a matplotlib Axis. If not passed, a new figure will be created.
  :param fig: a matplotlib Figure. If not passed, a new figure will be created.
  :param label_dict: optional, dictionary of replacement labels for data.
      Default is None.
  :param title: whether to include a title in visualizations. Default is True.
  :param highlight_fairness: whether to highlight treemaps by disparity
      magnitude, or by related fairness determination.
  :param min_group_size: minimum proportion of total group size (all data)
      a population group must meet in order to be included in bias metric
      visualization
  :param significance_alpha: statistical significance level. Used to
      determine visual representation of significance (number of
      asterisks on treemap).
  
  :return: A Matplotlib axis
code: def plot_disparity(
      self,
      disparity_table,
      group_metric,
      attribute_name,
      color_mapping=None,
      ax=None,
      fig=None,
      label_dict=None,
      title=True,
      highlight_fairness=False,
      min_group_size=None,
      significance_alpha=0.05,
  ):
      """
      Create treemap based on a single bias disparity metric across attribute
      groups.
  
      Adapted from https://plot.ly/python/treemaps/,
      https://gist.github.com/gVallverdu/0b446d0061a785c808dbe79262a37eea,
      and https://fcpython.com/visualisation/python-treemaps-squarify-matplotlib
  
      :param disparity_table: a disparity table. Output of bias.get_disparity or
          fairness.get_fairness function.
      :param group_metric: the metric to plot. Must be a column in the
          disparity_table.
      :param attribute_name: which attribute to plot group_metric across.
      :param color_mapping: matplotlib colormapping for treemap value boxes.
      :param ax: a matplotlib Axis. If not passed, a new figure will be created.
      :param fig: a matplotlib Figure. If not passed, a new figure will be created.
      :param label_dict: optional, dictionary of replacement labels for data.
          Default is None.
      :param title: whether to include a title in visualizations. Default is True.
      :param highlight_fairness: whether to highlight treemaps by disparity
          magnitude, or by related fairness determination.
      :param min_group_size: minimum proportion of total group size (all data)
          a population group must meet in order to be included in bias metric
          visualization
      :param significance_alpha: statistical significance level. Used to
          determine visual representation of significance (number of
          asterisks on treemap).
  
      :return: A Matplotlib axis
      """
      # Use matplotlib to truncate colormap, scale metric values
      # between the min and max, then assign colors to individual values
  
      model_id = self._check_model_id(
          df=disparity_table, method_table_name="disparities_table"
      )
  
      table_columns = set(disparity_table.columns)
      if group_metric not in table_columns:
          raise ValueError(
              f"Specified disparity metric {group_metric} not in 'disparity_table'."
          )
  
      attribute_table = disparity_table.loc[
          disparity_table["attribute_name"] == attribute_name
      ]
  
      # sort by group size, as box size is indicative of group size
      sorted_df = attribute_table.sort_values(
          "group_size", ascending=False
      )
  
      x = 0.0
      y = 0.0
      width = 100.0
      height = 100.0
  
      (
          ref_group_rel_idx,
          ref_group_name,
      ) = self._locate_ref_group_indices(
          disparities_table=sorted_df,
          attribute_name=attribute_name,
          group_metric=group_metric,
      )
  
      if min_group_size:
          if min_group_size > (
              disparity_table.group_size.max()
              / disparity_table.group_size.sum()
          ):
              raise ValueError(
                  f"'min_group_size' proportion specified: '{min_group_size}' "
                  f"is larger than all groups in sample."
              )
  
          min_size = min_group_size * disparity_table.group_size.sum()
  
          # raise warning if minimum group size specified would exclude
          # reference group
          if any(
              sorted_df.loc[
                  (sorted_df["attribute_value"] == ref_group_name),
                  ["group_size"],
              ].values
              < min_size
          ):
              logging.warning(
                  f"Reference group size is smaller than 'min_group_size' proportion "
                  f"specified: '{min_group_size}'. Reference group '{ref_group_name}' "
                  f"was not excluded."
              )
  
          sorted_df = sorted_df.loc[
              (sorted_df["group_size"] >= min_size)
              | (sorted_df["attribute_value"] == ref_group_name)
          ]
  
      # select group size as values for size of boxes
      values = sorted_df.loc[:, "group_size"]
  
      # get new index for ref group
      ref_group_rel_idx, _ = self._locate_ref_group_indices(
          disparities_table=sorted_df,
          attribute_name=attribute_name,
          group_metric=group_metric,
      )
  
      # labels for squares in tree map:
      # label should always be disparity value (but boxes visualized should be
      # always be the metric absolute value capped between 0.1x ref group and
      # 10x ref group)
      if group_metric + "_disparity" not in attribute_table.columns:
          related_disparity = group_metric
  
      else:
          related_disparity = group_metric + "_disparity"
  
      if highlight_fairness:
          if (
              not len(
                  table_columns.intersection(
                      self._metric_parity_mapping.values()
                  )
              )
              > 1
          ):
              raise ValueError(
                  "Data table must include at least one fairness "
                  "determination to visualize metric parity."
              )
  
          # apply red for "False" fairness determinations and green for "True"
          # determinations
          cb_green = "#1b7837"
          cb_red = "#a50026"
  
          parity = self._metric_parity_mapping[group_metric]
          if parity not in table_columns:
              raise ValueError(
                  f"Related fairness determination for {group_metric} must be "
                  f"included in data table to color visualization based on "
                  f"metric fairness."
              )
          clrs = [
              cb_green if val else cb_red for val in sorted_df[parity]
          ]
  
      else:
          aq_palette = sns.diverging_palette(
              225, 35, sep=10, as_cmap=True
          )
  
          if not color_mapping:
              norm = matplotlib.colors.Normalize(vmin=0, vmax=2)
              color_mapping = matplotlib.cm.ScalarMappable(
                  norm=norm, cmap=aq_palette
              )
  
          clrs = [
              color_mapping.to_rgba(val)
              for val in sorted_df[related_disparity]
          ]
  
      # color reference group grey
      clrs[ref_group_rel_idx] = "#D3D3D3"
  
      compare_value = values.iloc[ref_group_rel_idx]
  
      scaled_values = [
          (0.1 * compare_value)
          if val < (0.1 * compare_value)
          else (10 * compare_value)
          if val >= (10 * compare_value)
          else val
          for val in values
      ]
  
      label_values = [
          "(Ref)" if attr_val == ref_group_name else f"{disp:.2f}"
          for attr_val, disp in zip(
              sorted_df["attribute_value"], sorted_df[related_disparity]
          )
      ]
  
      if label_dict:
          labels = [
              label_dict.get(label, label)
              for label in sorted_df["attribute_value"]
          ]
      else:
          labels = sorted_df["attribute_value"].values
  
      # if df includes significance columns, add stars to indicate significance
      if (
          self._significance_disparity_mapping[related_disparity]
          in sorted_df.columns
      ):
          # truncated_signif_mapping = {k: v for k,v in self._significance_disparity_mapping.items() if v in sorted_df.columns}
  
          if (
              sorted_df.columns[
                  sorted_df.columns.str.contains("_significance")
              ]
              .value_counts()
              .sum()
              > 0
          ):
              # unmasked significance
              # find indices where related significance have smaller value than significance_alpha
              if np.issubdtype(
                  sorted_df[
                      self._significance_disparity_mapping[
                          related_disparity
                      ]
                  ].dtype,
                  # truncated_signif_mapping[related_disparity]].dtype,
                  np.number,
              ):
                  to_star = sorted_df.loc[
                      sorted_df[
                          self._significance_disparity_mapping[
                              related_disparity
                          ]
                      ]
                      < significance_alpha
                  ].index.tolist()
                  # truncated_signif_mapping[related_disparity]] < significance_alpha].index.tolist()
  
              # masked significance
              # find indices where attr values have True value for each of those two columns,
              else:
                  to_star = sorted_df.loc[
                      sorted_df[
                          self._significance_disparity_mapping[
                              related_disparity
                          ]
                      ]
                      > 0
                  ].index.tolist()
                  # truncated_signif_mapping[related_disparity]] > 0].index.tolist()
  
              # add stars to label value where significant
              for idx in to_star:
                  # convert idx location to relative index in sorted df and label_values list
                  idx_adj = sorted_df.index.get_loc(idx)
  
                  # star significant disparities in visualizations based on significance level
                  if 0.10 >= significance_alpha > 0.05:
                      significance_stars = "*"
                  elif 0.05 >= significance_alpha > 0.01:
                      significance_stars = "**"
                  elif significance_alpha <= 0.01:
                      significance_stars = "***"
                  else:
                      significance_stars = ""
                  label_values[idx_adj] = (
                      label_values[idx_adj] + significance_stars
                  )
  
      normed = sf.normalize_sizes(scaled_values, width, height)
  
      padded_rects = sf.padded_squarify(normed, x, y, width, height)
  
      # make plot
      if not (ax and fig):
          fig, ax = plt.subplots(figsize=(5, 4))
  
      ax = sf.squarify_plot_rects(
          padded_rects,
          color=clrs,
          labels=labels,
          values=label_values,
          ax=ax,
          alpha=0.8,
          acronyms=False,
      )
  
      if title:
          ax.set_title(
              f"{related_disparity.replace('_', ' ').upper()}: {attribute_name.upper()}",
              fontsize=23,
          )
  
      if not highlight_fairness:
          # create dummy invisible image with a color map to leverage for color bar
          img = plt.imshow([[0, 2]], cmap=aq_palette, alpha=0.8)
          img.set_visible(False)
          fig.colorbar(img, orientation="vertical", shrink=0.96, ax=ax)
  
      #     Remove axes and display the plot
      ax.axis("off")
  
imports: import logging
  import math
  import numpy
  import collections
  import seaborn
  import matplotlib.pyplot
  import matplotlib.colors
  import matplotlib.cm
  from aequitas import squarify_flipped
label_desc: Use image node_id 16 for calling the Plot obj's underlying member method code with example usage: obj.plot_disparity(disparity_table, group_metric, attribute_name, color_mapping, ax, fig, label_dict, title, highlight_fairness, min_group_size, significance_alpha) without return types