code: def plot_pd(
      exp: Explanation,
      features: Union[List[int], Literal["all"]] = "all",
      target: Union[str, int] = 0,
      n_cols: int = 3,
      n_ice: Union[Literal["all"], int, List[int]] = 100,
      center: bool = False,
      pd_limits: Optional[Tuple[float, float]] = None,
      levels: int = 8,
      ax: Optional[Union["plt.Axes", np.ndarray]] = None,
      sharey: Optional[Literal["all", "row"]] = "all",
      pd_num_kw: Optional[dict] = None,
      ice_num_kw: Optional[dict] = None,
      pd_cat_kw: Optional[dict] = None,
      ice_cat_kw: Optional[dict] = None,
      pd_num_num_kw: Optional[dict] = None,
      pd_num_cat_kw: Optional[dict] = None,
      pd_cat_cat_kw: Optional[dict] = None,
      fig_kw: Optional[dict] = None,
  ) -> "np.ndarray":
      """
      Plot partial dependence curves on matplotlib axes.
  
      Parameters
      ----------
      exp
          An `Explanation` object produced by a call to the
          :py:meth:`alibi.explainers.partial_dependence.PartialDependence.explain` method.
      features
          A list of features entries in the `exp.data['feature_names']` to plot the partial dependence curves for,
          or ``'all'`` to plot all the explained feature or tuples of features. This includes tuples of features.
          For example, if ``exp.data['feature_names'] = ['temp', 'hum', ('temp', 'windspeed')]`` and we want to plot
          the partial dependence only for the ``'temp'`` and ``('temp', 'windspeed')``, then we would set
          ``features=[0, 2]``. Defaults to ``'all'``.
      target
          The target name or index for which to plot the partial dependence (PD) curves. Can be a mix of integers
          denoting target index or strings denoting entries in `exp.meta['params']['target_names']`.
      n_cols
          Number of columns to organize the resulting plot into.
      n_ice
          Number of ICE plots to be displayed. Can be
  
           - a string taking the value ``'all'`` to display the ICE curves for every instance in the reference dataset.
  
           - an integer for which `n_ice` instances from the reference dataset will be sampled uniformly at random to \
           display their ICE curves.
  
           - a list of integers, where each integer represents an index of an instance in the reference dataset to \
           display their ICE curves.
  
      center
          Boolean flag to center the individual conditional expectation (ICE) curves. As mentioned in
          `Goldstein et al. (2014)`_, the heterogeneity in the model can be difficult to discern when the intercepts
          of the ICE curves cover a wide range. Centering the ICE curves removes the level effects and helps
          to visualise the heterogeneous effect.
  
          .. _Goldstein et al. (2014):
                  https://arxiv.org/abs/1309.6392
  
      pd_limits
          Minimum and maximum y-limits for all the one-way PD plots. If ``None`` will be automatically inferred.
      levels
          Number of levels in the contour plot.
      ax
          A `matplotlib` axes object or a `numpy` array of `matplotlib` axes to plot on.
      sharey
          A parameter specifying whether the y-axis of the PD and ICE curves should be on the same scale
          for several features. Possible values are: ``'all'`` | ``'row'`` | ``None``.
      pd_num_kw
          Keyword arguments passed to the `matplotlib.pyplot.plot`_ function when plotting the PD for a
          numerical feature.
      ice_num_kw
          Keyword arguments passed to the `matplotlib.pyplot.plot`_ function when plotting the ICE for a
          numerical feature.
      pd_cat_kw
          Keyword arguments passed to the `matplotlib.pyplot.plot`_ function when plotting the PD for a
          categorical feature.
      ice_cat_kw
          Keyword arguments passed to the `matplotlib.pyplot.plot`_ function when plotting the ICE for a
          categorical feature.
      pd_num_num_kw
          Keyword arguments passed to the `matplotlib.pyplot.contourf`_ function when plotting the PD for two
          numerical features.
      pd_num_cat_kw
          Keyword arguments passed to the `matplotlib.pyplot.plot`_ function when plotting the PD for a numerical and a
          categorical feature.
      pd_cat_cat_kw
          Keyword arguments passed to the :py:meth:`alibi.utils.visualization.heatmap` functon when plotting the PD for
          two categorical features.
      fig_kw
          Keyword arguments passed to the `matplotlib.figure.set`_ function.
  
          .. _matplotlib.pyplot.plot:
              https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html
  
          .. _matplotlib.pyplot.contourf:
              https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.contourf.html
  
          .. _matplotlib.figure.set:
              https://matplotlib.org/stable/api/figure_api.html
  
      Returns
      -------
      An array of `plt.Axes` with the resulting partial dependence plots.
      """
      import matplotlib.pyplot as plt
      from matplotlib.gridspec import GridSpec
  
      default_fig_kw = {"tight_layout": "tight"}
      if fig_kw is None:
          fig_kw = {}
      fig_kw = {**default_fig_kw, **fig_kw}
  
      if features == "all":
          features = range(0, len(exp.data["feature_names"]))
      else:
          for ifeatures in features:
              if ifeatures >= len(exp.data["feature_names"]):
                  raise IndexError(
                      f"The `features` indices must be less than the "
                      f"``len(feature_names) = {len(exp.data['feature_names'])}``. "
                      f"Received {ifeatures}."
                  )
  
      # set target index
      if isinstance(target, str):
          try:
              target_idx = exp.meta["params"]["target_names"].index(
                  target
              )
          except ValueError:
              raise ValueError(
                  f"Unknown `target` name. Received {target}. "
                  f"Available values are: {exp.meta['params']['target_names']}."
              )
      else:
          target_idx = target
          if target_idx >= len(exp.meta["params"]["target_names"]):
              raise IndexError(
                  f"Target index out of range. Received {target_idx}. "
                  f"The number of targets is {len(exp.meta['params']['target_names'])}."
              )
  
      # corresponds to the number of subplots
      n_features = len(features)
  
      # create axes
      if ax is None:
          fig, ax = plt.subplots()
  
      def _is_categorical(feature):
          feature_idx = exp.meta["params"]["feature_names"].index(
              feature
          )
          return feature_idx in exp.meta["params"]["categorical_names"]
  
      if isinstance(ax, plt.Axes) and n_features != 1:
          ax.set_axis_off()  # treat passed axis as a canvas for subplots
          fig = ax.figure
          n_cols = min(n_cols, n_features)
          n_rows = math.ceil(n_features / n_cols)
  
          axes = np.empty((n_rows, n_cols), dtype=object)
          axes_ravel = axes.ravel()
          gs = GridSpec(n_rows, n_cols)
          for i, spec in enumerate(list(gs)[:n_features]):
              axes_ravel[i] = fig.add_subplot(spec)
  
      else:  # array-like
          if isinstance(ax, plt.Axes):
              ax = np.array(ax)
          if ax.size < n_features:
              raise ValueError(
                  f"Expected ax to have {n_features} axes, got {ax.size}"
              )
          axes = np.atleast_2d(ax)
          axes_ravel = axes.ravel()
          fig = axes_ravel[0].figure
  
      # create plots
      one_way_axs = {}
  
      for i, (ifeatures, ax_ravel) in enumerate(
          zip(features, axes_ravel)
      ):
          # extract the feature names
          feature_names = exp.data["feature_names"][ifeatures]
  
          # if it is tuple, then we need a 2D plot and address 4 cases: (num, num), (num, cat), (cat, num), (cat, cat)
          if isinstance(feature_names, tuple):
              f0, f1 = feature_names
  
              if (not _is_categorical(f0)) and (
                  not _is_categorical(f1)
              ):
                  ax, ax_pd_limits = _plot_two_pd_num_num(
                      exp=exp,
                      feature=ifeatures,
                      target_idx=target_idx,
                      levels=levels,
                      ax=ax_ravel,
                      pd_num_num_kw=pd_num_num_kw,
                  )
  
              elif _is_categorical(f0) and _is_categorical(f1):
                  ax, ax_pd_limits = _plot_two_pd_cat_cat(
                      exp=exp,
                      feature=ifeatures,
                      target_idx=target_idx,
                      ax=ax_ravel,
                      pd_cat_cat_kw=pd_cat_cat_kw,
                  )
  
              else:
                  ax, ax_pd_limits = _plot_two_pd_num_cat(
                      exp=exp,
                      feature=ifeatures,
                      target_idx=target_idx,
                      pd_limits=pd_limits,
                      ax=ax_ravel,
                      pd_num_cat_kw=pd_num_cat_kw,
                  )
  
          else:
              if _is_categorical(feature_names):
                  ax, ax_pd_limits = _plot_one_pd_cat(
                      exp=exp,
                      feature=ifeatures,
                      target_idx=target_idx,
                      center=center,
                      pd_limits=pd_limits,
                      n_ice=n_ice,
                      ax=ax_ravel,
                      pd_cat_kw=pd_cat_kw,
                      ice_cat_kw=ice_cat_kw,
                  )
              else:
                  ax, ax_pd_limits = _plot_one_pd_num(
                      exp=exp,
                      feature=ifeatures,
                      target_idx=target_idx,
                      center=center,
                      pd_limits=pd_limits,
                      n_ice=n_ice,
                      ax=ax_ravel,
                      pd_num_kw=pd_num_kw,
                      ice_num_kw=ice_num_kw,
                  )
  
          # group the `ax_ravel` that share the appropriate y axes.
          if ax_pd_limits is not None:
              if sharey == "all":
                  if one_way_axs.get("all", None) is None:
                      one_way_axs["all"] = []
  
                  # add them all in the same group
                  one_way_axs["all"].append((ax, ax_pd_limits))
              elif sharey == "row":
                  # identify the row to which they belong
                  row = i // n_cols
  
                  if one_way_axs.get(row, None) is None:
                      one_way_axs[row] = []
  
                  # add them the `row` group
                  one_way_axs[row].append((ax, ax_pd_limits))
              else:
                  # if no axis are share, each `ax_ravel` will have its own group
                  one_way_axs[i] = [(ax, ax_pd_limits)]
  
      #  share the y-axis for the axes within the same group and set the `ymin`, `ymax` values.
      #  This step is necessary and applied here because `vlines` overwrites the `ylim`.
      for ax_group in one_way_axs.values():
          min_val = min([ax_pd_lim[0] for _, ax_pd_lim in ax_group])
          max_val = max([ax_pd_lim[1] for _, ax_pd_lim in ax_group])
          axs = [ax[0] for ax in ax_group]
          for ax in axs[1:]:
              ax.sharey(axs[0])
          axs[0].set_ylim(min_val, max_val)
  
      fig.set(**fig_kw)
      return axes
  
imports: import copy
  import logging
  import math
  import numbers
  import sys
  from abc import ABC, abstractmethod
  from enum import Enum
  from typing import Callable, Dict, Iterable, List, Optional, Tuple, Union, no_type_check
  import matplotlib.pyplot
  import numpy
  from scipy.stats.mstats import mquantiles
  from sklearn.base import BaseEstimator, is_classifier, is_regressor
  from sklearn.ensemble import RandomForestRegressor
  from sklearn.ensemble._gb import BaseGradientBoosting
  from sklearn.ensemble._hist_gradient_boosting.gradient_boosting import BaseHistGradientBoosting
  from sklearn.tree import DecisionTreeRegressor
  from sklearn.utils.extmath import cartesian
  from sklearn.utils.validation import check_is_fitted
  from tqdm import tqdm
  from alibi.api.defaults import DEFAULT_DATA_PD, DEFAULT_META_PD
  from alibi.api.interfaces import Explainer, Explanation
  from alibi.explainers.ale import get_quantiles
  from alibi.utils import _get_options_string
label_desc: Use image node_id 1 for calling a global function with example usage: plot_pd(exp, features, target, n_cols, n_ice, center, pd_limits, levels, ax, sharey, pd_num_kw, ice_num_kw, pd_cat_kw, ice_cat_kw, pd_num_num_kw, pd_num_cat_kw, pd_cat_cat_kw, fig_kw) and returns: axes, unknown