Skip to content

Commit

Permalink
Merge pull request #136 from mwang87/mirror-json
Browse files Browse the repository at this point in the history
Adding new API for JSON Mirror function
  • Loading branch information
bittremieux authored Mar 4, 2021
2 parents 68ae8b8 + 5075822 commit 3a2e553
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 15 deletions.
28 changes: 14 additions & 14 deletions parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,44 +20,44 @@
# USI specification: http://www.psidev.info/usi
usi_pattern = re.compile(
# mzspec preamble
'^mzspec'
r'^mzspec'
# collection identifier
# Proteomics collection identifiers: PXDnnnnnn, MSVnnnnnnnnn, RPXDnnnnnn,
# PXLnnnnnn
# Unofficial: MASSIVEKB
# https://github.com/HUPO-PSI/usi/blob/master/CollectionIdentifiers.md
':(MSV\d{9}|PXD\d{6}|PXL\d{6}|RPXD\d{6})'
r':(MSV\d{9}|PXD\d{6}|PXL\d{6}|RPXD\d{6})'
# msRun identifier
':(.*)'
r':(.*)'
# index flag
':(scan|index|nativeId|trace)'
r':(scan|index|nativeId|trace)'
# index number
':(.+)'
r':(.+)'
# optional spectrum interpretation
'(:.+)?$',
r'(:.+)?$',
flags=re.IGNORECASE
)
# OR: Metabolomics USIs.
usi_pattern_draft = re.compile(
# mzdraft preamble
'^(?:mzspec|mzdraft)'
r'^(?:mzspec|mzdraft)'
# collection identifier
# Unofficial proteomics spectral library identifier: MASSIVEKB
# Metabolomics collection identifiers: GNPS, MASSBANK, MS2LDA, MOTIFDB
':(MASSIVEKB|GNPS|MASSBANK|MS2LDA|MOTIFDB)'
r':(MASSIVEKB|GNPS|MASSBANK|MS2LDA|MOTIFDB)'
# msRun identifier
':(.*)'
r':(.*)'
# index flag
':(scan|index|nativeId|trace|accession)'
r':(scan|index|nativeId|trace|accession)'
# index number
':(.+)'
r':(.+)'
# optional spectrum interpretation
'(:.+)?$',
r'(:.+)?$',
flags=re.IGNORECASE
)
gnps_task_pattern = re.compile('^TASK-([a-z0-9]{32})-(.+)$',
gnps_task_pattern = re.compile(r'^TASK-([a-z0-9]{32})-(.+)$',
flags=re.IGNORECASE)
ms2lda_task_pattern = re.compile('^TASK-(\d+)$', flags=re.IGNORECASE)
ms2lda_task_pattern = re.compile(r'^TASK-(\d+)$', flags=re.IGNORECASE)

splash_builder = splash.Splash()

Expand Down
2 changes: 1 addition & 1 deletion run_server.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash
source activate usi

gunicorn -w 2 -b 0.0.0.0:5000 --timeout 3600 main:app --access-logfile /app/logs/access.log --max-requests 1000
gunicorn -w 2 --threads=1 -b 0.0.0.0:5000 main:app --access-logfile /app/logs/access.log --timeout 30 --max-requests 100 --max-requests-jitter 20
7 changes: 7 additions & 0 deletions templates/mirror.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@
</div>
<div class="row mt-2">
<div class="col-2 offset-4">
<a class="btn btn-primary"
id="download_json"
href="/json/mirror/?usi1=(( usi1 ))&usi2=(( usi2 ))">
Download as JSON
</a>
</div>
<div class="col-2">
<a class="btn btn-primary"
id="download_svg"
href="/svg/mirror/?usi1=(( usi1 ))&usi2=(( usi2 ))"
Expand Down
7 changes: 7 additions & 0 deletions test/locustfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,10 @@ def generate_mirror_svg(self):
usi2 = random.choice(usis_to_test)
self.client.get(f'/svg/mirror/?usi1={usi1}&usi2={usi2}',
name='/svg/mirror/')

@locust.task
def generate_mirror_json(self):
usi1 = random.choice(usis_to_test)
usi2 = random.choice(usis_to_test)
self.client.get(f'/json/mirror/?usi1={usi1}&usi2={usi2}',
name='/json/mirror/')
24 changes: 24 additions & 0 deletions test/test_integration.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def _get_splash_remote(spectrum):
splash_response = requests.post(
'https://splash.fiehnlab.ucdavis.edu/splash/it',
data=json.dumps(payload), headers=headers)
if splash_response.status_code != 200:
pytest.skip('external SPLASH unavailable')
return splash_response.text


Expand Down Expand Up @@ -473,6 +475,28 @@ def test_peak_csv_invalid(client):
assert response.status_code == status_code, usi


def test_mirror_json(client):
for usi1, usi2 in pairwise(usis_to_test):
response = client.get('/json/mirror/',
query_string=f'usi1={usi1}&usi2={usi2}')
assert response.status_code == 200
response_dict = json.loads(response.data)
assert 'spectrum1' in response_dict
assert 'spectrum2' in response_dict
assert 'cosine' in response_dict
assert 'n_peak_matches' in response_dict
assert 'peak_matches' in response_dict
assert (response_dict['n_peak_matches']
== len(response_dict['peak_matches']))
for peak_match in response_dict['peak_matches']:
assert len(peak_match) == 2
for i, usi in enumerate((usi1, usi2), 1):
mz, intensity = zip(*response_dict[f'spectrum{i}']['peaks'])
assert (response_dict[f'spectrum{i}']['splash']
== _get_splash_remote(sus.MsmsSpectrum(usi, 0, 0, mz,
intensity)))


def test_generate_qr(client):
for usi in usis_to_test:
response = client.get('/qrcode/', query_string=f'usi={usi}')
Expand Down
2 changes: 2 additions & 0 deletions test/test_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ def _get_splash_remote(spectrum):
splash_response = requests.post(
'https://splash.fiehnlab.ucdavis.edu/splash/it',
data=json.dumps(payload), headers=headers)
if splash_response.status_code != 200:
pytest.skip('external SPLASH unavailable')
return splash_response.text


Expand Down
1 change: 1 addition & 0 deletions test/usi_test_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
# FIXME: RPXD not resolved by MassIVE.
# 'mzspec:RPXD006668:Adult_Frontalcortex_bRP_Elite_85_f09:scan:17555',
'mzspec:GNPS:TASK-c95481f0c53d42e78a61bf899e9f9adb-spectra/specs_ms.mgf:scan:1943',
'mzspec:GNPS:TASK-9c27c9cc037c443dbecafb07039a8528-spectra/specs_ms.mgf:scan:1',
'mzspec:GNPS:GNPS-LIBRARY:accession:CCMSLIB00005436077',
'mzspec:MASSBANK::accession:SM858102',
'mzspec:MS2LDA:TASK-190:accession:270684',
Expand Down
40 changes: 40 additions & 0 deletions views.py
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,46 @@ def peak_json():
return flask.jsonify(result_dict)


@blueprint.route('/json/mirror/')
def mirror_json():
try:
usi1 = flask.request.args.get('usi1')
usi2 = flask.request.args.get('usi2')

plotting_args = _get_plotting_args(flask.request.args, mirror=True)
spectrum1, source1, splash_key1 = parsing.parse_usi(usi1)
spectrum2, source2, splash_key2 = parsing.parse_usi(usi2)
_spectrum1, _spectrum2 = _prepare_mirror_spectra(spectrum1, spectrum2,
plotting_args)
similarity, peak_matches = _cosine(
_spectrum1, _spectrum2, plotting_args['fragment_mz_tolerance'],
plotting_args['cosine'] == 'shifted')

spectrum1_dict = {
'peaks': _get_peaks(spectrum1),
'n_peaks': len(spectrum1.mz),
'precursor_mz': spectrum1.precursor_mz,
'splash': splash_key1
}
spectrum2_dict = {
'peaks': _get_peaks(spectrum2),
'n_peaks': len(spectrum2.mz),
'precursor_mz': spectrum2.precursor_mz,
'splash': splash_key2
}
result_dict = {'spectrum1': spectrum1_dict,
'spectrum2': spectrum2_dict,
'cosine': similarity,
'n_peak_matches': len(peak_matches),
'peak_matches': peak_matches}

except UsiError as e:
result_dict = {'error': {'code': e.error_code, 'message': str(e)}}
except ValueError as e:
result_dict = {'error': {'code': 404, 'message': str(e)}}
return flask.jsonify(result_dict)


@blueprint.route('/proxi/v0.1/spectra')
def peak_proxi_json():
try:
Expand Down

0 comments on commit 3a2e553

Please sign in to comment.