From a4950839d03f7866dc534cdcca46b7fbfad21ad9 Mon Sep 17 00:00:00 2001 From: Dominik Demuth Date: Fri, 30 Dec 2022 14:07:38 +0100 Subject: [PATCH] reworked import of text files; fixes T249 --- src/gui_qt/_py/asciidialog.py | 234 ++++++--- .../data/signaledit/editsignalwidget.py | 6 +- src/gui_qt/io/asciireader.py | 189 ++++--- src/gui_qt/io/filereaders.py | 9 +- src/gui_qt/lib/expandablewidget.py | 5 +- src/nmreval/io/asciireader.py | 208 ++++---- src/resources/_ui/asciidialog.ui | 485 +++++++++++------- 7 files changed, 707 insertions(+), 429 deletions(-) diff --git a/src/gui_qt/_py/asciidialog.py b/src/gui_qt/_py/asciidialog.py index 0b2e0a2..66ceccf 100644 --- a/src/gui_qt/_py/asciidialog.py +++ b/src/gui_qt/_py/asciidialog.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file '/autohome/dominik/nmreval/src/resources/_ui/asciidialog.ui' +# Form implementation generated from reading ui file 'src/resources/_ui/asciidialog.ui' # -# Created by: PyQt5 UI code generator 5.15.4 +# Created by: PyQt5 UI code generator 5.15.7 # # 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. @@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_ascii_reader(object): def setupUi(self, ascii_reader): ascii_reader.setObjectName("ascii_reader") - ascii_reader.resize(667, 509) + ascii_reader.resize(627, 703) self.verticalLayout = QtWidgets.QVBoxLayout(ascii_reader) self.verticalLayout.setObjectName("verticalLayout") self.tabWidget = QtWidgets.QTabWidget(ascii_reader) @@ -22,14 +22,123 @@ class Ui_ascii_reader(object): self.tabWidgetPage1 = QtWidgets.QWidget() self.tabWidgetPage1.setObjectName("tabWidgetPage1") self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tabWidgetPage1) - self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_3.setContentsMargins(6, 6, 6, 6) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.comment_textfield = QtWidgets.QPlainTextEdit(self.tabWidgetPage1) - self.comment_textfield.setEnabled(False) - self.comment_textfield.setMaximumSize(QtCore.QSize(16777215, 180)) - self.comment_textfield.setObjectName("comment_textfield") - self.verticalLayout_3.addWidget(self.comment_textfield) - self.ascii_table = QtWidgets.QTableWidget(self.tabWidgetPage1) + self.header_widget = ExpandableWidget(self.tabWidgetPage1) + self.header_widget.setObjectName("header_widget") + self.verticalLayout_3.addWidget(self.header_widget) + self.groupBox = QtWidgets.QGroupBox(self.tabWidgetPage1) + self.groupBox.setObjectName("groupBox") + self.gridLayout = QtWidgets.QGridLayout(self.groupBox) + self.gridLayout.setContentsMargins(3, 3, 3, 3) + self.gridLayout.setHorizontalSpacing(9) + self.gridLayout.setObjectName("gridLayout") + self.FID_radioButton = QtWidgets.QRadioButton(self.groupBox) + self.FID_radioButton.setAutoExclusive(True) + self.FID_radioButton.setObjectName("FID_radioButton") + self.buttonGroup = QtWidgets.QButtonGroup(ascii_reader) + self.buttonGroup.setObjectName("buttonGroup") + self.buttonGroup.addButton(self.FID_radioButton) + self.gridLayout.addWidget(self.FID_radioButton, 2, 1, 1, 1) + self.x_lineedit = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.x_lineedit.sizePolicy().hasHeightForWidth()) + self.x_lineedit.setSizePolicy(sizePolicy) + self.x_lineedit.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) + self.x_lineedit.setObjectName("x_lineedit") + self.gridLayout.addWidget(self.x_lineedit, 1, 3, 1, 1) + self.y_label = QtWidgets.QLabel(self.groupBox) + self.y_label.setObjectName("y_label") + self.gridLayout.addWidget(self.y_label, 2, 2, 1, 1) + self.pts_radioButton = QtWidgets.QRadioButton(self.groupBox) + self.pts_radioButton.setChecked(True) + self.pts_radioButton.setAutoExclusive(True) + self.pts_radioButton.setObjectName("pts_radioButton") + self.buttonGroup.addButton(self.pts_radioButton) + self.gridLayout.addWidget(self.pts_radioButton, 1, 1, 1, 1) + self.deltay_lineEdit = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.deltay_lineEdit.sizePolicy().hasHeightForWidth()) + self.deltay_lineEdit.setSizePolicy(sizePolicy) + self.deltay_lineEdit.setObjectName("deltay_lineEdit") + self.gridLayout.addWidget(self.deltay_lineEdit, 3, 3, 1, 1) + self.label_5 = QtWidgets.QLabel(self.groupBox) + self.label_5.setObjectName("label_5") + self.gridLayout.addWidget(self.label_5, 3, 2, 1, 1) + self.column_checkBox = QtWidgets.QCheckBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.column_checkBox.sizePolicy().hasHeightForWidth()) + self.column_checkBox.setSizePolicy(sizePolicy) + self.column_checkBox.setObjectName("column_checkBox") + self.gridLayout.addWidget(self.column_checkBox, 0, 0, 1, 1) + self.label = QtWidgets.QLabel(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 1, 1, 1) + self.label_7 = QtWidgets.QLabel(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth()) + self.label_7.setSizePolicy(sizePolicy) + self.label_7.setObjectName("label_7") + self.gridLayout.addWidget(self.label_7, 0, 2, 1, 2) + self.y_lineedit = QtWidgets.QLineEdit(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.y_lineedit.sizePolicy().hasHeightForWidth()) + self.y_lineedit.setSizePolicy(sizePolicy) + self.y_lineedit.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) + self.y_lineedit.setObjectName("y_lineedit") + self.gridLayout.addWidget(self.y_lineedit, 2, 3, 1, 1) + self.spectrum_radioButton = QtWidgets.QRadioButton(self.groupBox) + self.spectrum_radioButton.setObjectName("spectrum_radioButton") + self.buttonGroup.addButton(self.spectrum_radioButton) + self.gridLayout.addWidget(self.spectrum_radioButton, 3, 1, 1, 1) + self.x_label = QtWidgets.QLabel(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.x_label.sizePolicy().hasHeightForWidth()) + self.x_label.setSizePolicy(sizePolicy) + self.x_label.setObjectName("x_label") + self.gridLayout.addWidget(self.x_label, 1, 2, 1, 1) + self.line_spinBox = QtWidgets.QSpinBox(self.groupBox) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.line_spinBox.sizePolicy().hasHeightForWidth()) + self.line_spinBox.setSizePolicy(sizePolicy) + self.line_spinBox.setMinimum(1) + self.line_spinBox.setObjectName("line_spinBox") + self.gridLayout.addWidget(self.line_spinBox, 1, 0, 1, 1) + self.preview_spinBox = QtWidgets.QSpinBox(self.groupBox) + self.preview_spinBox.setMinimum(1) + self.preview_spinBox.setProperty("value", 10) + self.preview_spinBox.setObjectName("preview_spinBox") + self.gridLayout.addWidget(self.preview_spinBox, 3, 0, 1, 1) + self.label_6 = QtWidgets.QLabel(self.groupBox) + self.label_6.setObjectName("label_6") + self.gridLayout.addWidget(self.label_6, 2, 0, 1, 1) + self.verticalLayout_3.addWidget(self.groupBox) + self.groupBox_2 = QtWidgets.QGroupBox(self.tabWidgetPage1) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_2.setContentsMargins(3, 3, 3, 3) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.ascii_table = QtWidgets.QTableWidget(self.groupBox_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -44,11 +153,13 @@ class Ui_ascii_reader(object): self.ascii_table.setColumnCount(0) self.ascii_table.setRowCount(0) self.ascii_table.horizontalHeader().setMinimumSectionSize(1) - self.verticalLayout_3.addWidget(self.ascii_table) + self.verticalLayout_2.addWidget(self.ascii_table) + self.verticalLayout_3.addWidget(self.groupBox_2) self.tabWidget.addTab(self.tabWidgetPage1, "") self.tabWidgetPage2 = QtWidgets.QWidget() self.tabWidgetPage2.setObjectName("tabWidgetPage2") self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.tabWidgetPage2) + self.horizontalLayout_3.setContentsMargins(6, 6, 6, 6) self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.delay_textfield = QtWidgets.QPlainTextEdit(self.tabWidgetPage2) self.delay_textfield.setObjectName("delay_textfield") @@ -102,48 +213,17 @@ class Ui_ascii_reader(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth()) self.pushButton.setSizePolicy(sizePolicy) - icon = QtGui.QIcon.fromTheme("accessories-calculator") - self.pushButton.setIcon(icon) self.pushButton.setObjectName("pushButton") self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.pushButton) + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.formLayout.setItem(6, QtWidgets.QFormLayout.FieldRole, spacerItem) self.horizontalLayout_3.addLayout(self.formLayout) self.tabWidget.addTab(self.tabWidgetPage2, "") self.verticalLayout.addWidget(self.tabWidget) self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem) - self.x_label = QtWidgets.QLabel(ascii_reader) - self.x_label.setObjectName("x_label") - self.horizontalLayout.addWidget(self.x_label) - self.x_lineedit = QtWidgets.QLineEdit(ascii_reader) - self.x_lineedit.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) - self.x_lineedit.setObjectName("x_lineedit") - self.horizontalLayout.addWidget(self.x_lineedit) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) - self.y_label = QtWidgets.QLabel(ascii_reader) - self.y_label.setObjectName("y_label") - self.horizontalLayout.addWidget(self.y_label) - self.y_lineedit = QtWidgets.QLineEdit(ascii_reader) - self.y_lineedit.setInputMethodHints(QtCore.Qt.ImhFormattedNumbersOnly|QtCore.Qt.ImhPreferNumbers) - self.y_lineedit.setObjectName("y_lineedit") - self.horizontalLayout.addWidget(self.y_lineedit) - self.widget = QtWidgets.QWidget(ascii_reader) - self.widget.setObjectName("widget") - self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.widget) - self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0) - self.horizontalLayout_4.setSpacing(0) - self.horizontalLayout_4.setObjectName("horizontalLayout_4") - spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_4.addItem(spacerItem2) - self.label_5 = QtWidgets.QLabel(self.widget) - self.label_5.setObjectName("label_5") - self.horizontalLayout_4.addWidget(self.label_5) - self.deltay_lineEdit = QtWidgets.QLineEdit(self.widget) - self.deltay_lineEdit.setObjectName("deltay_lineEdit") - self.horizontalLayout_4.addWidget(self.deltay_lineEdit) - self.horizontalLayout.addWidget(self.widget) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setContentsMargins(-1, 0, -1, -1) @@ -151,25 +231,8 @@ class Ui_ascii_reader(object): self.skippy_checkbox = QtWidgets.QCheckBox(ascii_reader) self.skippy_checkbox.setObjectName("skippy_checkbox") self.horizontalLayout_2.addWidget(self.skippy_checkbox) - spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout_2.addItem(spacerItem3) - self.pts_radioButton = QtWidgets.QRadioButton(ascii_reader) - self.pts_radioButton.setChecked(True) - self.pts_radioButton.setAutoExclusive(True) - self.pts_radioButton.setObjectName("pts_radioButton") - self.buttonGroup = QtWidgets.QButtonGroup(ascii_reader) - self.buttonGroup.setObjectName("buttonGroup") - self.buttonGroup.addButton(self.pts_radioButton) - self.horizontalLayout_2.addWidget(self.pts_radioButton) - self.FID_radioButton = QtWidgets.QRadioButton(ascii_reader) - self.FID_radioButton.setAutoExclusive(True) - self.FID_radioButton.setObjectName("FID_radioButton") - self.buttonGroup.addButton(self.FID_radioButton) - self.horizontalLayout_2.addWidget(self.FID_radioButton) - self.spectrum_radioButton = QtWidgets.QRadioButton(ascii_reader) - self.spectrum_radioButton.setObjectName("spectrum_radioButton") - self.buttonGroup.addButton(self.spectrum_radioButton) - self.horizontalLayout_2.addWidget(self.spectrum_radioButton) + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_2.addItem(spacerItem2) self.verticalLayout.addLayout(self.horizontalLayout_2) self.buttonbox = QtWidgets.QDialogButtonBox(ascii_reader) self.buttonbox.setStandardButtons(QtWidgets.QDialogButtonBox.Apply|QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) @@ -178,12 +241,46 @@ class Ui_ascii_reader(object): self.retranslateUi(ascii_reader) self.tabWidget.setCurrentIndex(0) - self.buttonbox.rejected.connect(ascii_reader.close) + self.buttonbox.rejected.connect(ascii_reader.close) # type: ignore QtCore.QMetaObject.connectSlotsByName(ascii_reader) + ascii_reader.setTabOrder(self.tabWidget, self.column_checkBox) + ascii_reader.setTabOrder(self.column_checkBox, self.line_spinBox) + ascii_reader.setTabOrder(self.line_spinBox, self.preview_spinBox) + ascii_reader.setTabOrder(self.preview_spinBox, self.pts_radioButton) + ascii_reader.setTabOrder(self.pts_radioButton, self.FID_radioButton) + ascii_reader.setTabOrder(self.FID_radioButton, self.spectrum_radioButton) + ascii_reader.setTabOrder(self.spectrum_radioButton, self.x_lineedit) + ascii_reader.setTabOrder(self.x_lineedit, self.y_lineedit) + ascii_reader.setTabOrder(self.y_lineedit, self.deltay_lineEdit) + ascii_reader.setTabOrder(self.deltay_lineEdit, self.ascii_table) + ascii_reader.setTabOrder(self.ascii_table, self.skippy_checkbox) + ascii_reader.setTabOrder(self.skippy_checkbox, self.delay_textfield) + ascii_reader.setTabOrder(self.delay_textfield, self.delay_lineedit) + ascii_reader.setTabOrder(self.delay_lineedit, self.start_lineedit) + ascii_reader.setTabOrder(self.start_lineedit, self.end_lineedit) + ascii_reader.setTabOrder(self.end_lineedit, self.log_checkBox) + ascii_reader.setTabOrder(self.log_checkBox, self.staggered_checkBox) + ascii_reader.setTabOrder(self.staggered_checkBox, self.stag_lineEdit) + ascii_reader.setTabOrder(self.stag_lineEdit, self.pushButton) def retranslateUi(self, ascii_reader): _translate = QtCore.QCoreApplication.translate ascii_reader.setWindowTitle(_translate("ascii_reader", "Read text file")) + self.groupBox.setTitle(_translate("ascii_reader", "Options")) + self.FID_radioButton.setText(_translate("ascii_reader", "FID")) + self.x_lineedit.setToolTip(_translate("ascii_reader", "

Specify which column is used as x-value.

")) + self.y_label.setText(_translate("ascii_reader", "y")) + self.pts_radioButton.setText(_translate("ascii_reader", "Points")) + self.label_5.setText(_translate("ascii_reader", "

Δy

")) + self.column_checkBox.setText(_translate("ascii_reader", "Column name")) + self.label.setText(_translate("ascii_reader", "Import as")) + self.label_7.setText(_translate("ascii_reader", "Use columns as")) + self.y_lineedit.setToolTip(_translate("ascii_reader", "

Specify which columns are read for y-values. (\'Points\': Every number creates a new data set;\'FID\'/\'Spectrum\': Numbers at even positions are used for real parts, at odd positions for imaginary parts.)

")) + self.spectrum_radioButton.setText(_translate("ascii_reader", "Spectrum")) + self.x_label.setText(_translate("ascii_reader", "x")) + self.line_spinBox.setPrefix(_translate("ascii_reader", "header line ")) + self.label_6.setText(_translate("ascii_reader", "Preview length")) + self.groupBox_2.setTitle(_translate("ascii_reader", "Preview")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("ascii_reader", "Data")) self.label_2.setText(_translate("ascii_reader", "Number of delays")) self.label_3.setText(_translate("ascii_reader", "Start value")) @@ -192,13 +289,6 @@ class Ui_ascii_reader(object): self.staggered_checkBox.setText(_translate("ascii_reader", "Staggered range")) self.pushButton.setText(_translate("ascii_reader", "Calculate delays")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage2), _translate("ascii_reader", "Delays")) - self.x_label.setText(_translate("ascii_reader", "x")) - self.x_lineedit.setToolTip(_translate("ascii_reader", "

Specify which column is used as x-value.

")) - self.y_label.setText(_translate("ascii_reader", "y")) - self.y_lineedit.setToolTip(_translate("ascii_reader", "

Specify which columns are read for y-values. (\'Points\': Every number creates a new data set;\'FID\'/\'Spectrum\': Numbers at even positions are used for real parts, at odd positions for imaginary parts.)

")) - self.label_5.setText(_translate("ascii_reader", "

Δy

")) self.skippy_checkbox.setToolTip(_translate("ascii_reader", "Use selection for next files. Deletes possible delay values.")) self.skippy_checkbox.setText(_translate("ascii_reader", "Skip next dialogues?")) - self.pts_radioButton.setText(_translate("ascii_reader", "Points")) - self.FID_radioButton.setText(_translate("ascii_reader", "FID")) - self.spectrum_radioButton.setText(_translate("ascii_reader", "Spectrum")) +from ..lib.expandablewidget import ExpandableWidget diff --git a/src/gui_qt/data/signaledit/editsignalwidget.py b/src/gui_qt/data/signaledit/editsignalwidget.py index 1137ce3..3232f9f 100644 --- a/src/gui_qt/data/signaledit/editsignalwidget.py +++ b/src/gui_qt/data/signaledit/editsignalwidget.py @@ -1,6 +1,6 @@ -from src.nmreval.math import apodization -from src.nmreval.lib.importer import find_models -from src.nmreval.utils.text import convert +from nmreval.math import apodization +from nmreval.lib.importer import find_models +from nmreval.utils.text import convert from ...Qt import QtCore, QtWidgets, QtGui from ...lib.forms import FormWidget diff --git a/src/gui_qt/io/asciireader.py b/src/gui_qt/io/asciireader.py index 01dd012..d4bf67f 100644 --- a/src/gui_qt/io/asciireader.py +++ b/src/gui_qt/io/asciireader.py @@ -1,24 +1,27 @@ from nmreval.io.asciireader import AsciiReader -from ..Qt import QtGui, QtCore, QtWidgets -from .._py.asciidialog import Ui_ascii_reader +from gui_qt.Qt import QtGui, QtCore, QtWidgets +from gui_qt._py.asciidialog import Ui_ascii_reader class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader): data_read = QtCore.pyqtSignal(list) file_ext = ['.dat', '.txt'] - skip = False def __init__(self, fname=None, parent=None): super().__init__(parent=parent) self.setupUi(self) - self.reader = AsciiReader(fname) + self.reader = None + self.comment_textfield = QtWidgets.QPlainTextEdit(self.header_widget) + self.comment_textfield.setReadOnly(True) pal = QtWidgets.QApplication.instance().palette() rgb = pal.color(pal.Base).getRgb()[:3] rgb2 = pal.color(pal.Text).getRgb()[:3] - self.comment_textfield.setStyleSheet(f'Qdelay_textfield {{ background-color: rgb{rgb} ; color: rgb{rgb2}; }}') + self.comment_textfield.setStyleSheet(f'background-color: rgb{rgb}; color: rgb{rgb2};') + self.header_widget.setText('Header') + self.header_widget.addWidget(self.comment_textfield) self.ascii_table.horizontalHeader().setStretchLastSection(True) self.buttonbox.button(QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.apply) @@ -30,45 +33,42 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader): self.ascii_table.horizontalHeader().setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.ascii_table.horizontalHeader().customContextMenuRequested.connect(self.ctx_table) + self.skip = False + + if fname is not None: + self.__call__(fname) + def __call__(self, fname, *args, **kwargs): + self.reader = AsciiReader(fname) + + if self.skip: + self.accept() + return + for i in [self.stag_lineEdit, self.start_lineedit, self.end_lineedit, self.comment_textfield, self.ascii_table, self.delay_lineedit]: i.clear() self.staggered_checkBox.setChecked(False) self.log_checkBox.setChecked(False) - self.comment_textfield.show() - self.reader = AsciiReader(fname) self.set_gui() - if QAsciiReader.skip: - self.accept() - else: - self.skippy_checkbox.blockSignals(True) - self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked) - self.skippy_checkbox.blockSignals(False) + self.skippy_checkbox.blockSignals(True) + self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked) + self.skippy_checkbox.blockSignals(False) - return self + return self def set_gui(self): for text in self.reader.header: self.comment_textfield.appendPlainText(text) - self.ascii_table.setRowCount(self.reader.shape[0]) - self.ascii_table.setColumnCount(self.reader.shape[1]) - try: - last_header_line = self.reader.header[-1].split() - if len(last_header_line) == self.reader.shape[1]: - self.ascii_table.setHorizontalHeaderLabels(last_header_line) - except IndexError: - self.comment_textfield.hide() - - for i, line in enumerate(self.reader.data): - for j, field in enumerate(line): - it = QtWidgets.QTableWidgetItem(field) - self.ascii_table.setItem(i, j, it) - - self.ascii_table.resizeColumnsToContents() + if self.reader.header: + self.line_spinBox.setMaximum(len(self.reader.header)) + else: + self.line_spinBox.setValue(0) + self.line_spinBox.setEnabled(False) + self.show_preview(10) if self.reader.delays is not None: set_string = ''.join(str(d) + '\n' for d in self.reader.delays) @@ -82,13 +82,13 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader): y_action = QtWidgets.QAction('Set as y', self) y_action.triggered.connect(lambda: self.set_columns('y')) menu.addActions([x_action, y_action]) - if self.label_5.isVisible(): + if self.deltay_lineEdit.isEnabled(): yerr_action = QtWidgets.QAction('Set as \u0394y', self) yerr_action.triggered.connect(lambda: self.set_columns('yerr')) menu.addAction(yerr_action) menu.popup(QtGui.QCursor.pos()) - def set_columns(self, mode): + def set_columns(self, mode: str): cols = ' '.join([str(s.column()+1) for s in self.ascii_table.selectionModel().selectedColumns()]) try: lineedit = {'x': self.x_lineedit, 'y': self.y_lineedit, 'yerr': self.deltay_lineEdit}[mode] @@ -96,30 +96,56 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader): except KeyError: pass - @QtCore.pyqtSlot(int, name='on_checkBox_2_stateChanged') - def changestaggeredrange(self, evt): - if evt == 2: - self.stag_lineEdit.show() - self.stag_lineEdit.setEnabled(True) - else: - self.stag_lineEdit.hide() - self.stag_lineEdit.setDisabled(True) + @QtCore.pyqtSlot(int, name='on_preview_spinBox_valueChanged') + def show_preview(self, line_no: int): + preview, width = self.reader.make_preview(line_no) + self.ascii_table.setRowCount(min(line_no, len(preview))) + self.ascii_table.setColumnCount(width) + + for i, line in enumerate(preview): + for j, field in enumerate(line): + it = QtWidgets.QTableWidgetItem(field) + self.ascii_table.setItem(i, j, it) + + self.ascii_table.resizeColumnsToContents() + + @QtCore.pyqtSlot(int, name='on_column_checkBox_stateChanged') + @QtCore.pyqtSlot(int, name='on_line_spinBox_valueChanged') + def set_column_names(self, _): + self.ascii_table.setHorizontalHeaderLabels(map(str, range(1, self.ascii_table.columnCount() + 1))) + if self.column_checkBox.isChecked(): + header_line = self.reader.header[self.line_spinBox.value()-1] + self.ascii_table.setHorizontalHeaderLabels(header_line.split()) + + @QtCore.pyqtSlot(int, name='on_staggered_checkBox_stateChanged') + def changestaggeredrange(self, state: int): + self.stag_lineEdit.setEnabled(state) @QtCore.pyqtSlot(name='on_pushButton_clicked') def calc_delays(self): - self.reader.calc_delays(float(self.start_lineedit.text()), float(self.end_lineedit.text()), - int(self.delay_lineedit.text()), log=self.log_checkBox.isChecked(), - stagg=self.staggered_checkBox.isChecked(), stag_size=int(self.stag_lineEdit.text())) + try: + start = float(self.start_lineedit.text()) + stop = float(self.end_lineedit.text()) + num_delays = int(self.delay_lineedit.text()) + is_staggered = self.staggered_checkBox.isChecked() + if is_staggered: + staggered_range = int(self.stag_lineEdit.text()) + else: + staggered_range = 0 + except ValueError: + _ = QtWidgets.QMessageBox.information(self, 'No delays', + 'Delays cannot be calculated: Not enough or wrong arguments.') + return - set_string = ''.join(str(d) + '\n' for d in self.reader.delays) - self.delay_textfield.setPlainText(set_string) + self.reader.calc_delays(start, stop, num_delays, log=self.log_checkBox.isChecked(), + stagg=staggered_range, stag_size=staggered_range) - def update_header(self, text, comment='#'): - text = text.replace(comment, '').lstrip().rstrip() - self.comment_textfield.appendPlainText(text) + if self.reader.delays is not None: + set_string = ''.join(str(d) + '\n' for d in self.reader.delays) + self.delay_textfield.setPlainText(set_string) - @QtCore.pyqtSlot() - def on_delay_textfield_textChanged(self): + @QtCore.pyqtSlot(name='on_delay_textfield_textChanged') + def delays_changed(self): new_delays = str(self.delay_textfield.toPlainText()).rstrip('\n').split('\n') self.delay_lineedit.setText(str(len(new_delays))) if new_delays[0] == '': @@ -139,48 +165,57 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader): def apply(self): # default row for x is the first row, it will be superseded if an integer number is given. - try: - x = [int(self.x_lineedit.text())-1] + x = int(self.x_lineedit.text())-1 + print(x) except ValueError: x = None + try: - y = [int(t)-1 for t in str(self.y_lineedit.text()).split(' ')] + y = [int(t)-1 for t in self.y_lineedit.text().split(' ')] except ValueError: y = None + try: - y_err = [int(t)-1 for t in str(self.deltay_lineEdit.text()).split(' ')] + y_err = [int(t)-1 for t in self.deltay_lineEdit.text().split(' ')] except ValueError: y_err = None - ret_dic = self.reader.export(xidx=x, yidx=y, yerridx=y_err, - mode=self.buttonGroup.checkedButton().text()) + col_header = None + if self.column_checkBox.isChecked(): + col_header = [self.ascii_table.horizontalHeaderItem(i).text() for i in range(self.ascii_table.columnCount())] - self.data_read.emit(ret_dic) + if y is not None and col_header is not None: + col_header = [col_header[i] for i in range(len(col_header)) if i in y] + + try: + ret_dic = self.reader.export(x=x, y=y, yerr=y_err, + mode=self.buttonGroup.checkedButton().text(), + col_names=col_header) + self.data_read.emit(ret_dic) + + except Exception as e: + _ = QtWidgets.QMessageBox.information(self, 'Reading failed', + f'Import data failed with {e.args}') return True - @staticmethod - def _update_dic(key, value, old_dic): - old_dic_keys = list(old_dic.keys()) - if key in old_dic_keys: - counter = 0 - replace_key = key + str(counter) - while replace_key in old_dic_keys: - counter += 1 - replace_key = key + str(counter) - else: - replace_key = key - old_dic[replace_key] = value - @QtCore.pyqtSlot(int, name='on_buttonGroup_buttonClicked') - def show_error(self, val): - if val == -2: - self.widget.show() - else: - self.deltay_lineEdit.setText('') - self.widget.hide() + def show_error(self, val: int): + self.deltay_lineEdit.setEnabled(val == -3) @QtCore.pyqtSlot(int, name='on_skippy_checkbox_stateChanged') - def skip_next_dial(self, _): - QAsciiReader.skip = self.skippy_checkbox.isChecked() + def skip_next_dial(self, _: int): + print('skippy das buschkänguru', _) + self.skip = self.skippy_checkbox.isChecked() + + +if __name__ == '__main__': + app = QtWidgets.QApplication([]) + # w = QAsciiReader(fname='/autohome/dominik/nmreval/testdata/T_1_omega/250.dat') + # w = QAsciiReader(fname='/autohome/dominik/nmreval/testdata/alter_fit_fitparameter.dat') + w = QAsciiReader(fname='/autohome/dominik/nmreval/testdata/alter_fit_fitparameter2.dat') + # w = QAsciiReader(fname='/autohome/dominik/nmreval/testdata/alter_fit_fit_200.dat') + + w.show() + app.exec() diff --git a/src/gui_qt/io/filereaders.py b/src/gui_qt/io/filereaders.py index d8c4fcd..11d28c2 100755 --- a/src/gui_qt/io/filereaders.py +++ b/src/gui_qt/io/filereaders.py @@ -55,16 +55,15 @@ class QFileReader(QtCore.QObject): else: raise ValueError(f'Unknown type for file {f}') - if r(f) is not None: + try: # If QAsciiReader.skip = True it accepts automatically and returns None r(f).exec() + except AttributeError: + pass self.data_read.emit(self.data) - try: - self.reader['txt'].skip = False - except KeyError: - pass + self.reader['txt'].skip = False return self.data diff --git a/src/gui_qt/lib/expandablewidget.py b/src/gui_qt/lib/expandablewidget.py index 29bfd82..12b9ec9 100644 --- a/src/gui_qt/lib/expandablewidget.py +++ b/src/gui_qt/lib/expandablewidget.py @@ -50,7 +50,6 @@ class ExpandableWidget(QtWidgets.QWidget): return self.setExpansion(not self._expanded) - self.expansionChanged.emit() def setExpansion(self, state: bool): @@ -61,5 +60,7 @@ class ExpandableWidget(QtWidgets.QWidget): self.toolButton.setArrowType(QtCore.Qt.RightArrow) self._expanded = state - self._widget.setVisible(state) + if self._widget is not None: + self._widget.setVisible(state) + self.blockSignals(False) diff --git a/src/nmreval/io/asciireader.py b/src/nmreval/io/asciireader.py index 7f29bb9..7265ad6 100644 --- a/src/nmreval/io/asciireader.py +++ b/src/nmreval/io/asciireader.py @@ -1,6 +1,7 @@ import pathlib import re from collections import OrderedDict +from itertools import islice, zip_longest import numpy as np @@ -13,42 +14,86 @@ NUMBERRE = re.compile(r'[0-9]\.*[0-9]*[Ee]*[+-]*[0-9]*') class AsciiReader: delimiters = ['\t', ' ', ','] - maxcount = 10 def __init__(self, fname): self.fname = None self.header = [] self.data = [] self.delays = None - self.shape = (0, 0) + self.width = [] + self.line_comment = [] + self._last_read_pos = 0 if fname: self.fname = pathlib.Path(fname) - self.load_file() + self.read_header() + self.make_preview(10) self.look_for_delay() def load_file(self, comments='#'): i = 0 - self.shape = (0, 0) with self.fname.open('r') as f: for line in f: line = line.rstrip('\n\t\r, ') + if line.startswith(comments): - self.maxcount += 1 - self.header.append(line.replace(comments, '').lstrip().rstrip()) + self.header.append(line.replace(comments, '').strip()) + else: if line == '': continue - line = self.check_delimiters(line, AsciiReader.delimiters) - self.shape = (self.shape[0]+1, max(self.shape[1], len(line))) + line = re.split('[\s,;]', line) + try: + comment_start = line.index('#') + self.line_comment.append(' '.join(line[comment_start:])) + line = line[:comment_start] + except ValueError: + self.line_comment.append('') + + self.width = max(self.width, len(line)) self.data.append(line) + i += 1 if i == self.maxcount: break + if all(l == '' for l in self.line_comment): + self.line_comment = [] + + def read_header(self, comments='#'): + with self.fname.open('r') as f: + for line in f.readlines(): + line = line.rstrip('\n\t\r, ') + if line.startswith(comments): + self.header.append(line.replace(comments, '').strip()) + else: + break + + def make_preview(self, num_lines: int): + if num_lines <= len(self.data): + return self.data[:num_lines], max(self.width[:num_lines]) + + num_lines += len(self.header) + with self.fname.open('r') as f: + for i, line in enumerate(islice(f, len(self.header)+len(self.data), num_lines)): + line = line.rstrip('\n\t\r, ') + + line = re.split('[\s,;]', line) + try: + comment_start = line.index('#') + self.line_comment.append(' '.join(line[comment_start:])) + line = line[:comment_start] + except ValueError: + self.line_comment.append('') + + self.width.append(len(line)) + self.data.append(line) + + return self.data, max(self.width) + def look_for_delay(self, fname=None): if fname is None: - fname = self.fname.with_name('%s_delay.%s' % (self.fname.name, self.fname.suffix)) + fname = self.fname.with_name(f'{self.fname.name}_delay.{self.fname.suffix}') try: self.delays = np.loadtxt(fname) @@ -64,113 +109,82 @@ class AsciiReader: if stagg: self.delays = staggered_range(self.delays, stepsize=stag_size) - def export(self, xidx=None, yidx=None, yerridx=None, mode='Points') -> list: - if xidx is None: - xidx = [0] + def export(self, x: int = None, y: list = None, yerr: list = None, + mode: str = 'Points', col_names=None) -> list: + if yerr is None: + yerr = [] + elif y is None: + raise ValueError('y is None and yerr is not None') - if yidx is None: - yidx = list(range(0, self.shape[1])) - yidx.remove(xidx[0]) + if (x is None) ^ (y is None): + raise ValueError(f'x is {type(x)} and y is {type(y)}, should be both None or both defined') - if yerridx is None: - yerridx = [] + if x is None: + x = [0] + elif isinstance(x, int): + x = [x] + else: + raise ValueError(f'x is {type(x)} not int') - cols = xidx + yidx + yerridx + if y is None: + y = list(range(1, max(self.width))) + + cols = x + y + yerr raw_data = np.genfromtxt(self.fname, usecols=cols, missing_values='--') - - try: - last_line = self.header[-1].split() - except IndexError: - last_line = [] + if raw_data.ndim == 1: + # only one row or column + if len(self.data) == 1: + # one row + raw_data = raw_data.reshape(1, -1) + else: + raw_data = raw_data.reshape(-1, 1) if self.delays is not None: if raw_data.shape[0] % len(self.delays) != 0: - raise ValueError('number of delays {} does not fit into length of date {}'.format( - len(self.delays), raw_data.shape[1])) + raise ValueError(f'number of delays {len(self.delays)} does not fit into length of date {raw_data.shape[1]}') raw_data = raw_data.reshape((len(self.delays), -1, raw_data.shape[1])) else: raw_data = raw_data.reshape((1, *raw_data.shape)) - names = True if len(last_line) == raw_data.shape[1] else False - only_f = self.fname.stem + filename = self.fname.stem if self.delays: - del_names = self.delays + delay_names = self.delays else: - del_names = [only_f] + delay_names = [filename] - ret_dic = OrderedDict() - for j in range(raw_data.shape[0]): - value = del_names[j] + imported_sets = [] + for i, value in enumerate(delay_names): + kwargs = {'value': value, 'filename': self.fname, 'name': filename, 'group': filename, 'y_err': None} + + num_y = len(y) if mode == 'Points': - try: - # TODO read errors correctly - for k in range(1, raw_data.shape[2]): - if raw_data.shape[2] < 3: - name = only_f - elif names: - name = last_line[k] - else: - name = only_f+'_'+str(k) - new_data = Points(raw_data[j, :, 0], raw_data[j, :, k], group=only_f, - name=name, value=value, filename=self.fname) - - self._update_dic(name, new_data, ret_dic) - except IndexError: - new_data = Points(np.arange(0, raw_data.shape[1]), raw_data[0, :], - name=only_f, group=str(only_f), filename=self.fname) - - self._update_dic(only_f, new_data, ret_dic) + single_len = 1 + cls = Points + stepsize = 1 + elif mode == 'FID': + cls = FID + single_len = 2 + stepsize = 2 + elif mode == 'Spectrum': + cls = Spectrum + single_len = 2 + stepsize = 2 else: - cls = FID if mode == 'FID' else Spectrum + raise ValueError(f'Unknown mode {mode}, mot ´Points´, ´FID´ or ´Spectrum´.') - try: - for k in range(1, raw_data.shape[2], 2): - if raw_data.shape[2] < 4: - name = only_f - elif names: - name = last_line[k] - else: - name = only_f + '_' + str(k) + for j in range(1, num_y+1, stepsize): + if col_names is not None: + # predefined name + kwargs['name'] = col_names[j-1] + elif num_y > single_len: + # more than one axis, append column number + kwargs['name'] = filename + '_' + str(y[j-1]) - new_data = cls(raw_data[j, :, 0], raw_data[j, :, k:k+2].T, value=value, - group=name, name=str(value), filename=self.fname) - self._update_dic(name, new_data, ret_dic) + if j+num_y+1 < raw_data.shape[2]: + kwargs['y_err'] = raw_data[i, j+num_y+1] - except OverflowError: - new_data = cls(np.arange(0, raw_data.shape[1]), raw_data[0, :], - group=only_f, name=str(only_f), filename=self.fname) - self._update_dic(only_f, new_data, ret_dic) + imported_sets.append(cls(x=raw_data[i, :, 0], y=raw_data[i, :, j:j+single_len].T, **kwargs)) - return list(ret_dic.values()) - - @staticmethod - def _update_dic(key, value, old_dic): - old_dic_keys = old_dic.keys() - if key in old_dic_keys: - counter = 0 - replace_key = key + str(counter) - while replace_key in old_dic_keys: - counter += 1 - replace_key = key + str(counter) - else: - replace_key = key - old_dic[replace_key] = value - - @staticmethod - def check_delimiters(line: str, delimiters: list): - line = [line] - - for delim in delimiters: - new_l = [] - for l in line: - if delim in [' ', '\t']: - new_l.extend(l.split()) - else: - new_l.extend((l.split(delim))) - line = new_l[:] - - ret_val = [l for l in line] - - return ret_val + return imported_sets diff --git a/src/resources/_ui/asciidialog.ui b/src/resources/_ui/asciidialog.ui index bd54180..cb9e338 100644 --- a/src/resources/_ui/asciidialog.ui +++ b/src/resources/_ui/asciidialog.ui @@ -6,8 +6,8 @@ 0 0 - 667 - 509 + 627 + 703 @@ -25,56 +25,274 @@ - 0 + 6 - 0 + 6 - 0 + 6 - 0 + 6 - - - false - - - - 16777215 - 180 - + + + + + + Options + + + 3 + + + 3 + + + 3 + + + 3 + + + 9 + + + + + FID + + + true + + + buttonGroup + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Specify which column is used as x-value.</p></body></html> + + + Qt::ImhFormattedNumbersOnly|Qt::ImhPreferNumbers + + + + + + + y + + + + + + + Points + + + true + + + true + + + buttonGroup + + + + + + + + 0 + 0 + + + + + + + + <html><head/><body><p>Δy</p></body></html> + + + + + + + + 0 + 0 + + + + Column name + + + + + + + + 0 + 0 + + + + Import as + + + + + + + + 0 + 0 + + + + Use columns as + + + + + + + + 0 + 0 + + + + <html><head/><body><p>Specify which columns are read for y-values. ('Points': Every number creates a new data set;'FID'/'Spectrum': Numbers at even positions are used for real parts, at odd positions for imaginary parts.)</p></body></html> + + + Qt::ImhFormattedNumbersOnly|Qt::ImhPreferNumbers + + + + + + + Spectrum + + + buttonGroup + + + + + + + + 0 + 0 + + + + x + + + + + + + + 0 + 0 + + + + header line + + + 1 + + + + + + + 1 + + + 10 + + + + + + + Preview length + + + + - - - - 0 - 0 - + + + Preview - - Qt::ScrollBarAsNeeded - - - QAbstractItemView::NoEditTriggers - - - true - - - QAbstractItemView::ExtendedSelection - - - QAbstractItemView::SelectColumns - - - 1 - + + + 0 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + Qt::ScrollBarAsNeeded + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectColumns + + + 1 + + + + @@ -84,6 +302,18 @@ Delays + + 6 + + + 6 + + + 6 + + + 6 + @@ -172,12 +402,21 @@ Calculate delays - - - ../../../../.designer/backup../../../../.designer/backup - + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -199,97 +438,6 @@ - - - - x - - - - - - - <html><head/><body><p>Specify which column is used as x-value.</p></body></html> - - - Qt::ImhFormattedNumbersOnly|Qt::ImhPreferNumbers - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - y - - - - - - - <html><head/><body><p>Specify which columns are read for y-values. ('Points': Every number creates a new data set;'FID'/'Spectrum': Numbers at even positions are used for real parts, at odd positions for imaginary parts.)</p></body></html> - - - Qt::ImhFormattedNumbersOnly|Qt::ImhPreferNumbers - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - <html><head/><body><p>Δy</p></body></html> - - - - - - - - - @@ -320,45 +468,6 @@ - - - - Points - - - true - - - true - - - buttonGroup - - - - - - - FID - - - true - - - buttonGroup - - - - - - - Spectrum - - - buttonGroup - - - @@ -370,6 +479,36 @@ + + + ExpandableWidget + QWidget +
..lib.expandablewidget
+ 1 +
+
+ + tabWidget + column_checkBox + line_spinBox + preview_spinBox + pts_radioButton + FID_radioButton + spectrum_radioButton + x_lineedit + y_lineedit + deltay_lineEdit + ascii_table + skippy_checkbox + delay_textfield + delay_lineedit + start_lineedit + end_lineedit + log_checkBox + staggered_checkBox + stag_lineEdit + pushButton +