From f956c111c2bfe983068bbb5c22efcadcb89cebf9 Mon Sep 17 00:00:00 2001
From: Dominik Demuth
Date: Sun, 5 Nov 2023 17:11:28 +0100
Subject: [PATCH] regex for numeric value for data from text files; closes #127
---
src/gui_qt/_py/asciidialog.py | 75 ++++++++++--------
src/gui_qt/io/asciireader.py | 68 +++++++++++++---
src/nmreval/io/asciireader.py | 23 ++++--
src/nmreval/utils/__init__.py | 1 +
src/resources/_ui/asciidialog.ui | 129 ++++++++++++++++++-------------
5 files changed, 196 insertions(+), 100 deletions(-)
diff --git a/src/gui_qt/_py/asciidialog.py b/src/gui_qt/_py/asciidialog.py
index 8fee8ed..404f5c0 100644
--- a/src/gui_qt/_py/asciidialog.py
+++ b/src/gui_qt/_py/asciidialog.py
@@ -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(627, 1245)
+ ascii_reader.resize(665, 904)
self.verticalLayout = QtWidgets.QVBoxLayout(ascii_reader)
self.verticalLayout.setObjectName("verticalLayout")
self.tabWidget = QtWidgets.QTabWidget(ascii_reader)
@@ -156,39 +156,51 @@ class Ui_ascii_reader(object):
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem1, 4, 1, 1, 1)
self.horizontalLayout_4.addLayout(self.gridLayout_2)
- self.verticalLayout_4 = QtWidgets.QVBoxLayout()
- self.verticalLayout_4.setObjectName("verticalLayout_4")
- self.horizontalLayout_4.addLayout(self.verticalLayout_4)
self.verticalLayout_3.addWidget(self.groupBox)
self.dsdfsf = QtWidgets.QLabel(self.tabWidgetPage1)
self.dsdfsf.setObjectName("dsdfsf")
self.verticalLayout_3.addWidget(self.dsdfsf)
- self.label_8 = QtWidgets.QLabel(self.tabWidgetPage1)
- self.label_8.setObjectName("label_8")
- self.verticalLayout_3.addWidget(self.label_8)
- self.radioButton = QtWidgets.QRadioButton(self.tabWidgetPage1)
- self.radioButton.setObjectName("radioButton")
+ self.gridLayout = QtWidgets.QGridLayout()
+ self.gridLayout.setObjectName("gridLayout")
+ self.re_match_index = QtWidgets.QSpinBox(self.tabWidgetPage1)
+ self.re_match_index.setMinimum(1)
+ self.re_match_index.setObjectName("re_match_index")
+ self.gridLayout.addWidget(self.re_match_index, 1, 3, 1, 1)
+ self.label_9 = QtWidgets.QLabel(self.tabWidgetPage1)
+ self.label_9.setObjectName("label_9")
+ self.gridLayout.addWidget(self.label_9, 1, 2, 1, 1)
+ self.regex_input = QtWidgets.QLineEdit(self.tabWidgetPage1)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.regex_input.sizePolicy().hasHeightForWidth())
+ self.regex_input.setSizePolicy(sizePolicy)
+ self.regex_input.setObjectName("regex_input")
+ self.gridLayout.addWidget(self.regex_input, 1, 1, 1, 1)
+ self.re_button = QtWidgets.QRadioButton(self.tabWidgetPage1)
+ self.re_button.setChecked(True)
+ self.re_button.setObjectName("re_button")
self.buttonGroup_2 = QtWidgets.QButtonGroup(ascii_reader)
self.buttonGroup_2.setObjectName("buttonGroup_2")
- self.buttonGroup_2.addButton(self.radioButton)
- self.verticalLayout_3.addWidget(self.radioButton)
- self.lineEdit = QtWidgets.QLineEdit(self.tabWidgetPage1)
- self.lineEdit.setObjectName("lineEdit")
- self.verticalLayout_3.addWidget(self.lineEdit)
- self.radioButton_2 = QtWidgets.QRadioButton(self.tabWidgetPage1)
- self.radioButton_2.setObjectName("radioButton_2")
- self.buttonGroup_2.addButton(self.radioButton_2)
- self.verticalLayout_3.addWidget(self.radioButton_2)
- self.lineEdit_2 = QtWidgets.QLineEdit(self.tabWidgetPage1)
- self.lineEdit_2.setObjectName("lineEdit_2")
- self.verticalLayout_3.addWidget(self.lineEdit_2)
- self.radioButton_3 = QtWidgets.QRadioButton(self.tabWidgetPage1)
- self.radioButton_3.setObjectName("radioButton_3")
- self.buttonGroup_2.addButton(self.radioButton_3)
- self.verticalLayout_3.addWidget(self.radioButton_3)
- self.spinBox = QtWidgets.QSpinBox(self.tabWidgetPage1)
- self.spinBox.setObjectName("spinBox")
- self.verticalLayout_3.addWidget(self.spinBox)
+ self.buttonGroup_2.addButton(self.re_button)
+ self.gridLayout.addWidget(self.re_button, 1, 0, 1, 1)
+ self.custom_input = QtWidgets.QLineEdit(self.tabWidgetPage1)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.custom_input.sizePolicy().hasHeightForWidth())
+ self.custom_input.setSizePolicy(sizePolicy)
+ self.custom_input.setObjectName("custom_input")
+ self.gridLayout.addWidget(self.custom_input, 2, 1, 1, 1)
+ self.custom_button = QtWidgets.QRadioButton(self.tabWidgetPage1)
+ self.custom_button.setObjectName("custom_button")
+ self.buttonGroup_2.addButton(self.custom_button)
+ self.gridLayout.addWidget(self.custom_button, 2, 0, 1, 1)
+ self.label_8 = QtWidgets.QLabel(self.tabWidgetPage1)
+ self.label_8.setWordWrap(True)
+ self.label_8.setObjectName("label_8")
+ self.gridLayout.addWidget(self.label_8, 0, 0, 1, 4)
+ self.verticalLayout_3.addLayout(self.gridLayout)
self.groupBox_2 = QtWidgets.QGroupBox(self.tabWidgetPage1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
@@ -330,10 +342,11 @@ class Ui_ascii_reader(object):
self.label_5.setText(_translate("ascii_reader", "
Δy
"))
self.x_label.setText(_translate("ascii_reader", "x"))
self.dsdfsf.setText(_translate("ascii_reader", "Numerical value"))
+ self.label_9.setText(_translate("ascii_reader", "Match index"))
+ self.regex_input.setToolTip(_translate("ascii_reader", "Token:
[abc]: Matches any of a, b, or c
[a-z]: Matches any digit in the range a-z
\\d: Matches any digit in the range 0-9 (equal to [0-9}
Quantifiers:
a*: 0 or more of a
a*: 1 or more of a
a?: 0 or 1 of a
"))
+ self.re_button.setText(_translate("ascii_reader", "Regex"))
+ self.custom_button.setText(_translate("ascii_reader", "Custom value"))
self.label_8.setText(_translate("ascii_reader", "Filename"))
- self.radioButton.setText(_translate("ascii_reader", "Regex"))
- self.radioButton_2.setText(_translate("ascii_reader", "Custom value"))
- self.radioButton_3.setText(_translate("ascii_reader", "Position in filename"))
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"))
diff --git a/src/gui_qt/io/asciireader.py b/src/gui_qt/io/asciireader.py
index f4b71a3..cbbb771 100644
--- a/src/gui_qt/io/asciireader.py
+++ b/src/gui_qt/io/asciireader.py
@@ -1,6 +1,6 @@
from __future__ import annotations
-from pathlib import Path
+import re
from nmreval.io.asciireader import AsciiReader
from nmreval.utils import NUMBER_RE
@@ -18,6 +18,9 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
self.setupUi(self)
self.reader = None
+ self._matches = []
+ self.regex_input.setText(NUMBER_RE.pattern)
+ self.custom_input.setValidator(QtGui.QDoubleValidator())
self.comment_textfield = QtWidgets.QPlainTextEdit(self.header_widget)
self.comment_textfield.setReadOnly(True)
@@ -46,6 +49,8 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
def __call__(self, fname, *args, **kwargs):
self.reader = AsciiReader(fname)
+ self.check_filename(self.regex_input.text())
+
if self.skip:
self.accept()
return
@@ -62,8 +67,6 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked)
self.skippy_checkbox.blockSignals(False)
- self.check_filename(fname)
-
return self
def set_gui(self):
@@ -145,7 +148,7 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
staggered_range = 0
except ValueError:
_ = QtWidgets.QMessageBox.information(self, 'No delays',
- 'Delays cannot be calculated: Not enough or wrong arguments.')
+ 'Delays cannot be calculated: Not enough or wrong arguments.')
return
self.reader.calc_delays(start, stop, num_delays, log=self.log_checkBox.isChecked(),
@@ -204,9 +207,14 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
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)
+ ret_dic = self.reader.export(
+ x=x,
+ y=y,
+ yerr=y_err,
+ mode=self.buttonGroup.checkedButton().text(),
+ col_names=col_header,
+ num_value=self.get_numerical_value(),
+ )
self.data_read.emit(ret_dic)
except ImportError as e:
@@ -223,7 +231,45 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
def skip_next_dial(self, _: int):
self.skip = self.skippy_checkbox.isChecked()
- def check_filename(self, filename: str | Path):
- self.label_8.setText(str(filename.stem))
- for i in NUMBER_RE.finditer(str(filename.stem)):
- print(i)
+ @QtCore.pyqtSlot(str, name='on_regex_input_textChanged')
+ def check_filename(self, pattern: str = NUMBER_RE.pattern):
+ if self.reader is None:
+ return
+
+ try:
+ pattern = re.compile(pattern)
+ self.regex_input.setStyleSheet('color: rgb(0, 0, 0)')
+ self._matches = [m for m in pattern.finditer(str(self.reader.fname.stem))]
+ except re.error:
+ self._matches = []
+
+ if self._matches:
+ self.re_match_index.blockSignals(True)
+ self.re_match_index.setMaximum(len(self._matches))
+ self.re_match_index.blockSignals(False)
+ else:
+ self.regex_input.setStyleSheet('color: rgb(255, 0, 0)')
+
+ self.show_match(self.re_match_index.value())
+
+ @QtCore.pyqtSlot(int, name='on_re_match_index_valueChanged')
+ def show_match(self, idx: int = 0):
+ fname = str(self.reader.fname.stem)
+
+ if self._matches:
+ m = self._matches[idx-1]
+ self.label_8.setText(f'{fname[:m.start()]}{fname[m.start():m.end()]}{fname[m.end():]}')
+ else:
+ self.label_8.setText(fname)
+
+ def get_numerical_value(self):
+ val = 0
+ if self.re_button.isChecked() and self._matches:
+ m = self._matches[self.re_match_index.value()-1]
+ val = float(NUMBER_RE.search(m.group()).group().replace('p', '.'))
+ elif self.custom_button.isChecked():
+ val = float(self.custom_input.text())
+
+ return val
+
+
diff --git a/src/nmreval/io/asciireader.py b/src/nmreval/io/asciireader.py
index dddf87d..afed5d8 100644
--- a/src/nmreval/io/asciireader.py
+++ b/src/nmreval/io/asciireader.py
@@ -11,8 +11,6 @@ from ..data.bds import BDS
from ..data.dsc import DSC
from ..utils.utils import staggered_range
-NUMBERRE = re.compile(r'[0-9]\.*[0-9]*[Ee]*[+-]*[0-9]*')
-
class AsciiReader:
# delimiters = ['\t', ' ', ',']
@@ -87,8 +85,15 @@ class AsciiReader:
if stagg:
self.delays = staggered_range(self.delays, stepsize=stag_size)
- def export(self, x: int = None, y: list = None, yerr: list = None,
- mode: str = 'points', col_names=None) -> list:
+ def export(
+ self: 'AsciiReader',
+ x: int = None,
+ y: list = None,
+ yerr: list = None,
+ mode: str = 'points',
+ col_names=None,
+ num_value: float = None,
+ ) -> list:
mode = mode.lower()
if mode not in ['points', 'fid', 'spectrum', 'dsc', 'bds']:
@@ -138,12 +143,18 @@ class AsciiReader:
if self.delays:
delay_names = self.delays
else:
- delay_names = [filename]
+ delay_names = [num_value]
imported_sets = []
for i, value in enumerate(delay_names):
- kwargs = {'value': value, 'filename': self.fname, 'name': filename, 'group': filename, 'y_err': None}
+ kwargs = {
+ 'value': value,
+ 'filename': self.fname,
+ 'name': filename,
+ 'group': filename,
+ 'y_err': None
+ }
num_y = len(y)
single_len = 1
diff --git a/src/nmreval/utils/__init__.py b/src/nmreval/utils/__init__.py
index cc86e30..24e8009 100755
--- a/src/nmreval/utils/__init__.py
+++ b/src/nmreval/utils/__init__.py
@@ -4,3 +4,4 @@ from .constants import *
NUMBER_RE = re.compile(r'[-+]?\d*[+p.]?\d+([eE][-+]?\d+)?', re.MULTILINE)
+UNSIGNED_NUMBER_RE = re.compile(r'[-+]?\d*[+p.]?\d+([eE][-+]?\d+)?', re.MULTILINE)
diff --git a/src/resources/_ui/asciidialog.ui b/src/resources/_ui/asciidialog.ui
index 1c91059..6822011 100644
--- a/src/resources/_ui/asciidialog.ui
+++ b/src/resources/_ui/asciidialog.ui
@@ -6,8 +6,8 @@
0
0
- 627
- 1245
+ 665
+ 904
@@ -301,9 +301,6 @@
- -
-
-
@@ -315,50 +312,78 @@
-
-
-
- Filename
-
-
-
- -
-
-
- Regex
-
-
- buttonGroup_2
-
-
-
- -
-
-
- -
-
-
- Custom value
-
-
- buttonGroup_2
-
-
-
- -
-
-
- -
-
-
- Position in filename
-
-
- buttonGroup_2
-
-
-
- -
-
+
+
-
+
+
+ 1
+
+
+
+ -
+
+
+ Match index
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ <html><head/><body><p>Token:<br/>[abc]: Matches any of a, b, or c<br/>[a-z]: Matches any digit in the range a-z<br/>\d: Matches any digit in the range 0-9 (equal to [0-9}</p><p>Quantifiers:<br/>a*: 0 or more of a<br/>a*: 1 or more of a<br/>a?: 0 or 1 of a</p></body></html>
+
+
+
+ -
+
+
+ Regex
+
+
+ true
+
+
+ buttonGroup_2
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+ Custom value
+
+
+ buttonGroup_2
+
+
+
+ -
+
+
+ Filename
+
+
+ true
+
+
+
+
-
@@ -614,8 +639,8 @@
close()
- 366
- 485
+ 375
+ 894
366
@@ -625,7 +650,7 @@
-
+