code: def _plot_heatmap(
      feature,
      date,
      hc_list,
      top_n,
      cmap,
      hist_names,
      hist_names_formatted,
      descriptions,
  ):
      # basic checks
      if len(hist_names) <= 0:
          # skip numeric heatmap
          return {"plot": ""}
  
      # filter out Nones (e.g. can happen with empty rolling hist)
      none_hists = [i for i, hc in enumerate(hc_list) if hc is None]
      hc_list = [
          hc for i, hc in enumerate(hc_list) if i not in none_hists
      ]
      hist_names = [
          hn for i, hn in enumerate(hist_names) if i not in none_hists
      ]
      # more basic checks
      if len(hc_list) == 0:
          return date, ""
      assert_similar_hists(hc_list)
      if hc_list[0].n_dim == 1:
          props = get_hist_props(hc_list[0])
          is_num = props["is_num"]
          is_ts = props["is_ts"]
          y_label = (
              "Bin count" if len(hc_list) == 1 else "Bin probability"
          )
  
          if is_num:
              # skip numeric heatmap
              return {"plot": ""}
          else:
              # categorical, retrieve values and bins
              entries_list, bins = get_consistent_numpy_entries(
                  hc_list, get_bin_labels=True
              )  # bins = bin-labels
  
              entries_list = np.stack(entries_list, axis=1)
  
              # if cardinality of feature is more than 20
              if len(bins) > top_n:
                  entries_list, bins = get_top_categories(
                      entries_list, bins, top_n
                  )
  
              # make 3 copies : 1st normal, 2nd for column normalized heatmap, 3rd for row normalized heatmap
              hists = []
              if "heatmap" in hist_names:
                  hist_normal = entries_list.copy()
                  hists.append(hist_normal)
  
              # normalize across column for a plot
              if "heatmap_column_normalized" in hist_names:
                  hist_col = entries_list.copy()
                  hist_col = np.stack(hist_col, axis=1)
                  hist_col = hist_col.astype(float)
                  for i in range(hist_col.shape[0]):
                      if hist_col[i].sum() > 0:
                          hist_col[i] = hist_col[i] / hist_col[i].sum()
                  hist_col = np.stack(hist_col, axis=1)
                  hists.append(hist_col)
  
              # normalize across row for a plot
              if "heatmap_row_normalized" in hist_names:
                  hist_row = entries_list.copy()
                  hist_row = hist_row.astype(float)
                  for i in range(hist_row.shape[0]):
                      if hist_row[i].sum() > 0:
                          hist_row[i] = hist_row[i] / hist_row[i].sum()
  
                  hists.append(hist_row)
  
          if len(bins) == 0:
              # skip empty histograms
              return {"plot": ""}
  
          args = [
              (
                  hist,
                  bins,
                  date,
                  feature,
                  hist_name,
                  y_label,
                  is_num,
                  is_ts,
                  cmap,
              )
              for hist, hist_name in zip(hists, hist_names)
          ]
          heatmaps = parallel(plot_heatmap, args)
  
          if isinstance(heatmaps, list):
              plot = [
                  hist_lookup(heatmaps, hist_name)
                  for hist_name in hist_names
              ]
          elif isinstance(heatmaps, dict):
              plot = [heatmaps]
  
          plots = [
              {
                  "name": hist_names_formatted[hist_name],
                  "type": "heatmap",
                  "description": descriptions[hist_name],
                  "plot": pl["plot"],
                  "layout": pl["layout"],
                  "full_width": True,
              }
              for pl, hist_name in zip(plot, hist_names)
          ]
  
      elif hc_list[0].n_dim == 2:
          plots = {"plot": ""}
      else:
          plots = {"plot": ""}
  
      return plots
  
file_path: popmon/popmon/visualization/histogram_section.py
imports: from __future__ import annotations
  import numpy
  import pandas
  from histogrammar.util import get_hist_props
  from tqdm import tqdm
  from popmon.analysis.hist_numpy import assert_similar_hists, get_consistent_numpy_1dhists, get_consistent_numpy_entries
  from popmon.base import Module
  from popmon.config import HistogramSectionModel
  from popmon.utils import parallel, short_date
  from popmon.visualization.utils import histogram_basic_checks, plot_heatmap, plot_histogram_overlay
label_desc: Use image node_id 2 for calling a global function with example usage: _plot_heatmap(feature, date, hc_list, top_n, cmap, hist_names, hist_names_formatted, descriptions) and returns: plots, dict, date,  str, dict, dict