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() |