forked from IPKM/nmreval
BUGFIX: VFT;
change to src layout
This commit is contained in:
2
src/gui_qt/data/signaledit/__init__.py
Normal file
2
src/gui_qt/data/signaledit/__init__.py
Normal file
@ -0,0 +1,2 @@
|
||||
from .phase_dialog import QApodDialog, QPhasedialog
|
||||
from .baseline_dialog import QBaselineDialog
|
94
src/gui_qt/data/signaledit/baseline_dialog.py
Normal file
94
src/gui_qt/data/signaledit/baseline_dialog.py
Normal file
@ -0,0 +1,94 @@
|
||||
import numpy as np
|
||||
import pyqtgraph as pg
|
||||
|
||||
from scipy.interpolate import splrep, splev
|
||||
|
||||
from ...Qt import QtCore, QtWidgets
|
||||
from ..._py.baseline_dialog import Ui_SignalEdit
|
||||
|
||||
|
||||
class QBaselineDialog(QtWidgets.QDialog, Ui_SignalEdit):
|
||||
finished = QtCore.pyqtSignal(str, tuple)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.data = None
|
||||
|
||||
self.graph = pg.PlotDataItem(x=[], y=[], pen=pg.mkPen({'color': 'b'}), name='Original')
|
||||
self.graph_corr = pg.PlotDataItem(x=[], y=[], pen=pg.mkPen({'color': 'r'}), name='Corrected')
|
||||
self.baseline = pg.PlotDataItem(x=[], y=[], name='Baseline')
|
||||
|
||||
self.anchors = []
|
||||
self.anchor_lines = []
|
||||
self.spline = None
|
||||
|
||||
self.legend = self.graphicsView.addLegend()
|
||||
|
||||
self.graphicsView.scene().sigMouseClicked.connect(self.add_node)
|
||||
self.graphicsView.addItem(self.graph_corr)
|
||||
self.graphicsView.addItem(self.graph)
|
||||
self.graphicsView.addItem(self.baseline)
|
||||
|
||||
def add_data(self, x, y):
|
||||
if self.data is not None:
|
||||
QtWidgets.QMessageBox().information(self, 'Invalid number of datasets',
|
||||
'Baseline correction is only working on one set at a time.')
|
||||
self.close()
|
||||
self.anchors.extend([np.min(x), np.max(x)])
|
||||
self.data = (x, y)
|
||||
self.graph.setData(x=x, y=y.real)
|
||||
self.graph_corr.setData(x=x, y=y.real)
|
||||
|
||||
def accept(self):
|
||||
self.finished.emit('bls', (splev(self.data[0], self.spline),))
|
||||
self.close()
|
||||
|
||||
def add_node(self, evt):
|
||||
vb = self.graphicsView.plotItem.vb
|
||||
|
||||
if self.graphicsView.plotItem.sceneBoundingRect().contains(evt.scenePos()) and evt.button() == 1:
|
||||
pos = vb.mapSceneToView(evt.scenePos())
|
||||
x = pos.x()
|
||||
|
||||
self.anchors.append(x)
|
||||
self.anchors.sort()
|
||||
row = self.anchors.index(x)
|
||||
self.listWidget.insertItem(row-1, QtWidgets.QListWidgetItem(str(x)))
|
||||
|
||||
inf_line = pg.InfiniteLine(pos=x)
|
||||
self.anchor_lines.insert(row-1, inf_line)
|
||||
self.graphicsView.addItem(inf_line)
|
||||
|
||||
self.change_baseline()
|
||||
|
||||
def change_baseline(self):
|
||||
if self.data:
|
||||
x, y = self.data
|
||||
|
||||
def mean(xx):
|
||||
return np.mean(y[max(0, np.argmin(abs(x-xx))-5):min(len(x), np.argmin(abs(x-xx))+6)].real)
|
||||
|
||||
y_node = [mean(x_node) for x_node in self.anchors]
|
||||
try:
|
||||
self.spline = splrep(self.anchors, y_node, per=False)
|
||||
except TypeError:
|
||||
self.spline = splrep(self.anchors, y_node, per=False, k=1)
|
||||
|
||||
bl = splev(x, self.spline)
|
||||
|
||||
self.baseline.setData(x=x, y=bl)
|
||||
self.graph_corr.setData(x=x, y=y.real-bl)
|
||||
|
||||
def keyPressEvent(self, evt):
|
||||
if self.listWidget.hasFocus() and evt.key() == QtCore.Qt.Key_Delete:
|
||||
r = self.listWidget.currentRow()
|
||||
self.anchors.pop(r+1)
|
||||
listitem = self.listWidget.takeItem(r)
|
||||
del listitem
|
||||
self.graphicsView.removeItem(self.anchor_lines.pop(r))
|
||||
self.change_baseline()
|
||||
|
||||
else:
|
||||
super().keyPressEvent(evt)
|
92
src/gui_qt/data/signaledit/editsignalwidget.py
Normal file
92
src/gui_qt/data/signaledit/editsignalwidget.py
Normal file
@ -0,0 +1,92 @@
|
||||
from src.nmreval.math import apodization
|
||||
from src.nmreval.lib.importer import find_models
|
||||
from src.nmreval.utils.text import convert
|
||||
|
||||
from ...Qt import QtCore, QtWidgets, QtGui
|
||||
from ...lib.forms import FormWidget
|
||||
from ..._py.editsignalwidget import Ui_Form
|
||||
|
||||
|
||||
class EditSignalWidget(QtWidgets.QWidget, Ui_Form):
|
||||
do_something = QtCore.pyqtSignal(str, tuple)
|
||||
get_values = QtCore.pyqtSignal()
|
||||
preview_triggered = QtCore.pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.apodlist = find_models(apodization)
|
||||
|
||||
self.lineEdit.hide()
|
||||
self.lineEdit.setValidator(QtGui.QDoubleValidator())
|
||||
|
||||
for ap in self.apodlist:
|
||||
self.apodcombobox.addItem(str(ap().name))
|
||||
self.change_apodization(0)
|
||||
|
||||
self.baselinebutton.clicked.connect(lambda: self.apply_changes('bl'))
|
||||
self.zfbutton.clicked.connect(lambda: self.apply_changes('zf'))
|
||||
self.phasebutton.clicked.connect(lambda: self.apply_changes('ph'))
|
||||
self.apodbutton.clicked.connect(lambda: self.apply_changes('ap'))
|
||||
self.leftshiftbutton.clicked.connect(lambda: self.apply_changes('ls'))
|
||||
self.fourierutton.clicked.connect(lambda: self.apply_changes('ft'))
|
||||
|
||||
self.pushButton.clicked.connect(lambda: self.preview_triggered.emit('ap'))
|
||||
self.pushButton_2.clicked.connect(lambda: self.preview_triggered.emit('ph'))
|
||||
|
||||
@QtCore.pyqtSlot(str)
|
||||
def apply_changes(self, sender):
|
||||
if sender in ['bl', 'zf', 'ft']:
|
||||
self.do_something.emit(sender, tuple())
|
||||
|
||||
elif sender == 'ls':
|
||||
if self.comboBox.currentIndex() == 0:
|
||||
_nop = int(self.lsspinBox.text())
|
||||
stype = 'pts'
|
||||
else:
|
||||
try:
|
||||
_nop = float(self.lineEdit.text())
|
||||
except ValueError:
|
||||
_nop = 0.0
|
||||
stype = 'time'
|
||||
self.do_something.emit(sender, (_nop, stype))
|
||||
|
||||
elif sender == 'ap':
|
||||
apodmodel = self.apodlist[self.apodcombobox.currentIndex()]
|
||||
p = [float(x.text()) for x in self.groupBox_3.findChildren(QtWidgets.QLineEdit)]
|
||||
self.do_something.emit(sender, (p, apodmodel))
|
||||
|
||||
elif sender == 'ph':
|
||||
ph0 = float(self.ph0slider.value())
|
||||
ph1 = float(self.ph1slider.value())
|
||||
pvt = float(self.pivot_lineedit.text())
|
||||
self.do_something.emit(sender, (ph0, ph1, pvt))
|
||||
|
||||
else:
|
||||
print('You should never reach this by accident.')
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_apodcombobox_currentIndexChanged')
|
||||
def change_apodization(self, index):
|
||||
apod_func = self.apodlist[index]
|
||||
self.label_2.setText(convert(apod_func.equation))
|
||||
|
||||
while self.verticalLayout_8.count():
|
||||
item = self.verticalLayout_8.takeAt(0)
|
||||
try:
|
||||
item.widget().deleteLater()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
for k, v in enumerate(apod_func.params):
|
||||
widgt = FormWidget(name=v)
|
||||
self.verticalLayout_8.addWidget(widgt)
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_comboBox_currentIndexChanged')
|
||||
def change_ls(self, idx):
|
||||
if idx:
|
||||
self.lineEdit.show()
|
||||
self.lsspinBox.hide()
|
||||
else:
|
||||
self.lineEdit.hide()
|
||||
self.lsspinBox.show()
|
208
src/gui_qt/data/signaledit/phase_dialog.py
Normal file
208
src/gui_qt/data/signaledit/phase_dialog.py
Normal file
@ -0,0 +1,208 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
from pyqtgraph import mkPen
|
||||
from numpy import inf, linspace
|
||||
from numpy.fft import fft, fftfreq, fftshift
|
||||
|
||||
from ...lib.pg_objects import PlotItem, LogInfiniteLine
|
||||
from nmreval.lib.importer import find_models
|
||||
from nmreval.math import apodization as apodization
|
||||
from nmreval.utils.text import convert
|
||||
|
||||
from ...Qt import QtCore, QtWidgets
|
||||
from ..._py.apod_dialog import Ui_ApodEdit
|
||||
from ..._py.phase_corr_dialog import Ui_SignalEdit
|
||||
from ...lib.forms import FormWidget
|
||||
|
||||
|
||||
class QPreviewDialogs(QtWidgets.QDialog):
|
||||
finished = QtCore.pyqtSignal(str, tuple)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.data = []
|
||||
self.graphs = []
|
||||
|
||||
self.mode = ''
|
||||
|
||||
def setRange(self, xlim: list, ylim: list, logmode: list[bool]):
|
||||
self.graphicsView.getPlotItem().setLogMode(x=logmode[0], y=logmode[1])
|
||||
if logmode[0]:
|
||||
xlim = [np.log10(x) for x in xlim]
|
||||
if logmode[1]:
|
||||
ylim = [np.log10(y) for y in ylim]
|
||||
|
||||
self.graphicsView.setRange(xRange=xlim, yRange=ylim, padding=0, disableAutoRange=True)
|
||||
|
||||
def add_data(self, x, y):
|
||||
self.data.append((x, y))
|
||||
real_plt = PlotItem(x=x, y=y.real, pen=mkPen('b'), )
|
||||
imag_plt = PlotItem(x=x, y=y.imag, pen=mkPen('r'))
|
||||
self.graphs.append((real_plt, imag_plt))
|
||||
self.graphicsView.addItem(real_plt)
|
||||
self.graphicsView.addItem(imag_plt)
|
||||
|
||||
def done(self, val):
|
||||
self.cleanup()
|
||||
super().done(val)
|
||||
|
||||
def close(self):
|
||||
self.cleanup()
|
||||
super().close()
|
||||
|
||||
def accept(self):
|
||||
self.finished.emit(self.mode, self.get_value())
|
||||
super().accept()
|
||||
|
||||
def get_value(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def cleanup(self):
|
||||
self.blockSignals(True)
|
||||
|
||||
for line in self.graphs:
|
||||
for g in line:
|
||||
self.graphicsView.removeItem(g)
|
||||
del g
|
||||
|
||||
self.graphicsView.clear()
|
||||
|
||||
self.data = []
|
||||
self.graphs = []
|
||||
|
||||
self.blockSignals(False)
|
||||
|
||||
|
||||
class QPhasedialog(QPreviewDialogs, Ui_SignalEdit):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.mode = 'ph'
|
||||
|
||||
self.pvt_line = LogInfiniteLine(pos=0, movable=True)
|
||||
self.graphicsView.addItem(self.pvt_line)
|
||||
self.pvt_line.sigPositionChanged.connect(self.move_line)
|
||||
|
||||
@QtCore.pyqtSlot(float, name='on_ph1slider_valueChanged')
|
||||
@QtCore.pyqtSlot(float, name='on_ph0slider_valueChanged')
|
||||
def _temp_phase(self, *args):
|
||||
ph0, ph1, pvt = self.get_value()
|
||||
self.pvt_line.setValue(pvt)
|
||||
|
||||
for i, (x, y) in enumerate(self.data):
|
||||
phasecorr = np.exp(-1j * (ph0 + ph1*(x-pvt)/np.max(x))*np.pi/180.)
|
||||
_y = y * phasecorr
|
||||
|
||||
self.graphs[i][0].setData(x=x, y=_y.real)
|
||||
self.graphs[i][1].setData(x=x, y=_y.imag)
|
||||
|
||||
def get_value(self):
|
||||
return float(self.ph0slider.text()), float(self.ph1slider.text()), float(self.pivot_lineedit.text())
|
||||
|
||||
def move_line(self, evt):
|
||||
self.pivot_lineedit.setText(str(int(evt.value())))
|
||||
|
||||
|
||||
class QApodDialog(QPreviewDialogs, Ui_ApodEdit):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self._limits = (-inf, inf), -inf
|
||||
|
||||
self.apods = []
|
||||
self.apods = find_models(apodization)
|
||||
|
||||
self.apodcombobox.blockSignals(True)
|
||||
for ap in self.apods:
|
||||
self.apodcombobox.addItem(ap().name)
|
||||
self.apodcombobox.blockSignals(False)
|
||||
|
||||
self.apod_graph = PlotItem(x=[], y=[])
|
||||
self.graphicsView.addItem(self.apod_graph)
|
||||
|
||||
self.mode = 'ap'
|
||||
|
||||
self.change_apodization(0)
|
||||
|
||||
def add_data(self, x, y):
|
||||
real_plt = PlotItem(x=x, y=y.real, pen=mkPen('b'))
|
||||
# imag_plt = (x=x, y=y.imag, pen=pg.mkPen('r'))
|
||||
self.graphicsView.addItem(real_plt)
|
||||
# self.graphicsView.addItem(imag_plt)
|
||||
|
||||
y_fft = fftshift(fft(y))
|
||||
x_fft = fftshift(fftfreq(len(x), d=x[1]-x[0]))
|
||||
real_plt_fft = PlotItem(x=x_fft, y=y_fft.real, pen=mkPen('b'))
|
||||
# imag_plt_fft = pg.PlotDataItem(x=x_fft, y=y_fft.imag, pen=pg.mkPen('b'))
|
||||
self.graphicsView_2.addItem(real_plt_fft)
|
||||
# self.graphicsView_2.addItem(imag_plt_fft)
|
||||
|
||||
self.graphs.append((real_plt, real_plt_fft))
|
||||
self.data.append((x, y, x_fft))
|
||||
|
||||
xlimits = (max(x.min(), self._limits[0][0]), min(x.max(), self._limits[0][1]))
|
||||
ylimit = max(self._limits[1], y.real.max())
|
||||
self._limits = xlimits, ylimit
|
||||
|
||||
@QtCore.pyqtSlot(int, name='on_apodcombobox_currentIndexChanged')
|
||||
def change_apodization(self, index):
|
||||
# delete old widgets
|
||||
self.eqn_label.setText(convert(self.apods[index].equation))
|
||||
while self.widget_layout.count():
|
||||
item = self.widget_layout.takeAt(0)
|
||||
try:
|
||||
item.widget().deleteLater()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
# set up parameter widgets for new model
|
||||
for k, v in enumerate(self.apods[index]().params):
|
||||
widgt = FormWidget(name=v)
|
||||
widgt.valueChanged.connect(self._temp_apod)
|
||||
self.widget_layout.addWidget(widgt)
|
||||
|
||||
self.widget_layout.addStretch()
|
||||
self._temp_apod()
|
||||
|
||||
def _temp_apod(self):
|
||||
apodmodel = self.apods[self.apodcombobox.currentIndex()]
|
||||
p = self._get_parameter()
|
||||
|
||||
if self.data:
|
||||
for i, (x, y, x_fft) in enumerate(self.data):
|
||||
y2 = apodmodel.apod(x, *p)
|
||||
_y = y2 * y
|
||||
self.graphs[i][0].setData(x=x, y=_y.real)
|
||||
# self.graphs[i][1].setData(y=_y.imag)
|
||||
y_fft = fftshift(fft(_y))
|
||||
self.graphs[i][1].setData(x=x_fft, y=y_fft.real)
|
||||
# self.graphs[i][3].setData(y=y_fft.imag)
|
||||
|
||||
_x_apod = linspace(self._limits[0][0], self._limits[0][1])
|
||||
try:
|
||||
_y_apod = apodmodel.apod(_x_apod, *p)
|
||||
self.apod_graph.setData(x=_x_apod, y=self._limits[1]*_y_apod)
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
def _get_parameter(self):
|
||||
p = []
|
||||
for i in range(self.widget_layout.count()):
|
||||
item = self.widget_layout.itemAt(i)
|
||||
w = item.widget()
|
||||
try:
|
||||
p.append(w.value)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
return p
|
||||
|
||||
def get_value(self):
|
||||
apodmodel = self.apods[self.apodcombobox.currentIndex()]
|
||||
p = self._get_parameter()
|
||||
|
||||
return p, apodmodel
|
Reference in New Issue
Block a user