diff --git a/datacollector.py b/datacollector.py index 2a3f84c2..769a37cf 100644 --- a/datacollector.py +++ b/datacollector.py @@ -670,7 +670,7 @@ def on_save(self, e): dlg = wx.FileDialog(self, "Save Collection in JSON Format", self.directory, self.savename, "*.json") if dlg.ShowModal() == wx.ID_OK: self.savename = dlg.GetPath() - with open(self.savename, "w") as outfile: + with open(self.savename, "w+") as outfile: json.dump(outdict, outfile) print("Saved: ", self.savename) dlg.Destroy() diff --git a/metaunidec/gui_elements/ud_menu_meta.py b/metaunidec/gui_elements/ud_menu_meta.py index 17565d2b..464ca280 100644 --- a/metaunidec/gui_elements/ud_menu_meta.py +++ b/metaunidec/gui_elements/ud_menu_meta.py @@ -221,6 +221,8 @@ def __init__(self, parent, config, pres): self.experimentalmenu.AppendSeparator() self.menulinreg = self.experimentalmenu.Append(wx.ID_ANY, "Linear Regression") self.parent.Bind(wx.EVT_MENU, self.pres.on_linreg, self.menulinreg) + self.menusubdiv = self.experimentalmenu.Append(wx.ID_ANY, "Subtract and Divide") + self.parent.Bind(wx.EVT_MENU, self.pres.sub_div, self.menusubdiv) #self.menuAdditionalParameters = self.experimentalmenu.Append(wx.ID_ANY, "Additional Parameters", # "Adjust some experimental parameters") # self.parent.Bind(wx.EVT_MENU, self.pres.on_additional_parameters, self.menuAdditionalParameters) diff --git a/metaunidec/mudeng.py b/metaunidec/mudeng.py index bd3ae591..6054a4dd 100644 --- a/metaunidec/mudeng.py +++ b/metaunidec/mudeng.py @@ -162,7 +162,7 @@ def export_spectra(self, e=None): outfile = self.config.outfname + "_" + str(s.var1) + ".txt" np.savetxt(outfile, s.rawdata) print(outfile) - self.config.config_export(self.config.outfname + "_config.dat") + self.config.config_export(self.config.outfname + "_conf.dat") def batch_set_config(self, paths): for p in paths: diff --git a/metaunidec/ultrameta.py b/metaunidec/ultrameta.py index 59e7d444..5fb1c327 100644 --- a/metaunidec/ultrameta.py +++ b/metaunidec/ultrameta.py @@ -361,7 +361,7 @@ def on_save(self, e): dlg = wx.FileDialog(self, "Save Collection in JSON Format", self.directory, self.savename, "*.json", wx.FD_SAVE) if dlg.ShowModal() == wx.ID_OK: self.savename = dlg.GetPath() - with open(self.savename, "w") as outfile: + with open(self.savename, "w+") as outfile: json.dump(outdict, outfile) print("Saved: ", self.savename) dlg.Destroy() @@ -461,7 +461,7 @@ def run_hdf5(self, path): print("Error3: File Not Found:", path) return out = mudeng.metaunidec_call(self.config, "-ultraextract", path=path) - if out is not 0: + if out != 0: self.SetStatusText("ERROR with File: " + path, number=2) print("ERROR C: File", path, out) diff --git a/readme.md b/readme.md index 217a10ed..bb8d7ef1 100644 --- a/readme.md +++ b/readme.md @@ -194,6 +194,16 @@ The main GUI class is GUniDec.UniDecApp. ## Change Log +v.4.1.2 + +**Added button in UniDec to turn off data normalization.** Note: the beta values will be automatically scaled to match this. + +Renamed the parameter ZScore in the UniScore calculation to CSScore. Added R squared to the UniScore calculation. + +Added several experimental subtract and divide features. Tweaks to linear regression experimental feature. + +Bug fixes and compatibility updates. + v.4.1.1 Added right click feature to color peaks by their scores. diff --git a/unidec.py b/unidec.py index afb251c7..d41e968e 100644 --- a/unidec.py +++ b/unidec.py @@ -310,7 +310,7 @@ def run_unidec(self, silent=False, efficiency=False): if out == 0: self.unidec_imports(efficiency) if not silent: - print("File Name: ", self.config.filename, "R Sqaured: ", self.config.error) + print("File Name: ", self.config.filename, "R Squared: ", self.config.error) return out else: print("UniDec Run Error:", out) @@ -1177,7 +1177,7 @@ def pks_mscore(self, xfwhm=2, pow=2): # print("Peak Mass:", p.mass, "Peak Shape Score", avg, p.mscore) p.mscore = avg - def pks_zscore(self, xfwhm=2): + def pks_csscore(self, xfwhm=2): try: if len(self.pks.peaks[0].zstack) < 1: self.get_zstack(xfwhm=xfwhm) @@ -1219,8 +1219,8 @@ def pks_zscore(self, xfwhm=2): else: badarea += val - low - p.z_score = 1 - ud.safedivide1(badarea, zs) - # print(badarea, zs, p.z_score) + p.cs_score = 1 - ud.safedivide1(badarea, zs) + # print(badarea, zs, p.cs_score) def get_mzstack(self, xfwhm=2): zarr = np.reshape(self.data.mzgrid[:, 2], (len(self.data.data2), len(self.data.ztab))) @@ -1344,6 +1344,15 @@ def pks_fscore(self): fscore2 = self.score_minimum(height, umin) # print("Fscore5", fscore2, umin, height) p.fscore *= fscore2 + ''' + def tscore(self): + try: + tscore = 1 - np.sum(np.abs(self.data.fitdat - self.data.data2[:, 1])) / np.sum(self.data.data2[:, 1]) + except Exception as e: + print("Error in Tscore: ", e) + tscore = 0 + self.data.tscore = tscore + return tscore''' def dscore(self, xfwhm=2, pow=2): """ @@ -1362,27 +1371,32 @@ def dscore(self, xfwhm=2, pow=2): self.pks_mscore(xfwhm=xfwhm, pow=pow) self.pks_uscore(pow=pow, xfwhm=xfwhm) - self.pks_zscore(xfwhm=xfwhm) + self.pks_csscore(xfwhm=xfwhm) self.pks_fscore() + #self.tscore() tscores = [] ints = [] for p in self.pks.peaks: - scores = np.array([p.mscore, p.uscore, p.z_score, p.fscore]) # p.rsquared, + scores = np.array([p.mscore, p.uscore, p.fscore, p.cs_score]) # p.rsquared, p.dscore = np.product(scores) + p.lscore = np.product(scores[:-1]) tscores.append(p.dscore) ints.append(p.height) print("Mass:", p.mass, "Peak Shape:", round(p.mscore * 100, 2), "Uniqueness:", round(p.uscore * 100, 2), # "Fitting R^2", round(p.rsquared * 100, 2), - "Charge:", round(p.z_score * 100, 2), + "Charge:", round(p.cs_score * 100, 2), "FWHM:", round(p.fscore * 100, 2), "Combined:", round(p.dscore * 100, 2)) # print(p.intervalFWHM) ints = np.array(ints) - self.pks.uniscore = ud.weighted_avg(tscores, ints ** pow) + self.pks.uniscore = ud.weighted_avg(tscores, ints ** pow) * self.config.error + print("R Squared:", self.config.error) + #print("TScore:", self.data.tscore) print("Average Peaks Score (UniScore):", self.pks.uniscore) + def filter_peaks(self, minscore=0.4): # w = deepcopy(self.config.peakwindow) # t = deepcopy(self.config.peakthresh) diff --git a/unidec_bin/Example Data/ADH_unidecfiles/ADH_conf.dat b/unidec_bin/Example Data/ADH_unidecfiles/ADH_conf.dat index ed43b92c..0fe0951e 100644 --- a/unidec_bin/Example Data/ADH_unidecfiles/ADH_conf.dat +++ b/unidec_bin/Example Data/ADH_unidecfiles/ADH_conf.dat @@ -45,6 +45,7 @@ spectracmap rainbow publicationmode 1 isotopemode 0 peaknorm 1 +datanorm 1 baselineflag 1.0 orbimode 0 integratelb -1000.0 diff --git a/unidec_bin/Example Data/BSA_unidecfiles/BSA_conf.dat b/unidec_bin/Example Data/BSA_unidecfiles/BSA_conf.dat index e28c482e..69d455b8 100644 --- a/unidec_bin/Example Data/BSA_unidecfiles/BSA_conf.dat +++ b/unidec_bin/Example Data/BSA_unidecfiles/BSA_conf.dat @@ -23,8 +23,8 @@ subbuff 0.0 subtype 2 smooth 0.0 mzbins 0.0 -peakwindow 50.0 -peakthresh 0.025 +peakwindow 500.0 +peakthresh 0.01 peakplotthresh 0.1 plotsep 0.025 intthresh 0.0 @@ -45,6 +45,7 @@ spectracmap rainbow publicationmode 1 isotopemode 0 peaknorm 1 +datanorm 1 baselineflag 1.0 orbimode 0 integratelb -1000.0 diff --git a/unidec_bin/Example Data/GroEL UniDec_unidecfiles/GroEL UniDec_conf.dat b/unidec_bin/Example Data/GroEL UniDec_unidecfiles/GroEL UniDec_conf.dat index 8c5d2f52..0303283f 100644 --- a/unidec_bin/Example Data/GroEL UniDec_unidecfiles/GroEL UniDec_conf.dat +++ b/unidec_bin/Example Data/GroEL UniDec_unidecfiles/GroEL UniDec_conf.dat @@ -20,7 +20,7 @@ mtabsig 0.0 minmz 10079.027219759617 maxmz 13777.256263028847 subbuff 0.0 -subtype 0 +subtype 2 smooth 0.0 mzbins 0.0 peakwindow 50000.0 @@ -45,6 +45,7 @@ spectracmap rainbow publicationmode 1 isotopemode 0 peaknorm 1 +datanorm 1 baselineflag 1.0 orbimode 0 integratelb -1000.0 diff --git a/unidec_bin/Example Data/POPC_Nanodiscs_unidecfiles/POPC_Nanodiscs_conf.dat b/unidec_bin/Example Data/POPC_Nanodiscs_unidecfiles/POPC_Nanodiscs_conf.dat index 701dd9dd..8be4c735 100644 --- a/unidec_bin/Example Data/POPC_Nanodiscs_unidecfiles/POPC_Nanodiscs_conf.dat +++ b/unidec_bin/Example Data/POPC_Nanodiscs_unidecfiles/POPC_Nanodiscs_conf.dat @@ -15,7 +15,7 @@ massub 160000.0 masslb 80000.0 msig 1.0 molig 760.0 -massbins 10.0 +massbins 1.0 mtabsig 0.0 minmz 8761.430704083608 maxmz 12864.965623887581 diff --git a/unidec_bin/UniDec.exe b/unidec_bin/UniDec.exe index 7808ed90..4b816a4b 100644 Binary files a/unidec_bin/UniDec.exe and b/unidec_bin/UniDec.exe differ diff --git a/unidec_bin/libiomp5md.dll b/unidec_bin/libiomp5md.dll index a4e603e5..84e12042 100644 Binary files a/unidec_bin/libiomp5md.dll and b/unidec_bin/libiomp5md.dll differ diff --git a/unidec_modules/gui_elements/ud_controls.py b/unidec_modules/gui_elements/ud_controls.py index 3fae8363..ce6dbf76 100644 --- a/unidec_modules/gui_elements/ud_controls.py +++ b/unidec_modules/gui_elements/ud_controls.py @@ -191,6 +191,8 @@ def __init__(self, parent, config, pres, panel, iconfile): gbox1b.Add(wx.StaticText(panel1b, label="Intensity Threshold: "), (i, 0), flag=wx.ALIGN_CENTER_VERTICAL) i += 1 + + self.ctladductmass = wx.TextCtrl(panel1b, value='', size=size1) gbox1b.Add(self.ctladductmass, (i, 1), span=(1, 1)) gbox1b.Add(wx.StaticText(panel1b, label="Adduct Mass (Da): "), (i, 0), flag=wx.ALIGN_CENTER_VERTICAL) @@ -202,16 +204,27 @@ def __init__(self, parent, config, pres, panel, iconfile): i += 1 if self.config.imflag == 0: + + self.ctldatareductionpercent = wx.TextCtrl(panel1b, value="", size=size1) gbox1b.Add(self.ctldatareductionpercent, (i, 1), span=(1, 1)) gbox1b.Add(wx.StaticText(panel1b, label="Data Reduction (%): "), (i, 0), flag=wx.ALIGN_CENTER_VERTICAL) i += 1 + + self.ctldatanorm = wx.CheckBox(panel1b, label="Normalize Data") + self.ctldatanorm.SetValue(True) + gbox1b.Add(self.ctldatanorm, (i, 0), span=(1, 2)) + i += 1 + self.ctlbintype = wx.Choice(panel1b, -1, size=(240, 50), choices=["Linear m/z (Constant " + '\N{GREEK CAPITAL LETTER DELTA}' + "m/z)", "Linear resolution (Constant (m/z)/(" + '\N{GREEK CAPITAL LETTER DELTA}' + "m/z))", "Nonlinear", "Linear Interpolated", "Linear Resolution Interpolated"]) gbox1b.Add(self.ctlbintype, (i, 0), span=(1, 2)) i += 1 + + + else: self.ctlconvertflag = wx.CheckBox(panel1b, label="Compress when converting to .txt") self.ctlconvertflag.SetValue(True) @@ -697,6 +710,7 @@ def import_config_to_gui(self): self.ctlmanualassign.SetValue(self.config.manualfileflag) self.ctlisotopemode.SetSelection(self.config.isotopemode) self.ctlorbimode.SetValue(self.config.orbimode) + self.ctldatanorm.SetValue(self.config.datanorm) self.ctlbintype.SetSelection(int(self.config.linflag)) self.ctlpsig.SetValue(str(self.config.psig)) self.ctlbeta.SetValue(str(self.config.beta)) @@ -827,6 +841,7 @@ def export_gui_to_config(self, e=None): self.config.reductionpercent = ud.string_to_value(self.ctldatareductionpercent.GetValue()) self.config.isotopemode = int(self.ctlisotopemode.GetSelection()) self.config.orbimode = int(self.ctlorbimode.GetValue()) + self.config.datanorm = int(self.ctldatanorm.GetValue()) self.config.psig = ud.string_to_value(self.ctlpsig.GetValue()) self.config.beta = ud.string_to_value(self.ctlbeta.GetValue()) self.config.manualfileflag = int(self.ctlmanualassign.GetValue()) @@ -957,6 +972,7 @@ def setup_tool_tips(self): self.ctlminnativez.SetToolTip(wx.ToolTip("Minimum offset from a native charge state")) self.ctlmaxnativez.SetToolTip(wx.ToolTip("Maximum offset from a native charge state")) if self.config.imflag == 0: + self.ctldatanorm.SetToolTip(wx.ToolTip("Normalize Data and Results")) self.ctldatareductionpercent.SetToolTip( wx.ToolTip( "Reduces the amount of data by removing everything below a threshold.\nSets the threshold to fit the percentage of data to remove.")) diff --git a/unidec_modules/gui_elements/ud_menu.py b/unidec_modules/gui_elements/ud_menu.py index da3a8ac4..79e4f700 100644 --- a/unidec_modules/gui_elements/ud_menu.py +++ b/unidec_modules/gui_elements/ud_menu.py @@ -244,6 +244,13 @@ def __init__(self, parent, config, pres, tabbed): self.experimentalmenu.AppendSeparator() self.menuAdditionalParameters = self.experimentalmenu.Append(wx.ID_ANY, "Additional Parameters", "Adjust some experimental parameters") + + self.experimentalmenu.AppendSeparator() + self.menulinreg = self.experimentalmenu.Append(wx.ID_ANY, "Linear Regression") + self.parent.Bind(wx.EVT_MENU, self.pres.on_linreg, self.menulinreg) + self.menusubdiv = self.experimentalmenu.Append(wx.ID_ANY, "Subtract and Divide") + self.parent.Bind(wx.EVT_MENU, self.pres.sub_div, self.menusubdiv) + self.experimentalmenu.AppendSeparator() self.menuscore1 = self.experimentalmenu.Append(wx.ID_ANY, "Show Peak Scores", "Show Peak Scores") @@ -325,9 +332,7 @@ def __init__(self, parent, config, pres, tabbed): self.menutheomass = self.experimentalmenu.Append(wx.ID_ANY, "Plot Theoretical Mass") self.parent.Bind(wx.EVT_MENU, self.pres.plot_theo_mass, self.menutheomass) - self.experimentalmenu.AppendSeparator() - self.menulinreg = self.experimentalmenu.Append(wx.ID_ANY, "Linear Regression") - self.parent.Bind(wx.EVT_MENU, self.pres.on_linreg, self.menulinreg) + # self.menucentroid = self.experimentalmenu.Append(wx.ID_ANY, "Get Centroid at FWHM") # self.parent.Bind(wx.EVT_MENU, self.pres.on_centroid, self.menucentroid) diff --git a/unidec_modules/isolated_packages/score_window.py b/unidec_modules/isolated_packages/score_window.py index 1736512d..966aa37d 100644 --- a/unidec_modules/isolated_packages/score_window.py +++ b/unidec_modules/isolated_packages/score_window.py @@ -19,7 +19,7 @@ def scr(score): def scr2(p): - scores = [p.dscore, p.uscore, p.mscore, p.z_score, p.fscore] + scores = [p.dscore, p.uscore, p.mscore, p.cs_score, p.fscore] strings = [scr(s) for s in scores] out = "" for s in strings: @@ -40,7 +40,7 @@ def score_plots(eng): plt.figure() plt.subplot(131) plt.title( - "Combined Score: " + str(round(p.dscore * 100, 2)) + "\nCharge Score: " + str(round(p.z_score * 100, 2)) + "Combined Score: " + str(round(p.dscore * 100, 2)) + "\nCharge Score: " + str(round(p.cs_score * 100, 2)) ) plt.plot(ztab, sumz) plt.plot(p.zdist[:, 0], p.zdist[:, 1], color="k") @@ -147,7 +147,7 @@ def populate(self, pks): l = len(pks.peaks) collabels = ["Mass", "Intensity", "DScore", "Uniqueness/Fit", "Peak Shape", - "Charge Dist.", "FWHM Penalties"] + "Charge Dist.", "FWHM Penalties", "Limited Score (DScore without CSScore)"] cl = len(collabels) self.CreateGrid(l + 1, cl) @@ -168,7 +168,7 @@ def populate(self, pks): self.SetCellFont(i, 0, wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.SetCellValue(i, 1, str(p.height)) - scores = [p.dscore, p.uscore, p.mscore, p.z_score, p.fscore] + scores = [p.dscore, p.uscore, p.mscore, p.cs_score, p.fscore, p.lscore] scores = deepcopy(scores) cindex = 2 for s in scores: diff --git a/unidec_modules/isolated_packages/texmaker.py b/unidec_modules/isolated_packages/texmaker.py index 728c557c..b61cd412 100644 --- a/unidec_modules/isolated_packages/texmaker.py +++ b/unidec_modules/isolated_packages/texmaker.py @@ -21,7 +21,7 @@ def MakeTexReport(fname, config, path, peaks, labels, names, color, figureflags) ['$\\bigcirc$', '$\\bigtriangledown$', '$\\bigtriangleup$', '$\\triangleright$', '$\\square$', '$\\lozenge$', '$\\bigstar$']])) - f = open(fname, 'w') + f = open(fname, 'w+') f.write("\\documentclass{article}\n") f.write("\\usepackage{graphicx}\n") f.write("\\usepackage{amsmath}\n") diff --git a/unidec_modules/peakstructure.py b/unidec_modules/peakstructure.py index 5719322c..082a15cb 100644 --- a/unidec_modules/peakstructure.py +++ b/unidec_modules/peakstructure.py @@ -62,17 +62,18 @@ def __init__(self): self.mzstack = [] self.mscore = 0 self.uscore = 0 - self.z_score = 0 + self.cs_score = 0 self.rsquared = 0 self.fscore = 0 self.dscore = 0 + self.lscore = 0 self.mdist = None self.zdist = None def line_out(self, type="Full"): if type == "Full": outputs = [self.mass, self.centroid, self.height, self.area, self.textmarker, self.match, self.matcherror, - self.integral, self.diff, self.avgcharge, self.dscore] + self.integral, self.diff, self.avgcharge, self.dscore, self.lscore] elif type == "Basic": outputs = [self.mass, self.height, self.integral] else: diff --git a/unidec_modules/tims_import_wizard/data_importer.py b/unidec_modules/tims_import_wizard/data_importer.py index 85138ed5..42b205ff 100644 --- a/unidec_modules/tims_import_wizard/data_importer.py +++ b/unidec_modules/tims_import_wizard/data_importer.py @@ -92,7 +92,7 @@ def auto_from_wizard(lines, exedir): for index in mapper: if l[index] == "None": l[index] = None - if mapper[index] is not '': + if mapper[index] != '': try: parse[conv[mapper[index]]] = l[index] except Exception as e: @@ -201,7 +201,7 @@ def MakeUniDecConfig(job_kwargs): else: twaveflag = 1 - f = open(filename, 'w') + f = open(filename, 'w+') f.write("twaveflag " + str(twaveflag) + "\n") f.write("mzbins " + str(job_kwargs[tt.BIN]) + "\n") if job_kwargs[tt.PUSHER] is not None: @@ -412,7 +412,7 @@ def parse_file(file_path, exp_type='linear', collision=None, debug=False, dir=No out[tt.DRIFT_V] = search_extern(file_path, 'Transfer Collision Energy') - if out[tt.TYPE] is not 'ms': + if out[tt.TYPE] != 'ms': # try to grab the pusher frequency from the stat code # pusher = get_stat_code(file_path, 76, dir=exedir) pusher = get_stat_name(file_path, "Transport RF") diff --git a/unidec_modules/unidec_enginebase.py b/unidec_modules/unidec_enginebase.py index 633446ca..82623401 100644 --- a/unidec_modules/unidec_enginebase.py +++ b/unidec_modules/unidec_enginebase.py @@ -15,7 +15,7 @@ def __init__(self): :return: None """ - self.version = "4.1.1" + self.version = "4.1.2" print("\nUniDec Engine v." + self.version) self.config = None self.config_history = [] @@ -174,16 +174,17 @@ def linear_regression_peaks(self): y = [] z = [] for p in self.pks.peaks: - y.append(p.mass) - z.append(p.height) - mnum = np.floor(p.mass / self.config.molig) - x.append(mnum) + if p.ignore == 0: + y.append(p.mass) + z.append(p.height) + mnum = np.floor(p.mass / self.config.molig) + x.append(mnum) x = np.array(x) y = np.array(y) z = np.array(z) - fit = np.polyfit(x, y, 1, w=z) + fit = np.polyfit(x, y, 1, w=z ** 2) slope = fit[0] intercept = fit[1] @@ -202,7 +203,7 @@ def linear_regression_peaks(self): print("Removing outliers with residuals greater than:", cutoff) print(residuals) boo2 = residuals < cutoff - fit = np.polyfit(x[boo2], y[boo2], 1, w=z[boo2]) + fit = np.polyfit(x[boo2], y[boo2], 1, w=np.array(z[boo2]) ** 2) slope = fit[0] intercept = fit[1] fitdat = x[boo2] * slope + intercept @@ -217,13 +218,16 @@ def linear_regression_peaks(self): print("Need to set the mass difference/mass of oligomer") return fit, rsquared + + + def oxidation_analysis(self, e=None): data = self.data.massdat maxindex = np.argmax(data[:, 1]) maxmass, maxint = data[maxindex] nox = np.arange(0, 4) - oxmasses = maxmass + nox* 16 + oxmasses = maxmass + nox * 16 areas = [] for i, m in enumerate(oxmasses): low = m + self.config.integratelb @@ -235,8 +239,7 @@ def oxidation_analysis(self, e=None): areas /= np.amax(areas) print("Relative Areas:", areas) - totox = np.sum(nox*areas)/np.sum(areas) + totox = np.sum(nox * areas) / np.sum(areas) print("Total Oxidations:", totox) return np.append(areas, totox) - diff --git a/unidec_modules/unidec_presbase.py b/unidec_modules/unidec_presbase.py index 17fa3189..ee9f0a68 100644 --- a/unidec_modules/unidec_presbase.py +++ b/unidec_modules/unidec_presbase.py @@ -5,7 +5,7 @@ import numpy as np import unidec_modules.unidectools as ud import unidec_modules.peakwidthtools as peakwidthtools -from unidec_modules import ManualSelectionWindow, AutocorrWindow, miscwindows +from unidec_modules import ManualSelectionWindow, AutocorrWindow, miscwindows, peakstructure import time @@ -296,6 +296,67 @@ def fpop(self, e=0): # Set data object value clipboard.SetText(outstring) + # Put the data in the clipboard + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(clipboard) + wx.TheClipboard.Close() + + def sub_div(self, e=0): + try: + masses=[] + for p in self.eng.pks.peaks: + if p.ignore==0: + masses.append(p.mass) + defaultsub = np.amin(masses) + except: + defaultsub = 44088 + + defaultdiv = self.eng.config.molig + dlg = miscwindows.DoubleInputDialog(self.view) + dlg.initialize_interface("Subtract and Divide", "Subtract:", str(defaultsub), + "Divide:", str(defaultdiv)) + dlg.ShowModal() + try: + sub = float(dlg.value) + div = float(dlg.value2) + except: + print("Error with Subtract and Divide Inputs:", dlg.value, dlg.value2) + return 0 + + try: + sd_results = [] + message= "Average Masses:\n\n" + outstring="" + for s in self.eng.data.spectra: + pks = peakstructure.Peaks() + peaks = ud.peakdetect(s.massdat, self.eng.config) + pks.add_peaks(peaks, massbins=self.eng.config.massbins) + sd_result = ud.subtract_and_divide(pks, sub, div) + sd_results.append(sd_result) + + outstring += str(sd_result) + "\n" + + avg = np.mean(sd_results) + message += outstring + message += "\nOverall Average: " + str(avg) + outstring += "\n" +str(avg) + self.copy_to_clipboard(outstring) + self.warn(message, caption="Subtract and Divide Results") + + except: + sd_result = ud.subtract_and_divide(self.eng.pks, sub, div) + outstring= str(sd_result) + message = "Average Mass: " + outstring + self.copy_to_clipboard(outstring) + self.warn(message, caption="Subtract and Divide Results") + + def copy_to_clipboard(self, outstring): + # Create text data object + clipboard = wx.TextDataObject() + + # Set data object value + clipboard.SetText(outstring) + # Put the data in the clipboard if wx.TheClipboard.Open(): wx.TheClipboard.SetData(clipboard) diff --git a/unidec_modules/unidecstructure.py b/unidec_modules/unidecstructure.py index e8c64fd9..3bd9a3ce 100644 --- a/unidec_modules/unidecstructure.py +++ b/unidec_modules/unidecstructure.py @@ -206,8 +206,16 @@ def config_export(self, name): :param name: File name to write to. :return: None """ + self.numz = self.endz - self.startz + 1 - f = open(name, 'w') + f = open(name, 'w+') + ''' + except: + path = os.path.join(os.getcwd(), name) + path = "\\\\?\\%s" % path + print(path) + f = open(path, 'w+') + print("NOTE: Your path length might exceed the limit for Windows. Please shorten your file name.")''' f.write("imflag " + str(self.imflag) + "\n") f.write("input " + str(self.infname) + "\n") f.write("output " + str(self.outfname) + "\n") @@ -265,6 +273,7 @@ def config_export(self, name): f.write("publicationmode " + str(self.publicationmode) + "\n") f.write("isotopemode " + str(self.isotopemode) + "\n") f.write("peaknorm " + str(self.peaknorm) + "\n") + f.write("datanorm " + str(self.datanorm) + "\n") f.write("baselineflag " + str(self.baselineflag) + "\n") f.write("orbimode " + str(self.orbimode) + "\n") if self.integratelb != "" and self.integrateub != "": @@ -463,6 +472,8 @@ def config_import(self, name): self.zerolog = ud.string_to_value(line.split()[1]) if line.startswith("peaknorm"): self.peaknorm = ud.string_to_value(line.split()[1]) + if line.startswith("datanorm"): + self.datanorm = ud.string_to_value(line.split()[1]) if line.startswith("baselineflag"): self.baselineflag = ud.string_to_value(line.split()[1]) if line.startswith("orbimode"): @@ -812,6 +823,12 @@ def check_badness(self): self.warning = "Note: One or more T-wave calibration parameters has been set to 0" \ "\nCheck to make sure this is correct" + path = os.path.join(os.getcwd(), self.confname) + if len(path) > 250: + self.badtest = 1 + self.warning = "ERROR: PATH LENGTH TOO LONG: Windows sets a 260 character path length." \ + "\nPlease shorten your file and folder path lengths." + return self.badtest, self.warning def default_high_res(self): @@ -1048,6 +1065,7 @@ def __init__(self): self.massccs = np.array([]) self.ccsz = np.array([]) self.ccsdata = np.array([]) + self.tscore = 0 def write_hdf5(self, file_name): hdf = h5py.File(file_name) diff --git a/unidec_modules/unidectools.py b/unidec_modules/unidectools.py index 80e97a54..b4a46ff5 100644 --- a/unidec_modules/unidectools.py +++ b/unidec_modules/unidectools.py @@ -796,9 +796,23 @@ def zip_folder(save_path): def dataexport(datatop, fname): - np.savetxt(fname, datatop, fmt='%f') + try: + np.savetxt(fname, datatop, fmt='%f') + except: + path = os.path.join(os.getcwd(), fname) + path = "\\\\?\\%s" % path + np.savetxt(path, datatop, fmt='%f') + print("NOTE: Your path length might exceed the limit for Windows. Please shorten your file name.") pass +def savetxt(fname, datatop): + try: + np.savetxt(fname, datatop) + except: + path = os.path.join(os.getcwd(), fname) + path = "\\\\?\\%s" % path + np.savetxt(path, datatop) + print("NOTE: Your path length might exceed the limit for Windows. Please shorten your file name.") def mergedata(data1, data2): """ @@ -1391,7 +1405,7 @@ def dataprep(datatop, config, removenoise=False): if config.intscale == "Square Root": data2[:, 1] = np.sqrt(data2[:, 1]) print("Square Root Scale") - elif config.intscale is "Logarithmic": + elif config.intscale == "Logarithmic": data2[:, 1] = fake_log(data2[:, 1]) data2[:, 1] -= np.amin(data2[:, 1]) print("Log Scale") @@ -1405,8 +1419,9 @@ def dataprep(datatop, config, removenoise=False): pass pass - # Normalization - data2 = normalize(data2) + if config.datanorm == 1: + # Normalization + data2 = normalize(data2) return data2 @@ -1867,9 +1882,9 @@ def single_cwt(a, width, wavelet_type="Ricker"): :return: cwt, wavelet Continous wavelet transform and wavelet of choice, both as numpy arrays of length N. """ - if wavelet_type is "Morlet": + if wavelet_type == "Morlet": wdat = signal.morlet(len(a), width) - elif wavelet_type is "1DG": + elif wavelet_type == "1DG": wdat = FD_gauss_wavelet(len(a), width) else: wdat = signal.ricker(len(a), width) @@ -1884,9 +1899,9 @@ def continuous_wavelet_transform(a, widths, wavelet_type="Ricker"): :param wavelet_type: Type of wavelet. Either "Ricker" (Mexican Hat) or "Morlet" (Gabor) :return: cwt_matrix (The continuous wavelet transform at the defined widths in a (W x N) array) """ - if wavelet_type is "Morlet": + if wavelet_type == "Morlet": wavelet = signal.morlet - elif wavelet_type is "1DG": + elif wavelet_type == "1DG": wavelet = FD_gauss_wavelet else: wavelet = signal.ricker @@ -2462,6 +2477,20 @@ def peaks_error_mean(pks, data, ztab, massdat, config): pk.errormean = std # pks.peaks[count].errormean = abs(sums[count] - pks.peaks[count].mass) +def subtract_and_divide(pks, basemass, refguess): + avgmass = [] + ints = [] + for p in pks.peaks: + if p.ignore==0: + mass = p.mass - basemass + num = np.round(mass/float(refguess)) + if num!=0: + avg = mass/num + avgmass.append(avg) + ints.append(p.height) + + return np.average(avgmass, weights=ints) + if __name__ == "__main__": testfile = "C:\Python\\UniDec\TestSpectra\\test_imms.raw" diff --git a/unidec_src/UniDec/UD_score.h b/unidec_src/UniDec/UD_score.h index 793f2ef8..66e18a49 100644 --- a/unidec_src/UniDec/UD_score.h +++ b/unidec_src/UniDec/UD_score.h @@ -243,9 +243,9 @@ double mscore(Config config, const int mlen, const double* massaxis, const doubl } -double zscore(Config config, const int mlen, const double* massaxis, const double* masssum, const double* massgrid, const double mlow, const double mhigh, const double peak) +double csscore(Config config, const int mlen, const double* massaxis, const double* masssum, const double* massgrid, const double mlow, const double mhigh, const double peak) { - double zscore = 0; + double csscore = 0; double* zvals = NULL; zvals = calloc(config.numz, sizeof(double)); @@ -309,11 +309,11 @@ double zscore(Config config, const int mlen, const double* massaxis, const doubl if (zsum != 0) { - zscore = 1 - (badarea / zsum); + csscore = 1 - (badarea / zsum); } } - return zscore; + return csscore; } @@ -392,17 +392,17 @@ double fscore(Config config, const int mlen, const double* massaxis, const doubl } -double score(Config config, const int mlen, const double * dataMZ, const double * dataInt, const double *mzgrid, const double *massaxis, const double* masssum, const double *massgrid, const int *nztab, const double threshold) +double score(Config config, Decon decon, const double * dataMZ, const double * dataInt, const double *mzgrid, const double *massaxis, const double* masssum, const double *massgrid, const int *nztab, const double threshold) { //printf("Starting Score %f %f\n", config.peakwin, config.peakthresh); double xfwhm = 2; double* peakx = NULL; double* peaky = NULL; - peakx = calloc(mlen, sizeof(double)); - peaky = calloc(mlen, sizeof(double)); + peakx = calloc(decon.mlen, sizeof(double)); + peaky = calloc(decon.mlen, sizeof(double)); - int plen = peak_detect(massaxis, masssum, mlen, config.peakwin, config.peakthresh, peakx, peaky); + int plen = peak_detect(massaxis, masssum, decon.mlen, config.peakwin, config.peakthresh, peakx, peaky); config.plen = plen; peakx = realloc(peakx, plen * sizeof(double)); @@ -417,7 +417,7 @@ double score(Config config, const int mlen, const double * dataMZ, const double fwhmhigh = calloc(plen, sizeof(double)); badfwhm = calloc(plen, sizeof(double)); - get_fwhms(config, mlen, massaxis, masssum, peakx, fwhmlow, fwhmhigh, badfwhm); + get_fwhms(config, decon.mlen, massaxis, masssum, peakx, fwhmlow, fwhmhigh, badfwhm); double numerator = 0; double denominator = 0; @@ -429,25 +429,27 @@ double score(Config config, const int mlen, const double * dataMZ, const double double ival = peaky[i]; double l = m - (m-fwhmlow[i])*xfwhm; double h = m + (fwhmhigh[i]-m)*xfwhm; - int index = nearfast(massaxis, m, mlen); + int index = nearfast(massaxis, m, decon.mlen); double height = masssum[index]; double usc = uscore(config, dataMZ, dataInt, mzgrid, nztab, l, h, m); - double msc = mscore(config, mlen, massaxis, masssum, massgrid, l, h, m); - double zsc = zscore(config, mlen, massaxis, masssum, massgrid, l, h, m); - double fsc = fscore(config, mlen, massaxis, masssum, peakx, height, fwhmlow[i], fwhmhigh[i], m, badfwhm[i]); + double msc = mscore(config, decon.mlen, massaxis, masssum, massgrid, l, h, m); + double cssc = csscore(config, decon.mlen, massaxis, masssum, massgrid, l, h, m); + double fsc = fscore(config, decon.mlen, massaxis, masssum, peakx, height, fwhmlow[i], fwhmhigh[i], m, badfwhm[i]); - double dsc = usc * msc * zsc * fsc; + double dsc = usc * msc * cssc * fsc; if (dsc > threshold) { - printf("Peak: Mass:%f Int:%f M:%f U:%f Z:%f F:%f D: %f \n", peakx[i], peaky[i], msc, usc, zsc, fsc, dsc); + printf("Peak: Mass:%f Int:%f M:%f U:%f CS:%f F:%f D: %f \n", peakx[i], peaky[i], msc, usc, cssc, fsc, dsc); numerator += ival * ival * dsc; denominator += ival * ival; } } - if (denominator != 0) { uniscore = numerator / denominator; } + printf("R Squared: %f\n", decon.rsquared); + if (denominator != 0) { uniscore = decon.rsquared * numerator / denominator; } + printf("Average Peaks Score (UniScore): %f\n", uniscore); return uniscore; } \ No newline at end of file diff --git a/unidec_src/UniDec/UniDec.h b/unidec_src/UniDec/UniDec.h index 2930c749..f7b37558 100644 --- a/unidec_src/UniDec/UniDec.h +++ b/unidec_src/UniDec/UniDec.h @@ -79,6 +79,7 @@ struct Decon { double* blur; double* newblur; double error; + double rsquared; int iterations; double uniscore; double conv; @@ -97,6 +98,7 @@ Decon SetupDecon() { decon.blur = NULL; decon.newblur = NULL; decon.error = 0; + decon.rsquared = 0; decon.iterations = 0; decon.uniscore = 0; decon.conv = 0; @@ -500,6 +502,20 @@ void PrintHelp() //printf("\nsize of: %d",sizeof(char)); } + +//Calculate Average +double Average(const int length, const double* xarray) +{ + double temp1 = 0; + double temp2 = (double) length; + for (int i = 0; i < length; i++) + { + temp1 += xarray[i]; + } + if (temp2 == 0) { return 0; } + return temp1 / temp2; +} + double ndis(double x, double y, double sig) { if (sig == 0) { return 0; } @@ -1527,8 +1543,8 @@ void ApplyCutoff1D(double *array, double cutoff, int lengthmz) } } -double getfitdatspeedy(double *fitdat, double *blur, int lengthmz,int numz,int maxlength,double maxint, - int isolength, int *isotopepos, float *isotopeval, int*starttab, int *endtab, double *mzdist, int speedyflag) +double getfitdatspeedy(double *fitdat, const double *blur, const int lengthmz,const int numz,const int maxlength, const double maxint, + const int isolength, const int *isotopepos, const float *isotopeval, const int*starttab, const int *endtab, const double *mzdist, const int speedyflag) { unsigned int i,j,k; double *deltas=NULL; @@ -1589,23 +1605,42 @@ double getfitdatspeedy(double *fitdat, double *blur, int lengthmz,int numz,int m return fitmax; } -double errfunspeedy(double *dataInt,double *fitdat, double *blur,int lengthmz,int numz,int maxlength, - int isolength, int *isotopepos, float *isotopeval, int*starttab, int *endtab, double *mzdist, int speedyflag) +double errfunspeedy(Config config, Decon decon, const double *dataInt, const int maxlength, + const int *isotopepos, const float *isotopeval, const int*starttab, const int *endtab, const double *mzdist, double *rsquared) { //Get max intensity double maxint = 0; - for (int i = 0; i < lengthmz; i++) + for (int i = 0; i < config.lengthmz; i++) { if (dataInt[i] > maxint) { maxint = dataInt[i]; } } - getfitdatspeedy(fitdat, blur,lengthmz, numz,maxlength, maxint,isolength, isotopepos, isotopeval,starttab,endtab,mzdist,speedyflag); + getfitdatspeedy(decon.fitdat, decon.blur, config.lengthmz, config.numz,maxlength, + maxint, config.isolength, isotopepos, isotopeval,starttab,endtab,mzdist,config.speedyflag); + if (config.baselineflag == 1) + { + #pragma omp parallel for schedule(auto) + for (int i = 0; i < config.lengthmz; i++) { + decon.fitdat[i] += decon.baseline[i];// +decon.noise[i]; + //decon.fitdat[i] = decon.noise[i]+0.1; + } + } + ApplyCutoff1D(decon.fitdat, 0, config.lengthmz); + + double fitmean = Average(config.lengthmz, dataInt); + double error=0; - for(int i=0;i Application false - Intel C++ Compiler 19.0 + Intel C++ Compiler 19.1 false true true @@ -82,7 +82,7 @@ Parallel true Parallel_Static - false + Parallel_Static @@ -218,6 +218,7 @@ false false stdcpp17 + NextGenNone libszip.lib;libzlib.lib;libhdf5.lib;libhdf5_hl.lib;ucrt.lib;vcruntime.lib;msvcrt.lib;%(AdditionalDependencies) diff --git a/unidec_src/UniDec/UniDec_Main.h b/unidec_src/UniDec/UniDec_Main.h index e20f5dea..dbb87819 100644 --- a/unidec_src/UniDec/UniDec_Main.h +++ b/unidec_src/UniDec/UniDec_Main.h @@ -153,6 +153,11 @@ Decon MainDeconvolution(const Config config, const Input inp, const int silent) if (silent == 0) { printf("Charges blurred: %d Oligomers blurred: %d\n", zlength, mlength); } + //Determine the maximum intensity in the data + double dmax = Max(inp.dataInt, config.lengthmz); + double betafactor = 1; + if (dmax > 1) { betafactor=dmax; } + //................................................... // // Setting up and running the iteration @@ -243,12 +248,12 @@ Decon MainDeconvolution(const Config config, const Input inp, const int silent) if (config.beta > 0 && iterations > 0) { - softargmax(decon.blur, config.lengthmz, config.numz, config.beta); + softargmax(decon.blur, config.lengthmz, config.numz, config.beta/betafactor); //printf("Beta %f\n", beta); } else if (config.beta < 0 && iterations >0) { - softargmax_transposed(decon.blur, config.lengthmz, config.numz, fabs(config.beta), barr, maxlength, config.isolength, inp.isotopepos, inp.isotopeval, config.speedyflag, starttab, endtab, rmzdist, config.mzsig); + softargmax_transposed(decon.blur, config.lengthmz, config.numz, fabs(config.beta/betafactor), barr, maxlength, config.isolength, inp.isotopepos, inp.isotopeval, config.speedyflag, starttab, endtab, rmzdist, config.mzsig); } if (config.psig >= 1 && iterations > 0) @@ -310,6 +315,7 @@ Decon MainDeconvolution(const Config config, const Input inp, const int silent) memcpy(oldblur, decon.blur, config.lengthmz * config.numz * sizeof(double)); } } + free(dataInt2); free(oldblur); @@ -343,17 +349,7 @@ Decon MainDeconvolution(const Config config, const Input inp, const int silent) //Calculate the fit data and error. decon.fitdat = calloc(config.lengthmz, sizeof(double)); - decon.error = errfunspeedy(inp.dataInt, decon.fitdat, decon.blur, config.lengthmz, config.numz, maxlength, - config.isolength, inp.isotopepos, inp.isotopeval, starttab, endtab, mzdist, config.speedyflag); - if (config.baselineflag == 1) - { -#pragma omp parallel for schedule(auto) - for (int i = 0; i < config.lengthmz; i++) { - decon.fitdat[i] += decon.baseline[i];// +decon.noise[i]; - //decon.fitdat[i] = decon.noise[i]+0.1; - } - } - ApplyCutoff1D(decon.fitdat, 0, config.lengthmz); + decon.error = errfunspeedy(config, decon, inp.dataInt, maxlength, inp.isotopepos, inp.isotopeval, starttab, endtab, mzdist, &decon.rsquared); // Charge scaling (orbimode) if (config.orbimode == 1) @@ -470,7 +466,8 @@ Decon MainDeconvolution(const Config config, const Input inp, const int silent) // ....................................... double scorethreshold = 0; - decon.uniscore = score(config, decon.mlen, inp.dataMZ, inp.dataInt, decon.newblur, decon.massaxis, decon.massaxisval, decon.massgrid, inp.nztab, scorethreshold); + decon.uniscore = score(config, decon, inp.dataMZ, inp.dataInt, decon.newblur, decon.massaxis, decon.massaxisval, decon.massgrid, inp.nztab, scorethreshold); + //Free Memory free(mzdist);