KrispyKarim commited on
Commit
8fcba5d
Β·
verified Β·
1 Parent(s): f98b1c9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +238 -195
app.py CHANGED
@@ -327,13 +327,10 @@ def build_nav_html(l1_cur, l2_cur, l3_cur):
327
  show_dropdown = ""
328
 
329
  # Add emoji icons for main sections
330
- icons = {
331
- "Explore": "πŸš€",
332
- "Help & Legal": "❓"
333
- }
334
  icon = icons.get(label, "πŸ“")
335
 
336
- # For main tabs, allow both navigation and dropdown functionality
337
  main_tab_href = href(label, None, None) # Link to main tab overview
338
  item = [
339
  f'<li role="none" class="{show_dropdown}">'
@@ -370,13 +367,9 @@ def build_nav_html(l1_cur, l2_cur, l3_cur):
370
 
371
  for L1, L2 in MENU.items():
372
  parts.append(li_top(L1, L2))
373
-
374
 
375
-
376
  parts.append('</ul></div>')
377
-
378
 
379
-
380
  return "".join(parts)
381
 
382
 
@@ -445,6 +438,7 @@ def render_current_page():
445
  # Default fallback - show Key Insights as home page
446
  show_key_insights_page()
447
 
 
448
  def show_explore_overview():
449
  """Overview page for Explore section when no subtab is selected"""
450
  st.markdown("""
@@ -454,12 +448,13 @@ def show_explore_overview():
454
  Discover insights into how communities experience climate-related emotions through our data-driven platform.
455
  </div>
456
  </div>
457
- """, unsafe_allow_html=True)
458
-
 
459
  st.markdown("### Choose Your Path")
460
-
461
  col1, col2 = st.columns(2)
462
-
463
  with col1:
464
  st.markdown("""
465
  #### πŸ’‘ Key Insights
@@ -471,11 +466,11 @@ def show_explore_overview():
471
  - Research starting points
472
  - Presentation-ready statistics
473
  """)
474
-
475
  if st.button("View Key Insights", use_container_width=True):
476
  st.query_params.update({"l1": "Explore", "l2": "Key Insights"})
477
  st.rerun()
478
-
479
  with col2:
480
  st.markdown("""
481
  #### πŸ“Š Interactive Dashboards
@@ -487,11 +482,12 @@ def show_explore_overview():
487
  - Custom analysis and filtering
488
  - Research and academic work
489
  """)
490
-
491
  if st.button("Explore Dashboards", use_container_width=True):
492
  st.query_params.update({"l1": "Explore", "l2": "Dashboards"})
493
  st.rerun()
494
 
 
495
  def show_help_legal_overview():
496
  """Overview page for Help & Legal section when no subtab is selected"""
497
  st.markdown("""
@@ -501,123 +497,85 @@ def show_help_legal_overview():
501
  Find answers to your questions and understand the terms and limitations of using ClimateLens.
502
  </div>
503
  </div>
504
- """, unsafe_allow_html=True)
505
-
 
506
  st.markdown("### Available Resources")
507
-
508
  col1, col2, col3 = st.columns(3)
509
-
510
  with col1:
511
  st.markdown("""
512
  #### 🀝 Support & FAQs
513
 
514
  Get help with using the platform and find answers to common questions about our research methods.
515
  """)
516
-
517
  if st.button("Get Support", use_container_width=True):
518
- st.query_params.update({"l1": "Help & Legal", "l2": "Support/FAQs"})
 
 
 
519
  st.rerun()
520
-
521
  with col2:
522
  st.markdown("""
523
  #### ⚠️ Disclaimer
524
 
525
  Important information about the research nature of this tool and its limitations.
526
  """)
527
-
528
  if st.button("Read Disclaimer", use_container_width=True):
529
  st.query_params.update({"l1": "Help & Legal", "l2": "Disclaimer"})
530
  st.rerun()
531
-
532
  with col3:
533
  st.markdown("""
534
  #### πŸ“‹ Terms of Use
535
 
536
  Legal terms and conditions for using the ClimateLens platform and data.
537
  """)
538
-
539
  if st.button("View Terms", use_container_width=True):
540
- st.query_params.update({"l1": "Help & Legal", "l2": "Terms of Use"})
 
 
 
541
  st.rerun()
542
 
543
 
544
  # PAGE CONTENT FUNCTIONS
545
  # ClimateLens Page Functions
546
 
 
547
  def show_key_insights_page():
548
  """Key Insights from Current Data"""
549
  st.markdown("""
550
  <div class="content-section">
551
  <div class="section-title">πŸ” Key Insights from Current Data</div>
552
  <div class="section-description">
553
- Real-time insights into how communities are experiencing climate-related emotions across different demographics and regions.
554
  </div>
555
  </div>
556
- """, unsafe_allow_html=True)
 
557
 
558
- # Current emotional landscape metrics
559
- col1, col2, col3 = st.columns(3)
560
 
561
- with col1:
562
- st.metric("Gen Z Climate Anxiety", "67%", "↑ 12% this year")
563
- st.caption("Ages 16-25: Highest levels but also highest action motivation")
564
 
565
- with col2:
566
- st.metric("Boomer Climate Concern", "34%", "↑ 8% this year")
567
- st.caption("Ages 65+: Growing awareness, focus on grandchildren's future")
568
 
569
- with col3:
570
- st.metric("Mid-Career Hope", "45%", "β†— 5% this month")
571
- st.caption("Ages 35-55: Increasing optimism about solutions")
572
-
573
- st.markdown("### Current Emotional Trends by Generation")
574
 
575
- trend_col1, trend_col2 = st.columns(2)
576
 
577
- with trend_col1:
578
- st.markdown("""
579
- **Students (16-22):**
580
- - High anxiety but coupled with determination
581
- - Seeking peer support and actionable solutions
582
- - Strong interest in climate justice movements
583
-
584
- **Young Professionals (23-35):**
585
- - Balancing career stress with climate concern
586
- - Looking for workplace mental health resources
587
- - Interest in sustainable lifestyle choices
588
- """)
589
 
590
- with trend_col2:
591
- st.markdown("""
592
- **Mid-Career (36-55):**
593
- - Concerned about children's future
594
- - Seeking family-oriented coping strategies
595
- - Interest in community-based solutions
596
-
597
- **Experienced Adults (55+):**
598
- - Processing legacy and responsibility feelings
599
- - Wanting to mentor younger generations
600
- - Focus on policy and systemic change
601
- """)
602
 
603
- st.markdown("### Real Impact Stories")
604
-
605
- impact_col1, impact_col2, impact_col3 = st.columns(3)
606
-
607
- with impact_col1:
608
- st.markdown("""
609
- **Recent Success:** A high school in California used our data to develop peer support groups, reducing climate anxiety by 40% in participating students.
610
- """)
611
-
612
- with impact_col2:
613
- st.markdown("""
614
- **Community Win:** Retirement community in Florida created intergenerational climate discussions, improving hope scores across all age groups.
615
- """)
616
-
617
- with impact_col3:
618
- st.markdown("""
619
- **Professional Growth:** 200+ therapists completed our climate psychology training this month, expanding access to specialized care.
620
- """)
621
 
622
  def show_dashboards_page():
623
  """Comprehensive Dashboards page with Topics and Sentiments tabs"""
@@ -628,32 +586,35 @@ def show_dashboards_page():
628
  This section lets you explore the conversations and feelings around climate anxiety. Think of it as moving from the headline to the full story. Use the Topics tab to see what people are talking about, and the Sentiments tab to understand how they feel.
629
  </div>
630
  </div>
631
- """, unsafe_allow_html=True)
 
632
 
633
  # Introduction & Guide Section
634
  with st.expander("πŸ“– Introduction & Guide"):
635
  st.markdown("""
636
  This section lets you explore the conversations and feelings around climate anxiety. Think of it as moving from the headline to the full story. Use the Topics tab to see what people are talking about, and the Sentiments tab to understand how they feel.
637
  """)
638
-
639
  with st.expander("πŸ”§ Understanding the Data Visualization Tools"):
640
  st.markdown("""
641
  Each tool shows the same conversations from a different angle. Some focus on what people discuss (topics), others on how they feel (sentiments). Together, they offer a fuller picture.
642
  """)
643
-
644
  with st.expander("πŸ“‹ How to Use This Dashboard"):
645
  st.markdown("""
646
  Start with the Barchart or Intertopic Map to see the main conversations. Use the Heatmap and Hierarchy to explore connections and branches. Then open the Sentiments tab to check the feelings behind the words. You don't need to view everythingβ€”follow your curiosity.
647
  """)
648
-
649
- st.markdown("### Pick a view and start exploring. You can switch tabs and charts anytime.")
650
-
 
 
651
  # Main tabs: Topics and Sentiments
652
  topics_tab, sentiments_tab = st.tabs(["πŸ“Š Topics", "🎭 Sentiments"])
653
-
654
  with topics_tab:
655
  show_topics_section()
656
-
657
  with sentiments_tab:
658
  show_sentiments_section()
659
 
@@ -663,12 +624,12 @@ def list_files_in_directory(directory, extensions):
663
  """List files in directory with specified extensions"""
664
  if not os.path.exists(directory):
665
  return []
666
-
667
  files = []
668
  for ext in extensions:
669
  pattern = os.path.join(directory, f"*.{ext}")
670
  files.extend(glob.glob(pattern))
671
-
672
  return [os.path.basename(f) for f in files]
673
 
674
 
@@ -692,7 +653,7 @@ def categorize_html_files(files):
692
  'barchart': [],
693
  'hierarchy': []
694
  }
695
-
696
  for file in files:
697
  filename_lower = file.lower()
698
  if 'intertopic' in filename_lower:
@@ -703,7 +664,7 @@ def categorize_html_files(files):
703
  categories['barchart'].append(file)
704
  elif 'hierarchy' in filename_lower or 'tree' in filename_lower:
705
  categories['hierarchy'].append(file)
706
-
707
  return categories
708
 
709
 
@@ -712,17 +673,17 @@ def render_html_visualization(file_path, explanation):
712
  if not os.path.exists(file_path):
713
  st.error(f"File not found: {file_path}")
714
  return
715
-
716
  # Show explanation
717
  st.markdown(explanation)
718
-
719
  try:
720
  with open(file_path, 'r', encoding='utf-8') as f:
721
  html_content = f.read()
722
-
723
  # Render HTML
724
  components.html(html_content, height=800, scrolling=True)
725
-
726
  except Exception as e:
727
  st.error(f"Error loading visualization: {str(e)}")
728
 
@@ -732,10 +693,10 @@ def render_image_visualization(file_path, explanation):
732
  if not os.path.exists(file_path):
733
  st.error(f"File not found: {file_path}")
734
  return
735
-
736
  # Show explanation
737
  st.markdown(explanation)
738
-
739
  try:
740
  st.image(file_path, use_container_width=True)
741
  except Exception as e:
@@ -745,85 +706,115 @@ def render_image_visualization(file_path, explanation):
745
  def show_topics_section():
746
  """Display Topics section with sub-tabs"""
747
  st.markdown("### Available Visualizations")
748
-
749
  # Add refresh button
750
  if st.button("πŸ”„ Refresh Files", key="refresh_topics"):
751
  st.rerun()
752
-
753
  # Get HTML files from interactives directory
754
- html_files = list_files_in_directory("visualizations/interactives", ["html"])
755
-
 
756
  if not html_files:
757
- st.info("No visualizations found yet. Visualizations will appear here once data is processed.")
 
 
758
  return
759
-
760
  # Categorize files
761
  categorized = categorize_html_files(html_files)
762
-
763
  # Create sub-tabs
764
- intertopic_tab, heatmap_tab, barchart_tab, hierarchy_tab = st.tabs([
765
- "πŸ”΅ Intertopic Map β“˜",
766
- "πŸ”₯ Heatmap β“˜",
767
- "πŸ“Š Barchart β“˜",
768
- "🌳 Hierarchy β“˜"
769
- ])
770
-
771
  with intertopic_tab:
772
- st.markdown("**What it shows:** Topics as bubbles on a map. Bubbles close together mean the conversations are similar; far apart means they're different.")
773
- st.markdown("**Why it matters:** Quickly spot clusters of related themes (for example, 'policy and activism').")
774
-
 
 
 
 
775
  files = categorized['intertopic']
776
  if not files:
777
  files = html_files # Fallback to all files
778
-
779
  if files:
780
- selected_file = st.selectbox("Choose visualization:", files, format_func=prettify_filename, key="intertopic_select")
781
- file_path = os.path.join("visualizations/interactives", selected_file)
 
 
 
 
782
  render_html_visualization(file_path, "")
783
  else:
784
  st.info("No intertopic distance maps found.")
785
-
786
  with heatmap_tab:
787
- st.markdown("**What it shows:** A grid where stronger colors mean stronger links between topics.")
788
- st.markdown("**Why it matters:** Reveals which themes often appear together.")
789
-
 
 
 
790
  files = categorized['heatmap']
791
  if not files:
792
  files = html_files
793
-
794
  if files:
795
- selected_file = st.selectbox("Choose visualization:", files, format_func=prettify_filename, key="heatmap_select")
796
- file_path = os.path.join("visualizations/interactives", selected_file)
 
 
 
 
797
  render_html_visualization(file_path, "")
798
  else:
799
  st.info("No heatmap visualizations found.")
800
-
801
  with barchart_tab:
802
- st.markdown("**What it shows:** A ranking of topics by sizeβ€”how much people talk about each one.")
803
- st.markdown("**Why it matters:** See which conversations dominate the climate anxiety space.")
804
-
 
 
 
 
805
  files = categorized['barchart']
806
  if not files:
807
  files = html_files
808
-
809
  if files:
810
- selected_file = st.selectbox("Choose visualization:", files, format_func=prettify_filename, key="barchart_select")
811
- file_path = os.path.join("visualizations/interactives", selected_file)
 
 
 
 
812
  render_html_visualization(file_path, "")
813
  else:
814
  st.info("No barchart visualizations found.")
815
-
816
  with hierarchy_tab:
817
- st.markdown("**What it shows:** A tree that splits broad themes into smaller branches.")
818
- st.markdown("**Why it matters:** Understand how big ideas break into specific concerns.")
819
-
 
 
 
 
820
  files = categorized['hierarchy']
821
  if not files:
822
  files = html_files
823
-
824
  if files:
825
- selected_file = st.selectbox("Choose visualization:", files, format_func=prettify_filename, key="hierarchy_select")
826
- file_path = os.path.join("visualizations/interactives", selected_file)
 
 
 
 
827
  render_html_visualization(file_path, "")
828
  else:
829
  st.info("No hierarchy visualizations found.")
@@ -832,63 +823,104 @@ def show_topics_section():
832
  def show_sentiments_section():
833
  """Display Sentiments section with sub-tabs"""
834
  st.markdown("### Sentiment Analysis Visualizations")
835
-
836
  # Add refresh button
837
  if st.button("πŸ”„ Refresh Files", key="refresh_sentiments"):
838
  st.rerun()
839
-
840
  # Create sub-tabs
841
  distribution_tab, histograms_tab, violins_tab = st.tabs([
842
- "πŸ“Š Distribution",
843
- "πŸ“ˆ Probability - Histograms",
844
  "🎻 Probability - Violins"
845
  ])
846
-
847
  with distribution_tab:
848
- st.markdown("**What it shows:** The overall balance of positive, neutral, and negative feelings.")
849
- st.markdown("**Why it matters:** A quick snapshot of the general mood.")
850
-
 
 
 
851
  # Get PNG files from sentiment distribution directory
852
- png_files = list_files_in_directory("visualizations/sentiment_insights/sentiment_distribution", ["png", "jpg", "jpeg"])
853
-
 
 
854
  if png_files:
855
- selected_file = st.selectbox("Choose visualization:", png_files, format_func=prettify_filename, key="distribution_select")
856
- file_path = os.path.join("visualizations/sentiment_insights/sentiment_distribution", selected_file)
 
 
 
 
 
857
  render_image_visualization(file_path, "")
858
  else:
859
  st.info("No sentiment distribution visualizations found yet.")
860
-
861
  with histograms_tab:
862
- st.markdown("**What it shows:** For each emotion label (positive/neutral/negative), a histogram shows how many messages fall into each 'confidence' level.")
863
- st.markdown("**Why it's useful:** Helps you see how certain or uncertain the system is. If many messages sit in the middle, feelings are mixed; if most are at the high end, the labeling is confident.")
864
-
 
 
 
 
865
  # Get image files from sentiment probability histograms directory
866
- hist_files = list_files_in_directory("visualizations/sentiment_insights/sentiment_probability_histograms", ["png", "jpg", "jpeg"])
867
-
 
 
868
  if hist_files:
869
- selected_file = st.selectbox("Choose visualization:", hist_files, format_func=prettify_filename, key="histograms_select")
870
- file_path = os.path.join("visualizations/sentiment_insights/sentiment_probability_histograms", selected_file)
 
 
 
 
 
871
  render_image_visualization(file_path, "")
872
  else:
873
- st.info("No sentiment probability histogram visualizations found yet.")
874
-
 
875
  with violins_tab:
876
- st.markdown("**What it shows:** For each emotion label, a violin plot shows the shape of the confidence scores (where they bunch up, spread out, or have multiple peaks).")
877
- st.markdown("**Why it's useful:** Makes it easy to spot uncertainty and overlap between emotions. For example, if negative and neutral have similar shapes, people may be expressing worry without being strongly negative.")
878
-
 
 
 
 
879
  # Get image files from sentiment probability violins directory
880
- violin_files = list_files_in_directory("visualizations/sentiment_insights/sentiment_probability_violins", ["png", "jpg", "jpeg"])
881
-
 
 
882
  if violin_files:
883
- selected_file = st.selectbox("Choose visualization:", violin_files, format_func=prettify_filename, key="violins_select")
884
- file_path = os.path.join("visualizations/sentiment_insights/sentiment_probability_violins", selected_file)
 
 
 
 
 
885
  render_image_visualization(file_path, "")
886
  else:
887
- st.info("No sentiment probability violin visualizations found yet.")
 
888
 
889
 
890
  def show_support_page():
891
  """Support and FAQs"""
 
 
 
 
 
 
 
 
892
  st.markdown("""
893
  <div class="content-section">
894
  <div class="section-title">❓ Support & FAQs</div>
@@ -896,20 +928,23 @@ def show_support_page():
896
  Get help using ClimateLens and find answers to common questions.
897
  </div>
898
  </div>
899
- """, unsafe_allow_html=True)
900
-
 
901
  st.markdown("### Frequently Asked Questions")
902
-
903
  with st.expander("1) What will your tool not do?"):
904
  st.markdown("""
905
  It won't run live surveillance or score individual youth in real time. And it won't auto-prescribe personalized interventions. Those are explicitly out-of-scope for this phase.
906
  """)
907
-
908
- with st.expander("2) If it doesn't flag individuals, what does a counselor actually see?"):
 
 
909
  st.markdown("""
910
  A visual dashboard of aggregate themes and interpretable signals (e.g., prevalent concerns, representative phrases), with an interface to explore how a prediction was made; KHP designs the human intervention guidance that sits beside these insights.
911
  """)
912
-
913
  with st.expander("3) What counts as a 'good' model here?"):
914
  st.markdown("""
915
  Not just accuracy. We'll judge success on:
@@ -917,37 +952,40 @@ def show_support_page():
917
  - (b) interpretability: clear linguistic cues you can inspect, and
918
  - (c) fairness across subgroups.
919
  """)
920
-
921
  with st.expander("4) Where does the data come from and do youth consent?"):
922
  st.markdown("""
923
  Phase I uses open-source, climate-related text. Phase II contemplates anonymized/de-identified Kids Help Phone transcripts that are used only after de-identification and governance review.
924
  """)
925
-
926
- with st.expander("5) How do you keep the system from drifting or getting brittle over time (slang, memes, shifts)?"):
 
 
927
  st.markdown("""
928
  We treat this like a living system: evaluate routinely, watch for distribution shift, and use human-in-the-loop review to update lexicons/models when new patterns appear. The lifecycle includes explicit monitoring and testing for changes.
929
  """)
930
-
931
  with st.expander("6) Could this be biased against certain groups?"):
932
  st.markdown("""
933
  Bias risk is real. We address it by measuring subgroup performance, requiring interpretable rationales (so reviewers can spot skewed cues), and baking fairness checks into testing alongside clear documentation of limits.
934
  """)
935
-
936
  with st.expander("7) Will this replace counselors?"):
937
  st.markdown("""
938
  No. It's decision support, not decision maker. The deliverables include an interpretable model + UI meant to surface patterns and speed human judgment. KHP leads on intervention strategy and practice.
939
  """)
940
-
941
  with st.expander("8) What happens when the model is wrong?"):
942
  st.markdown("""
943
  We plan for error. Baselines and evaluation tests are set up to catch regressions; the UI shows why a prediction happened; and there's a human feedback loop to correct mistakes and refine the system.
944
  """)
945
-
946
- with st.expander("9) Can communities reuse this without heavy ML expertise?"):
 
947
  st.markdown("""
948
  Yes! Code and models are released with usage guidelines, and the interface ships with built-in visualizations so non-technical teams can explore results safely and meaningfully.
949
  """)
950
-
951
  st.markdown("### For Mental Health Professionals")
952
  st.markdown("""
953
  If you are a licensed psychologist, counselor, or other mental health professional:
@@ -957,12 +995,12 @@ def show_support_page():
957
  - Follow your profession's ethical guidelines regarding use of research tools and data
958
  - Seek appropriate training if you plan to incorporate climate psychology research into your practice
959
  """)
960
-
961
  st.markdown("### Questions or Concerns")
962
  st.markdown("""
963
  For questions about appropriate use, data sources, or research methodology, please contact the project team through programs@crcgreen.com
964
  """)
965
-
966
  st.markdown("### Help Us Improve ClimateLens")
967
  st.markdown("""
968
  Your feedback helps us improve the platform for everyone. Share your experience, suggest features, or report issues.
@@ -970,6 +1008,7 @@ def show_support_page():
970
  [πŸ’¬ Submit Feedback via Google Form](https://forms.gle/o7QQBZNijJo9E76E7)
971
  """)
972
 
 
973
  def show_disclaimer_page():
974
  """Disclaimer"""
975
  st.markdown("""
@@ -979,8 +1018,9 @@ def show_disclaimer_page():
979
  Important information about using ClimateLens data and platform.
980
  </div>
981
  </div>
982
- """, unsafe_allow_html=True)
983
-
 
984
  st.markdown("""
985
  ### Research and Educational Purposes Only
986
 
@@ -1003,6 +1043,7 @@ def show_disclaimer_page():
1003
  This project is open source and provided "as is" without warranties of any kind, either express or implied. The developers make no guarantees regarding the accuracy, completeness, reliability, or fitness for any particular purpose.
1004
  """)
1005
 
 
1006
  def show_terms_page():
1007
  """Terms of Use"""
1008
  st.markdown("""
@@ -1012,8 +1053,9 @@ def show_terms_page():
1012
  Terms and conditions for using the ClimateLens platform.
1013
  </div>
1014
  </div>
1015
- """, unsafe_allow_html=True)
1016
-
 
1017
  st.markdown("""
1018
  ### Scope of Acceptable Use
1019
 
@@ -1071,5 +1113,6 @@ def show_terms_page():
1071
  *Last updated: August 2025*
1072
  """)
1073
 
 
1074
  if __name__ == "__main__":
1075
  main()
 
327
  show_dropdown = ""
328
 
329
  # Add emoji icons for main sections
330
+ icons = {"Explore": "πŸš€", "Help & Legal": "❓"}
 
 
 
331
  icon = icons.get(label, "πŸ“")
332
 
333
+ # For main tabs, allow both navigation and dropdown functionality
334
  main_tab_href = href(label, None, None) # Link to main tab overview
335
  item = [
336
  f'<li role="none" class="{show_dropdown}">'
 
367
 
368
  for L1, L2 in MENU.items():
369
  parts.append(li_top(L1, L2))
 
370
 
 
371
  parts.append('</ul></div>')
 
372
 
 
373
  return "".join(parts)
374
 
375
 
 
438
  # Default fallback - show Key Insights as home page
439
  show_key_insights_page()
440
 
441
+
442
  def show_explore_overview():
443
  """Overview page for Explore section when no subtab is selected"""
444
  st.markdown("""
 
448
  Discover insights into how communities experience climate-related emotions through our data-driven platform.
449
  </div>
450
  </div>
451
+ """,
452
+ unsafe_allow_html=True)
453
+
454
  st.markdown("### Choose Your Path")
455
+
456
  col1, col2 = st.columns(2)
457
+
458
  with col1:
459
  st.markdown("""
460
  #### πŸ’‘ Key Insights
 
466
  - Research starting points
467
  - Presentation-ready statistics
468
  """)
469
+
470
  if st.button("View Key Insights", use_container_width=True):
471
  st.query_params.update({"l1": "Explore", "l2": "Key Insights"})
472
  st.rerun()
473
+
474
  with col2:
475
  st.markdown("""
476
  #### πŸ“Š Interactive Dashboards
 
482
  - Custom analysis and filtering
483
  - Research and academic work
484
  """)
485
+
486
  if st.button("Explore Dashboards", use_container_width=True):
487
  st.query_params.update({"l1": "Explore", "l2": "Dashboards"})
488
  st.rerun()
489
 
490
+
491
  def show_help_legal_overview():
492
  """Overview page for Help & Legal section when no subtab is selected"""
493
  st.markdown("""
 
497
  Find answers to your questions and understand the terms and limitations of using ClimateLens.
498
  </div>
499
  </div>
500
+ """,
501
+ unsafe_allow_html=True)
502
+
503
  st.markdown("### Available Resources")
504
+
505
  col1, col2, col3 = st.columns(3)
506
+
507
  with col1:
508
  st.markdown("""
509
  #### 🀝 Support & FAQs
510
 
511
  Get help with using the platform and find answers to common questions about our research methods.
512
  """)
513
+
514
  if st.button("Get Support", use_container_width=True):
515
+ st.query_params.update({
516
+ "l1": "Help & Legal",
517
+ "l2": "Support/FAQs"
518
+ })
519
  st.rerun()
520
+
521
  with col2:
522
  st.markdown("""
523
  #### ⚠️ Disclaimer
524
 
525
  Important information about the research nature of this tool and its limitations.
526
  """)
527
+
528
  if st.button("Read Disclaimer", use_container_width=True):
529
  st.query_params.update({"l1": "Help & Legal", "l2": "Disclaimer"})
530
  st.rerun()
531
+
532
  with col3:
533
  st.markdown("""
534
  #### πŸ“‹ Terms of Use
535
 
536
  Legal terms and conditions for using the ClimateLens platform and data.
537
  """)
538
+
539
  if st.button("View Terms", use_container_width=True):
540
+ st.query_params.update({
541
+ "l1": "Help & Legal",
542
+ "l2": "Terms of Use"
543
+ })
544
  st.rerun()
545
 
546
 
547
  # PAGE CONTENT FUNCTIONS
548
  # ClimateLens Page Functions
549
 
550
+
551
  def show_key_insights_page():
552
  """Key Insights from Current Data"""
553
  st.markdown("""
554
  <div class="content-section">
555
  <div class="section-title">πŸ” Key Insights from Current Data</div>
556
  <div class="section-description">
557
+ Climate conversations online reveal not just facts and opinions, but the emotions people carry when talking about the future of our planet. Our analysis of recent discussions highlights several important insights.
558
  </div>
559
  </div>
560
+ """,
561
+ unsafe_allow_html=True)
562
 
563
+ st.markdown("""
564
+ ### Key Insights from Current Data
565
 
566
+ **Climate anxiety is widespread:** Many people express worry, stress, or fear about the future, often tied to uncertainty about what can be done.
 
 
567
 
568
+ **Hope and motivation still shine through:** Alongside anxiety, we also see voices of determination β€” calls for action, sharing solutions, and community support.
 
 
569
 
570
+ **Different groups focus on different concerns:** Some emphasize policy and global decisions, while others focus on personal responsibility or lifestyle changes.
 
 
 
 
571
 
572
+ **Emotions are mixed, not one-dimensional:** It's common to see comments that are both worried and hopeful, or frustrated yet motivated.
573
 
574
+ **Community plays a big role:** Many express that talking, sharing, and organizing with others helps balance the heavy emotions around climate change.
 
 
 
 
 
 
 
 
 
 
 
575
 
576
+ Together, these insights show a picture that is both challenging and inspiring: the emotional weight of climate change is real, but so are the collective voices searching for solutions and connection.
577
+ """)
 
 
 
 
 
 
 
 
 
 
578
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
 
580
  def show_dashboards_page():
581
  """Comprehensive Dashboards page with Topics and Sentiments tabs"""
 
586
  This section lets you explore the conversations and feelings around climate anxiety. Think of it as moving from the headline to the full story. Use the Topics tab to see what people are talking about, and the Sentiments tab to understand how they feel.
587
  </div>
588
  </div>
589
+ """,
590
+ unsafe_allow_html=True)
591
 
592
  # Introduction & Guide Section
593
  with st.expander("πŸ“– Introduction & Guide"):
594
  st.markdown("""
595
  This section lets you explore the conversations and feelings around climate anxiety. Think of it as moving from the headline to the full story. Use the Topics tab to see what people are talking about, and the Sentiments tab to understand how they feel.
596
  """)
597
+
598
  with st.expander("πŸ”§ Understanding the Data Visualization Tools"):
599
  st.markdown("""
600
  Each tool shows the same conversations from a different angle. Some focus on what people discuss (topics), others on how they feel (sentiments). Together, they offer a fuller picture.
601
  """)
602
+
603
  with st.expander("πŸ“‹ How to Use This Dashboard"):
604
  st.markdown("""
605
  Start with the Barchart or Intertopic Map to see the main conversations. Use the Heatmap and Hierarchy to explore connections and branches. Then open the Sentiments tab to check the feelings behind the words. You don't need to view everythingβ€”follow your curiosity.
606
  """)
607
+
608
+ st.markdown(
609
+ "### Pick a view and start exploring. You can switch tabs and charts anytime."
610
+ )
611
+
612
  # Main tabs: Topics and Sentiments
613
  topics_tab, sentiments_tab = st.tabs(["πŸ“Š Topics", "🎭 Sentiments"])
614
+
615
  with topics_tab:
616
  show_topics_section()
617
+
618
  with sentiments_tab:
619
  show_sentiments_section()
620
 
 
624
  """List files in directory with specified extensions"""
625
  if not os.path.exists(directory):
626
  return []
627
+
628
  files = []
629
  for ext in extensions:
630
  pattern = os.path.join(directory, f"*.{ext}")
631
  files.extend(glob.glob(pattern))
632
+
633
  return [os.path.basename(f) for f in files]
634
 
635
 
 
653
  'barchart': [],
654
  'hierarchy': []
655
  }
656
+
657
  for file in files:
658
  filename_lower = file.lower()
659
  if 'intertopic' in filename_lower:
 
664
  categories['barchart'].append(file)
665
  elif 'hierarchy' in filename_lower or 'tree' in filename_lower:
666
  categories['hierarchy'].append(file)
667
+
668
  return categories
669
 
670
 
 
673
  if not os.path.exists(file_path):
674
  st.error(f"File not found: {file_path}")
675
  return
676
+
677
  # Show explanation
678
  st.markdown(explanation)
679
+
680
  try:
681
  with open(file_path, 'r', encoding='utf-8') as f:
682
  html_content = f.read()
683
+
684
  # Render HTML
685
  components.html(html_content, height=800, scrolling=True)
686
+
687
  except Exception as e:
688
  st.error(f"Error loading visualization: {str(e)}")
689
 
 
693
  if not os.path.exists(file_path):
694
  st.error(f"File not found: {file_path}")
695
  return
696
+
697
  # Show explanation
698
  st.markdown(explanation)
699
+
700
  try:
701
  st.image(file_path, use_container_width=True)
702
  except Exception as e:
 
706
  def show_topics_section():
707
  """Display Topics section with sub-tabs"""
708
  st.markdown("### Available Visualizations")
709
+
710
  # Add refresh button
711
  if st.button("πŸ”„ Refresh Files", key="refresh_topics"):
712
  st.rerun()
713
+
714
  # Get HTML files from interactives directory
715
+ html_files = list_files_in_directory("visualizations/interactives",
716
+ ["html"])
717
+
718
  if not html_files:
719
+ st.info(
720
+ "No visualizations found yet. Visualizations will appear here once data is processed."
721
+ )
722
  return
723
+
724
  # Categorize files
725
  categorized = categorize_html_files(html_files)
726
+
727
  # Create sub-tabs
728
+ intertopic_tab, heatmap_tab, barchart_tab, hierarchy_tab = st.tabs(
729
+ ["πŸ”΅ Intertopic Map β“˜", "πŸ”₯ Heatmap β“˜", "πŸ“Š Barchart β“˜", "🌳 Hierarchy β“˜"])
730
+
 
 
 
 
731
  with intertopic_tab:
732
+ st.markdown(
733
+ "**What it shows:** Topics as bubbles on a map. Bubbles close together mean the conversations are similar; far apart means they're different."
734
+ )
735
+ st.markdown(
736
+ "**Why it matters:** Quickly spot clusters of related themes (for example, 'policy and activism')."
737
+ )
738
+
739
  files = categorized['intertopic']
740
  if not files:
741
  files = html_files # Fallback to all files
742
+
743
  if files:
744
+ selected_file = st.selectbox("Choose visualization:",
745
+ files,
746
+ format_func=prettify_filename,
747
+ key="intertopic_select")
748
+ file_path = os.path.join("visualizations/interactives",
749
+ selected_file)
750
  render_html_visualization(file_path, "")
751
  else:
752
  st.info("No intertopic distance maps found.")
753
+
754
  with heatmap_tab:
755
+ st.markdown(
756
+ "**What it shows:** A grid where stronger colors mean stronger links between topics."
757
+ )
758
+ st.markdown(
759
+ "**Why it matters:** Reveals which themes often appear together.")
760
+
761
  files = categorized['heatmap']
762
  if not files:
763
  files = html_files
764
+
765
  if files:
766
+ selected_file = st.selectbox("Choose visualization:",
767
+ files,
768
+ format_func=prettify_filename,
769
+ key="heatmap_select")
770
+ file_path = os.path.join("visualizations/interactives",
771
+ selected_file)
772
  render_html_visualization(file_path, "")
773
  else:
774
  st.info("No heatmap visualizations found.")
775
+
776
  with barchart_tab:
777
+ st.markdown(
778
+ "**What it shows:** A ranking of topics by sizeβ€”how much people talk about each one."
779
+ )
780
+ st.markdown(
781
+ "**Why it matters:** See which conversations dominate the climate anxiety space."
782
+ )
783
+
784
  files = categorized['barchart']
785
  if not files:
786
  files = html_files
787
+
788
  if files:
789
+ selected_file = st.selectbox("Choose visualization:",
790
+ files,
791
+ format_func=prettify_filename,
792
+ key="barchart_select")
793
+ file_path = os.path.join("visualizations/interactives",
794
+ selected_file)
795
  render_html_visualization(file_path, "")
796
  else:
797
  st.info("No barchart visualizations found.")
798
+
799
  with hierarchy_tab:
800
+ st.markdown(
801
+ "**What it shows:** A tree that splits broad themes into smaller branches."
802
+ )
803
+ st.markdown(
804
+ "**Why it matters:** Understand how big ideas break into specific concerns."
805
+ )
806
+
807
  files = categorized['hierarchy']
808
  if not files:
809
  files = html_files
810
+
811
  if files:
812
+ selected_file = st.selectbox("Choose visualization:",
813
+ files,
814
+ format_func=prettify_filename,
815
+ key="hierarchy_select")
816
+ file_path = os.path.join("visualizations/interactives",
817
+ selected_file)
818
  render_html_visualization(file_path, "")
819
  else:
820
  st.info("No hierarchy visualizations found.")
 
823
  def show_sentiments_section():
824
  """Display Sentiments section with sub-tabs"""
825
  st.markdown("### Sentiment Analysis Visualizations")
826
+
827
  # Add refresh button
828
  if st.button("πŸ”„ Refresh Files", key="refresh_sentiments"):
829
  st.rerun()
830
+
831
  # Create sub-tabs
832
  distribution_tab, histograms_tab, violins_tab = st.tabs([
833
+ "πŸ“Š Distribution", "πŸ“ˆ Probability - Histograms",
 
834
  "🎻 Probability - Violins"
835
  ])
836
+
837
  with distribution_tab:
838
+ st.markdown(
839
+ "**What it shows:** The overall balance of positive, neutral, and negative feelings."
840
+ )
841
+ st.markdown(
842
+ "**Why it matters:** A quick snapshot of the general mood.")
843
+
844
  # Get PNG files from sentiment distribution directory
845
+ png_files = list_files_in_directory(
846
+ "visualizations/sentiment_insights/sentiment_distribution",
847
+ ["png", "jpg", "jpeg"])
848
+
849
  if png_files:
850
+ selected_file = st.selectbox("Choose visualization:",
851
+ png_files,
852
+ format_func=prettify_filename,
853
+ key="distribution_select")
854
+ file_path = os.path.join(
855
+ "visualizations/sentiment_insights/sentiment_distribution",
856
+ selected_file)
857
  render_image_visualization(file_path, "")
858
  else:
859
  st.info("No sentiment distribution visualizations found yet.")
860
+
861
  with histograms_tab:
862
+ st.markdown(
863
+ "**What it shows:** For each emotion label (positive/neutral/negative), a histogram shows how many messages fall into each 'confidence' level."
864
+ )
865
+ st.markdown(
866
+ "**Why it's useful:** Helps you see how certain or uncertain the system is. If many messages sit in the middle, feelings are mixed; if most are at the high end, the labeling is confident."
867
+ )
868
+
869
  # Get image files from sentiment probability histograms directory
870
+ hist_files = list_files_in_directory(
871
+ "visualizations/sentiment_insights/sentiment_probability_histograms",
872
+ ["png", "jpg", "jpeg"])
873
+
874
  if hist_files:
875
+ selected_file = st.selectbox("Choose visualization:",
876
+ hist_files,
877
+ format_func=prettify_filename,
878
+ key="histograms_select")
879
+ file_path = os.path.join(
880
+ "visualizations/sentiment_insights/sentiment_probability_histograms",
881
+ selected_file)
882
  render_image_visualization(file_path, "")
883
  else:
884
+ st.info(
885
+ "No sentiment probability histogram visualizations found yet.")
886
+
887
  with violins_tab:
888
+ st.markdown(
889
+ "**What it shows:** For each emotion label, a violin plot shows the shape of the confidence scores (where they bunch up, spread out, or have multiple peaks)."
890
+ )
891
+ st.markdown(
892
+ "**Why it's useful:** Makes it easy to spot uncertainty and overlap between emotions. For example, if negative and neutral have similar shapes, people may be expressing worry without being strongly negative."
893
+ )
894
+
895
  # Get image files from sentiment probability violins directory
896
+ violin_files = list_files_in_directory(
897
+ "visualizations/sentiment_insights/sentiment_probability_violins",
898
+ ["png", "jpg", "jpeg"])
899
+
900
  if violin_files:
901
+ selected_file = st.selectbox("Choose visualization:",
902
+ violin_files,
903
+ format_func=prettify_filename,
904
+ key="violins_select")
905
+ file_path = os.path.join(
906
+ "visualizations/sentiment_insights/sentiment_probability_violins",
907
+ selected_file)
908
  render_image_visualization(file_path, "")
909
  else:
910
+ st.info(
911
+ "No sentiment probability violin visualizations found yet.")
912
 
913
 
914
  def show_support_page():
915
  """Support and FAQs"""
916
+ # Add Google Form button at the very top
917
+ st.markdown("### πŸ’¬ Share Your Feedback")
918
+ st.link_button("Submit Feedback",
919
+ "https://forms.gle/o7QQBZNijJo9E76E7",
920
+ use_container_width=True)
921
+
922
+ st.markdown("---")
923
+
924
  st.markdown("""
925
  <div class="content-section">
926
  <div class="section-title">❓ Support & FAQs</div>
 
928
  Get help using ClimateLens and find answers to common questions.
929
  </div>
930
  </div>
931
+ """,
932
+ unsafe_allow_html=True)
933
+
934
  st.markdown("### Frequently Asked Questions")
935
+
936
  with st.expander("1) What will your tool not do?"):
937
  st.markdown("""
938
  It won't run live surveillance or score individual youth in real time. And it won't auto-prescribe personalized interventions. Those are explicitly out-of-scope for this phase.
939
  """)
940
+
941
+ with st.expander(
942
+ "2) If it doesn't flag individuals, what does a counselor actually see?"
943
+ ):
944
  st.markdown("""
945
  A visual dashboard of aggregate themes and interpretable signals (e.g., prevalent concerns, representative phrases), with an interface to explore how a prediction was made; KHP designs the human intervention guidance that sits beside these insights.
946
  """)
947
+
948
  with st.expander("3) What counts as a 'good' model here?"):
949
  st.markdown("""
950
  Not just accuracy. We'll judge success on:
 
952
  - (b) interpretability: clear linguistic cues you can inspect, and
953
  - (c) fairness across subgroups.
954
  """)
955
+
956
  with st.expander("4) Where does the data come from and do youth consent?"):
957
  st.markdown("""
958
  Phase I uses open-source, climate-related text. Phase II contemplates anonymized/de-identified Kids Help Phone transcripts that are used only after de-identification and governance review.
959
  """)
960
+
961
+ with st.expander(
962
+ "5) How do you keep the system from drifting or getting brittle over time (slang, memes, shifts)?"
963
+ ):
964
  st.markdown("""
965
  We treat this like a living system: evaluate routinely, watch for distribution shift, and use human-in-the-loop review to update lexicons/models when new patterns appear. The lifecycle includes explicit monitoring and testing for changes.
966
  """)
967
+
968
  with st.expander("6) Could this be biased against certain groups?"):
969
  st.markdown("""
970
  Bias risk is real. We address it by measuring subgroup performance, requiring interpretable rationales (so reviewers can spot skewed cues), and baking fairness checks into testing alongside clear documentation of limits.
971
  """)
972
+
973
  with st.expander("7) Will this replace counselors?"):
974
  st.markdown("""
975
  No. It's decision support, not decision maker. The deliverables include an interpretable model + UI meant to surface patterns and speed human judgment. KHP leads on intervention strategy and practice.
976
  """)
977
+
978
  with st.expander("8) What happens when the model is wrong?"):
979
  st.markdown("""
980
  We plan for error. Baselines and evaluation tests are set up to catch regressions; the UI shows why a prediction happened; and there's a human feedback loop to correct mistakes and refine the system.
981
  """)
982
+
983
+ with st.expander(
984
+ "9) Can communities reuse this without heavy ML expertise?"):
985
  st.markdown("""
986
  Yes! Code and models are released with usage guidelines, and the interface ships with built-in visualizations so non-technical teams can explore results safely and meaningfully.
987
  """)
988
+
989
  st.markdown("### For Mental Health Professionals")
990
  st.markdown("""
991
  If you are a licensed psychologist, counselor, or other mental health professional:
 
995
  - Follow your profession's ethical guidelines regarding use of research tools and data
996
  - Seek appropriate training if you plan to incorporate climate psychology research into your practice
997
  """)
998
+
999
  st.markdown("### Questions or Concerns")
1000
  st.markdown("""
1001
  For questions about appropriate use, data sources, or research methodology, please contact the project team through programs@crcgreen.com
1002
  """)
1003
+
1004
  st.markdown("### Help Us Improve ClimateLens")
1005
  st.markdown("""
1006
  Your feedback helps us improve the platform for everyone. Share your experience, suggest features, or report issues.
 
1008
  [πŸ’¬ Submit Feedback via Google Form](https://forms.gle/o7QQBZNijJo9E76E7)
1009
  """)
1010
 
1011
+
1012
  def show_disclaimer_page():
1013
  """Disclaimer"""
1014
  st.markdown("""
 
1018
  Important information about using ClimateLens data and platform.
1019
  </div>
1020
  </div>
1021
+ """,
1022
+ unsafe_allow_html=True)
1023
+
1024
  st.markdown("""
1025
  ### Research and Educational Purposes Only
1026
 
 
1043
  This project is open source and provided "as is" without warranties of any kind, either express or implied. The developers make no guarantees regarding the accuracy, completeness, reliability, or fitness for any particular purpose.
1044
  """)
1045
 
1046
+
1047
  def show_terms_page():
1048
  """Terms of Use"""
1049
  st.markdown("""
 
1053
  Terms and conditions for using the ClimateLens platform.
1054
  </div>
1055
  </div>
1056
+ """,
1057
+ unsafe_allow_html=True)
1058
+
1059
  st.markdown("""
1060
  ### Scope of Acceptable Use
1061
 
 
1113
  *Last updated: August 2025*
1114
  """)
1115
 
1116
+
1117
  if __name__ == "__main__":
1118
  main()