code: def degree(
      dataset_regex: Optional[str],
      min_triples: Optional[int],
      max_triples: Optional[int],
      restrict_split: Optional[str],
      force: bool,
      plot: bool,
      output_root: pathlib.Path,
  ):
      """Analyze degree distributions."""
      output_root.mkdir(exist_ok=True, parents=True)
      base_path = output_root.joinpath("degree-distributions")
      path = base_path.with_suffix(suffix=".tsv.gz")
      if path.is_file() and not force:
          df = pd.read_csv(path, sep="\t")
          logger.info(f"Loaded degree statistics from {path}")
      else:
          with logging_redirect_tqdm():
              rows = [
                  (name, split, factory.num_triples, *row)
                  for name, dataset in iter_dataset_instances(
                      regex_name_filter=dataset_regex,
                      min_triples=min_triples,
                      max_triples=max_triples,
                  )
                  for split, factory in dataset.factory_dict.items()
                  if (restrict_split is None or split == restrict_split)
                  for row in _summarize_degree_distribution(
                      factory=factory
                  )
              ]
          df = pd.DataFrame(
              data=rows,
              columns=[
                  "dataset",
                  "split",
                  "num_triples",
                  "target",
                  "nobs",
                  "minmax",
                  "mean",
                  "variance",
                  "skewness",
                  "kurtosis",
              ],
          )
          # only save full data
          if (
              dataset_regex is None
              and min_triples is None
              and max_triples is None
              and restrict_split is None
          ):
              df.to_csv(path, sep="\t", index=False)
              logger.info(f"Written degree statistics to {path}")
      if not plot:
          return
      plt, sns = _get_plotting_libraries()
  
      # Plot: Descriptive Statistics of Degree Distributions per dataset / split vs. number of triples (=size)
      df = df.melt(
          id_vars=["dataset", "split", "num_triples", "target"],
          value_vars=["mean", "variance", "skewness", "kurtosis"],
          var_name="statistic",
      )
      grid_1: sns.FacetGrid = sns.relplot(  # type: ignore
          data=df,
          hue="dataset",
          x="num_triples",
          style=None if restrict_split is not None else "split",
          col="statistic",
          row="target",
          y="value",
          facet_kws=dict(
              margin_titles=True,
              sharey="col",
          ),
          height=2.5,
          hue_order=sorted(df["dataset"].unique()),
      )
      grid_1.fig.suptitle("Dataset Degree Distributions", x=0.4, y=0.98)
      plt.subplots_adjust(top=0.85)
      sns.move_legend(
          grid_1,
          "lower center",
          bbox_to_anchor=(0.45, -0.35),
          ncol=6,
          title=None,
          frameon=False,
      )
      grid_1.tight_layout()
      grid_1.set(xscale="log", yscale="log", xlabel="Triples")
      path = base_path.with_suffix(suffix=".pdf")
      grid_1.savefig(path)
      grid_1.savefig(
          IMG_DIR.joinpath("dataset_degree_distributions.svg")
      )
      logger.info(f"Saved plot to {path}")
  
      # Plot: difference between mean head and tail degree
      df_2 = df.loc[df["statistic"] == "mean"].pivot(
          index=["dataset", "split", "num_triples"],
          columns="target",
          values="value",
      )
      df_2["difference"] = df_2["head"] - df_2["tail"]
      grid_2: sns.FacetGrid = sns.relplot(  # type: ignore
          data=df_2,
          hue="dataset",
          x="num_triples",
          style=None if restrict_split is not None else "split",
          y="difference",
          height=2.5,
          aspect=4,
          hue_order=sorted(df["dataset"].unique()),
      )
      grid_2.fig.suptitle(
          "Dataset Mean Degree Imbalance", x=0.4, y=0.98
      )
      sns.move_legend(
          grid_2,
          "lower center",
          bbox_to_anchor=(0.45, -0.55),
          ncol=6,
          title=None,
          frameon=False,
      )
      grid_2.tight_layout()
      grid_2.set(xscale="log", yscale="symlog", xlabel="Triples")
      path = base_path.with_name("degree-imbalance").with_suffix(
          suffix=".pdf"
      )
      grid_2.savefig(path)
      grid_2.savefig(IMG_DIR.joinpath("degree_imbalance.svg"))
      logger.info(f"Saved plot to {path}")
  
imports: import itertools
  import json
  import logging
  import math
  import pathlib
  from textwrap import dedent
  from typing import Iterable, List, Mapping, MutableMapping, Optional, Tuple, Union
  import click
  import docdata
  import pandas
  import scipy.stats
  from more_click import force_option, log_level_option, verbose_option
  from tqdm import tqdm
  from tqdm.contrib.logging import logging_redirect_tqdm
  from .base import Dataset
  from .utils import dataset_regex_option, iter_dataset_instances, max_triples_option, min_triples_option
  from ..constants import COLUMN_LABELS, PYKEEN_DATASETS
  from ..evaluation.evaluator import get_candidate_set_size
  from ..metrics.ranking import ArithmeticMeanRank, GeometricMeanRank, HarmonicMeanRank, HitsAtK, InverseArithmeticMeanRank, InverseGeometricMeanRank, InverseHarmonicMeanRank, InverseMedianRank, MedianRank
  from ..triples import CoreTriplesFactory
  from ..typing import LABEL_HEAD, LABEL_RELATION, LABEL_TAIL, SIDE_MAPPING, ExtendedTarget
label_desc: Use image node_id 9 for calling a global function with example usage: degree(dataset_regex, min_triples, max_triples, restrict_split, force, plot, output_root) without return types