diff --git a/main.py b/main.py index 3fe1704..73dea31 100644 --- a/main.py +++ b/main.py @@ -20,5 +20,6 @@ if __name__ == "__main__": app.installTranslator(translator) # fire up main ui ui = MainWindow() - ui.show() + ui.showMaximized() + #ui.show() sys.exit(app.exec_()) diff --git a/pydsf.py b/pydsf.py index f84054c..62fe33a 100644 --- a/pydsf.py +++ b/pydsf.py @@ -478,80 +478,44 @@ class Plate: self.max_tm = max(self.tms) self.min_tm = min(self.tms) - def write_tm_table(self, filename): + def write_tm_table(self, filename, avg=False): with open(filename, 'w') as f: - f.write('#{:<4s}{:>13s}\n'.format('ID', '"Tm [°C]"')) + writer = csv.writer(f, dialect='excel') + header = ['ID', 'Tm [°C]'] + if avg: + header.append('SD [°C]') + writer.writerow(header) for well in self.wells: - if np.isnan(well.tm) or well in self.denatured_wells: - f.write('{:<5s}{:>12s}\n'.format(well.name, 'NaN')) - else: - f.write('{:<5s}{:>12s}\n'.format(well.name, str(well.tm))) + row = [well.name, well.tm] + if avg: + row.append(well.tm_sd) + writer.writerow(row) - def write_avg_tm_table(self, filename): + def write_data_table(self, filename, dataType='raw'): with open(filename, 'w') as f: - f.write('#{:<4s}{:>13s}{:>13s}\n'.format('"ID"', '"Tm [°C]"', - '"SD"')) + writer = csv.writer(f, dialect='excel') + header = ['Tm [°C]'] for well in self.wells: - if np.isnan(well.tm) or well in self.denatured_wells: - f.write('{:<5s}{:>12s}{:>12s}\n'.format(well.name, 'NaN', - 'NaN')) - else: - f.write('{:<5s}{:>12s}{:>12s}\n'.format(well.name, - str(well.tm), - str(well.tm_sd))) - - def write_raw_table(self, filename): - with open(filename, 'w') as f: - f.write('#"Raw data"\n') - f.write('#{:<10s}'.format('"T [°C]"')) - for well in self.wells: - f.write('{:>15s}'.format(well.name)) - f.write('\n') + header.append(well.name) + writer.writerow(header) i = 0 + row = [] for t in self.temprange: - f.write('{:<10s}'.format(str(t))) + row.append(str(t)) for well in self.wells: - d = well.raw[i] + if dataType == 'raw': + d = well.raw[i] + elif dataType == 'filtered': + d = well.filtered[i] + elif dataType == 'derivative': + d = well.derivatives[1][i] + else: + raise ValueError('Valid dataTypes are "raw", "filtered", and "derivative"! dataType provided was:{}'.format(dataType)) d_rounded = float(np.round(d, decimals=3)) - f.write('{:>-15.3f}'.format(d_rounded)) - f.write('\n') - i += 1 - - def write_filtered_table(self, filename): - with open(filename, 'w') as f: - f.write('#"Filtered data" \n') - f.write('#{:<10s}'.format('"T [°C]"')) - for well in self.wells: - f.write('{:>15s}'.format(well.name)) - f.write('\n') - - i = 0 - for t in self.temprange: - f.write('{:<10s}'.format(str(t))) - for well in self.wells: - d = well.filtered[i] - d_rounded = float(np.round(d, decimals=3)) - f.write('{:>-15.3f}'.format(d_rounded)) - f.write('\n') - i += 1 - - def write_derivative_table(self, filename): - with open(filename, 'w') as f: - f.write('#"Derivative dI/dT"\n') - f.write('#{:<10s}'.format('"T [°C]"')) - for well in self.wells: - f.write('{:>15s}'.format(well.name)) - f.write('\n') - - i = 0 - for t in self.temprange: - f.write('{:<10s}'.format(str(t))) - for well in self.wells: - d = well.derivatives[1][i] - d_rounded = float(np.round(d, decimals=3)) - f.write('{:>-15.3f}'.format(d_rounded)) - f.write('\n') + row.append(d_rounded) + writer.writerow(row) + row = [] i += 1 # TODO: Implement 'write_baseline_corrected_table() diff --git a/ui/Ui_mainwindow.py b/ui/Ui_mainwindow.py index 31af081..d16c4a8 100644 --- a/ui/Ui_mainwindow.py +++ b/ui/Ui_mainwindow.py @@ -11,7 +11,12 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") - MainWindow.resize(1066, 795) + MainWindow.resize(4095, 4095) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) + MainWindow.setSizePolicy(sizePolicy) MainWindow.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.centralWidget = QtWidgets.QWidget(MainWindow) self.centralWidget.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) @@ -128,33 +133,6 @@ class Ui_MainWindow(object): self.doubleSpinBox_dt.setObjectName("doubleSpinBox_dt") self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_dt) self.gridLayout.addWidget(self.groupBox_temp, 0, 0, 1, 1) - self.groupBox_cutoff = QtWidgets.QGroupBox(self.groupBox_processing) - self.groupBox_cutoff.setEnabled(True) - self.groupBox_cutoff.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) - self.groupBox_cutoff.setCheckable(True) - self.groupBox_cutoff.setChecked(False) - self.groupBox_cutoff.setObjectName("groupBox_cutoff") - self.formLayout_2 = QtWidgets.QFormLayout(self.groupBox_cutoff) - self.formLayout_2.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) - self.formLayout_2.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.formLayout_2.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) - self.formLayout_2.setObjectName("formLayout_2") - self.label_cutoff_high = QtWidgets.QLabel(self.groupBox_cutoff) - self.label_cutoff_high.setObjectName("label_cutoff_high") - self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_cutoff_high) - self.doubleSpinBox_upper = QtWidgets.QDoubleSpinBox(self.groupBox_cutoff) - self.doubleSpinBox_upper.setPrefix("") - self.doubleSpinBox_upper.setDecimals(1) - self.doubleSpinBox_upper.setObjectName("doubleSpinBox_upper") - self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_upper) - self.label_cutoff_low = QtWidgets.QLabel(self.groupBox_cutoff) - self.label_cutoff_low.setObjectName("label_cutoff_low") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_cutoff_low) - self.doubleSpinBox_lower = QtWidgets.QDoubleSpinBox(self.groupBox_cutoff) - self.doubleSpinBox_lower.setDecimals(1) - self.doubleSpinBox_lower.setObjectName("doubleSpinBox_lower") - self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_lower) - self.gridLayout.addWidget(self.groupBox_cutoff, 0, 1, 1, 1) self.groupBox_signal_threshold = QtWidgets.QGroupBox(self.groupBox_processing) self.groupBox_signal_threshold.setEnabled(True) self.groupBox_signal_threshold.setCheckable(True) @@ -190,8 +168,67 @@ class Ui_MainWindow(object): self.doubleSpinBox_cbar_end.setObjectName("doubleSpinBox_cbar_end") self.formLayout_4.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_cbar_end) self.gridLayout.addWidget(self.groupBox_cbar, 1, 1, 1, 1) + self.groupBox_cutoff = QtWidgets.QGroupBox(self.groupBox_processing) + self.groupBox_cutoff.setEnabled(True) + self.groupBox_cutoff.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.groupBox_cutoff.setCheckable(True) + self.groupBox_cutoff.setChecked(False) + self.groupBox_cutoff.setObjectName("groupBox_cutoff") + self.formLayout_2 = QtWidgets.QFormLayout(self.groupBox_cutoff) + self.formLayout_2.setFieldGrowthPolicy(QtWidgets.QFormLayout.ExpandingFieldsGrow) + self.formLayout_2.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout_2.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.formLayout_2.setObjectName("formLayout_2") + self.label_cutoff_high = QtWidgets.QLabel(self.groupBox_cutoff) + self.label_cutoff_high.setObjectName("label_cutoff_high") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_cutoff_high) + self.doubleSpinBox_upper = QtWidgets.QDoubleSpinBox(self.groupBox_cutoff) + self.doubleSpinBox_upper.setPrefix("") + self.doubleSpinBox_upper.setDecimals(1) + self.doubleSpinBox_upper.setObjectName("doubleSpinBox_upper") + self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_upper) + self.label_cutoff_low = QtWidgets.QLabel(self.groupBox_cutoff) + self.label_cutoff_low.setObjectName("label_cutoff_low") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_cutoff_low) + self.doubleSpinBox_lower = QtWidgets.QDoubleSpinBox(self.groupBox_cutoff) + self.doubleSpinBox_lower.setDecimals(1) + self.doubleSpinBox_lower.setObjectName("doubleSpinBox_lower") + self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.doubleSpinBox_lower) + self.gridLayout.addWidget(self.groupBox_cutoff, 0, 1, 1, 1) + self.groupBox_output = QtWidgets.QGroupBox(self.groupBox_processing) + self.groupBox_output.setCheckable(True) + self.groupBox_output.setChecked(False) + self.groupBox_output.setObjectName("groupBox_output") + self.gridLayout_2 = QtWidgets.QGridLayout(self.groupBox_output) + self.gridLayout_2.setObjectName("gridLayout_2") + self.checkBox_saveplots = QtWidgets.QCheckBox(self.groupBox_output) + self.checkBox_saveplots.setObjectName("checkBox_saveplots") + self.gridLayout_2.addWidget(self.checkBox_saveplots, 0, 0, 1, 1) + self.buttonBox_output = QtWidgets.QDialogButtonBox(self.groupBox_output) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox_output.sizePolicy().hasHeightForWidth()) + self.buttonBox_output.setSizePolicy(sizePolicy) + self.buttonBox_output.setOrientation(QtCore.Qt.Vertical) + self.buttonBox_output.setStandardButtons(QtWidgets.QDialogButtonBox.Open) + self.buttonBox_output.setObjectName("buttonBox_output") + self.gridLayout_2.addWidget(self.buttonBox_output, 2, 1, 1, 1) + self.lineEdit_output = QtWidgets.QLineEdit(self.groupBox_output) + self.lineEdit_output.setObjectName("lineEdit_output") + self.gridLayout_2.addWidget(self.lineEdit_output, 2, 0, 1, 1) + self.checkBox_savetables = QtWidgets.QCheckBox(self.groupBox_output) + self.checkBox_savetables.setObjectName("checkBox_savetables") + self.gridLayout_2.addWidget(self.checkBox_savetables, 1, 0, 1, 1) + self.gridLayout.addWidget(self.groupBox_output, 2, 0, 1, 2) self.formLayout_3.setWidget(2, QtWidgets.QFormLayout.SpanningRole, self.groupBox_processing) self.buttonBox_process = QtWidgets.QDialogButtonBox(self.groupBox_experiment) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.buttonBox_process.sizePolicy().hasHeightForWidth()) + self.buttonBox_process.setSizePolicy(sizePolicy) + self.buttonBox_process.setMinimumSize(QtCore.QSize(0, 0)) self.buttonBox_process.setStandardButtons(QtWidgets.QDialogButtonBox.NoButton) self.buttonBox_process.setObjectName("buttonBox_process") self.formLayout_3.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.buttonBox_process) @@ -220,7 +257,7 @@ class Ui_MainWindow(object): self.horizontalLayout.addWidget(self.splitter) MainWindow.setCentralWidget(self.centralWidget) self.menuBar = QtWidgets.QMenuBar(MainWindow) - self.menuBar.setGeometry(QtCore.QRect(0, 0, 1066, 28)) + self.menuBar.setGeometry(QtCore.QRect(0, 0, 4095, 28)) self.menuBar.setLocale(QtCore.QLocale(QtCore.QLocale.English, QtCore.QLocale.UnitedStates)) self.menuBar.setObjectName("menuBar") self.menuFile = QtWidgets.QMenu(self.menuBar) @@ -251,10 +288,10 @@ class Ui_MainWindow(object): self.label_tmin.setBuddy(self.doubleSpinBox_tmin) self.label_tmax.setBuddy(self.doubleSpinBox_tmax) self.label_dt.setBuddy(self.doubleSpinBox_dt) - self.label_cutoff_high.setBuddy(self.doubleSpinBox_upper) - self.label_cutoff_low.setBuddy(self.doubleSpinBox_lower) self.label_cbar_start.setBuddy(self.doubleSpinBox_cbar_start) self.label_cbar_end.setBuddy(self.doubleSpinBox_cbar_end) + self.label_cutoff_high.setBuddy(self.doubleSpinBox_upper) + self.label_cutoff_low.setBuddy(self.doubleSpinBox_lower) self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(-1) @@ -279,12 +316,6 @@ class Ui_MainWindow(object): self.doubleSpinBox_tmax.setSuffix(_translate("MainWindow", " °C")) self.label_dt.setText(_translate("MainWindow", "

ΔT

")) self.doubleSpinBox_dt.setSuffix(_translate("MainWindow", " °C")) - self.groupBox_cutoff.setToolTip(_translate("MainWindow", "

Only Tm values within this limit are considered valid.

")) - self.groupBox_cutoff.setTitle(_translate("MainWindow", "&Cutoff")) - self.label_cutoff_high.setText(_translate("MainWindow", "&Upper")) - self.doubleSpinBox_upper.setSuffix(_translate("MainWindow", " °C")) - self.label_cutoff_low.setText(_translate("MainWindow", "Lower")) - self.doubleSpinBox_lower.setSuffix(_translate("MainWindow", " °C")) self.groupBox_signal_threshold.setToolTip(_translate("MainWindow", "

If the signal exceeds this threshold, the coresponding well is assumed to be denatured.

")) self.groupBox_signal_threshold.setTitle(_translate("MainWindow", "Signal &Threshold")) self.groupBox_cbar.setToolTip(_translate("MainWindow", "

Defines the range of the colorbar used for the Tm heatmap.

")) @@ -293,6 +324,16 @@ class Ui_MainWindow(object): self.doubleSpinBox_cbar_start.setSuffix(_translate("MainWindow", " °C")) self.label_cbar_end.setText(_translate("MainWindow", "En&d")) self.doubleSpinBox_cbar_end.setSuffix(_translate("MainWindow", " °C")) + self.groupBox_cutoff.setToolTip(_translate("MainWindow", "

Only Tm values within this limit are considered valid.

")) + self.groupBox_cutoff.setTitle(_translate("MainWindow", "&Cutoff")) + self.label_cutoff_high.setText(_translate("MainWindow", "&Upper")) + self.doubleSpinBox_upper.setSuffix(_translate("MainWindow", " °C")) + self.label_cutoff_low.setText(_translate("MainWindow", "Lower")) + self.doubleSpinBox_lower.setSuffix(_translate("MainWindow", " °C")) + self.groupBox_output.setTitle(_translate("MainWindow", "Sa&ve processing results")) + self.checkBox_saveplots.setText(_translate("MainWindow", "Save plots")) + self.lineEdit_output.setToolTip(_translate("MainWindow", "Output results to this path")) + self.checkBox_savetables.setText(_translate("MainWindow", "Save tabular results")) self.groupBox_results.setTitle(_translate("MainWindow", "Plots")) self.menuFile.setTitle(_translate("MainWindow", "Fi&le")) self.menuHelp.setTitle(_translate("MainWindow", "Hel&p")) diff --git a/ui/mainwindow.py b/ui/mainwindow.py index 3c100b5..72bbbf3 100644 --- a/ui/mainwindow.py +++ b/ui/mainwindow.py @@ -5,11 +5,13 @@ Module implementing MainWindow. from PyQt5.QtCore import (pyqtSlot, QObject, pyqtSignal, QThreadPool, QRunnable, QCoreApplication) from PyQt5.QtWidgets import (QMainWindow, QProgressBar, QDialogButtonBox, - QFileDialog, QMessageBox, QApplication) + QFileDialog, QMessageBox, QApplication, + QTableWidget, QTableWidgetItem) from .Ui_mainwindow import Ui_MainWindow from .mplwidget import MplWidget from pydsf import Experiment, PlotResults +import os VERSION = "1.0" _translate = QCoreApplication.translate @@ -125,6 +127,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.tasks = Tasks() self.worker = Worker(self) + self.outputPath = None + @pyqtSlot("QAbstractButton*") def on_buttonBox_open_reset_clicked(self, button): """ @@ -142,7 +146,12 @@ class MainWindow(QMainWindow, Ui_MainWindow): elif button == self.buttonBox_open_reset.button( QDialogButtonBox.Reset): self.listWidget_data.clear() - self.remove_plate_tabs() + + @pyqtSlot("QAbstractButton*") + def on_buttonBox_output_clicked(self, button): + if button == self.buttonBox_output.button(QDialogButtonBox.Open): + path = QFileDialog.getExistingDirectory(parent=self, caption=_translate('MainWindow', 'Choose output path'), options=QFileDialog.ShowDirsOnly) + self.lineEdit_output.setText(path.strip()) @pyqtSlot("QString") def on_comboBox_instrument_currentIndexChanged(self, p0): @@ -155,7 +164,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.groupBox_temp.setEnabled(False) def generate_plot_tab(self, name): - tab = MplWidget(parent=self) + tab = MplWidget(parent=self.tabWidget) tab.setObjectName(name) return tab @@ -171,26 +180,35 @@ class MainWindow(QMainWindow, Ui_MainWindow): def generate_plate_tabs(self, plate): plotter = PlotResults() - if id != 'average': - tab = self.generate_plot_tab("tab_heatmap_{}".format(id)) + if plate.id != 'average': + tab = self.generate_plot_tab("tab_heatmap_{}".format(plate.id)) title = _translate("MainWindow", "Heatmap #") self.tabWidget.addTab(tab, title + str(plate.id)) plotter.plot_tm_heatmap_single(plate, tab) + if self.checkBox_saveplots.isChecked(): + tab.canvas.save("{}/heatmap_{}.svg".format(self.outputPath, plate.id)) - tab = self.generate_plot_tab("tab_raw_{}".format(id)) + tab = self.generate_plot_tab("tab_raw_{}".format(plate.id)) title = _translate("MainWindow", "Raw Data #") self.tabWidget.addTab(tab, title + str(plate.id)) plotter.plot_raw(plate, tab) + if self.checkBox_saveplots.isChecked(): + tab.canvas.save("{}/raw_{}.svg".format(self.outputPath, plate.id)) - tab = self.generate_plot_tab("tab_derivative_{}".format(id)) + tab = self.generate_plot_tab("tab_derivative_{}".format(plate.id)) title = _translate("MainWindow", "Derivatives #") self.tabWidget.addTab(tab, title + str(plate.id)) plotter.plot_derivative(plate, tab) + if self.checkBox_saveplots.isChecked(): + tab.canvas.save("{}/derivatives_{}.svg".format(self.outputPath, plate.id)) else: - tab = self.generate_plot_tab("tab_heatmap_{}".format(id)) + tab = self.generate_plot_tab("tab_heatmap_{}".format(plate.id)) title = _translate("MainWindow", "Heatmap ") self.tabWidget.addTab(tab, title + str(plate.id)) plotter.plot_tm_heatmap_single(plate, tab) + if self.checkBox_saveplots.isChecked(): + tab.canvas.save("{}/heatmap_{}.svg".format(self.outputPath, plate.id)) + @pyqtSlot() def on_buttonBox_process_accepted(self): @@ -204,6 +222,22 @@ class MainWindow(QMainWindow, Ui_MainWindow): _translate("MainWindow", "No data file loaded!"), QMessageBox.Close, QMessageBox.Close) return + if self.groupBox_output.isChecked() and self.lineEdit_output.text().strip() == '': + QMessageBox.critical( + self, _translate("MainWindow", "Error"), + _translate("MainWindow", "No output path set!"), + QMessageBox.Close, QMessageBox.Close) + return + elif self.groupBox_output.isChecked() and self.lineEdit_output.text().strip() != '': + path = self.lineEdit_output.text().strip() + if os.path.isdir(path): + self.outputPath = self.lineEdit_output.text().strip() + else: + QMessageBox.critical( + self, _translate("MainWindow", "Error"), + _translate("MainWindow", "Output path does not exist!"), + QMessageBox.Close, QMessageBox.Close) + if self.spinBox_signal_threshold.value( ) == 0 and self.groupBox_signal_threshold.isChecked(): QMessageBox.warning( @@ -213,6 +247,7 @@ class MainWindow(QMainWindow, Ui_MainWindow): "Signal threshold is currently set to zero."), QMessageBox.Ok, QMessageBox.Ok) + self.remove_plate_tabs() self.progressBar.setEnabled(True) self.statusBar.showMessage(_translate("MainWindow", "Processing...")) @@ -225,32 +260,6 @@ class MainWindow(QMainWindow, Ui_MainWindow): # For now, only read the first entry exp = self.tasks.data[0] - save_data = QMessageBox.question( - self, _translate("MainWindow", "Save data"), - _translate( - "MainWindow", "Calculations are finished. Save results?"), - QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) - if save_data == QMessageBox.Yes: - dialog = QFileDialog() - dialog.setFileMode(QFileDialog.Directory) - folder = dialog.getExistingDirectory( - self, _translate("MainWindow", "Choose path for results")) - for plate in exp.plates: - plate.write_tm_table( - '{}/plate_{}_04_tm.csv'.format(folder, str(plate.id))) - plate.write_derivative_table( - '{}/plate_{}_03_dI_dT.csv'.format(folder, str(plate.id))) - plate.write_filtered_table( - '{}/plate_{}_02_filtered_data.csv'.format(folder, - str(plate.id))) - plate.write_raw_table('{}/plate_{}_01_raw_data.csv'.format( - folder, str(plate.id))) - - if exp.avg_plate: - exp.avg_plate.write_avg_tm_table( - '{}/plate_{}_05_tm_avg.csv'.format( - folder, str(self.worker.exp.avg_plate.id))) - for i in range(len(self.worker.exp.plates)): plate = exp.plates[i] @@ -261,6 +270,24 @@ class MainWindow(QMainWindow, Ui_MainWindow): plate = exp.avg_plate self.generate_plate_tabs(plate) + if self.groupBox_output.isChecked(): + if self.checkBox_savetables.isChecked(): + for plate in exp.plates: + plate.write_tm_table( + '{}/plate_{}_tm.csv'.format(self.outputPath, str(plate.id))) + plate.write_data_table( + '{}/plate_{}_dI_dT.csv'.format(self.outputPath, str(plate.id)), dataType='derivative') + plate.write_data_table( + '{}/plate_{}_filtered_data.csv'.format(self.outputPath, + str(plate.id)), dataType='filtered') + plate.write_data_table('{}/plate_{}_raw_data.csv'.format( + self.outputPath, str(plate.id))) + + if exp.avg_plate: + exp.avg_plate.write_tm_table( + '{}/plate_{}_tm_avg.csv'.format( + self.outputPath, str(self.worker.exp.avg_plate.id)), avg=True) + self.progressBar.setEnabled(False) self.statusBar.showMessage(_translate("MainWindow", "Finished!")) diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index e1d92eb..c2a4596 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -6,10 +6,16 @@ 0 0 - 1066 - 795 + 4095 + 4095 + + + 0 + 0 + + PyDSF @@ -291,82 +297,6 @@ - - - - true - - - <html><head/><body><p>Only T<span style=" vertical-align:sub;">m</span> values within this limit are considered valid.</p></body></html> - - - &Cutoff - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - false - - - - QFormLayout::ExpandingFieldsGrow - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - - &Upper - - - doubleSpinBox_upper - - - - - - - - - - °C - - - 1 - - - - - - - Lower - - - doubleSpinBox_lower - - - - - - - °C - - - 1 - - - - - - @@ -459,11 +389,151 @@ + + + + true + + + <html><head/><body><p>Only T<span style=" vertical-align:sub;">m</span> values within this limit are considered valid.</p></body></html> + + + &Cutoff + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + true + + + false + + + + QFormLayout::ExpandingFieldsGrow + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + &Upper + + + doubleSpinBox_upper + + + + + + + + + + °C + + + 1 + + + + + + + Lower + + + doubleSpinBox_lower + + + + + + + °C + + + 1 + + + + + + + + + + Sa&ve processing results + + + true + + + false + + + + + + Save plots + + + + + + + + 0 + 0 + + + + Qt::Vertical + + + QDialogButtonBox::Open + + + + + + + Output results to this path + + + + + + + Save tabular results + + + + + + + + + 0 + 0 + + + + + 0 + 0 + + QDialogButtonBox::NoButton @@ -530,7 +600,7 @@ 0 0 - 1066 + 4095 28 diff --git a/ui/mplwidget.py b/ui/mplwidget.py index a4e4af1..b90694f 100644 --- a/ui/mplwidget.py +++ b/ui/mplwidget.py @@ -28,6 +28,15 @@ class MplCanvas(FigureCanvas): self.ax.clear() self.fig.clear() + def save(self, filename): + try: + self.fig.savefig(filename, dpi=300) + except IOError: + QtWidgets.QMessageBox.critical( + self, _translate("MainWindow", "Error"), + _translate("MainWindow", "Error saving figure! Please check permissions/free space of target path!"), + QtWidgets.QMessageBox.Close, QtWidgets.QMessageBox.Close) + class CustomNavigationToolbar(NavigationToolbar): toolitems = (