code: def get_adjusted_cluster_centers(
      clusters,
      n_required_clusters,
      find_center_clusters_method,
      **kwargs,
  ):
      """
      From a dict containing clusters per page, find the cluster centers and apply some adjustments to them
      (filter bad values, interpolate missing values).
  
      Return the adjusted cluster centers in a dict with page number -> cluster center mapping.
  
      If parameter <return_center_clusters_diffsums> is True, additionally return a dict with summed differences between
      found centers and "model" centers as quality measure.
      <n_required_clusters> is the number of cluster centers (i.e. number of columns or lines) to be found.
      <find_center_clusters_method> is the clustering method to cluster aligned ("normalized") centers (<kwargs> will
      be passed to this function).
      <image_scaling> is an optional parameter: dict with page number -> <scaling> mapping with which the
      final centers for each page are calculated by <center> / <scaling>.
      <arr_matching_same_size_use_model_arr_diff_thresh> is an optional parameter. During cluster array matching,
      this parameter defines the array difference threshold, upon which the averaged "model array" (e.g. model clusters)
      is used instead of the detected cluster array, because the detected clusters do not fit to the model clusters.
      """
      return_center_clusters_diffsums = kwargs.pop(
          "return_center_clusters_diffsums", False
      )
      image_scaling = kwargs.pop("image_scaling", None)
      same_size_use_model_arr_diff_thresh = kwargs.pop(
          "arr_matching_same_size_use_model_arr_diff_thresh", None
      )
  
      # 1. Align the cluster centers so that they all start with 0 and create a flat list that contains all centers
      all_clusters_centers = {}
      for p_num, clusters_w_vals in clusters.items():
          all_clusters_centers[p_num] = calc_cluster_centers_1d(
              clusters_w_vals
          )
  
      centers_norm = []
      for p_num, centers in all_clusters_centers.items():
          centers = np.array(centers)
          centers_norm.extend(centers - centers[0])
  
      centers_norm = np.array(centers_norm)
  
      # 2. Clustering second pass: Cluster aligned ("normalized") centers and filter them
      centers_norm_clusters_ind = find_center_clusters_method(
          centers_norm, **kwargs
      )
      centers_norm_clusters = zip_clusters_and_values(
          centers_norm_clusters_ind, centers_norm
      )
  
      if len(centers_norm_clusters) < n_required_clusters:
          logger.warning(
              "Number of found clusters is smaller than number of required clusters `n_required_clusters`. "
              "Try to decrease break distance or adapt other clustering parameters."
          )
          center_norm_medians = np.array(
              sorted(
                  [np.median(vals) for _, vals in centers_norm_clusters]
              )
          )
      else:
          # Filter clusters: take only clusters with at least <min_n_values> inside. Decrease this value on each iteration.
          center_norm_medians = []
          min_n_startval = max(map(len, centers_norm_clusters_ind))
          for min_n_values in range(min_n_startval, 0, -1):
              clust_ids_to_remove = []
              for i, (_, vals) in enumerate(centers_norm_clusters):
                  val_median = np.median(vals)
                  if (
                      len(vals) >= min_n_values
                      and val_median not in center_norm_medians
                  ):
                      center_norm_medians.append(val_median)
                      clust_ids_to_remove.append(i)
  
                  if len(center_norm_medians) == n_required_clusters:
                      break
              else:
                  centers_norm_clusters = [
                      c
                      for i, c in enumerate(centers_norm_clusters)
                      if i not in clust_ids_to_remove
                  ]
                  continue
              break
  
          assert len(center_norm_medians) == n_required_clusters
  
          center_norm_medians = np.array(sorted(center_norm_medians))
  
      # 3. Adjust the cluster centers by finding the best matching array to <center_norm_medians> if sizes differ
      adjusted_centers = {}
      diffsums = {} if return_center_clusters_diffsums else None
      for p_num, centers in all_clusters_centers.items():
          centers = np.array(centers)
          corrected_centers, diffsum = find_best_matching_array(
              centers,
              center_norm_medians,
              same_size_use_model_arr_diff_thresh=same_size_use_model_arr_diff_thresh,
          )
          # print(p_num, diffsum)
          # print(list((center_norm_medians + centers[0]) / image_scaling[p_num]))
          # print(list((centers_norm + centers[0]) / image_scaling[p_num]))
          # print()
  
          if image_scaling is not None:
              scaling_for_page = image_scaling[p_num]
              corrected_centers /= scaling_for_page
  
          adjusted_centers[p_num] = corrected_centers
          if return_center_clusters_diffsums:
              diffsums[p_num] = diffsum
  
      if return_center_clusters_diffsums:
          return adjusted_centers, diffsums
      else:
          return adjusted_centers
  
file_path: pdftabextract/pdftabextract/clustering.py
imports: import itertools
  import numpy
  from scipy.stats import chisquare
  from pdftabextract import logger
  from pdftabextract.common import fill_array_a_with_values_from_b, sorted_by_attr, flatten_list, update_text_dict_dim, DIRECTION_HORIZONTAL, DIRECTION_VERTICAL
label_desc: Use image node_id 3 for calling a global function with example usage: get_adjusted_cluster_centers(clusters, n_required_clusters, find_center_clusters_method) and returns: adjusted_centers,  diffsums, adjusted_centers