class_docstr: Find outliers samples with respect to the given properties.
  
  The check computes several properties and then computes the number of outliers for each property.
  The check uses `IQR <https://en.wikipedia.org/wiki/Interquartile_range#Outliers>`_ to detect outliers out of the
  single dimension properties.
  
  Parameters
  ----------
  properties : List[Dict[str, Any]], default: None
      List of properties. Replaces the default deepchecks properties.
      Each property is a dictionary with keys ``'name'`` (str), ``method`` (Callable) and ``'output_type'`` (str),
      representing attributes of said method. 'output_type' must be one of:
  
      - ``'numerical'`` - for continuous ordinal outputs.
      - ``'categorical'`` - for discrete, non-ordinal outputs. These can still be numbers,
        but these numbers do not have inherent value.
      - ``'class_id'`` - for properties that return the class_id. This is used because these
        properties are later matched with the ``VisionData.label_map``, if one was given.
  
      For more on image / label properties, see the guide about :ref:`vision__properties_guide`.
  property_input_type : PropertiesInputType , default: PropertiesInputType.IMAGES
      The type of input to the properties, required for caching the results after first calculation.
  n_show_top : int , default: 3
      number of outliers to show from each direction (upper limit and bottom limit)
  iqr_percentiles : Tuple[int, int] , default: (25, 75)
      Two percentiles which define the IQR range
  iqr_scale : float, default : 1.5
      The scale to multiply the IQR range for the outliers detection
  draw_label_on_image : bool, default : True
      Whether to draw the label on the image displayed or not.
  min_samples : int , default: 10
      Minimum number of samples required to calculate IQR. If there are not enough non-null samples a specific
      property, the check will skip it. If all properties are skipped, the check will raise a NotEnoughSamplesError.
docstr: Compute final result.
docstr_tok: ["Compute","final","result","."]
code: def compute(
      self, context: Context, dataset_kind: DatasetKind
  ) -> CheckResult:
      """Compute final result."""
      data = context.get_data_by_kind(dataset_kind)
      check_result = {}
      self._images_uuid = np.asarray(self._images_uuid)
  
      if all(
          len(np.hstack(v).squeeze()) < self.min_samples
          for v in self._properties_results.values()
      ):
          raise NotEnoughSamplesError(
              f"Need at least {self.min_samples} non-null samples to calculate IQR outliers."
          )
  
      for name, values in self._properties_results.items():
          values_lengths_cumsum = np.cumsum(
              np.array([len(v) for v in values])
          )
  
          values_arr = np.hstack(values).astype(float).squeeze()
          values_arr = np.array(
              [x for x in values_arr if pd.notnull(x)]
          )
  
          if len(values_arr) < self.min_samples:
              check_result[
                  name
              ] = "Not enough non-null samples to calculate outliers."
              continue
  
          lower_limit, upper_limit = iqr_outliers_range(
              values_arr, self.iqr_percentiles, self.iqr_scale
          )
  
          outlier_values_idx = np.argwhere(
              (values_arr < lower_limit) | (values_arr > upper_limit)
          ).squeeze(axis=1)
          outlier_img_idx = np.unique(
              [
                  _sample_index_from_flatten_index(
                      values_lengths_cumsum, outlier_index
                  )
                  for outlier_index in outlier_values_idx
              ]
          )
          outlier_img_identifiers = (
              self._images_uuid[outlier_img_idx]
              if len(outlier_img_idx) > 0
              else []
          )
          check_result[name] = {
              "outliers_identifiers": outlier_img_identifiers,
              "lower_limit": max(lower_limit, min(values_arr)),
              "upper_limit": min(upper_limit, max(values_arr)),
          }
  
      # Create display
      if context.with_display:
          display = []
          no_outliers = pd.Series([], dtype="str")
          for property_name, info in check_result.items():
              # If info is string it means there was error
              if isinstance(info, str):
                  no_outliers = pd.concat(
                      [
                          no_outliers,
                          pd.Series(property_name, index=[info]),
                      ]
                  )
              elif len(info["outliers_identifiers"]) == 0:
                  no_outliers = pd.concat(
                      [
                          no_outliers,
                          pd.Series(
                              property_name,
                              index=["No outliers found."],
                          ),
                      ]
                  )
              else:
                  # Create id of alphabetic characters
                  images_and_values = self._get_property_outlier_images(
                      property_name,
                      info["lower_limit"],
                      info["upper_limit"],
                      data,
                  )
                  sid = "".join(
                      [choice(string.ascii_uppercase) for _ in range(6)]
                  )
                  values_combine = "".join(
                      [
                          f'<div class="{sid}-item">{format_number(x[0])}</div>'
                          for x in images_and_values
                      ]
                  )
                  images_combine = "".join(
                      [
                          f'<div class="{sid}-item">{x[1]}</div>'
                          for x in images_and_values
                      ]
                  )
  
                  html = HTML_TEMPLATE.format(
                      prop_name=property_name,
                      values=values_combine,
                      images=images_combine,
                      count=len(info["outliers_identifiers"]),
                      n_of_images=len(images_and_values),
                      lower_limit=format_number(info["lower_limit"]),
                      upper_limit=format_number(info["upper_limit"]),
                      id=sid,
                  )
  
                  display.append(html)
          display = ["".join(display)]
  
          if not no_outliers.empty:
              grouped = (
                  no_outliers.groupby(level=0).unique().str.join(", ")
              )
              grouped_df = pd.DataFrame(grouped, columns=["Properties"])
              grouped_df["More Info"] = grouped_df.index
              grouped_df = grouped_df[["More Info", "Properties"]]
              display.append(
                  "<h5><b>Properties With No Outliers Found</h5></b>"
              )
              display.append(hide_index_for_display(grouped_df))
  
      else:
          display = None
  
      return CheckResult(check_result, display=display)
  
imports: import string
  import typing
  import warnings
  from abc import abstractmethod
  from collections import defaultdict
  from numbers import Number
  from secrets import choice
  import numpy
  import pandas
  from deepchecks.core import CheckResult, DatasetKind
  from deepchecks.core.errors import DeepchecksProcessError, NotEnoughSamplesError
  from deepchecks.utils.dataframes import hide_index_for_display
  from deepchecks.utils.outliers import iqr_outliers_range
  from deepchecks.utils.strings import format_number
  from deepchecks.vision.base_checks import SingleDatasetCheck
  from deepchecks.vision.context import Context
  from deepchecks.vision.utils.image_functions import draw_image
  from deepchecks.vision.utils.vision_properties import PropertiesInputType
  from deepchecks.vision.vision_data import TaskType, VisionData
  from deepchecks.vision.vision_data.batch_wrapper import BatchWrapper
label_desc: Use image node_id 4 for calling the AbstractPropertyOutliers obj's underlying member method code with example usage: obj.compute(context, dataset_kind) and returns: CheckResult