Attached is a sneak preview of a new popup for Analysis which handles
titrations to some degree. There is a little more work to do before it
appears in the program proper, but it currently has most of the
functionality.
You will need to set up your experiments in a similar manner to the rates
analysis, i.e. set up an experiment series with the values for each
condition for each experiment. This is important because it finds peak
groups (partly) by finding peaks that best fit the shift distance to
condition value function. Also, make sure that the reference peak list is
an assigned one and that any peak list assignments do not cross different
mol systems.
In this system you can compare as many experiments as you like and missing
peaks are not generally a problem. There is also a simple function to
export the individual shift values for each residue/spinSystem at each
condition point as a text file, given the absence of fancy analyses in
Analysis.
T.
> I just wondered what is the best way to export chemical shift titration data
> for subsequent analysis elsewhere i.e Open Office?
>
> Currently, I am using the Shift Differences pop up to export my titration
> data for use in a spreadsheet. As far as I can tell it can only consider one
> titration point (one spectrum) at a time (Peak List A as reference and Peak
> List B as the data) so I have to export each titration point seperately.
>
> Is it possible to add more peak lists here (Peak List C, D etc) so that I
> can export my entire titration data in one go and in one .csv file? Or is
> there already a way to do this that I have overlooked?
>
>
> Cheers
>
> Ben
>
> ps Also, exporting them this way I run into a problem if a peak is missing
> from one of the peaks as in the export data that line is missing so the rows
> in my collated table dont line up. Is there anyway of having the option that
> when a peak is missing from either Peak List A or B that that line gets
> included but with no values for it?
-------------------------------------------------------------------------------
Dr Tim Stevens Email: [log in to unmask]
Department of Biochemistry [log in to unmask]
University of Cambridge Phone: +44 1223 766018 (office)
80 Tennis Court Road +44 7816 338275 (mobile)
Old Addenbrooke's Site +44 1223 364613 (home)
Cambridge CB2 1GA WWWeb: http://www.bio.cam.ac.uk/~tjs23
United Kingdom http://www.pantonia.co.uk
-------------------------------------------------------------------------------
------ +NH3CH(CH(CH3)OH)C(O)NHCH(CH(CH3)CH2CH3)C(O)NHCH(CH2CH2SCH3)CO2- -------
-------------------------------------------------------------------------------
"""
======================COPYRIGHT/LICENSE START==========================
FollowTitrationPopup.py: Part of the CcpNmr Analysis program
Copyright (C) 2005 Wayne Boucher and Tim Stevens (University of Cambridge)
=======================================================================
This file contains reserved and/or proprietary information
belonging to the author and/or organisation holding the copyright.
It may not be used, distributed, modified, transmitted, stored,
or in any way accessed, except by members or employees of the CCPN,
and by these people only until 31 December 2005 and in accordance with
the guidelines of the CCPN.
A copy of this license can be found in ../../../license/CCPN.license.
======================COPYRIGHT/LICENSE END============================
for further information, please contact :
- CCPN website (http://www.ccpn.ac.uk/)
- email: [log in to unmask]
- contact the authors: [log in to unmask], [log in to unmask]
=======================================================================
If you are using this software for academic purposes, we suggest
quoting the following references:
===========================REFERENCE START=============================
R. Fogh, J. Ionides, E. Ulrich, W. Boucher, W. Vranken, J.P. Linge, M.
Habeck, W. Rieping, T.N. Bhat, J. Westbrook, K. Henrick, G. Gilliland,
H. Berman, J. Thornton, M. Nilges, J. Markley and E. Laue (2002). The
CCPN project: An interim report on a data model for the NMR community
(Progress report). Nature Struct. Biol. 9, 416-418.
Wim F. Vranken, Wayne Boucher, Tim J. Stevens, Rasmus
H. Fogh, Anne Pajon, Miguel Llinas, Eldon L. Ulrich, John L. Markley, John
Ionides and Ernest D. Laue (2005). The CCPN Data Model for NMR Spectroscopy:
Development of a Software Pipeline. Proteins 59, 687 - 696.
===========================REFERENCE END===============================
"""
from math import sqrt
from ccpnmr.analysis.EditFitGraphPopup import EditFitGraphPopup
from ccpnmr.analysis.BasePopup import BasePopup
from memops.gui.ButtonList import ButtonList
from memops.gui.CheckButton import CheckButton
from memops.gui.Entry import Entry
from memops.gui.FloatEntry import FloatEntry
from memops.gui.Frame import Frame
from memops.gui.Label import Label
from memops.gui.LabelFrame import LabelFrame
from memops.gui.ProgressBar import ProgressBar
from memops.gui.PulldownMenu import PulldownMenu
from memops.gui.ScrolledMatrix import ScrolledMatrix
from memops.gui.MessageReporter import showWarning, showYesNo
from memops.editor.Util import createDismissHelpButtonList
from ccpnmr.analysis.AssignmentBasic import propagatePeakAssignments
from ccpnmr.analysis.DataAnalysisBasic import functionFitData, getNmrExpSeriesSampleConditions, makeDataList
from ccpnmr.analysis.ExperimentBasic import newShiftList, getSpectrumIsotopes
from ccpnmr.analysis.PeakBasic import findSameAssignmentPeaks, findClosePeaks, arePeaksAssignedSame
from ccpnmr.analysis.Util import getUseBootstrap, setUseBootstrap, getSpectrumActivePeakList
from ccpnmr.analysis.WindowBasic import getDataDimAxisMapping
maxStepSizes = {'1H':0.05,'15N':0.50,'13C':0.50,'13C,15N':0.50}
isotopeWeights = {'1H':1.00,'15N':0.15,'13C':0.10,'13C,15N':0.10}
# TBD
# Generic parameter bounds
# Fix/remove gradient
# Cope with dissappearing peaks
# Macro to export shift deltas per concentration
def FollowTitrationMacro(argServer):
popup = FollowShiftChangesPopup(argServer.parent)
popup.open()
def exportSeriesShifts(experimentSeries):
from ccpnmr.analysis.AssignmentBasic import getResonanceResidue, makeResonanceGuiName
shiftData = {}
sampleConditions = {}
conditionName = experimentSeries.conditionNames[0]
for experiment in experimentSeries.experiments:
sampleConditionSet = experiment.sampleConditionSet
if not sampleConditionSet:
continue
sampleCondition = sampleConditionSet.findFirstSampleCondition(condition=conditionName)
if not sampleCondition:
continue
sampleConditions[sampleCondition] = True
for spectrum in experiment.dataSources:
numDim = spectrum.numDim
peakList = getSpectrumActivePeakList(spectrum)
for peak in peakList.peaks:
key = None
for peakDim in peak.peakDims:
for contrib in peakDim.peakDimContribs:
resonance = contrib.resonance
if resonance.resonanceGroup:
key = resonance.resonanceGroup
break
if key is not None:
if shiftData.get(key) is None:
shiftData[key] = {}
shiftData[key][sampleCondition] = ['%.3f' % peakDim.value for peakDim in peak.peakDims]
conditions = [(sc.value, sc) for sc in sampleConditions.keys()]
conditions.sort()
sampleConditions = [x[1] for x in conditions]
keys = []
for ss in shiftData.keys():
if ss.residue:
keys.append(['%5.5d' % ss.residue.seqCode, ss])
else:
keys.append(['{%5.5d' % ss.serial, ss])
keys.sort()
lines = []
line = '!' + ' ' * 11
for value, sc in conditions:
line += '%14.14s' % ('%.3f' % value)
lines.append(line)
for name, ss in keys:
seqCode = '-'
ccpCode = '-'
sysCode = '%d' % ss.serial
residue = ss.residue
if residue:
seqCode = '%d' % residue.seqCode
ccpCode = residue.ccpCode
ppms = []
for condition in sampleConditions:
values = shiftData[ss].get(condition)
if values is None:
ppms.append(' '.join(['%6.6s' % '-' for v in range(numDim)]))
else:
ppms.append(' '.join(['%6.6s' % v for v in values]))
line = ''
for text in (sysCode, seqCode, ccpCode):
line += '%4.4s' % text
for ppm in ppms:
line += ' '
line += ppm
lines.append(line)
return lines
class FollowShiftChangesPopup(BasePopup):
def __init__(self, parent, *args, **kw):
self.waiting = False
self.guiParent = parent
self.fitFunc = 1
self.peakList = None
self.doAssignGroups = True
self.fitGraphPopup = None
self.expSeries = None
self.peakGroup = None
self.peakGroups = []
self.dataList = None
self.groupDict = {}
self.noise = 0.0
self.dataDims = []
BasePopup.__init__(self, parent=parent, title='Follow Shift Changes', **kw)
self.updateAfter()
def body(self, guiFrame):
guiFrame.grid_columnconfigure(0, weight=1)
row = 0
frame = LabelFrame(guiFrame, text='Setup Experiments')
frame.grid(row=row,column=0, sticky='nsew')
frame.grid_columnconfigure(3, weight=1)
label = Label(frame, text='Ref Peak List:')
label.grid(row=0, column=0,sticky='nw')
self.peakListPulldown = PulldownMenu(frame, self.changePeakList, selected_index=-1)
self.peakListPulldown.grid(row=0, column=1, sticky='nw')
label = Label(frame, text='Expt Series:')
label.grid(row=0, column=2,sticky='nw')
self.expSeriesPulldown = PulldownMenu(frame, self.changeExpSeries, selected_index=-1)
self.expSeriesPulldown.grid(row=0, column=3, sticky='nw')
label = Label(frame, text='Fit Function:')
label.grid(row=1, column=0,sticky='nw')
self.fitFuncPulldown = PulldownMenu(frame, self.changeFitFunc, selected_index=-1)
self.fitFuncPulldown.grid(row=1, column=1, sticky='nw')
label = Label(frame, text='Follow Dims:')
label.grid(row=1, column=2,sticky='nw')
self.dataDimsPulldown = PulldownMenu(frame, self.changeDataDim, selected_index=0)
self.dataDimsPulldown.grid(row=1, column=3, sticky='nw')
label = Label(frame, text='Data List Type:')
label.grid(row=2, column=0,sticky='nw')
self.dataListTypeLabel = Label(frame, text='')
self.dataListTypeLabel.grid(row=2, column=1, sticky='nw')
label = Label(frame, text='Assign groups?')
label.grid(row=2, column=2,sticky='nw')
self.assignSelect = CheckButton(frame)
self.assignSelect.grid(row=2, column=3, sticky='nw')
self.assignSelect.set(1)
label = Label(frame, text='Data List Unit:')
label.grid(row=3, column=0,sticky='nw')
self.dataListUnitLabel = Label(frame, text='')
self.dataListUnitLabel.grid(row=3, column=1, sticky='nw')
label = Label(frame, text='Bootstrap Errors?')
label.grid(row=3, column=2,sticky='nw')
project = self.guiParent.getProject()
self.useBootstrap = getUseBootstrap(project)
self.bootstrapSelect = CheckButton(frame, selected=True)
self.bootstrapSelect.grid(row=3, column=3, sticky='nw')
label = Label(frame, text='Shift Error (points):')
label.grid(row=4, column=0,sticky='nw')
self.shiftErrorEntry = FloatEntry(frame, text=4.0, width=8)
self.shiftErrorEntry.grid(row=4, column=1, sticky='nw')
label = Label(frame, text='Min F2/F1 Grad:')
label.grid(row=4, column=2,sticky='nw')
self.minGradientEntry = FloatEntry(frame, text=None, width=8)
self.minGradientEntry.grid(row=4, column=3, sticky='nw')
label = Label(frame, text='Max F2/F1 Grad:')
label.grid(row=5, column=2,sticky='nw')
self.maxGradientEntry = FloatEntry(frame, text=None, width=8)
self.maxGradientEntry.grid(row=5, column=3, sticky='nw')
row +=1
frame = LabelFrame(guiFrame, text='Isotope Parameters')
frame.grid(row=row,column=0, sticky='nsew')
frame.grid_columnconfigure(6, weight=1)
frame.grid_rowconfigure(1, weight=1)
label = Label(frame, text='Shift Weighting: ')
label.grid(row=0, column=0, sticky='w')
label = Label(frame, text='1H')
label.grid(row=0, column=1, sticky='w')
self.tolHydrogenEntry = FloatEntry(frame, text=isotopeWeights['1H'], width=8)
self.tolHydrogenEntry.grid(row=0, column=2, sticky='w')
label = Label(frame, text='15N')
label.grid(row=0, column=3, sticky='w')
self.tolNitrogenEntry = FloatEntry(frame, text=isotopeWeights['15N'], width=8)
self.tolNitrogenEntry.grid(row=0, column=4, sticky='w')
label = Label(frame, text='13C')
label.grid(row=0, column=5, sticky='w')
self.tolCarbonEntry = FloatEntry(frame, text=isotopeWeights['13C'], width=8)
self.tolCarbonEntry.grid(row=0, column=6, sticky='w')
label = Label(frame, text='Max Step Size: ')
label.grid(row=1, column=0, sticky='w')
label = Label(frame, text='1H')
label.grid(row=1, column=1, sticky='w')
self.stepHydrogenEntry = FloatEntry(frame, text=maxStepSizes['1H'], width=8)
self.stepHydrogenEntry.grid(row=1, column=2, sticky='w')
label = Label(frame, text='15N')
label.grid(row=1, column=3, sticky='w')
self.stepNitrogenEntry = FloatEntry(frame, text=maxStepSizes['15N'], width=8)
self.stepNitrogenEntry.grid(row=1, column=4, sticky='w')
label = Label(frame, text='13C')
label.grid(row=1, column=5, sticky='w')
self.stepCarbonEntry = FloatEntry(frame, text=maxStepSizes['13C'], width=8)
self.stepCarbonEntry.grid(row=1, column=6, sticky='w')
row +=1
texts = ['Group Peaks','Fit All Groups','Edit Exp.Series','Export Shifts']
commands = [self.groupPeaks,self.calculateAllFits,self.editExpSeries, self.exportShifts]
buttonList = ButtonList(guiFrame, expands=True, commands=commands, texts=texts)
buttonList.grid(row=row, column=0, sticky='ew')
row +=1
guiFrame.grid_rowconfigure(row, weight=1)
frame = LabelFrame(guiFrame, text='Peak Groups')
frame.grid(row=row,column=0, sticky='nsew')
frame.grid_columnconfigure(0, weight=1)
frame.grid_rowconfigure(0, weight=1)
headingList = self.getHeadingList(2)
self.scrolledMatrix = ScrolledMatrix(frame, headingList=headingList, callback=self.selectGroup,
multiSelect=True, deleteFunc=self.removeGroup)
self.scrolledMatrix.grid(row=0, column=0, sticky='nsew')
row +=1
texts = ['Remove\nGroups','Fit\nSelected','Show Fit\nGraph','Show\nPeaks']
commands = [self.removeGroup,self.calculateFit,self.showFunctionFit,self.showPeaks]
#texts = ['Remove\nGroups','Fit\nSelected','Show Fit\nGraph','Show\nPeaks','Make Data\nList']
#commands = [self.removeGroup,self.calculateFit,self.showFunctionFit,self.showPeaks,self.makeDataList]
bottomButtons = createDismissHelpButtonList(guiFrame, expands=True, commands=commands, texts=texts)
bottomButtons.grid(row=row, column=0, sticky='ew')
for func in ('__init__','delete','setName'):
self.registerNotify(self.updatePeakLists, 'ccp.Nmr.Experiment', func)
self.registerNotify(self.updatePeakLists, 'ccp.Nmr.DataSource', func)
for func in ('__init__','delete'):
self.registerNotify(self.updatePeakLists, 'ccp.Nmr.PeakList', func)
self.registerNotify(self.updatePeaks, 'ccp.Nmr.Peak', 'delete')
for func in ('__init__','delete','setVariableUnit','setVariableDescriptor','setVariableName','setName'):
self.registerNotify(self.updateExpSeries, 'ccp.Nmr.NmrExpSeries', func)
# Specify which Isotopes to follow shifts for
self.updateExpSeries()
self.updatePeakLists()
self.updateDataDims()
self.updateFitFuncs()
self.updateAfter()
def open(self):
self.updateExpSeries()
self.updatePeakLists()
self.updateDataDims()
self.updateFitFuncs()
self.updateAfter()
BasePopup.open(self)
def close(self):
BasePopup.close(self)
def exportShifts(self):
from memops.gui.FileSelect import FileType
from memops.gui.FileSelectPopup import FileSelectPopup
if self.expSeries:
lines = exportSeriesShifts(self.expSeries)
if lines:
fileTypes = [ FileType('All', ['*'])]
fileSelectPopup = FileSelectPopup(self, file_types = fileTypes,
title = 'Export Series Shifts', dismiss_text = 'Cancel',
selected_file_must_exist = False)
fileName = fileSelectPopup.getFile()
if fileName:
file = open(fileName, 'w')
for line in lines:
file.write(line)
file.write('\n')
file.close()
def calculateAllFits(self):
self.updateIsotopeWeights()
self.updateMaxStepSizes()
if self.peakGroups and self.expSeries:
if not self.fitFunc:
showWarning('Warining','No fitting function selected')
return
progressBar = ProgressBar(self, text="Calculating Fit ",total = len(self.peakGroups))
for group in self.peakGroups:
self.fitPeakGroup(group, self.fitFunc)
progressBar.increment()
progressBar.destroy()
self.updateAfter()
def calculateFit(self):
self.updateIsotopeWeights()
self.updateMaxStepSizes()
if self.peakGroups and self.expSeries:
if not self.fitFunc:
showWarning('Warining','No fitting function selected')
return
progressBar = ProgressBar(self, text="Calculating Fit ",total = len(self.peakGroups))
for group in self.scrolledMatrix.currentObjects:
self.fitPeakGroup(group, self.fitFunc)
progressBar.increment()
progressBar.destroy()
self.updateAfter()
def fitPeakGroup(self, group, func=None):
peak, dist, constant, error, fitError, numPeaks, method, peaks = group
if func is None:
func = method
if (len(peaks) < 2) or ((func > 1) and (len(peaks) < 3)):
group[1] = None
group[2] = None
group[3] = None
group[4] = None
return
xData,yData,xWidths,yWidths = self.getPeakSeriesData(peaks)
try:
data = functionFitData(func, xData, yData,xWidths,yWidths, noiseLevel=self.noise, useBootstrap=self.useBootstrap)
except:
group[1] = None
group[2] = None
group[3] = None
group[4] = None
return
constant,error,fitError,params,paramErrs,yFit = data
group[1] = yData[-1]
group[2] = constant
group[3] = error
group[4] = fitError
group[6] = func
def updateIsotopeWeights(self):
isotopeWeights['1H'] = self.tolHydrogenEntry.get() or 1.0
isotopeWeights['15N'] = self.tolNitrogenEntry.get() or 0.15
isotopeWeights['13C'] = self.tolCarbonEntry.get() or 0.1
isotopeWeights['13C,15N'] = isotopeWeights['13C']
isotopeWeights['15N,13C'] = isotopeWeights['13C']
def updateMaxStepSizes(self):
maxStepSizes['1H'] = self.stepHydrogenEntry.get() or 1.0
maxStepSizes['15N'] = self.stepNitrogenEntry.get() or 0.15
maxStepSizes['13C'] = self.stepCarbonEntry.get() or 0.1
maxStepSizes['13C,15N'] = maxStepSizes['13C']
maxStepSizes['15N,13C'] = maxStepSizes['13C']
def getPeakSeriesData(self, peaks):
pointError = self.shiftErrorEntry.get() or 0.0
xData = []
yData = []
xWidths = [] # From expt series
yWidths = [] # Based upon the digital resolution at the moment
if self.peakList and self.dataDims and self.expSeries:
yData = [0.0,]
dimNums = [dataDim.dim for dataDim in self.dataDims]
sampleConditions = self.getSampleConditions()
experimentDict = {}
for sampleCondition in sampleConditions:
for experiment in sampleCondition.sampleConditionSet.experiments:
experimentDict[experiment] = sampleCondition
locations = []
for peak in peaks:
experiment = peak.peakList.dataSource.experiment
sampleCondition = experimentDict.get(experiment)
if sampleCondition:
xData.append(sampleCondition.value)
xWidths.append(sampleCondition.error)
else:
xData.append(0.0)
xWidths.append(0.0)
location = []
yWidth = 0.0
for peakDim in peak.peakDims:
dataDimRef = peakDim.dataDimRef
i = peakDim.dim
if i in dimNums:
isotope = ','.join(dataDimRef.expDimRef.isotopeCodes)
weight = isotopeWeights.get(isotope, 1.0)
error = weight * dataDimRef.valuePerPoint * pointError
yWidth += error * error
location.append((peakDim.value, weight))
yWidths.append(sqrt(yWidth))
locations.append(location)
for i in range(1,len(locations)):
location1 = locations[i]
location0 = locations[i-1]
shiftDist = 0.0
for j in range(len(location1)):
value1, weight1 = location1[j]
value0, weight0 = location0[j]
diff = (value1 - value0) * weight1
shiftDist += diff * diff
yData.append( yData[-1] + sqrt(shiftDist) )
return xData, yData, xWidths, yWidths
def getSampleConditions(self):
sampleConditions = []
if self.expSeries:
conditionName = self.expSeries.conditionNames[0]
sampleConditions = getNmrExpSeriesSampleConditions(self.expSeries).get(conditionName, [])
return sampleConditions
def groupPeaks(self):
self.updateMaxStepSizes()
self.minGrad = self.minGradientEntry.get()
self.maxGrad = self.maxGradientEntry.get()
# Score using regularity of spacing - optional switch?
pointError = self.shiftErrorEntry.get() or 0.0
def getAlignScore(peaks):
xData,yData,xWidths,yWidths = self.getPeakSeriesData(peaks)
data = functionFitData(self.fitFunc, xData, yData,xWidths,yWidths, noiseLevel=self.noise, useBootstrap=self.useBootstrap)
constant,error,fitError,params,paramErrs,yFit = data
locations = []
for peak0 in peaks:
location = [peakDim.value for peakDim in peak0.peakDims]
locations.append(location)
N = len(locations)-2
if N > 0:
M = len(locations[0])
meanCos = 0.0
for i in range(N):
vector1 = []
vector2 = []
sumSq1 = 0.0
sumSq2 = 0.0
product = 0.0
for j in range(M):
coord1 = locations[i+1][j] - locations[i][j]
coord2 = locations[i+2][j] - locations[i][j]
sumSq1 += coord1 * coord1
sumSq2 += coord2 * coord2
product += coord1 * coord2
if sumSq1 and sumSq2:
meanCos += product/( sqrt(sumSq1) * sqrt(sumSq2) )
if meanCos:
fitError /= meanCos * meanCos
return fitError
def getRoutes(refPeak, peakSets, tolerances, routes, weights, route=None, i=0, dists=None):
if not route:
route = []
if not dists:
dists = []
N = len(peakSets)
if i >= N:
routes.append(route)
return
peaks = peakSets[i]
# if peaks is empty but the next one is not...
# carry on but adjust the valid distance
if (i>0) and (not peaks) and (i < N-1):
route2 = list(route)
dists2 = list(dists)
getRoutes(refPeak, peakSets, tolerances, routes, weights, route2, i+1, dists2)
for peak in peaks:
distE = None
tolE = None
deltas = []
route2 = list(route)
route2.append(peak)
dists2 = list(dists)
if len(route2) > 1:
ppms1 = [pd.value for pd in route2[ 0].peakDims]
ppms2 = [pd.value for pd in route2[-2].peakDims]
ppms3 = [pd.value for pd in route2[-1].peakDims]
distE = 0.0
tolE = 0.0
for j in range(len(ppms1)):
weight = weights[j]
deltaE = ppms1[j] - ppms3[j]
deltaN = ppms2[j] - ppms3[j]
distE += deltaE * deltaE * weight * weight
deltas.append(abs(deltaN))
errorE = peak.peakDims[j].dataDimRef.valuePerPoint * pointError * weight
tolE += errorE * errorE
distE = sqrt(distE)
tolE = sqrt(tolE)
if (self.maxGrad is not None) or (self.minGrad is not None):
if deltas[0]:
grad = (deltas[1]*weights[1])/(deltas[0]*weights[0])
if (self.maxGrad is not None) and (grad > self.maxGrad):
continue
if (self.minGrad is not None) and (grad < self.minGrad):
continue
else:
if (self.maxGrad is not None):
continue
if distE is not None:
if dists and ( (dists[-1] - distE) > tolE ): # backward check
if (len(peaks) != 1) or ( not arePeaksAssignedSame(peak, refPeak) ):
continue
dists2.append(distE)
for j in range(len(deltas)):
valuePerPoint = peak.peakDims[j].dataDimRef.valuePerPoint
if (deltas[j] - tolerances[j]) > valuePerPoint * pointError:
if (len(peaks) != 1) or ( not arePeaksAssignedSame(peak, refPeak) ):
break
else:
getRoutes(refPeak, peakSets, tolerances, routes, weights, route2, i+1, dists2)
return routes
if not self.expSeries and self.peakList:
return
if self.assignSelect.get():
self.checkShiftLists()
self.peakGroups = []
sampleConditions = [(sc.value, sc) for sc in self.getSampleConditions()]
sampleConditions.sort()
experimentDict = {}
for value, sampleCondition in sampleConditions:
for experiment in sampleCondition.sampleConditionSet.experiments:
experimentDict[experiment] = sampleCondition
experiments = self.expSeries.experiments
refIsotopes = getSpectrumIsotopes(self.peakList.dataSource)
peakLists = {}
for experiment in experiments:
sampleCondition = experimentDict.get(experiment)
if not sampleCondition:
continue
for spectrum in experiment.dataSources:
if (spectrum.dataType == 'processed') and ( getSpectrumIsotopes(spectrum) == refIsotopes):
peakList = getSpectrumActivePeakList(spectrum)
if peakList:
peakLists[sampleCondition] = peakList
break
sortedPeakLists = []
for value, sampleCondition in sampleConditions:
peakList = peakLists.get(sampleCondition)
if peakList:
sortedPeakLists.append(peakList)
refIndex = sortedPeakLists.index(self.peakList)
searchWidths = []
for isotope in refIsotopes:
delta = maxStepSizes.get(isotope, 0.1)
searchWidths.append(delta)
def isPeakAssigned(peak):
for peakDim in peak.peakDims:
if peakDim.peakDimContribs:
return True
return False
# Find candidate peaks for follwing a titration from a reference peak
mapping = {}
candidates = {}
for peak in self.peakList.peaks:
peaks0 = []
i = 0
for peakList in sortedPeakLists:
if peakList is self.peakList:
peaks2 = [peak,]
else:
peaks2 = findSameAssignmentPeaks(peak, peakList) # Could get more than one
peaks4 = []
if not peaks2:
intervals = abs(refIndex-i)
tolerances = [x*intervals for x in searchWidths]
peaks3 = findClosePeaks(peak, peakList, tolerances=tolerances, pickNewPeaks=False)
peaks2 = []
for peak3 in peaks3:
if not isPeakAssigned(peak3):
peaks2.append(peak3)
peaks0.append(peaks2)
i += 1
candidates[peak] = peaks0
progressBar = ProgressBar(self, text="Grouping Peaks ",total = len(self.peakList.peaks))
grouping = {}
peakGroups = {}
for peak in self.peakList.peaks:
peaks = []
weights = []
tolerances = []
peakGroups[peak] = {}
for peakDim in peak.peakDims:
isotope = ','.join(peakDim.dataDimRef.expDimRef.isotopeCodes)
tolerances.append(maxStepSizes.get(isotope))
weights.append(isotopeWeights.get(isotope))
routes = getRoutes(peak, candidates[peak],tolerances,[],weights)
if routes:
bestRoute = routes[0]
bestScore = getAlignScore(bestRoute)
for route in routes:
score = getAlignScore(route)
if score < bestScore:
bestScore = score
bestRoute = route
peakGroups[peak] = bestRoute
for peak1 in bestRoute:
if grouping.get(peak1) is None:
grouping[peak1] = []
grouping[peak1].append([bestScore, peak])
progressBar.increment()
progressBar.destroy()
for peak1 in grouping.keys():
matches = grouping[peak1]
matches.sort()
grouping[peak1] = matches[0][1]
for peak in self.peakList.peaks:
peaks1 = peakGroups[peak]
peaks2 = []
for peak1 in peaks1:
if grouping[peak1] is peak:
peaks2.append(peak1)
peakGroups[peak] = peaks2
self.peakGroups.append([peak, None, None, None, None, len(peaks2), self.fitFunc, peaks2])
if self.assignSelect.get():
for peak in self.peakList.peaks:
propagatePeakAssignments(peakGroups[peak], refPeak=peak, cleanNonRef=True)
self.calculateAllFits()
def editExpSeries(self):
self.guiParent.editExpSeries()
def checkShiftLists(self):
dict = {}
experiments = self.expSeries.experiments
for experiment in experiments:
shiftList = experiment.shiftList
if shiftList:
if not dict.get(shiftList):
dict[shiftList] = []
dict[shiftList].append(experiment)
refExperiment = self.peakList.dataSource.experiment
if len(experiments) != len(dict.keys()):
msg = 'Experiments in series do not have individual shift lists. '
msg += 'Link each experiment to its own shift list?'
if showYesNo('Query',msg):
for shiftList in dict.keys():
experiments1 = dict[shiftList]
if len(experiments1) > 1:
if refExperiment in experiments1:
experiment1 = refExperiment
else:
experiment1 = experiments1[0]
for experiment2 in experiments1:
if experiment2 is not experiment1:
experiment2.shiftList = newShiftList(refExperiment.root, unit=shiftList.unit)
for experiment in experiments:
if not experiment.shiftList:
experiment.shiftList = newShiftList(refExperiment.root)
def getDataListInfo(self):
name = ''
unit = ''
if self.expSeries:
name = '%s series' % (','.join(self.expSeries.conditionNames))
unit = 'None'
dict = getNmrExpSeriesSampleConditions(self.expSeries)
for conditionName in self.expSeries.conditionNames:
for sampleCondition in dict.get(conditionName, []):
unit = sampleCondition.unit
break
else:
continue
break
return name, unit
def updateDataListInfo(self):
name, unit = self.getDataListInfo()
self.dataListTypeLabel.set(name)
self.dataListUnitLabel.set(unit)
def showPeaks(self):
peakGroups = self.scrolledMatrix.currentObjects
if peakGroups:
peaks = []
for peakGroup in peakGroups:
peaks.extend(peakGroup[-1])
self.guiParent.viewPeaks(peaks)
def selectGroup(self, peakGroup, row, col):
if peakGroup:
self.peakGroup = peakGroup
self.updateButtons()
def removeGroup(self, *event):
peakGroups = self.scrolledMatrix.currentObjects
if peakGroups:
for peakGroup in peakGroups:
self.peakGroups.remove(peakGroup)
for peak in peakGroup[-1]:
self.groupDict[peak] = None
self.peakGroup = None
self.updateAfter()
def getPeakLists(self):
peakLists = []
project = self.guiParent.getProject()
if self.expSeries:
experiments = self.expSeries.experiments
else:
experiments = project.NmrExperiments
for experiment in experiments:
for spectrum in experiment.dataSources:
if (spectrum.dataType == 'processed') and (spectrum.numDim > 1):
for peakList in spectrum.peakLists:
peakLists.append(peakList)
return peakLists
def changePeakList(self, i , name):
self.peakList = self.getPeakLists()[i]
self.updateDataDims()
def getFitFuncs(self):
fitFunctions = ['<None>','Ax + B','log (A exp(-Bx))','A exp(-Bx)','A exp(-Bx) + C']
return fitFunctions
def changeFitFunc(self, i, name):
self.fitFunc = int(i)
def updateFitFuncs(self, *opt):
names = self.getFitFuncs()
if self.fitFunc > len(names):
self.fitFunc = 1
self.fitFuncPulldown.setup(names,self.fitFunc)
def getHeadingList(self, numDim):
headingList = ['#',]
for i in range(numDim):
headingList.append( 'Assign\nF%d' % (i+1) )
headingList.extend(['Shift\nDist','Constant','Error','Fit\nError','Num\nPeaks','Fitted\nFunction'])
return headingList
def showFunctionFit(self, noOpen=False):
if self.peakGroup:
peak, dist, k, error, fitError, numPeaks, func, peaks = self.peakGroup
title = '.'.join([pd.annotation for pd in peak.peakDims])
else:
peaks = []
func = 1
title = ''
xLabel = ','.join(self.expSeries.conditionNames)
yLabel = 'Shift Distance'
if self.fitGraphPopup:
self.fitGraphPopup.update(objects=peaks, method=func,
xLabel=xLabel, yLabel=yLabel,
noiseLevel=self.noise,
graphTitle=title, force=True)
if not noOpen:
self.fitGraphPopup.open()
else:
self.fitGraphPopup = EditFitGraphPopup(self, peaks, self.getPeakSeriesData, self.updateGroup, xLabel,
yLabel, nextSetFunction=self.showNextGroup,
noiseLevel=self.noise, method=func, graphTitle=title)
def updateGroup(self, peaks, constant, error, fitError, method=None):
if method is None:
method = self.fitFunc
# TBD calculate shift dist and deltas
if self.peakGroup:
# peak, dist, constant, error, fitError, numPeaks, method, peaks
self.peakGroup[2] = constant
self.peakGroup[3] = error
self.peakGroup[4] = fitError
self.peakGroup[5] = len(peaks)
self.peakGroup[6] = method
self.peakGroup[7] = peaks
self.updateAfter()
def showNextGroup(self):
peakGroups = self.scrolledMatrix.objectList
if peakGroups:
if self.peakGroup and (self.peakGroup in peakGroups):
i = peakGroups.index(self.peakGroup)
i += 1
if i >= len(peakGroups):
i = 0
self.peakGroup = peakGroups[i]
self.scrolledMatrix.selectNthObject(i)
self.showFunctionFit()
def updateAfter(self, *obj):
if self.waiting:
return
else:
self.waiting = True
self.after_idle(self.update)
def updatePeaks(self, peak):
if peak.isDeleted and (self.groupDict.get(peak) is not None):
group = self.peakGroups[self.groupDict[peak]][-1]
if peak in group:
group.remove(peak)
if len(group) < 2:
for peak2 in group:
self.groupDict[peak2] = None
self.peakGroups.pop(self.groupDict[peak])
self.groupDict[peak] = None
self.updateAfter()
def getPeakListName(self, peakList):
spectrum = peakList.dataSource
return '%s:%s:%d' % (spectrum.experiment.name,spectrum.name,peakList.serial)
def updatePeakLists(self, *peakList):
index = -1
names = []
peakLists = self.getPeakLists()
if peakLists:
names = [self.getPeakListName(pl) for pl in peakLists]
if self.peakList not in peakLists:
self.peakList = peakLists[0]
index = peakLists.index(self.peakList)
self.updateDataDims()
self.peakListPulldown.setup(names, index)
def updateButtons(self):
pass
def update(self):
self.updateButtons()
if self.fitGraphPopup:
self.showFunctionFit(noOpen=True)
numDim = 2
if self.peakList:
numDim = self.peakList.dataSource.numDim
headingList = self.getHeadingList(numDim)
objectList = self.peakGroups
textMatrix = []
i = 0
for peak, dist, k, error, fitError, numPeaks, func, peaks in objectList:
i += 1
datum = []
datum.append(i)
for j in range(numDim):
datum.append(peak.peakDims[j].annotation)
datum.append(dist)
datum.append(k)
datum.append(error)
datum.append(fitError)
datum.append(numPeaks)
datum.append(self.getFitFuncs()[func])
textMatrix.append( datum )
self.scrolledMatrix.update(textMatrix=textMatrix, objectList=objectList, headingList=headingList)
self.waiting = False
def makeDataList(self):
if self.peakGroups and self.expSeries:
name, unit = self.getDataListInfo()
peakGroups = []
values = []
errors = []
peakDimGroups = []
shiftGroups = []
for peak, dist, value, error, fitError, numPeaks, func, peaks in self.peakGroups:
shiftList = peak.peakList.dataSource.experiment.shiftList or \
peak.root.findFirstNmrMeasurementList(className='ShiftList')
peakDims = []
for peakB in peaks:
for peakDim in peakB.peakDims:
if peakDim.dataDimRef.dataDim in self.dataDims:
peakDims.append(peakDim)
shifts = []
for peakDim in peak.peakDims:
if peakDim.dataDimRef.dataDim in self.dataDims:
for contrib in peakDim.peakDimContribs:
shift = contrib.resonance.findFirstShift(parentList=shiftList)
if shift:
shifts.append(shift)
values.append(value)
errors.append(error)
peakGroups.append(peaks)
shiftGroups.append(shifts)
peakDimGroups.append(peakDims)
dataList = makeDataList(self.expSeries.root, name, unit, values, errors=errors,
peaks=peakGroups, peakDims=peakDimGroups, measurements=shiftGroups)
print dataList
#self.parent.editDerivedData(dataList=dataList)
def getDataDimName(self,dataDim):
isotopes = ''
if dataDim.expDim.expDimRefs:
for isotope in dataDim.expDim.expDimRefs[0].isotopeCodes:
isotopes += isotope
return 'F%d %s' % (dataDim.dim, isotopes)
def getDataDimOptName(self,dataDims):
return ','.join([self.getDataDimName(dataDim) for dataDim in dataDims])
def getDataDimOpts(self):
opts = []
if self.peakList:
dataDims = list(self.peakList.dataSource.dataDims)
opts.append(dataDims)
if len(dataDims) > 2:
for dataDim in dataDims:
dataDims2 = list(dataDims)
dataDims2.remove(dataDim)
opts.append(dataDims2)
for dataDim in dataDims:
opts.append([dataDim,])
return opts
def changeDataDim(self, i, name):
dataDims = self.getDataDimOpts()[i]
if dataDims != self.dataDims:
self.dataDims = dataDims
if self.peakGroups:
self.calculateAllFits()
def updateDataDims(self, *obj):
dataDimOpts = self.getDataDimOpts()
dataDims = self.dataDims
names = [self.getDataDimOptName(opt) for opt in dataDimOpts]
index = -1
if dataDimOpts:
if dataDims not in dataDimOpts:
dataDims = dataDimOpts[0]
index = dataDimOpts.index(dataDims)
if dataDims != self.dataDims:
self.dataDims = dataDims
if self.peakGroups:
self.calculateAllFits()
self.dataDimsPulldown.setup(names, index)
def getExpSeries(self):
project = self.guiParent.getProject()
return list(project.nmrExpSeries)
# Could add option to filter out some series
def getExpSeriesName(self, series):
return '%s:%s' % (series.serial,','.join([n for n in series.conditionNames]))
def changeExpSeries(self, i, name):
expSeries = self.getExpSeries()[i]
if self.expSeries is not expSeries:
self.expSeries = expSeries
self.peakGroups = []
self.groupDict = {}
self.updatePeakLists()
self.updateDataListInfo()
self.updateAfter()
def updateExpSeries(self, *obj):
expSeries = self.expSeries
expSeriesList = self.getExpSeries()
names = [ self.getExpSeriesName(es) for es in expSeriesList ]
index = -1
if expSeriesList:
if expSeries not in expSeriesList:
expSeries = expSeriesList[0]
index = expSeriesList.index(expSeries)
if expSeries != self.expSeries:
self.expSeries = expSeries
self.peakGroups = []
self.groupDict = {}
self.updateDataListInfo()
self.updateAfter()
self.expSeriesPulldown.setup(names, index)
|