docs: def plot_distance(
          self,
          rank="auto",
          metric="braycurtis",
          title=None,
          xlabel=None,
          ylabel=None,
          tooltip=None,
          return_chart=False,
          linkage="average",
          label=None,
      ):
          """Plot beta diversity distance matrix as a heatmap and dendrogram.
  
          Parameters
          ----------
          rank : {'auto', 'kingdom', 'phylum', 'class', 'order', 'family', 'genus', 'species'}, optional
              Analysis will be restricted to abundances of taxa at the specified level.
          metric : {'braycurtis', 'manhattan', 'jaccard', 'unifrac', 'unweighted_unifrac}, optional
              Function to use when calculating the distance between two samples.
          linkage : {'average', 'single', 'complete', 'weighted', 'centroid', 'median'}
              The type of linkage to use when clustering axes.
          title : `string`, optional
              Text label at the top of the plot.
          xlabel : `string`, optional
              Text label along the horizontal axis.
          ylabel : `string`, optional
              Text label along the vertical axis.
          tooltip : `string` or `list`, optional
              A string or list containing strings representing metadata fields. When a point in the
              plot is hovered over, the value of the metadata associated with that sample will be
              displayed in a modal.
          label : `string` or `callable`, optional
              A metadata field (or function) used to label each analysis. If passing a function, a
              dict containing the metadata for each analysis is passed as the first and only
              positional argument. The callable function must return a string.
  
          Examples
          --------
          Plot the weighted UniFrac distance between all our samples, using counts at the genus level.
  
          >>> plot_distance(rank='genus', metric='unifrac')
          """
          if len(self._results) < 2:
              raise OneCodexException(
                  "`plot_distance` requires 2 or more valid classification results."
              )
  
          # this will be passed to the heatmap chart as a dataframe eventually
          plot_data = {"1) Label": [], "2) Label": [], "Distance": [], "classification_id": []}
  
          # here we figure out what to put in the tooltips and get the appropriate data
          if tooltip:
              if not isinstance(tooltip, list):
                  tooltip = [tooltip]
          else:
              tooltip = []
  
          tooltip.insert(0, "Label")
  
          magic_metadata, magic_fields = self._metadata_fetch(tooltip, label=label)
          formatted_fields = []
  
          for _, magic_field in magic_fields.items():
              field_group = []
  
              for i in (1, 2):
                  field = "{}) {}".format(i, magic_field)
                  plot_data[field] = []
                  field_group.append(field)
  
              formatted_fields.append(field_group)
  
          clust = self._cluster_by_sample(rank=rank, metric=metric, linkage=linkage)
  
          # must convert to long format for heatmap plotting
          for idx1, id1 in enumerate(clust["dist_matrix"].index):
              for idx2, id2 in enumerate(clust["dist_matrix"].index):
                  if idx1 == idx2:
                      plot_data["Distance"].append(np.nan)
                  else:
                      plot_data["Distance"].append(clust["dist_matrix"].iloc[idx1, idx2])
  
                  plot_data["classification_id"].append(id1)
  
                  for field_group, magic_field in zip(formatted_fields, magic_fields.values()):
                      plot_data[field_group[0]].append(magic_metadata[magic_field][id1])
                      plot_data[field_group[1]].append(magic_metadata[magic_field][id2])
  
          plot_data = pd.DataFrame(data=plot_data)
  
          labels_in_order = magic_metadata["Label"][clust["ids_in_order"]].tolist()
  
          # it's important to tell altair to order the cells in the heatmap according to the clustering
          # obtained from scipy
          alt_kwargs = dict(
              x=alt.X("1) Label:N", axis=alt.Axis(title=xlabel), sort=labels_in_order),
              y=alt.Y(
                  "2) Label:N", axis=alt.Axis(title=ylabel, orient="right"), sort=labels_in_order
              ),
              color="Distance:Q",
              tooltip=list(chain.from_iterable(formatted_fields)) + ["Distance:Q"],
              href="url:N",
              url="https://app.onecodex.com/classification/" + alt.datum.classification_id,
          )
  
          chart = (
              alt.Chart(
                  plot_data,
                  width=15 * len(clust["dist_matrix"].index),
                  height=15 * len(clust["dist_matrix"].index),
              )
              .transform_calculate(url=alt_kwargs.pop("url"))
              .mark_rect()
              .encode(**alt_kwargs)
          )
  
          if title:
              chart = chart.properties(title=title)
  
          dendro_chart = dendrogram(clust["scipy_tree"])
  
          if return_chart:
              return dendro_chart | chart
          else:
              (dendro_chart | chart).display()