paulnhuu174 commited on
Commit
d107fd9
·
verified ·
1 Parent(s): add1533

Upload 32 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ saved_models/mm_dnn_model.keras filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Entry point for HuggingFace Spaces - UAB Theme
3
+ """
4
+
5
+ from sud_promise_uab_theme import create_interface
6
+
7
+ if __name__ == "__main__":
8
+ demo = create_interface()
9
+ demo.launch()
10
+
const_config.py ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Configuration Constants - ML Settings, Paths, App Metadata, Messages
3
+ All configuration and system-level constants
4
+ """
5
+
6
+ # ========================================
7
+ # APPLICATION METADATA
8
+ # ========================================
9
+
10
+ APP_NAME = "SUD-PROMISE Drug Repositioning Assessment Platform"
11
+ APP_VERSION = "3.3.0"
12
+ INSTITUTION = "University of Alabama at Birmingham"
13
+
14
+ # ========================================
15
+ # FILE PATHS
16
+ # ========================================
17
+
18
+ DATA_DIR = "data1"
19
+ MODEL_DIR = "saved_models"
20
+
21
+ DRUGS_FILE = f"{DATA_DIR}/drugsInfo.csv"
22
+ DISEASES_FILE = f"{DATA_DIR}/diseasesInfo.csv"
const_data.py ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Data Constants - SUD Categories, Drug/Project Templates, Synthetic Data Settings
3
+ All data generation and template related constants
4
+ """
5
+
6
+ # ========================================
7
+ # SUD CATEGORIES (Used in generate_synthetic_data)
8
+ # ========================================
9
+
10
+ SUD_CATEGORY_DESCRIPTIONS = {
11
+ "Opioid-Related Disorders": "Addiction to opioids including prescription painkillers, heroin, and fentanyl",
12
+ "Alcohol Use Disorder": "Problematic pattern of alcohol use leading to clinically significant impairment",
13
+ "Stimulant Use Disorder": "Addiction to cocaine, methamphetamine, or prescription stimulants",
14
+ "Cannabis Use Disorder": "Problematic cannabis use with withdrawal and tolerance symptoms",
15
+ "Sedative/Hypnotic Disorder": "Dependence on benzodiazepines or other sedative medications",
16
+ "Nicotine Use Disorder": "Tobacco/nicotine dependence and addiction",
17
+ }
18
+
19
+ SUD_CATEGORY_COLORS = {
20
+ "Opioid-Related Disorders": "#1E6B52",
21
+ "Alcohol Use Disorder": "#008C95",
22
+ "Stimulant Use Disorder": "#5A9B7F",
23
+ "Cannabis Use Disorder": "#16533E",
24
+ "Sedative/Hypnotic Disorder": "#4A8B7A",
25
+ "Nicotine Use Disorder": "#2C7A64",
26
+ }
27
+
28
+ DISEASE_SEARCH_CONFIG = {
29
+ "Opioid-Related Disorders": {
30
+ "search_terms": ["Opioid-Related Disorders"],
31
+ },
32
+ "Alcohol Use Disorder": {
33
+ "search_terms": ["Alcoholism"],
34
+ },
35
+ "Stimulant Use Disorder": {
36
+ "search_terms": ["Stimulant Use Disorder"],
37
+ },
38
+ "Cannabis Use Disorder": {
39
+ "search_terms": ["Cannabis Use Disorder"],
40
+ },
41
+ "Nicotine Use Disorder": {
42
+ "search_terms": ["Tobacco Use Disorder"],
43
+ },
44
+ "Sedative/Hypnotic Disorder": {
45
+ "search_terms": ["Sedative/Hypnotic Disorder"],
46
+ },
47
+ }
48
+
49
+ # ========================================
50
+ # DRUG TEMPLATES (Used in generate_synthetic_data)
51
+ # ========================================
52
+
53
+ DRUG_TEMPLATES = {
54
+ "Opioid-Related Disorders": [
55
+ ("Naltrexone", "Alcohol/opioid dependence", "μ-opioid receptor antagonist", "S5"),
56
+ ("Buprenorphine", "Opioid dependence", "Partial μ-opioid agonist", "S6"),
57
+ ("Lofexidine", "Hypertension", "α2-adrenergic agonist", "S4"),
58
+ ("Gabapentin", "Epilepsy, neuropathic pain", "GABA analog", "S4"),
59
+ ("Topiramate", "Epilepsy, migraine", "GABA modulator", "S3"),
60
+ ("Ondansetron", "Nausea/vomiting", "5-HT3 antagonist", "S2"),
61
+ ("Clonidine", "Hypertension", "α2-adrenergic agonist", "S3"),
62
+ ("Memantine", "Alzheimer's disease", "NMDA antagonist", "S2"),
63
+ ("Prazosin", "Hypertension", "α1-adrenergic antagonist", "S1"),
64
+ ("Mirtazapine", "Depression", "α2-adrenergic antagonist", "S2"),
65
+ ],
66
+ "Alcohol Use Disorder": [
67
+ ("Acamprosate", "Alcohol dependence", "NMDA antagonist", "S5"),
68
+ ("Naltrexone", "Opioid dependence", "μ-opioid antagonist", "S5"),
69
+ ("Baclofen", "Muscle spasticity", "GABA-B agonist", "S4"),
70
+ ("Topiramate", "Epilepsy", "GABA modulator", "S4"),
71
+ ("Varenicline", "Smoking cessation", "Nicotinic receptor agonist", "S3"),
72
+ ("Ondansetron", "Nausea/vomiting", "5-HT3 antagonist", "S3"),
73
+ ("Gabapentin", "Epilepsy", "GABA analog", "S2"),
74
+ ("Zonisamide", "Epilepsy", "Carbonic anhydrase inhibitor", "S1"),
75
+ ],
76
+ "Stimulant Use Disorder": [
77
+ ("Modafinil", "Narcolepsy", "Dopamine reuptake inhibitor", "S4"),
78
+ ("Bupropion", "Depression", "NDRI", "S4"),
79
+ ("Topiramate", "Epilepsy", "GABA modulator", "S3"),
80
+ ("N-acetylcysteine", "Acetaminophen overdose", "Antioxidant", "S3"),
81
+ ("Mirtazapine", "Depression", "α2-antagonist", "S2"),
82
+ ("Atomoxetine", "ADHD", "NRI", "S1"),
83
+ ],
84
+ "Cannabis Use Disorder": [
85
+ ("N-acetylcysteine", "Acetaminophen overdose", "Antioxidant", "S3"),
86
+ ("Gabapentin", "Epilepsy", "GABA analog", "S3"),
87
+ ("Zolpidem", "Insomnia", "GABA-A modulator", "S2"),
88
+ ("Dronabinol", "Nausea/vomiting", "CB1 agonist", "S2"),
89
+ ("Buspirone", "Anxiety", "5-HT1A agonist", "S1"),
90
+ ],
91
+ "Sedative/Hypnotic Disorder": [
92
+ ("Flumazenil", "Benzodiazepine overdose", "GABA-A antagonist", "S3"),
93
+ ("Gabapentin", "Epilepsy", "GABA analog", "S3"),
94
+ ("Pregabalin", "Neuropathic pain", "GABA analog", "S2"),
95
+ ],
96
+ "Nicotine Use Disorder": [
97
+ ("Varenicline", "Smoking cessation", "Nicotinic receptor agonist", "S6"),
98
+ ("Cytisine", "Smoking cessation (EU)", "Nicotinic receptor agonist", "S5"),
99
+ ("Bupropion", "Depression", "NDRI", "S5"),
100
+ ("Naltrexone", "Opioid dependence", "μ-opioid antagonist", "S4"),
101
+ ],
102
+ }
103
+
104
+ # ========================================
105
+ # PROJECT TEMPLATES (Used in generate_synthetic_data)
106
+ # ========================================
107
+
108
+ PROJECT_TEMPLATES = [
109
+ {
110
+ "name": "NIDA Clinical Trial NCT02892123",
111
+ "type": "Clinical Trial",
112
+ "size_range": (150, 500),
113
+ "impact_range": (0.10, 0.20),
114
+ "summary": "Randomized controlled trial showing significant reduction in relapse rates"
115
+ },
116
+ {
117
+ "name": "Meta-Analysis Lee et al. 2024",
118
+ "type": "Meta-Analysis",
119
+ "size_range": (800, 3000),
120
+ "impact_range": (0.08, 0.15),
121
+ "summary": "Pooled analysis of multiple RCTs demonstrating efficacy across populations"
122
+ },
123
+ {
124
+ "name": "RWE Claims Database Analysis",
125
+ "type": "Real-World Evidence",
126
+ "size_range": (2000, 10000),
127
+ "impact_range": (0.05, 0.12),
128
+ "summary": "Insurance claims data showing real-world treatment adherence and outcomes"
129
+ },
130
+ {
131
+ "name": "Biomarker Validation Study",
132
+ "type": "Biomarker Study",
133
+ "size_range": (50, 200),
134
+ "impact_range": (0.06, 0.10),
135
+ "summary": "Identification of predictive biomarkers for treatment response"
136
+ },
137
+ {
138
+ "name": "Phase II Safety Trial",
139
+ "type": "Clinical Trial",
140
+ "size_range": (100, 300),
141
+ "impact_range": (0.07, 0.13),
142
+ "summary": "Safety and tolerability data in target SUD population"
143
+ },
144
+ {
145
+ "name": "Safety Concern Report FDA-2024",
146
+ "type": "Safety Analysis",
147
+ "size_range": (80, 250),
148
+ "impact_range": (-0.15, -0.08),
149
+ "summary": "Adverse event reports indicating potential safety concerns in target population"
150
+ },
151
+ {
152
+ "name": "Negative RCT Results Study",
153
+ "type": "Clinical Trial",
154
+ "size_range": (120, 400),
155
+ "impact_range": (-0.12, -0.06),
156
+ "summary": "Randomized trial showing no significant efficacy compared to placebo"
157
+ },
158
+ ]
159
+
160
+ # ========================================
161
+ # METRICS & ANALYTICS (Used in analytics functions)
162
+ # ========================================
163
+
164
+ AVERAGE_TIME_TO_IND = 12.7 # months
165
+ CURRENT_IND_READY_COUNT = 2
166
+
167
+ TIME_BINS_LABELS = ['6-9', '9-12', '12-15', '15-18', '18-21', '21-24', '24+']
168
+ TIME_BINS_COUNTS = [10, 16, 25, 31, 39, 42, 49]
169
+
170
+ QUARTERLY_DELIVERIES = [
171
+ {'quarter': 'Sep 2025', 'year': 2025, 'count': 0, 'cumulative': 0},
172
+ {'quarter': 'Jan 2026', 'year': 2026, 'count': 0.5, 'cumulative': 0.5},
173
+ {'quarter': 'Apr 2026', 'year': 2026, 'count': 0.3, 'cumulative': 0.8},
174
+ {'quarter': 'Jun 2026', 'year': 2026, 'count': 1.2, 'cumulative': 2.0},
175
+ {'quarter': 'Sep 2026', 'year': 2026, 'count': 0, 'cumulative': 2.0},
176
+ ]
const_ui.py ADDED
@@ -0,0 +1,114 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ UI Constants - Colors, Styling, Display Settings
3
+ All visual/interface related constants
4
+ """
5
+
6
+ # ========================================
7
+ # COLOR PALETTE (Used throughout pipeline)
8
+ # ========================================
9
+
10
+ UAB_GREEN = "#1E6B52"
11
+ UAB_DARK_GREEN = "#16533E"
12
+ UAB_LIGHT_GREEN = "#5A9B7F"
13
+ UAB_ACCENT_TEAL = "#008C95"
14
+ UAB_PALE_GREEN = "#E8F4F0"
15
+ UAB_WHITE = "#FFFFFF"
16
+
17
+ # ========================================
18
+ # STAGE CONFIGURATION (Used in generate_synthetic_data, badges, etc.)
19
+ # ========================================
20
+
21
+ STAGE_MAPPING = {
22
+ "S0": (0.35, 0.50),
23
+ "S1": (0.45, 0.58),
24
+ "S2": (0.55, 0.68),
25
+ "S3": (0.65, 0.78),
26
+ "S4": (0.73, 0.85),
27
+ "S5": (0.80, 0.92),
28
+ "S6": (0.88, 0.95),
29
+ }
30
+
31
+ STAGE_NAMES = {
32
+ "S0": "Ideation",
33
+ "S1": "Intake",
34
+ "S2": "Feasibility",
35
+ "S3": "In Silico",
36
+ "S4": "Wet Lab",
37
+ "S5": "IND-Ready",
38
+ "S6": "Handoff"
39
+ }
40
+
41
+ STAGE_COLORS = {
42
+ "S0": "#94A3B8",
43
+ "S1": "#A8CABD",
44
+ "S2": UAB_LIGHT_GREEN,
45
+ "S3": UAB_GREEN,
46
+ "S4": UAB_GREEN,
47
+ "S5": UAB_DARK_GREEN,
48
+ "S6": UAB_DARK_GREEN,
49
+ }
50
+
51
+ # ========================================
52
+ # SCORE THRESHOLDS (Used in charts and interpretation)
53
+ # ========================================
54
+
55
+ SCORE_THRESHOLD_HIGH = 0.7
56
+ SCORE_THRESHOLD_MODERATE = 0.5
57
+
58
+ # ========================================
59
+ # DISPLAY SETTINGS (Used in UI rendering)
60
+ # ========================================
61
+
62
+ MAX_CATEGORY_CANDIDATES_DISPLAY = 12
63
+ MAX_TOP_CANDIDATES_DISPLAY = 5
64
+ SMILES_DISPLAY_LENGTH = 60
65
+ MAX_TARGET_DISPLAY = 5
66
+
67
+ # Chart heights
68
+ CHART_HEIGHT_SMALL = 190
69
+ CHART_HEIGHT_MEDIUM = 300
70
+ CHART_HEIGHT_LARGE = 400
71
+
72
+ # ========================================
73
+ # HELPER FUNCTIONS
74
+ # ========================================
75
+
76
+ def get_status_badge(stage):
77
+ """Generate HTML badge for stage status"""
78
+ colors = STAGE_COLORS
79
+ names = STAGE_NAMES
80
+
81
+ color = colors.get(stage, "#CBD5E0")
82
+ name = names.get(stage, stage)
83
+
84
+ return f'<span style="background: {color}; padding: 5px 12px; border-radius: 15px; font-weight: bold; color: white; font-family: \'Times New Roman\', Times, serif;">{stage} - {name}</span>'
85
+
86
+
87
+ def get_score_type_badge(score_type):
88
+ """Get badge for score type (Real ML/DL or Synthetic/AI)"""
89
+ if score_type == "Real":
90
+ return f'<span style="background: {UAB_DARK_GREEN}; padding: 4px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif; font-size: 11px;">🤖 Real ML/DL</span>'
91
+ else:
92
+ return f'<span style="background: #FFA500; padding: 4px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif; font-size: 11px;">🔮 Synthetic/AI</span>'
93
+
94
+
95
+ def get_evidence_stars(score):
96
+ """Convert score to star rating"""
97
+ stars = int(score * 5)
98
+ return "⭐" * stars
99
+
100
+
101
+ def get_impact_badge(impact):
102
+ """Generate HTML badge for project impact"""
103
+ if impact >= 0.10:
104
+ return f'<span style="background: {UAB_DARK_GREEN}; padding: 3px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif;">High +{impact:.2f}</span>'
105
+ elif impact >= 0.05:
106
+ return f'<span style="background: {UAB_GREEN}; padding: 3px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif;">Moderate +{impact:.2f}</span>'
107
+ elif impact > 0:
108
+ return f'<span style="background: #A0AEC0; padding: 3px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif;">Low +{impact:.2f}</span>'
109
+ elif impact <= -0.10:
110
+ return f'<span style="background: #DC2626; padding: 3px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif;">High Risk {impact:.2f}</span>'
111
+ elif impact <= -0.05:
112
+ return f'<span style="background: #EF4444; padding: 3px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif;">Moderate Risk {impact:.2f}</span>'
113
+ else:
114
+ return f'<span style="background: #F87171; padding: 3px 10px; border-radius: 10px; color: white; font-family: \'Times New Roman\', Times, serif;">Low Risk {impact:.2f}</span>'
data1/diseasesInfo.csv ADDED
The diff for this file is too large to render. See raw diff
 
data1/drugsInfo.csv ADDED
The diff for this file is too large to render. See raw diff
 
data1/mapping.csv ADDED
The diff for this file is too large to render. See raw diff
 
data_generator.py ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Data Generator Module
3
+ Extracted from sud_promise_uab_theme.py
4
+ Handles disease ID mapping and synthetic data generation with real ML/DL scores
5
+ """
6
+
7
+ import random
8
+ from datetime import datetime, timedelta
9
+ from dataclasses import dataclass, field
10
+ from typing import List
11
+
12
+ # Import dependencies
13
+ from const_ui import (
14
+ UAB_GREEN, UAB_DARK_GREEN, UAB_LIGHT_GREEN, UAB_ACCENT_TEAL,
15
+ STAGE_MAPPING
16
+ )
17
+ from const_data import (
18
+ SUD_CATEGORY_DESCRIPTIONS, DISEASE_SEARCH_CONFIG,
19
+ DRUG_TEMPLATES, PROJECT_TEMPLATES
20
+ )
21
+ from func_drug import find_drug_in_database
22
+
23
+ # ========================================
24
+ # DATA MODELS
25
+ # ========================================
26
+
27
+ @dataclass
28
+ class Project:
29
+ """Research project providing evidence"""
30
+ id: str
31
+ name: str
32
+ project_type: str
33
+ added_date: datetime
34
+ sample_size: int
35
+ impact_score: float
36
+ status: str
37
+ summary: str
38
+
39
+ @dataclass
40
+ class DrugCandidate:
41
+ """Drug being evaluated for repositioning"""
42
+ id: str
43
+ drug_name: str
44
+ current_indication: str
45
+ target_sud_subtype: str
46
+ mechanism: str
47
+ stage: str
48
+ evidence_score: float
49
+ baseline_score: float
50
+ smiles: str
51
+ attached_projects: List[Project]
52
+ last_updated: datetime
53
+ cohort_count: int
54
+ has_market_analysis: bool
55
+ has_validation_plan: bool
56
+ team_members: int
57
+ data_produced: int
58
+ publications: int
59
+ tools_used: int
60
+ data_governance: int
61
+ training_participated: int
62
+ stage_entry_date: datetime = None
63
+ stage_history: List[tuple] = field(default_factory=list)
64
+ score_type: str = "Synthetic"
65
+ model_scores: dict = field(default_factory=dict)
66
+ protein_targets: List[str] = field(default_factory=list)
67
+ disease_id: str = ""
68
+
69
+ @dataclass
70
+ class SUDCategory:
71
+ """SUD disease category"""
72
+ name: str
73
+ color: str
74
+ hex_color: str
75
+ icon: str
76
+ candidate_count: int
77
+ description: str
78
+ disease_id: str = ""
79
+
80
+ # ========================================
81
+ # DISEASE ID MAPPING
82
+ # ========================================
83
+
84
+ def setup_disease_mapping(diseases_df):
85
+ """Setup disease ID mapping from database"""
86
+ DISEASE_ID_MAPPING = {}
87
+
88
+ if diseases_df is not None:
89
+ print("\n🔍 Searching for best disease name matches in database...")
90
+
91
+ for category, config in DISEASE_SEARCH_CONFIG.items():
92
+ print(f"\n Searching for: {category}")
93
+ found = False
94
+
95
+ for search_term in config["search_terms"]:
96
+ # Try exact match first
97
+ exact_mask = diseases_df['DiseaseName'].str.lower() == search_term.lower()
98
+ exact_matches = diseases_df[exact_mask]
99
+
100
+ if len(exact_matches) > 0:
101
+ disease_id = exact_matches.iloc[0]['DiseaseID']
102
+ disease_name = exact_matches.iloc[0]['DiseaseName']
103
+ DISEASE_ID_MAPPING[category] = disease_id
104
+ print(f" EXACT MATCH: '{disease_name}'")
105
+ print(f" → {disease_id}")
106
+ found = True
107
+ break
108
+
109
+ # Try partial match if exact fails
110
+ partial_mask = diseases_df['DiseaseName'].str.lower().str.contains(search_term.lower(), na=False)
111
+ partial_matches = diseases_df[partial_mask]
112
+
113
+ if len(partial_matches) > 0:
114
+ disease_id = partial_matches.iloc[0]['DiseaseID']
115
+ disease_name = partial_matches.iloc[0]['DiseaseName']
116
+ DISEASE_ID_MAPPING[category] = disease_id
117
+ print(f" Partial match for '{search_term}': '{disease_name}'")
118
+ print(f" → {disease_id}")
119
+ found = True
120
+ break
121
+
122
+ if not found:
123
+ print(f" No matches found for {category}")
124
+
125
+ print(f"\n{'='*80}")
126
+ print(f"📋 FINAL DISEASE MAPPING:")
127
+ print(f"{'='*80}")
128
+ for category, disease_id in DISEASE_ID_MAPPING.items():
129
+ disease_row = diseases_df[diseases_df['DiseaseID'] == disease_id]
130
+ if len(disease_row) > 0:
131
+ disease_name = disease_row.iloc[0]['DiseaseName']
132
+ print(f"{category}:")
133
+ print(f" → {disease_id} ({disease_name})")
134
+
135
+ print(f"\n Successfully mapped {len(DISEASE_ID_MAPPING)}/6 SUD categories\n")
136
+
137
+ return DISEASE_ID_MAPPING
138
+
139
+ # ========================================
140
+ # SYNTHETIC DATA GENERATION WITH REAL ML/DL SCORES
141
+ # ========================================
142
+
143
+ def generate_synthetic_data(DISEASE_ID_MAPPING, MODELS_AVAILABLE, ml_components, drugs_df):
144
+ """Generate realistic synthetic SUD repositioning data with REAL ML/DL scores where possible"""
145
+
146
+ # Import here to avoid circular dependency
147
+ from func_models import predict_with_ml_models
148
+
149
+ print("\n" + "="*70)
150
+ print("🔬 GENERATING CANDIDATE DATA WITH ML/DL PREDICTIONS")
151
+ print("="*70)
152
+
153
+ # Use corrected category names
154
+ sud_categories = [
155
+ SUDCategory("Opioid-Related Disorders", "", UAB_GREEN, "", 0,
156
+ SUD_CATEGORY_DESCRIPTIONS["Opioid-Related Disorders"],
157
+ disease_id=DISEASE_ID_MAPPING.get("Opioid-Related Disorders", "")),
158
+ SUDCategory("Alcohol Use Disorder", "", UAB_ACCENT_TEAL, "", 0,
159
+ SUD_CATEGORY_DESCRIPTIONS["Alcohol Use Disorder"],
160
+ disease_id=DISEASE_ID_MAPPING.get("Alcohol Use Disorder", "")),
161
+ SUDCategory("Stimulant Use Disorder", "", UAB_LIGHT_GREEN, "", 0,
162
+ SUD_CATEGORY_DESCRIPTIONS["Stimulant Use Disorder"],
163
+ disease_id=DISEASE_ID_MAPPING.get("Stimulant Use Disorder", "")),
164
+ SUDCategory("Cannabis Use Disorder", "", UAB_DARK_GREEN, "", 0,
165
+ SUD_CATEGORY_DESCRIPTIONS["Cannabis Use Disorder"],
166
+ disease_id=DISEASE_ID_MAPPING.get("Cannabis Use Disorder", "")),
167
+ SUDCategory("Sedative/Hypnotic Disorder", "", "#4A8B7A", "", 0,
168
+ SUD_CATEGORY_DESCRIPTIONS["Sedative/Hypnotic Disorder"],
169
+ disease_id=DISEASE_ID_MAPPING.get("Sedative/Hypnotic Disorder", "")),
170
+ SUDCategory("Nicotine Use Disorder", "", "#2C7A64", "", 0,
171
+ SUD_CATEGORY_DESCRIPTIONS["Nicotine Use Disorder"],
172
+ disease_id=DISEASE_ID_MAPPING.get("Nicotine Use Disorder", "")),
173
+ ]
174
+
175
+ candidates = []
176
+ candidate_id = 1
177
+
178
+ total_real_scores = 0
179
+ total_synthetic_scores = 0
180
+
181
+ for category in sud_categories:
182
+ if category.name not in DRUG_TEMPLATES:
183
+ continue
184
+
185
+ category_real = 0
186
+ category_synthetic = 0
187
+
188
+ print(f"\n🔬 Processing {category.name}...")
189
+ if category.disease_id:
190
+ print(f" Disease ID: {category.disease_id}")
191
+ else:
192
+ print(f" No disease ID mapped - using synthetic scores only")
193
+
194
+ for drug_info in DRUG_TEMPLATES[category.name]:
195
+ drug_name, current_use, mechanism, stage = drug_info
196
+
197
+ # Try to find drug in database using corrected function
198
+ drug_smiles, drug_targets = find_drug_in_database(drug_name, drugs_df)
199
+
200
+ if not drug_smiles:
201
+ # Generate random SMILES if not found
202
+ drug_smiles = f"C{'C' * random.randint(5, 15)}N"
203
+ drug_targets = []
204
+ print(f" {drug_name}: Not in database, using synthetic SMILES")
205
+ else:
206
+ print(f" {drug_name}: Found in database")
207
+
208
+ # Generate stage history
209
+ stage_num = int(stage[1])
210
+ stage_history = []
211
+
212
+ days_in_pipeline = random.randint(360, 900)
213
+ start_date_candidate = datetime.now() - timedelta(days=days_in_pipeline)
214
+
215
+ current_date = start_date_candidate
216
+ for s in range(stage_num + 1):
217
+ stage_name = f"S{s}"
218
+ days_in_stage = random.randint(60, 120)
219
+ stage_entry = current_date
220
+ stage_history.append((stage_name, stage_entry))
221
+ current_date = current_date + timedelta(days=days_in_stage)
222
+
223
+ stage_entry_date = stage_history[-1][1] if stage_history else datetime.now()
224
+
225
+ score_min, score_max = STAGE_MAPPING[stage]
226
+ baseline = random.uniform(0.40, 0.55)
227
+
228
+ # Try to get REAL ML/DL scores
229
+ score_type = "Synthetic"
230
+ model_scores = {}
231
+ evidence_score = baseline
232
+ baseline_score = baseline # Will be updated for Real predictions
233
+
234
+ if category.disease_id and drug_smiles and MODELS_AVAILABLE:
235
+ print(f" Predicting {drug_name} → {category.disease_id}...", end=" ")
236
+ ml_results, message, ml_score_type = predict_with_ml_models(
237
+ drug_smiles, drug_targets, category.disease_id, ml_components
238
+ )
239
+
240
+ if ml_results is not None and ml_score_type == "Real":
241
+ score_type = "Real"
242
+ model_scores = ml_results
243
+
244
+ # FIXED: Use ensemble as BASELINE
245
+ baseline_score = ml_results.get('Ensemble', baseline)
246
+
247
+ # Calculate target evidence score
248
+ num_projects = random.randint(3, 5)
249
+ total_impact_needed = random.uniform(0.15, 0.35) # Total impact from projects
250
+ evidence_score = baseline_score + total_impact_needed
251
+ evidence_score = max(0.20, min(0.95, evidence_score))
252
+
253
+ # Recalculate actual impact needed after clamping
254
+ total_impact_needed = evidence_score - baseline_score
255
+
256
+ print(f" Real ML/DL: {baseline_score:.3f} → {evidence_score:.3f}")
257
+ category_real += 1
258
+ total_real_scores += 1
259
+ else:
260
+ # Generate synthetic score with projects
261
+ baseline_score = baseline
262
+ num_projects = random.randint(3, 5)
263
+ total_impact_needed = random.uniform(0.20, 0.40)
264
+ evidence_score = baseline_score + total_impact_needed
265
+ evidence_score = max(0.20, min(0.95, evidence_score))
266
+ total_impact_needed = evidence_score - baseline_score
267
+
268
+ print(f" Synthetic score: {evidence_score:.3f} ({message})")
269
+ category_synthetic += 1
270
+ total_synthetic_scores += 1
271
+ else:
272
+ # Generate synthetic score
273
+ baseline_score = baseline
274
+ num_projects = random.randint(3, 5)
275
+ total_impact_needed = random.uniform(0.20, 0.40)
276
+ evidence_score = baseline_score + total_impact_needed
277
+ evidence_score = max(0.20, min(0.95, evidence_score))
278
+ total_impact_needed = evidence_score - baseline_score
279
+
280
+ print(f" {drug_name}: Synthetic score: {evidence_score:.3f}")
281
+ category_synthetic += 1
282
+ total_synthetic_scores += 1
283
+
284
+ # NOW Generate projects with impacts that sum EXACTLY to total_impact_needed
285
+ projects = []
286
+
287
+ # Distribute the total impact across projects
288
+ remaining_impact = total_impact_needed
289
+ for i in range(num_projects):
290
+ template = random.choice(PROJECT_TEMPLATES)
291
+ days_ago = random.randint(30 + i*50, days_in_pipeline - (num_projects - i)*30)
292
+
293
+ if i == num_projects - 1:
294
+ # Last project gets exactly the remaining impact
295
+ impact = remaining_impact
296
+ else:
297
+ # Random portion of remaining, but ensure we don't exhaust it
298
+ max_this_impact = remaining_impact * 0.6 # Use at most 60% of remaining
299
+ impact = random.uniform(-0.05, max_this_impact)
300
+ remaining_impact -= impact
301
+
302
+ project = Project(
303
+ id=f"proj_{candidate_id}_{i}",
304
+ name=template["name"],
305
+ project_type=template["type"],
306
+ added_date=datetime.now() - timedelta(days=days_ago),
307
+ sample_size=random.randint(*template["size_range"]),
308
+ impact_score=impact, # Use calculated impact
309
+ status="Completed" if random.random() > 0.2 else "Active",
310
+ summary=template["summary"]
311
+ )
312
+ projects.append(project)
313
+
314
+ # Sort by date
315
+ projects.sort(key=lambda p: p.added_date)
316
+
317
+ stage_num = int(stage[1])
318
+
319
+ candidate = DrugCandidate(
320
+ id=f"cand_{candidate_id}",
321
+ drug_name=drug_name,
322
+ current_indication=current_use,
323
+ target_sud_subtype=category.name,
324
+ mechanism=mechanism,
325
+ stage=stage,
326
+ evidence_score=evidence_score,
327
+ baseline_score=baseline_score, # Now uses ensemble for Real scores
328
+ smiles=drug_smiles,
329
+ attached_projects=projects,
330
+ last_updated=datetime.now() - timedelta(days=random.randint(1, 30)),
331
+ cohort_count=random.randint(1 + stage_num, 4 + stage_num * 2),
332
+ has_market_analysis=random.random() > 0.3,
333
+ has_validation_plan=random.random() > 0.4,
334
+ team_members=random.randint(2 + stage_num, 5 + stage_num * 2),
335
+ data_produced=random.randint(1 + stage_num, 3 + stage_num * 2),
336
+ publications=random.randint(0 + stage_num // 2, 2 + stage_num),
337
+ tools_used=random.randint(1 + stage_num // 2, 3 + stage_num),
338
+ data_governance=random.randint(1, 2 + stage_num // 2),
339
+ training_participated=random.randint(stage_num, 2 + stage_num),
340
+ stage_entry_date=stage_entry_date,
341
+ stage_history=stage_history,
342
+ score_type=score_type,
343
+ model_scores=model_scores,
344
+ protein_targets=drug_targets,
345
+ disease_id=category.disease_id
346
+ )
347
+ candidates.append(candidate)
348
+ candidate_id += 1
349
+
350
+ # Update category count
351
+ category.candidate_count = category_real + category_synthetic
352
+ print(f" Summary: {category_real} real, {category_synthetic} synthetic")
353
+
354
+ print(f"\n{'='*70}")
355
+ print(f" FINAL STATISTICS")
356
+ print(f"{'='*70}")
357
+ print(f"Total candidates: {len(candidates)}")
358
+ print(f"Real ML/DL scores: {total_real_scores}")
359
+ print(f"Synthetic scores: {total_synthetic_scores}")
360
+ print(f"Real score percentage: {total_real_scores / len(candidates) * 100:.1f}%")
361
+ print(f"{'='*70}\n")
362
+
363
+ return sud_categories, candidates
func_drug.py ADDED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Drug Database Utility Functions
3
+ Handles searching and extracting drug information from the database
4
+ """
5
+
6
+ import pandas as pd
7
+ import ast
8
+ from typing import Optional, List, Tuple
9
+
10
+
11
+ def find_drug_in_database(drug_name: str, drugs_df: pd.DataFrame) -> Tuple[Optional[str], Optional[List[str]]]:
12
+ """
13
+ Extract SMILES and targets for a drug by EXACT name match first, then partial
14
+
15
+ Args:
16
+ drug_name: Name of the drug to search for
17
+ drugs_df: DataFrame containing drug information with columns:
18
+ - DrugName: name of the drug
19
+ - DrugSmile: SMILES structure
20
+ - DrugTarget: protein targets (as string representation of list)
21
+
22
+ Returns:
23
+ Tuple of (smiles, targets):
24
+ - smiles: SMILES string representation of molecular structure, or None if not found
25
+ - targets: List of protein target names, or empty list if none found
26
+
27
+ Examples:
28
+ >>> smiles, targets = find_drug_in_database("Naltrexone", drugs_df)
29
+ >>> print(f"SMILES: {smiles}")
30
+ >>> print(f"Targets: {targets}")
31
+ """
32
+ if drugs_df is None:
33
+ return None, None
34
+
35
+ # Try EXACT match first (case-insensitive)
36
+ mask = drugs_df['DrugName'].str.lower() == drug_name.lower()
37
+ matches = drugs_df[mask]
38
+
39
+ # If no exact match, try partial match
40
+ if len(matches) == 0:
41
+ mask = drugs_df['DrugName'].str.lower().str.contains(drug_name.lower(), na=False)
42
+ matches = drugs_df[mask]
43
+
44
+ if len(matches) == 0:
45
+ return None, None
46
+
47
+ # Get the first match
48
+ row = matches.iloc[0]
49
+
50
+ # Extract SMILES - try multiple possible column names
51
+ smiles = None
52
+ smiles_columns = ['DrugSmile', 'SMILES', 'Smiles', 'smiles', 'DrugSMILES', 'Structure']
53
+ for col in smiles_columns:
54
+ if col in row.index and pd.notna(row[col]) and str(row[col]).strip():
55
+ smiles = str(row[col]).strip()
56
+ break
57
+
58
+ # Extract Targets - try multiple possible column names
59
+ targets = []
60
+ target_columns = ['DrugTarget', 'Targets', 'Target', 'targets', 'ProteinTargets']
61
+ for col in target_columns:
62
+ if col in row.index and pd.notna(row[col]) and str(row[col]).strip():
63
+ raw_targets = str(row[col]).strip()
64
+
65
+ # Parse if it's a string representation of a list
66
+ if raw_targets.startswith('[') and raw_targets.endswith(']'):
67
+ try:
68
+ targets = ast.literal_eval(raw_targets)
69
+ except:
70
+ targets = [raw_targets]
71
+ elif ',' in raw_targets:
72
+ # Handle comma-separated targets
73
+ targets = [t.strip() for t in raw_targets.split(',')]
74
+ else:
75
+ # Single target
76
+ targets = [raw_targets]
77
+ break
78
+
79
+ return smiles, targets if targets else []
80
+
81
+
82
+ def search_drugs_by_target(target_name: str, drugs_df: pd.DataFrame,
83
+ exact_match: bool = False) -> pd.DataFrame:
84
+ """
85
+ Search for drugs that target a specific protein
86
+
87
+ Args:
88
+ target_name: Name of the protein target to search for
89
+ drugs_df: DataFrame containing drug information
90
+ exact_match: If True, only return exact matches; if False, use partial matching
91
+
92
+ Returns:
93
+ DataFrame containing all drugs that target the specified protein
94
+ """
95
+ if drugs_df is None:
96
+ return pd.DataFrame()
97
+
98
+ def has_target(targets_str):
99
+ if pd.isna(targets_str):
100
+ return False
101
+
102
+ # Parse targets
103
+ targets = []
104
+ if str(targets_str).startswith('['):
105
+ try:
106
+ targets = ast.literal_eval(str(targets_str))
107
+ except:
108
+ targets = [str(targets_str)]
109
+ else:
110
+ targets = [str(targets_str)]
111
+
112
+ # Check if target matches
113
+ for target in targets:
114
+ if exact_match:
115
+ if target.lower() == target_name.lower():
116
+ return True
117
+ else:
118
+ if target_name.lower() in target.lower():
119
+ return True
120
+ return False
121
+
122
+ mask = drugs_df['DrugTarget'].apply(has_target)
123
+ return drugs_df[mask]
124
+
125
+
126
+ def get_drug_info(drug_name: str, drugs_df: pd.DataFrame) -> dict:
127
+ """
128
+ Get complete information about a drug
129
+
130
+ Args:
131
+ drug_name: Name of the drug
132
+ drugs_df: DataFrame containing drug information
133
+
134
+ Returns:
135
+ Dictionary with drug information including:
136
+ - name: Drug name
137
+ - smiles: SMILES structure
138
+ - targets: List of protein targets
139
+ - found: Boolean indicating if drug was found
140
+ """
141
+ smiles, targets = find_drug_in_database(drug_name, drugs_df)
142
+
143
+ return {
144
+ 'name': drug_name,
145
+ 'smiles': smiles,
146
+ 'targets': targets if targets else [],
147
+ 'found': smiles is not None
148
+ }
149
+
150
+
151
+ def validate_smiles(smiles: str) -> bool:
152
+ """
153
+ Validate if a SMILES string is valid (requires RDKit)
154
+
155
+ Args:
156
+ smiles: SMILES string to validate
157
+
158
+ Returns:
159
+ True if valid, False otherwise
160
+ """
161
+ try:
162
+ from rdkit import Chem
163
+ mol = Chem.MolFromSmiles(smiles)
164
+ return mol is not None
165
+ except:
166
+ return False
167
+
168
+
169
+ # Example usage and testing
170
+ if __name__ == "__main__":
171
+ # Load example data
172
+ try:
173
+ drugs_df = pd.read_csv("data1/drugsInfo.csv")
174
+ print(f" Loaded {len(drugs_df)} drugs from database\n")
175
+
176
+ # Test 1: Find a specific drug
177
+ print("="*60)
178
+ print("TEST 1: Find Naltrexone")
179
+ print("="*60)
180
+ smiles, targets = find_drug_in_database("Naltrexone", drugs_df)
181
+ if smiles:
182
+ print(f" Found!")
183
+ print(f" SMILES: {smiles[:60]}...")
184
+ print(f" Targets: {targets[:3]}{'...' if len(targets) > 3 else ''}")
185
+ else:
186
+ print(f"❌ Not found")
187
+
188
+ # Test 2: Get complete info
189
+ print("\n" + "="*60)
190
+ print("TEST 2: Get complete drug info")
191
+ print("="*60)
192
+ info = get_drug_info("Buprenorphine", drugs_df)
193
+ print(f"Drug: {info['name']}")
194
+ print(f"Found: {info['found']}")
195
+ print(f"Targets: {len(info['targets'])} targets")
196
+
197
+ # Test 3: Search by target
198
+ print("\n" + "="*60)
199
+ print("TEST 3: Search drugs targeting opioid receptors")
200
+ print("="*60)
201
+ results = search_drugs_by_target("opioid", drugs_df, exact_match=False)
202
+ print(f"Found {len(results)} drugs")
203
+ if len(results) > 0:
204
+ print("Examples:")
205
+ for i, (idx, row) in enumerate(results.head(3).iterrows(), 1):
206
+ print(f" {i}. {row['DrugName']}")
207
+
208
+ except FileNotFoundError:
209
+ print("❌ Error: data1/drugsInfo.csv not found")
210
+ print(" Make sure the database file exists in the correct location")
func_models.py ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ ML/DL Prediction Utilities
3
+ Functions for making predictions with trained ML/DL models
4
+
5
+ VERSION: 3.5.0 - Single initialization function for easy integration
6
+ - Added initialize_ml_system() function
7
+ - Consolidates all loading logic
8
+ - Returns complete system state
9
+ - Uses const_config for default paths
10
+ """
11
+
12
+ import numpy as np
13
+ import pandas as pd
14
+ from pathlib import Path
15
+ from typing import Tuple, Dict, List, Optional
16
+ import joblib
17
+
18
+ # Import configuration constants
19
+ from const_config import MODEL_DIR, DRUGS_FILE, DISEASES_FILE
20
+
21
+ def initialize_ml_system(model_dir: str = MODEL_DIR,
22
+ drugs_file: str = DRUGS_FILE,
23
+ diseases_file: str = DISEASES_FILE) -> Dict:
24
+ """
25
+ Initialize the complete ML/DL prediction system
26
+
27
+ This single function replaces all the initialization code in the main script.
28
+ It loads CSV datasets and ML/DL models, handling all errors gracefully.
29
+
30
+ Args:
31
+ model_dir: Path to directory containing model files (default from const_config.MODEL_DIR)
32
+ drugs_file: Path to drugs CSV file (default from const_config.DRUGS_FILE)
33
+ diseases_file: Path to diseases CSV file (default from const_config.DISEASES_FILE)
34
+
35
+ Returns:
36
+ Dictionary containing:
37
+ - 'models_available': bool - Whether ML/DL models loaded successfully
38
+ - 'ml_components': dict - Loaded models and preprocessors
39
+ - 'drugs_df': DataFrame or None - Drugs database
40
+ - 'diseases_df': DataFrame or None - Diseases database
41
+ """
42
+
43
+ result = {
44
+ 'models_available': False,
45
+ 'ml_components': {},
46
+ 'drugs_df': None,
47
+ 'diseases_df': None
48
+ }
49
+
50
+ try:
51
+ # Suppress RDKit warnings
52
+ from rdkit import RDLogger
53
+ RDLogger.DisableLog('rdApp.*')
54
+
55
+ # Suppress TensorFlow warnings
56
+ try:
57
+ import tensorflow as tf
58
+ tf.get_logger().setLevel('ERROR')
59
+ except:
60
+ pass
61
+
62
+ # Load CSV datasets
63
+ print(" Loading drug and disease datasets...")
64
+ try:
65
+ result['drugs_df'] = pd.read_csv(drugs_file)
66
+ result['diseases_df'] = pd.read_csv(diseases_file)
67
+ print(f" Loaded {len(result['drugs_df'])} drugs and {len(result['diseases_df'])} diseases")
68
+ except Exception as e:
69
+ print(f" Could not load CSV files: {e}")
70
+ print(" Continuing without drug/disease databases")
71
+
72
+ # Load ML/DL models
73
+ model_path = Path(model_dir)
74
+
75
+ if not model_path.exists():
76
+ print(f" ML/DL models directory not found: {model_path}")
77
+ print(" Using synthetic scores only.")
78
+ return result
79
+
80
+ print(f"\n Loading ML/DL models from: {model_path}")
81
+ success, ml_components = load_ml_models(model_path)
82
+
83
+ if success:
84
+ result['models_available'] = True
85
+ result['ml_components'] = ml_components
86
+ print("\n ML/DL Models loaded successfully!")
87
+ print(f" Available diseases in model: {len(ml_components['le_disease'].classes_)}")
88
+ print(f" Available targets in model: {len(ml_components['mlb'].classes_)}")
89
+ else:
90
+ print("\n ML/DL models not found. Using synthetic scores only.")
91
+
92
+ except Exception as e:
93
+ print(f"\n Error during ML system initialization: {e}")
94
+ print(" Using synthetic scores only.")
95
+
96
+ # Try to at least load CSV files if models failed
97
+ if result['drugs_df'] is None:
98
+ try:
99
+ result['drugs_df'] = pd.read_csv(drugs_file)
100
+ result['diseases_df'] = pd.read_csv(diseases_file)
101
+ print(f" Loaded {len(result['drugs_df'])} drugs and {len(result['diseases_df'])} diseases (without ML models)")
102
+ except:
103
+ print(" Could not load CSV files either. Using fully synthetic data.")
104
+
105
+ return result
106
+
107
+
108
+ def load_ml_models(model_dir: Path) -> Tuple[bool, Dict]:
109
+ """
110
+ Load all ML/DL models and preprocessors with detailed error reporting
111
+
112
+ Args:
113
+ model_dir: Path to directory containing model files
114
+
115
+ Returns:
116
+ Tuple of (success: bool, ml_components: dict)
117
+ """
118
+ try:
119
+ from tensorflow import keras
120
+ from rdkit import Chem
121
+ from rdkit.Chem import AllChem
122
+
123
+ ml_components = {}
124
+
125
+ print(f"\n Loading models from: {model_dir.absolute()}")
126
+
127
+ # Define all model files
128
+ model_files = {
129
+ 'lr_model': ('logistic_regression.pkl', 'joblib'),
130
+ 'rf_model': ('random_forest.pkl', 'joblib'),
131
+ 'dnn_model': ('mm_dnn_model.keras', 'keras'),
132
+ 'mlb': ('target_binarizer.pkl', 'joblib'),
133
+ 'le_disease': ('disease_encoder.pkl', 'joblib'),
134
+ 'disease_ohe_df': ('disease_ohe_df.pkl', 'pandas'), # Special handling
135
+ 'scaler': ('scaler.pkl', 'joblib'),
136
+ }
137
+
138
+ # Load each file with individual error handling
139
+ for component_name, (filename, file_type) in model_files.items():
140
+ file_path = model_dir / filename
141
+
142
+ if not file_path.exists():
143
+ print(f" {filename}: File not found, skipping...")
144
+ continue
145
+
146
+ try:
147
+ if file_type == 'joblib':
148
+ # FIXED: Use joblib for sklearn models
149
+ ml_components[component_name] = joblib.load(file_path)
150
+ print(f" {filename}: Loaded successfully")
151
+
152
+ elif file_type == 'pandas':
153
+ # FIXED: Use pd.read_pickle for pandas DataFrames
154
+ ml_components[component_name] = pd.read_pickle(file_path)
155
+ print(f" {filename}: Loaded successfully")
156
+
157
+ elif file_type == 'keras':
158
+ ml_components[component_name] = keras.models.load_model(str(file_path))
159
+ print(f" {filename}: Loaded successfully")
160
+
161
+ except Exception as e:
162
+ print(f" {filename}: Failed to load")
163
+ print(f" Error: {e}")
164
+ # Continue loading other files
165
+ continue
166
+
167
+ # Check all required components are loaded
168
+ required = ['lr_model', 'rf_model', 'dnn_model', 'mlb', 'le_disease', 'scaler']
169
+ missing = [k for k in required if k not in ml_components]
170
+
171
+ if missing:
172
+ print(f"\n Missing required components: {missing}")
173
+ return False, {}
174
+ else:
175
+ print(f"\n All required components loaded successfully!")
176
+ return True, ml_components
177
+
178
+ except ImportError as e:
179
+ print(f" Import error: {e}")
180
+ print(" Make sure tensorflow and rdkit are installed:")
181
+ print(" pip install tensorflow rdkit --break-system-packages")
182
+ return False, {}
183
+ except Exception as e:
184
+ print(f" Unexpected error loading ML models: {e}")
185
+ import traceback
186
+ traceback.print_exc()
187
+ return False, {}
188
+
189
+
190
+ def prepare_drug_features(drug_smiles: str, drug_targets: List[str], mlb) -> Optional[np.ndarray]:
191
+ """
192
+ Prepare drug features from SMILES and targets
193
+
194
+ Args:
195
+ drug_smiles: SMILES string of the drug
196
+ drug_targets: List of protein target names
197
+ mlb: MultiLabelBinarizer for targets
198
+
199
+ Returns:
200
+ Feature vector or None if error
201
+ """
202
+ try:
203
+ from rdkit import Chem
204
+ from rdkit.Chem import AllChem
205
+
206
+ # Generate Morgan fingerprint
207
+ mol = Chem.MolFromSmiles(drug_smiles)
208
+ if mol is None:
209
+ return None
210
+
211
+ fp = AllChem.GetMorganFingerprintAsBitVect(mol, radius=2, nBits=1024)
212
+ fp_array = np.array(fp)
213
+
214
+ # Encode targets
215
+ if drug_targets:
216
+ target_encoded = mlb.transform([drug_targets])
217
+ else:
218
+ target_encoded = mlb.transform([[]])
219
+
220
+ # Concatenate features
221
+ features = np.concatenate([fp_array, target_encoded[0]])
222
+
223
+ return features
224
+
225
+ except Exception as e:
226
+ print(f"Error preparing drug features: {e}")
227
+ return None
228
+
229
+
230
+ def predict_with_ml_models(drug_smiles: str,
231
+ drug_targets: List[str],
232
+ disease_id: str,
233
+ ml_components: Dict) -> Tuple[Optional[Dict], str, str]:
234
+ """
235
+ Make predictions using ML/DL models
236
+
237
+ Args:
238
+ drug_smiles: SMILES string of drug
239
+ drug_targets: List of protein targets
240
+ disease_id: Disease ID (e.g., 'MESH:D009293')
241
+ ml_components: Dictionary containing loaded models and preprocessors
242
+
243
+ Returns:
244
+ Tuple of (results_dict, message, score_type)
245
+ - results_dict: {'LR': score, 'RF': score, 'DNN': score, 'Ensemble': score} or None
246
+ - message: Status message
247
+ - score_type: 'Real' or 'Synthetic'
248
+ """
249
+ try:
250
+ # Validate inputs
251
+ if not drug_smiles or not disease_id:
252
+ return None, "Missing drug SMILES or disease ID", "Synthetic"
253
+
254
+ if not ml_components:
255
+ return None, "ML models not available", "Synthetic"
256
+
257
+ # Convert disease classes to list and check membership
258
+ disease_classes = ml_components['le_disease'].classes_
259
+ if isinstance(disease_classes, pd.Series):
260
+ disease_classes = disease_classes.tolist()
261
+ elif isinstance(disease_classes, np.ndarray):
262
+ disease_classes = disease_classes.tolist()
263
+ else:
264
+ disease_classes = list(disease_classes)
265
+
266
+ # Check membership in Python list
267
+ if disease_id not in disease_classes:
268
+ return None, f"Disease {disease_id} not in training data", "Synthetic"
269
+
270
+ # Prepare drug features
271
+ drug_features = prepare_drug_features(drug_smiles, drug_targets, ml_components['mlb'])
272
+ if drug_features is None:
273
+ return None, "Failed to generate drug features", "Synthetic"
274
+
275
+ # Encode disease (for DNN input)
276
+ disease_encoded = ml_components['le_disease'].transform([disease_id])
277
+
278
+ # FIXED: Get disease OHE and drop 'DiseaseID' column (matching working code)
279
+ if 'disease_ohe_df' in ml_components:
280
+ disease_ohe_df = ml_components['disease_ohe_df']
281
+
282
+ # Use the exact approach from sud_promise_uab_theme.py line 259
283
+ disease_matches = disease_ohe_df[disease_ohe_df['DiseaseID'] == disease_id]
284
+ if len(disease_matches) == 0:
285
+ return None, f"Disease ID '{disease_id}' not found in disease_ohe_df", "Synthetic"
286
+
287
+ # CRITICAL: Drop DiseaseID column before getting values
288
+ disease_ohe = disease_matches.drop('DiseaseID', axis=1).values
289
+ else:
290
+ return None, "disease_ohe_df not loaded", "Synthetic"
291
+
292
+ # FIXED: Prepare full feature vector for ML models (LR, RF)
293
+ # Drug features (1024 + target_dim) + disease OHE (should give 4615 total)
294
+ X_combined = np.concatenate([
295
+ drug_features.reshape(1, -1),
296
+ disease_ohe # This is the full one-hot vector WITHOUT DiseaseID column
297
+ ], axis=1)
298
+
299
+ # Scale features for LR (RF might not need it, check your training)
300
+ if 'scaler' in ml_components:
301
+ X_scaled = ml_components['scaler'].transform(X_combined)
302
+ else:
303
+ X_scaled = X_combined
304
+
305
+ # Make predictions with each model
306
+ results = {}
307
+
308
+ # Logistic Regression (uses scaled features)
309
+ if 'lr_model' in ml_components:
310
+ try:
311
+ lr_pred = ml_components['lr_model'].predict_proba(X_scaled)[0][1]
312
+ results['Logistic Regression'] = float(lr_pred)
313
+ except Exception as e:
314
+ print(f" LR prediction failed: {e}")
315
+
316
+ # Random Forest (check if it needs scaled or unscaled)
317
+ # Based on working code, RF uses unscaled ml_input
318
+ if 'rf_model' in ml_components:
319
+ try:
320
+ rf_pred = ml_components['rf_model'].predict_proba(X_combined)[0][1]
321
+ results['Random Forest'] = float(rf_pred)
322
+ except Exception as e:
323
+ print(f" RF prediction failed: {e}")
324
+
325
+ # FIXED: Deep Neural Network uses different input format
326
+ # DNN takes [drug_features, disease_index] as separate inputs
327
+ if 'dnn_model' in ml_components:
328
+ try:
329
+ disease_idx_arr = np.array([disease_encoded[0]], dtype=np.int32)
330
+ dnn_pred = ml_components['dnn_model'].predict(
331
+ [drug_features.reshape(1, -1), disease_idx_arr],
332
+ verbose=0
333
+ )[0][0]
334
+ results['MM-DNN'] = float(dnn_pred)
335
+ except Exception as e:
336
+ print(f" DNN prediction failed: {e}")
337
+
338
+ # Calculate ensemble (average of all models)
339
+ if results:
340
+ ensemble_score = np.mean(list(results.values()))
341
+ results['Ensemble'] = float(ensemble_score)
342
+
343
+ return results, " Prediction successful", "Real"
344
+ else:
345
+ return None, "No models available for prediction", "Synthetic"
346
+
347
+ except Exception as e:
348
+ import traceback
349
+ error_msg = f"Prediction error: {str(e)}"
350
+ # Uncomment for debugging:
351
+ print(f"\n🔍 DETAILED ERROR:")
352
+ print(traceback.format_exc())
353
+ return None, error_msg, "Synthetic"
354
+
355
+
356
+ def get_ensemble_prediction(results: Dict) -> float:
357
+ """Get ensemble prediction from model results"""
358
+ if not results:
359
+ return 0.5
360
+
361
+ if 'Ensemble' in results:
362
+ return results['Ensemble']
363
+
364
+ scores = [v for k, v in results.items() if k != 'Ensemble']
365
+ if scores:
366
+ return np.mean(scores)
367
+ else:
368
+ return 0.5
369
+
370
+
371
+ def interpret_prediction_score(score: float) -> Tuple[str, str, str]:
372
+ """Interpret prediction score"""
373
+ if score >= 0.7:
374
+ return "HIGH", "🟢", "Strong therapeutic potential"
375
+ elif score >= 0.5:
376
+ return "MODERATE", "🟡", "Mixed evidence, further investigation needed"
377
+ else:
378
+ return "LOW", "🔴", "Limited evidence for this indication"
379
+
380
+
381
+ def batch_predict(drug_disease_pairs: List[Tuple[str, List[str], str]],
382
+ ml_components: Dict) -> List[Dict]:
383
+ """Make predictions for multiple drug-disease pairs"""
384
+ results = []
385
+
386
+ for drug_smiles, drug_targets, disease_id in drug_disease_pairs:
387
+ pred_results, message, score_type = predict_with_ml_models(
388
+ drug_smiles, drug_targets, disease_id, ml_components
389
+ )
390
+
391
+ results.append({
392
+ 'drug_smiles': drug_smiles,
393
+ 'disease_id': disease_id,
394
+ 'predictions': pred_results,
395
+ 'message': message,
396
+ 'score_type': score_type
397
+ })
398
+
399
+ return results
400
+
401
+
402
+ if __name__ == "__main__":
403
+ print("="*70)
404
+ print("ML PREDICTION UTILITIES - TESTING")
405
+ print("="*70)
406
+
407
+ # NEW: Single function call uses defaults from const_config
408
+ # No need to specify paths - they're already in const_config!
409
+ system = initialize_ml_system()
410
+
411
+ print("\n" + "="*70)
412
+ print("SYSTEM STATUS")
413
+ print("="*70)
414
+ print(f"Models Available: {system['models_available']}")
415
+ print(f"Drugs Database: {' Loaded' if system['drugs_df'] is not None else ' Not loaded'}")
416
+ print(f"Diseases Database: {' Loaded' if system['diseases_df'] is not None else ' Not loaded'}")
417
+
418
+ if system['models_available']:
419
+ print("\n ALL TESTS PASSED")
420
+
421
+ # Test feature dimensions
422
+ print("\n🔍 Testing feature dimensions...")
423
+ test_smiles = "CC(C)NCC(COc1ccccc1)O" # Example SMILES
424
+ test_targets = []
425
+ test_disease = list(system['ml_components']['le_disease'].classes_)[0]
426
+
427
+ results, msg, score_type = predict_with_ml_models(
428
+ test_smiles, test_targets, test_disease, system['ml_components']
429
+ )
430
+
431
+ if results:
432
+ print(f" Prediction successful!")
433
+ print(f" Score Type: {score_type}")
434
+ print(f" Results: {results}")
435
+ else:
436
+ print(f" Prediction failed: {msg}")
437
+ else:
438
+ print("\n MODEL LOADING FAILED - System will use synthetic scores")
439
+
440
+ print("="*70)
module_dashboard.py ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Executive Dashboard Functions
3
+ Handles KPI calculations, metrics, and dashboard visualizations
4
+
5
+ VERSION: 1.0.0 - Modularized dashboard functionality
6
+ """
7
+
8
+ import plotly.graph_objects as go
9
+ from datetime import datetime, timedelta
10
+ from typing import List, Dict
11
+
12
+ # Import constants
13
+ from const_ui import (
14
+ UAB_GREEN, UAB_DARK_GREEN, UAB_LIGHT_GREEN, UAB_PALE_GREEN,
15
+ CHART_HEIGHT_SMALL, CHART_HEIGHT_MEDIUM
16
+ )
17
+
18
+ from const_data import (
19
+ AVERAGE_TIME_TO_IND, CURRENT_IND_READY_COUNT,
20
+ TIME_BINS_LABELS, TIME_BINS_COUNTS, QUARTERLY_DELIVERIES
21
+ )
22
+
23
+
24
+ def calculate_executive_metrics(candidates: List, categories: List, models_available: bool) -> Dict:
25
+ """
26
+ Calculate KPIs for executive dashboard
27
+
28
+ Args:
29
+ candidates: List of DrugCandidate objects
30
+ categories: List of SUDCategory objects
31
+ models_available: Whether ML/DL models are loaded
32
+
33
+ Returns:
34
+ Dictionary containing all executive metrics
35
+ """
36
+ total_candidates = len(candidates)
37
+ active_projects = sum(len(c.attached_projects) for c in candidates)
38
+ total_cohorts = sum(c.cohort_count for c in candidates)
39
+ num_sud_types = len(categories)
40
+
41
+ avg_time_ind = AVERAGE_TIME_TO_IND
42
+ quarterly_deliveries = QUARTERLY_DELIVERIES
43
+
44
+ # Count real vs synthetic scores
45
+ real_scores = sum(1 for c in candidates if c.score_type == "Real")
46
+ synthetic_scores = total_candidates - real_scores
47
+
48
+ return {
49
+ 'total_candidates': total_candidates,
50
+ 'active_projects': active_projects,
51
+ 'total_cohorts': total_cohorts,
52
+ 'num_sud_types': num_sud_types,
53
+ 'avg_time_ind_ready': avg_time_ind,
54
+ 'quarterly_deliveries': quarterly_deliveries,
55
+ 'real_scores': real_scores,
56
+ 'synthetic_scores': synthetic_scores
57
+ }
58
+
59
+
60
+ def calculate_stage_distribution_over_time(candidates: List) -> List[Dict]:
61
+ """
62
+ Calculate stage distribution over last 12 months
63
+
64
+ Args:
65
+ candidates: List of DrugCandidate objects
66
+
67
+ Returns:
68
+ List of dictionaries containing stage counts per month
69
+ """
70
+ months = []
71
+ current_date = datetime.now()
72
+
73
+ for i in range(12):
74
+ month_date = current_date - timedelta(days=i*30)
75
+ month_name = month_date.strftime('%b')
76
+
77
+ stage_counts = {f'S{i}': 0 for i in range(7)}
78
+
79
+ for candidate in candidates:
80
+ candidate_stage = 'S0'
81
+ for stage, date in candidate.stage_history:
82
+ if date <= month_date:
83
+ candidate_stage = stage
84
+ else:
85
+ break
86
+ stage_counts[candidate_stage] += 1
87
+
88
+ months.append({
89
+ 'month': month_name,
90
+ 'date': month_date,
91
+ **stage_counts
92
+ })
93
+
94
+ return list(reversed(months))
95
+
96
+
97
+ def calculate_portfolio_breakdown(candidates: List, categories: List) -> List[Dict]:
98
+ """
99
+ Calculate active portfolio breakdown by SUD category
100
+
101
+ Args:
102
+ candidates: List of DrugCandidate objects
103
+ categories: List of SUDCategory objects
104
+
105
+ Returns:
106
+ List of dictionaries containing category breakdown
107
+ """
108
+ breakdown = []
109
+ for category in categories:
110
+ count = len([c for c in candidates if c.target_sud_subtype == category.name])
111
+ if count > 0:
112
+ breakdown.append({
113
+ 'category': category.name,
114
+ 'count': count,
115
+ 'color': category.hex_color
116
+ })
117
+
118
+ return breakdown
119
+
120
+
121
+ def create_time_to_ind_distribution() -> go.Figure:
122
+ """
123
+ Create bar chart showing distribution of time to IND-ready
124
+
125
+ Returns:
126
+ Plotly figure object
127
+ """
128
+ bin_labels = TIME_BINS_LABELS
129
+ bin_counts = TIME_BINS_COUNTS
130
+
131
+ colors = [
132
+ UAB_LIGHT_GREEN,
133
+ '#4A9B7A',
134
+ UAB_GREEN,
135
+ '#1E7B52',
136
+ UAB_DARK_GREEN,
137
+ '#16533E',
138
+ '#0F3E2E'
139
+ ]
140
+
141
+ y_max = max(bin_counts)
142
+
143
+ fig = go.Figure()
144
+ fig.add_trace(go.Bar(
145
+ x=bin_labels,
146
+ y=bin_counts,
147
+ marker_color=colors,
148
+ text=bin_counts,
149
+ textposition='outside',
150
+ textfont=dict(size=11, color=UAB_DARK_GREEN),
151
+ cliponaxis=False,
152
+ showlegend=False
153
+ ))
154
+
155
+ fig.update_layout(
156
+ title="Distribution 12 months",
157
+ xaxis_title="Months",
158
+ height=CHART_HEIGHT_SMALL,
159
+ margin=dict(l=25, r=10, t=55, b=45),
160
+ plot_bgcolor='#F0F9F6',
161
+ paper_bgcolor='white',
162
+ font=dict(family="Times New Roman, serif", color=UAB_DARK_GREEN, size=12),
163
+ showlegend=False,
164
+ yaxis=dict(
165
+ showticklabels=False,
166
+ showgrid=False,
167
+ zeroline=False,
168
+ range=[0, y_max * 1.18],
169
+ )
170
+ )
171
+
172
+ return fig
173
+
174
+
175
+ def create_quarterly_deliveries_chart(quarterly_data: List[Dict]) -> go.Figure:
176
+ """
177
+ Create line chart showing quarterly IND-ready deliveries
178
+
179
+ Args:
180
+ quarterly_data: List of quarterly delivery metrics
181
+
182
+ Returns:
183
+ Plotly figure object
184
+ """
185
+ labels = [q['quarter'] for q in quarterly_data]
186
+ cumulative = [q['cumulative'] for q in quarterly_data]
187
+
188
+ display_percentages = ['0%', '4%', '6.5%', '20%', '21%', '14.5%'][:len(labels)]
189
+
190
+ y_max = max(cumulative) if cumulative else 1.0
191
+
192
+ fig = go.Figure()
193
+
194
+ fig.add_trace(go.Scatter(
195
+ x=labels,
196
+ y=cumulative,
197
+ mode='lines+markers+text',
198
+ line=dict(color=UAB_GREEN, width=3),
199
+ marker=dict(size=11, color=UAB_GREEN),
200
+ text=display_percentages,
201
+ textposition='top center',
202
+ textfont=dict(size=12, family="Times New Roman, serif", color=UAB_DARK_GREEN),
203
+ cliponaxis=False,
204
+ showlegend=False
205
+ ))
206
+
207
+ fig.update_layout(
208
+ title="% IND-Ready Start",
209
+ xaxis_title="",
210
+ yaxis_title="Cumulative",
211
+ height=CHART_HEIGHT_SMALL,
212
+ margin=dict(l=55, r=15, t=55, b=45),
213
+ plot_bgcolor='#F0F9F6',
214
+ paper_bgcolor='white',
215
+ font=dict(family="Times New Roman, serif", color=UAB_DARK_GREEN, size=12),
216
+ showlegend=False,
217
+ yaxis=dict(
218
+ range=[0, y_max * 1.35],
219
+ showgrid=True,
220
+ gridcolor="rgba(30,107,82,0.12)",
221
+ zeroline=False
222
+ )
223
+ )
224
+
225
+ return fig
226
+
227
+
228
+ def create_pipeline_progression_chart(stage_data: List[Dict]) -> go.Figure:
229
+ """
230
+ Create stacked area chart for pipeline progression over time
231
+
232
+ Args:
233
+ stage_data: List of stage distribution data by month
234
+
235
+ Returns:
236
+ Plotly figure object
237
+ """
238
+ months = [d['month'] for d in stage_data]
239
+
240
+ fig = go.Figure()
241
+
242
+ stages = ['S0', 'S1', 'S2', 'S3', 'S4', 'S5', 'S6']
243
+ colors_map = {
244
+ 'S0': '#CBD5E0',
245
+ 'S1': '#A0AEC0',
246
+ 'S2': UAB_LIGHT_GREEN,
247
+ 'S3': UAB_GREEN,
248
+ 'S4': UAB_GREEN,
249
+ 'S5': UAB_DARK_GREEN,
250
+ 'S6': UAB_DARK_GREEN,
251
+ }
252
+
253
+ for stage in stages:
254
+ values = [d[stage] for d in stage_data]
255
+ fig.add_trace(go.Scatter(
256
+ x=months,
257
+ y=values,
258
+ mode='lines',
259
+ name=stage,
260
+ stackgroup='one',
261
+ fillcolor=colors_map[stage],
262
+ line=dict(width=0.5, color=colors_map[stage]),
263
+ ))
264
+
265
+ fig.update_layout(
266
+ title="",
267
+ xaxis_title="",
268
+ yaxis_title="Candidates",
269
+ height=CHART_HEIGHT_MEDIUM,
270
+ margin=dict(l=40, r=20, t=50, b=40),
271
+ plot_bgcolor='white',
272
+ paper_bgcolor='white',
273
+ font=dict(family="Times New Roman, serif", color=UAB_DARK_GREEN, size=10),
274
+ legend=dict(
275
+ orientation="h",
276
+ yanchor="bottom",
277
+ y=1.02,
278
+ xanchor="right",
279
+ x=1
280
+ ),
281
+ hovermode='x unified'
282
+ )
283
+
284
+ return fig
285
+
286
+
287
+ def create_portfolio_breakdown_chart(breakdown_data: List[Dict]) -> go.Figure:
288
+ """
289
+ Create donut chart for active portfolio breakdown by SUD category
290
+
291
+ Args:
292
+ breakdown_data: List of category breakdowns
293
+
294
+ Returns:
295
+ Plotly figure object
296
+ """
297
+ labels = [d['category'] for d in breakdown_data]
298
+ values = [d['count'] for d in breakdown_data]
299
+ colors = [d['color'] for d in breakdown_data]
300
+
301
+ fig = go.Figure(data=[go.Pie(
302
+ labels=labels,
303
+ values=values,
304
+ marker=dict(colors=colors),
305
+ textinfo='label+percent',
306
+ textposition='auto',
307
+ textfont=dict(size=10, family="Times New Roman, serif"),
308
+ hole=0.4
309
+ )])
310
+
311
+ fig.update_layout(
312
+ title="",
313
+ height=CHART_HEIGHT_MEDIUM,
314
+ margin=dict(l=20, r=20, t=50, b=20),
315
+ paper_bgcolor='white',
316
+ font=dict(family="Times New Roman, serif", color=UAB_DARK_GREEN, size=10),
317
+ showlegend=True,
318
+ legend=dict(
319
+ orientation="v",
320
+ yanchor="middle",
321
+ y=0.5,
322
+ xanchor="left",
323
+ x=1.05,
324
+ font=dict(size=9)
325
+ )
326
+ )
327
+
328
+ return fig
329
+
330
+
331
+ def render_executive_dashboard(candidates: List, categories: List, models_available: bool) -> tuple:
332
+ """
333
+ Render complete executive dashboard with all components
334
+
335
+ Args:
336
+ candidates: List of DrugCandidate objects
337
+ categories: List of SUDCategory objects
338
+ models_available: Whether ML/DL models are loaded
339
+
340
+ Returns:
341
+ Tuple of (html, time_fig, quarterly_fig, pipeline_fig, portfolio_fig, avg_time, ind_ready)
342
+ """
343
+ # Calculate all metrics
344
+ metrics = calculate_executive_metrics(candidates, categories, models_available)
345
+ stage_data = calculate_stage_distribution_over_time(candidates)
346
+ breakdown_data = calculate_portfolio_breakdown(candidates, categories)
347
+
348
+ # Create all charts
349
+ time_dist_fig = create_time_to_ind_distribution()
350
+ quarterly_fig = create_quarterly_deliveries_chart(metrics['quarterly_deliveries'])
351
+ pipeline_fig = create_pipeline_progression_chart(stage_data)
352
+ portfolio_fig = create_portfolio_breakdown_chart(breakdown_data)
353
+
354
+ current_ind_ready = CURRENT_IND_READY_COUNT
355
+
356
+ # Add ML/DL status indicator
357
+ ml_color = UAB_GREEN if models_available else "#FFA500"
358
+
359
+ # Generate HTML
360
+ html = f"""
361
+ <div style="padding: 15px; font-family: 'Times New Roman', Times, serif;">
362
+ <h2 style="color: {UAB_DARK_GREEN}; margin: 0 0 15px 0; font-size: 18px;">Executive Dashboard: SUD Repositioning KPI Overview</h2>
363
+
364
+ <!-- Top Row: 4 Metrics -->
365
+ <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 20px;">
366
+ <div style="background: linear-gradient(135deg, {UAB_GREEN} 0%, {UAB_DARK_GREEN} 100%); padding: 20px; border-radius: 10px; color: white; text-align: center; box-shadow: 0 2px 4px rgba(30,107,82,0.3);">
367
+ <h2 style="margin: 0; font-size: 32px; color: white;">{metrics['total_candidates']}</h2>
368
+ <p style="margin: 5px 0 0 0; font-size: 12px; opacity: 0.9; color: white;">Drug Candidates</p>
369
+ </div>
370
+ <div style="background: linear-gradient(135deg, {UAB_GREEN} 0%, {UAB_DARK_GREEN} 100%); padding: 20px; border-radius: 10px; color: white; text-align: center; box-shadow: 0 2px 4px rgba(30,107,82,0.3);">
371
+ <h2 style="margin: 0; font-size: 32px; color: white;">{metrics['active_projects']}</h2>
372
+ <p style="margin: 5px 0 0 0; font-size: 12px; opacity: 0.9; color: white;">Evidence Projects</p>
373
+ </div>
374
+ <div style="background: linear-gradient(135deg, {UAB_GREEN} 0%, {UAB_DARK_GREEN} 100%); padding: 20px; border-radius: 10px; color: white; text-align: center; box-shadow: 0 2px 4px rgba(30,107,82,0.3);">
375
+ <h2 style="margin: 0; font-size: 32px; color: white;">{metrics['total_cohorts']}</h2>
376
+ <p style="margin: 5px 0 0 0; font-size: 12px; opacity: 0.9; color: white;">Patient Cohorts</p>
377
+ </div>
378
+ <div style="background: linear-gradient(135deg, {UAB_GREEN} 0%, {UAB_DARK_GREEN} 100%); padding: 20px; border-radius: 10px; color: white; text-align: center; box-shadow: 0 2px 4px rgba(30,107,82,0.3);">
379
+ <h2 style="margin: 0; font-size: 32px; color: white;">{metrics['num_sud_types']}</h2>
380
+ <p style="margin: 5px 0 0 0; font-size: 12px; opacity: 0.9; color: white;">Types of SUD Indications</p>
381
+ </div>
382
+ </div>
383
+ </div>
384
+ """
385
+
386
+ return html, time_dist_fig, quarterly_fig, pipeline_fig, portfolio_fig, metrics['avg_time_ind_ready'], current_ind_ready
387
+
388
+
389
+ if __name__ == "__main__":
390
+ print("="*70)
391
+ print("DASHBOARD FUNCTIONS - TESTING")
392
+ print("="*70)
393
+ print("This module provides executive dashboard functionality.")
394
+ print("Import and use: render_executive_dashboard(candidates, categories, models_available)")
395
+ print("="*70)
page_candidate.py ADDED
@@ -0,0 +1,429 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Candidate Detail Page Module
3
+ Extracted from sud_promise_uab_theme.py
4
+ """
5
+
6
+ import plotly.graph_objects as go
7
+ from datetime import datetime, timedelta
8
+
9
+ # Import UI constants
10
+ from const_ui import (
11
+ UAB_GREEN, UAB_DARK_GREEN, UAB_LIGHT_GREEN, UAB_ACCENT_TEAL, UAB_PALE_GREEN,
12
+ SCORE_THRESHOLD_HIGH, SCORE_THRESHOLD_MODERATE,
13
+ SMILES_DISPLAY_LENGTH, MAX_TARGET_DISPLAY,
14
+ get_status_badge, get_score_type_badge, get_evidence_stars, get_impact_badge
15
+ )
16
+
17
+ from const_config import INSTITUTION
18
+
19
+
20
+ def create_score_gauge(score: float, score_type: str, model_scores: dict = None) -> go.Figure:
21
+ """Create a gauge chart for the evidence score"""
22
+
23
+ # Determine color based on score
24
+ if score >= SCORE_THRESHOLD_HIGH:
25
+ color = UAB_DARK_GREEN
26
+ elif score >= SCORE_THRESHOLD_MODERATE:
27
+ color = UAB_GREEN
28
+ else:
29
+ color = UAB_LIGHT_GREEN
30
+
31
+ fig = go.Figure(go.Indicator(
32
+ mode="gauge+number+delta",
33
+ value=score,
34
+ domain={'x': [0, 1], 'y': [0, 1]},
35
+ title={'text': f"Evidence Score ({score_type})",
36
+ 'font': {'size': 16, 'family': "Times New Roman, serif", 'color': UAB_DARK_GREEN}},
37
+ number={'font': {'size': 40, 'family': "Times New Roman, serif"}},
38
+ gauge={
39
+ 'axis': {'range': [0, 1], 'tickwidth': 1, 'tickcolor': UAB_DARK_GREEN},
40
+ 'bar': {'color': color},
41
+ 'bgcolor': "white",
42
+ 'borderwidth': 2,
43
+ 'bordercolor': UAB_DARK_GREEN,
44
+ 'steps': [
45
+ {'range': [0, 0.5], 'color': '#FFE5E5'},
46
+ {'range': [0.5, 0.7], 'color': '#FFF4E5'},
47
+ {'range': [0.7, 1], 'color': UAB_PALE_GREEN}
48
+ ],
49
+ 'threshold': {
50
+ 'line': {'color': "red", 'width': 4},
51
+ 'thickness': 0.75,
52
+ 'value': 0.7
53
+ }
54
+ }
55
+ ))
56
+
57
+ fig.update_layout(
58
+ height=300,
59
+ margin=dict(l=20, r=20, t=60, b=20),
60
+ paper_bgcolor='white',
61
+ font={'family': 'Times New Roman, serif', 'color': UAB_DARK_GREEN}
62
+ )
63
+
64
+ return fig
65
+
66
+ def create_model_comparison_chart(model_scores: dict, score_type: str) -> go.Figure:
67
+ """Create a bar chart comparing different model scores"""
68
+
69
+ if not model_scores or score_type != "Real":
70
+ # Return empty figure for synthetic scores
71
+ fig = go.Figure()
72
+ fig.update_layout(
73
+ title="Model Scores (Not Available for Synthetic Predictions)",
74
+ height=300,
75
+ paper_bgcolor='white',
76
+ font={'family': 'Times New Roman, serif', 'color': UAB_DARK_GREEN}
77
+ )
78
+ return fig
79
+
80
+ models = list(model_scores.keys())
81
+ scores = list(model_scores.values())
82
+
83
+ colors = [UAB_GREEN if s >= SCORE_THRESHOLD_HIGH else UAB_LIGHT_GREEN if s >= SCORE_THRESHOLD_MODERATE else '#FFA500' for s in scores]
84
+
85
+ fig = go.Figure(data=[
86
+ go.Bar(
87
+ x=models,
88
+ y=scores,
89
+ marker_color=colors,
90
+ text=[f'{s:.3f}' for s in scores],
91
+ textposition='outside',
92
+ textfont=dict(size=12, family="Times New Roman, serif", color=UAB_DARK_GREEN)
93
+ )
94
+ ])
95
+
96
+ fig.update_layout(
97
+ title="Individual Model Predictions",
98
+ xaxis_title="",
99
+ yaxis_title="Prediction Score",
100
+ height=300,
101
+ margin=dict(l=40, r=20, t=50, b=80),
102
+ plot_bgcolor=UAB_PALE_GREEN,
103
+ paper_bgcolor='white',
104
+ font={'family': 'Times New Roman, serif', 'color': UAB_DARK_GREEN},
105
+ yaxis=dict(range=[0, 1]),
106
+ showlegend=False
107
+ )
108
+
109
+ fig.add_hline(y=0.5, line_dash="dash", line_color="orange", annotation_text="Threshold 0.5")
110
+ fig.add_hline(y=SCORE_THRESHOLD_HIGH, line_dash="dash", line_color=UAB_DARK_GREEN, annotation_text="Threshold 0.7")
111
+
112
+ return fig
113
+
114
+ def create_evidence_timeline(candidate):
115
+ """Create timeline showing baseline + all project impacts"""
116
+ timeline_data = []
117
+
118
+ # Start with baseline (either ML/DL ensemble or random baseline)
119
+ start_date = candidate.attached_projects[0].added_date - timedelta(days=30) if candidate.attached_projects else datetime.now() - timedelta(days=365)
120
+
121
+ if candidate.score_type == "Real":
122
+ timeline_data.append({
123
+ 'date': start_date,
124
+ 'score': candidate.baseline_score,
125
+ 'label': f'ML/DL Ensemble Baseline: {candidate.baseline_score:.3f}',
126
+ 'color': UAB_DARK_GREEN,
127
+ 'impact': 0
128
+ })
129
+ else:
130
+ timeline_data.append({
131
+ 'date': start_date,
132
+ 'score': candidate.baseline_score,
133
+ 'label': 'Baseline (No Evidence)',
134
+ 'color': '#A0AEC0',
135
+ 'impact': 0
136
+ })
137
+
138
+ # Add each project's impact
139
+ cumulative_score = candidate.baseline_score
140
+ for project in candidate.attached_projects:
141
+ cumulative_score += project.impact_score
142
+ cumulative_score = max(0.20, min(0.95, cumulative_score))
143
+
144
+ marker_color = UAB_GREEN if project.impact_score > 0 else '#DC2626'
145
+
146
+ timeline_data.append({
147
+ 'date': project.added_date,
148
+ 'score': cumulative_score,
149
+ 'label': f'+ {project.name}' if project.impact_score > 0 else f'- {project.name}',
150
+ 'color': marker_color,
151
+ 'impact': project.impact_score,
152
+ 'impact_text': f'+{project.impact_score:.2f}' if project.impact_score > 0 else f'{project.impact_score:.2f}'
153
+ })
154
+
155
+ fig = go.Figure()
156
+
157
+ # Draw line segments
158
+ for i in range(len(timeline_data) - 1):
159
+ segment_color = timeline_data[i+1]['color']
160
+
161
+ fig.add_trace(go.Scatter(
162
+ x=[timeline_data[i]['date'], timeline_data[i+1]['date']],
163
+ y=[timeline_data[i]['score'], timeline_data[i+1]['score']],
164
+ mode='lines',
165
+ line=dict(color=segment_color, width=3),
166
+ showlegend=False,
167
+ hoverinfo='skip'
168
+ ))
169
+
170
+ # Draw markers
171
+ fig.add_trace(go.Scatter(
172
+ x=[d['date'] for d in timeline_data],
173
+ y=[d['score'] for d in timeline_data],
174
+ mode='markers',
175
+ marker=dict(
176
+ size=12,
177
+ color=[d['color'] for d in timeline_data],
178
+ line=dict(width=2, color='white')
179
+ ),
180
+ text=[d['label'] for d in timeline_data],
181
+ hovertemplate='<b>%{text}</b><br>Score: %{y:.3f}<br>%{x|%b %d, %Y}<extra></extra>',
182
+ showlegend=False
183
+ ))
184
+
185
+ # Add annotations for ALL project impacts (including Real ML/DL)
186
+ for i in range(1, len(timeline_data)):
187
+ if 'impact_text' in timeline_data[i]:
188
+ impact_value = timeline_data[i]['impact']
189
+ arrow_color = UAB_GREEN if impact_value > 0 else '#DC2626'
190
+ bg_color = UAB_GREEN if impact_value > 0 else '#DC2626'
191
+
192
+ ay_value = 40 if impact_value > 0 else -40
193
+
194
+ fig.add_annotation(
195
+ x=timeline_data[i]['date'],
196
+ y=timeline_data[i]['score'],
197
+ text=timeline_data[i]['impact_text'],
198
+ showarrow=True,
199
+ arrowhead=2,
200
+ arrowcolor=arrow_color,
201
+ ax=0,
202
+ ay=ay_value,
203
+ bgcolor=bg_color,
204
+ bordercolor=bg_color,
205
+ font=dict(color='white', size=10, family="Times New Roman, serif")
206
+ )
207
+
208
+ # Add special annotation for ML/DL baseline
209
+ if candidate.score_type == "Real":
210
+ fig.add_annotation(
211
+ x=timeline_data[0]['date'],
212
+ y=timeline_data[0]['score'],
213
+ text=f"🤖 ML/DL: {candidate.baseline_score:.3f}",
214
+ showarrow=True,
215
+ arrowhead=2,
216
+ arrowcolor=UAB_DARK_GREEN,
217
+ ax=-50,
218
+ ay=-40,
219
+ bgcolor=UAB_DARK_GREEN,
220
+ bordercolor=UAB_DARK_GREEN,
221
+ font=dict(color='white', size=11, family="Times New Roman, serif", weight='bold')
222
+ )
223
+
224
+ # Title
225
+ if candidate.score_type == "Real":
226
+ title_text = "Evidence Score Evolution Over Time (ML/DL Baseline + Project Evidence)"
227
+ else:
228
+ title_text = "Evidence Score Evolution Over Time (Synthetic Baseline + Project Evidence)"
229
+
230
+ fig.update_layout(
231
+ title=title_text,
232
+ xaxis_title="Date",
233
+ yaxis_title="Prediction Score",
234
+ hovermode='closest',
235
+ height=400,
236
+ plot_bgcolor='#F0F9F6',
237
+ paper_bgcolor='white',
238
+ font=dict(family="Times New Roman, serif", color=UAB_DARK_GREEN),
239
+ yaxis=dict(range=[0, 1])
240
+ )
241
+
242
+ return fig
243
+
244
+
245
+ def format_date_ago(date):
246
+ delta = datetime.now() - date
247
+ if delta.days == 0:
248
+ return "Today"
249
+ elif delta.days == 1:
250
+ return "Yesterday"
251
+ elif delta.days < 7:
252
+ return f"{delta.days} days ago"
253
+ elif delta.days < 30:
254
+ return f"{delta.days // 7} weeks ago"
255
+ else:
256
+ return f"{delta.days // 30} months ago"
257
+
258
+
259
+ def render_candidate_dashboard(candidate_selection, category_selection):
260
+ from sud_promise_uab_theme import CANDIDATES
261
+
262
+ if not candidate_selection:
263
+ return "<p>Please select a candidate</p>", None, None, None, ""
264
+
265
+ candidate_name = candidate_selection.split(" (Score:")[0].strip()
266
+ category_name = category_selection.split(" (")[0].strip() if category_selection else None
267
+
268
+ if category_name:
269
+ candidate = next((c for c in CANDIDATES if c.drug_name == candidate_name and c.target_sud_subtype == category_name), None)
270
+ else:
271
+ candidate = next((c for c in CANDIDATES if c.drug_name == candidate_name), None)
272
+
273
+ if not candidate:
274
+ return "<p>Candidate not found</p>", None, None, None, ""
275
+
276
+ stars = get_evidence_stars(candidate.evidence_score)
277
+ status_badge = get_status_badge(candidate.stage)
278
+ score_type_badge = get_score_type_badge(candidate.score_type)
279
+
280
+ timeline_fig = create_evidence_timeline(candidate)
281
+ gauge_fig = create_score_gauge(candidate.evidence_score, candidate.score_type, candidate.model_scores)
282
+ model_comparison_fig = create_model_comparison_chart(candidate.model_scores, candidate.score_type)
283
+
284
+ # Evidence Evolution section
285
+ html_evolution = ""
286
+ if candidate.score_type == "Real":
287
+ html_evolution = f"""
288
+ <h2 style="color: {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">Evidence Evolution</h2>
289
+ <div style="background: {UAB_PALE_GREEN}; padding: 20px; border-radius: 10px; margin-bottom: 20px; border-left: 4px solid {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">
290
+ <p><b>ML/DL Ensemble Baseline:</b> {candidate.baseline_score:.3f} 🤖</p>
291
+ <p><b>Current Score (with Projects):</b> <span style="color: {UAB_GREEN}; font-weight: bold;">{candidate.evidence_score:.3f}</span></p>
292
+ <p style="color: {UAB_GREEN}; font-weight: bold;">Evidence Contribution: +{candidate.evidence_score - candidate.baseline_score:.3f} ({((candidate.evidence_score - candidate.baseline_score) / candidate.baseline_score * 100):.1f}%)</p>
293
+ <p style="color: #4A5568; font-size: 13px; margin-top: 10px;">
294
+ <i>Starting from ML/DL ensemble prediction, additional evidence projects further refine confidence.</i>
295
+ </p>
296
+ </div>
297
+ """
298
+ else:
299
+ html_evolution = f"""
300
+ <h2 style="color: {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">Evidence Evolution</h2>
301
+ <div style="background: {UAB_PALE_GREEN}; padding: 20px; border-radius: 10px; margin-bottom: 20px; border-left: 4px solid {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">
302
+ <p><b>Baseline Score:</b> {candidate.baseline_score:.2f} (no evidence)</p>
303
+ <p><b>Current Score:</b> <span style="color: {UAB_GREEN}; font-weight: bold;">{candidate.evidence_score:.2f}</span></p>
304
+ <p style="color: {UAB_GREEN}; font-weight: bold;">Total Improvement: +{candidate.evidence_score - candidate.baseline_score:.2f} ({((candidate.evidence_score - candidate.baseline_score) / candidate.baseline_score * 100):.1f}%)</p>
305
+ </div>
306
+ """
307
+
308
+ html_before_plot = f"""
309
+ <div style="padding: 20px; font-family: 'Times New Roman', Times, serif;">
310
+ <div style="background: linear-gradient(135deg, {UAB_GREEN} 0%, {UAB_DARK_GREEN} 100%); padding: 30px; border-radius: 15px; color: white; margin-bottom: 30px; box-shadow: 0 4px 6px rgba(30,107,82,0.3);">
311
+ <h1 style="margin: 0; font-family: 'Times New Roman', Times, serif; color: white;">{candidate.drug_name}</h1>
312
+ <p style="margin: 10px 0 0 0; font-size: 18px; opacity: 0.9; font-family: 'Times New Roman', Times, serif; color: white;">Repositioning Candidate for {candidate.target_sud_subtype}</p>
313
+ <p style="margin: 5px 0 0 0; font-size: 14px; opacity: 0.8; font-family: 'Times New Roman', Times, serif; color: white;">{INSTITUTION} - SUD-PROMISE</p>
314
+ </div>
315
+
316
+ <div style="display: flex; gap: 10px; margin-bottom: 30px; align-items: center;">
317
+ <div>{status_badge}</div>
318
+ <div style="background: {UAB_GREEN}; padding: 5px 12px; border-radius: 15px; font-weight: bold; color: white; font-family: 'Times New Roman', Times, serif;">
319
+ {stars} {candidate.evidence_score:.2f}
320
+ </div>
321
+ {score_type_badge}
322
+ </div>
323
+
324
+ <h2 style="color: {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">Drug Summary</h2>
325
+ <div style="background: #F0F9F6; padding: 20px; border-radius: 10px; margin-bottom: 30px; border-left: 4px solid {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">
326
+ <p style="margin: 10px 0;"><b>Current Indication:</b> {candidate.current_indication}</p>
327
+ <p style="margin: 10px 0;"><b>Target SUD:</b> {candidate.target_sud_subtype}</p>
328
+ <p style="margin: 10px 0;"><b>Disease ID:</b> {candidate.disease_id if candidate.disease_id else 'Not Mapped'}</p>
329
+ <p style="margin: 10px 0;"><b>Mechanism of Action:</b> {candidate.mechanism}</p>
330
+ <p style="margin: 10px 0;"><b>SMILES:</b> <code style="background: white; padding: 2px 6px; border-radius: 4px;">{candidate.smiles[:SMILES_DISPLAY_LENGTH]}{'...' if len(candidate.smiles) > SMILES_DISPLAY_LENGTH else ''}</code></p>
331
+ <p style="margin: 10px 0;"><b>Protein Targets:</b> {', '.join(candidate.protein_targets[:MAX_TARGET_DISPLAY]) if candidate.protein_targets else 'Not specified'}{' (...)' if len(candidate.protein_targets) > MAX_TARGET_DISPLAY else ''}</p>
332
+ </div>
333
+
334
+ <h2 style="color: {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">Project Metrics</h2>
335
+ <div style="background: {UAB_PALE_GREEN}; padding: 20px; border-radius: 10px; margin-bottom: 20px; border-left: 4px solid {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">
336
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin: 15px 0;">
337
+ <div style="text-align: center;">
338
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.team_members}</div>
339
+ <div style="color: #4A5568;">Team Members</div>
340
+ </div>
341
+ <div style="text-align: center;">
342
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.data_produced}</div>
343
+ <div style="color: #4A5568;">Datasets Produced</div>
344
+ </div>
345
+ <div style="text-align: center;">
346
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.publications}</div>
347
+ <div style="color: #4A5568;">Publications</div>
348
+ </div>
349
+ </div>
350
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin: 15px 0;">
351
+ <div style="text-align: center;">
352
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.tools_used}</div>
353
+ <div style="color: #4A5568;">Tools/Instruments</div>
354
+ </div>
355
+ <div style="text-align: center;">
356
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.data_governance}</div>
357
+ <div style="color: #4A5568;">Data Governance Policies</div>
358
+ </div>
359
+ <div style="text-align: center;">
360
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.training_participated}</div>
361
+ <div style="color: #4A5568;">Training Sessions</div>
362
+ </div>
363
+ </div>
364
+ </div>
365
+
366
+ {html_evolution}
367
+ </div>
368
+ """
369
+
370
+ html_after_plot = f"""
371
+ <div style="padding: 0 20px 20px 20px; font-family: 'Times New Roman', Times, serif;">
372
+ <h2 style="color: {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">Attached Evidence Projects ({len(candidate.attached_projects)})</h2>
373
+ <p style="color: #718096; margin-bottom: 15px; font-family: 'Times New Roman', Times, serif;">Projects contributing to prediction confidence</p>
374
+ """
375
+
376
+ for project in candidate.attached_projects:
377
+ impact_badge = get_impact_badge(project.impact_score)
378
+ border_color = UAB_GREEN if project.impact_score > 0 else '#DC2626'
379
+
380
+ html_after_plot += f"""
381
+ <div style="background: white; border-left: 5px solid {border_color}; padding: 20px; margin: 15px 0; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); font-family: 'Times New Roman', Times, serif;">
382
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
383
+ <h3 style="margin: 0; color: {UAB_DARK_GREEN}; font-family: 'Times New Roman', Times, serif;">{project.name}</h3>
384
+ {impact_badge}
385
+ </div>
386
+
387
+ <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin: 15px 0;">
388
+ <div>
389
+ <p style="margin: 5px 0; color: #4A5568;"><b>Type:</b> {project.project_type}</p>
390
+ <p style="margin: 5px 0; color: #4A5568;"><b>Sample Size:</b> {project.sample_size:,} patients</p>
391
+ </div>
392
+ <div>
393
+ <p style="margin: 5px 0; color: #4A5568;"><b>Status:</b> {project.status}</p>
394
+ <p style="margin: 5px 0; color: #4A5568;"><b>Added:</b> {format_date_ago(project.added_date)}</p>
395
+ </div>
396
+ </div>
397
+
398
+ <div style="background: #F0F9F6; padding: 15px; border-radius: 8px; margin-top: 10px;">
399
+ <p style="margin: 0; font-style: italic; color: #4A5568;">"{project.summary}"</p>
400
+ </div>
401
+ </div>
402
+ """
403
+
404
+ html_after_plot += f"""
405
+ <div style="margin-top: 30px; padding: 20px; background: #F0F9F6; border-radius: 10px; border-left: 4px solid {UAB_GREEN}; font-family: 'Times New Roman', Times, serif;">
406
+ <h3 style="color: {UAB_DARK_GREEN}; font-family: 'Times New Roman', Times, serif;">Summary Statistics</h3>
407
+ <div style="display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-bottom: 15px;">
408
+ <div style="text-align: center; font-family: 'Times New Roman', Times, serif;">
409
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{len(candidate.attached_projects)}</div>
410
+ <div style="color: #4A5568;">Evidence Projects</div>
411
+ </div>
412
+ <div style="text-align: center; font-family: 'Times New Roman', Times, serif;">
413
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{candidate.cohort_count}</div>
414
+ <div style="color: #4A5568;">Patient Cohorts</div>
415
+ </div>
416
+ <div style="text-align: center; font-family: 'Times New Roman', Times, serif;">
417
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{"✅" if candidate.has_validation_plan else "—"}</div>
418
+ <div style="color: #4A5568;">Validation Plan</div>
419
+ </div>
420
+ <div style="text-align: center; font-family: 'Times New Roman', Times, serif;">
421
+ <div style="font-weight: bold; font-size: 24px; color: {UAB_GREEN};">{"✅" if candidate.has_market_analysis else "—"}</div>
422
+ <div style="color: #4A5568;">Market Analysis</div>
423
+ </div>
424
+ </div>
425
+ </div>
426
+ </div>
427
+ """
428
+
429
+ return html_before_plot, gauge_fig, model_comparison_fig, timeline_fig, html_after_plot
page_category.py ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Category Page Module
3
+ Extracted from sud_promise_uab_theme.py
4
+ """
5
+
6
+ # Import UI constants
7
+ from const_ui import (
8
+ UAB_GREEN, UAB_DARK_GREEN,
9
+ MAX_TOP_CANDIDATES_DISPLAY
10
+ )
11
+
12
+ from const_data import SUD_CATEGORY_DESCRIPTIONS
13
+
14
+
15
+ def render_landing_dashboard():
16
+ from sud_promise_uab_theme import CANDIDATES, SUD_CATEGORIES
17
+
18
+ top_candidates = sorted(CANDIDATES, key=lambda c: c.evidence_score, reverse=True)[:MAX_TOP_CANDIDATES_DISPLAY]
19
+
20
+ html = ""
21
+
22
+ category_choices = [f"{cat.name} ({cat.candidate_count} candidates)" for cat in SUD_CATEGORIES]
23
+
24
+ return html, category_choices, top_candidates
25
+
26
+ def render_category_view(category_selection, sort_by="Evidence Score"):
27
+ from sud_promise_uab_theme import CANDIDATES, SUD_CATEGORIES
28
+
29
+ if not category_selection:
30
+ return "<p>Please select a category</p>", [], []
31
+
32
+ category_name = category_selection.split(" (")[0].strip()
33
+ category = next((c for c in SUD_CATEGORIES if c.name == category_name), None)
34
+ if not category:
35
+ return "<p>Category not found</p>", [], []
36
+
37
+ filtered = [c for c in CANDIDATES if c.target_sud_subtype == category_name]
38
+
39
+ if sort_by == "Evidence Score" or sort_by == "evidence_score":
40
+ filtered.sort(key=lambda c: c.evidence_score, reverse=True)
41
+ elif sort_by == "Recent" or sort_by == "recent":
42
+ filtered.sort(key=lambda c: c.last_updated, reverse=True)
43
+ elif sort_by == "Name" or sort_by == "name":
44
+ filtered.sort(key=lambda c: c.drug_name)
45
+ elif sort_by == "Stage":
46
+ filtered.sort(key=lambda c: c.stage, reverse=True)
47
+
48
+
49
+ candidate_choices = [f"{c.drug_name} (Score: {c.evidence_score:.2f})" for c in filtered]
50
+
51
+ html = ""
52
+
53
+ return html, candidate_choices, filtered
requirements.txt ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Core Data Science Libraries
2
+ pandas>=1.5.0
3
+ numpy>=1.23.0
4
+
5
+ # Machine Learning & Deep Learning
6
+ tensorflow>=2.13.0
7
+ scikit-learn>=1.3.0
8
+ joblib>=1.3.0
9
+
10
+ # Chemistry & Drug Discovery
11
+ rdkit>=2023.3.1
12
+
13
+ # Visualization
14
+ plotly>=5.17.0
15
+
16
+ # Web Interface
17
+ gradio>=4.0.0
18
+
19
+ # Additional Dependencies (automatically installed with above, but listed for clarity)
20
+ kaleido>=0.2.1 # For static image export in Plotly (optional but recommended)
saved_models/MODEL_INVENTORY.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "saved_files": {
3
+ "ML_Models": [
4
+ "logistic_regression.pkl",
5
+ "random_forest.pkl",
6
+ "xgboost.pkl"
7
+ ],
8
+ "DNN_Models": [
9
+ "mm_dnn_model.keras",
10
+ "mm_dnn_model.h5"
11
+ ],
12
+ "Preprocessing": [
13
+ "scaler.pkl",
14
+ "target_binarizer.pkl",
15
+ "disease_encoder.pkl",
16
+ "disease_ohe_df.pkl",
17
+ "disease_onehot_encoder.pkl"
18
+ ],
19
+ "Metadata": [
20
+ "dimensions.json",
21
+ "performance.json",
22
+ "metadata.json",
23
+ "training_history.csv",
24
+ "target_classes.json",
25
+ "disease_classes.json"
26
+ ]
27
+ },
28
+ "total_files": 17,
29
+ "total_size_mb": 927.69
30
+ }
saved_models/dimensions.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "drug_dim": 3042,
3
+ "num_diseases": 1573,
4
+ "num_drugs": 1410,
5
+ "num_targets": 2018,
6
+ "num_positive_samples": 42200,
7
+ "train_test_split": 0.2
8
+ }
saved_models/disease_classes.json ADDED
@@ -0,0 +1,1577 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "classes": [
3
+ "MESH:D000013",
4
+ "MESH:D000014",
5
+ "MESH:D000015",
6
+ "MESH:D000022",
7
+ "MESH:D000026",
8
+ "MESH:D000037",
9
+ "MESH:D000067877",
10
+ "MESH:D000068079",
11
+ "MESH:D000070642",
12
+ "MESH:D000072657",
13
+ "MESH:D000072660",
14
+ "MESH:D000075222",
15
+ "MESH:D000077192",
16
+ "MESH:D000077195",
17
+ "MESH:D000077216",
18
+ "MESH:D000077273",
19
+ "MESH:D000077274",
20
+ "MESH:D000077277",
21
+ "MESH:D000138",
22
+ "MESH:D000140",
23
+ "MESH:D000141",
24
+ "MESH:D000152",
25
+ "MESH:D000163",
26
+ "MESH:D000169",
27
+ "MESH:D000172",
28
+ "MESH:D000210",
29
+ "MESH:D000224",
30
+ "MESH:D000230",
31
+ "MESH:D000236",
32
+ "MESH:D000275",
33
+ "MESH:D000303",
34
+ "MESH:D000307",
35
+ "MESH:D000309",
36
+ "MESH:D000310",
37
+ "MESH:D000312",
38
+ "MESH:D000361",
39
+ "MESH:D000380",
40
+ "MESH:D000382",
41
+ "MESH:D000402",
42
+ "MESH:D000419",
43
+ "MESH:D000430",
44
+ "MESH:D000435",
45
+ "MESH:D000437",
46
+ "MESH:D000471",
47
+ "MESH:D000505",
48
+ "MESH:D000506",
49
+ "MESH:D000542",
50
+ "MESH:D000544",
51
+ "MESH:D000568",
52
+ "MESH:D000647",
53
+ "MESH:D000648",
54
+ "MESH:D000686",
55
+ "MESH:D000690",
56
+ "MESH:D000707",
57
+ "MESH:D000740",
58
+ "MESH:D000741",
59
+ "MESH:D000743",
60
+ "MESH:D000744",
61
+ "MESH:D000748",
62
+ "MESH:D000749",
63
+ "MESH:D000751",
64
+ "MESH:D000753",
65
+ "MESH:D000755",
66
+ "MESH:D000756",
67
+ "MESH:D000757",
68
+ "MESH:D000782",
69
+ "MESH:D000783",
70
+ "MESH:D000784",
71
+ "MESH:D000787",
72
+ "MESH:D000789",
73
+ "MESH:D000799",
74
+ "MESH:D000848",
75
+ "MESH:D000853",
76
+ "MESH:D000855",
77
+ "MESH:D000856",
78
+ "MESH:D000857",
79
+ "MESH:D000858",
80
+ "MESH:D000860",
81
+ "MESH:D000987",
82
+ "MESH:D001002",
83
+ "MESH:D001005",
84
+ "MESH:D001006",
85
+ "MESH:D001008",
86
+ "MESH:D001010",
87
+ "MESH:D001014",
88
+ "MESH:D001018",
89
+ "MESH:D001019",
90
+ "MESH:D001022",
91
+ "MESH:D001037",
92
+ "MESH:D001049",
93
+ "MESH:D001068",
94
+ "MESH:D001139",
95
+ "MESH:D001145",
96
+ "MESH:D001157",
97
+ "MESH:D001161",
98
+ "MESH:D001165",
99
+ "MESH:D001167",
100
+ "MESH:D001168",
101
+ "MESH:D001169",
102
+ "MESH:D001170",
103
+ "MESH:D001171",
104
+ "MESH:D001172",
105
+ "MESH:D001176",
106
+ "MESH:D001195",
107
+ "MESH:D001201",
108
+ "MESH:D001228",
109
+ "MESH:D001237",
110
+ "MESH:D001238",
111
+ "MESH:D001247",
112
+ "MESH:D001249",
113
+ "MESH:D001254",
114
+ "MESH:D001259",
115
+ "MESH:D001260",
116
+ "MESH:D001281",
117
+ "MESH:D001284",
118
+ "MESH:D001289",
119
+ "MESH:D001308",
120
+ "MESH:D001321",
121
+ "MESH:D001327",
122
+ "MESH:D001342",
123
+ "MESH:D001416",
124
+ "MESH:D001424",
125
+ "MESH:D001471",
126
+ "MESH:D001477",
127
+ "MESH:D001478",
128
+ "MESH:D001480",
129
+ "MESH:D001523",
130
+ "MESH:D001528",
131
+ "MESH:D001607",
132
+ "MESH:D001649",
133
+ "MESH:D001650",
134
+ "MESH:D001651",
135
+ "MESH:D001661",
136
+ "MESH:D001714",
137
+ "MESH:D001724",
138
+ "MESH:D001744",
139
+ "MESH:D001745",
140
+ "MESH:D001748",
141
+ "MESH:D001749",
142
+ "MESH:D001750",
143
+ "MESH:D001752",
144
+ "MESH:D001763",
145
+ "MESH:D001764",
146
+ "MESH:D001766",
147
+ "MESH:D001768",
148
+ "MESH:D001778",
149
+ "MESH:D001791",
150
+ "MESH:D001835",
151
+ "MESH:D001847",
152
+ "MESH:D001848",
153
+ "MESH:D001849",
154
+ "MESH:D001851",
155
+ "MESH:D001855",
156
+ "MESH:D001859",
157
+ "MESH:D001862",
158
+ "MESH:D001913",
159
+ "MESH:D001919",
160
+ "MESH:D001927",
161
+ "MESH:D001928",
162
+ "MESH:D001929",
163
+ "MESH:D001930",
164
+ "MESH:D001932",
165
+ "MESH:D001941",
166
+ "MESH:D001943",
167
+ "MESH:D001982",
168
+ "MESH:D001987",
169
+ "MESH:D001989",
170
+ "MESH:D001997",
171
+ "MESH:D002006",
172
+ "MESH:D002051",
173
+ "MESH:D002056",
174
+ "MESH:D002057",
175
+ "MESH:D002100",
176
+ "MESH:D002114",
177
+ "MESH:D002177",
178
+ "MESH:D002178",
179
+ "MESH:D002180",
180
+ "MESH:D002181",
181
+ "MESH:D002189",
182
+ "MESH:D002276",
183
+ "MESH:D002277",
184
+ "MESH:D002280",
185
+ "MESH:D002289",
186
+ "MESH:D002292",
187
+ "MESH:D002294",
188
+ "MESH:D002295",
189
+ "MESH:D002296",
190
+ "MESH:D002303",
191
+ "MESH:D002305",
192
+ "MESH:D002310",
193
+ "MESH:D002311",
194
+ "MESH:D002312",
195
+ "MESH:D002313",
196
+ "MESH:D002318",
197
+ "MESH:D002340",
198
+ "MESH:D002341",
199
+ "MESH:D002349",
200
+ "MESH:D002357",
201
+ "MESH:D002375",
202
+ "MESH:D002386",
203
+ "MESH:D002389",
204
+ "MESH:D002446",
205
+ "MESH:D002471",
206
+ "MESH:D002481",
207
+ "MESH:D002493",
208
+ "MESH:D002524",
209
+ "MESH:D002526",
210
+ "MESH:D002532",
211
+ "MESH:D002534",
212
+ "MESH:D002538",
213
+ "MESH:D002542",
214
+ "MESH:D002543",
215
+ "MESH:D002544",
216
+ "MESH:D002545",
217
+ "MESH:D002546",
218
+ "MESH:D002547",
219
+ "MESH:D002561",
220
+ "MESH:D002578",
221
+ "MESH:D002583",
222
+ "MESH:D002607",
223
+ "MESH:D002637",
224
+ "MESH:D002658",
225
+ "MESH:D002659",
226
+ "MESH:D002690",
227
+ "MESH:D002761",
228
+ "MESH:D002769",
229
+ "MESH:D002779",
230
+ "MESH:D002780",
231
+ "MESH:D002805",
232
+ "MESH:D002806",
233
+ "MESH:D002813",
234
+ "MESH:D002819",
235
+ "MESH:D002869",
236
+ "MESH:D002908",
237
+ "MESH:D002971",
238
+ "MESH:D002972",
239
+ "MESH:D003025",
240
+ "MESH:D003057",
241
+ "MESH:D003072",
242
+ "MESH:D003092",
243
+ "MESH:D003093",
244
+ "MESH:D003103",
245
+ "MESH:D003110",
246
+ "MESH:D003111",
247
+ "MESH:D003117",
248
+ "MESH:D003123",
249
+ "MESH:D003128",
250
+ "MESH:D003161",
251
+ "MESH:D003229",
252
+ "MESH:D003240",
253
+ "MESH:D003248",
254
+ "MESH:D003286",
255
+ "MESH:D003294",
256
+ "MESH:D003316",
257
+ "MESH:D003318",
258
+ "MESH:D003320",
259
+ "MESH:D003323",
260
+ "MESH:D003324",
261
+ "MESH:D003327",
262
+ "MESH:D003328",
263
+ "MESH:D003329",
264
+ "MESH:D003330",
265
+ "MESH:D003371",
266
+ "MESH:D003384",
267
+ "MESH:D003394",
268
+ "MESH:D003398",
269
+ "MESH:D003409",
270
+ "MESH:D003424",
271
+ "MESH:D003456",
272
+ "MESH:D003480",
273
+ "MESH:D003490",
274
+ "MESH:D003550",
275
+ "MESH:D003554",
276
+ "MESH:D003556",
277
+ "MESH:D003557",
278
+ "MESH:D003560",
279
+ "MESH:D003586",
280
+ "MESH:D003638",
281
+ "MESH:D003639",
282
+ "MESH:D003643",
283
+ "MESH:D003645",
284
+ "MESH:D003677",
285
+ "MESH:D003680",
286
+ "MESH:D003681",
287
+ "MESH:D003704",
288
+ "MESH:D003711",
289
+ "MESH:D003715",
290
+ "MESH:D003865",
291
+ "MESH:D003866",
292
+ "MESH:D003872",
293
+ "MESH:D003875",
294
+ "MESH:D003876",
295
+ "MESH:D003877",
296
+ "MESH:D003882",
297
+ "MESH:D003914",
298
+ "MESH:D003919",
299
+ "MESH:D003920",
300
+ "MESH:D003921",
301
+ "MESH:D003922",
302
+ "MESH:D003924",
303
+ "MESH:D003925",
304
+ "MESH:D003928",
305
+ "MESH:D003929",
306
+ "MESH:D003930",
307
+ "MESH:D003967",
308
+ "MESH:D003969",
309
+ "MESH:D004195",
310
+ "MESH:D004198",
311
+ "MESH:D004211",
312
+ "MESH:D004283",
313
+ "MESH:D004310",
314
+ "MESH:D004314",
315
+ "MESH:D004370",
316
+ "MESH:D004374",
317
+ "MESH:D004381",
318
+ "MESH:D004401",
319
+ "MESH:D004409",
320
+ "MESH:D004412",
321
+ "MESH:D004413",
322
+ "MESH:D004417",
323
+ "MESH:D004421",
324
+ "MESH:D004427",
325
+ "MESH:D004443",
326
+ "MESH:D004476",
327
+ "MESH:D004485",
328
+ "MESH:D004487",
329
+ "MESH:D004489",
330
+ "MESH:D004617",
331
+ "MESH:D004646",
332
+ "MESH:D004660",
333
+ "MESH:D004681",
334
+ "MESH:D004700",
335
+ "MESH:D004714",
336
+ "MESH:D004715",
337
+ "MESH:D004719",
338
+ "MESH:D004749",
339
+ "MESH:D004751",
340
+ "MESH:D004760",
341
+ "MESH:D004769",
342
+ "MESH:D004802",
343
+ "MESH:D004806",
344
+ "MESH:D004820",
345
+ "MESH:D004827",
346
+ "MESH:D004829",
347
+ "MESH:D004830",
348
+ "MESH:D004831",
349
+ "MESH:D004832",
350
+ "MESH:D004833",
351
+ "MESH:D004890",
352
+ "MESH:D004892",
353
+ "MESH:D004915",
354
+ "MESH:D004916",
355
+ "MESH:D004927",
356
+ "MESH:D004932",
357
+ "MESH:D004935",
358
+ "MESH:D004938",
359
+ "MESH:D004940",
360
+ "MESH:D004941",
361
+ "MESH:D004942",
362
+ "MESH:D005076",
363
+ "MESH:D005119",
364
+ "MESH:D005124",
365
+ "MESH:D005128",
366
+ "MESH:D005131",
367
+ "MESH:D005132",
368
+ "MESH:D005134",
369
+ "MESH:D005141",
370
+ "MESH:D005146",
371
+ "MESH:D005148",
372
+ "MESH:D005158",
373
+ "MESH:D005183",
374
+ "MESH:D005198",
375
+ "MESH:D005199",
376
+ "MESH:D005207",
377
+ "MESH:D005221",
378
+ "MESH:D005234",
379
+ "MESH:D005235",
380
+ "MESH:D005262",
381
+ "MESH:D005264",
382
+ "MESH:D005271",
383
+ "MESH:D005313",
384
+ "MESH:D005315",
385
+ "MESH:D005316",
386
+ "MESH:D005317",
387
+ "MESH:D005327",
388
+ "MESH:D005334",
389
+ "MESH:D005350",
390
+ "MESH:D005354",
391
+ "MESH:D005355",
392
+ "MESH:D005357",
393
+ "MESH:D005483",
394
+ "MESH:D005494",
395
+ "MESH:D005497",
396
+ "MESH:D005512",
397
+ "MESH:D005532",
398
+ "MESH:D005596",
399
+ "MESH:D005600",
400
+ "MESH:D005621",
401
+ "MESH:D005687",
402
+ "MESH:D005706",
403
+ "MESH:D005715",
404
+ "MESH:D005759",
405
+ "MESH:D005761",
406
+ "MESH:D005764",
407
+ "MESH:D005767",
408
+ "MESH:D005770",
409
+ "MESH:D005776",
410
+ "MESH:D005832",
411
+ "MESH:D005833",
412
+ "MESH:D005871",
413
+ "MESH:D005879",
414
+ "MESH:D005885",
415
+ "MESH:D005886",
416
+ "MESH:D005891",
417
+ "MESH:D005901",
418
+ "MESH:D005902",
419
+ "MESH:D005909",
420
+ "MESH:D005910",
421
+ "MESH:D005911",
422
+ "MESH:D005921",
423
+ "MESH:D005922",
424
+ "MESH:D005923",
425
+ "MESH:D006008",
426
+ "MESH:D006030",
427
+ "MESH:D006042",
428
+ "MESH:D006044",
429
+ "MESH:D006053",
430
+ "MESH:D006059",
431
+ "MESH:D006073",
432
+ "MESH:D006083",
433
+ "MESH:D006086",
434
+ "MESH:D006104",
435
+ "MESH:D006106",
436
+ "MESH:D006111",
437
+ "MESH:D006130",
438
+ "MESH:D006177",
439
+ "MESH:D006201",
440
+ "MESH:D006212",
441
+ "MESH:D006222",
442
+ "MESH:D006228",
443
+ "MESH:D006255",
444
+ "MESH:D006258",
445
+ "MESH:D006259",
446
+ "MESH:D006261",
447
+ "MESH:D006311",
448
+ "MESH:D006314",
449
+ "MESH:D006317",
450
+ "MESH:D006319",
451
+ "MESH:D006323",
452
+ "MESH:D006327",
453
+ "MESH:D006330",
454
+ "MESH:D006331",
455
+ "MESH:D006332",
456
+ "MESH:D006333",
457
+ "MESH:D006335",
458
+ "MESH:D006342",
459
+ "MESH:D006343",
460
+ "MESH:D006344",
461
+ "MESH:D006345",
462
+ "MESH:D006349",
463
+ "MESH:D006356",
464
+ "MESH:D006391",
465
+ "MESH:D006394",
466
+ "MESH:D006402",
467
+ "MESH:D006406",
468
+ "MESH:D006408",
469
+ "MESH:D006417",
470
+ "MESH:D006429",
471
+ "MESH:D006432",
472
+ "MESH:D006457",
473
+ "MESH:D006461",
474
+ "MESH:D006463",
475
+ "MESH:D006467",
476
+ "MESH:D006470",
477
+ "MESH:D006471",
478
+ "MESH:D006474",
479
+ "MESH:D006484",
480
+ "MESH:D006501",
481
+ "MESH:D006502",
482
+ "MESH:D006504",
483
+ "MESH:D006505",
484
+ "MESH:D006509",
485
+ "MESH:D006519",
486
+ "MESH:D006520",
487
+ "MESH:D006521",
488
+ "MESH:D006526",
489
+ "MESH:D006527",
490
+ "MESH:D006528",
491
+ "MESH:D006529",
492
+ "MESH:D006530",
493
+ "MESH:D006548",
494
+ "MESH:D006554",
495
+ "MESH:D006556",
496
+ "MESH:D006561",
497
+ "MESH:D006566",
498
+ "MESH:D006620",
499
+ "MESH:D006628",
500
+ "MESH:D006679",
501
+ "MESH:D006689",
502
+ "MESH:D006712",
503
+ "MESH:D006816",
504
+ "MESH:D006831",
505
+ "MESH:D006849",
506
+ "MESH:D006869",
507
+ "MESH:D006929",
508
+ "MESH:D006930",
509
+ "MESH:D006932",
510
+ "MESH:D006934",
511
+ "MESH:D006935",
512
+ "MESH:D006937",
513
+ "MESH:D006938",
514
+ "MESH:D006940",
515
+ "MESH:D006941",
516
+ "MESH:D006942",
517
+ "MESH:D006943",
518
+ "MESH:D006946",
519
+ "MESH:D006947",
520
+ "MESH:D006948",
521
+ "MESH:D006949",
522
+ "MESH:D006950",
523
+ "MESH:D006951",
524
+ "MESH:D006952",
525
+ "MESH:D006953",
526
+ "MESH:D006954",
527
+ "MESH:D006955",
528
+ "MESH:D006958",
529
+ "MESH:D006959",
530
+ "MESH:D006961",
531
+ "MESH:D006962",
532
+ "MESH:D006963",
533
+ "MESH:D006965",
534
+ "MESH:D006966",
535
+ "MESH:D006967",
536
+ "MESH:D006968",
537
+ "MESH:D006969",
538
+ "MESH:D006971",
539
+ "MESH:D006972",
540
+ "MESH:D006973",
541
+ "MESH:D006974",
542
+ "MESH:D006975",
543
+ "MESH:D006976",
544
+ "MESH:D006977",
545
+ "MESH:D006978",
546
+ "MESH:D006980",
547
+ "MESH:D006981",
548
+ "MESH:D006983",
549
+ "MESH:D006984",
550
+ "MESH:D006985",
551
+ "MESH:D006994",
552
+ "MESH:D006996",
553
+ "MESH:D007003",
554
+ "MESH:D007006",
555
+ "MESH:D007008",
556
+ "MESH:D007009",
557
+ "MESH:D007010",
558
+ "MESH:D007011",
559
+ "MESH:D007018",
560
+ "MESH:D007020",
561
+ "MESH:D007021",
562
+ "MESH:D007022",
563
+ "MESH:D007024",
564
+ "MESH:D007035",
565
+ "MESH:D007037",
566
+ "MESH:D007039",
567
+ "MESH:D007040",
568
+ "MESH:D007057",
569
+ "MESH:D007079",
570
+ "MESH:D007105",
571
+ "MESH:D007119",
572
+ "MESH:D007153",
573
+ "MESH:D007154",
574
+ "MESH:D007172",
575
+ "MESH:D007174",
576
+ "MESH:D007177",
577
+ "MESH:D007232",
578
+ "MESH:D007235",
579
+ "MESH:D007238",
580
+ "MESH:D007247",
581
+ "MESH:D007248",
582
+ "MESH:D007249",
583
+ "MESH:D007251",
584
+ "MESH:D007319",
585
+ "MESH:D007333",
586
+ "MESH:D007340",
587
+ "MESH:D007405",
588
+ "MESH:D007410",
589
+ "MESH:D007414",
590
+ "MESH:D007415",
591
+ "MESH:D007416",
592
+ "MESH:D007417",
593
+ "MESH:D007511",
594
+ "MESH:D007562",
595
+ "MESH:D007567",
596
+ "MESH:D007569",
597
+ "MESH:D007589",
598
+ "MESH:D007592",
599
+ "MESH:D007619",
600
+ "MESH:D007627",
601
+ "MESH:D007634",
602
+ "MESH:D007642",
603
+ "MESH:D007644",
604
+ "MESH:D007645",
605
+ "MESH:D007647",
606
+ "MESH:D007669",
607
+ "MESH:D007674",
608
+ "MESH:D007676",
609
+ "MESH:D007680",
610
+ "MESH:D007683",
611
+ "MESH:D007690",
612
+ "MESH:D007706",
613
+ "MESH:D007738",
614
+ "MESH:D007752",
615
+ "MESH:D007805",
616
+ "MESH:D007806",
617
+ "MESH:D007822",
618
+ "MESH:D007835",
619
+ "MESH:D007859",
620
+ "MESH:D007889",
621
+ "MESH:D007890",
622
+ "MESH:D007896",
623
+ "MESH:D007897",
624
+ "MESH:D007898",
625
+ "MESH:D007905",
626
+ "MESH:D007918",
627
+ "MESH:D007938",
628
+ "MESH:D007942",
629
+ "MESH:D007943",
630
+ "MESH:D007945",
631
+ "MESH:D007948",
632
+ "MESH:D007951",
633
+ "MESH:D007960",
634
+ "MESH:D007964",
635
+ "MESH:D007970",
636
+ "MESH:D007972",
637
+ "MESH:D007984",
638
+ "MESH:D008060",
639
+ "MESH:D008064",
640
+ "MESH:D008067",
641
+ "MESH:D008068",
642
+ "MESH:D008080",
643
+ "MESH:D008103",
644
+ "MESH:D008104",
645
+ "MESH:D008105",
646
+ "MESH:D008106",
647
+ "MESH:D008107",
648
+ "MESH:D008108",
649
+ "MESH:D008113",
650
+ "MESH:D008114",
651
+ "MESH:D008133",
652
+ "MESH:D008171",
653
+ "MESH:D008173",
654
+ "MESH:D008175",
655
+ "MESH:D008179",
656
+ "MESH:D008180",
657
+ "MESH:D008181",
658
+ "MESH:D008207",
659
+ "MESH:D008209",
660
+ "MESH:D008223",
661
+ "MESH:D008224",
662
+ "MESH:D008228",
663
+ "MESH:D008231",
664
+ "MESH:D008232",
665
+ "MESH:D008258",
666
+ "MESH:D008268",
667
+ "MESH:D008269",
668
+ "MESH:D008275",
669
+ "MESH:D008286",
670
+ "MESH:D008288",
671
+ "MESH:D008305",
672
+ "MESH:D008325",
673
+ "MESH:D008382",
674
+ "MESH:D008413",
675
+ "MESH:D008415",
676
+ "MESH:D008439",
677
+ "MESH:D008527",
678
+ "MESH:D008545",
679
+ "MESH:D008546",
680
+ "MESH:D008548",
681
+ "MESH:D008569",
682
+ "MESH:D008579",
683
+ "MESH:D008580",
684
+ "MESH:D008581",
685
+ "MESH:D008582",
686
+ "MESH:D008585",
687
+ "MESH:D008589",
688
+ "MESH:D008590",
689
+ "MESH:D008591",
690
+ "MESH:D008607",
691
+ "MESH:D008641",
692
+ "MESH:D008654",
693
+ "MESH:D008659",
694
+ "MESH:D008661",
695
+ "MESH:D008679",
696
+ "MESH:D008708",
697
+ "MESH:D008831",
698
+ "MESH:D008850",
699
+ "MESH:D008881",
700
+ "MESH:D008924",
701
+ "MESH:D008944",
702
+ "MESH:D009021",
703
+ "MESH:D009056",
704
+ "MESH:D009057",
705
+ "MESH:D009059",
706
+ "MESH:D009062",
707
+ "MESH:D009069",
708
+ "MESH:D009080",
709
+ "MESH:D009084",
710
+ "MESH:D009101",
711
+ "MESH:D009102",
712
+ "MESH:D009103",
713
+ "MESH:D009122",
714
+ "MESH:D009123",
715
+ "MESH:D009127",
716
+ "MESH:D009128",
717
+ "MESH:D009133",
718
+ "MESH:D009134",
719
+ "MESH:D009135",
720
+ "MESH:D009136",
721
+ "MESH:D009137",
722
+ "MESH:D009139",
723
+ "MESH:D009157",
724
+ "MESH:D009164",
725
+ "MESH:D009165",
726
+ "MESH:D009175",
727
+ "MESH:D009182",
728
+ "MESH:D009190",
729
+ "MESH:D009196",
730
+ "MESH:D009202",
731
+ "MESH:D009203",
732
+ "MESH:D009205",
733
+ "MESH:D009212",
734
+ "MESH:D009216",
735
+ "MESH:D009220",
736
+ "MESH:D009222",
737
+ "MESH:D009223",
738
+ "MESH:D009224",
739
+ "MESH:D009260",
740
+ "MESH:D009290",
741
+ "MESH:D009293",
742
+ "MESH:D009298",
743
+ "MESH:D009303",
744
+ "MESH:D009325",
745
+ "MESH:D009336",
746
+ "MESH:D009361",
747
+ "MESH:D009362",
748
+ "MESH:D009364",
749
+ "MESH:D009369",
750
+ "MESH:D009373",
751
+ "MESH:D009374",
752
+ "MESH:D009375",
753
+ "MESH:D009376",
754
+ "MESH:D009377",
755
+ "MESH:D009381",
756
+ "MESH:D009385",
757
+ "MESH:D009389",
758
+ "MESH:D009393",
759
+ "MESH:D009395",
760
+ "MESH:D009396",
761
+ "MESH:D009397",
762
+ "MESH:D009400",
763
+ "MESH:D009401",
764
+ "MESH:D009402",
765
+ "MESH:D009404",
766
+ "MESH:D009410",
767
+ "MESH:D009421",
768
+ "MESH:D009422",
769
+ "MESH:D009436",
770
+ "MESH:D009437",
771
+ "MESH:D009442",
772
+ "MESH:D009447",
773
+ "MESH:D009461",
774
+ "MESH:D009468",
775
+ "MESH:D009471",
776
+ "MESH:D009503",
777
+ "MESH:D009669",
778
+ "MESH:D009765",
779
+ "MESH:D009771",
780
+ "MESH:D009784",
781
+ "MESH:D009798",
782
+ "MESH:D009837",
783
+ "MESH:D009839",
784
+ "MESH:D009845",
785
+ "MESH:D009846",
786
+ "MESH:D009886",
787
+ "MESH:D009896",
788
+ "MESH:D009901",
789
+ "MESH:D009902",
790
+ "MESH:D009976",
791
+ "MESH:D009999",
792
+ "MESH:D010001",
793
+ "MESH:D010003",
794
+ "MESH:D010009",
795
+ "MESH:D010014",
796
+ "MESH:D010020",
797
+ "MESH:D010022",
798
+ "MESH:D010024",
799
+ "MESH:D010026",
800
+ "MESH:D010048",
801
+ "MESH:D010049",
802
+ "MESH:D010051",
803
+ "MESH:D010146",
804
+ "MESH:D010148",
805
+ "MESH:D010149",
806
+ "MESH:D010182",
807
+ "MESH:D010190",
808
+ "MESH:D010195",
809
+ "MESH:D010198",
810
+ "MESH:D010212",
811
+ "MESH:D010214",
812
+ "MESH:D010235",
813
+ "MESH:D010243",
814
+ "MESH:D010244",
815
+ "MESH:D010257",
816
+ "MESH:D010259",
817
+ "MESH:D010267",
818
+ "MESH:D010282",
819
+ "MESH:D010291",
820
+ "MESH:D010292",
821
+ "MESH:D010300",
822
+ "MESH:D010302",
823
+ "MESH:D010382",
824
+ "MESH:D010390",
825
+ "MESH:D010391",
826
+ "MESH:D010392",
827
+ "MESH:D010409",
828
+ "MESH:D010411",
829
+ "MESH:D010412",
830
+ "MESH:D010437",
831
+ "MESH:D010438",
832
+ "MESH:D010490",
833
+ "MESH:D010505",
834
+ "MESH:D010510",
835
+ "MESH:D010518",
836
+ "MESH:D010520",
837
+ "MESH:D010523",
838
+ "MESH:D010538",
839
+ "MESH:D010547",
840
+ "MESH:D010554",
841
+ "MESH:D010623",
842
+ "MESH:D010673",
843
+ "MESH:D010698",
844
+ "MESH:D010859",
845
+ "MESH:D010899",
846
+ "MESH:D010900",
847
+ "MESH:D010911",
848
+ "MESH:D010916",
849
+ "MESH:D010922",
850
+ "MESH:D010930",
851
+ "MESH:D010995",
852
+ "MESH:D010996",
853
+ "MESH:D010997",
854
+ "MESH:D010998",
855
+ "MESH:D011008",
856
+ "MESH:D011014",
857
+ "MESH:D011015",
858
+ "MESH:D011018",
859
+ "MESH:D011024",
860
+ "MESH:D011030",
861
+ "MESH:D011085",
862
+ "MESH:D011086",
863
+ "MESH:D011087",
864
+ "MESH:D011115",
865
+ "MESH:D011123",
866
+ "MESH:D011125",
867
+ "MESH:D011141",
868
+ "MESH:D011164",
869
+ "MESH:D011183",
870
+ "MESH:D011218",
871
+ "MESH:D011225",
872
+ "MESH:D011230",
873
+ "MESH:D011248",
874
+ "MESH:D011249",
875
+ "MESH:D011271",
876
+ "MESH:D011297",
877
+ "MESH:D011371",
878
+ "MESH:D011469",
879
+ "MESH:D011470",
880
+ "MESH:D011471",
881
+ "MESH:D011472",
882
+ "MESH:D011488",
883
+ "MESH:D011507",
884
+ "MESH:D011537",
885
+ "MESH:D011546",
886
+ "MESH:D011547",
887
+ "MESH:D011552",
888
+ "MESH:D011561",
889
+ "MESH:D011565",
890
+ "MESH:D011595",
891
+ "MESH:D011596",
892
+ "MESH:D011605",
893
+ "MESH:D011618",
894
+ "MESH:D011625",
895
+ "MESH:D011628",
896
+ "MESH:D011629",
897
+ "MESH:D011644",
898
+ "MESH:D011654",
899
+ "MESH:D011655",
900
+ "MESH:D011656",
901
+ "MESH:D011657",
902
+ "MESH:D011658",
903
+ "MESH:D011668",
904
+ "MESH:D011695",
905
+ "MESH:D011697",
906
+ "MESH:D011704",
907
+ "MESH:D011778",
908
+ "MESH:D011782",
909
+ "MESH:D011832",
910
+ "MESH:D011833",
911
+ "MESH:D011928",
912
+ "MESH:D012004",
913
+ "MESH:D012008",
914
+ "MESH:D012021",
915
+ "MESH:D012035",
916
+ "MESH:D012120",
917
+ "MESH:D012127",
918
+ "MESH:D012128",
919
+ "MESH:D012130",
920
+ "MESH:D012131",
921
+ "MESH:D012135",
922
+ "MESH:D012140",
923
+ "MESH:D012141",
924
+ "MESH:D012148",
925
+ "MESH:D012162",
926
+ "MESH:D012163",
927
+ "MESH:D012164",
928
+ "MESH:D012170",
929
+ "MESH:D012173",
930
+ "MESH:D012174",
931
+ "MESH:D012175",
932
+ "MESH:D012178",
933
+ "MESH:D012206",
934
+ "MESH:D012208",
935
+ "MESH:D012220",
936
+ "MESH:D012221",
937
+ "MESH:D012279",
938
+ "MESH:D012282",
939
+ "MESH:D012393",
940
+ "MESH:D012422",
941
+ "MESH:D012468",
942
+ "MESH:D012481",
943
+ "MESH:D012507",
944
+ "MESH:D012509",
945
+ "MESH:D012512",
946
+ "MESH:D012513",
947
+ "MESH:D012514",
948
+ "MESH:D012516",
949
+ "MESH:D012555",
950
+ "MESH:D012559",
951
+ "MESH:D012563",
952
+ "MESH:D012594",
953
+ "MESH:D012595",
954
+ "MESH:D012598",
955
+ "MESH:D012600",
956
+ "MESH:D012608",
957
+ "MESH:D012640",
958
+ "MESH:D012678",
959
+ "MESH:D012713",
960
+ "MESH:D012734",
961
+ "MESH:D012751",
962
+ "MESH:D012769",
963
+ "MESH:D012770",
964
+ "MESH:D012771",
965
+ "MESH:D012772",
966
+ "MESH:D012791",
967
+ "MESH:D012798",
968
+ "MESH:D012804",
969
+ "MESH:D012848",
970
+ "MESH:D012851",
971
+ "MESH:D012852",
972
+ "MESH:D012857",
973
+ "MESH:D012859",
974
+ "MESH:D012868",
975
+ "MESH:D012871",
976
+ "MESH:D012877",
977
+ "MESH:D012878",
978
+ "MESH:D012883",
979
+ "MESH:D012891",
980
+ "MESH:D012892",
981
+ "MESH:D012893",
982
+ "MESH:D012912",
983
+ "MESH:D012983",
984
+ "MESH:D013001",
985
+ "MESH:D013035",
986
+ "MESH:D013036",
987
+ "MESH:D013064",
988
+ "MESH:D013117",
989
+ "MESH:D013118",
990
+ "MESH:D013119",
991
+ "MESH:D013121",
992
+ "MESH:D013132",
993
+ "MESH:D013158",
994
+ "MESH:D013160",
995
+ "MESH:D013163",
996
+ "MESH:D013167",
997
+ "MESH:D013203",
998
+ "MESH:D013217",
999
+ "MESH:D013226",
1000
+ "MESH:D013262",
1001
+ "MESH:D013272",
1002
+ "MESH:D013274",
1003
+ "MESH:D013276",
1004
+ "MESH:D013280",
1005
+ "MESH:D013313",
1006
+ "MESH:D013341",
1007
+ "MESH:D013342",
1008
+ "MESH:D013345",
1009
+ "MESH:D013375",
1010
+ "MESH:D013398",
1011
+ "MESH:D013471",
1012
+ "MESH:D013479",
1013
+ "MESH:D013494",
1014
+ "MESH:D013576",
1015
+ "MESH:D013584",
1016
+ "MESH:D013585",
1017
+ "MESH:D013610",
1018
+ "MESH:D013616",
1019
+ "MESH:D013617",
1020
+ "MESH:D013625",
1021
+ "MESH:D013651",
1022
+ "MESH:D013684",
1023
+ "MESH:D013705",
1024
+ "MESH:D013733",
1025
+ "MESH:D013736",
1026
+ "MESH:D013771",
1027
+ "MESH:D013832",
1028
+ "MESH:D013896",
1029
+ "MESH:D013899",
1030
+ "MESH:D013920",
1031
+ "MESH:D013921",
1032
+ "MESH:D013922",
1033
+ "MESH:D013923",
1034
+ "MESH:D013927",
1035
+ "MESH:D013953",
1036
+ "MESH:D013959",
1037
+ "MESH:D013964",
1038
+ "MESH:D013967",
1039
+ "MESH:D013971",
1040
+ "MESH:D013981",
1041
+ "MESH:D014012",
1042
+ "MESH:D014029",
1043
+ "MESH:D014062",
1044
+ "MESH:D014076",
1045
+ "MESH:D014098",
1046
+ "MESH:D014103",
1047
+ "MESH:D014178",
1048
+ "MESH:D014188",
1049
+ "MESH:D014202",
1050
+ "MESH:D014277",
1051
+ "MESH:D014313",
1052
+ "MESH:D014314",
1053
+ "MESH:D014339",
1054
+ "MESH:D014376",
1055
+ "MESH:D014397",
1056
+ "MESH:D014402",
1057
+ "MESH:D014424",
1058
+ "MESH:D014435",
1059
+ "MESH:D014456",
1060
+ "MESH:D014474",
1061
+ "MESH:D014511",
1062
+ "MESH:D014514",
1063
+ "MESH:D014516",
1064
+ "MESH:D014517",
1065
+ "MESH:D014552",
1066
+ "MESH:D014555",
1067
+ "MESH:D014564",
1068
+ "MESH:D014565",
1069
+ "MESH:D014571",
1070
+ "MESH:D014581",
1071
+ "MESH:D014591",
1072
+ "MESH:D014594",
1073
+ "MESH:D014605",
1074
+ "MESH:D014607",
1075
+ "MESH:D014625",
1076
+ "MESH:D014648",
1077
+ "MESH:D014652",
1078
+ "MESH:D014657",
1079
+ "MESH:D014693",
1080
+ "MESH:D014694",
1081
+ "MESH:D014718",
1082
+ "MESH:D014766",
1083
+ "MESH:D014777",
1084
+ "MESH:D014786",
1085
+ "MESH:D014802",
1086
+ "MESH:D014806",
1087
+ "MESH:D014808",
1088
+ "MESH:D014820",
1089
+ "MESH:D014839",
1090
+ "MESH:D014854",
1091
+ "MESH:D014855",
1092
+ "MESH:D014869",
1093
+ "MESH:D014890",
1094
+ "MESH:D014898",
1095
+ "MESH:D014899",
1096
+ "MESH:D014901",
1097
+ "MESH:D014927",
1098
+ "MESH:D014947",
1099
+ "MESH:D014950",
1100
+ "MESH:D014973",
1101
+ "MESH:D014983",
1102
+ "MESH:D015173",
1103
+ "MESH:D015175",
1104
+ "MESH:D015179",
1105
+ "MESH:D015207",
1106
+ "MESH:D015209",
1107
+ "MESH:D015210",
1108
+ "MESH:D015212",
1109
+ "MESH:D015228",
1110
+ "MESH:D015266",
1111
+ "MESH:D015352",
1112
+ "MESH:D015417",
1113
+ "MESH:D015427",
1114
+ "MESH:D015428",
1115
+ "MESH:D015430",
1116
+ "MESH:D015431",
1117
+ "MESH:D015432",
1118
+ "MESH:D015433",
1119
+ "MESH:D015451",
1120
+ "MESH:D015452",
1121
+ "MESH:D015458",
1122
+ "MESH:D015459",
1123
+ "MESH:D015461",
1124
+ "MESH:D015464",
1125
+ "MESH:D015470",
1126
+ "MESH:D015473",
1127
+ "MESH:D015479",
1128
+ "MESH:D015508",
1129
+ "MESH:D015526",
1130
+ "MESH:D015535",
1131
+ "MESH:D015576",
1132
+ "MESH:D015619",
1133
+ "MESH:D015658",
1134
+ "MESH:D015663",
1135
+ "MESH:D015674",
1136
+ "MESH:D015745",
1137
+ "MESH:D015746",
1138
+ "MESH:D015792",
1139
+ "MESH:D015812",
1140
+ "MESH:D015834",
1141
+ "MESH:D015837",
1142
+ "MESH:D015858",
1143
+ "MESH:D015861",
1144
+ "MESH:D015877",
1145
+ "MESH:D016055",
1146
+ "MESH:D016111",
1147
+ "MESH:D016114",
1148
+ "MESH:D016135",
1149
+ "MESH:D016137",
1150
+ "MESH:D016142",
1151
+ "MESH:D016171",
1152
+ "MESH:D016301",
1153
+ "MESH:D016393",
1154
+ "MESH:D016399",
1155
+ "MESH:D016403",
1156
+ "MESH:D016410",
1157
+ "MESH:D016411",
1158
+ "MESH:D016470",
1159
+ "MESH:D016471",
1160
+ "MESH:D016472",
1161
+ "MESH:D016481",
1162
+ "MESH:D016483",
1163
+ "MESH:D016491",
1164
+ "MESH:D016506",
1165
+ "MESH:D016510",
1166
+ "MESH:D016534",
1167
+ "MESH:D016535",
1168
+ "MESH:D016543",
1169
+ "MESH:D016553",
1170
+ "MESH:D016584",
1171
+ "MESH:D016603",
1172
+ "MESH:D016609",
1173
+ "MESH:D016638",
1174
+ "MESH:D016640",
1175
+ "MESH:D016649",
1176
+ "MESH:D016736",
1177
+ "MESH:D016757",
1178
+ "MESH:D016769",
1179
+ "MESH:D016773",
1180
+ "MESH:D016778",
1181
+ "MESH:D016870",
1182
+ "MESH:D016883",
1183
+ "MESH:D016889",
1184
+ "MESH:D016891",
1185
+ "MESH:D016893",
1186
+ "MESH:D016905",
1187
+ "MESH:D016908",
1188
+ "MESH:D017029",
1189
+ "MESH:D017086",
1190
+ "MESH:D017088",
1191
+ "MESH:D017093",
1192
+ "MESH:D017094",
1193
+ "MESH:D017096",
1194
+ "MESH:D017098",
1195
+ "MESH:D017114",
1196
+ "MESH:D017116",
1197
+ "MESH:D017118",
1198
+ "MESH:D017119",
1199
+ "MESH:D017180",
1200
+ "MESH:D017202",
1201
+ "MESH:D017240",
1202
+ "MESH:D017241",
1203
+ "MESH:D017246",
1204
+ "MESH:D017285",
1205
+ "MESH:D017379",
1206
+ "MESH:D017380",
1207
+ "MESH:D017445",
1208
+ "MESH:D017449",
1209
+ "MESH:D017453",
1210
+ "MESH:D017492",
1211
+ "MESH:D017495",
1212
+ "MESH:D017496",
1213
+ "MESH:D017497",
1214
+ "MESH:D017511",
1215
+ "MESH:D017512",
1216
+ "MESH:D017544",
1217
+ "MESH:D017545",
1218
+ "MESH:D017563",
1219
+ "MESH:D017566",
1220
+ "MESH:D017588",
1221
+ "MESH:D017599",
1222
+ "MESH:D017674",
1223
+ "MESH:D017681",
1224
+ "MESH:D017682",
1225
+ "MESH:D017689",
1226
+ "MESH:D017700",
1227
+ "MESH:D017728",
1228
+ "MESH:D017880",
1229
+ "MESH:D017889",
1230
+ "MESH:D018149",
1231
+ "MESH:D018177",
1232
+ "MESH:D018188",
1233
+ "MESH:D018192",
1234
+ "MESH:D018197",
1235
+ "MESH:D018200",
1236
+ "MESH:D018212",
1237
+ "MESH:D018213",
1238
+ "MESH:D018221",
1239
+ "MESH:D018222",
1240
+ "MESH:D018223",
1241
+ "MESH:D018226",
1242
+ "MESH:D018232",
1243
+ "MESH:D018233",
1244
+ "MESH:D018235",
1245
+ "MESH:D018236",
1246
+ "MESH:D018239",
1247
+ "MESH:D018241",
1248
+ "MESH:D018242",
1249
+ "MESH:D018248",
1250
+ "MESH:D018256",
1251
+ "MESH:D018262",
1252
+ "MESH:D018263",
1253
+ "MESH:D018268",
1254
+ "MESH:D018269",
1255
+ "MESH:D018270",
1256
+ "MESH:D018275",
1257
+ "MESH:D018276",
1258
+ "MESH:D018281",
1259
+ "MESH:D018287",
1260
+ "MESH:D018288",
1261
+ "MESH:D018307",
1262
+ "MESH:D018316",
1263
+ "MESH:D018317",
1264
+ "MESH:D018318",
1265
+ "MESH:D018325",
1266
+ "MESH:D018328",
1267
+ "MESH:D018352",
1268
+ "MESH:D018357",
1269
+ "MESH:D018358",
1270
+ "MESH:D018376",
1271
+ "MESH:D018382",
1272
+ "MESH:D018442",
1273
+ "MESH:D018450",
1274
+ "MESH:D018476",
1275
+ "MESH:D018487",
1276
+ "MESH:D018496",
1277
+ "MESH:D018497",
1278
+ "MESH:D018500",
1279
+ "MESH:D018567",
1280
+ "MESH:D018589",
1281
+ "MESH:D018636",
1282
+ "MESH:D018754",
1283
+ "MESH:D018771",
1284
+ "MESH:D018777",
1285
+ "MESH:D018792",
1286
+ "MESH:D018798",
1287
+ "MESH:D018805",
1288
+ "MESH:D018827",
1289
+ "MESH:D018856",
1290
+ "MESH:D018879",
1291
+ "MESH:D018883",
1292
+ "MESH:D018908",
1293
+ "MESH:D018917",
1294
+ "MESH:D018921",
1295
+ "MESH:D018923",
1296
+ "MESH:D018979",
1297
+ "MESH:D019046",
1298
+ "MESH:D019048",
1299
+ "MESH:D019066",
1300
+ "MESH:D019082",
1301
+ "MESH:D019150",
1302
+ "MESH:D019189",
1303
+ "MESH:D019190",
1304
+ "MESH:D019226",
1305
+ "MESH:D019247",
1306
+ "MESH:D019283",
1307
+ "MESH:D019305",
1308
+ "MESH:D019337",
1309
+ "MESH:D019446",
1310
+ "MESH:D019457",
1311
+ "MESH:D019465",
1312
+ "MESH:D019512",
1313
+ "MESH:D019578",
1314
+ "MESH:D019586",
1315
+ "MESH:D019588",
1316
+ "MESH:D019636",
1317
+ "MESH:D019693",
1318
+ "MESH:D019694",
1319
+ "MESH:D019698",
1320
+ "MESH:D019767",
1321
+ "MESH:D019851",
1322
+ "MESH:D019873",
1323
+ "MESH:D019896",
1324
+ "MESH:D019954",
1325
+ "MESH:D019956",
1326
+ "MESH:D019957",
1327
+ "MESH:D019958",
1328
+ "MESH:D019964",
1329
+ "MESH:D019965",
1330
+ "MESH:D019966",
1331
+ "MESH:D019967",
1332
+ "MESH:D019969",
1333
+ "MESH:D019970",
1334
+ "MESH:D020016",
1335
+ "MESH:D020018",
1336
+ "MESH:D020078",
1337
+ "MESH:D020083",
1338
+ "MESH:D020138",
1339
+ "MESH:D020149",
1340
+ "MESH:D020151",
1341
+ "MESH:D020158",
1342
+ "MESH:D020163",
1343
+ "MESH:D020176",
1344
+ "MESH:D020178",
1345
+ "MESH:D020181",
1346
+ "MESH:D020190",
1347
+ "MESH:D020191",
1348
+ "MESH:D020194",
1349
+ "MESH:D020198",
1350
+ "MESH:D020199",
1351
+ "MESH:D020225",
1352
+ "MESH:D020233",
1353
+ "MESH:D020234",
1354
+ "MESH:D020244",
1355
+ "MESH:D020246",
1356
+ "MESH:D020256",
1357
+ "MESH:D020257",
1358
+ "MESH:D020258",
1359
+ "MESH:D020261",
1360
+ "MESH:D020262",
1361
+ "MESH:D020267",
1362
+ "MESH:D020270",
1363
+ "MESH:D020294",
1364
+ "MESH:D020295",
1365
+ "MESH:D020300",
1366
+ "MESH:D020301",
1367
+ "MESH:D020323",
1368
+ "MESH:D020325",
1369
+ "MESH:D020326",
1370
+ "MESH:D020329",
1371
+ "MESH:D020345",
1372
+ "MESH:D020347",
1373
+ "MESH:D020370",
1374
+ "MESH:D020388",
1375
+ "MESH:D020417",
1376
+ "MESH:D020426",
1377
+ "MESH:D020514",
1378
+ "MESH:D020520",
1379
+ "MESH:D020521",
1380
+ "MESH:D020522",
1381
+ "MESH:D020529",
1382
+ "MESH:D020734",
1383
+ "MESH:D020751",
1384
+ "MESH:D020754",
1385
+ "MESH:D020760",
1386
+ "MESH:D020767",
1387
+ "MESH:D020774",
1388
+ "MESH:D020790",
1389
+ "MESH:D020795",
1390
+ "MESH:D020803",
1391
+ "MESH:D020817",
1392
+ "MESH:D020820",
1393
+ "MESH:D020821",
1394
+ "MESH:D020879",
1395
+ "MESH:D020886",
1396
+ "MESH:D020920",
1397
+ "MESH:D020925",
1398
+ "MESH:D020936",
1399
+ "MESH:D020945",
1400
+ "MESH:D020961",
1401
+ "MESH:D020964",
1402
+ "MESH:D020967",
1403
+ "MESH:D020968",
1404
+ "MESH:D021081",
1405
+ "MESH:D021441",
1406
+ "MESH:D022124",
1407
+ "MESH:D023341",
1408
+ "MESH:D023903",
1409
+ "MESH:D023921",
1410
+ "MESH:D024801",
1411
+ "MESH:D024821",
1412
+ "MESH:D027601",
1413
+ "MESH:D028227",
1414
+ "MESH:D028361",
1415
+ "MESH:D029241",
1416
+ "MESH:D029242",
1417
+ "MESH:D029424",
1418
+ "MESH:D029481",
1419
+ "MESH:D029502",
1420
+ "MESH:D029503",
1421
+ "MESH:D029597",
1422
+ "MESH:D030342",
1423
+ "MESH:D030361",
1424
+ "MESH:D030401",
1425
+ "MESH:D033461",
1426
+ "MESH:D034141",
1427
+ "MESH:D034381",
1428
+ "MESH:D034721",
1429
+ "MESH:D038062",
1430
+ "MESH:D038261",
1431
+ "MESH:D039682",
1432
+ "MESH:D041781",
1433
+ "MESH:D042822",
1434
+ "MESH:D042882",
1435
+ "MESH:D042883",
1436
+ "MESH:D043171",
1437
+ "MESH:D043183",
1438
+ "MESH:D044148",
1439
+ "MESH:D044342",
1440
+ "MESH:D044483",
1441
+ "MESH:D044584",
1442
+ "MESH:D044882",
1443
+ "MESH:D044903",
1444
+ "MESH:D045169",
1445
+ "MESH:D045262",
1446
+ "MESH:D045743",
1447
+ "MESH:D046110",
1448
+ "MESH:D046152",
1449
+ "MESH:D046349",
1450
+ "MESH:D046350",
1451
+ "MESH:D046351",
1452
+ "MESH:D046748",
1453
+ "MESH:D047508",
1454
+ "MESH:D047748",
1455
+ "MESH:D047928",
1456
+ "MESH:D048550",
1457
+ "MESH:D048629",
1458
+ "MESH:D048909",
1459
+ "MESH:D049188",
1460
+ "MESH:D049310",
1461
+ "MESH:D049912",
1462
+ "MESH:D049970",
1463
+ "MESH:D050031",
1464
+ "MESH:D050171",
1465
+ "MESH:D050177",
1466
+ "MESH:D050197",
1467
+ "MESH:D050500",
1468
+ "MESH:D050723",
1469
+ "MESH:D051359",
1470
+ "MESH:D051436",
1471
+ "MESH:D051437",
1472
+ "MESH:D051474",
1473
+ "MESH:D052016",
1474
+ "MESH:D052177",
1475
+ "MESH:D052439",
1476
+ "MESH:D052456",
1477
+ "MESH:D052496",
1478
+ "MESH:D052556",
1479
+ "MESH:D052776",
1480
+ "MESH:D052878",
1481
+ "MESH:D053040",
1482
+ "MESH:D053098",
1483
+ "MESH:D053099",
1484
+ "MESH:D053201",
1485
+ "MESH:D053565",
1486
+ "MESH:D053578",
1487
+ "MESH:D053608",
1488
+ "MESH:D053609",
1489
+ "MESH:D053627",
1490
+ "MESH:D053713",
1491
+ "MESH:D053840",
1492
+ "MESH:D054038",
1493
+ "MESH:D054058",
1494
+ "MESH:D054066",
1495
+ "MESH:D054078",
1496
+ "MESH:D054079",
1497
+ "MESH:D054143",
1498
+ "MESH:D054144",
1499
+ "MESH:D054179",
1500
+ "MESH:D054198",
1501
+ "MESH:D054218",
1502
+ "MESH:D054220",
1503
+ "MESH:D054221",
1504
+ "MESH:D054318",
1505
+ "MESH:D054391",
1506
+ "MESH:D054429",
1507
+ "MESH:D054537",
1508
+ "MESH:D054556",
1509
+ "MESH:D054559",
1510
+ "MESH:D054882",
1511
+ "MESH:D054971",
1512
+ "MESH:D054990",
1513
+ "MESH:D055013",
1514
+ "MESH:D055031",
1515
+ "MESH:D055191",
1516
+ "MESH:D055370",
1517
+ "MESH:D055371",
1518
+ "MESH:D055665",
1519
+ "MESH:D055728",
1520
+ "MESH:D055752",
1521
+ "MESH:D055959",
1522
+ "MESH:D055963",
1523
+ "MESH:D056486",
1524
+ "MESH:D056627",
1525
+ "MESH:D056647",
1526
+ "MESH:D056693",
1527
+ "MESH:D056735",
1528
+ "MESH:D056769",
1529
+ "MESH:D056784",
1530
+ "MESH:D056829",
1531
+ "MESH:D056889",
1532
+ "MESH:D056912",
1533
+ "MESH:D056929",
1534
+ "MESH:D057049",
1535
+ "MESH:D057066",
1536
+ "MESH:D057180",
1537
+ "MESH:D057772",
1538
+ "MESH:D057973",
1539
+ "MESH:D058065",
1540
+ "MESH:D058186",
1541
+ "MESH:D058226",
1542
+ "MESH:D058426",
1543
+ "MESH:D058447",
1544
+ "MESH:D058496",
1545
+ "MESH:D058566",
1546
+ "MESH:D058625",
1547
+ "MESH:D058729",
1548
+ "MESH:D058739",
1549
+ "MESH:D058922",
1550
+ "MESH:D059348",
1551
+ "MESH:D059350",
1552
+ "MESH:D059352",
1553
+ "MESH:D059366",
1554
+ "MESH:D059606",
1555
+ "MESH:D060050",
1556
+ "MESH:D060825",
1557
+ "MESH:D061205",
1558
+ "MESH:D062787",
1559
+ "MESH:D063646",
1560
+ "MESH:D063647",
1561
+ "MESH:D064129",
1562
+ "MESH:D064726",
1563
+ "MESH:D064793",
1564
+ "MESH:D065306",
1565
+ "MESH:D065626",
1566
+ "MESH:D065630",
1567
+ "MESH:D065631",
1568
+ "MESH:D065646",
1569
+ "MESH:D065666",
1570
+ "MESH:D065766",
1571
+ "MESH:D065817",
1572
+ "MESH:D065886",
1573
+ "MESH:D066088",
1574
+ "MESH:D066126",
1575
+ "MESH:D066253"
1576
+ ]
1577
+ }
saved_models/disease_encoder.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7114defa10f1565caf2c7554720b9faaa5fb9651dd3ecbfd0930f056a82941df
3
+ size 24107
saved_models/disease_ohe_df.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a74b25677f82a65e759b8007fee949d3b998fcc3e53b0c4caeb75d86e619b992
3
+ size 19832087
saved_models/disease_onehot_encoder.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:01a49419d9ec3d2f59a60e51ac54c4b9aefc19c78d584a4b493c7c159432ef64
3
+ size 24603
saved_models/logistic_regression.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e4c679bee7eeee672231864710b629a7e372b2c758ded409f39e255222d6da03
3
+ size 37791
saved_models/metadata.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "training_date": "2026-01-19 14:03:28",
3
+ "model_versions": {
4
+ "tensorflow": "2.16.2",
5
+ "xgboost": "3.1.3",
6
+ "sklearn": "1.4.0",
7
+ "python": "3.10"
8
+ },
9
+ "dataset_info": {
10
+ "num_drugs": 1410,
11
+ "num_diseases": 1573,
12
+ "num_associations": 42200,
13
+ "num_targets": 2018
14
+ },
15
+ "feature_engineering": {
16
+ "morgan_fp_bits": 1024,
17
+ "morgan_fp_radius": 2,
18
+ "target_encoding": "multi-hot",
19
+ "disease_encoding_ml": "one-hot",
20
+ "disease_encoding_dnn": "embedding"
21
+ },
22
+ "model_architecture": {
23
+ "dnn_drug_layers": [
24
+ 256,
25
+ 128
26
+ ],
27
+ "dnn_embedding_dim": 32,
28
+ "dnn_dropout": 0.3,
29
+ "dnn_l2_reg": 0.001
30
+ },
31
+ "training_config": {
32
+ "negative_sampling": "1:1 balanced",
33
+ "train_test_split": 0.2,
34
+ "random_seed": 42,
35
+ "dnn_epochs": 30,
36
+ "dnn_batch_size": 128,
37
+ "dnn_learning_rate": 0.0001
38
+ }
39
+ }
saved_models/mm_dnn_model.h5 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5ff53567647b2f029769e1bda8f4a81decde91d74196dcc9e0070d23c6d89785
3
+ size 10421416
saved_models/mm_dnn_model.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6e0a0433d9bd08f94cd118ed9a1445bdfe1c51236c9f5ca33b79e45138d61280
3
+ size 10422861
saved_models/performance.json ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "test_metrics": {
3
+ "Logistic_Regression": {
4
+ "AUC": 0.8412681094315042,
5
+ "Accuracy": 0.7679502369668246,
6
+ "F1": 0.7698184168772404
7
+ },
8
+ "Random_Forest": {
9
+ "AUC": 0.8273200989420723,
10
+ "Accuracy": 0.7533767772511848,
11
+ "F1": 0.717628705148206
12
+ },
13
+ "XGBoost": {
14
+ "AUC": 0.7347429724175111,
15
+ "Accuracy": 0.7026658767772512,
16
+ "F1": 0.610477299185099
17
+ },
18
+ "MM_DNN": {
19
+ "AUC": 0.8507875496956492,
20
+ "Accuracy": 0.7731635071090047,
21
+ "F1": 0.7757540263543192
22
+ }
23
+ },
24
+ "training_info": {
25
+ "train_size": 67520,
26
+ "test_size": 16880,
27
+ "positive_ratio": 0.5
28
+ }
29
+ }
saved_models/random_forest.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:798846bfc6d6b4d0ac12a4c8c3d818223ecf9786b8a384f3fe8274cefcffb38c
3
+ size 930998329
saved_models/scaler.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c856a7d71e02c97ce9d694638eec6850ef8568b67afcb51587906ef9f3786ecb
3
+ size 150927
saved_models/target_binarizer.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:408b1daa97b6c894afea0ffd4229baae7b996e9bf8ac81a195fe979080d4c64a
3
+ size 18723
saved_models/target_classes.json ADDED
@@ -0,0 +1,2022 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "classes": [
3
+ "A0A024R8I1",
4
+ "A0A045ISQ8",
5
+ "A0A045KKX4",
6
+ "A0A0E1R3H3",
7
+ "A0A0H2XJ39",
8
+ "A0A0T9AZ62",
9
+ "A0A143ZZK9",
10
+ "A0A1K3GRG2",
11
+ "A1L3X4",
12
+ "A2QLK4",
13
+ "A5X5Y0",
14
+ "A9X444",
15
+ "B0B3C9",
16
+ "B2ZTR6",
17
+ "B4YQT9",
18
+ "C0H4L1",
19
+ "C0H4V6",
20
+ "C0H4X5",
21
+ "C0H4Y6",
22
+ "C0H546",
23
+ "C0H551",
24
+ "C0H571",
25
+ "C0H5C2",
26
+ "C0H5H0",
27
+ "C1KC03",
28
+ "C3T8E2",
29
+ "C6KSR5",
30
+ "C6KT34",
31
+ "C6KT50",
32
+ "C6KTA4",
33
+ "C6S3C7",
34
+ "C9EH48",
35
+ "D6R448",
36
+ "F1L7U3",
37
+ "F1T0I5",
38
+ "F7VJQ1",
39
+ "H3BUU9",
40
+ "O00180",
41
+ "O00206",
42
+ "O00217",
43
+ "O00264",
44
+ "O00299",
45
+ "O00305",
46
+ "O00329",
47
+ "O00398",
48
+ "O00408",
49
+ "O00469",
50
+ "O00483",
51
+ "O00519",
52
+ "O00555",
53
+ "O00591",
54
+ "O00763",
55
+ "O00764",
56
+ "O14521",
57
+ "O14556",
58
+ "O14561",
59
+ "O14594",
60
+ "O14618",
61
+ "O14649",
62
+ "O14717",
63
+ "O14727",
64
+ "O14732",
65
+ "O14746",
66
+ "O14764",
67
+ "O14788",
68
+ "O14791",
69
+ "O14832",
70
+ "O14920",
71
+ "O14939",
72
+ "O14958",
73
+ "O14983",
74
+ "O15111",
75
+ "O15239",
76
+ "O15264",
77
+ "O15269",
78
+ "O15270",
79
+ "O15304",
80
+ "O15350",
81
+ "O15374",
82
+ "O15375",
83
+ "O15379",
84
+ "O15382",
85
+ "O15392",
86
+ "O15393",
87
+ "O15399",
88
+ "O15403",
89
+ "O15427",
90
+ "O15439",
91
+ "O15440",
92
+ "O15528",
93
+ "O15530",
94
+ "O15547",
95
+ "O15554",
96
+ "O25608",
97
+ "O39930",
98
+ "O43175",
99
+ "O43181",
100
+ "O43193",
101
+ "O43252",
102
+ "O43451",
103
+ "O43497",
104
+ "O43519",
105
+ "O43525",
106
+ "O43526",
107
+ "O43570",
108
+ "O43612",
109
+ "O43617",
110
+ "O43674",
111
+ "O43676",
112
+ "O43677",
113
+ "O43678",
114
+ "O43681",
115
+ "O43708",
116
+ "O43741",
117
+ "O43766",
118
+ "O43772",
119
+ "O43837",
120
+ "O43920",
121
+ "O60218",
122
+ "O60359",
123
+ "O60391",
124
+ "O60427",
125
+ "O60488",
126
+ "O60494",
127
+ "O60502",
128
+ "O60568",
129
+ "O60603",
130
+ "O60656",
131
+ "O60658",
132
+ "O60669",
133
+ "O60674",
134
+ "O60701",
135
+ "O60706",
136
+ "O60733",
137
+ "O60840",
138
+ "O60858",
139
+ "O60931",
140
+ "O60939",
141
+ "O68601",
142
+ "O75185",
143
+ "O75251",
144
+ "O75306",
145
+ "O75311",
146
+ "O75330",
147
+ "O75340",
148
+ "O75343",
149
+ "O75380",
150
+ "O75438",
151
+ "O75469",
152
+ "O75489",
153
+ "O75493",
154
+ "O75600",
155
+ "O75636",
156
+ "O75715",
157
+ "O75762",
158
+ "O75838",
159
+ "O75880",
160
+ "O75891",
161
+ "O75897",
162
+ "O75899",
163
+ "O75908",
164
+ "O75911",
165
+ "O75912",
166
+ "O75936",
167
+ "O75964",
168
+ "O76054",
169
+ "O76074",
170
+ "O76082",
171
+ "O76083",
172
+ "O77323",
173
+ "O77361",
174
+ "O90777",
175
+ "O94760",
176
+ "O94788",
177
+ "O94903",
178
+ "O94956",
179
+ "O95069",
180
+ "O95139",
181
+ "O95167",
182
+ "O95168",
183
+ "O95169",
184
+ "O95178",
185
+ "O95180",
186
+ "O95182",
187
+ "O95237",
188
+ "O95255",
189
+ "O95259",
190
+ "O95263",
191
+ "O95264",
192
+ "O95298",
193
+ "O95299",
194
+ "O95342",
195
+ "O95470",
196
+ "O95477",
197
+ "O95479",
198
+ "O95622",
199
+ "O95644",
200
+ "O95665",
201
+ "O95718",
202
+ "O95749",
203
+ "O95864",
204
+ "O95907",
205
+ "O95954",
206
+ "O95977",
207
+ "O96000",
208
+ "O96221",
209
+ "O97313",
210
+ "P00091",
211
+ "P00138",
212
+ "P00167",
213
+ "P00183",
214
+ "P00325",
215
+ "P00326",
216
+ "P00338",
217
+ "P00352",
218
+ "P00363",
219
+ "P00367",
220
+ "P00374",
221
+ "P00378",
222
+ "P00387",
223
+ "P00390",
224
+ "P00395",
225
+ "P00439",
226
+ "P00441",
227
+ "P00450",
228
+ "P00484",
229
+ "P00491",
230
+ "P00492",
231
+ "P00505",
232
+ "P00509",
233
+ "P00519",
234
+ "P00533",
235
+ "P00558",
236
+ "P00582",
237
+ "P00709",
238
+ "P00720",
239
+ "P00734",
240
+ "P00736",
241
+ "P00738",
242
+ "P00739",
243
+ "P00740",
244
+ "P00742",
245
+ "P00747",
246
+ "P00748",
247
+ "P00749",
248
+ "P00750",
249
+ "P00751",
250
+ "P00797",
251
+ "P00811",
252
+ "P00813",
253
+ "P00846",
254
+ "P00915",
255
+ "P00918",
256
+ "P00966",
257
+ "P01008",
258
+ "P01009",
259
+ "P01011",
260
+ "P01019",
261
+ "P01023",
262
+ "P01024",
263
+ "P01031",
264
+ "P01042",
265
+ "P01100",
266
+ "P01106",
267
+ "P01133",
268
+ "P01137",
269
+ "P01138",
270
+ "P01189",
271
+ "P01303",
272
+ "P01308",
273
+ "P01375",
274
+ "P01579",
275
+ "P01584",
276
+ "P01591",
277
+ "P01599",
278
+ "P01619",
279
+ "P01709",
280
+ "P01857",
281
+ "P01861",
282
+ "P01871",
283
+ "P01876",
284
+ "P02359",
285
+ "P02452",
286
+ "P02533",
287
+ "P02538",
288
+ "P02585",
289
+ "P02647",
290
+ "P02649",
291
+ "P02652",
292
+ "P02655",
293
+ "P02656",
294
+ "P02671",
295
+ "P02689",
296
+ "P02708",
297
+ "P02743",
298
+ "P02746",
299
+ "P02747",
300
+ "P02748",
301
+ "P02749",
302
+ "P02750",
303
+ "P02751",
304
+ "P02753",
305
+ "P02763",
306
+ "P02765",
307
+ "P02766",
308
+ "P02768",
309
+ "P02775",
310
+ "P02786",
311
+ "P02787",
312
+ "P02788",
313
+ "P02790",
314
+ "P02792",
315
+ "P02794",
316
+ "P02795",
317
+ "P02818",
318
+ "P02918",
319
+ "P02919",
320
+ "P03366",
321
+ "P03369",
322
+ "P03372",
323
+ "P03886",
324
+ "P03891",
325
+ "P03897",
326
+ "P03901",
327
+ "P03905",
328
+ "P03915",
329
+ "P03923",
330
+ "P03951",
331
+ "P03952",
332
+ "P04003",
333
+ "P04004",
334
+ "P04035",
335
+ "P04040",
336
+ "P04049",
337
+ "P04054",
338
+ "P04070",
339
+ "P04075",
340
+ "P04080",
341
+ "P04083",
342
+ "P04114",
343
+ "P04150",
344
+ "P04155",
345
+ "P04156",
346
+ "P04179",
347
+ "P04181",
348
+ "P04196",
349
+ "P04217",
350
+ "P04264",
351
+ "P04271",
352
+ "P04278",
353
+ "P04279",
354
+ "P04293",
355
+ "P04350",
356
+ "P04406",
357
+ "P04585",
358
+ "P04626",
359
+ "P04629",
360
+ "P04637",
361
+ "P04731",
362
+ "P04732",
363
+ "P04733",
364
+ "P04746",
365
+ "P04792",
366
+ "P04798",
367
+ "P04818",
368
+ "P04839",
369
+ "P05023",
370
+ "P05026",
371
+ "P05067",
372
+ "P05089",
373
+ "P05090",
374
+ "P05091",
375
+ "P05093",
376
+ "P05106",
377
+ "P05108",
378
+ "P05109",
379
+ "P05113",
380
+ "P05121",
381
+ "P05129",
382
+ "P05141",
383
+ "P05155",
384
+ "P05156",
385
+ "P05160",
386
+ "P05164",
387
+ "P05165",
388
+ "P05166",
389
+ "P05177",
390
+ "P05181",
391
+ "P05187",
392
+ "P05193",
393
+ "P05230",
394
+ "P05231",
395
+ "P05362",
396
+ "P05412",
397
+ "P05452",
398
+ "P05543",
399
+ "P05546",
400
+ "P05653",
401
+ "P05771",
402
+ "P05787",
403
+ "P06149",
404
+ "P06213",
405
+ "P06239",
406
+ "P06241",
407
+ "P06276",
408
+ "P06307",
409
+ "P06396",
410
+ "P06401",
411
+ "P06478",
412
+ "P06576",
413
+ "P06702",
414
+ "P06703",
415
+ "P06715",
416
+ "P06727",
417
+ "P06732",
418
+ "P06733",
419
+ "P06737",
420
+ "P06744",
421
+ "P06746",
422
+ "P06748",
423
+ "P06756",
424
+ "P06818",
425
+ "P06858",
426
+ "P06864",
427
+ "P06870",
428
+ "P06881",
429
+ "P07098",
430
+ "P07101",
431
+ "P07195",
432
+ "P07202",
433
+ "P07203",
434
+ "P07204",
435
+ "P07225",
436
+ "P07237",
437
+ "P07288",
438
+ "P07327",
439
+ "P07333",
440
+ "P07355",
441
+ "P07357",
442
+ "P07358",
443
+ "P07359",
444
+ "P07360",
445
+ "P07437",
446
+ "P07438",
447
+ "P07451",
448
+ "P07477",
449
+ "P07550",
450
+ "P07686",
451
+ "P07737",
452
+ "P07741",
453
+ "P07864",
454
+ "P07900",
455
+ "P07947",
456
+ "P07948",
457
+ "P07949",
458
+ "P08069",
459
+ "P08100",
460
+ "P08149",
461
+ "P08172",
462
+ "P08173",
463
+ "P08174",
464
+ "P08183",
465
+ "P08185",
466
+ "P08235",
467
+ "P08238",
468
+ "P08243",
469
+ "P08253",
470
+ "P08294",
471
+ "P08319",
472
+ "P08473",
473
+ "P08493",
474
+ "P08506",
475
+ "P08519",
476
+ "P08546",
477
+ "P08559",
478
+ "P08581",
479
+ "P08588",
480
+ "P08603",
481
+ "P08620",
482
+ "P08648",
483
+ "P08670",
484
+ "P08684",
485
+ "P08686",
486
+ "P08697",
487
+ "P08700",
488
+ "P08708",
489
+ "P08729",
490
+ "P08758",
491
+ "P08779",
492
+ "P08865",
493
+ "P08908",
494
+ "P08909",
495
+ "P08912",
496
+ "P08913",
497
+ "P08922",
498
+ "P09038",
499
+ "P09172",
500
+ "P09210",
501
+ "P09211",
502
+ "P09250",
503
+ "P09252",
504
+ "P09382",
505
+ "P09417",
506
+ "P09429",
507
+ "P09455",
508
+ "P09466",
509
+ "P09486",
510
+ "P09488",
511
+ "P09493",
512
+ "P09525",
513
+ "P09601",
514
+ "P09619",
515
+ "P09622",
516
+ "P09769",
517
+ "P09871",
518
+ "P09874",
519
+ "P09884",
520
+ "P09917",
521
+ "P0A0K8",
522
+ "P0A334",
523
+ "P0A3M5",
524
+ "P0A3M6",
525
+ "P0A4L9",
526
+ "P0A6I3",
527
+ "P0A6J8",
528
+ "P0A6R0",
529
+ "P0A749",
530
+ "P0A7J6",
531
+ "P0A7R5",
532
+ "P0A7S3",
533
+ "P0A7S9",
534
+ "P0A7U3",
535
+ "P0A7V3",
536
+ "P0A7V8",
537
+ "P0A7W7",
538
+ "P0A7X3",
539
+ "P0A7Z4",
540
+ "P0A8T7",
541
+ "P0A8V2",
542
+ "P0A953",
543
+ "P0AAI5",
544
+ "P0ABP8",
545
+ "P0ABQ4",
546
+ "P0AC13",
547
+ "P0AD63",
548
+ "P0AD65",
549
+ "P0AD68",
550
+ "P0ADY7",
551
+ "P0AEB2",
552
+ "P0AES4",
553
+ "P0AF12",
554
+ "P0AFI5",
555
+ "P0AFU8",
556
+ "P0AG59",
557
+ "P0C002",
558
+ "P0C0H6",
559
+ "P0C0L5",
560
+ "P0C0X1",
561
+ "P0C0X2",
562
+ "P0C1U9",
563
+ "P0CG04",
564
+ "P0DJD9",
565
+ "P0DM35",
566
+ "P0DMS8",
567
+ "P0DP23",
568
+ "P0DP24",
569
+ "P0DP25",
570
+ "P10109",
571
+ "P10253",
572
+ "P10275",
573
+ "P10276",
574
+ "P10398",
575
+ "P10412",
576
+ "P10415",
577
+ "P10515",
578
+ "P10613",
579
+ "P10632",
580
+ "P10635",
581
+ "P10636",
582
+ "P10696",
583
+ "P10721",
584
+ "P10724",
585
+ "P10809",
586
+ "P10826",
587
+ "P10827",
588
+ "P10828",
589
+ "P10909",
590
+ "P10915",
591
+ "P10997",
592
+ "P11021",
593
+ "P11137",
594
+ "P11142",
595
+ "P11166",
596
+ "P11168",
597
+ "P11177",
598
+ "P11216",
599
+ "P11217",
600
+ "P11229",
601
+ "P11274",
602
+ "P11362",
603
+ "P11387",
604
+ "P11388",
605
+ "P11413",
606
+ "P11473",
607
+ "P11474",
608
+ "P11485",
609
+ "P11498",
610
+ "P11511",
611
+ "P11586",
612
+ "P11678",
613
+ "P11712",
614
+ "P11766",
615
+ "P11802",
616
+ "P11926",
617
+ "P12004",
618
+ "P12070",
619
+ "P12104",
620
+ "P12235",
621
+ "P12236",
622
+ "P12256",
623
+ "P12268",
624
+ "P12277",
625
+ "P12429",
626
+ "P12461",
627
+ "P12532",
628
+ "P12644",
629
+ "P12724",
630
+ "P12814",
631
+ "P12821",
632
+ "P12823",
633
+ "P12851",
634
+ "P12931",
635
+ "P13196",
636
+ "P13498",
637
+ "P13500",
638
+ "P13551",
639
+ "P13568",
640
+ "P13569",
641
+ "P13611",
642
+ "P13631",
643
+ "P13637",
644
+ "P13640",
645
+ "P13645",
646
+ "P13647",
647
+ "P13674",
648
+ "P13693",
649
+ "P13716",
650
+ "P13817",
651
+ "P13827",
652
+ "P13830",
653
+ "P13922",
654
+ "P13945",
655
+ "P13995",
656
+ "P14060",
657
+ "P14061",
658
+ "P14207",
659
+ "P14210",
660
+ "P14223",
661
+ "P14324",
662
+ "P14410",
663
+ "P14415",
664
+ "P14416",
665
+ "P14550",
666
+ "P14555",
667
+ "P14598",
668
+ "P14618",
669
+ "P14625",
670
+ "P14642",
671
+ "P14677",
672
+ "P14679",
673
+ "P14735",
674
+ "P14770",
675
+ "P14780",
676
+ "P14866",
677
+ "P14867",
678
+ "P14902",
679
+ "P14923",
680
+ "P15056",
681
+ "P15121",
682
+ "P15144",
683
+ "P15153",
684
+ "P15169",
685
+ "P15328",
686
+ "P15336",
687
+ "P15382",
688
+ "P15428",
689
+ "P15502",
690
+ "P15531",
691
+ "P15538",
692
+ "P15555",
693
+ "P15559",
694
+ "P15587",
695
+ "P15692",
696
+ "P15814",
697
+ "P15880",
698
+ "P15924",
699
+ "P16050",
700
+ "P16066",
701
+ "P16070",
702
+ "P16083",
703
+ "P16152",
704
+ "P16219",
705
+ "P16220",
706
+ "P16233",
707
+ "P16234",
708
+ "P16389",
709
+ "P16444",
710
+ "P16455",
711
+ "P16499",
712
+ "P16502",
713
+ "P16581",
714
+ "P16615",
715
+ "P16860",
716
+ "P17050",
717
+ "P17117",
718
+ "P17174",
719
+ "P17252",
720
+ "P17302",
721
+ "P17405",
722
+ "P17516",
723
+ "P17540",
724
+ "P17544",
725
+ "P17568",
726
+ "P17612",
727
+ "P17658",
728
+ "P17707",
729
+ "P17735",
730
+ "P17752",
731
+ "P17787",
732
+ "P17802",
733
+ "P17844",
734
+ "P17936",
735
+ "P17948",
736
+ "P18089",
737
+ "P18251",
738
+ "P18283",
739
+ "P18314",
740
+ "P18405",
741
+ "P18505",
742
+ "P18507",
743
+ "P18545",
744
+ "P18669",
745
+ "P18825",
746
+ "P18846",
747
+ "P18847",
748
+ "P18848",
749
+ "P18850",
750
+ "P18858",
751
+ "P19021",
752
+ "P19113",
753
+ "P19320",
754
+ "P19404",
755
+ "P19525",
756
+ "P19634",
757
+ "P19652",
758
+ "P19793",
759
+ "P19801",
760
+ "P19823",
761
+ "P19827",
762
+ "P19838",
763
+ "P19878",
764
+ "P19961",
765
+ "P20020",
766
+ "P20035",
767
+ "P20061",
768
+ "P20132",
769
+ "P20276",
770
+ "P20309",
771
+ "P20618",
772
+ "P20648",
773
+ "P20701",
774
+ "P20711",
775
+ "P20742",
776
+ "P20810",
777
+ "P20815",
778
+ "P20831",
779
+ "P20839",
780
+ "P20851",
781
+ "P21281",
782
+ "P21291",
783
+ "P21333",
784
+ "P21397",
785
+ "P21430",
786
+ "P21453",
787
+ "P21462",
788
+ "P21549",
789
+ "P21554",
790
+ "P21589",
791
+ "P21695",
792
+ "P21728",
793
+ "P21731",
794
+ "P21796",
795
+ "P21802",
796
+ "P21817",
797
+ "P21917",
798
+ "P21918",
799
+ "P21964",
800
+ "P22001",
801
+ "P22033",
802
+ "P22102",
803
+ "P22303",
804
+ "P22352",
805
+ "P22455",
806
+ "P22459",
807
+ "P22460",
808
+ "P22557",
809
+ "P22607",
810
+ "P22626",
811
+ "P22676",
812
+ "P22748",
813
+ "P22792",
814
+ "P22888",
815
+ "P22894",
816
+ "P23141",
817
+ "P23219",
818
+ "P23246",
819
+ "P23258",
820
+ "P23280",
821
+ "P23297",
822
+ "P23367",
823
+ "P23368",
824
+ "P23378",
825
+ "P23415",
826
+ "P23416",
827
+ "P23458",
828
+ "P23469",
829
+ "P23526",
830
+ "P23528",
831
+ "P23560",
832
+ "P23634",
833
+ "P23743",
834
+ "P23786",
835
+ "P23921",
836
+ "P23975",
837
+ "P24024",
838
+ "P24046",
839
+ "P24093",
840
+ "P24228",
841
+ "P24298",
842
+ "P24300",
843
+ "P24385",
844
+ "P24462",
845
+ "P24530",
846
+ "P24666",
847
+ "P24752",
848
+ "P25021",
849
+ "P25024",
850
+ "P25092",
851
+ "P25098",
852
+ "P25100",
853
+ "P25101",
854
+ "P25103",
855
+ "P25105",
856
+ "P25311",
857
+ "P25705",
858
+ "P25713",
859
+ "P25815",
860
+ "P25963",
861
+ "P26358",
862
+ "P26439",
863
+ "P26447",
864
+ "P26676",
865
+ "P27169",
866
+ "P27338",
867
+ "P27361",
868
+ "P27487",
869
+ "P27635",
870
+ "P27707",
871
+ "P27797",
872
+ "P27815",
873
+ "P27816",
874
+ "P27824",
875
+ "P27907",
876
+ "P28062",
877
+ "P28065",
878
+ "P28074",
879
+ "P28221",
880
+ "P28222",
881
+ "P28223",
882
+ "P28329",
883
+ "P28331",
884
+ "P28335",
885
+ "P28472",
886
+ "P28482",
887
+ "P28566",
888
+ "P28676",
889
+ "P28702",
890
+ "P28845",
891
+ "P29034",
892
+ "P29074",
893
+ "P29218",
894
+ "P29274",
895
+ "P29275",
896
+ "P29317",
897
+ "P29371",
898
+ "P29372",
899
+ "P29401",
900
+ "P29422",
901
+ "P29466",
902
+ "P29474",
903
+ "P29475",
904
+ "P29590",
905
+ "P29597",
906
+ "P29622",
907
+ "P29762",
908
+ "P29803",
909
+ "P29972",
910
+ "P30038",
911
+ "P30041",
912
+ "P30043",
913
+ "P30044",
914
+ "P30049",
915
+ "P30085",
916
+ "P30086",
917
+ "P30101",
918
+ "P30405",
919
+ "P30411",
920
+ "P30518",
921
+ "P30519",
922
+ "P30531",
923
+ "P30532",
924
+ "P30536",
925
+ "P30542",
926
+ "P30556",
927
+ "P30559",
928
+ "P30613",
929
+ "P30626",
930
+ "P30837",
931
+ "P30838",
932
+ "P30872",
933
+ "P30874",
934
+ "P30926",
935
+ "P30939",
936
+ "P30968",
937
+ "P31025",
938
+ "P31040",
939
+ "P31151",
940
+ "P31152",
941
+ "P31153",
942
+ "P31213",
943
+ "P31260",
944
+ "P31350",
945
+ "P31391",
946
+ "P31415",
947
+ "P31639",
948
+ "P31644",
949
+ "P31645",
950
+ "P31749",
951
+ "P31937",
952
+ "P31939",
953
+ "P31942",
954
+ "P31943",
955
+ "P31946",
956
+ "P31948",
957
+ "P32004",
958
+ "P32119",
959
+ "P32238",
960
+ "P32239",
961
+ "P32297",
962
+ "P32322",
963
+ "P32418",
964
+ "P32745",
965
+ "P32754",
966
+ "P32929",
967
+ "P33121",
968
+ "P33151",
969
+ "P33261",
970
+ "P33402",
971
+ "P33527",
972
+ "P34896",
973
+ "P34897",
974
+ "P34903",
975
+ "P34969",
976
+ "P34972",
977
+ "P34995",
978
+ "P35218",
979
+ "P35219",
980
+ "P35222",
981
+ "P35228",
982
+ "P35346",
983
+ "P35348",
984
+ "P35354",
985
+ "P35367",
986
+ "P35368",
987
+ "P35372",
988
+ "P35408",
989
+ "P35462",
990
+ "P35498",
991
+ "P35499",
992
+ "P35520",
993
+ "P35527",
994
+ "P35556",
995
+ "P35579",
996
+ "P35610",
997
+ "P35626",
998
+ "P35858",
999
+ "P35869",
1000
+ "P35908",
1001
+ "P35913",
1002
+ "P35916",
1003
+ "P35968",
1004
+ "P36021",
1005
+ "P36507",
1006
+ "P36542",
1007
+ "P36544",
1008
+ "P36578",
1009
+ "P36888",
1010
+ "P36896",
1011
+ "P36955",
1012
+ "P36969",
1013
+ "P37023",
1014
+ "P37058",
1015
+ "P37059",
1016
+ "P37088",
1017
+ "P37108",
1018
+ "P37231",
1019
+ "P37288",
1020
+ "P37610",
1021
+ "P37802",
1022
+ "P37840",
1023
+ "P38435",
1024
+ "P38545",
1025
+ "P38606",
1026
+ "P38936",
1027
+ "P39019",
1028
+ "P39023",
1029
+ "P39086",
1030
+ "P39748",
1031
+ "P39900",
1032
+ "P40238",
1033
+ "P40261",
1034
+ "P40306",
1035
+ "P40394",
1036
+ "P40925",
1037
+ "P40926",
1038
+ "P40933",
1039
+ "P40939",
1040
+ "P41143",
1041
+ "P41145",
1042
+ "P41146",
1043
+ "P41180",
1044
+ "P41222",
1045
+ "P41231",
1046
+ "P41238",
1047
+ "P41240",
1048
+ "P41250",
1049
+ "P41439",
1050
+ "P41594",
1051
+ "P41595",
1052
+ "P41743",
1053
+ "P42261",
1054
+ "P42262",
1055
+ "P42263",
1056
+ "P42330",
1057
+ "P42336",
1058
+ "P42338",
1059
+ "P42345",
1060
+ "P42574",
1061
+ "P42684",
1062
+ "P42685",
1063
+ "P42765",
1064
+ "P42766",
1065
+ "P42858",
1066
+ "P42898",
1067
+ "P42971",
1068
+ "P43088",
1069
+ "P43115",
1070
+ "P43116",
1071
+ "P43119",
1072
+ "P43155",
1073
+ "P43166",
1074
+ "P43353",
1075
+ "P43405",
1076
+ "P43487",
1077
+ "P43652",
1078
+ "P43657",
1079
+ "P43681",
1080
+ "P43700",
1081
+ "P43702",
1082
+ "P44345",
1083
+ "P44469",
1084
+ "P45059",
1085
+ "P45381",
1086
+ "P45844",
1087
+ "P45954",
1088
+ "P45973",
1089
+ "P45983",
1090
+ "P45984",
1091
+ "P46059",
1092
+ "P46098",
1093
+ "P46597",
1094
+ "P46663",
1095
+ "P46736",
1096
+ "P46781",
1097
+ "P46782",
1098
+ "P46925",
1099
+ "P46939",
1100
+ "P46940",
1101
+ "P47712",
1102
+ "P47775",
1103
+ "P47869",
1104
+ "P47870",
1105
+ "P47895",
1106
+ "P47898",
1107
+ "P47900",
1108
+ "P47901",
1109
+ "P47944",
1110
+ "P47989",
1111
+ "P48029",
1112
+ "P48039",
1113
+ "P48047",
1114
+ "P48048",
1115
+ "P48050",
1116
+ "P48051",
1117
+ "P48058",
1118
+ "P48163",
1119
+ "P48167",
1120
+ "P48169",
1121
+ "P48181",
1122
+ "P48443",
1123
+ "P48448",
1124
+ "P48506",
1125
+ "P48507",
1126
+ "P48544",
1127
+ "P48547",
1128
+ "P48549",
1129
+ "P48637",
1130
+ "P48651",
1131
+ "P48723",
1132
+ "P48728",
1133
+ "P49019",
1134
+ "P49069",
1135
+ "P49146",
1136
+ "P49189",
1137
+ "P49228",
1138
+ "P49286",
1139
+ "P49327",
1140
+ "P49354",
1141
+ "P49356",
1142
+ "P49368",
1143
+ "P49411",
1144
+ "P49419",
1145
+ "P49448",
1146
+ "P49585",
1147
+ "P49589",
1148
+ "P49619",
1149
+ "P49642",
1150
+ "P49721",
1151
+ "P49747",
1152
+ "P49788",
1153
+ "P49821",
1154
+ "P49841",
1155
+ "P49888",
1156
+ "P49902",
1157
+ "P49908",
1158
+ "P49916",
1159
+ "P50052",
1160
+ "P50135",
1161
+ "P50213",
1162
+ "P50250",
1163
+ "P50406",
1164
+ "P50416",
1165
+ "P50440",
1166
+ "P50453",
1167
+ "P50579",
1168
+ "P50747",
1169
+ "P50859",
1170
+ "P50897",
1171
+ "P50914",
1172
+ "P50993",
1173
+ "P51160",
1174
+ "P51168",
1175
+ "P51170",
1176
+ "P51172",
1177
+ "P51512",
1178
+ "P51553",
1179
+ "P51575",
1180
+ "P51580",
1181
+ "P51582",
1182
+ "P51648",
1183
+ "P51649",
1184
+ "P51659",
1185
+ "P51681",
1186
+ "P51692",
1187
+ "P51693",
1188
+ "P51787",
1189
+ "P51788",
1190
+ "P51800",
1191
+ "P51812",
1192
+ "P51843",
1193
+ "P51857",
1194
+ "P51858",
1195
+ "P51884",
1196
+ "P51970",
1197
+ "P52209",
1198
+ "P52333",
1199
+ "P52429",
1200
+ "P52647",
1201
+ "P52664",
1202
+ "P52788",
1203
+ "P52824",
1204
+ "P52895",
1205
+ "P53004",
1206
+ "P53041",
1207
+ "P53667",
1208
+ "P53778",
1209
+ "P53779",
1210
+ "P53805",
1211
+ "P53848",
1212
+ "P53985",
1213
+ "P54219",
1214
+ "P54284",
1215
+ "P54289",
1216
+ "P54577",
1217
+ "P54619",
1218
+ "P54646",
1219
+ "P54687",
1220
+ "P54709",
1221
+ "P54710",
1222
+ "P54750",
1223
+ "P54756",
1224
+ "P54760",
1225
+ "P54762",
1226
+ "P54965",
1227
+ "P55011",
1228
+ "P55017",
1229
+ "P55055",
1230
+ "P55157",
1231
+ "P55211",
1232
+ "P55786",
1233
+ "P56181",
1234
+ "P56282",
1235
+ "P56373",
1236
+ "P56381",
1237
+ "P56524",
1238
+ "P56537",
1239
+ "P56556",
1240
+ "P56696",
1241
+ "P56937",
1242
+ "P57059",
1243
+ "P59676",
1244
+ "P59768",
1245
+ "P59796",
1246
+ "P60174",
1247
+ "P60568",
1248
+ "P60723",
1249
+ "P60842",
1250
+ "P61024",
1251
+ "P61073",
1252
+ "P61769",
1253
+ "P61978",
1254
+ "P61987",
1255
+ "P62166",
1256
+ "P62241",
1257
+ "P62269",
1258
+ "P62277",
1259
+ "P62316",
1260
+ "P62508",
1261
+ "P62580",
1262
+ "P62594",
1263
+ "P62750",
1264
+ "P62753",
1265
+ "P62807",
1266
+ "P62857",
1267
+ "P62937",
1268
+ "P62942",
1269
+ "P62955",
1270
+ "P63000",
1271
+ "P63244",
1272
+ "P63252",
1273
+ "P63261",
1274
+ "P63316",
1275
+ "P66010",
1276
+ "P67870",
1277
+ "P68104",
1278
+ "P68366",
1279
+ "P68371",
1280
+ "P68400",
1281
+ "P68871",
1282
+ "P69905",
1283
+ "P69924",
1284
+ "P72355",
1285
+ "P72524",
1286
+ "P72525",
1287
+ "P76577",
1288
+ "P78330",
1289
+ "P78334",
1290
+ "P78348",
1291
+ "P78362",
1292
+ "P78508",
1293
+ "P78527",
1294
+ "P78559",
1295
+ "P80075",
1296
+ "P80294",
1297
+ "P80297",
1298
+ "P80303",
1299
+ "P80365",
1300
+ "P80404",
1301
+ "P80511",
1302
+ "P80748",
1303
+ "P81605",
1304
+ "P83223",
1305
+ "P83812",
1306
+ "P84077",
1307
+ "P86287",
1308
+ "P87764",
1309
+ "P95029",
1310
+ "P95468",
1311
+ "P96965",
1312
+ "P98066",
1313
+ "P98194",
1314
+ "P99999",
1315
+ "P9WGR1",
1316
+ "P9WGY7",
1317
+ "P9WIE5",
1318
+ "P9WIP7",
1319
+ "P9WJ63",
1320
+ "P9WJY5",
1321
+ "P9WNL5",
1322
+ "P9WNL7",
1323
+ "P9WNL9",
1324
+ "P9WNX1",
1325
+ "P9WPS1",
1326
+ "Q00080",
1327
+ "Q00266",
1328
+ "Q00534",
1329
+ "Q00653",
1330
+ "Q00796",
1331
+ "Q00975",
1332
+ "Q00987",
1333
+ "Q01064",
1334
+ "Q01082",
1335
+ "Q01118",
1336
+ "Q01344",
1337
+ "Q01668",
1338
+ "Q01718",
1339
+ "Q01814",
1340
+ "Q01959",
1341
+ "Q01995",
1342
+ "Q02083",
1343
+ "Q02108",
1344
+ "Q02127",
1345
+ "Q02153",
1346
+ "Q02155",
1347
+ "Q02156",
1348
+ "Q02218",
1349
+ "Q02252",
1350
+ "Q02338",
1351
+ "Q02383",
1352
+ "Q02641",
1353
+ "Q02750",
1354
+ "Q02763",
1355
+ "Q02768",
1356
+ "Q02809",
1357
+ "Q02817",
1358
+ "Q02818",
1359
+ "Q02880",
1360
+ "Q02928",
1361
+ "Q03154",
1362
+ "Q03181",
1363
+ "Q03393",
1364
+ "Q03403",
1365
+ "Q03721",
1366
+ "Q04206",
1367
+ "Q04707",
1368
+ "Q04759",
1369
+ "Q04760",
1370
+ "Q04771",
1371
+ "Q04828",
1372
+ "Q04912",
1373
+ "Q05486",
1374
+ "Q05513",
1375
+ "Q05586",
1376
+ "Q05603",
1377
+ "Q05655",
1378
+ "Q05901",
1379
+ "Q05932",
1380
+ "Q05940",
1381
+ "Q06033",
1382
+ "Q06187",
1383
+ "Q06203",
1384
+ "Q06278",
1385
+ "Q06323",
1386
+ "Q06432",
1387
+ "Q06481",
1388
+ "Q06830",
1389
+ "Q06AK7",
1390
+ "Q07020",
1391
+ "Q07021",
1392
+ "Q07343",
1393
+ "Q07699",
1394
+ "Q07806",
1395
+ "Q07864",
1396
+ "Q07869",
1397
+ "Q07912",
1398
+ "Q07955",
1399
+ "Q08170",
1400
+ "Q08210",
1401
+ "Q08257",
1402
+ "Q08288",
1403
+ "Q08289",
1404
+ "Q08345",
1405
+ "Q08426",
1406
+ "Q08460",
1407
+ "Q08462",
1408
+ "Q08493",
1409
+ "Q08499",
1410
+ "Q08828",
1411
+ "Q08853",
1412
+ "Q08881",
1413
+ "Q09428",
1414
+ "Q09470",
1415
+ "Q0VD83",
1416
+ "Q12791",
1417
+ "Q12809",
1418
+ "Q12879",
1419
+ "Q12882",
1420
+ "Q13002",
1421
+ "Q13003",
1422
+ "Q13085",
1423
+ "Q13126",
1424
+ "Q13131",
1425
+ "Q13133",
1426
+ "Q13164",
1427
+ "Q13224",
1428
+ "Q13258",
1429
+ "Q13303",
1430
+ "Q13315",
1431
+ "Q13332",
1432
+ "Q13370",
1433
+ "Q13393",
1434
+ "Q13423",
1435
+ "Q13547",
1436
+ "Q13564",
1437
+ "Q13574",
1438
+ "Q13621",
1439
+ "Q13630",
1440
+ "Q13639",
1441
+ "Q13698",
1442
+ "Q13733",
1443
+ "Q13748",
1444
+ "Q13838",
1445
+ "Q13882",
1446
+ "Q13936",
1447
+ "Q13938",
1448
+ "Q13946",
1449
+ "Q13956",
1450
+ "Q14003",
1451
+ "Q14032",
1452
+ "Q14081",
1453
+ "Q14103",
1454
+ "Q14123",
1455
+ "Q14145",
1456
+ "Q14181",
1457
+ "Q14289",
1458
+ "Q14330",
1459
+ "Q14353",
1460
+ "Q14432",
1461
+ "Q14457",
1462
+ "Q14500",
1463
+ "Q14520",
1464
+ "Q14524",
1465
+ "Q14534",
1466
+ "Q14541",
1467
+ "Q14542",
1468
+ "Q14571",
1469
+ "Q14573",
1470
+ "Q14624",
1471
+ "Q14643",
1472
+ "Q14654",
1473
+ "Q14697",
1474
+ "Q14721",
1475
+ "Q14722",
1476
+ "Q14749",
1477
+ "Q14872",
1478
+ "Q14957",
1479
+ "Q14978",
1480
+ "Q14994",
1481
+ "Q15080",
1482
+ "Q15111",
1483
+ "Q15125",
1484
+ "Q15155",
1485
+ "Q15185",
1486
+ "Q15238",
1487
+ "Q15274",
1488
+ "Q15303",
1489
+ "Q15391",
1490
+ "Q15428",
1491
+ "Q15493",
1492
+ "Q15596",
1493
+ "Q15637",
1494
+ "Q15722",
1495
+ "Q15738",
1496
+ "Q15746",
1497
+ "Q15759",
1498
+ "Q15800",
1499
+ "Q15822",
1500
+ "Q15825",
1501
+ "Q15842",
1502
+ "Q15858",
1503
+ "Q15878",
1504
+ "Q15942",
1505
+ "Q16099",
1506
+ "Q16134",
1507
+ "Q16322",
1508
+ "Q16348",
1509
+ "Q16445",
1510
+ "Q16478",
1511
+ "Q16515",
1512
+ "Q16539",
1513
+ "Q16555",
1514
+ "Q16558",
1515
+ "Q16568",
1516
+ "Q16595",
1517
+ "Q16602",
1518
+ "Q16620",
1519
+ "Q16647",
1520
+ "Q16654",
1521
+ "Q16659",
1522
+ "Q16665",
1523
+ "Q16671",
1524
+ "Q16678",
1525
+ "Q16718",
1526
+ "Q16719",
1527
+ "Q16720",
1528
+ "Q16739",
1529
+ "Q16760",
1530
+ "Q16773",
1531
+ "Q16790",
1532
+ "Q16795",
1533
+ "Q16798",
1534
+ "Q16832",
1535
+ "Q16836",
1536
+ "Q16850",
1537
+ "Q16853",
1538
+ "Q16873",
1539
+ "Q16878",
1540
+ "Q16881",
1541
+ "Q23022",
1542
+ "Q25634",
1543
+ "Q27218",
1544
+ "Q27738",
1545
+ "Q27743",
1546
+ "Q2G0P0",
1547
+ "Q32P28",
1548
+ "Q47066",
1549
+ "Q49184",
1550
+ "Q4U2R8",
1551
+ "Q51504",
1552
+ "Q51911",
1553
+ "Q53707",
1554
+ "Q53ET4",
1555
+ "Q54873",
1556
+ "Q59192",
1557
+ "Q59961",
1558
+ "Q59FK2",
1559
+ "Q59GM9",
1560
+ "Q5JAM2",
1561
+ "Q5JVS0",
1562
+ "Q5JXX5",
1563
+ "Q5KSL6",
1564
+ "Q5L478",
1565
+ "Q5R2K6",
1566
+ "Q5SHN7",
1567
+ "Q5SL87",
1568
+ "Q5SSJ5",
1569
+ "Q5UBX3",
1570
+ "Q5VZ30",
1571
+ "Q60FT7",
1572
+ "Q693P7",
1573
+ "Q6FHJ7",
1574
+ "Q6GI75",
1575
+ "Q6IB77",
1576
+ "Q6IBS8",
1577
+ "Q6LFH8",
1578
+ "Q6MZM0",
1579
+ "Q6N063",
1580
+ "Q6NS38",
1581
+ "Q6NUM9",
1582
+ "Q6PIU1",
1583
+ "Q6UX15",
1584
+ "Q6V0L0",
1585
+ "Q6W5P4",
1586
+ "Q6WRI0",
1587
+ "Q6YP21",
1588
+ "Q6ZMR3",
1589
+ "Q6ZQY3",
1590
+ "Q701N4",
1591
+ "Q70KI2",
1592
+ "Q70Z44",
1593
+ "Q71U36",
1594
+ "Q72547",
1595
+ "Q72874",
1596
+ "Q75N90",
1597
+ "Q75Y35",
1598
+ "Q76NM6",
1599
+ "Q76NN7",
1600
+ "Q7CRA4",
1601
+ "Q7DHH4",
1602
+ "Q7K6A4",
1603
+ "Q7KQK0",
1604
+ "Q7KQL5",
1605
+ "Q7KQM4",
1606
+ "Q7L0J3",
1607
+ "Q7LG56",
1608
+ "Q7RTT9",
1609
+ "Q7RTX0",
1610
+ "Q7SIE2",
1611
+ "Q7Z2W7",
1612
+ "Q7Z3S7",
1613
+ "Q7Z5B4",
1614
+ "Q86T13",
1615
+ "Q86U10",
1616
+ "Q86UW7",
1617
+ "Q86V67",
1618
+ "Q86VZ1",
1619
+ "Q86W47",
1620
+ "Q86XP1",
1621
+ "Q86Y39",
1622
+ "Q86YN6",
1623
+ "Q86YZ3",
1624
+ "Q89ZI2",
1625
+ "Q8DNB6",
1626
+ "Q8DR59",
1627
+ "Q8I0V4",
1628
+ "Q8I0X2",
1629
+ "Q8I2Z8",
1630
+ "Q8I3T9",
1631
+ "Q8I3X4",
1632
+ "Q8I3Z5",
1633
+ "Q8I431",
1634
+ "Q8I487",
1635
+ "Q8I492",
1636
+ "Q8I4R5",
1637
+ "Q8I4W4",
1638
+ "Q8I5G6",
1639
+ "Q8I5H4",
1640
+ "Q8I5Y3",
1641
+ "Q8I6U8",
1642
+ "Q8IAW0",
1643
+ "Q8IB72",
1644
+ "Q8IB78",
1645
+ "Q8IBI3",
1646
+ "Q8IBN5",
1647
+ "Q8IBS5",
1648
+ "Q8IC05",
1649
+ "Q8ID50",
1650
+ "Q8IDD3",
1651
+ "Q8IDH5",
1652
+ "Q8IDI5",
1653
+ "Q8IDP1",
1654
+ "Q8IDP8",
1655
+ "Q8IDQ9",
1656
+ "Q8IDV0",
1657
+ "Q8IE67",
1658
+ "Q8IE82",
1659
+ "Q8IEM3",
1660
+ "Q8IEN3",
1661
+ "Q8IHS5",
1662
+ "Q8II73",
1663
+ "Q8IIA4",
1664
+ "Q8III5",
1665
+ "Q8IIJ9",
1666
+ "Q8IIR9",
1667
+ "Q8IJ60",
1668
+ "Q8IJ74",
1669
+ "Q8IJA9",
1670
+ "Q8IJC6",
1671
+ "Q8IJK8",
1672
+ "Q8IJN7",
1673
+ "Q8IJR6",
1674
+ "Q8IJT2",
1675
+ "Q8IKF0",
1676
+ "Q8IKH8",
1677
+ "Q8IKK7",
1678
+ "Q8IKL4",
1679
+ "Q8IKM5",
1680
+ "Q8IKM6",
1681
+ "Q8IKR1",
1682
+ "Q8IKW5",
1683
+ "Q8IL80",
1684
+ "Q8IL86",
1685
+ "Q8IL88",
1686
+ "Q8ILE8",
1687
+ "Q8ILF7",
1688
+ "Q8ILK3",
1689
+ "Q8ILQ7",
1690
+ "Q8ILV2",
1691
+ "Q8IM15",
1692
+ "Q8IM16",
1693
+ "Q8IM74",
1694
+ "Q8IUZ5",
1695
+ "Q8IVA8",
1696
+ "Q8IVH4",
1697
+ "Q8IVL5",
1698
+ "Q8IVL6",
1699
+ "Q8IWT1",
1700
+ "Q8IZS8",
1701
+ "Q8L103",
1702
+ "Q8N0U8",
1703
+ "Q8N1C3",
1704
+ "Q8N1G2",
1705
+ "Q8N1Q1",
1706
+ "Q8N339",
1707
+ "Q8N543",
1708
+ "Q8N5Z0",
1709
+ "Q8N8N7",
1710
+ "Q8N8R3",
1711
+ "Q8N907",
1712
+ "Q8NBN7",
1713
+ "Q8NCM2",
1714
+ "Q8NER1",
1715
+ "Q8NET8",
1716
+ "Q8NFJ5",
1717
+ "Q8NG66",
1718
+ "Q8RLY5",
1719
+ "Q8TAB3",
1720
+ "Q8TAE7",
1721
+ "Q8TC12",
1722
+ "Q8TCC7",
1723
+ "Q8TCG2",
1724
+ "Q8TCT1",
1725
+ "Q8TCT9",
1726
+ "Q8TCU5",
1727
+ "Q8TD08",
1728
+ "Q8TD30",
1729
+ "Q8TD43",
1730
+ "Q8TDN1",
1731
+ "Q8TDN2",
1732
+ "Q8TDS4",
1733
+ "Q8TDU6",
1734
+ "Q8TE23",
1735
+ "Q8TED1",
1736
+ "Q8TET4",
1737
+ "Q8WTV0",
1738
+ "Q8WU03",
1739
+ "Q8WUI4",
1740
+ "Q8WWG9",
1741
+ "Q8WWQ8",
1742
+ "Q8WXA8",
1743
+ "Q8WXI7",
1744
+ "Q8WXS5",
1745
+ "Q8WYK2",
1746
+ "Q8XB74",
1747
+ "Q8XJ01",
1748
+ "Q91RS4",
1749
+ "Q92206",
1750
+ "Q92482",
1751
+ "Q92506",
1752
+ "Q92570",
1753
+ "Q92731",
1754
+ "Q92736",
1755
+ "Q92753",
1756
+ "Q92769",
1757
+ "Q92781",
1758
+ "Q92806",
1759
+ "Q92887",
1760
+ "Q92911",
1761
+ "Q92945",
1762
+ "Q92952",
1763
+ "Q92953",
1764
+ "Q93083",
1765
+ "Q93086",
1766
+ "Q93088",
1767
+ "Q969G6",
1768
+ "Q969I3",
1769
+ "Q969P6",
1770
+ "Q969S2",
1771
+ "Q969S8",
1772
+ "Q96A70",
1773
+ "Q96C36",
1774
+ "Q96DB2",
1775
+ "Q96DP5",
1776
+ "Q96EB6",
1777
+ "Q96EN8",
1778
+ "Q96ER9",
1779
+ "Q96FI4",
1780
+ "Q96FQ6",
1781
+ "Q96G91",
1782
+ "Q96GA7",
1783
+ "Q96GD0",
1784
+ "Q96I15",
1785
+ "Q96KK3",
1786
+ "Q96KS0",
1787
+ "Q96L12",
1788
+ "Q96L21",
1789
+ "Q96L42",
1790
+ "Q96LZ3",
1791
+ "Q96NR8",
1792
+ "Q96P88",
1793
+ "Q96PD5",
1794
+ "Q96PR1",
1795
+ "Q96Q40",
1796
+ "Q96Q83",
1797
+ "Q96QT4",
1798
+ "Q96RD7",
1799
+ "Q96RE1",
1800
+ "Q96RI1",
1801
+ "Q96RJ0",
1802
+ "Q96RP8",
1803
+ "Q96RQ3",
1804
+ "Q96S37",
1805
+ "Q96S86",
1806
+ "Q96SL4",
1807
+ "Q96SW2",
1808
+ "Q99250",
1809
+ "Q99259",
1810
+ "Q99456",
1811
+ "Q99497",
1812
+ "Q99500",
1813
+ "Q99519",
1814
+ "Q99527",
1815
+ "Q99571",
1816
+ "Q99572",
1817
+ "Q99584",
1818
+ "Q99623",
1819
+ "Q99653",
1820
+ "Q99677",
1821
+ "Q99705",
1822
+ "Q99707",
1823
+ "Q99712",
1824
+ "Q99714",
1825
+ "Q99720",
1826
+ "Q99808",
1827
+ "Q99828",
1828
+ "Q99829",
1829
+ "Q99835",
1830
+ "Q99870",
1831
+ "Q99928",
1832
+ "Q9BPV8",
1833
+ "Q9BQ31",
1834
+ "Q9BQB6",
1835
+ "Q9BTZ2",
1836
+ "Q9BUF5",
1837
+ "Q9BVG9",
1838
+ "Q9BXA1",
1839
+ "Q9BXJ7",
1840
+ "Q9BXT2",
1841
+ "Q9BY41",
1842
+ "Q9BY49",
1843
+ "Q9BY66",
1844
+ "Q9BYF1",
1845
+ "Q9BYV1",
1846
+ "Q9BYZ2",
1847
+ "Q9BZV3",
1848
+ "Q9C0B1",
1849
+ "Q9GPQ4",
1850
+ "Q9GZT4",
1851
+ "Q9GZT9",
1852
+ "Q9GZZ6",
1853
+ "Q9H015",
1854
+ "Q9H169",
1855
+ "Q9H228",
1856
+ "Q9H244",
1857
+ "Q9H252",
1858
+ "Q9H2M3",
1859
+ "Q9H2S1",
1860
+ "Q9H2X9",
1861
+ "Q9H3M0",
1862
+ "Q9H3N8",
1863
+ "Q9H3S4",
1864
+ "Q9H4B7",
1865
+ "Q9H6Z9",
1866
+ "Q9HA77",
1867
+ "Q9HAB3",
1868
+ "Q9HB55",
1869
+ "Q9HBA0",
1870
+ "Q9HBH5",
1871
+ "Q9HBK9",
1872
+ "Q9HC97",
1873
+ "Q9HCC0",
1874
+ "Q9HCR9",
1875
+ "Q9HD40",
1876
+ "Q9L888",
1877
+ "Q9N587",
1878
+ "Q9N623",
1879
+ "Q9NP56",
1880
+ "Q9NPA1",
1881
+ "Q9NPA2",
1882
+ "Q9NPC2",
1883
+ "Q9NPD5",
1884
+ "Q9NPH2",
1885
+ "Q9NQX3",
1886
+ "Q9NR19",
1887
+ "Q9NR33",
1888
+ "Q9NR82",
1889
+ "Q9NR96",
1890
+ "Q9NR97",
1891
+ "Q9NRF9",
1892
+ "Q9NRX3",
1893
+ "Q9NS40",
1894
+ "Q9NS75",
1895
+ "Q9NS85",
1896
+ "Q9NSA0",
1897
+ "Q9NSA2",
1898
+ "Q9NUB1",
1899
+ "Q9NUV7",
1900
+ "Q9NVH6",
1901
+ "Q9NVS9",
1902
+ "Q9NWM0",
1903
+ "Q9NXB9",
1904
+ "Q9NXE4",
1905
+ "Q9NXG6",
1906
+ "Q9NY46",
1907
+ "Q9NY47",
1908
+ "Q9NY56",
1909
+ "Q9NY59",
1910
+ "Q9NY72",
1911
+ "Q9NYK1",
1912
+ "Q9NYL2",
1913
+ "Q9NYP7",
1914
+ "Q9NYR8",
1915
+ "Q9NYV7",
1916
+ "Q9NYX4",
1917
+ "Q9NZD4",
1918
+ "Q9NZK7",
1919
+ "Q9NZQ7",
1920
+ "Q9NZV8",
1921
+ "Q9P0J0",
1922
+ "Q9P0X4",
1923
+ "Q9P0Z9",
1924
+ "Q9QNF7",
1925
+ "Q9TY94",
1926
+ "Q9UBC3",
1927
+ "Q9UBK8",
1928
+ "Q9UBL9",
1929
+ "Q9UBM7",
1930
+ "Q9UBN1",
1931
+ "Q9UBN7",
1932
+ "Q9UBS5",
1933
+ "Q9UBV8",
1934
+ "Q9UDR5",
1935
+ "Q9UDX4",
1936
+ "Q9UE69",
1937
+ "Q9UF02",
1938
+ "Q9UG56",
1939
+ "Q9UGI5",
1940
+ "Q9UGI6",
1941
+ "Q9UGI9",
1942
+ "Q9UGJ0",
1943
+ "Q9UGM1",
1944
+ "Q9UGN5",
1945
+ "Q9UHC3",
1946
+ "Q9UHC9",
1947
+ "Q9UHF0",
1948
+ "Q9UHW9",
1949
+ "Q9UI09",
1950
+ "Q9UI33",
1951
+ "Q9UIX4",
1952
+ "Q9UJ90",
1953
+ "Q9UJ96",
1954
+ "Q9UJT0",
1955
+ "Q9UJT1",
1956
+ "Q9UJU2",
1957
+ "Q9UJX1",
1958
+ "Q9UK17",
1959
+ "Q9UKG9",
1960
+ "Q9UKQ2",
1961
+ "Q9UKV0",
1962
+ "Q9ULB1",
1963
+ "Q9ULD8",
1964
+ "Q9ULU8",
1965
+ "Q9ULX7",
1966
+ "Q9UM07",
1967
+ "Q9UM73",
1968
+ "Q9UN88",
1969
+ "Q9UNA0",
1970
+ "Q9UNX9",
1971
+ "Q9UP95",
1972
+ "Q9UPY5",
1973
+ "Q9UQ05",
1974
+ "Q9UQD0",
1975
+ "Q9UQF2",
1976
+ "Q9UQL6",
1977
+ "Q9UQQ2",
1978
+ "Q9X1H9",
1979
+ "Q9X6V3",
1980
+ "Q9X6W0",
1981
+ "Q9Y233",
1982
+ "Q9Y234",
1983
+ "Q9Y257",
1984
+ "Q9Y271",
1985
+ "Q9Y289",
1986
+ "Q9Y2D0",
1987
+ "Q9Y2D1",
1988
+ "Q9Y2I1",
1989
+ "Q9Y2Q0",
1990
+ "Q9Y2T6",
1991
+ "Q9Y3R4",
1992
+ "Q9Y478",
1993
+ "Q9Y4I5",
1994
+ "Q9Y4R7",
1995
+ "Q9Y4U1",
1996
+ "Q9Y4W6",
1997
+ "Q9Y5K3",
1998
+ "Q9Y5N1",
1999
+ "Q9Y5S1",
2000
+ "Q9Y5S8",
2001
+ "Q9Y5Y4",
2002
+ "Q9Y5Y6",
2003
+ "Q9Y5Y7",
2004
+ "Q9Y5Y9",
2005
+ "Q9Y600",
2006
+ "Q9Y617",
2007
+ "Q9Y666",
2008
+ "Q9Y691",
2009
+ "Q9Y694",
2010
+ "Q9Y697",
2011
+ "Q9Y698",
2012
+ "Q9Y6F1",
2013
+ "Q9Y6H6",
2014
+ "Q9Y6J6",
2015
+ "Q9Y6K1",
2016
+ "Q9Y6L6",
2017
+ "Q9Y6M9",
2018
+ "Q9Y6T7",
2019
+ "Q9Y6Y9",
2020
+ "T1RTG8"
2021
+ ]
2022
+ }
saved_models/training_history.csv ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ AUC,accuracy,loss,val_AUC,val_accuracy,val_loss
2
+ 0.507036566734314,0.506087064743042,1.251436471939087,0.560474157333374,0.537973940372467,1.118517518043518
3
+ 0.5717569589614868,0.5529028177261353,1.094144582748413,0.7252181768417358,0.6705568432807922,1.0167717933654785
4
+ 0.6771646738052368,0.6323607563972473,0.9863069653511047,0.8049399852752686,0.7427725195884705,0.9220553636550903
5
+ 0.7607740759849548,0.6971563696861267,0.8919795155525208,0.8290924429893494,0.7576422095298767,0.840315043926239
6
+ 0.8090741634368896,0.7406398057937622,0.8109089136123657,0.8403506278991699,0.7670023441314697,0.7717797160148621
7
+ 0.8317762613296509,0.7588270306587219,0.7453528046607971,0.8435057997703552,0.7688388824462891,0.7186243534088135
8
+ 0.8440607786178589,0.7671060562133789,0.6934641003608704,0.846678614616394,0.7714455127716064,0.6751850247383118
9
+ 0.8495978713035583,0.7718898057937622,0.6534435749053955,0.84805828332901,0.7710307836532593,0.6414969563484192
10
+ 0.8531641960144043,0.7733116149902344,0.6213479042053223,0.8488333225250244,0.7728673219680786,0.6156119704246521
11
+ 0.8555516600608826,0.7748815417289734,0.5954170823097229,0.8501092791557312,0.7738744020462036,0.5926122069358826
12
+ 0.8566988110542297,0.7768661379814148,0.5746751427650452,0.8504654765129089,0.7740521430969238,0.5752732753753662
13
+ 0.8578413724899292,0.7773104310035706,0.5575758814811707,0.8504075407981873,0.7749999761581421,0.5614798665046692
14
+ 0.8588142395019531,0.7775177955627441,0.5431153774261475,0.8505890965461731,0.7734597325325012,0.5496740341186523
15
+ 0.8591389060020447,0.7778288125991821,0.5316771864891052,0.8502337336540222,0.773281991481781,0.5407591462135315
16
+ 0.8595371246337891,0.7791172862052917,0.5219547152519226,0.8508097529411316,0.773281991481781,0.5321451425552368
17
+ 0.8597018122673035,0.7780953645706177,0.5140978097915649,0.850566565990448,0.7745853066444397,0.5260604023933411
18
+ 0.8601245284080505,0.7787173986434937,0.5070772171020508,0.8509330749511719,0.7748222947120667,0.5200948119163513
19
+ 0.8601078987121582,0.7798281908035278,0.5016252994537354,0.8509336113929749,0.7737559080123901,0.5155055522918701
20
+ 0.8604037761688232,0.7799763083457947,0.4965570271015167,0.8508681654930115,0.7736374139785767,0.5119370818138123
21
+ 0.8608267307281494,0.7800799608230591,0.4920053780078888,0.850792646408081,0.7748815417289734,0.5087065696716309
22
+ 0.8607773780822754,0.7803317308425903,0.4887770414352417,0.850511372089386,0.7736374139785767,0.5064854025840759
23
+ 0.8605943918228149,0.7799763083457947,0.48619967699050903,0.8505977392196655,0.7748222947120667,0.5042062401771545
24
+ 0.8608408570289612,0.7800503373146057,0.4833099842071533,0.8505635261535645,0.7739336490631104,0.5024905800819397
25
+ 0.8606656789779663,0.7801984548568726,0.4814632534980774,0.8504072427749634,0.7748222947120667,0.5012912154197693
26
+ 0.8609856367111206,0.781013011932373,0.47936224937438965,0.8508611917495728,0.7736966609954834,0.4995896518230438
27
+ 0.8608008623123169,0.7801095843315125,0.47802749276161194,0.8506401181221008,0.7749407291412354,0.4986792206764221
28
+ 0.8611049056053162,0.7803761959075928,0.4761931002140045,0.8509538769721985,0.7743483185768127,0.4975397288799286
29
+ 0.8612802624702454,0.7809537649154663,0.47482502460479736,0.8503994941711426,0.773518979549408,0.49760735034942627
30
+ 0.8610990047454834,0.7807019948959351,0.4740986227989197,0.8510578870773315,0.7741706371307373,0.49625903367996216
31
+ 0.8611677885055542,0.7814128994941711,0.47304511070251465,0.8507607579231262,0.7731634974479675,0.49609485268592834
saved_models/xgboost.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b8dd6a73cb2aaa26429ceabddb608e9e4c0dc9cf8084d476077780370f7f33c7
3
+ size 752881
sud_promise_uab_theme.py ADDED
@@ -0,0 +1,708 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 🧬 SUD-PROMISE Drug Repositioning Assessment Platform
3
+ UAB Color Theme: Forest Green/Blue (#1E6B52) & White
4
+ Font: Times New Roman
5
+ Stage System: S0 (Ideation) → S1 (Intake) → S2 (Feasibility) → S3 (In Silico) → S4 (Wet Lab) → S5 (IND-Ready) → S6 (Handoff)
6
+
7
+ VERSION: 3.4.0 - Clickable Card Overlay
8
+ - NEW: Entire card is clickable with invisible overlay button
9
+ - CLEAN: No visible "View Details" button - card itself is the button
10
+ - FIXED: Timeline shows ensemble baseline + all project impacts
11
+ - FIXED: Real ML/DL scores start from ensemble, then show evidence progression
12
+
13
+ UPDATED THEME:
14
+ - Changed Gradio default primary button color ("View Candidates") to UAB GREEN
15
+ """
16
+
17
+ import gradio as gr
18
+ import pandas as pd
19
+ import plotly.graph_objects as go
20
+ from datetime import datetime, timedelta
21
+ import random
22
+ import json
23
+ import numpy as np
24
+ from pathlib import Path
25
+ import warnings
26
+
27
+ # Import custom utilities
28
+ from func_drug import find_drug_in_database
29
+ from func_models import initialize_ml_system, predict_with_ml_models, load_ml_models
30
+ from module_dashboard import render_executive_dashboard
31
+ from page_candidate import render_candidate_dashboard
32
+ from page_category import render_landing_dashboard, render_category_view
33
+
34
+ # Import UI constants and helpers
35
+ from const_ui import (
36
+ # Colors
37
+ UAB_GREEN, UAB_DARK_GREEN, UAB_LIGHT_GREEN, UAB_ACCENT_TEAL, UAB_PALE_GREEN, UAB_WHITE,
38
+ # Stage configuration
39
+ STAGE_MAPPING, STAGE_NAMES, STAGE_COLORS,
40
+ # Thresholds
41
+ SCORE_THRESHOLD_HIGH, SCORE_THRESHOLD_MODERATE,
42
+ # Display limits
43
+ MAX_CATEGORY_CANDIDATES_DISPLAY, MAX_TOP_CANDIDATES_DISPLAY,
44
+ SMILES_DISPLAY_LENGTH, MAX_TARGET_DISPLAY,
45
+ CHART_HEIGHT_SMALL, CHART_HEIGHT_MEDIUM, CHART_HEIGHT_LARGE,
46
+ # Helper functions
47
+ get_status_badge, get_score_type_badge, get_evidence_stars, get_impact_badge
48
+ )
49
+
50
+ # Import data constants
51
+ from const_data import (
52
+ # SUD Categories
53
+ SUD_CATEGORY_DESCRIPTIONS, SUD_CATEGORY_COLORS, DISEASE_SEARCH_CONFIG,
54
+ # Templates
55
+ DRUG_TEMPLATES, PROJECT_TEMPLATES,
56
+ # Metrics
57
+ AVERAGE_TIME_TO_IND, CURRENT_IND_READY_COUNT,
58
+ TIME_BINS_LABELS, TIME_BINS_COUNTS, QUARTERLY_DELIVERIES,
59
+ )
60
+
61
+ # Import config constants
62
+ from const_config import (
63
+ APP_NAME, APP_VERSION, INSTITUTION,
64
+ DATA_DIR, MODEL_DIR, DRUGS_FILE, DISEASES_FILE,
65
+ )
66
+
67
+ # Import data generation module
68
+ from data_generator import (
69
+ Project, DrugCandidate, SUDCategory,
70
+ setup_disease_mapping,
71
+ generate_synthetic_data
72
+ )
73
+
74
+ warnings.filterwarnings('ignore')
75
+
76
+ uab_blue_theme = gr.themes.Soft(
77
+ primary_hue="blue",
78
+ secondary_hue="slate",
79
+ ).set(
80
+ # Primary buttons
81
+ button_primary_background_fill=UAB_GREEN,
82
+ button_primary_background_fill_hover=UAB_DARK_GREEN,
83
+ button_primary_text_color="white",
84
+
85
+ # Secondary buttons
86
+ button_secondary_border_color=UAB_GREEN,
87
+ button_secondary_text_color=UAB_GREEN,
88
+
89
+ # Inputs focus ring / highlights
90
+ input_border_color_focus=UAB_GREEN,
91
+ block_label_background_fill=UAB_GREEN,
92
+ block_label_text_color="white",
93
+ link_text_color=UAB_GREEN,
94
+ )
95
+
96
+ # ========================================
97
+ # ML/DL MODEL LOADING
98
+ # ========================================
99
+
100
+ system = initialize_ml_system()
101
+
102
+ # Extract for backwards compatibility
103
+ MODELS_AVAILABLE = system['models_available']
104
+ ml_components = system['ml_components']
105
+ drugs_df = system['drugs_df']
106
+ diseases_df = system['diseases_df']
107
+
108
+ # ========================================
109
+ # DISEASE ID MAPPING
110
+ # ========================================
111
+
112
+ DISEASE_ID_MAPPING = setup_disease_mapping(diseases_df)
113
+
114
+ # ========================================
115
+ # GENERATE DATA
116
+ # ========================================
117
+
118
+ SUD_CATEGORIES, CANDIDATES = generate_synthetic_data(
119
+ DISEASE_ID_MAPPING,
120
+ MODELS_AVAILABLE,
121
+ ml_components,
122
+ drugs_df
123
+ )
124
+
125
+ # ========================================
126
+ # HELPER FUNCTIONS
127
+ # ========================================
128
+
129
+ def format_date_ago(date):
130
+ delta = datetime.now() - date
131
+ if delta.days == 0:
132
+ return "Today"
133
+ elif delta.days == 1:
134
+ return "Yesterday"
135
+ elif delta.days < 7:
136
+ return f"{delta.days} days ago"
137
+ elif delta.days < 30:
138
+ return f"{delta.days // 7} weeks ago"
139
+ else:
140
+ return f"{delta.days // 30} months ago"
141
+
142
+ def render_candidate_card(candidate, rank, border_color=None):
143
+ stars = get_evidence_stars(candidate.evidence_score)
144
+ status_badge = get_status_badge(candidate.stage)
145
+ score_type_badge = get_score_type_badge(candidate.score_type)
146
+ border = UAB_GREEN
147
+ market_analysis_num = 1 if hasattr(candidate, 'has_market_analysis') and candidate.has_market_analysis else 0
148
+
149
+ html = f"""
150
+ <div style="background: white; border: 2px solid {border}; padding: 15px 20px; margin: 10px 20px;
151
+ border-radius: 12px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);
152
+ font-family: 'Times New Roman', Times, serif; cursor: pointer; transition: all 0.3s ease;">
153
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
154
+ <div style="display: flex; align-items: center; gap: 12px;">
155
+ <span style="background: #EDF2F7; padding: 4px 10px; border-radius: 20px;
156
+ font-size: 14px; color: {UAB_DARK_GREEN}; font-weight: bold;">
157
+ {rank}
158
+ </span>
159
+ <span style="font-size: 24px; font-weight: bold; color: {UAB_DARK_GREEN};">
160
+ {candidate.drug_name}
161
+ </span>
162
+ <span style="font-size: 16px; color: {UAB_GREEN}; font-weight: bold;">
163
+ {stars} {candidate.evidence_score:.2f}
164
+ </span>
165
+ {score_type_badge}
166
+ </div>
167
+ {status_badge}
168
+ </div>
169
+
170
+ <p style="margin: 8px 0; color: #4A5568;"><b>Current Use:</b> {candidate.current_indication}</p>
171
+ <p style="margin: 8px 0; color: #4A5568;"><b>Mechanism:</b> {candidate.mechanism}</p>
172
+
173
+ <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 12px 0;">
174
+ <div style="text-align: center; padding: 10px; background: {UAB_GREEN}; border-radius: 8px;">
175
+ <div style="font-weight: bold; color: white; font-size: 20px;">{len(candidate.attached_projects)}</div>
176
+ <div style="font-size: 12px; color: white;">Projects</div>
177
+ </div>
178
+ <div style="text-align: center; padding: 10px; background: {UAB_GREEN}; border-radius: 8px;">
179
+ <div style="font-weight: bold; color: white; font-size: 20px;">{candidate.cohort_count}</div>
180
+ <div style="font-size: 12px; color: white;">Cohorts</div>
181
+ </div>
182
+ <div style="text-align: center; padding: 10px; background: {UAB_GREEN}; border-radius: 8px;">
183
+ <div style="font-weight: bold; color: white; font-size: 20px;">{market_analysis_num}</div>
184
+ <div style="font-size: 12px; color: white;">Market Analysis</div>
185
+ </div>
186
+ </div>
187
+
188
+ <div style="background: {UAB_PALE_GREEN}; padding: 12px; border-radius: 8px; margin: 12px 0;
189
+ border-left: 3px solid {UAB_GREEN};">
190
+ <p style="margin: 5px 0; color: #4A5568; font-size: 13px;">
191
+ <b>Team Members:</b> {candidate.team_members} |
192
+ <b>Data Produced:</b> {candidate.data_produced} |
193
+ <b>Publications:</b> {candidate.publications}
194
+ </p>
195
+ <p style="margin: 5px 0; color: #4A5568; font-size: 13px;">
196
+ <b>Tools Used:</b> {candidate.tools_used} |
197
+ <b>Data Governance:</b> {candidate.data_governance} |
198
+ <b>Training:</b> {candidate.training_participated}
199
+ </p>
200
+ </div>
201
+
202
+ <p style="margin: 8px 0 0 0; font-size: 13px; color: #A0AEC0;">
203
+ Last updated: {format_date_ago(candidate.last_updated)}
204
+ </p>
205
+ </div>
206
+ """
207
+ return html
208
+
209
+ # ========================================
210
+ # GRADIO INTERFACE
211
+ # ========================================
212
+
213
+ def create_interface():
214
+ CSS = f"""
215
+ * {{
216
+ font-family: 'Times New Roman', Times, serif !important;
217
+ }}
218
+
219
+ .gr-button {{
220
+ font-family: 'Times New Roman', Times, serif !important;
221
+ }}
222
+
223
+ /* Dropdown highlight: UAB GREEN */
224
+ .choices__item--selectable.is-highlighted {{
225
+ background-color: rgba(30, 58, 138, 0.15) !important;
226
+ color: {UAB_DARK_GREEN} !important;
227
+ }}
228
+
229
+ /* Force Gradio primary button color to UAB GREEN (HF Spaces safe) */
230
+ .gr-button-primary,
231
+ .gr-button-primary button {{
232
+ background: {UAB_GREEN} !important;
233
+ border-color: {UAB_GREEN} !important;
234
+ color: white !important;
235
+ font-weight: bold !important;
236
+ }}
237
+
238
+ .gr-button-primary:hover,
239
+ .gr-button-primary button:hover {{
240
+ background: {UAB_DARK_GREEN} !important;
241
+ border-color: {UAB_DARK_GREEN} !important;
242
+ }}
243
+
244
+ /* Card container with relative positioning */
245
+ .card-wrap {{
246
+ position: relative;
247
+ width: 100%;
248
+ margin: 10px 0;
249
+ }}
250
+
251
+ /* Invisible overlay button covering entire card */
252
+ .overlay-btn {{
253
+ position: absolute !important;
254
+ inset: 0 !important;
255
+ z-index: 10 !important;
256
+ opacity: 0 !important;
257
+ cursor: pointer !important;
258
+ }}
259
+
260
+ .overlay-btn button {{
261
+ width: 100% !important;
262
+ height: 100% !important;
263
+ border-radius: 12px !important;
264
+ }}
265
+
266
+ /* Hover effect on card when hovering over invisible button */
267
+ .card-wrap:hover > div:first-child > div {{
268
+ box-shadow: 0 4px 12px rgba(30, 58, 138, 0.22) !important;
269
+ transform: translateY(-2px);
270
+ }}
271
+ """
272
+
273
+ with gr.Blocks(
274
+ title="SUD-PROMISE | UAB",
275
+ css=CSS,
276
+ theme=uab_blue_theme, # APPLY THEME HERE
277
+ ) as demo:
278
+
279
+ current_view = gr.State("dashboard")
280
+ selected_category = gr.State(None)
281
+ selected_candidate = gr.State(None)
282
+
283
+ with gr.Column():
284
+ gr.HTML(f"""
285
+ <div style="text-align: center; padding: 40px 20px;
286
+ background: linear-gradient(135deg, {UAB_GREEN} 0%, {UAB_DARK_GREEN} 100%);
287
+ border-radius: 15px; margin-bottom: 20px;
288
+ box-shadow: 0 4px 6px rgba(30,107,82,0.3);">
289
+ <div style="font-size: 60px; margin-bottom: 20px;">🧬</div>
290
+ <h1 style="color: white; margin: 0; font-size: 42px; font-weight: bold;">
291
+ {APP_NAME}
292
+ </h1>
293
+ <p style="color: white; opacity: 0.95; margin: 15px 0 0 0; font-size: 18px;">
294
+ {INSTITUTION} - Evidence-Based Drug Discovery for Substance Use Disorders
295
+ </p>
296
+ <p style="color: white; opacity: 0.85; margin: 10px 0 0 0; font-size: 14px;">
297
+ 🤖 v8: Clickable Card Overlay + UAB Green Primary Buttons
298
+ </p>
299
+ </div>
300
+ """)
301
+
302
+ breadcrumb = gr.Markdown("")
303
+
304
+ with gr.Column() as main_content:
305
+
306
+ # DASHBOARD VIEW
307
+ with gr.Column(visible=True) as dashboard_view:
308
+ exec_html = gr.HTML()
309
+
310
+ gr.Markdown("---")
311
+
312
+ with gr.Row():
313
+ with gr.Column():
314
+ gr.Markdown("### Average Time to IND-Ready")
315
+ with gr.Row():
316
+ with gr.Column(scale=1):
317
+ avg_time_display = gr.Markdown("")
318
+ with gr.Column(scale=2):
319
+ time_dist_plot = gr.Plot()
320
+
321
+ with gr.Column():
322
+ gr.Markdown("### Quarterly Deliveries")
323
+ with gr.Row():
324
+ with gr.Column(scale=1):
325
+ quarterly_display = gr.Markdown("")
326
+ with gr.Column(scale=2):
327
+ quarterly_plot = gr.Plot()
328
+
329
+ with gr.Row():
330
+ with gr.Column():
331
+ gr.Markdown("### Pipeline Progression - Stage Distribution Over Time")
332
+ pipeline_plot = gr.Plot()
333
+
334
+ with gr.Column():
335
+ gr.Markdown("### Active Portfolio Breakdown")
336
+ portfolio_plot = gr.Plot()
337
+
338
+ gr.Markdown("---")
339
+
340
+ dashboard_html = gr.HTML()
341
+ gr.Markdown("### Top Candidates by Evidence Score")
342
+ gr.Markdown("*Click on any card to view detailed information*")
343
+
344
+ top_candidate_components = []
345
+ for i in range(MAX_TOP_CANDIDATES_DISPLAY):
346
+ with gr.Column(elem_classes=["card-wrap"]):
347
+ top_html = gr.HTML()
348
+ top_btn = gr.Button("View Details", elem_classes=["overlay-btn"])
349
+ top_candidate_components.append((top_html, top_btn))
350
+
351
+ gr.Markdown("---")
352
+ gr.Markdown("### Select a SUD Category to Explore")
353
+
354
+ category_selector = gr.Dropdown(
355
+ choices=[],
356
+ label="",
357
+ show_label=False,
358
+ interactive=True
359
+ )
360
+
361
+ # This is the button in your screenshot: now it becomes UAB GREEN
362
+ view_category_btn = gr.Button("View Candidates", variant="primary", size="lg")
363
+
364
+ # CATEGORY VIEW
365
+ with gr.Column(visible=False) as category_view:
366
+ category_html = gr.HTML()
367
+
368
+ gr.Markdown("**Sort by**")
369
+ with gr.Row():
370
+ sort_dropdown = gr.Dropdown(
371
+ choices=["Evidence Score", "Recent", "Name", "Stage"],
372
+ value="Evidence Score",
373
+ label="",
374
+ show_label=False,
375
+ interactive=True
376
+ )
377
+
378
+ candidate_selector = gr.Dropdown(
379
+ choices=[],
380
+ label="",
381
+ show_label=False,
382
+ interactive=True,
383
+ visible=False
384
+ )
385
+
386
+ gr.Markdown("*Click on any card to view detailed information*")
387
+
388
+ category_candidate_components = []
389
+ category_candidate_buttons = []
390
+ for i in range(MAX_CATEGORY_CANDIDATES_DISPLAY):
391
+ with gr.Column(visible=False, elem_classes=["card-wrap"]) as cat_card_col:
392
+ cat_html = gr.HTML()
393
+ cat_btn = gr.Button("View Details", elem_classes=["overlay-btn"])
394
+ category_candidate_components.append((cat_card_col, cat_html))
395
+ category_candidate_buttons.append(cat_btn)
396
+
397
+ with gr.Row():
398
+ back_to_dashboard_btn = gr.Button("← Back to Dashboard", variant="secondary")
399
+
400
+ # CANDIDATE DETAIL VIEW
401
+ with gr.Column(visible=False) as candidate_view:
402
+ candidate_html_before = gr.HTML()
403
+
404
+ with gr.Row():
405
+ with gr.Column():
406
+ gr.Markdown("### Evidence Score Gauge")
407
+ gauge_plot = gr.Plot()
408
+ with gr.Column():
409
+ gr.Markdown("### Model Score Comparison")
410
+ model_comparison_plot = gr.Plot()
411
+
412
+ gr.Markdown("### Evidence Score Evolution Timeline")
413
+ timeline_plot = gr.Plot()
414
+ gr.Markdown("---")
415
+ candidate_html_after = gr.HTML()
416
+ back_to_category_btn = gr.Button("← Back to Category", variant="secondary", size="lg")
417
+
418
+ # ==========================================================
419
+ # EVENT HANDLERS
420
+ # ==========================================================
421
+
422
+ def show_dashboard():
423
+ exec_html_content, time_fig, quart_fig, pipe_fig, port_fig, avg_time, ind_ready = render_executive_dashboard(
424
+ candidates=CANDIDATES,
425
+ categories=SUD_CATEGORIES,
426
+ models_available=MODELS_AVAILABLE
427
+ )
428
+
429
+ avg_time_md = f"""
430
+ <div style="text-align: center; padding: 15px; background: white;
431
+ border: 2px solid {UAB_GREEN}; border-radius: 10px;">
432
+ <div style="font-size: 36px; font-weight: bold; color: {UAB_GREEN};">{avg_time:.1f}</div>
433
+ <div style="font-size: 14px; color: {UAB_DARK_GREEN};">months</div>
434
+ </div>
435
+ """
436
+
437
+ quarterly_md = f"""
438
+ <div style="text-align: center; padding: 15px; background: white;
439
+ border: 2px solid {UAB_GREEN}; border-radius: 10px;">
440
+ <div style="font-size: 36px; font-weight: bold; color: {UAB_GREEN};">{ind_ready}</div>
441
+ <div style="font-size: 14px; color: {UAB_DARK_GREEN};">IND-Ready</div>
442
+ </div>
443
+ """
444
+
445
+ dash_html, categories, top_5 = render_landing_dashboard()
446
+
447
+ top_outputs = [
448
+ exec_html_content,
449
+ avg_time_md,
450
+ time_fig,
451
+ quarterly_md,
452
+ quart_fig,
453
+ pipe_fig,
454
+ port_fig,
455
+ dash_html,
456
+ gr.update(choices=categories, value=None)
457
+ ]
458
+
459
+ for i, (html_component, btn_component) in enumerate(top_candidate_components):
460
+ if i < len(top_5):
461
+ candidate = top_5[i]
462
+ card_html = render_candidate_card(candidate, f"#{i+1}")
463
+ top_outputs.append(card_html)
464
+ else:
465
+ top_outputs.append("")
466
+
467
+ for col, html in category_candidate_components:
468
+ top_outputs.extend([gr.update(visible=False), ""])
469
+
470
+ top_outputs.extend([
471
+ gr.update(visible=True),
472
+ gr.update(visible=False),
473
+ gr.update(visible=False),
474
+ "dashboard",
475
+ "📊 Dashboard"
476
+ ])
477
+
478
+ return top_outputs
479
+
480
+ def show_category(category_selection):
481
+ if not category_selection:
482
+ return [gr.update()] * (2 + len(category_candidate_components) * 2 + 6)
483
+
484
+ cat_html, candidates, filtered = render_category_view(category_selection)
485
+ category_name = category_selection.split(" (")[0]
486
+
487
+ outputs = [
488
+ cat_html,
489
+ gr.update(choices=candidates, value=None),
490
+ ]
491
+
492
+ for i, (col, html) in enumerate(category_candidate_components):
493
+ if i < len(filtered):
494
+ candidate = filtered[i]
495
+ card_html = render_candidate_card(candidate, f"#{i+1}")
496
+ outputs.extend([gr.update(visible=True), card_html])
497
+ else:
498
+ outputs.extend([gr.update(visible=False), ""])
499
+
500
+ outputs.extend([
501
+ gr.update(visible=False),
502
+ gr.update(visible=True),
503
+ gr.update(visible=False),
504
+ category_selection,
505
+ "category",
506
+ f"📊 Dashboard > {category_name}",
507
+ ])
508
+ return outputs
509
+
510
+ def show_candidate(candidate_selection, category_selection):
511
+ if not candidate_selection:
512
+ return [gr.update()] * 10
513
+
514
+ html_before, gauge_fig, model_fig, timeline_fig, html_after = render_candidate_dashboard(
515
+ candidate_selection, category_selection
516
+ )
517
+ candidate_name = candidate_selection.split(" (Score:")[0]
518
+ category_name = category_selection.split(" (")[0] if category_selection else "Category"
519
+
520
+ return (
521
+ f"📊 Dashboard > {category_name} > {candidate_name}",
522
+ html_before,
523
+ gauge_fig,
524
+ model_fig,
525
+ timeline_fig,
526
+ html_after,
527
+ gr.update(visible=False),
528
+ gr.update(visible=False),
529
+ gr.update(visible=True),
530
+ category_selection,
531
+ )
532
+
533
+ def update_category_sort(category_selection, sort_by):
534
+ if not category_selection:
535
+ return [gr.update()] * (2 + len(category_candidate_components) * 2)
536
+
537
+ cat_html, candidates, filtered = render_category_view(category_selection, sort_by)
538
+ outputs = [cat_html, gr.update(choices=candidates)]
539
+
540
+ for i, (col, html) in enumerate(category_candidate_components):
541
+ if i < len(filtered):
542
+ candidate = filtered[i]
543
+ card_html = render_candidate_card(candidate, f"#{i+1}")
544
+ outputs.extend([gr.update(visible=True), card_html])
545
+ else:
546
+ outputs.extend([gr.update(visible=False), ""])
547
+
548
+ return outputs
549
+
550
+ def make_view_candidate_handler(candidate_index, is_top=False):
551
+ def handler():
552
+ if is_top:
553
+ top_5 = sorted(CANDIDATES, key=lambda c: c.evidence_score, reverse=True)[:MAX_TOP_CANDIDATES_DISPLAY]
554
+ if candidate_index >= len(top_5):
555
+ return [gr.update()] * 10
556
+ candidate = top_5[candidate_index]
557
+ else:
558
+ return [gr.update()] * 10
559
+
560
+ category_str = f"{candidate.target_sud_subtype} ({sum(1 for c in CANDIDATES if c.target_sud_subtype == candidate.target_sud_subtype)} candidates)"
561
+ candidate_str = f"{candidate.drug_name} (Score: {candidate.evidence_score:.2f})"
562
+
563
+ html_before, gauge_fig, model_fig, timeline_fig, html_after = render_candidate_dashboard(candidate_str, category_str)
564
+ return (
565
+ f"📊 Dashboard > {candidate.target_sud_subtype} > {candidate.drug_name}",
566
+ html_before,
567
+ gauge_fig,
568
+ model_fig,
569
+ timeline_fig,
570
+ html_after,
571
+ gr.update(visible=False),
572
+ gr.update(visible=False),
573
+ gr.update(visible=True),
574
+ category_str,
575
+ )
576
+ return handler
577
+
578
+ def make_category_candidate_handler(candidate_index):
579
+ def handler(category_selection):
580
+ if not category_selection:
581
+ return [gr.update()] * 10
582
+
583
+ category_name = category_selection.split(" (")[0].strip()
584
+ filtered = [c for c in CANDIDATES if c.target_sud_subtype == category_name]
585
+ filtered.sort(key=lambda c: c.evidence_score, reverse=True)
586
+
587
+ if candidate_index >= len(filtered):
588
+ return [gr.update()] * 10
589
+
590
+ candidate = filtered[candidate_index]
591
+ candidate_str = f"{candidate.drug_name} (Score: {candidate.evidence_score:.2f})"
592
+
593
+ html_before, gauge_fig, model_fig, timeline_fig, html_after = render_candidate_dashboard(candidate_str, category_selection)
594
+ return (
595
+ f"📊 Dashboard > {category_name} > {candidate.drug_name}",
596
+ html_before,
597
+ gauge_fig,
598
+ model_fig,
599
+ timeline_fig,
600
+ html_after,
601
+ gr.update(visible=False),
602
+ gr.update(visible=False),
603
+ gr.update(visible=True),
604
+ category_selection,
605
+ )
606
+ return handler
607
+
608
+ # ==========================================================
609
+ # CONNECT EVENTS
610
+ # ==========================================================
611
+
612
+ demo.load(
613
+ fn=show_dashboard,
614
+ outputs=[
615
+ exec_html, avg_time_display, time_dist_plot, quarterly_display, quarterly_plot, pipeline_plot, portfolio_plot,
616
+ dashboard_html, category_selector
617
+ ] +
618
+ [comp for pair in top_candidate_components for comp in [pair[0]]] +
619
+ [comp for pair in category_candidate_components for comp in [pair[0], pair[1]]] +
620
+ [dashboard_view, category_view, candidate_view, current_view, breadcrumb]
621
+ )
622
+
623
+ view_category_btn.click(
624
+ fn=show_category,
625
+ inputs=[category_selector],
626
+ outputs=[category_html, candidate_selector] +
627
+ [comp for pair in category_candidate_components for comp in [pair[0], pair[1]]] +
628
+ [dashboard_view, category_view, candidate_view, selected_category, current_view, breadcrumb]
629
+ )
630
+
631
+ sort_dropdown.change(
632
+ fn=update_category_sort,
633
+ inputs=[selected_category, sort_dropdown],
634
+ outputs=[category_html, candidate_selector] +
635
+ [comp for pair in category_candidate_components for comp in [pair[0], pair[1]]]
636
+ )
637
+
638
+ for i, (html, btn) in enumerate(top_candidate_components):
639
+ btn.click(
640
+ fn=make_view_candidate_handler(i, is_top=True),
641
+ outputs=[
642
+ breadcrumb, candidate_html_before, gauge_plot, model_comparison_plot, timeline_plot, candidate_html_after,
643
+ dashboard_view, category_view, candidate_view, selected_category
644
+ ]
645
+ )
646
+
647
+ for i, btn in enumerate(category_candidate_buttons):
648
+ btn.click(
649
+ fn=make_category_candidate_handler(i),
650
+ inputs=[selected_category],
651
+ outputs=[
652
+ breadcrumb, candidate_html_before, gauge_plot, model_comparison_plot, timeline_plot, candidate_html_after,
653
+ dashboard_view, category_view, candidate_view, selected_category
654
+ ]
655
+ )
656
+
657
+ candidate_selector.change(
658
+ fn=show_candidate,
659
+ inputs=[candidate_selector, selected_category],
660
+ outputs=[
661
+ breadcrumb, candidate_html_before, gauge_plot, model_comparison_plot, timeline_plot, candidate_html_after,
662
+ dashboard_view, category_view, candidate_view, selected_category
663
+ ]
664
+ )
665
+
666
+ back_to_dashboard_btn.click(
667
+ fn=show_dashboard,
668
+ outputs=[
669
+ exec_html, avg_time_display, time_dist_plot, quarterly_display, quarterly_plot, pipeline_plot, portfolio_plot,
670
+ dashboard_html, category_selector
671
+ ] +
672
+ [comp for pair in top_candidate_components for comp in [pair[0]]] +
673
+ [comp for pair in category_candidate_components for comp in [pair[0], pair[1]]] +
674
+ [dashboard_view, category_view, candidate_view, current_view, breadcrumb]
675
+ )
676
+
677
+ back_to_category_btn.click(
678
+ fn=show_category,
679
+ inputs=[selected_category],
680
+ outputs=[category_html, candidate_selector] +
681
+ [comp for pair in category_candidate_components for comp in [pair[0], pair[1]]] +
682
+ [dashboard_view, category_view, candidate_view, selected_category, current_view, breadcrumb]
683
+ )
684
+
685
+ return demo
686
+
687
+ # ========================================
688
+ # MAIN
689
+ # ========================================
690
+
691
+ if __name__ == "__main__":
692
+ print("\n" + "="*60)
693
+ print(f"🧬 {APP_NAME}")
694
+ print(f"Version: 3.4.0 - Clickable Card Overlay + UAB Green Primary Buttons")
695
+ print("="*60)
696
+ print(f"ML/DL Models Status: {' LOADED' if MODELS_AVAILABLE else ' NOT AVAILABLE'}")
697
+ if MODELS_AVAILABLE:
698
+ print(f"Available Diseases: {len(ml_components['le_disease'].classes_)}")
699
+ print(f"Available Targets: {len(ml_components['mlb'].classes_)}")
700
+ if drugs_df is not None:
701
+ print(f"Drugs Database: {len(drugs_df)} drugs loaded")
702
+ if diseases_df is not None:
703
+ print(f"Diseases Database: {len(diseases_df)} diseases loaded")
704
+ print(f"Disease ID Mappings: {len(DISEASE_ID_MAPPING)} SUD categories mapped")
705
+ print("="*60 + "\n")
706
+
707
+ demo = create_interface()
708
+ demo.launch()