import pprint from itertools import cycle from numpy import array, nan, isnan from pyqtgraph import mkPen, mkBrush, LegendItem from nmreval.dsc.hodge import tau_hodge from nmreval.lib.colors import Tab10 from ..Qt import QtWidgets, QtCore from .._py.tnmh_dialog import Ui_Dialog from ..lib.pg_objects import PlotItem, RegionItem from nmreval.data import DSC, Points class TgCalculator(QtWidgets.QDialog, Ui_Dialog): newTg = QtCore.pyqtSignal(dict, list, str) def __init__(self, management, parent=None): super().__init__(parent=parent) self.setupUi(self) self._management = management self._colors = cycle(Tab10) self._dsc = {} self._plots = {} self._tg_value = {} self._fit = {} self._lines = {} self._hodge = { 'onset': (PlotItem(x=[], y=[], pen=None, symbol='o', symbolBrush=Tab10.TabBlue.rgb(), name='Onset'), None), 'midpoint': (PlotItem(x=[], y=[], pen=None, symbol='s', symbolBrush=Tab10.TabOrange.rgb(), name='Midpoint'), None), 'end': (PlotItem(x=[], y=[], pen=None, symbol='t', symbolBrush=Tab10.TabGreen.rgb(), name='End'), None), 'inflection': (PlotItem(x=[], y=[], pen=None, symbol='d', symbolBrush=Tab10.TabRed.rgb(), name='Inflection'), None), # 'fictive': PlotItem(x=[], y=[], pen=None, symbol='t1', symbolBrush=Tab10.TabPurple.rgb(), name='Fictive'), # 'TNMH': PlotItem(x=[], y=[], pen=None, symbol='star', symbolBrush=Tab10.TabPurple.rgb(), name='TNMH'), } self.tau_plot.getPlotItem().addLegend() for plt, _ in self._hodge.values(): self.tau_plot.addItem(plt) self.tau_plot.setLogMode(y=True) self.pushButton_2.hide() self.label_4.hide() self.label_5.hide() self.limits = RegionItem(), RegionItem() for lim in self.limits: self.dsc_plot.addItem(lim) self._limitless = True self.add_sets() self.listWidget.itemClicked.connect(self.show_tg_values) self.new_graph_tau_combo.setEnabled(False) self.new_graph_tau_check.stateChanged.connect(lambda state: self.new_graph_tau_combo.setEnabled(not bool(state))) def __call__(self): self.clear() self._colors = cycle(Tab10) self.add_sets() return self def clear(self): self.listWidget.clear() for plots in self._plots.values(): for val in plots: self.dsc_plot.removeItem(val) self.graphicsView_2.removeItem(val) for key, plt in self._hodge.items(): plt[0].setData(x=[], y=[]) self._hodge[key] = (plt[0], None) self._dsc = {} self._plots = {} self._tg_value = {} self._lines = {} self._fit = {} def add_sets(self): self.new_graph_tau_combo.clear() for graphs in self._management.graphs.list(): self.new_graph_tau_combo.addItem(graphs[1], userData=graphs[0]) min_x = 10_000_000 max_x = -10_000_000 for (key, name), c in zip(self._management.active_sets, self._colors): data = self._management[key].data if not isinstance(data, DSC): continue min_x = min(min_x, data.x.min()) max_x = max(max_x, data.x.max()) item = QtWidgets.QListWidgetItem(name) item.setCheckState(QtCore.Qt.Checked) item.setData(QtCore.Qt.UserRole, key) item.setForeground(mkBrush(c.rgb())) self.listWidget.addItem(item) self._dsc[key] = (data, None) data_plot = PlotItem(x=data.x, y=data.y, pen=mkPen(c.rgb())) self.dsc_plot.addItem(data_plot) glass = PlotItem() glass.set_line(style=2, color=c) self.dsc_plot.addItem(glass) liquid = PlotItem() liquid.set_line(style=2, color=c) self.dsc_plot.addItem(liquid) tangent = PlotItem() tangent.set_line(style=2, color=c) self.dsc_plot.addItem(tangent) tg_plot = PlotItem(pen=None, symbolBrush=c.rgb(), symbol='o') self.dsc_plot.addItem(tg_plot) fictive_cp = PlotItem(pen=mkPen(c.rgb())) self.graphicsView_2.addItem(fictive_cp) tnmh_fit = PlotItem() tnmh_fit.set_line(style=2, color=c) self.graphicsView_2.addItem(tnmh_fit) self._plots[key] = (data_plot, tg_plot, glass, liquid, tangent, fictive_cp, tnmh_fit) self._tg_value[key] = {'onset': (nan, nan), 'mid': (nan, nan), 'end': (nan, nan), 'inflection': (nan, nan)} # , 'fictive': (nan, nan)} if self._limitless: dist = max_x - min_x self.limits[0].setRegion((min_x, min_x+min(0.1*dist, 5))) self.limits[1].setRegion((max_x-min(5, 0.1*dist), max_x)) self._limitless = False @QtCore.pyqtSlot(name='on_calctg_button_clicked') def calc_tg(self): baselines = tuple(lim.getRegion() for lim in self.limits) if baselines[0][0] > baselines[1][0]: baselines = baselines[1], baselines[0] for idx in range(self.listWidget.count()): item = self.listWidget.item(idx) if item.checkState() == QtCore.Qt.Unchecked: continue key = item.data(QtCore.Qt.UserRole) plot = self._plots[key] data, _ = self._dsc[key] tg_results, glass, liquid, tangent = data.glass_transition(*baselines) self._lines[key] = (glass, liquid, tangent) for i, line in enumerate((glass, liquid, tangent)): plot[i+2].setData(x=line.x, y=line.y) self._tg_value[key].update(tg_results) self._update_tg_plots() def show_tg_values(self, item): values = self._tg_value.get(item.data(QtCore.Qt.UserRole)) if values is not None: label = '\n'.join((f'{name.capitalize()}: {pos[0]:.2f} K' for name, pos in values.items())) self.tg_value_label.setText(label) fit = self._fit.get(item.data(QtCore.Qt.UserRole)) if fit is not None: self.label_5.setText(fit._parameter_string()) def _update_tg_plots(self): for idx in range(self.listWidget.count()): item = self.listWidget.item(idx) key = item.data(QtCore.Qt.UserRole) plot = self._plots[key] data, _ = self._dsc[key] plot[1].setData(array(list(self._tg_value[key].values()))) self.hodge() @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name='on_listWidget_itemChanged') def change_visibility(self, item: QtWidgets.QListWidgetItem): is_checked = bool(item.checkState()) plot = self._plots[item.data(QtCore.Qt.UserRole)] for val in plot: val.setVisible(is_checked) @QtCore.pyqtSlot(name='on_pushButton_2_clicked') def get_fictive(self): baselines = tuple(lim.getRegion() for lim in self.limits) if baselines[0][0] > baselines[1][0]: baselines = baselines[1], baselines[0] for idx in range(self.listWidget.count()): item = self.listWidget.item(idx) if item.checkState() == QtCore.Qt.Unchecked: continue key = item.data(QtCore.Qt.UserRole) plot = self._plots[key] data, _ = self._dsc[key] cp, tg = data.get_fictive_cp(*baselines) plot[5].setData(cp.x, cp.y) self._dsc[key] = (data, cp) self._tg_value[key]['fictive'] = (tg, 0) self._update_tg_plots() @QtCore.pyqtSlot(name='on_pushButton_3_clicked') def make_tnmh(self): baselines = tuple(lim.getRegion() for lim in self.limits) if baselines[0][0] > baselines[1][0]: baselines = baselines[1], baselines[0] for idx in range(self.listWidget.count()): item = self.listWidget.item(idx) if item.checkState() == QtCore.Qt.Unchecked: continue key = item.data(QtCore.Qt.UserRole) plot = self._plots[key] _, data = self._dsc[key] if data is None: continue res = data.calculate_tnmh([60, 0.5, 1, 2e5], *baselines, return_fictive=False) self._fit[key] = res plot[-1].setData(res.x, res.y) def hodge(self): for tg_type, (plot, data) in self._hodge.items(): m = [] for idx in range(self.listWidget.count()): item = self.listWidget.item(idx) key = item.data(QtCore.Qt.UserRole) data, _ = self._dsc[key] tg_value = self._tg_value[key][tg_type][0] if isnan(tg_value): continue m.append([tg_value, data.value]) if len(m) > 1: data = tau_hodge(*array(m).T) data.name = f'{data.name} ({tg_type.capitalize()})' plot.setData(data.x, data.y) self._hodge[tg_type] = (plot, data) def close(self) -> bool: self.clear() return super().close() def accept(self) -> None: if self.new_graph_tau_check.isChecked(): graph_id = '' else: graph_id = self.new_graph_tau_combo.currentData() ret_dic = {} for key, tg in self._tg_value.items(): tgx = [x for x, y in tg.values()] tgy = [y for x, y in tg.values()] if self.tg_export_check.isChecked(): tg_pts = Points(x=tgx, y=tgy, name=self._management[key].name + ' (Tg)', value=self._management[key].value) else: tg_pts = None if self.tglines_export_check.isChecked(): line = self._lines[key] else: line = [] ret_dic[key] = (tg_pts, line) ret_dic2 = [] for i in range(self.hodge_selection.count()): if self.hodge_selection.isChecked(i): item = self.hodge_selection.itemText(i).lower() v = self._hodge.get(item) ret_dic2.append(v[1]) self.newTg.emit(ret_dic, ret_dic2, graph_id) self.close()