code: def heatmap(shap_values):
      # constants
  
      TREE_NODE_KEY_TOKENS = "tokens"
      TREE_NODE_KEY_CHILDREN = "children"
  
      uuid = "".join(random.choices(string.ascii_lowercase, k=20))
  
      def get_color(shap_value, cmax):
          scaled_value = 0.5 + 0.5 * shap_value / cmax
          color = colors.red_transparent_blue(scaled_value)
          color = (
              color[0] * 255,
              color[1] * 255,
              color[2] * 255,
              color[3],
          )
          return color
  
      def process_text_to_text_shap_values(shap_values):
          processed_values = []
  
          (
              unpacked_values,
              clustering,
          ) = unpack_shap_explanation_contents(shap_values)
          max_val = 0
  
          for index, output_token in enumerate(
              shap_values.output_names
          ):
              (
                  tokens,
                  values,
                  group_sizes,
                  token_id_to_node_id_mapping,
                  collapsed_node_ids,
              ) = process_shap_values(
                  shap_values.data,
                  unpacked_values[:, index],
                  1,
                  "",
                  clustering,
                  True,
              )
              processed_value = {
                  "tokens": tokens,
                  "values": values,
                  "group_sizes": group_sizes,
                  "token_id_to_node_id_mapping": token_id_to_node_id_mapping,
                  "collapsed_node_ids": collapsed_node_ids,
              }
  
              processed_values.append(processed_value)
              max_val = max(max_val, np.max(values))
  
          return processed_values, max_val
  
      # unpack input tokens and output tokens
      model_input = shap_values.data
      model_output = shap_values.output_names
  
      processed_values, max_val = process_text_to_text_shap_values(
          shap_values
      )
  
      # generate dictionary containing precomputed background colors and shap values which are addressable by html token ids
      colors_dict = {}
      shap_values_dict = {}
      token_id_to_node_id_mapping = {}
      cmax = max(
          abs(shap_values.values.min()),
          abs(shap_values.values.max()),
          max_val,
      )
  
      # input token -> output token color and label value mapping
  
      for row_index in range(len(model_input)):
          color_values = {}
          shap_values_list = {}
  
          for col_index in range(len(model_output)):
              color_values[
                  uuid + "_output_flat_token_" + str(col_index)
              ] = "rgba" + str(
                  get_color(
                      shap_values.values[row_index][col_index], cmax
                  )
              )
              shap_values_list[
                  uuid + "_output_flat_value_label_" + str(col_index)
              ] = round(shap_values.values[row_index][col_index], 3)
  
          colors_dict[
              f"{uuid}_input_node_{row_index}_content"
          ] = color_values
          shap_values_dict[
              f"{uuid}_input_node_{row_index}_content"
          ] = shap_values_list
  
      # output token -> input token color and label value mapping
  
      for col_index in range(len(model_output)):
          color_values = {}
          shap_values_list = {}
  
          for row_index in range(
              processed_values[col_index]["collapsed_node_ids"].shape[0]
          ):
              color_values[
                  uuid
                  + "_input_node_"
                  + str(
                      processed_values[col_index]["collapsed_node_ids"][
                          row_index
                      ]
                  )
                  + "_content"
              ] = "rgba" + str(
                  get_color(
                      processed_values[col_index]["values"][row_index],
                      cmax,
                  )
              )
              shap_label_value_str = str(
                  round(
                      processed_values[col_index]["values"][row_index],
                      3,
                  )
              )
              if (
                  processed_values[col_index]["group_sizes"][row_index]
                  > 1
              ):
                  shap_label_value_str += "/" + str(
                      processed_values[col_index]["group_sizes"][
                          row_index
                      ]
                  )
  
              shap_values_list[
                  uuid
                  + "_input_node_"
                  + str(
                      processed_values[col_index]["collapsed_node_ids"][
                          row_index
                      ]
                  )
                  + "_label"
              ] = shap_label_value_str
  
          colors_dict[
              uuid + "_output_flat_token_" + str(col_index)
          ] = color_values
          shap_values_dict[
              uuid + "_output_flat_token_" + str(col_index)
          ] = shap_values_list
  
          token_id_to_node_id_mapping_dict = {}
  
          for index, node_id in enumerate(
              processed_values[col_index][
                  "token_id_to_node_id_mapping"
              ].tolist()
          ):
              token_id_to_node_id_mapping_dict[
                  f"{uuid}_input_node_{index}_content"
              ] = f"{uuid}_input_node_{int(node_id)}_content"
  
          token_id_to_node_id_mapping[
              uuid + "_output_flat_token_" + str(col_index)
          ] = token_id_to_node_id_mapping_dict
  
      # convert python dictionary into json to be inserted into the runtime javascript environment
      colors_json = json.dumps(colors_dict)
      shap_values_json = json.dumps(shap_values_dict)
      token_id_to_node_id_mapping_json = json.dumps(
          token_id_to_node_id_mapping
      )
  
      javascript_values = (
          "<script> "
          + f"colors_{uuid} = "
          + colors_json
          + "\n"
          + f" shap_values_{uuid} = "
          + shap_values_json
          + "\n"
          + f" token_id_to_node_id_mapping_{uuid} = "
          + token_id_to_node_id_mapping_json
          + "\n"
          + "</script> \n "
      )
  
      def generate_tree(shap_values):
          num_tokens = len(shap_values.data)
          token_list = {}
  
          for index in range(num_tokens):
              node_content = {}
              node_content[TREE_NODE_KEY_TOKENS] = shap_values.data[
                  index
              ]
              node_content[TREE_NODE_KEY_CHILDREN] = {}
              token_list[str(index)] = node_content
  
          counter = num_tokens
          for pair in shap_values.clustering:
              first_node = str(int(pair[0]))
              second_node = str(int(pair[1]))
  
              new_node_content = {}
              new_node_content[TREE_NODE_KEY_CHILDREN] = {
                  first_node: token_list[first_node],
                  second_node: token_list[second_node],
              }
  
              token_list[str(counter)] = new_node_content
              counter += 1
  
              del token_list[first_node]
              del token_list[second_node]
  
          return token_list
  
      tree = generate_tree(shap_values)
  
      # generates the input token html elements
      # each element contains the label value (initially hidden) and the token text
  
      input_text_html = ""
  
      def populate_input_tree(
          input_index, token_list_subtree, input_text_html
      ):
          content = token_list_subtree[input_index]
          input_text_html += f'<div id="{uuid}_input_node_{input_index}_container" style="display:inline;text-align:center">'
  
          input_text_html += f'<div id="{uuid}_input_node_{input_index}_label" style="display:none; padding-top: 0px; font-size:12px;">'
  
          input_text_html += "</div>"
  
          if token_list_subtree[input_index][TREE_NODE_KEY_CHILDREN]:
              input_text_html += f'<div id="{uuid}_input_node_{input_index}_content" style="display:inline;">'
              for child_index, child_content in token_list_subtree[
                  input_index
              ][TREE_NODE_KEY_CHILDREN].items():
                  input_text_html = populate_input_tree(
                      child_index,
                      token_list_subtree[input_index][
                          TREE_NODE_KEY_CHILDREN
                      ],
                      input_text_html,
                  )
              input_text_html += "</div>"
          else:
              input_text_html += (
                  f'<div id="{uuid}_input_node_{input_index}_content"'
                  + "style='display: inline; background:transparent; border-radius: 3px; padding: 0px;cursor: default;cursor: pointer;'"
                  + f'onmouseover="onMouseHoverFlat_{uuid}(this.id)" '
                  + f'onmouseout="onMouseOutFlat_{uuid}(this.id)" '
                  + f'onclick="onMouseClickFlat_{uuid}(this.id)" '
                  + ">"
              )
              input_text_html += (
                  content[TREE_NODE_KEY_TOKENS]
                  .replace("<", "&lt;")
                  .replace(">", "&gt;")
                  .replace(" ##", "")
                  .replace("▁", "")
                  .replace("Ġ", "")
              )
              input_text_html += "</div>"
  
          input_text_html += "</div>"
  
          return input_text_html
  
      input_text_html = populate_input_tree(
          list(tree.keys())[0], tree, input_text_html
      )
  
      # generates the output token html elements
      output_text_html = ""
  
      for i in range(len(model_output)):
          output_text_html += (
              "<div style='display:inline; text-align:center;'>"
              + f"<div id='{uuid}_output_flat_value_label_"
              + str(i)
              + "'"
              + "style='display:none;color: #999; padding-top: 0px; font-size:12px;'>"
              + "</div>"
              + f"<div id='{uuid}_output_flat_token_"
              + str(i)
              + "'"
              + "style='display: inline; background:transparent; border-radius: 3px; padding: 0px;cursor: default;cursor: pointer;'"
              + f'onmouseover="onMouseHoverFlat_{uuid}(this.id)" '
              + f'onmouseout="onMouseOutFlat_{uuid}(this.id)" '
              + f'onclick="onMouseClickFlat_{uuid}(this.id)" '
              + ">"
              + model_output[i]
              .replace("<", "&lt;")
              .replace(">", "&gt;")
              .replace(" ##", "")
              .replace("▁", "")
              .replace("Ġ", "")
              + " </div>"
              + "</div>"
          )
  
      heatmap_html = f"""
          <div id="{uuid}_heatmap" class="{uuid}_viz_content">
            <div id="{uuid}_heatmap_header" style="padding:15px;margin:5px;font-family:sans-serif;font-weight:bold;">
              <div style="display:inline">
                <span style="font-size: 20px;"> Input/Output - Heatmap </span>
              </div>
              <div style="display:inline;float:right">
                Layout :
                <select name="alignment" id="{uuid}_alignment" onchange="selectAlignment_{uuid}(this)">
                  <option value="left-right" selected="selected">Left/Right</option>
                  <option value="top-bottom">Top/Bottom</option>
                </select>
              </div>
            </div>
            <div id="{uuid}_heatmap_content" style="display:flex;">
              <div id="{uuid}_input_container" style="padding:15px;border-style:solid;margin:5px;flex:1;">
                <div id="{uuid}_input_header" style="margin:5px;font-weight:bold;font-family:sans-serif;margin-bottom:10px">
                  Input Text
                </div>
                <div id="{uuid}_input_content" style="margin:5px;font-family:sans-serif;">
                    {input_text_html}
                </div>
              </div>
              <div id="{uuid}_output_container" style="padding:15px;border-style:solid;margin:5px;flex:1;">
                <div id="{uuid}_output_header" style="margin:5px;font-weight:bold;font-family:sans-serif;margin-bottom:10px">
                  Output Text
                </div>
                <div id="{uuid}_output_content" style="margin:5px;font-family:sans-serif;">
                    {output_text_html}
                </div>
              </div>
            </div>
          </div>
      """
  
      heatmap_javascript = f"""
          <script>
              function selectAlignment_{uuid}(selectObject) {{
                  var value = selectObject.value;
                  if ( value === "left-right" ){{
                    document.getElementById('{uuid}_heatmap_content').style.display  = "flex";
                  }}
                  else if ( value === "top-bottom" ) {{
                    document.getElementById('{uuid}_heatmap_content').style.display  = "inline";
                  }}
              }}
  
              var {uuid}_heatmap_flat_state = null;
  
              function onMouseHoverFlat_{uuid}(id) {{
                  if ({uuid}_heatmap_flat_state === null) {{
                      setBackgroundColors_{uuid}(id);
                      document.getElementById(id).style.backgroundColor  = "grey";
                  }}
  
                  if (getIdSide_{uuid}(id) === 'input' && getIdSide_{uuid}({uuid}_heatmap_flat_state) === 'output'){{
  
                      label_content_id = token_id_to_node_id_mapping_{uuid}[{uuid}_heatmap_flat_state][id];
  
                      if (document.getElementById(label_content_id).previousElementSibling.style.display == 'none'){{
                          document.getElementById(label_content_id).style.textShadow = "0px 0px 1px #000000";
                      }}
  
                  }}
  
              }}
  
              function onMouseOutFlat_{uuid}(id) {{
                  if ({uuid}_heatmap_flat_state === null) {{
                      cleanValuesAndColors_{uuid}(id);
                      document.getElementById(id).style.backgroundColor  = "transparent";
                  }}
  
                  if (getIdSide_{uuid}(id) === 'input' && getIdSide_{uuid}({uuid}_heatmap_flat_state) === 'output'){{
  
                      label_content_id = token_id_to_node_id_mapping_{uuid}[{uuid}_heatmap_flat_state][id];
  
                      if (document.getElementById(label_content_id).previousElementSibling.style.display == 'none'){{
                          document.getElementById(label_content_id).style.textShadow = "inherit";
                      }}
  
                  }}
  
              }}
  
              function onMouseClickFlat_{uuid}(id) {{
                  if ({uuid}_heatmap_flat_state === id) {{
  
                      // If the clicked token was already selected
  
                      document.getElementById(id).style.backgroundColor  = "transparent";
                      cleanValuesAndColors_{uuid}(id);
                      {uuid}_heatmap_flat_state = null;
                  }}
                  else {{
                      if ({uuid}_heatmap_flat_state === null) {{
  
                          // No token previously selected, new token clicked on
  
                          cleanValuesAndColors_{uuid}(id)
                          {uuid}_heatmap_flat_state = id;
                          document.getElementById(id).style.backgroundColor  = "grey";
                          setLabelValues_{uuid}(id);
                          setBackgroundColors_{uuid}(id);
                      }}
                      else {{
                          if (getIdSide_{uuid}({uuid}_heatmap_flat_state) === getIdSide_{uuid}(id)) {{
  
                              // User clicked a token on the same side as the currently selected token
  
                              cleanValuesAndColors_{uuid}({uuid}_heatmap_flat_state)
                              document.getElementById({uuid}_heatmap_flat_state).style.backgroundColor  = "transparent";
                              {uuid}_heatmap_flat_state = id;
                              document.getElementById(id).style.backgroundColor  = "grey";
                              setLabelValues_{uuid}(id);
                              setBackgroundColors_{uuid}(id);
                          }}
                          else{{
  
                              if (getIdSide_{uuid}(id) === 'input') {{
                                  label_content_id = token_id_to_node_id_mapping_{uuid}[{uuid}_heatmap_flat_state][id];
  
                                  if (document.getElementById(label_content_id).previousElementSibling.style.display == 'none') {{
                                      document.getElementById(label_content_id).previousElementSibling.style.display = 'block';
                                      document.getElementById(label_content_id).parentNode.style.display = 'inline-block';
                                      document.getElementById(label_content_id).style.textShadow = "0px 0px 1px #000000";
                                    }}
                                  else {{
                                      document.getElementById(label_content_id).previousElementSibling.style.display = 'none';
                                      document.getElementById(label_content_id).parentNode.style.display = 'inline';
                                      document.getElementById(label_content_id).style.textShadow  = "inherit";
                                    }}
  
                              }}
                              else {{
                                  if (document.getElementById(id).previousElementSibling.style.display == 'none') {{
                                      document.getElementById(id).previousElementSibling.style.display = 'block';
                                      document.getElementById(id).parentNode.style.display = 'inline-block';
                                    }}
                                  else {{
                                      document.getElementById(id).previousElementSibling.style.display = 'none';
                                      document.getElementById(id).parentNode.style.display = 'inline';
                                    }}
                              }}
  
                          }}
                      }}
  
                  }}
              }}
  
              function setLabelValues_{uuid}(id) {{
                  for(const token in shap_values_{uuid}[id]){{
                      document.getElementById(token).innerHTML = shap_values_{uuid}[id][token];
                      document.getElementById(token).nextElementSibling.title = 'SHAP Value : ' + shap_values_{uuid}[id][token];
                  }}
              }}
  
              function setBackgroundColors_{uuid}(id) {{
                  for(const token in colors_{uuid}[id]){{
                      document.getElementById(token).style.backgroundColor  = colors_{uuid}[id][token];
                  }}
              }}
  
              function cleanValuesAndColors_{uuid}(id) {{
                  for(const token in shap_values_{uuid}[id]){{
                      document.getElementById(token).innerHTML = "";
                      document.getElementById(token).nextElementSibling.title = "";
                  }}
                   for(const token in colors_{uuid}[id]){{
                      document.getElementById(token).style.backgroundColor  = "transparent";
                      document.getElementById(token).previousElementSibling.style.display = 'none';
                      document.getElementById(token).parentNode.style.display = 'inline';
                      document.getElementById(token).style.textShadow  = "inherit";
                  }}
              }}
  
              function getIdSide_{uuid}(id) {{
                  if (id === null) {{
                      return 'null'
                  }}
                  return id.split("_")[1];
              }}
          </script>
      """
  
      return heatmap_html + heatmap_javascript + javascript_values
  
file_path: shap/shap/plots/_text.py
imports: import json
  import random
  import string
  import numpy
  from .None import colors
label_desc: Use image node_id 7 for calling a global function with example usage: heatmap(shap_values) and returns: unknown, color, processed_values,  max_val, token_list, input_text_html