Commit 781531ed authored by Yan's avatar Yan
Browse files

Add parent completely redone, add daughter removed

* Revision towards JR wishes
parent d335b0dd
......@@ -5,13 +5,12 @@ from matplotlib.figure import Figure
from matplotlib.widgets import SpanSelector
from PyQt5 import QtCore
from PyQt5 import QtWidgets
import prasopes.graphtools as gt
from PyQt5 import QtGui
import sys
import matplotlib
import numpy as np
matplotlib.use("Qt5Agg")
class HBar(QtWidgets.QFrame):
"""horizontal bar class"""
def __init__(self):
......@@ -20,258 +19,171 @@ class HBar(QtWidgets.QFrame):
self.setFrameShape(QtWidgets.QFrame.HLine)
def add_parent(parent_widget, mass_selector, spectrum, ds, parenttable):
"""add parent ion to the table"""
ap_dial = QtWidgets.QDialog(parent_widget, windowTitle='Add Ion')
parent_widget.finished.connect(ap_dial.close)
ion = dict(x=[0], y=[0], line=None, name="", xlabel="m/z",
ylabel="ion count", annotation=[])
ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
ionspect = ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8))
graph_canvas = FigureCanvas(ion_graph)
ion_graph.tight_layout()
graph_canvas.setStyleSheet("background-color:transparent;")
graph_canvas.setAutoFillBackground(False)
graph_canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
gt.pop_plot(ionspect, ion)
def add_ion(start_mz, end_mz, figure, canvas, table, dialog):
"""extracts provided widgets and put them into table"""
newrow = table.rowCount()
table.setRowCount(newrow+1)
table.setItem(newrow,0,QtWidgets.QTableWidgetItem())
table.horizontalHeader().setSectionResizeMode(
1, QtWidgets.QHeaderView.ResizeToContents)
table.horizontalHeader().setSectionResizeMode(
2, QtWidgets.QHeaderView.ResizeToContents)
figure.subplots_adjust(-0.01,0,1,1,0,0)
table.setCellWidget(newrow,1,start_mz)
table.setCellWidget(newrow,2,end_mz)
table.setCellWidget(newrow,3,canvas)
dialog.close()
def end_bindings(bindings, axis):
fig = axis.get_figure()
for i in bindings:
axis.canvas.mpl_disconnect(i)
return
def update_parent(start_mz, end_mz, spectrum, ion_set, dataset):
start = start_mz.value()
end = end_mz.value()
if start > end:
start = end_mz.value()
end = start_mz.value()
start_mz.setValue(start)
end_mz.setValue(end)
#Dont do anything to graph when the spectrum is not populated
if (start == 0 and start == end) or type(dataset['masses']) == type(None):
return
#TODO: make the function more economical both in CPU load and in linecount
start_mass = None
end_mass = None
for i, mass in enumerate(dataset['masses'][0:]):
if mass > start and start_mass is None:
start_mass = i
if mass > end and end_mass is None:
end_mass = i
if end_mass is None:
end_mass = len(dataset['masses'])
if start_mass is None:
start_mass = len(dataset['masses'])-1
if start_mass == end_mass:
if start_mass == 0:
end_mass = 1
else:
start_mass -= 1
end_mass = start_mass + 2
spectrum.clear()
gt.pop_plot(spectrum, ion_set)
yshape = np.mean(dataset['matrix'], axis=0)
dots_x = dataset['masses']
dots_y = yshape
full_x = dataset['masses'][start_mass:end_mass]
full_y = yshape[start_mass:end_mass]
spectrum.plot(dots_x, dots_y, ':', color='gray')
spectrum.plot(full_x, full_y, 'r')
xex = (dataset['masses'][end_mass-1]-dataset['masses'][start_mass])*0.25
spectrum.set_xlim(dataset['masses'][start_mass]-xex,dataset['masses'][end_mass-1]+xex)
ymax = max(yshape[start_mass:end_mass])
spectrum.set_ylim(ymax*-0.1, ymax*1.1)
spectrum.figure.canvas.draw()
def update_fields(x_min, x_max, startw, endw, spectrum, ion_set, dataset):
endw.setValue(x_max)
startw.setValue(x_min)
update_parent(startw, endw, spectrum, ion_set, dataset)
def activate_altselector(event, mass_selector, picker):
if event.key == 'shift':
mass_selector.active = False
picker.active = True
def deactivate_altselector(mass_selector, picker):
mass_selector.active = True
picker.active = False
def deactivate_keyrelease(event, mass_selector, picker):
if event.key == 'shift':
deactivate_altselector(mass_selector, picker)
ax = spectrum.get_figure()
bindings = []
bindings.append(ax.canvas.mpl_connect('key_press_event', lambda
event: activate_altselector(event, mass_selector, picker)))
bindings.append(ax.canvas.mpl_connect('key_release_event', lambda
event: deactivate_keyrelease(event, mass_selector, picker)))
# TODO: somehow manage if user enters with shift pressed, but
# figure_enter_event cannot handle this :( and with QT it is PIA
bindings.append(ax.canvas.mpl_connect('figure_leave_event', lambda
event: deactivate_altselector(mass_selector, picker)))
ap_dial.finished.connect(lambda: end_bindings(bindings, ax))
start_mz = QtWidgets.QDoubleSpinBox(maximum=999999)
start_mz.editingFinished.connect(lambda: update_parent(
start_mz, end_mz, ionspect, ion, ds))
end_mz = QtWidgets.QDoubleSpinBox(maximum=999999)
end_mz.editingFinished.connect(lambda: update_parent(
start_mz, end_mz, ionspect, ion, ds))
submit = QtWidgets.QPushButton("&Submit")
submit.clicked.connect(lambda: add_ion(start_mz, end_mz, ion_graph, graph_canvas, parenttable, ap_dial))
cancel = QtWidgets.QPushButton("Cancel")
cancel.clicked.connect(ap_dial.close)
main_layout = QtWidgets.QVBoxLayout(ap_dial)
data_layout = QtWidgets.QHBoxLayout()
butt_layout = QtWidgets.QHBoxLayout()
butt_layout.addStretch(1)
butt_layout.addWidget(submit)
butt_layout.addWidget(cancel)
data_layout.addWidget(QtWidgets.QLabel("start:"))
data_layout.addWidget(start_mz)
data_layout.addWidget(QtWidgets.QLabel("m/z"))
data_layout.addSpacing(20)
data_layout.addWidget(QtWidgets.QLabel("end:"))
data_layout.addWidget(end_mz)
data_layout.addWidget(QtWidgets.QLabel("m/z"))
data_layout.addStretch(0)
main_layout.addWidget(QtWidgets.QLabel("Press shift in "
"the chromatogram window and \n"
"select the ion range by the right mouse button\n"
"or fill the columns manually"))
main_layout.addWidget(graph_canvas, 1)
main_layout.addLayout(data_layout)
main_layout.addLayout(butt_layout)
picker = SpanSelector(spectrum, lambda x_min, x_max:
update_fields(x_min, x_max, start_mz, end_mz,
ionspect, ion, ds),
'horizontal', useblit=True, rectprops=dict(
alpha=0.15, facecolor='orange'), button=3)
picker.active = False
ap_dial.show()
def add_daughter(parent_widget, p_table, d_table):
ad_dial = QtWidgets.QDialog(parent_widget, windowTitle='Add line')
parent_widget.finished.connect(ad_dial.close)
if p_table.rowCount() is 0:
QtWidgets.QMessageBox.warning(parent_widget,
'Add line', "The Raw ions table is empty, "
"cancelling request")
def update_spectrum(start, end, spectrum, dataset):
"""spectrum updating procedure"""
#Dont do anything to graph when the spectrum is not populated
if (start == 0 and start == end) or type(dataset['masses']) == type(None):
return
def add_ion(parent_widget, parent, correction, cf, ptable, dtable):
pn = parent.currentIndex()
corr = correction.currentIndex()-1
cf = cf.value()
print(pn,corr,cf)
print(ptable.cellWidget(pn,1).value())
start_mz = QtWidgets.QDoubleSpinBox(maximum=999999)
start_mz.setValue(ptable.cellWidget(pn,1).value())
end_mz = QtWidgets.QDoubleSpinBox(maximum=999999)
end_mz.setValue(ptable.cellWidget(pn,2).value())
newrow = dtable.rowCount()
dtable.setRowCount(newrow+1)
dtable.setItem(newrow,0,QtWidgets.QTableWidgetItem())
dtable.item(newrow,0).setText(ptable.item(pn,0).text())
dtable.horizontalHeader().setSectionResizeMode(
1, QtWidgets.QHeaderView.ResizeToContents)
dtable.horizontalHeader().setSectionResizeMode(
2, QtWidgets.QHeaderView.ResizeToContents)
dtable.setCellWidget(newrow,1,start_mz)
dtable.setCellWidget(newrow,2,end_mz)
#TODO: make the function more economical both in CPU load and in linecount
nlen = len(dataset['masses'])
start_mass = None
end_mass = None
for i, mass in enumerate(dataset['masses'][0:]):
if mass > start and start_mass is None:
start_mass = i
if mass > end and end_mass is None:
end_mass = i
if end_mass is None:
end_mass = len(dataset['masses'])
if start_mass is None:
start_mass = len(dataset['masses'])-1
if start_mass == end_mass:
if start_mass == 0:
end_mass = 1
else:
start_mass -= 1
end_mass = start_mass + 2
spectrum.clear()
yshape = np.mean(dataset['matrix'], axis=0)
dots_x = dataset['masses']
dots_y = yshape
full_x = dataset['masses'][start_mass:end_mass]
full_y = yshape[start_mass:end_mass]
spectrum.plot(dots_x, dots_y, ':', color='gray')
spectrum.plot(full_x, full_y, 'r')
xex = (dataset['masses'][end_mass-1]-dataset['masses'][start_mass])*0.25
spectrum.set_xlim(dataset['masses'][start_mass]-xex,dataset['masses'][end_mass-1]+xex)
ymax = max(yshape[start_mass:end_mass])
spectrum.set_ylim(ymax*-0.1, ymax*1.2)
spectrum.figure.canvas.draw()
def getTableItemList(ptable):
ion_list = []
for i in range(p_table.rowCount()):
if type(p_table.item(i,0)) is not type(None):
name = p_table.item(i,0).text()
for i in range(ptable.rowCount()):
if type(ptable.cellWidget(i,0)) is not type(None):
name = ptable.cellWidget(i,0).text()
else:
name = ""
text = "{} ({}-{})".format(
name, p_table.cellWidget(i,1).value(),
p_table.cellWidget(i,2).value())
name, (ptable.cellWidget(i,1).text()),
(ptable.cellWidget(i,2).text()))
ion_list.append(text)
return ion_list
def update_daughter(pname, start_mz, end_mz, dname, ptable, dtable):
"""update daugher Ion name and "corr to" selection"""
dname.setText("{} ({:.2f}-{:.2f})".format(
pname.text(),float(start_mz.text()),float(end_mz.text())))
for i in (range(dtable.rowCount())):
index = dtable.cellWidget(i,2).currentIndex()
dtable.cellWidget(i,2).clear()
dtable.cellWidget(i,2).addItem("")
dtable.cellWidget(i,2).addItems(getTableItemList(ptable))
dtable.cellWidget(i,2).setCurrentIndex(index)
def update_drl(start_mz, end_mz, spectrum, dataset, pname, dname,
ptable, dtable):
"""keeps start < end and updates spectrum and daughter table"""
start = float(start_mz.text())
end = float(end_mz.text())
if start > end:
start, end = end, start
start_mz.setText(str(start))
end_mz.setText(str(end))
update_spectrum(start, end, spectrum, dataset)
update_daughter(pname, start_mz, end_mz, dname, ptable, dtable)
def remove_rows(ptable, dtable):
# TODO: maybe better selection in future, but this works for now
rows = reversed(list(set(
map(lambda index: index.row(), ptable.selectedIndexes()))))
for row in rows:
dtable.removeRow(row)
ptable.removeRow(row)
for i in range(dtable.rowCount()):
index = dtable.cellWidget(i,2).currentIndex()
dtable.cellWidget(i,2).clear()
dtable.cellWidget(i,2).addItem("")
dtable.cellWidget(i,2).addItems(getTableItemList(ptable))
if index == row+1:
dtable.cellWidget(i,2).setCurrentIndex(0)
elif index > row+1:
dtable.cellWidget(i,2).setCurrentIndex(index-1)
def setDoubleCell(table,row,column):
"""populate table cell with float-validated posititve text"""
table.setCellWidget(row,column,QtWidgets.QLineEdit())
validator = QtGui.QDoubleValidator()
validator.setBottom(0)
table.cellWidget(row,column).setValidator(validator)
table.cellWidget(row,column).setFrame(False)
table.cellWidget(row,column).setText("0")
table.horizontalHeader().setSectionResizeMode(
column, QtWidgets.QHeaderView.ResizeToContents)
return table.cellWidget(row,column)
def add_line(parent_widget, mass_selector, spectrum, ds, parenttable, daughtertable):
"""add parent ion to the table"""
ion_graph = Figure(figsize=(3, 1.5), dpi=100, facecolor="None")
ionspect = ion_graph.add_subplot(111, facecolor=(1, 1, 1, 0.8),
position=(-0.01,-0.01,1.02,1.02))
graph_canvas = FigureCanvas(ion_graph)
graph_canvas.setStyleSheet("background-color:transparent;")
graph_canvas.setAutoFillBackground(False)
newrow = parenttable.rowCount()
p_sel = QtWidgets.QComboBox()
p_sel.addItems(ion_list)
c_sel = QtWidgets.QComboBox()
c_sel.addItem(None)
c_sel.addItems(ion_list)
corr_factor = QtWidgets.QDoubleSpinBox(maximum=1337)
parenttable.setRowCount(newrow + 1)
pname = QtWidgets.QLineEdit()
pname.setFrame(False)
parenttable.setCellWidget(newrow, 0, pname)
start_mz = setDoubleCell(parenttable, newrow, 1)
end_mz = setDoubleCell(parenttable, newrow, 2)
parenttable.setCellWidget(newrow, 3, graph_canvas)
submit = QtWidgets.QPushButton("&Submit")
cancel = QtWidgets.QPushButton("Cancel")
cancel.clicked.connect(ad_dial.close)
daughtertable.setRowCount(newrow + 1)
daughtertable.setItem(newrow,0, QtWidgets.QTableWidgetItem())
daughtertable.item(newrow,0).setFlags(daughtertable.item(newrow,0).flags()
& ~QtCore.Qt.ItemIsSelectable)
daughtertable.setCellWidget(newrow, 0, QtWidgets.QCheckBox())
main_layout = QtWidgets.QVBoxLayout(ad_dial)
data_layout = QtWidgets.QHBoxLayout()
butt_layout = QtWidgets.QHBoxLayout()
dname = QtWidgets.QTableWidgetItem()
dname.setFlags(dname.flags() & ~QtCore.Qt.ItemIsEditable)
daughtertable.setItem(newrow, 1, dname)
butt_layout.addStretch(1)
butt_layout.addWidget(submit)
submit.clicked.connect(lambda: add_ion(
ad_dial, p_sel, c_sel, corr_factor, p_table, d_table))
butt_layout.addWidget(cancel)
corto = QtWidgets.QComboBox()
corto.setFrame(False)
corto.addItem("")
corto.addItems(getTableItemList(parenttable))
daughtertable.setCellWidget(newrow, 2, corto)
data_layout.addWidget(QtWidgets.QLabel("parent ion:"))
data_layout.addWidget(p_sel)
data_layout.addSpacing(20)
data_layout.addWidget(QtWidgets.QLabel("Correct to:"))
data_layout.addWidget(c_sel)
data_layout.addWidget(QtWidgets.QLabel("mutliplied by:"))
data_layout.addWidget(corr_factor)
data_layout.addWidget(QtWidgets.QLabel("%"))
corfact = setDoubleCell(daughtertable, newrow, 3)
main_layout.addLayout(data_layout)
main_layout.addLayout(butt_layout)
update_drl(start_mz, end_mz, ionspect, ds, pname, dname,
parenttable, daughtertable)
ad_dial.show()
pname.editingFinished.connect(lambda: update_daughter(
pname, start_mz, end_mz, dname, parenttable, daughtertable))
start_mz.editingFinished.connect(lambda: update_drl(
start_mz, end_mz, ionspect, ds, pname, dname, parenttable,
daughtertable))
end_mz.editingFinished.connect(lambda: update_drl(
start_mz, end_mz, ionspect, ds, pname, dname, parenttable,
daughtertable))
def iontable(labels, exp_col):
"""creates a table for ions"""
def remove_rows(table):
# TODO: maybe better selection in future, but this works for now
rows = reversed(list(set(
map(lambda index: index.row(), table.selectedIndexes()))))
for row in rows:
table.removeRow(row)
table = QtWidgets.QTableWidget(columnCount=len(labels))
table.setSizePolicy(QtWidgets.QSizePolicy.Expanding,
QtWidgets.QSizePolicy.Expanding)
......@@ -283,21 +195,7 @@ def iontable(labels, exp_col):
n, QtWidgets.QHeaderView.Stretch)
table.setMinimumSize(600,0)
"""tx = table.verticalHeader().width() \
+ table.verticalScrollBar().height()
for n in range(len(labels)):
tx = tx + table.columnWidth(n)
table.setMinimumSize(tx, 0)"""
"""table.horizontalHeader().setSectionResizeMode(
exp_col, QtWidgets.QHeaderView.ResizeToContents)"""
table_add = QtWidgets.QPushButton("Add")
table_rem = QtWidgets.QPushButton("Remove")
table_rem.clicked.connect(lambda: remove_rows(table))
table_butlayout = QtWidgets.QHBoxLayout()
table_butlayout.addWidget(table_add)
table_butlayout.addWidget(table_rem)
table_butlayout.addStretch(0)
return table, table_butlayout, table_add, table_rem
return table
def dialog(parent, ds, filename, mass_selector, spectrum):
......@@ -319,19 +217,24 @@ def dialog(parent, ds, filename, mass_selector, spectrum):
close.clicked.connect(dial_widget.close)
# pt = parenttable
pt, pt_butlayout, pt_add, pt_rem = iontable(
["Name", "start (m/z)", "end (m/z)", "profile"], 2)
pt_add.setText("&Add")
pt_add.clicked.connect(lambda: add_parent(
dial_widget, mass_selector, spectrum, ds, pt))
pt = iontable(["Name", "start (m/z)", "end (m/z)", "profile"], 2)
# dt = daughtertable
dt, dt_butlayout, dt_add, dt_rem = iontable(
["Name", "start (m/z)", "end (m/z)", "corr to", "factor"], 2)
add_corr = QtWidgets.QPushButton("Add correction")
dt_butlayout.addWidget(add_corr)
dt_add.clicked.connect(lambda: add_daughter(
dial_widget, pt, dt))
dt = iontable(["","Name", "corrected to", "factor"], 2)
dt.horizontalHeader().setSectionResizeMode(
0, QtWidgets.QHeaderView.ResizeToContents)
dt.horizontalHeader().setSectionResizeMode(
3, QtWidgets.QHeaderView.Fixed)
btn_add = QtWidgets.QPushButton("&Add")
btn_rem = QtWidgets.QPushButton("Remove")
pt_butlayout = QtWidgets.QHBoxLayout()
pt_butlayout.addWidget(btn_add)
pt_butlayout.addWidget(btn_rem)
pt_butlayout.addStretch(0)
btn_add.clicked.connect(lambda: add_line(
dial_widget, mass_selector, spectrum, ds, pt, dt))
btn_rem.clicked.connect(lambda: remove_rows(pt,dt))
main_layout = QtWidgets.QVBoxLayout(dial_widget)
sub_layout = QtWidgets.QHBoxLayout()
......@@ -354,9 +257,7 @@ def dialog(parent, ds, filename, mass_selector, spectrum):
tablelayout.addWidget(QtWidgets.QLabel("Raw ions table:"))
tablelayout.addWidget(pt)
tablelayout.addLayout(pt_butlayout)
tablelayout.addWidget(HBar())
tablelayout.addWidget(QtWidgets.QLabel("Corrected ions table:"))
tablelayout.addWidget(dt)
tablelayout.addLayout(dt_butlayout)
dial_widget.show()
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