From 4ec7ee9ba0e98637afd3d5c38db029850a30b5bc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:56:19 +0000 Subject: [PATCH 1/3] Initial plan From 5c3e3c842d86fae23aeaf156faa85bc73bd5c247 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 20:58:14 +0000 Subject: [PATCH 2/3] chore: remove PhosphoScoring.py and GUI_*.py files from examples Co-authored-by: timosachsenberg <5803621+timosachsenberg@users.noreply.github.com> --- src/examples/GUI_EXAMPLE_BASE.py | 53 -------- src/examples/GUI_ErrorWidget.py | 27 ---- src/examples/GUI_MS1MapWidget.py | 21 --- src/examples/GUI_ScanBrowserWidget.py | 20 --- src/examples/GUI_ScanTableWidget.py | 20 --- src/examples/GUI_SequenceIonsWidget.py | 19 --- src/examples/GUI_SpectrumWidget.py | 21 --- src/examples/GUI_TICWidget.py | 46 ------- src/examples/PhosphoScoring.py | 169 ------------------------- 9 files changed, 396 deletions(-) delete mode 100644 src/examples/GUI_EXAMPLE_BASE.py delete mode 100644 src/examples/GUI_ErrorWidget.py delete mode 100644 src/examples/GUI_MS1MapWidget.py delete mode 100644 src/examples/GUI_ScanBrowserWidget.py delete mode 100644 src/examples/GUI_ScanTableWidget.py delete mode 100644 src/examples/GUI_SequenceIonsWidget.py delete mode 100644 src/examples/GUI_SpectrumWidget.py delete mode 100644 src/examples/GUI_TICWidget.py delete mode 100644 src/examples/PhosphoScoring.py diff --git a/src/examples/GUI_EXAMPLE_BASE.py b/src/examples/GUI_EXAMPLE_BASE.py deleted file mode 100644 index 34969bc89..000000000 --- a/src/examples/GUI_EXAMPLE_BASE.py +++ /dev/null @@ -1,53 +0,0 @@ -import sys - -import pyqtgraph as pg -from PyQt5.QtWidgets import QApplication -from PyQt5.QtWidgets import QMainWindow -from PyQt5.QtWidgets import QVBoxLayout -from PyQt5.QtWidgets import QWidget -from PyQt5.QtWidgets import QAction - -pg.setConfigOption("background", "w") # white background -pg.setConfigOption("foreground", "k") # black peaks - - -class GUI_EXAMPLE_BASE(QMainWindow): - def __init__(self): - QMainWindow.__init__(self) - self.resize(800, 601) - self._initUI() - - def _initUI(self): - self.setWindowTitle("Example Widget Viewer") - self.centerWidget = QWidget(self) - self.setCentralWidget(self.centerWidget) - self.layout = QVBoxLayout(self.centerWidget) - - self._setMainMenu() - self._setExitButton() - - def _setMainMenu(self): - mainMenu = self.menuBar() - mainMenu.setNativeMenuBar(False) - self.titleMenu = mainMenu.addMenu("PyOpenMS") - - def _setExitButton(self): - exitButton = QAction("Exit", self) - exitButton.setShortcut("Ctrl+Q") - exitButton.setStatusTip("Exit application") - exitButton.triggered.connect(self.close) - self.titleMenu.addAction(exitButton) - - def closeEvent(self, event): - event.accept() - - def setExampleWidget(self, widget): - self.widget = widget - self.layout.addWidget(self.widget) - - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_ErrorWidget.py b/src/examples/GUI_ErrorWidget.py deleted file mode 100644 index 2361cb33e..000000000 --- a/src/examples/GUI_ErrorWidget.py +++ /dev/null @@ -1,27 +0,0 @@ -import sys - -import numpy as np -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtWidgets import QApplication - -sys.path.insert(0, "../view") -from ErrorWidget import ErrorWidget - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - - # add example widget to window - example_widget = ErrorWidget(ex) - x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) - y = np.array([-2, 3, -8, -4, 3, 12, -15, 10, 5, -12]) - green = (0, 255, 0) - purple = (128, 0, 255) - c = np.array( - [green, purple, green, purple, green, - purple, green, purple, green, green] - ) - example_widget.setMassErrors(x, y, c) - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_MS1MapWidget.py b/src/examples/GUI_MS1MapWidget.py deleted file mode 100644 index 9c631c2b2..000000000 --- a/src/examples/GUI_MS1MapWidget.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys - -import pyopenms -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtWidgets import QApplication - -sys.path.insert(0, "../view") -from MS1MapWidget import MS1MapWidget - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - - # load spectra and add example widget to window - exp = pyopenms.MSExperiment() - pyopenms.MzMLFile().load("../data/190509_Ova_native_25ngul_R.mzML", exp) - example_widget = MS1MapWidget(ex) - example_widget.setSpectra(exp) - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_ScanBrowserWidget.py b/src/examples/GUI_ScanBrowserWidget.py deleted file mode 100644 index 723cb7d8b..000000000 --- a/src/examples/GUI_ScanBrowserWidget.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys - -import pyopenms -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtWidgets import QApplication - -sys.path.insert(0, "../view") -from ScanBrowserWidget import ScanBrowserWidget - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - - # load spectra and add example widget to window - exp = pyopenms.MSExperiment() - example_widget = ScanBrowserWidget() - example_widget.loadFile("../data/190509_Ova_native_25ngul_R.mzML") - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_ScanTableWidget.py b/src/examples/GUI_ScanTableWidget.py deleted file mode 100644 index 10046746d..000000000 --- a/src/examples/GUI_ScanTableWidget.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys - -import pyopenms -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtWidgets import QApplication - -sys.path.insert(0, "../view") -from ScanTableWidget import ScanTableWidget - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - - # load spectra and add example widget to window - exp = pyopenms.MSExperiment() - pyopenms.MzMLFile().load("../data/190509_Ova_native_25ngul_R.mzML", exp) - example_widget = ScanTableWidget(exp) - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_SequenceIonsWidget.py b/src/examples/GUI_SequenceIonsWidget.py deleted file mode 100644 index 4c363227a..000000000 --- a/src/examples/GUI_SequenceIonsWidget.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtWidgets import QApplication -sys.path.insert(0, "../view") -from SequenceIonsWidget import SequenceIonsWidget - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - example_widget = SequenceIonsWidget(ex) - example_widget.setPeptide("HLDKIDMLKSLD") - example_widget.setPrefix( - {1: ["a1", "b1", "c1"], 3: ["a3", "b3", "c3"], 5: ["a3", "b3", "c3"]} - ) - example_widget.setSuffix( - {1: ["x1", "x3"], 2: ["x2", "y2"], 4: ["x4", "y4", "z4"]}) - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_SpectrumWidget.py b/src/examples/GUI_SpectrumWidget.py deleted file mode 100644 index 4fed25a2e..000000000 --- a/src/examples/GUI_SpectrumWidget.py +++ /dev/null @@ -1,21 +0,0 @@ -import sys - -import pyopenms -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtWidgets import QApplication - -sys.path.insert(0, "../view") -from SpectrumWidget import SpectrumWidget - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - - # load spectra and add example widget to window - exp = pyopenms.MSExperiment() - pyopenms.MzMLFile().load("../data/190509_Ova_native_25ngul_R.mzML", exp) - example_widget = SpectrumWidget(ex) - example_widget.setSpectrum(exp.getSpectrum(0)) - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/GUI_TICWidget.py b/src/examples/GUI_TICWidget.py deleted file mode 100644 index ca1475850..000000000 --- a/src/examples/GUI_TICWidget.py +++ /dev/null @@ -1,46 +0,0 @@ -import sys - -import pyopenms -from GUI_EXAMPLE_BASE import GUI_EXAMPLE_BASE -from PyQt5.QtCore import QObject -from PyQt5.QtWidgets import QApplication - -sys.path.insert(0, "../view") -from TICWidget import TICWidget - - -# mock object to test the mouse click signal by TICWidget - - -class TestMouseClick(QObject): - old_variable = (0, 0) - - def __init__(self): - QObject.__init__(self) - - def printRT(self, rt): - print("Mouse clicked at RT=" + str(rt)) - - def printRTBounds(self, start_rt, stop_rt): - if TestMouseClick.old_variable != (start_rt, stop_rt): - print("RT Bounds: ", start_rt, stop_rt) - - TestMouseClick.old_variable = (start_rt, stop_rt) - - -if __name__ == "__main__": - app = QApplication(sys.argv) - ex = GUI_EXAMPLE_BASE() # plain QMainWindow with basic layout and menu bar - - # load spectra and add example widget to window - exp = pyopenms.MSExperiment() - pyopenms.MzMLFile().load("../data/190509_Ova_native_25ngul_R.mzML", exp) - example_widget = TICWidget(ex) - example_widget.setTIC(exp.calculateTIC()) - mouse_click_test = TestMouseClick() - example_widget.sigRTClicked.connect(mouse_click_test.printRT) - example_widget.sigSeleRTRegionChangeFinished.connect( - mouse_click_test.printRTBounds) - ex.setExampleWidget(example_widget) - ex.show() - sys.exit(app.exec_()) diff --git a/src/examples/PhosphoScoring.py b/src/examples/PhosphoScoring.py deleted file mode 100644 index b1a951ed7..000000000 --- a/src/examples/PhosphoScoring.py +++ /dev/null @@ -1,169 +0,0 @@ -""" --------------------------------------------------------------------------- - OpenMS -- Open-Source Mass Spectrometry --------------------------------------------------------------------------- -Copyright The OpenMS Team -- Eberhard Karls University Tuebingen, -ETH Zurich, and Freie Universitaet Berlin 2002-2013. - -This software is released under a three-clause BSD license: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of any author or any participating institution - may be used to endorse or promote products derived from this software - without specific prior written permission. -For a full list of authors, refer to the file AUTHORS. --------------------------------------------------------------------------- -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING -INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" -import re - -import pyopenms - - -def convertToRichMSSpectrum(input_): - rs = pyopenms.RichMSSpectrum() - for p in input_: - rp = pyopenms.RichPeak1D() - rp.setMZ(p.getMZ()) - rp.setIntensity(p.getIntensity()) - rs.push_back(rp) - return rs - - -def convertToMSSpectrum(input_): - spectrum = pyopenms.MSSpectrum() - for p in input_: - rp = pyopenms.Peak1D() - rp.setMZ(p.getMZ()) - rp.setIntensity(p.getIntensity()) - spectrum.push_back(rp) - return spectrum - - -""" -Two phospho scorers, the interface is available through the "score" function: - -- Input: - - PeptideHit (pyopenms.PeptideHit) - - Spectrum (pyopenms.MSSpectrum) - - [Scorer massDelta] - -- Output: - [ Score, NewSequence ] -""" - - -class PhosphoScorerAScore: - def score(self, phit, spectrum, massDelta=0.5): - nr_sites = phit.getSequence().toString().count("Phospho") - rs = convertToRichMSSpectrum(spectrum) - newhit = pyopenms.AScore().compute(phit, rs, massDelta, nr_sites) - return [newhit.getScore(), newhit.getSequence()] - - -class PhosphoScorerSimple: - def score(self, phit, spectrum): - nr_sites = phit.getSequence().toString().count("Phospho") - if nr_sites != 1: - return [-1, pyopenms.AASequence()] - return self.simplisticBinnedScoring(phit, spectrum) - - def simplisticBinnedScoring(self, phit, spectrum): - """Simplistic phospho-scoring of a spectrum against a peptide hit. - - This function enumerates all possible locations for the - phosphorylation and computes a similarity score between the - experimental spectrum and the theoretical spectrum for each - possibility. - """ - seq = phit.getSequence().toString() - seq = seq.replace("(Phospho)", "") - possibilities = [] - spectrum_b = self.binSpectrum(spectrum) - charge = 1 - # Iterate over all possible phosphosites - for m in re.finditer("[STY]", seq): - new_sequence = \ - seq[: m.start() + 1] + "(Phospho)" + seq[m.start() - 1:] - new_aaseq = pyopenms.AASequence(new_sequence) - # Generate theoretical spectrum - spectrum_generator = pyopenms.TheoreticalSpectrumGenerator() - rs = pyopenms.RichMSSpectrum() - try: - spectrum_generator.addPeaks( - rs, new_aaseq, pyopenms.Residue.ResidueType.YIon, charge - ) - spectrum_generator.addPeaks( - rs, new_aaseq, pyopenms.Residue.ResidueType.BIon, charge - ) - except AttributeError: - # 1.11 - spectrum_generator.addPeaks( - rs, new_aaseq, pyopenms.ResidueType.YIon, charge - ) - spectrum_generator.addPeaks( - rs, new_aaseq, pyopenms.ResidueType.BIon, charge - ) - theor = convertToMSSpectrum(rs) - theor_b = self.binSpectrum(theor) - # Compare theoretical spectrum to experimental spectrum - comp_score = self.compare_binnedSpectra(spectrum_b, theor_b) - possibilities.append([comp_score, new_aaseq]) - - # Sort the result by score, return the best scoring result - possibilities.sort(lambda x, y: -cmp(x[0], y[0])) - return possibilities[0] - - def compare_binnedSpectra(self, sp1, sp2): - """Compare two binned spectra, return a similarity score - - The two binned spectra should be created by a call to binSpectrum.""" - - start = max(min(sp1.keys()), min(sp2.keys())) - end = min(max(sp1.keys()), max(sp2.keys())) + 1 - - # Normalize input - import math - - magnitude1 = math.sqrt(sum([v * v for v in sp1.values()])) - magnitude2 = math.sqrt(sum([v * v for v in sp2.values()])) - - sp1_norm = dict([(k, v / magnitude1) for k, v in sp1.iteritems()]) - sp2_norm = dict([(k, v / magnitude2) for k, v in sp2.iteritems()]) - - # Compute similarity score - score = 0 - for i in range(start, end): - score += sp1_norm[i] * sp2_norm[i] - return score - - def binSpectrum(self, sp): - """Bin a spectrum into single, 1 m/z wide bins""" - assert sp.isSorted() - peaks = sp.get_peaks() - mz = sp.get_peaks()[:, 0] - bins = {} - start = int(min(mz)) - end = int(max(mz)) + 1 - for i in range(start, end): - bins[i] = sum([p[1] for p in peaks if int(p[0]) == i]) - return bins - - -if __name__ == "__main__": - print - "This file is intended as library and not as Python executable," - "please do not execute it directly." From b4f16d42b6c0d993a3d12943f51957adbc266596 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 21:10:22 +0000 Subject: [PATCH 3/3] chore: remove runPhosphoScoring.py and update README.md Co-authored-by: timosachsenberg <5803621+timosachsenberg@users.noreply.github.com> --- src/examples/README.md | 7 +- src/examples/runPhosphoScoring.py | 131 ------------------------------ 2 files changed, 1 insertion(+), 137 deletions(-) delete mode 100755 src/examples/runPhosphoScoring.py diff --git a/src/examples/README.md b/src/examples/README.md index fcf9f3914..c48ddc45e 100644 --- a/src/examples/README.md +++ b/src/examples/README.md @@ -19,9 +19,4 @@ This folder contains example scripts using pyOpenMS: - `pymol_example.py` * An example of mapping identified peptide sequences from an MS/MS experiment onto a 3D crystal strucutre of a protein using Python with - `pymol`. -- `runPhosphoScoring.py` - * An implementation of a phospho-site scoring algorithm completely in - Python using the available OpenMS data structures. It compares its result - with the search-engine provided result and the one of the AScore - algorithm as implemented in OpenMS. + `pymol`. diff --git a/src/examples/runPhosphoScoring.py b/src/examples/runPhosphoScoring.py deleted file mode 100755 index 10905b7bf..000000000 --- a/src/examples/runPhosphoScoring.py +++ /dev/null @@ -1,131 +0,0 @@ -########################################################################### -# Biological example of phosphopeptide-scoring -########################################################################### -from PhosphoScoring import PhosphoScorerSimple, PhosphoScorerAScore -import pyopenms -import csv - -pepxml_file = "data/sample_xtandem_output.pep.xml" -mzml_file = "data/sample_spectra.mzML" -output = "sample_ascore_output.csv" -fh = open(output, "w") -writer = csv.writer(fh) - -# Cutoff for filtering peptide hits by their score -cutoff_score = 0.75 - -# -# Data I/O : load the pep.xml file and the mzXML file -# -protein_ids = [] -peptide_ids = [] -pyopenms.PepXMLFile().load(pepxml_file, protein_ids, peptide_ids) -exp = pyopenms.MSExperiment() -pyopenms.FileHandler().loadExperiment(mzml_file, exp) - - -def compute_spectrum_bins(exp): - rt_bins = {} - for s in exp: - if s.getMSLevel() == 1: - continue - tmp = rt_bins.get(int(s.getRT()), []) - tmp.append(s) - rt_bins[int(s.getRT())] = tmp - return rt_bins - - -def mapPeptideIdsToSpectra(peptide_ids, exp, matching_mass_tol=1.0): - rt_bins = compute_spectrum_bins(exp) - hit_mapping = {} - for i, pid in enumerate(peptide_ids): - rt = pid.getMetaValue("RT") - mz = pid.getMetaValue("MZ") - # identify the corresponding spectrum from the correct RT bin - corresponding_spectras = rt_bins[int(rt)] - for corresponding_spectrum in corresponding_spectras: - if ( - abs( - corresponding_spectrum.getPrecursors()[0].getMZ() - mz - ) < - matching_mass_tol - ): - hit_mapping[i] = corresponding_spectrum - if not hit_mapping.hasKey(i): - print - "Could not map hit at RT %s and MZ %s" % (rt, mz) - return hit_mapping - - -# -# Filter the search results and create the mapping of search results to spectra -# -filtered_ids = [p for p in peptide_ids if p.getHits()[0].getScore() > - cutoff_score] -# For teaching purposes, only ids betwen 1200 and 1600 s in RT are kept -# (also the spectra are filtered) -filtered_ids = [ - p - for p in filtered_ids - if p.getMetaValue("RT") > 1200 and p.getMetaValue("RT") < 1600 -] -print -"===========================================================================" -print -"Filtered: kept %s ids below the cutoff score of %s out of %s" % ( - len(filtered_ids), - cutoff_score, - len(peptide_ids), -) -hit_mapping = mapPeptideIdsToSpectra(filtered_ids, exp) - -# -# Iterate through all peptide hits, extract the corresponding spectra and hand -# it to a scoring function. -# - -# Writer CSV header -print -"Will print the original, search-engine sequence," \ - " the AScore sequence and the PhosphoScorerSimple sequence" -writer.writerow( - [ - "Search-Engine Score", - "AScore", - "AScore sequence", - "Simple Scorer sequence", - "Old Sequence", - "# Sites", - ] -) -for i in range(len(filtered_ids)): - # Retrieve the input data: - # - the peptide hit from the search engine (we take the first hit here) - # - the corresponding spectrum - phit = filtered_ids[i].getHits()[0] - spectrum = hit_mapping[i] - nr_sites = phit.getSequence().toString().count("Phospho") - - # Skip non-phospho hits - if nr_sites == 0: - continue - - ascore_result = PhosphoScorerAScore().score(phit, spectrum) - simple_result = PhosphoScorerSimple().score(phit, spectrum) - print - "====", phit.getSequence().toString(), ascore_result[ - 1 - ].toString(), simple_result[1].toString() - - # Store the resulting hit in our CSV file - row = [ - phit.getScore(), - ascore_result[0], - ascore_result[1].toString(), - simple_result[1].toString(), - phit.getSequence().toString(), - nr_sites, - ] - writer.writerow(row) - -fh.close()