diff --git a/mdb/spectra/migrations/0007_auto_20210609_2238.py b/mdb/spectra/migrations/0007_auto_20210609_2238.py new file mode 100644 index 0000000..3e42846 --- /dev/null +++ b/mdb/spectra/migrations/0007_auto_20210609_2238.py @@ -0,0 +1,29 @@ +# Generated by Django 3.1 on 2021-06-09 22:38 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('spectra', '0006_auto_20210517_0456'), + ] + + operations = [ + migrations.CreateModel( + name='BinnedPeaks', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('peak_mass', models.TextField(blank=True)), + ('peak_intensity', models.TextField(blank=True)), + ('peak_snr', models.TextField(blank=True)), + ('spectra', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='spectra.collapsedspectra')), + ], + ), + migrations.AddField( + model_name='collapsedcosinescore', + name='binned_peaks', + field=models.ManyToManyField(to='spectra.BinnedPeaks'), + ), + ] diff --git a/mdb/spectra/models.py b/mdb/spectra/models.py index de4a916..f1ce8b4 100644 --- a/mdb/spectra/models.py +++ b/mdb/spectra/models.py @@ -234,8 +234,23 @@ class AbstractCosineScore(models.Model): class Meta: abstract = True +class BinnedPeaks(models.Model): + ''' + Binned peaks version of a spectra when matched against set of spectra. + ''' + peak_mass = models.TextField(blank = True) + peak_intensity = models.TextField(blank = True) + peak_snr = models.TextField(blank = True) + spectra = models.ForeignKey( + 'CollapsedSpectra', + # ~ related_name = 'spectra', + on_delete = models.CASCADE) + # ~ class CollapsedCosineScore(AbstractCosineScore): class CollapsedCosineScore(models.Model): + ''' + Todo: Needs to save binned peaks representation of spectra + ''' spectra = models.ForeignKey( 'CollapsedSpectra', # ~ related_name = 'spectra', @@ -245,6 +260,7 @@ class CollapsedCosineScore(models.Model): on_delete = models.CASCADE) scores = models.TextField() spectra_ids = models.TextField() + binned_peaks = models.ManyToManyField('BinnedPeaks') # ~ class CollapsedCosineScore(AbstractCosineScore): # ~ spectra1 = models.ForeignKey( diff --git a/mdb/spectra_search/views.py b/mdb/spectra_search/views.py index e785168..8c9d816 100644 --- a/mdb/spectra_search/views.py +++ b/mdb/spectra_search/views.py @@ -133,10 +133,10 @@ def process_file(request, file, form, owner): ) # TODO - # if multiple spectra, await user response - # if single spectra, continue + # If multiple spectra, await user response + # If single spectra, continue - # if more than one protein spectra, then collapse + # Collapse if there is a protein spectra if info['spectra']['protein'] > 0: ##### > 1 data = { 'id': form.cleaned_data['library'].id, @@ -146,33 +146,36 @@ def process_file(request, file, form, owner): 'http://plumber:8000/collapseLibrary', params = data ) - # In the case of a collapsed spectra which had mass > 6000 but - # when collapsed lost those peaks, it is necessary to - # retrieve the CollapsedSpectra using the spectra_content - # attribute. - n1 = CollapsedSpectra.objects.filter( # unknown spectra - library_id__exact = form.cleaned_data['library'].id, - spectra_content__exact = 'PR' - #max_mass__gt = 6000 - ).first() - n2 = CollapsedSpectra.objects.filter( - library__exact = form.cleaned_data['search_library'].id, - max_mass__gt = 6000 - ).values('id') - data = { - 'ids': [n1.id] + [s['id'] for s in list(n2)] - } - r = requests.post( - 'http://plumber:8000/cosine', - params = data - ) + # In the case of a collapsed spectra which had mass > 6000 but + # when collapsed lost those peaks, it is necessary to + # retrieve the CollapsedSpectra using the spectra_content + # attribute. + n1 = CollapsedSpectra.objects.filter( # unknown spectra + library_id__exact = form.cleaned_data['library'].id, + spectra_content__exact = 'PR' + ).first() + n2 = CollapsedSpectra.objects.filter( + library__exact = form.cleaned_data['search_library'].id, + spectra_content__exact = 'PR' + #max_mass__gt = 6000 + ).values('id') + data = { + 'ids': [n1.id] + [s['id'] for s in list(n2)] + } + r = requests.post( + 'http://plumber:8000/cosine', + params = data + ) + + print('bp', r.json()['binnedPeaks'][1][0]) + # ~ # test # ~ from spectra.models import * # ~ import requests # ~ n2 = CollapsedSpectra.objects.filter( - # ~ library__title__exact = 'R01 Data', - # ~ max_mass__gt = 6000 +# ~ library__title__exact = 'R01 Data', +# ~ max_mass__gt = 6000 # ~ ).values('id') # ~ data = {'ids': [2] + [s['id'] for s in list(n2)]} # ~ r = requests.post('http://plumber:8000/cosine', params = data) @@ -181,57 +184,60 @@ def process_file(request, file, form, owner): # ~ k = [str(s['id']) for s in list(n2)] # one less # ~ v = r.json()[1:] # one more, remove first # ~ o = OrderedDict( - # ~ sorted(dict(zip(k, v)).items(), - # ~ key = lambda x: (x[1], x[0]), reverse = True) +# ~ sorted(dict(zip(k, v)).items(), + # ~ key = lambda x: (x[1], x[0]), reverse = True) # ~ ) - # create a dictionary and sort by its values - from collections import OrderedDict - k = [str(s['id']) for s in list(n2)] # one less - v = r.json()[1:] # one more, remove first - o = OrderedDict( - sorted(dict(zip(k, v)).items(), - key = lambda x: (x[1], x[0]), reverse = True) - ) + # create a dictionary and sort by its values + from collections import OrderedDict + k = [str(s['id']) for s in list(n2)] # one less + v = r.json()['similarity'][1:] # one more remove first??? + o = OrderedDict( + sorted(dict(zip(k, v)).items(), + key = lambda x: (x[1], x[0]), reverse = True) + ) - obj = CollapsedCosineScore.objects.create( - spectra = n1, - library = form.cleaned_data['library'], # lib unnecessary in ccs model - scores = ','.join(map(str, list(o.values()))), - spectra_ids = ','.join(map(str, o.keys()))) - - if obj: - l = { - 'result': [], - 'original': { - 'peak_mass': n1.peak_mass, - 'peak_intensity': n1.peak_intensity, - } + obj = CollapsedCosineScore.objects.create( + spectra = n1, + library = form.cleaned_data['library'], # lib unnecessary in ccs model + scores = ','.join(map(str, list(o.values()))), + spectra_ids = ','.join(map(str, o.keys()))) + + if obj: + l = { + 'result': [], + 'original': { + 'peak_mass': n1.peak_mass, + 'peak_intensity': n1.peak_intensity, } - - from django.db.models import Case, When - preserved = Case(*[When(pk = pk, then = pos) for pos, pk in enumerate(o)]) - q = CollapsedSpectra.objects.filter(id__in = o.keys()).order_by(preserved) - rowcount = 1 - for cs in q: - l['result'].append({ - 'score': o[str(cs.id)], - 'strain': cs.strain_id.strain_id, - 'kingdom': cs.strain_id.cKingdom, - 'phylum': cs.strain_id.cPhylum, - 'class': cs.strain_id.cClass, - 'order': cs.strain_id.cOrder, - # ~ 'family': cs.strain_id.cFamily, - 'genus': cs.strain_id.cGenus, - 'species': cs.strain_id.cSpecies, - 'rowcount': rowcount, - 'peak_mass': cs.peak_mass, - 'peak_intensity': cs.peak_intensity, - }) - rowcount += 1 - ws.send(json.dumps(l)) - else: - pass + } + + # Add binned peaks representation for each spectra + + + from django.db.models import Case, When + preserved = Case(*[When(pk = pk, then = pos) for pos, pk in enumerate(o)]) + q = CollapsedSpectra.objects.filter(id__in = o.keys()).order_by(preserved) + rowcount = 1 + for cs in q: + l['result'].append({ + 'score': o[str(cs.id)], + 'strain': cs.strain_id.strain_id, + 'kingdom': cs.strain_id.cKingdom, + 'phylum': cs.strain_id.cPhylum, + 'class': cs.strain_id.cClass, + 'order': cs.strain_id.cOrder, + # ~ 'family': cs.strain_id.cFamily, + 'genus': cs.strain_id.cGenus, + 'species': cs.strain_id.cSpecies, + 'rowcount': rowcount, + 'peak_mass': cs.peak_mass, + 'peak_intensity': cs.peak_intensity, + }) + rowcount += 1 + ws.send(json.dumps(l)) + # ~ else: + # ~ pass # ~ r = requests.post( # ~ 'http://plumber:8000/cosine', # ~ params = data diff --git a/rplumber/plumber.R b/rplumber/plumber.R index cdcd8e7..3a5ff5d 100644 --- a/rplumber/plumber.R +++ b/rplumber/plumber.R @@ -64,11 +64,12 @@ print.data.frame <- function ( #* Todo: library=, lab=, strain=, user=, ... #* @param req Built-in #* @param ids List of IDs from Spectra table -#* @return Returns first row from cosine similarity matrix +#* @return -----------Returns first row from cosine similarity matrix +#* @return Returns first cos. similarity matrix row, and binnedPeaks #* @post /cosine function(req, ids) { ids <- as.numeric(ids) - if (length(ids) < 2) {#---- + if (length(ids) < 2) { stop('less than two comparison ids given!') } @@ -81,11 +82,16 @@ function(req, ids) { binnedPeaks <- MALDIquant::binPeaks(allPeaks, tolerance = 0.002) featureMatrix <- MALDIquant::intensityMatrix(binnedPeaks, allSpectra) # manual inspection... + print(toString(head(binnedPeaks, 2))) +#~ print(toString(binnedPeaks)) #print(toString(featureMatrix[1,])) #print(toString(featureMatrix[2,])) #print(coop::cosine(featureMatrix[1,], featureMatrix[2,])) d <- coop::cosine(t(featureMatrix)) d <- round(d, 3) + + return(list('similarity' = d[1,], 'binnedPeaks' = capture.output(binnedPeaks))) + return(d[1,]) emptyProtein <- unlist( @@ -114,6 +120,8 @@ function(req, ids) { d <- as.matrix(d) d <- round(d, 3) d <- d[1,] + + return(d) ## not used @@ -238,7 +246,7 @@ function(req, ids) { #~ jsonlite::toJSON(a) } -# Helper function to retrive list of IDs from Django's DB +# Helper function to retrieve list of IDs from Django's DB dbSpectra <- function(ids) { #~ if (class(ids) != 'integer') { #~ stop('dbSpectra: not integer!') # stop throws 500 @@ -249,9 +257,6 @@ dbSpectra <- function(ids) { c <- connect() s <- paste(unlist(ids), collapse = ',') -#~ s <- paste0('SELECT peak_mass, peak_intensity, peak_snr -#~ FROM spectra_spectra -#~ WHERE id IN (', s, ')') s <- paste0('SELECT peak_mass, peak_intensity, peak_snr, id FROM spectra_collapsedspectra WHERE id IN (', s, ')') @@ -375,9 +380,7 @@ collapseStrainsInLibrary <- function(lid, sid, type, owner) { t <- MALDIquant::filterPeaks(t, minFrequency = 70 / 100) t <- MALDIquant::mergeMassPeaks(t, method = 'mean') - # save to Django's DB - # --curl - # "Content-Type: application/json" + # Save to Django's DB h <- new_handle() x <- paste0( '{',