diff --git a/src/gui_qt/_py/basewindow.py b/src/gui_qt/_py/basewindow.py
index d916548..8d23235 100644
--- a/src/gui_qt/_py/basewindow.py
+++ b/src/gui_qt/_py/basewindow.py
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'src/resources/_ui/basewindow.ui'
+# Form implementation generated from reading ui file './nmreval/src/resources/_ui/basewindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.10
#
@@ -87,6 +87,8 @@ class Ui_BaseWindow(object):
self.menuSave.setObjectName("menuSave")
self.menuData = QtWidgets.QMenu(self.menubar)
self.menuData.setObjectName("menuData")
+ self.menuCut_to_visible_range = QtWidgets.QMenu(self.menuData)
+ self.menuCut_to_visible_range.setObjectName("menuCut_to_visible_range")
self.menuHelp = QtWidgets.QMenu(self.menubar)
self.menuHelp.setObjectName("menuHelp")
self.menuExtra = QtWidgets.QMenu(self.menubar)
@@ -304,8 +306,6 @@ class Ui_BaseWindow(object):
self.actionDerivation.setObjectName("actionDerivation")
self.actionIntegration = QtWidgets.QAction(BaseWindow)
self.actionIntegration.setObjectName("actionIntegration")
- self.action_cut = QtWidgets.QAction(BaseWindow)
- self.action_cut.setObjectName("action_cut")
self.actionMove_between_plots = QtWidgets.QAction(BaseWindow)
self.actionMove_between_plots.setObjectName("actionMove_between_plots")
self.actionBaseline = QtWidgets.QAction(BaseWindow)
@@ -368,6 +368,10 @@ class Ui_BaseWindow(object):
self.actionExclude_region = QtWidgets.QAction(BaseWindow)
self.actionExclude_region.setCheckable(True)
self.actionExclude_region.setObjectName("actionExclude_region")
+ self.action_cut_xaxis = QtWidgets.QAction(BaseWindow)
+ self.action_cut_xaxis.setObjectName("action_cut_xaxis")
+ self.action_cut_yaxis = QtWidgets.QAction(BaseWindow)
+ self.action_cut_yaxis.setObjectName("action_cut_yaxis")
self.menuSave.addAction(self.actionSave)
self.menuSave.addAction(self.actionExportGraphic)
self.menuSave.addAction(self.action_save_fit_parameter)
@@ -380,6 +384,9 @@ class Ui_BaseWindow(object):
self.menuFile.addSeparator()
self.menuFile.addAction(self.action_close)
self.menuFile.addSeparator()
+ self.menuCut_to_visible_range.addSeparator()
+ self.menuCut_to_visible_range.addAction(self.action_cut_xaxis)
+ self.menuCut_to_visible_range.addAction(self.action_cut_yaxis)
self.menuData.addAction(self.action_new_set)
self.menuData.addAction(self.action_delete_sets)
self.menuData.addAction(self.actionMove_between_plots)
@@ -389,7 +396,7 @@ class Ui_BaseWindow(object):
self.menuData.addAction(self.action_sort_pts)
self.menuData.addAction(self.actionSkip_points)
self.menuData.addSeparator()
- self.menuData.addAction(self.action_cut)
+ self.menuData.addAction(self.menuCut_to_visible_range.menuAction())
self.menuData.addSeparator()
self.menuData.addAction(self.actionChange_datatypes)
self.menuHelp.addAction(self.actionShow_error_log)
@@ -515,6 +522,7 @@ class Ui_BaseWindow(object):
self.menuFile.setTitle(_translate("BaseWindow", "&File"))
self.menuSave.setTitle(_translate("BaseWindow", "&Save..."))
self.menuData.setTitle(_translate("BaseWindow", "&Data"))
+ self.menuCut_to_visible_range.setTitle(_translate("BaseWindow", "Cut to visible range"))
self.menuHelp.setTitle(_translate("BaseWindow", "&Help"))
self.menuExtra.setTitle(_translate("BaseWindow", "Math"))
self.menuNormalize.setTitle(_translate("BaseWindow", "&Normalize"))
@@ -608,7 +616,6 @@ class Ui_BaseWindow(object):
self.actionIntegrate.setText(_translate("BaseWindow", "Integrate"))
self.actionDerivation.setText(_translate("BaseWindow", "Differentiation..."))
self.actionIntegration.setText(_translate("BaseWindow", "Integration..."))
- self.action_cut.setText(_translate("BaseWindow", "Cut to visible range"))
self.actionMove_between_plots.setText(_translate("BaseWindow", "Move sets..."))
self.actionBaseline.setText(_translate("BaseWindow", "Baseline..."))
self.actionCalculateT1.setText(_translate("BaseWindow", "Calculate relaxation..."))
@@ -636,6 +643,10 @@ class Ui_BaseWindow(object):
self.actionBinning.setText(_translate("BaseWindow", "Binning..."))
self.actionTNMH.setText(_translate("BaseWindow", "TNMH..."))
self.actionExclude_region.setText(_translate("BaseWindow", "Exclude region"))
+ self.action_cut_xaxis.setText(_translate("BaseWindow", "x axis"))
+ self.action_cut_xaxis.setToolTip(_translate("BaseWindow", "Remove data points outside visible x range."))
+ self.action_cut_yaxis.setText(_translate("BaseWindow", "y axis"))
+ self.action_cut_yaxis.setToolTip(_translate("BaseWindow", "Remove data points outside visible y range. Uses real part of points."))
from ..data.datawidget.datawidget import DataWidget
from ..data.integral_widget import IntegralWidget
from ..data.point_select import PointSelectWidget
diff --git a/src/gui_qt/_py/interpol_dialog.py b/src/gui_qt/_py/interpol_dialog.py
index c3b0827..c0ef858 100644
--- a/src/gui_qt/_py/interpol_dialog.py
+++ b/src/gui_qt/_py/interpol_dialog.py
@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'src/resources/_ui/interpol_dialog.ui'
+# Form implementation generated from reading ui file './nmreval/src/resources/_ui/interpol_dialog.ui'
#
-# Created by: PyQt5 UI code generator 5.15.9
+# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -55,7 +55,7 @@ class Ui_Dialog(object):
self.gridLayout.addWidget(self.interp_comboBox, 4, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
+ self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 12, 0, 1, 2)
self.line = QtWidgets.QFrame(Dialog)
@@ -132,8 +132,6 @@ class Ui_Dialog(object):
self.label_8.setBuddy(self.dest_combobox)
self.retranslateUi(Dialog)
- self.buttonBox.accepted.connect(Dialog.accept) # type: ignore
- self.buttonBox.rejected.connect(Dialog.reject) # type: ignore
QtCore.QMetaObject.connectSlotsByName(Dialog)
Dialog.setTabOrder(self.listWidget, self.ylog_checkBox)
Dialog.setTabOrder(self.ylog_checkBox, self.interp_comboBox)
diff --git a/src/gui_qt/data/container.py b/src/gui_qt/data/container.py
index 71bf9f4..7364579 100644
--- a/src/gui_qt/data/container.py
+++ b/src/gui_qt/data/container.py
@@ -300,10 +300,12 @@ class ExperimentContainer(QtCore.QObject):
self._relations.pop(relation_type)
def _update_actions(self):
- self.actions.update({'sort': self._data.sort,
- 'cut': self._data.cut,
- 'norm': self._data.normalize,
- 'center': self.center})
+ self.actions.update({
+ 'sort': self._data.sort,
+ 'cut': self._data.cut,
+ 'norm': self._data.normalize,
+ 'center': self.center,
+ })
@plot_update
def update(self, opts: dict):
@@ -311,9 +313,11 @@ class ExperimentContainer(QtCore.QObject):
def get_properties(self) -> dict:
props = OrderedDict()
- props['General'] = OrderedDict([('Name', self.name),
- ('Value', str(self.value)),
- ('Group', str(self.group))])
+ props['General'] = OrderedDict([
+ ('Name', self.name),
+ ('Value', str(self.value)),
+ ('Group', str(self.group)),
+ ])
props['Symbol'] = OrderedDict()
props['Line'] = OrderedDict()
@@ -480,10 +484,12 @@ class ExperimentContainer(QtCore.QObject):
else:
prefix = f'g[{i}].s[{j}].'
- namespace = {prefix + 'x': (self.x, 'x values'),
- prefix + 'y': [self.y, 'y values'],
- prefix + 'y_err': (self.y_err, 'y error values'),
- prefix + 'value': (self.value, str(self.value))}
+ namespace = {
+ prefix + 'x': (self.x, 'x values'),
+ prefix + 'y': [self.y, 'y values'],
+ prefix + 'y_err': (self.y_err, 'y error values'),
+ prefix + 'value': (self.value, str(self.value)),
+ }
if len(self._fits) == 1:
namespace.update({
diff --git a/src/gui_qt/data/valueeditwidget.py b/src/gui_qt/data/valueeditwidget.py
index ae95a5f..de2376b 100644
--- a/src/gui_qt/data/valueeditwidget.py
+++ b/src/gui_qt/data/valueeditwidget.py
@@ -385,6 +385,6 @@ class ValueModel(QtCore.QAbstractTableModel):
@staticmethod
def as_string(value) -> str:
if isinstance(value, complex):
- return f'{value.real:.8g}{value.imag:+.8g}j'
+ return f'{value.real:.13g}{value.imag:+.13g}j'
else:
- return f'{value:.8g}'
+ return f'{value:.13g}'
diff --git a/src/gui_qt/io/fcbatchreader.py b/src/gui_qt/io/fcbatchreader.py
index c4bb80b..a4444e6 100644
--- a/src/gui_qt/io/fcbatchreader.py
+++ b/src/gui_qt/io/fcbatchreader.py
@@ -28,6 +28,12 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
self.listWidget.installEventFilter(self)
+ def __call__(self, path=None):
+ if path is None:
+ path = pathlib.Path().home()
+ self.path = path
+ self.listWidget.clear()
+
def eventFilter(self, src: QtCore.QObject, evt: QtCore.QEvent) -> bool:
# intercept key press in listwidget to allow deletion with Del
if evt.type() == QtCore.QEvent.Type.KeyPress:
@@ -82,6 +88,7 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
def accept(self):
items = [self.listWidget.item(i).text() for i in range(self.listWidget.count())]
+ print(items)
if items:
with busy_cursor():
self.read(items)
@@ -116,6 +123,7 @@ class QFCReader(QtWidgets.QDialog, Ui_FCEval_dialog):
ret_vals = []
ret_vals.extend(fc_eval.get_parameter(path=self.label.text(), kind='temp', parameter=save_variables))
+ print(ret_vals)
grp = ''
if not self.graph_checkbox.isChecked():
diff --git a/src/gui_qt/main/mainwindow.py b/src/gui_qt/main/mainwindow.py
index 7f6123b..34e94ba 100644
--- a/src/gui_qt/main/mainwindow.py
+++ b/src/gui_qt/main/mainwindow.py
@@ -62,6 +62,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.fitresult_dialog = None
self.eval = None
self.editor = None
+ self._interpol_dialog = None
+ self.fc_reader = None
self.logtext = QTextHandler(self)
logger.addHandler(self.logtext)
@@ -233,7 +235,8 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
self.action_norm_first.triggered.connect(lambda: self.management.apply('norm', ('first',)))
self.action_norm_last.triggered.connect(lambda: self.management.apply('norm', ('last',)))
self.action_norm_area.triggered.connect(lambda: self.management.apply('norm', ('area',)))
- self.action_cut.triggered.connect(lambda: self.management.cut())
+ self.action_cut_xaxis.triggered.connect(lambda: self.management.cut(True, False))
+ self.action_cut_yaxis.triggered.connect(lambda: self.management.cut(False, True))
self.actionConcatenate_sets.triggered.connect(lambda: self.management.cat())
@@ -264,14 +267,15 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
@QtCore.pyqtSlot(name='on_actionOpen_FC_triggered')
def read_fc(self):
- reader = QFCReader(path=self.path, parent=self)
- reader.add_graphs(self.management.graphs.list())
- reader.data_read.connect(self.management.add_new_data)
- reader.exec()
+ if self.fc_reader is None:
+ self.fc_reader = QFCReader(path=self.path, parent=self)
+ self.fc_reader.data_read.connect(self.management.add_new_data)
+ else:
+ self.fc_reader(path=self.path)
+ self.fc_reader.add_graphs(self.management.graphs.list())
+ self.fc_reader.exec()
- self.path = reader.path
-
- del reader
+ self.path = self.fc_reader.path
@QtCore.pyqtSlot(name='on_actionPrint_triggered')
def print(self):
@@ -701,10 +705,13 @@ class NMRMainWindow(QtWidgets.QMainWindow, Ui_BaseWindow):
return
gnames = self.management.graphs.tree()
- dialog = InterpolDialog(parent=self)
- dialog.set_data(gnames, self.current_graph_widget.id)
- dialog.new_data.connect(self.management.interpolate_data)
- dialog.show()
+ if self._interpol_dialog is None:
+ self._interpol_dialog = InterpolDialog(parent=self)
+ self._interpol_dialog.new_data.connect(self.management.interpolate_data)
+ else:
+ self._interpol_dialog()
+ self._interpol_dialog.set_data(gnames, self.current_graph_widget.id)
+ self._interpol_dialog.show()
@QtCore.pyqtSlot(name='on_action_calc_triggered')
def open_eval_dialog(self):
diff --git a/src/gui_qt/main/management.py b/src/gui_qt/main/management.py
index 56c387a..f47362b 100644
--- a/src/gui_qt/main/management.py
+++ b/src/gui_qt/main/management.py
@@ -450,10 +450,17 @@ class UpperManagement(QtCore.QObject):
self.undostack.push(single_undo)
self.undostack.endMacro()
- def cut(self):
+ def cut(self, x: bool = False, y: bool = False) -> None:
if self.current_graph:
- xlim, _ = self.graphs[self.current_graph].ranges
- self.apply('cut', xlim)
+ xlim, ylim = self.graphs[self.current_graph].ranges
+
+ if x is False:
+ xlim = (None, None)
+
+ if y is False:
+ ylim = (None, None)
+
+ self.apply('cut', (*xlim, *ylim))
@QtCore.pyqtSlot()
def unmask(self):
diff --git a/src/gui_qt/math/interpol.py b/src/gui_qt/math/interpol.py
index c58d03c..046a7bc 100644
--- a/src/gui_qt/math/interpol.py
+++ b/src/gui_qt/math/interpol.py
@@ -16,6 +16,12 @@ class InterpolDialog(QtWidgets.QDialog, Ui_Dialog):
self.step_lineEdit.setValidator(QtGui.QIntValidator())
self._data = {}
+ self._src_id = None
+ self._dest_graph = ''
+
+ def __call__(self):
+ self.listWidget.clear()
+ self._data = {}
@QtCore.pyqtSlot(int, name='on_xaxis_comboBox_currentIndexChanged')
def change_x_source(self, idx: int):
@@ -25,29 +31,41 @@ class InterpolDialog(QtWidgets.QDialog, Ui_Dialog):
def set_data(self, data, current_gid):
self.graph_combobox.blockSignals(True)
self._data = {}
+ dest_idx = 0
for (gid, graph_name), sets in data.items():
self.graph_combobox.addItem(graph_name, userData=gid)
self.dest_combobox.addItem(graph_name, userData=gid)
+ if self._dest_graph == gid:
+ dest_idx = self.dest_combobox.currentIndex()
if gid == current_gid:
self.make_list(sets)
self._data[gid] = sets
self.graph_combobox.blockSignals(False)
- self.change_graph(0)
+ self.change_graph(dest_idx)
def make_list(self, current_sets):
for sid, set_name in current_sets:
item = QtWidgets.QListWidgetItem(set_name)
- item.setData(QtCore.Qt.UserRole, sid)
- item.setCheckState(QtCore.Qt.Checked)
+ item.setData(QtCore.Qt.ItemDataRole.UserRole, sid)
+ item.setCheckState(QtCore.Qt.CheckState.Checked)
self.listWidget.addItem(item)
@QtCore.pyqtSlot(int, name='on_graph_combobox_currentIndexChanged')
def change_graph(self, idx: int):
self.set_combobox.clear()
- gid = self.graph_combobox.itemData(idx, QtCore.Qt.UserRole)
+ gid = self.graph_combobox.itemData(idx, QtCore.Qt.ItemDataRole.UserRole)
+ set_idx = -1
if gid is not None:
- for set_key, set_name in self._data[gid]:
+ for i, (set_key, set_name) in enumerate(self._data[gid]):
+ print(self._src_id, set_key, set_name, i)
self.set_combobox.addItem(set_name, userData=set_key)
+ print(self.set_combobox.currentIndex())
+ if self._src_id == set_key:
+ set_idx = i
+
+ print(set_idx)
+ if set_idx > -1:
+ self.set_combobox.setCurrentIndex(set_idx)
def collect_parameter(self):
xlog = self.xlog_checkBox.isChecked()
@@ -71,21 +89,35 @@ class InterpolDialog(QtWidgets.QDialog, Ui_Dialog):
x_src = (start, stop, step, loggy)
else:
- x_src = (self.set_combobox.currentData(QtCore.Qt.UserRole),)
+ self._src_id = self.set_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
+ x_src = (self._src_id,)
- dest_graph = self.dest_combobox.currentData(QtCore.Qt.UserRole)
+ self._dest_graph = self.dest_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
use_data = []
for i in range(self.listWidget.count()):
item = self.listWidget.item(i)
- if item.checkState() == QtCore.Qt.Checked:
- use_data.append(item.data(QtCore.Qt.UserRole))
+ if item.checkState() == QtCore.Qt.CheckState.Checked:
+ use_data.append(item.data(QtCore.Qt.ItemDataRole.UserRole))
- self.new_data.emit(use_data, mode, xlog, ylog, x_src, dest_graph)
+ self.new_data.emit(use_data, mode, xlog, ylog, x_src, self._dest_graph)
return True
- def accept(self):
- success = self.collect_parameter()
- if success:
- super().accept()
+ def _save_state(self):
+ self._src_id = self.set_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
+ self._dest_graph = self.dest_combobox.currentData(QtCore.Qt.ItemDataRole.UserRole)
+
+ @QtCore.pyqtSlot(QtWidgets.QAbstractButton, name='on_buttonBox_clicked')
+ def check_next_actions(self, bttn: QtWidgets.QAbstractButton):
+ role = self.buttonBox.buttonRole(bttn)
+ self._save_state()
+
+ if role == self.buttonBox.ButtonRole.RejectRole:
+ self.close()
+ else:
+ success = self.collect_parameter()
+
+ if success and role == self.buttonBox.ButtonRole.AcceptRole:
+ self.close()
+
diff --git a/src/nmreval/data/points.py b/src/nmreval/data/points.py
index 8332084..1f891ae 100644
--- a/src/nmreval/data/points.py
+++ b/src/nmreval/data/points.py
@@ -540,26 +540,37 @@ class Points:
return self
- def cut(self, low_lim: float = None, high_lim: float = None):
+ def cut(self, x_low: float = None, x_high: float = None, y_low: float = None, y_high: float = None):
"""
Cut
Args:
- low_lim:
- high_lim:
+ x_low: Lower limit
+ x_high: Upper limit for x values
+ y_low: Lower limit
+ y_high: Upper limit for x valuew
Returns:
"""
- if low_lim is None and high_lim is None:
+
+ if x_low is None and x_high is None and y_low is None and y_high is None:
return self
- if low_lim is None:
- low_lim = np.min(self._x)
+ if x_low is None:
+ x_low = np.min(self._x)-1
- if high_lim is None:
- high_lim = np.max(self._x)
+ if x_high is None:
+ x_high = np.max(self._x)+1
- _mask = np.ma.masked_inside(self._x, low_lim, high_lim).mask
+ if y_low is None:
+ y_low = np.min(self._y.real)-1
+
+ if y_high is None:
+ y_high = np.max(self._y.real)+1
+
+ x_mask = (self._x >= x_low) & (self._x <= x_high)
+ y_mask = (self._y.real >= y_low) & (self._y.real <= y_high)
+ _mask = x_mask & y_mask
self._x = self._x[_mask]
self._y = self._y[_mask]
diff --git a/src/nmreval/models/basic.py b/src/nmreval/models/basic.py
index 411e218..ce4308d 100644
--- a/src/nmreval/models/basic.py
+++ b/src/nmreval/models/basic.py
@@ -191,6 +191,18 @@ class PowerLawCross:
return ret_val
+class Sinc:
+ type = 'Basic'
+ name = 'Sinc'
+ equation = 'C * sinc((x-x_{0})/w)'
+ params = ['C', 'x_{0}', 'w']
+
+ @staticmethod
+ def func(x, c: float, x0: float, w: float):
+ # numpy sinc is defined as sin(pi*x)/(pi*x)
+ return c * np.sinc(((x-x0)/w)/np.pi)
+
+
class Sine:
"""
Wavy sine function
diff --git a/src/resources/_ui/basewindow.ui b/src/resources/_ui/basewindow.ui
index 01987b8..85c1f68 100644
--- a/src/resources/_ui/basewindow.ui
+++ b/src/resources/_ui/basewindow.ui
@@ -172,6 +172,14 @@
&Data
+
@@ -181,7 +189,7 @@
-
+
@@ -862,11 +870,6 @@
Integration...
-
-
- Cut to visible range
-
-
Move sets...
@@ -1030,6 +1033,22 @@
Exclude region
+
+
+ x axis
+
+
+ Remove data points outside visible x range.
+
+
+
+
+ y axis
+
+
+ Remove data points outside visible y range. Uses real part of points.
+
+
diff --git a/src/resources/_ui/interpol_dialog.ui b/src/resources/_ui/interpol_dialog.ui
index 28fa858..865f70b 100644
--- a/src/resources/_ui/interpol_dialog.ui
+++ b/src/resources/_ui/interpol_dialog.ui
@@ -119,7 +119,7 @@
Qt::Horizontal
- QDialogButtonBox::Cancel|QDialogButtonBox::Ok
+ QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
@@ -300,38 +300,5 @@
dest_combobox
-
-
- buttonBox
- accepted()
- Dialog
- accept()
-
-
- 251
- 490
-
-
- 157
- 274
-
-
-
-
- buttonBox
- rejected()
- Dialog
- reject()
-
-
- 319
- 490
-
-
- 286
- 274
-
-
-
-
+