docstr: Constructs data profiles of predictions and errors and a step card instance corresponding
  to the current evaluate step state.
  
  :param run_id: The ID of the MLflow Run to which to log model evaluation results.
  :param model_uri: The URI of the model being evaluated.
  :param eval_metrics: the evaluation result keyed by dataset name from `mlflow.evaluate`.
  :param validation_results: a list of `MetricValidationResult` instances
  :param output_directory: output directory used by the evaluate step.
docstr_tok: ["Constructs","data","profiles","of","predictions","and","errors","and","a","step","card","instance","corresponding","to","the","current","evaluate","step","state",".",":","param","run_id",":","The","ID","of","the","MLflow","Run","to","which","to","log","model","evaluation","results",".",":","param","model_uri",":","The","URI","of","the","model","being","evaluated",".",":","param","eval_metrics",":","the","evaluation","result","keyed","by","dataset","name","from","`","mlflow.evaluate","`",".",":","param","validation_results",":","a","list","of","`","MetricValidationResult","`","instances",":","param","output_directory",":","output","directory","used","by","the","evaluate","step","."]
code: def _build_profiles_and_card(
      self,
      run_id,
      model_uri,
      eval_metrics,
      validation_results,
      output_directory,
  ):
      """
      Constructs data profiles of predictions and errors and a step card instance corresponding
      to the current evaluate step state.
  
      :param run_id: The ID of the MLflow Run to which to log model evaluation results.
      :param model_uri: The URI of the model being evaluated.
      :param eval_metrics: the evaluation result keyed by dataset name from `mlflow.evaluate`.
      :param validation_results: a list of `MetricValidationResult` instances
      :param output_directory: output directory used by the evaluate step.
      """
      import pandas as pd
  
      # Build card
      card = BaseCard(self.recipe_name, self.name)
      # Tab 0: model performance summary.
      metric_df = (
          get_merged_eval_metrics(
              eval_metrics,
              ordered_metric_names=[
                  self.primary_metric,
                  *self.user_defined_custom_metrics,
              ],
          )
          .reset_index()
          .rename(columns={"index": "Metric"})
      )
  
      def row_style(row):
          if (
              row.Metric == self.primary_metric
              or row.Metric in self.user_defined_custom_metrics
          ):
              return pd.Series("font-weight: bold", row.index)
          else:
              return pd.Series("", row.index)
  
      metric_table_html = BaseCard.render_table(
          metric_df.style.format(
              {"training": "{:.6g}", "validation": "{:.6g}"}
          ).apply(row_style, axis=1)
      )
  
      card.add_tab(
          "Model Performance (Test)",
          "<h3 class='section-title'>Summary Metrics</h3>"
          "<b>NOTE</b>: Use evaluation metrics over test dataset with care. "
          "Fine-tuning model over the test dataset is not advised."
          "{{ METRICS }} ",
      ).add_html("METRICS", metric_table_html)
  
      # Tab 1: model validation results, if exists.
      if validation_results is not None:
  
          def get_icon(validated):
              return (
                  # check mark button emoji
                  "\u2705"
                  if validated
                  # cross mark emoji
                  else "\u274c"
              )
  
          result_df = pd.DataFrame(validation_results).assign(
              validated=lambda df: df["validated"].map(get_icon)
          )
  
          criteria_html = BaseCard.render_table(
              result_df.style.format(
                  {"value": "{:.6g}", "threshold": "{:.6g}"}
              )
          )
          card.add_tab(
              "Model Validation", "{{ METRIC_VALIDATION_RESULTS }}"
          ).add_html(
              "METRIC_VALIDATION_RESULTS",
              "<h3 class='section-title'>Model Validation Results (Test Dataset)</h3> "
              + criteria_html,
          )
  
      # Tab 2: Classifier plots.
      if self.recipe == "classification/v1":
          classifiers_plot_tab = card.add_tab(
              "Model Performance Plots",
              "{{ CONFUSION_MATRIX }} {{CONFUSION_MATRIX_PLOT}}"
              + "{{ LIFT_CURVE }} {{LIFT_CURVE_PLOT}}"
              + "{{ PR_CURVE }} {{PR_CURVE_PLOT}}"
              + "{{ ROC_CURVE }} {{ROC_CURVE_PLOT}}",
          )
          confusion_matrix_path = os.path.join(
              output_directory,
              "eval_validation/artifacts",
              f"{_VALIDATION_METRIC_PREFIX}confusion_matrix.png",
          )
          if os.path.exists(confusion_matrix_path):
              classifiers_plot_tab.add_html(
                  "CONFUSION_MATRIX",
                  '<h3 class="section-title">Confusion Matrix Plot</h3>',
              )
              classifiers_plot_tab.add_image(
                  "CONFUSION_MATRIX_PLOT",
                  confusion_matrix_path,
                  width=400,
              )
  
          lift_curve_path = os.path.join(
              output_directory,
              "eval_validation/artifacts",
              f"{_VALIDATION_METRIC_PREFIX}lift_curve_plot.png",
          )
          if os.path.exists(lift_curve_path):
              classifiers_plot_tab.add_html(
                  "LIFT_CURVE",
                  '<h3 class="section-title">Lift Curve Plot</h3>',
              )
              classifiers_plot_tab.add_image(
                  "LIFT_CURVE_PLOT", lift_curve_path, width=400
              )
  
          pr_curve_path = os.path.join(
              output_directory,
              "eval_validation/artifacts",
              f"{_VALIDATION_METRIC_PREFIX}precision_recall_curve_plot.png",
          )
          if os.path.exists(pr_curve_path):
              classifiers_plot_tab.add_html(
                  "PR_CURVE",
                  '<h3 class="section-title">Precision Recall Curve Plot</h3>',
              )
              classifiers_plot_tab.add_image(
                  "PR_CURVE_PLOT", pr_curve_path, width=400
              )
  
          roc_curve_path = os.path.join(
              output_directory,
              "eval_validation/artifacts",
              f"{_VALIDATION_METRIC_PREFIX}roc_curve_plot.png",
          )
          if os.path.exists(roc_curve_path):
              classifiers_plot_tab.add_html(
                  "ROC_CURVE",
                  '<h3 class="section-title">ROC Curve Plot</h3>',
              )
              classifiers_plot_tab.add_image(
                  "ROC_CURVE_PLOT", roc_curve_path, width=400
              )
  
      # Tab 3: SHAP plots.
      def _add_shap_plots(card):
          """Contingent on shap being installed."""
          shap_plot_tab = card.add_tab(
              "Feature Importance",
              '<h3 class="section-title">Feature Importance on Validation Dataset</h3>'
              '<h3 class="section-title">SHAP Bar Plot</h3>{{SHAP_BAR_PLOT}}'
              '<h3 class="section-title">SHAP Beeswarm Plot</h3>{{SHAP_BEESWARM_PLOT}}',
          )
  
          shap_bar_plot_path = os.path.join(
              output_directory,
              "eval_validation/artifacts",
              f"{_VALIDATION_METRIC_PREFIX}shap_feature_importance_plot.png",
          )
          shap_beeswarm_plot_path = os.path.join(
              output_directory,
              "eval_validation/artifacts",
              f"{_VALIDATION_METRIC_PREFIX}shap_beeswarm_plot.png",
          )
          shap_plot_tab.add_image(
              "SHAP_BAR_PLOT", shap_bar_plot_path, width=800
          )
          shap_plot_tab.add_image(
              "SHAP_BEESWARM_PLOT", shap_beeswarm_plot_path, width=800
          )
  
      try:
          import shap  # noqa: F401
          from matplotlib import pyplot  # noqa: F401
  
          _add_shap_plots(card)
      except ImportError:
          _logger.warning(
              "SHAP or matplotlib package is not installed, so shap plots will not be added."
          )
  
      # Tab 3: Warning log outputs.
      warning_output_path = os.path.join(
          output_directory, "warning_logs.txt"
      )
      if os.path.exists(warning_output_path):
          warnings_output_tab = card.add_tab(
              "Warning Logs", "{{ STEP_WARNINGS }}"
          )
          with open(warning_output_path) as f:
              warnings_output_tab.add_html(
                  "STEP_WARNINGS", f"<pre>{f.read()}</pre>"
              )
  
      # Tab 4: Run summary.
      run_summary_card_tab = card.add_tab(
          "Run Summary",
          "{{ RUN_ID }} "
          + "{{ MODEL_URI }}"
          + "{{ VALIDATION_STATUS }}"
          + "{{ EXE_DURATION }}"
          + "{{ LAST_UPDATE_TIME }}",
      ).add_markdown(
          "VALIDATION_STATUS",
          f"**Validation status:** `{self.model_validation_status}`",
      )
      run_url = get_databricks_run_url(
          tracking_uri=mlflow.get_tracking_uri(),
          run_id=run_id,
      )
      model_uri = f"runs:/{run_id}/train/{TrainStep.MODEL_ARTIFACT_RELATIVE_PATH}"
      model_url = get_databricks_run_url(
          tracking_uri=mlflow.get_tracking_uri(),
          run_id=run_id,
          artifact_path=f"train/{TrainStep.MODEL_ARTIFACT_RELATIVE_PATH}",
      )
  
      if run_url is not None:
          run_summary_card_tab.add_html(
              "RUN_ID",
              f"<b>MLflow Run ID:</b> <a href={run_url}>{run_id}</a><br><br>",
          )
      else:
          run_summary_card_tab.add_markdown(
              "RUN_ID", f"**MLflow Run ID:** `{run_id}`"
          )
  
      if model_url is not None:
          run_summary_card_tab.add_html(
              "MODEL_URI",
              f"<b>MLflow Model URI:</b> <a href={model_url}>{model_uri}</a>",
          )
      else:
          run_summary_card_tab.add_markdown(
              "MODEL_URI", f"**MLflow Model URI:** `{model_uri}`"
          )
  
      return card
  
imports: import datetime
  import logging
  import operator
  import os
  import sys
  import warnings
  from collections import namedtuple
  from pathlib import Path
  from typing import Any, Dict
  import mlflow
  from mlflow.exceptions import MlflowException
  from mlflow.protos.databricks_pb2 import INVALID_PARAMETER_VALUE
  from mlflow.recipes.cards import BaseCard
  from mlflow.recipes.step import BaseStep, StepClass
  from mlflow.recipes.steps.train import TrainStep
  from mlflow.recipes.utils.execution import get_step_output_path
  from mlflow.recipes.utils.metrics import _get_builtin_metrics, _get_custom_metrics, _get_extended_task, _get_model_type_from_template, _get_primary_metric, _load_custom_metrics, transform_multiclass_metric
  from mlflow.recipes.utils.step import get_merged_eval_metrics, validate_classification_config
  from mlflow.recipes.utils.tracking import TrackingConfig, apply_recipe_tracking_config, get_recipe_tracking_config, get_run_tags_env_vars
  from mlflow.tracking.fluent import _get_experiment_id, _set_experiment_primary_metric
  from mlflow.utils.databricks_utils import get_databricks_env_vars, get_databricks_run_url
  from mlflow.utils.string_utils import strip_prefix
label_desc: Use image node_id 7 for calling the EvaluateStep obj's underlying member method code with example usage: obj._build_profiles_and_card(run_id, model_uri, eval_metrics, validation_results, output_directory) and returns: card, pd, pd, unknown