Mercurial > repos > computational-metabolomics > metfrag_vis
comparison metfrag-vis.py @ 0:3dbe79671820 draft default tip
"planemo upload for repository https://github.com/computational-metabolomics/metfrag-galaxy commit b337c6296968848e3214f4b51df3d86776f84b6a"
| author | computational-metabolomics |
|---|---|
| date | Tue, 14 Jul 2020 07:42:34 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:3dbe79671820 |
|---|---|
| 1 #!/usr/bin/env python | |
| 2 | |
| 3 # Load modules | |
| 4 import argparse | |
| 5 import base64 | |
| 6 import csv | |
| 7 import os | |
| 8 import re | |
| 9 import time | |
| 10 import urllib.parse | |
| 11 | |
| 12 import matplotlib.pyplot as plt | |
| 13 | |
| 14 import pubchempy | |
| 15 | |
| 16 import requests | |
| 17 | |
| 18 # Parse arguments | |
| 19 parser = argparse.ArgumentParser( | |
| 20 description='Visualise MetFrag results in html.') | |
| 21 parser.add_argument('-v', '--version', action='version', | |
| 22 version='MetFrag-vis Version 0.9', | |
| 23 help='show version') | |
| 24 parser.add_argument('-i', '--input', metavar='metfrag_results.tsv', | |
| 25 dest="input_tsv", required=True, | |
| 26 help='MetFrag results as input') | |
| 27 parser.add_argument('-o', '--output', metavar='metfrag_results.html', | |
| 28 dest="output_html", required=True, | |
| 29 help='Write MetFrag results into this output file') | |
| 30 parser.add_argument('-m', '--max-candidates', metavar='10', | |
| 31 dest="max_candidates", default=10, type=int, | |
| 32 required=False, | |
| 33 help='Maximum number of candidates per compound [1-1000]') | |
| 34 parser.add_argument('-s', '--synonyms', dest='synonyms', action='store_true', | |
| 35 required=False, | |
| 36 help='Fetch synonyms from PubChem [disabled by default]') | |
| 37 parser.add_argument('-c', '--classyfire', dest='classyfire', | |
| 38 action='store_true', required=False, | |
| 39 help='Fetch compound classes from ClassyFire' | |
| 40 ' [disabled by default]') | |
| 41 | |
| 42 args = parser.parse_args() | |
| 43 | |
| 44 # Input CSV with MetFrag results | |
| 45 input_tsv = args.input_tsv | |
| 46 | |
| 47 # Output html of MetFrag results | |
| 48 output_html = args.output_html | |
| 49 | |
| 50 # Max number of candidates per compound | |
| 51 max_candidates = args.max_candidates | |
| 52 | |
| 53 # PubChem synonyms | |
| 54 pubchem_synonyms_enabled = args.synonyms | |
| 55 | |
| 56 # ClassyFire classes | |
| 57 classyfire_classes_enabled = args.classyfire | |
| 58 | |
| 59 | |
| 60 # ---------- cdk_inchi_to_svg ---------- | |
| 61 def cdk_inchi_to_svg(inchi): | |
| 62 if "cdk-inchi-to-svg" in os.environ: | |
| 63 JAVA_CMD = 'cdk-inchi-to-svg' + ' ' + str( | |
| 64 '\'' + inchi + '\'') + ' ' + 'cdk-inchi-to-svg-output.svg' | |
| 65 else: | |
| 66 JAVA_BINARY = '/usr/local/bin/java' | |
| 67 CDK_INCHI_TO_SVG_JAR = '/usr/local/bin/' \ | |
| 68 'cdk-inchi-to-svg-0.0.1-' \ | |
| 69 'SNAPSHOT-jar-with-dependencies.jar' | |
| 70 JAVA_CMD = str( | |
| 71 JAVA_BINARY + ' ' + '-jar' + ' ' + CDK_INCHI_TO_SVG_JAR + ' ' | |
| 72 + str('\'' + inchi + '\'') + ' ' + 'cdk-inchi-to-svg-output.svg') | |
| 73 | |
| 74 # Exec cdk-inchi-to-svg JAVA binary | |
| 75 exitcode = os.system(JAVA_CMD) | |
| 76 | |
| 77 # Check whether binary has successfully been run | |
| 78 if (exitcode == 0): | |
| 79 with open("cdk-inchi-to-svg-output.svg", "r") as svg_file: | |
| 80 svg_string = [] | |
| 81 for line in svg_file: | |
| 82 if not ('<?xml' in line) and not ('<!DOCTYPE' in line): | |
| 83 if (' fill=\'#FFFFFF\'' in line): | |
| 84 line = re.sub(' fill=\'#FFFFFF\'', | |
| 85 ' fill=\'#FFFFFF\' fill-opacity=\'0.0\'', | |
| 86 line) | |
| 87 svg_string.append(line) | |
| 88 svg_file.close() | |
| 89 os.remove("cdk-inchi-to-svg-output.svg") | |
| 90 return (str(''.join(svg_string))) | |
| 91 else: | |
| 92 return (' ') | |
| 93 | |
| 94 | |
| 95 # ---------- pubchem_link ---------- | |
| 96 def pubchem_link(compound_name): | |
| 97 return (str('https://pubchem.ncbi.nlm.nih.gov/#query=' + compound_name)) | |
| 98 | |
| 99 | |
| 100 # ---------- kegg_link ---------- | |
| 101 def kegg_link(compound_name): | |
| 102 return (str( | |
| 103 'https://www.genome.jp/dbget-bin/' | |
| 104 'www_bfind_sub?mode=bfind&max_hit=1000&dbkey=kegg&keywords=' + | |
| 105 compound_name)) | |
| 106 | |
| 107 | |
| 108 # ---------- biocyc_link ---------- | |
| 109 def biocyc_link(compound_name): | |
| 110 biocyc_url = urllib.parse.urlparse( | |
| 111 str( | |
| 112 'https://www.biocyc.org/' | |
| 113 'substring-search?type=NIL&object=' + | |
| 114 compound_name + '&quickSearch=Quick+Search')) | |
| 115 return (biocyc_url.geturl()) | |
| 116 | |
| 117 | |
| 118 # ---------- hmdb_link ---------- | |
| 119 def hmdb_link(compound_name): | |
| 120 hmdb_url = urllib.parse.urlparse( | |
| 121 str( | |
| 122 'https://hmdb.ca/unearth/q?utf8=\xe2&query=' + | |
| 123 compound_name + '&searcher=metabolites&button=')) | |
| 124 return (hmdb_url.geturl()) | |
| 125 | |
| 126 | |
| 127 # ---------- hmdb_link ---------- | |
| 128 def chebi_link(inchi): | |
| 129 return (str( | |
| 130 'https://www.ebi.ac.uk/chebi/advancedSearchFT.do?searchString=' | |
| 131 + inchi)) | |
| 132 | |
| 133 | |
| 134 # ---------- PubChem Synonyms ---------- | |
| 135 def fetch_pubchem_synonyms(inchi): | |
| 136 if not ('InChI=' in inchi): | |
| 137 return (' ') | |
| 138 | |
| 139 # Fetch CID from InChI | |
| 140 print('Retrieving PubChem CID from InChI...') | |
| 141 compound = pubchempy.get_compounds(identifier=inchi, namespace='inchi') | |
| 142 compound_cid = re.sub(r'\).*', '', re.sub(r'.*\(', '', str(compound))) | |
| 143 if len(compound_cid) <= 1: | |
| 144 print(str('Warning. No match for InChI \"' + str(inchi) + '\".')) | |
| 145 return (' ') | |
| 146 | |
| 147 # Retrieve compound | |
| 148 print('Retrieving PubChem compound information...') | |
| 149 compound = pubchempy.Compound.from_cid(compound_cid) | |
| 150 if ('synonyms' in dir(compound)): | |
| 151 return ('; '.join(compound.synonyms)) | |
| 152 else: | |
| 153 print(str('Warning. No synonyms found for CID \"' + str( | |
| 154 compound_cid) + '\".')) | |
| 155 return (' ') | |
| 156 | |
| 157 | |
| 158 # ---------- ClassyFire ---------- | |
| 159 def fetch_classyfire_classes(inchi): | |
| 160 if not ('InChI=' in inchi): | |
| 161 return (' ') | |
| 162 | |
| 163 # Send POST request to ClassyFire | |
| 164 print('Sending request to ClassyFire...') | |
| 165 classyfire_url = 'http://classyfire.wishartlab.com/queries.json' | |
| 166 classyfire_post = str( | |
| 167 '{\"label\":\"metfrag\",\"query_input\":\"' + inchi + | |
| 168 '\",\"query_type\":\"STRUCTURE\"}') | |
| 169 classyfire_headers = {'Content-Type': 'application/json'} | |
| 170 classyfire_request = requests.post(classyfire_url, data=classyfire_post, | |
| 171 headers=classyfire_headers) | |
| 172 | |
| 173 # Only continue when request has been successfully sent | |
| 174 if (classyfire_request.status_code != 201): | |
| 175 print('Error! Could not send request to ClassyFire. \"', | |
| 176 str(classyfire_request.status_code) + ': ' + str( | |
| 177 classyfire_request.reason), '\". Skipping entry.') | |
| 178 return (' ') | |
| 179 | |
| 180 # Get ClassyFire Query ID | |
| 181 classyfire_request.json() | |
| 182 classyfire_query_id = classyfire_request.json()['id'] | |
| 183 | |
| 184 # Query ClassyFire in max. 20 attempts | |
| 185 classyfire_request_loop = 0 | |
| 186 while (classyfire_request_loop < 20): | |
| 187 print(str( | |
| 188 'Sending query ' + str(classyfire_query_id) + ' to ClassyFire...')) | |
| 189 time.sleep(10) | |
| 190 classyfire_query = requests.get( | |
| 191 str('http://classyfire.wishartlab.com/queries/' + str( | |
| 192 classyfire_query_id) + '.json')) | |
| 193 | |
| 194 if (classyfire_query.status_code == 200) and ( | |
| 195 classyfire_query.json()['classification_status'] == 'Done'): | |
| 196 classyfire_request_loop = 999 | |
| 197 break | |
| 198 else: | |
| 199 classyfire_request_loop += 1 | |
| 200 | |
| 201 if classyfire_request_loop == 999: | |
| 202 # Direct parent | |
| 203 direct_parent_name = classyfire_query.json()[ | |
| 204 'entities'][0]['direct_parent']['name'] | |
| 205 direct_parent_url = classyfire_query.json()[ | |
| 206 'entities'][0]['direct_parent']['url'] | |
| 207 direct_parent = str( | |
| 208 '<a target="_blank" href="' + direct_parent_url + '">' + | |
| 209 direct_parent_name + '</a>') | |
| 210 | |
| 211 # Alternative parents | |
| 212 alt_parents = [] | |
| 213 for i in range(0, len(classyfire_query.json()['entities'][0][ | |
| 214 'alternative_parents'])): | |
| 215 alt_parent_name = classyfire_query.json()[ | |
| 216 'entities'][0]['alternative_parents'][i]['name'] | |
| 217 alt_parent_url = classyfire_query.json()[ | |
| 218 'entities'][0]['alternative_parents'][i]['url'] | |
| 219 alt_parent = str( | |
| 220 '<a target="_blank" href="' + alt_parent_url + '">' + | |
| 221 alt_parent_name + '</a>') | |
| 222 alt_parents.append(alt_parent) | |
| 223 | |
| 224 # Concat classes | |
| 225 classes = str('<b>' + direct_parent + '</b>, <br>' + str( | |
| 226 ', <br>'.join(alt_parents))) | |
| 227 else: | |
| 228 print('Warning. Timout sending query to ClassyFire. Skipping entry.') | |
| 229 classes = ' ' | |
| 230 | |
| 231 return (classes) | |
| 232 | |
| 233 | |
| 234 # ---------- Plot Spectrum ---------- | |
| 235 def plot_spectrum(spectrum, spectrum_explained, spectrum_explained_formulas): | |
| 236 # Plot | |
| 237 plt.figure(figsize=[5.5, 4.4]) | |
| 238 plt.xlabel('m/z') | |
| 239 plt.ylabel('intensity') | |
| 240 | |
| 241 # Plot spectrum | |
| 242 x = [] | |
| 243 y = [] | |
| 244 for i in spectrum.split(';'): | |
| 245 t = i.split('_') | |
| 246 x.append(t[0]) | |
| 247 y.append(t[1]) | |
| 248 | |
| 249 for i in range(0, len(x)): | |
| 250 plt.plot([float(x[i]), float(x[i])], [0, float(y[i])], linewidth=1, | |
| 251 color='black') | |
| 252 plt.plot(float(x[i]), float(y[i]), 'o', color='black', markersize=4) | |
| 253 | |
| 254 if not (spectrum_explained == 'NA') and not ( | |
| 255 spectrum_explained_formulas == 'NA'): | |
| 256 # Plot explained peaks | |
| 257 ex = [] | |
| 258 ey = [] | |
| 259 for i in spectrum_explained.split(';'): | |
| 260 t = i.split('_') | |
| 261 ex.append(t[0]) | |
| 262 ey.append(y[x.index(t[0])]) | |
| 263 | |
| 264 for i in range(0, len(ex)): | |
| 265 plt.plot([float(ex[i]), float(ex[i])], [0, float(ey[i])], | |
| 266 linewidth=3, color='#2b8126') | |
| 267 plt.plot(float(ex[i]), float(ey[i]), 'o', color='#2b8126', | |
| 268 markersize=8) | |
| 269 | |
| 270 # Plot formulas on explained peaks | |
| 271 ex = [] | |
| 272 ey = [] | |
| 273 ez = [] | |
| 274 for i in spectrum_explained_formulas.split(';'): | |
| 275 t = i.split(':') | |
| 276 ex.append(t[0]) | |
| 277 ey.append(y[x.index(t[0])]) | |
| 278 ez.append(t[1]) | |
| 279 | |
| 280 for i in range(0, len(ex)): | |
| 281 plt.text(float(ex[i]), float(ey[i]) + 1000, ez[i], color='#2b8126', | |
| 282 fontsize=8, | |
| 283 horizontalalignment='center', verticalalignment='bottom') | |
| 284 | |
| 285 # Save SVG | |
| 286 plt.savefig("metfrag-vis-spectrum.svg", format="svg", transparent=True) | |
| 287 plt.close() | |
| 288 | |
| 289 # Import SVG | |
| 290 with open("metfrag-vis-spectrum.svg", "r") as svg_file: | |
| 291 svg_string = [] | |
| 292 for line in svg_file: | |
| 293 if not ('<?xml' in line) and not ('<!DOCTYPE' in line) and not ( | |
| 294 ' "http://www.w3.org/Graphics' in line): | |
| 295 svg_string.append(line) | |
| 296 svg_file.close() | |
| 297 os.remove("metfrag-vis-spectrum.svg") | |
| 298 return (str(''.join(svg_string))) | |
| 299 | |
| 300 | |
| 301 # #################### MAIN #################### | |
| 302 if pubchem_synonyms_enabled: | |
| 303 print('Fetching of PubChem Synonyms enabled.') | |
| 304 if classyfire_classes_enabled: | |
| 305 print('Fetching of ClassyFire Classes enabled.') | |
| 306 | |
| 307 # Open output html file | |
| 308 try: | |
| 309 metfrag_html = open(output_html, "w") | |
| 310 except Exception as e: | |
| 311 print("Error writing output file. {}".format(e)) | |
| 312 exit(1) | |
| 313 | |
| 314 # Write html header | |
| 315 metfrag_html.write('<!DOCTYPE html>\n') | |
| 316 metfrag_html.write('<html>\n') | |
| 317 metfrag_html.write('<head>\n') | |
| 318 metfrag_html.write('<title>' + 'msPurity MetFrag results' + '</title>\n') | |
| 319 metfrag_html.write('<style type="text/css">\n') | |
| 320 metfrag_html.write('svg { width: 200px; height: 100%; }\n') | |
| 321 metfrag_html.write( | |
| 322 'body { font-family: Lucida, Verdana, Arial, Helvetica, sans-serif; ' | |
| 323 'font-size: 13px; text-align: left; ' | |
| 324 'color: #000000; margin: 8px 8px 8px 8px; }\n') | |
| 325 metfrag_html.write( | |
| 326 'A { color: #2b8126; text-decoration: none; background: transparent; }\n') | |
| 327 metfrag_html.write( | |
| 328 'A:visited { ' | |
| 329 'color: #19681a; text-decoration: none; background: transparent; ' | |
| 330 '}\n') | |
| 331 metfrag_html.write( | |
| 332 'A:hover { ' | |
| 333 'color: #8fc180; text-decoration: underline; background: transparent; ' | |
| 334 '}\n') | |
| 335 metfrag_html.write( | |
| 336 'h1 { font-size: 32px; font-weight: bold; text-align: center; ' | |
| 337 'padding: 0px 0px 4px 0px; margin: 26px 0px 0px 0px; }\n') | |
| 338 metfrag_html.write( | |
| 339 'h2 { font-size: 24px; font-weight: bold; text-align: left; ' | |
| 340 'padding: 0px 0px 4px 0px; margin: 26px 0px 0px 0px; }\n') | |
| 341 metfrag_html.write( | |
| 342 'table { font-family: Lucida, Verdana, Arial, Helvetica, sans-serif; ' | |
| 343 'font-size: 10px; text-align: left; ' | |
| 344 'line-height: 10px; border: 1px solid #e3efdf; ' | |
| 345 'background-color: #ecf5ea; margin-bottom: 8px; ' | |
| 346 'min-width: 1600px; max-width: 2400px; }\n') | |
| 347 metfrag_html.write( | |
| 348 '#tablediv { width: 100%; min-width: 20px; max-width: 200px; }\n') | |
| 349 metfrag_html.write('.tdmax { min-width: 200px; max-width: 200px; }\n') | |
| 350 metfrag_html.write('.tdvar { min-width: 200px; max-width: 600px; }\n') | |
| 351 metfrag_html.write('tr:nth-child(even) { background-color: #f6faf5; }\n') | |
| 352 metfrag_html.write('</style>\n') | |
| 353 metfrag_html.write('</head>\n') | |
| 354 metfrag_html.write('<body>\n') | |
| 355 | |
| 356 # Read input csv file | |
| 357 with open(input_tsv, "r") as metfrag_file: | |
| 358 metfrag_results = csv.DictReader(metfrag_file, delimiter='\t') | |
| 359 # Parse each line | |
| 360 line_count = 0 | |
| 361 compound = "" | |
| 362 candidates = 0 | |
| 363 for row in metfrag_results: | |
| 364 | |
| 365 # Start new document | |
| 366 if (line_count == 0): | |
| 367 if os.path.join(os.path.dirname(os.path.abspath(__file__)), | |
| 368 'metfrag_logo.png'): | |
| 369 logo_pth = os.path.join( | |
| 370 os.path.dirname(os.path.abspath(__file__)), | |
| 371 'metfrag_logo.png') | |
| 372 else: | |
| 373 logo_pth = '/usr/local/share/metfrag/metfrag_logo.png' | |
| 374 | |
| 375 with open(logo_pth, "rb") as png_file: | |
| 376 png_encoded = base64.b64encode(png_file.read()) | |
| 377 metfrag_html.write(str( | |
| 378 '\n<h1><img style="vertical-align:bottom" ' | |
| 379 'src="data:image/png;base64,' + | |
| 380 png_encoded.decode('utf-8') + | |
| 381 '" alt="metfrag-logo" width="150"></img><text ' | |
| 382 'style="line-height:2.0"> results</text></h1>\n' | |
| 383 )) | |
| 384 else: | |
| 385 # Parameter list at beginning of document | |
| 386 if (line_count == 1): | |
| 387 metfrag_html.write('\n<h2>Parameter list</h2>\n') | |
| 388 metfrag_html.write(str('MetFragDatabaseType=' + | |
| 389 re.sub(' .*', '', | |
| 390 re.sub('.*MetFragDatabaseType=', | |
| 391 '', | |
| 392 row[ | |
| 393 "MetFragCLIString"])) | |
| 394 + '<br>\n') | |
| 395 ) | |
| 396 metfrag_html.write(str('PrecursorIonMode=' + | |
| 397 re.sub(' .*', '', | |
| 398 re.sub('.*PrecursorIonMode=', '', | |
| 399 row[ | |
| 400 "MetFragCLIString"])) | |
| 401 + '<br>\n') | |
| 402 ) | |
| 403 metfrag_html.write(str('DatabaseSearchRelativeMassDeviation=' + | |
| 404 re.sub(' .*', '', | |
| 405 re.sub( | |
| 406 '.*DatabaseSearchRelative' | |
| 407 'MassDeviation=', | |
| 408 '', | |
| 409 row[ | |
| 410 "MetFragCLIString"])) + | |
| 411 '<br>\n') | |
| 412 ) | |
| 413 metfrag_html.write( | |
| 414 str('FragmentPeakMatchAbsoluteMassDeviation=' + | |
| 415 re.sub(' .*', '', | |
| 416 re.sub( | |
| 417 '.*FragmentPeakMatchAbsoluteMassDeviation=', | |
| 418 '', | |
| 419 row["MetFragCLIString"])) + '<br>\n') | |
| 420 ) | |
| 421 metfrag_html.write( | |
| 422 str('FragmentPeakMatchRelativeMassDeviation=' + | |
| 423 re.sub(' .*', '', | |
| 424 re.sub( | |
| 425 '.*FragmentPeakMatchRelativeMassDeviation=', | |
| 426 '', | |
| 427 row["MetFragCLIString"])) + '<br>\n') | |
| 428 ) | |
| 429 metfrag_html.write(str('FilterExcludedElements=' + | |
| 430 re.sub(' .*', '', | |
| 431 re.sub( | |
| 432 '.*FilterExcludedElements=', | |
| 433 '', | |
| 434 row[ | |
| 435 "MetFragCLIString"])) + | |
| 436 '<br>\n') | |
| 437 ) | |
| 438 metfrag_html.write(str('FilterIncludedElements=' + | |
| 439 re.sub(' .*', '', | |
| 440 re.sub( | |
| 441 '.*FilterIncludedElements=', | |
| 442 '', | |
| 443 row[ | |
| 444 "MetFragCLIString"])) + | |
| 445 '<br>\n') | |
| 446 ) | |
| 447 metfrag_html.write(str('MetFragScoreTypes=' + | |
| 448 re.sub(' .*', '', | |
| 449 re.sub('.*MetFragScoreTypes=', | |
| 450 '', | |
| 451 row[ | |
| 452 "MetFragCLIString"])) | |
| 453 + '<br>\n') | |
| 454 ) | |
| 455 # New compound in list | |
| 456 if (row["name"] != compound): | |
| 457 compound = row["name"] | |
| 458 candidates = 0 | |
| 459 identifier = row["name"] | |
| 460 monoisotopic_mass = row["MonoisotopicMass"] | |
| 461 precursor_mz = row["precursor_mz"] | |
| 462 | |
| 463 if "retention_time" in row: | |
| 464 precursor_rt = row["retention_time"] | |
| 465 try: | |
| 466 precursor_rt = round(float(precursor_rt), 4) | |
| 467 except ValueError: | |
| 468 continue | |
| 469 else: | |
| 470 precursor_rt = '' | |
| 471 | |
| 472 if "precursor_type" in row: | |
| 473 precursor_type = row["precursor_type"] | |
| 474 elif "adduct" in row: | |
| 475 precursor_type = row["adduct"] | |
| 476 else: | |
| 477 precursor_type = '' | |
| 478 | |
| 479 if line_count > 1: | |
| 480 metfrag_html.write(str('</table>\n')) | |
| 481 | |
| 482 metfrag_html.write(str('\n' + '<h2>' + identifier + '</h2>\n')) | |
| 483 metfrag_html.write(str('<p><b>Precursor Type:</b> ' + str( | |
| 484 precursor_type) + '<br>')) | |
| 485 metfrag_html.write(str('<b>Precursor Mass:</b> ' + str( | |
| 486 round(float(precursor_mz), 4)) + '<br>')) | |
| 487 metfrag_html.write( | |
| 488 str('<b>Precursor Retention Time:</b> ' + str( | |
| 489 precursor_mz) + '<br></p>')) | |
| 490 metfrag_html.write(str('\n' + '<table>\n')) | |
| 491 metfrag_html.write(str( | |
| 492 '<tr style="vertical-align:bottom; ' | |
| 493 'background-color:#e3efdf;">' | |
| 494 + '<td class="tdmax">' + '<b>Spectrum</b>' + '</td>' | |
| 495 + '<td class="tdmax">' + '<b>Structure</b>' + '</td>' | |
| 496 + '<td>' + '<b>Monoisotopic Mass</b>' + '</td>' | |
| 497 + '<td>' + '<b>Molecular Formula</b>' + '</td>' | |
| 498 + '<td>' + '<b>Compound Name</b>' + '</td>' | |
| 499 + '<td class="tdvar">' + '<b>PubChem Synonyms</b>'+'</td>' | |
| 500 + '<td>' + '<b>Compound Classes</b>' + '</td>' | |
| 501 + '<td>' + '<b>MetFrag Score</b>' + '</td>' | |
| 502 + '<td>' + '<b>MetFusion Score</b>' + '</td>' | |
| 503 + '<td>' + '<b>Fragmenter Score</b>' + '</td>' | |
| 504 + '<td>' + '<b>Suspectlist Score</b>' + '</td>' | |
| 505 + '<td>' + '<b>Explained Peaks</b>' + '</td>' | |
| 506 + '<td>' + '<b>MetFrag Web</b>' + '</td>' | |
| 507 + '<td>' + '<b>External Links</b>' + '</td>' | |
| 508 + '<td class="tdmax">' + '<b>InChI</b>' + '</td>' | |
| 509 + '</tr>\n')) | |
| 510 | |
| 511 # Compound candidate | |
| 512 if (candidates < max_candidates): | |
| 513 # Column variables | |
| 514 inchi = row["InChI"] | |
| 515 smiles = row["SMILES"] | |
| 516 mol_formula = row["MolecularFormula"] | |
| 517 compound_name = row["IUPACName"] | |
| 518 frag_score = row["FragmenterScore"] | |
| 519 metfusion_score = row["OfflineMetFusionScore"] | |
| 520 score = row["Score"] | |
| 521 if "SuspectListScore" in row: | |
| 522 suspectlist_score = row["SuspectListScore"] | |
| 523 else: | |
| 524 suspectlist_score = 0 | |
| 525 peaks_explained = row["NoExplPeaks"] | |
| 526 peaks_used = row["NumberPeaksUsed"] | |
| 527 spectrum_explained = row["ExplPeaks"] | |
| 528 spectrum_explained_formulas = row["FormulasOfExplPeaks"] | |
| 529 identifier = row["Identifier"] | |
| 530 | |
| 531 # PubChem Synonyms | |
| 532 if pubchem_synonyms_enabled: | |
| 533 pubchem_synonyms = fetch_pubchem_synonyms(inchi) | |
| 534 else: | |
| 535 pubchem_synonyms = ' ' | |
| 536 | |
| 537 # Compound Classes | |
| 538 if classyfire_classes_enabled: | |
| 539 compound_classes = fetch_classyfire_classes(inchi) | |
| 540 else: | |
| 541 compound_classes = ' ' | |
| 542 | |
| 543 # Draw Spectrum | |
| 544 spectrum = re.sub(' .*', '', re.sub('.*PeakListString=', '', | |
| 545 row["MetFragCLIString"])) | |
| 546 spectrum_string = plot_spectrum(spectrum, spectrum_explained, | |
| 547 spectrum_explained_formulas) | |
| 548 | |
| 549 # Draw SVG | |
| 550 svg_string = cdk_inchi_to_svg(str(inchi)) | |
| 551 | |
| 552 # External links | |
| 553 external_links = str( | |
| 554 '<a target="_blank" href="' + pubchem_link( | |
| 555 compound_name) + '">PubChem</a>' + ', ' + | |
| 556 '<a target="_blank" href="' + kegg_link( | |
| 557 compound_name) + '">KEGG</a>' + ', ' + | |
| 558 '<a target="_blank" href="' + hmdb_link( | |
| 559 compound_name) + '">HMDB</a>' + ', ' + | |
| 560 '<a target="_blank" href="' + biocyc_link( | |
| 561 compound_name) + '">BioCyc</a>' + ', ' + | |
| 562 '<a target="_blank" href="' + chebi_link( | |
| 563 inchi) + '">ChEBI</a>') | |
| 564 | |
| 565 # MetFragWeb | |
| 566 FragmentPeakMatchAbsoluteMassDeviation = str( | |
| 567 '' + | |
| 568 re.sub(' .*', '', | |
| 569 re.sub( | |
| 570 '.*FragmentPeakMatchAbsoluteMassDeviation=', | |
| 571 'FragmentPeakMatchAbsoluteMassDeviation=', | |
| 572 row["MetFragCLIString"])) | |
| 573 ) | |
| 574 FragmentPeakMatchRelativeMassDeviation = str( | |
| 575 '' + | |
| 576 re.sub(' .*', '', | |
| 577 re.sub( | |
| 578 '.*FragmentPeakMatchRelativeMassDeviation=', | |
| 579 'FragmentPeakMatchRelativeMassDeviation=', | |
| 580 row["MetFragCLIString"])) | |
| 581 ) | |
| 582 DatabaseSearchRelativeMassDeviation = str( | |
| 583 '' + | |
| 584 re.sub(' .*', '', | |
| 585 re.sub( | |
| 586 '.*DatabaseSearchRelativeMassDeviation=', | |
| 587 'DatabaseSearchRelativeMassDeviation=', | |
| 588 row["MetFragCLIString"])) | |
| 589 ) | |
| 590 IonizedPrecursorMass = str( | |
| 591 'IonizedPrecursorMass=' + str(row["precursor_mz"])) | |
| 592 NeutralPrecursorMass = str( | |
| 593 '' + re.sub(' .*', '', | |
| 594 re.sub( | |
| 595 '.*NeutralPrecursorMass=', | |
| 596 'NeutralPrecursorMass=', | |
| 597 row[ | |
| 598 "MetFragCLIString"])) | |
| 599 ) | |
| 600 NeutralPrecursorMolecularFormula = str( | |
| 601 'NeutralPrecursorMolecularFormula=' + str( | |
| 602 row["MolecularFormula"])) | |
| 603 PrecursorIonMode = str( | |
| 604 '' + re.sub(' .*', '', re.sub('.*PrecursorIonMode=', | |
| 605 'PrecursorIonMode=', | |
| 606 row["MetFragCLIString"]))) | |
| 607 PeakList = str( | |
| 608 '' + re.sub(' .*', '', | |
| 609 re.sub('.*PeakListString=', 'PeakList=', | |
| 610 row["MetFragCLIString"]))) | |
| 611 MetFragDatabaseType = str( | |
| 612 '' + re.sub(' .*', '', | |
| 613 re.sub( | |
| 614 '.*MetFragDatabaseType=', | |
| 615 'MetFragDatabaseType=', | |
| 616 row["MetFragCLIString"]))) | |
| 617 | |
| 618 metfrag_web = str( | |
| 619 'https://msbi.ipb-halle.de/MetFrag/landing.xhtml?' + | |
| 620 FragmentPeakMatchAbsoluteMassDeviation + '&' + | |
| 621 FragmentPeakMatchRelativeMassDeviation + '&' + | |
| 622 DatabaseSearchRelativeMassDeviation + '&' + | |
| 623 IonizedPrecursorMass + '&' + | |
| 624 NeutralPrecursorMass + '&' + | |
| 625 # NeutralPrecursorMolecularFormula + '&' + | |
| 626 PrecursorIonMode + '&' + | |
| 627 PeakList + '&' + | |
| 628 MetFragDatabaseType) | |
| 629 | |
| 630 # Write html code | |
| 631 metfrag_html.write(str('<tr style="vertical-align:center">' + | |
| 632 '<td class="tdmax">' + | |
| 633 spectrum_string + | |
| 634 '</td>' + | |
| 635 '<td class="tdmax">' + | |
| 636 svg_string + | |
| 637 '</td>' + | |
| 638 '<td>' + | |
| 639 monoisotopic_mass + | |
| 640 '</td>' + | |
| 641 '<td>' + | |
| 642 mol_formula + | |
| 643 '</td>' + | |
| 644 '<td>' + | |
| 645 compound_name + | |
| 646 '</td>' + | |
| 647 '<td class="tdvar">' + | |
| 648 pubchem_synonyms + | |
| 649 '</td>' + | |
| 650 '<td>' + | |
| 651 compound_classes + '</td>' + | |
| 652 '<td>' + | |
| 653 str(round(float(score), 3)) + | |
| 654 '</td>' + | |
| 655 '<td>' + | |
| 656 str(round(float(metfusion_score), 3)) + | |
| 657 '</td>' + | |
| 658 '<td>' + | |
| 659 str(round(float(frag_score), 3)) + | |
| 660 '</td>' + | |
| 661 '<td>' + | |
| 662 str( | |
| 663 round(float(suspectlist_score), 3) | |
| 664 ) + | |
| 665 '</td>' + | |
| 666 '<td>' + | |
| 667 peaks_explained + | |
| 668 ' / ' + | |
| 669 peaks_used + | |
| 670 '</td>' + | |
| 671 '<td>' + | |
| 672 '<a target="_blank" href="' + | |
| 673 metfrag_web + | |
| 674 '">MetFragWeb</a>' + | |
| 675 '</td>' + | |
| 676 '<td>' + | |
| 677 external_links + | |
| 678 '</td>' + | |
| 679 '<td class="tdmax">' + | |
| 680 inchi + | |
| 681 '</td>' + | |
| 682 '</tr>\n')) | |
| 683 | |
| 684 line_count += 1 | |
| 685 candidates += 1 | |
| 686 | |
| 687 # Finish candidate list | |
| 688 metfrag_html.write(str('</table>\n')) | |
| 689 | |
| 690 # Write html footer | |
| 691 metfrag_html.write('\n</body>\n') | |
| 692 metfrag_html.write('</html>\n') | |
| 693 | |
| 694 # Close output html file | |
| 695 metfrag_html.close() |
