code: def log_explanation(predict_function, features, artifact_path=None):
      r"""
      Given a ``predict_function`` capable of computing ML model output on the provided ``features``,
      computes and logs explanations of an ML model's output. Explanations are logged as a directory
      of artifacts containing the following items generated by `SHAP`_ (SHapley Additive
      exPlanations).
  
          - Base values
          - SHAP values (computed using `shap.KernelExplainer`_)
          - Summary bar plot (shows the average impact of each feature on model output)
  
      :param predict_function:
          A function to compute the output of a model (e.g. ``predict_proba`` method of
          scikit-learn classifiers). Must have the following signature:
  
          .. code-block:: python
  
              def predict_function(X) -> pred:
                  ...
  
          - ``X``: An array-like object whose shape should be (# samples, # features).
          - ``pred``: An array-like object whose shape should be (# samples) for
            a regressor or (# classes, # samples) for a classifier. For a classifier,
            the values in ``pred`` should correspond to the predicted probability of each class.
  
          Acceptable array-like object types:
  
              - ``numpy.array``
              - ``pandas.DataFrame``
              - ``shap.common.DenseData``
              - ``scipy.sparse matrix``
  
      :param features:
          A matrix of features to compute SHAP values with. The provided features should
          have shape (# samples, # features), and can be either of the array-like object
          types listed above.
  
          .. note::
              Background data for `shap.KernelExplainer`_ is generated by subsampling ``features``
              with `shap.kmeans`_. The background data size is limited to 100 rows for performance
              reasons.
  
      :param artifact_path:
          The run-relative artifact path to which the explanation is saved.
          If unspecified, defaults to "model_explanations_shap".
  
      :return: Artifact URI of the logged explanations.
  
      .. _SHAP: https://github.com/slundberg/shap
  
      .. _shap.KernelExplainer: https://shap.readthedocs.io/en/latest/generated
          /shap.KernelExplainer.html#shap.KernelExplainer
  
      .. _shap.kmeans: https://github.com/slundberg/shap/blob/v0.36.0/shap/utils/_legacy.py#L9
  
      .. code-block:: python
          :caption: Example
  
          import os
  
          import numpy as np
          import pandas as pd
          from sklearn.datasets import load_diabetes
          from sklearn.linear_model import LinearRegression
  
          import mlflow
          from mlflow import MlflowClient
  
          # prepare training data
          X, y = dataset = load_diabetes(return_X_y=True, as_frame=True)
          X = pd.DataFrame(dataset.data[:50, :8], columns=dataset.feature_names[:8])
          y = dataset.target[:50]
  
          # train a model
          model = LinearRegression()
          model.fit(X, y)
  
          # log an explanation
          with mlflow.start_run() as run:
              mlflow.shap.log_explanation(model.predict, X)
  
          # list artifacts
          client = MlflowClient()
          artifact_path = "model_explanations_shap"
          artifacts = [x.path for x in client.list_artifacts(run.info.run_id, artifact_path)]
          print("# artifacts:")
          print(artifacts)
  
          # load back the logged explanation
          dst_path = client.download_artifacts(run.info.run_id, artifact_path)
          base_values = np.load(os.path.join(dst_path, "base_values.npy"))
          shap_values = np.load(os.path.join(dst_path, "shap_values.npy"))
  
          print("\n# base_values:")
          print(base_values)
          print("\n# shap_values:")
          print(shap_values[:3])
  
      .. code-block:: text
          :caption: Output
  
          # artifacts:
          ['model_explanations_shap/base_values.npy',
           'model_explanations_shap/shap_values.npy',
           'model_explanations_shap/summary_bar_plot.png']
  
          # base_values:
          20.502000000000002
  
          # shap_values:
          [[ 2.09975523  0.4746513   7.63759026  0.        ]
           [ 2.00883109 -0.18816665 -0.14419184  0.        ]
           [ 2.00891772 -0.18816665 -0.14419184  0.        ]]
  
      .. figure:: ../_static/images/shap-ui-screenshot.png
  
          Logged artifacts
      """
      import matplotlib.pyplot as plt
      import shap
  
      artifact_path = (
          _DEFAULT_ARTIFACT_PATH
          if artifact_path is None
          else artifact_path
      )
      with mlflow.utils.autologging_utils.disable_autologging():
          background_data = shap.kmeans(
              features,
              min(_MAXIMUM_BACKGROUND_DATA_SIZE, len(features)),
          )
          explainer = shap.KernelExplainer(
              predict_function, background_data
          )
          shap_values = explainer.shap_values(features)
  
          _log_numpy(
              explainer.expected_value,
              _BASE_VALUES_FILE_NAME,
              artifact_path,
          )
          _log_numpy(shap_values, _SHAP_VALUES_FILE_NAME, artifact_path)
  
          shap.summary_plot(
              shap_values, features, plot_type="bar", show=False
          )
          fig = plt.gcf()
          fig.tight_layout()
          _log_matplotlib_figure(
              fig, _SUMMARY_BAR_PLOT_FILE_NAME, artifact_path
          )
          plt.close(fig)
  
      return append_to_uri_path(
          mlflow.active_run().info.artifact_uri, artifact_path
      )
  
imports: import os
  import tempfile
  import types
  import warnings
  from contextlib import contextmanager
  from typing import Any, Dict, Optional
  import numpy
  import yaml
  import mlflow
  import mlflow.utils.autologging_utils
  from mlflow import pyfunc
  from mlflow.models import Model, ModelInputExample, ModelSignature
  from mlflow.models.model import MLMODEL_FILE_NAME
  from mlflow.models.utils import _save_example
  from mlflow.tracking._model_registry import DEFAULT_AWAIT_MAX_SLEEP_SECONDS
  from mlflow.tracking.artifact_utils import _download_artifact_from_uri
  from mlflow.utils.docstring_utils import LOG_MODEL_PARAM_DOCS, format_docstring
  from mlflow.utils.environment import _CONDA_ENV_FILE_NAME, _CONSTRAINTS_FILE_NAME, _PYTHON_ENV_FILE_NAME, _REQUIREMENTS_FILE_NAME, _get_pip_deps, _mlflow_conda_env, _process_conda_env, _process_pip_requirements, _PythonEnv, _validate_env_arguments
  from mlflow.utils.file_utils import write_to
  from mlflow.utils.model_utils import _add_code_from_conf_to_system_path, _get_flavor_configuration, _validate_and_copy_code_paths, _validate_and_prepare_target_save_path
  from mlflow.utils.requirements_utils import _get_package_name
  from mlflow.utils.uri import append_to_uri_path
label_desc: Use image node_id 9 for calling a global function with example usage: log_explanation(predict_function, features, artifact_path) and returns: append_to_uri_path