rework
This commit is contained in:
32 files changed
+75060
-630
No files matched your search
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
import PySide6.QtWidgets as qw
|
||||
import PySide6.QtCore as qc
|
||||
from PySide6.QtCore import Slot, Qt
|
||||
import PySide6.QtGui as qg
|
||||
import pyqtgraph as pg
|
||||
|
||||
import sys
|
||||
|
||||
sys.path.append('../build')
|
||||
|
||||
import slopefit as sf
|
||||
|
||||
class ParamTableModel(qc.QAbstractTableModel):
|
||||
HEADERS = ['property', 'initial value', 'delta']
|
||||
init_changed = qc.Signal(int, float)
|
||||
delta_changed = qc.Signal(int, float)
|
||||
|
||||
def __init__(self, parent = None):
|
||||
super().__init__(parent)
|
||||
self._rows = []
|
||||
|
||||
def rowCount(self, parent=qc.QModelIndex()):
|
||||
return len(self._rows)
|
||||
|
||||
def columnCount(self, parent=qc.QModelIndex()):
|
||||
return len(self.HEADERS)
|
||||
|
||||
def data(self, index, role=Qt.ItemDataRole.DisplayRole):
|
||||
if not index.isValid():
|
||||
return None
|
||||
row, col = index.row(), index.column()
|
||||
value = self._rows[row][col]
|
||||
|
||||
if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole):
|
||||
return "" if value is None else str(value)
|
||||
if role == Qt.ItemDataRole.TextAlignmentRole and col > 0:
|
||||
return int(Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
return None
|
||||
|
||||
def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
|
||||
if not index.isValid() or role != Qt.ItemDataRole.EditRole:
|
||||
return False
|
||||
row, col = index.row(), index.column()
|
||||
if col == 0: # name column: plain text
|
||||
return False
|
||||
else: # x / dx columns: float
|
||||
try:
|
||||
self._rows[row][col] = float(value) if value != "" else None
|
||||
except ValueError:
|
||||
return False
|
||||
self.dataChanged.emit(index, index, [Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole])
|
||||
if col == 1:
|
||||
self.init_changed.emit(row, float(value))
|
||||
elif col == 2:
|
||||
self.delta_changed.emit(row, float(value))
|
||||
return True
|
||||
|
||||
def flags(self, index):
|
||||
if not index.isValid() or index.column() == 0:
|
||||
return Qt.ItemFlag.NoItemFlags
|
||||
return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEditable
|
||||
|
||||
def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
|
||||
if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
|
||||
return self.HEADERS[section]
|
||||
return None
|
||||
|
||||
def set_params(self, params):
|
||||
self.beginResetModel()
|
||||
self._rows = [[name, v, d] for (name, v, d) in params]
|
||||
self.endResetModel()
|
||||
|
||||
|
||||
|
||||
class MainWindow(qw.QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle('slopefit')
|
||||
|
||||
|
||||
self.input_plot = pg.PlotWidget()
|
||||
|
||||
self.lower_bounds = qw.QDoubleSpinBox()
|
||||
self.lower_bounds.setValue(0.0)
|
||||
self.lower_bounds.valueChanged.connect(self.set_lb)
|
||||
|
||||
self.upper_bounds = qw.QDoubleSpinBox()
|
||||
self.upper_bounds.setValue(0.0)
|
||||
self.upper_bounds.valueChanged.connect(self.set_ub)
|
||||
|
||||
|
||||
bounds_layout = qw.QHBoxLayout()
|
||||
bounds_layout.addWidget(self.lower_bounds)
|
||||
bounds_layout.addWidget(self.upper_bounds)
|
||||
|
||||
bounds_widget = qw.QWidget()
|
||||
bounds_widget.setLayout(bounds_layout)
|
||||
|
||||
self.slope_plot = pg.PlotWidget()
|
||||
|
||||
self.curve_box = qw.QComboBox()
|
||||
self.curve_box.addItems(['parabola', 'ellipse'])
|
||||
self.curve_box.currentIndexChanged.connect(self.set_curve_i)
|
||||
|
||||
self.table = qw.QTableView()
|
||||
self.param_model = ParamTableModel()
|
||||
self.param_model.init_changed.connect(self.set_init)
|
||||
self.param_model.delta_changed.connect(self.set_delta)
|
||||
self.table.setModel(self.param_model)
|
||||
self.table.horizontalHeader().setSectionResizeMode(qw.QHeaderView.Stretch)
|
||||
|
||||
self.flip_curve = qw.QCheckBox()
|
||||
self.flip_curve.checkStateChanged.connect(self.set_check)
|
||||
|
||||
self.fit_button = qw.QPushButton()
|
||||
self.fit_button.setText("calculate fit")
|
||||
self.fit_button.clicked.connect(self.do_fit)
|
||||
|
||||
self.error_plot = pg.PlotWidget()
|
||||
plot_group_1 = qw.QHBoxLayout()
|
||||
plot_group_1.addWidget(self.input_plot)
|
||||
plot_group_1.addWidget(self.slope_plot)
|
||||
|
||||
layout = qw.QVBoxLayout()
|
||||
layout.addWidget(qw.QWidget(layout=plot_group_1))
|
||||
layout.addWidget(bounds_widget)
|
||||
layout.addWidget(self.flip_curve)
|
||||
layout.addWidget(self.curve_box)
|
||||
layout.addWidget(self.table)
|
||||
layout.addWidget(self.fit_button)
|
||||
layout.addWidget(self.error_plot)
|
||||
|
||||
central_widget = qw.QWidget()
|
||||
central_widget.setLayout(layout)
|
||||
self.setCentralWidget(central_widget)
|
||||
|
||||
self.init_menu()
|
||||
|
||||
self.optimizer = sf.Optimizer()
|
||||
self.optimizer.set_plot_input_cb(self.plot_input_cb)
|
||||
self.optimizer.set_init_bounds_cb(self.init_bounds_cb)
|
||||
self.optimizer.set_plot_slope_cb(self.plot_slope_cb)
|
||||
self.optimizer.set_update_table_cb(self.update_table_cb)
|
||||
self.optimizer.set_plot_error_cb(self.plot_error_cb)
|
||||
|
||||
@Slot(float)
|
||||
def set_lb(self, lb):
|
||||
self.optimizer.set_lower_bound(lb)
|
||||
|
||||
@Slot(float)
|
||||
def set_ub(self, ub):
|
||||
self.optimizer.set_upper_bound(ub)
|
||||
|
||||
@Slot(int)
|
||||
def set_curve_i(self, i):
|
||||
self.optimizer.set_curve_type(i)
|
||||
|
||||
@Slot(int, float)
|
||||
def set_init(self, i, v):
|
||||
self.optimizer.set_initial(i, v)
|
||||
|
||||
@Slot(int, float)
|
||||
def set_delta(self, i, v):
|
||||
self.optimizer.set_delta(i, v)
|
||||
|
||||
@Slot(bool)
|
||||
def set_check(self, flip):
|
||||
self.optimizer.flip_curve()
|
||||
|
||||
@Slot()
|
||||
def do_fit(self):
|
||||
self.optimizer.calc_fit()
|
||||
|
||||
def init_menu(self):
|
||||
import_action = qg.QAction('&import', self)
|
||||
import_action.triggered.connect(self.import_file)
|
||||
|
||||
menu = self.menuBar()
|
||||
file_menu = menu.addMenu('&file')
|
||||
file_menu.addAction(import_action)
|
||||
|
||||
def import_file(self):
|
||||
print("import file...")
|
||||
fn, _ = qw.QFileDialog.getOpenFileName(self, caption='import file...', filter='data files (*.dat)')
|
||||
print(f"open file {fn}")
|
||||
self.optimizer.import_file(fn)
|
||||
|
||||
def plot_input_cb(self, xs, yss):
|
||||
self.input_plot.clear()
|
||||
for ys in yss:
|
||||
self.input_plot.plot(xs, ys)
|
||||
|
||||
def init_bounds_cb(self, lb, ub, step):
|
||||
self.lower_bounds.setRange(lb, ub)
|
||||
self.lower_bounds.setSingleStep(step)
|
||||
self.lower_bounds.setValue(lb)
|
||||
|
||||
self.upper_bounds.setRange(lb, ub)
|
||||
self.upper_bounds.setSingleStep(step)
|
||||
self.upper_bounds.setValue(ub)
|
||||
|
||||
def plot_slope_cb(self, xs, ys_data, ys_curve):
|
||||
self.slope_plot.clear()
|
||||
self.slope_plot.plot(xs, ys_data)
|
||||
self.slope_plot.plot(xs, ys_curve)
|
||||
|
||||
def update_table_cb(self, entries):
|
||||
self.param_model.set_params(entries)
|
||||
print(entries)
|
||||
|
||||
def plot_error_cb(self, xs, ys):
|
||||
self.error_plot.clear()
|
||||
self.error_plot.plot(xs, ys)
|
||||
|
||||
|
||||
app = qw.QApplication(sys.argv)
|
||||
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
|
||||
app.exec()
|
||||
@@ -0,0 +1,4 @@
|
||||
import PySide6.QtWidgets
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user