Spaces:
Sleeping
Sleeping
Commit
·
40ccb79
1
Parent(s):
e2a4031
notebooks
Browse files- notebooks/2v1.ipynb +0 -261
- notebooks/UMAP_spectra_embeddings.ipynb +0 -0
- notebooks/attribute_viz.ipynb +0 -56
- notebooks/diff_rankers.ipynb +221 -0
- notebooks/eval_bad_instances.ipynb +4 -4
- notebooks/filip_viz.ipynb +254 -160
- notebooks/fine-grained_vs_global.ipynb +0 -0
- notebooks/good_vs_bad_instances.ipynb +691 -0
- notebooks/hyperparameter_tuning_result.ipynb +0 -0
- notebooks/msgym_result.ipynb +799 -0
- notebooks/peak_embedding_UMAP.ipynb +0 -0
- notebooks/peak_formula_analysis.ipynb +4 -4
- notebooks/scaffold_identification.ipynb +4 -4
- notebooks/spectra_sim.ipynb +0 -0
- notebooks/substructure_extraction.ipynb +0 -0
- notebooks/visualization.ipynb +50 -34
notebooks/2v1.ipynb
DELETED
|
@@ -1,261 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"cells": [
|
| 3 |
-
{
|
| 4 |
-
"cell_type": "code",
|
| 5 |
-
"execution_count": 33,
|
| 6 |
-
"id": "d3fe3363",
|
| 7 |
-
"metadata": {},
|
| 8 |
-
"outputs": [],
|
| 9 |
-
"source": [
|
| 10 |
-
"import pickle\n",
|
| 11 |
-
"from rdkit import Chem\n",
|
| 12 |
-
"import pandas\n",
|
| 13 |
-
"import matplotlib.pyplot as plt\n",
|
| 14 |
-
"import numpy as np\n",
|
| 15 |
-
"from rdkit.Chem.Draw import MolsToGridImage"
|
| 16 |
-
]
|
| 17 |
-
},
|
| 18 |
-
{
|
| 19 |
-
"cell_type": "code",
|
| 20 |
-
"execution_count": 2,
|
| 21 |
-
"id": "efdf1cc0",
|
| 22 |
-
"metadata": {},
|
| 23 |
-
"outputs": [],
|
| 24 |
-
"source": [
|
| 25 |
-
"with open(\"/data/yzhouc01/FILIP-MS/experiments/20250824_filipContrastive/result_MassSpecGym_retrieval_candidates_formula.pkl\", 'rb') as f:\n",
|
| 26 |
-
" result = pickle.load(f)"
|
| 27 |
-
]
|
| 28 |
-
},
|
| 29 |
-
{
|
| 30 |
-
"cell_type": "code",
|
| 31 |
-
"execution_count": null,
|
| 32 |
-
"id": "0113e869",
|
| 33 |
-
"metadata": {},
|
| 34 |
-
"outputs": [],
|
| 35 |
-
"source": []
|
| 36 |
-
},
|
| 37 |
-
{
|
| 38 |
-
"cell_type": "code",
|
| 39 |
-
"execution_count": 8,
|
| 40 |
-
"id": "de9cacb6",
|
| 41 |
-
"metadata": {},
|
| 42 |
-
"outputs": [
|
| 43 |
-
{
|
| 44 |
-
"data": {
|
| 45 |
-
"text/html": [
|
| 46 |
-
"<div>\n",
|
| 47 |
-
"<style scoped>\n",
|
| 48 |
-
" .dataframe tbody tr th:only-of-type {\n",
|
| 49 |
-
" vertical-align: middle;\n",
|
| 50 |
-
" }\n",
|
| 51 |
-
"\n",
|
| 52 |
-
" .dataframe tbody tr th {\n",
|
| 53 |
-
" vertical-align: top;\n",
|
| 54 |
-
" }\n",
|
| 55 |
-
"\n",
|
| 56 |
-
" .dataframe thead th {\n",
|
| 57 |
-
" text-align: right;\n",
|
| 58 |
-
" }\n",
|
| 59 |
-
"</style>\n",
|
| 60 |
-
"<table border=\"1\" class=\"dataframe\">\n",
|
| 61 |
-
" <thead>\n",
|
| 62 |
-
" <tr style=\"text-align: right;\">\n",
|
| 63 |
-
" <th></th>\n",
|
| 64 |
-
" <th>identifier</th>\n",
|
| 65 |
-
" <th>candidates</th>\n",
|
| 66 |
-
" <th>scores</th>\n",
|
| 67 |
-
" <th>labels</th>\n",
|
| 68 |
-
" <th>rank</th>\n",
|
| 69 |
-
" </tr>\n",
|
| 70 |
-
" </thead>\n",
|
| 71 |
-
" <tbody>\n",
|
| 72 |
-
" <tr>\n",
|
| 73 |
-
" <th>17551</th>\n",
|
| 74 |
-
" <td>MassSpecGymID0414164</td>\n",
|
| 75 |
-
" <td>[CN(C)[C@H]1[C@@H]2[C@H]([C@@H]3C(=C)C4=C(C=CC...</td>\n",
|
| 76 |
-
" <td>[0.5793027877807617, 0.5367040038108826, 0.487...</td>\n",
|
| 77 |
-
" <td>[True, False, False, False, False, False, Fals...</td>\n",
|
| 78 |
-
" <td>7</td>\n",
|
| 79 |
-
" </tr>\n",
|
| 80 |
-
" <tr>\n",
|
| 81 |
-
" <th>17552</th>\n",
|
| 82 |
-
" <td>MassSpecGymID0414165</td>\n",
|
| 83 |
-
" <td>[CN(C)[C@H]1[C@@H]2[C@H]([C@@H]3C(=C)C4=C(C(=C...</td>\n",
|
| 84 |
-
" <td>[0.38384538888931274, 0.24421672523021698, 0.2...</td>\n",
|
| 85 |
-
" <td>[True, False, False, False, False, False, Fals...</td>\n",
|
| 86 |
-
" <td>31</td>\n",
|
| 87 |
-
" </tr>\n",
|
| 88 |
-
" <tr>\n",
|
| 89 |
-
" <th>17553</th>\n",
|
| 90 |
-
" <td>MassSpecGymID0414166</td>\n",
|
| 91 |
-
" <td>[C[C@H]1/C=C/C=C/2\\CO[C@H]3[C@@]2([C@@H](C=C([...</td>\n",
|
| 92 |
-
" <td>[0.6297411918640137, 0.5269991159439087, 0.183...</td>\n",
|
| 93 |
-
" <td>[True, False, False, False, False, False, Fals...</td>\n",
|
| 94 |
-
" <td>11</td>\n",
|
| 95 |
-
" </tr>\n",
|
| 96 |
-
" <tr>\n",
|
| 97 |
-
" <th>17554</th>\n",
|
| 98 |
-
" <td>MassSpecGymID0414167</td>\n",
|
| 99 |
-
" <td>[C[C@H]1/C=C/C=C/2\\CO[C@H]3[C@@]2([C@@H](C=C([...</td>\n",
|
| 100 |
-
" <td>[0.613699197769165, 0.554176390171051, 0.21911...</td>\n",
|
| 101 |
-
" <td>[True, False, False, False, False, False, Fals...</td>\n",
|
| 102 |
-
" <td>12</td>\n",
|
| 103 |
-
" </tr>\n",
|
| 104 |
-
" <tr>\n",
|
| 105 |
-
" <th>17555</th>\n",
|
| 106 |
-
" <td>MassSpecGymID0414171</td>\n",
|
| 107 |
-
" <td>[C[C@@]1([C@H]2C[C@H]3[C@@H](C(=O)C(=C([C@]3(C...</td>\n",
|
| 108 |
-
" <td>[0.5223979949951172, 0.5548790693283081, 0.512...</td>\n",
|
| 109 |
-
" <td>[True, False, False, False, False, False, Fals...</td>\n",
|
| 110 |
-
" <td>14</td>\n",
|
| 111 |
-
" </tr>\n",
|
| 112 |
-
" </tbody>\n",
|
| 113 |
-
"</table>\n",
|
| 114 |
-
"</div>"
|
| 115 |
-
],
|
| 116 |
-
"text/plain": [
|
| 117 |
-
" identifier \\\n",
|
| 118 |
-
"17551 MassSpecGymID0414164 \n",
|
| 119 |
-
"17552 MassSpecGymID0414165 \n",
|
| 120 |
-
"17553 MassSpecGymID0414166 \n",
|
| 121 |
-
"17554 MassSpecGymID0414167 \n",
|
| 122 |
-
"17555 MassSpecGymID0414171 \n",
|
| 123 |
-
"\n",
|
| 124 |
-
" candidates \\\n",
|
| 125 |
-
"17551 [CN(C)[C@H]1[C@@H]2[C@H]([C@@H]3C(=C)C4=C(C=CC... \n",
|
| 126 |
-
"17552 [CN(C)[C@H]1[C@@H]2[C@H]([C@@H]3C(=C)C4=C(C(=C... \n",
|
| 127 |
-
"17553 [C[C@H]1/C=C/C=C/2\\CO[C@H]3[C@@]2([C@@H](C=C([... \n",
|
| 128 |
-
"17554 [C[C@H]1/C=C/C=C/2\\CO[C@H]3[C@@]2([C@@H](C=C([... \n",
|
| 129 |
-
"17555 [C[C@@]1([C@H]2C[C@H]3[C@@H](C(=O)C(=C([C@]3(C... \n",
|
| 130 |
-
"\n",
|
| 131 |
-
" scores \\\n",
|
| 132 |
-
"17551 [0.5793027877807617, 0.5367040038108826, 0.487... \n",
|
| 133 |
-
"17552 [0.38384538888931274, 0.24421672523021698, 0.2... \n",
|
| 134 |
-
"17553 [0.6297411918640137, 0.5269991159439087, 0.183... \n",
|
| 135 |
-
"17554 [0.613699197769165, 0.554176390171051, 0.21911... \n",
|
| 136 |
-
"17555 [0.5223979949951172, 0.5548790693283081, 0.512... \n",
|
| 137 |
-
"\n",
|
| 138 |
-
" labels rank \n",
|
| 139 |
-
"17551 [True, False, False, False, False, False, Fals... 7 \n",
|
| 140 |
-
"17552 [True, False, False, False, False, False, Fals... 31 \n",
|
| 141 |
-
"17553 [True, False, False, False, False, False, Fals... 11 \n",
|
| 142 |
-
"17554 [True, False, False, False, False, False, Fals... 12 \n",
|
| 143 |
-
"17555 [True, False, False, False, False, False, Fals... 14 "
|
| 144 |
-
]
|
| 145 |
-
},
|
| 146 |
-
"execution_count": 8,
|
| 147 |
-
"metadata": {},
|
| 148 |
-
"output_type": "execute_result"
|
| 149 |
-
}
|
| 150 |
-
],
|
| 151 |
-
"source": [
|
| 152 |
-
"result.tail()"
|
| 153 |
-
]
|
| 154 |
-
},
|
| 155 |
-
{
|
| 156 |
-
"cell_type": "code",
|
| 157 |
-
"execution_count": 52,
|
| 158 |
-
"id": "f420c511",
|
| 159 |
-
"metadata": {},
|
| 160 |
-
"outputs": [
|
| 161 |
-
{
|
| 162 |
-
"name": "stderr",
|
| 163 |
-
"output_type": "stream",
|
| 164 |
-
"text": [
|
| 165 |
-
"[19:30:58] \n",
|
| 166 |
-
"\n",
|
| 167 |
-
"****\n",
|
| 168 |
-
"Pre-condition Violation\n",
|
| 169 |
-
"bad size\n",
|
| 170 |
-
"Violation occurred on line 183 in file /project/build/temp.linux-x86_64-cpython-311/rdkit/Code/GraphMol/MolDraw2D/MolDraw2D.cpp\n",
|
| 171 |
-
"Failed Expression: !legends || legends->size() == mols.size()\n",
|
| 172 |
-
"----------\n",
|
| 173 |
-
"Stacktrace:\n",
|
| 174 |
-
"----------\n",
|
| 175 |
-
"****\n",
|
| 176 |
-
"\n"
|
| 177 |
-
]
|
| 178 |
-
},
|
| 179 |
-
{
|
| 180 |
-
"ename": "RuntimeError",
|
| 181 |
-
"evalue": "Pre-condition Violation\n\tbad size\n\tViolation occurred on line 183 in file Code/GraphMol/MolDraw2D/MolDraw2D.cpp\n\tFailed Expression: !legends || legends->size() == mols.size()\n\tRDKIT: 2024.03.5\n\tBOOST: 1_85\n",
|
| 182 |
-
"output_type": "error",
|
| 183 |
-
"traceback": [
|
| 184 |
-
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
| 185 |
-
"\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)",
|
| 186 |
-
"Cell \u001b[0;32mIn[52], line 21\u001b[0m\n\u001b[1;32m 18\u001b[0m cand2 \u001b[38;5;241m=\u001b[39m Chem\u001b[38;5;241m.\u001b[39mMolFromSmiles(candidates[sorted_scores][\u001b[38;5;241m2\u001b[39m])\n\u001b[1;32m 20\u001b[0m mols \u001b[38;5;241m=\u001b[39m [target, cand, cand1]\n\u001b[0;32m---> 21\u001b[0m img \u001b[38;5;241m=\u001b[39m \u001b[43mMolsToGridImage\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmols\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmolsPerRow\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msubImgSize\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m200\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m200\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlegends\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mtarget (\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mtarget_score\u001b[49m\u001b[38;5;132;43;01m:\u001b[39;49;00m\u001b[38;5;124;43m.3f\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m)\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mcand@1 (\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mcand1_score\u001b[49m\u001b[38;5;132;43;01m:\u001b[39;49;00m\u001b[38;5;124;43m.3f\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m)\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 23\u001b[0m plt\u001b[38;5;241m.\u001b[39mshow()\n\u001b[1;32m 24\u001b[0m display(img)\n",
|
| 187 |
-
"File \u001b[0;32m/data/yzc-conda/spec/lib/python3.11/site-packages/rdkit/Chem/Draw/IPythonConsole.py:271\u001b[0m, in \u001b[0;36mShowMols\u001b[0;34m(mols, maxMols, **kwargs)\u001b[0m\n\u001b[1;32m 268\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdrawOptions\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m kwargs:\n\u001b[1;32m 269\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mdrawOptions\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m drawOptions\n\u001b[0;32m--> 271\u001b[0m res \u001b[38;5;241m=\u001b[39m \u001b[43mfn\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmols\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 272\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m InteractiveRenderer\u001b[38;5;241m.\u001b[39misEnabled():\n\u001b[1;32m 273\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m HTML(res)\n",
|
| 188 |
-
"File \u001b[0;32m/data/yzc-conda/spec/lib/python3.11/site-packages/rdkit/Chem/Draw/__init__.py:821\u001b[0m, in \u001b[0;36mMolsToGridImage\u001b[0;34m(mols, molsPerRow, subImgSize, legends, highlightAtomLists, highlightBondLists, useSVG, returnPNG, **kwargs)\u001b[0m\n\u001b[1;32m 817\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _MolsToGridSVG(mols, molsPerRow\u001b[38;5;241m=\u001b[39mmolsPerRow, subImgSize\u001b[38;5;241m=\u001b[39msubImgSize, legends\u001b[38;5;241m=\u001b[39mlegends,\n\u001b[1;32m 818\u001b[0m highlightAtomLists\u001b[38;5;241m=\u001b[39mhighlightAtomLists,\n\u001b[1;32m 819\u001b[0m highlightBondLists\u001b[38;5;241m=\u001b[39mhighlightBondLists, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 820\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 821\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_MolsToGridImage\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmols\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmolsPerRow\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmolsPerRow\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43msubImgSize\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43msubImgSize\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlegends\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlegends\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 822\u001b[0m \u001b[43m \u001b[49m\u001b[43mhighlightAtomLists\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhighlightAtomLists\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 823\u001b[0m \u001b[43m \u001b[49m\u001b[43mhighlightBondLists\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhighlightBondLists\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mreturnPNG\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mreturnPNG\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
| 189 |
-
"File \u001b[0;32m/data/yzc-conda/spec/lib/python3.11/site-packages/rdkit/Chem/Draw/__init__.py:567\u001b[0m, in \u001b[0;36m_MolsToGridImage\u001b[0;34m(mols, molsPerRow, subImgSize, legends, highlightAtomLists, highlightBondLists, drawOptions, returnPNG, **kwargs)\u001b[0m\n\u001b[1;32m 565\u001b[0m \u001b[38;5;28msetattr\u001b[39m(dops, k, v)\n\u001b[1;32m 566\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m kwargs[k]\n\u001b[0;32m--> 567\u001b[0m \u001b[43md2d\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mDrawMolecules\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mmols\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mlegends\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mlegends\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01mor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mhighlightAtoms\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhighlightAtomLists\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 568\u001b[0m \u001b[43m \u001b[49m\u001b[43mhighlightBonds\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhighlightBondLists\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 569\u001b[0m d2d\u001b[38;5;241m.\u001b[39mFinishDrawing()\n\u001b[1;32m 570\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m returnPNG:\n",
|
| 190 |
-
"\u001b[0;31mRuntimeError\u001b[0m: Pre-condition Violation\n\tbad size\n\tViolation occurred on line 183 in file Code/GraphMol/MolDraw2D/MolDraw2D.cpp\n\tFailed Expression: !legends || legends->size() == mols.size()\n\tRDKIT: 2024.03.5\n\tBOOST: 1_85\n"
|
| 191 |
-
]
|
| 192 |
-
},
|
| 193 |
-
{
|
| 194 |
-
"data": {
|
| 195 |
-
"image/png": "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3nuvBgwYoA4dOuiHH37QqlWrdNVVV130cQcNGqQXXnhBr732mlq2bKm7775bTZo04RkfFcjHXGbXlAoLCxUcHKyCggIFBQVVdjmA14oZk+myvndqn0qqBN5q/vz5Gjx4sAoKClSjRo3KLgeXOXc+v7nhFAAgSZo3b54aNmyounXr6quvvtLo0aN1zz33EDzgcYQPAICkU8+9mDBhgvLy8hQZGam7775bTz/9dGWXhSqI8AEAkCSNGjVKo0aNquwycAXghlMAgFsux9l04V0IHwAAjzhy5Iief/55de7cWREREapbt666du2q//7v/z5rCntJeuONN9SlSxcFBQXJx8dHhw4dKtd5f//9dz3wwAMKCgpSSEiIhgwZoiNHjlxwv+zsbHXt2lW1atVSUFCQbr75Zv373/8+q19RUZGuv/56+fj4KCcnx9m+d+9e+fj4nLWsX7++XK/jSkL4AABcsk2bNql58+ZasmSJkpKS9OGHH2rp0qVKTEzUnDlz1KFDB5cHfUmnfjrbq1cvPfHEE5d07gceeEDbtm1zTpK3du1aDR069Lz7ZGdnq1evXurRo4c2btyoL774QikpKWc9bEw69XXU+Z738cknnzgn0jt48KDatWt3Sa/nilDBM+y6zZ0peQGcW/3RS10WVD0nT540zz77rImNjTX+/v4mOjraPPXUU87to0aNMo0bNzY1atQwDRo0MOPGjTMnTpxwbp84caJp06aNmTdvnqlfv74JCgoy/fv3N4WFhc4+R44cMQMGDDC1atUyERER5rnnnjO33HKLeeyxx5x99u7da8LCwswbb7xRZp2lpaVm/Pjx5oYbbnA5/2mffvqpkWT++OMPt8dg+/btRpL54osvnG3/7//9P+Pj42MOHDhwzv3i4uLMuHHjLnj8ZcuWmaZNm5pt27YZSWbLli3ObXv27Dmr7Urmzuc3Vz4AwEulpaVp6tSpGj9+vLZv364FCxa4zOAaGBioOXPmaPv27Xr55Zf15ptv6sUXX3Q5xq5du7RkyRItXbpUS5cu1Zo1azR16lTn9pEjR2rNmjX64IMP9PHHH2v16tXavHmzyzHGjBmjwYMHKykpST/++KP+8z//U2FhYerZs6emTJmihx9+WE8++aRq1aqlf/7zn269xi5dumjQoEHn3J6dna2QkBC1b9/e2da9e3f5+vqeNZ/NaT///LM2bNigsLAw3XjjjQoPD9ctt9yizz77zKVffn6+kpKS9D//8z+qWbPmOWu4/fbbFRYWps6dO+vDDz906/VdqQgfAOCFDh8+rJdfflnTpk1TYmKiYmNj1blzZ/3tb39z9hk3bpxuvPFGxcTEKCEhQY8//rgWLlzocpzS0lLNmTNHLVu21E033aQBAwYoKytL0ql7ON5++20999xz6tatm1q1aqW5c+e63L9x5MgRZWZmOidlS0xMlJ+fn5YvX66BAwdq2rRpOn78uHPbihUr3Hqd9erVO+/Ebnl5eQoLC3Npq1atmkJDQ5WXl1fmPrt375YkTZo0SUlJSVq+fLluuOEGdevWTd9//72kU3O6DBo0SMOGDXMJNn9Wu3ZtPf/883rvvfeUmZmpzp07q2/fvgSQi8BPbQHAC3377bcqKipSt27dztnn3Xff1SuvvKJdu3bpyJEjKikpOevJkzExMQoMDHSuR0ZGOu/N2LVrl06cOKG4uDjn9tDQUDVp0sS5vmPHDsXExOjqq6/W0aNHtWrVKh04cEBRUVG64YYbtHr1aufj0CMjI/XHH3+49TrnzZvnVv+LcXq+mYceekiDBw+WJLVt21ZZWVl65513lJ6erldffVWHDx9WWlraOY9Tp04dpaamOtc7dOign376SdOnT9ftt9/u8bqrEq58AIAXutBTR7Ozs/XAAw/otttu09KlS7VlyxaNHTtWJ06ccOlXvXp1l3UfHx/nh/PFKCkpcdZyOmScnuFWOnV14LTNmzerUaNGF33sixEREXHWjawlJSX6/fffFRERUeY+p6+knDlbbrNmzZxz0axatUrZ2dlyOByqVq2as+727dsrMTHxnPXExcVp586d5X49VwrCBwB4ocaNG6tGjRrOr0jO9Pnnn6t+/foaO3as2rdvr8aNG+uHH35w6xyxsbGqXr26y70Tf/zxh3bs2OFcb9iwoXbs2KHi4mKFhISoRYsWevrpp1VcXKzvvvtOGRkZKi0tVWZmpmbMmKGUlJTyveBziI+P16FDh7Rp0yZn26pVq1RaWupyxebPYmJiFBUVpdzcXJf2HTt2qH79+pKkV155RV999ZVycnKUk5OjZcuWSTp1Nel8T33Nyck579dEOIWvXQDACwUEBGj06NEaNWqU/P391alTJ/3yyy/atm2bhgwZosaNG2vfvn3KyMhQhw4dlJmZqcWLF7t1jtq1a2vIkCEaOXKkrr76aoWFhWns2LEuP0etU6eOWrdurX/+858aPHiwZs+erTvvvFMvvPCCIiIidPvtt+vNN9/Utm3btHDhQjVr1sy5b15envLy8pxXCrZu3arAwEDVq1dPoaGhkqSBAweqbt26Sk9PL7PGZs2aqVevXkpKStKsWbNUXFyslJQU3Xvvvc6fxx44cEDdunXTvHnz1LFjR/n4+GjkyJGaOHGi2rRpo+uvv15z587Vd999p/fff1/SqXtNzhwL6VQgu/baayVJc+fOlb+/v9q2bStJWrRokd555x299dZbbo3zlYjwAQBeavz48apWrZomTJign376SZGRkRo2bJikU7/AGDFihFJSUlRUVKQ+ffpo/PjxmjRpklvnmD59uo4cOaKEhAQFBgbqH//4hwoKClz6pKenKyEhQW3atFGHDh20b98+HTx4UGFhYTp+/LieffZZhYSEnHXsWbNmafLkyc71m2++WZI0e/Zs5y9c9u3bV+azN/5s/vz5SklJUbdu3eTr66t+/frplVdecW4vLi5Wbm6ujh075mwbPny4jh8/rhEjRuj3339XmzZttHLlSsXGxro1PlOmTNEPP/ygatWqqWnTpnr33Xd11113uXWMK5GPMcZUdhF/5s6UvADOLWZMpsv63ql9KqkSXAnmzp2rxx57TH//+981cOBAxcbG6uTJk9q4caPS09PVtWtXjRgxorLLRAVy5/Obez4AAJcsMTFRa9eu1fbt29WmTRv5+/vL4XDowQcfVOfOnZWcnFzZJeIywtcuAJzOvFoiccUEF69169Z6//33VVJSovz8fDkcDtWpU6eyy8JliPABAPCoatWqqW7dupVdBi5jfO0CAACsInwAAACrCB8AAMAqwgcAALCK8AEAAKwifAAAAKvcCh/p6enq0KGDAgMDFRYWpr59+541MU+XLl3k4+Pjspx+3C8AAIBb4WPNmjVKTk7W+vXrtXLlShUXF6tHjx46evSoS7+kpCQdPHjQuUybNs2jRQMAAO/l1kPGli9f7rI+Z84chYWFadOmTc4JgSSpZs2aioiI8EyFAACgSrmkez5Oz2x4eurj0+bPn686deqoZcuWSktLc5lJ8ExFRUUqLCx0WQAAQNVV7serl5aWavjw4erUqZNatmzpbL///vtVv359RUVF6euvv9bo0aOVm5urRYsW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",
|
| 196 |
-
"text/plain": [
|
| 197 |
-
"<Figure size 640x480 with 1 Axes>"
|
| 198 |
-
]
|
| 199 |
-
},
|
| 200 |
-
"metadata": {},
|
| 201 |
-
"output_type": "display_data"
|
| 202 |
-
}
|
| 203 |
-
],
|
| 204 |
-
"source": [
|
| 205 |
-
"row = result[result['rank'] ==2].sample(1)\n",
|
| 206 |
-
"scores = row['scores'].iloc[0]\n",
|
| 207 |
-
"plt.hist(scores, bins=np.arange(0,1,0.01))\n",
|
| 208 |
-
"ax = plt.gca()\n",
|
| 209 |
-
"\n",
|
| 210 |
-
"target_score = scores[0]\n",
|
| 211 |
-
"cand1_score = np.max(scores)\n",
|
| 212 |
-
"\n",
|
| 213 |
-
"plt.text(0.665, 0.9, f'target: {target_score:.3f}',transform=ax.transAxes,)\n",
|
| 214 |
-
"plt.text(0.665, 0.86, f'cand@1: {cand1_score:.3f}',transform=ax.transAxes,)\n",
|
| 215 |
-
"\n",
|
| 216 |
-
"candidates = np.array(row['candidates'].iloc[0])\n",
|
| 217 |
-
"target = Chem.MolFromSmiles(candidates[0])\n",
|
| 218 |
-
"sorted_scores = np.argsort(scores)\n",
|
| 219 |
-
"\n",
|
| 220 |
-
"cand = Chem.MolFromSmiles(candidates[sorted_scores][0])\n",
|
| 221 |
-
"cand1 = Chem.MolFromSmiles(candidates[sorted_scores][1])\n",
|
| 222 |
-
"cand2 = Chem.MolFromSmiles(candidates[sorted_scores][2])\n",
|
| 223 |
-
"\n",
|
| 224 |
-
"mols = [target, cand, cand1]\n",
|
| 225 |
-
"img = MolsToGridImage(mols, molsPerRow=3, subImgSize=(200, 200), legends=[f'target ({target_score:.3f})', f'cand@1 ({cand1_score:.3f})'])\n",
|
| 226 |
-
"\n",
|
| 227 |
-
"plt.show()\n",
|
| 228 |
-
"display(img)"
|
| 229 |
-
]
|
| 230 |
-
},
|
| 231 |
-
{
|
| 232 |
-
"cell_type": "code",
|
| 233 |
-
"execution_count": null,
|
| 234 |
-
"id": "541cd229",
|
| 235 |
-
"metadata": {},
|
| 236 |
-
"outputs": [],
|
| 237 |
-
"source": []
|
| 238 |
-
}
|
| 239 |
-
],
|
| 240 |
-
"metadata": {
|
| 241 |
-
"kernelspec": {
|
| 242 |
-
"display_name": "spec",
|
| 243 |
-
"language": "python",
|
| 244 |
-
"name": "python3"
|
| 245 |
-
},
|
| 246 |
-
"language_info": {
|
| 247 |
-
"codemirror_mode": {
|
| 248 |
-
"name": "ipython",
|
| 249 |
-
"version": 3
|
| 250 |
-
},
|
| 251 |
-
"file_extension": ".py",
|
| 252 |
-
"mimetype": "text/x-python",
|
| 253 |
-
"name": "python",
|
| 254 |
-
"nbconvert_exporter": "python",
|
| 255 |
-
"pygments_lexer": "ipython3",
|
| 256 |
-
"version": "3.11.7"
|
| 257 |
-
}
|
| 258 |
-
},
|
| 259 |
-
"nbformat": 4,
|
| 260 |
-
"nbformat_minor": 5
|
| 261 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notebooks/UMAP_spectra_embeddings.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/attribute_viz.ipynb
DELETED
|
@@ -1,56 +0,0 @@
|
|
| 1 |
-
{
|
| 2 |
-
"cells": [
|
| 3 |
-
{
|
| 4 |
-
"cell_type": "code",
|
| 5 |
-
"execution_count": null,
|
| 6 |
-
"id": "76c4ed82",
|
| 7 |
-
"metadata": {},
|
| 8 |
-
"outputs": [],
|
| 9 |
-
"source": [
|
| 10 |
-
"# preprocessing code\n",
|
| 11 |
-
"\n",
|
| 12 |
-
"# input is a labeled formulas file from mist code\n",
|
| 13 |
-
"# molecule is smiles\n",
|
| 14 |
-
"\n"
|
| 15 |
-
]
|
| 16 |
-
},
|
| 17 |
-
{
|
| 18 |
-
"cell_type": "code",
|
| 19 |
-
"execution_count": null,
|
| 20 |
-
"id": "04ea680e",
|
| 21 |
-
"metadata": {},
|
| 22 |
-
"outputs": [],
|
| 23 |
-
"source": [
|
| 24 |
-
"# load data"
|
| 25 |
-
]
|
| 26 |
-
},
|
| 27 |
-
{
|
| 28 |
-
"cell_type": "code",
|
| 29 |
-
"execution_count": null,
|
| 30 |
-
"id": "990ccd94",
|
| 31 |
-
"metadata": {},
|
| 32 |
-
"outputs": [],
|
| 33 |
-
"source": [
|
| 34 |
-
"# load model"
|
| 35 |
-
]
|
| 36 |
-
},
|
| 37 |
-
{
|
| 38 |
-
"cell_type": "code",
|
| 39 |
-
"execution_count": null,
|
| 40 |
-
"id": "77334bf5",
|
| 41 |
-
"metadata": {},
|
| 42 |
-
"outputs": [],
|
| 43 |
-
"source": [
|
| 44 |
-
"# encode spectra and molecules\n",
|
| 45 |
-
"# vilisualize attributes"
|
| 46 |
-
]
|
| 47 |
-
}
|
| 48 |
-
],
|
| 49 |
-
"metadata": {
|
| 50 |
-
"language_info": {
|
| 51 |
-
"name": "python"
|
| 52 |
-
}
|
| 53 |
-
},
|
| 54 |
-
"nbformat": 4,
|
| 55 |
-
"nbformat_minor": 5
|
| 56 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
notebooks/diff_rankers.ipynb
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": 15,
|
| 6 |
+
"id": "b1c8f5ac",
|
| 7 |
+
"metadata": {},
|
| 8 |
+
"outputs": [],
|
| 9 |
+
"source": [
|
| 10 |
+
"import pickle\n",
|
| 11 |
+
"import numpy as np\n",
|
| 12 |
+
"import pandas as pd\n",
|
| 13 |
+
"import matplotlib.pyplot as plt"
|
| 14 |
+
]
|
| 15 |
+
},
|
| 16 |
+
{
|
| 17 |
+
"cell_type": "code",
|
| 18 |
+
"execution_count": 2,
|
| 19 |
+
"id": "2856583d",
|
| 20 |
+
"metadata": {},
|
| 21 |
+
"outputs": [],
|
| 22 |
+
"source": [
|
| 23 |
+
"result_paths = [\"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/main_result/result_MassSpecGym_retrieval_candidates_mass.pkl\",\n",
|
| 24 |
+
"\"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/result_top5.pkl\",\n",
|
| 25 |
+
"\"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/result_softmax05.pkl\",\n",
|
| 26 |
+
"\"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/result_geom1e-6.pkl\"]\n",
|
| 27 |
+
"\n",
|
| 28 |
+
"methods = ['standard', 'top5', 'softmax', 'geom']"
|
| 29 |
+
]
|
| 30 |
+
},
|
| 31 |
+
{
|
| 32 |
+
"cell_type": "code",
|
| 33 |
+
"execution_count": 4,
|
| 34 |
+
"id": "ad1083b0",
|
| 35 |
+
"metadata": {},
|
| 36 |
+
"outputs": [],
|
| 37 |
+
"source": [
|
| 38 |
+
"result_dict = {}\n",
|
| 39 |
+
"for p, m in zip(result_paths, methods):\n",
|
| 40 |
+
" with open(p, 'rb') as f:\n",
|
| 41 |
+
" result_dict[m] = pickle.load(f)"
|
| 42 |
+
]
|
| 43 |
+
},
|
| 44 |
+
{
|
| 45 |
+
"cell_type": "code",
|
| 46 |
+
"execution_count": 9,
|
| 47 |
+
"id": "42f87b88",
|
| 48 |
+
"metadata": {},
|
| 49 |
+
"outputs": [
|
| 50 |
+
{
|
| 51 |
+
"data": {
|
| 52 |
+
"text/html": [
|
| 53 |
+
"<div>\n",
|
| 54 |
+
"<style scoped>\n",
|
| 55 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 56 |
+
" vertical-align: middle;\n",
|
| 57 |
+
" }\n",
|
| 58 |
+
"\n",
|
| 59 |
+
" .dataframe tbody tr th {\n",
|
| 60 |
+
" vertical-align: top;\n",
|
| 61 |
+
" }\n",
|
| 62 |
+
"\n",
|
| 63 |
+
" .dataframe thead th {\n",
|
| 64 |
+
" text-align: right;\n",
|
| 65 |
+
" }\n",
|
| 66 |
+
"</style>\n",
|
| 67 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 68 |
+
" <thead>\n",
|
| 69 |
+
" <tr style=\"text-align: right;\">\n",
|
| 70 |
+
" <th></th>\n",
|
| 71 |
+
" <th>1</th>\n",
|
| 72 |
+
" <th>5</th>\n",
|
| 73 |
+
" <th>20</th>\n",
|
| 74 |
+
" </tr>\n",
|
| 75 |
+
" </thead>\n",
|
| 76 |
+
" <tbody>\n",
|
| 77 |
+
" <tr>\n",
|
| 78 |
+
" <th>standard</th>\n",
|
| 79 |
+
" <td>0.431533</td>\n",
|
| 80 |
+
" <td>0.755924</td>\n",
|
| 81 |
+
" <td>0.928913</td>\n",
|
| 82 |
+
" </tr>\n",
|
| 83 |
+
" <tr>\n",
|
| 84 |
+
" <th>top5</th>\n",
|
| 85 |
+
" <td>0.237810</td>\n",
|
| 86 |
+
" <td>0.538164</td>\n",
|
| 87 |
+
" <td>0.807986</td>\n",
|
| 88 |
+
" </tr>\n",
|
| 89 |
+
" <tr>\n",
|
| 90 |
+
" <th>softmax</th>\n",
|
| 91 |
+
" <td>0.112041</td>\n",
|
| 92 |
+
" <td>0.352301</td>\n",
|
| 93 |
+
" <td>0.730178</td>\n",
|
| 94 |
+
" </tr>\n",
|
| 95 |
+
" <tr>\n",
|
| 96 |
+
" <th>geom</th>\n",
|
| 97 |
+
" <td>0.192413</td>\n",
|
| 98 |
+
" <td>0.378332</td>\n",
|
| 99 |
+
" <td>0.502335</td>\n",
|
| 100 |
+
" </tr>\n",
|
| 101 |
+
" </tbody>\n",
|
| 102 |
+
"</table>\n",
|
| 103 |
+
"</div>"
|
| 104 |
+
],
|
| 105 |
+
"text/plain": [
|
| 106 |
+
" 1 5 20\n",
|
| 107 |
+
"standard 0.431533 0.755924 0.928913\n",
|
| 108 |
+
"top5 0.237810 0.538164 0.807986\n",
|
| 109 |
+
"softmax 0.112041 0.352301 0.730178\n",
|
| 110 |
+
"geom 0.192413 0.378332 0.502335"
|
| 111 |
+
]
|
| 112 |
+
},
|
| 113 |
+
"execution_count": 9,
|
| 114 |
+
"metadata": {},
|
| 115 |
+
"output_type": "execute_result"
|
| 116 |
+
}
|
| 117 |
+
],
|
| 118 |
+
"source": [
|
| 119 |
+
"topk = [1,5,20]\n",
|
| 120 |
+
"result_data = []\n",
|
| 121 |
+
"for m in result_dict:\n",
|
| 122 |
+
" curr_result = [] \n",
|
| 123 |
+
" for k in topk:\n",
|
| 124 |
+
" curr_result.append(len(result_dict[m][result_dict[m]['rank'] <= k])/len(result_dict[m]))\n",
|
| 125 |
+
" result_data.append(curr_result)\n",
|
| 126 |
+
"\n",
|
| 127 |
+
"result_df = pd.DataFrame(result_data, index=result_dict.keys(), columns=topk)\n",
|
| 128 |
+
"result_df"
|
| 129 |
+
]
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
"cell_type": "code",
|
| 133 |
+
"execution_count": 18,
|
| 134 |
+
"id": "252767dd",
|
| 135 |
+
"metadata": {},
|
| 136 |
+
"outputs": [],
|
| 137 |
+
"source": [
|
| 138 |
+
"def get_target_score(scores, labels):\n",
|
| 139 |
+
" return np.array(scores)[np.array(labels)][0]\n",
|
| 140 |
+
"\n",
|
| 141 |
+
"def get_avg_cand_scores(scores, labels):\n",
|
| 142 |
+
" return np.mean(np.array(scores)[~np.array(labels)])\n",
|
| 143 |
+
"\n",
|
| 144 |
+
"for m, r in result_dict.items():\n",
|
| 145 |
+
" r['target_score'] = r.apply(lambda row: get_target_score(row['scores'], row['labels']), axis=1)\n",
|
| 146 |
+
" r['avg_cand_scores'] = r.apply(lambda row: get_avg_cand_scores(row['scores'], row['labels']), axis=1)\n"
|
| 147 |
+
]
|
| 148 |
+
},
|
| 149 |
+
{
|
| 150 |
+
"cell_type": "code",
|
| 151 |
+
"execution_count": 40,
|
| 152 |
+
"id": "26b609ca",
|
| 153 |
+
"metadata": {},
|
| 154 |
+
"outputs": [
|
| 155 |
+
{
|
| 156 |
+
"data": {
|
| 157 |
+
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA90AAAPdCAYAAACXzguGAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjYsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvq6yFwwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAviJJREFUeJzs3X98jvX////7zHbuh53nkP3KsEwYRlRMkSKj8VLxLuWFinzUVCiT10uSfiglFPFK5UfZSyp6vbMyC6MXS6jlR1I0pmZWaZuf22zH94++O96dNjKdx879uF0vl/NS53E8j+N4HGe79Djv5/HLwzAMQwAAAAAAwOXquLsAAAAAAABqKkI3AAAAAAAWIXQDAAAAAGARQjcAAAAAABYhdAMAAAAAYBFCNwAAAAAAFiF0AwAAAABgkbruLqA6KCkpUVZWlgICAuTh4eHucgAAcDnDMHT8+HGFhYWpTp2//ps8vRMAUNNdbO8kdF+ErKwshYeHu7sMAAAsd/jwYTVu3Pgvr4feCQCoLf6sdxK6L0JAQICk3z9Mu93u5moAAHC9/Px8hYeHmz3vr6J3AgBquovtnYTui1B6WpzdbueLAwCgRnPVqeD0TgBAbfFnvZMbqQEAAAAAYBFCNwAAAAAAFiF0AwAAAABgEa7pBoAqori4WEVFRe4uAzWUl5eXPD093V0GALgUvRNWclXvJHQDgJsZhqHs7Gzl5ua6uxTUcIGBgQoJCeG52QCqPXonKosreiehGwDcrPRLQ1BQkPz8/AhEcDnDMHTq1Cnl5ORIkkJDQ91cEQD8NfROWM2VvZPQDQBuVFxcbH5paNiwobvLQQ3m6+srScrJyVFQUBCnmgOotuidqCyu6p3cSA0A3Kj0OjQ/Pz83V4LaoPTvjOsfAVRn9E5UJlf0TkI3AFQBnBaHysDfGYCahP+noTK44u+M0A0AAAAAgEUI3QAAAAAAWIQbqQFAFZX0QValbi9uYFiFxvfo0UMdOnTQ7NmzrSnoElTFmgAAlacyeyd9ExeLI90AALcqLCx0dwmWqun7BwCoXDW9r9TE/SN0AwAq7J577tHGjRs1Z84ceXh4yMPDQwcPHlRxcbFGjBihiIgI+fr6qmXLlpozZ06ZZW+99VY9++yzCgsLU8uWLSVJW7ZsUYcOHeTj46Orr75aH374oTw8PJSenm4uu3v3bvXt21f16tVTcHCwhg4dql9++eWCNZXntddeU4sWLeTj46Pg4GANGjTInFdSUqIZM2YoMjJSNptNTZo00bPPPmvO37Vrl2666Sb5+vqqYcOGGjVqlE6cOPGn+3f48GHdcccdCgwMVIMGDTRgwIDz1gcAqFnom7W7b3J6OQCgwubMmaPvvvtObdu21bRp0yRJjRo1UklJiRo3bqz33ntPDRs21JYtWzRq1CiFhobqjjvuMJdft26d7Ha7UlJSJEn5+fnq37+/brnlFiUmJurQoUMaO3as0zZzc3N10003aeTIkZo1a5ZOnz6tiRMn6o477tD69evPW9O5tm/frocfflhvv/22unbtqmPHjumzzz4z50+aNEkLFy7UrFmzdP311+vIkSP69ttvJUknT55UbGysYmJitG3bNuXk5GjkyJEaM2aMFi9efN79KyoqMpf77LPPVLduXT3zzDPq06ePdu7cKW9v77/+HwUAUGXRN2t33yR0AwAqzOFwyNvbW35+fgoJCTGne3p66qmnnjLfR0REKC0tTStWrHD68uDv76833njDbJoLFiyQh4eHFi5cKB8fH0VFRemnn37S/fffby4zd+5cXXXVVXruuefMaW+99ZbCw8P13Xff6corryy3pnNlZmbK399f/fr1U0BAgJo2baqrrrpKknT8+HHNmTNHc+fO1fDhwyVJzZs31/XXXy9JSkxM1JkzZ7R06VL5+/ubdfXv318vvPCCgoODy92/d955RyUlJXrjjTfMR48sWrRIgYGBSk1NVe/evSv6nwAAUI3QN2t33yR0AwBcat68eXrrrbeUmZmp06dPq7CwUB06dHAa065dO6dfqfft26fo6Gj5+PiY06699lqnZb7++mtt2LBB9erVK7PNAwcO6Morr7yo+m6++WY1bdpUV1xxhfr06aM+ffrotttuk5+fn/bu3auCggL17Nmz3GX37t2r9u3bm18cJOm6665TSUmJ9u3bZ355OHf/vv76a+3fv18BAQFO6ztz5owOHDhwUXUDAGom+mbN75uEbgCAyyxfvlyPPfaYZs6cqZiYGAUEBOjFF1/U1q1bncb9sflerBMnTpi/jJ8rNDT0otcTEBCgL7/8UqmpqVq7dq2mTJmiqVOnatu2bfL19a1wXeU5d/9OnDihTp06admyZWXGlncqHwCgdqBv/q6m901CNwDgknh7e6u4uNhp2ubNm9W1a1c9+OCD5rSL+UW6ZcuWeuedd1RQUCCbzSZJ2rZtm9OYjh076oMPPlCzZs1Ut2757au8mspTt25d9erVS7169dKTTz6pwMBArV+/Xrfccot8fX21bt06jRw5ssxyrVu31uLFi3Xy5EnzC8LmzZtVp04d88Yv5enYsaPeffddBQUFyW63/2l9AICah75Ze/smdy8HAFySZs2aaevWrTp48KB++eUXlZSUqEWLFtq+fbuSk5P13Xff6YknnijzJaA8d999t0pKSjRq1Cjt3btXycnJeumllyTJvJYrPj5ex44d01133aVt27bpwIEDSk5O1r333mt+YSivpnOtXr1ar7zyitLT03Xo0CEtXbpUJSUlatmypXx8fDRx4kQlJCRo6dKlOnDggD7//HO9+eabkqQhQ4bIx8dHw4cP1+7du7VhwwY99NBDGjp0qHmKXHmGDBmiyy67TAMGDNBnn32mjIwMpaam6uGHH9aPP/5Y4c8eAFD90Ddrb98kdAMALsljjz0mT09PRUVFqVGjRsrMzNT/+3//T7fffrvuvPNOde7cWb/++qvTr/fnY7fb9dFHHyk9PV0dOnTQP//5T02ZMkWSzOvVwsLCtHnzZhUXF6t3795q166dxo4dq8DAQNWpU+e8NZ0rMDBQK1eu1E033aTWrVtrwYIF+ve//602bdpIkp544gk9+uijmjJlilq3bq0777xTOTk5kiQ/Pz8lJyfr2LFjuuaaazRo0CD17NlTc+fOveD++fn5adOmTWrSpIluv/12tW7dWiNGjNCZM2dqxC/4AIA/R9+svX3TwzAMw91FVHX5+flyOBzKy8urlv+RAVRdZ86cUUZGhiIiIpxuhgJp2bJluvfee5WXl+eya8Zquwv9vbm619E7AViF3lk++qY1XNE7uaYbAFAlLF26VFdccYUuv/xyff311+azRPniAABAWfTN6oPQDQCoErKzszVlyhRlZ2crNDRU//M//6Nnn33W3WUBAFAl0TerD0I3AKBKSEhIUEJCgrvLAACgWqBvVh/cSA0AAAAAAItUmdD9/PPPy8PDQ2PHjjWnnTlzRvHx8WrYsKHq1aungQMH6ujRo07LZWZmKi4uTn5+fgoKCtKECRN09uxZpzGpqanq2LGjbDabIiMjtXjx4krYIwAAAABAbVclQve2bdv0r3/9S9HR0U7Tx40bp48++kjvvfeeNm7cqKysLN1+++3m/OLiYsXFxamwsFBbtmzRkiVLtHjxYvN2+ZKUkZGhuLg43XjjjUpPT9fYsWM1cuRIJScnV9r+AQAAAABqJ7eH7hMnTmjIkCFauHCh6tevb07Py8vTm2++qZdfflk33XSTOnXqpEWLFmnLli36/PPPJUlr167VN998o3feeUcdOnRQ37599fTTT2vevHkqLCyUJC1YsEARERGaOXOmWrdurTFjxmjQoEGaNWuWW/YXAAAAAFB7uD10x8fHKy4uTr169XKavmPHDhUVFTlNb9WqlZo0aaK0tDRJUlpamtq1a6fg4GBzTGxsrPLz87Vnzx5zzLnrjo2NNddRnoKCAuXn5zu9AADA+dE7AQAon1tD9/Lly/Xll19q+vTpZeZlZ2fL29tbgYGBTtODg4OVnZ1tjvlj4C6dXzrvQmPy8/N1+vTpcuuaPn26HA6H+QoPD7+k/QMAoLagdwIAUD63he7Dhw/rkUce0bJly+Tj4+OuMso1adIk5eXlma/Dhw+7uyQAgJvdc889uvXWW91dRpVF7wQA/BF98/+47TndO3bsUE5Ojjp27GhOKy4u1qZNmzR37lwlJyersLBQubm5Tke7jx49qpCQEElSSEiIvvjiC6f1lt7d/I9jzr3j+dGjR2W32+Xr61tubTabTTab7S/vIwD8FcWplXvDR88esZW6PdQs9E4AVUFl9k76Ji6W24509+zZU7t27VJ6err5uvrqqzVkyBDz3728vLRu3TpzmX379ikzM1MxMTGSpJiYGO3atUs5OTnmmJSUFNntdkVFRZlj/riO0jGl6wAAoDoqKipydwkAAFQb7uybbgvdAQEBatu2rdPL399fDRs2VNu2beVwODRixAiNHz9eGzZs0I4dO3TvvfcqJiZGXbp0kST17t1bUVFRGjp0qL7++mslJydr8uTJio+PN39tHz16tH744QclJCTo22+/1WuvvaYVK1Zo3Lhx7tp1AKgR1qxZo+uvv16BgYFq2LCh+vXrpwMHDpjzu3btqokTJzot8/PPP8vLy0ubNm2SJB05ckRxcXHy9fVVRESEEhMT1axZM82ePfuC237rrbfUpk0b2Ww2hYaGasyYMea8l19+We3atZO/v7/Cw8P14IMP6sSJE+b8xYsXKzAwUMnJyWrdurXq1aunPn366MiRI+aY4uJijR8/3ty3hIQEGYZxwZoOHTqk/v37q379+vL391ebNm308ccfm/P37Nmjfv36yW63KyAgQN26dTM/r5KSEk2bNk2NGzeWzWZThw4dtGbNGnPZgwcPysPDQ++++65uuOEG+fj4aNmyZZKkN954Q61bt5aPj49atWql11577YJ1AgDcg77prDb1TbffvfxCZs2apX79+mngwIHq3r27QkJCtHLlSnO+p6enVq9eLU9PT8XExOjvf/+7hg0bpmnTppljIiIilJSUpJSUFLVv314zZ87UG2+8odhYTgcBgL/i5MmTGj9+vLZv365169apTp06uu2221RSUiJJGjJkiJYvX+7UdN99912FhYWpW7dukqRhw4YpKytLqamp+uCDD/T66687nb1Unvnz5ys+Pl6jRo3Srl279L//+7+KjIw059epU0evvPKK9uzZoyVLlmj9+vVKSEhwWsepU6f00ksv6e2339amTZuUmZmpxx57zJw/c+ZMLV68WG+99Zb++9//6tixY1q1atUF64qPj1dBQYE2bdqkXbt26YUXXlC9evUkST/99JO6d+8um82m9evXa8eOHbrvvvt09uxZSdKcOXM0c+ZMvfTSS9q5c6diY2P1t7/9Td9//73TNh5//HE98sgj2rt3r2JjY7Vs2TJNmTJFzz77rPbu3avnnntOTzzxhJYsWXLBWgEAlY++6axW9U0DfyovL8+QZOTl5bm7FAA1zOnTp41vvvnGOH36dJl5ZzesqdTXX/Xzzz8bkoxdu3YZhmEYOTk5Rt26dY1NmzaZY2JiYoyJEycahmEYe/fuNSQZ27ZtM+d///33hiRj1qxZ591OWFiY8c9//vOi63rvvfeMhg0bmu8XLVpkSDL2799vTps3b54RHBxsvg8NDTVmzJhhvi8qKjIaN25sDBgw4LzbadeunTF16tRy502aNMmIiIgwCgsLy50fFhZmPPvss07TrrnmGuPBBx80DMMwMjIyDEnG7NmzncY0b97cSExMdJr29NNPGzExMeVu50J/b67udfROAFapKr3zr6JvVv2+aRiu6Z1V+kg3AKDq+v7773XXXXfpiiuukN1uV7NmzSRJmZmZkqRGjRqpd+/e5ulcGRkZSktL05AhQyT9fp+OunXrOt1QMzIyUvXr1z/vNnNycpSVlaWePXued8ynn36qnj176vLLL1dAQICGDh2q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Hy9J8vDw0BNPPCE/Pz9zXnFxsbZu3aoOHTq4vEAAqC4SExOVk5OjsWPHursUAABqlC1btmjt2rUaO3asAgMDLdvOwYMHz3v27r///W8NHjzYsm2j5rro0P3VV19J+v1I965du+Tt7W3O8/b2Vvv27fXYY4+5vkIAqCYSExO1e/duQjcAAC62ZcsWPfXUU7rnnnssDd2l7rrrLt1yyy1O02JiYizfLmqmiw7dGzZskCTde++9mjNnjux2u2VFAQDcr6SkRIWFhVw6BACodTp27Ki///3v7i4DNUSFr+letGiRywL39OnTdc011yggIEBBQUG69dZbtW/fPqcxPXr0kIeHh9Nr9OjRTmMyMzMVFxcnPz8/BQUFacKECTp79qzTmNTUVHXs2FE2m02RkZFavHixS/YBQO1x/PhxjR07Vs2aNZPNZlNQUJBuvvlmffnll+rRo4eSkpJ06NAh8/9VpddWFxYWasqUKerUqZMcDof8/f3VrVs388fMUgcPHpSHh4deeuklvf7662revLlsNpuuueYabdu2rUw9H374odq2bSsfHx+1bdtWq1atKrful156SV27dlXDhg3l6+urTp066f333y8zzsPDQ2PGjNGyZcvUpk0b2Ww2rVmzRpK0Z88e3XTTTfL19VXjxo31zDPPqKSk5C9+ogAA/LmpU6dqwoQJkn6/qXNpnz148KDOnj2rp59+2uyZzZo10z/+8Q8VFBQ4raNZs2bq16+f1q5dqw4dOsjHx0dRUVFauXLlebd78uRJFRYWWrpvqB08jPKe/3UBJ0+e1PPPP69169YpJyenzJeuH3744aLX1adPHw0ePFjXXHONzp49q3/84x/avXu3vvnmG/n7+0v6PXRfeeWVmjZtmrmcn5+fGfyLi4vVoUMHhYSE6MUXX9SRI0c0bNgw3X///XruueckSRkZGWrbtq1Gjx6tkSNHat26dRo7dqySkpIUGxv7p3Xm5+fL4XAoLy+PI/xALTZkyBC9//77GjNmjKKiovTrr7/qv//9r+68804FBQUpISFBP/74o2bNmiVJqlevnm699Vb98ssvio6O1l133aUWLVro+PHjevPNN/XDDz/oiy++MO+HUXod2VVXXaXjx4/r/vvvl4eHh2bMmCEfHx/98MMP8vLykiStXbtWffv2VVRUlO677z79+uuvmjt3rho3bqwTJ0443dwsPDxcf/vb3xQVFaXCwkItX75cX3zxhVavXq24uDhznIeHh1q3bq1ffvlFY8aM0WWXXaauXbsqJCRE0dHROnv2rB555BH5+/vr9ddfl6+vr3bu3KmMjIxKu3kbrOPqXkfvBOAqO3fu1PPPP69///vfmjVrli677DJJ0m233ab4+HgtWbJEgwYN0o033qitW7dq6dKluvXWW51+jC79wTwnJ0ejR49WUFCQFi1apD179mjNmjW6+eabJf1fL65Xr55OnDghDw8PderUSc8++6x69+7tlv1H1XXRvc6ooMGDBxuhoaFGQkKCMWvWLGP27NlOr78iJyfHkGRs3LjRnHbDDTcYjzzyyHmX+fjjj406deoY2dnZ5rT58+cbdrvdKCgoMAzDMBISEow2bdo4LXfnnXcasbGxF1VXXl6eIcnIy8urwN4AqGkcDocRHx9/3vlxcXFG06ZNy0w/e/as+f+jUr/99psRHBxs3Hfffea0jIwMQ5LRsGFD49ixY+b0//znP4Yk46OPPjKndejQwQgNDTVyc3PNaWvXrjUklanh1KlTTu8LCwuNtm3bGjfddJPTdElGnTp1jD179jhNHzt2rCHJ2Lp1qzktJyfHcDgchiQjIyOj/A8E1Yqrex29E4Arvfjii2V6Tnp6uiHJGDlypNPYxx57zJBkrF+/3pzWtGlTQ5LxwQcfmNPy8vKM0NBQ46qrrjKnHTp0yOjdu7cxf/5843//93+N2bNnG02aNDHq1KljrF692rodRLV0sb3uoq/pLvXJJ58oKSlJ1113XUUX/VN5eXmSpAYNGjhNX7Zsmd555x2FhISof//+TndPT0tLU7t27RQcHGyOj42N1QMPPKA9e/boqquuUlpamnr16uW0ztjY2PPe7KigoMDplJT8/HxX7B6Aai4wMFBbt25VVlaWwsLCLno5T09PeXp6Svr9Ounc3FyVlJTo6quv1pdffllm/J133qn69eub77t16ybp/84kOnLkiNLT0/X444/L4XCY426++WZFRUXp5MmTTuvz9fU1//23335TcXGxunXrpn//+99ltn3DDTcoKirKadrHH3+sLl266NprrzWnNWrUSEOGDNFrr7120Z8DajZ6J4DK9vHHH0v6v6cslXr00Uf10ksvKSkpSTfeeKM5PSwsTLfddpv53m63a9iwYXrhhReUnZ2tkJAQNWnSRMnJyU7rGzp0qKKiovToo486nSEGXKwKX9Ndv379MqHYFUpKSjR27Fhdd911atu2rTn97rvv1jvvvKMNGzZo0qRJevvtt51uapCdne0UuCWZ77Ozsy84Jj8/X6dPny5Ty/Tp0+VwOMxXeHi4y/YTQPU1Y8YM7d69W+Hh4br22ms1derUi76kZsmSJYqOjpaPj48aNmyoRo0aKSkpyfyx8Y+aNGni9L40gP/222+SpEOHDkmSWrRoUWbZli1blpm2evVqdenSRT4+PmrQoIEaNWqk+fPnl7vt8h6TcujQoYveFmoveieAynbo0CHVqVNHkZGRTtNDQkIUGBho9stSkZGR8vDwcJp25ZVXSpLTZVnnatCgge69917t27dPP/74o2uKR61S4dD99NNPa8qUKTp16pRLC4mPj9fu3bu1fPlyp+mjRo1SbGys2rVrpyFDhmjp0qVatWqVDhw44NLt/9GkSZOUl5dnvg4fPmzZtgBUH3fccYd++OEHvfrqqwoLC9OLL76oNm3a6JNPPrngcu+8847uueceNW/eXG+++abWrFmjlJQU3XTTTeXejKz0qPi5jIrdgkOS9Nlnn+lvf/ubfHx89Nprr+njjz9WSkqK7r777nLX98ej4kBF0DsBuMu5QdoKpT8kHjt2zPJtoeap8OnlM2fO1IEDBxQcHKxmzZqZN/UpVd6pkn9mzJgxWr16tTZt2qTGjRtfcGznzp0lSfv371fz5s0VEhKiL774wmnM0aNHJf3+K1fpP0un/XGM3W4v9wumzWaTzWar8H4AqPlCQ0P14IMP6sEHH1ROTo46duyoZ599Vn379j1v03///fd1xRVXaOXKlU5jnnzyyUuqoWnTppKk77//vsy8c58A8cEHH8jHx0fJyclO/19btGhRhbZ3MdtC7UbvBGCl8nps06ZNVVJSou+//16tW7c2px89elS5ublmvyy1f/9+GYbhtK7vvvtOkv70hqClZ7Y1atToUncBtViFj3TfeuutevTRR/XYY49p0KBBGjBggNOrIgzD0JgxY7Rq1SqtX7++3NMaz5Weni7p9y++0u8Pqd+1a5dycnLMMSkpKbLb7eZ1iTExMVq3bp3TelJSUnjAPYCLVlxcXOZ07KCgIIWFhZnXsfr7+5d7ynbpkes/HlneunWr0tLSLqmW0NBQdejQQUuWLHHaXkpKir755psy2/bw8FBxcbE57eDBg/rwww8venu33HKLPv/8c6cfOH/++WctW7bskuoHAKCiSp9slJuba0675ZZbJEmzZ892Gvvyyy9LUpnrr7OyspzuaJ6fn6+lS5eaT0KSfu9v5/rpp5/01ltvKTo62swgQEVU+Ej3pR6ZKU98fLwSExP1n//8RwEBAeY12A6HQ76+vjpw4IASExN1yy23qGHDhtq5c6fGjRun7t27Kzo6WpLUu3dvRUVFaejQoZoxY4ays7M1efJkxcfHm7+4jx49WnPnzlVCQoLuu+8+rV+/XitWrFBSUpLL9gVAzXb8+HE1btxYgwYNUvv27VWvXj19+umn2rZtm2bOnClJ6tSpk959912NHz9e11xzjerVq6f+/furX79+WrlypW677TbFxcUpIyNDCxYsUFRUlE6cOHFJ9UyfPl1xcXG6/vrrdd999+nYsWN69dVX1aZNG6d1xsXF6eWXX1afPn109913KycnR/PmzVNkZKR27tx5UdtKSEjQ22+/rT59+jg9Mqxp06YXvQ4AAP6KTp06SZL++c9/avDgwfLy8lL//v01fPhwvf7668rNzdUNN9ygL774QkuWLNGtt97qdBM16ffrt0eMGKFt27YpODhYb731lo4ePep09ldCQoIOHDignj17KiwsTAcPHtS//vUvnTx5UnPmzKnUfUYNYv2N1M9PUrmvRYsWGYZhGJmZmUb37t2NBg0aGDabzYiMjDQmTJhQ5pbsBw8eNPr27Wv4+voal112mfHoo48aRUVFTmM2bNhgdOjQwfD29jauuOIKcxsXg8eeACgoKDAmTJhgtG/f3ggICDD8/f2N9u3bG6+99po55sSJE8bdd99tBAYGOj26q6SkxHjuueeMpk2bGjabzbjqqquM1atXG8OHD3d6vFfpI8NefPHFMtuXZDz55JNO0z744AOjdevWhs1mM6KiooyVK1eWWadhGMabb75ptGjRwrDZbEarVq2MRYsWGU8++aRxbguQdN5Hou3cudO44YYbDB8fH+Pyyy83nn76aePNN9/kkWE1CI8MA1DVPf3008bll19u1KlTx+w/RUVFxlNPPWVEREQYXl5eRnh4uDFp0iTjzJkzTss2bdrUiIuLM5KTk43o6GizJ7733ntO4xITE43u3bsbjRo1MurWrWtcdtllxm233Wbs2LGjMncV1cTF9joPw6jY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/BQSEmJO9/T01FNPPWW+j4iIUFpamlasWOH05cHf319vvPGG2TQXLFggDw8PLVy4UD4+PoqKitJPP/2k+++/31xm7ty5uuqqq/Tcc8+Z09566y2Fh4fru+++05VXXlluTefKzMyUv7+/+vXrp4CAADVt2lRXXXWVJOn48eOaM2eO5s6dq+HDh0uSmjdvruuvv16SlJiYqDNnzmjp0qXy9/c36+rfv79eeOEFBQcHl7t/77zzjkpKSvTGG2+Yz/tctGiRAgMDlZqaqt69e1f0PwEAoBqhb9buvknoBgC41Lx58/TWW28pMzNTp0+fVmFhoTp06OA0pl27dk6/Uu/bt0/R0dHy8fExp1177bVOy3z99dfasGGD6tWrV2abBw4c0JVXXnlR9d18881q2rSprrjiCvXp00d9+vTRbbfdJj8/P+3du1cFBQXq2bNnucvu3btX7du3N784SNJ1112nkpIS7du3z/zycO7+ff3119q/f78CAgKc1nfmzBkdOHDgouoGANRM9M2a3zcJ3QAAl1m+fLkee+wxzZw5UzExMQoICNCLL76orVu3Oo37Y/O9WCdOnDB/GT9XaGjoRa8nICBAX375pVJTU7V27VpNmTJFU6dO1bZt2+Tr61vhuspz7v6dOHFCnTp10rJly8qMLe9UPgBA7UDf/F1N75uEbgDAJfH29lZxcbHTtM2bN6tr16568MEHzWkX84t0y5Yt9c4776igoEA2m02StG3bNqcxHTt21AcffKBmzZqpbt3y21d5NZWnbt266tWrl3r16qUnn3xSgYGBWr9+vW655Rb5+vpq3bp1GjlyZJnlWrdurcWLF+vkyZPmF4TNmzerTp065o1fytOxY0e9++67CgoKkt1u/9P6gKqoODX5vPM8e8RWYiVA9UTfrL19k7uXAwAuSbNmzbR161YdPHhQv/zyi0pKStSiRQtt375dycnJ+u677/TEE0+U+RJQnrvvvlslJSUaNWqU9u7dq+TkZL300kuSZF7LFR8fr2PHjumuu+7Stm3bdODAASUnJ+vee+81vzCUV9O5Vq9erVdeeUXp6ek6dOiQli5dqpKSErVs2VI+Pj6aOHGiEhIStHTpUh04cECff/653nzzTUnSkCFD5OPjo+HDh2v37t3asGGDHnroIQ0dOtQ8Ra48Q4YM0WWXXaYBAwbos88+U0ZGhlJTU/Xwww/rxx9/rPBnDwCofuibtbhvGvhTeXl5hiQjLy/P3aUAqGFOnz5tfPPNN8bp06fdXUqF7du3z+jSpYvh6+trSDIyMjKMM2fOGPfcc4/hcDiMwMBA44EHHjAef/xxo3379uZyw4cPNwYMGFBmfZs3bzaio6MNb29vo1OnTkZiYqIhyfj222/NMd99951x2223GYGBgYavr6/RqlUrY+zYsUZJScl5azrXZ599Ztxwww1G/fr1DV9fXyM6Otp49913zfnFxcXGM888YzRt2tTw8vIymjRpYjz33HPm/J07dxo33nij4ePjYzRo0MC4//77jePHj//p/h05csQYNmyYcdlllxk2m8244oorjPvvv79Se8uF/t5c3evonTXP2Q1rzvsCKlN17Z30zerXNw3DNb3TwzAMw12Bv7rIz8+Xw+FQXl5ejTi9AUDVcebMGWVkZCgiIsLpZiiQli1bpnvvvVd5eXkuu2astrvQ35urex29s+bh9HJUFfTO8tE3reGK3sk13QCAKmHp0qW64oordPnll+vrr782nyXKFwcAAMqib1YfhG4AQJWQnZ2tKVOmKDs7W6Ghofqf//kfPfvss+4uCwCAKom+WX0QugEAVUJCQoISEhLcXQYAANUCfbP6qDJ3L3/++efl4eGhsWPHmtPOnDmj+Ph4NWzYUPXq1dPAgQN19OhRp+UyMzMVFxcnPz8/BQUFacKECTp79qzTmNTUVHXs2FE2m02RkZFavHhxJewRAAAAAKC2qxKhe9u2bfrXv/6l6Ohop+njxo3TRx99pPfee08bN25UVlaWbr/9dnN+cXGx4uLiVFhYqC1btmjJkiVavHixpkyZYo7JyMhQXFycbrzxRqWnp2vs2LEaOXKkkpPPfzMQAAAAAABcwe2h+8SJExoyZIgWLlyo+vXrm9Pz8vL05ptv6uWXX9ZNN92kTp06adGiRdqyZYs+//xzSdLatWv1zTff6J133lGHDh3Ut29fPf3005o3b54KCwslSQsWLFBERIRmzpyp1q1ba8yYMRo0aJBmzZrllv0FAAAAANQebg/d8fHxiouLU69evZym79ixQ0VFRU7TW7VqpSZNmigtLU2SlJaWpnbt2jk9WD02Nlb5+fnas2ePOebcdcfGxprrKE9BQYHy8/OdXgAA4PzonQAAlM+toXv58uX68ssvNX369DLzsrOz5e3trcDAQKfpwcHBys7ONsf8MXCXzi+dd6Ex+fn5On36dLl1TZ8+XQ6Hw3yFh4df0v4BAFBb0DsBACif20L34cOH9cgjj2jZsmVV7qH2kyZNUl5envk6fPiwu0sCAKBKo3cCAFA+tz0ybMeOHcrJyVHHjh3NacXFxdq0aZPmzp2r5ORkFRYWKjc31+lo99GjRxUSEiJJCgkJ0RdffOG03tK7m/9xzLl3PD969Kjsdvt5Hxxvs9lks9n+8j4CwF9RnFq5N3z07BFbqdurbu655x7l5ubqww8/dHcpVRK9E0BVUJm9k755YfTN/+O2I909e/bUrl27lJ6ebr6uvvpqDRkyxPx3Ly8vrVu3zlxm3759yszMVExMjCQpJiZGu3btUk5OjjkmJSVFdrtdUVFR5pg/rqN0TOk6AAAAAACwituOdAcEBKht27ZO0/z9/dWwYUNz+ogRIzR+/Hg1aNBAdrtdDz30kGJiYtSlSxdJUu/evRUVFaWhQ4dqxowZys7O1uTJkxUfH2/+2j569GjNnTtXCQkJuu+++7R+/XqtWLFCSUlJlbvDAAC4UFFRkby8vNxdBgAA1YI7+6bb715+IbNmzVK/fv00cOBAde/eXSEhIVq5cqU539PTU6tXr5anp6diYmL097//XcOGDdO0adPMMREREUpKSlJKSorat2+vmTNn6o033lBsLKeDAMBfsWbNGl1//fUKDAxUw4YN1a9fPx04cMCc37VrV02cONFpmZ9//lleXl7atGmTJOnIkSOKi4uTr6+vIiIilJiYqGbNmmn27NkX3PZbb72lNm3ayGazKTQ0VGPGjDHnvfzyy2rXrp38/f0VHh6uBx98UCdOnDDnL168WIGBgUpOTlbr1q1Vr1499enTR0eOHDHHFBcXa/z48ea+JSQkyDCMC9Z06NAh9e/fX/Xr15e/v7/atGmjjz/+2Jy/Z88e9evXT3a7XQEBAerWrZv5eZWUlGjatGlq3LixbDabOnTooDVr1pjLHjx4UB4eHnr33Xd1ww03yMfHR8uWLZMkvfHGG2rdurV8fHzUqlUrvfbaaxesEwDgHvRNZ7Wpb1ap0J2amur0B+Pj46N58+bp2LFjOnnypFauXGleq12qadOm+vjjj3Xq1Cn9/PPPeumll1S3rvMB/B49euirr75SQUGBDhw4oHvuuacS9gYAaraTJ09q/Pjx2r59u9atW6c6derotttuU0lJiSRpyJAhWr58uVPTfffddxUWFqZu3bpJkoYNG6asrCylpqbqgw8+0Ouvv+50yVB55s+fr/j4eI0aNUq7du3S//7v/yoyMtKcX6dOHb3yyivas2ePlixZovXr1yshIcFpHadOndJLL72kt99+W5s2bVJmZqYee+wxc/7MmTO1ePFivfXWW/rvf/+rY8eOadWqVResKz4+XgUFBdq0aZN27dqlF154QfXq1ZMk/fTTT+revbtsNpvWr1+vHTt26L777tPZs2clSXPmzNHMmTP10ksvaefOnYqNjdXf/vY3ff/9907bePzxx/XII49o7969io2N1bJlyzRlyhQ9++yz2rt3r5577jk98cQTWrJkyQVrBQBUPvqms9rUNz2MP/sJAsrPz5fD4VBeXp7sdru7ywFQg5w5c0YZGRmKiIgo8ySH6nYjtV9++UWNGjXSrl271LZtW/38888KCwvT+vXrzS8LXbt2Vffu3fX888/r22+/VevWrbVt2zZdffXVkqT9+/erRYsWmjVrlsaOHVvudi6//HLde++9euaZZy6qrvfff1+jR4/WL7/8Iun3X+zvvfde7d+/X82bN5ckvfbaa5o2bZr5uMmwsDCNGzdOEyZMkCSdPXtWERER6tSp03lvCBMdHa2BAwfqySefLDPvH//4h5YvX659+/aVe2rb5Zdfrvj4eP3jH/8wp1177bW65pprNG/ePB08eFARERGaPXu2HnnkEXNMZGSknn76ad11113mtGeeeUYff/yxtmzZUmY7F/p7c3Wvo3fWPBf6fxI3lEJlqiq9k75Z8/um5JreWaWOdAMAqo/vv/9ed911l6644grZ7XY1a9ZMkpSZmSlJatSokXr37m2ezpWRkaG0tDQNGTJE0u83x6xbt67TUywiIyNVv379824zJydHWVlZ6tmz53nHfPrpp+rZs6cuv/xyBQQEaOjQofr111916tQpc4yfn5/5xUGSQkNDzSMFeXl5OnLkiDp37mzOr1u3rvkF53wefvhhPfPMM7ruuuv05JNPaufOnea89PR0devWrdwvDvn5+crKytJ1113nNP26667T3r17nab9sYaTJ0/qwIEDGjFihOrVq2e+nnnmGafTFQEAVQN901lt6puEbgDAJenfv7+OHTumhQsXauvWrdq6daskqbCw0BwzZMgQvf/+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U+Xt7a0FCxYoIiJCM2fOlCS1bt1a//3vfzVr1qzzhu6CggIVFBSY7/Pz812xuwAA1Fj0TgAAyldlrukuLi7W8uXLdfLkScXExJjTly1bpssuu0xt27bVpEmTdOrUKXNeWlqa2rVrp+DgYHNabGys8vPztWfPHnNMr169nLYVGxurtLS089Yyffp0ORwO8xUeHu6q3QQAoEaidwIAUD63h+5du3apXr16stlsGj16tFatWqWoqChJ0t1336133nlHGzZs0KRJk/T222/r73//u7lsdna2U+CWZL7Pzs6+4Jj8/HydPn263JomTZqkvLw883X48GGX7S8AADURvRMAgPK59fRySWrZsqXS09OVl5en999/X8OHD9fGjRsVFRWlUaNGmePatWun0NBQ9ezZUwcOHFDz5s0tq8lms8lms1m2fgAAahp6JwAA5XP7kW5vb29FRkaqU6dOmj59utq3b685c+aUO7Zz586SpP3790uSQkJCdPToUacxpe9LrwM/3xi73S5fX1+X7gsAAAAAAH/k9tB9rpKSEqcbsfxRenq6JCk0NFSSFBMTo127diknJ8cck5KSIrvdbp6iHhMTo3Xr1jmtJyUlxem6cQAAAAAArODW08snTZqkvn37qkmTJjp+/LgSExOVmpqq5ORkHThwQImJibrlllvUsGFD7dy5U+PGjVP37t0VHR0tSerdu7eioqI0dOhQzZgxQ9nZ2Zo8ebLi4+PNU9xGjx6tuXPnKiEhQffdd5/Wr1+vFStWKCkpyZ27DgAAAACoBdwaunNycjRs2DAdOXJEDodD0dHRSk5O1s0336zDhw/r008/1ezZs3Xy5EmFh4dr4MCBmjx5srm8p6enVq9erQceeEAxMTHy9/fX8OHDnZ7rHRERoaSkJI0bN05z5sxR48aN9cYbb/CMbgAAAACA5TwMwzDcXURVl5+fL4fDoby8PNntdneXAwCAy7m619E7q6fi1ORLWs6zBwczANQ+F9vrqtw13QAAAAAA1BSEbgAAAAAALELoBgAAAADAIoRuAAAAAAAsQugGAAAAAMAihG4AAAAAACxC6AYAAAAAwCKEbgAAAAAALELoBgAAAADAIoRuAAAAAAAsQugGAAAAAMAihG4AAAAAACxC6AYAAAAAwCKEbgAAAAAALELoBgAAAADAIoRuAAAAAAAsQugGAAAAAMAihG4A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",
|
| 158 |
+
"text/plain": [
|
| 159 |
+
"<Figure size 1000x1000 with 4 Axes>"
|
| 160 |
+
]
|
| 161 |
+
},
|
| 162 |
+
"metadata": {},
|
| 163 |
+
"output_type": "display_data"
|
| 164 |
+
}
|
| 165 |
+
],
|
| 166 |
+
"source": [
|
| 167 |
+
"fig, axs = plt.subplots(2, 2, figsize=(10, 10), sharex=True, sharey=True)\n",
|
| 168 |
+
"i =0\n",
|
| 169 |
+
"j = 0\n",
|
| 170 |
+
"for m, r in result_dict.items():\n",
|
| 171 |
+
" axs[i, j].hist(r['target_score'], bins=np.arange(-0.2, 1, 0.02), label=f'target score', alpha=0.5, color='slateblue')\n",
|
| 172 |
+
" axs[i, j].hist(r['avg_cand_scores'], bins=np.arange(-0.2, 1, 0.02), label=f'avg cand score', alpha=0.5, color='salmon')\n",
|
| 173 |
+
" axs[i, j].annotate(m, (0.6, 2500), ha='center', va='center', fontsize=12)\n",
|
| 174 |
+
" axs[i, j].legend()\n",
|
| 175 |
+
"\n",
|
| 176 |
+
" if i % 2 == 0 and j == 1:\n",
|
| 177 |
+
" i += 1\n",
|
| 178 |
+
" j = 0\n",
|
| 179 |
+
" else:\n",
|
| 180 |
+
" j += 1\n",
|
| 181 |
+
"\n",
|
| 182 |
+
"axs[0, 0].set_ylabel('spectra count')\n",
|
| 183 |
+
"axs[1, 0].set_ylabel('spectra count')\n",
|
| 184 |
+
"axs[1, 0].set_xlabel('target score - avg cand score')\n",
|
| 185 |
+
"axs[1, 1].set_xlabel('target score - avg cand score')\n",
|
| 186 |
+
"\n",
|
| 187 |
+
"plt.tight_layout()\n",
|
| 188 |
+
"plt.show()"
|
| 189 |
+
]
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"cell_type": "code",
|
| 193 |
+
"execution_count": null,
|
| 194 |
+
"id": "1307a597",
|
| 195 |
+
"metadata": {},
|
| 196 |
+
"outputs": [],
|
| 197 |
+
"source": []
|
| 198 |
+
}
|
| 199 |
+
],
|
| 200 |
+
"metadata": {
|
| 201 |
+
"kernelspec": {
|
| 202 |
+
"display_name": "Python (spec)",
|
| 203 |
+
"language": "python",
|
| 204 |
+
"name": "spec"
|
| 205 |
+
},
|
| 206 |
+
"language_info": {
|
| 207 |
+
"codemirror_mode": {
|
| 208 |
+
"name": "ipython",
|
| 209 |
+
"version": 3
|
| 210 |
+
},
|
| 211 |
+
"file_extension": ".py",
|
| 212 |
+
"mimetype": "text/x-python",
|
| 213 |
+
"name": "python",
|
| 214 |
+
"nbconvert_exporter": "python",
|
| 215 |
+
"pygments_lexer": "ipython3",
|
| 216 |
+
"version": "3.11.7"
|
| 217 |
+
}
|
| 218 |
+
},
|
| 219 |
+
"nbformat": 4,
|
| 220 |
+
"nbformat_minor": 5
|
| 221 |
+
}
|
notebooks/eval_bad_instances.ipynb
CHANGED
|
@@ -282,7 +282,7 @@
|
|
| 282 |
"output_type": "stream",
|
| 283 |
"text": [
|
| 284 |
"100%|██████████| 231104/231104 [00:18<00:00, 12309.47it/s]\n",
|
| 285 |
-
"/data/yzhouc01/FILIP-MS/
|
| 286 |
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 287 |
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 288 |
"\n",
|
|
@@ -309,10 +309,10 @@
|
|
| 309 |
"from massspecgym.models.base import Stage\n",
|
| 310 |
"import os\n",
|
| 311 |
"\n",
|
| 312 |
-
"from
|
| 313 |
-
"from
|
| 314 |
"\n",
|
| 315 |
-
"from
|
| 316 |
"import yaml\n",
|
| 317 |
"from functools import partial\n",
|
| 318 |
"# Suppress RDKit warnings and errors\n",
|
|
|
|
| 282 |
"output_type": "stream",
|
| 283 |
"text": [
|
| 284 |
"100%|██████████| 231104/231104 [00:18<00:00, 12309.47it/s]\n",
|
| 285 |
+
"/data/yzhouc01/FILIP-MS/flare/data/datasets.py:221: SettingWithCopyWarning: \n",
|
| 286 |
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 287 |
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 288 |
"\n",
|
|
|
|
| 309 |
"from massspecgym.models.base import Stage\n",
|
| 310 |
"import os\n",
|
| 311 |
"\n",
|
| 312 |
+
"from flare.utils.data import get_spec_featurizer, get_mol_featurizer, get_ms_dataset\n",
|
| 313 |
+
"from flare.utils.models import get_model\n",
|
| 314 |
"\n",
|
| 315 |
+
"from flare.definitions import TEST_RESULTS_DIR\n",
|
| 316 |
"import yaml\n",
|
| 317 |
"from functools import partial\n",
|
| 318 |
"# Suppress RDKit warnings and errors\n",
|
notebooks/filip_viz.ipynb
CHANGED
|
@@ -31,6 +31,7 @@
|
|
| 31 |
"name": "stdout",
|
| 32 |
"output_type": "stream",
|
| 33 |
"text": [
|
|
|
|
| 34 |
"Data path: /r/hassounlab/spectra_data/msgym/MassSpecGym.tsv\n",
|
| 35 |
"Processing formula spectra\n"
|
| 36 |
]
|
|
@@ -39,21 +40,14 @@
|
|
| 39 |
"name": "stderr",
|
| 40 |
"output_type": "stream",
|
| 41 |
"text": [
|
| 42 |
-
"100%|██████████|
|
| 43 |
-
"/data/yzhouc01/FILIP-MS/
|
| 44 |
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 45 |
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 46 |
"\n",
|
| 47 |
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
|
| 48 |
" tmp_df['spec'] = tmp_df.apply(lambda row: data_utils.make_tmp_subformula_spectra(row), axis=1)\n"
|
| 49 |
]
|
| 50 |
-
},
|
| 51 |
-
{
|
| 52 |
-
"name": "stdout",
|
| 53 |
-
"output_type": "stream",
|
| 54 |
-
"text": [
|
| 55 |
-
"Loaded Model from checkpoint\n"
|
| 56 |
-
]
|
| 57 |
}
|
| 58 |
],
|
| 59 |
"source": [
|
|
@@ -67,10 +61,10 @@
|
|
| 67 |
"from massspecgym.models.base import Stage\n",
|
| 68 |
"import os\n",
|
| 69 |
"\n",
|
| 70 |
-
"from
|
| 71 |
-
"from
|
| 72 |
"\n",
|
| 73 |
-
"from
|
| 74 |
"import yaml\n",
|
| 75 |
"from functools import partial\n",
|
| 76 |
"# Suppress RDKit warnings and errors\n",
|
|
@@ -79,20 +73,20 @@
|
|
| 79 |
"\n",
|
| 80 |
"# Load model and data\n",
|
| 81 |
"\n",
|
| 82 |
-
"param_pth =
|
| 83 |
"with open(param_pth) as f:\n",
|
| 84 |
" params = yaml.load(f, Loader=yaml.FullLoader)\n",
|
| 85 |
"\n",
|
| 86 |
"spec_featurizer = get_spec_featurizer(params['spectra_view'], params)\n",
|
| 87 |
"mol_featurizer = get_mol_featurizer(params['molecule_view'], params)\n",
|
| 88 |
-
"dataset = get_ms_dataset(params['spectra_view'], params['molecule_view'], spec_featurizer, mol_featurizer, params)\n",
|
| 89 |
-
"\n",
|
| 90 |
"\n",
|
| 91 |
"# load model\n",
|
| 92 |
"import torch \n",
|
| 93 |
-
"checkpoint_pth = \"/data/yzhouc01/FILIP-MS/experiments/
|
| 94 |
"params['checkpoint_pth'] = checkpoint_pth\n",
|
| 95 |
-
"model = get_model(params['model'], params)"
|
|
|
|
|
|
|
| 96 |
]
|
| 97 |
},
|
| 98 |
{
|
|
@@ -150,7 +144,7 @@
|
|
| 150 |
},
|
| 151 |
{
|
| 152 |
"cell_type": "code",
|
| 153 |
-
"execution_count":
|
| 154 |
"metadata": {},
|
| 155 |
"outputs": [],
|
| 156 |
"source": [
|
|
@@ -213,7 +207,7 @@
|
|
| 213 |
},
|
| 214 |
{
|
| 215 |
"cell_type": "code",
|
| 216 |
-
"execution_count":
|
| 217 |
"metadata": {},
|
| 218 |
"outputs": [],
|
| 219 |
"source": [
|
|
@@ -330,7 +324,7 @@
|
|
| 330 |
},
|
| 331 |
{
|
| 332 |
"cell_type": "code",
|
| 333 |
-
"execution_count":
|
| 334 |
"metadata": {},
|
| 335 |
"outputs": [
|
| 336 |
{
|
|
@@ -375,64 +369,64 @@
|
|
| 375 |
" </thead>\n",
|
| 376 |
" <tbody>\n",
|
| 377 |
" <tr>\n",
|
| 378 |
-
" <th>
|
| 379 |
-
" <td>
|
| 380 |
-
" <td>
|
| 381 |
-
" <td>0.
|
| 382 |
-
" <td>
|
| 383 |
-
" <td>
|
| 384 |
-
" <td>
|
| 385 |
-
" <td>
|
| 386 |
-
" <td>
|
| 387 |
-
" <td>
|
| 388 |
" <td>[M+H]+</td>\n",
|
| 389 |
" <td>Orbitrap</td>\n",
|
| 390 |
-
" <td>
|
| 391 |
" <td>train</td>\n",
|
| 392 |
-
" <td>
|
| 393 |
-
" <td>[
|
| 394 |
-
" <td>[
|
| 395 |
-
" <td>[0.
|
| 396 |
" </tr>\n",
|
| 397 |
" <tr>\n",
|
| 398 |
-
" <th>
|
| 399 |
-
" <td>
|
| 400 |
-
" <td>
|
| 401 |
-
" <td>
|
| 402 |
-
" <td>
|
| 403 |
-
" <td>
|
| 404 |
-
" <td>
|
| 405 |
-
" <td>
|
| 406 |
-
" <td>
|
| 407 |
-
" <td>
|
| 408 |
" <td>[M+H]+</td>\n",
|
| 409 |
" <td>Orbitrap</td>\n",
|
| 410 |
-
" <td>
|
| 411 |
" <td>train</td>\n",
|
| 412 |
-
" <td>
|
| 413 |
-
" <td>[
|
| 414 |
-
" <td>[
|
| 415 |
-
" <td>[
|
| 416 |
" </tr>\n",
|
| 417 |
" <tr>\n",
|
| 418 |
-
" <th>
|
| 419 |
-
" <td>
|
| 420 |
-
" <td>
|
| 421 |
-
" <td>0.
|
| 422 |
-
" <td>CC(=
|
| 423 |
-
" <td>
|
| 424 |
-
" <td>
|
| 425 |
-
" <td>
|
| 426 |
-
" <td>
|
| 427 |
-
" <td>
|
| 428 |
-
" <td>[M+
|
| 429 |
" <td>Orbitrap</td>\n",
|
| 430 |
" <td>NaN</td>\n",
|
| 431 |
" <td>train</td>\n",
|
| 432 |
" <td>False</td>\n",
|
| 433 |
-
" <td>[
|
| 434 |
-
" <td>[
|
| 435 |
-
" <td>[0.
|
| 436 |
" </tr>\n",
|
| 437 |
" </tbody>\n",
|
| 438 |
"</table>\n",
|
|
@@ -440,52 +434,52 @@
|
|
| 440 |
],
|
| 441 |
"text/plain": [
|
| 442 |
" identifier \\\n",
|
| 443 |
-
"
|
| 444 |
-
"
|
| 445 |
-
"
|
| 446 |
"\n",
|
| 447 |
" mzs \\\n",
|
| 448 |
-
"
|
| 449 |
-
"
|
| 450 |
-
"
|
| 451 |
"\n",
|
| 452 |
" intensities \\\n",
|
| 453 |
-
"
|
| 454 |
-
"
|
| 455 |
-
"
|
| 456 |
"\n",
|
| 457 |
-
"
|
| 458 |
-
"
|
| 459 |
-
"
|
| 460 |
-
"
|
| 461 |
"\n",
|
| 462 |
-
" precursor_formula parent_mass precursor_mz
|
| 463 |
-
"
|
| 464 |
-
"
|
| 465 |
-
"
|
| 466 |
"\n",
|
| 467 |
" collision_energy fold simulation_challenge \\\n",
|
| 468 |
-
"
|
| 469 |
-
"
|
| 470 |
-
"
|
| 471 |
"\n",
|
| 472 |
" formulas \\\n",
|
| 473 |
-
"
|
| 474 |
-
"
|
| 475 |
-
"
|
| 476 |
"\n",
|
| 477 |
" formula_mzs \\\n",
|
| 478 |
-
"
|
| 479 |
-
"
|
| 480 |
-
"
|
| 481 |
"\n",
|
| 482 |
" formula_intensities \n",
|
| 483 |
-
"
|
| 484 |
-
"
|
| 485 |
-
"
|
| 486 |
]
|
| 487 |
},
|
| 488 |
-
"execution_count":
|
| 489 |
"metadata": {},
|
| 490 |
"output_type": "execute_result"
|
| 491 |
}
|
|
@@ -496,22 +490,43 @@
|
|
| 496 |
},
|
| 497 |
{
|
| 498 |
"cell_type": "code",
|
| 499 |
-
"execution_count":
|
| 500 |
"metadata": {},
|
| 501 |
"outputs": [
|
| 502 |
{
|
| 503 |
"data": {
|
| 504 |
"application/vnd.jupyter.widget-view+json": {
|
| 505 |
-
"model_id": "
|
| 506 |
"version_major": 2,
|
| 507 |
"version_minor": 0
|
| 508 |
},
|
| 509 |
"text/plain": [
|
| 510 |
"FigureWidget({\n",
|
| 511 |
-
" 'data': [{'customdata': [0, 1, 2, 3, 4, 5, 6, 7
|
| 512 |
-
"
|
| 513 |
-
"
|
| 514 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 515 |
" 'marker': {'cmax': 1,\n",
|
| 516 |
" 'cmin': 0,\n",
|
| 517 |
" 'color': 'lightgray',\n",
|
|
@@ -527,60 +542,128 @@
|
|
| 527 |
" '#b5de2b'], [1.0, '#fde725']]},\n",
|
| 528 |
" 'name': 'peak',\n",
|
| 529 |
" 'type': 'bar',\n",
|
| 530 |
-
" 'uid': '
|
| 531 |
-
" 'x': [
|
| 532 |
-
"
|
| 533 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 534 |
" 'xaxis': 'x',\n",
|
| 535 |
-
" 'y': [0.
|
| 536 |
-
"
|
| 537 |
-
" 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 538 |
" 'yaxis': 'y'},\n",
|
| 539 |
" {'hoverinfo': 'none',\n",
|
| 540 |
" 'line': {'color': 'gray', 'width': 2},\n",
|
| 541 |
" 'mode': 'lines',\n",
|
| 542 |
" 'showlegend': False,\n",
|
| 543 |
" 'type': 'scatter',\n",
|
| 544 |
-
" 'uid': '
|
| 545 |
-
" 'x': [
|
| 546 |
-
"
|
| 547 |
-
"
|
| 548 |
-
" -
|
| 549 |
-
" -2.
|
| 550 |
-
" -
|
| 551 |
-
" -
|
| 552 |
-
" -
|
| 553 |
-
"
|
| 554 |
-
"
|
| 555 |
-
"
|
| 556 |
-
"
|
| 557 |
-
"
|
| 558 |
-
"
|
| 559 |
-
"
|
| 560 |
-
"
|
| 561 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 562 |
" 'xaxis': 'x2',\n",
|
| 563 |
-
" 'y': [
|
| 564 |
-
"
|
| 565 |
-
"
|
| 566 |
-
"
|
| 567 |
-
"
|
| 568 |
-
" 1.
|
| 569 |
-
"
|
| 570 |
-
" 0.
|
| 571 |
-
" 0.
|
| 572 |
-
" -
|
| 573 |
-
" -
|
| 574 |
-
" -2.
|
| 575 |
-
" -
|
| 576 |
-
" 0.
|
| 577 |
-
"
|
| 578 |
-
" 0.
|
| 579 |
-
"
|
| 580 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 581 |
" 'yaxis': 'y2'},\n",
|
| 582 |
" {'customdata': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n",
|
| 583 |
-
" 16
|
|
|
|
| 584 |
" 'marker': {'cmax': 1,\n",
|
| 585 |
" 'cmin': 0,\n",
|
| 586 |
" 'color': 'lightgray',\n",
|
|
@@ -597,23 +680,34 @@
|
|
| 597 |
" 'size': 20},\n",
|
| 598 |
" 'mode': 'markers+text',\n",
|
| 599 |
" 'name': 'node',\n",
|
| 600 |
-
" 'text': [C,
|
|
|
|
| 601 |
" 'textposition': 'middle center',\n",
|
| 602 |
" 'type': 'scatter',\n",
|
| 603 |
-
" 'uid': '
|
| 604 |
-
" 'x': [
|
| 605 |
-
" -
|
| 606 |
-
" -
|
| 607 |
-
"
|
| 608 |
-
"
|
| 609 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
" 'xaxis': 'x2',\n",
|
| 611 |
-
" 'y': [
|
| 612 |
-
"
|
| 613 |
-
"
|
| 614 |
-
" -
|
| 615 |
-
" -
|
| 616 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 617 |
" 'yaxis': 'y2'}],\n",
|
| 618 |
" 'layout': {'annotations': [{'font': {'size': 16},\n",
|
| 619 |
" 'showarrow': False,\n",
|
|
@@ -643,7 +737,7 @@
|
|
| 643 |
"})"
|
| 644 |
]
|
| 645 |
},
|
| 646 |
-
"execution_count":
|
| 647 |
"metadata": {},
|
| 648 |
"output_type": "execute_result"
|
| 649 |
}
|
|
@@ -654,7 +748,7 @@
|
|
| 654 |
"# Data\n",
|
| 655 |
"# i = 40991\n",
|
| 656 |
"\n",
|
| 657 |
-
"ms_id = \"
|
| 658 |
"i = dataset.metadata[dataset.metadata['identifier'] == ms_id].index[0]\n",
|
| 659 |
"s = dataset.metadata.iloc[i]['smiles']\n",
|
| 660 |
"mol = Chem.MolFromSmiles(s)\n",
|
|
|
|
| 31 |
"name": "stdout",
|
| 32 |
"output_type": "stream",
|
| 33 |
"text": [
|
| 34 |
+
"Loaded Model from checkpoint\n",
|
| 35 |
"Data path: /r/hassounlab/spectra_data/msgym/MassSpecGym.tsv\n",
|
| 36 |
"Processing formula spectra\n"
|
| 37 |
]
|
|
|
|
| 40 |
"name": "stderr",
|
| 41 |
"output_type": "stream",
|
| 42 |
"text": [
|
| 43 |
+
"100%|██████████| 231104/231104 [00:15<00:00, 14902.24it/s]\n",
|
| 44 |
+
"/data/yzhouc01/FILIP-MS/flare/data/datasets.py:221: SettingWithCopyWarning: \n",
|
| 45 |
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 46 |
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 47 |
"\n",
|
| 48 |
"See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy\n",
|
| 49 |
" tmp_df['spec'] = tmp_df.apply(lambda row: data_utils.make_tmp_subformula_spectra(row), axis=1)\n"
|
| 50 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
}
|
| 52 |
],
|
| 53 |
"source": [
|
|
|
|
| 61 |
"from massspecgym.models.base import Stage\n",
|
| 62 |
"import os\n",
|
| 63 |
"\n",
|
| 64 |
+
"from flare.utils.data import get_spec_featurizer, get_mol_featurizer, get_ms_dataset\n",
|
| 65 |
+
"from flare.utils.models import get_model\n",
|
| 66 |
"\n",
|
| 67 |
+
"from flare.definitions import TEST_RESULTS_DIR\n",
|
| 68 |
"import yaml\n",
|
| 69 |
"from functools import partial\n",
|
| 70 |
"# Suppress RDKit warnings and errors\n",
|
|
|
|
| 73 |
"\n",
|
| 74 |
"# Load model and data\n",
|
| 75 |
"\n",
|
| 76 |
+
"param_pth = \"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/lightning_logs/version_0/hparams.yaml\"\n",
|
| 77 |
"with open(param_pth) as f:\n",
|
| 78 |
" params = yaml.load(f, Loader=yaml.FullLoader)\n",
|
| 79 |
"\n",
|
| 80 |
"spec_featurizer = get_spec_featurizer(params['spectra_view'], params)\n",
|
| 81 |
"mol_featurizer = get_mol_featurizer(params['molecule_view'], params)\n",
|
|
|
|
|
|
|
| 82 |
"\n",
|
| 83 |
"# load model\n",
|
| 84 |
"import torch \n",
|
| 85 |
+
"checkpoint_pth = \"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/epoch=1959-train_loss=0.08.ckpt\"\n",
|
| 86 |
"params['checkpoint_pth'] = checkpoint_pth\n",
|
| 87 |
+
"model = get_model(params['model'], params)\n",
|
| 88 |
+
"\n",
|
| 89 |
+
"dataset = get_ms_dataset(params['spectra_view'], params['molecule_view'], spec_featurizer, mol_featurizer, params)"
|
| 90 |
]
|
| 91 |
},
|
| 92 |
{
|
|
|
|
| 144 |
},
|
| 145 |
{
|
| 146 |
"cell_type": "code",
|
| 147 |
+
"execution_count": 4,
|
| 148 |
"metadata": {},
|
| 149 |
"outputs": [],
|
| 150 |
"source": [
|
|
|
|
| 207 |
},
|
| 208 |
{
|
| 209 |
"cell_type": "code",
|
| 210 |
+
"execution_count": 5,
|
| 211 |
"metadata": {},
|
| 212 |
"outputs": [],
|
| 213 |
"source": [
|
|
|
|
| 324 |
},
|
| 325 |
{
|
| 326 |
"cell_type": "code",
|
| 327 |
+
"execution_count": 6,
|
| 328 |
"metadata": {},
|
| 329 |
"outputs": [
|
| 330 |
{
|
|
|
|
| 369 |
" </thead>\n",
|
| 370 |
" <tbody>\n",
|
| 371 |
" <tr>\n",
|
| 372 |
+
" <th>178176</th>\n",
|
| 373 |
+
" <td>MassSpecGymID0253457</td>\n",
|
| 374 |
+
" <td>51.023201,53.013199,53.0383,53.041401,55.01419...</td>\n",
|
| 375 |
+
" <td>0.002549437908838331,0.0017867526000527193,0.0...</td>\n",
|
| 376 |
+
" <td>C(CCCCC(=O)O)CCC/C=C/C(=O)O</td>\n",
|
| 377 |
+
" <td>MAZWDMBCPDUFDJ</td>\n",
|
| 378 |
+
" <td>C12H20O4</td>\n",
|
| 379 |
+
" <td>C12H21O4</td>\n",
|
| 380 |
+
" <td>228.135724</td>\n",
|
| 381 |
+
" <td>229.143</td>\n",
|
| 382 |
" <td>[M+H]+</td>\n",
|
| 383 |
" <td>Orbitrap</td>\n",
|
| 384 |
+
" <td>NaN</td>\n",
|
| 385 |
" <td>train</td>\n",
|
| 386 |
+
" <td>False</td>\n",
|
| 387 |
+
" <td>[C4H4, C3H2O, C3H2O, C4H6, C4H6, C3H4O, C4H8, ...</td>\n",
|
| 388 |
+
" <td>[53.0383, 55.017502, 55.020901, 55.053902, 55....</td>\n",
|
| 389 |
+
" <td>[0.12179901477434044, 0.5270370005986297, 0.22...</td>\n",
|
| 390 |
" </tr>\n",
|
| 391 |
" <tr>\n",
|
| 392 |
+
" <th>221801</th>\n",
|
| 393 |
+
" <td>MassSpecGymID0401651</td>\n",
|
| 394 |
+
" <td>50.287594,52.302277,52.304676,52.307671,52.313...</td>\n",
|
| 395 |
+
" <td>0.0027461495504881362,0.011530528389442945,0.0...</td>\n",
|
| 396 |
+
" <td>C(C(CC(=O)O)O)C(=O)O</td>\n",
|
| 397 |
+
" <td>ZQHYXNSQOIDNTL</td>\n",
|
| 398 |
+
" <td>C5H8O5</td>\n",
|
| 399 |
+
" <td>C5H9O5</td>\n",
|
| 400 |
+
" <td>148.036724</td>\n",
|
| 401 |
+
" <td>149.044</td>\n",
|
| 402 |
" <td>[M+H]+</td>\n",
|
| 403 |
" <td>Orbitrap</td>\n",
|
| 404 |
+
" <td>NaN</td>\n",
|
| 405 |
" <td>train</td>\n",
|
| 406 |
+
" <td>False</td>\n",
|
| 407 |
+
" <td>[C3H2O2, C4H8O, C4H4O2, C3H4O3, C5H4O3, C3H8O5...</td>\n",
|
| 408 |
+
" <td>[71.012451, 73.064476, 85.028152, 89.022858, 1...</td>\n",
|
| 409 |
+
" <td>[0.0945515732285825, 0.15281688388394785, 0.19...</td>\n",
|
| 410 |
" </tr>\n",
|
| 411 |
" <tr>\n",
|
| 412 |
+
" <th>115831</th>\n",
|
| 413 |
+
" <td>MassSpecGymID0173164</td>\n",
|
| 414 |
+
" <td>56.964001,75.023003,76.029999,89.038002,90.985...</td>\n",
|
| 415 |
+
" <td>0.027,0.044,0.15,0.615,0.028,1.0,0.103,0.082,0...</td>\n",
|
| 416 |
+
" <td>COC1=C(C=CC(=C1)C=O)O</td>\n",
|
| 417 |
+
" <td>MWOOGOJBHIARFG</td>\n",
|
| 418 |
+
" <td>C8H8O3</td>\n",
|
| 419 |
+
" <td>C8H8NaO3</td>\n",
|
| 420 |
+
" <td>152.050782</td>\n",
|
| 421 |
+
" <td>175.040</td>\n",
|
| 422 |
+
" <td>[M+Na]+</td>\n",
|
| 423 |
" <td>Orbitrap</td>\n",
|
| 424 |
" <td>NaN</td>\n",
|
| 425 |
" <td>train</td>\n",
|
| 426 |
" <td>False</td>\n",
|
| 427 |
+
" <td>[C4H4, C4H5, C5H6, C5H8, C6H6, C5H5O, C6H6O, C...</td>\n",
|
| 428 |
+
" <td>[75.023003, 76.029999, 89.038002, 91.054001, 1...</td>\n",
|
| 429 |
+
" <td>[0.20976176963403032, 0.3872983346207417, 0.78...</td>\n",
|
| 430 |
" </tr>\n",
|
| 431 |
" </tbody>\n",
|
| 432 |
"</table>\n",
|
|
|
|
| 434 |
],
|
| 435 |
"text/plain": [
|
| 436 |
" identifier \\\n",
|
| 437 |
+
"178176 MassSpecGymID0253457 \n",
|
| 438 |
+
"221801 MassSpecGymID0401651 \n",
|
| 439 |
+
"115831 MassSpecGymID0173164 \n",
|
| 440 |
"\n",
|
| 441 |
" mzs \\\n",
|
| 442 |
+
"178176 51.023201,53.013199,53.0383,53.041401,55.01419... \n",
|
| 443 |
+
"221801 50.287594,52.302277,52.304676,52.307671,52.313... \n",
|
| 444 |
+
"115831 56.964001,75.023003,76.029999,89.038002,90.985... \n",
|
| 445 |
"\n",
|
| 446 |
" intensities \\\n",
|
| 447 |
+
"178176 0.002549437908838331,0.0017867526000527193,0.0... \n",
|
| 448 |
+
"221801 0.0027461495504881362,0.011530528389442945,0.0... \n",
|
| 449 |
+
"115831 0.027,0.044,0.15,0.615,0.028,1.0,0.103,0.082,0... \n",
|
| 450 |
"\n",
|
| 451 |
+
" smiles inchikey formula \\\n",
|
| 452 |
+
"178176 C(CCCCC(=O)O)CCC/C=C/C(=O)O MAZWDMBCPDUFDJ C12H20O4 \n",
|
| 453 |
+
"221801 C(C(CC(=O)O)O)C(=O)O ZQHYXNSQOIDNTL C5H8O5 \n",
|
| 454 |
+
"115831 COC1=C(C=CC(=C1)C=O)O MWOOGOJBHIARFG C8H8O3 \n",
|
| 455 |
"\n",
|
| 456 |
+
" precursor_formula parent_mass precursor_mz adduct instrument_type \\\n",
|
| 457 |
+
"178176 C12H21O4 228.135724 229.143 [M+H]+ Orbitrap \n",
|
| 458 |
+
"221801 C5H9O5 148.036724 149.044 [M+H]+ Orbitrap \n",
|
| 459 |
+
"115831 C8H8NaO3 152.050782 175.040 [M+Na]+ Orbitrap \n",
|
| 460 |
"\n",
|
| 461 |
" collision_energy fold simulation_challenge \\\n",
|
| 462 |
+
"178176 NaN train False \n",
|
| 463 |
+
"221801 NaN train False \n",
|
| 464 |
+
"115831 NaN train False \n",
|
| 465 |
"\n",
|
| 466 |
" formulas \\\n",
|
| 467 |
+
"178176 [C4H4, C3H2O, C3H2O, C4H6, C4H6, C3H4O, C4H8, ... \n",
|
| 468 |
+
"221801 [C3H2O2, C4H8O, C4H4O2, C3H4O3, C5H4O3, C3H8O5... \n",
|
| 469 |
+
"115831 [C4H4, C4H5, C5H6, C5H8, C6H6, C5H5O, C6H6O, C... \n",
|
| 470 |
"\n",
|
| 471 |
" formula_mzs \\\n",
|
| 472 |
+
"178176 [53.0383, 55.017502, 55.020901, 55.053902, 55.... \n",
|
| 473 |
+
"221801 [71.012451, 73.064476, 85.028152, 89.022858, 1... \n",
|
| 474 |
+
"115831 [75.023003, 76.029999, 89.038002, 91.054001, 1... \n",
|
| 475 |
"\n",
|
| 476 |
" formula_intensities \n",
|
| 477 |
+
"178176 [0.12179901477434044, 0.5270370005986297, 0.22... \n",
|
| 478 |
+
"221801 [0.0945515732285825, 0.15281688388394785, 0.19... \n",
|
| 479 |
+
"115831 [0.20976176963403032, 0.3872983346207417, 0.78... "
|
| 480 |
]
|
| 481 |
},
|
| 482 |
+
"execution_count": 6,
|
| 483 |
"metadata": {},
|
| 484 |
"output_type": "execute_result"
|
| 485 |
}
|
|
|
|
| 490 |
},
|
| 491 |
{
|
| 492 |
"cell_type": "code",
|
| 493 |
+
"execution_count": 11,
|
| 494 |
"metadata": {},
|
| 495 |
"outputs": [
|
| 496 |
{
|
| 497 |
"data": {
|
| 498 |
"application/vnd.jupyter.widget-view+json": {
|
| 499 |
+
"model_id": "257b01d1c7674ffb9c02851ef9e955c0",
|
| 500 |
"version_major": 2,
|
| 501 |
"version_minor": 0
|
| 502 |
},
|
| 503 |
"text/plain": [
|
| 504 |
"FigureWidget({\n",
|
| 505 |
+
" 'data': [{'customdata': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n",
|
| 506 |
+
" 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,\n",
|
| 507 |
+
" 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41,\n",
|
| 508 |
+
" 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,\n",
|
| 509 |
+
" 55, 56, 57, 58, 59, 60],\n",
|
| 510 |
+
" 'hovertext': [Formula H8C5, Formula H8C6, Formula H2C4O2, Formula\n",
|
| 511 |
+
" H10C6, Formula H8C7, Formula H10C7, Formula H8C6O,\n",
|
| 512 |
+
" Formula H8C8, Formula H10C8, Formula H12C8, Formula\n",
|
| 513 |
+
" H10C9, Formula H12C9, Formula H10C8O, Formula H14C9,\n",
|
| 514 |
+
" Formula H10C10, Formula H12C10, Formula H10C9O, Formula\n",
|
| 515 |
+
" H14C10, Formula H12C9O, Formula H12C11, Formula\n",
|
| 516 |
+
" H10C10O, Formula H14C11, Formula H12C10O, Formula\n",
|
| 517 |
+
" H16C11, Formula H6C8O3, Formula H14C10O, Formula\n",
|
| 518 |
+
" H12C12, Formula H14C12, Formula H12C11O, Formula\n",
|
| 519 |
+
" H16C12, Formula H14C11O, Formula H18C12, Formula\n",
|
| 520 |
+
" H12C10O2, Formula H16C11O, Formula H8C8O4, Formula\n",
|
| 521 |
+
" H14C13, Formula H16C13, Formula H14C12O, Formula\n",
|
| 522 |
+
" H18C13, Formula H12C11O2, Formula H16C12O, Formula\n",
|
| 523 |
+
" H10C10O3, Formula H16C14, Formula H18C14, Formula\n",
|
| 524 |
+
" H12C12O2, Formula H16C13O, Formula H14C12O2, Formula\n",
|
| 525 |
+
" H18C13O, Formula H12C11O3, Formula H14C13O2, Formula\n",
|
| 526 |
+
" H18C14O, Formula H16C13O2, Formula H20C14O, Formula\n",
|
| 527 |
+
" H10C11O4, Formula H14C11O4, Formula H16C14O2, Formula\n",
|
| 528 |
+
" H22C17, Formula H18C15O2, Formula H24C17O, Formula\n",
|
| 529 |
+
" H32C24O3, Formula H36C26O5],\n",
|
| 530 |
" 'marker': {'cmax': 1,\n",
|
| 531 |
" 'cmin': 0,\n",
|
| 532 |
" 'color': 'lightgray',\n",
|
|
|
|
| 542 |
" '#b5de2b'], [1.0, '#fde725']]},\n",
|
| 543 |
" 'name': 'peak',\n",
|
| 544 |
" 'type': 'bar',\n",
|
| 545 |
+
" 'uid': '403be33c-16b4-47eb-854b-9dd044f4d253',\n",
|
| 546 |
+
" 'x': [68.06240171584189, 80.06239778193533, 82.00539944571182,\n",
|
| 547 |
+
" 82.07799766179622, 92.06239912303984, 94.07799900290073,\n",
|
| 548 |
+
" 96.05729742442145, 104.06240046414435, 106.07800034400523,\n",
|
| 549 |
+
" 108.0936002238661, 118.07799641009868, 120.09359628995955,\n",
|
| 550 |
+
" 122.07289998649136, 122.10919693570733, 130.07800302621425,\n",
|
| 551 |
+
" 132.09360290607512, 134.0728960525848, 134.1092035518229,\n",
|
| 552 |
+
" 136.08849593244568, 144.09359897216856, 146.07290266870038,\n",
|
| 553 |
+
" 146.10919961791635, 148.08850254856125, 148.12479949777722,\n",
|
| 554 |
+
" 150.0314991287984, 150.10410319430903, 156.093595038262,\n",
|
| 555 |
+
" 158.1091956840098, 160.0884986146547, 160.12479556387066,\n",
|
| 556 |
+
" 162.10409926040248, 162.14039544373153, 164.08340219104736,\n",
|
| 557 |
+
" 164.11969914026335, 168.04199903408886, 170.10920230012536,\n",
|
| 558 |
+
" 172.12480217998623, 174.10409532649592, 174.1404020598471,\n",
|
| 559 |
+
" 176.0833982571408, 176.1196952063568, 178.06270195367262,\n",
|
| 560 |
+
" 184.12479824607968, 186.14039812594055, 188.08339432323424,\n",
|
| 561 |
+
" 188.11970182247236, 190.09899496898203, 190.13530170233324,\n",
|
| 562 |
+
" 192.07829789962693, 202.0990015850976, 202.13529776842668,\n",
|
| 563 |
+
" 204.11460146495847, 204.15089764828758, 206.0575976622522,\n",
|
| 564 |
+
" 210.08879818786085, 216.1145975310519, 226.17159663396478,\n",
|
| 565 |
+
" 230.13020402702836, 244.1820961563118, 368.2342900551997,\n",
|
| 566 |
+
" 428.25530531140714],\n",
|
| 567 |
" 'xaxis': 'x',\n",
|
| 568 |
+
" 'y': [0.535057008266449, 0.5284685492515564, 0.6902723908424377,\n",
|
| 569 |
+
" 0.40269342064857483, 0.5650832056999207, 0.6598749756813049,\n",
|
| 570 |
+
" 0.3621201515197754, 0.48294201493263245, 0.9612096548080444,\n",
|
| 571 |
+
" 0.7318032383918762, 0.7540351748466492, 1.0,\n",
|
| 572 |
+
" 0.4338064193725586, 0.5893615484237671, 0.41372817754745483,\n",
|
| 573 |
+
" 0.9374854564666748, 0.5265709757804871, 0.7560238242149353,\n",
|
| 574 |
+
" 0.5331829190254211, 0.6711556911468506, 0.3809790015220642,\n",
|
| 575 |
+
" 0.6613901853561401, 0.5919036865234375, 0.38619813323020935,\n",
|
| 576 |
+
" 0.8819172382354736, 0.5150388479232788, 0.4185391366481781,\n",
|
| 577 |
+
" 0.8670363426208496, 0.42916664481163025, 0.6460781693458557,\n",
|
| 578 |
+
" 0.913145124912262, 0.47982287406921387, 0.3621201515197754,\n",
|
| 579 |
+
" 0.6859081387519836, 0.564196765422821, 0.5935924649238586,\n",
|
| 580 |
+
" 0.6460781693458557, 0.4870698153972626, 0.3756873607635498,\n",
|
| 581 |
+
" 0.5275205969810486, 0.49824491143226624, 0.7922297716140747,\n",
|
| 582 |
+
" 0.5052276849746704, 0.6232078075408936, 0.4418087899684906,\n",
|
| 583 |
+
" 0.5169787406921387, 0.5322433710098267, 0.41372817754745483,\n",
|
| 584 |
+
" 0.43149274587631226, 0.37966302037239075, 0.38489997386932373,\n",
|
| 585 |
+
" 0.6343516111373901, 0.535057008266449, 0.3989473581314087,\n",
|
| 586 |
+
" 0.38749194145202637, 0.7440121173858643, 0.6159374713897705,\n",
|
| 587 |
+
" 0.40517157316207886, 0.5650832056999207, 0.36349964141845703,\n",
|
| 588 |
+
" 1.100000023841858],\n",
|
| 589 |
" 'yaxis': 'y'},\n",
|
| 590 |
" {'hoverinfo': 'none',\n",
|
| 591 |
" 'line': {'color': 'gray', 'width': 2},\n",
|
| 592 |
" 'mode': 'lines',\n",
|
| 593 |
" 'showlegend': False,\n",
|
| 594 |
" 'type': 'scatter',\n",
|
| 595 |
+
" 'uid': 'bafe82b8-b282-4e95-ae37-012553da7f51',\n",
|
| 596 |
+
" 'x': [2.5583421472905834, 1.7753548365655238, None,\n",
|
| 597 |
+
" 1.7753548365655238, 0.27584576911133163, None,\n",
|
| 598 |
+
" 0.27584576911133163, -0.5071415416137278, None,\n",
|
| 599 |
+
" -0.5071415416137278, -2.006650609067919, None,\n",
|
| 600 |
+
" -2.006650609067919, -2.7231723657970504, None,\n",
|
| 601 |
+
" -2.7231723657970504, -4.222681433251242, None,\n",
|
| 602 |
+
" -4.222681433251242, -5.005668743976302, None,\n",
|
| 603 |
+
" -5.005668743976302, -6.505177811430492, None,\n",
|
| 604 |
+
" -5.005668743976302, -4.28914698724717, None, -4.28914698724717,\n",
|
| 605 |
+
" -2.7896379197929786, None, -2.7896379197929786,\n",
|
| 606 |
+
" -2.0731161630638466, None, -2.0731161630638466,\n",
|
| 607 |
+
" -0.5736070956096556, None, -0.5736070956096556,\n",
|
| 608 |
+
" 0.2093802151154039, None, 0.2093802151154039,\n",
|
| 609 |
+
" 1.7088892825695952, None, 1.7088892825695952,\n",
|
| 610 |
+
" 2.4918765932946547, None, 2.4918765932946547,\n",
|
| 611 |
+
" 3.9506394063295636, None, 3.9506394063295636,\n",
|
| 612 |
+
" 4.069217095584485, None, 4.069217095584485, 2.6837393248165426,\n",
|
| 613 |
+
" None, 2.6837393248165426, 2.3344385156183947, None,\n",
|
| 614 |
+
" 4.069217095584485, 5.348643088459236, None, 3.9506394063295636,\n",
|
| 615 |
+
" 5.0906689652143875, None, 2.4918765932946547,\n",
|
| 616 |
+
" 3.4043110505061365, None, 1.7088892825695952,\n",
|
| 617 |
+
" 1.1340403052652162, None, 1.1340403052652162,\n",
|
| 618 |
+
" 0.2181749852801769, None, 1.1340403052652162, 2.0464747624767,\n",
|
| 619 |
+
" None, 2.0464747624767, 1.4716257851723231, None,\n",
|
| 620 |
+
" 0.2093802151154039, 0.9259019718445355, None,\n",
|
| 621 |
+
" -4.28914698724717, -4.066550889929987, None, -4.28914698724717,\n",
|
| 622 |
+
" -5.711349241391562, None, -2.006650609067919,\n",
|
| 623 |
+
" -1.2236632983428586, None, 2.4918765932946547,\n",
|
| 624 |
+
" 1.7753548365655238, None, 0.2093802151154039,\n",
|
| 625 |
+
" -0.5071415416137278, None, -2.7896379197929786,\n",
|
| 626 |
+
" -2.006650609067919, None, 2.6837393248165426,\n",
|
| 627 |
+
" 1.7088892825695952, None],\n",
|
| 628 |
" 'xaxis': 'x2',\n",
|
| 629 |
+
" 'y': [2.9569768914725025, 1.677550898597754, None,\n",
|
| 630 |
+
" 1.677550898597754, 1.7159248040891406, None,\n",
|
| 631 |
+
" 1.7159248040891406, 0.43649881121439116, None,\n",
|
| 632 |
+
" 0.43649881121439116, 0.4748727167057778, None,\n",
|
| 633 |
+
" 0.4748727167057778, 1.7926726150719152, None,\n",
|
| 634 |
+
" 1.7926726150719152, 1.8310465205633017, None,\n",
|
| 635 |
+
" 1.8310465205633017, 0.5516205276885522, None,\n",
|
| 636 |
+
" 0.5516205276885522, 0.5899944331799385, None,\n",
|
| 637 |
+
" 0.5516205276885522, -0.7661793706775843, None,\n",
|
| 638 |
+
" -0.7661793706775843, -0.8045532761689715, None,\n",
|
| 639 |
+
" -0.8045532761689715, -2.122353174535109, None,\n",
|
| 640 |
+
" -2.122353174535109, -2.1607270800264953, None,\n",
|
| 641 |
+
" -2.1607270800264953, -0.8813010871517453, None,\n",
|
| 642 |
+
" -0.8813010871517453, -0.9196749926431328, None,\n",
|
| 643 |
+
" -0.9196749926431328, 0.35975100023161755, None,\n",
|
| 644 |
+
" 0.35975100023161755, 0.010450191033470002, None,\n",
|
| 645 |
+
" 0.010450191033470002, -1.484855574223577, None,\n",
|
| 646 |
+
" -1.484855574223577, -2.059704551527956, None,\n",
|
| 647 |
+
" -2.059704551527956, -3.5184673645628646, None,\n",
|
| 648 |
+
" -1.484855574223577, -2.2678428849486365, None,\n",
|
| 649 |
+
" 0.010450191033470002, 0.9853002332804177, None,\n",
|
| 650 |
+
" 0.35975100023161755, 1.5503237033006856, None,\n",
|
| 651 |
+
" -0.9196749926431328, 0.4658027781248113, None,\n",
|
| 652 |
+
" 0.4658027781248113, 0.8259998604959788, None,\n",
|
| 653 |
+
" 0.4658027781248113, 1.6563754811938778, None,\n",
|
| 654 |
+
" 1.6563754811938778, 3.0418532519618227, None,\n",
|
| 655 |
+
" -0.8813010871517453, -2.199100985517882, None,\n",
|
| 656 |
+
" -0.7661793706775843, -2.24957108477712, None,\n",
|
| 657 |
+
" -0.7661793706775843, -1.2429820010254153, None,\n",
|
| 658 |
+
" 0.4748727167057778, 1.754298709580529, None,\n",
|
| 659 |
+
" 0.35975100023161755, 1.677550898597754, None,\n",
|
| 660 |
+
" -0.8813010871517453, 0.43649881121439116, None,\n",
|
| 661 |
+
" -0.8045532761689715, 0.4748727167057778, None,\n",
|
| 662 |
+
" -2.059704551527956, -0.9196749926431328, None],\n",
|
| 663 |
" 'yaxis': 'y2'},\n",
|
| 664 |
" {'customdata': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n",
|
| 665 |
+
" 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,\n",
|
| 666 |
+
" 29, 30],\n",
|
| 667 |
" 'marker': {'cmax': 1,\n",
|
| 668 |
" 'cmin': 0,\n",
|
| 669 |
" 'color': 'lightgray',\n",
|
|
|
|
| 680 |
" 'size': 20},\n",
|
| 681 |
" 'mode': 'markers+text',\n",
|
| 682 |
" 'name': 'node',\n",
|
| 683 |
+
" 'text': [C, C, C, C, C, C, C, C, O, C, C, C, C, C, C, C, C, C, C, O,\n",
|
| 684 |
+
" C, O, C, C, O, O, C, C, C, C, C],\n",
|
| 685 |
" 'textposition': 'middle center',\n",
|
| 686 |
" 'type': 'scatter',\n",
|
| 687 |
+
" 'uid': '07c41a52-ebdc-4197-bfba-0b0c5eb1e54c',\n",
|
| 688 |
+
" 'x': [2.5583421472905834, 1.7753548365655238, 0.27584576911133163,\n",
|
| 689 |
+
" -0.5071415416137278, -2.006650609067919, -2.7231723657970504,\n",
|
| 690 |
+
" -4.222681433251242, -5.005668743976302, -6.505177811430492,\n",
|
| 691 |
+
" -4.28914698724717, -2.7896379197929786, -2.0731161630638466,\n",
|
| 692 |
+
" -0.5736070956096556, 0.2093802151154039, 1.7088892825695952,\n",
|
| 693 |
+
" 2.4918765932946547, 3.9506394063295636, 4.069217095584485,\n",
|
| 694 |
+
" 2.6837393248165426, 2.3344385156183947, 5.348643088459236,\n",
|
| 695 |
+
" 5.0906689652143875, 3.4043110505061365, 1.1340403052652162,\n",
|
| 696 |
+
" 0.2181749852801769, 2.0464747624767, 1.4716257851723231,\n",
|
| 697 |
+
" 0.9259019718445355, -4.066550889929987, -5.711349241391562,\n",
|
| 698 |
+
" -1.2236632983428586],\n",
|
| 699 |
" 'xaxis': 'x2',\n",
|
| 700 |
+
" 'y': [2.9569768914725025, 1.677550898597754, 1.7159248040891406,\n",
|
| 701 |
+
" 0.43649881121439116, 0.4748727167057778, 1.7926726150719152,\n",
|
| 702 |
+
" 1.8310465205633017, 0.5516205276885522, 0.5899944331799385,\n",
|
| 703 |
+
" -0.7661793706775843, -0.8045532761689715, -2.122353174535109,\n",
|
| 704 |
+
" -2.1607270800264953, -0.8813010871517453, -0.9196749926431328,\n",
|
| 705 |
+
" 0.35975100023161755, 0.010450191033470002, -1.484855574223577,\n",
|
| 706 |
+
" -2.059704551527956, -3.5184673645628646, -2.2678428849486365,\n",
|
| 707 |
+
" 0.9853002332804177, 1.5503237033006856, 0.4658027781248113,\n",
|
| 708 |
+
" 0.8259998604959788, 1.6563754811938778, 3.0418532519618227,\n",
|
| 709 |
+
" -2.199100985517882, -2.24957108477712, -1.2429820010254153,\n",
|
| 710 |
+
" 1.754298709580529],\n",
|
| 711 |
" 'yaxis': 'y2'}],\n",
|
| 712 |
" 'layout': {'annotations': [{'font': {'size': 16},\n",
|
| 713 |
" 'showarrow': False,\n",
|
|
|
|
| 737 |
"})"
|
| 738 |
]
|
| 739 |
},
|
| 740 |
+
"execution_count": 11,
|
| 741 |
"metadata": {},
|
| 742 |
"output_type": "execute_result"
|
| 743 |
}
|
|
|
|
| 748 |
"# Data\n",
|
| 749 |
"# i = 40991\n",
|
| 750 |
"\n",
|
| 751 |
+
"ms_id = \"MassSpecGymID0001014\"\n",
|
| 752 |
"i = dataset.metadata[dataset.metadata['identifier'] == ms_id].index[0]\n",
|
| 753 |
"s = dataset.metadata.iloc[i]['smiles']\n",
|
| 754 |
"mol = Chem.MolFromSmiles(s)\n",
|
notebooks/fine-grained_vs_global.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/good_vs_bad_instances.ipynb
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": 1,
|
| 6 |
+
"id": "e482a752",
|
| 7 |
+
"metadata": {},
|
| 8 |
+
"outputs": [],
|
| 9 |
+
"source": [
|
| 10 |
+
"import torch\n",
|
| 11 |
+
"import numpy as np\n",
|
| 12 |
+
"import plotly.graph_objects as go\n",
|
| 13 |
+
"from plotly.subplots import make_subplots\n",
|
| 14 |
+
"from rdkit import Chem\n",
|
| 15 |
+
"from rdkit.Chem import rdDepictor\n",
|
| 16 |
+
"from rdkit.Chem.Draw import rdMolDraw2D\n",
|
| 17 |
+
"import pandas as pd\n",
|
| 18 |
+
"import matchms"
|
| 19 |
+
]
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
"cell_type": "code",
|
| 23 |
+
"execution_count": 2,
|
| 24 |
+
"id": "c92d2ad6",
|
| 25 |
+
"metadata": {},
|
| 26 |
+
"outputs": [
|
| 27 |
+
{
|
| 28 |
+
"name": "stdout",
|
| 29 |
+
"output_type": "stream",
|
| 30 |
+
"text": [
|
| 31 |
+
"Loaded Model from checkpoint\n"
|
| 32 |
+
]
|
| 33 |
+
}
|
| 34 |
+
],
|
| 35 |
+
"source": [
|
| 36 |
+
"import sys\n",
|
| 37 |
+
"sys.path.insert(0, \"..\")\n",
|
| 38 |
+
"from flare.subformula_assign.utils.spectra_utils import assign_subforms\n",
|
| 39 |
+
"\n",
|
| 40 |
+
"from rdkit import RDLogger\n",
|
| 41 |
+
"\n",
|
| 42 |
+
"from flare.utils.data import get_spec_featurizer, get_mol_featurizer\n",
|
| 43 |
+
"from flare.utils.models import get_model\n",
|
| 44 |
+
"\n",
|
| 45 |
+
"import yaml\n",
|
| 46 |
+
"# Suppress RDKit warnings and errors\n",
|
| 47 |
+
"lg = RDLogger.logger()\n",
|
| 48 |
+
"lg.setLevel(RDLogger.CRITICAL)\n",
|
| 49 |
+
"\n",
|
| 50 |
+
"# Load model and data\n",
|
| 51 |
+
"\n",
|
| 52 |
+
"param_pth = '/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/lightning_logs/version_0/hparams.yaml'\n",
|
| 53 |
+
"with open(param_pth) as f:\n",
|
| 54 |
+
" params = yaml.load(f, Loader=yaml.FullLoader)\n",
|
| 55 |
+
"\n",
|
| 56 |
+
"spec_featurizer = get_spec_featurizer(params['spectra_view'], params)\n",
|
| 57 |
+
"mol_featurizer = get_mol_featurizer(params['molecule_view'], params)\n",
|
| 58 |
+
"\n",
|
| 59 |
+
"# load model\n",
|
| 60 |
+
"import torch \n",
|
| 61 |
+
"checkpoint_pth = \"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/epoch=1959-train_loss=0.08.ckpt\"\n",
|
| 62 |
+
"params['checkpoint_pth'] = checkpoint_pth\n",
|
| 63 |
+
"model = get_model(params['model'], params)"
|
| 64 |
+
]
|
| 65 |
+
},
|
| 66 |
+
{
|
| 67 |
+
"cell_type": "code",
|
| 68 |
+
"execution_count": 3,
|
| 69 |
+
"id": "7705e8bf",
|
| 70 |
+
"metadata": {},
|
| 71 |
+
"outputs": [],
|
| 72 |
+
"source": [
|
| 73 |
+
"# load data\n",
|
| 74 |
+
"# result\n",
|
| 75 |
+
"with open(\"/data/yzhouc01/FILIP-MS/experiments/20250930_optimized_flare_42/main_result/result_MassSpecGym_retrieval_candidates_mass.pkl\", \"rb\") as f:\n",
|
| 76 |
+
" results = pd.read_pickle(f)\n",
|
| 77 |
+
"\n",
|
| 78 |
+
"# raw data\n",
|
| 79 |
+
"data = pd.read_csv(\"/r/hassounlab/spectra_data/msgym/MassSpecGym.tsv\", sep=\"\\t\")"
|
| 80 |
+
]
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
"cell_type": "code",
|
| 84 |
+
"execution_count": 5,
|
| 85 |
+
"id": "13bfa58f",
|
| 86 |
+
"metadata": {},
|
| 87 |
+
"outputs": [],
|
| 88 |
+
"source": [
|
| 89 |
+
"def get_n_heavy_atoms(target):\n",
|
| 90 |
+
" mol = Chem.MolFromSmiles(target)\n",
|
| 91 |
+
" if mol is None:\n",
|
| 92 |
+
" return 0\n",
|
| 93 |
+
" return mol.GetNumHeavyAtoms()\n",
|
| 94 |
+
"\n",
|
| 95 |
+
"results['n_heavy_atoms'] = results['target'].apply(get_n_heavy_atoms)"
|
| 96 |
+
]
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
"cell_type": "code",
|
| 100 |
+
"execution_count": 6,
|
| 101 |
+
"id": "6f4bd61a",
|
| 102 |
+
"metadata": {},
|
| 103 |
+
"outputs": [],
|
| 104 |
+
"source": [
|
| 105 |
+
"\n",
|
| 106 |
+
"import torch.nn.functional as F\n",
|
| 107 |
+
"\n",
|
| 108 |
+
"def mol_to_graph_coords(mol):\n",
|
| 109 |
+
" \"\"\"Return atom coordinates and bond list for a molecule.\"\"\"\n",
|
| 110 |
+
" rdDepictor.Compute2DCoords(mol)\n",
|
| 111 |
+
" conf = mol.GetConformer()\n",
|
| 112 |
+
" coords = {i: conf.GetAtomPosition(i) for i in range(mol.GetNumAtoms())}\n",
|
| 113 |
+
" bonds = [(b.GetBeginAtomIdx(), b.GetEndAtomIdx()) for b in mol.GetBonds()]\n",
|
| 114 |
+
" return coords, bonds\n",
|
| 115 |
+
"\n",
|
| 116 |
+
"import torch\n",
|
| 117 |
+
"import torch.nn.functional as F\n",
|
| 118 |
+
"import plotly.graph_objects as go\n",
|
| 119 |
+
"from plotly.subplots import make_subplots\n",
|
| 120 |
+
"from ipywidgets import VBox\n",
|
| 121 |
+
"\n",
|
| 122 |
+
"def interactive_attention_visualization(spectral_embeds, graph_embeds, \n",
|
| 123 |
+
" peak_mzs, peak_intensities, peak_formulas, mol):\n",
|
| 124 |
+
" \"\"\"\n",
|
| 125 |
+
" Interactive visualization of peak-node similarity.\n",
|
| 126 |
+
" - Click a peak: recolor molecule nodes by similarity; other peaks turn gray\n",
|
| 127 |
+
" - Click a node: recolor peaks by similarity; other nodes turn gray\n",
|
| 128 |
+
" \"\"\"\n",
|
| 129 |
+
"\n",
|
| 130 |
+
" # --- Compute similarity ---\n",
|
| 131 |
+
" spectral_embeds = F.normalize(spectral_embeds, p=2, dim=-1)\n",
|
| 132 |
+
" graph_embeds = F.normalize(graph_embeds, p=2, dim=-1)\n",
|
| 133 |
+
" similarity = torch.matmul(spectral_embeds, graph_embeds.T).detach().cpu().numpy()\n",
|
| 134 |
+
" sim_norm = (similarity - similarity.min()) / (similarity.max() - similarity.min() + 1e-8)\n",
|
| 135 |
+
" num_peaks, num_nodes = similarity.shape\n",
|
| 136 |
+
"\n",
|
| 137 |
+
" # --- Molecule layout ---\n",
|
| 138 |
+
" coords, bonds = mol_to_graph_coords(mol)\n",
|
| 139 |
+
" atom_labels = [a.GetSymbol() for a in mol.GetAtoms()]\n",
|
| 140 |
+
" atom_x = [coords[i].x for i in range(num_nodes)]\n",
|
| 141 |
+
" atom_y = [coords[i].y for i in range(num_nodes)]\n",
|
| 142 |
+
"\n",
|
| 143 |
+
" # --- Draw vertical bar lines ---\n",
|
| 144 |
+
" bar_x, bar_y = [], []\n",
|
| 145 |
+
" for mz, inten in zip(peak_mzs, peak_intensities):\n",
|
| 146 |
+
" bar_x += [mz, mz, None]\n",
|
| 147 |
+
" bar_y += [0, inten, None]\n",
|
| 148 |
+
" bar_lines = go.Scatter(\n",
|
| 149 |
+
" x=bar_x, y=bar_y,\n",
|
| 150 |
+
" mode=\"lines\",\n",
|
| 151 |
+
" line=dict(color=\"lightgray\", width=4),\n",
|
| 152 |
+
" hoverinfo=\"skip\",\n",
|
| 153 |
+
" showlegend=False\n",
|
| 154 |
+
" )\n",
|
| 155 |
+
"\n",
|
| 156 |
+
" # --- Clickable markers for peaks ---\n",
|
| 157 |
+
" spectrum_clickables = go.Scatter(\n",
|
| 158 |
+
" x=peak_mzs, y=peak_intensities,\n",
|
| 159 |
+
" mode=\"markers\",\n",
|
| 160 |
+
" marker=dict(\n",
|
| 161 |
+
" size=12,\n",
|
| 162 |
+
" color=[\"lightgray\"] * num_peaks,\n",
|
| 163 |
+
" colorscale=\"Viridis\",\n",
|
| 164 |
+
" cmin=0, cmax=1,\n",
|
| 165 |
+
" opacity=0.8,\n",
|
| 166 |
+
" colorbar=dict(title=\"Similarity\", len=0.8, y=0.5)\n",
|
| 167 |
+
" ),\n",
|
| 168 |
+
" name=\"peaks\",\n",
|
| 169 |
+
" # hovertext=[f\"m/z {mz:.4f}<br>Intensity: {inten:.2f}<br>Formula: {form}\"\n",
|
| 170 |
+
" # for mz, inten, form in zip(peak_mzs, peak_intensities, peak_formulas)],\n",
|
| 171 |
+
" hovertext = [f for f in peak_formulas],\n",
|
| 172 |
+
" customdata=list(range(num_peaks))\n",
|
| 173 |
+
" )\n",
|
| 174 |
+
"\n",
|
| 175 |
+
" # --- Graph bonds ---\n",
|
| 176 |
+
" edge_x, edge_y = [], []\n",
|
| 177 |
+
" for i, j in bonds:\n",
|
| 178 |
+
" edge_x += [coords[i].x, coords[j].x, None]\n",
|
| 179 |
+
" edge_y += [coords[i].y, coords[j].y, None]\n",
|
| 180 |
+
" graph_edges = go.Scatter(\n",
|
| 181 |
+
" x=edge_x, y=edge_y,\n",
|
| 182 |
+
" mode=\"lines\", line=dict(color=\"gray\", width=2),\n",
|
| 183 |
+
" hoverinfo=\"none\", showlegend=False\n",
|
| 184 |
+
" )\n",
|
| 185 |
+
"\n",
|
| 186 |
+
" # --- Graph nodes ---\n",
|
| 187 |
+
" graph_nodes = go.Scatter(\n",
|
| 188 |
+
" x=atom_x, y=atom_y,\n",
|
| 189 |
+
" mode=\"markers+text\",\n",
|
| 190 |
+
" text=atom_labels,\n",
|
| 191 |
+
" textposition=\"middle center\",\n",
|
| 192 |
+
" name=\"nodes\",\n",
|
| 193 |
+
" marker=dict(\n",
|
| 194 |
+
" size=25,\n",
|
| 195 |
+
" color=[\"lightgray\"] * num_nodes,\n",
|
| 196 |
+
" colorscale=\"Viridis\",\n",
|
| 197 |
+
" cmin=0, cmax=1,\n",
|
| 198 |
+
" colorbar=dict(title=\"Similarity\", len=0.8, y=0.5)\n",
|
| 199 |
+
" ),\n",
|
| 200 |
+
" customdata=list(range(num_nodes)),\n",
|
| 201 |
+
" hovertext=[f\"Atom {i} ({label})\" for i, label in enumerate(atom_labels)]\n",
|
| 202 |
+
" )\n",
|
| 203 |
+
"\n",
|
| 204 |
+
" spectrum_clickables.hoverlabel = dict(font_size=20, font_family=\"Arial\")\n",
|
| 205 |
+
" graph_nodes.hoverlabel = dict(font_size=20, font_family=\"Arial\")\n",
|
| 206 |
+
"\n",
|
| 207 |
+
" # --- Layout ---\n",
|
| 208 |
+
" fig = make_subplots(\n",
|
| 209 |
+
" rows=1, cols=2,\n",
|
| 210 |
+
" subplot_titles=(\"Spectrum\", \"Molecule\"),\n",
|
| 211 |
+
" column_widths=[0.6, 0.4]\n",
|
| 212 |
+
" )\n",
|
| 213 |
+
"\n",
|
| 214 |
+
" fig.add_trace(bar_lines, row=1, col=1) # index 0\n",
|
| 215 |
+
" fig.add_trace(spectrum_clickables, row=1, col=1) # index 1\n",
|
| 216 |
+
" fig.add_trace(graph_edges, row=1, col=2) # index 2\n",
|
| 217 |
+
" fig.add_trace(graph_nodes, row=1, col=2) # index 3\n",
|
| 218 |
+
"\n",
|
| 219 |
+
" # --- Axis titles and tick labels ---\n",
|
| 220 |
+
" fig.update_xaxes(\n",
|
| 221 |
+
" title=\"m/z\",\n",
|
| 222 |
+
" title_font=dict(size=24),\n",
|
| 223 |
+
" tickfont=dict(size=20),\n",
|
| 224 |
+
" row=1, col=1\n",
|
| 225 |
+
" )\n",
|
| 226 |
+
" fig.update_yaxes(\n",
|
| 227 |
+
" title=\"Intensity\",\n",
|
| 228 |
+
" title_font=dict(size=24),\n",
|
| 229 |
+
" tickfont=dict(size=20),\n",
|
| 230 |
+
" row=1, col=1\n",
|
| 231 |
+
" )\n",
|
| 232 |
+
" fig.update_xaxes(visible=False, row=1, col=2)\n",
|
| 233 |
+
" fig.update_yaxes(visible=False, row=1, col=2)\n",
|
| 234 |
+
"\n",
|
| 235 |
+
" # --- General layout and fonts ---\n",
|
| 236 |
+
" fig.update_layout(\n",
|
| 237 |
+
" title=dict(text=\"Peak ↔ Node Similarity\", font=dict(size=30)),\n",
|
| 238 |
+
" showlegend=False,\n",
|
| 239 |
+
" font=dict(size=22), # affects all text elements\n",
|
| 240 |
+
" margin=dict(l=80, r=80, t=100, b=80),\n",
|
| 241 |
+
" )\n",
|
| 242 |
+
"\n",
|
| 243 |
+
" # --- Increase font for subplot titles (Spectrum, Molecule) ---\n",
|
| 244 |
+
" for ann in fig.layout.annotations:\n",
|
| 245 |
+
" ann.font.size = 24\n",
|
| 246 |
+
"\n",
|
| 247 |
+
" # --- Increase colorbar font sizes for both peaks and nodes ---\n",
|
| 248 |
+
" fig.data[1].marker.colorbar.title.font = dict(size=22)\n",
|
| 249 |
+
" fig.data[1].marker.colorbar.tickfont = dict(size=18)\n",
|
| 250 |
+
"\n",
|
| 251 |
+
" fig.data[3].marker.colorbar.title.font = dict(size=22)\n",
|
| 252 |
+
" fig.data[3].marker.colorbar.tickfont = dict(size=18)\n",
|
| 253 |
+
"\n",
|
| 254 |
+
" # --- Make atom labels (graph_nodes) larger ---\n",
|
| 255 |
+
" fig.data[3].textfont = dict(size=22)\n",
|
| 256 |
+
"\n",
|
| 257 |
+
"\n",
|
| 258 |
+
" fig.update_layout(\n",
|
| 259 |
+
" title=dict(text=\"Peak ↔ Node Similarity\", font=dict(size=30)),\n",
|
| 260 |
+
" showlegend=False,\n",
|
| 261 |
+
" font=dict(size=22), # affects general text\n",
|
| 262 |
+
" hoverlabel=dict(\n",
|
| 263 |
+
" font_size=20, # make hovertext larger globally\n",
|
| 264 |
+
" font_family=\"Arial\"\n",
|
| 265 |
+
" ),\n",
|
| 266 |
+
" margin=dict(l=80, r=80, t=100, b=80),\n",
|
| 267 |
+
" ) \n",
|
| 268 |
+
"\n",
|
| 269 |
+
" fw = go.FigureWidget(fig)\n",
|
| 270 |
+
"\n",
|
| 271 |
+
" # --- Interactivity handlers ---\n",
|
| 272 |
+
" def highlight_nodes(trace, points, selector):\n",
|
| 273 |
+
" \"\"\"Click a peak → recolor molecule nodes & gray other peaks\"\"\"\n",
|
| 274 |
+
" if points.point_inds:\n",
|
| 275 |
+
" peak_idx = points.point_inds[0]\n",
|
| 276 |
+
" scores = sim_norm[peak_idx, :]\n",
|
| 277 |
+
" with fw.batch_update():\n",
|
| 278 |
+
" # recolor nodes by similarity\n",
|
| 279 |
+
" fw.data[3].marker.color = scores\n",
|
| 280 |
+
" # make all peaks gray, clicked one red\n",
|
| 281 |
+
" fw.data[1].marker.color = [\n",
|
| 282 |
+
" \"red\" if i == peak_idx else \"lightgray\" for i in range(num_peaks)\n",
|
| 283 |
+
" ]\n",
|
| 284 |
+
"\n",
|
| 285 |
+
" def highlight_peaks(trace, points, selector):\n",
|
| 286 |
+
" \"\"\"Click a node → recolor peaks & gray other nodes\"\"\"\n",
|
| 287 |
+
" if points.point_inds:\n",
|
| 288 |
+
" node_idx = points.point_inds[0]\n",
|
| 289 |
+
" scores = sim_norm[:, node_idx]\n",
|
| 290 |
+
" with fw.batch_update():\n",
|
| 291 |
+
" # recolor peaks by similarity\n",
|
| 292 |
+
" fw.data[1].marker.color = scores\n",
|
| 293 |
+
" # make all nodes gray, clicked one red\n",
|
| 294 |
+
" fw.data[3].marker.color = [\n",
|
| 295 |
+
" \"red\" if j == node_idx else \"lightgray\" for j in range(num_nodes)\n",
|
| 296 |
+
" ]\n",
|
| 297 |
+
"\n",
|
| 298 |
+
" fw.data[1].on_click(highlight_nodes) # clickable peaks\n",
|
| 299 |
+
" fw.data[3].on_click(highlight_peaks) # clickable nodes\n",
|
| 300 |
+
"\n",
|
| 301 |
+
" return fw\n",
|
| 302 |
+
"\n"
|
| 303 |
+
]
|
| 304 |
+
},
|
| 305 |
+
{
|
| 306 |
+
"cell_type": "code",
|
| 307 |
+
"execution_count": 7,
|
| 308 |
+
"id": "32423f15",
|
| 309 |
+
"metadata": {},
|
| 310 |
+
"outputs": [],
|
| 311 |
+
"source": [
|
| 312 |
+
"def run(ms, smiles, formula, precursor_mz, adduct, mass_diff_thresh=20, precursor_intensity=1.1, model=model):\n",
|
| 313 |
+
"\n",
|
| 314 |
+
" # step 1 - label peaks with formula, setup matchms spectrum\n",
|
| 315 |
+
" x = assign_subforms(formula, np.array(ms), adduct, mass_diff_thresh=mass_diff_thresh)\n",
|
| 316 |
+
" if x['output_tbl'] is None:\n",
|
| 317 |
+
" return None, None\n",
|
| 318 |
+
" \n",
|
| 319 |
+
" formulas = np.array(x['output_tbl']['formula'])\n",
|
| 320 |
+
" mzs = x['output_tbl']['mz']\n",
|
| 321 |
+
" intensities = x['output_tbl']['ms2_inten']\n",
|
| 322 |
+
" mzs = np.array([float(m) for m in mzs])\n",
|
| 323 |
+
" intensities = np.array([float(i) for i in intensities])\n",
|
| 324 |
+
"\n",
|
| 325 |
+
" # add precursor if not already present\n",
|
| 326 |
+
" if formula not in formulas: \n",
|
| 327 |
+
" mzs = np.concatenate([mzs, [float(precursor_mz)]])\n",
|
| 328 |
+
" formulas = np.concatenate([formulas, [formula]])\n",
|
| 329 |
+
" intensities = np.concatenate([intensities, [float(precursor_intensity)]])\n",
|
| 330 |
+
" else:\n",
|
| 331 |
+
" i = np.where(formulas==formula)[0]\n",
|
| 332 |
+
" intensities[i] = precursor_intensity\n",
|
| 333 |
+
"\n",
|
| 334 |
+
" # keep intensities larger than 0.05\n",
|
| 335 |
+
" keep_idx = intensities >= 0.05\n",
|
| 336 |
+
" mzs = mzs[keep_idx]\n",
|
| 337 |
+
" intensities = intensities[keep_idx]\n",
|
| 338 |
+
" formulas = formulas[keep_idx]\n",
|
| 339 |
+
"\n",
|
| 340 |
+
" sorted_idx = np.argsort(mzs)\n",
|
| 341 |
+
" mzs = mzs[sorted_idx]\n",
|
| 342 |
+
" intensities = intensities[sorted_idx]\n",
|
| 343 |
+
" formulas = formulas[sorted_idx]\n",
|
| 344 |
+
"\n",
|
| 345 |
+
" spectrum = matchms.Spectrum(\n",
|
| 346 |
+
" mz = mzs,\n",
|
| 347 |
+
" intensities = intensities,\n",
|
| 348 |
+
" metadata = {'precursor_mz': precursor_mz, 'formulas': formulas}\n",
|
| 349 |
+
" )\n",
|
| 350 |
+
"\n",
|
| 351 |
+
" # step 2 - featurize spectra\n",
|
| 352 |
+
" spectrum_encoding = spec_featurizer['SpecFormula'](spectrum)\n",
|
| 353 |
+
"\n",
|
| 354 |
+
" # step 3 - featuraize molecule\n",
|
| 355 |
+
" molecule_encoding = mol_featurizer(smiles)\n",
|
| 356 |
+
" \n",
|
| 357 |
+
" # step 4 - Embed spectra & molecules\n",
|
| 358 |
+
" model_input = {'mol': molecule_encoding, 'SpecFormula': spectrum_encoding}\n",
|
| 359 |
+
" \n",
|
| 360 |
+
" model = model.to(torch.device('cpu'))\n",
|
| 361 |
+
" model.eval()\n",
|
| 362 |
+
" with torch.no_grad():\n",
|
| 363 |
+
" spec_embed, mol_embed = model.forward(model_input, stage='test')\n",
|
| 364 |
+
"\n",
|
| 365 |
+
"\n",
|
| 366 |
+
" # step 5 - visualization\n",
|
| 367 |
+
" mol = Chem.MolFromSmiles(smiles)\n",
|
| 368 |
+
" fw = interactive_attention_visualization(spec_embed, mol_embed, mzs, intensities, formulas, mol)\n",
|
| 369 |
+
" return fw"
|
| 370 |
+
]
|
| 371 |
+
},
|
| 372 |
+
{
|
| 373 |
+
"cell_type": "code",
|
| 374 |
+
"execution_count": null,
|
| 375 |
+
"id": "d9a4bc6d",
|
| 376 |
+
"metadata": {},
|
| 377 |
+
"outputs": [
|
| 378 |
+
{
|
| 379 |
+
"data": {
|
| 380 |
+
"text/plain": [
|
| 381 |
+
"33"
|
| 382 |
+
]
|
| 383 |
+
},
|
| 384 |
+
"execution_count": 8,
|
| 385 |
+
"metadata": {},
|
| 386 |
+
"output_type": "execute_result"
|
| 387 |
+
}
|
| 388 |
+
],
|
| 389 |
+
"source": [
|
| 390 |
+
"len(results[cond1 & cond2])"
|
| 391 |
+
]
|
| 392 |
+
},
|
| 393 |
+
{
|
| 394 |
+
"cell_type": "code",
|
| 395 |
+
"execution_count": 9,
|
| 396 |
+
"id": "e3346225",
|
| 397 |
+
"metadata": {},
|
| 398 |
+
"outputs": [
|
| 399 |
+
{
|
| 400 |
+
"name": "stdout",
|
| 401 |
+
"output_type": "stream",
|
| 402 |
+
"text": [
|
| 403 |
+
"MassSpecGymID0235850 1\n"
|
| 404 |
+
]
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
"data": {
|
| 408 |
+
"application/vnd.jupyter.widget-view+json": {
|
| 409 |
+
"model_id": "008dba4038c94b049a2757c59806b672",
|
| 410 |
+
"version_major": 2,
|
| 411 |
+
"version_minor": 0
|
| 412 |
+
},
|
| 413 |
+
"text/plain": [
|
| 414 |
+
"FigureWidget({\n",
|
| 415 |
+
" 'data': [{'hoverinfo': 'skip',\n",
|
| 416 |
+
" 'line': {'color': 'lightgray', 'width': 4},\n",
|
| 417 |
+
" 'mode': 'lines',\n",
|
| 418 |
+
" 'showlegend': False,\n",
|
| 419 |
+
" 'type': 'scatter',\n",
|
| 420 |
+
" 'uid': 'bd98f226-685c-4d7f-a895-7df8b9071d42',\n",
|
| 421 |
+
" 'x': [53.038452, 53.038452, None, 55.054085, 55.054085, None,\n",
|
| 422 |
+
" 79.021011, 79.021011, None, 174.03746, 174.03746, None,\n",
|
| 423 |
+
" 178.043579, 178.043579, None, 189.048355, 189.048355, None,\n",
|
| 424 |
+
" 204.059418, 204.059418, None, 205.079803, 205.079803, None,\n",
|
| 425 |
+
" 206.075012, 206.075012, None, 218.075211, 218.075211, None,\n",
|
| 426 |
+
" 232.09082, 232.09082, None, 260.122498, 260.122498, None],\n",
|
| 427 |
+
" 'xaxis': 'x',\n",
|
| 428 |
+
" 'y': [0, 0.05035, None, 0, 1.0, None, 0, 0.25114000000000003, None,\n",
|
| 429 |
+
" 0, 0.07694, None, 0, 0.11010999999999999, None, 0,\n",
|
| 430 |
+
" 0.20248000000000002, None, 0, 0.1573, None, 0, 0.11588, None,\n",
|
| 431 |
+
" 0, 0.60917, None, 0, 0.16637000000000002, None, 0, 0.49138,\n",
|
| 432 |
+
" None, 0, 1.1, None],\n",
|
| 433 |
+
" 'yaxis': 'y'},\n",
|
| 434 |
+
" {'customdata': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],\n",
|
| 435 |
+
" 'hoverlabel': {'font': {'family': 'Arial', 'size': 20}},\n",
|
| 436 |
+
" 'hovertext': [C4H4, C4H6, H4N3S, C10H7NS, C8H7N3S, C10H8N2S,\n",
|
| 437 |
+
" C10H9N3S, C11H12N2S, C10H11N3S, C11H11N3S, C12H13N3S,\n",
|
| 438 |
+
" C14H17N3S],\n",
|
| 439 |
+
" 'marker': {'cmax': 1,\n",
|
| 440 |
+
" 'cmin': 0,\n",
|
| 441 |
+
" 'color': [lightgray, lightgray, lightgray, lightgray,\n",
|
| 442 |
+
" lightgray, lightgray, lightgray, lightgray,\n",
|
| 443 |
+
" lightgray, lightgray, lightgray, lightgray],\n",
|
| 444 |
+
" 'colorbar': {'len': 0.8,\n",
|
| 445 |
+
" 'tickfont': {'size': 18},\n",
|
| 446 |
+
" 'title': {'font': {'size': 22}, 'text': 'Similarity'},\n",
|
| 447 |
+
" 'y': 0.5},\n",
|
| 448 |
+
" 'colorscale': [[0.0, '#440154'], [0.1111111111111111,\n",
|
| 449 |
+
" '#482878'], [0.2222222222222222,\n",
|
| 450 |
+
" '#3e4989'], [0.3333333333333333,\n",
|
| 451 |
+
" '#31688e'], [0.4444444444444444,\n",
|
| 452 |
+
" '#26828e'], [0.5555555555555556,\n",
|
| 453 |
+
" '#1f9e89'], [0.6666666666666666,\n",
|
| 454 |
+
" '#35b779'], [0.7777777777777778,\n",
|
| 455 |
+
" '#6ece58'], [0.8888888888888888,\n",
|
| 456 |
+
" '#b5de2b'], [1.0, '#fde725']],\n",
|
| 457 |
+
" 'opacity': 0.8,\n",
|
| 458 |
+
" 'size': 12},\n",
|
| 459 |
+
" 'mode': 'markers',\n",
|
| 460 |
+
" 'name': 'peaks',\n",
|
| 461 |
+
" 'type': 'scatter',\n",
|
| 462 |
+
" 'uid': '37ac6b58-1355-4c51-bd72-338119d34fb9',\n",
|
| 463 |
+
" 'x': array([ 53.038452, 55.054085, 79.021011, 174.03746 , 178.043579, 189.048355,\n",
|
| 464 |
+
" 204.059418, 205.079803, 206.075012, 218.075211, 232.09082 , 260.122498]),\n",
|
| 465 |
+
" 'xaxis': 'x',\n",
|
| 466 |
+
" 'y': array([0.05035, 1. , 0.25114, 0.07694, 0.11011, 0.20248, 0.1573 , 0.11588,\n",
|
| 467 |
+
" 0.60917, 0.16637, 0.49138, 1.1 ]),\n",
|
| 468 |
+
" 'yaxis': 'y'},\n",
|
| 469 |
+
" {'hoverinfo': 'none',\n",
|
| 470 |
+
" 'line': {'color': 'gray', 'width': 2},\n",
|
| 471 |
+
" 'mode': 'lines',\n",
|
| 472 |
+
" 'showlegend': False,\n",
|
| 473 |
+
" 'type': 'scatter',\n",
|
| 474 |
+
" 'uid': '6bcc6994-06b8-47dd-bc01-48f99335042b',\n",
|
| 475 |
+
" 'x': [-2.8864509970581214, -4.199129042378362, None,\n",
|
| 476 |
+
" -4.199129042378362, -4.22685271205967, None, -4.22685271205967,\n",
|
| 477 |
+
" -2.9418983364207385, None, -2.9418983364207385,\n",
|
| 478 |
+
" -1.6292202911004985, None, -1.6292202911004985,\n",
|
| 479 |
+
" -1.6014966214191901, None, -1.6292202911004985,\n",
|
| 480 |
+
" -0.5332442192164174, None, -0.5332442192164174,\n",
|
| 481 |
+
" 0.9611817175340794, None, 0.9611817175340794,\n",
|
| 482 |
+
" 1.8202800722452985, None, 1.8202800722452985,\n",
|
| 483 |
+
" 1.1849524902060187, None, 1.1849524902060187,\n",
|
| 484 |
+
" -0.30947344654447856, None, -0.30947344654447856,\n",
|
| 485 |
+
" -1.1685718012556967, None, -1.1685718012556967,\n",
|
| 486 |
+
" -2.65720191283034, None, 0.9611817175340794,\n",
|
| 487 |
+
" 1.5965092995733587, None, 1.5965092995733587,\n",
|
| 488 |
+
" 3.0909352363238556, None, 3.0909352363238556,\n",
|
| 489 |
+
" 4.056299914782093, None, 4.056299914782093, 5.204372664038527,\n",
|
| 490 |
+
" None, 5.204372664038527, 4.2390079855802885, None,\n",
|
| 491 |
+
" -1.6014966214191901, -2.8864509970581214, None,\n",
|
| 492 |
+
" -2.65720191283034, -2.9418983364207385, None,\n",
|
| 493 |
+
" -1.1685718012556967, -0.5332442192164174, None,\n",
|
| 494 |
+
" 4.2390079855802885, 3.0909352363238556, None],\n",
|
| 495 |
+
" 'xaxis': 'x2',\n",
|
| 496 |
+
" 'y': [-2.7111910913163433, -1.9853286047982452, None,\n",
|
| 497 |
+
" -1.9853286047982452, -0.4855848273017684, None,\n",
|
| 498 |
+
" -0.4855848273017684, 0.28829646367661116, None,\n",
|
| 499 |
+
" 0.28829646367661116, -0.4375660228414861, None,\n",
|
| 500 |
+
" -0.4375660228414861, -1.937309800337963, None,\n",
|
| 501 |
+
" -0.4375660228414861, 0.586561142044564, None,\n",
|
| 502 |
+
" 0.586561142044564, 0.45736702620564956, None,\n",
|
| 503 |
+
" 0.45736702620564956, 1.6869807935864805, None,\n",
|
| 504 |
+
" 1.6869807935864805, 3.0457886768062257, None,\n",
|
| 505 |
+
" 3.0457886768062257, 3.1749827926451397, None,\n",
|
| 506 |
+
" 3.1749827926451397, 1.945369025264309, None, 1.945369025264309,\n",
|
| 507 |
+
" 1.7610313163893583, None, 0.45736702620564956,\n",
|
| 508 |
+
" -0.901440857014096, None, -0.901440857014096,\n",
|
| 509 |
+
" -1.0306349728530104, None, -1.0306349728530104,\n",
|
| 510 |
+
" -2.178707722109445, None, -2.178707722109445,\n",
|
| 511 |
+
" -1.2133430436512074, None, -1.2133430436512074,\n",
|
| 512 |
+
" -0.06527029439477412, None, -1.937309800337963,\n",
|
| 513 |
+
" -2.7111910913163433, None, 1.7610313163893583,\n",
|
| 514 |
+
" 0.28829646367661116, None, 1.945369025264309,\n",
|
| 515 |
+
" 0.586561142044564, None, -0.06527029439477412,\n",
|
| 516 |
+
" -1.0306349728530104, None],\n",
|
| 517 |
+
" 'yaxis': 'y2'},\n",
|
| 518 |
+
" {'customdata': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,\n",
|
| 519 |
+
" 16, 17],\n",
|
| 520 |
+
" 'hoverlabel': {'font': {'family': 'Arial', 'size': 20}},\n",
|
| 521 |
+
" 'hovertext': [Atom 0 (C), Atom 1 (C), Atom 2 (C), Atom 3 (C), Atom 4\n",
|
| 522 |
+
" (C), Atom 5 (C), Atom 6 (C), Atom 7 (C), Atom 8 (N),\n",
|
| 523 |
+
" Atom 9 (C), Atom 10 (N), Atom 11 (C), Atom 12 (S), Atom\n",
|
| 524 |
+
" 13 (N), Atom 14 (C), Atom 15 (C), Atom 16 (C), Atom 17\n",
|
| 525 |
+
" (C)],\n",
|
| 526 |
+
" 'marker': {'cmax': 1,\n",
|
| 527 |
+
" 'cmin': 0,\n",
|
| 528 |
+
" 'color': [lightgray, lightgray, lightgray, lightgray,\n",
|
| 529 |
+
" lightgray, lightgray, lightgray, lightgray,\n",
|
| 530 |
+
" lightgray, lightgray, lightgray, lightgray,\n",
|
| 531 |
+
" lightgray, lightgray, lightgray, lightgray,\n",
|
| 532 |
+
" lightgray, lightgray],\n",
|
| 533 |
+
" 'colorbar': {'len': 0.8,\n",
|
| 534 |
+
" 'tickfont': {'size': 18},\n",
|
| 535 |
+
" 'title': {'font': {'size': 22}, 'text': 'Similarity'},\n",
|
| 536 |
+
" 'y': 0.5},\n",
|
| 537 |
+
" 'colorscale': [[0.0, '#440154'], [0.1111111111111111,\n",
|
| 538 |
+
" '#482878'], [0.2222222222222222,\n",
|
| 539 |
+
" '#3e4989'], [0.3333333333333333,\n",
|
| 540 |
+
" '#31688e'], [0.4444444444444444,\n",
|
| 541 |
+
" '#26828e'], [0.5555555555555556,\n",
|
| 542 |
+
" '#1f9e89'], [0.6666666666666666,\n",
|
| 543 |
+
" '#35b779'], [0.7777777777777778,\n",
|
| 544 |
+
" '#6ece58'], [0.8888888888888888,\n",
|
| 545 |
+
" '#b5de2b'], [1.0, '#fde725']],\n",
|
| 546 |
+
" 'size': 25},\n",
|
| 547 |
+
" 'mode': 'markers+text',\n",
|
| 548 |
+
" 'name': 'nodes',\n",
|
| 549 |
+
" 'text': [C, C, C, C, C, C, C, C, N, C, N, C, S, N, C, C, C, C],\n",
|
| 550 |
+
" 'textfont': {'size': 22},\n",
|
| 551 |
+
" 'textposition': 'middle center',\n",
|
| 552 |
+
" 'type': 'scatter',\n",
|
| 553 |
+
" 'uid': '0c88c92e-9a32-47e0-b9b4-38c43485725d',\n",
|
| 554 |
+
" 'x': [-2.8864509970581214, -4.199129042378362, -4.22685271205967,\n",
|
| 555 |
+
" -2.9418983364207385, -1.6292202911004985, -1.6014966214191901,\n",
|
| 556 |
+
" -0.5332442192164174, 0.9611817175340794, 1.8202800722452985,\n",
|
| 557 |
+
" 1.1849524902060187, -0.30947344654447856, -1.1685718012556967,\n",
|
| 558 |
+
" -2.65720191283034, 1.5965092995733587, 3.0909352363238556,\n",
|
| 559 |
+
" 4.056299914782093, 5.204372664038527, 4.2390079855802885],\n",
|
| 560 |
+
" 'xaxis': 'x2',\n",
|
| 561 |
+
" 'y': [-2.7111910913163433, -1.9853286047982452, -0.4855848273017684,\n",
|
| 562 |
+
" 0.28829646367661116, -0.4375660228414861, -1.937309800337963,\n",
|
| 563 |
+
" 0.586561142044564, 0.45736702620564956, 1.6869807935864805,\n",
|
| 564 |
+
" 3.0457886768062257, 3.1749827926451397, 1.945369025264309,\n",
|
| 565 |
+
" 1.7610313163893583, -0.901440857014096, -1.0306349728530104,\n",
|
| 566 |
+
" -2.178707722109445, -1.2133430436512074, -0.06527029439477412],\n",
|
| 567 |
+
" 'yaxis': 'y2'}],\n",
|
| 568 |
+
" 'layout': {'annotations': [{'font': {'size': 24},\n",
|
| 569 |
+
" 'showarrow': False,\n",
|
| 570 |
+
" 'text': 'Spectrum',\n",
|
| 571 |
+
" 'x': 0.27,\n",
|
| 572 |
+
" 'xanchor': 'center',\n",
|
| 573 |
+
" 'xref': 'paper',\n",
|
| 574 |
+
" 'y': 1.0,\n",
|
| 575 |
+
" 'yanchor': 'bottom',\n",
|
| 576 |
+
" 'yref': 'paper'},\n",
|
| 577 |
+
" {'font': {'size': 24},\n",
|
| 578 |
+
" 'showarrow': False,\n",
|
| 579 |
+
" 'text': 'Molecule',\n",
|
| 580 |
+
" 'x': 0.8200000000000001,\n",
|
| 581 |
+
" 'xanchor': 'center',\n",
|
| 582 |
+
" 'xref': 'paper',\n",
|
| 583 |
+
" 'y': 1.0,\n",
|
| 584 |
+
" 'yanchor': 'bottom',\n",
|
| 585 |
+
" 'yref': 'paper'}],\n",
|
| 586 |
+
" 'font': {'size': 22},\n",
|
| 587 |
+
" 'hoverlabel': {'font': {'family': 'Arial', 'size': 20}},\n",
|
| 588 |
+
" 'margin': {'b': 80, 'l': 80, 'r': 80, 't': 100},\n",
|
| 589 |
+
" 'showlegend': False,\n",
|
| 590 |
+
" 'template': '...',\n",
|
| 591 |
+
" 'title': {'font': {'size': 30}, 'text': 'Peak ↔ Node Similarity'},\n",
|
| 592 |
+
" 'xaxis': {'anchor': 'y',\n",
|
| 593 |
+
" 'domain': [0.0, 0.54],\n",
|
| 594 |
+
" 'tickfont': {'size': 20},\n",
|
| 595 |
+
" 'title': {'font': {'size': 24}, 'text': 'm/z'}},\n",
|
| 596 |
+
" 'xaxis2': {'anchor': 'y2', 'domain': [0.64, 1.0], 'visible': False},\n",
|
| 597 |
+
" 'yaxis': {'anchor': 'x',\n",
|
| 598 |
+
" 'domain': [0.0, 1.0],\n",
|
| 599 |
+
" 'tickfont': {'size': 20},\n",
|
| 600 |
+
" 'title': {'font': {'size': 24}, 'text': 'Intensity'}},\n",
|
| 601 |
+
" 'yaxis2': {'anchor': 'x2', 'domain': [0.0, 1.0], 'visible': False}}\n",
|
| 602 |
+
"})"
|
| 603 |
+
]
|
| 604 |
+
},
|
| 605 |
+
"execution_count": 9,
|
| 606 |
+
"metadata": {},
|
| 607 |
+
"output_type": "execute_result"
|
| 608 |
+
}
|
| 609 |
+
],
|
| 610 |
+
"source": [
|
| 611 |
+
"cond1 = results['rank'] >=20\n",
|
| 612 |
+
"cond2 = results['n_heavy_atoms'] <=25\n",
|
| 613 |
+
"\n",
|
| 614 |
+
"# spec_id = results[cond1 & cond2].sample(1).iloc[0]['identifier']\n",
|
| 615 |
+
"spec_id = \"MassSpecGymID0235850\"\n",
|
| 616 |
+
"print(spec_id, results[results['identifier']==spec_id]['rank'].item())\n",
|
| 617 |
+
"d = data[data['identifier'] == spec_id].iloc[0]\n",
|
| 618 |
+
"mzs = [float(m) for m in d['mzs'].strip().split(',')]\n",
|
| 619 |
+
"intensities = [float(i) for i in d['intensities'].strip().split(',')]\n",
|
| 620 |
+
"\n",
|
| 621 |
+
"ms = []\n",
|
| 622 |
+
"for m, i in zip(mzs, intensities):\n",
|
| 623 |
+
" ms.append([m, i])\n",
|
| 624 |
+
"\n",
|
| 625 |
+
"run(ms, d['smiles'], d['formula'], d['precursor_mz'], d['adduct'])"
|
| 626 |
+
]
|
| 627 |
+
},
|
| 628 |
+
{
|
| 629 |
+
"cell_type": "code",
|
| 630 |
+
"execution_count": 33,
|
| 631 |
+
"id": "fb27164b",
|
| 632 |
+
"metadata": {},
|
| 633 |
+
"outputs": [
|
| 634 |
+
{
|
| 635 |
+
"data": {
|
| 636 |
+
"image/png": "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",
|
| 637 |
+
"text/plain": [
|
| 638 |
+
"<rdkit.Chem.rdchem.Mol at 0x7f51717358c0>"
|
| 639 |
+
]
|
| 640 |
+
},
|
| 641 |
+
"execution_count": 33,
|
| 642 |
+
"metadata": {},
|
| 643 |
+
"output_type": "execute_result"
|
| 644 |
+
}
|
| 645 |
+
],
|
| 646 |
+
"source": [
|
| 647 |
+
"Chem.MolFromSmiles(d['smiles'])"
|
| 648 |
+
]
|
| 649 |
+
},
|
| 650 |
+
{
|
| 651 |
+
"cell_type": "code",
|
| 652 |
+
"execution_count": 9,
|
| 653 |
+
"id": "b5082c7b",
|
| 654 |
+
"metadata": {},
|
| 655 |
+
"outputs": [],
|
| 656 |
+
"source": [
|
| 657 |
+
"import plotly.io as pio\n",
|
| 658 |
+
"pio.renderers.default = 'notebook_connected'"
|
| 659 |
+
]
|
| 660 |
+
},
|
| 661 |
+
{
|
| 662 |
+
"cell_type": "code",
|
| 663 |
+
"execution_count": null,
|
| 664 |
+
"id": "616fe59c",
|
| 665 |
+
"metadata": {},
|
| 666 |
+
"outputs": [],
|
| 667 |
+
"source": []
|
| 668 |
+
}
|
| 669 |
+
],
|
| 670 |
+
"metadata": {
|
| 671 |
+
"kernelspec": {
|
| 672 |
+
"display_name": "spec",
|
| 673 |
+
"language": "python",
|
| 674 |
+
"name": "python3"
|
| 675 |
+
},
|
| 676 |
+
"language_info": {
|
| 677 |
+
"codemirror_mode": {
|
| 678 |
+
"name": "ipython",
|
| 679 |
+
"version": 3
|
| 680 |
+
},
|
| 681 |
+
"file_extension": ".py",
|
| 682 |
+
"mimetype": "text/x-python",
|
| 683 |
+
"name": "python",
|
| 684 |
+
"nbconvert_exporter": "python",
|
| 685 |
+
"pygments_lexer": "ipython3",
|
| 686 |
+
"version": "3.11.7"
|
| 687 |
+
}
|
| 688 |
+
},
|
| 689 |
+
"nbformat": 4,
|
| 690 |
+
"nbformat_minor": 5
|
| 691 |
+
}
|
notebooks/hyperparameter_tuning_result.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/msgym_result.ipynb
ADDED
|
@@ -0,0 +1,799 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"metadata": {},
|
| 6 |
+
"source": [
|
| 7 |
+
"Result for all models on the MSGym benchmark"
|
| 8 |
+
]
|
| 9 |
+
},
|
| 10 |
+
{
|
| 11 |
+
"cell_type": "markdown",
|
| 12 |
+
"metadata": {},
|
| 13 |
+
"source": [
|
| 14 |
+
"1. Load data\n",
|
| 15 |
+
"2. Compute MCES\n",
|
| 16 |
+
"3. Compute confidence interval"
|
| 17 |
+
]
|
| 18 |
+
},
|
| 19 |
+
{
|
| 20 |
+
"cell_type": "code",
|
| 21 |
+
"execution_count": 1,
|
| 22 |
+
"metadata": {},
|
| 23 |
+
"outputs": [],
|
| 24 |
+
"source": [
|
| 25 |
+
"import pickle\n",
|
| 26 |
+
"import pandas as pd\n",
|
| 27 |
+
"import numpy as np"
|
| 28 |
+
]
|
| 29 |
+
},
|
| 30 |
+
{
|
| 31 |
+
"cell_type": "code",
|
| 32 |
+
"execution_count": 2,
|
| 33 |
+
"metadata": {},
|
| 34 |
+
"outputs": [],
|
| 35 |
+
"source": [
|
| 36 |
+
"import sys\n",
|
| 37 |
+
"sys.path.append('..')\n",
|
| 38 |
+
"import flare.utils.eval as eval_utils"
|
| 39 |
+
]
|
| 40 |
+
},
|
| 41 |
+
{
|
| 42 |
+
"cell_type": "code",
|
| 43 |
+
"execution_count": 5,
|
| 44 |
+
"metadata": {},
|
| 45 |
+
"outputs": [],
|
| 46 |
+
"source": [
|
| 47 |
+
"from tqdm import tqdm"
|
| 48 |
+
]
|
| 49 |
+
},
|
| 50 |
+
{
|
| 51 |
+
"cell_type": "markdown",
|
| 52 |
+
"metadata": {},
|
| 53 |
+
"source": [
|
| 54 |
+
"## Candidates by Mass"
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"cell_type": "markdown",
|
| 59 |
+
"metadata": {},
|
| 60 |
+
"source": [
|
| 61 |
+
"### load data"
|
| 62 |
+
]
|
| 63 |
+
},
|
| 64 |
+
{
|
| 65 |
+
"cell_type": "code",
|
| 66 |
+
"execution_count": 27,
|
| 67 |
+
"metadata": {},
|
| 68 |
+
"outputs": [],
|
| 69 |
+
"source": [
|
| 70 |
+
"flare_pth = \"../experiments/20250930_optimized_flare_42/result_MassSpecGym_retrieval_candidates_mass.pkl\"\n",
|
| 71 |
+
"flare_w_sirius_pth = \"../experiments/20251001_flare_sirius_labels_42/result_MassSpecGym_retrieval_candidates_mass.pkl\"\n",
|
| 72 |
+
"mzint_token_pth = \"../experiments/20250929_flare_mzIntTokens/result_MassSpecGym_retrieval_candidates_mass.pkl\"\n",
|
| 73 |
+
"crossatt_pth = \"../experiments/20250914_crossAttnModel/result_MassSpecGym_retrieval_candidates_mass.pkl\"\n",
|
| 74 |
+
"\n",
|
| 75 |
+
"def load_data(pth):\n",
|
| 76 |
+
" with open(pth, \"rb\") as f:\n",
|
| 77 |
+
" data = pickle.load(f)\n",
|
| 78 |
+
" return data\n",
|
| 79 |
+
"\n",
|
| 80 |
+
"flare = load_data(flare_pth)\n",
|
| 81 |
+
"sirius_labels = load_data(flare_w_sirius_pth)\n",
|
| 82 |
+
"mzint_token = load_data(mzint_token_pth)\n",
|
| 83 |
+
"crossatt = load_data(crossatt_pth)"
|
| 84 |
+
]
|
| 85 |
+
},
|
| 86 |
+
{
|
| 87 |
+
"cell_type": "code",
|
| 88 |
+
"execution_count": 5,
|
| 89 |
+
"metadata": {},
|
| 90 |
+
"outputs": [],
|
| 91 |
+
"source": [
|
| 92 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 93 |
+
" \n",
|
| 94 |
+
" # get target\n",
|
| 95 |
+
" result['target'] = result.apply(lambda row: eval_utils.get_target(row['candidates'], row['labels']), axis=1)\n",
|
| 96 |
+
"\n",
|
| 97 |
+
" # get cand@1\n",
|
| 98 |
+
" result['cand@1'] = result.apply(lambda row: eval_utils.get_top_cand(row['candidates'], row['scores']), axis=1)\n",
|
| 99 |
+
"\n",
|
| 100 |
+
" # convert rank to hit rates\n",
|
| 101 |
+
" result[['hit_rate@1', 'hit_rate@5', 'hit_rate@20']] = result.apply(lambda row: eval_utils.convert_rank_to_hit_rates(row, 'rank'), axis=1, result_type='expand')\n",
|
| 102 |
+
" \n"
|
| 103 |
+
]
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"cell_type": "markdown",
|
| 107 |
+
"metadata": {},
|
| 108 |
+
"source": [
|
| 109 |
+
"### compute mces"
|
| 110 |
+
]
|
| 111 |
+
},
|
| 112 |
+
{
|
| 113 |
+
"cell_type": "code",
|
| 114 |
+
"execution_count": 6,
|
| 115 |
+
"metadata": {},
|
| 116 |
+
"outputs": [
|
| 117 |
+
{
|
| 118 |
+
"name": "stdout",
|
| 119 |
+
"output_type": "stream",
|
| 120 |
+
"text": [
|
| 121 |
+
"Number of unique target_cand combo: 29247\n"
|
| 122 |
+
]
|
| 123 |
+
}
|
| 124 |
+
],
|
| 125 |
+
"source": [
|
| 126 |
+
"target_cand_dict = {}\n",
|
| 127 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 128 |
+
" target_cand_list = list(zip(result['target'].tolist(), result['cand@1'].tolist()))\n",
|
| 129 |
+
" for target, cand in target_cand_list:\n",
|
| 130 |
+
" pair = f'{target}::{cand}'\n",
|
| 131 |
+
" if pair in target_cand_dict:\n",
|
| 132 |
+
" continue\n",
|
| 133 |
+
"\n",
|
| 134 |
+
" target_cand_dict[pair] = [target, cand]\n",
|
| 135 |
+
" \n",
|
| 136 |
+
"target_cand_list = list(target_cand_dict.values())\n",
|
| 137 |
+
"print(\"Number of unique target_cand combo: \", len(target_cand_list))"
|
| 138 |
+
]
|
| 139 |
+
},
|
| 140 |
+
{
|
| 141 |
+
"cell_type": "code",
|
| 142 |
+
"execution_count": 7,
|
| 143 |
+
"metadata": {},
|
| 144 |
+
"outputs": [
|
| 145 |
+
{
|
| 146 |
+
"name": "stderr",
|
| 147 |
+
"output_type": "stream",
|
| 148 |
+
"text": [
|
| 149 |
+
"100%|██████████| 29247/29247 [09:35<00:00, 50.84it/s] \n"
|
| 150 |
+
]
|
| 151 |
+
}
|
| 152 |
+
],
|
| 153 |
+
"source": [
|
| 154 |
+
"mces_result = eval_utils.Compute_Myopic_MCES.compute_mces_parallel(target_cand_list)"
|
| 155 |
+
]
|
| 156 |
+
},
|
| 157 |
+
{
|
| 158 |
+
"cell_type": "code",
|
| 159 |
+
"execution_count": 8,
|
| 160 |
+
"metadata": {},
|
| 161 |
+
"outputs": [],
|
| 162 |
+
"source": [
|
| 163 |
+
"# Assign MCES to ranking\n",
|
| 164 |
+
"tar_cand_mces_dict = {}\n",
|
| 165 |
+
"for tar_cand, mces in mces_result:\n",
|
| 166 |
+
" tar, can = tar_cand\n",
|
| 167 |
+
" if f'{tar}::{can}' not in tar_cand_mces_dict:\n",
|
| 168 |
+
" tar_cand_mces_dict[f'{tar}::{can}'] = mces\n",
|
| 169 |
+
" \n",
|
| 170 |
+
"def assign_mces(tar, can):\n",
|
| 171 |
+
" return tar_cand_mces_dict[f'{tar}::{can}']"
|
| 172 |
+
]
|
| 173 |
+
},
|
| 174 |
+
{
|
| 175 |
+
"cell_type": "code",
|
| 176 |
+
"execution_count": 9,
|
| 177 |
+
"metadata": {},
|
| 178 |
+
"outputs": [],
|
| 179 |
+
"source": [
|
| 180 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 181 |
+
" result['mces'] = result.apply(lambda row: assign_mces(row['target'], row['cand@1']), axis=1)"
|
| 182 |
+
]
|
| 183 |
+
},
|
| 184 |
+
{
|
| 185 |
+
"cell_type": "code",
|
| 186 |
+
"execution_count": 11,
|
| 187 |
+
"metadata": {},
|
| 188 |
+
"outputs": [],
|
| 189 |
+
"source": [
|
| 190 |
+
"# save result\n",
|
| 191 |
+
"for result, pth in zip([flare, sirius_labels, mzint_token, crossatt], [flare_pth, flare_w_sirius_pth, mzint_token_pth, crossatt_pth]):\n",
|
| 192 |
+
" result.to_pickle(pth)"
|
| 193 |
+
]
|
| 194 |
+
},
|
| 195 |
+
{
|
| 196 |
+
"cell_type": "markdown",
|
| 197 |
+
"metadata": {},
|
| 198 |
+
"source": [
|
| 199 |
+
"### compute confidence interval"
|
| 200 |
+
]
|
| 201 |
+
},
|
| 202 |
+
{
|
| 203 |
+
"cell_type": "code",
|
| 204 |
+
"execution_count": null,
|
| 205 |
+
"metadata": {},
|
| 206 |
+
"outputs": [],
|
| 207 |
+
"source": [
|
| 208 |
+
"tqdm.pandas()"
|
| 209 |
+
]
|
| 210 |
+
},
|
| 211 |
+
{
|
| 212 |
+
"cell_type": "code",
|
| 213 |
+
"execution_count": 28,
|
| 214 |
+
"metadata": {},
|
| 215 |
+
"outputs": [
|
| 216 |
+
{
|
| 217 |
+
"name": "stderr",
|
| 218 |
+
"output_type": "stream",
|
| 219 |
+
"text": [
|
| 220 |
+
"100%|██████████| 4/4 [00:35<00:00, 8.79s/it]\n"
|
| 221 |
+
]
|
| 222 |
+
},
|
| 223 |
+
{
|
| 224 |
+
"data": {
|
| 225 |
+
"text/plain": [
|
| 226 |
+
"hit_rate@1 41.92-44.38\n",
|
| 227 |
+
"hit_rate@5 74.54-76.66\n",
|
| 228 |
+
"hit_rate@20 92.21-93.50\n",
|
| 229 |
+
"mces 7.63-8.10\n",
|
| 230 |
+
"dtype: object"
|
| 231 |
+
]
|
| 232 |
+
},
|
| 233 |
+
"metadata": {},
|
| 234 |
+
"output_type": "display_data"
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
"name": "stdout",
|
| 238 |
+
"output_type": "stream",
|
| 239 |
+
"text": [
|
| 240 |
+
"===========================================================\n"
|
| 241 |
+
]
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"name": "stderr",
|
| 245 |
+
"output_type": "stream",
|
| 246 |
+
"text": [
|
| 247 |
+
"100%|██████████| 4/4 [00:35<00:00, 8.79s/it]\n"
|
| 248 |
+
]
|
| 249 |
+
},
|
| 250 |
+
{
|
| 251 |
+
"data": {
|
| 252 |
+
"text/plain": [
|
| 253 |
+
"hit_rate@1 42.14-44.57\n",
|
| 254 |
+
"hit_rate@5 72.11-74.31\n",
|
| 255 |
+
"hit_rate@20 91.51-92.87\n",
|
| 256 |
+
"mces 7.87-8.36\n",
|
| 257 |
+
"dtype: object"
|
| 258 |
+
]
|
| 259 |
+
},
|
| 260 |
+
"metadata": {},
|
| 261 |
+
"output_type": "display_data"
|
| 262 |
+
},
|
| 263 |
+
{
|
| 264 |
+
"name": "stdout",
|
| 265 |
+
"output_type": "stream",
|
| 266 |
+
"text": [
|
| 267 |
+
"===========================================================\n"
|
| 268 |
+
]
|
| 269 |
+
},
|
| 270 |
+
{
|
| 271 |
+
"name": "stderr",
|
| 272 |
+
"output_type": "stream",
|
| 273 |
+
"text": [
|
| 274 |
+
"100%|██████████| 4/4 [00:35<00:00, 8.78s/it]\n"
|
| 275 |
+
]
|
| 276 |
+
},
|
| 277 |
+
{
|
| 278 |
+
"data": {
|
| 279 |
+
"text/plain": [
|
| 280 |
+
"hit_rate@1 6.55-7.82\n",
|
| 281 |
+
"hit_rate@5 21.14-23.13\n",
|
| 282 |
+
"hit_rate@20 42.98-45.48\n",
|
| 283 |
+
"mces 25.71-26.51\n",
|
| 284 |
+
"dtype: object"
|
| 285 |
+
]
|
| 286 |
+
},
|
| 287 |
+
"metadata": {},
|
| 288 |
+
"output_type": "display_data"
|
| 289 |
+
},
|
| 290 |
+
{
|
| 291 |
+
"name": "stdout",
|
| 292 |
+
"output_type": "stream",
|
| 293 |
+
"text": [
|
| 294 |
+
"===========================================================\n"
|
| 295 |
+
]
|
| 296 |
+
},
|
| 297 |
+
{
|
| 298 |
+
"name": "stderr",
|
| 299 |
+
"output_type": "stream",
|
| 300 |
+
"text": [
|
| 301 |
+
"100%|██████████| 4/4 [00:35<00:00, 8.80s/it]\n"
|
| 302 |
+
]
|
| 303 |
+
},
|
| 304 |
+
{
|
| 305 |
+
"data": {
|
| 306 |
+
"text/plain": [
|
| 307 |
+
"hit_rate@1 0.47-0.86\n",
|
| 308 |
+
"hit_rate@5 2.55-3.39\n",
|
| 309 |
+
"hit_rate@20 11.84-13.50\n",
|
| 310 |
+
"mces 26.61-27.22\n",
|
| 311 |
+
"dtype: object"
|
| 312 |
+
]
|
| 313 |
+
},
|
| 314 |
+
"metadata": {},
|
| 315 |
+
"output_type": "display_data"
|
| 316 |
+
},
|
| 317 |
+
{
|
| 318 |
+
"name": "stdout",
|
| 319 |
+
"output_type": "stream",
|
| 320 |
+
"text": [
|
| 321 |
+
"===========================================================\n"
|
| 322 |
+
]
|
| 323 |
+
}
|
| 324 |
+
],
|
| 325 |
+
"source": [
|
| 326 |
+
"hit_rate_metrics = ['hit_rate@1', 'hit_rate@5', 'hit_rate@20', 'mces']\n",
|
| 327 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 328 |
+
" result[hit_rate_metrics[:-1]]*=100\n",
|
| 329 |
+
" df_ci = result[hit_rate_metrics].progress_apply(eval_utils.get_ci)\n",
|
| 330 |
+
" display(df_ci)\n",
|
| 331 |
+
" print(\"===========================================================\")"
|
| 332 |
+
]
|
| 333 |
+
},
|
| 334 |
+
{
|
| 335 |
+
"cell_type": "code",
|
| 336 |
+
"execution_count": 30,
|
| 337 |
+
"metadata": {},
|
| 338 |
+
"outputs": [
|
| 339 |
+
{
|
| 340 |
+
"data": {
|
| 341 |
+
"text/html": [
|
| 342 |
+
"<div>\n",
|
| 343 |
+
"<style scoped>\n",
|
| 344 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 345 |
+
" vertical-align: middle;\n",
|
| 346 |
+
" }\n",
|
| 347 |
+
"\n",
|
| 348 |
+
" .dataframe tbody tr th {\n",
|
| 349 |
+
" vertical-align: top;\n",
|
| 350 |
+
" }\n",
|
| 351 |
+
"\n",
|
| 352 |
+
" .dataframe thead th {\n",
|
| 353 |
+
" text-align: right;\n",
|
| 354 |
+
" }\n",
|
| 355 |
+
"</style>\n",
|
| 356 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 357 |
+
" <thead>\n",
|
| 358 |
+
" <tr style=\"text-align: right;\">\n",
|
| 359 |
+
" <th></th>\n",
|
| 360 |
+
" <th>hit_rate@1</th>\n",
|
| 361 |
+
" <th>hit_rate@5</th>\n",
|
| 362 |
+
" <th>hit_rate@20</th>\n",
|
| 363 |
+
" <th>mces</th>\n",
|
| 364 |
+
" </tr>\n",
|
| 365 |
+
" </thead>\n",
|
| 366 |
+
" <tbody>\n",
|
| 367 |
+
" <tr>\n",
|
| 368 |
+
" <th>flare</th>\n",
|
| 369 |
+
" <td>43.15</td>\n",
|
| 370 |
+
" <td>75.59</td>\n",
|
| 371 |
+
" <td>92.89</td>\n",
|
| 372 |
+
" <td>7.85</td>\n",
|
| 373 |
+
" </tr>\n",
|
| 374 |
+
" <tr>\n",
|
| 375 |
+
" <th>flare_w_sirius_labels</th>\n",
|
| 376 |
+
" <td>43.33</td>\n",
|
| 377 |
+
" <td>73.22</td>\n",
|
| 378 |
+
" <td>92.25</td>\n",
|
| 379 |
+
" <td>8.11</td>\n",
|
| 380 |
+
" </tr>\n",
|
| 381 |
+
" <tr>\n",
|
| 382 |
+
" <th>mzint_tokens</th>\n",
|
| 383 |
+
" <td>7.17</td>\n",
|
| 384 |
+
" <td>22.12</td>\n",
|
| 385 |
+
" <td>44.24</td>\n",
|
| 386 |
+
" <td>26.10</td>\n",
|
| 387 |
+
" </tr>\n",
|
| 388 |
+
" <tr>\n",
|
| 389 |
+
" <th>crossatten</th>\n",
|
| 390 |
+
" <td>0.64</td>\n",
|
| 391 |
+
" <td>2.94</td>\n",
|
| 392 |
+
" <td>12.64</td>\n",
|
| 393 |
+
" <td>26.91</td>\n",
|
| 394 |
+
" </tr>\n",
|
| 395 |
+
" </tbody>\n",
|
| 396 |
+
"</table>\n",
|
| 397 |
+
"</div>"
|
| 398 |
+
],
|
| 399 |
+
"text/plain": [
|
| 400 |
+
" hit_rate@1 hit_rate@5 hit_rate@20 mces\n",
|
| 401 |
+
"flare 43.15 75.59 92.89 7.85\n",
|
| 402 |
+
"flare_w_sirius_labels 43.33 73.22 92.25 8.11\n",
|
| 403 |
+
"mzint_tokens 7.17 22.12 44.24 26.10\n",
|
| 404 |
+
"crossatten 0.64 2.94 12.64 26.91"
|
| 405 |
+
]
|
| 406 |
+
},
|
| 407 |
+
"execution_count": 30,
|
| 408 |
+
"metadata": {},
|
| 409 |
+
"output_type": "execute_result"
|
| 410 |
+
}
|
| 411 |
+
],
|
| 412 |
+
"source": [
|
| 413 |
+
"result_data = {}\n",
|
| 414 |
+
"for result, method in zip([flare, sirius_labels, mzint_token, crossatt], ['flare', 'flare_w_sirius_labels', 'mzint_tokens', 'crossatten']):\n",
|
| 415 |
+
" result_data[method] = []\n",
|
| 416 |
+
" for m in hit_rate_metrics:\n",
|
| 417 |
+
" val = np.mean(result[m])\n",
|
| 418 |
+
" result_data[method].append(round(val,2))\n",
|
| 419 |
+
"\n",
|
| 420 |
+
"\n",
|
| 421 |
+
"result_df = pd.DataFrame.from_dict(result_data, orient='index', columns=hit_rate_metrics)\n",
|
| 422 |
+
"result_df"
|
| 423 |
+
]
|
| 424 |
+
},
|
| 425 |
+
{
|
| 426 |
+
"cell_type": "markdown",
|
| 427 |
+
"metadata": {},
|
| 428 |
+
"source": [
|
| 429 |
+
"## Candidates by Formula"
|
| 430 |
+
]
|
| 431 |
+
},
|
| 432 |
+
{
|
| 433 |
+
"cell_type": "code",
|
| 434 |
+
"execution_count": 42,
|
| 435 |
+
"metadata": {},
|
| 436 |
+
"outputs": [],
|
| 437 |
+
"source": [
|
| 438 |
+
"flare_pth = \"../experiments/20250930_optimized_flare_42/result_MassSpecGym_retrieval_candidates_formula.pkl\"\n",
|
| 439 |
+
"flare_w_sirius_pth = \"../experiments/20251001_flare_sirius_labels_42/result_MassSpecGym_retrieval_candidates_formula.pkl\"\n",
|
| 440 |
+
"mzint_token_pth = \"../experiments/20250929_flare_mzIntTokens/result_MassSpecGym_retrieval_candidates_formula.pkl\"\n",
|
| 441 |
+
"crossatt_pth = \"../experiments/20250914_crossAttnModel/result_MassSpecGym_retrieval_candidates_formula.pkl\"\n",
|
| 442 |
+
"\n",
|
| 443 |
+
"def load_data(pth):\n",
|
| 444 |
+
" with open(pth, \"rb\") as f:\n",
|
| 445 |
+
" data = pickle.load(f)\n",
|
| 446 |
+
" return data\n",
|
| 447 |
+
"\n",
|
| 448 |
+
"flare = load_data(flare_pth)\n",
|
| 449 |
+
"sirius_labels = load_data(flare_w_sirius_pth)\n",
|
| 450 |
+
"mzint_token = load_data(mzint_token_pth)\n",
|
| 451 |
+
"crossatt = load_data(crossatt_pth)"
|
| 452 |
+
]
|
| 453 |
+
},
|
| 454 |
+
{
|
| 455 |
+
"cell_type": "code",
|
| 456 |
+
"execution_count": 32,
|
| 457 |
+
"metadata": {},
|
| 458 |
+
"outputs": [],
|
| 459 |
+
"source": [
|
| 460 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 461 |
+
" \n",
|
| 462 |
+
" # get target\n",
|
| 463 |
+
" result['target'] = result.apply(lambda row: eval_utils.get_target(row['candidates'], row['labels']), axis=1)\n",
|
| 464 |
+
"\n",
|
| 465 |
+
" # get cand@1\n",
|
| 466 |
+
" result['cand@1'] = result.apply(lambda row: eval_utils.get_top_cand(row['candidates'], row['scores']), axis=1)\n",
|
| 467 |
+
"\n",
|
| 468 |
+
" # convert rank to hit rates\n",
|
| 469 |
+
" result[['hit_rate@1', 'hit_rate@5', 'hit_rate@20']] = result.apply(lambda row: eval_utils.convert_rank_to_hit_rates(row, 'rank'), axis=1, result_type='expand')\n",
|
| 470 |
+
" \n"
|
| 471 |
+
]
|
| 472 |
+
},
|
| 473 |
+
{
|
| 474 |
+
"cell_type": "markdown",
|
| 475 |
+
"metadata": {},
|
| 476 |
+
"source": [
|
| 477 |
+
"### compute mces"
|
| 478 |
+
]
|
| 479 |
+
},
|
| 480 |
+
{
|
| 481 |
+
"cell_type": "code",
|
| 482 |
+
"execution_count": 33,
|
| 483 |
+
"metadata": {},
|
| 484 |
+
"outputs": [
|
| 485 |
+
{
|
| 486 |
+
"name": "stdout",
|
| 487 |
+
"output_type": "stream",
|
| 488 |
+
"text": [
|
| 489 |
+
"Number of unique target_cand combo: 28985\n"
|
| 490 |
+
]
|
| 491 |
+
}
|
| 492 |
+
],
|
| 493 |
+
"source": [
|
| 494 |
+
"target_cand_dict = {}\n",
|
| 495 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 496 |
+
" target_cand_list = list(zip(result['target'].tolist(), result['cand@1'].tolist()))\n",
|
| 497 |
+
" for target, cand in target_cand_list:\n",
|
| 498 |
+
" pair = f'{target}::{cand}'\n",
|
| 499 |
+
" if pair in target_cand_dict:\n",
|
| 500 |
+
" continue\n",
|
| 501 |
+
"\n",
|
| 502 |
+
" target_cand_dict[pair] = [target, cand]\n",
|
| 503 |
+
" \n",
|
| 504 |
+
"target_cand_list = list(target_cand_dict.values())\n",
|
| 505 |
+
"print(\"Number of unique target_cand combo: \", len(target_cand_list))"
|
| 506 |
+
]
|
| 507 |
+
},
|
| 508 |
+
{
|
| 509 |
+
"cell_type": "code",
|
| 510 |
+
"execution_count": null,
|
| 511 |
+
"metadata": {},
|
| 512 |
+
"outputs": [
|
| 513 |
+
{
|
| 514 |
+
"name": "stderr",
|
| 515 |
+
"output_type": "stream",
|
| 516 |
+
"text": [
|
| 517 |
+
"100%|██████████| 28985/28985 [16:12<00:00, 29.82it/s] \n"
|
| 518 |
+
]
|
| 519 |
+
}
|
| 520 |
+
],
|
| 521 |
+
"source": [
|
| 522 |
+
"# 16 minutes\n",
|
| 523 |
+
"mces_result = eval_utils.Compute_Myopic_MCES.compute_mces_parallel(target_cand_list)"
|
| 524 |
+
]
|
| 525 |
+
},
|
| 526 |
+
{
|
| 527 |
+
"cell_type": "code",
|
| 528 |
+
"execution_count": 38,
|
| 529 |
+
"metadata": {},
|
| 530 |
+
"outputs": [],
|
| 531 |
+
"source": [
|
| 532 |
+
"# Assign MCES to ranking\n",
|
| 533 |
+
"tar_cand_mces_dict = {}\n",
|
| 534 |
+
"for tar_cand, mces in mces_result:\n",
|
| 535 |
+
" tar, can = tar_cand\n",
|
| 536 |
+
" if f'{tar}::{can}' not in tar_cand_mces_dict:\n",
|
| 537 |
+
" tar_cand_mces_dict[f'{tar}::{can}'] = mces\n",
|
| 538 |
+
" \n",
|
| 539 |
+
"def assign_mces(tar, can):\n",
|
| 540 |
+
" return tar_cand_mces_dict[f'{tar}::{can}']\n",
|
| 541 |
+
"\n",
|
| 542 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 543 |
+
" result['mces'] = result.apply(lambda row: assign_mces(row['target'], row['cand@1']), axis=1)"
|
| 544 |
+
]
|
| 545 |
+
},
|
| 546 |
+
{
|
| 547 |
+
"cell_type": "code",
|
| 548 |
+
"execution_count": 39,
|
| 549 |
+
"metadata": {},
|
| 550 |
+
"outputs": [],
|
| 551 |
+
"source": [
|
| 552 |
+
"# save result\n",
|
| 553 |
+
"for result, pth in zip([flare, sirius_labels, mzint_token, crossatt], [flare_pth, flare_w_sirius_pth, mzint_token_pth, crossatt_pth]):\n",
|
| 554 |
+
" result.to_pickle(pth)"
|
| 555 |
+
]
|
| 556 |
+
},
|
| 557 |
+
{
|
| 558 |
+
"cell_type": "markdown",
|
| 559 |
+
"metadata": {},
|
| 560 |
+
"source": [
|
| 561 |
+
"### compute confidence interval"
|
| 562 |
+
]
|
| 563 |
+
},
|
| 564 |
+
{
|
| 565 |
+
"cell_type": "code",
|
| 566 |
+
"execution_count": 48,
|
| 567 |
+
"metadata": {},
|
| 568 |
+
"outputs": [
|
| 569 |
+
{
|
| 570 |
+
"name": "stderr",
|
| 571 |
+
"output_type": "stream",
|
| 572 |
+
"text": [
|
| 573 |
+
"100%|██████████| 4/4 [00:34<00:00, 8.54s/it]\n"
|
| 574 |
+
]
|
| 575 |
+
},
|
| 576 |
+
{
|
| 577 |
+
"data": {
|
| 578 |
+
"text/plain": [
|
| 579 |
+
"hit_rate@1 21.65-23.72\n",
|
| 580 |
+
"hit_rate@5 48.75-51.20\n",
|
| 581 |
+
"hit_rate@20 74.06-76.20\n",
|
| 582 |
+
"mces 8.82-9.18\n",
|
| 583 |
+
"dtype: object"
|
| 584 |
+
]
|
| 585 |
+
},
|
| 586 |
+
"metadata": {},
|
| 587 |
+
"output_type": "display_data"
|
| 588 |
+
},
|
| 589 |
+
{
|
| 590 |
+
"name": "stdout",
|
| 591 |
+
"output_type": "stream",
|
| 592 |
+
"text": [
|
| 593 |
+
"===========================================================\n"
|
| 594 |
+
]
|
| 595 |
+
},
|
| 596 |
+
{
|
| 597 |
+
"name": "stderr",
|
| 598 |
+
"output_type": "stream",
|
| 599 |
+
"text": [
|
| 600 |
+
"100%|██████████| 4/4 [00:34<00:00, 8.75s/it]\n"
|
| 601 |
+
]
|
| 602 |
+
},
|
| 603 |
+
{
|
| 604 |
+
"data": {
|
| 605 |
+
"text/plain": [
|
| 606 |
+
"hit_rate@1 21.39-23.42\n",
|
| 607 |
+
"hit_rate@5 47.43-49.88\n",
|
| 608 |
+
"hit_rate@20 73.32-75.40\n",
|
| 609 |
+
"mces 8.89-9.25\n",
|
| 610 |
+
"dtype: object"
|
| 611 |
+
]
|
| 612 |
+
},
|
| 613 |
+
"metadata": {},
|
| 614 |
+
"output_type": "display_data"
|
| 615 |
+
},
|
| 616 |
+
{
|
| 617 |
+
"name": "stdout",
|
| 618 |
+
"output_type": "stream",
|
| 619 |
+
"text": [
|
| 620 |
+
"===========================================================\n"
|
| 621 |
+
]
|
| 622 |
+
},
|
| 623 |
+
{
|
| 624 |
+
"name": "stderr",
|
| 625 |
+
"output_type": "stream",
|
| 626 |
+
"text": [
|
| 627 |
+
"100%|██████████| 4/4 [00:35<00:00, 8.78s/it]\n"
|
| 628 |
+
]
|
| 629 |
+
},
|
| 630 |
+
{
|
| 631 |
+
"data": {
|
| 632 |
+
"text/plain": [
|
| 633 |
+
"hit_rate@1 8.29-9.71\n",
|
| 634 |
+
"hit_rate@5 24.35-26.48\n",
|
| 635 |
+
"hit_rate@20 50.80-53.32\n",
|
| 636 |
+
"mces 12.96-13.31\n",
|
| 637 |
+
"dtype: object"
|
| 638 |
+
]
|
| 639 |
+
},
|
| 640 |
+
"metadata": {},
|
| 641 |
+
"output_type": "display_data"
|
| 642 |
+
},
|
| 643 |
+
{
|
| 644 |
+
"name": "stdout",
|
| 645 |
+
"output_type": "stream",
|
| 646 |
+
"text": [
|
| 647 |
+
"===========================================================\n"
|
| 648 |
+
]
|
| 649 |
+
},
|
| 650 |
+
{
|
| 651 |
+
"name": "stderr",
|
| 652 |
+
"output_type": "stream",
|
| 653 |
+
"text": [
|
| 654 |
+
"100%|██████████| 4/4 [00:34<00:00, 8.75s/it]\n"
|
| 655 |
+
]
|
| 656 |
+
},
|
| 657 |
+
{
|
| 658 |
+
"data": {
|
| 659 |
+
"text/plain": [
|
| 660 |
+
"hit_rate@1 3.17-4.09\n",
|
| 661 |
+
"hit_rate@5 11.44-13.04\n",
|
| 662 |
+
"hit_rate@20 26.98-29.23\n",
|
| 663 |
+
"mces 14.41-14.71\n",
|
| 664 |
+
"dtype: object"
|
| 665 |
+
]
|
| 666 |
+
},
|
| 667 |
+
"metadata": {},
|
| 668 |
+
"output_type": "display_data"
|
| 669 |
+
},
|
| 670 |
+
{
|
| 671 |
+
"name": "stdout",
|
| 672 |
+
"output_type": "stream",
|
| 673 |
+
"text": [
|
| 674 |
+
"===========================================================\n"
|
| 675 |
+
]
|
| 676 |
+
}
|
| 677 |
+
],
|
| 678 |
+
"source": [
|
| 679 |
+
"hit_rate_metrics = ['hit_rate@1', 'hit_rate@5', 'hit_rate@20', 'mces']\n",
|
| 680 |
+
"for result in [flare, sirius_labels, mzint_token, crossatt]:\n",
|
| 681 |
+
" result[hit_rate_metrics[:-1]]*=100\n",
|
| 682 |
+
" df_ci = result[hit_rate_metrics].progress_apply(eval_utils.get_ci)\n",
|
| 683 |
+
" display(df_ci)\n",
|
| 684 |
+
" print(\"===========================================================\")"
|
| 685 |
+
]
|
| 686 |
+
},
|
| 687 |
+
{
|
| 688 |
+
"cell_type": "code",
|
| 689 |
+
"execution_count": 49,
|
| 690 |
+
"metadata": {},
|
| 691 |
+
"outputs": [
|
| 692 |
+
{
|
| 693 |
+
"data": {
|
| 694 |
+
"text/html": [
|
| 695 |
+
"<div>\n",
|
| 696 |
+
"<style scoped>\n",
|
| 697 |
+
" .dataframe tbody tr th:only-of-type {\n",
|
| 698 |
+
" vertical-align: middle;\n",
|
| 699 |
+
" }\n",
|
| 700 |
+
"\n",
|
| 701 |
+
" .dataframe tbody tr th {\n",
|
| 702 |
+
" vertical-align: top;\n",
|
| 703 |
+
" }\n",
|
| 704 |
+
"\n",
|
| 705 |
+
" .dataframe thead th {\n",
|
| 706 |
+
" text-align: right;\n",
|
| 707 |
+
" }\n",
|
| 708 |
+
"</style>\n",
|
| 709 |
+
"<table border=\"1\" class=\"dataframe\">\n",
|
| 710 |
+
" <thead>\n",
|
| 711 |
+
" <tr style=\"text-align: right;\">\n",
|
| 712 |
+
" <th></th>\n",
|
| 713 |
+
" <th>hit_rate@1</th>\n",
|
| 714 |
+
" <th>hit_rate@5</th>\n",
|
| 715 |
+
" <th>hit_rate@20</th>\n",
|
| 716 |
+
" <th>mces</th>\n",
|
| 717 |
+
" </tr>\n",
|
| 718 |
+
" </thead>\n",
|
| 719 |
+
" <tbody>\n",
|
| 720 |
+
" <tr>\n",
|
| 721 |
+
" <th>flare</th>\n",
|
| 722 |
+
" <td>22.66</td>\n",
|
| 723 |
+
" <td>50.00</td>\n",
|
| 724 |
+
" <td>75.15</td>\n",
|
| 725 |
+
" <td>9.00</td>\n",
|
| 726 |
+
" </tr>\n",
|
| 727 |
+
" <tr>\n",
|
| 728 |
+
" <th>flare_w_sirius_labels</th>\n",
|
| 729 |
+
" <td>22.45</td>\n",
|
| 730 |
+
" <td>48.64</td>\n",
|
| 731 |
+
" <td>74.37</td>\n",
|
| 732 |
+
" <td>9.07</td>\n",
|
| 733 |
+
" </tr>\n",
|
| 734 |
+
" <tr>\n",
|
| 735 |
+
" <th>mzint_tokens</th>\n",
|
| 736 |
+
" <td>8.98</td>\n",
|
| 737 |
+
" <td>25.38</td>\n",
|
| 738 |
+
" <td>52.04</td>\n",
|
| 739 |
+
" <td>13.14</td>\n",
|
| 740 |
+
" </tr>\n",
|
| 741 |
+
" <tr>\n",
|
| 742 |
+
" <th>crossatten</th>\n",
|
| 743 |
+
" <td>3.62</td>\n",
|
| 744 |
+
" <td>12.25</td>\n",
|
| 745 |
+
" <td>28.10</td>\n",
|
| 746 |
+
" <td>14.56</td>\n",
|
| 747 |
+
" </tr>\n",
|
| 748 |
+
" </tbody>\n",
|
| 749 |
+
"</table>\n",
|
| 750 |
+
"</div>"
|
| 751 |
+
],
|
| 752 |
+
"text/plain": [
|
| 753 |
+
" hit_rate@1 hit_rate@5 hit_rate@20 mces\n",
|
| 754 |
+
"flare 22.66 50.00 75.15 9.00\n",
|
| 755 |
+
"flare_w_sirius_labels 22.45 48.64 74.37 9.07\n",
|
| 756 |
+
"mzint_tokens 8.98 25.38 52.04 13.14\n",
|
| 757 |
+
"crossatten 3.62 12.25 28.10 14.56"
|
| 758 |
+
]
|
| 759 |
+
},
|
| 760 |
+
"execution_count": 49,
|
| 761 |
+
"metadata": {},
|
| 762 |
+
"output_type": "execute_result"
|
| 763 |
+
}
|
| 764 |
+
],
|
| 765 |
+
"source": [
|
| 766 |
+
"result_data = {}\n",
|
| 767 |
+
"for result, method in zip([flare, sirius_labels, mzint_token, crossatt], ['flare', 'flare_w_sirius_labels', 'mzint_tokens', 'crossatten']):\n",
|
| 768 |
+
" result_data[method] = []\n",
|
| 769 |
+
" for m in hit_rate_metrics:\n",
|
| 770 |
+
" val = np.mean(result[m])\n",
|
| 771 |
+
" result_data[method].append(round(val,2))\n",
|
| 772 |
+
"\n",
|
| 773 |
+
"\n",
|
| 774 |
+
"result_df = pd.DataFrame.from_dict(result_data, orient='index', columns=hit_rate_metrics)\n",
|
| 775 |
+
"result_df"
|
| 776 |
+
]
|
| 777 |
+
},
|
| 778 |
+
{
|
| 779 |
+
"cell_type": "code",
|
| 780 |
+
"execution_count": null,
|
| 781 |
+
"metadata": {},
|
| 782 |
+
"outputs": [],
|
| 783 |
+
"source": []
|
| 784 |
+
}
|
| 785 |
+
],
|
| 786 |
+
"metadata": {
|
| 787 |
+
"kernelspec": {
|
| 788 |
+
"display_name": "spec",
|
| 789 |
+
"language": "python",
|
| 790 |
+
"name": "python3"
|
| 791 |
+
},
|
| 792 |
+
"language_info": {
|
| 793 |
+
"name": "python",
|
| 794 |
+
"version": "3.11.7"
|
| 795 |
+
}
|
| 796 |
+
},
|
| 797 |
+
"nbformat": 4,
|
| 798 |
+
"nbformat_minor": 2
|
| 799 |
+
}
|
notebooks/peak_embedding_UMAP.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/peak_formula_analysis.ipynb
CHANGED
|
@@ -35,10 +35,10 @@
|
|
| 35 |
"from massspecgym.models.base import Stage\n",
|
| 36 |
"import os\n",
|
| 37 |
"\n",
|
| 38 |
-
"from
|
| 39 |
-
"from
|
| 40 |
"\n",
|
| 41 |
-
"from
|
| 42 |
"import yaml\n",
|
| 43 |
"from functools import partial\n",
|
| 44 |
"# Suppress RDKit warnings and errors\n",
|
|
@@ -71,7 +71,7 @@
|
|
| 71 |
"source": [
|
| 72 |
"# Load model and data\n",
|
| 73 |
"# param_pth = '/data/yzhouc01/FILIP-MS/experiments/20250824_filipContrastive/lightning_logs/version_0/hparams.yaml'\n",
|
| 74 |
-
"param_pth = \"/data/yzhouc01/FILIP-MS/
|
| 75 |
"with open(param_pth) as f:\n",
|
| 76 |
" params = yaml.load(f, Loader=yaml.FullLoader)\n",
|
| 77 |
"# params['dataset_pth'] = \"/data/yzhouc01/MVP/data/sample/data.tsv\"\n",
|
|
|
|
| 35 |
"from massspecgym.models.base import Stage\n",
|
| 36 |
"import os\n",
|
| 37 |
"\n",
|
| 38 |
+
"from flare.utils.data import get_spec_featurizer, get_mol_featurizer, get_ms_dataset,get_test_ms_dataset\n",
|
| 39 |
+
"from flare.utils.models import get_model\n",
|
| 40 |
"\n",
|
| 41 |
+
"from flare.definitions import TEST_RESULTS_DIR\n",
|
| 42 |
"import yaml\n",
|
| 43 |
"from functools import partial\n",
|
| 44 |
"# Suppress RDKit warnings and errors\n",
|
|
|
|
| 71 |
"source": [
|
| 72 |
"# Load model and data\n",
|
| 73 |
"# param_pth = '/data/yzhouc01/FILIP-MS/experiments/20250824_filipContrastive/lightning_logs/version_0/hparams.yaml'\n",
|
| 74 |
+
"param_pth = \"/data/yzhouc01/FILIP-MS/flare/params_formSpec.yaml\"\n",
|
| 75 |
"with open(param_pth) as f:\n",
|
| 76 |
" params = yaml.load(f, Loader=yaml.FullLoader)\n",
|
| 77 |
"# params['dataset_pth'] = \"/data/yzhouc01/MVP/data/sample/data.tsv\"\n",
|
notebooks/scaffold_identification.ipynb
CHANGED
|
@@ -228,7 +228,7 @@
|
|
| 228 |
"output_type": "stream",
|
| 229 |
"text": [
|
| 230 |
"100%|██████████| 231104/231104 [00:23<00:00, 9679.67it/s] \n",
|
| 231 |
-
"/data/yzhouc01/FILIP-MS/
|
| 232 |
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 233 |
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 234 |
"\n",
|
|
@@ -255,10 +255,10 @@
|
|
| 255 |
"from massspecgym.models.base import Stage\n",
|
| 256 |
"import os\n",
|
| 257 |
"\n",
|
| 258 |
-
"from
|
| 259 |
-
"from
|
| 260 |
"\n",
|
| 261 |
-
"from
|
| 262 |
"import yaml\n",
|
| 263 |
"from functools import partial\n",
|
| 264 |
"# Suppress RDKit warnings and errors\n",
|
|
|
|
| 228 |
"output_type": "stream",
|
| 229 |
"text": [
|
| 230 |
"100%|██████████| 231104/231104 [00:23<00:00, 9679.67it/s] \n",
|
| 231 |
+
"/data/yzhouc01/FILIP-MS/flare/data/datasets.py:221: SettingWithCopyWarning: \n",
|
| 232 |
"A value is trying to be set on a copy of a slice from a DataFrame.\n",
|
| 233 |
"Try using .loc[row_indexer,col_indexer] = value instead\n",
|
| 234 |
"\n",
|
|
|
|
| 255 |
"from massspecgym.models.base import Stage\n",
|
| 256 |
"import os\n",
|
| 257 |
"\n",
|
| 258 |
+
"from flare.utils.data import get_spec_featurizer, get_mol_featurizer, get_ms_dataset\n",
|
| 259 |
+
"from flare.utils.models import get_model\n",
|
| 260 |
"\n",
|
| 261 |
+
"from flare.definitions import TEST_RESULTS_DIR\n",
|
| 262 |
"import yaml\n",
|
| 263 |
"from functools import partial\n",
|
| 264 |
"# Suppress RDKit warnings and errors\n",
|
notebooks/spectra_sim.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/substructure_extraction.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
notebooks/visualization.ipynb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
"cells": [
|
| 3 |
{
|
| 4 |
"cell_type": "code",
|
| 5 |
-
"execution_count":
|
| 6 |
"metadata": {},
|
| 7 |
"outputs": [
|
| 8 |
{
|
|
@@ -11,42 +11,58 @@
|
|
| 11 |
"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:rdkit=\"http://www.rdkit.org/xml\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" baseProfile=\"full\" xml:space=\"preserve\" width=\"400px\" height=\"400px\" viewBox=\"0 0 400 400\">\n",
|
| 12 |
"<!-- END OF HEADER -->\n",
|
| 13 |
"<rect style=\"opacity:1.0;fill:#FFFFFF;stroke:none\" width=\"400.0\" height=\"400.0\" x=\"0.0\" y=\"0.0\"> </rect>\n",
|
| 14 |
-
"<ellipse cx=\"
|
| 15 |
-
"<ellipse cx=\"
|
| 16 |
-
"<ellipse cx=\"
|
| 17 |
-
"<ellipse cx=\"
|
| 18 |
-
"<ellipse cx=\"
|
| 19 |
-
"<ellipse cx=\"
|
| 20 |
-
"<ellipse cx=\"
|
| 21 |
-
"<ellipse cx=\"
|
| 22 |
-
"<
|
| 23 |
-
"<
|
| 24 |
-
"<
|
| 25 |
-
"<
|
| 26 |
-
"<
|
| 27 |
-
"<path class=\"bond-
|
| 28 |
-
"<path class=\"bond-
|
| 29 |
-
"<path class=\"bond-
|
| 30 |
-
"<path class=\"bond-
|
| 31 |
-
"<path class=\"bond-
|
| 32 |
-
"<path class=\"bond-
|
| 33 |
-
"<path class=\"bond-
|
| 34 |
-
"<path class=\"bond-
|
| 35 |
-
"<path class=\"bond-
|
| 36 |
-
"<path d=\"M
|
| 37 |
-
"<path d=\"M
|
| 38 |
-
"<path
|
| 39 |
-
"<path d=\"M
|
| 40 |
-
"<path d=\"M
|
| 41 |
-
"<path
|
| 42 |
-
"<path class=\"atom-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 43 |
"</svg>"
|
| 44 |
],
|
| 45 |
"text/plain": [
|
| 46 |
"<IPython.core.display.SVG object>"
|
| 47 |
]
|
| 48 |
},
|
| 49 |
-
"execution_count":
|
| 50 |
"metadata": {},
|
| 51 |
"output_type": "execute_result"
|
| 52 |
}
|
|
@@ -58,7 +74,7 @@
|
|
| 58 |
"from IPython.display import SVG\n",
|
| 59 |
"\n",
|
| 60 |
"# Example molecule\n",
|
| 61 |
-
"mol = Chem.MolFromSmiles(\"
|
| 62 |
"Chem.rdDepictor.Compute2DCoords(mol)\n",
|
| 63 |
"\n",
|
| 64 |
"# Define colors for atom types\n",
|
|
@@ -178,9 +194,9 @@
|
|
| 178 |
],
|
| 179 |
"metadata": {
|
| 180 |
"kernelspec": {
|
| 181 |
-
"display_name": "spec",
|
| 182 |
"language": "python",
|
| 183 |
-
"name": "
|
| 184 |
},
|
| 185 |
"language_info": {
|
| 186 |
"codemirror_mode": {
|
|
|
|
| 2 |
"cells": [
|
| 3 |
{
|
| 4 |
"cell_type": "code",
|
| 5 |
+
"execution_count": 1,
|
| 6 |
"metadata": {},
|
| 7 |
"outputs": [
|
| 8 |
{
|
|
|
|
| 11 |
"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:rdkit=\"http://www.rdkit.org/xml\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" version=\"1.1\" baseProfile=\"full\" xml:space=\"preserve\" width=\"400px\" height=\"400px\" viewBox=\"0 0 400 400\">\n",
|
| 12 |
"<!-- END OF HEADER -->\n",
|
| 13 |
"<rect style=\"opacity:1.0;fill:#FFFFFF;stroke:none\" width=\"400.0\" height=\"400.0\" x=\"0.0\" y=\"0.0\"> </rect>\n",
|
| 14 |
+
"<ellipse cx=\"42.5\" cy=\"174.3\" rx=\"22.5\" ry=\"12.1\" class=\"atom-0\" style=\"fill:#F99999;fill-rule:evenodd;stroke:#F99999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 15 |
+
"<ellipse cx=\"108.9\" cy=\"165.3\" rx=\"11.8\" ry=\"11.8\" class=\"atom-1\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 16 |
+
"<ellipse cx=\"145.7\" cy=\"211.3\" rx=\"11.8\" ry=\"11.8\" class=\"atom-2\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 17 |
+
"<ellipse cx=\"116.1\" cy=\"266.3\" rx=\"22.5\" ry=\"12.1\" class=\"atom-3\" style=\"fill:#F99999;fill-rule:evenodd;stroke:#F99999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 18 |
+
"<ellipse cx=\"203.9\" cy=\"202.4\" rx=\"11.8\" ry=\"11.8\" class=\"atom-4\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 19 |
+
"<ellipse cx=\"245.4\" cy=\"244.2\" rx=\"11.8\" ry=\"11.8\" class=\"atom-5\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 20 |
+
"<ellipse cx=\"243.7\" cy=\"302.5\" rx=\"21.9\" ry=\"12.1\" class=\"atom-6\" style=\"fill:#F99999;fill-rule:evenodd;stroke:#F99999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 21 |
+
"<ellipse cx=\"298.0\" cy=\"217.8\" rx=\"11.8\" ry=\"11.8\" class=\"atom-7\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 22 |
+
"<ellipse cx=\"358.1\" cy=\"244.9\" rx=\"21.9\" ry=\"12.1\" class=\"atom-8\" style=\"fill:#F99999;fill-rule:evenodd;stroke:#F99999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 23 |
+
"<ellipse cx=\"289.1\" cy=\"159.5\" rx=\"11.8\" ry=\"11.8\" class=\"atom-9\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 24 |
+
"<ellipse cx=\"338.7\" cy=\"118.3\" rx=\"21.9\" ry=\"12.1\" class=\"atom-10\" style=\"fill:#F99999;fill-rule:evenodd;stroke:#F99999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 25 |
+
"<ellipse cx=\"230.9\" cy=\"150.0\" rx=\"11.8\" ry=\"11.8\" class=\"atom-11\" style=\"fill:#999999;fill-rule:evenodd;stroke:#999999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 26 |
+
"<ellipse cx=\"196.3\" cy=\"97.5\" rx=\"22.5\" ry=\"12.1\" class=\"atom-12\" style=\"fill:#F99999;fill-rule:evenodd;stroke:#F99999;stroke-width:1.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 27 |
+
"<path class=\"bond-0 atom-0 atom-1\" d=\"M 60.3,172.7 L 84.6,169.0\" style=\"fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 28 |
+
"<path class=\"bond-0 atom-0 atom-1\" d=\"M 84.6,169.0 L 108.9,165.3\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 29 |
+
"<path class=\"bond-1 atom-1 atom-2\" d=\"M 108.9,165.3 L 145.7,211.3\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 30 |
+
"<path class=\"bond-2 atom-2 atom-3\" d=\"M 145.7,211.3 L 137.1,233.5\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 31 |
+
"<path class=\"bond-2 atom-2 atom-3\" d=\"M 137.1,233.5 L 128.4,255.7\" style=\"fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 32 |
+
"<path class=\"bond-3 atom-2 atom-4\" d=\"M 145.7,211.3 L 203.9,202.4\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 33 |
+
"<path class=\"bond-4 atom-4 atom-5\" d=\"M 203.9,202.4 L 245.4,244.2\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 34 |
+
"<path class=\"bond-5 atom-5 atom-6\" d=\"M 245.4,244.2 L 241.4,268.1\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 35 |
+
"<path class=\"bond-5 atom-5 atom-6\" d=\"M 241.4,268.1 L 237.5,291.9\" style=\"fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 36 |
+
"<path class=\"bond-6 atom-5 atom-7\" d=\"M 245.4,244.2 L 298.0,217.8\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 37 |
+
"<path class=\"bond-7 atom-7 atom-8\" d=\"M 298.0,217.8 L 319.3,228.8\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 38 |
+
"<path class=\"bond-7 atom-7 atom-8\" d=\"M 319.3,228.8 L 340.7,239.8\" style=\"fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 39 |
+
"<path class=\"bond-8 atom-7 atom-9\" d=\"M 298.0,217.8 L 289.1,159.5\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 40 |
+
"<path class=\"bond-9 atom-9 atom-10\" d=\"M 289.1,159.5 L 305.2,143.6\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 41 |
+
"<path class=\"bond-9 atom-9 atom-10\" d=\"M 305.2,143.6 L 321.3,127.6\" style=\"fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 42 |
+
"<path class=\"bond-10 atom-9 atom-11\" d=\"M 289.1,159.5 L 230.9,150.0\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 43 |
+
"<path class=\"bond-11 atom-11 atom-12\" d=\"M 230.9,150.0 L 220.4,129.0\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 44 |
+
"<path class=\"bond-11 atom-11 atom-12\" d=\"M 220.4,129.0 L 209.8,108.1\" style=\"fill:none;fill-rule:evenodd;stroke:#FF0000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 45 |
+
"<path class=\"bond-12 atom-11 atom-4\" d=\"M 230.9,150.0 L 203.9,202.4\" style=\"fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1\"/>\n",
|
| 46 |
+
"<path d=\"M 107.7,165.5 L 108.9,165.3 L 110.8,167.6\" style=\"fill:none;stroke:#000000;stroke-width:2.0px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;\"/>\n",
|
| 47 |
+
"<path class=\"atom-0\" d=\"M 26.6 166.0 L 28.8 166.0 L 28.8 173.1 L 37.4 173.1 L 37.4 166.0 L 39.6 166.0 L 39.6 182.6 L 37.4 182.6 L 37.4 174.9 L 28.8 174.9 L 28.8 182.6 L 26.6 182.6 L 26.6 166.0 \" fill=\"#FF0000\"/>\n",
|
| 48 |
+
"<path class=\"atom-0\" d=\"M 43.1 174.3 Q 43.1 170.3, 45.0 168.0 Q 47.0 165.8, 50.7 165.8 Q 54.4 165.8, 56.4 168.0 Q 58.4 170.3, 58.4 174.3 Q 58.4 178.3, 56.4 180.6 Q 54.4 182.9, 50.7 182.9 Q 47.0 182.9, 45.0 180.6 Q 43.1 178.3, 43.1 174.3 M 50.7 181.0 Q 53.2 181.0, 54.6 179.3 Q 56.0 177.6, 56.0 174.3 Q 56.0 171.0, 54.6 169.3 Q 53.2 167.7, 50.7 167.7 Q 48.2 167.7, 46.8 169.3 Q 45.4 171.0, 45.4 174.3 Q 45.4 177.6, 46.8 179.3 Q 48.2 181.0, 50.7 181.0 \" fill=\"#FF0000\"/>\n",
|
| 49 |
+
"<path class=\"atom-3\" d=\"M 100.2 257.9 L 102.5 257.9 L 102.5 265.0 L 111.0 265.0 L 111.0 257.9 L 113.3 257.9 L 113.3 274.6 L 111.0 274.6 L 111.0 266.9 L 102.5 266.9 L 102.5 274.6 L 100.2 274.6 L 100.2 257.9 \" fill=\"#FF0000\"/>\n",
|
| 50 |
+
"<path class=\"atom-3\" d=\"M 116.7 266.2 Q 116.7 262.2, 118.7 259.9 Q 120.6 257.7, 124.3 257.7 Q 128.0 257.7, 130.0 259.9 Q 132.0 262.2, 132.0 266.2 Q 132.0 270.2, 130.0 272.5 Q 128.0 274.8, 124.3 274.8 Q 120.7 274.8, 118.7 272.5 Q 116.7 270.2, 116.7 266.2 M 124.3 272.9 Q 126.9 272.9, 128.2 271.2 Q 129.6 269.5, 129.6 266.2 Q 129.6 262.9, 128.2 261.2 Q 126.9 259.6, 124.3 259.6 Q 121.8 259.6, 120.4 261.2 Q 119.0 262.9, 119.0 266.2 Q 119.0 269.5, 120.4 271.2 Q 121.8 272.9, 124.3 272.9 \" fill=\"#FF0000\"/>\n",
|
| 51 |
+
"<path class=\"atom-6\" d=\"M 228.2 302.4 Q 228.2 298.4, 230.2 296.1 Q 232.1 293.9, 235.8 293.9 Q 239.5 293.9, 241.5 296.1 Q 243.5 298.4, 243.5 302.4 Q 243.5 306.4, 241.5 308.7 Q 239.5 311.0, 235.8 311.0 Q 232.2 311.0, 230.2 308.7 Q 228.2 306.4, 228.2 302.4 M 235.8 309.1 Q 238.4 309.1, 239.7 307.4 Q 241.1 305.7, 241.1 302.4 Q 241.1 299.1, 239.7 297.4 Q 238.4 295.8, 235.8 295.8 Q 233.3 295.8, 231.9 297.4 Q 230.5 299.1, 230.5 302.4 Q 230.5 305.7, 231.9 307.4 Q 233.3 309.1, 235.8 309.1 \" fill=\"#FF0000\"/>\n",
|
| 52 |
+
"<path class=\"atom-6\" d=\"M 246.1 294.1 L 248.4 294.1 L 248.4 301.2 L 256.9 301.2 L 256.9 294.1 L 259.1 294.1 L 259.1 310.8 L 256.9 310.8 L 256.9 303.1 L 248.4 303.1 L 248.4 310.8 L 246.1 310.8 L 246.1 294.1 \" fill=\"#FF0000\"/>\n",
|
| 53 |
+
"<path class=\"atom-8\" d=\"M 342.6 244.8 Q 342.6 240.8, 344.6 238.6 Q 346.6 236.3, 350.3 236.3 Q 354.0 236.3, 356.0 238.6 Q 357.9 240.8, 357.9 244.8 Q 357.9 248.9, 355.9 251.2 Q 353.9 253.5, 350.3 253.5 Q 346.6 253.5, 344.6 251.2 Q 342.6 248.9, 342.6 244.8 M 350.3 251.6 Q 352.8 251.6, 354.2 249.9 Q 355.6 248.2, 355.6 244.8 Q 355.6 241.5, 354.2 239.9 Q 352.8 238.2, 350.3 238.2 Q 347.7 238.2, 346.4 239.9 Q 345.0 241.5, 345.0 244.8 Q 345.0 248.2, 346.4 249.9 Q 347.7 251.6, 350.3 251.6 \" fill=\"#FF0000\"/>\n",
|
| 54 |
+
"<path class=\"atom-8\" d=\"M 360.5 236.5 L 362.8 236.5 L 362.8 243.6 L 371.3 243.6 L 371.3 236.5 L 373.6 236.5 L 373.6 253.2 L 371.3 253.2 L 371.3 245.5 L 362.8 245.5 L 362.8 253.2 L 360.5 253.2 L 360.5 236.5 \" fill=\"#FF0000\"/>\n",
|
| 55 |
+
"<path class=\"atom-10\" d=\"M 323.3 118.2 Q 323.3 114.2, 325.2 111.9 Q 327.2 109.7, 330.9 109.7 Q 334.6 109.7, 336.6 111.9 Q 338.6 114.2, 338.6 118.2 Q 338.6 122.2, 336.6 124.5 Q 334.6 126.8, 330.9 126.8 Q 327.2 126.8, 325.2 124.5 Q 323.3 122.2, 323.3 118.2 M 330.9 124.9 Q 333.5 124.9, 334.8 123.2 Q 336.2 121.5, 336.2 118.2 Q 336.2 114.9, 334.8 113.3 Q 333.5 111.6, 330.9 111.6 Q 328.4 111.6, 327.0 113.2 Q 325.6 114.9, 325.6 118.2 Q 325.6 121.5, 327.0 123.2 Q 328.4 124.9, 330.9 124.9 \" fill=\"#FF0000\"/>\n",
|
| 56 |
+
"<path class=\"atom-10\" d=\"M 341.2 109.9 L 343.4 109.9 L 343.4 117.0 L 352.0 117.0 L 352.0 109.9 L 354.2 109.9 L 354.2 126.6 L 352.0 126.6 L 352.0 118.9 L 343.4 118.9 L 343.4 126.6 L 341.2 126.6 L 341.2 109.9 \" fill=\"#FF0000\"/>\n",
|
| 57 |
+
"<path class=\"atom-12\" d=\"M 180.4 89.2 L 182.6 89.2 L 182.6 96.3 L 191.2 96.3 L 191.2 89.2 L 193.4 89.2 L 193.4 105.9 L 191.2 105.9 L 191.2 98.2 L 182.6 98.2 L 182.6 105.9 L 180.4 105.9 L 180.4 89.2 \" fill=\"#FF0000\"/>\n",
|
| 58 |
+
"<path class=\"atom-12\" d=\"M 196.8 97.5 Q 196.8 93.5, 198.8 91.2 Q 200.8 89.0, 204.5 89.0 Q 208.2 89.0, 210.2 91.2 Q 212.1 93.5, 212.1 97.5 Q 212.1 101.5, 210.1 103.8 Q 208.1 106.1, 204.5 106.1 Q 200.8 106.1, 198.8 103.8 Q 196.8 101.5, 196.8 97.5 M 204.5 104.2 Q 207.0 104.2, 208.4 102.5 Q 209.8 100.8, 209.8 97.5 Q 209.8 94.2, 208.4 92.5 Q 207.0 90.9, 204.5 90.9 Q 201.9 90.9, 200.6 92.5 Q 199.2 94.2, 199.2 97.5 Q 199.2 100.8, 200.6 102.5 Q 201.9 104.2, 204.5 104.2 \" fill=\"#FF0000\"/>\n",
|
| 59 |
"</svg>"
|
| 60 |
],
|
| 61 |
"text/plain": [
|
| 62 |
"<IPython.core.display.SVG object>"
|
| 63 |
]
|
| 64 |
},
|
| 65 |
+
"execution_count": 1,
|
| 66 |
"metadata": {},
|
| 67 |
"output_type": "execute_result"
|
| 68 |
}
|
|
|
|
| 74 |
"from IPython.display import SVG\n",
|
| 75 |
"\n",
|
| 76 |
"# Example molecule\n",
|
| 77 |
+
"mol = Chem.MolFromSmiles(\"OCC(O)C1C(O)C(O)C(O)C(O)1\") \n",
|
| 78 |
"Chem.rdDepictor.Compute2DCoords(mol)\n",
|
| 79 |
"\n",
|
| 80 |
"# Define colors for atom types\n",
|
|
|
|
| 194 |
],
|
| 195 |
"metadata": {
|
| 196 |
"kernelspec": {
|
| 197 |
+
"display_name": "Python (spec)",
|
| 198 |
"language": "python",
|
| 199 |
+
"name": "spec"
|
| 200 |
},
|
| 201 |
"language_info": {
|
| 202 |
"codemirror_mode": {
|