de-Rodrigo commited on
Commit
fa0575b
·
1 Parent(s): 703aeff

Improve Heatmap

Browse files
Files changed (1) hide show
  1. app.py +49 -19
app.py CHANGED
@@ -2,7 +2,7 @@ import streamlit as st
2
  import pandas as pd
3
  import numpy as np
4
  from bokeh.plotting import figure
5
- from bokeh.models import ColumnDataSource, DataTable, TableColumn, CustomJS, Select, Button, HoverTool, LinearColorMapper, ColorBar
6
  from bokeh.layouts import column
7
  from bokeh.palettes import Reds9, Blues9, Oranges9, Purples9, Greys9, BuGn9, Greens9
8
  from sklearn.decomposition import PCA
@@ -12,6 +12,7 @@ import io
12
  import ot
13
  from sklearn.linear_model import LinearRegression
14
  from scipy.stats import binned_statistic_2d
 
15
 
16
 
17
  N_COMPONENTS = 2
@@ -1059,11 +1060,10 @@ def run_model(model_name):
1059
  # --- INICIO DEL BLOQUE: Heatmap de características ---
1060
  st.markdown("## Heatmap de Características")
1061
 
1062
- # Cargar el CSV que contiene las características para el heatmap.
1063
- # Se asume que el archivo se encuentra en "data/heatmaps.csv"
1064
  try:
1065
- df_heat = pd.read_csv("data/heatmaps.csv", sep=";")
1066
- df_heat.columns = [col.strip("'\"") for col in df_heat.columns]
 
1067
  except Exception as e:
1068
  st.error(f"Error al cargar heatmaps.csv: {e}")
1069
  df_heat = None
@@ -1073,19 +1073,18 @@ def run_model(model_name):
1073
  if 'img' not in df_all["real"].columns:
1074
  st.error("La columna 'img' no se encuentra en las muestras reales para hacer el merge con heatmaps.csv.")
1075
  else:
1076
- # Crear la columna 'name' extrayendo el nombre sin la extensión '.png'
1077
  df_all["real"]["name"] = df_all["real"]["img"].apply(
1078
  lambda x: x.split("/")[-1].replace(".png", "") if isinstance(x, str) else x
1079
  )
1080
- print(df_all["real"]["name"])
1081
- print(df_heat)
1082
 
1083
  # Hacemos merge de las posiciones reales con el CSV de heatmaps usando la columna 'name'
1084
  df_heatmap = pd.merge(df_all["real"], df_heat, on="name", how="inner")
1085
 
1086
  # Extraemos las características disponibles (excluyendo 'name')
1087
  feature_options = [col for col in df_heat.columns if col != "name"]
1088
- selected_feature = st.selectbox("Seleccione la característica para el heatmap:", options=feature_options)
 
1089
 
1090
  # Determinar el rango de las posiciones (x, y) de las muestras reales
1091
  x_min, x_max = df_heatmap['x'].min(), df_heatmap['x'].max()
@@ -1096,31 +1095,62 @@ def run_model(model_name):
1096
  x_bins = np.linspace(x_min, x_max, grid_size + 1)
1097
  y_bins = np.linspace(y_min, y_max, grid_size + 1)
1098
 
1099
- # Utilizamos binned_statistic_2d para calcular la media de la característica seleccionada en cada celda
1100
- heat_stat, x_edges, y_edges, binnumber = binned_statistic_2d(
1101
- df_heatmap['x'], df_heatmap['y'], df_heatmap[selected_feature],
1102
- statistic='mean', bins=[x_bins, y_bins]
1103
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1104
 
1105
- # La función image de Bokeh espera una lista de arrays y el arreglo debe estar orientado correctamente
1106
- heatmap_data = heat_stat.T # Transponemos para alinear los ejes
1107
 
1108
  # Crear el mapa de color
1109
  color_mapper = LinearColorMapper(palette="Viridis256", low=np.nanmin(heatmap_data), high=np.nanmax(heatmap_data))
1110
 
1111
- # Crear la figura para el heatmap
1112
  heatmap_fig = figure(title=f"Heatmap de '{selected_feature}'",
1113
  x_range=(x_min, x_max), y_range=(y_min, y_max),
1114
  width=600, height=600,
1115
  tools="pan,wheel_zoom,reset,save", active_scroll="wheel_zoom")
 
1116
 
1117
- # Dibujar el heatmap usando la imagen (se pasa la lista con el array de datos)
1118
  heatmap_fig.image(image=[heatmap_data], x=x_min, y=y_min,
1119
  dw=x_max - x_min, dh=y_max - y_min,
1120
  color_mapper=color_mapper)
1121
 
1122
- # Agregar barra de colores
1123
  color_bar = ColorBar(color_mapper=color_mapper, location=(0, 0))
 
 
 
 
 
 
 
 
 
 
 
 
 
1124
  heatmap_fig.add_layout(color_bar, 'right')
1125
 
1126
  st.bokeh_chart(heatmap_fig)
 
2
  import pandas as pd
3
  import numpy as np
4
  from bokeh.plotting import figure
5
+ from bokeh.models import ColumnDataSource, DataTable, TableColumn, CustomJS, Select, Button, HoverTool, LinearColorMapper, ColorBar, FuncTickFormatter
6
  from bokeh.layouts import column
7
  from bokeh.palettes import Reds9, Blues9, Oranges9, Purples9, Greys9, BuGn9, Greens9
8
  from sklearn.decomposition import PCA
 
12
  import ot
13
  from sklearn.linear_model import LinearRegression
14
  from scipy.stats import binned_statistic_2d
15
+ import json
16
 
17
 
18
  N_COMPONENTS = 2
 
1060
  # --- INICIO DEL BLOQUE: Heatmap de características ---
1061
  st.markdown("## Heatmap de Características")
1062
 
 
 
1063
  try:
1064
+ df_heat = pd.read_csv("data/heatmaps.csv")
1065
+ # Si fuera necesario, se pueden limpiar los nombres de las columnas:
1066
+ # df_heat.columns = [col.strip("'\"") for col in df_heat.columns]
1067
  except Exception as e:
1068
  st.error(f"Error al cargar heatmaps.csv: {e}")
1069
  df_heat = None
 
1073
  if 'img' not in df_all["real"].columns:
1074
  st.error("La columna 'img' no se encuentra en las muestras reales para hacer el merge con heatmaps.csv.")
1075
  else:
1076
+ # Crear la columna 'name' extrayendo el nombre final de la URL y removiendo ".png"
1077
  df_all["real"]["name"] = df_all["real"]["img"].apply(
1078
  lambda x: x.split("/")[-1].replace(".png", "") if isinstance(x, str) else x
1079
  )
 
 
1080
 
1081
  # Hacemos merge de las posiciones reales con el CSV de heatmaps usando la columna 'name'
1082
  df_heatmap = pd.merge(df_all["real"], df_heat, on="name", how="inner")
1083
 
1084
  # Extraemos las características disponibles (excluyendo 'name')
1085
  feature_options = [col for col in df_heat.columns if col != "name"]
1086
+ selected_feature = st.selectbox("Seleccione la característica para el heatmap:",
1087
+ options=feature_options, key=f"heatmap_{model_name}")
1088
 
1089
  # Determinar el rango de las posiciones (x, y) de las muestras reales
1090
  x_min, x_max = df_heatmap['x'].min(), df_heatmap['x'].max()
 
1095
  x_bins = np.linspace(x_min, x_max, grid_size + 1)
1096
  y_bins = np.linspace(y_min, y_max, grid_size + 1)
1097
 
1098
+ # Si la variable seleccionada no es numérica, la convertimos a códigos numéricos
1099
+ # y guardamos la correspondencia para la leyenda.
1100
+ cat_mapping = None
1101
+ if not pd.api.types.is_numeric_dtype(df_heatmap[selected_feature]):
1102
+ cat = df_heatmap[selected_feature].astype('category')
1103
+ cat_mapping = list(cat.cat.categories)
1104
+ df_heatmap[selected_feature] = cat.cat.codes
1105
+
1106
+ # Intentamos calcular el heatmap; si falla, aplicamos la conversión a categoría
1107
+ try:
1108
+ heat_stat, x_edges, y_edges, binnumber = binned_statistic_2d(
1109
+ df_heatmap['x'], df_heatmap['y'], df_heatmap[selected_feature],
1110
+ statistic='mean', bins=[x_bins, y_bins]
1111
+ )
1112
+ except:
1113
+ cat = df_heatmap[selected_feature].astype('category')
1114
+ cat_mapping = list(cat.cat.categories)
1115
+ df_heatmap[selected_feature] = cat.cat.codes
1116
+ heat_stat, x_edges, y_edges, binnumber = binned_statistic_2d(
1117
+ df_heatmap['x'], df_heatmap['y'], df_heatmap[selected_feature],
1118
+ statistic='mean', bins=[x_bins, y_bins]
1119
+ )
1120
 
1121
+ # La función image de Bokeh espera una lista de arrays; se transpone para alinear los ejes.
1122
+ heatmap_data = heat_stat.T
1123
 
1124
  # Crear el mapa de color
1125
  color_mapper = LinearColorMapper(palette="Viridis256", low=np.nanmin(heatmap_data), high=np.nanmax(heatmap_data))
1126
 
1127
+ # Crear la figura para el heatmap con fondo blanco
1128
  heatmap_fig = figure(title=f"Heatmap de '{selected_feature}'",
1129
  x_range=(x_min, x_max), y_range=(y_min, y_max),
1130
  width=600, height=600,
1131
  tools="pan,wheel_zoom,reset,save", active_scroll="wheel_zoom")
1132
+ heatmap_fig.background_fill_color = "white"
1133
 
1134
+ # Dibujar el heatmap usando la imagen
1135
  heatmap_fig.image(image=[heatmap_data], x=x_min, y=y_min,
1136
  dw=x_max - x_min, dh=y_max - y_min,
1137
  color_mapper=color_mapper)
1138
 
1139
+ # Crear la barra de colores
1140
  color_bar = ColorBar(color_mapper=color_mapper, location=(0, 0))
1141
+ # Si se usó conversión a categoría, formateamos la barra para mostrar las etiquetas originales
1142
+ if cat_mapping is not None:
1143
+
1144
+ categories_json = json.dumps(cat_mapping)
1145
+ color_bar.formatter = FuncTickFormatter(code=f"""
1146
+ var categories = {categories_json};
1147
+ var index = Math.round(tick);
1148
+ if(index >= 0 && index < categories.length) {{
1149
+ return categories[index];
1150
+ }} else {{
1151
+ return "";
1152
+ }}
1153
+ """)
1154
  heatmap_fig.add_layout(color_bar, 'right')
1155
 
1156
  st.bokeh_chart(heatmap_fig)