Spaces:
Sleeping
Sleeping
Commit
·
640dcd1
1
Parent(s):
aaf8876
Multiple Principal Components Combinations
Browse files
app.py
CHANGED
@@ -13,9 +13,10 @@ 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 =
|
19 |
TSNE_NEIGHBOURS = 150
|
20 |
# WEIGHT_FACTOR = 0.05
|
21 |
|
@@ -508,6 +509,12 @@ def compute_global_regression(df_combined, embedding_cols, tsne_params, df_f1, r
|
|
508 |
|
509 |
return results
|
510 |
|
|
|
|
|
|
|
|
|
|
|
|
|
511 |
def optimize_tsne_params(df_combined, embedding_cols, df_f1, distance_metric):
|
512 |
perplexity_range = np.linspace(30, 50, 10)
|
513 |
learning_rate_range = np.linspace(200, 1000, 20)
|
@@ -730,21 +737,22 @@ def run_model(model_name):
|
|
730 |
key=f"download_button_excel_{model_name}"
|
731 |
)
|
732 |
|
733 |
-
# Nuevo bloque: PCA solo para df_real
|
734 |
if reduction_method == "PCA":
|
735 |
st.markdown("## PCA - Solo Muestras Reales")
|
736 |
-
#
|
|
|
737 |
df_real_only = embeddings["real"].copy()
|
738 |
pca_real = PCA(n_components=N_COMPONENTS)
|
739 |
reduced_real = pca_real.fit_transform(df_real_only[embedding_cols].values)
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
df_real_only['
|
|
|
744 |
explained_variance_real = pca_real.explained_variance_ratio_
|
745 |
unique_labels_real = sorted(df_real_only['label'].unique().tolist())
|
746 |
|
747 |
-
#
|
748 |
num_labels = len(unique_labels_real)
|
749 |
if num_labels <= 9:
|
750 |
red_palette = Reds9[:num_labels]
|
@@ -752,6 +760,7 @@ def run_model(model_name):
|
|
752 |
red_palette = (Reds9 * ((num_labels // 9) + 1))[:num_labels]
|
753 |
real_color_mapping = {label: red_palette[i] for i, label in enumerate(unique_labels_real)}
|
754 |
|
|
|
755 |
st.subheader("PCA - Real: Explained Variance Ratio")
|
756 |
component_names_real = [f"PC{i+1}" for i in range(len(explained_variance_real))]
|
757 |
variance_df_real = pd.DataFrame({
|
@@ -759,8 +768,8 @@ def run_model(model_name):
|
|
759 |
"Explained Variance": explained_variance_real
|
760 |
})
|
761 |
st.table(variance_df_real)
|
762 |
-
|
763 |
-
# Mostrar los plots de loadings
|
764 |
st.subheader("PCA - Real: Component Loadings")
|
765 |
st.markdown("### Pesos de las Componentes Principales (Loadings) - Conjunto Combinado")
|
766 |
for i, comp in enumerate(pca_real.components_):
|
@@ -777,62 +786,52 @@ def run_model(model_name):
|
|
777 |
tools="pan,wheel_zoom,reset,save,hover",
|
778 |
active_scroll="wheel_zoom"
|
779 |
)
|
780 |
-
# Fondo blanco y solo grid horizontal
|
781 |
p.background_fill_color = "white"
|
782 |
p.xgrid.grid_line_color = None
|
783 |
p.ygrid.grid_line_color = "gray"
|
784 |
p.vbar(x='dimensions', top='weight', width=0.8, source=source,
|
785 |
fill_color="#2b83ba", line_color="#2b83ba")
|
786 |
-
# No se muestran etiquetas en el eje horizontal
|
787 |
p.xaxis.axis_label = "Dimensiones Originales"
|
788 |
p.xaxis.major_label_text_font_size = '0pt'
|
789 |
-
# Configurar el HoverTool
|
790 |
hover = p.select_one(HoverTool)
|
791 |
hover.tooltips = [("Dimensión", "@dimensions"), ("Peso", "@weight")]
|
792 |
st.bokeh_chart(p)
|
793 |
|
794 |
-
#
|
795 |
-
|
796 |
-
|
797 |
-
# Crear un diccionario para almacenar las proyecciones usando el PCA calculado con las muestras reales (pca_real)
|
798 |
df_all = {}
|
799 |
-
|
800 |
-
# Proyectar las muestras reales
|
801 |
df_real_proj = embeddings["real"].copy()
|
802 |
proj_real = pca_real.transform(df_real_proj[embedding_cols].values)
|
803 |
-
|
804 |
-
|
805 |
df_all["real"] = df_real_proj
|
806 |
|
807 |
-
#
|
808 |
if "synthetic" in embeddings:
|
809 |
df_synth_proj = embeddings["synthetic"].copy()
|
810 |
proj_synth = pca_real.transform(df_synth_proj[embedding_cols].values)
|
811 |
-
|
812 |
-
|
813 |
df_all["synthetic"] = df_synth_proj
|
814 |
|
815 |
-
#
|
816 |
if "pretrained" in embeddings:
|
817 |
df_pretr_proj = embeddings["pretrained"].copy()
|
818 |
proj_pretr = pca_real.transform(df_pretr_proj[embedding_cols].values)
|
819 |
-
|
820 |
-
|
821 |
df_all["pretrained"] = df_pretr_proj
|
822 |
|
823 |
-
# Para
|
824 |
-
# renombramos las columnas 'pc1' y 'pc2' a 'x' y 'y' en cada dataframe
|
825 |
for key in df_all:
|
826 |
-
df_all[key]["x"] = df_all[key]["
|
827 |
-
df_all[key]["y"] = df_all[key]["
|
828 |
|
829 |
-
# Construir los subconjuntos únicos
|
830 |
-
# - Para "real" y "pretrained": agrupamos por label.
|
831 |
-
# - Para "synthetic": agrupamos por la columna "source" (cada source tendrá sus labels).
|
832 |
unique_subsets = {}
|
833 |
-
# Real:
|
834 |
unique_subsets["real"] = sorted(df_all["real"]['label'].unique().tolist())
|
835 |
-
# Synthetic:
|
836 |
if "synthetic" in df_all:
|
837 |
unique_synth = {}
|
838 |
for source in df_all["synthetic"]["source"].unique():
|
@@ -840,16 +839,15 @@ def run_model(model_name):
|
|
840 |
unique_subsets["synthetic"] = unique_synth
|
841 |
else:
|
842 |
unique_subsets["synthetic"] = {}
|
843 |
-
# Pretrained:
|
844 |
if "pretrained" in df_all:
|
845 |
unique_subsets["pretrained"] = sorted(df_all["pretrained"]['label'].unique().tolist())
|
846 |
else:
|
847 |
unique_subsets["pretrained"] = []
|
848 |
-
|
849 |
-
# Obtener
|
850 |
color_maps = get_color_maps(unique_subsets)
|
851 |
-
|
852 |
-
#
|
853 |
marker_mapping = {
|
854 |
"es-digital-paragraph-degradation-seq": "x",
|
855 |
"es-digital-line-degradation-seq": "cross",
|
@@ -858,9 +856,9 @@ def run_model(model_name):
|
|
858 |
"es-digital-zoom-degradation-seq": "asterisk",
|
859 |
"es-render-seq": "inverted_triangle"
|
860 |
}
|
861 |
-
|
862 |
-
#
|
863 |
-
|
864 |
fig_all = figure(
|
865 |
title="PCA - Todos los subconjuntos proyectados",
|
866 |
plot_width=600,
|
@@ -870,11 +868,10 @@ def run_model(model_name):
|
|
870 |
background_fill_color="white",
|
871 |
tooltips=TOOLTIPS
|
872 |
)
|
873 |
-
# Solo grid horizontal
|
874 |
fig_all.xgrid.grid_line_color = None
|
875 |
fig_all.ygrid.grid_line_color = "gray"
|
876 |
-
|
877 |
-
#
|
878 |
for label in unique_subsets["real"]:
|
879 |
subset = df_all["real"][df_all["real"]['label'] == label]
|
880 |
source = ColumnDataSource(data={
|
@@ -883,28 +880,28 @@ def run_model(model_name):
|
|
883 |
'label': subset['label'],
|
884 |
'img': subset['img']
|
885 |
})
|
886 |
-
# Usamos 'circle' para las reales
|
887 |
fig_all.circle('x', 'y', size=10,
|
888 |
fill_color=color_maps["real"][label],
|
889 |
line_color=color_maps["real"][label],
|
890 |
legend_label=f"Real: {label}",
|
891 |
source=source)
|
892 |
-
|
893 |
show_real_only = st.checkbox("Show only real samples", value=True, key=f"show_real_only_{model_name}")
|
894 |
-
|
895 |
if not show_real_only:
|
896 |
-
|
897 |
-
# Ploteamos los puntos de synthetic, diferenciando cada source con su marcador
|
898 |
if unique_subsets["synthetic"]:
|
899 |
for source_name, labels in unique_subsets["synthetic"].items():
|
900 |
df_source = df_all["synthetic"][df_all["synthetic"]["source"] == source_name]
|
901 |
marker = marker_mapping.get(source_name, "square")
|
902 |
-
#
|
903 |
-
|
904 |
-
|
905 |
-
|
906 |
-
|
907 |
-
|
|
|
|
|
|
|
908 |
if unique_subsets["pretrained"]:
|
909 |
for label in unique_subsets["pretrained"]:
|
910 |
subset = df_all["pretrained"][df_all["pretrained"]['label'] == label]
|
@@ -914,76 +911,151 @@ def run_model(model_name):
|
|
914 |
'label': subset['label'],
|
915 |
'img': subset['img']
|
916 |
})
|
917 |
-
# Usamos 'triangle' para pretrained (por ejemplo)
|
918 |
fig_all.triangle('x', 'y', size=10,
|
919 |
fill_color=color_maps["pretrained"][label],
|
920 |
line_color=color_maps["pretrained"][label],
|
921 |
legend_label=f"Pretrained: {label}",
|
922 |
source=source)
|
923 |
-
|
924 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
925 |
center_x = df_all["real"]['x'].mean()
|
926 |
center_y = df_all["real"]['y'].mean()
|
927 |
distances = np.sqrt((df_all["real"]['x'] - center_x)**2 + (df_all["real"]['y'] - center_y)**2)
|
928 |
radius = distances.max()
|
929 |
-
|
930 |
-
# Dibujar el centroide y la circunferencia
|
931 |
centroid_glyph = fig_all.circle(
|
932 |
x=center_x, y=center_y, size=15,
|
933 |
fill_color="white", line_color="black",
|
934 |
legend_label="Centroide",
|
935 |
-
name="centroid"
|
936 |
)
|
937 |
-
|
938 |
circumference_glyph = fig_all.circle(
|
939 |
x=center_x, y=center_y, radius=radius,
|
940 |
fill_color=None, line_color="black",
|
941 |
line_dash="dashed",
|
942 |
legend_label="Circunferencia",
|
943 |
-
name="circumference"
|
944 |
)
|
945 |
-
|
|
|
946 |
fig_all.xaxis.axis_label = "PC1"
|
947 |
fig_all.yaxis.axis_label = "PC2"
|
948 |
hover_all = fig_all.select_one(HoverTool)
|
949 |
hover_all.renderers = [r for r in fig_all.renderers if r.name not in ["centroid", "circumference"]]
|
950 |
-
|
951 |
-
# hover_all.tooltips = [("Label", "@label"), ("PC1", "@x"), ("PC2", "@y")]
|
952 |
-
|
953 |
-
# Agregar checkbox para mostrar u ocultar la leyenda, igual que en el primer PCA
|
954 |
-
show_legend_second = st.checkbox("Show Legend", value=False, key=f"legend_second_{model_name}")
|
955 |
-
fig_all.legend.visible = show_legend_second
|
956 |
-
fig_all.legend.location = "top_right"
|
957 |
-
fig_all.match_aspect = True
|
958 |
-
|
959 |
-
st.bokeh_chart(fig_all)
|
960 |
-
|
961 |
-
# Mostrar el valor del radio debajo del gráfico
|
962 |
st.write(f"El radio de la circunferencia (calculado a partir de las muestras reales) es: {radius:.4f}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
963 |
|
964 |
-
|
965 |
-
#
|
966 |
-
|
967 |
-
# Se calcula la distancia de cada subset synthetic a cada subset real usando los datos proyectados (df_all)
|
968 |
-
# Se utiliza la función compute_cluster_distances_synthetic_individual ya definida
|
969 |
real_labels_new = sorted(df_all["real"]['label'].unique().tolist())
|
970 |
df_distances_new = compute_cluster_distances_synthetic_individual(
|
971 |
df_all["synthetic"],
|
972 |
df_all["real"],
|
973 |
real_labels_new,
|
974 |
-
metric="wasserstein", #
|
975 |
bins=20
|
976 |
)
|
977 |
-
|
978 |
-
# Extraer las distancias globales (por cada source) del dataframe obtenido,
|
979 |
-
# buscando filas cuyo índice comience con "Global" (formato "Global (source)")
|
980 |
global_distances_new = {}
|
981 |
for idx in df_distances_new.index:
|
982 |
if idx.startswith("Global"):
|
983 |
source_name = idx.split("(")[1].rstrip(")")
|
984 |
global_distances_new[source_name] = df_distances_new.loc[idx].values
|
985 |
-
|
986 |
-
# Ahora, relacionar estas distancias con los valores de F1 (ya cargados en df_f1)
|
987 |
all_x_new = []
|
988 |
all_y_new = []
|
989 |
for source in df_f1.columns:
|
@@ -994,14 +1066,12 @@ def run_model(model_name):
|
|
994 |
all_y_new.extend(y_vals)
|
995 |
all_x_arr_new = np.array(all_x_new).reshape(-1, 1)
|
996 |
all_y_arr_new = np.array(all_y_new)
|
997 |
-
|
998 |
-
# Realizar la regresión lineal global sobre estos datos
|
999 |
model_global_new = LinearRegression().fit(all_x_arr_new, all_y_arr_new)
|
1000 |
r2_new = model_global_new.score(all_x_arr_new, all_y_arr_new)
|
1001 |
slope_new = model_global_new.coef_[0]
|
1002 |
intercept_new = model_global_new.intercept_
|
1003 |
-
|
1004 |
-
# Crear el scatter plot
|
1005 |
scatter_fig_new = figure(
|
1006 |
width=600,
|
1007 |
height=600,
|
@@ -1011,12 +1081,10 @@ def run_model(model_name):
|
|
1011 |
background_fill_color="white",
|
1012 |
y_range=(0, 1)
|
1013 |
)
|
1014 |
-
# Configurar únicamente grid horizontal
|
1015 |
scatter_fig_new.xgrid.grid_line_color = None
|
1016 |
scatter_fig_new.ygrid.grid_line_color = "gray"
|
1017 |
scatter_fig_new.match_aspect = True
|
1018 |
-
|
1019 |
-
# Mantenemos el mismo código de colores que en el otro scatter plot
|
1020 |
source_colors = {
|
1021 |
"es-digital-paragraph-degradation-seq": "blue",
|
1022 |
"es-digital-line-degradation-seq": "green",
|
@@ -1026,8 +1094,7 @@ def run_model(model_name):
|
|
1026 |
"es-digital-rotation-zoom-degradation-seq": "brown",
|
1027 |
"es-render-seq": "cyan"
|
1028 |
}
|
1029 |
-
|
1030 |
-
# Dibujar cada conjunto: para cada source (por ejemplo, es-render-seq, etc.)
|
1031 |
for source in df_f1.columns:
|
1032 |
if source in global_distances_new:
|
1033 |
x_vals = global_distances_new[source]
|
@@ -1040,81 +1107,59 @@ def run_model(model_name):
|
|
1040 |
line_color=source_colors.get(source, "gray"),
|
1041 |
legend_label=source
|
1042 |
)
|
1043 |
-
|
1044 |
scatter_fig_new.xaxis.axis_label = "Distance (Global, por Colegio) - Nueva PCA"
|
1045 |
scatter_fig_new.yaxis.axis_label = "F1 Score"
|
1046 |
scatter_fig_new.legend.location = "top_right"
|
1047 |
-
|
1048 |
hover_tool_new = scatter_fig_new.select_one(HoverTool)
|
1049 |
hover_tool_new.tooltips = [("Distance", "@x"), ("F1", "@y"), ("Subset", "@Fuente")]
|
1050 |
-
|
1051 |
-
# Dibujar la línea de regresión global
|
1052 |
x_line_new = np.linspace(all_x_arr_new.min(), all_x_arr_new.max(), 100)
|
1053 |
y_line_new = model_global_new.predict(x_line_new.reshape(-1,1))
|
1054 |
scatter_fig_new.line(x_line_new, y_line_new, line_width=2, line_color="black", legend_label="Global Regression")
|
1055 |
-
|
1056 |
st.bokeh_chart(scatter_fig_new)
|
1057 |
-
|
1058 |
st.write(f"Regresión global (Nueva PCA): R² = {r2_new:.4f}, Slope = {slope_new:.4f}, Intercept = {intercept_new:.4f}")
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
# --- INICIO DEL BLOQUE: Heatmap de características ---
|
1069 |
st.markdown("## Heatmap de Características")
|
1070 |
-
|
1071 |
try:
|
1072 |
df_heat = pd.read_csv("data/heatmaps.csv")
|
1073 |
-
# Si fuera necesario, se pueden limpiar los nombres de las columnas:
|
1074 |
-
# df_heat.columns = [col.strip("'\"") for col in df_heat.columns]
|
1075 |
except Exception as e:
|
1076 |
st.error(f"Error al cargar heatmaps.csv: {e}")
|
1077 |
df_heat = None
|
1078 |
-
|
1079 |
if df_heat is not None:
|
1080 |
-
# Verificamos que la columna 'img' esté presente en df_all["real"]
|
1081 |
if 'img' not in df_all["real"].columns:
|
1082 |
st.error("La columna 'img' no se encuentra en las muestras reales para hacer el merge con heatmaps.csv.")
|
1083 |
else:
|
1084 |
-
# Crear
|
1085 |
df_all["real"]["name"] = df_all["real"]["img"].apply(
|
1086 |
lambda x: x.split("/")[-1].replace(".png", "") if isinstance(x, str) else x
|
1087 |
)
|
1088 |
-
|
1089 |
-
# Hacemos merge de las posiciones reales con el CSV de heatmaps usando la columna 'name'
|
1090 |
df_heatmap = pd.merge(df_all["real"], df_heat, on="name", how="inner")
|
1091 |
|
1092 |
-
#
|
1093 |
feature_options = [col for col in df_heat.columns if col != "name"]
|
1094 |
selected_feature = st.selectbox("Select heatmap feature:",
|
1095 |
options=feature_options, key=f"heatmap_{model_name}")
|
1096 |
-
|
1097 |
select_extra_dataset_hm = st.selectbox("Select a dataset:",
|
1098 |
options=["-", "es-digital-line-degradation-seq", "es-digital-seq", "es-digital-rotation-degradation-seq", "es-digital-zoom-degradation-seq", "es-render-seq"], key=f"heatmap_extra_dataset_{model_name}")
|
1099 |
|
1100 |
-
#
|
1101 |
x_min, x_max = df_heatmap['x'].min(), df_heatmap['x'].max()
|
1102 |
y_min, y_max = df_heatmap['y'].min(), df_heatmap['y'].max()
|
1103 |
|
1104 |
-
# Definir resolución de la rejilla (por ejemplo, 50x50)
|
1105 |
grid_size = 50
|
1106 |
x_bins = np.linspace(x_min, x_max, grid_size + 1)
|
1107 |
y_bins = np.linspace(y_min, y_max, grid_size + 1)
|
1108 |
|
1109 |
-
# Si la variable seleccionada no es numérica, la convertimos a códigos numéricos
|
1110 |
-
# y guardamos la correspondencia para la leyenda.
|
1111 |
cat_mapping = None
|
1112 |
if df_heatmap[selected_feature].dtype == bool or not pd.api.types.is_numeric_dtype(df_heatmap[selected_feature]):
|
1113 |
cat = df_heatmap[selected_feature].astype('category')
|
1114 |
cat_mapping = list(cat.cat.categories)
|
1115 |
df_heatmap[selected_feature] = cat.cat.codes
|
1116 |
|
1117 |
-
# Intentamos calcular el heatmap; si falla, aplicamos la conversión a categoría
|
1118 |
try:
|
1119 |
heat_stat, x_edges, y_edges, binnumber = binned_statistic_2d(
|
1120 |
df_heatmap['x'], df_heatmap['y'], df_heatmap[selected_feature],
|
@@ -1129,32 +1174,23 @@ def run_model(model_name):
|
|
1129 |
statistic='mean', bins=[x_bins, y_bins]
|
1130 |
)
|
1131 |
|
1132 |
-
#
|
1133 |
heatmap_data = heat_stat.T
|
1134 |
|
1135 |
-
|
1136 |
-
color_mapper = LinearColorMapper(palette="Viridis256", low=np.nanmin(heatmap_data), high=np.nanmax(heatmap_data), nan_color = 'rgba(0, 0, 0, 0)')
|
1137 |
|
1138 |
-
# Crear la figura para el heatmap con fondo blanco
|
1139 |
heatmap_fig = figure(title=f"Heatmap de '{selected_feature}'",
|
1140 |
x_range=(x_min, x_max), y_range=(y_min, y_max),
|
1141 |
width=600, height=600,
|
1142 |
tools="pan,wheel_zoom,reset,save", active_scroll="wheel_zoom", tooltips=TOOLTIPS)
|
1143 |
-
|
1144 |
-
# Dibujar el heatmap usando la imagen
|
1145 |
heatmap_fig.image(image=[heatmap_data], x=x_min, y=y_min,
|
1146 |
dw=x_max - x_min, dh=y_max - y_min,
|
1147 |
color_mapper=color_mapper)
|
1148 |
|
1149 |
-
# Crear la barra de colores
|
1150 |
color_bar = ColorBar(color_mapper=color_mapper, location=(0, 0))
|
1151 |
-
# Si se usó conversión a categoría, formateamos la barra para mostrar las etiquetas originales
|
1152 |
if cat_mapping is not None:
|
1153 |
-
|
1154 |
-
# Creamos ticks fijos solo para cada categoría
|
1155 |
ticks = list(range(len(cat_mapping)))
|
1156 |
color_bar.ticker = FixedTicker(ticks=ticks)
|
1157 |
-
|
1158 |
categories_json = json.dumps(cat_mapping)
|
1159 |
color_bar.formatter = FuncTickFormatter(code=f"""
|
1160 |
var categories = {categories_json};
|
@@ -1166,22 +1202,17 @@ def run_model(model_name):
|
|
1166 |
}}
|
1167 |
""")
|
1168 |
heatmap_fig.add_layout(color_bar, 'right')
|
1169 |
-
|
1170 |
-
|
1171 |
-
|
1172 |
-
# Agregar renderer de puntos invisibles para tooltips
|
1173 |
source_points = ColumnDataSource(data={
|
1174 |
'x': df_heatmap['x'],
|
1175 |
'y': df_heatmap['y'],
|
1176 |
'img': df_heatmap['img'],
|
1177 |
-
'label': df_heatmap['name']
|
1178 |
})
|
1179 |
-
# Dibujar círculos con transparencia total (no se verán)
|
1180 |
invisible_renderer = heatmap_fig.circle('x', 'y', size=10, source=source_points, fill_alpha=0, line_alpha=0.5)
|
1181 |
-
|
1182 |
if select_extra_dataset_hm != "-":
|
1183 |
df_extra = df_all["synthetic"][df_all["synthetic"]["source"] == select_extra_dataset_hm]
|
1184 |
-
# Asegurarse de que exista la columna 'name'
|
1185 |
if 'name' not in df_extra.columns:
|
1186 |
df_extra["name"] = df_extra["img"].apply(
|
1187 |
lambda x: x.split("/")[-1].replace(".png", "") if isinstance(x, str) else x
|
@@ -1192,9 +1223,8 @@ def run_model(model_name):
|
|
1192 |
'img': df_extra['img'],
|
1193 |
'label': df_extra['name']
|
1194 |
})
|
1195 |
-
# Agregar renderer para el dataset extra
|
1196 |
extra_renderer = heatmap_fig.circle('x', 'y', size=10, source=source_extra_points, fill_alpha=0, line_alpha=0.5, color="red")
|
1197 |
-
|
1198 |
hover_tool_points = HoverTool(renderers=[invisible_renderer], tooltips=TOOLTIPS)
|
1199 |
heatmap_fig.add_tools(hover_tool_points)
|
1200 |
|
|
|
13 |
from sklearn.linear_model import LinearRegression
|
14 |
from scipy.stats import binned_statistic_2d
|
15 |
import json
|
16 |
+
import itertools
|
17 |
|
18 |
|
19 |
+
N_COMPONENTS = 3
|
20 |
TSNE_NEIGHBOURS = 150
|
21 |
# WEIGHT_FACTOR = 0.05
|
22 |
|
|
|
509 |
|
510 |
return results
|
511 |
|
512 |
+
# def get_color(color_entry):
|
513 |
+
# if isinstance(color_entry, dict):
|
514 |
+
# # Extrae el primer valor (o ajusta según convenga)
|
515 |
+
# return list(color_entry.values())[0]
|
516 |
+
# return color_entry
|
517 |
+
|
518 |
def optimize_tsne_params(df_combined, embedding_cols, df_f1, distance_metric):
|
519 |
perplexity_range = np.linspace(30, 50, 10)
|
520 |
learning_rate_range = np.linspace(200, 1000, 20)
|
|
|
737 |
key=f"download_button_excel_{model_name}"
|
738 |
)
|
739 |
|
|
|
740 |
if reduction_method == "PCA":
|
741 |
st.markdown("## PCA - Solo Muestras Reales")
|
742 |
+
# -------------------------------------------------------------------------
|
743 |
+
# 1. PCA sobre las muestras reales
|
744 |
df_real_only = embeddings["real"].copy()
|
745 |
pca_real = PCA(n_components=N_COMPONENTS)
|
746 |
reduced_real = pca_real.fit_transform(df_real_only[embedding_cols].values)
|
747 |
+
|
748 |
+
# Agregar columnas PC1, PC2, … a df_real_only
|
749 |
+
for i in range(reduced_real.shape[1]):
|
750 |
+
df_real_only[f'PC{i+1}'] = reduced_real[:, i]
|
751 |
+
|
752 |
explained_variance_real = pca_real.explained_variance_ratio_
|
753 |
unique_labels_real = sorted(df_real_only['label'].unique().tolist())
|
754 |
|
755 |
+
# Mapeo de colores para las muestras reales usando la paleta Reds9
|
756 |
num_labels = len(unique_labels_real)
|
757 |
if num_labels <= 9:
|
758 |
red_palette = Reds9[:num_labels]
|
|
|
760 |
red_palette = (Reds9 * ((num_labels // 9) + 1))[:num_labels]
|
761 |
real_color_mapping = {label: red_palette[i] for i, label in enumerate(unique_labels_real)}
|
762 |
|
763 |
+
# Mostrar tabla de Explained Variance Ratio
|
764 |
st.subheader("PCA - Real: Explained Variance Ratio")
|
765 |
component_names_real = [f"PC{i+1}" for i in range(len(explained_variance_real))]
|
766 |
variance_df_real = pd.DataFrame({
|
|
|
768 |
"Explained Variance": explained_variance_real
|
769 |
})
|
770 |
st.table(variance_df_real)
|
771 |
+
|
772 |
+
# Mostrar los plots de loadings para cada componente
|
773 |
st.subheader("PCA - Real: Component Loadings")
|
774 |
st.markdown("### Pesos de las Componentes Principales (Loadings) - Conjunto Combinado")
|
775 |
for i, comp in enumerate(pca_real.components_):
|
|
|
786 |
tools="pan,wheel_zoom,reset,save,hover",
|
787 |
active_scroll="wheel_zoom"
|
788 |
)
|
|
|
789 |
p.background_fill_color = "white"
|
790 |
p.xgrid.grid_line_color = None
|
791 |
p.ygrid.grid_line_color = "gray"
|
792 |
p.vbar(x='dimensions', top='weight', width=0.8, source=source,
|
793 |
fill_color="#2b83ba", line_color="#2b83ba")
|
|
|
794 |
p.xaxis.axis_label = "Dimensiones Originales"
|
795 |
p.xaxis.major_label_text_font_size = '0pt'
|
|
|
796 |
hover = p.select_one(HoverTool)
|
797 |
hover.tooltips = [("Dimensión", "@dimensions"), ("Peso", "@weight")]
|
798 |
st.bokeh_chart(p)
|
799 |
|
800 |
+
# -------------------------------------------------------------------------
|
801 |
+
# 2. Proyección de todos los subconjuntos usando los loadings de df_real (para PC completos)
|
802 |
+
# Se proyectan real, synthetic y pretrained (si existen) y se agregan todas las PC's.
|
|
|
803 |
df_all = {}
|
804 |
+
# Real
|
|
|
805 |
df_real_proj = embeddings["real"].copy()
|
806 |
proj_real = pca_real.transform(df_real_proj[embedding_cols].values)
|
807 |
+
for i in range(proj_real.shape[1]):
|
808 |
+
df_real_proj[f'PC{i+1}'] = proj_real[:, i]
|
809 |
df_all["real"] = df_real_proj
|
810 |
|
811 |
+
# Synthetic
|
812 |
if "synthetic" in embeddings:
|
813 |
df_synth_proj = embeddings["synthetic"].copy()
|
814 |
proj_synth = pca_real.transform(df_synth_proj[embedding_cols].values)
|
815 |
+
for i in range(proj_synth.shape[1]):
|
816 |
+
df_synth_proj[f'PC{i+1}'] = proj_synth[:, i]
|
817 |
df_all["synthetic"] = df_synth_proj
|
818 |
|
819 |
+
# Pretrained
|
820 |
if "pretrained" in embeddings:
|
821 |
df_pretr_proj = embeddings["pretrained"].copy()
|
822 |
proj_pretr = pca_real.transform(df_pretr_proj[embedding_cols].values)
|
823 |
+
for i in range(proj_pretr.shape[1]):
|
824 |
+
df_pretr_proj[f'PC{i+1}'] = proj_pretr[:, i]
|
825 |
df_all["pretrained"] = df_pretr_proj
|
826 |
|
827 |
+
# Para el plot global usaremos PC1 y PC2 (se asignan a 'x' y 'y')
|
|
|
828 |
for key in df_all:
|
829 |
+
df_all[key]["x"] = df_all[key]["PC1"]
|
830 |
+
df_all[key]["y"] = df_all[key]["PC2"]
|
831 |
|
832 |
+
# Construir los subconjuntos únicos para agrupar:
|
|
|
|
|
833 |
unique_subsets = {}
|
|
|
834 |
unique_subsets["real"] = sorted(df_all["real"]['label'].unique().tolist())
|
|
|
835 |
if "synthetic" in df_all:
|
836 |
unique_synth = {}
|
837 |
for source in df_all["synthetic"]["source"].unique():
|
|
|
839 |
unique_subsets["synthetic"] = unique_synth
|
840 |
else:
|
841 |
unique_subsets["synthetic"] = {}
|
|
|
842 |
if "pretrained" in df_all:
|
843 |
unique_subsets["pretrained"] = sorted(df_all["pretrained"]['label'].unique().tolist())
|
844 |
else:
|
845 |
unique_subsets["pretrained"] = []
|
846 |
+
|
847 |
+
# Obtener mapeo de colores para cada subconjunto (función definida externamente)
|
848 |
color_maps = get_color_maps(unique_subsets)
|
849 |
+
|
850 |
+
# Mapeo de marcadores para synthetic (por source)
|
851 |
marker_mapping = {
|
852 |
"es-digital-paragraph-degradation-seq": "x",
|
853 |
"es-digital-line-degradation-seq": "cross",
|
|
|
856 |
"es-digital-zoom-degradation-seq": "asterisk",
|
857 |
"es-render-seq": "inverted_triangle"
|
858 |
}
|
859 |
+
|
860 |
+
# Plot global: se muestran real, synthetic y pretrained (según checkbox)
|
861 |
+
st.subheader("PCA - Todos los subconjuntos proyectados (PC1 vs PC2)")
|
862 |
fig_all = figure(
|
863 |
title="PCA - Todos los subconjuntos proyectados",
|
864 |
plot_width=600,
|
|
|
868 |
background_fill_color="white",
|
869 |
tooltips=TOOLTIPS
|
870 |
)
|
|
|
871 |
fig_all.xgrid.grid_line_color = None
|
872 |
fig_all.ygrid.grid_line_color = "gray"
|
873 |
+
|
874 |
+
# Plotear las muestras reales, agrupadas por label
|
875 |
for label in unique_subsets["real"]:
|
876 |
subset = df_all["real"][df_all["real"]['label'] == label]
|
877 |
source = ColumnDataSource(data={
|
|
|
880 |
'label': subset['label'],
|
881 |
'img': subset['img']
|
882 |
})
|
|
|
883 |
fig_all.circle('x', 'y', size=10,
|
884 |
fill_color=color_maps["real"][label],
|
885 |
line_color=color_maps["real"][label],
|
886 |
legend_label=f"Real: {label}",
|
887 |
source=source)
|
888 |
+
|
889 |
show_real_only = st.checkbox("Show only real samples", value=True, key=f"show_real_only_{model_name}")
|
|
|
890 |
if not show_real_only:
|
891 |
+
# Agregar synthetic
|
|
|
892 |
if unique_subsets["synthetic"]:
|
893 |
for source_name, labels in unique_subsets["synthetic"].items():
|
894 |
df_source = df_all["synthetic"][df_all["synthetic"]["source"] == source_name]
|
895 |
marker = marker_mapping.get(source_name, "square")
|
896 |
+
# Se usa el mapeo de colores para synthetic
|
897 |
+
color_val = color_maps["synthetic"][source_name]
|
898 |
+
renderers = add_synthetic_dataset_to_fig(
|
899 |
+
fig_all, df_source, labels,
|
900 |
+
marker=marker,
|
901 |
+
color_mapping=color_val,
|
902 |
+
group_label=source_name
|
903 |
+
)
|
904 |
+
# Agregar pretrained
|
905 |
if unique_subsets["pretrained"]:
|
906 |
for label in unique_subsets["pretrained"]:
|
907 |
subset = df_all["pretrained"][df_all["pretrained"]['label'] == label]
|
|
|
911 |
'label': subset['label'],
|
912 |
'img': subset['img']
|
913 |
})
|
|
|
914 |
fig_all.triangle('x', 'y', size=10,
|
915 |
fill_color=color_maps["pretrained"][label],
|
916 |
line_color=color_maps["pretrained"][label],
|
917 |
legend_label=f"Pretrained: {label}",
|
918 |
source=source)
|
919 |
+
|
920 |
+
show_legend_global = st.checkbox("Show Legend", value=False, key=f"legend_global_{model_name}")
|
921 |
+
fig_all.legend.visible = show_legend_global
|
922 |
+
fig_all.legend.location = "top_right"
|
923 |
+
fig_all.match_aspect = True
|
924 |
+
st.bokeh_chart(fig_all)
|
925 |
+
|
926 |
+
# Calcular centroide y radio (usando solo las muestras reales)
|
927 |
center_x = df_all["real"]['x'].mean()
|
928 |
center_y = df_all["real"]['y'].mean()
|
929 |
distances = np.sqrt((df_all["real"]['x'] - center_x)**2 + (df_all["real"]['y'] - center_y)**2)
|
930 |
radius = distances.max()
|
931 |
+
|
932 |
+
# Dibujar el centroide y la circunferencia
|
933 |
centroid_glyph = fig_all.circle(
|
934 |
x=center_x, y=center_y, size=15,
|
935 |
fill_color="white", line_color="black",
|
936 |
legend_label="Centroide",
|
937 |
+
name="centroid"
|
938 |
)
|
|
|
939 |
circumference_glyph = fig_all.circle(
|
940 |
x=center_x, y=center_y, radius=radius,
|
941 |
fill_color=None, line_color="black",
|
942 |
line_dash="dashed",
|
943 |
legend_label="Circunferencia",
|
944 |
+
name="circumference"
|
945 |
)
|
946 |
+
|
947 |
+
# Ajustar ejes y tooltips
|
948 |
fig_all.xaxis.axis_label = "PC1"
|
949 |
fig_all.yaxis.axis_label = "PC2"
|
950 |
hover_all = fig_all.select_one(HoverTool)
|
951 |
hover_all.renderers = [r for r in fig_all.renderers if r.name not in ["centroid", "circumference"]]
|
952 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
953 |
st.write(f"El radio de la circunferencia (calculado a partir de las muestras reales) es: {radius:.4f}")
|
954 |
+
|
955 |
+
# -------------------------------------------------------------------------
|
956 |
+
# Calcular el rango global: recorrer todas las proyecciones de todos los subconjuntos
|
957 |
+
all_vals = []
|
958 |
+
for key in df_all:
|
959 |
+
for comp in [f'PC{i+1}' for i in range(N_COMPONENTS)]:
|
960 |
+
all_vals.append(df_all[key][comp])
|
961 |
+
all_vals = pd.concat(all_vals)
|
962 |
+
# Tomar el máximo valor absoluto de todas las proyecciones
|
963 |
+
max_val = all_vals.abs().max()
|
964 |
+
global_range = (-max_val, max_val)
|
965 |
+
|
966 |
+
# 3. Scatter plots para cada combinación (vistas planta, alzado y perfil)
|
967 |
+
st.subheader("Scatter Plots: Vistas de Componentes (Combinaciones)")
|
968 |
+
pairs = list(itertools.combinations(range(N_COMPONENTS), 2))
|
969 |
+
for (i, j) in pairs:
|
970 |
+
x_comp = f'PC{i+1}'
|
971 |
+
y_comp = f'PC{j+1}'
|
972 |
+
|
973 |
+
st.markdown(f"### Scatter Plot: {x_comp} vs {y_comp}")
|
974 |
+
# Usar el rango global para ambos ejes
|
975 |
+
p = figure(
|
976 |
+
title=f"{x_comp} vs {y_comp}",
|
977 |
+
plot_width=700,
|
978 |
+
plot_height=700,
|
979 |
+
x_range=global_range,
|
980 |
+
y_range=global_range,
|
981 |
+
tools="pan,wheel_zoom,reset,save,hover",
|
982 |
+
active_scroll="wheel_zoom",
|
983 |
+
background_fill_color="white",
|
984 |
+
tooltips=TOOLTIPS
|
985 |
+
)
|
986 |
+
# Etiquetas de ejes
|
987 |
+
p.xaxis.axis_label = x_comp
|
988 |
+
p.yaxis.axis_label = y_comp
|
989 |
+
|
990 |
+
# Muestras reales: se usan directamente los valores de PC{i+1} y PC{j+1}
|
991 |
+
for label in unique_subsets["real"]:
|
992 |
+
subset = df_all["real"][df_all["real"]['label'] == label]
|
993 |
+
source = ColumnDataSource(data={
|
994 |
+
'x': subset[x_comp],
|
995 |
+
'y': subset[y_comp],
|
996 |
+
'label': subset['label'],
|
997 |
+
'img': subset['img']
|
998 |
+
})
|
999 |
+
p.circle('x', 'y', size=10,
|
1000 |
+
fill_color=color_maps["real"][label],
|
1001 |
+
line_color=color_maps["real"][label],
|
1002 |
+
legend_label=f"Real: {label}",
|
1003 |
+
source=source)
|
1004 |
+
|
1005 |
+
# Selector para incluir o no synthetic y pretrained en este gráfico
|
1006 |
+
show_pair_only_real = st.checkbox("Show only real samples", value=True, key=f"pair_show_real_{i}_{j}_{model_name}")
|
1007 |
+
if not show_pair_only_real:
|
1008 |
+
# Synthetic
|
1009 |
+
if "synthetic" in df_all:
|
1010 |
+
for source_name, labels in unique_subsets["synthetic"].items():
|
1011 |
+
# Obtener las filas de synthetic para ese source y asignar el rango adecuado
|
1012 |
+
df_source = df_all["synthetic"][df_all["synthetic"]["source"] == source_name].copy()
|
1013 |
+
df_source["x"] = df_source[x_comp]
|
1014 |
+
df_source["y"] = df_source[y_comp]
|
1015 |
+
marker = marker_mapping.get(source_name, "square")
|
1016 |
+
renderers = add_synthetic_dataset_to_fig(
|
1017 |
+
p, df_source, labels,
|
1018 |
+
marker=marker,
|
1019 |
+
color_mapping=color_maps["synthetic"][source_name],
|
1020 |
+
group_label=source_name
|
1021 |
+
)
|
1022 |
+
# Pretrained
|
1023 |
+
if "pretrained" in df_all:
|
1024 |
+
for label in unique_subsets["pretrained"]:
|
1025 |
+
subset = df_all["pretrained"][df_all["pretrained"]['label'] == label]
|
1026 |
+
source = ColumnDataSource(data={
|
1027 |
+
'x': subset[x_comp],
|
1028 |
+
'y': subset[y_comp],
|
1029 |
+
'label': subset['label'],
|
1030 |
+
'img': subset['img']
|
1031 |
+
})
|
1032 |
+
p.triangle('x', 'y', size=10,
|
1033 |
+
fill_color=color_maps["pretrained"][label],
|
1034 |
+
line_color=color_maps["pretrained"][label],
|
1035 |
+
legend_label=f"Pretrained: {label}",
|
1036 |
+
source=source)
|
1037 |
+
show_legend_pair = st.checkbox("Show Legend", value=False, key=f"legend_pair_{i}_{j}_{model_name}")
|
1038 |
+
p.legend.visible = show_legend_pair
|
1039 |
+
st.bokeh_chart(p)
|
1040 |
|
1041 |
+
|
1042 |
+
# -------------------------------------------------------------------------
|
1043 |
+
# 4. Cálculo de distancias y scatter plot: Distance vs F1 (usando PC1 y PC2 globales)
|
|
|
|
|
1044 |
real_labels_new = sorted(df_all["real"]['label'].unique().tolist())
|
1045 |
df_distances_new = compute_cluster_distances_synthetic_individual(
|
1046 |
df_all["synthetic"],
|
1047 |
df_all["real"],
|
1048 |
real_labels_new,
|
1049 |
+
metric="wasserstein", # O la métrica que prefieras
|
1050 |
bins=20
|
1051 |
)
|
1052 |
+
|
|
|
|
|
1053 |
global_distances_new = {}
|
1054 |
for idx in df_distances_new.index:
|
1055 |
if idx.startswith("Global"):
|
1056 |
source_name = idx.split("(")[1].rstrip(")")
|
1057 |
global_distances_new[source_name] = df_distances_new.loc[idx].values
|
1058 |
+
|
|
|
1059 |
all_x_new = []
|
1060 |
all_y_new = []
|
1061 |
for source in df_f1.columns:
|
|
|
1066 |
all_y_new.extend(y_vals)
|
1067 |
all_x_arr_new = np.array(all_x_new).reshape(-1, 1)
|
1068 |
all_y_arr_new = np.array(all_y_new)
|
1069 |
+
|
|
|
1070 |
model_global_new = LinearRegression().fit(all_x_arr_new, all_y_arr_new)
|
1071 |
r2_new = model_global_new.score(all_x_arr_new, all_y_arr_new)
|
1072 |
slope_new = model_global_new.coef_[0]
|
1073 |
intercept_new = model_global_new.intercept_
|
1074 |
+
|
|
|
1075 |
scatter_fig_new = figure(
|
1076 |
width=600,
|
1077 |
height=600,
|
|
|
1081 |
background_fill_color="white",
|
1082 |
y_range=(0, 1)
|
1083 |
)
|
|
|
1084 |
scatter_fig_new.xgrid.grid_line_color = None
|
1085 |
scatter_fig_new.ygrid.grid_line_color = "gray"
|
1086 |
scatter_fig_new.match_aspect = True
|
1087 |
+
|
|
|
1088 |
source_colors = {
|
1089 |
"es-digital-paragraph-degradation-seq": "blue",
|
1090 |
"es-digital-line-degradation-seq": "green",
|
|
|
1094 |
"es-digital-rotation-zoom-degradation-seq": "brown",
|
1095 |
"es-render-seq": "cyan"
|
1096 |
}
|
1097 |
+
|
|
|
1098 |
for source in df_f1.columns:
|
1099 |
if source in global_distances_new:
|
1100 |
x_vals = global_distances_new[source]
|
|
|
1107 |
line_color=source_colors.get(source, "gray"),
|
1108 |
legend_label=source
|
1109 |
)
|
1110 |
+
|
1111 |
scatter_fig_new.xaxis.axis_label = "Distance (Global, por Colegio) - Nueva PCA"
|
1112 |
scatter_fig_new.yaxis.axis_label = "F1 Score"
|
1113 |
scatter_fig_new.legend.location = "top_right"
|
|
|
1114 |
hover_tool_new = scatter_fig_new.select_one(HoverTool)
|
1115 |
hover_tool_new.tooltips = [("Distance", "@x"), ("F1", "@y"), ("Subset", "@Fuente")]
|
|
|
|
|
1116 |
x_line_new = np.linspace(all_x_arr_new.min(), all_x_arr_new.max(), 100)
|
1117 |
y_line_new = model_global_new.predict(x_line_new.reshape(-1,1))
|
1118 |
scatter_fig_new.line(x_line_new, y_line_new, line_width=2, line_color="black", legend_label="Global Regression")
|
|
|
1119 |
st.bokeh_chart(scatter_fig_new)
|
|
|
1120 |
st.write(f"Regresión global (Nueva PCA): R² = {r2_new:.4f}, Slope = {slope_new:.4f}, Intercept = {intercept_new:.4f}")
|
1121 |
+
|
1122 |
+
# -------------------------------------------------------------------------
|
1123 |
+
# 5. BLOQUE: Heatmap de Características
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1124 |
st.markdown("## Heatmap de Características")
|
|
|
1125 |
try:
|
1126 |
df_heat = pd.read_csv("data/heatmaps.csv")
|
|
|
|
|
1127 |
except Exception as e:
|
1128 |
st.error(f"Error al cargar heatmaps.csv: {e}")
|
1129 |
df_heat = None
|
1130 |
+
|
1131 |
if df_heat is not None:
|
|
|
1132 |
if 'img' not in df_all["real"].columns:
|
1133 |
st.error("La columna 'img' no se encuentra en las muestras reales para hacer el merge con heatmaps.csv.")
|
1134 |
else:
|
1135 |
+
# Crear columna 'name' a partir del nombre final de la URL de la imagen
|
1136 |
df_all["real"]["name"] = df_all["real"]["img"].apply(
|
1137 |
lambda x: x.split("/")[-1].replace(".png", "") if isinstance(x, str) else x
|
1138 |
)
|
1139 |
+
# Realizar merge de las posiciones reales con el CSV de heatmaps
|
|
|
1140 |
df_heatmap = pd.merge(df_all["real"], df_heat, on="name", how="inner")
|
1141 |
|
1142 |
+
# Extraer las características disponibles (excluyendo 'name')
|
1143 |
feature_options = [col for col in df_heat.columns if col != "name"]
|
1144 |
selected_feature = st.selectbox("Select heatmap feature:",
|
1145 |
options=feature_options, key=f"heatmap_{model_name}")
|
|
|
1146 |
select_extra_dataset_hm = st.selectbox("Select a dataset:",
|
1147 |
options=["-", "es-digital-line-degradation-seq", "es-digital-seq", "es-digital-rotation-degradation-seq", "es-digital-zoom-degradation-seq", "es-render-seq"], key=f"heatmap_extra_dataset_{model_name}")
|
1148 |
|
1149 |
+
# Definir el rango de posiciones (x, y)
|
1150 |
x_min, x_max = df_heatmap['x'].min(), df_heatmap['x'].max()
|
1151 |
y_min, y_max = df_heatmap['y'].min(), df_heatmap['y'].max()
|
1152 |
|
|
|
1153 |
grid_size = 50
|
1154 |
x_bins = np.linspace(x_min, x_max, grid_size + 1)
|
1155 |
y_bins = np.linspace(y_min, y_max, grid_size + 1)
|
1156 |
|
|
|
|
|
1157 |
cat_mapping = None
|
1158 |
if df_heatmap[selected_feature].dtype == bool or not pd.api.types.is_numeric_dtype(df_heatmap[selected_feature]):
|
1159 |
cat = df_heatmap[selected_feature].astype('category')
|
1160 |
cat_mapping = list(cat.cat.categories)
|
1161 |
df_heatmap[selected_feature] = cat.cat.codes
|
1162 |
|
|
|
1163 |
try:
|
1164 |
heat_stat, x_edges, y_edges, binnumber = binned_statistic_2d(
|
1165 |
df_heatmap['x'], df_heatmap['y'], df_heatmap[selected_feature],
|
|
|
1174 |
statistic='mean', bins=[x_bins, y_bins]
|
1175 |
)
|
1176 |
|
1177 |
+
# Transponer la matriz para alinear correctamente los ejes
|
1178 |
heatmap_data = heat_stat.T
|
1179 |
|
1180 |
+
color_mapper = LinearColorMapper(palette="Viridis256", low=np.nanmin(heatmap_data), high=np.nanmax(heatmap_data), nan_color='rgba(0, 0, 0, 0)')
|
|
|
1181 |
|
|
|
1182 |
heatmap_fig = figure(title=f"Heatmap de '{selected_feature}'",
|
1183 |
x_range=(x_min, x_max), y_range=(y_min, y_max),
|
1184 |
width=600, height=600,
|
1185 |
tools="pan,wheel_zoom,reset,save", active_scroll="wheel_zoom", tooltips=TOOLTIPS)
|
|
|
|
|
1186 |
heatmap_fig.image(image=[heatmap_data], x=x_min, y=y_min,
|
1187 |
dw=x_max - x_min, dh=y_max - y_min,
|
1188 |
color_mapper=color_mapper)
|
1189 |
|
|
|
1190 |
color_bar = ColorBar(color_mapper=color_mapper, location=(0, 0))
|
|
|
1191 |
if cat_mapping is not None:
|
|
|
|
|
1192 |
ticks = list(range(len(cat_mapping)))
|
1193 |
color_bar.ticker = FixedTicker(ticks=ticks)
|
|
|
1194 |
categories_json = json.dumps(cat_mapping)
|
1195 |
color_bar.formatter = FuncTickFormatter(code=f"""
|
1196 |
var categories = {categories_json};
|
|
|
1202 |
}}
|
1203 |
""")
|
1204 |
heatmap_fig.add_layout(color_bar, 'right')
|
1205 |
+
|
|
|
|
|
|
|
1206 |
source_points = ColumnDataSource(data={
|
1207 |
'x': df_heatmap['x'],
|
1208 |
'y': df_heatmap['y'],
|
1209 |
'img': df_heatmap['img'],
|
1210 |
+
'label': df_heatmap['name']
|
1211 |
})
|
|
|
1212 |
invisible_renderer = heatmap_fig.circle('x', 'y', size=10, source=source_points, fill_alpha=0, line_alpha=0.5)
|
1213 |
+
|
1214 |
if select_extra_dataset_hm != "-":
|
1215 |
df_extra = df_all["synthetic"][df_all["synthetic"]["source"] == select_extra_dataset_hm]
|
|
|
1216 |
if 'name' not in df_extra.columns:
|
1217 |
df_extra["name"] = df_extra["img"].apply(
|
1218 |
lambda x: x.split("/")[-1].replace(".png", "") if isinstance(x, str) else x
|
|
|
1223 |
'img': df_extra['img'],
|
1224 |
'label': df_extra['name']
|
1225 |
})
|
|
|
1226 |
extra_renderer = heatmap_fig.circle('x', 'y', size=10, source=source_extra_points, fill_alpha=0, line_alpha=0.5, color="red")
|
1227 |
+
|
1228 |
hover_tool_points = HoverTool(renderers=[invisible_renderer], tooltips=TOOLTIPS)
|
1229 |
heatmap_fig.add_tools(hover_tool_points)
|
1230 |
|