code: def generic_box_plot_loop(
      cmaps: List[str],
      target_uncert_dicts: Dict[str, List[List[float]]],
      uncertainty_types_list: List[List[str]],
      models: List[str],
      x_axis_labels: List[str],
      x_label: str,
      y_label: str,
      num_bins: int,
      list_comp_bool: bool,
      width: float,
      y_lim_min: float,
      font_size_1: int,
      font_size_2: int,
      show_sample_info: str = "None",
      save_path: Optional[str] = None,
      y_lim: int = 120,
      convert_to_percent: bool = True,
      to_log: bool = False,
      show_individual_dots: bool = True,
  ) -> None:
      """
      This function generates box plots for multiple types of data coming from various models. It is highly customizable
      and can handle different specifications for plot attributes.
  
      Customizations include:
  
      1. Color specification: User can provide a list of color specifications for each box plot using `cmaps` parameter.
      2. Axis labels: The x and y axis labels can be customized using `x_label` and `y_label` parameters.
      3. Box width: The width of each box plot can be adjusted using `width` parameter.
      4. Font sizes: Two different font sizes can be used in the plot, adjustable by `font_size_1` and `font_size_2`.
      5. Limits of y-axis: The upper and lower limits of the y-axis can be set using `y_lim` and `y_lim_min` parameters.
      6. Logarithmic scale: If `to_log` is set to True, the y-axis will be in logarithmic scale.
      7. Display of individual data points: The user can choose to display individual data points in each box plot
         by setting `show_individual_dots` to True.
      8. Data transformation: The data can be transformed to percentages using `convert_to_percent` parameter.
      9. Display of sample information: The user can choose to display information about the number of samples in each
         box plot by setting `show_sample_info` to "None", "All", or "Average".
  
      The function creates box plots for each combination of model and uncertainty type. It can save the resulting plot
      to a specified location.
  
  
  
      Args:
          cmaps (List[str]): Colors for the box plots.
          target_uncert_dicts (Dict[str, List[List[float]]]): Dictionary with lists of [error, uncertainty values] for all targets
            and corresponding data.
          uncertainty_types_list (List[List[str]]): List of lists containing uncertainty types.
          models (List[str]): List of models for which box plots are being made.
          x_axis_labels (List[str]): Labels for the x-axis.
          x_label (str): The label for the x-axis.
          y_label (str): The label for the y-axis.
          num_bins (int): The number of bins to be used for the box plot.
          list_comp_bool (bool): Flag to determine if list comprehension should be used.
          width (float): The width of the boxes in the box plot.
          y_lim_min (float): The minimum limit for the y-axis.
          font_size_1 (int): Font size for the first element.
          font_size_2 (int): Font size for the second element.
          show_sample_info (str): Information about the samples to be displayed. Default is "None".
          save_path (Optional[str]): The path where the plot will be saved. If None, the plot won't be saved. Default is None.
          y_lim (int): The maximum limit for the y-axis. Default is 120.
          convert_to_percent (bool): Flag to determine if data should be converted to percentages. Default is True.
          to_log (bool): Flag to determine if a logarithmic scale should be used. Default is False.
          show_individual_dots (bool): Flag to determine if individual data points should be shown. Default is True.
  
      Returns:
          None. The function displays and/or saves a plot.
      """
      hatch_type = "o"
  
      plt.style.use("fivethirtyeight")
  
      orders = []
      ax = plt.gca()
      ax.xaxis.grid(False)
  
      bin_label_locs: List[float] = []
      all_rects = []
      outer_min_x_loc = 0.0
      middle_min_x_loc = 0.0
      inner_min_x_loc = 0.0
  
      circ_patches = []
      max_bin_height = 0.0
  
      all_sample_label_x_locs = []
      all_sample_percs = []
  
      for i, (uncert_pair) in enumerate(uncertainty_types_list):
          uncertainty_type = (uncert_pair)[0]
  
          for j in range(num_bins):
              inbetween_locs = []
              average_samples_per_bin = []
  
              for hash_idx, model_type in enumerate(models):
                  if j == 0:
                      if hash_idx == 1:
                          circ11 = patches.Patch(
                              facecolor=cmaps[i],
                              label=model_type + " " + uncertainty_type,
                              hatch=hatch_type,
                              edgecolor="black",
                          )
                      else:
                          circ11 = patches.Patch(
                              facecolor=cmaps[i],
                              label=model_type + " " + uncertainty_type,
                          )
                      circ_patches.append(circ11)
  
                  dict_key = [
                      x
                      for x in list(target_uncert_dicts.keys())
                      if (model_type in x) and (uncertainty_type in x)
                  ][0]
                  model_data = target_uncert_dicts[dict_key]
  
                  if list_comp_bool:
                      all_b_data = [
                          x for x in model_data[j] if x is not None
                      ]
                  else:
                      all_b_data = model_data[j]
  
                  orders.append(model_type + uncertainty_type)
  
                  x_loc = [
                      (
                          outer_min_x_loc
                          + inner_min_x_loc
                          + middle_min_x_loc
                      )
                  ]
                  inbetween_locs.append(x_loc[0])
  
                  # Turn data to percentages
                  if convert_to_percent:
                      displayed_data = [(x) * 100 for x in all_b_data]
                  else:
                      displayed_data = all_b_data
                  rect = ax.boxplot(
                      displayed_data,
                      positions=x_loc,
                      sym="",
                      widths=width,
                      showmeans=True,
                      patch_artist=True,
                  )
  
                  if show_individual_dots:
                      # Add some random "jitter" to the x-axis
                      x = np.random.normal(
                          x_loc, 0.01, size=len(displayed_data)
                      )
                      ax.plot(
                          x,
                          displayed_data,
                          color=cmaps[len(uncertainty_types_list)],
                          marker=".",
                          linestyle="None",
                          alpha=0.75,
                      )
  
                  # Set color, pattern, median line and mean marker.
                  for r in rect["boxes"]:
                      r.set(color="black", linewidth=1)
                      r.set(facecolor=cmaps[i])
  
                      if hash_idx == 1:
                          r.set_hatch(hatch_type)
  
                  for median in rect["medians"]:
                      median.set(color="crimson", linewidth=3)
  
                  for mean in rect["means"]:
                      mean.set(
                          markerfacecolor="crimson",
                          markeredgecolor="black",
                          markersize=10,
                      )
  
                  max_bin_height = max(
                      max(rect["caps"][-1].get_ydata()), max_bin_height
                  )
  
                  """If we are showing sample statistics, keep track of it and display after on top of biggest whisker."""
                  if show_sample_info != "None":
                      flattened_model_data = [
                          x for xss in model_data for x in xss
                      ]
                      percent_size = np.round(
                          len(all_b_data)
                          / len(flattened_model_data)
                          * 100,
                          1,
                      )
                      average_samples_per_bin.append(percent_size)
  
                      if show_sample_info == "All":
                          """This adds the number of samples on top of the top whisker"""
                          (x_l, y), (x_r, _) = rect["caps"][
                              -1
                          ].get_xydata()
                          x_line_center = (x_l + x_r) / 2
                          all_sample_label_x_locs.append(x_line_center)
                          all_sample_percs.append(percent_size)
                  all_rects.append(rect)
  
                  inner_min_x_loc += 0.1 + width
  
              """ Keep track of average sample statistics. Plot at the END so we know what the max height for all Qs are."""
              if show_sample_info == "Average":
                  middle_x = np.mean(inbetween_locs)
                  mean_perc = np.round(
                      np.mean(average_samples_per_bin), 1
                  )
                  std_perc = np.round(
                      np.std(average_samples_per_bin), 1
                  )
                  all_sample_label_x_locs.append(middle_x)
                  all_sample_percs.append([mean_perc, std_perc])
  
              if list_comp_bool:
                  bin_label_locs = bin_label_locs + inbetween_locs
              else:
                  bin_label_locs.append(np.mean(inbetween_locs))
  
              middle_min_x_loc += 0.02
  
          # If lots of bins we must make the gap between plots bigger to prevent overlapping x-tick labels.
          if list_comp_bool:
              if num_bins > 9:
                  middle_min_x_loc += 0.25
              else:
                  middle_min_x_loc += 0.12
          else:
              if num_bins > 10:
                  outer_min_x_loc += 0.35
              else:
                  outer_min_x_loc += 0.25
  
      format_plot(
          ax,
          save_path,
          show_sample_info,
          to_log,
          circ_patches,
          y_lim,
          y_lim_min,
          convert_to_percent,
          x_label,
          y_label,
          font_size_1,
          font_size_2,
          bin_label_locs,
          x_axis_labels,
          num_bins,
          uncertainty_types_list,
          all_sample_percs,
          all_sample_label_x_locs,
          max_bin_height,
      )
  
imports: import logging
  import math
  import os
  from typing import Any, Dict, List, Optional, Tuple, Union
  import matplotlib.lines
  import matplotlib.patches
  import matplotlib.pyplot
  import matplotlib.ticker
  import numpy
  import pandas
  import pwlf
  from matplotlib.ticker import ScalarFormatter
  from scipy import stats
  from sklearn.isotonic import IsotonicRegression
  from kale.evaluate.similarity_metrics import evaluate_correlations
  from kale.evaluate.uncertainty_metrics import evaluate_bounds, evaluate_jaccard, get_mean_errors
  from kale.prepdata.tabular_transform import generate_struct_for_qbin
  from kale.utils.save_xlsx import generate_summary_df
label_desc: Use image node_id 3 for calling a global function with example usage: generic_box_plot_loop(cmaps, target_uncert_dicts, uncertainty_types_list, models, x_axis_labels, x_label, y_label, num_bins, list_comp_bool, width, y_lim_min, font_size_1, font_size_2, show_sample_info, save_path, y_lim, convert_to_percent, to_log, show_individual_dots) without return types