JoeVonDahab commited on
Commit
d96163c
·
1 Parent(s): 1d12809

Rebuild Space as static no-GAT explorer (Ablation 2)

Browse files

Replace the broken Gradio app (Jinja2 unhashable-dict crash) with a static
front-end for the current 'No Drug Graphs' model. Data is served cross-origin
from the project's GitHub Pages so the Space and Pages share one source of truth.

.gitattributes CHANGED
@@ -1,35 +1,2 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
- *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz 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
 
1
+ *.html linguist-language=HTML
2
+ * text=auto eol=lf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
.gitignore DELETED
@@ -1,68 +0,0 @@
1
- # Ignore everything by default
2
-
3
-
4
- # But not these files:
5
- !.gitignore
6
-
7
- # Allow CSV files
8
- !*.csv
9
-
10
- # Allow Jupyter notebooks
11
- !*.ipynb
12
-
13
- # Allow Python files
14
- !*.py
15
-
16
- # Allow directories (so we can traverse into them)
17
- !*/
18
-
19
- # Ignore common large files even if they match above patterns
20
- *.pkl
21
- *.npy
22
- *.db
23
- *.xml
24
- *.h5
25
- *.hdf5
26
-
27
- # Ignore model checkpoints and weights
28
- *.pth
29
- *.pt
30
- *.ckpt
31
- *.safetensors
32
-
33
- # Ignore image outputs
34
- *.png
35
- *.jpg
36
- *.jpeg
37
- *.gif
38
- *.svg
39
-
40
- # Ignore compressed files
41
- *.zip
42
- *.tar
43
- *.gz
44
- *.rar
45
-
46
- # Ignore Python cache
47
- __pycache__/
48
- *.pyc
49
- *.pyo
50
- *.pyd
51
- .Python
52
-
53
- # Ignore Jupyter checkpoints
54
- .ipynb_checkpoints/
55
-
56
- # Ignore environment files
57
- .env
58
- .venv
59
- env/
60
- venv/
61
- ENV/
62
-
63
- # Ignore IDE files
64
- .vscode/
65
- .idea/
66
- *.swp
67
- *.swo
68
- *~
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
APP_GUIDE.md DELETED
@@ -1,277 +0,0 @@
1
- # 🚀 Gradio App Quick Start Guide
2
-
3
- ## What I Created
4
-
5
- I've built a **fully interactive Gradio web app** for your Pharmacology Knowledge Graph that includes:
6
-
7
- ✅ **Drug search functionality** - Search by name or ChEMBL ID
8
- ✅ **Known interactions display** - View verified drug-target and drug-effect relationships
9
- ✅ **AI predictions** - See novel targets and therapeutic uses predicted by your model
10
- ✅ **Interactive network visualization** - Beautiful Plotly graph showing drug mechanisms
11
- ✅ **Ready for Hugging Face deployment** - One-click hosting on HF Spaces
12
-
13
- ---
14
-
15
- ## 📁 Files Created
16
-
17
- | File | Purpose |
18
- |------|---------|
19
- | `app.py` | Main Gradio application (500+ lines) |
20
- | `requirements_app.txt` | Python dependencies for the app |
21
- | `run_app.sh` | Local testing script |
22
- | `DEPLOYMENT.md` | Step-by-step HF Spaces deployment guide |
23
- | `SPACE_README.md` | README for your Hugging Face Space |
24
-
25
- ---
26
-
27
- ## 🎮 How to Use It
28
-
29
- ### Option 1: Test Locally (Recommended First)
30
-
31
- ```bash
32
- # Run the app on your machine
33
- ./run_app.sh
34
-
35
- # Or manually:
36
- python app.py
37
- ```
38
-
39
- Then open: **http://localhost:7860**
40
-
41
- ### Option 2: Deploy to Hugging Face Spaces
42
-
43
- Follow the guide in `DEPLOYMENT.md`. Summary:
44
-
45
- 1. **Create Space** on huggingface.co/spaces
46
- 2. **Upload files:**
47
- - `app.py`
48
- - `requirements_app.txt` → rename to `requirements.txt`
49
- - All CSV files (drug_nodes, protein_nodes, etc.)
50
- - All NPY files (graph_embeddings, node_to_idx)
51
- 3. **Wait 2-3 minutes** for build
52
- 4. **Share your link!** `https://huggingface.co/spaces/YOUR_USERNAME/pharmacology-knowledge-graph`
53
-
54
- ---
55
-
56
- ## 🎨 App Features
57
-
58
- ### 1. Drug Search
59
- - Type any drug name (e.g., "Morphine", "Aspirin")
60
- - Or use ChEMBL ID (e.g., "CHEMBL70")
61
- - Get auto-suggestions as you type
62
-
63
- ### 2. Information Panels
64
-
65
- **Left Side:**
66
- - Drug basic info (name, ChEMBL ID, SMILES)
67
- - Known protein targets with binding affinity (pChEMBL)
68
- - Known clinical effects (indications)
69
-
70
- **Right Side:**
71
- - **Predicted novel targets** (drug repurposing opportunities)
72
- - **Predicted novel effects** (new therapeutic uses)
73
- - Confidence scores and similarity metrics
74
-
75
- ### 3. Interactive Network Graph
76
-
77
- Shows your drug as the **center node** with:
78
- - 🔵 **Blue nodes** = Known protein targets (solid edges)
79
- - 🟢 **Green nodes** = Predicted targets (dashed edges)
80
- - 🟡 **Yellow nodes** = Known effects (solid edges)
81
- - 🟨 **Light yellow nodes** = Predicted effects (dashed edges)
82
-
83
- **Controls:**
84
- - Toggle known/predicted interactions on/off
85
- - Adjust number of nodes displayed (10-50)
86
- - Hover over nodes for details
87
- - Zoom/pan the graph
88
-
89
- ---
90
-
91
- ## 📊 Example Queries to Try
92
-
93
- | Drug | What You'll See |
94
- |------|----------------|
95
- | **Morphine** | Opioid receptors (μ, δ, κ), analgesic effects, similar drugs like Fentanyl |
96
- | **Aspirin** | COX-1/COX-2 inhibition, anti-inflammatory effects, cardiovascular uses |
97
- | **Talazoparib** | PARP1/2 targets + **predicted** PARP3/4 homologs (novel finding!) |
98
- | **Metformin** | AMPK activation, diabetes treatment, **predicted** anti-aging effects |
99
- | **Rivaroxaban** | Known anticoagulation + **predicted** myocardial infarction prevention |
100
-
101
- ---
102
-
103
- ## 🏗️ Technical Architecture
104
-
105
- ```
106
- User Input (Drug Name)
107
-
108
- [Search Function] → Find drug in database
109
-
110
- [Embedding Lookup] → Get drug's 128-dim vector
111
-
112
- [Similarity Computation] → Cosine similarity to all proteins/effects
113
-
114
- [Ranking & Filtering] → Top-K predictions, remove known interactions
115
-
116
- [Network Builder] → Create interactive Plotly graph
117
-
118
- Display Results
119
- ```
120
-
121
- **Key Components:**
122
-
123
- 1. **Data Loading** (startup):
124
- - CSV files → Pandas DataFrames
125
- - NPY files → NumPy arrays (embeddings)
126
- - Cached in memory for fast access
127
-
128
- 2. **Search Engine**:
129
- - Fuzzy matching on drug names
130
- - ChEMBL ID exact matching
131
- - Returns top 20 matches
132
-
133
- 3. **Prediction Engine**:
134
- - Cosine similarity: `cos(drug_emb, target_emb)`
135
- - Threshold filtering: High (>0.5), Medium (>0.45), Low
136
- - Excludes known interactions
137
-
138
- 4. **Visualization**:
139
- - NetworkX for graph layout (spring layout)
140
- - Plotly for interactive rendering
141
- - Color-coded by node type and known/predicted status
142
-
143
- ---
144
-
145
- ## 🎯 Deployment Checklist
146
-
147
- ### Pre-Deployment (Do This First)
148
-
149
- - [ ] Test app locally: `./run_app.sh`
150
- - [ ] Try 5-10 different drugs
151
- - [ ] Check network visualization works
152
- - [ ] Verify predictions make sense
153
-
154
- ### Hugging Face Setup
155
-
156
- - [ ] Create HF account (if needed)
157
- - [ ] Create new Space
158
- - [ ] Choose "Gradio" SDK
159
- - [ ] Select CPU basic (free tier)
160
-
161
- ### File Upload
162
-
163
- - [ ] Upload `app.py`
164
- - [ ] Rename `requirements_app.txt` → `requirements.txt` and upload
165
- - [ ] Upload all CSV files:
166
- - [ ] `drug_nodes.csv`
167
- - [ ] `protein_nodes_with_embeddings.csv`
168
- - [ ] `drug_effects.csv`
169
- - [ ] `drugs_interactions.csv`
170
- - [ ] Upload NPY files:
171
- - [ ] `graph_embeddings.npy`
172
- - [ ] `node_to_idx.npy`
173
- - [ ] Use `SPACE_README.md` content for Space README
174
-
175
- ### Post-Deployment
176
-
177
- - [ ] Wait for build (check logs)
178
- - [ ] Test live app
179
- - [ ] Share link on social media
180
- - [ ] Add to competition submission
181
-
182
- ---
183
-
184
- ## 💡 Pro Tips
185
-
186
- ### For Competitions/Demos
187
-
188
- 1. **Prepare example queries** - Have 3-5 drugs ready to show during demo
189
- 2. **Highlight novel predictions** - Point out predicted interactions not in training data
190
- 3. **Show validation** - Mention the ~90% precision rate
191
- 4. **Explain the network** - Walk through how to interpret the visualization
192
-
193
- ### For Presentations
194
-
195
- **30-second pitch:**
196
- > "This app lets you explore how drugs work using AI. Type any drug name, and you'll see known targets plus AI-predicted new uses. The network shows everything visually. We trained it on 800 drugs and validated 90% accuracy on predictions."
197
-
198
- **Key talking points:**
199
- - Novel approach: Learns from drug structure + protein sequence
200
- - Real data: 800 FDA drugs, 200 proteins, 400 effects
201
- - Practical use: Drug repurposing, target discovery, safety prediction
202
- - Validated: 90% of top predictions are biologically coherent
203
-
204
- ### For Further Development
205
-
206
- Want to enhance it? Easy additions:
207
-
208
- ```python
209
- # 1. Add SMILES input for novel molecules
210
- def predict_from_smiles(smiles_string):
211
- # Use your Ridge regression model
212
- # Return predictions
213
-
214
- # 2. Export results to CSV
215
- def export_predictions(drug_name):
216
- # Generate downloadable file
217
- return gr.File(...)
218
-
219
- # 3. Batch analysis
220
- def analyze_multiple_drugs(drug_list):
221
- # Loop and aggregate results
222
- ```
223
-
224
- ---
225
-
226
- ## 🐛 Troubleshooting
227
-
228
- ### "Module not found" error
229
- ```bash
230
- # Install missing package
231
- uv pip install <package_name>
232
- ```
233
-
234
- ### "File not found" error
235
- ```bash
236
- # Check all CSV/NPY files are in same directory as app.py
237
- ls *.csv *.npy
238
- ```
239
-
240
- ### Slow performance
241
- - Predictions are cached after first run
242
- - Consider pre-computing all predictions (add CSV files)
243
- - Hugging Face Spaces: upgrade to CPU upgrade ($0.03/hr)
244
-
245
- ### Network visualization not showing
246
- - Check Plotly is installed: `uv pip install plotly`
247
- - Try reducing max_nodes in settings
248
-
249
- ---
250
-
251
- ## 📈 Next Steps
252
-
253
- 1. **Test locally** → Run `./run_app.sh` and try it out
254
- 2. **Deploy to HF** → Follow `DEPLOYMENT.md` guide
255
- 3. **Share** → Get the public URL and share widely
256
- 4. **Iterate** → Gather feedback, add features
257
-
258
- ---
259
-
260
- ## 🎉 You're Ready!
261
-
262
- You now have a **professional, interactive web app** that:
263
- - ✅ Showcases your research
264
- - ✅ Is easy to use (no code required for users)
265
- - ✅ Deploys with one click
266
- - ✅ Looks impressive in competitions/demos
267
-
268
- **Questions?** Check:
269
- - `DEPLOYMENT.md` for HF Spaces setup
270
- - `app.py` comments for code details
271
- - GitHub issues for community support
272
-
273
- ---
274
-
275
- **Good luck with your competition! 🚀**
276
-
277
- *P.S. - Once deployed, share the link! People love interactive ML demos.*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
DEPLOYMENT.md DELETED
@@ -1,221 +0,0 @@
1
- # Hugging Face Space Deployment Guide
2
-
3
- ## 🚀 Deploy to Hugging Face Spaces
4
-
5
- ### Step 1: Create a New Space
6
-
7
- 1. Go to [Hugging Face Spaces](https://huggingface.co/spaces)
8
- 2. Click "Create new Space"
9
- 3. Choose:
10
- - **Space name:** `pharmacology-knowledge-graph`
11
- - **License:** MIT
12
- - **Space SDK:** Gradio
13
- - **Space hardware:** CPU basic (free tier works fine)
14
-
15
- ### Step 2: Upload Required Files
16
-
17
- Upload these files to your Space:
18
-
19
- **Required files:**
20
- ```
21
- app.py # Main Gradio app
22
- requirements_app.txt # Python dependencies (rename to requirements.txt)
23
- drug_nodes.csv # Drug metadata
24
- protein_nodes_with_embeddings.csv # Protein data
25
- drug_effects.csv # Clinical effects
26
- drugs_interactions.csv # Known drug-protein interactions
27
- graph_embeddings.npy # Trained embeddings
28
- node_to_idx.npy # Node index mapping
29
- top_50_predicted_drug_protein.csv # Pre-computed predictions (optional)
30
- top_50_predicted_drug_effects.csv # Pre-computed predictions (optional)
31
- ```
32
-
33
- **File structure on Hugging Face:**
34
- ```
35
- your-space/
36
- ├── app.py
37
- ├── requirements.txt # (rename requirements_app.txt)
38
- ├── README.md # Space description
39
- ├── drug_nodes.csv
40
- ├── protein_nodes_with_embeddings.csv
41
- ├── drug_effects.csv
42
- ├── drugs_interactions.csv
43
- ├── graph_embeddings.npy
44
- ├── node_to_idx.npy
45
- ├── top_50_predicted_drug_protein.csv
46
- └── top_50_predicted_drug_effects.csv
47
- ```
48
-
49
- ### Step 3: Create Space README.md
50
-
51
- Create a `README.md` in your Space with this content:
52
-
53
- ```markdown
54
- ---
55
- title: Pharmacology Knowledge Graph Explorer
56
- emoji: 💊
57
- colorFrom: blue
58
- colorTo: green
59
- sdk: gradio
60
- sdk_version: 4.44.0
61
- app_file: app.py
62
- pinned: false
63
- license: mit
64
- ---
65
-
66
- # 💊 Pharmacology Knowledge Graph Explorer
67
-
68
- Explore drug-target-effect relationships using AI-powered predictions from a TransE knowledge graph model.
69
-
70
- ## Features
71
-
72
- - 🔍 Search 800+ FDA-approved drugs
73
- - 🎯 View known and predicted protein targets
74
- - 💉 Discover potential therapeutic uses (drug repurposing)
75
- - 🕸️ Interactive network visualization
76
-
77
- ## How It Works
78
-
79
- This app uses a **TransE knowledge graph embedding model** trained on:
80
- - 800+ FDA-approved drugs (from ChEMBL)
81
- - 200+ human protein targets (with ESM-2 embeddings)
82
- - 400+ clinical effects and indications
83
-
84
- **Prediction method:** Cosine similarity in learned embedding space
85
- **Model performance:** ~90% precision on top-50 predictions
86
-
87
- ## Example Queries
88
-
89
- Try searching for:
90
- - **Morphine** - See opioid receptor targets and analgesic effects
91
- - **Aspirin** - COX inhibition and cardiovascular effects
92
- - **Metformin** - Diabetes and potential repurposing candidates
93
-
94
- ## Citation
95
-
96
- ```bibtex
97
- @software{pharmacology_graph_2025,
98
- author = {Joe VonDahab},
99
- title = {Pharmacology Knowledge Graph: Drug-Target-Effect Prediction},
100
- year = {2025},
101
- url = {https://github.com/JoeVonDahab/pharmacology-graph}
102
- }
103
- ```
104
-
105
- ## Disclaimer
106
-
107
- This is a research tool for exploratory analysis only. Predictions should be validated experimentally. Not for clinical use.
108
- ```
109
-
110
- ### Step 4: File Preparation Commands
111
-
112
- Run these commands in your project directory:
113
-
114
- ```bash
115
- # 1. Copy app requirements (rename for HF)
116
- cp requirements_app.txt requirements.txt
117
-
118
- # 2. Verify all data files exist
119
- ls -lh *.csv *.npy
120
-
121
- # Expected files:
122
- # - drug_nodes.csv (~200KB)
123
- # - protein_nodes_with_embeddings.csv (~500KB)
124
- # - drug_effects.csv (~300KB)
125
- # - drugs_interactions.csv (~2MB)
126
- # - graph_embeddings.npy (~700KB)
127
- # - node_to_idx.npy (~50KB)
128
- ```
129
-
130
- ### Step 5: Upload to Hugging Face
131
-
132
- **Option A: Web Upload**
133
-
134
- 1. Go to your Space's Files tab
135
- 2. Click "Add file" → "Upload files"
136
- 3. Drag and drop all files
137
- 4. Commit changes
138
-
139
- **Option B: Git Upload**
140
-
141
- ```bash
142
- # Clone your space
143
- git clone https://huggingface.co/spaces/YOUR_USERNAME/pharmacology-knowledge-graph
144
- cd pharmacology-knowledge-graph
145
-
146
- # Copy files
147
- cp /path/to/pharmacology-graph/app.py .
148
- cp /path/to/pharmacology-graph/requirements_app.txt requirements.txt
149
- cp /path/to/pharmacology-graph/*.csv .
150
- cp /path/to/pharmacology-graph/*.npy .
151
-
152
- # Commit and push
153
- git add .
154
- git commit -m "Initial app deployment"
155
- git push
156
- ```
157
-
158
- ### Step 6: Monitor Deployment
159
-
160
- 1. The Space will automatically build (takes ~2-3 minutes)
161
- 2. Check the build logs for errors
162
- 3. Once running, test the app with example drugs
163
-
164
- ### Step 7: Optional Enhancements
165
-
166
- **Upgrade to GPU (for faster predictions):**
167
- - Settings → Hardware → Upgrade to T4 small ($0.60/hour)
168
- - Useful if computing predictions on-the-fly for new molecules
169
-
170
- **Enable persistence:**
171
- - Add a `cache/` directory for storing results
172
- - Set `GRADIO_CACHE_EXAMPLES=True` in Space settings
173
-
174
- **Add analytics:**
175
- ```python
176
- # In app.py, add Hugging Face analytics
177
- import os
178
- from huggingface_hub import HfApi
179
-
180
- # Track usage
181
- api = HfApi()
182
- ```
183
-
184
- ### Troubleshooting
185
-
186
- **"File not found" errors:**
187
- - Make sure all CSV and NPY files are in the root directory
188
- - Check file names match exactly (case-sensitive)
189
-
190
- **Memory errors:**
191
- - If embeddings are too large, upgrade to "CPU upgrade" ($0.03/hour)
192
- - Or pre-compute all predictions and use lookup tables
193
-
194
- **Slow loading:**
195
- - Add caching: `@st.cache_data` (Streamlit) or `gr.State()` (Gradio)
196
- - Pre-load data in global scope (already done in `app.py`)
197
-
198
- ### Cost Estimate
199
-
200
- **Free tier (CPU basic):**
201
- - ✅ Sufficient for this app
202
- - 2 vCPU, 16GB RAM
203
- - Always-on
204
-
205
- **Paid tier (if needed):**
206
- - CPU upgrade: $0.03/hour (~$22/month)
207
- - T4 GPU: $0.60/hour (only if doing real-time SMILES predictions)
208
-
209
- ---
210
-
211
- ## 🎉 You're Done!
212
-
213
- Your app should now be live at:
214
- `https://huggingface.co/spaces/YOUR_USERNAME/pharmacology-knowledge-graph`
215
-
216
- Share it with:
217
- - Colleagues and collaborators
218
- - On Twitter/LinkedIn with #DrugDiscovery #AI
219
- - In your competition submission
220
-
221
- Good luck! 🚀
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
FILES.md DELETED
@@ -1,214 +0,0 @@
1
- # File Manifest - Pharmacology Graph
2
-
3
- Quick reference for what each file does.
4
-
5
- ---
6
-
7
- ## 🚀 **ESSENTIAL FILES** (Keep These)
8
-
9
- ### Application Files
10
- - **`app.py`** - Main Gradio web application (604 lines)
11
- - **`requirements_app.txt`** - Python dependencies for the app
12
- - **`start_app.sh`** - Launch script (recommended)
13
- - **`test_app.py`** - Diagnostic test for data loading
14
-
15
- ### Data Files (Required)
16
- - **`drug_nodes.csv`** - 3,127 approved drugs with SMILES structures
17
- - **`protein_nodes_with_embeddings.csv`** - 1,156 protein targets
18
- - **`drug_effects.csv`** - 8,312 clinical effects/indications
19
- - **`drugs_interactions.csv`** - 11,703 known drug-protein interactions
20
- - **`graph_embeddings.npy`** - Trained 128-dim TransE embeddings (5,201 nodes)
21
- - **`node_to_idx.npy`** - Node ID to embedding index mapping
22
- - **`top_50_predicted_drug_protein.csv`** - Top 50 predicted drug-target pairs
23
- - **`top_50_predicted_drug_effects.csv`** - Top 50 predicted drug-effect pairs
24
-
25
- ### Documentation
26
- - **`README.md`** - Project overview, results, and citations
27
- - **`SETUP.md`** - Complete setup guide (START HERE!)
28
- - **`DEPLOYMENT.md`** - Guide for deploying to Hugging Face Spaces
29
- - **`APP_GUIDE.md`** - User guide for the web application
30
-
31
- ---
32
-
33
- ## 🔬 **DEVELOPMENT FILES** (Optional)
34
-
35
- ### Research Notebook
36
- - **`code.ipynb`** - Main Jupyter notebook with full pipeline:
37
- - Data extraction from ChEMBL
38
- - ESM-2 protein embedding generation (~30 min GPU)
39
- - TransE graph model training (100 epochs)
40
- - Link prediction and validation
41
-
42
- **Note**: Only needed if you want to retrain the model or explore the data processing pipeline.
43
-
44
- ### Full Dependencies
45
- - **`requirements.txt`** - Complete dependencies (includes transformers, torch, rdkit)
46
- - **Use this if**: You want to run `code.ipynb`
47
- - **Skip if**: You just want to run the app (use `requirements_app.txt` instead)
48
-
49
- ### ChEMBL Database
50
- - **`chembl_36/chembl_36_sqlite/chembl_36.db`** - Full ChEMBL 36 database (4.2GB)
51
- - **Needed for**: Running `code.ipynb` to extract fresh data
52
- - **Skip if**: You're using the pre-extracted CSV files
53
-
54
- ---
55
-
56
- ## 🗑️ **REMOVABLE FILES** (Can Delete)
57
-
58
- ### Duplicates/Old Versions
59
- - `run_app.sh` - Old launch script (use `start_app.sh` instead)
60
- - `APP_SUMMARY.md` - Duplicate of `APP_GUIDE.md`
61
- - `CHECKLIST.md` - Deployment checklist (one-time use)
62
- - `BUGFIX_SUMMARY.md` - Development notes about version fixes
63
-
64
- ### Testing Scripts
65
- - `test_search.py` - Manual testing guide (not automated)
66
-
67
- ### Intermediate Files (Can Regenerate)
68
- - `main.py` - Old/experimental code
69
- - `.python-version` - Python version pin (use pyproject.toml instead)
70
- - `*.png` - Visualization outputs (can regenerate from notebook)
71
- - `*.pkl` - Pickle serializations (can regenerate from CSV)
72
- - `drug_mechanism_filtered.csv` - Intermediate processing file
73
- - `drug_warnings.csv` - Intermediate processing file
74
- - `edges_drug_protein.csv` - Intermediate processing file
75
- - `proteins_for_embedding.csv` - Intermediate processing file
76
- - `top_50_predicted_drug_targets.csv` - Duplicate of `top_50_predicted_drug_protein.csv`
77
-
78
- **Run cleanup script**: `./cleanup.sh` to remove these automatically.
79
-
80
- ---
81
-
82
- ## 📏 **FILE SIZES**
83
-
84
- ### App Files (~10 MB total)
85
- ```
86
- drug_nodes.csv 700 KB
87
- protein_nodes_with_embeddings.csv 400 KB
88
- drug_effects.csv 800 KB
89
- drugs_interactions.csv 1.5 MB
90
- graph_embeddings.npy 5 MB
91
- node_to_idx.npy 50 KB
92
- top_50_predicted_*.csv 10 KB each
93
- app.py 50 KB
94
- ```
95
-
96
- ### Development Files (4.2 GB)
97
- ```
98
- chembl_36/chembl_36_sqlite/chembl_36.db 4.2 GB
99
- code.ipynb 500 KB
100
- ```
101
-
102
- ---
103
-
104
- ## 🎯 **WHAT YOU NEED FOR...**
105
-
106
- ### Running the App Only
107
- ```
108
- ✓ app.py
109
- ✓ requirements_app.txt
110
- ✓ start_app.sh (or test_app.py)
111
- ✓ All CSV files
112
- ✓ graph_embeddings.npy
113
- ✓ node_to_idx.npy
114
- ✓ README.md, SETUP.md (for reference)
115
- ```
116
- **Total**: ~10 MB
117
-
118
- ### Retraining the Model
119
- ```
120
- ✓ Everything from "Running the App"
121
- ✓ code.ipynb
122
- ✓ requirements.txt
123
- ✓ chembl_36/ directory (ChEMBL database)
124
- ```
125
- **Total**: ~4.2 GB
126
-
127
- ### Deploying to Hugging Face Spaces
128
- ```
129
- ✓ app.py
130
- ✓ All CSV files
131
- ✓ graph_embeddings.npy
132
- ✓ node_to_idx.npy
133
- ✓ requirements_app.txt → rename to requirements.txt
134
- ✓ SPACE_README.md → use as README.md
135
- ```
136
- **Total**: ~10 MB (HF Spaces free tier supports up to 50GB)
137
-
138
- ---
139
-
140
- ## 🧹 **CLEANUP COMMANDS**
141
-
142
- ### Remove all unnecessary files
143
- ```bash
144
- ./cleanup.sh
145
- ```
146
-
147
- ### Manual cleanup
148
- ```bash
149
- # Remove duplicate documentation
150
- rm -f BUGFIX_SUMMARY.md APP_SUMMARY.md CHECKLIST.md
151
-
152
- # Remove old scripts
153
- rm -f run_app.sh test_search.py main.py
154
-
155
- # Remove generated outputs
156
- rm -f *.png *.pkl
157
-
158
- # Remove intermediate CSV files
159
- rm -f drug_mechanism_filtered.csv drug_warnings.csv edges_drug_protein.csv proteins_for_embedding.csv
160
- ```
161
-
162
- ### Remove development files (if you don't need to retrain)
163
- ```bash
164
- # Remove notebook and database (WARNING: Large files!)
165
- rm -rf code.ipynb chembl_36/ requirements.txt
166
- ```
167
-
168
- ---
169
-
170
- ## 📦 **WHAT'S IN GIT**
171
-
172
- The `.gitignore` is configured to:
173
-
174
- **✅ Track:**
175
- - All Python files (`*.py`)
176
- - All CSV files (`*.csv`)
177
- - All Jupyter notebooks (`*.ipynb`)
178
- - Documentation (`*.md`)
179
- - Config files (`requirements*.txt`, `pyproject.toml`)
180
-
181
- **❌ Ignore:**
182
- - Large binary files (`*.npy`, `*.pkl`, `*.db`)
183
- - Images (`*.png`, `*.jpg`)
184
- - Python cache (`__pycache__/`, `*.pyc`)
185
- - Model checkpoints (`*.pth`, `*.pt`)
186
- - Compressed files (`*.zip`, `*.tar.gz`)
187
-
188
- **Why NPY files aren't tracked**: They're 5MB+ and can be regenerated from the notebook. Download them separately or run the notebook to create them.
189
-
190
- ---
191
-
192
- ## 🔄 **REGENERATING FILES**
193
-
194
- If you're missing `.npy` files or want to retrain:
195
-
196
- ```bash
197
- # Install full dependencies
198
- pip install -r requirements.txt
199
-
200
- # Open notebook
201
- jupyter notebook code.ipynb
202
-
203
- # Run all cells (takes ~40 minutes on GPU)
204
- # This will regenerate:
205
- # - All CSV files
206
- # - graph_embeddings.npy
207
- # - node_to_idx.npy
208
- # - Prediction CSVs
209
- ```
210
-
211
- ---
212
-
213
- **Last Updated**: October 10, 2025
214
- **Total Project Size**: 4.2 GB (with database) or 10 MB (app only)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,415 +1,29 @@
1
  ---
2
- title: Pharmacology Knowledge Graph
3
  emoji: 💊
4
  colorFrom: blue
5
  colorTo: purple
6
- sdk: gradio
7
- sdk_version: 4.44.1
8
- app_file: app.py
9
  pinned: false
10
  license: mit
11
- python_version: "3.10"
12
  ---
13
 
14
- # Pharmacology Knowledge Graph: Drug-Target-Effect Prediction
15
 
16
- A novel machine learning system that learns **pharmacology-aligned embeddings** by integrating chemical structures (SMILES), protein sequences (ESM-2), and clinical outcomes into a unified knowledge graph. The model predicts novel drug-target interactions and therapeutic indications through contrastive graph learning.
 
 
 
17
 
18
- **🚀 [Try the Interactive Demo](https://huggingface.co/spaces/JoeVonDahab/pharmacology-graph)** | **📖 [Full Setup Guide](SETUP.md)** | **🎓 [Research Notebook](code.ipynb)**
 
19
 
20
- ---
21
-
22
- ## Quick Start
23
-
24
- ```bash
25
- # 1. Clone the repository
26
- git clone https://github.com/JoeVonDahab/pharmacology-graph.git
27
- cd pharmacology-graph
28
-
29
- # 2. Install dependencies
30
- pip install -r requirements_app.txt
31
-
32
- # 3. Run the interactive app
33
- ./start_app.sh
34
- # Open http://localhost:7860 in your browser
35
- ```
36
-
37
- **Requirements**: Python 3.9+, 8GB RAM, 10MB disk space (app only)
38
-
39
- For complete setup instructions and troubleshooting, see **[SETUP.md](SETUP.md)**.
40
-
41
- ---
42
-
43
- ## 🎯 Project Overview
44
-
45
- This project builds an end-to-end pipeline that:
46
-
47
- 1. **Extracts pharmacological data** from ChEMBL database (approved drugs, protein targets, clinical effects)
48
- 2. **Generates molecular representations** using:
49
- - ESM-2 protein language models (2560-dim embeddings)
50
- - SMILES-based molecular fingerprints
51
- 3. **Trains a TransE graph embedding model** to align drugs, proteins, and clinical effects in a shared latent space
52
- 4. **Predicts novel interactions** using GPU-accelerated similarity search
53
-
54
- ### Key Innovation: Pharmacology-Aligned Embeddings
55
-
56
- Unlike traditional chemical similarity (fingerprints) or docking approaches, our model learns embeddings where **drugs cluster by functional mechanism** rather than just structural similarity. For example:
57
-
58
- - **Opioid analgesics** (Morphine, l) cluster together despite different structures
59
- - **Antivirals** (Acyclovir, Famciclovir) group by shared viral DNA polymerase targets
60
- - **Bronchodilators** (Tiotropium, Ipratropium) align based on muscarinic receptor activity
61
-
62
- ---
63
-
64
- ## 🏗️ Architecture
65
-
66
- ```
67
- ChEMBL Database
68
-
69
- [Data Extraction]
70
- ├── Approved Drugs (SMILES)
71
- ├── Protein Targets (sequences)
72
- └── Clinical Effects (indications)
73
-
74
- [Embedding Generation]
75
- ├── ESM-2 (facebook/esm2_t36_3B_UR50D) → Protein embeddings
76
- └── Morgan Fingerprints → Drug structure features
77
-
78
- [Knowledge Graph Construction]
79
- ├── Nodes: Drugs, Proteins, Effects
80
- └── Edges: binds_to, treats
81
-
82
- [TransE Training]
83
- └── 128-dim unified embedding space
84
-
85
- [Link Prediction]
86
- ├── Drug → Protein (novel targets)
87
- └── Drug → Effect (repurposing)
88
- ```
89
-
90
- ---
91
-
92
- ## 📊 Results
93
-
94
- ### Validation: Drug Clustering
95
-
96
- The model successfully groups drugs by pharmacological class:
97
-
98
- | Anchor Drug | Top Similar Drugs | Pharmacological Class |
99
- |-------------|-------------------|----------------------|
100
- | **Morphine** | l, Oxycodone, Hydromorphone | Opioid analgesics (μ-receptor) |
101
- | **Acyclovir** | Famciclovir, Penciclovir, Valacyclovir | Nucleoside antiviral (DNA polymerase) |
102
- | **Tiotropium** | Glycopyrronium, Ipratropium, Aclidinium | Anticholinergic bronchodilators (M3-receptor) |
103
- | **Miconazole** | Posaconazole, Ketoconazole | Azole antifungals (CYP51A1) |
104
-
105
- **Mean cosine similarity:**
106
- - Within therapeutic class: **0.72 ± 0.08**
107
- - Between classes: **0.31 ± 0.12**
108
-
109
- ### Top Predicted Drug-Target Interactions
110
-
111
- From **2.8M novel predictions**, top examples with biological validation:
112
-
113
- | Drug | Predicted Target | Similarity | Biological Rationale |
114
- |------|-----------------|------------|---------------------|
115
- | **Talazoparib** | Protein mono-ADP-ribosyltransferase (PARP3/4) | 0.60 | ✅ Known PARP1/2 inhibitor; homologous family members |
116
- | **Dasatinib** | Blk tyrosine kinase | 0.51 | ✅ Broad-spectrum Src-family kinase inhibitor |
117
- | **Imipramine** | α1D adrenergic receptor | 0.52 | ✅ Tricyclic with known adrenergic off-targets |
118
- | **Zonisamide** | Carbonic anhydrase 14 | 0.51 | ✅ Known CA inhibitory activity |
119
- | **Pipamazine** | Muscarinic M4 receptor | 0.54 | ✅ Phenothiazine with anticholinergic effects |
120
-
121
- ### Top Predicted Drug-Effect (Repurposing Candidates)
122
-
123
- | Drug | Predicted Indication | Similarity | Clinical Plausibility |
124
- |------|---------------------|------------|---------------------|
125
- | **Rivaroxaban** | Myocardial infarction (secondary prevention) | 0.54 | ✅ Anticoagulant; approved for post-MI use |
126
- | **Sertraline** | Panic disorder | 0.53 | ✅ FDA-approved indication |
127
- | **Rosuvastatin** | Dyslipidemias | 0.52 | ✅ Primary statin indication |
128
- | **Ozanimod** | Crohn's disease | 0.49 | ⚠️ Plausible (approved for ulcerative colitis) |
129
- | **Clopidogrel** | Pulmonary embolism | 0.49 | ⚠️ Antiplatelet; not first-line but mechanistically coherent |
130
-
131
- **Precision metrics:**
132
- - Top-50 predictions: **~90% pharmacologically coherent**
133
- - Mean similarity (novel predictions): **0.48 ± 0.05**
134
- - Baseline (random pairing): **0.23 ± 0.11**
135
-
136
- ---
137
-
138
- ## 🚀 Quick Start
139
-
140
- ### Requirements
141
-
142
- ```bash
143
- # Install dependencies with UV
144
- uv pip install -r requirements.txt
145
-
146
- # Core dependencies:
147
- - pandas
148
- - numpy
149
- - torch
150
- - transformers (ESM-2)
151
- - rdkit
152
- - networkx
153
- - scikit-learn
154
- - tqdm
155
- - matplotlib
156
- ```
157
-
158
- ### Data
159
-
160
- Download ChEMBL 36 SQLite database:
161
- ```bash
162
- # Place in: chembl_36/chembl_36_sqlite/chembl_36.db
163
- # Size: ~4.2 GB
164
- ```
165
-
166
- ### Run the Pipeline
167
-
168
- ```bash
169
- # Open the Jupyter notebook
170
- jupyter notebook code.ipynb
171
-
172
- # Or run as Python script (convert cells first)
173
- jupyter nbconvert --to script code.ipynb
174
- python code.py
175
- ```
176
-
177
- **Pipeline stages:**
178
-
179
- 1. **Data extraction** (cells 1-14): Query ChEMBL for drugs, targets, effects
180
- 2. **Protein embeddings** (cells 15-18): Generate ESM-2 embeddings (GPU recommended, ~30 min)
181
- 3. **Graph construction** (cells 19-35): Build NetworkX graph with nodes/edges
182
- 4. **TransE training** (cell 36): Train embedding model (100 epochs, ~15 min on GPU)
183
- 5. **Prediction** (cells 37-42): Generate novel drug-target and drug-effect predictions
184
- 6. **Visualization** (cells 43-45): t-SNE plots, neighbor analysis
185
-
186
- ---
187
-
188
- ## 📁 Project Structure
189
-
190
- ```
191
- pharmacology-graph/
192
- ├── code.ipynb # Main analysis notebook
193
- ├── README.md # This file
194
- ├── .gitignore # Git ignore rules
195
- ├── requirements.txt # Python dependencies (UV)
196
-
197
- ├── chembl_36/
198
- │ └── chembl_36_sqlite/
199
- │ └── chembl_36.db # ChEMBL database (not in git)
200
-
201
- ├── protein_nodes_with_embeddings.pkl # ESM-2 protein embeddings (not in git)
202
- ├── drug_nodes.pkl # Drug metadata (not in git)
203
- ├── drug_effects.pkl # Drug-indication mappings (not in git)
204
- ├── drug_protein_interactions.pkl # Known drug-target edges (not in git)
205
-
206
- ├── graph_embeddings.npy # Trained TransE embeddings (not in git)
207
- ├── node_to_idx.npy # Node index mapping (not in git)
208
-
209
- ├── top_50_predicted_drug_protein.csv # Novel target predictions
210
- ├── top_50_predicted_drug_effects.csv # Novel indication predictions
211
- └── drug_neighbors_visualization.png # t-SNE cluster plot (not in git)
212
- ```
213
-
214
- ---
215
-
216
- ## 🔬 Technical Details
217
-
218
- ### Model Architecture: TransE
219
-
220
- **TranslatingEmbeddings for Multi-Relational Graphs**
221
-
222
- For each edge `(head, relation, tail)`:
223
- - **Scoring function:** `f(h, r, t) = ||h + r - t||₂`
224
- - **Loss:** Margin-based ranking loss with negative sampling
225
-
226
- **Hyperparameters:**
227
- ```python
228
- EMBEDDING_DIM = 128
229
- LEARNING_RATE = 0.01
230
- EPOCHS = 100
231
- BATCH_SIZE = 32
232
- MARGIN = 1.0
233
- ```
234
-
235
- **Training stats:**
236
- - Nodes: ~1,400 (drugs: ~800, proteins: ~200, effects: ~400)
237
- - Edges: ~15,000 (drug-protein: ~12,000, drug-effect: ~3,000)
238
- - Training time: 15 minutes (NVIDIA GPU)
239
- - Final loss: ~0.15
240
-
241
- ### ESM-2 Protein Embeddings
242
-
243
- **Model:** `facebook/esm2_t36_3B_UR50D`
244
- - Parameters: 3B
245
- - Embedding dimension: 2560
246
- - Context length: 1024 amino acids
247
- - Mean pooling over sequence length
248
 
249
- **Processing:**
250
- - Batch size: 4 proteins
251
- - Total proteins: ~200
252
- - Compute time: ~30 minutes (GPU) / ~3 hours (CPU)
253
-
254
- ### Drug Representations
255
-
256
- **SMILES → Morgan Fingerprints**
257
- ```python
258
- radius = 2
259
- n_bits = 2048
260
- ```
261
-
262
- **Bridge to Graph Embeddings:**
263
- - Ridge regression: Fingerprint → TransE embedding
264
- - R² score: 0.67 (on training drugs)
265
- - Enables predictions for completely novel molecules
266
-
267
- ---
268
-
269
- ## 🧪 Validation Strategy
270
-
271
- ### 1. **Held-out Known Interactions**
272
-
273
- Split known drug-target edges:
274
- - Train: 80% (used for TransE)
275
- - Test: 20% (hidden during training)
276
-
277
- **Metrics:**
278
- - Recall@50: How many true targets appear in top-50 predictions?
279
- - Mean Reciprocal Rank (MRR)
280
- - AUROC for ranked predictions
281
-
282
- ### 2. **Time-based Split**
283
-
284
- - Train on: Drug approvals ≤ 2015
285
- - Test on: Approvals > 2015
286
- - Simulates prospective prediction
287
-
288
- ### 3. **Baseline Comparisons**
289
-
290
- | Method | Recall@50 | MRR | AUROC |
291
- |--------|-----------|-----|-------|
292
- | **Our Model (TransE)** | 0.68 | 0.42 | 0.83 |
293
- | ECFP Tanimoto (fingerprint) | 0.31 | 0.18 | 0.67 |
294
- | Random baseline | 0.02 | 0.01 | 0.50 |
295
-
296
- **Ablation studies:**
297
- - Without ESM-2 (random protein init): -0.15 AUROC
298
- - Without contrastive training: -0.11 AUROC
299
-
300
- ---
301
-
302
- ## 📈 Use Cases
303
-
304
- ### 1. **Drug Repurposing**
305
-
306
- Find new therapeutic uses for approved drugs:
307
-
308
- ```python
309
- # Example: Query novel indications for Aspirin
310
- drug_smiles = "CC(=O)Oc1ccccc1C(=O)O" # Aspirin
311
- predictions = predict_new_drug_embedding(drug_smiles, top_k=10)
312
-
313
- # Output: Predicted new effects beyond pain/inflammation
314
- # - Cardiovascular prevention (known)
315
- # - Colorectal cancer prevention (emerging evidence)
316
- ```
317
-
318
- ### 2. **Target Identification**
319
-
320
- Predict protein targets for experimental compounds:
321
-
322
- ```python
323
- # Novel kinase inhibitor candidate
324
- novel_smiles = "Cc1ccc(Nc2nccc(...)...)cc1"
325
- targets = predict_protein_targets(novel_smiles, top_k=20)
326
-
327
- # Helps prioritize biochemical assays
328
- ```
329
-
330
- ### 3. **Off-target Prediction**
331
-
332
- Identify safety liabilities early:
333
-
334
- ```python
335
- # Check for unintended receptor binding
336
- all_targets = predict_all_targets(drug_smiles, threshold=0.45)
337
- safety_flags = [t for t in all_targets if t in ['hERG', 'CYP3A4', 'Opioid']]
338
- ```
339
-
340
- ---
341
-
342
- ## 🎓 Scientific Contributions
343
-
344
- 1. **Cross-modal contrastive learning** for drug discovery
345
- - First work aligning SMILES + ESM-2 in shared space
346
-
347
- 2. **Pharmacology-aligned embeddings**
348
- - Cluster by mechanism, not just structure
349
- - Enables interpretable predictions
350
-
351
- 3. **Scalable graph-based prediction**
352
- - Handles multi-relational heterogeneous graphs
353
- - GPU-accelerated inference (~1M predictions/sec)
354
-
355
- 4. **Validated on real-world pharmacology**
356
- - Recovers known drug classes (opioids, antivirals, statins)
357
- - Predicts plausible novel targets with >80% precision
358
-
359
- ---
360
-
361
- ## 📝 Citation
362
-
363
- ```bibtex
364
- @software{pharmacology_graph_2025,
365
- author = {Joe VonDahab},
366
- title = {Pharmacology Knowledge Graph: Drug-Target-Effect Prediction},
367
- year = {2025},
368
- url = {https://github.com/JoeVonDahab/pharmacology-graph}
369
- }
370
- ```
371
-
372
- **Related work:**
373
- - **TransE:** Bordes et al., "Translating Embeddings for Modeling Multi-relational Data" (NeurIPS 2013)
374
- - **ESM-2:** Lin et al., "Evolutionary-scale prediction of atomic-level protein structure" (Science 2023)
375
- - **ChEMBL:** Gaulton et al., "The ChEMBL database in 2017" (Nucleic Acids Research 2017)
376
-
377
- ---
378
-
379
- ## 🤝 Contributing
380
-
381
- Contributions welcome! Areas for improvement:
382
-
383
- - [ ] Add attention-based graph neural network (GAT/RGCN)
384
- - [ ] Incorporate 3D protein structures (AlphaFold2)
385
- - [ ] Multi-task learning (toxicity + efficacy)
386
- - [ ] Temporal dynamics (drug resistance evolution)
387
- - [ ] Web interface (Streamlit/Gradio demo)
388
-
389
- ---
390
-
391
- ## 📄 License
392
-
393
- MIT License - see LICENSE file for details
394
-
395
- ---
396
-
397
- ## 🙏 Acknowledgments
398
-
399
- - **ChEMBL** for curated pharmacological data
400
- - **Meta AI** for ESM-2 protein language models
401
- - **RDKit** for cheminformatics tools
402
- - **PyTorch** ecosystem for deep learning infrastructure
403
-
404
- ---
405
-
406
- ## 📧 Contact
407
-
408
- **Author:** Youssef Abo-Dahab
409
- **Repository:** [github.com/JoeVonDahab/pharmacology-graph](https://github.com/JoeVonDahab/pharmacology-graph)
410
-
411
- For questions or collaboration: [create an issue](https://github.com/JoeVonDahab/pharmacology-graph/issues)
412
-
413
- ---
414
 
415
- *Last updated: October 2025*
 
1
  ---
2
+ title: Pharmacology Graph Explorer
3
  emoji: 💊
4
  colorFrom: blue
5
  colorTo: purple
6
+ sdk: static
7
+ app_file: index.html
 
8
  pinned: false
9
  license: mit
 
10
  ---
11
 
12
+ # Pharmacology Graph Explorer
13
 
14
+ Interactive explorer for the **Ablation 2 "No Drug Graphs"** model (~3.29M params) from
15
+ *pharmacology-graph* — learnable drug embeddings + ESM-2 protein representations + heterogeneous
16
+ GraphSAGE message passing. Removing the GAT drug-structure encoder *improved* drug–protein
17
+ prediction (PR-AUC 0.5631 → 0.5785) while cutting memory 5.30 GB → 353 MB.
18
 
19
+ Search a **drug** to see predicted targets & indications, or an **indication / protein** to see the
20
+ drugs most likely linked to it — each flagged *known* or *novel*.
21
 
22
+ A static front-end. Prediction data is served from the project's GitHub Pages
23
+ (<https://joevondahab.github.io/pharmacology-graph/>), so this Space and the Pages site share one
24
+ source of truth.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
+ - Code & notebooks: <https://github.com/JoeVonDahab/pharmacology-graph>
27
+ - Paper: <https://arxiv.org/abs/2603.01537>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
+ Predictions are model outputs for research exploration only — not clinical or experimental validation.
SETUP.md DELETED
@@ -1,351 +0,0 @@
1
- # Setup Guide - Pharmacology Knowledge Graph
2
-
3
- Complete guide for setting up and running the Pharmacology Graph Explorer on your local machine.
4
-
5
- ---
6
-
7
- ## 📋 Prerequisites
8
-
9
- - **Python**: 3.9 or higher
10
- - **RAM**: At least 8GB (16GB recommended for large datasets)
11
- - **Disk Space**: ~5GB for ChEMBL database and model files
12
-
13
- ---
14
-
15
- ## 🚀 Quick Start (3 Steps)
16
-
17
- ### 1. Clone the Repository
18
-
19
- ```bash
20
- git clone https://github.com/JoeVonDahab/pharmacology-graph.git
21
- cd pharmacology-graph
22
- ```
23
-
24
- ### 2. Install Dependencies
25
-
26
- **Option A: Using `uv` (Recommended - Fast)**
27
- ```bash
28
- # Install uv if you don't have it
29
- pip install uv
30
-
31
- # Install project dependencies
32
- uv pip install -r requirements_app.txt
33
- ```
34
-
35
- **Option B: Using `pip`**
36
- ```bash
37
- pip install -r requirements_app.txt
38
- ```
39
-
40
- **Critical Version Note**: Make sure you have:
41
- - `gradio>=4.44.0` (not 4.36.x)
42
- - `numpy<2.0` (NumPy 2.x breaks compatibility)
43
-
44
- ### 3. Run the App
45
-
46
- ```bash
47
- ./start_app.sh
48
- ```
49
-
50
- Or manually:
51
- ```bash
52
- python app.py
53
- ```
54
-
55
- Then open your browser to: **http://localhost:7860**
56
-
57
- ---
58
-
59
- ## 📦 What's Included
60
-
61
- ### Essential Files (Required to Run)
62
-
63
- | File | Purpose | Size |
64
- |------|---------|------|
65
- | `app.py` | Main Gradio web application | 604 lines |
66
- | `requirements_app.txt` | Python dependencies | - |
67
- | `start_app.sh` | Convenience launcher script | - |
68
-
69
- ### Data Files (Required to Run)
70
-
71
- All these CSV files are **required** for the app to work:
72
-
73
- | File | Description | Rows |
74
- |------|-------------|------|
75
- | `drug_nodes.csv` | Drug metadata (name, SMILES, ChEMBL ID) | 3,127 |
76
- | `protein_nodes_with_embeddings.csv` | Protein targets with ESM-2 features | 1,156 |
77
- | `drug_effects.csv` | Clinical effects and indications | 8,312 |
78
- | `drugs_interactions.csv` | Known drug-protein interactions | 11,703 |
79
- | `graph_embeddings.npy` | Trained TransE embeddings (128-dim) | 5,201 nodes |
80
- | `node_to_idx.npy` | Node ID mappings | - |
81
- | `top_50_predicted_drug_protein.csv` | Top predicted drug-target pairs | 50 |
82
- | `top_50_predicted_drug_effects.csv` | Top predicted drug-effect pairs | 50 |
83
-
84
- **Note**: The `.npy` files are NOT tracked in git (they're large). You need to generate them by running the notebook.
85
-
86
- ### Documentation Files
87
-
88
- | File | Purpose |
89
- |------|---------|
90
- | `README.md` | Project overview and results |
91
- | `DEPLOYMENT.md` | Guide for deploying to Hugging Face Spaces |
92
- | `APP_GUIDE.md` | User guide for the web application |
93
- | `BUGFIX_SUMMARY.md` | Recent bug fixes (version compatibility) |
94
-
95
- ### Development Files
96
-
97
- | File | Purpose |
98
- |------|---------|
99
- | `code.ipynb` | Main research notebook (data extraction, training, prediction) |
100
- | `requirements.txt` | Full dependencies for running the notebook |
101
- | `test_app.py` | Diagnostic test for app data loading |
102
- | `test_search.py` | Manual testing guide for search functionality |
103
-
104
- ---
105
-
106
- ## 🔄 Full Setup (If You Want to Retrain the Model)
107
-
108
- If you want to regenerate the embeddings and predictions from scratch:
109
-
110
- ### 1. Download ChEMBL Database
111
-
112
- ```bash
113
- # The ChEMBL 36 database is large (~4.2GB)
114
- # It's already in chembl_36/chembl_36_sqlite/chembl_36.db
115
- # If missing, download from: https://ftp.ebi.ac.uk/pub/databases/chembl/ChEMBLdb/latest/
116
- ```
117
-
118
- ### 2. Install Full Dependencies
119
-
120
- ```bash
121
- pip install -r requirements.txt
122
- ```
123
-
124
- This includes:
125
- - `transformers` (for ESM-2 protein embeddings)
126
- - `torch` (for TransE training)
127
- - `rdkit` (for molecular fingerprints)
128
- - `sqlite3` (for ChEMBL database queries)
129
-
130
- ### 3. Run the Notebook
131
-
132
- Open `code.ipynb` in Jupyter and run all cells:
133
-
134
- ```bash
135
- jupyter notebook code.ipynb
136
- ```
137
-
138
- This will:
139
- 1. Extract data from ChEMBL (drugs, proteins, effects)
140
- 2. Generate ESM-2 embeddings for proteins (~30 min on GPU)
141
- 3. Train TransE graph model (100 epochs, ~10 min)
142
- 4. Generate predictions using cosine similarity
143
- 5. Export all CSV and NPY files
144
-
145
- ---
146
-
147
- ## 🧪 Testing the App
148
-
149
- ### Quick Test
150
-
151
- ```bash
152
- python test_app.py
153
- ```
154
-
155
- This checks:
156
- - ✓ All data files are present
157
- - ✓ Libraries are correctly installed
158
- - ✓ Search function works
159
- - ✓ Data structure is valid
160
-
161
- ### Manual Testing
162
-
163
- 1. Start the app: `./start_app.sh`
164
- 2. Open: http://localhost:7860
165
- 3. Search for: "Aspirin", "Morphine", or "Imatinib"
166
- 4. Verify:
167
- - Dropdown shows matching results
168
- - Selecting a drug displays data tables
169
- - Network visualization renders correctly
170
- - No errors in console
171
-
172
- ---
173
-
174
- ## 🐛 Troubleshooting
175
-
176
- ### Port Already in Use
177
-
178
- ```bash
179
- # Kill existing app instance
180
- pkill -f "python.*app.py"
181
-
182
- # Or use a different port
183
- GRADIO_SERVER_PORT=7861 python app.py
184
- ```
185
-
186
- ### Import Errors
187
-
188
- ```bash
189
- # Check gradio version (must be >=4.44.0)
190
- pip show gradio
191
-
192
- # Check numpy version (must be <2.0)
193
- pip show numpy
194
-
195
- # Reinstall with correct versions
196
- pip install --force-reinstall "gradio>=4.44.0" "numpy<2.0"
197
- ```
198
-
199
- ### Missing Data Files
200
-
201
- If you see errors about missing CSV files:
202
- 1. Make sure you cloned the full repository
203
- 2. Run `code.ipynb` to regenerate data files
204
- 3. Check `.gitignore` - some large files aren't tracked
205
-
206
- ### Search Not Showing Results
207
-
208
- Make sure you:
209
- 1. Updated to Gradio 4.44+ (older versions have bugs)
210
- 2. Refreshed your browser after restarting the app
211
- 3. Check console for debug output (should show "Search 'xxx' found N results")
212
-
213
- ---
214
-
215
- ## 📊 Understanding the Output
216
-
217
- ### When You Search for a Drug
218
-
219
- **Example: Searching "Aspirin"**
220
-
221
- You'll see:
222
- 1. **Basic Info**: ChEMBL ID, SMILES structure
223
- 2. **Known Targets**: Proteins with measured pChEMBL values
224
- 3. **Predicted Targets**: Novel protein interactions (cosine similarity >0.7)
225
- 4. **Clinical Effects**: Known indications and phases
226
- 5. **Predicted Effects**: Potential repurposing opportunities
227
- 6. **Network Graph**: Interactive visualization of relationships
228
-
229
- ### Interpreting Predictions
230
-
231
- - **Similarity Score**: 0.0-1.0 (higher = more confident)
232
- - >0.8: Very high confidence
233
- - 0.7-0.8: High confidence
234
- - 0.6-0.7: Moderate confidence
235
- - <0.6: Low confidence (not shown)
236
-
237
- - **Confidence**: "Very High", "High", "Medium" based on similarity threshold
238
-
239
- ---
240
-
241
- ## 🚢 Deploying to Hugging Face Spaces
242
-
243
- See `DEPLOYMENT.md` for complete step-by-step guide.
244
-
245
- **Quick version:**
246
-
247
- 1. Create a Space at https://huggingface.co/spaces
248
- 2. Upload these files:
249
- - `app.py`
250
- - All CSV files
251
- - `graph_embeddings.npy` and `node_to_idx.npy`
252
- - Rename `requirements_app.txt` → `requirements.txt`
253
- - Use `SPACE_README.md` content for README.md
254
- 3. Wait 2-3 minutes for build
255
- 4. Your app will be live!
256
-
257
- ---
258
-
259
- ## 🗑️ Unnecessary Files (Can Be Deleted)
260
-
261
- **For end users who just want to run the app:**
262
-
263
- You can safely delete:
264
- - `BUGFIX_SUMMARY.md` (development notes)
265
- - `APP_SUMMARY.md` (duplicate of APP_GUIDE.md)
266
- - `CHECKLIST.md` (deployment checklist)
267
- - `run_app.sh` (use `start_app.sh` instead)
268
- - `test_search.py` (manual testing guide, not needed if app works)
269
- - `requirements.txt` (only needed for notebook, use `requirements_app.txt`)
270
-
271
- **If you're NOT retraining the model:**
272
- - `code.ipynb` (the notebook)
273
- - `chembl_36/` directory (large database)
274
- - `full database.xml` (if present)
275
-
276
- **Keep these minimal files:**
277
- ```
278
- pharmacology-graph/
279
- ├── app.py
280
- ├── requirements_app.txt
281
- ├── start_app.sh
282
- ├── test_app.py
283
- ├── README.md
284
- ├── DEPLOYMENT.md
285
- ├── APP_GUIDE.md
286
- ├── *.csv (all CSV files)
287
- ├── graph_embeddings.npy
288
- └── node_to_idx.npy
289
- ```
290
-
291
- ---
292
-
293
- ## 📝 File Size Reference
294
-
295
- ```
296
- drug_nodes.csv ~700 KB
297
- protein_nodes_with_embeddings.csv ~400 KB
298
- drug_effects.csv ~800 KB
299
- drugs_interactions.csv ~1.5 MB
300
- graph_embeddings.npy ~5 MB
301
- node_to_idx.npy ~50 KB
302
- top_50_predicted_*.csv ~10 KB each
303
- ```
304
-
305
- **Total app files**: ~10 MB
306
- **With ChEMBL database**: ~4.2 GB
307
-
308
- ---
309
-
310
- ## 🤝 Contributing
311
-
312
- If you want to improve the project:
313
-
314
- 1. Fork the repository
315
- 2. Run the full notebook to understand the pipeline
316
- 3. Make changes (better predictions, UI improvements, etc.)
317
- 4. Test with `python test_app.py`
318
- 5. Submit a pull request
319
-
320
- ---
321
-
322
- ## 📚 Additional Resources
323
-
324
- - **ChEMBL Database**: https://www.ebi.ac.uk/chembl/
325
- - **ESM-2 Model**: https://github.com/facebookresearch/esm
326
- - **TransE Paper**: "Translating Embeddings for Modeling Multi-relational Data" (Bordes et al., 2013)
327
- - **Gradio Docs**: https://gradio.app/docs/
328
-
329
- ---
330
-
331
- ## ⚖️ License
332
-
333
- This project uses publicly available ChEMBL data (CC BY-SA 3.0).
334
- Model and code are provided as-is for research purposes only.
335
-
336
- **Not for clinical use.**
337
-
338
- ---
339
-
340
- ## 📧 Support
341
-
342
- Issues? Questions?
343
- - Open an issue: https://github.com/JoeVonDahab/pharmacology-graph/issues
344
- - Check existing documentation: README.md, APP_GUIDE.md, DEPLOYMENT.md
345
-
346
- ---
347
-
348
- **Last Updated**: October 10, 2025
349
- **Version**: 1.0.0
350
- **Python**: 3.9+
351
- **Gradio**: 4.44.1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
SPACE_README.md DELETED
@@ -1,157 +0,0 @@
1
- ---
2
- title: Pharmacology Knowledge Graph Explorer
3
- emoji: 💊
4
- colorFrom: blue
5
- colorTo: green
6
- sdk: gradio
7
- sdk_version: 4.44.0
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- ---
12
-
13
- # 💊 Pharmacology Knowledge Graph Explorer
14
-
15
- **Explore drug-target-effect relationships using AI-powered predictions**
16
-
17
- ## 🎯 What is this?
18
-
19
- An interactive web app that lets you explore:
20
- - **Known interactions** between drugs and protein targets
21
- - **Predicted novel targets** for drug repurposing
22
- - **Clinical effects** and therapeutic indications
23
- - **Interactive network visualizations** of drug mechanisms
24
-
25
- ## 🧬 How It Works
26
-
27
- This app uses a **TransE knowledge graph embedding model** trained on:
28
- - **800+ FDA-approved drugs** from ChEMBL database
29
- - **200+ human protein targets** with ESM-2 sequence embeddings
30
- - **400+ clinical effects** and disease indications
31
-
32
- The model learns a unified embedding space where:
33
- - Drugs with similar mechanisms cluster together
34
- - Predictions are based on cosine similarity in latent space
35
- - Novel drug-target pairs are ranked by confidence
36
-
37
- ## 🔍 Example Queries
38
-
39
- Try searching for these drugs to see interesting results:
40
-
41
- | Drug | What you'll see |
42
- |------|----------------|
43
- | **Morphine** | Opioid receptor targets, analgesic effects, similar opioids (Fentanyl, Oxycodone) |
44
- | **Aspirin** | COX enzyme inhibition, anti-inflammatory effects, cardiovascular prevention |
45
- | **Metformin** | Diabetes targets, metabolic effects, potential repurposing for cancer/aging |
46
- | **Ibuprofen** | COX-1/COX-2 targets, NSAID effects, similar drugs (Naproxen, Diclofenac) |
47
- | **Talazoparib** | PARP family targets, cancer indications, predicted PARP homologs |
48
-
49
- ## 📊 Model Performance
50
-
51
- **Validation metrics:**
52
- - **Precision@50:** ~90% pharmacologically coherent predictions
53
- - **Mean similarity (top predictions):** 0.48-0.60
54
- - **Baseline (random):** 0.23
55
-
56
- **Key achievements:**
57
- - ✅ Correctly clusters drugs by therapeutic class (e.g., opioids, antivirals, statins)
58
- - ✅ Recovers known drug-target relationships with high accuracy
59
- - ✅ Predicts plausible novel targets for experimental validation
60
-
61
- ## 🕸️ Network Visualization Features
62
-
63
- The interactive graph shows:
64
- - 🔴 **Central drug node** (red)
65
- - 🔵 **Known protein targets** (blue, solid edges)
66
- - 🟢 **Predicted novel targets** (green, dashed edges)
67
- - 🟡 **Known clinical effects** (yellow, solid edges)
68
- - 🟨 **Predicted effects** (light yellow, dashed edges)
69
-
70
- **Controls:**
71
- - Toggle known/predicted interactions
72
- - Adjust max nodes displayed
73
- - Hover over nodes for details
74
-
75
- ## 🚀 Use Cases
76
-
77
- 1. **Drug Repurposing:** Find new therapeutic uses for existing drugs
78
- 2. **Target Discovery:** Identify potential protein targets for lead compounds
79
- 3. **Safety Assessment:** Predict off-target effects and side effects
80
- 4. **Mechanism Exploration:** Understand drug action through network context
81
-
82
- ## 📖 Citation
83
-
84
- If you use this tool in your research, please cite:
85
-
86
- ```bibtex
87
- @software{pharmacology_graph_2025,
88
- author = {Joe VonDahab},
89
- title = {Pharmacology Knowledge Graph: Drug-Target-Effect Prediction},
90
- year = {2025},
91
- url = {https://github.com/JoeVonDahab/pharmacology-graph},
92
- note = {Hugging Face Space: https://huggingface.co/spaces/YOUR_USERNAME/pharmacology-knowledge-graph}
93
- }
94
- ```
95
-
96
- ## 🔗 Links
97
-
98
- - **GitHub Repository:** [pharmacology-graph](https://github.com/JoeVonDahab/pharmacology-graph)
99
- - **Paper/Blog:** *(Coming soon)*
100
- - **Dataset:** [ChEMBL 36](https://www.ebi.ac.uk/chembl/)
101
- - **Protein Model:** [ESM-2 (Meta AI)](https://github.com/facebookresearch/esm)
102
-
103
- ## ⚠️ Disclaimer
104
-
105
- **This is a research tool for exploratory analysis only.**
106
-
107
- - Predictions are computational and require experimental validation
108
- - Not intended for clinical decision-making or medical diagnosis
109
- - Drug repurposing candidates need rigorous testing before clinical use
110
- - Always consult scientific literature and regulatory databases
111
-
112
- ## 🛠️ Technical Details
113
-
114
- **Model Architecture:**
115
- - **Graph embedding:** TransE (Translation-based)
116
- - **Embedding dimension:** 128
117
- - **Protein featurization:** ESM-2 (2560-dim) → mean pooling
118
- - **Drug featurization:** Morgan fingerprints (2048-bit)
119
-
120
- **Training:**
121
- - Epochs: 100
122
- - Learning rate: 0.01
123
- - Negative sampling: 1:1 ratio
124
- - Margin loss: 1.0
125
-
126
- **Data sources:**
127
- - ChEMBL 36 (drugs, targets, indications)
128
- - UniProt (protein sequences)
129
- - MeSH (clinical effects taxonomy)
130
-
131
- ## 💡 Future Enhancements
132
-
133
- Planned features:
134
- - [ ] SMILES input for novel molecules
135
- - [ ] 3D protein structure integration (AlphaFold2)
136
- - [ ] Multi-task learning (toxicity + efficacy)
137
- - [ ] Batch analysis and export
138
- - [ ] API endpoint for programmatic access
139
-
140
- ## 🤝 Contributing
141
-
142
- Found a bug or have a feature request?
143
- - Open an issue on [GitHub](https://github.com/JoeVonDahab/pharmacology-graph/issues)
144
- - Submit a pull request
145
- - Contact: [create an issue](https://github.com/JoeVonDahab/pharmacology-graph/issues)
146
-
147
- ## 📜 License
148
-
149
- MIT License - See [LICENSE](https://github.com/JoeVonDahab/pharmacology-graph/blob/main/LICENSE) for details
150
-
151
- ---
152
-
153
- **Built with:** 🤗 Gradio • PyTorch • NetworkX • Plotly • ESM-2
154
-
155
- **Powered by:** ChEMBL • Hugging Face Spaces
156
-
157
- *Last updated: October 2025*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
USER_SETUP_SUMMARY.md DELETED
@@ -1,302 +0,0 @@
1
- # 📋 Summary: Setup for New Users
2
-
3
- ## What Someone Needs to Do to Run Your App
4
-
5
- ### **Method 1: Just Run the App (Recommended for Most Users)**
6
-
7
- ```bash
8
- # 1. Clone repository
9
- git clone https://github.com/JoeVonDahab/pharmacology-graph.git
10
- cd pharmacology-graph
11
-
12
- # 2. Install dependencies
13
- pip install -r requirements_app.txt
14
-
15
- # 3. Download the .npy files (NOT in git)
16
- # They need to either:
17
- # a) Run the notebook to generate them, OR
18
- # b) Download from a release/separate link you provide
19
-
20
- # 4. Run the app
21
- ./start_app.sh
22
- # Open browser to http://localhost:7860
23
- ```
24
-
25
- **Requirements:**
26
- - Python 3.9+
27
- - 8GB RAM
28
- - ~10MB disk space
29
-
30
- **What they get:**
31
- - ✅ Interactive web app
32
- - ✅ Search 3,127 drugs
33
- - ✅ View predictions
34
- - ✅ Network visualization
35
-
36
- ---
37
-
38
- ### **Method 2: Full Research Pipeline (Advanced Users)**
39
-
40
- ```bash
41
- # 1-2. Same as above
42
-
43
- # 3. Download ChEMBL database (4.2GB)
44
- # Already included in repo if you pushed it, otherwise:
45
- # wget https://ftp.ebi.ac.uk/pub/databases/chembl/ChEMBLdb/releases/chembl_36/chembl_36_sqlite.tar.gz
46
-
47
- # 4. Install full dependencies
48
- pip install -r requirements.txt
49
-
50
- # 5. Run the notebook
51
- jupyter notebook code.ipynb
52
- # Run all cells (~40 minutes)
53
-
54
- # 6. Run the app
55
- ./start_app.sh
56
- ```
57
-
58
- **Requirements:**
59
- - Python 3.9+
60
- - 16GB RAM (for ESM-2)
61
- - GPU recommended (or 30+ min on CPU)
62
- - ~5GB disk space
63
-
64
- **What they get:**
65
- - ✅ Everything from Method 1
66
- - ✅ Ability to retrain model
67
- - ✅ Explore data processing
68
- - ✅ Modify predictions
69
-
70
- ---
71
-
72
- ## 🗑️ Files You Can Remove Before Sharing
73
-
74
- Run this to clean up unnecessary files:
75
-
76
- ```bash
77
- ./cleanup.sh
78
- ```
79
-
80
- Or manually remove:
81
-
82
- ### Definitely Remove (Duplicates/Debugging)
83
- ```bash
84
- rm -f BUGFIX_SUMMARY.md # Development notes
85
- rm -f APP_SUMMARY.md # Duplicate of APP_GUIDE.md
86
- rm -f CHECKLIST.md # One-time deployment checklist
87
- rm -f run_app.sh # Old script (use start_app.sh)
88
- rm -f test_search.py # Manual testing guide
89
- rm -f main.py # Old experimental code
90
- rm -f .python-version # Unnecessary version pin
91
- ```
92
-
93
- ### Optional Remove (Can Regenerate)
94
- ```bash
95
- rm -f *.png # Visualization outputs
96
- rm -f *.pkl # Pickle files
97
- rm -f drug_mechanism_filtered.csv
98
- rm -f drug_warnings.csv
99
- rm -f edges_drug_protein.csv
100
- rm -f proteins_for_embedding.csv
101
- rm -f top_50_predicted_drug_targets.csv # Duplicate
102
- ```
103
-
104
- ### Consider Removing (If Users Don't Need to Retrain)
105
- ```bash
106
- rm -f code.ipynb # Research notebook (750KB)
107
- rm -f requirements.txt # Full deps (use requirements_app.txt only)
108
- rm -rf chembl_36/ # Database (4.2GB!)
109
- ```
110
-
111
- ---
112
-
113
- ## 📦 Minimal File Set for App-Only Distribution
114
-
115
- After cleanup, you'd have:
116
-
117
- ```
118
- pharmacology-graph/
119
- ├── app.py # Main app
120
- ├── requirements_app.txt # Dependencies
121
- ├── start_app.sh # Launcher
122
- ├── test_app.py # Diagnostic
123
- ├── README.md # Overview
124
- ├── SETUP.md # Setup guide ⭐
125
- ├── FILES.md # This file list
126
- ├── DEPLOYMENT.md # HF Spaces guide
127
- ├── APP_GUIDE.md # User guide
128
- ├── SPACE_README.md # For HF deployment
129
- ├── drug_nodes.csv # Data
130
- ├── protein_nodes_with_embeddings.csv # Data
131
- ├── drug_effects.csv # Data
132
- ├── drugs_interactions.csv # Data
133
- ├── top_50_predicted_drug_protein.csv # Predictions
134
- ├── top_50_predicted_drug_effects.csv # Predictions
135
- ├── graph_embeddings.npy # Model ⚠️ NOT IN GIT
136
- ├── node_to_idx.npy # Mapping ⚠️ NOT IN GIT
137
- └── .gitignore # Git config
138
- ```
139
-
140
- **Total size**: ~10 MB (without .npy files)
141
-
142
- ---
143
-
144
- ## ⚠️ IMPORTANT: The .npy Files Problem
145
-
146
- ### The Issue
147
- The `.npy` files (`graph_embeddings.npy` and `node_to_idx.npy`) are:
148
- - **Essential** for the app to run
149
- - **NOT tracked in git** (they're in `.gitignore`)
150
- - **~5MB total** (not huge, but binary)
151
-
152
- ### Solutions
153
-
154
- **Option 1: Add them to git** (Simplest)
155
- ```bash
156
- # Edit .gitignore to allow these specific files
157
- echo '!graph_embeddings.npy' >> .gitignore
158
- echo '!node_to_idx.npy' >> .gitignore
159
-
160
- # Add and push
161
- git add graph_embeddings.npy node_to_idx.npy
162
- git commit -m "Add model embeddings"
163
- git push
164
- ```
165
-
166
- **Option 2: GitHub Release** (Cleaner)
167
- 1. Go to GitHub → Releases → Create new release
168
- 2. Upload `graph_embeddings.npy` and `node_to_idx.npy`
169
- 3. Update SETUP.md with download instructions:
170
- ```bash
171
- # Download embeddings
172
- wget https://github.com/YOUR_USERNAME/pharmacology-graph/releases/download/v1.0/graph_embeddings.npy
173
- wget https://github.com/YOUR_USERNAME/pharmacology-graph/releases/download/v1.0/node_to_idx.npy
174
- ```
175
-
176
- **Option 3: Git LFS** (Professional)
177
- ```bash
178
- # Install Git LFS
179
- git lfs install
180
-
181
- # Track .npy files
182
- git lfs track "*.npy"
183
- git add .gitattributes
184
-
185
- # Add and push
186
- git add graph_embeddings.npy node_to_idx.npy
187
- git commit -m "Add model embeddings via LFS"
188
- git push
189
- ```
190
-
191
- **Option 4: External Storage** (If files are huge)
192
- - Upload to Hugging Face Hub, Google Drive, Dropbox
193
- - Provide download link in SETUP.md
194
-
195
- ### Recommendation
196
- For 5MB files, **Option 1** (just add to git) is fine. GitHub allows files up to 100MB.
197
-
198
- ---
199
-
200
- ## 📝 Updated SETUP.md Instructions
201
-
202
- I've created **`SETUP.md`** with complete instructions including:
203
-
204
- ✅ **Quick Start** (3 commands)
205
- ✅ **Full Setup** (retrain from scratch)
206
- ✅ **Troubleshooting** (version issues, port conflicts)
207
- ✅ **Testing** (verify it works)
208
- ✅ **Deployment** (Hugging Face Spaces)
209
- ✅ **File cleanup** (remove unnecessary files)
210
-
211
- **For new users, tell them:**
212
- > "Read **SETUP.md** for complete installation and usage instructions."
213
-
214
- ---
215
-
216
- ## 🎯 Recommended Git Workflow
217
-
218
- ### Before sharing on GitHub:
219
-
220
- 1. **Clean up files**:
221
- ```bash
222
- ./cleanup.sh
223
- ```
224
-
225
- 2. **Add .npy files to git** (if you choose Option 1):
226
- ```bash
227
- echo '!graph_embeddings.npy' >> .gitignore
228
- echo '!node_to_idx.npy' >> .gitignore
229
- git add graph_embeddings.npy node_to_idx.npy .gitignore
230
- git commit -m "Add model embeddings for app"
231
- ```
232
-
233
- 3. **Update README**:
234
- - Already updated with Quick Start section
235
- - Points to SETUP.md for details
236
-
237
- 4. **Push everything**:
238
- ```bash
239
- git add .
240
- git commit -m "Add setup documentation and cleanup scripts"
241
- git push
242
- ```
243
-
244
- ### User experience:
245
- ```bash
246
- git clone https://github.com/YOUR_USERNAME/pharmacology-graph
247
- cd pharmacology-graph
248
- pip install -r requirements_app.txt
249
- ./start_app.sh
250
- ```
251
-
252
- **That's it!** 3 commands and they're running.
253
-
254
- ---
255
-
256
- ## 📊 File Organization Summary
257
-
258
- | Category | Files | Purpose | Size | In Git? |
259
- |----------|-------|---------|------|---------|
260
- | **App Core** | app.py, start_app.sh | Run the interface | 50KB | ✅ Yes |
261
- | **Data** | 6 CSV files | Drug/protein/effect data | 3.5MB | ✅ Yes |
262
- | **Model** | 2 NPY files | Trained embeddings | 5MB | ⚠️ **No** (need to add) |
263
- | **Predictions** | 2 CSV files | Top 50 predictions | 20KB | ✅ Yes |
264
- | **Docs** | 7 MD files | Setup, deployment, usage | 50KB | ✅ Yes |
265
- | **Research** | code.ipynb | Full pipeline | 500KB | ✅ Yes |
266
- | **Database** | chembl_36/ | ChEMBL SQLite | 4.2GB | ❌ No (too large) |
267
- | **Cleanup** | 10+ files | Duplicates, old versions | 2MB | ✅ Yes (but can remove) |
268
-
269
- **Action Items:**
270
- 1. ✅ Created SETUP.md (complete guide)
271
- 2. ✅ Created FILES.md (file manifest)
272
- 3. ✅ Created cleanup.sh (remove junk)
273
- 4. ✅ Updated README.md (quick start)
274
- 5. ⚠️ **TODO**: Decide how to distribute .npy files (Option 1-4 above)
275
-
276
- ---
277
-
278
- ## 🎓 Bottom Line
279
-
280
- **For someone to download and run your app, they need:**
281
-
282
- ### Minimum (App Only):
283
- 1. Clone repo
284
- 2. `pip install -r requirements_app.txt`
285
- 3. Download/generate `.npy` files
286
- 4. `./start_app.sh`
287
-
288
- ### Full (Research):
289
- 1. Clone repo
290
- 2. `pip install -r requirements.txt`
291
- 3. Download ChEMBL (or use included)
292
- 4. Run notebook → generates everything
293
- 5. `./start_app.sh`
294
-
295
- **Unnecessary files removed**: ~15 files, saving 2MB and reducing clutter
296
-
297
- **New documentation**:
298
- - ✅ SETUP.md (start here!)
299
- - ✅ FILES.md (what each file does)
300
- - ✅ cleanup.sh (automated cleanup)
301
-
302
- Users should read **SETUP.md** first. It has everything they need.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.js ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use strict';
2
+
3
+ const V = 'p5'; // bump on each data/app redeploy to bust caches
4
+ // ponytail: data is served by the project's GitHub Pages (CORS: access-control-allow-origin *),
5
+ // so this static Space stays ~25KB and shares one source of truth. Point at local 'data' if self-hosting.
6
+ const DATA = 'https://joevondahab.github.io/pharmacology-graph/data';
7
+ const bust = u => `${u}${u.includes('?') ? '&' : '?'}v=${V}`;
8
+ const CHEMBL_CMP = id => `https://www.ebi.ac.uk/chembl/explore/compound/${id}`;
9
+ const CHEMBL_TGT = id => `https://www.ebi.ac.uk/chembl/explore/target/${id}`;
10
+ const MESH = id => `https://meshb.nlm.nih.gov/record/ui?ui=${id}`;
11
+ const EXT = { drug: CHEMBL_CMP, protein: CHEMBL_TGT, mesh: MESH };
12
+
13
+ // entity-type config for search + display
14
+ const TYPES = {
15
+ drug: { label: 'Drug', chip: 'drug', file: id => `predictions/${id}.json`, index: 'drugs.json' },
16
+ indication: { label: 'Indication', chip: 'ind', file: id => `by_indication/${id}.json`, index: 'indications.json' },
17
+ protein: { label: 'Protein', chip: 'prot', file: id => `by_protein/${id}.json`, index: 'proteins.json' },
18
+ };
19
+
20
+ let ENTITIES = []; // combined search index: {type,id,name,...counts}
21
+ let current = null; // {type, view:[{key,label,linkType}], data}
22
+ let activeList = null;
23
+ let statusFilter = 'all';
24
+
25
+ const $ = s => document.querySelector(s);
26
+ const esc = s => String(s).replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));
27
+
28
+ async function init() {
29
+ try {
30
+ const [drugs, inds, prots, meta] = await Promise.all([
31
+ fetch(bust(`${DATA}/drugs.json`)).then(r => r.json()),
32
+ fetch(bust(`${DATA}/indications.json`)).then(r => r.json()),
33
+ fetch(bust(`${DATA}/proteins.json`)).then(r => r.json()),
34
+ fetch(bust(`${DATA}/meta.json`)).then(r => r.json()).catch(() => null),
35
+ ]);
36
+ ENTITIES = [
37
+ ...drugs.map(d => ({ ...d, type: 'drug' })),
38
+ ...inds.map(d => ({ ...d, type: 'indication' })),
39
+ ...prots.map(d => ({ ...d, type: 'protein' })),
40
+ ];
41
+ if (meta) {
42
+ $('#meta-line').textContent =
43
+ `${meta.num_drugs.toLocaleString()} drugs · ${meta.num_proteins.toLocaleString()} proteins · ` +
44
+ `${meta.num_indications.toLocaleString()} indications · top-${meta.top_k} each way`;
45
+ if (meta.metrics) {
46
+ const m = meta.metrics;
47
+ $('#metrics-note').textContent =
48
+ `Model test metrics — Drug–Protein PR-AUC ${m.dp.pr_auc.toFixed(3)}, Hits@10 ${m.dp['hits@10'].toFixed(3)} · ` +
49
+ `Drug–Indication PR-AUC ${m.di.pr_auc.toFixed(3)}, Hits@10 ${m.di['hits@10'].toFixed(3)}`;
50
+ }
51
+ }
52
+ buildExamples();
53
+ wireSearch();
54
+ if (location.hash.length > 1) {
55
+ const [t, id] = decodeURIComponent(location.hash.slice(1)).split(':');
56
+ if (id) select(t, id);
57
+ }
58
+ } catch (e) {
59
+ $('#empty-state').innerHTML = `<p style="color:#e06b6b">Failed to load data (${e}). Serve this folder over HTTP.</p>`;
60
+ }
61
+ }
62
+
63
+ function buildExamples() {
64
+ const picks = [
65
+ ['drug', 'SUNITINIB'], ['indication', 'Breast Neoplasms'],
66
+ ['drug', 'ASPIRIN'], ['indication', 'Hypertension'], ['protein', 'Histamine H1 receptor'],
67
+ ];
68
+ const box = $('#examples');
69
+ picks.forEach(([type, name]) => {
70
+ const e = ENTITIES.find(x => x.type === type && x.name.toUpperCase() === name.toUpperCase());
71
+ if (!e) return;
72
+ const b = document.createElement('button');
73
+ b.innerHTML = `<span class="chip ${TYPES[type].chip}">${TYPES[type].label}</span> ${esc(e.name)}`;
74
+ b.onclick = () => select(type, e.id);
75
+ box.appendChild(b);
76
+ });
77
+ }
78
+
79
+ // ---------- search ----------
80
+ let activeIdx = -1, matches = [];
81
+ function wireSearch() {
82
+ const input = $('#search'), list = $('#suggestions');
83
+ input.addEventListener('input', () => {
84
+ const q = input.value.trim().toLowerCase();
85
+ if (!q) { list.hidden = true; return; }
86
+ matches = ENTITIES
87
+ .filter(e => e.name.toLowerCase().includes(q) || e.id.toLowerCase().includes(q))
88
+ .sort((a, b) => (a.name.toLowerCase().indexOf(q) - b.name.toLowerCase().indexOf(q)) || a.name.length - b.name.length)
89
+ .slice(0, 14);
90
+ renderSuggestions(q);
91
+ });
92
+ input.addEventListener('keydown', e => {
93
+ if (list.hidden) return;
94
+ if (e.key === 'ArrowDown') { activeIdx = Math.min(activeIdx + 1, matches.length - 1); paint(); e.preventDefault(); }
95
+ else if (e.key === 'ArrowUp') { activeIdx = Math.max(activeIdx - 1, 0); paint(); e.preventDefault(); }
96
+ else if (e.key === 'Enter') { const m = matches[activeIdx] || matches[0]; if (m) select(m.type, m.id); }
97
+ else if (e.key === 'Escape') list.hidden = true;
98
+ });
99
+ document.addEventListener('click', e => { if (!e.target.closest('.search-box')) list.hidden = true; });
100
+ }
101
+ function renderSuggestions(q) {
102
+ const list = $('#suggestions'); activeIdx = -1;
103
+ if (!matches.length) { list.hidden = true; return; }
104
+ list.innerHTML = matches.map((e, i) => {
105
+ const t = TYPES[e.type];
106
+ const sub = e.type === 'drug' ? `${e.kp}+${e.ki} known` : `${e.kd} known drugs`;
107
+ return `<li data-i="${i}"><span class="s-left"><span class="chip ${t.chip}">${t.label}</span>
108
+ <span class="sname">${hl(e.name, q)}</span></span><span class="sid">${e.id} · ${sub}</span></li>`;
109
+ }).join('');
110
+ [...list.children].forEach((li, i) => li.onclick = () => select(matches[i].type, matches[i].id));
111
+ list.hidden = false;
112
+ }
113
+ function paint() { [...$('#suggestions').children].forEach(li => li.classList.toggle('active', +li.dataset.i === activeIdx)); }
114
+ function hl(text, q) {
115
+ const i = text.toLowerCase().indexOf(q);
116
+ return i < 0 ? esc(text) : esc(text.slice(0, i)) + '<mark>' + esc(text.slice(i, i + q.length)) + '</mark>' + esc(text.slice(i + q.length));
117
+ }
118
+
119
+ // ---------- selection ----------
120
+ async function select(type, id) {
121
+ $('#suggestions').hidden = true; $('#search').value = '';
122
+ let data;
123
+ try {
124
+ data = await fetch(bust(`${DATA}/${TYPES[type].file(id)}`)).then(r => { if (!r.ok) throw new Error(r.status); return r.json(); });
125
+ } catch (e) { alert(`No predictions found for ${type} "${id}".`); return; }
126
+
127
+ let view, head;
128
+ if (type === 'drug') {
129
+ view = [{ key: 'proteins', label: 'Protein targets', linkType: 'protein' },
130
+ { key: 'indications', label: 'Indications', linkType: 'mesh' }];
131
+ head = { name: data.drug.name, id: data.drug.id, ext: 'drug' };
132
+ } else if (type === 'indication') {
133
+ view = [{ key: 'drugs', label: 'Predicted drugs', linkType: 'drug' }];
134
+ head = { name: data.indication.name, id: data.indication.id, ext: 'mesh' };
135
+ } else {
136
+ view = [{ key: 'drugs', label: 'Predicted drugs', linkType: 'drug' }];
137
+ head = { name: data.protein.name, id: data.protein.id, ext: 'protein' };
138
+ }
139
+ current = { type, view, data, head };
140
+ activeList = view[0].key; statusFilter = 'all';
141
+ history.replaceState(null, '', `#${type}:${id}`);
142
+ $('#empty-state').hidden = true; $('#result').hidden = false;
143
+ renderHead(); renderControls(); renderTable();
144
+ }
145
+
146
+ function renderHead() {
147
+ const { type, head, view, data } = current;
148
+ $('#drug-name').textContent = head.name;
149
+ $('#type-chip').className = `chip ${TYPES[type].chip}`;
150
+ $('#type-chip').textContent = TYPES[type].label;
151
+ const link = $('#drug-link'); link.href = EXT[head.ext](head.id); link.textContent = `${head.id} ↗`;
152
+
153
+ const cards = [];
154
+ const count = (key, st) => (data[key] || []).filter(r => r.status === st).length;
155
+ if (type === 'drug') {
156
+ cards.push(['known', count('proteins', 'known'), 'known prot'], ['novel', count('proteins', 'novel'), 'novel prot'],
157
+ ['known', count('indications', 'known'), 'known ind'], ['novel', count('indications', 'novel'), 'novel ind']);
158
+ } else {
159
+ cards.push(['known', count('drugs', 'known'), 'known drugs'], ['novel', count('drugs', 'novel'), 'novel drugs']);
160
+ }
161
+ $('#stat-cards').innerHTML = cards.map(([c, n, l]) => `<div class="stat ${c}"><b>${n}</b><span>${l}</span></div>`).join('');
162
+ }
163
+
164
+ function renderControls() {
165
+ const tabs = $('#tabs');
166
+ if (current.view.length > 1) {
167
+ tabs.hidden = false;
168
+ tabs.innerHTML = current.view.map(v =>
169
+ `<button class="tab ${v.key === activeList ? 'active' : ''}" data-list="${v.key}">${v.label}</button>`).join('');
170
+ } else { tabs.hidden = true; }
171
+ }
172
+
173
+ function activeRows() {
174
+ const rows = current.data[activeList] || [];
175
+ const q = $('#table-filter').value.trim().toLowerCase();
176
+ return rows.filter(r => statusFilter === 'all' || r.status === statusFilter)
177
+ .filter(r => !q || r.name.toLowerCase().includes(q) || r.id.toLowerCase().includes(q));
178
+ }
179
+
180
+ function renderTable() {
181
+ const v = current.view.find(x => x.key === activeList);
182
+ const linkFn = EXT[v.linkType];
183
+ const colHead = v.linkType === 'drug' ? 'Drug' : (v.linkType === 'protein' ? 'Target' : 'Indication');
184
+ $('#th-target').textContent = colHead;
185
+ const rows = activeRows();
186
+ $('#pred-body').innerHTML = rows.map(r => `
187
+ <tr>
188
+ <td class="c-rank">${r.rank}</td>
189
+ <td class="tname">${esc(r.name)}</td>
190
+ <td class="tid"><a href="${linkFn(r.id)}" target="_blank" rel="noopener">${r.id} ↗</a></td>
191
+ <td><div class="scorewrap"><div class="bar"><i style="width:${Math.round(r.score * 100)}%"></i></div>
192
+ <span class="scoreval">${r.score.toFixed(3)}</span></div></td>
193
+ <td><span class="badge ${r.status}">${r.status}</span></td>
194
+ </tr>`).join('');
195
+ $('#no-rows').hidden = rows.length > 0;
196
+ }
197
+
198
+ // ---------- controls ----------
199
+ document.addEventListener('click', e => {
200
+ const t = e.target;
201
+ if (t.classList.contains('tab')) { activeList = t.dataset.list; renderControls(); renderTable(); }
202
+ if (t.classList.contains('chip') && t.dataset.status) {
203
+ statusFilter = t.dataset.status;
204
+ document.querySelectorAll('#status-filter .chip').forEach(x => x.classList.toggle('active', x === t));
205
+ renderTable();
206
+ }
207
+ if (t.id === 'dl-csv') downloadCSV();
208
+ if (t.id === 'dl-json') downloadJSON();
209
+ });
210
+ document.addEventListener('input', e => { if (e.target.id === 'table-filter') renderTable(); });
211
+
212
+ // ---------- downloads ----------
213
+ function downloadCSV() {
214
+ if (!current) return;
215
+ const v = current.view.find(x => x.key === activeList);
216
+ const what = v.linkType === 'drug' ? 'drug' : (v.linkType === 'protein' ? 'protein' : 'indication');
217
+ const head = ['rank', `${what}_id`, `${what}_name`, 'score', 'raw_score', 'status'];
218
+ const lines = [head.join(',')];
219
+ for (const r of activeRows())
220
+ lines.push([r.rank, r.id, `"${r.name.replace(/"/g, '""')}"`, r.score, r.raw ?? '', r.status].join(','));
221
+ save(lines.join('\n'), `${current.head.id}_${activeList}.csv`, 'text/csv');
222
+ }
223
+ function downloadJSON() {
224
+ if (!current) return;
225
+ save(JSON.stringify(current.data, null, 2), `${current.head.id}_predictions.json`, 'application/json');
226
+ }
227
+ function save(text, name, type) {
228
+ const url = URL.createObjectURL(new Blob([text], { type }));
229
+ const a = document.createElement('a'); a.href = url; a.download = name; a.click();
230
+ setTimeout(() => URL.revokeObjectURL(url), 1000);
231
+ }
232
+
233
+ init();
app.py DELETED
@@ -1,609 +0,0 @@
1
- import gradio as gr
2
- import pandas as pd
3
- import numpy as np
4
- import plotly.graph_objects as go
5
- import networkx as nx
6
- from sklearn.metrics.pairwise import cosine_similarity
7
- import json
8
-
9
- # Load data
10
- print("Loading data...")
11
- drug_nodes = pd.read_csv('drug_nodes.csv')
12
- protein_nodes = pd.read_csv('protein_nodes_with_embeddings.csv')
13
- drug_effects = pd.read_csv('drug_effects.csv')
14
- drugs_interactions = pd.read_csv('drugs_interactions.csv')
15
-
16
- # Load predictions
17
- predicted_targets = pd.read_csv('top_50_predicted_drug_protein.csv')
18
- predicted_effects = pd.read_csv('top_50_predicted_drug_effects.csv')
19
-
20
- # Load embeddings
21
- embeddings = np.load('graph_embeddings.npy')
22
- node_to_idx = np.load('node_to_idx.npy', allow_pickle=True).item()
23
-
24
- print(f"✓ Loaded {len(drug_nodes)} drugs, {len(protein_nodes)} proteins, {len(drug_effects)} effects")
25
-
26
- # Create reverse mappings
27
- internal_to_drug_info = dict(zip(drug_nodes['drug_internal_id'],
28
- zip(drug_nodes['drug_id'], drug_nodes['drug_name'])))
29
- protein_id_to_name = dict(zip(protein_nodes['protein_id'], protein_nodes['protein_name']))
30
- effect_id_to_name = dict(zip(drug_effects['effect_id'], drug_effects['effect_name']))
31
-
32
- def search_drugs(query):
33
- """Search for drugs by name or ChEMBL ID"""
34
- try:
35
- if not query:
36
- return []
37
-
38
- query = query.lower()
39
- matches = drug_nodes[
40
- drug_nodes['drug_name'].str.lower().str.contains(query, na=False) |
41
- drug_nodes['drug_id'].str.lower().str.contains(query, na=False)
42
- ]
43
-
44
- # Return list of tuples (display_name, drug_internal_id)
45
- results = [(f"{row['drug_name']} ({row['drug_id']})", row['drug_internal_id'])
46
- for _, row in matches.head(20).iterrows()]
47
-
48
- return results
49
- except Exception as e:
50
- print(f"Error in search_drugs: {e}")
51
- return []
52
-
53
- def get_drug_info(drug_internal_id):
54
- """Get basic drug information"""
55
- if drug_internal_id is None:
56
- return "No drug selected"
57
-
58
- drug_row = drug_nodes[drug_nodes['drug_internal_id'] == drug_internal_id]
59
- if len(drug_row) == 0:
60
- return "Drug not found"
61
-
62
- drug_row = drug_row.iloc[0]
63
-
64
- info = f"""
65
- ## 💊 {drug_row['drug_name']}
66
-
67
- **ChEMBL ID:** {drug_row['drug_id']}
68
- **SMILES:** `{drug_row['smile'][:100]}...`
69
- """
70
- return info
71
-
72
- def get_known_targets(drug_internal_id):
73
- """Get known protein targets for a drug"""
74
- if drug_internal_id is None:
75
- return pd.DataFrame()
76
-
77
- # Get ChEMBL ID
78
- drug_row = drug_nodes[drug_nodes['drug_internal_id'] == drug_internal_id]
79
- if len(drug_row) == 0:
80
- return pd.DataFrame()
81
-
82
- drug_chembl_id = drug_row.iloc[0]['drug_id']
83
-
84
- # Get known interactions
85
- known = drugs_interactions[drugs_interactions['drug_id'] == drug_chembl_id].copy()
86
-
87
- if len(known) == 0:
88
- return pd.DataFrame(columns=['Target Protein', 'pChEMBL (max)', 'Measurements'])
89
-
90
- # Format for display
91
- display_df = pd.DataFrame({
92
- 'Target Protein': known['protein_name'].values,
93
- 'ChEMBL ID': known['protein_id'].values,
94
- 'pChEMBL (max)': known['pchembl_max'].values,
95
- 'pChEMBL (avg)': known['pchembl_avg'].values,
96
- 'Measurements': known['num_measurements'].values
97
- })
98
-
99
- return display_df.sort_values('pChEMBL (max)', ascending=False)
100
-
101
- def get_known_effects(drug_internal_id):
102
- """Get known clinical effects for a drug"""
103
- if drug_internal_id is None:
104
- return pd.DataFrame()
105
-
106
- # Get known effects
107
- known = drug_effects[drug_effects['drug_internal_id'] == drug_internal_id].copy()
108
-
109
- if len(known) == 0:
110
- return pd.DataFrame(columns=['Clinical Effect', 'Phase', 'References'])
111
-
112
- # Format for display
113
- display_df = pd.DataFrame({
114
- 'Clinical Effect': known['effect_name'].values,
115
- 'MeSH ID': known['effect_id'].values,
116
- 'Phase': known['indication_phase'].values,
117
- 'References': known['num_references'].values
118
- })
119
-
120
- return display_df.sort_values('Phase', ascending=False)
121
-
122
- def get_predicted_targets(drug_internal_id, top_k=10):
123
- """Get predicted novel protein targets"""
124
- if drug_internal_id is None:
125
- return pd.DataFrame()
126
-
127
- # Get ChEMBL ID
128
- drug_row = drug_nodes[drug_nodes['drug_internal_id'] == drug_internal_id]
129
- if len(drug_row) == 0:
130
- return pd.DataFrame()
131
-
132
- drug_chembl_id = drug_row.iloc[0]['drug_id']
133
-
134
- # Get known targets to filter out
135
- known_targets = set(drugs_interactions[
136
- drugs_interactions['drug_id'] == drug_chembl_id
137
- ]['protein_id'].values)
138
-
139
- # Check if drug is in embedding space
140
- if drug_internal_id not in node_to_idx:
141
- return pd.DataFrame(columns=['Predicted Target', 'Similarity', 'Confidence'])
142
-
143
- # Get drug embedding
144
- drug_idx = node_to_idx[drug_internal_id]
145
- drug_emb = embeddings[drug_idx].reshape(1, -1)
146
-
147
- # Compute similarities to all proteins
148
- predictions = []
149
- for _, protein_row in protein_nodes.iterrows():
150
- protein_id = protein_row['protein_id']
151
- protein_name = protein_row['protein_name']
152
-
153
- # Skip known targets
154
- if protein_id in known_targets:
155
- continue
156
-
157
- # Get protein embedding
158
- if protein_id not in node_to_idx:
159
- continue
160
-
161
- protein_idx = node_to_idx[protein_id]
162
- protein_emb = embeddings[protein_idx].reshape(1, -1)
163
-
164
- # Calculate similarity
165
- sim = cosine_similarity(drug_emb, protein_emb)[0][0]
166
-
167
- predictions.append({
168
- 'Predicted Target': protein_name,
169
- 'ChEMBL ID': protein_id,
170
- 'Similarity': f"{sim:.4f}",
171
- 'Confidence': 'High' if sim > 0.5 else 'Medium' if sim > 0.45 else 'Low'
172
- })
173
-
174
- # Sort and return top-k
175
- predictions_df = pd.DataFrame(predictions)
176
- if len(predictions_df) == 0:
177
- return pd.DataFrame(columns=['Predicted Target', 'Similarity', 'Confidence'])
178
-
179
- predictions_df['Similarity_Float'] = predictions_df['Similarity'].astype(float)
180
- predictions_df = predictions_df.sort_values('Similarity_Float', ascending=False).head(top_k)
181
-
182
- return predictions_df[['Predicted Target', 'ChEMBL ID', 'Similarity', 'Confidence']]
183
-
184
- def get_predicted_effects(drug_internal_id, top_k=10):
185
- """Get predicted novel clinical effects"""
186
- if drug_internal_id is None:
187
- return pd.DataFrame()
188
-
189
- # Get known effects to filter out
190
- known_effects = set(drug_effects[
191
- drug_effects['drug_internal_id'] == drug_internal_id
192
- ]['effect_id'].values)
193
-
194
- # Check if drug is in embedding space
195
- if drug_internal_id not in node_to_idx:
196
- return pd.DataFrame(columns=['Predicted Effect', 'Similarity', 'Confidence'])
197
-
198
- # Get drug embedding
199
- drug_idx = node_to_idx[drug_internal_id]
200
- drug_emb = embeddings[drug_idx].reshape(1, -1)
201
-
202
- # Compute similarities to all effects
203
- predictions = []
204
- unique_effects = drug_effects[['effect_id', 'effect_name']].drop_duplicates()
205
-
206
- for _, effect_row in unique_effects.iterrows():
207
- effect_id = effect_row['effect_id']
208
- effect_name = effect_row['effect_name']
209
-
210
- # Skip known effects
211
- if effect_id in known_effects:
212
- continue
213
-
214
- # Get effect embedding
215
- if effect_id not in node_to_idx:
216
- continue
217
-
218
- effect_idx = node_to_idx[effect_id]
219
- effect_emb = embeddings[effect_idx].reshape(1, -1)
220
-
221
- # Calculate similarity
222
- sim = cosine_similarity(drug_emb, effect_emb)[0][0]
223
-
224
- predictions.append({
225
- 'Predicted Effect': effect_name,
226
- 'MeSH ID': effect_id,
227
- 'Similarity': f"{sim:.4f}",
228
- 'Confidence': 'High' if sim > 0.5 else 'Medium' if sim > 0.45 else 'Low'
229
- })
230
-
231
- # Sort and return top-k
232
- predictions_df = pd.DataFrame(predictions)
233
- if len(predictions_df) == 0:
234
- return pd.DataFrame(columns=['Predicted Effect', 'Similarity', 'Confidence'])
235
-
236
- predictions_df['Similarity_Float'] = predictions_df['Similarity'].astype(float)
237
- predictions_df = predictions_df.sort_values('Similarity_Float', ascending=False).head(top_k)
238
-
239
- return predictions_df[['Predicted Effect', 'MeSH ID', 'Similarity', 'Confidence']]
240
-
241
- def create_network_visualization(drug_internal_id, show_known=True, show_predicted=True, max_nodes=20):
242
- """Create interactive network visualization using Plotly"""
243
- if drug_internal_id is None:
244
- return None
245
-
246
- # Get drug info
247
- drug_row = drug_nodes[drug_nodes['drug_internal_id'] == drug_internal_id]
248
- if len(drug_row) == 0:
249
- return None
250
-
251
- drug_name = drug_row.iloc[0]['drug_name']
252
- drug_chembl_id = drug_row.iloc[0]['drug_id']
253
-
254
- # Create network
255
- G = nx.Graph()
256
-
257
- # Add central drug node
258
- G.add_node(drug_name, node_type='drug', color='#FF6B6B', size=30)
259
-
260
- edge_traces = []
261
- node_texts = []
262
-
263
- # Add known targets
264
- if show_known:
265
- known_targets_df = get_known_targets(drug_internal_id)
266
- for idx, row in known_targets_df.head(max_nodes // 2).iterrows():
267
- target_name = row['Target Protein'][:30]
268
- G.add_node(target_name, node_type='protein_known', color='#4ECDC4', size=15)
269
- G.add_edge(drug_name, target_name, edge_type='known', color='#95E1D3', width=3)
270
-
271
- # Add predicted targets
272
- if show_predicted:
273
- predicted_targets_df = get_predicted_targets(drug_internal_id, top_k=max_nodes // 2)
274
- for idx, row in predicted_targets_df.iterrows():
275
- target_name = row['Predicted Target'][:30]
276
- similarity = float(row['Similarity'])
277
- G.add_node(target_name, node_type='protein_predicted', color='#A8E6CF', size=10)
278
- G.add_edge(drug_name, target_name, edge_type='predicted',
279
- color='#DCEDC8', width=1.5, similarity=similarity)
280
-
281
- # Add known effects
282
- if show_known:
283
- known_effects_df = get_known_effects(drug_internal_id)
284
- for idx, row in known_effects_df.head(max_nodes // 3).iterrows():
285
- effect_name = row['Clinical Effect'][:30]
286
- G.add_node(effect_name, node_type='effect_known', color='#FFD93D', size=15)
287
- G.add_edge(drug_name, effect_name, edge_type='known_effect', color='#FCF4A3', width=3)
288
-
289
- # Add predicted effects
290
- if show_predicted:
291
- predicted_effects_df = get_predicted_effects(drug_internal_id, top_k=max_nodes // 3)
292
- for idx, row in predicted_effects_df.iterrows():
293
- effect_name = row['Predicted Effect'][:30]
294
- similarity = float(row['Similarity'])
295
- G.add_node(effect_name, node_type='effect_predicted', color='#FFF9A3', size=10)
296
- G.add_edge(drug_name, effect_name, edge_type='predicted_effect',
297
- color='#FFFACD', width=1.5, similarity=similarity)
298
-
299
- # Calculate layout
300
- pos = nx.spring_layout(G, k=2, iterations=50, seed=42)
301
-
302
- # Create edge traces
303
- edge_traces = []
304
- for edge in G.edges(data=True):
305
- x0, y0 = pos[edge[0]]
306
- x1, y1 = pos[edge[1]]
307
-
308
- edge_trace = go.Scatter(
309
- x=[x0, x1, None],
310
- y=[y0, y1, None],
311
- mode='lines',
312
- line=dict(
313
- width=edge[2].get('width', 1),
314
- color=edge[2].get('color', '#888')
315
- ),
316
- hoverinfo='none',
317
- showlegend=False
318
- )
319
- edge_traces.append(edge_trace)
320
-
321
- # Create node trace
322
- node_x = []
323
- node_y = []
324
- node_color = []
325
- node_size = []
326
- node_text = []
327
-
328
- for node in G.nodes(data=True):
329
- x, y = pos[node[0]]
330
- node_x.append(x)
331
- node_y.append(y)
332
- node_color.append(node[1].get('color', '#888'))
333
- node_size.append(node[1].get('size', 10))
334
-
335
- # Create hover text
336
- node_type = node[1].get('node_type', 'unknown')
337
- if node_type == 'drug':
338
- text = f"<b>{node[0]}</b><br>Type: Drug<br>ChEMBL: {drug_chembl_id}"
339
- elif 'protein' in node_type:
340
- text = f"<b>{node[0]}</b><br>Type: Protein Target<br>{'Known' if 'known' in node_type else 'Predicted'}"
341
- elif 'effect' in node_type:
342
- text = f"<b>{node[0]}</b><br>Type: Clinical Effect<br>{'Known' if 'known' in node_type else 'Predicted'}"
343
- else:
344
- text = f"<b>{node[0]}</b>"
345
-
346
- node_text.append(text)
347
-
348
- node_trace = go.Scatter(
349
- x=node_x,
350
- y=node_y,
351
- mode='markers+text',
352
- text=[node[0] for node in G.nodes()],
353
- textposition='top center',
354
- textfont=dict(size=8),
355
- hovertext=node_text,
356
- hoverinfo='text',
357
- marker=dict(
358
- size=node_size,
359
- color=node_color,
360
- line=dict(width=2, color='white')
361
- ),
362
- showlegend=False
363
- )
364
-
365
- # Create figure
366
- fig = go.Figure(data=edge_traces + [node_trace])
367
-
368
- fig.update_layout(
369
- title=dict(
370
- text=f"Knowledge Graph for {drug_name}",
371
- font=dict(size=20)
372
- ),
373
- showlegend=False,
374
- hovermode='closest',
375
- margin=dict(b=0, l=0, r=0, t=40),
376
- xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
377
- yaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
378
- plot_bgcolor='rgba(240,240,240,0.9)',
379
- height=700
380
- )
381
-
382
- # Add legend manually
383
- fig.add_annotation(
384
- text="<b>Legend:</b><br>" +
385
- "🔴 Drug | 🔵 Known Target | 🟢 Predicted Target<br>" +
386
- "🟡 Known Effect | 🟨 Predicted Effect",
387
- xref="paper", yref="paper",
388
- x=0.02, y=0.98,
389
- showarrow=False,
390
- bgcolor="white",
391
- bordercolor="black",
392
- borderwidth=1,
393
- font=dict(size=10),
394
- align="left"
395
- )
396
-
397
- return fig
398
-
399
- def analyze_drug(search_query, drug_selection, show_known, show_predicted, max_nodes):
400
- """Main analysis function"""
401
- try:
402
- if drug_selection is None:
403
- return (
404
- "Please search and select a drug from the dropdown",
405
- pd.DataFrame(),
406
- pd.DataFrame(),
407
- pd.DataFrame(),
408
- pd.DataFrame(),
409
- None
410
- )
411
-
412
- # Extract drug_internal_id from selection
413
- drug_internal_id = drug_selection
414
-
415
- # Get all data with error handling
416
- info = get_drug_info(drug_internal_id)
417
- known_targets = get_known_targets(drug_internal_id)
418
- known_effects = get_known_effects(drug_internal_id)
419
- pred_targets = get_predicted_targets(drug_internal_id, top_k=15)
420
- pred_effects = get_predicted_effects(drug_internal_id, top_k=15)
421
- network = create_network_visualization(drug_internal_id, show_known, show_predicted, max_nodes)
422
-
423
- return info, known_targets, known_effects, pred_targets, pred_effects, network
424
-
425
- except Exception as e:
426
- error_msg = f"⚠️ Error analyzing drug: {str(e)}\n\nPlease try selecting a different drug or check the console for details."
427
- print(f"Error in analyze_drug: {e}")
428
- import traceback
429
- traceback.print_exc()
430
-
431
- return (
432
- error_msg,
433
- pd.DataFrame(),
434
- pd.DataFrame(),
435
- pd.DataFrame(),
436
- pd.DataFrame(),
437
- None
438
- )
439
-
440
- # Create Gradio interface
441
- with gr.Blocks(title="Pharmacology Knowledge Graph Explorer", theme=gr.themes.Soft()) as demo:
442
- gr.Markdown(
443
- """
444
- # 💊 Pharmacology Knowledge Graph Explorer
445
-
446
- Explore drug-target-effect relationships using AI-powered predictions from a TransE knowledge graph model.
447
-
448
- **Features:**
449
- - 🔍 Search **2,526** FDA-approved drugs
450
- - 🎯 View known and predicted protein targets
451
- - 💉 Discover potential therapeutic uses (drug repurposing)
452
- - 🕸️ Interactive network visualization
453
-
454
- ---
455
- """
456
- )
457
-
458
- with gr.Row():
459
- with gr.Column(scale=1):
460
- gr.Markdown("### 🔍 Drug Search")
461
- search_box = gr.Textbox(
462
- label="Search by drug name or ChEMBL ID",
463
- placeholder="e.g., Aspirin, Morphine, CHEMBL25",
464
- info="Type to search, then select from dropdown"
465
- )
466
-
467
- drug_dropdown = gr.Dropdown(
468
- label="Select Drug",
469
- choices=[],
470
- interactive=True
471
- )
472
-
473
- gr.Markdown("### ⚙️ Visualization Settings")
474
- show_known_checkbox = gr.Checkbox(label="Show known interactions", value=True)
475
- show_predicted_checkbox = gr.Checkbox(label="Show predicted interactions", value=True)
476
- max_nodes_slider = gr.Slider(
477
- minimum=10, maximum=50, value=20, step=5,
478
- label="Max nodes to display"
479
- )
480
-
481
- analyze_btn = gr.Button("🔬 Analyze Drug", variant="primary", size="lg")
482
-
483
- with gr.Column(scale=2):
484
- drug_info = gr.Markdown("### Select a drug to begin analysis")
485
-
486
- gr.Markdown("---")
487
-
488
- with gr.Row():
489
- with gr.Column():
490
- gr.Markdown("### 🎯 Known Protein Targets")
491
- known_targets_table = gr.Dataframe(
492
- headers=['Target Protein', 'ChEMBL ID', 'pChEMBL (max)', 'pChEMBL (avg)', 'Measurements'],
493
- interactive=False
494
- )
495
-
496
- with gr.Column():
497
- gr.Markdown("### 🔮 Predicted Novel Targets")
498
- predicted_targets_table = gr.Dataframe(
499
- headers=['Predicted Target', 'ChEMBL ID', 'Similarity', 'Confidence'],
500
- interactive=False
501
- )
502
-
503
- gr.Markdown("---")
504
-
505
- with gr.Row():
506
- with gr.Column():
507
- gr.Markdown("### 💉 Known Clinical Effects")
508
- known_effects_table = gr.Dataframe(
509
- headers=['Clinical Effect', 'MeSH ID', 'Phase', 'References'],
510
- interactive=False
511
- )
512
-
513
- with gr.Column():
514
- gr.Markdown("### 💡 Predicted Novel Effects (Repurposing)")
515
- predicted_effects_table = gr.Dataframe(
516
- headers=['Predicted Effect', 'MeSH ID', 'Similarity', 'Confidence'],
517
- interactive=False
518
- )
519
-
520
- gr.Markdown("---")
521
-
522
- gr.Markdown("### 🕸️ Interactive Knowledge Graph")
523
- network_plot = gr.Plot()
524
-
525
- gr.Markdown(
526
- """
527
- ---
528
-
529
- ### 📊 About the Model
530
-
531
- This app uses a **TransE knowledge graph embedding model** trained on:
532
- - **2,526** FDA-approved drugs
533
- - **1,156** human protein targets (with ESM-2 embeddings)
534
- - **1,065** clinical indications
535
- - **18,789** total known links
536
-
537
- **Prediction method:** Cosine similarity in learned embedding space
538
- **Model performance:** ~90% precision on top-50 predictions
539
-
540
- **By:** Youssef Abo-Dahab, Pharm.D.
541
- **AICD3 M.S. Candidate, UCSF** | October 2025
542
-
543
- [GitHub Repository](https://github.com/JoeVonDahab/pharmacology-graph)
544
-
545
- ---
546
- **Disclaimer:** This is a research tool for exploratory analysis only. Predictions should be validated experimentally. Not for clinical use.
547
- """
548
- )
549
-
550
- # Event handlers
551
- # Store mapping globally to avoid re-searching
552
- drug_display_to_id = gr.State({})
553
- selected_drug_id = gr.State()
554
-
555
- def update_dropdown(search_query):
556
- if not search_query or len(search_query) < 1:
557
- return gr.update(choices=[]), {}
558
-
559
- results = search_drugs(search_query)
560
- print(f"Search '{search_query}' found {len(results)} results") # Debug output
561
-
562
- # Create mapping: display_name -> internal_id
563
- mapping = {display: internal_id for display, internal_id in results}
564
- choices = list(mapping.keys())
565
-
566
- print(f"Returning choices: {choices[:3]}..." if len(choices) > 3 else f"Returning choices: {choices}") # Debug
567
- return gr.update(choices=choices, value=None), mapping
568
-
569
- def store_selection(dropdown_value, mapping):
570
- if not dropdown_value or not mapping:
571
- return None
572
-
573
- # Get internal_id from mapping
574
- return mapping.get(dropdown_value, None)
575
-
576
- search_box.change(
577
- fn=update_dropdown,
578
- inputs=[search_box],
579
- outputs=[drug_dropdown, drug_display_to_id]
580
- )
581
-
582
- drug_dropdown.change(
583
- fn=store_selection,
584
- inputs=[drug_dropdown, drug_display_to_id],
585
- outputs=[selected_drug_id]
586
- )
587
-
588
- analyze_btn.click(
589
- fn=analyze_drug,
590
- inputs=[
591
- search_box,
592
- selected_drug_id,
593
- show_known_checkbox,
594
- show_predicted_checkbox,
595
- max_nodes_slider
596
- ],
597
- outputs=[
598
- drug_info,
599
- known_targets_table,
600
- known_effects_table,
601
- predicted_targets_table,
602
- predicted_effects_table,
603
- network_plot
604
- ]
605
- )
606
-
607
- # Launch
608
- if __name__ == "__main__":
609
- demo.launch(share=False, server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cleanup.sh DELETED
@@ -1,59 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Cleanup script to remove unnecessary files for end users
4
- # This keeps only essential files needed to run the Gradio app
5
-
6
- echo "🧹 Pharmacology Graph - Cleanup Script"
7
- echo "======================================"
8
- echo ""
9
- echo "This will remove development/duplicate files not needed to run the app."
10
- echo "Essential files (app.py, CSV data, requirements_app.txt) will be kept."
11
- echo ""
12
- read -p "Continue? (y/n) " -n 1 -r
13
- echo ""
14
-
15
- if [[ ! $REPLY =~ ^[Yy]$ ]]; then
16
- echo "Cancelled."
17
- exit 0
18
- fi
19
-
20
- echo ""
21
- echo "Removing unnecessary files..."
22
-
23
- # Documentation duplicates
24
- rm -f BUGFIX_SUMMARY.md && echo " ✓ Removed BUGFIX_SUMMARY.md"
25
- rm -f APP_SUMMARY.md && echo " ✓ Removed APP_SUMMARY.md"
26
- rm -f CHECKLIST.md && echo " ✓ Removed CHECKLIST.md"
27
-
28
- # Duplicate/old scripts
29
- rm -f run_app.sh && echo " ✓ Removed run_app.sh (use start_app.sh instead)"
30
- rm -f test_search.py && echo " ✓ Removed test_search.py"
31
-
32
- # Old/temporary files (if they exist)
33
- rm -f main.py && echo " ✓ Removed main.py"
34
- rm -f .python-version && echo " ✓ Removed .python-version"
35
-
36
- # Image outputs (can regenerate from notebook)
37
- rm -f *.png && echo " ✓ Removed PNG images"
38
-
39
- # Pickle files (can regenerate from notebook)
40
- rm -f *.pkl && echo " ✓ Removed PKL files"
41
-
42
- # Intermediate CSV files (not needed for app)
43
- rm -f drug_mechanism_filtered.csv && echo " ✓ Removed drug_mechanism_filtered.csv"
44
- rm -f drug_warnings.csv && echo " ✓ Removed drug_warnings.csv"
45
- rm -f edges_drug_protein.csv && echo " ✓ Removed edges_drug_protein.csv"
46
- rm -f proteins_for_embedding.csv && echo " ✓ Removed proteins_for_embedding.csv"
47
- rm -f top_50_predicted_drug_targets.csv && echo " ✓ Removed top_50_predicted_drug_targets.csv (duplicate)"
48
-
49
- echo ""
50
- echo "✅ Cleanup complete!"
51
- echo ""
52
- echo "Remaining essential files:"
53
- ls -lh *.py *.txt *.sh *.md 2>/dev/null | awk '{print " - " $9 " (" $5 ")"}'
54
- echo ""
55
- echo "Data files:"
56
- ls -lh *.csv *.npy 2>/dev/null | awk '{print " - " $9 " (" $5 ")"}'
57
- echo ""
58
- echo "Total size:"
59
- du -sh . | awk '{print " " $1}'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
code.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
drug_effects.csv DELETED
The diff for this file is too large to render. See raw diff
 
drug_nodes.csv DELETED
The diff for this file is too large to render. See raw diff
 
drugs_interactions.csv DELETED
The diff for this file is too large to render. See raw diff
 
graph_embeddings.npy DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:a5bfc5b74dcc2a159c88885b92432888d42a32101c34d7490051865be5d22dab
3
- size 2663040
 
 
 
 
index.html ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Pharmacology Graph — Drug · Disease · Target Explorer</title>
7
+ <link rel="icon" href="data:image/svg+xml,&lt;svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'&gt;&lt;text y='.9em' font-size='90'&gt;💊&lt;/text&gt;&lt;/svg&gt;" />
8
+ <link rel="stylesheet" href="style.css?v=p5" />
9
+ </head>
10
+ <body>
11
+ <header class="site-header">
12
+ <div class="wrap">
13
+ <h1>💊 Pharmacology Graph Explorer</h1>
14
+ <p class="tagline">
15
+ Search a <span class="chip drug">Drug</span> to see its predicted targets &amp; indications, or a
16
+ <span class="chip ind">Indication</span> / <span class="chip prot">Protein</span> to see the drugs most likely
17
+ linked to it — each flagged <span class="badge known">known</span> or <span class="badge novel">novel</span>.
18
+ </p>
19
+ <p class="meta-line" id="meta-line"></p>
20
+ <p class="meta-line" id="metrics-note"></p>
21
+ </div>
22
+ </header>
23
+
24
+ <main class="wrap">
25
+ <section class="search-box">
26
+ <label for="search" class="sr-only">Search</label>
27
+ <input id="search" type="text" autocomplete="off" spellcheck="false"
28
+ placeholder="Search a drug, disease/indication, or protein (e.g. sunitinib, breast neoplasms, CHEMBL231)…" />
29
+ <ul id="suggestions" class="suggestions" hidden></ul>
30
+ </section>
31
+
32
+ <section id="empty-state" class="empty">
33
+ <p>Start typing above. <span class="hint">Drugs · Indications · Proteins — all searchable, both directions.</span></p>
34
+ <div class="examples" id="examples"></div>
35
+ </section>
36
+
37
+ <section id="result" class="result" hidden>
38
+ <div class="drug-head">
39
+ <div>
40
+ <span class="chip" id="type-chip"></span>
41
+ <h2 id="drug-name"></h2>
42
+ <a id="drug-link" class="ext" target="_blank" rel="noopener"></a>
43
+ </div>
44
+ <div class="stat-cards" id="stat-cards"></div>
45
+ </div>
46
+
47
+ <div class="controls">
48
+ <div class="tabs" id="tabs" role="tablist"></div>
49
+ <div class="filters">
50
+ <div class="chips" id="status-filter">
51
+ <button class="chip active" data-status="all">All</button>
52
+ <button class="chip" data-status="novel">Novel only</button>
53
+ <button class="chip" data-status="known">Known only</button>
54
+ </div>
55
+ <input id="table-filter" class="table-filter" type="text" placeholder="Filter rows…" />
56
+ <div class="downloads">
57
+ <button id="dl-csv" class="dl">⬇ CSV</button>
58
+ <button id="dl-json" class="dl">⬇ JSON</button>
59
+ </div>
60
+ </div>
61
+ </div>
62
+
63
+ <table class="pred-table">
64
+ <thead>
65
+ <tr><th class="c-rank">#</th><th id="th-target">Target</th><th>ID</th><th class="c-score">Score</th><th class="c-status">Status</th></tr>
66
+ </thead>
67
+ <tbody id="pred-body"></tbody>
68
+ </table>
69
+ <p id="no-rows" class="no-rows" hidden>No rows match the current filter.</p>
70
+ </section>
71
+ </main>
72
+
73
+ <footer class="site-footer">
74
+ <div class="wrap">
75
+ <p>
76
+ Predictions are model outputs for research exploration only — not clinical or experimental validation.
77
+ Score is the model's relative confidence within each ranking (1.0 = top). Download full tables:
78
+ <a href="https://joevondahab.github.io/pharmacology-graph/data/predictions_drug_protein.csv">drug–protein CSV</a> ·
79
+ <a href="https://joevondahab.github.io/pharmacology-graph/data/predictions_drug_indication.csv">drug–indication CSV</a>.
80
+ </p>
81
+ <p class="src">Model: Ablation 2 “No Drug Graphs” (~3.29M params), faithfully reconstructed from
82
+ <a href="https://arxiv.org/abs/2603.01537" target="_blank" rel="noopener">arXiv:2603.01537</a> —
83
+ learnable drug embeddings + ESM-2 proteins + heterogeneous GraphSAGE message passing.</p>
84
+ </div>
85
+ </footer>
86
+
87
+ <script src="app.js?v=p5"></script>
88
+ </body>
89
+ </html>
node_to_idx.npy DELETED
@@ -1,3 +0,0 @@
1
- version https://git-lfs.github.com/spec/v1
2
- oid sha256:b88d5415499ea4b8732915f1459f14b330c79b377886ee2137b2d65f3131a15d
3
- size 55513
 
 
 
 
protein_nodes_with_embeddings.csv DELETED
The diff for this file is too large to render. See raw diff
 
pyproject.toml DELETED
@@ -1,7 +0,0 @@
1
- [project]
2
- name = "pharmacology-graph"
3
- version = "0.1.0"
4
- description = "Add your description here"
5
- readme = "README.md"
6
- requires-python = ">=3.11"
7
- dependencies = []
 
 
 
 
 
 
 
 
requirements.txt DELETED
@@ -1,11 +0,0 @@
1
- # Hugging Face Spaces Requirements
2
- # Updated versions confirmed working (2025-10-11)
3
-
4
- gradio==4.44.1
5
- pandas==2.3.3
6
- numpy>=1.26.0,<2.0
7
- plotly==6.3.1
8
- networkx==3.2.1
9
- scikit-learn==1.4.0
10
-
11
- huggingface-hub==0.23.5
 
 
 
 
 
 
 
 
 
 
 
 
requirements_app.txt DELETED
@@ -1,14 +0,0 @@
1
- # Updated versions after testing (2025-01-24)
2
- # These versions are confirmed to work together without conflicts
3
-
4
- gradio==4.44.1
5
- pandas==2.3.3
6
- numpy>=1.26.0,<2.0 # NumPy 2.x breaks compatibility with pandas/numexpr
7
- plotly==6.3.1
8
- networkx==3.2.1
9
- scikit-learn==1.4.0==4.44.0
10
- pandas==2.2.0
11
- numpy==1.26.3
12
- plotly==5.18.0
13
- networkx==3.2.1
14
- scikit-learn==1.4.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
start_app.sh DELETED
@@ -1,24 +0,0 @@
1
- #!/bin/bash
2
-
3
- echo "🚀 Starting Pharmacology Graph App"
4
- echo "=================================="
5
- echo ""
6
-
7
- # Kill any existing instances
8
- pkill -f "python.*app.py" 2>/dev/null
9
- sleep 1
10
-
11
- # Clear port if needed
12
- lsof -ti:7860 | xargs kill -9 2>/dev/null
13
- sleep 1
14
-
15
- echo "✓ Port 7860 ready"
16
- echo "✓ Starting app..."
17
- echo ""
18
- echo "Open in browser: http://localhost:7860"
19
- echo "Press Ctrl+C to stop"
20
- echo ""
21
-
22
- # Start the app
23
- cd /home/joe/projects/pharmacology-graph
24
- python app.py
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
style.css ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ :root{
2
+ --bg:#0f1420; --panel:#171e2e; --panel2:#1f2840; --line:#2b3550;
3
+ --text:#e7ecf5; --muted:#9aa7c2; --accent:#5b8cff; --accent2:#7c5cff;
4
+ --known:#3fb27f; --known-bg:rgba(63,178,127,.14);
5
+ --novel:#e0a83b; --novel-bg:rgba(224,168,59,.14);
6
+ }
7
+ *{box-sizing:border-box}
8
+ body{margin:0;background:var(--bg);color:var(--text);
9
+ font:15px/1.5 system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif}
10
+ .wrap{max-width:960px;margin:0 auto;padding:0 20px}
11
+ .sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
12
+ a{color:var(--accent)}
13
+ .site-header{background:linear-gradient(160deg,#1a2236,#0f1420);
14
+ border-bottom:1px solid var(--line);padding:34px 0 26px}
15
+ h1{margin:0 0 6px;font-size:26px}
16
+ .tagline{margin:0;color:var(--muted);max-width:640px}
17
+ .tagline em{color:var(--text);font-style:normal;font-weight:600}
18
+ .meta-line{margin:10px 0 0;color:var(--muted);font-size:13px}
19
+
20
+ .search-box{position:relative;margin:26px 0 10px}
21
+ #search{width:100%;padding:15px 18px;font-size:16px;border-radius:12px;
22
+ background:var(--panel);border:1px solid var(--line);color:var(--text);outline:none}
23
+ #search:focus{border-color:var(--accent)}
24
+ .suggestions{list-style:none;margin:6px 0 0;padding:6px;position:absolute;z-index:20;
25
+ width:100%;background:var(--panel2);border:1px solid var(--line);border-radius:12px;
26
+ max-height:320px;overflow:auto;box-shadow:0 18px 40px rgba(0,0,0,.45)}
27
+ .suggestions li{padding:10px 12px;border-radius:8px;cursor:pointer;display:flex;
28
+ justify-content:space-between;gap:12px;align-items:center}
29
+ .suggestions li.active,.suggestions li:hover{background:var(--panel)}
30
+ .suggestions .sid{color:var(--muted);font-size:12px;font-variant-numeric:tabular-nums}
31
+ .suggestions mark{background:transparent;color:var(--accent);font-weight:700}
32
+
33
+ .empty{padding:40px 0;color:var(--muted);text-align:center}
34
+ .empty .hint{display:block;margin-top:8px;font-size:13px;opacity:.8}
35
+ .examples{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:20px}
36
+ .examples button{background:var(--panel);border:1px solid var(--line);color:var(--text);
37
+ padding:7px 13px;border-radius:20px;cursor:pointer;font-size:13px}
38
+ .examples button:hover{border-color:var(--accent)}
39
+
40
+ .drug-head{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;
41
+ align-items:flex-start;margin:8px 0 18px}
42
+ #drug-name{margin:0;font-size:23px}
43
+ .ext{font-size:13px}
44
+ .stat-cards{display:flex;gap:10px;flex-wrap:wrap}
45
+ .stat{background:var(--panel);border:1px solid var(--line);border-radius:10px;
46
+ padding:8px 14px;text-align:center;min-width:78px}
47
+ .stat b{display:block;font-size:19px}
48
+ .stat span{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}
49
+ .stat.known b{color:var(--known)} .stat.novel b{color:var(--novel)}
50
+
51
+ .controls{display:flex;justify-content:space-between;gap:14px;flex-wrap:wrap;
52
+ align-items:center;margin-bottom:12px}
53
+ .tabs{display:flex;gap:4px;background:var(--panel);padding:4px;border-radius:10px;border:1px solid var(--line)}
54
+ .tab{background:transparent;border:0;color:var(--muted);padding:8px 16px;border-radius:7px;cursor:pointer;font-size:14px}
55
+ .tab.active{background:var(--accent);color:#fff}
56
+ .filters{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
57
+ .chips{display:flex;gap:4px}
58
+ .chip{background:var(--panel);border:1px solid var(--line);color:var(--muted);
59
+ padding:7px 12px;border-radius:7px;cursor:pointer;font-size:13px}
60
+ .chip.active{color:var(--text);border-color:var(--accent)}
61
+ .table-filter{background:var(--panel);border:1px solid var(--line);color:var(--text);
62
+ padding:8px 12px;border-radius:7px;outline:none;font-size:13px;width:140px}
63
+ .downloads{display:flex;gap:6px}
64
+ .dl{background:var(--panel2);border:1px solid var(--line);color:var(--text);
65
+ padding:8px 11px;border-radius:7px;cursor:pointer;font-size:13px}
66
+ .dl:hover{border-color:var(--accent)}
67
+
68
+ .pred-table{width:100%;border-collapse:collapse;font-size:14px}
69
+ .pred-table th{text-align:left;color:var(--muted);font-weight:600;font-size:12px;
70
+ text-transform:uppercase;letter-spacing:.04em;padding:8px 10px;border-bottom:1px solid var(--line)}
71
+ .pred-table td{padding:9px 10px;border-bottom:1px solid var(--panel2)}
72
+ .pred-table tr:hover td{background:var(--panel)}
73
+ .c-rank{width:38px;color:var(--muted)} .c-score{width:150px} .c-status{width:80px}
74
+ .tname{font-weight:600}
75
+ .tid a{font-size:12px;color:var(--muted)} .tid a:hover{color:var(--accent)}
76
+ .scorewrap{display:flex;align-items:center;gap:8px}
77
+ .bar{flex:1;height:7px;border-radius:5px;background:var(--panel2);overflow:hidden}
78
+ .bar>i{display:block;height:100%;background:linear-gradient(90deg,var(--accent),var(--accent2))}
79
+ .scoreval{font-variant-numeric:tabular-nums;color:var(--muted);font-size:12px;min-width:42px}
80
+ .badge{font-size:11px;padding:3px 9px;border-radius:20px;font-weight:700;text-transform:uppercase;letter-spacing:.03em}
81
+ .badge.known{color:var(--known);background:var(--known-bg)}
82
+ .badge.novel{color:var(--novel);background:var(--novel-bg)}
83
+ .no-rows{color:var(--muted);text-align:center;padding:24px}
84
+
85
+ /* entity-type chips */
86
+ .chip.drug,.chip.ind,.chip.prot{font-size:11px;padding:2px 8px;border-radius:20px;font-weight:700;
87
+ text-transform:uppercase;letter-spacing:.03em;border:0;cursor:default;vertical-align:middle}
88
+ .chip.drug{color:#7fb2ff;background:rgba(91,140,255,.16)}
89
+ .chip.ind{color:#e08bd0;background:rgba(224,139,208,.16)}
90
+ .chip.prot{color:#6fd3c0;background:rgba(63,178,178,.16)}
91
+ .tagline .chip{margin:0 1px}
92
+ #type-chip{margin-bottom:6px;display:inline-block}
93
+ .suggestions .s-left{display:flex;align-items:center;gap:8px;min-width:0}
94
+ .suggestions .sname{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
95
+ .examples button{display:inline-flex;align-items:center;gap:7px}
96
+
97
+ .site-footer{margin-top:50px;border-top:1px solid var(--line);padding:22px 0 40px;color:var(--muted);font-size:13px}
98
+ .site-footer .src{margin-top:6px;font-size:12px;opacity:.75}
test_app.py DELETED
@@ -1,157 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Quick test script to verify app.py data loading and functions work
4
- Run this before launching the full Gradio app to catch errors early
5
- """
6
-
7
- import sys
8
-
9
- print("="*80)
10
- print("TESTING APP.PY DATA LOADING AND FUNCTIONS")
11
- print("="*80)
12
-
13
- # Test 1: Import libraries
14
- print("\n1. Testing library imports...")
15
- try:
16
- import pandas as pd
17
- import numpy as np
18
- import networkx as nx
19
- print(" ✓ Core libraries imported")
20
- except Exception as e:
21
- print(f" ✗ Error importing libraries: {e}")
22
- sys.exit(1)
23
-
24
- try:
25
- import gradio as gr
26
- print(" ✓ Gradio imported")
27
- except Exception as e:
28
- print(f" ✗ Error importing Gradio: {e}")
29
- print(" → Install with: uv pip install gradio")
30
- sys.exit(1)
31
-
32
- try:
33
- import plotly.graph_objects as go
34
- print(" ✓ Plotly imported")
35
- except Exception as e:
36
- print(f" ✗ Error importing Plotly: {e}")
37
- print(" → Install with: uv pip install plotly")
38
- sys.exit(1)
39
-
40
- # Test 2: Load data files
41
- print("\n2. Testing data file loading...")
42
-
43
- required_files = {
44
- 'drug_nodes.csv': None,
45
- 'protein_nodes_with_embeddings.csv': None,
46
- 'drug_effects.csv': None,
47
- 'drugs_interactions.csv': None,
48
- 'graph_embeddings.npy': None,
49
- 'node_to_idx.npy': None
50
- }
51
-
52
- errors = []
53
-
54
- try:
55
- drug_nodes = pd.read_csv('drug_nodes.csv')
56
- required_files['drug_nodes.csv'] = f"✓ {len(drug_nodes)} drugs"
57
- print(f" ✓ drug_nodes.csv: {len(drug_nodes)} rows")
58
- except Exception as e:
59
- errors.append(f"drug_nodes.csv: {e}")
60
- print(f" ✗ drug_nodes.csv: {e}")
61
-
62
- try:
63
- protein_nodes = pd.read_csv('protein_nodes_with_embeddings.csv')
64
- required_files['protein_nodes_with_embeddings.csv'] = f"✓ {len(protein_nodes)} proteins"
65
- print(f" ✓ protein_nodes_with_embeddings.csv: {len(protein_nodes)} rows")
66
- except Exception as e:
67
- errors.append(f"protein_nodes_with_embeddings.csv: {e}")
68
- print(f" ✗ protein_nodes_with_embeddings.csv: {e}")
69
-
70
- try:
71
- drug_effects = pd.read_csv('drug_effects.csv')
72
- required_files['drug_effects.csv'] = f"✓ {len(drug_effects)} effects"
73
- print(f" ✓ drug_effects.csv: {len(drug_effects)} rows")
74
- except Exception as e:
75
- errors.append(f"drug_effects.csv: {e}")
76
- print(f" ✗ drug_effects.csv: {e}")
77
-
78
- try:
79
- drugs_interactions = pd.read_csv('drugs_interactions.csv')
80
- required_files['drugs_interactions.csv'] = f"✓ {len(drugs_interactions)} interactions"
81
- print(f" ✓ drugs_interactions.csv: {len(drugs_interactions)} rows")
82
- except Exception as e:
83
- errors.append(f"drugs_interactions.csv: {e}")
84
- print(f" ✗ drugs_interactions.csv: {e}")
85
-
86
- try:
87
- embeddings = np.load('graph_embeddings.npy')
88
- required_files['graph_embeddings.npy'] = f"✓ {embeddings.shape}"
89
- print(f" ✓ graph_embeddings.npy: shape {embeddings.shape}")
90
- except Exception as e:
91
- errors.append(f"graph_embeddings.npy: {e}")
92
- print(f" ✗ graph_embeddings.npy: {e}")
93
-
94
- try:
95
- node_to_idx = np.load('node_to_idx.npy', allow_pickle=True).item()
96
- required_files['node_to_idx.npy'] = f"✓ {len(node_to_idx)} nodes"
97
- print(f" ✓ node_to_idx.npy: {len(node_to_idx)} nodes")
98
- except Exception as e:
99
- errors.append(f"node_to_idx.npy: {e}")
100
- print(f" ✗ node_to_idx.npy: {e}")
101
-
102
- # Test 3: Check data structure
103
- if not errors:
104
- print("\n3. Testing data structure...")
105
-
106
- # Check drug_nodes columns
107
- required_cols = ['drug_internal_id', 'drug_id', 'drug_name', 'smile']
108
- missing_cols = [col for col in required_cols if col not in drug_nodes.columns]
109
- if missing_cols:
110
- print(f" ✗ drug_nodes missing columns: {missing_cols}")
111
- errors.append(f"Missing columns in drug_nodes: {missing_cols}")
112
- else:
113
- print(f" ✓ drug_nodes has all required columns")
114
-
115
- # Check protein_nodes columns
116
- required_cols = ['protein_internal_id', 'protein_id', 'protein_name']
117
- missing_cols = [col for col in required_cols if col not in protein_nodes.columns]
118
- if missing_cols:
119
- print(f" ✗ protein_nodes missing columns: {missing_cols}")
120
- errors.append(f"Missing columns in protein_nodes: {missing_cols}")
121
- else:
122
- print(f" ✓ protein_nodes has all required columns")
123
-
124
- # Test search function
125
- print("\n4. Testing search function...")
126
- try:
127
- # Search for common drug
128
- test_queries = ['Morphine', 'Aspirin', 'CHEMBL25']
129
- for query in test_queries:
130
- matches = drug_nodes[
131
- drug_nodes['drug_name'].str.lower().str.contains(query.lower(), na=False) |
132
- drug_nodes['drug_id'].str.lower().str.contains(query.lower(), na=False)
133
- ]
134
- if len(matches) > 0:
135
- print(f" ✓ Search '{query}': found {len(matches)} results")
136
- else:
137
- print(f" ⚠ Search '{query}': no results (might be OK)")
138
- except Exception as e:
139
- print(f" ✗ Search function error: {e}")
140
- errors.append(f"Search error: {e}")
141
-
142
- # Summary
143
- print("\n" + "="*80)
144
- if errors:
145
- print("❌ TESTING FAILED")
146
- print("\nErrors found:")
147
- for i, error in enumerate(errors, 1):
148
- print(f" {i}. {error}")
149
- print("\nPlease fix these errors before running the app.")
150
- sys.exit(1)
151
- else:
152
- print("✅ ALL TESTS PASSED!")
153
- print("\nYour app should work correctly. Run it with:")
154
- print(" ./run_app.sh")
155
- print(" or")
156
- print(" python app.py")
157
- sys.exit(0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
top_50_predicted_drug_effects.csv DELETED
@@ -1,51 +0,0 @@
1
- drug_chembl_id,drug_name,effect_id,effect_name,similarity
2
- CHEMBL1257040,TRIFLUOPERAZINE HYDROCHLORIDE,D001714,Bipolar Disorder,0.545596
3
- CHEMBL198362,RIVAROXABAN,D009203,Myocardial Infarction,0.5439486
4
- CHEMBL435298,ESFLURBIPROFEN,D012216,Rheumatic Diseases,0.53732586
5
- CHEMBL1201782,FOSAPREPITANT DIMEGLUMINE,D009325,Nausea,0.5282381
6
- CHEMBL1709,SERTRALINE HYDROCHLORIDE,D016584,Panic Disorder,0.52576035
7
- CHEMBL1200470,ESOMEPRAZOLE SODIUM,D015043,Zollinger-Ellison Syndrome,0.5249922
8
- CHEMBL1951071,ARFORMOTEROL TARTRATE,D001986,Bronchial Spasm,0.51872176
9
- CHEMBL1744447,ROSUVASTATIN CALCIUM,D050171,Dyslipidemias,0.5174923
10
- CHEMBL2110372,RANITIDINE HYDROCHLORIDE,D004941,Esophagitis,0.5167754
11
- CHEMBL1138,EZETIMIBE,D050171,Dyslipidemias,0.5112109
12
- CHEMBL1201002,CARTEOLOL HYDROCHLORIDE,D009798,Ocular Hypertension,0.50021476
13
- CHEMBL3707246,OZANIMOD HYDROCHLORIDE,D003424,Crohn Disease,0.49325937
14
- CHEMBL4297088,CHLORHEXIDINE GLUCONATE,D003731,Dental Caries,0.49153596
15
- CHEMBL4297216,FEDRATINIB HYDROCHLORIDE,D013920,"Thrombocythemia, Essential",0.49133992
16
- CHEMBL1083385,CLOPIDOGREL BISULFATE,D011655,Pulmonary Embolism,0.49014294
17
- CHEMBL1027,TIAGABINE,D012640,Seizures,0.48950252
18
- CHEMBL2110372,RANITIDINE HYDROCHLORIDE,D005764,Gastroesophageal Reflux,0.48923716
19
- CHEMBL572,NITROFURANTOIN,D011704,Pyelonephritis,0.4890899
20
- CHEMBL503,LOVASTATIN,D050171,Dyslipidemias,0.48880434
21
- CHEMBL1059,PREGABALIN,D001007,Anxiety,0.4883793
22
- CHEMBL2105395,OSPEMIFENE,D016649,Primary Ovarian Insufficiency,0.48489913
23
- CHEMBL2105662,LOMITAPIDE MESYLATE,D050171,Dyslipidemias,0.48404413
24
- CHEMBL5314378,CASPOFUNGIN ACETATE,D016919,"Meningitis, Cryptococcal",0.48210338
25
- CHEMBL2218894,FLUVASTATIN SODIUM,D050171,Dyslipidemias,0.48126566
26
- CHEMBL3989844,DEXTROAMPHETAMINE SACCHARATE,D020181,"Sleep Apnea, Obstructive",0.48038968
27
- CHEMBL501,AMPHETAMINE SULFATE,D020181,"Sleep Apnea, Obstructive",0.4802664
28
- CHEMBL1650,CORTISONE ACETATE,D013167,"Spondylitis, Ankylosing",0.48004442
29
- CHEMBL1213250,CEFTOLOZANE SULFATE,D011704,Pyelonephritis,0.47739014
30
- CHEMBL1200402,AMLODIPINE BESYLATE,D050171,Dyslipidemias,0.47715414
31
- CHEMBL1364144,METHYLPREDNISOLONE ACETATE,D013167,"Spondylitis, Ankylosing",0.4765048
32
- CHEMBL406393,DEOXYCHOLIC ACID,D008105,"Liver Cirrhosis, Biliary",0.4760623
33
- CHEMBL3544971,DEXTROAMPHETAMINE SULFATE,D020181,"Sleep Apnea, Obstructive",0.4735379
34
- CHEMBL149972,PHENOBARBITAL SODIUM,D065768,Lennox Gastaut Syndrome,0.47247866
35
- CHEMBL1650,CORTISONE ACETATE,D006255,"Rhinitis, Allergic, Seasonal",0.46704072
36
- CHEMBL4650272,TRILACICLIB DIHYDROCHLORIDE,D018288,"Carcinoma, Small Cell",0.46695238
37
- CHEMBL1201782,FOSAPREPITANT DIMEGLUMINE,D000855,Anorexia,0.46403712
38
- CHEMBL3989923,PITAVASTATIN MAGNESIUM,D006938,Hyperlipoproteinemia Type II,0.46182984
39
- CHEMBL1650,CORTISONE ACETATE,D009205,Myocarditis,0.4610492
40
- CHEMBL1439,TAZOBACTAM SODIUM,D011704,Pyelonephritis,0.46001813
41
- CHEMBL1441059,ALBUTEROL SULFATE,D008173,"Lung Diseases, Obstructive",0.45689774
42
- CHEMBL650,METHYLPREDNISOLONE,D009879,"Ophthalmia, Sympathetic",0.45684493
43
- CHEMBL1200804,DICLOFENAC POTASSIUM,D013166,Spondylitis,0.45582262
44
- CHEMBL444633,RIFABUTIN,D001327,Autoimmune Diseases,0.45484185
45
- CHEMBL5314378,CASPOFUNGIN ACETATE,D009091,Mucormycosis,0.45365286
46
- CHEMBL137,METRONIDAZOLE,D012141,Respiratory Tract Infections,0.45224336
47
- CHEMBL675,ALENDRONATE SODIUM,D001847,Bone Diseases,0.45178664
48
- CHEMBL1269025,EDOXABAN,D054556,Venous Thromboembolism,0.4506775
49
- CHEMBL1200865,LOTEPREDNOL ETABONATE,D006255,"Rhinitis, Allergic, Seasonal",0.44942963
50
- CHEMBL1790041,RANITIDINE,D004381,Duodenal Ulcer,0.44910604
51
- CHEMBL89598,VIGABATRIN,D012640,Seizures,0.44849676
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
top_50_predicted_drug_protein.csv DELETED
@@ -1,51 +0,0 @@
1
- drug_chembl_id,drug_name,protein_id,protein_name,similarity
2
- CHEMBL3137320,TALAZOPARIB,CHEMBL2429709,Protein mono-ADP-ribosyltransferase PARP12,0.6001407
3
- CHEMBL3137320,TALAZOPARIB,CHEMBL2429708,Protein mono-ADP-ribosyltransferase PARP10,0.5721854
4
- CHEMBL1909072,PIPAMAZINE,CHEMBL1821,Muscarinic acetylcholine receptor M4,0.5399119
5
- CHEMBL419,MAFENIDE,CHEMBL3912,Carbonic anhydrase 13,0.5392196
6
- CHEMBL633,AMIODARONE,CHEMBL3371,5-hydroxytryptamine receptor 6,0.530897
7
- CHEMBL11,IMIPRAMINE,CHEMBL223,Alpha-1D adrenergic receptor,0.5215963
8
- CHEMBL17860,LOFEXIDINE,CHEMBL223,Alpha-1D adrenergic receptor,0.51608485
9
- CHEMBL1421,DASATINIB ANHYDROUS,CHEMBL2250,Tyrosine-protein kinase Blk,0.512127
10
- CHEMBL750,ZONISAMIDE,CHEMBL3510,Carbonic anhydrase 14,0.5120319
11
- CHEMBL1567,SUNITINIB MALATE,CHEMBL2007,Platelet-derived growth factor receptor alpha,0.5054646
12
- CHEMBL1173055,RUCAPARIB,CHEMBL2429709,Protein mono-ADP-ribosyltransferase PARP12,0.5037701
13
- CHEMBL5315125,DUVELISIB MONOHYDRATE,CHEMBL3267,"Phosphatidylinositol 4,5-bisphosphate 3-kinase catalytic subunit gamma isoform",0.5015378
14
- CHEMBL1963681,AVANAFIL,CHEMBL3977,"Cone cGMP-specific 3',5'-cyclic phosphodiesterase subunit alpha'",0.4979903
15
- CHEMBL1621,PALIPERIDONE,CHEMBL3371,5-hydroxytryptamine receptor 6,0.49721804
16
- CHEMBL762,OXYMETAZOLINE,CHEMBL217,D(2) dopamine receptor,0.4957183
17
- CHEMBL1078178,MOMELOTINIB,CHEMBL5970,Mitogen-activated protein kinase kinase kinase 3,0.49483612
18
- CHEMBL3301610,ABEMACICLIB,CHEMBL3529,Inhibitor of nuclear factor kappa-B kinase subunit epsilon,0.49270734
19
- CHEMBL3233142,LUMATEPERONE TOSYLATE,CHEMBL1899,5-hydroxytryptamine receptor 3A,0.49170905
20
- CHEMBL3301607,FILGOTINIB,CHEMBL1913,Platelet-derived growth factor receptor beta,0.48964554
21
- CHEMBL11,IMIPRAMINE,CHEMBL287,Sigma non-opioid intracellular receptor 1,0.48921353
22
- CHEMBL1535,HYDROXYCHLOROQUINE,CHEMBL245,Muscarinic acetylcholine receptor M3,0.48900294
23
- CHEMBL27,PROPRANOLOL,CHEMBL234,D(3) dopamine receptor,0.4874745
24
- CHEMBL4164059,PITOLISANT HYDROCHLORIDE,CHEMBL3371,5-hydroxytryptamine receptor 6,0.48707014
25
- CHEMBL669,CYCLOBENZAPRINE,CHEMBL1821,Muscarinic acetylcholine receptor M4,0.48594135
26
- CHEMBL978,METHACHOLINE,CHEMBL2035,Muscarinic acetylcholine receptor M5,0.48447487
27
- CHEMBL487253,BENDAMUSTINE,CHEMBL3310,Histone deacetylase 11,0.48373866
28
- CHEMBL86,METOCLOPRAMIDE,CHEMBL287,Sigma non-opioid intracellular receptor 1,0.48338604
29
- CHEMBL644,TRIMIPRAMINE,CHEMBL223,Alpha-1D adrenergic receptor,0.48287874
30
- CHEMBL808,ECONAZOLE,CHEMBL2035,Muscarinic acetylcholine receptor M5,0.4823854
31
- CHEMBL621,TRAZODONE,CHEMBL2056,D(1A) dopamine receptor,0.4819331
32
- CHEMBL1078178,MOMELOTINIB,CHEMBL3981,Serine/threonine-protein kinase 10,0.48185122
33
- CHEMBL726,FLUPHENAZINE,CHEMBL2035,Muscarinic acetylcholine receptor M5,0.48140538
34
- CHEMBL1421,DASATINIB ANHYDROUS,CHEMBL2007,Platelet-derived growth factor receptor alpha,0.48100707
35
- CHEMBL1123,DICYCLOMINE,CHEMBL222,Sodium-dependent noradrenaline transporter,0.4806236
36
- CHEMBL1834657,INFIGRATINIB PHOSPHATE,CHEMBL4722,Aurora kinase A,0.47917944
37
- CHEMBL1852688,INFIGRATINIB,CHEMBL5627,Leukocyte tyrosine kinase receptor,0.47882342
38
- CHEMBL671,THIOTEPA,CHEMBL1821,Muscarinic acetylcholine receptor M4,0.47861254
39
- CHEMBL24778,SILODOSIN,CHEMBL2056,D(1A) dopamine receptor,0.47838083
40
- CHEMBL3348923,TOVORAFENIB,CHEMBL2637,Mitogen-activated protein kinase 10,0.47791788
41
- CHEMBL81,RALOXIFENE,CHEMBL2035,Muscarinic acetylcholine receptor M5,0.47773397
42
- CHEMBL3301622,GILTERITINIB,CHEMBL3357,Interleukin-1 receptor-associated kinase 1,0.47708613
43
- CHEMBL1714574,TERCONAZOLE,CHEMBL231,Histamine H1 receptor,0.47602153
44
- CHEMBL644,TRIMIPRAMINE,CHEMBL1821,Muscarinic acetylcholine receptor M4,0.47474152
45
- CHEMBL1628227,DOXEPIN,CHEMBL233,Mu-type opioid receptor,0.47406977
46
- CHEMBL1633,KETOTIFEN FUMARATE,CHEMBL287,Sigma non-opioid intracellular receptor 1,0.47347492
47
- CHEMBL2035187,PACRITINIB,CHEMBL3778,Interleukin-1 receptor-associated kinase 4,0.47341335
48
- CHEMBL255863,NILOTINIB,CHEMBL3981,Serine/threonine-protein kinase 10,0.4726472
49
- CHEMBL1614701,SELUMETINIB,CHEMBL3938,Serine/threonine-protein kinase 16,0.47264248
50
- CHEMBL3545110,RIBOCICLIB,CHEMBL5261,Serine/threonine-protein kinase TAO1,0.47261065
51
- CHEMBL17860,LOFEXIDINE,CHEMBL2056,D(1A) dopamine receptor,0.47247177