regex for numeric value for data from text files; closes #127

This commit is contained in:
Dominik Demuth 2023-11-05 17:11:28 +01:00
parent cb2bc78a2a
commit f956c111c2
5 changed files with 196 additions and 100 deletions

View File

@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ascii_reader(object): class Ui_ascii_reader(object):
def setupUi(self, ascii_reader): def setupUi(self, ascii_reader):
ascii_reader.setObjectName("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 = QtWidgets.QVBoxLayout(ascii_reader)
self.verticalLayout.setObjectName("verticalLayout") self.verticalLayout.setObjectName("verticalLayout")
self.tabWidget = QtWidgets.QTabWidget(ascii_reader) 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) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.gridLayout_2.addItem(spacerItem1, 4, 1, 1, 1) self.gridLayout_2.addItem(spacerItem1, 4, 1, 1, 1)
self.horizontalLayout_4.addLayout(self.gridLayout_2) 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.verticalLayout_3.addWidget(self.groupBox)
self.dsdfsf = QtWidgets.QLabel(self.tabWidgetPage1) self.dsdfsf = QtWidgets.QLabel(self.tabWidgetPage1)
self.dsdfsf.setObjectName("dsdfsf") self.dsdfsf.setObjectName("dsdfsf")
self.verticalLayout_3.addWidget(self.dsdfsf) self.verticalLayout_3.addWidget(self.dsdfsf)
self.label_8 = QtWidgets.QLabel(self.tabWidgetPage1) self.gridLayout = QtWidgets.QGridLayout()
self.label_8.setObjectName("label_8") self.gridLayout.setObjectName("gridLayout")
self.verticalLayout_3.addWidget(self.label_8) self.re_match_index = QtWidgets.QSpinBox(self.tabWidgetPage1)
self.radioButton = QtWidgets.QRadioButton(self.tabWidgetPage1) self.re_match_index.setMinimum(1)
self.radioButton.setObjectName("radioButton") 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 = QtWidgets.QButtonGroup(ascii_reader)
self.buttonGroup_2.setObjectName("buttonGroup_2") self.buttonGroup_2.setObjectName("buttonGroup_2")
self.buttonGroup_2.addButton(self.radioButton) self.buttonGroup_2.addButton(self.re_button)
self.verticalLayout_3.addWidget(self.radioButton) self.gridLayout.addWidget(self.re_button, 1, 0, 1, 1)
self.lineEdit = QtWidgets.QLineEdit(self.tabWidgetPage1) self.custom_input = QtWidgets.QLineEdit(self.tabWidgetPage1)
self.lineEdit.setObjectName("lineEdit") sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
self.verticalLayout_3.addWidget(self.lineEdit) sizePolicy.setHorizontalStretch(0)
self.radioButton_2 = QtWidgets.QRadioButton(self.tabWidgetPage1) sizePolicy.setVerticalStretch(0)
self.radioButton_2.setObjectName("radioButton_2") sizePolicy.setHeightForWidth(self.custom_input.sizePolicy().hasHeightForWidth())
self.buttonGroup_2.addButton(self.radioButton_2) self.custom_input.setSizePolicy(sizePolicy)
self.verticalLayout_3.addWidget(self.radioButton_2) self.custom_input.setObjectName("custom_input")
self.lineEdit_2 = QtWidgets.QLineEdit(self.tabWidgetPage1) self.gridLayout.addWidget(self.custom_input, 2, 1, 1, 1)
self.lineEdit_2.setObjectName("lineEdit_2") self.custom_button = QtWidgets.QRadioButton(self.tabWidgetPage1)
self.verticalLayout_3.addWidget(self.lineEdit_2) self.custom_button.setObjectName("custom_button")
self.radioButton_3 = QtWidgets.QRadioButton(self.tabWidgetPage1) self.buttonGroup_2.addButton(self.custom_button)
self.radioButton_3.setObjectName("radioButton_3") self.gridLayout.addWidget(self.custom_button, 2, 0, 1, 1)
self.buttonGroup_2.addButton(self.radioButton_3) self.label_8 = QtWidgets.QLabel(self.tabWidgetPage1)
self.verticalLayout_3.addWidget(self.radioButton_3) self.label_8.setWordWrap(True)
self.spinBox = QtWidgets.QSpinBox(self.tabWidgetPage1) self.label_8.setObjectName("label_8")
self.spinBox.setObjectName("spinBox") self.gridLayout.addWidget(self.label_8, 0, 0, 1, 4)
self.verticalLayout_3.addWidget(self.spinBox) self.verticalLayout_3.addLayout(self.gridLayout)
self.groupBox_2 = QtWidgets.QGroupBox(self.tabWidgetPage1) self.groupBox_2 = QtWidgets.QGroupBox(self.tabWidgetPage1)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
@ -330,10 +342,11 @@ class Ui_ascii_reader(object):
self.label_5.setText(_translate("ascii_reader", "<html><head/><body><p>Δy</p></body></html>")) self.label_5.setText(_translate("ascii_reader", "<html><head/><body><p>Δy</p></body></html>"))
self.x_label.setText(_translate("ascii_reader", "x")) self.x_label.setText(_translate("ascii_reader", "x"))
self.dsdfsf.setText(_translate("ascii_reader", "Numerical value")) self.dsdfsf.setText(_translate("ascii_reader", "Numerical value"))
self.label_9.setText(_translate("ascii_reader", "Match index"))
self.regex_input.setToolTip(_translate("ascii_reader", "<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>"))
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.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.groupBox_2.setTitle(_translate("ascii_reader", "Preview"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("ascii_reader", "Data")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tabWidgetPage1), _translate("ascii_reader", "Data"))
self.label_2.setText(_translate("ascii_reader", "Number of delays")) self.label_2.setText(_translate("ascii_reader", "Number of delays"))

View File

@ -1,6 +1,6 @@
from __future__ import annotations from __future__ import annotations
from pathlib import Path import re
from nmreval.io.asciireader import AsciiReader from nmreval.io.asciireader import AsciiReader
from nmreval.utils import NUMBER_RE from nmreval.utils import NUMBER_RE
@ -18,6 +18,9 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
self.setupUi(self) self.setupUi(self)
self.reader = None 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 = QtWidgets.QPlainTextEdit(self.header_widget)
self.comment_textfield.setReadOnly(True) self.comment_textfield.setReadOnly(True)
@ -46,6 +49,8 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
def __call__(self, fname, *args, **kwargs): def __call__(self, fname, *args, **kwargs):
self.reader = AsciiReader(fname) self.reader = AsciiReader(fname)
self.check_filename(self.regex_input.text())
if self.skip: if self.skip:
self.accept() self.accept()
return return
@ -62,8 +67,6 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked) self.skippy_checkbox.setCheckState(QtCore.Qt.Unchecked)
self.skippy_checkbox.blockSignals(False) self.skippy_checkbox.blockSignals(False)
self.check_filename(fname)
return self return self
def set_gui(self): def set_gui(self):
@ -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] col_header = [col_header[i] for i in range(len(col_header)) if i in y]
try: try:
ret_dic = self.reader.export(x=x, y=y, yerr=y_err, ret_dic = self.reader.export(
x=x,
y=y,
yerr=y_err,
mode=self.buttonGroup.checkedButton().text(), mode=self.buttonGroup.checkedButton().text(),
col_names=col_header) col_names=col_header,
num_value=self.get_numerical_value(),
)
self.data_read.emit(ret_dic) self.data_read.emit(ret_dic)
except ImportError as e: except ImportError as e:
@ -223,7 +231,45 @@ class QAsciiReader(QtWidgets.QDialog, Ui_ascii_reader):
def skip_next_dial(self, _: int): def skip_next_dial(self, _: int):
self.skip = self.skippy_checkbox.isChecked() self.skip = self.skippy_checkbox.isChecked()
def check_filename(self, filename: str | Path): @QtCore.pyqtSlot(str, name='on_regex_input_textChanged')
self.label_8.setText(str(filename.stem)) def check_filename(self, pattern: str = NUMBER_RE.pattern):
for i in NUMBER_RE.finditer(str(filename.stem)): if self.reader is None:
print(i) 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()]}<b>{fname[m.start():m.end()]}</b>{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

View File

@ -11,8 +11,6 @@ from ..data.bds import BDS
from ..data.dsc import DSC from ..data.dsc import DSC
from ..utils.utils import staggered_range from ..utils.utils import staggered_range
NUMBERRE = re.compile(r'[0-9]\.*[0-9]*[Ee]*[+-]*[0-9]*')
class AsciiReader: class AsciiReader:
# delimiters = ['\t', ' ', ','] # delimiters = ['\t', ' ', ',']
@ -87,8 +85,15 @@ class AsciiReader:
if stagg: if stagg:
self.delays = staggered_range(self.delays, stepsize=stag_size) self.delays = staggered_range(self.delays, stepsize=stag_size)
def export(self, x: int = None, y: list = None, yerr: list = None, def export(
mode: str = 'points', col_names=None) -> list: 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() mode = mode.lower()
if mode not in ['points', 'fid', 'spectrum', 'dsc', 'bds']: if mode not in ['points', 'fid', 'spectrum', 'dsc', 'bds']:
@ -138,12 +143,18 @@ class AsciiReader:
if self.delays: if self.delays:
delay_names = self.delays delay_names = self.delays
else: else:
delay_names = [filename] delay_names = [num_value]
imported_sets = [] imported_sets = []
for i, value in enumerate(delay_names): 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) num_y = len(y)
single_len = 1 single_len = 1

View File

@ -4,3 +4,4 @@ from .constants import *
NUMBER_RE = re.compile(r'[-+]?\d*[+p.]?\d+([eE][-+]?\d+)?', re.MULTILINE) 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)

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>627</width> <width>665</width>
<height>1245</height> <height>904</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -301,9 +301,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4"/>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -315,27 +312,59 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QLabel" name="label_8"> <layout class="QGridLayout" name="gridLayout">
<property name="text"> <item row="1" column="3">
<string>Filename</string> <widget class="QSpinBox" name="re_match_index">
<property name="minimum">
<number>1</number>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item row="1" column="2">
<widget class="QRadioButton" name="radioButton"> <widget class="QLabel" name="label_9">
<property name="text">
<string>Match index</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="regex_input">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Token:&lt;br/&gt;[abc]: Matches any of a, b, or c&lt;br/&gt;[a-z]: Matches any digit in the range a-z&lt;br/&gt;\d: Matches any digit in the range 0-9 (equal to [0-9}&lt;/p&gt;&lt;p&gt;Quantifiers:&lt;br/&gt;a*: 0 or more of a&lt;br/&gt;a*: 1 or more of a&lt;br/&gt;a?: 0 or 1 of a&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="re_button">
<property name="text"> <property name="text">
<string>Regex</string> <string>Regex</string>
</property> </property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup"> <attribute name="buttonGroup">
<string notr="true">buttonGroup_2</string> <string notr="true">buttonGroup_2</string>
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item> <item row="2" column="1">
<widget class="QLineEdit" name="lineEdit"/> <widget class="QLineEdit" name="custom_input">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item> </item>
<item> <item row="2" column="0">
<widget class="QRadioButton" name="radioButton_2"> <widget class="QRadioButton" name="custom_button">
<property name="text"> <property name="text">
<string>Custom value</string> <string>Custom value</string>
</property> </property>
@ -344,21 +373,17 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item> <item row="0" column="0" colspan="4">
<widget class="QLineEdit" name="lineEdit_2"/> <widget class="QLabel" name="label_8">
</item>
<item>
<widget class="QRadioButton" name="radioButton_3">
<property name="text"> <property name="text">
<string>Position in filename</string> <string>Filename</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<attribute name="buttonGroup">
<string notr="true">buttonGroup_2</string>
</attribute>
</widget> </widget>
</item> </item>
<item> </layout>
<widget class="QSpinBox" name="spinBox"/>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="groupBox_2"> <widget class="QGroupBox" name="groupBox_2">
@ -614,8 +639,8 @@
<slot>close()</slot> <slot>close()</slot>
<hints> <hints>
<hint type="sourcelabel"> <hint type="sourcelabel">
<x>366</x> <x>375</x>
<y>485</y> <y>894</y>
</hint> </hint>
<hint type="destinationlabel"> <hint type="destinationlabel">
<x>366</x> <x>366</x>
@ -625,7 +650,7 @@
</connection> </connection>
</connections> </connections>
<buttongroups> <buttongroups>
<buttongroup name="buttonGroup"/>
<buttongroup name="buttonGroup_2"/> <buttongroup name="buttonGroup_2"/>
<buttongroup name="buttonGroup"/>
</buttongroups> </buttongroups>
</ui> </ui>