Commit 7c665cde authored by Yan's avatar Yan
Browse files

Merge branch 'master' into tsq_cid

parents 7dbca9a5 3aece644
## Prasopes
Prasopes
========
Prasopes is a free and open source Thermo/Finnigan .RAW spectra viewer. It is an implementation example of the rawFin library. Its limitation in means of the supported format scope is defined by the current developemnt state of the rawFin library.
## Installation
Install using the command bellow. Remove --user from command if You want to
install the application into system directory.
```
python3 setup.py install --user
```
## Usage
If running from cmdline, the first argument is taken as a spectrum file. Otherwise use File -> Open or Ctrl+O to open a spectrum.
Execute as: `prasopes [<SPECTRUM_FILE_PATH>]`
The `SPECTRUM_FILE_PATH` argument is optional, it is path to file with spectrum.
Use File -> Open or Ctrl+O to open a spectrum from GUI.
For exporting a spectrum use File -> Export or Ctrl+E.
## GUI control ##
### GUI control
* **Doubleclick** resets active graph
* **right button selection** selects timelapse in chromatogram and zoom the selection in mass spectrum
* **left button** pan on x-axis
* **scrolling** zoom on x-axis
* **shift + scrolling** zoom on y-axis
#!/usr/bin/env python3
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.widgets import SpanSelector
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from rawprasslib import load_raw
import prasopes.graphtools as gt
import prasopes.filetools as ft
import prasopes.zcetools as zce
import sys
import matplotlib
import logging
matplotlib.use("Qt5Agg")
def load_file(chrom_plot, spc, d_set, ms_s, fn, chrom_s):
"""populates dataset and plots it"""
lf = ft.open_dial(d_set)
if lf is not None:
gt.populate(chrom_plot, spc, d_set, ms_s, chrom_s)
fn[0] = lf
if __name__ == "__main__":
# ds for data_set, ms for mass_spec_dataset, chrom for chrom_dataset
ds = dict(chrom_dat=None, masses=None, matrix=None)
ms = dict(x=[0], y=[0], line=None, annotation=[],
name="Spectrum", xlabel="m/z", ylabel="ion count")
chrom = dict(x=[0], y=[0], line=None, t_start=None, t_end=None,
name="Chromatogram", xlabel="time(min)",
ylabel="total ion count")
filename = [None]
p_logger = logging.getLogger('parseLogger')
logging.basicConfig()
p_logger.setLevel("WARN")
graph = Figure(figsize=(5, 4), dpi=100)
graph.patch.set_facecolor("None")
chromatogram = graph.add_subplot(211, facecolor=(1, 1, 1, 0.8))
spectrum = graph.add_subplot(212, facecolor=(1, 1, 1, 0.8))
graph.tight_layout()
mpl_canvas = FigureCanvas(graph)
mpl_canvas.setStyleSheet("background-color:transparent;")
mpl_canvas.setAutoFillBackground(False)
mpl_canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
gt.pan_factory(chromatogram)
gt.zoom_factory(chromatogram, 1.15)
gt.pan_factory(spectrum, ms)
gt.zoom_factory(spectrum, 1.15, ms)
gt.mass_selector = SpanSelector(
spectrum, lambda x_min, x_max: gt.pick_masses(
x_min, x_max, spectrum, ms),
'horizontal', useblit=True, rectprops=dict(
alpha=0.15, facecolor='purple'), button=3)
gt.time_selector = SpanSelector(
chromatogram, lambda x_min, x_max: gt.pick_times(
x_min, x_max, spectrum, ds, chromatogram, ms, chrom),
'horizontal', useblit=True, rectprops=dict(
alpha=0.15, facecolor='purple'), button=3)
app = QtWidgets.QApplication(sys.argv)
main_window = QtWidgets.QMainWindow()
main_window.setWindowTitle("Prasopes")
file_menu = QtWidgets.QMenu('&File', main_window)
main_window.menuBar().addMenu(file_menu)
file_menu.addAction('&Open..', lambda: load_file(
chromatogram, spectrum, ds, ms, filename, chrom),
QtCore.Qt.CTRL + QtCore.Qt.Key_O)
file_menu.addAction('&Export..', lambda: ft.export_dial(
ms, chrom, filename, main_window),
QtCore.Qt.CTRL + QtCore.Qt.Key_E)
file_menu.addAction('&Quit', main_window.close,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
tools_menu = QtWidgets.QMenu('&Tools', main_window)
main_window.menuBar().addMenu(tools_menu)
tools_menu.addAction('&TSQ zce', lambda: zce.dialog(
main_window, ds, filename), QtCore.Qt.CTRL + QtCore.Qt.Key_T)
main_widget = QtWidgets.QWidget(main_window)
main_window.setCentralWidget(main_widget)
layout = QtWidgets.QVBoxLayout(main_widget)
layout.addWidget(mpl_canvas)
mpl_canvas.setFocus()
if len(sys.argv) == 2:
raw_file = sys.argv[1]
filename[0] = raw_file
ds['chrom_dat'], ds['masses'], ds['matrix'] = load_raw(raw_file)
gt.populate(chromatogram, spectrum, ds, ms, chrom)
else:
gt.pop_plot(spectrum, ms)
gt.pop_plot(chromatogram, chrom)
main_window.show()
sys.exit(app.exec_())
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from rawprasslib import load_raw
import os.path
def open_dial(d_set):
"""Populates dataset, returns filename"""
filename = QtWidgets.QFileDialog.getOpenFileName(
caption="Open spectrum",
filter="Finnigan RAW files (*.raw, *.RAW)")[0]
if filename is not'':
d_set['chrom_dat'], d_set['masses'], d_set['matrix'] \
= load_raw(filename)
return filename
else:
return None
def export_dial(mass_spec, chrom_spec, fn, main_window):
"""exports the chromatogram into the .dat file format"""
if fn[0] is None:
QtWidgets.QMessageBox.warning(
main_window, "Export spectrum",
"Nothing to export, cancelling request")
return
exp_f_name = QtWidgets.QFileDialog.getSaveFileName(
caption="Export spectrum",
filter="dat table format (*.dat)")[0]
if exp_f_name is not '':
# fix for Qt5 "Feature"
if exp_f_name[-4:] != '.dat':
exp_f_name = exp_f_name + ".dat"
if os.path.isfile(exp_f_name):
quest = QtWidgets.QMessageBox.warning(
main_window, "Export spectrum",
"{} already exists.\n Do you want to replace it?"
.format(os.path.basename(exp_f_name)),
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
if(hex(quest)) == "0x10000":
return
expf = open(exp_f_name, 'w')
expf.write("mass ion_count\n"
"m/z\n"
"{}_{:.4}-{:.4}_minutes_of_the_aquisition\n".format(
os.path.basename(fn[0]),
chrom_spec['t_start'], chrom_spec['t_end']))
for i in range(len(mass_spec['x'])):
expf.write("{} {}\n".format(
mass_spec['x'][i], mass_spec['y'][i]))
expf.close()
#!/usr/bin/env python3
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
from matplotlib.widgets import SpanSelector
from PyQt5 import QtCore
from PyQt5 import QtWidgets
from rawParse import load_raw
import os.path
import sys
import matplotlib
import numpy as np
import logging
matplotlib.use("Qt5Agg")
def zoom_factory(axis, base_scale, plot_data=None):
......@@ -148,26 +135,6 @@ def pick_times(x_min, x_max, mpl_spectrum, data_set, mpl_chromatogram,
mpl_chromatogram.plot(dots_x, dots_y, 'b.')
def populate(mpl_chromatogram, mpl_spectrum, data_set,
mass_spect, chrom_spect):
"""populate the GUI plots with desired dataset"""
mass_spect['annotation'].clear()
mpl_spectrum.clear()
mpl_chromatogram.clear()
mass_spect['x'] = data_set['masses']
mass_spect['y'] = np.mean(data_set['matrix'], axis=0)
pop_plot(mpl_spectrum, mass_spect)
mpl_spectrum.figure.canvas.draw()
chrom_spect['x'] = data_set['chrom_dat'][0, :]
chrom_spect['y'] = data_set['chrom_dat'][1, :]
chrom_spect['t_start'] = data_set['chrom_dat'][0, 0]
chrom_spect['t_end'] = data_set['chrom_dat'][0, -1]
pop_plot(mpl_chromatogram, chrom_spect)
mpl_chromatogram.figure.canvas.draw()
def ann_spec(ms_spec, msdata, ann_limit=0.01):
"""annotate spectrum
......@@ -240,249 +207,22 @@ def pop_plot(plot, plot_data):
ann_spec(plot, plot_data)
def open_file(chrom_plot, spc, d_set, ms_s, fn, chrom_s):
"""Returns chromatogram, masses and ion intensities"""
fn[0] = QtWidgets.QFileDialog.getOpenFileName(
caption="Open spectrum",
filter="Finnigan RAW files (*.raw, *.RAW)")[0]
if fn[0] is not'':
d_set['chrom_dat'], d_set['masses'], d_set['matrix'] \
= load_raw(fn[0])
populate(chrom_plot, spc, d_set, ms_s, chrom_s)
def export(mass_spec, chrom_spec, fn):
"""exports the spectrum into the .dat file format"""
if fn[0] is None:
QtWidgets.QMessageBox.warning(
main_window, "Export spectrum",
"Nothing to export, cancelling request")
return
exp_f_name = QtWidgets.QFileDialog.getSaveFileName(
caption="Export spectrum",
filter="dat table format (*.dat)")[0]
if exp_f_name is not '':
# fix for Qt5 "Feature"
if exp_f_name[-4:] != '.dat':
exp_f_name = exp_f_name + ".dat"
if os.path.isfile(exp_f_name):
quest = QtWidgets.QMessageBox.warning(
main_window, "Export spectrum",
"{} already exists.\n Do you want to replace it?"
.format(os.path.basename(exp_f_name)),
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
if(hex(quest)) == "0x10000":
return
expf = open(exp_f_name, 'w')
expf.write("mass ion_count\n"
"m/z\n"
"{}_{:.4}-{:.4}_minutes_of_the_aquisition\n".format(
os.path.basename(fn[0]),
chrom_spec['t_start'], chrom_spec['t_end']))
for i in range(len(mass_spec['x'])):
expf.write("{} {}\n".format(
mass_spec['x'][i], mass_spec['y'][i]))
expf.close()
def pop_zce(zcespec, gradspect, data_set, widget, zce_d, zgrad_d,
textfield, fn):
if fn[0] is None:
QtWidgets.QMessageBox.warning(
main_window, "ZCE calculation",
"No spectrum opened, cancelling request")
return
zcespec.clear()
gradspect.clear()
zce_d['x'] = data_set['masses']-196
zce_d['y'] = np.mean(data_set['matrix'], axis=0)
zgrad_d['x'] = zce['x']
zgrad_d['y'] = -np.gradient(zce_d['y'])
pop_plot(zcespec, zce_d)
pop_plot(gradspect, zgrad_d)
zgrad_d['line'][0].set_color("red")
gradspect.set_ylim(bottom=gradspect.get_ylim()[1] * -0.1)
zcespec.set_title("COFF", loc="center")
maxarg = np.argmax(zgrad_d['y'])
zgrad_d['gmax'] = zce_d['x'][maxarg]
climb = np.argsort(zgrad_d['y'][:maxarg])
fall = np.argsort(zgrad_d['y'][maxarg:]) + maxarg
halfmax = np.max(zgrad_d['y']) / 2
zgrad_d['fwhm_y'] = [halfmax, halfmax]
zgrad_d['fwhm_x'] = [
np.interp(halfmax, zgrad_d['y'][climb], zgrad_d['x'][climb]),
np.interp(halfmax, zgrad_d['y'][fall], zgrad_d['x'][fall])]
zgrad_d['fwhm'] = zgrad_d['fwhm_x'][1] - zgrad_d['fwhm_x'][0]
gradspect.plot(zgrad_d['fwhm_x'], zgrad_d['fwhm_y'], "#880088")
textfield.setText(
"ZCE = {:.2f}\nFWHM = {:.2f}\nCenter(HM) = {:.2f}".format(
zgrad_d['gmax'], zgrad_d['fwhm'],
np.mean(zgrad_d['fwhm_x'])))
gradspect.annotate(' FWHM = {:.2f}'.format(zgrad_d['fwhm']),
xy=(zgrad_d['fwhm_x'][1], zgrad_d['fwhm_y'][1]))
gradspect.annotate('{:.2f}'.format(zgrad_d['gmax']),
xy=(zgrad_d['x'][maxarg], zgrad_d['y'][maxarg]))
zcespec.figure.canvas.draw()
widget.show()
def exp_zce(zce_spec, zcegrad_spec, fn, widget):
"""export the ZCE graph into the .dat file format"""
if fn[0] is None:
QtWidgets.QMessageBox.warning(
main_window, "Export ZCE spectrum",
"Nothing to export, cancelling request")
return
exp_f_name = QtWidgets.QFileDialog.getSaveFileName(
caption="Export ZCE spectrum",
filter="dat table format (*.dat)")[0]
if exp_f_name is not '':
# fix for Qt5 "Feature"
if exp_f_name[-4:] != '.dat':
exp_f_name = exp_f_name + ".dat"
if os.path.isfile(exp_f_name):
quest = QtWidgets.QMessageBox.warning(
main_window, "Export spectrum",
"{} already exists.\n Do you want to replace it?"
.format(os.path.basename(exp_f_name)),
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
if(hex(quest)) == "0x10000":
return
expf = open(exp_f_name, 'w')
expf.write("mass ion_count ion_count_gradient fwhm_x fwhm_y\n"
"m/z\n"
"{} zce={} fwhm={} hmcenter={}\n".format(
os.path.basename(fn[0]), zcegrad_spec['gmax'],
zcegrad_spec['fwhm'],
np.mean(zcegrad_spec['fwhm_x'])))
for i in range(len(zce_spec['x'])):
fwhm = ["",""]
if i <= 1:
fwhm = [zcegrad_spec['fwhm_x'][i],
zcegrad_spec['fwhm_y'][i]]
expf.write("{} {} {} {} {}\n".format(
zce_spec['x'][i], zce_spec['y'][i], zcegrad_spec['y'][i],
fwhm[0], fwhm[1]))
expf.close()
if __name__ == "__main__":
# ds for data_set, ms for mass_spec_dataset, chrom for chrom_dataset
ds = dict(chrom_dat=None, masses=None, matrix=None)
ms = dict(x=[0], y=[0], line=None, annotation=[],
name="Spectrum", xlabel="m/z", ylabel="ion count")
chrom = dict(x=[0], y=[0], line=None, t_start=None, t_end=None,
name="Chromatogram", xlabel="time(min)",
ylabel="total ion count")
filename = [None]
p_logger = logging.getLogger('parseLogger')
logging.basicConfig()
p_logger.setLevel("WARN")
graph = Figure(figsize=(5, 4), dpi=100)
graph.patch.set_facecolor("None")
chromatogram = graph.add_subplot(211, facecolor=(1, 1, 1, 0.8))
spectrum = graph.add_subplot(212, facecolor=(1, 1, 1, 0.8))
graph.tight_layout()
mpl_canvas = FigureCanvas(graph)
mpl_canvas.setStyleSheet("background-color:transparent;")
mpl_canvas.setAutoFillBackground(False)
mpl_canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
pan_factory(chromatogram)
zoom_factory(chromatogram, 1.15)
pan_factory(spectrum, ms)
zoom_factory(spectrum, 1.15, ms)
mass_selector = SpanSelector(
spectrum, lambda x_min, x_max: pick_masses(
x_min, x_max, spectrum, ms),
'horizontal', useblit=True, rectprops=dict(
alpha=0.15, facecolor='purple'), button=3)
time_selector = SpanSelector(
chromatogram, lambda x_min, x_max: pick_times(
x_min, x_max, spectrum, ds, chromatogram, ms, chrom),
'horizontal', useblit=True, rectprops=dict(
alpha=0.15, facecolor='purple'), button=3)
app = QtWidgets.QApplication(sys.argv)
main_window = QtWidgets.QMainWindow()
zce = dict(x=[0], y=[0], line=None, name="",
xlabel="Voltage (V)", ylabel="ion count")
zcegrad = dict(x=[0], y=[0], c_ymin=-0.1, line=None, name="",
xlabel="", ylabel="ion count gradient", gmax=None,
fwhm_x=None,fwhm_y=None, fwhm=None)
zce_graph = Figure(figsize=(5, 2), dpi=100)
zce_graph.patch.set_facecolor("None")
zce_spect = zce_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8))
zce_spect_grad = zce_spect.twinx()
zce_canvas = FigureCanvas(zce_graph)
zce_canvas.setStyleSheet("background-color:transparent;")
zce_canvas.setAutoFillBackground(False)
zce_canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
zoom_factory(zce_spect_grad, 1.15, zcegrad)
pan_factory(zce_spect_grad, zcegrad)
zce_export = QtWidgets.QPushButton("Export ZCE")
zce_export.clicked.connect(lambda: exp_zce(zce,zcegrad,filename, zce_widget))
zce_help = QtWidgets.QPushButton("Help")
zce_close = QtWidgets.QPushButton("Close")
zce_butlayout = QtWidgets.QHBoxLayout()
zce_butlayout.addWidget(zce_help)
zce_butlayout.addStretch(1)
zce_textfield = QtWidgets.QLabel(zcegrad['gmax'])
zce_butlayout.addWidget(zce_textfield)
zce_butlayout.addStretch(1)
zce_butlayout.addWidget(zce_export)
zce_butlayout.addWidget(zce_close)
zce_widget = QtWidgets.QDialog(main_window)
zce_widget.setWindowTitle('TSQ zero collision energy calculator')
zce_layout = QtWidgets.QVBoxLayout(zce_widget)
zce_layout.addWidget(zce_canvas)
zce_layout.addLayout(zce_butlayout)
file_menu = QtWidgets.QMenu('&File', main_window)
main_window.menuBar().addMenu(file_menu)
file_menu.addAction('&Open..', lambda: open_file(
chromatogram, spectrum, ds, ms, filename, chrom),
QtCore.Qt.CTRL + QtCore.Qt.Key_O)
file_menu.addAction('&Export..', lambda: export(
ms, chrom, filename), QtCore.Qt.CTRL + QtCore.Qt.Key_E)
file_menu.addAction('&Quit', main_window.close,
QtCore.Qt.CTRL + QtCore.Qt.Key_Q)
tools_menu = QtWidgets.QMenu('&Tools', main_window)
main_window.menuBar().addMenu(tools_menu)
tools_menu.addAction('&TSQ zce', lambda: pop_zce(
zce_spect, zce_spect_grad, ds, zce_widget, zce, zcegrad,
zce_textfield, filename),
QtCore.Qt.CTRL + QtCore.Qt.Key_T)
main_widget = QtWidgets.QWidget(main_window)
main_window.setCentralWidget(main_widget)
def populate(mpl_chromatogram, mpl_spectrum, data_set,
mass_spect, chrom_spect):
"""populate the GUI plots with desired dataset"""
mass_spect['annotation'].clear()
mpl_spectrum.clear()
mpl_chromatogram.clear()
layout = QtWidgets.QVBoxLayout(main_widget)
layout.addWidget(mpl_canvas)
mpl_canvas.setFocus()
mass_spect['x'] = data_set['masses']
mass_spect['y'] = np.mean(data_set['matrix'], axis=0)
pop_plot(mpl_spectrum, mass_spect)
mpl_spectrum.figure.canvas.draw()
if len(sys.argv) == 2:
raw_file = sys.argv[1]
filename[0] = raw_file
ds['chrom_dat'], ds['masses'], ds['matrix'] = load_raw(raw_file)
populate(chromatogram, spectrum, ds, ms, chrom)
else:
pop_plot(spectrum, ms)
pop_plot(chromatogram, chrom)
chrom_spect['x'] = data_set['chrom_dat'][0, :]
chrom_spect['y'] = data_set['chrom_dat'][1, :]
chrom_spect['t_start'] = data_set['chrom_dat'][0, 0]
chrom_spect['t_end'] = data_set['chrom_dat'][0, -1]
pop_plot(mpl_chromatogram, chrom_spect)
mpl_chromatogram.figure.canvas.draw()
main_window.show()
sys.exit(app.exec_())
from setuptools import setup
with open("README.md", "r") as fh:
long_description = fh.read()
setup(
name="prasopes",
version="0.0.1",
author="Jan Zelenka",
author_email="3yanyanyan@gmail.com",
description="Thermo/Finnigan .raw file viewer based on rawprasslib",
long_description=long_description,
url="https://gitlab.science.ru.nl/jzelenka/prasopes",
packages=['prasopes'],
classifiers=[
"Programming Language :: Python :: 3",
"Operating System :: OS Independent",
"Development Status :: 3-Alpha",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Chemistry",
],
install_requires=['numpy', 'PyQt5-sip', 'matplotlib', 'rawprasslib'],
entry_points={
'console_scripts': [
# example:
'prasopes = prasopes.__main__'
],
}
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment