acmc commited on
Commit
b410269
Β·
verified Β·
1 Parent(s): d6b031d

Update streamlit_app.py

Browse files
Files changed (1) hide show
  1. streamlit_app.py +98 -257
streamlit_app.py CHANGED
@@ -416,239 +416,88 @@ def main():
416
  )
417
  st.stop()
418
 
419
- # Metric selection
420
- st.sidebar.header("πŸ“Š Metrics")
421
-
422
- # Dynamic metric categorization based on common patterns
423
- def categorize_metrics(metrics):
424
- """Dynamically categorize metrics based on naming patterns"""
425
- categories = {"All": metrics} # Always include all metrics
426
-
427
- # Common patterns to look for
428
- patterns = {
429
- "Length": ["length", "byte", "word", "token", "char"],
430
- "Readability": ["readability", "flesch", "standard"],
431
- "Compression": ["lzw", "compression"],
432
- "Language Model": ["ll_", "rll_", "logprob"],
433
- "Working Memory": ["wm_"],
434
- "Discourse": ["discourse"],
435
- "Evaluation": ["rubric", "evaluation", "stealth"],
436
- "Distribution": ["zipf", "type_token"],
437
- "Coherence": ["coherence"],
438
- "Entity": ["entity", "entities"],
439
- "Cognitive": ["cognitive", "load"],
440
- }
441
-
442
- # Categorize metrics
443
- for category, keywords in patterns.items():
444
- matching_metrics = [
445
- m for m in metrics if any(keyword in m.lower() for keyword in keywords)
446
- ]
447
- if matching_metrics:
448
- categories[category] = matching_metrics
449
-
450
- # Find uncategorized metrics
451
- categorized = set()
452
- for cat_metrics in categories.values():
453
- if cat_metrics != metrics: # Skip "All" category
454
- categorized.update(cat_metrics)
455
-
456
- uncategorized = [m for m in metrics if m not in categorized]
457
- if uncategorized:
458
- categories["Other"] = uncategorized
459
-
460
- return categories
461
-
462
- metric_categories = categorize_metrics(available_metrics)
463
-
464
- # Metric selection interface
465
- selection_mode = st.sidebar.radio(
466
- "Selection Mode",
467
- ["By Category", "Search/Filter", "Select All"],
468
- help="Choose how to select metrics",
469
- )
470
-
471
- if selection_mode == "By Category":
472
- selected_category = st.sidebar.selectbox(
473
- "Metric Category",
474
- options=list(metric_categories.keys()),
475
- help=f"Found {len(metric_categories)} categories",
476
- )
477
-
478
- available_in_category = metric_categories[selected_category]
479
- default_selection = (
480
- available_in_category[:5]
481
- if len(available_in_category) > 5
482
- else available_in_category
483
- )
484
-
485
- # Add select all button for category
486
- col1, col2 = st.sidebar.columns(2)
487
- with col1:
488
- if st.button("Select All", key="select_all_category"):
489
- st.session_state.selected_metrics_category = available_in_category
490
- with col2:
491
- if st.button("Clear All", key="clear_all_category"):
492
- st.session_state.selected_metrics_category = []
493
-
494
- # Use session state for persistence
495
- if "selected_metrics_category" not in st.session_state:
496
- st.session_state.selected_metrics_category = default_selection
497
-
498
- selected_metrics = st.sidebar.multiselect(
499
- f"Select Metrics ({len(available_in_category)} available)",
500
- options=available_in_category,
501
- default=st.session_state.selected_metrics_category,
502
- key="metrics_multiselect_category",
503
- help="Choose metrics to visualize",
504
- )
505
-
506
- elif selection_mode == "Search/Filter":
507
- search_term = st.sidebar.text_input(
508
- "Search Metrics",
509
- placeholder="Enter keywords to filter metrics...",
510
- help="Search for metrics containing specific terms",
511
- )
512
-
513
- if search_term:
514
- filtered_metrics = [
515
- m for m in available_metrics if search_term.lower() in m.lower()
516
- ]
517
- else:
518
- filtered_metrics = available_metrics
519
-
520
- st.sidebar.write(f"Found {len(filtered_metrics)} metrics")
521
-
522
- # Add select all button for search results
523
- col1, col2 = st.sidebar.columns(2)
524
- with col1:
525
- if st.button("Select All", key="select_all_search"):
526
- st.session_state.selected_metrics_search = filtered_metrics
527
- with col2:
528
- if st.button("Clear All", key="clear_all_search"):
529
- st.session_state.selected_metrics_search = []
530
-
531
- # Use session state for persistence
532
- if "selected_metrics_search" not in st.session_state:
533
- st.session_state.selected_metrics_search = (
534
- filtered_metrics[:5]
535
- if len(filtered_metrics) > 5
536
- else filtered_metrics[:3]
537
- )
538
-
539
- selected_metrics = st.sidebar.multiselect(
540
- "Select Metrics",
541
- options=filtered_metrics,
542
- default=st.session_state.selected_metrics_search,
543
- key="metrics_multiselect_search",
544
- help="Choose metrics to visualize",
545
- )
546
-
547
- else: # Select All
548
- # Add select all button for all metrics
549
- col1, col2 = st.sidebar.columns(2)
550
- with col1:
551
- if st.button("Select All", key="select_all_all"):
552
- st.session_state.selected_metrics_all = available_metrics
553
- with col2:
554
- if st.button("Clear All", key="clear_all_all"):
555
- st.session_state.selected_metrics_all = []
556
-
557
- # Use session state for persistence
558
- if "selected_metrics_all" not in st.session_state:
559
- st.session_state.selected_metrics_all = available_metrics[
560
- :10
561
- ] # Limit default to first 10 for performance
562
-
563
- selected_metrics = st.sidebar.multiselect(
564
- f"All Metrics ({len(available_metrics)} total)",
565
- options=available_metrics,
566
- default=st.session_state.selected_metrics_all,
567
- key="metrics_multiselect_all",
568
- help="All available metrics - be careful with performance for large selections",
569
- )
570
-
571
- # Show selection summary
572
- if selected_metrics:
573
- st.sidebar.success(f"Selected {len(selected_metrics)} metrics")
574
-
575
- # Performance warning for large selections
576
- if len(selected_metrics) > 20:
577
- st.sidebar.warning(
578
- f"⚠️ Large selection ({len(selected_metrics)} metrics) may impact performance"
579
- )
580
- elif len(selected_metrics) > 50:
581
- st.sidebar.error(
582
- f"🚨 Very large selection ({len(selected_metrics)} metrics) - consider reducing for better performance"
583
- )
584
- else:
585
- st.sidebar.warning("No metrics selected")
586
-
587
- # Metric info expander
588
- with st.sidebar.expander("ℹ️ Metric Information", expanded=False):
589
- st.write(f"**Total Available Metrics:** {len(available_metrics)}")
590
- st.write(f"**Categories Found:** {len(metric_categories)}")
591
-
592
- if st.checkbox("Show all metric names", key="show_all_metrics"):
593
- st.write("**All Available Metrics:**")
594
- for i, metric in enumerate(available_metrics, 1):
595
- st.write(f"{i}. `{metric}`")
596
-
597
  # Main content tabs
598
  tab1, tab2, tab3, tab4, tab5 = st.tabs(
599
  [
600
  "πŸ“Š Distributions",
601
- "πŸ”— Correlations",
602
  "πŸ“ˆ Comparisons",
603
  "πŸ” Conversation",
604
  "🎯 Details",
605
  ]
606
  )
607
 
 
 
 
608
  with tab1:
609
  st.header("Distribution Analysis")
610
-
611
- if not selected_metrics:
612
- st.warning("Please select at least one metric to visualize.")
613
- return
614
-
615
- # Create buttons for each metric to prevent loading all at once
616
- st.info(
617
- f"πŸ“Š Select a metric to plot its distribution ({len(selected_metrics)} metrics available)"
 
 
618
  )
 
 
 
 
 
 
 
 
619
 
620
- # Organize buttons in columns for better layout
621
- cols_per_row = 3
622
- for i in range(0, len(selected_metrics), cols_per_row):
623
- cols = st.columns(cols_per_row)
624
- for j, metric in enumerate(selected_metrics[i : i + cols_per_row]):
625
- with cols[j]:
626
- friendly_name = get_human_friendly_metric_name(metric)
627
- # Truncate button text if too long
628
- button_text = (
629
- friendly_name[:25] + "..."
630
- if len(friendly_name) > 25
631
- else friendly_name
632
- )
633
-
634
- if st.button(
635
- f"πŸ“ˆ {button_text}",
636
- key=f"plot_{metric}",
637
- help=f"Plot distribution for {friendly_name}",
638
- ):
639
- render_metric_distribution(
640
- metric, filtered_df_exploded, selected_types
641
  )
642
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
643
  with tab2:
644
  st.header("Correlation Analysis")
645
 
646
- if len(selected_metrics) < 2:
647
  st.warning("Please select at least 2 metrics for correlation analysis.")
648
  else:
649
  # Add button to trigger correlation analysis
650
  st.info(
651
- f"πŸ”— Ready to analyze correlations between {len(selected_metrics)} metrics"
652
  )
653
 
654
  col1, col2 = st.columns([1, 3])
@@ -658,15 +507,15 @@ def main():
658
  help="Calculate and display correlation matrix and scatter plots",
659
  )
660
  with col2:
661
- if len(selected_metrics) > 10:
662
  st.warning(
663
- f"⚠️ Large analysis ({len(selected_metrics)} metrics) - may take some time"
664
  )
665
 
666
  if run_correlation:
667
  with st.spinner("Calculating correlations..."):
668
  # Prepare correlation data
669
- corr_columns = [f"turn.turn_metrics.{m}" for m in selected_metrics]
670
  corr_data = filtered_df_exploded[corr_columns + ["type"]].copy()
671
 
672
  # Clean column names for display
@@ -739,11 +588,11 @@ def main():
739
  with tab3:
740
  st.header("Type Comparisons")
741
 
742
- if not selected_metrics:
743
  st.warning("Please select at least one metric to compare.")
744
  else:
745
  # Box plots for each metric
746
- for metric in selected_metrics:
747
  full_metric_name = f"turn.turn_metrics.{metric}"
748
 
749
  if full_metric_name not in filtered_df_exploded.columns:
@@ -777,53 +626,45 @@ def main():
777
  # Conversation selector
778
  st.subheader("πŸ” Select Conversation")
779
 
780
- # Get unique conversations with some metadata
781
- conversation_info = []
782
- for idx, row in filtered_df.iterrows():
783
- conv_type = row["type"]
784
- # Get basic info about the conversation
785
- conv_turns = len(row.get("conversation", []))
786
- conversation_info.append(
787
- {
788
- "index": idx,
789
- "type": conv_type,
790
- "turns": conv_turns,
791
- "display": f"Conversation {idx} ({conv_type}) - {conv_turns} turns",
792
- }
793
- )
794
-
795
- # Sort by type and number of turns for better organization
796
- conversation_info = sorted(
797
- conversation_info, key=lambda x: (x["type"], -x["turns"])
798
- )
799
 
800
- # Conversation selection
801
- col1, col2 = st.columns([3, 1])
802
 
803
  with col1:
804
- selected_conv_display = st.selectbox(
805
- "Choose a conversation to analyze",
806
- options=[conv["display"] for conv in conversation_info],
807
- help="Select a conversation to view detailed metrics and content",
 
 
 
808
  )
809
 
810
  with col2:
811
  if st.button("🎲 Random", help="Select a random conversation"):
812
  import random
813
-
814
- selected_conv_display = random.choice(
815
- [conv["display"] for conv in conversation_info]
816
- )
817
  st.rerun()
 
 
 
 
 
 
 
 
818
 
819
- # Get the selected conversation data
820
- selected_conv_info = next(
821
- conv
822
- for conv in conversation_info
823
- if conv["display"] == selected_conv_display
824
- )
825
- selected_idx = selected_conv_info["index"]
826
- selected_conversation = filtered_df.iloc[selected_idx]
827
 
828
  # Display conversation metadata
829
  st.subheader("πŸ“‹ Conversation Overview")
@@ -979,7 +820,7 @@ def main():
979
  st.subheader("πŸ’¬ Conversation with Metrics")
980
 
981
  # Get actual turn-level data for this conversation
982
- turn_metric_columns = [f"turn.turn_metrics.{m}" for m in selected_metrics]
983
  available_columns = [
984
  col
985
  for col in turn_metric_columns
@@ -1200,7 +1041,7 @@ def main():
1200
  "No numeric metric data available to plot for this conversation type."
1201
  )
1202
 
1203
- elif selected_metrics:
1204
  st.info(
1205
  "Select metrics that are available in the dataset to see turn-level analysis."
1206
  )
@@ -1223,7 +1064,7 @@ def main():
1223
  help="Generate comprehensive dataset overview and metric analysis",
1224
  )
1225
  with col2:
1226
- if len(selected_metrics) > 20:
1227
  st.warning("⚠️ Large metric selection - analysis may take some time")
1228
 
1229
  if show_details:
@@ -1263,7 +1104,7 @@ def main():
1263
  if st.checkbox("Show raw data sample"):
1264
  sample_cols = ["type"] + [
1265
  f"turn.turn_metrics.{m}"
1266
- for m in selected_metrics
1267
  if f"turn.turn_metrics.{m}" in filtered_df_exploded.columns
1268
  ]
1269
  sample_data = filtered_df_exploded[sample_cols].head(100)
@@ -1273,7 +1114,7 @@ def main():
1273
  st.subheader("πŸ“Š Metric Availability")
1274
 
1275
  metric_completeness = {}
1276
- for metric in selected_metrics:
1277
  full_metric_name = f"turn.turn_metrics.{metric}"
1278
  if full_metric_name in filtered_df_exploded.columns:
1279
  completeness = (
 
416
  )
417
  st.stop()
418
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  # Main content tabs
420
  tab1, tab2, tab3, tab4, tab5 = st.tabs(
421
  [
422
  "πŸ“Š Distributions",
423
+ "πŸ”— Correlations",
424
  "πŸ“ˆ Comparisons",
425
  "πŸ” Conversation",
426
  "🎯 Details",
427
  ]
428
  )
429
 
430
+ # Make available metrics accessible to all tabs
431
+ available_metrics_for_analysis = available_metrics
432
+
433
  with tab1:
434
  st.header("Distribution Analysis")
435
+
436
+ # Simple metric selection - just show all metrics with checkboxes
437
+ st.subheader("πŸ“Š Select Metrics to Plot")
438
+ st.info(f"**{len(available_metrics)} metrics available** - Check the boxes below to plot their distributions")
439
+
440
+ # Optional: Add search functionality to help users find metrics
441
+ search_term = st.text_input(
442
+ "πŸ” Search metrics (optional)",
443
+ placeholder="Enter keywords to filter metrics...",
444
+ help="Search for metrics containing specific terms"
445
  )
446
+
447
+ if search_term:
448
+ filtered_metrics = [
449
+ m for m in available_metrics if search_term.lower() in m.lower()
450
+ ]
451
+ st.write(f"**{len(filtered_metrics)} metrics** match your search")
452
+ else:
453
+ filtered_metrics = available_metrics
454
 
455
+ # Create checkboxes for each metric to allow multiple selections
456
+ if not filtered_metrics:
457
+ st.warning("No metrics found. Try adjusting your search.")
458
+ else:
459
+ # Organize checkboxes in columns for better layout
460
+ cols_per_row = 3
461
+ selected_for_plotting = []
462
+
463
+ for i in range(0, len(filtered_metrics), cols_per_row):
464
+ cols = st.columns(cols_per_row)
465
+ for j, metric in enumerate(filtered_metrics[i : i + cols_per_row]):
466
+ with cols[j]:
467
+ friendly_name = get_human_friendly_metric_name(metric)
468
+ # Truncate checkbox text if too long
469
+ checkbox_text = (
470
+ friendly_name[:25] + "..."
471
+ if len(friendly_name) > 25
472
+ else friendly_name
 
 
 
473
  )
474
 
475
+ if st.checkbox(
476
+ f"πŸ“ˆ {checkbox_text}",
477
+ key=f"plot_{metric}",
478
+ help=f"Plot distribution for {friendly_name}",
479
+ ):
480
+ selected_for_plotting.append(metric)
481
+
482
+ # Render selected metrics
483
+ if selected_for_plotting:
484
+ st.success(f"Plotting {len(selected_for_plotting)} selected metrics...")
485
+ for metric in selected_for_plotting:
486
+ render_metric_distribution(
487
+ metric, filtered_df_exploded, selected_types
488
+ )
489
+ else:
490
+ st.info("πŸ‘† Check the boxes above to plot metric distributions")
491
+
492
  with tab2:
493
  st.header("Correlation Analysis")
494
 
495
+ if len(available_metrics_for_analysis) < 2:
496
  st.warning("Please select at least 2 metrics for correlation analysis.")
497
  else:
498
  # Add button to trigger correlation analysis
499
  st.info(
500
+ f"πŸ”— Ready to analyze correlations between {len(available_metrics_for_analysis)} metrics"
501
  )
502
 
503
  col1, col2 = st.columns([1, 3])
 
507
  help="Calculate and display correlation matrix and scatter plots",
508
  )
509
  with col2:
510
+ if len(available_metrics_for_analysis) > 10:
511
  st.warning(
512
+ f"⚠️ Large analysis ({len(available_metrics_for_analysis)} metrics) - may take some time"
513
  )
514
 
515
  if run_correlation:
516
  with st.spinner("Calculating correlations..."):
517
  # Prepare correlation data
518
+ corr_columns = [f"turn.turn_metrics.{m}" for m in available_metrics_for_analysis]
519
  corr_data = filtered_df_exploded[corr_columns + ["type"]].copy()
520
 
521
  # Clean column names for display
 
588
  with tab3:
589
  st.header("Type Comparisons")
590
 
591
+ if not available_metrics_for_analysis:
592
  st.warning("Please select at least one metric to compare.")
593
  else:
594
  # Box plots for each metric
595
+ for metric in available_metrics_for_analysis:
596
  full_metric_name = f"turn.turn_metrics.{metric}"
597
 
598
  if full_metric_name not in filtered_df_exploded.columns:
 
626
  # Conversation selector
627
  st.subheader("πŸ” Select Conversation")
628
 
629
+ # Get total number of conversations and basic info
630
+ total_conversations = len(filtered_df)
631
+ available_indices = list(filtered_df.index)
632
+
633
+ st.info(f"πŸ“Š Dataset contains {total_conversations:,} conversations (indices: {min(available_indices)} to {max(available_indices)})")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
634
 
635
+ # Conversation selection with number input
636
+ col1, col2, col3 = st.columns([2, 1, 1])
637
 
638
  with col1:
639
+ selected_idx = st.number_input(
640
+ "Conversation Index",
641
+ min_value=min(available_indices),
642
+ max_value=max(available_indices),
643
+ value=available_indices[0], # Default to first available
644
+ step=1,
645
+ help=f"Enter a conversation index between {min(available_indices)} and {max(available_indices)}"
646
  )
647
 
648
  with col2:
649
  if st.button("🎲 Random", help="Select a random conversation"):
650
  import random
651
+ selected_idx = random.choice(available_indices)
 
 
 
652
  st.rerun()
653
+
654
+ with col3:
655
+ if st.button("ℹ️ Info", help="Show conversation preview"):
656
+ if selected_idx in available_indices:
657
+ preview_row = filtered_df.loc[selected_idx]
658
+ st.info(f"**Type:** {preview_row['type']} | **Turns:** {len(preview_row.get('conversation', []))}")
659
+ else:
660
+ st.error("Invalid conversation index")
661
 
662
+ # Validate and get the selected conversation data
663
+ if selected_idx not in available_indices:
664
+ st.error(f"❌ Conversation index {selected_idx} not found in filtered dataset. Available range: {min(available_indices)} to {max(available_indices)}")
665
+ st.stop()
666
+
667
+ selected_conversation = filtered_df.loc[selected_idx]
 
 
668
 
669
  # Display conversation metadata
670
  st.subheader("πŸ“‹ Conversation Overview")
 
820
  st.subheader("πŸ’¬ Conversation with Metrics")
821
 
822
  # Get actual turn-level data for this conversation
823
+ turn_metric_columns = [f"turn.turn_metrics.{m}" for m in available_metrics_for_analysis]
824
  available_columns = [
825
  col
826
  for col in turn_metric_columns
 
1041
  "No numeric metric data available to plot for this conversation type."
1042
  )
1043
 
1044
+ elif available_metrics_for_analysis:
1045
  st.info(
1046
  "Select metrics that are available in the dataset to see turn-level analysis."
1047
  )
 
1064
  help="Generate comprehensive dataset overview and metric analysis",
1065
  )
1066
  with col2:
1067
+ if len(available_metrics_for_analysis) > 20:
1068
  st.warning("⚠️ Large metric selection - analysis may take some time")
1069
 
1070
  if show_details:
 
1104
  if st.checkbox("Show raw data sample"):
1105
  sample_cols = ["type"] + [
1106
  f"turn.turn_metrics.{m}"
1107
+ for m in available_metrics_for_analysis
1108
  if f"turn.turn_metrics.{m}" in filtered_df_exploded.columns
1109
  ]
1110
  sample_data = filtered_df_exploded[sample_cols].head(100)
 
1114
  st.subheader("πŸ“Š Metric Availability")
1115
 
1116
  metric_completeness = {}
1117
+ for metric in available_metrics_for_analysis:
1118
  full_metric_name = f"turn.turn_metrics.{metric}"
1119
  if full_metric_name in filtered_df_exploded.columns:
1120
  completeness = (