devjas1 commited on
Commit
81ec5ec
·
1 Parent(s): 5054409

(FEAT)[Add Spectrum Modality Validation in Input]:

Browse files

- Integrated `validate_spectrum_modality` to check if input spectrum matches selected modality.
- Added warnings and user confirmation for modality-spectrum mismatch in `render_input_column`.
- Users can stop or continue with mismatched data.

(FEAT)[Spectrum Modality Validation in Comparison Tab]:
- Added validation before comparison analysis; displays errors if modality does not match spectrum.
- Prevents further processing upon validation failure.

(REFACTOR)[Independent Modality State for Comparison Tab]:
- Changed modality selector key to "`comparison_tab_modality`" for isolated state.
- Avoids unintended overwrites of main modality session state.

(FIX)[Graceful Handling of Empty Comparison Data]:
- Added warnings for missing confidence/performance data in comparison tab.
- Visualization/stats are now only shown when data is present.

Files changed (1) hide show
  1. modules/ui_components.py +139 -98
modules/ui_components.py CHANGED
@@ -27,7 +27,7 @@ from core_logic import (
27
  )
28
  from utils.results_manager import ResultsManager
29
  from utils.multifile import process_multiple_files
30
- from utils.preprocessing import resample_spectrum
31
  from utils.confidence import calculate_softmax_confidence
32
 
33
 
@@ -406,6 +406,30 @@ def render_input_column():
406
  else:
407
  try:
408
  x_raw, y_raw = parse_spectrum_data(st.session_state["input_text"])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  x_resampled, y_resampled = resample_spectrum(x_raw, y_raw, TARGET_LEN)
410
  st.session_state.update(
411
  {
@@ -932,18 +956,10 @@ def render_results_column():
932
 
933
  ##### Supported Data Format
934
 
935
- - **File Type:** Plain text (`.txt`)
936
  - **Content:** Must contain two columns: `wavenumber` and `intensity`.
937
  - **Separators:** Values can be separated by spaces or commas.
938
  - **Preprocessing:** Your spectrum will be automatically resampled to 500 data points to match the model's input requirements.
939
-
940
- ---
941
-
942
- ##### Example Applications
943
- - 🔬 Research on polymer degradation
944
- - ♻️ Recycling feasibility assessment
945
- - 🌱 Sustainability impact studies
946
- - 🏭 Quality control in manufacturing
947
  """
948
  )
949
  else:
@@ -963,18 +979,10 @@ def render_results_column():
963
 
964
  ##### Supported Data Format
965
 
966
- - **File Type:** Plain text (`.txt`)
967
  - **Content:** Must contain two columns: `wavenumber` and `intensity`.
968
  - **Separators:** Values can be separated by spaces or commas.
969
  - **Preprocessing:** Your spectrum will be automatically resampled to 500 data points to match the model's input requirements.
970
-
971
- ---
972
-
973
- ##### Example Applications
974
- - 🔬 Research on polymer degradation
975
- - ♻️ Recycling feasibility assessment
976
- - 🌱 Sustainability impact studies
977
- - 🏭 Quality control in manufacturing
978
  """
979
  )
980
 
@@ -1004,19 +1012,18 @@ def render_comparison_tab():
1004
  "Compare predictions across different AI models for comprehensive analysis."
1005
  )
1006
 
1007
- # Modality selector
1008
  col_mod1, col_mod2 = st.columns([1, 2])
1009
  with col_mod1:
 
 
1010
  modality = st.selectbox(
1011
  "Select Modality",
1012
  ["raman", "ftir"],
1013
- index=0,
1014
  help="Choose the spectroscopy modality for analysis",
1015
- key="comparison_modality",
1016
- )
1017
- # Don't override existing session state
1018
- if "modality_select" not in st.session_state:
1019
- st.session_state["modality_select"] = modality
1020
 
1021
  with col_mod2:
1022
  # Filter models by modality
@@ -1123,6 +1130,19 @@ def render_comparison_tab():
1123
  str(input_text), filename or "unknown_filename"
1124
  )
1125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1126
  # Preprocess spectrum once
1127
  _, y_processed = preprocess_spectrum(
1128
  x_raw, y_raw, modality=modality, target_len=500
@@ -1272,52 +1292,68 @@ def render_comparison_tab():
1272
  for m in models
1273
  ]
1274
 
1275
- fig, ax = plt.subplots(figsize=(8, 5))
1276
- colors = plt.cm.Set3(
1277
- np.linspace(0, 1, len(models))
1278
- )
1279
- bars = ax.bar(
1280
- models,
1281
- confidences,
1282
- alpha=0.8,
1283
- color=colors,
1284
- )
1285
 
1286
- # Add value labels on bars
1287
- for bar, conf in zip(bars, confidences):
1288
- height = bar.get_height()
1289
- ax.text(
1290
- bar.get_x() + bar.get_width() / 2.0,
1291
- height + 0.01,
1292
- f"{conf:.3f}",
1293
- ha="center",
1294
- va="bottom",
1295
  )
1296
 
1297
- ax.set_ylabel("Confidence")
1298
- ax.set_title("Model Confidence Comparison")
1299
- ax.set_ylim(0, 1.1)
1300
- plt.xticks(rotation=45)
1301
- plt.tight_layout()
1302
- st.pyplot(fig)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1303
 
1304
  with col2:
1305
  # Confidence distribution
1306
  st.markdown("**Confidence Statistics**")
1307
- conf_stats = {
1308
- "Mean": np.mean(confidences),
1309
- "Std Dev": np.std(confidences),
1310
- "Min": np.min(confidences),
1311
- "Max": np.max(confidences),
1312
- "Range": np.max(confidences)
1313
- - np.min(confidences),
1314
- }
1315
-
1316
- for stat, value in conf_stats.items():
1317
- st.metric(stat, f"{value:.4f}")
1318
- except Exception as e:
 
 
 
 
 
 
1319
  st.error(f"Error rendering results: {e}")
1320
- except Exception as e:
 
1321
  st.error(f"Error rendering results: {e}")
1322
  st.error(f"Error in Confidence Analysis tab: {e}")
1323
 
@@ -1328,45 +1364,50 @@ def render_comparison_tab():
1328
  successful_results[m]["processing_time"]
1329
  for m in models
1330
  ]
1331
-
1332
- perf_col1, perf_col2 = st.columns(2)
1333
-
1334
- with perf_col1:
1335
- # Processing time comparison
1336
- fig, ax = plt.subplots(figsize=(8, 5))
1337
- bars = ax.bar(
1338
- models, times, alpha=0.8, color="skyblue"
1339
  )
 
 
 
1340
 
1341
- for bar, time_val in zip(bars, times):
1342
- height = bar.get_height()
1343
- ax.text(
1344
- bar.get_x() + bar.get_width() / 2.0,
1345
- height + 0.001,
1346
- f"{time_val:.3f}s",
1347
- ha="center",
1348
- va="bottom",
1349
  )
1350
 
1351
- ax.set_ylabel("Processing Time (s)")
1352
- ax.set_title("Model Processing Time Comparison")
1353
- plt.xticks(rotation=45)
1354
- plt.tight_layout()
1355
- st.pyplot(fig)
1356
-
1357
- with perf_col2:
1358
- # Performance statistics
1359
- st.markdown("**Performance Statistics**")
1360
- perf_stats = {
1361
- "Fastest Model": models[np.argmin(times)],
1362
- "Slowest Model": models[np.argmax(times)],
1363
- "Total Time": f"{np.sum(times):.3f}s",
1364
- "Average Time": f"{np.mean(times):.3f}s",
1365
- "Speed Difference": f"{np.max(times) - np.min(times):.3f}s",
1366
- }
1367
 
1368
- for stat, value in perf_stats.items():
1369
- st.write(f"**{stat}**: {value}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1370
 
1371
  with tab3:
1372
  # Detailed breakdown
 
27
  )
28
  from utils.results_manager import ResultsManager
29
  from utils.multifile import process_multiple_files
30
+ from utils.preprocessing import resample_spectrum, validate_spectrum_modality
31
  from utils.confidence import calculate_softmax_confidence
32
 
33
 
 
406
  else:
407
  try:
408
  x_raw, y_raw = parse_spectrum_data(st.session_state["input_text"])
409
+
410
+ # Validate that spectrum matches selected modality
411
+ selected_modality = st.session_state.get("modality_select", "raman")
412
+ is_valid, issues = validate_spectrum_modality(
413
+ x_raw, y_raw, selected_modality
414
+ )
415
+
416
+ if not is_valid:
417
+ st.warning("⚠️ **Spectrum-Modality Mismatch Detected**")
418
+ for issue in issues:
419
+ st.warning(f"• {issue}")
420
+
421
+ # Ask user if they want to continue
422
+ st.info(
423
+ "💡 **Suggestion**: Check if the correct modality is selected in the sidebar, or verify your data file."
424
+ )
425
+
426
+ if st.button("⚠️ Continue Anyway", key="continue_with_mismatch"):
427
+ st.warning(
428
+ "Proceeding with potentially mismatched data. Results may be unreliable."
429
+ )
430
+ else:
431
+ st.stop() # Stop processing until user confirms
432
+
433
  x_resampled, y_resampled = resample_spectrum(x_raw, y_raw, TARGET_LEN)
434
  st.session_state.update(
435
  {
 
956
 
957
  ##### Supported Data Format
958
 
959
+ - **File Type(s):** `.txt`, `.csv`, `.json`
960
  - **Content:** Must contain two columns: `wavenumber` and `intensity`.
961
  - **Separators:** Values can be separated by spaces or commas.
962
  - **Preprocessing:** Your spectrum will be automatically resampled to 500 data points to match the model's input requirements.
 
 
 
 
 
 
 
 
963
  """
964
  )
965
  else:
 
979
 
980
  ##### Supported Data Format
981
 
982
+ - **File Type(s):** `.txt`, `.csv`, `.json`
983
  - **Content:** Must contain two columns: `wavenumber` and `intensity`.
984
  - **Separators:** Values can be separated by spaces or commas.
985
  - **Preprocessing:** Your spectrum will be automatically resampled to 500 data points to match the model's input requirements.
 
 
 
 
 
 
 
 
986
  """
987
  )
988
 
 
1012
  "Compare predictions across different AI models for comprehensive analysis."
1013
  )
1014
 
1015
+ # Modality selector - Use independant state for comparison tab
1016
  col_mod1, col_mod2 = st.columns([1, 2])
1017
  with col_mod1:
1018
+ # Get the current sidebar modality but don't try to sync back
1019
+ current_modality = st.session_state.get("modality_select", "raman")
1020
  modality = st.selectbox(
1021
  "Select Modality",
1022
  ["raman", "ftir"],
1023
+ index=0 if current_modality == "raman" else 1,
1024
  help="Choose the spectroscopy modality for analysis",
1025
+ key="comparison_tab_modality", # Independant key for session state to avoid duplication of UI elements
1026
+ ) # Note: Intentially not synching back to avoid state conflicts
 
 
 
1027
 
1028
  with col_mod2:
1029
  # Filter models by modality
 
1130
  str(input_text), filename or "unknown_filename"
1131
  )
1132
 
1133
+ # Validate spectrum modality
1134
+ is_valid, issues = validate_spectrum_modality(
1135
+ x_raw, y_raw, modality
1136
+ )
1137
+ if not is_valid:
1138
+ st.error("**Spectrum-Modality Mismatch in Comparison**")
1139
+ for issue in issues:
1140
+ st.error(f"• {issue}")
1141
+ st.info(
1142
+ "Please check the selected modality or verify your data file."
1143
+ )
1144
+ return # Exit comparison if validation fails
1145
+
1146
  # Preprocess spectrum once
1147
  _, y_processed = preprocess_spectrum(
1148
  x_raw, y_raw, modality=modality, target_len=500
 
1292
  for m in models
1293
  ]
1294
 
1295
+ if len(confidences) == 0:
1296
+ st.warning(
1297
+ "No confidence data available for visualization."
1298
+ )
1299
+ else:
1300
+ fig, ax = plt.subplots(figsize=(8, 5))
1301
+ colors = plt.cm.Set3(
1302
+ np.linspace(0, 1, len(models))
1303
+ )
 
1304
 
1305
+ bars = ax.bar(
1306
+ models,
1307
+ confidences,
1308
+ alpha=0.8,
1309
+ color=colors,
 
 
 
 
1310
  )
1311
 
1312
+ # Add value labels on bars
1313
+ for bar, conf in zip(bars, confidences):
1314
+ height = bar.get_height()
1315
+ ax.text(
1316
+ bar.get_x()
1317
+ + bar.get_width() / 2.0,
1318
+ height + 0.01,
1319
+ f"{conf:.3f}",
1320
+ ha="center",
1321
+ va="bottom",
1322
+ )
1323
+
1324
+ ax.set_ylabel("Confidence")
1325
+ ax.set_title(
1326
+ "Model Confidence Comparison"
1327
+ )
1328
+ ax.set_ylim(0, 1.1)
1329
+ plt.xticks(rotation=45)
1330
+ plt.tight_layout()
1331
+ st.pyplot(fig)
1332
 
1333
  with col2:
1334
  # Confidence distribution
1335
  st.markdown("**Confidence Statistics**")
1336
+ if len(confidences) == 0:
1337
+ st.warning(
1338
+ "No confidence data available for statistics."
1339
+ )
1340
+ else:
1341
+ conf_stats = {
1342
+ "Mean": np.mean(confidences),
1343
+ "Std Dev": np.std(confidences),
1344
+ "Min": np.min(confidences),
1345
+ "Max": np.max(confidences),
1346
+ "Range": np.max(confidences)
1347
+ - np.min(confidences),
1348
+ }
1349
+
1350
+ for stat, value in conf_stats.items():
1351
+ st.metric(stat, f"{value:.4f}")
1352
+
1353
+ except ValueError as e:
1354
  st.error(f"Error rendering results: {e}")
1355
+
1356
+ except ValueError as e:
1357
  st.error(f"Error rendering results: {e}")
1358
  st.error(f"Error in Confidence Analysis tab: {e}")
1359
 
 
1364
  successful_results[m]["processing_time"]
1365
  for m in models
1366
  ]
1367
+ if len(times) == 0:
1368
+ st.warning(
1369
+ "No performance data available for visualization"
 
 
 
 
 
1370
  )
1371
+ else:
1372
+
1373
+ perf_col1, perf_col2 = st.columns(2)
1374
 
1375
+ with perf_col1:
1376
+ # Processing time comparison
1377
+ fig, ax = plt.subplots(figsize=(8, 5))
1378
+ bars = ax.bar(
1379
+ models, times, alpha=0.8, color="skyblue"
 
 
 
1380
  )
1381
 
1382
+ for bar, time_val in zip(bars, times):
1383
+ height = bar.get_height()
1384
+ ax.text(
1385
+ bar.get_x() + bar.get_width() / 2.0,
1386
+ height + 0.001,
1387
+ f"{time_val:.3f}s",
1388
+ ha="center",
1389
+ va="bottom",
1390
+ )
 
 
 
 
 
 
 
1391
 
1392
+ ax.set_ylabel("Processing Time (s)")
1393
+ ax.set_title("Model Processing Time Comparison")
1394
+ plt.xticks(rotation=45)
1395
+ plt.tight_layout()
1396
+ st.pyplot(fig)
1397
+
1398
+ with perf_col2:
1399
+ # Performance statistics
1400
+ st.markdown("**Performance Statistics**")
1401
+ perf_stats = {
1402
+ "Fastest Model": models[np.argmin(times)],
1403
+ "Slowest Model": models[np.argmax(times)],
1404
+ "Total Time": f"{np.sum(times):.3f}s",
1405
+ "Average Time": f"{np.mean(times):.3f}s",
1406
+ "Speed Difference": f"{np.max(times) - np.min(times):.3f}s",
1407
+ }
1408
+
1409
+ for stat, value in perf_stats.items():
1410
+ st.write(f"**{stat}**: {value}")
1411
 
1412
  with tab3:
1413
  # Detailed breakdown