def fig_press(self, event): """ 点击图像交互 :param event: :return: """ print('you pressed', event.button, event.xdata, event.ydata) if self.line_valve: self.line_valve.remove() if self.v_line: self.v_line.remove() # 添加线 self.v_line = self.ax.axvline(event.xdata, color='lime', ls='--') # 注解 for i in range(len(self.ar_data_show_x)): if event.xdata < self.ar_data_show_x[i]: break self.line_valve = self.ax.annotate( str(self.ar_data_show[i]) + 'mA', (event.xdata, max(self.ar_data_show)), xycoords='data', xytext=(20, 0), textcoords='offset points', fontsize=16, color='lime', arrowprops=dict(arrowstyle='-|>', connectionstyle="arc3,rad=.2", color='lime')) FigureCanvas.draw_idle(self)
class DistDialog(QtWidgets.QDialog): ''' Dialog for editing distribution parameters ''' def __init__(self, name, dist, parent=None): super().__init__(parent=parent) self.name = name self.dist = dist args = self.dist.get_config() args.update({'median': self.dist.median()}) self.table = gui_widgets.DistributionEditTable(args) self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.btnBox = QtWidgets.QDialogButtonBox( QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel) self.setWindowTitle('Configure Probability Distribution') self.setMaximumSize(600, 600) layout = QtWidgets.QVBoxLayout() layout.addWidget(self.table, stretch=10) layout.addWidget(self.canvas, stretch=10) layout.addWidget(self.btnBox) self.setLayout(layout) self.btnBox.accepted.connect(self.accept) self.btnBox.rejected.connect(self.reject) self.table.changed.connect(self.replot) self.replot() def get_dist(self): ''' Get the distribution distributions.Distribution object ''' return self.dist def replot(self): ''' Update the distribution and replot ''' self.dist = self.table.statsdist median = self.dist.median() std = self.dist.std() if not np.isfinite( std): # Some distributions (e.g. alpha) have infinite stdev std = self.dist.kwds.get('scale', 1) xx = np.linspace(median - 4 * std, median + 4 * std, num=200) try: yy = self.dist.pdf(xx) except (TypeError, ValueError): yy = np.full(len(xx), np.nan) self.fig.clf() ax = self.fig.add_subplot(1, 1, 1) ax.plot(xx, yy) ax.set_xlabel(report.Math(self.name).latex()) self.fig.tight_layout() self.canvas.draw_idle()
def setup_figure(parent, layout): figure = Figure() figure.set_facecolor(color='#FcF9F6') canvas = FigureCanvas(figure) figure.ax = figure.add_subplot(111) toolbar = NavigationToolbar(canvas, parent, coordinates=True) layout.addWidget(toolbar) layout.addWidget(canvas) canvas.draw_idle() cursor = Cursor(figure.ax, useblit=True, color='green', linewidth=0.75) figure.ax.grid(alpha=0.4) #figure.tight_layout() return figure, canvas, toolbar
def onclick(self, event): if not (event.inaxes == self.ax or event.inaxes == self.popax): return if event.xdata is None or self.wh is None: return hw = self.projection.shape x, y = (int(event.xdata), int(event.ydata)) if not (0 <= x < hw[1] and 0 <= y < hw[0]): return if (x, y) in self.selected: self.removePoint((x, y)) elif not self.addPoint((x, y)): return FigureCanvas.draw_idle(self) self.changedSelected.emit(len(self.selected))
def onclick(self, event): if event.inaxes != self.ax: return if event.xdata is None or self.pixelxy is None: return changed = False for p in range(len(self.rects)): if self.rects[p].contains(event)[0]: changed = True if p in self.selected: self.deselectPoint(p) else: self.selectPoint(p) if changed: FigureCanvas.draw_idle(self) self.changedSelected.emit(len(self.selected))
class Plot(QWidget): def __init__(self): super().__init__() self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setParent(self) self.toolbar = NavigationToolbar(self.canvas, self) def plot(self, name): self.figure.clf() ax = self.figure.add_subplot(111) ax.plot(name, 'o') ax.set_title('Oryginal dataset') ax.grid(True) self.canvas.draw_idle() print('Plotted')
class MatplotlibFigure(QWidget): # constructor def __init__(self, parent=None): super().__init__() self.figure = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.figure) self.canvas.setParent(self) self.setMinimumHeight(300) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) self.setSizePolicy(sizePolicy) self.setAutoFillBackground(True) p = self.palette() #p.setColor(self.backgroundRole(), QtGui.QColor('lightgreen')) self.setPalette(p) def setLables(self, xlable, ylable): self.xLable = xlable self.yLable = ylable def setTitle(self, title): self.title = title def plot(self, xValues, yValues): self.figure.clf() self.figure.subplots_adjust(top=0.8) ax = self.figure.add_subplot(111) ax.set_ylabel(self.yLable) ax.set_xlabel(self.xLable) ax.set_title(self.title) #ax.plot(xValues, yValues, color='blue', lw=3) ax.scatter(xValues, yValues) self.canvas.draw_idle() print('PLOTTED')
class MatplotlibWidget(QtWidgets.QWidget): timelen = 900 def __init__(self, parent=None): super().__init__(parent) self.figure = Figure() self.canvas = FigureCanvasQTAgg(self.figure) # self.canvas.setMinimumSize(QtCore.QSize(1500, 0)) self.axis = self.figure.add_subplot(111) self.update(0) #self.spos = Slider(self.axis, 'Время', 0, 150) #self.spos.on_changed(self.update) self.sld = QtWidgets.QSlider(QtCore.Qt.Horizontal, self) self.sld.setFocusPolicy(QtCore.Qt.NoFocus) self.sld.valueChanged[int].connect(self.update) self.sld.valueChanged.connect(self.redraw) self.layoutVertical = QtWidgets.QVBoxLayout(self) self.layoutVertical.addWidget(self.canvas) self.layoutVertical.addWidget(self.sld) def clear(self): self.axis.clear() self.sld.setValue(0) def redraw(self): self.canvas.draw_idle() def update(self, val): a, b = val * (self.timelen // 100), (val + 1) * (self.timelen // 100) #self.axis.set_xticklabels(self.ticks[a:b]) self.axis.set_xlim(a, b)
class Dendrogram(QWidget): def __init__(self): super().__init__() self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.setParent(self) self.toolbar = NavigationToolbar(self.canvas, self) def plot_kmean(self, X, k): self.figure.clf() ax = self.figure.add_subplot(111) # sch.dendrogram(sch.linkage(X, method='ward'), leaf_rotation=0, leaf_font_size=10) scv.kmeans2(X, k=k, iter=10, thresh=1e-05, minit='random', missing='warn', check_finite=True) print('Kmeans plotting...') ax.set_title('Cluster analysis with k-means method') ax.grid(True) self.canvas.draw_idle() print('Plotted!') def plot_agnes(self, X): self.figure.clf() ax = self.figure.add_subplot(111) sch.dendrogram(sch.linkage(X, method='ward'), leaf_rotation=0, leaf_font_size=10) print('Agnes plotting...') ax.set_title('Cluster analysis with agglomerative clustering method') ax.grid(True) self.canvas.draw_idle() print('Plotted!') def plot_slink(self, X): self.figure.clf() ax = self.figure.add_subplot(111) sch.dendrogram(sch.linkage(X, method='single'), leaf_rotation=0, leaf_font_size=10) print('Slink plotting...') ax.set_title('Cluster analysis with single linkage method') ax.grid(True) self.canvas.draw_idle() print('Plotted!')
class PrettyWidget(QWidget): NumButtons = ['plot1', 'plot2', 'plot3'] def __init__(self): super(PrettyWidget, self).__init__() font = QFont() font.setPointSize(16) self.initUI() def initUI(self): self.setGeometry(100, 100, 800, 600) self.center() self.setWindowTitle('S Plot') grid = QGridLayout() self.setLayout(grid) self.createVerticalGroupBox() buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.verticalGroupBox) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) grid.addWidget(self.canvas, 0, 1, 9, 9) grid.addLayout(buttonLayout, 0, 0) self.show() def createVerticalGroupBox(self): self.verticalGroupBox = QGroupBox() layout = QVBoxLayout() for i in self.NumButtons: button = QPushButton(i) button.setObjectName(i) layout.addWidget(button) layout.setSpacing(10) self.verticalGroupBox.setLayout(layout) button.clicked.connect(self.submitCommand) def submitCommand(self): eval('self.' + str(self.sender().objectName()) + '()') def plot1(self): self.figure.clf() ax1 = self.figure.add_subplot(211) x1 = [i for i in range(100)] y1 = [i**0.5 for i in x1] ax1.plot(x1, y1, 'b.-') ax2 = self.figure.add_subplot(212) x2 = [i for i in range(100)] y2 = [i for i in x2] ax2.plot(x2, y2, 'b.-') self.canvas.draw_idle() def plot2(self): self.figure.clf() ax3 = self.figure.add_subplot(111) x = [i for i in range(100)] y = [i**0.5 for i in x] ax3.plot(x, y, 'r.-') ax3.set_title('Square Root Plot') self.canvas.draw_idle() def plot3(self): self.figure.clf() B = nx.Graph() B.add_nodes_from([1, 2, 3, 4], bipartite=0) B.add_nodes_from(['a', 'b', 'c', 'd', 'e'], bipartite=1) B.add_edges_from([(1, 'a'), (2, 'c'), (3, 'd'), (3, 'e'), (4, 'e'), (4, 'd')]) X = set(n for n, d in B.nodes(data=True) if d['bipartite'] == 0) Y = set(B) - X X = sorted(X, reverse=True) Y = sorted(Y, reverse=True) pos = dict() pos.update( (n, (1, i)) for i, n in enumerate(X)) # put nodes from X at x=1 pos.update( (n, (2, i)) for i, n in enumerate(Y)) # put nodes from Y at x=2 nx.draw(B, pos=pos, with_labels=True) self.canvas.draw_idle() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
class XviewGui(*uic.loadUiType(ui_path)): #class GUI(QtWidgets.QMainWindow, gui_form): def __init__(self, hhm_pulses_per_deg, processing_sender=None, db=None, db_analysis=None, *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) self.hhm_pulses_per_deg = hhm_pulses_per_deg self.sender = processing_sender self.db = db self.db_analysis = db_analysis self.gen_parser = xasdata.XASdataGeneric(hhm_pulses_per_deg, db=db) self.xasproject = xasproject.XASProject() self.xasproject.datasets_changed.connect(self.update_xas_project_list) # pushbuttons self.pushbuttonSelectFolder.clicked.connect(self.select_working_folder) self.pushbuttonRefreshFolder.clicked.connect(self.getFileList) self.pushbutton_plot_bin.clicked.connect(self.plotBinnedData) self.comboBox_sort_files_by.addItems(['Time','Name']) self.comboBox_sort_files_by.currentIndexChanged.connect((self.getFileList)) # file lists self.listFiles_bin.itemSelectionChanged.connect(self.selectBinnedDataFilesToPlot) self.listFiles_bin.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.addCanvas() self.keys = [] self.last_keys = [] self.current_plot_in = '' self.binned_data = [] self.gen = xasdata.XASdataGeneric(self.hhm_pulses_per_deg, db=None) self.last_num = '' self.last_den = '' # Persistent settings self.settings = QSettings('ISS Beamline', 'Xview') self.working_folder = self.settings.value('WorkingFolder', defaultValue='/GPFS/xf08id/User Data', type=str) if self.working_folder != '/GPFS/xf08id/User Data': self.label_working_folder.setText(self.working_folder) self.label_working_folder.setToolTip(self.working_folder) self.getFileList() self.label_E0.setText("E<sub>0</sub>") # Setting up Preprocess tab: self.pushbutton_add_to_xasproject.clicked.connect(self.add_files_to_xas_project) self.listView_xasproject.itemSelectionChanged.connect(self.show_ds_params) self.listView_xasproject.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.pushbutton_plotE_xasproject.clicked.connect(self.plot_xas_project_in_E) self.pushbutton_plotK_xasproject.clicked.connect(self.plot_xas_project_in_K) self.pushbutton_plotR_xasproject.clicked.connect(self.plot_xas_project_in_R) self.lineEdit_e0.textEdited.connect(self.update_ds_params) self.lineEdit_preedge_lo.textEdited.connect(self.update_ds_params) self.lineEdit_preedge_hi.textEdited.connect(self.update_ds_params) self.lineEdit_postedge_lo.textEdited.connect(self.update_ds_params) self.lineEdit_postedge_hi.textEdited.connect(self.update_ds_params) self.lineEdit_spline_lo.textEdited.connect(self.update_ds_params) self.lineEdit_spline_hi.textEdited.connect(self.update_ds_params) self.lineEdit_clamp_lo.textEdited.connect(self.update_ds_params) self.lineEdit_clamp_hi.textEdited.connect(self.update_ds_params) self.lineEdit_k_ft_lo.textEdited.connect(self.update_ds_params) self.lineEdit_k_ft_hi.textEdited.connect(self.update_ds_params) self.pushButton_e0_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_preedge_lo_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_preedge_hi_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_postedge_lo_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_postedge_hi_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_spline_lo_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_spline_hi_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_k_ft_lo_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_k_ft_hi_set.clicked.connect(self.set_ds_params_from_plot) self.pushButton_truncate_at_set.clicked.connect(self.set_ds_params_from_plot) # Push to selected/all buttons defs self.pushButton_push_norm_param_to_selected.clicked.connect(self.push_param) self.pushButton_push_norm_param_to_all.clicked.connect(self.push_param) self.pushButton_push_bkg_param_to_selected.clicked.connect(self.push_param) self.pushButton_push_bkg_param_to_all.clicked.connect(self.push_param) self.pushButton_truncate_below.clicked.connect(self.truncate) self.pushButton_truncate_above.clicked.connect(self.truncate) #Menu defs self.action_exit.triggered.connect(self.close_app) self.action_save_project.triggered.connect(self.save_xas_project) self.action_open_project.triggered.connect(self.open_xas_project) self.action_save_datasets_as_text.triggered.connect(self.save_xas_datasets_as_text) self.action_combine_and_save_as_text.triggered.connect(self.combine_and_save_xas_datasets_as_text) self.action_merge.triggered.connect(self.merge_datasets) self.action_rename.triggered.connect(self.rename_dataset) self.action_remove.triggered.connect(self.remove_from_xas_project) self.lineEdit_to_ds_parameter_dict = { 'lineEdit_preedge_lo': 'pre1', 'lineEdit_preedge_hi': 'pre2', 'lineEdit_postedge_lo': 'norm1', 'lineEdit_postedge_hi': 'norm2', 'lineEdit_e0': 'e0', 'lineEdit_spline_lo': 'kmin', 'lineEdit_spline_hi': 'kmax', 'lineEdit_clamp_lo': 'clamp_lo', 'lineEdit_clamp_hi': 'clamp_hi', 'lineEdit_truncate_at': 'truncate', 'lineEdit_k_ft_lo': 'kmin_ft', 'lineEdit_k_ft_hi': 'kmax_ft' } self.pushButton_set_to_lineEdit_dict = { 'pushButton_e0_set': 'lineEdit_e0', 'pushButton_preedge_lo_set': 'lineEdit_preedge_lo', 'pushButton_preedge_hi_set': 'lineEdit_preedge_hi', 'pushButton_postedge_lo_set': 'lineEdit_postedge_lo', 'pushButton_postedge_hi_set': 'lineEdit_postedge_hi', 'pushButton_spline_lo_set': 'lineEdit_spline_lo', 'pushButton_spline_hi_set': 'lineEdit_spline_hi', 'pushButton_k_ft_lo_set': 'lineEdit_k_ft_lo', 'pushButton_k_ft_hi_set': 'lineEdit_k_ft_hi', 'pushButton_truncate_at_set': 'lineEdit_truncate_at' } self.windows_list = [ 'hanning', 'kaiser', 'gaussian', 'sine' ] def close_app(self): self.close() def addCanvas(self): self.figureBinned = Figure() self.figureBinned.set_facecolor(color='#FcF9F6') self.figureBinned.ax = self.figureBinned.add_subplot(111) self.canvas = FigureCanvas(self.figureBinned) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.setMaximumHeight(25) self.layout_plot_bin.addWidget(self.toolbar) self.layout_plot_bin.addWidget(self.canvas) self.canvas.draw() # XASProject Plot: self.figureXASProject = Figure() self.figureXASProject.set_facecolor(color='#FcF9F6') self.figureXASProject.ax = self.figureXASProject.add_subplot(111) self.figureXASProject.ax.grid(alpha = 0.4) self.canvasXASProject = FigureCanvas(self.figureXASProject) self.toolbar_XASProject = NavigationToolbar(self.canvasXASProject, self) self.layout_plot_xasproject.addWidget(self.canvasXASProject) self.layout_plot_xasproject.addWidget(self.toolbar_XASProject) self.canvasXASProject.draw() #layout_plot_xasproject def select_working_folder(self): self.working_folder = QtWidgets.QFileDialog.getExistingDirectory(self, "Select a folder", self.working_folder, QtWidgets.QFileDialog.ShowDirsOnly) if self.working_folder: self.settings.setValue('WorkingFolder', self.working_folder) if len(self.working_folder) > 50: self.label_working_folder.setText(self.working_folder[1:20] + '...' + self.working_folder[-30:]) else: self.label_working_folder.setText(self.working_folder) self.getFileList() def getFileList(self): if self.working_folder: self.listFiles_bin.clear() files_bin = [f for f in os.listdir(self.working_folder) if f.endswith('.dat')] if self.comboBox_sort_files_by.currentText() == 'Name': files_bin.sort() elif self.comboBox_sort_files_by.currentText() == 'Time': files_bin.sort(key=lambda x: os.path.getmtime('{}/{}'.format(self.working_folder, x))) files_bin.reverse() self.listFiles_bin.addItems(files_bin) def selectBinnedDataFilesToPlot(self): header = xasdata.XASdataGeneric.read_header(None, '{}/{}'.format(self.working_folder, self.listFiles_bin.currentItem().text())) self.keys = header[header.rfind('#'):][1:-1].split() self.keys.insert(0, '1') if 'timestamp' in self.keys: del self.keys[self.keys.index('timestamp')] if self.keys != self.last_keys: self.listBinnedDataNumerator.clear() self.listBinnedDataDenominator.clear() self.listBinnedDataNumerator.insertItems(0, self.keys) self.listBinnedDataDenominator.insertItems(0, self.keys) if self.last_num != '' and self.last_num <= len(self.keys) - 1: self.listBinnedDataNumerator.setCurrentRow(self.last_num) if self.last_den != '' and self.last_den <= len(self.keys) - 1: self.listBinnedDataDenominator.setCurrentRow(self.last_den) def plotBinnedData(self): selected_items = (self.listFiles_bin.selectedItems()) self.figureBinned.ax.clear() self.toolbar._views.clear() self.toolbar._positions.clear() ßself.toolbar._update_view() self.canvas.draw_idle() if self.listBinnedDataNumerator.currentRow() == -1 or self.listBinnedDataDenominator.currentRow() == -1: self.statusBar().showMessage('Please select numerator and denominator') return self.last_num = self.listBinnedDataNumerator.currentRow() self.last_den = self.listBinnedDataDenominator.currentRow() if 'En. (eV)' in self.keys: energy_key = 'En. (eV)' elif 'energy' in self.keys: energy_key = 'energy' handles = [] for i in selected_items: self.gen.loadInterpFile('{}/{}'.format(self.working_folder, i.text())) df = pd.DataFrame({k: v[:, 1] for k, v in self.gen.interp_arrays.items()}).sort_values(energy_key) spectrum = df[self.listBinnedDataNumerator.currentItem().text()] \ / df[self.listBinnedDataDenominator.currentItem().text()] if self.checkBox_log_bin.checkState(): spectrum = np.log(spectrum) if self.checkBox_inv_bin.checkState(): spectrum = -spectrum self.figureBinned.ax.plot(df[energy_key], spectrum) self.figureBinned.ax.set_xlabel('Energy (eV)') self.figureBinned.ax.set_ylabel('{} / {}'.format(self.listBinnedDataNumerator.currentItem().text(), self.listBinnedDataDenominator.currentItem().text())) last_trace = self.figureBinned.ax.get_lines()[len(self.figureBinned.ax.get_lines()) - 1] patch = mpatches.Patch(color=last_trace.get_color(), label=i.text()) handles.append(patch) self.figureBinned.ax.legend(handles=handles) self.figureBinned.tight_layout() self.canvas.draw_idle() def push_param(self): self.norm_param_list = [ 'e0', 'pre1', 'pre2', 'norm1', 'norm2', ] self.bkg_param_list = [ 'kmin', 'kmax', 'clamp_lo', 'clamp_hi' ] self.ft_param_list =[ ] selection = self.listView_xasproject.selectedIndexes() if selection != []: sender = QObject() sender_object = sender.sender().objectName() index = selection[0].row() ds_master = self.xasproject[index] if sender_object == 'pushButton_push_norm_param_to_selected': for indx, obj in enumerate(selection): ds = self.xasproject[selection[indx].row()] for param in self.norm_param_list: setattr(ds, param, getattr(ds_master, param)) if sender_object == 'pushButton_push_norm_param_to_all': for indx, obj in enumerate(self.xasproject): for param in self.norm_param_list: setattr(self.xasproject[indx], param, getattr(ds_master, param)) if sender_object == 'pushButton_push_bkg_param_to_selected': for indx, obj in enumerate(selection): ds = self.xasproject[selection[indx].row()] for param in self.bkg_param_list: setattr(ds, param, getattr(ds_master, param)) if sender_object == 'pushButton_push_bkg_param_to_all': for indx, obj in enumerate(self.xasproject): for param in self.bkg_param_list: setattr(self.xasproject[indx], param, getattr(ds_master, param)) # here we begin to work on the second pre-processing tab def update_ds_params(self): sender = QObject() sender_object = sender.sender().objectName() print(sender_object) selection = self.listView_xasproject.selectedIndexes() if selection != []: index=selection[0].row() ds = self.xasproject[index] try: self.statusBar().showMessage(sender_object) print(getattr(self, sender_object).text()) setattr(ds, self.lineEdit_to_ds_parameter_dict[sender_object], float(getattr(self, sender_object).text())) except: self.statusBar().showMessage('Use numbers only') def set_ds_params_from_plot(self): sender = QObject() self.sender_object = sender.sender().objectName() self.statusBar().showMessage('Click on graph or press Esc') self.cid = self.canvasXASProject.mpl_connect('button_press_event', self.mouse_press_event) def _disconnect_cid(self): if hasattr(self, 'cid'): self.canvasXASProject.mpl_disconnect(self.cid) delattr(self, 'cid') def keyPressEvent(self, event): if event.key() == QtCore.Qt.Key_Escape: self._disconnect_cid() def mouse_press_event(self, event): e_vs_k_discriminate_list = ['pushButton_spline_lo_set', 'pushButton_spline_hi_set', 'pushButton_k_ft_lo_set', 'pushButton_k_ft_hi_set' ] lineEdit=getattr(self, self.pushButton_set_to_lineEdit_dict[self.sender_object]) e0=float(self.lineEdit_e0.text()) if self.sender_object == 'pushButton_e0_set': new_value = event.xdata elif self.sender_object == 'pushButton_truncate_at_set': if self.current_plot_in == 'e': new_value = event.xdata elif self.current_plot_in == 'k': new_value = k2e(event.xdata, e0) elif self.sender_object in e_vs_k_discriminate_list: if self.current_plot_in == 'k': new_value = event.xdata elif self.current_plot_in == 'e': new_value = e2k(event.xdata, e0) else: new_value = event.xdata-e0 lineEdit.setText('{:.1f}'.format(new_value)) sender_object = lineEdit print (sender_object) selection = self.listView_xasproject.selectedIndexes() if selection != []: index=selection[0].row() ds = self.xasproject[index] try: float(sender_object.text()) setattr(ds, self.lineEdit_to_ds_parameter_dict[sender_object.objectName()], float(sender_object.text())) except: print('what''s going wrong') self._disconnect_cid() def show_ds_params(self): if self.listView_xasproject.selectedIndexes(): index=self.listView_xasproject.selectedIndexes()[0] ds = self.xasproject[index.row()] self.lineEdit_e0.setText('{:.1f}'.format(ds.e0)) self.lineEdit_preedge_lo.setText('{:.1f}'.format(ds.pre1)) self.lineEdit_preedge_hi.setText('{:.1f}'.format(ds.pre2)) self.lineEdit_postedge_lo.setText('{:.1f}'.format(ds.norm1)) self.lineEdit_postedge_hi.setText('{:.1f}'.format(ds.norm2)) self.lineEdit_spline_lo.setText('{:.1f}'.format(ds.kmin)) self.lineEdit_spline_hi.setText('{:.1f}'.format(ds.kmax)) self.lineEdit_clamp_lo.setText('{:.1f}'.format(ds.clamp_lo)) self.lineEdit_clamp_hi.setText('{:.1f}'.format(ds.clamp_hi)) self.lineEdit_k_ft_lo.setText('{:.1f}'.format(ds.kmin_ft)) self.lineEdit_k_ft_hi.setText('{:.1f}'.format(ds.kmax_ft)) # Make the first selected line bold, and reset bold font for other selections font = QtGui.QFont() font.setBold(False) for i in range(self.listView_xasproject.count()): self.listView_xasproject.item(i).setFont(font) font.setBold(True) self.listView_xasproject.item(index.row()).setFont(font) def add_files_to_xas_project(self): if self.listBinnedDataNumerator.currentRow() != -1 and self.listBinnedDataDenominator.currentRow() != -1: for item in self.listFiles_bin.selectedItems(): filepath = str(Path(self.working_folder) / Path(item.text())) name = Path(filepath).resolve().stem header = self.gen_parser.read_header(filepath) uid = header[header.find('UID:')+5:header.find('\n', header.find('UID:'))] #FIXME different UID syntax in two files from manual binning and 0mq processing try: md = self.db[uid]['start'] except: print('Metadata not found') md={} self.gen_parser.data_manager.loadBinFile(filepath) df = self.gen_parser.data_manager.binned_df df = df.sort_values('energy') num_key = self.listBinnedDataNumerator.currentItem().text() den_key = self.listBinnedDataDenominator.currentItem().text() mu = df[num_key] / df[den_key] if self.checkBox_log_bin.checkState(): mu = np.log(mu) if self.checkBox_inv_bin.checkState(): mu = -mu mu=np.array(mu) print(type(mu)) ds = xasproject.XASDataSet(name=name,md=md,energy=df['energy'],mu=mu, filename=filepath,datatype='experiment') ds.header = header self.xasproject.append(ds) self.statusBar().showMessage('Scans added to the project successfully') else: self.statusBar().showMessage('Select numerator and denominator columns') def update_xas_project_list(self, datasets): self.listView_xasproject.clear() for ds in datasets: self.listView_xasproject.addItem(ds.name) def remove_from_xas_project(self): for index in self.listView_xasproject.selectedIndexes()[::-1]: #[::-1] to remove using indexes from last to first self.xasproject.removeDatasetIndex(index.row()) self.statusBar().showMessage('Datasets deleted') def plot_xas_project_in_E(self): if self.listView_xasproject.selectedIndexes(): self.reset_figure(self.figureXASProject.ax, self.toolbar_XASProject, self.canvasXASProject) for index in self.listView_xasproject.selectedIndexes(): ds = self.xasproject[index.row()] ds.normalize_force() ds.extract_chi_force() ds.extract_ft() energy = ds.energy if self.radioButton_mu_xasproject.isChecked(): data = ds.mu elif self.radioButton_norm_xasproject.isChecked(): if self.checkBox_norm_flat_xasproject.checkState(): data = ds.flat else: data = ds.norm if self.checkBox_deriv.isChecked(): data = ds.mu_deriv energy = ds.energy_deriv self.figureXASProject.ax.plot(energy, data, label = ds.name) if self.radioButton_mu_xasproject.isChecked() and not self.checkBox_deriv.isChecked(): if self.checkBox_preedge_show.checkState(): self.figureXASProject.ax.plot(ds.energy, ds.pre_edge,label='Preedge', linewidth=0.75) if self.checkBox_postedge_show.checkState(): self.figureXASProject.ax.plot(ds.energy, ds.post_edge, label='Postedge', linewidth=0.75) if self.checkBox_background_show.checkState(): self.figureXASProject.ax.plot(ds.energy, ds.bkg, label='Background', linewidth=0.75) self.set_figure(self.figureXASProject.ax, self.canvasXASProject,label_x ='Energy /eV', label_y =r'$\chi \mu$' + '(E)'), if self.checkBox_force_range_E.checkState(): self.figureXASProject.ax.set_xlim((float(self.lineEdit_e0.text())+float(self.lineEdit_range_E_lo.text())), (float(self.lineEdit_e0.text()) + float(self.lineEdit_range_E_hi.text()))) self.current_plot_in = 'e' def plot_xas_project_in_K(self): if self.listView_xasproject.selectedIndexes(): self.reset_figure(self.figureXASProject.ax, self.toolbar_XASProject, self.canvasXASProject) window=self.set_ft_window() for index in self.listView_xasproject.selectedIndexes(): ds = self.xasproject[index.row()] ds.extract_chi_force() ds.extract_ft_force(window = window) data = ds.chi * np.power(ds.k,self.spinBox_k_weight.value()) self.figureXASProject.ax.plot(ds.k, data, label = ds.name) data_max = data.max() if self.checkBox_show_window.isChecked(): self.figureXASProject.ax.plot(ds.k, ds.kwin*data_max/2, label='Windows') self.set_figure(self.figureXASProject.ax, self.canvasXASProject,label_x ='k (' + r'$\AA$' + '$^1$' +')', label_y =r'$\chi \mu$' + '(k)') if self.checkBox_force_range_k.checkState(): self.figureXASProject.ax.set_xlim(float(self.lineEdit_range_k_lo.text()), float(self.lineEdit_range_k_hi.text())) self.current_plot_in = 'k' def plot_xas_project_in_R(self): if self.listView_xasproject.selectedIndexes(): self.reset_figure(self.figureXASProject.ax,self.toolbar_XASProject, self.canvasXASProject) window = self.set_ft_window() for index in self.listView_xasproject.selectedIndexes(): ds = self.xasproject[index.row()] ds.extract_ft_force(window=window) if self.checkBox_show_chir_mag.checkState(): self.figureXASProject.ax.plot(ds.r, ds.chir_mag, label = ds.name) if self.checkBox_show_chir_im.checkState(): self.figureXASProject.ax.plot(ds.r, ds.chir_im, label=(ds.name + ' Im')) if self.checkBox_show_chir_re.checkState(): self.figureXASProject.ax.plot(ds.r, ds.chir_re, label=(ds.name + ' Re')) #if self.checkBox_show_chir_pha.checked: # self.figureXASProject.ax.plot(ds.r, ds.chir_pha, label=(ds.name + ' Ph')) self.set_figure(self.figureXASProject.ax,self.canvasXASProject, label_y=r'$\chi \mu$' + '(k)', label_x='R (' + r'$\AA$' +')') if self.checkBox_force_range_R.checkState(): self.figureXASProject.ax.set_xlim(float(self.lineEdit_range_R_lo.text()), float(self.lineEdit_range_R_hi.text())) self.current_plot_in = 'R' def save_xas_project(self): options = QtWidgets.QFileDialog.DontUseNativeDialog filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save XAS project as', self.working_folder, 'XAS project files (*.xas)', options=options) if filename: if Path(filename).suffix != '.xas': filename = filename + '.xas' print(filename) self.xasproject.save(filename=filename) def open_xas_project(self): options = QtWidgets.QFileDialog.DontUseNativeDialog filename, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Load XAS project', self.working_folder, 'XAS project files (*.xas)', options=options) if filename: self.xasproject_loaded_from_file = xasproject.XASProject() self.xasproject_loaded_from_file.load(filename = filename) if ret == 0: self.xasproject = self.xasproject_loaded_from_file self.update_xas_project_list(self.xasproject._datasets) if ret == 1: for i in self.xasproject_loaded_from_file._datasets: self.xasproject.append(i) def save_xas_datasets_as_text(self): #options = QtWidgets.QFileDialog.DontUseNativeDialog #filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save XAS project as', self.working_folder, # 'XAS project files (*.xas)', options=options) selection = self.listView_xasproject.selectedIndexes() if selection != []: ret = self.message_box_save_datasets_as() options = QtWidgets.QFileDialog.DontUseNativeDialog pathname = QtWidgets.QFileDialog.getExistingDirectory(self, 'Choose folder...', self.working_folder, options=options) separator = '#______________________________________________________\n' if pathname is not '': for indx, obj in enumerate(selection): ds = self.xasproject._datasets[selection[indx].row()] filename = str(Path(ds.filename).stem) if ret == 0: xx = ds.energy yy = np.array(ds.mu.mu) keys = '# energy(eV), mu(E)\n' elif ret == 1: xx = ds.energy yy = ds.norm keys = '# energy(eV), normalized mu(E)\n' elif ret == 2: xx = ds.energy yy = ds.flat keys = '# energy(eV), flattened normalized mu(E)\n' table = np.stack((xx, yy)).T filename_new = '{}/{}.{}'.format(pathname,filename,'mu') fid = open(filename_new, 'w') header_wo_cols_names = ds.header[0:ds.header.rfind('#')] fid.write(header_wo_cols_names) fid.write(separator) fid.write(keys) fid.close() fid = open(filename_new, 'a') np.savetxt(fid,table) fid.close() def merge_datasets(self): selection = self.listView_xasproject.selectedIndexes() if selection != []: mu = self.xasproject._datasets[selection[0].row()].mu energy_master=self.xasproject._datasets[selection[0].row()].energy mu_array=np.zeros([len(selection),len(mu)]) energy = self.xasproject._datasets[selection[0].row()].energy md=['merged'] for indx, obj in enumerate(selection): energy = self.xasproject._datasets[selection[indx].row()].energy mu = self.xasproject._datasets[selection[indx].row()].mu.mu mu = np.interp(energy_master, energy, mu) mu_array[indx, :]=mu md.append(self.xasproject._datasets[selection[indx].row()].filename) mu_merged = np.average(mu_array, axis=0) merged = xasproject.XASDataSet(name='merge', md=md, energy=energy, mu=mu_merged, filename='', datatype='processed') self.xasproject.append(merged) self.xasproject.project_changed() def combine_and_save_xas_datasets_as_text(self): selection = self.listView_xasproject.selectedIndexes() if selection != []: ds_list = [] md = [] for indx, obj in enumerate(selection): ds_list.append(self.xasproject._datasets[selection[indx].row()]) ds_list.sort(key=lambda x: x.name) mu = ds_list[0].mu mu_array = np.zeros([len(selection)+1, len(mu)]) energy_master = ds_list[0].energy mu_array[0, :]=energy_master ret = self.message_box_save_datasets_as() for indx, obj in enumerate(selection): ds = ds_list[indx] energy=ds.energy if ret == 0: yy = np.array(ds.mu.mu) keys = '# energy(eV), mu(E)\n' elif ret == 1: yy = ds.norm keys = '# energy(eV), normalized mu(E)\n' elif ret == 2: yy = ds.flat keys = '# energy(eV), flattened normalized mu(E)\n' yy=np.interp(energy_master,energy,yy) mu_array[indx+1, :] = yy md.append(ds.name) self.mu_array = mu_array options = QtWidgets.QFileDialog.DontUseNativeDialog filename, _ = QtWidgets.QFileDialog.getSaveFileName(self, 'Save XAS project', self.working_folder, 'XAS dataset (*.dat)', options=options) if filename: if Path(filename).suffix != '.xas': filename = filename + '.xas' print(filename) filelist = "{}".format("\n".join(md[0:])) separator = '\n #______________________________________________________\n' header = '{} {} {}'.format(filelist,separator,keys) fid = open(filename, 'w') np.savetxt(fid, np.transpose(mu_array), header = header) fid.close() def rename_dataset(self): selection = self.listView_xasproject.selectedIndexes() if selection != []: name = self.xasproject._datasets[selection[0].row()].name new_name, ok = QtWidgets.QInputDialog.getText(self, 'Rename dataset', 'Enter new name:',QtWidgets.QLineEdit.Normal, name) if ok: self.xasproject._datasets[selection[0].row()].name=new_name self.xasproject.project_changed() def truncate(self): sender = QObject() sender_object = sender.sender().objectName() print(sender_object) selection = self.listView_xasproject.selectedIndexes() if selection != []: for indx, obj in enumerate(selection): print(indx) ds = self.xasproject._datasets[selection[indx].row()] print(ds.name) energy=ds.energy mu = ds.mu indx_energy_to_truncate_at = (np.abs(energy - float(self.lineEdit_truncate_at.text()))).argmin() if sender_object == 'pushButton_truncate_below': ds.energy = energy[indx_energy_to_truncate_at:] ds.mu = mu[indx_energy_to_truncate_at:] elif sender_object == 'pushButton_truncate_above': ds.energy = energy[0:indx_energy_to_truncate_at] ds.mu = mu[0:indx_energy_to_truncate_at:] ds.update_larch() self.xasproject._datasets[selection[indx].row()]=ds ''' Service routines ''' def set_figure(self,axis,canvas, label_x='', label_y=''): axis.legend(fontsize='small') axis.grid(alpha=0.4) axis.set_ylabel(label_y, size='13') axis.set_xlabel(label_x, size='13') canvas.draw_idle() def reset_figure(self,axis,toolbar,canvas): axis.clear() toolbar._views.clear() toolbar._positions.clear() toolbar._update_view() canvas.draw_idle() def message_box_save_datasets_as(self): messageBox = QtWidgets.QMessageBox() messageBox.setText('Save datasets as..') messageBox.addButton(QtWidgets.QPushButton('mu(E)'), QtWidgets.QMessageBox.YesRole) messageBox.addButton(QtWidgets.QPushButton('normalized mu(E)'), QtWidgets.QMessageBox.NoRole) messageBox.addButton(QtWidgets.QPushButton('flattened mu(E)'), QtWidgets.QMessageBox.NoRole) ret = messageBox.exec_() return ret def message_box_warning(self,line1='Warning', line2=''): messageBox = QtWidgets.QMessageBox() messageBox.setText(line1) if line2: messageBox.setInformativeText(line2) messageBox.setWindowTitle("Warning") messageBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel) messageBox.exec_() def set_ft_window(self): window = dict() window['window_type'] = self.windows_list[self.comboBox_window.currentIndex()] window['r_weight'] = self.spinBox_r_weight.value() try: window['tapering'] = float(self.lineEdit_window_tapering.text()) except: window['tapering'] = 1 return window
class MplWidget(QtWidgets.QWidget): def __init__(self, parent=None): QtWidgets.QWidget.__init__(self, parent) self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus) self.canvas.setFocus() self.canvas.setParent(self) self.canvas.mpl_connect('scroll_event', self.onWheel) self.canvas.mpl_connect('button_press_event', self.start_pan) self.canvas.mpl_connect('button_release_event', self.pan) self.canvas.mpl_connect('motion_notify_event', self.pan_motion) self.axes = self.fig.add_subplot(111) self.fig.tight_layout() self.dragx = None self.dragy = None # self.mpl_toolbar = NavigationToolbar(self.canvas, self) vbox = QtWidgets.QVBoxLayout() vbox.addWidget(self.canvas) # vbox.addWidget(self.mpl_toolbar) self.setLayout(vbox) def start_pan(self, event): if event.button == 3: self.dragx, self.dragy = event.xdata, event.ydata def do_pan(self, xdata, ydata): diffx, diffy = self.dragx - xdata, self.dragy - ydata x1, x2 = self.axes.get_xlim() y1, y2 = self.axes.get_ylim() self.axes.set_xlim(x1 + diffx, x2 + diffx) self.axes.set_ylim(y1 + diffy, y2 + diffy) self.canvas.draw_idle() def stop_pan(self): self.dragx, self.dragy = None, None def pan(self, event): if event.button == 3: if event.inaxes is not None and \ self.dragx is not None and self.dragy is not None and \ event.xdata is not None and event.ydata is not None: self.do_pan(event.xdata, event.ydata) self.stop_pan() def pan_motion(self, event): if event.inaxes is not None and \ self.dragx is not None and self.dragy is not None and \ event.xdata is not None and event.ydata is not None: self.do_pan(event.xdata, event.ydata) def _rescale(self, lo, hi, step, pt=None, bal=None, scale='linear'): """ Rescale (lo,hi) by step, returning the new (lo,hi) The scaling is centered on pt, with positive values of step driving lo/hi away from pt and negative values pulling them in. If bal is given instead of point, it is already in [0,1] coordinates. This is a helper function for step-based zooming. """ # Convert values into the correct scale for a linear transformation # TODO: use proper scale transformers if scale == 'log': lo, hi = math.log10(lo), math.log10(hi) if pt is not None: pt = math.log10(pt) # Compute delta from axis range * %, or 1-% if percent is negative if step > 0: delta = float(hi - lo) * step / 100 else: delta = float(hi - lo) * step / (100 - step) # Add scale factor proportionally to the lo and hi values, preserving the # point under the mouse if bal is None: bal = float(pt - lo) / (hi - lo) lo -= bal * delta hi += (1 - bal) * delta # Convert transformed values back to the original scale if scale == 'log': lo, hi = math.pow(10., lo), math.pow(10., hi) return (lo, hi) def onWheel(self, event): """ Process mouse wheel as zoom events """ ax = event.inaxes # Older versions of matplotlib do not have event.step defined try: step = 20.0 * event.step except: if event.button == 'up': step = 20 else: step = -20 # If in plot, use the xdata, ydata as the center point # If not in plot, check if we are in a plot axis if ax == None: # Event not on plot: check if it happened in an axis xdata, ydata = None, None x, y = event.x, event.y axes = event.canvas.figure.get_axes() for ax in axes: inx, _ = ax.xaxis.contains(event) if inx: xdata, _ = ax.transData.inverted().transform_point((x, y)) break iny, _ = ax.yaxis.contains(event) if iny: _, ydata = ax.transData.inverted().transform_point((x, y)) break else: ax = None else: xdata, ydata = event.xdata, event.ydata # Axis scrolling requires remapping the axis limits if xdata is not None: lo, hi = ax.get_xlim() lo, hi = self._rescale(lo, hi, step, pt=xdata, scale=ax.get_xscale()) ax.set_xlim((lo, hi)) if ydata is not None: lo, hi = ax.get_ylim() lo, hi = self._rescale(lo, hi, step, pt=ydata, scale=ax.get_yscale()) ax.set_ylim((lo, hi)) if xdata is not None or ydata is not None: event.canvas.draw_idle()
class UISDDManager(*uic.loadUiType(ui_path)): def __init__(self, xia_list=[], *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) self.addCanvas() self.xia_list = xia_list self.xia_parser = xiaparser self.xia_graphs_names = [] self.xia_graphs_labels = [] self.xia_handles = [] self.xia = self.xia_list[0] self.xia_channels = [ int(mca.split('mca')[1]) for mca in set(self.xia.read_attrs) & set(self.xia.component_names) ] self.xia_tog_channels = [] self.xia.mca_max_energy.subscribe(self.update_xia_params) self.xia.real_time.subscribe(self.update_xia_params) self.xia.real_time_rb.subscribe(self.update_xia_params) self.edit_xia_acq_time.returnPressed.connect( self.update_xia_acqtime_pv) self.edit_xia_energy_range.returnPressed.connect( self.update_xia_energyrange_pv) self.push_gain_matching.clicked.connect(self.run_gain_matching) self.push_run_xia_measurement.clicked.connect(self.update_xia_rois) self.push_run_xia_measurement.clicked.connect(self.start_xia_spectra) if self.xia.connected: max_en = self.xia.mca_max_energy.value energies = np.linspace(0, max_en, 2048) self.roi_colors = [] for mult in range(4): self.roi_colors.append((.4 + (.2 * mult), 0, 0)) self.roi_colors.append((0, .4 + (.2 * mult), 0)) self.roi_colors.append((0, 0, .4 + (.2 * mult))) for roi in range(12): low = getattr(self.xia, "mca1.roi{}".format(roi)).low.value high = getattr(self.xia, "mca1.roi{}".format(roi)).high.value if low > 0: getattr(self, 'edit_roi_from_{}'.format(roi)).setText( '{:.0f}'.format( np.floor(energies[getattr( self.xia, "mca1.roi{}".format(roi)).low.value] * 1000))) else: getattr(self, 'edit_roi_from_{}'.format(roi)).setText( '{:.0f}'.format(low)) if high > 0: getattr(self, 'edit_roi_to_{}'.format(roi)).setText( '{:.0f}'.format( np.floor(energies[getattr( self.xia, "mca1.roi{}".format(roi)).high.value] * 1000))) else: getattr(self, 'edit_roi_to_{}'.format(roi)).setText( '{:.0f}'.format(high)) label = getattr(self.xia, "mca1.roi{}".format(roi)).label.value getattr(self, 'edit_roi_name_{}'.format(roi)).setText(label) getattr(self, 'edit_roi_from_{}'.format(roi)).returnPressed.connect( self.update_xia_rois) getattr(self, 'edit_roi_to_{}'.format(roi)).returnPressed.connect( self.update_xia_rois) getattr(self, 'edit_roi_name_{}'.format(roi)).returnPressed.connect( self.update_xia_rois) for channel in self.xia_channels: getattr(self, "checkBox_gm_ch{}".format(channel)).setEnabled(True) getattr(self.xia, "mca{}".format(channel)).array.subscribe( self.update_xia_graph) getattr(self, "checkBox_gm_ch{}".format(channel)).toggled.connect( self.toggle_xia_checkbox) self.push_checkall_xia.clicked.connect(self.toggle_xia_all) if hasattr(self.xia, 'input_trigger'): if self.xia.input_trigger is not None: self.xia.input_trigger.unit_sel.put(1) # ms, not us def addCanvas(self): self.figure_gain_matching = Figure() self.figure_gain_matching.set_facecolor(color='#FcF9F6') self.canvas_gain_matching = FigureCanvas(self.figure_gain_matching) self.figure_gain_matching.ax = self.figure_gain_matching.add_subplot( 111) self.toolbar_gain_matching = NavigationToolbar( self.canvas_gain_matching, self, coordinates=True) self.plot_gain_matching.addWidget(self.toolbar_gain_matching) self.plot_gain_matching.addWidget(self.canvas_gain_matching) self.canvas_gain_matching.draw_idle() self.figure_xia_all_graphs = Figure() self.figure_xia_all_graphs.set_facecolor(color='#FcF9F6') self.canvas_xia_all_graphs = FigureCanvas(self.figure_xia_all_graphs) self.figure_xia_all_graphs.ax = self.figure_xia_all_graphs.add_subplot( 111) self.toolbar_xia_all_graphs = NavigationToolbar( self.canvas_xia_all_graphs, self, coordinates=True) self.plot_xia_all_graphs.addWidget(self.toolbar_xia_all_graphs) self.plot_xia_all_graphs.addWidget(self.canvas_xia_all_graphs) self.canvas_xia_all_graphs.draw_idle() self.cursor_xia_all_graphs = Cursor(self.figure_xia_all_graphs.ax, useblit=True, color='green', linewidth=0.75) self.figure_xia_all_graphs.ax.clear() def toggle_xia_checkbox(self, value): if value: self.xia_tog_channels.append(self.sender().text()) elif self.sender().text() in self.xia_tog_channels: self.xia_tog_channels.remove(self.sender().text()) self.erase_xia_graph() for chan in self.xia_tog_channels: self.update_xia_graph(getattr(self.xia, 'mca{}.array.value'.format(chan)), obj=getattr(self.xia, 'mca{}.array'.format(chan))) def toggle_xia_all(self): if len(self.xia_tog_channels) != len(self.xia.read_attrs): for index, mca in enumerate(self.xia.read_attrs): if getattr(self, 'checkBox_gm_ch{}'.format(index + 1)).isEnabled(): getattr(self, 'checkBox_gm_ch{}'.format(index + 1)).setChecked(True) else: for index, mca in enumerate(self.xia.read_attrs): if getattr(self, 'checkBox_gm_ch{}'.format(index + 1)).isEnabled(): getattr(self, 'checkBox_gm_ch{}'.format(index + 1)).setChecked(False) def update_xia_params(self, value, **kwargs): if kwargs['obj'].name == 'xia1_real_time': self.edit_xia_acq_time.setText('{:.2f}'.format(round(value, 2))) elif kwargs['obj'].name == 'xia1_real_time_rb': self.label_acq_time_rbv.setText('{:.2f}'.format(round(value, 2))) elif kwargs['obj'].name == 'xia1_mca_max_energy': self.edit_xia_energy_range.setText('{:.0f}'.format(value * 1000)) def erase_xia_graph(self): self.figure_xia_all_graphs.ax.clear() for roi in range(12): if hasattr(self.figure_xia_all_graphs.ax, 'roi{}l'.format(roi)): exec('del self.figure_xia_all_graphs.ax.roi{}l,\ self.figure_xia_all_graphs.ax.roi{}h'.format(roi, roi)) self.figure_xia_all_graphs.ax.clear() self.toolbar_xia_all_graphs.update() self.xia_graphs_names.clear() self.xia_graphs_labels.clear() self.xia_handles.clear() self.canvas_xia_all_graphs.draw_idle() def start_xia_spectra(self): if self.xia.collect_mode.value != 0: self.xia.collect_mode.put(0) ttime.sleep(2) self.xia.erase_start.put(1) def update_xia_rois(self): energies = np.linspace(0, float(self.edit_xia_energy_range.text()) / 1000, 2048) for roi in range(12): if float(getattr( self, 'edit_roi_from_{}'.format(roi)).text()) < 0 or float( getattr(self, 'edit_roi_to_{}'.format(roi)).text()) < 0: exec('start{} = -1'.format(roi)) exec('end{} = -1'.format(roi)) else: indexes_array = np.where( (energies >= float( getattr(self, 'edit_roi_from_{}'.format(roi)).text()) / 1000) & (energies <= float( getattr(self, 'edit_roi_to_{}'.format(roi)).text()) / 1000) == True)[0] if len(indexes_array): exec('start{} = indexes_array.min()'.format(roi)) exec('end{} = indexes_array.max()'.format(roi)) else: exec('start{} = -1'.format(roi)) exec('end{} = -1'.format(roi)) exec( 'roi{}x = [float(self.edit_roi_from_{}.text()), float(self.edit_roi_to_{}.text())]' .format(roi, roi, roi)) exec('label{} = self.edit_roi_name_{}.text()'.format(roi, roi)) for channel in self.xia_channels: for roi in range(12): getattr(self.xia, "mca{}.roi{}".format(channel, roi)).low.put( eval('start{}'.format(roi))) getattr(self.xia, "mca{}.roi{}".format(channel, roi)).high.put( eval('end{}'.format(roi))) getattr(self.xia, "mca{}.roi{}".format(channel, roi)).label.put( eval('label{}'.format(roi))) for roi in range(12): if not hasattr(self.figure_xia_all_graphs.ax, 'roi{}l'.format(roi)): exec( 'self.figure_xia_all_graphs.ax.roi{}l = self.figure_xia_all_graphs.ax.axvline(x=roi{}x[0], color=self.roi_colors[roi])' .format(roi, roi)) exec( 'self.figure_xia_all_graphs.ax.roi{}h = self.figure_xia_all_graphs.ax.axvline(x=roi{}x[1], color=self.roi_colors[roi])' .format(roi, roi)) else: exec( 'self.figure_xia_all_graphs.ax.roi{}l.set_xdata([roi{}x[0], roi{}x[0]])' .format(roi, roi, roi)) exec( 'self.figure_xia_all_graphs.ax.roi{}h.set_xdata([roi{}x[1], roi{}x[1]])' .format(roi, roi, roi)) self.figure_xia_all_graphs.ax.grid(True) self.canvas_xia_all_graphs.draw_idle() def update_xia_acqtime_pv(self): self.xia.real_time.put(float(self.edit_xia_acq_time.text())) def update_xia_energyrange_pv(self): self.xia.mca_max_energy.put( float(self.edit_xia_energy_range.text()) / 1000) def update_xia_graph(self, value, **kwargs): curr_name = kwargs['obj'].name curr_index = -1 if len(self.figure_xia_all_graphs.ax.lines): if float(self.edit_xia_energy_range.text( )) != self.figure_xia_all_graphs.ax.lines[0].get_xdata()[-1]: self.figure_xia_all_graphs.ax.clear() for roi in range(12): if hasattr(self.figure_xia_all_graphs.ax, 'roi{}l'.format(roi)): exec('del self.figure_xia_all_graphs.ax.roi{}l,\ self.figure_xia_all_graphs.ax.roi{}h'.format( roi, roi)) update_figure([self.figure_xia_all_graphs.ax], self.toolbar_xia_all_graphs, self.canvas_xia_all_graphs) self.xia_graphs_names.clear() self.xia_graphs_labels.clear() self.canvas_xia_all_graphs.draw_idle() if curr_name in self.xia_graphs_names: for index, name in enumerate(self.xia_graphs_names): if curr_name == name: curr_index = index line = self.figure_xia_all_graphs.ax.lines[curr_index] line.set_ydata(value) break else: ch_number = curr_name.split('_')[1].split('mca')[1] if ch_number in self.xia_tog_channels: self.xia_graphs_names.append(curr_name) label = 'Chan {}'.format(ch_number) self.xia_graphs_labels.append(label) handles, = self.figure_xia_all_graphs.ax.plot(np.linspace( 0, float(self.edit_xia_energy_range.text()), 2048), value, label=label) self.xia_handles.append(handles) self.figure_xia_all_graphs.ax.legend(self.xia_handles, self.xia_graphs_labels) if len(self.figure_xia_all_graphs.ax.lines) == len( self.xia_tog_channels) != 0: for roi in range(12): exec( 'roi{}x = [float(self.edit_roi_from_{}.text()), float(self.edit_roi_to_{}.text())]' .format(roi, roi, roi)) for roi in range(12): if not hasattr(self.figure_xia_all_graphs.ax, 'roi{}l'.format(roi)): exec( 'self.figure_xia_all_graphs.ax.roi{}l = self.figure_xia_all_graphs.ax.axvline(x=roi{}x[0], color=self.roi_colors[roi])' .format(roi, roi)) exec( 'self.figure_xia_all_graphs.ax.roi{}h = self.figure_xia_all_graphs.ax.axvline(x=roi{}x[1], color=self.roi_colors[roi])' .format(roi, roi)) self.figure_xia_all_graphs.ax.grid(True) self.figure_xia_all_graphs.ax.relim() self.figure_xia_all_graphs.ax.autoscale(True, True, True) y_interval = self.figure_xia_all_graphs.ax.get_yaxis( ).get_data_interval() ''' if len(y_interval): if y_interval[0] != 0 or y_interval[1] != 0: self.figure_xia_all_graphs.ax.set_ylim([y_interval[0] - (y_interval[1] - y_interval[0]) * 0.05, y_interval[1] + (y_interval[1] - y_interval[0]) * 0.05]) ''' self.canvas_xia_all_graphs.draw_idle() def run_gain_matching(self): ax = self.figure_gain_matching.add_subplot(111) gain_adjust = [0.001] * len( self.xia_channels) # , 0.001, 0.001, 0.001] diff = [0] * len(self.xia_channels) # , 0, 0, 0] diff_old = [0] * len(self.xia_channels) # , 0, 0, 0] # Run number of iterations defined in the text edit edit_gain_matching_iterations: for i in range(int(self.edit_gain_matching_iterations.text())): self.xia.collect_mode.put('MCA spectra') ttime.sleep(0.25) self.xia.mode.put('Real time') ttime.sleep(0.25) self.xia.real_time.put('1') self.xia.capt_start_stop.put(1) ttime.sleep(0.05) self.xia.erase_start.put(1) ttime.sleep(2) ax.clear() self.toolbar_gain_matching.update() # For each channel: for chann in self.xia_channels: # If checkbox of current channel is checked: if getattr(self, "checkBox_gm_ch{}".format(chann)).checkState() > 0: # Get current channel pre-amp gain: curr_ch_gain = getattr(self.xia, "pre_amp_gain{}".format(chann)) coeff = self.xia_parser.gain_matching( self.xia, self.edit_center_gain_matching.text(), self.edit_range_gain_matching.text(), chann, ax) # coeff[0] = Intensity # coeff[1] = Fitted mean # coeff[2] = Sigma diff[chann - 1] = float( self.edit_gain_matching_target.text()) - float( coeff[1] * 1000) if i != 0: sign = (diff[chann - 1] * diff_old[chann - 1]) / math.fabs( diff[chann - 1] * diff_old[chann - 1]) if int(sign) == -1: gain_adjust[chann - 1] /= 2 print('Chan ' + str(chann) + ': ' + str(diff[chann - 1]) + '\n') # Update current channel pre-amp gain: curr_ch_gain.put(curr_ch_gain.value - diff[chann - 1] * gain_adjust[chann - 1]) diff_old[chann - 1] = diff[chann - 1] self.canvas_gain_matching.draw_idle()
class UIXviewData(*uic.loadUiType(ui_path)): def __init__(self, db=None, parent=None, *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) self.db = db self.parent = parent self.push_select_folder.clicked.connect(self.select_working_folder) self.push_refresh_folder.clicked.connect(self.get_file_list) self.push_plot_data.clicked.connect(self.plot_xas_data) self.comboBox_sort_files_by.addItems(['Time','Name']) self.comboBox_sort_files_by.currentIndexChanged.connect((self.get_file_list)) self.comboBox_data_numerator.currentIndexChanged.connect(self.update_current_numerator) self.comboBox_data_denominator.currentIndexChanged.connect(self.update_current_denominator) self.list_data.itemSelectionChanged.connect(self.select_files_to_plot) self.push_add_to_project.clicked.connect(self.add_data_to_project) self.list_data.setContextMenuPolicy(Qt.CustomContextMenu) self.list_data.customContextMenuRequested.connect(self.xas_data_context_menu) self.list_data.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) self.addCanvas() self.keys = [] self.last_keys = [] self.current_plot_in = '' self.binned_data = [] self.last_numerator= '' self.last_denominator = '' # Persistent settings self.settings = QSettings('ISS Beamline', 'Xview') self.working_folder = self.settings.value('working_folder', defaultValue='/GPFS/xf08id/User Data', type=str) if self.working_folder != '/GPFS/xf08id/User Data': self.label_working_folder.setText(self.working_folder) self.label_working_folder.setToolTip(self.working_folder) self.get_file_list() def xas_data_context_menu(self,QPos): menu = QMenu() plot_action = menu.addAction("&Plot") add_to_project_action = menu.addAction("&Add to project") parentPosition = self.list_data.mapToGlobal(QtCore.QPoint(0, 0)) menu.move(parentPosition+QPos) action = menu.exec_() if action == plot_action: self.plot_xas_data() elif action == add_to_project_action: self.add_data_to_project() def addCanvas(self): self.figure_data = Figure() #self.figure_data.set_facecolor(color='#E2E2E2') self.figure_data.ax = self.figure_data.add_subplot(111) self.canvas = FigureCanvas(self.figure_data) self.toolbar = NavigationToolbar(self.canvas, self) self.toolbar.resize(1, 10) self.layout_plot_data.addWidget(self.toolbar) self.layout_plot_data.addWidget(self.canvas) self.figure_data.tight_layout() self.canvas.draw() def select_working_folder(self): self.working_folder = QtWidgets.QFileDialog.getExistingDirectory(self, "Select a folder", self.working_folder, QtWidgets.QFileDialog.ShowDirsOnly) if self.working_folder: self.set_working_folder() def set_working_folder(self): self.settings.setValue('working_folder', self.working_folder) if len(self.working_folder) > 50: self.label_working_folder.setText(self.working_folder[1:20] + '...' + self.working_folder[-30:]) else: self.label_working_folder.setText(self.working_folder) self.get_file_list() def get_file_list(self): if self.working_folder: self.list_data.clear() self.file_list = [f for f in os.listdir(self.working_folder) if f.endswith('.dat')] if self.comboBox_sort_files_by.currentText() == 'Name': self.file_list.sort() elif self.comboBox_sort_files_by.currentText() == 'Time': self.file_list.sort(key=lambda x: os.path.getmtime('{}/{}'.format(self.working_folder, x))) self.file_list.reverse() self.list_data.addItems(self.file_list) def select_files_to_plot(self): df, header = load_binned_df_from_file(f'{self.working_folder}/{self.list_data.currentItem().text()}') keys = df.keys() refined_keys = [] for key in keys: if not (('timestamp' in key) or ('energy' in key)): refined_keys.append(key) self.keys = refined_keys if self.keys != self.last_keys: self.last_keys = self.keys self.comboBox_data_numerator.clear() self.comboBox_data_denominator.clear() self.comboBox_data_numerator.insertItems(0, self.keys) self.comboBox_data_denominator.insertItems(0, self.keys) if self.last_numerator!= '' and self.last_numerator in self.keys: indx = self.comboBox_data_numerator.findText(self.last_numerator) self.comboBox_data_numerator.setCurrentIndex(indx) if self.last_denominator!= '' and self.last_denominator in self.keys: indx = self.comboBox_data_denominator.findText(self.last_denominator) self.comboBox_data_denominator.setCurrentIndex(indx) def update_current_numerator(self): self.last_numerator= self.comboBox_data_numerator.currentText() # print(f'Chanhin last num to {self.last_numerator}') def update_current_denominator(self): self.last_denominator= self.comboBox_data_denominator.currentText() # print(f'I am there {self.last_denominator}') def plot_xas_data(self): selected_items = (self.list_data.selectedItems()) update_figure([self.figure_data.ax], self.toolbar, self.canvas) if self.comboBox_data_numerator.currentText() == -1 or self.comboBox_data_denominator.currentText() == -1: message_box('Warning','Please select numerator and denominator') return self.last_numerator = self.comboBox_data_numerator.currentText() self.last_denominator = self.comboBox_data_denominator.currentText() energy_key = 'energy' handles = [] for i in selected_items: path = f'{self.working_folder}/{i.text()}' print(path) df, header = load_binned_df_from_file(path) numer = np.array(df[self.comboBox_data_numerator.currentText()]) denom = np.array(df[self.comboBox_data_denominator.currentText()]) if self.checkBox_ratio.checkState(): y_label = (f'{self.comboBox_data_numerator.currentText()} / ' f'{self.comboBox_data_denominator.currentText()}') spectrum = numer/denom else: y_label = (f'{self.comboBox_data_numerator.currentText()}') spectrum = numer if self.checkBox_log_bin.checkState(): spectrum = np.log(spectrum) y_label = f'ln ({y_label})' if self.checkBox_inv_bin.checkState(): spectrum = -spectrum y_label = f'- {y_label}' self.figure_data.ax.plot(df[energy_key], spectrum) self.parent.set_figure(self.figure_data.ax,self.canvas,label_x='Energy (eV)', label_y=y_label) self.figure_data.ax.set_xlabel('Energy (eV)') self.figure_data.ax.set_ylabel(y_label) last_trace = self.figure_data.ax.get_lines()[len(self.figure_data.ax.get_lines()) - 1] patch = mpatches.Patch(color=last_trace.get_color(), label=i.text()) handles.append(patch) self.figure_data.ax.legend(handles=handles) self.figure_data.tight_layout() self.canvas.draw_idle() # def merge_xas_data(self): # selected_items = (self.list_data.selectedItems()) # energy_key = 'energy' # i0_key, it_key, ir_key, if_key = 'i0', 'it', 'ir', 'iff' # # # # mus_array = [] # for i, item in enumerate(selected_items): # # path = f'{self.working_folder}/{item.text()}' # print('merging', path) # df, header = load_binned_df_from_file(path) # if i == 0: # enregy_master = df[energy_key] # mus_array_all = def add_data_to_project(self): if self.comboBox_data_numerator.currentText() != -1 and self.comboBox_data_denominator.currentText() != -1: for item in self.list_data.selectedItems(): filepath = str(Path(self.working_folder) / Path(item.text())) name = Path(filepath).resolve().stem df, header = load_binned_df_from_file(filepath) uid = header[header.find('UID:')+5:header.find('\n', header.find('UID:'))] try: md = self.db[uid]['start'] except: print('Metadata not found') md={} df = df.sort_values('energy') num_key = self.comboBox_data_numerator.currentText() den_key = self.comboBox_data_denominator.currentText() mu = df[num_key] / df[den_key] if self.checkBox_log_bin.checkState(): mu = np.log(mu) if self.checkBox_inv_bin.checkState(): mu = -mu mu=np.array(mu) ds = XASDataSet(name=name,md=md,energy=df['energy'],mu=mu, filename=filepath,datatype='experiment') ds.header = header self.parent.project.append(ds) self.parent.statusBar().showMessage('Scans added to the project successfully') else: message_box('Error', 'Select numerator and denominator columns') def set_selection(self, name): index = 0 names = [] for index in range(self.list_data.count()): names.append(self.list_data.item(index).text().split('.')[0]) try: index = names.index(name) print(index) except: print('not found') if index: self.list_data.setCurrentRow(index)
class bExportWidget(QtWidgets.QWidget): """ Open a window and display the raw Vm of a bAnalysis abf file """ myCloseSignal = QtCore.Signal(object) def __init__( self, sweepX, sweepY, xyUnits=('', ''), path='', darkTheme=False, xMin=None, xMax=None, xMargin=2, type='vm', # (vm, dvdt, meanclip) parent=None): """ """ super(bExportWidget, self).__init__(parent) self._inCallback = False self.shortcut = QtWidgets.QShortcut(QtGui.QKeySequence("Ctrl+w"), self) self.shortcut.activated.connect(self.myCloseAction) self.setFont( QtGui.QFont("Helvetica", 11, QtGui.QFont.Normal, italic=False)) self.myType = type # use this to size defaults for scale bar self.myParent = parent self.mySweepX = sweepX self.mySweepY = sweepY self.mySweepX_Downsample = self.mySweepX self.mySweepY_Downsample = self.mySweepY #okGo = self.setFile(file) self.path = path self.xyUnits = xyUnits self.darkTheme = darkTheme if self.darkTheme: plt.style.use('dark_background') else: plt.rcParams.update(plt.rcParamsDefault) self.scaleBarDict = {} self.scaleBarDict['hLength'] = 5 self.scaleBarDict['vLength'] = 20 self.scaleBarDict['lineWidth'] = 5 if self.darkTheme: self.scaleBarDict['color'] = 'w' else: self.scaleBarDict['color'] = 'k' if self.myType == 'vm': self.scaleBarDict['hLength'] = 1 # second self.scaleBarDict['vLength'] = 20 # mv elif self.myType == 'dvdt': self.scaleBarDict['hLength'] = 1 # secon self.scaleBarDict['vLength'] = 10 elif self.myType == 'meanclip': self.scaleBarDict['hLength'] = 5 # ms self.scaleBarDict['vLength'] = 20 # mv self.xMargin = xMargin # seconds self.internalUpdate = False self.initUI() if xMin is not None and xMax is not None: pass #self.xMin = xMin #self.xMax = xMax else: xMin = np.nanmin(self.mySweepX_Downsample) xMax = np.nanmax(self.mySweepX_Downsample) # self.myAxis.set_xlim(xMin, xMax) #self._setXAxis(xMin, xMax) def myCloseAction(self): self.closeEvent() def closeEvent(self, event=None): """ in Qt, close only hides the widget! """ #print('bExportWidget.closeEvent()') self.deleteLater() self.myCloseSignal.emit(self) def initUI(self): self.setStyleSheet(qdarkstyle.load_stylesheet(qt_api='pyqt5')) ''' myPath = os.path.dirname(os.path.abspath(__file__)) mystylesheet_css = os.path.join(myPath, 'css', 'mystylesheet.css') myStyleSheet = None if os.path.isfile(mystylesheet_css): with open(mystylesheet_css) as f: myStyleSheet = f.read() if myStyleSheet is not None: self.setStyleSheet(myStyleSheet) ''' #self.setGeometry(100, 100, 1000, 600) self.center() if self.path: windowTitle = os.path.split(self.path)[1] self.setWindowTitle('Export Trace: ' + windowTitle) else: self.setWindowTitle('Export Trace: ' + 'None') myAlignLeft = QtCore.Qt.AlignLeft myAlignTop = QtCore.Qt.AlignTop hMasterLayout = QtWidgets.QHBoxLayout() hMasterLayout.setAlignment(QtCore.Qt.AlignTop) self.setLayout(hMasterLayout) left_container = QtWidgets.QWidget(self) left_container.setFixedWidth(350) hMasterLayout.addWidget(left_container, myAlignTop) vBoxLayout = QtWidgets.QVBoxLayout(left_container) # VBox for controls vBoxLayout.setAlignment(QtCore.Qt.AlignTop) hBoxRow0 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow0, myAlignTop) # # first row of controls # x axis on/off (todo: does not need self) self.xAxisCheckBox = QtWidgets.QCheckBox('') self.xAxisCheckBox.setToolTip('Toggle X-Axis On/Off') self.xAxisCheckBox.setChecked(True) self.xAxisCheckBox.stateChanged.connect(self.xAxisToggle) hBoxRow0.addWidget(self.xAxisCheckBox, myAlignLeft) # x min xMinLabel = QtWidgets.QLabel('X-Min') hBoxRow0.addWidget(xMinLabel, myAlignLeft) self.xMinSpinBox = QtWidgets.QDoubleSpinBox() self.xMinSpinBox.setToolTip('X-Axis Minimum') self.xMinSpinBox.setSingleStep(0.1) self.xMinSpinBox.setMinimum(-1e6) self.xMinSpinBox.setMaximum(1e6) self.xMinSpinBox.setValue(0) self.xMinSpinBox.setToolTip('X-Axis Minimum') self.xMinSpinBox.setKeyboardTracking(False) self.xMinSpinBox.valueChanged.connect(self._setXAxis) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow0.addWidget(self.xMinSpinBox, myAlignLeft) # x max xMax = np.nanmax( self.mySweepX_Downsample) # self.mySweepX_Downsample[-1] xMaxLabel = QtWidgets.QLabel('X-Max') hBoxRow0.addWidget(xMaxLabel, myAlignLeft) self.xMaxSpinBox = QtWidgets.QDoubleSpinBox() self.xMaxSpinBox.setToolTip('X-Axis Maximum') self.xMaxSpinBox.setSingleStep(0.1) self.xMaxSpinBox.setMinimum(-1e6) self.xMaxSpinBox.setMaximum(1e6) self.xMaxSpinBox.setValue(xMax) self.xMaxSpinBox.setToolTip('X-Axis Maximum') self.xMaxSpinBox.setKeyboardTracking(False) self.xMaxSpinBox.valueChanged.connect(self._setXAxis) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow0.addWidget(self.xMaxSpinBox, myAlignLeft) # # second row hBoxRow1 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow1) # y axis self.yAxisCheckBox = QtWidgets.QCheckBox('') self.yAxisCheckBox.setToolTip('Toggle Y-Axis On/Off') self.yAxisCheckBox.setChecked(True) self.yAxisCheckBox.stateChanged.connect(self.yAxisToggle) hBoxRow1.addWidget(self.yAxisCheckBox) # y min yMinLabel = QtWidgets.QLabel('Y-Min') hBoxRow1.addWidget(yMinLabel) yMinValue = np.nanmin(self.mySweepY_Downsample) self.yMinSpinBox = QtWidgets.QDoubleSpinBox() self.yMinSpinBox.setSingleStep(0.1) self.yMinSpinBox.setMinimum(-1e6) self.yMinSpinBox.setMaximum(1e6) self.yMinSpinBox.setValue(yMinValue) # flipped self.yMinSpinBox.setToolTip('Y-Axis Minimum') self.yMinSpinBox.setKeyboardTracking(False) self.yMinSpinBox.valueChanged.connect(self._setYAxis) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow1.addWidget(self.yMinSpinBox) # y max yMaxLabel = QtWidgets.QLabel('Y-Max') hBoxRow1.addWidget(yMaxLabel) yMaxValue = np.nanmax(self.mySweepY_Downsample) self.yMaxSpinBox = QtWidgets.QDoubleSpinBox() self.yMaxSpinBox.setSingleStep(0.1) self.yMaxSpinBox.setMinimum(-1e6) self.yMaxSpinBox.setMaximum(1e6) self.yMaxSpinBox.setValue(yMaxValue) # flipped self.yMaxSpinBox.setToolTip('Y-Axis Maximum') self.yMaxSpinBox.setKeyboardTracking(False) self.yMaxSpinBox.valueChanged.connect(self._setYAxis) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow1.addWidget(self.yMaxSpinBox) # # one 1/2 row hBoxRow1_5 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow1_5) # x-tick major lineWidthLabel = QtWidgets.QLabel('X-Tick Major') hBoxRow1_5.addWidget(lineWidthLabel) self.xTickIntervalSpinBox = QtWidgets.QDoubleSpinBox() self.xTickIntervalSpinBox.setSingleStep(0.1) self.xTickIntervalSpinBox.setMinimum(0.0) self.xTickIntervalSpinBox.setMaximum(1e6) self.xTickIntervalSpinBox.setValue(10) self.xTickIntervalSpinBox.setToolTip( 'Major Tick Interval, 0 To Turn Off') self.xTickIntervalSpinBox.setKeyboardTracking(False) self.xTickIntervalSpinBox.valueChanged.connect( self._setTickMajorInterval) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow1_5.addWidget(self.xTickIntervalSpinBox) # x-tick minor lineWidthLabel = QtWidgets.QLabel('Minor') hBoxRow1_5.addWidget(lineWidthLabel) self.xTickMinorIntervalSpinBox = QtWidgets.QDoubleSpinBox() self.xTickMinorIntervalSpinBox.setSingleStep(0.1) self.xTickMinorIntervalSpinBox.setMinimum(0.0) self.xTickMinorIntervalSpinBox.setMaximum(1e6) self.xTickMinorIntervalSpinBox.setValue(10) self.xTickMinorIntervalSpinBox.setToolTip( 'Minor Tick Interval, 0 To Turn Off') self.xTickMinorIntervalSpinBox.setKeyboardTracking(False) self.xTickMinorIntervalSpinBox.valueChanged.connect( self._setTickMinorInterval) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow1_5.addWidget(self.xTickMinorIntervalSpinBox) # # one 3/4 row hBoxRow1_ytick = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow1_ytick) # y-tick major lineWidthLabel = QtWidgets.QLabel('Y-Tick Major') hBoxRow1_ytick.addWidget(lineWidthLabel) self.yTickIntervalSpinBox = QtWidgets.QDoubleSpinBox() self.yTickIntervalSpinBox.setSingleStep(0.1) self.yTickIntervalSpinBox.setMinimum(0.0) self.yTickIntervalSpinBox.setMaximum(1e6) self.yTickIntervalSpinBox.setValue(20) self.yTickIntervalSpinBox.setToolTip( 'Major Y-Tick Interval, 0 To Turn Off') self.yTickIntervalSpinBox.setKeyboardTracking(False) self.yTickIntervalSpinBox.valueChanged.connect( self._setYTickMajorInterval) #todo: FIX THIS RECURSION WITH USING UP/DOWN ARROWS #self.yTickIntervalSpinBox.editingFinished.connect(self._setYTickMajorInterval) hBoxRow1_ytick.addWidget(self.yTickIntervalSpinBox) # y-tick minor lineWidthLabel = QtWidgets.QLabel('Minor') hBoxRow1_ytick.addWidget(lineWidthLabel) self.yTickMinorIntervalSpinBox = QtWidgets.QDoubleSpinBox() self.yTickMinorIntervalSpinBox.setSingleStep(0.1) self.yTickMinorIntervalSpinBox.setMinimum(0.0) self.yTickMinorIntervalSpinBox.setMaximum(1e6) self.yTickMinorIntervalSpinBox.setValue(20) self.yTickMinorIntervalSpinBox.setToolTip( 'Minor Y-Tick Interval, 0 To Turn Off') self.yTickMinorIntervalSpinBox.setKeyboardTracking(False) self.yTickMinorIntervalSpinBox.valueChanged.connect( self._setYTickMinorInterval) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow1_ytick.addWidget(self.yTickMinorIntervalSpinBox) # # third row hBoxRow2 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow2) # x margin xMaxLabel = QtWidgets.QLabel('X-Margin') hBoxRow2.addWidget(xMaxLabel) self.xMarginSpinBox = QtWidgets.QDoubleSpinBox() self.xMarginSpinBox.setToolTip('X-Axis Maximum') self.xMarginSpinBox.setSingleStep(0.1) self.xMarginSpinBox.setMinimum(0) self.xMarginSpinBox.setMaximum(1e6) self.xMarginSpinBox.setValue(self.xMargin) self.xMarginSpinBox.setKeyboardTracking(False) self.xMarginSpinBox.valueChanged.connect(self._setXMargin) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow2.addWidget(self.xMarginSpinBox) # # fourth row hBoxRow3 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow3) # line width lineWidthLabel = QtWidgets.QLabel('Line Width') hBoxRow3.addWidget(lineWidthLabel) self.lineWidthSpinBox = QtWidgets.QDoubleSpinBox() self.lineWidthSpinBox.setSingleStep(0.1) self.lineWidthSpinBox.setMinimum(0.01) self.lineWidthSpinBox.setMaximum(100.0) self.lineWidthSpinBox.setValue(0.5) self.lineWidthSpinBox.setKeyboardTracking(False) self.lineWidthSpinBox.valueChanged.connect(self._setLineWidth) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) hBoxRow3.addWidget(self.lineWidthSpinBox) # color colorList = [ 'red', 'green', 'blue', 'cyan', 'magenta', 'yellow', 'black', 'white' ] wIdx = colorList.index('white') kIdx = colorList.index('black') colorLabel = QtWidgets.QLabel('Line Color') hBoxRow3.addWidget(colorLabel) self.colorDropdown = QtWidgets.QComboBox() self.colorDropdown.addItems(colorList) self.colorDropdown.setCurrentIndex(wIdx if self.darkTheme else kIdx) self.colorDropdown.currentIndexChanged.connect(self._setLineColor) hBoxRow3.addWidget(self.colorDropdown) # # fifth row hBoxRow4 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow4) # downsample downsampleLabel = QtWidgets.QLabel('Downsample') hBoxRow4.addWidget(downsampleLabel) self.downSampleSpinBox = QtWidgets.QSpinBox() self.downSampleSpinBox.setSingleStep(1) self.downSampleSpinBox.setMinimum(1) self.downSampleSpinBox.setMaximum(200) self.downSampleSpinBox.setValue(1) self.downSampleSpinBox.setKeyboardTracking(False) self.downSampleSpinBox.valueChanged.connect(self._setDownSample) #self.downSampleSpinBox.editingFinished.connect(self._setDownSample) hBoxRow4.addWidget(self.downSampleSpinBox) # meadianFilter medianFilterLabel = QtWidgets.QLabel('Median Filter (points)') hBoxRow4.addWidget(medianFilterLabel) self.medianFilterSpinBox = QtWidgets.QSpinBox() #self.medianFilterSpinBox.setStyle(CustomStyle()) self.medianFilterSpinBox.setSingleStep(2) self.medianFilterSpinBox.setMinimum(1) self.medianFilterSpinBox.setMaximum(1000) self.medianFilterSpinBox.setValue(1) self.medianFilterSpinBox.setKeyboardTracking(False) self.medianFilterSpinBox.valueChanged.connect(self._setDownSample) #self.medianFilterSpinBox.editingFinished.connect(self._setDownSample) hBoxRow4.addWidget(self.medianFilterSpinBox) # # fifth row hBoxRow4_5 = QtWidgets.QHBoxLayout() vBoxLayout.addLayout(hBoxRow4_5, myAlignTop) # dark theme self.darkThemeCheckBox = QtWidgets.QCheckBox('Dark Theme') self.darkThemeCheckBox.setChecked(self.darkTheme) self.darkThemeCheckBox.stateChanged.connect(self._changeTheme) hBoxRow4_5.addWidget(self.darkThemeCheckBox) # # sixth row scaleBarGroupBox = QtWidgets.QGroupBox('Scale Bar') scaleBarGroupBox.setAlignment(myAlignTop) vBoxLayout.addWidget(scaleBarGroupBox, myAlignTop) gridBoxScaleBar = QtWidgets.QGridLayout() scaleBarGroupBox.setLayout(gridBoxScaleBar) hLength = self.scaleBarDict['hLength'] vLength = self.scaleBarDict['vLength'] lineWidth = self.scaleBarDict['lineWidth'] # scale bar width (length) scaleBarWidthLabel = QtWidgets.QLabel('Width') gridBoxScaleBar.addWidget(scaleBarWidthLabel, 0, 0) self.scaleBarWidthSpinBox = QtWidgets.QDoubleSpinBox() self.scaleBarWidthSpinBox.setToolTip('X Scale Bar Width (0 to remove)') self.scaleBarWidthSpinBox.setSingleStep(0.1) self.scaleBarWidthSpinBox.setMinimum(-1e6) self.scaleBarWidthSpinBox.setMaximum(1e6) self.scaleBarWidthSpinBox.setValue(hLength) self.scaleBarWidthSpinBox.setKeyboardTracking(False) self.scaleBarWidthSpinBox.valueChanged.connect(self._setScaleBarSize) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) gridBoxScaleBar.addWidget(self.scaleBarWidthSpinBox, 0, 1) # scale bar height (length) scaleBarHeightLabel = QtWidgets.QLabel('Height') gridBoxScaleBar.addWidget(scaleBarHeightLabel, 1, 0) self.scaleBarHeightSpinBox = QtWidgets.QDoubleSpinBox() self.scaleBarHeightSpinBox.setToolTip( 'Y Scale Bar Height (0 to remove)') self.scaleBarHeightSpinBox.setSingleStep(0.1) self.scaleBarHeightSpinBox.setMinimum(-1e6) self.scaleBarHeightSpinBox.setMaximum(1e6) self.scaleBarHeightSpinBox.setValue(vLength) self.scaleBarHeightSpinBox.setKeyboardTracking(False) self.scaleBarHeightSpinBox.valueChanged.connect(self._setScaleBarSize) #self.lineWidthSpinBox.editingFinished.connect(self._setLineWidth) gridBoxScaleBar.addWidget(self.scaleBarHeightSpinBox, 1, 1) # scale bar line thickness scaleBarThicknessLabel = QtWidgets.QLabel('Thickness') gridBoxScaleBar.addWidget(scaleBarThicknessLabel, 2, 0) self.scaleBarThicknessSpinBox = QtWidgets.QDoubleSpinBox() self.scaleBarThicknessSpinBox.setToolTip('Scale Bar Thickness') self.scaleBarThicknessSpinBox.setSingleStep(1) self.scaleBarThicknessSpinBox.setMinimum(0.1) self.scaleBarThicknessSpinBox.setMaximum(1e6) self.scaleBarThicknessSpinBox.setValue(lineWidth) self.scaleBarThicknessSpinBox.setKeyboardTracking(False) self.scaleBarThicknessSpinBox.valueChanged.connect( self._setScaleBarThickness) gridBoxScaleBar.addWidget(self.scaleBarThicknessSpinBox, 2, 1) # save button saveButton = QtWidgets.QPushButton('Save', self) saveButton.resize(saveButton.sizeHint()) saveButton.clicked.connect(self.save) vBoxLayout.addWidget(saveButton) #vBoxLayout.addStretch() self.figure = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.figure) # set defaullt save name baseName = 'export' if self.path: baseName = os.path.splitext(self.path)[0] self.canvas.get_default_filename = lambda: f'{baseName}' # matplotlib navigation toolbar self.toolbar = NavigationToolbar(self.canvas, self) #self.toolbar.zoom() # need self. here to set theme self.plotVBoxLayout = QtWidgets.QVBoxLayout() self.plotVBoxLayout.addWidget(self.toolbar) self.plotVBoxLayout.addWidget(self.canvas) hMasterLayout.addLayout(self.plotVBoxLayout) #, stretch=8) #self.myAxis = None self.plotRaw(firstPlot=True) self.show() def _changeTheme(self): """ to change the theme, we need to redraw everything """ checked = self.darkThemeCheckBox.isChecked() # get x/y axes limits xMin, xMax = self.myAxis.get_xlim() yMin, yMax = self.myAxis.get_ylim() # remove self.plotVBoxLayout.removeWidget(self.toolbar) self.plotVBoxLayout.removeWidget(self.canvas) self.toolbar.setParent(None) self.canvas.setParent(None) self.figure = None # ??? self.toolbar = None self.canvas = None #self.canvas.draw() #self.repaint() # set theme if checked: plt.style.use('dark_background') self.darkTheme = True else: plt.rcParams.update(plt.rcParamsDefault) self.darkTheme = False self.figure = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.figure) # matplotlib navigation toolbar self.toolbar = NavigationToolbar(self.canvas, self) #self.toolbar.zoom() self.plotVBoxLayout.addWidget(self.toolbar) self.plotVBoxLayout.addWidget(self.canvas) # self.grid.addWidget(self.toolbar, ??) if self.darkTheme: self.scaleBarDict['color'] = 'w' else: self.scaleBarDict['color'] = 'k' #self.myAxis = None self.plotRaw(firstPlot=True) # restore original x/y axes self.myAxis.set_xlim(xMin, xMax) self.myAxis.set_ylim(yMin, yMax) def _setXMargin(self): self.xMarginSpinBox.setEnabled(False) self.xMargin = self.xMarginSpinBox.value() self.plotRaw() self.xMarginSpinBox.setEnabled(True) def _setXAxis(self): """ called when user sets values in x spin boxes see: on_xlim_change """ self.xMinSpinBox.setEnabled(False) self.xMaxSpinBox.setEnabled(False) xMin = self.xMinSpinBox.value() xMax = self.xMaxSpinBox.value() #print('_setXAxis() calling self.myAxis.set_xlim()', xMin, xMax) xMin -= self.xMargin xMax += self.xMargin self.internalUpdate = True self.myAxis.set_xlim(xMin, xMax) self.internalUpdate = False self.scaleBars.setPos(xPos=xMax, fromMax=True) #self.plotRaw(xMin=xMin, xMax=xMax) self.plotRaw() self.xMinSpinBox.setEnabled(True) self.xMaxSpinBox.setEnabled(True) def _setYAxis(self): """ called when user sets values in y spin boxes see: on_xlim_change """ self.yMinSpinBox.setEnabled(False) self.yMaxSpinBox.setEnabled(False) yMin = self.yMinSpinBox.value() yMax = self.yMaxSpinBox.value() self.myAxis.set_ylim(yMin, yMax) self.scaleBars.setPos(yPos=yMax, fromMax=True) self.yMinSpinBox.setEnabled(True) self.yMaxSpinBox.setEnabled(True) def on_xlims_change(self, mplEvent): """ matplotlib callback """ if self.internalUpdate: return xLim = mplEvent.get_xlim() #print('on_xlims_change() xLim:', xLim) xMin = xLim[0] xMax = xLim[1] self.xMinSpinBox.setValue(xMin) self.xMaxSpinBox.setValue(xMax) self.plotRaw() #self.canvas.draw_idle() def _setDownSample(self): self.downSampleSpinBox.setEnabled(False) self.medianFilterSpinBox.setEnabled(False) try: downSample = self.downSampleSpinBox.value() medianFilter = self.medianFilterSpinBox.value() if (medianFilter % 2) == 0: medianFilter += 1 #print('_setDownSample() downSample:', downSample, 'medianFilter:', medianFilter) #print('downSample ... please wait') self.mySweepX_Downsample = self.mySweepX[::downSample] self.mySweepY_Downsample = self.mySweepY[::downSample] if medianFilter > 1: #print('medianFilter ... please wait') self.mySweepY_Downsample = scipy.signal.medfilt( self.mySweepY_Downsample, kernel_size=medianFilter) # self.plotRaw() # refresh scale-bar xPos = np.nanmax( self.mySweepX_Downsample) # self.mySweepX_Downsample[-1] yPos = np.nanmax(self.mySweepY_Downsample) #self.scaleBars.setPos(xPos, yPos, fromMax=True) except (Exception) as e: logger.exceptiion('EXCEPTION in _setDownSample():', e) self.canvas.draw_idle() #self.repaint() self.downSampleSpinBox.setEnabled(True) self.medianFilterSpinBox.setEnabled(True) def xAxisToggle(self): checked = self.xAxisCheckBox.isChecked() self._toggleAxis('bottom', checked) def yAxisToggle(self): checked = self.yAxisCheckBox.isChecked() self._toggleAxis('left', checked) def scaleBarToggle(self): xChecked = self.xScaleBarCheckBox.isChecked() yChecked = self.yScaleBarCheckBox.isChecked() self._toggleScaleBar(xChecked, yChecked) def _setScaleBarSize(self): self.scaleBarWidthSpinBox.setEnabled(False) self.scaleBarHeightSpinBox.setEnabled(False) width = self.scaleBarWidthSpinBox.value() height = self.scaleBarHeightSpinBox.value() self.scaleBars.setWidthHeight(width=width, height=height) # self.canvas.draw_idle() #self.repaint() self.scaleBarWidthSpinBox.setEnabled(True) self.scaleBarHeightSpinBox.setEnabled(True) def _setScaleBarThickness(self): self.scaleBarThicknessSpinBox.setEnabled(False) thickness = self.scaleBarThicknessSpinBox.value() self.scaleBars.setThickness(thickness) # self.canvas.draw_idle() #self.repaint() self.scaleBarThicknessSpinBox.setEnabled(True) def _setYTickMajorInterval(self): #, interval): self.yTickIntervalSpinBox.setEnabled(False) interval = self.yTickIntervalSpinBox.value() if interval == 0: ml = ticker.NullLocator() else: ml = ticker.MultipleLocator(interval) self.myAxis.yaxis.set_major_locator(ml) # self.canvas.draw_idle() #self.repaint() self.yTickIntervalSpinBox.setEnabled(True) def _setYTickMinorInterval(self, interval): self.yTickMinorIntervalSpinBox.setEnabled(False) if interval == 0: ml = ticker.NullLocator() else: ml = ticker.MultipleLocator(interval) self.myAxis.yaxis.set_minor_locator(ml) # self.canvas.draw_idle() #self.repaint() self.yTickMinorIntervalSpinBox.setEnabled(True) def _setTickMajorInterval(self, interval): self.xTickIntervalSpinBox.setEnabled(False) if interval == 0: ml = ticker.NullLocator() else: ml = ticker.MultipleLocator(interval) self.myAxis.xaxis.set_major_locator(ml) # self.canvas.draw_idle() #self.repaint() self.xTickIntervalSpinBox.setEnabled(True) def _setTickMinorInterval(self, interval): self.xTickMinorIntervalSpinBox.setEnabled(False) if interval == 0: ml = ticker.NullLocator() else: ml = ticker.MultipleLocator(interval) self.myAxis.xaxis.set_minor_locator(ml) # self.canvas.draw_idle() #self.repaint() self.xTickMinorIntervalSpinBox.setEnabled(True) def _toggleAxis(self, leftBottom, onOff): if leftBottom == 'bottom': self.myAxis.get_xaxis().set_visible(onOff) self.myAxis.spines['bottom'].set_visible(onOff) elif leftBottom == 'left': self.myAxis.get_yaxis().set_visible(onOff) self.myAxis.spines['left'].set_visible(onOff) # self.canvas.draw_idle() #self.repaint() def _toggleScaleBar(self, xChecked, yChecked): self.scaleBars.hideScaleBar(xChecked, yChecked) def _setLineColor(self, colorStr): colorStr = self.colorDropdown.currentText() self.myTraceLine.set_color(colorStr) ''' for line in self.myAxis.lines: print('_setLineColor:', line.get_label()) line.set_color(colorStr) ''' # self.canvas.draw_idle() #self.repaint() def _setLineWidth(self): self.lineWidthSpinBox.setEnabled(False) lineWidth = self.lineWidthSpinBox.value() #print('bExportWidget._setLineWidth() lineWidth:', lineWidth) self.myTraceLine.set_linewidth(lineWidth) ''' for line in self.myAxis.lines: line.set_linewidth(lineWidth) ''' # self.canvas.draw_idle() #self.repaint() self.lineWidthSpinBox.setEnabled(True) def plotRaw(self, xMin=None, xMax=None, firstPlot=False): if firstPlot: self.figure.clf() self.myAxis = self.figure.add_subplot(111) ''' left = .2 #0.05 bottom = 0.05 width = 0.7 #0.9 height = 0.9 self.myAxis = self.figure.add_axes([left, bottom, width, height]) ''' self.myAxis.spines['right'].set_visible(False) self.myAxis.spines['top'].set_visible(False) if self.darkTheme: color = 'w' else: color = 'k' lineWidth = self.lineWidthSpinBox.value() sweepX = self.mySweepX_Downsample sweepY = self.mySweepY_Downsample if firstPlot: xMinOrig = sweepX[0] xMaxOrig = np.nanmax(sweepX) # sweepX[-1] else: xMinOrig, xMaxOrig = self.myAxis.get_xlim() yMinOrig = np.nanmin(sweepY) yMaxOrig = np.nanmax(sweepY) xClip = self.xMargin if xMin is not None and xMax is not None: minClip = xMin + xClip maxClip = xMax - xClip else: minClip = xMinOrig + xClip maxClip = xMaxOrig - xClip sweepX = np.ma.masked_where((sweepX < minClip), sweepX) sweepY = np.ma.masked_where((sweepX < minClip), sweepY) sweepX = np.ma.masked_where((sweepX > maxClip), sweepX) sweepY = np.ma.masked_where((sweepX > maxClip), sweepY) #print('sweepX:', sweepX.shape, type(sweepX)) #print('sweepY:', sweepY.shape, type(sweepY)) if firstPlot: # using label 'myTrace' to differentiate from x/y scale bar self.myTraceLine, = self.myAxis.plot( sweepX, sweepY, '-', # fmt = '[marker][line][color]' c=color, linewidth=lineWidth, label='myTrace') #matplotlib.lines.Line2D self.myAxis.callbacks.connect('xlim_changed', self.on_xlims_change) # scale bar hLength = self.scaleBarDict['hLength'] vLength = self.scaleBarDict['vLength'] scaleBarLineWidth = self.scaleBarDict['lineWidth'] scaleBarColor = self.scaleBarDict['color'] xPos = xMaxOrig #sweepX[-1] yPos = yMaxOrig #np.nanmax(sweepY) self.scaleBars = draggable_lines(self.myAxis, xPos, yPos, hLength=hLength, vLength=vLength, linewidth=scaleBarLineWidth, color=scaleBarColor, doPick=True) self.scaleBars.setPos(xPos, yPos, fromMax=True) else: self.myTraceLine.set_xdata(sweepX) self.myTraceLine.set_ydata(sweepY) ''' for line in self.myAxis.lines: print('plotRaw() is updating with set_xdata/set_ydata') line.set_xdata(sweepX) line.set_ydata(sweepY) ''' #self.myAxis.use_sticky_edges = False #self.myAxis.margins(self.xMargin, tight=None) if firstPlot: #self.myAxis.set_ylabel('Vm (mV)') #self.myAxis.set_xlabel('Time (sec)') self.myAxis.set_ylabel(self.xyUnits[1]) self.myAxis.set_xlabel(self.xyUnits[0]) self.canvas.draw_idle() #self.repaint() def save(self): """ Save the current view to a pdf file """ # get min/max of x-axis [xMin, xMax] = self.myAxis.get_xlim() #if xMin < 0: # xMin = 0 xMin += self.xMargin xMax -= self.xMargin xMin = '%.2f' % (xMin) xMax = '%.2f' % (xMax) lhs, rhs = xMin.split('.') xMin = 'b' + lhs + '_' + rhs lhs, rhs = xMax.split('.') xMax = 'e' + lhs + '_' + rhs # construct a default save file name saveFilePath = '' if self.path: parentPath, filename = os.path.split(self.path) baseFilename, file_extension = os.path.splitext(filename) #saveFileName = baseFilename + '_' + self.myType + '_' + xMin + '_' + xMax + '.svg' saveFileName = f'{baseFilename}_{self.myType}_{xMin}_{xMax}.svg' #saveFileName = baseFilename + '.svg' saveFilePath = os.path.join(parentPath, saveFileName) # file save dialog #fullSavePath, ignore = QtWidgets.QFileDialog.getSaveFileName(self, 'Save File', saveFilePath, "pdf Files (*.pdf)") fullSavePath, ignore = QtWidgets.QFileDialog.getSaveFileName( self, 'Save File', saveFilePath) # do actual save if len(fullSavePath) > 0: logger.info(f'saving: {fullSavePath}') self.figure.savefig(fullSavePath) def center(self): """ Center the window on the screen """ qr = self.frameGeometry() cp = QtWidgets.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
class ProtocoleWidget(QtWidgets.QWidget): # sets the window def __init__(self): super().__init__() self.chemin = QtWidgets.QLineEdit() text = QtWidgets.QLabel("Chemin du fichier du protocole à ouvrir :") button = QtWidgets.QPushButton("Generate graph and give acyclicity") button.clicked.connect(self.graph_generation) layout = QtWidgets.QHBoxLayout() layout.addWidget(text) layout.addWidget(self.chemin) layout.addWidget(button) layout.setAlignment(QtCore.Qt.AlignTop) self.protocol = QtWidgets.QListView() self.protocol.setEditTriggers( QtWidgets.QAbstractItemView.NoEditTriggers) self.protocol.setWindowTitle('Protocol') #self.protocol.setMinimumSize(600, 400) # Create an empty model for the list's data self.model = QtGui.QStandardItemModel(self.protocol) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.resize(600, 400) layoutProtocolGraph = QtWidgets.QHBoxLayout() layoutProtocolGraph.addWidget(self.protocol) layoutProtocolGraph.addWidget(self.canvas) layoutGeneral = QtWidgets.QVBoxLayout() layoutGeneral.addLayout(layout) layoutGeneral.addLayout(layoutProtocolGraph) self.setLayout(layoutGeneral) # draws graph and protocol on the window def graph_generation(self): #tester avec ../tests/parser/protocolForTests self.model.removeRows(0, self.model.rowCount()) print(self.chemin.text()) protocol = parseFromFile(self.chemin.text()) self.ficherEnregistrementProtocol = open(protocol.name + " parsé.txt", "w") print("\n\nVARIABLES FOUND :") for var in protocol.listVar: if (not (var.isDeclaredOnTheFly())): print(var) self.ficherEnregistrementProtocol.write( var.toStringOnVarDeclaration() + "\n") item = QtGui.QStandardItem(var.toStringOnVarDeclaration()) self.model.appendRow(item) self.ficherEnregistrementProtocol.write("\n\n") self.model.appendRow("") self.model.appendRow("") print("\n\nTRANSACTIONS FOUND :") for trans in protocol.listTransactions: self.ficherEnregistrementProtocol.write(trans.label + "\n") print(trans.label) item = QtGui.QStandardItem(trans.label) self.model.appendRow(item) for action in trans.actions: act = action.__str__() print("-" + act) self.ficherEnregistrementProtocol.write(act + "\n") item = QtGui.QStandardItem(act) self.model.appendRow(item) self.ficherEnregistrementProtocol.write("\n") self.model.appendRow("") # Apply the model to the list view self.protocol.setModel(self.model) print("\n\nTYPES FOUND :") for type in protocol.listTypes: print(type) self.ficherEnregistrementProtocol.close() nxgraph = getnxFromDependencies(protocol, protocol.build_dependencies()) self.figure.clf() self.canvas.draw_idle() savenxGraph(nxgraph, self.chemin.text() + "-graph.png") protocol.reset()
class tabdemo(QTabWidget): def __init__(self, parent = None): super(tabdemo, self).__init__(parent) self.tab1 = QWidget() self.tab2 = QWidget() self.tab3 = QWidget() self.addTab(self.tab1,"Tab 1") self.addTab(self.tab2,"Tab 2") self.addTab(self.tab3,"Tab 3") self.tab1UI() self.graphUI() self.tableUI() self.setWindowTitle("tab demo") def tab1UI(self): layout = QHBoxLayout() button = QPushButton("Select File", self) layout.addWidget(button) button.clicked.connect(lambda: self.openFileNameDialog()) txt = ("""Note: \nProgram can only accept csv files.\n""" """Can only take 2 columns for input data.\nEx: Price vs. Time or """ """Velocity vs. Time.\nAs of right now, this program is only capable line plots""") label = QLabel(txt) layout.addWidget(label) layout.addStretch(1) button3 = QPushButton("Show Table", self) layout.addWidget(button3) button3.clicked.connect(lambda: self.createTable(self.data_)) self.setTabText(0,"Data") self.tab1.setLayout(layout) self.resize(800,480) def graphUI(self): self.setTabText(1,"Graph") self.figure = plt.figure(figsize=(8,8)) self.canvas = FigureCanvasQTAgg(self.figure) layout = QVBoxLayout() layout.addWidget(self.canvas) button2 = QPushButton("Graph", self) layout.addWidget(button2) button2.clicked.connect(lambda: self.plot(self.x_, self.y_)) self.tab2.setLayout(layout) def tableUI(self): self.setTabText(2,"Table") self.layout = QVBoxLayout() def plot(self, x, y): ax = self.figure.add_subplot(111) ax.plot(x, y, '*-') self.canvas.draw_idle() def getCSV(self, csvpath_tmp): with open('out.csv', newline='') as f: reader = csv.reader(f) next(reader) #skip first line, assume csv file has header data_ = list(reader) self.data_ = data_ self.x_ = [] self.y_ = [] for i in data_: self.x_.append(int(i[0])) self.y_.append(int(i[1])) def openFileNameDialog(self): options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog fileName, _ = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "",".csv Files (*.csv)", options=options) if fileName: self.getCSV(fileName) def createTable(self, data): self.tableWidget = QTableWidget() #Row count self.tableWidget.setRowCount(len(self.x_)) #Column count self.tableWidget.setColumnCount(2) for (i, data_) in enumerate(data, 0): x, y = data_ self.tableWidget.setItem(i,0, QTableWidgetItem(x)) self.tableWidget.setItem(i,1, QTableWidgetItem(y)) #Table will fit the screen horizontally self.tableWidget.horizontalHeader().setStretchLastSection(True) self.tableWidget.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.layout.addWidget(self.tableWidget) #self.setLayout(self.layout) self.tab3.setLayout(self.layout) self.show()
class UIProcessing(*uic.loadUiType(ui_path)): def __init__(self, hhm, db, det_dict, parent_gui, job_submitter, *args, **kwargs): ''' hhm: the monochromator db : the data database det_dict: detector dictionary parent_gui: the parent gui job_submitter: function the function that submits jobs for processing takes uid as argument only (pass the rest through functools.partial) ''' super().__init__(*args, **kwargs) self.setupUi(self) self.addCanvas() self.job_submitter = job_submitter self.hhm = hhm self.db = db self.det_dict = det_dict self.gen_parser = xasdata.XASdataGeneric(self.hhm.enc.pulses_per_deg, self.db) self.settings = QSettings(parent_gui.window_title, 'XLive') self.edit_E0_2.setText( self.settings.value('e0_processing', defaultValue='11470', type=str)) self.edit_E0_2.textChanged.connect(self.save_e0_processing_value) self.user_dir = self.settings.value('user_dir', defaultValue='/GPFS/xf08id/users/', type=str) # Initialize 'processing' tab self.push_select_file.clicked.connect(self.selectFile) self.push_bin_save.clicked.connect(self.bin_single_data) self.push_calibrate.clicked.connect(self.calibrate_offset) self.push_replot_file.clicked.connect(self.replot_data) self.push_reset_data.clicked.connect(self.reset_data_plots) self.cid = self.canvas_old_scans_2.mpl_connect('button_press_event', self.getX) self.edge_found = -1 # Disable buttons self.push_bin_save.setDisabled(True) self.push_replot_file.setDisabled(True) self.active_threads = 0 self.total_threads = 0 self.plotting_list = [] self.last_num = '' self.last_den = '' self.last_num_text = 'i0' self.last_den_text = 'it' self.bin_data_sets = [] self.interp_data_sets = [] self.handles_interp = [] self.handles_bin = [] def addCanvas(self): self.figure_old_scans_2 = Figure() self.figure_old_scans_2.set_facecolor(color='#FcF9F6') self.canvas_old_scans_2 = FigureCanvas(self.figure_old_scans_2) self.figure_old_scans_2.ax = self.figure_old_scans_2.add_subplot(111) self.figure_old_scans_2.ax2 = self.figure_old_scans_2.ax.twinx() self.toolbar_old_scans_2 = NavigationToolbar(self.canvas_old_scans_2, self, coordinates=True) self.plot_old_scans_2.addWidget(self.toolbar_old_scans_2) self.plot_old_scans_2.addWidget(self.canvas_old_scans_2) self.canvas_old_scans_2.draw_idle() self.figure_old_scans_2.ax.grid(alpha=0.4) self.figure_old_scans_3 = Figure() self.figure_old_scans_3.set_facecolor(color='#FcF9F6') self.canvas_old_scans_3 = FigureCanvas(self.figure_old_scans_3) self.figure_old_scans_3.ax = self.figure_old_scans_3.add_subplot(111) self.figure_old_scans_3.ax2 = self.figure_old_scans_3.ax.twinx() self.toolbar_old_scans_3 = NavigationToolbar(self.canvas_old_scans_3, self, coordinates=True) self.plot_old_scans_3.addWidget(self.toolbar_old_scans_3) self.plot_old_scans_3.addWidget(self.canvas_old_scans_3) self.canvas_old_scans_3.draw_idle() self.figure_old_scans_3.ax.grid(alpha=0.4) def getX(self, event): if event.button == 3: ret = self.questionMessage( 'Setting Edge', 'Would like to set the edge to {:.0f}?'.format(event.xdata)) if ret: self.edit_E0_2.setText(str(int(np.round(event.xdata)))) def set_new_angle_offset(self, value): try: self.hhm.angle_offset.put(float(value)) except Exception as exc: if type(exc) == ophyd_utils.errors.LimitError: print('[New offset] {}. No reason to be desperate, though.'. format(exc)) else: print('[New offset] Something went wrong, not the limit: {}'. format(exc)) return 1 return 0 def save_e0_processing_value(self, string): self.settings.setValue('e0_processing', string) def selectFile(self): if self.checkBox_process_bin.checkState() > 0: self.selected_filename_bin = QtWidgets.QFileDialog.getOpenFileNames( directory=self.user_dir, filter='*.txt', parent=self)[0] else: self.selected_filename_bin = QtWidgets.QFileDialog.getOpenFileName( directory=self.user_dir, filter='*.txt', parent=self)[0] if len(self.selected_filename_bin) > 0: self.selected_filename_bin = [self.selected_filename_bin] else: self.selected_filename_bin = [] if len(self.selected_filename_bin): self.handles_interp = [] self.handles_bin = [] self.interp_data_sets = [] self.bin_data_sets = [] self.uids = [] if len(self.selected_filename_bin) > 1: filenames = [] self.user_dir = self.selected_filename_bin[0].rsplit('/', 1)[0] for name in self.selected_filename_bin: filenames.append(name.rsplit('/', 1)[1]) self.uids.append( self.gen_parser.read_header(name).split('UID: ') [1].split('\n')[0]) filenames = ', '.join(filenames) self.push_bin_save.setEnabled(False) elif len(self.selected_filename_bin) == 1: filenames = self.selected_filename_bin[0] self.user_dir = filenames.rsplit('/', 1)[0] self.uids.append( self.gen_parser.read_header(filenames).split('UID: ') [1].split('\n')[0]) self.push_bin_save.setEnabled(True) print(self.uids) self.settings.setValue('user_dir', self.user_dir) self.label_24.setText(filenames) self.send_data_request() def update_listWidgets(self): index = [ index for index, item in enumerate([ self.listWidget_numerator.item(index) for index in range(self.listWidget_numerator.count()) ]) if item.text() == self.last_num_text ] if len(index): self.listWidget_numerator.setCurrentRow(index[0]) else: self.listWidget_numerator.setCurrentRow(0) index = [ index for index, item in enumerate([ self.listWidget_denominator.item(index) for index in range(self.listWidget_denominator.count()) ]) if item.text() == self.last_den_text ] if len(index): self.listWidget_denominator.setCurrentRow(index[0]) else: self.listWidget_denominator.setCurrentRow(0) def create_lists(self, list_num, list_den): self.listWidget_numerator.clear() self.listWidget_denominator.clear() self.listWidget_numerator.insertItems(0, list_num) self.listWidget_denominator.insertItems(0, list_den) def bin_single_data(self): for index, uid in enumerate(self.uids): self.send_bin_request(uid, filepath=self.selected_filename_bin[index]) def send_bin_request(self, uid, filepath): e0 = int(self.edit_E0_2.text()) edge_start = int(self.edit_edge_start.text()) edge_end = int(self.edit_edge_end.text()) preedge_spacing = float(self.edit_preedge_spacing.text()) xanes_spacing = float(self.edit_xanes_spacing.text()) exafs_spacing = float(self.edit_exafs_spacing.text()) req = { 'uid': uid, 'requester': socket.gethostname(), 'type': 'spectroscopy', 'processing_info': { 'type': 'bin', 'filepath': filepath, #self.selected_filename_bin[index], 'e0': e0, 'edge_start': edge_start, 'edge_end': edge_end, 'preedge_spacing': preedge_spacing, 'xanes_spacing': xanes_spacing, 'exafs_spacing': exafs_spacing, } } self.job_submitter(req) def send_data_request(self): print("Submitting a data request") index = 1 self.old_scans_control = 1 self.old_scans_2_control = 1 self.old_scans_3_control = 1 self.figure_old_scans_2.ax.clear() self.figure_old_scans_2.ax2.clear() self.toolbar_old_scans_2.update() self.canvas_old_scans_2.draw_idle() self.figure_old_scans_2.ax.grid(alpha=0.4) self.figure_old_scans_3.ax.clear() self.figure_old_scans_3.ax2.clear() self.toolbar_old_scans_3.update() self.figure_old_scans_3.ax.grid(alpha=0.4) self.canvas_old_scans_3.draw_idle() # print('[Launching Threads]') if self.listWidget_numerator.currentRow() is not -1: self.last_num = self.listWidget_numerator.currentRow() self.last_num_text = self.listWidget_numerator.currentItem().text() if self.listWidget_denominator.currentRow() is not -1: self.last_den = self.listWidget_denominator.currentRow() self.last_den_text = self.listWidget_denominator.currentItem( ).text() self.listWidget_numerator.setCurrentRow(-1) self.listWidget_denominator.setCurrentRow(-1) for index, uid in enumerate(self.uids): req = { 'uid': uid, 'requester': socket.gethostname(), 'type': 'spectroscopy', 'processing_info': { 'type': 'request_interpolated_data', 'filepath': self.selected_filename_bin[index], } } self.job_submitter(req) if self.checkBox_process_bin.checkState() > 0: self.send_bin_request(uid, self.selected_filename_bin[index]) def save_bin(self): filename = self.curr_filename_save self.gen_parser.data_manager.export_dat(filename) print('[Save File] File Saved! [{}]'.format(filename[:-3] + 'dat')) def calibrate_offset(self): ret = self.questionMessage( 'Confirmation', 'Are you sure you would like to calibrate it?') if not ret: print('[E0 Calibration] Aborted!') return False new_value = str( self.hhm.angle_offset.value - (xray.energy2encoder(float(self.edit_E0_2.text( )), self.hhm.pulses_per_deg) - xray.energy2encoder( float(self.edit_ECal.text()), self.hhm.pulses_per_deg)) / self.hhm.pulses_per_deg) if self.set_new_angle_offset(new_value): return print('[E0 Calibration] New value: {}\n[E0 Calibration] Completed!'. format(new_value)) def replot_data(self): self.replot(self.bin_data_sets, self.handles_bin, self.figure_old_scans_3, self.toolbar_old_scans_3) self.replot(self.interp_data_sets, self.handles_interp, self.figure_old_scans_2, self.toolbar_old_scans_2) self.replot_y() def replot_y(self): for data in self.bin_data_sets: df = data['processing_ret']['data'] def replot(self, list_data_set, handles, figure, toolbar): figure.ax.clear() if hasattr(figure, 'ax2'): figure.ax2.clear() figure.canvas.draw_idle() toolbar.update() if self.listWidget_numerator.currentRow() is not -1: self.last_num = self.listWidget_numerator.currentRow() self.last_num_text = self.listWidget_numerator.currentItem().text() if self.listWidget_denominator.currentRow() is not -1: self.last_den = self.listWidget_denominator.currentRow() self.last_den_text = self.listWidget_denominator.currentItem( ).text() for data in list_data_set: df = data['processing_ret']['data'] if isinstance(df, str): # load data, it's astring df = self.gen_parser.getInterpFromFile(df) df = df.sort_values('energy') result = df[self.last_num_text] / df[self.last_den_text] ylabel = '{} / {}'.format(self.last_num_text, self.last_den_text) self.bin_offset = 0 if self.checkBox_log.checkState() > 0: ylabel = 'log({})'.format(ylabel) warnings.filterwarnings('error') try: result_log = np.log(result) except Warning as wrn: self.bin_offset = 0.1 + np.abs(result.min()) print( '{}: Added an offset of {} so that we can plot the graphs properly (only for data visualization)' .format(wrn, self.bin_offset)) result_log = np.log(result + self.bin_offset) # self.checkBox_log.setChecked(False) warnings.filterwarnings('default') result = result_log if self.checkBox_neg.checkState() > 0: result = -result figure.ax.plot(df['energy'].iloc[:len(result)], result) figure.ax.set_ylabel(ylabel) figure.ax.set_xlabel('energy') figure.ax.legend(handles=handles) figure.canvas.draw_idle() def plot_data(self, data): df = data['processing_ret']['data'] if isinstance(df, str): # load data, it's astring df = self.gen_parser.getInterpFromFile(df) #df = pd.DataFrame.from_dict(json.loads(data['processing_ret']['data'])) df = df.sort_values('energy') self.df = df self.bin_data_sets.append(data) self.create_lists(df.keys(), df.keys()) self.update_listWidgets() self.push_replot_file.setEnabled(True) division = df[self.last_num_text] / df[self.last_den_text] if self.checkBox_log.checkState() > 0: division[division < 0] = 1 division = np.log(division) if self.checkBox_neg.checkState() > 0: division = -division self.figure_old_scans_3.ax.plot(df['energy'], division) last_trace = self.figure_old_scans_3.ax.get_lines()[ len(self.figure_old_scans_3.ax.get_lines()) - 1] patch = mpatches.Patch( color=last_trace.get_color(), label=data['processing_ret']['metadata']['name']) self.handles_bin.append(patch) self.figure_old_scans_3.ax.legend(handles=self.handles_bin) self.canvas_old_scans_3.draw_idle() def plot_interp_data(self, data): ''' Plot the interpolated data. This will check if the data is a string. ''' df = data['processing_ret']['data'] # TODO : implement this if isinstance(df, str): # load data, it's astring df = self.gen_parser.getInterpFromFile(df) #df = pd.DataFrame.from_dict(json.loads(data['processing_ret']['data'])) df = df.sort_values('energy') self.df = df self.interp_data_sets.append(data) self.create_lists(df.keys(), df.keys()) self.update_listWidgets() self.push_replot_file.setEnabled(True) division = df[self.last_num_text] / df[self.last_den_text] if self.checkBox_log.checkState() > 0: division[division < 0] = 1 division = np.log(division) if self.checkBox_neg.checkState() > 0: division = -division self.figure_old_scans_2.ax.plot(df['energy'], division) last_trace = self.figure_old_scans_2.ax.get_lines()[ len(self.figure_old_scans_2.ax.get_lines()) - 1] patch = mpatches.Patch( color=last_trace.get_color(), label=data['processing_ret']['metadata']['name']) self.handles_interp.append(patch) self.figure_old_scans_2.ax.legend(handles=self.handles_interp) self.canvas_old_scans_2.draw_idle() def erase_plots(self): self.figure_old_scans_2.ax.clear() self.figure_old_scans_2.ax2.clear() self.toolbar_old_scans_2.update() self.canvas_old_scans_2.draw_idle() self.figure_old_scans_2.ax.grid(alpha=0.4) self.figure_old_scans_3.ax.clear() self.figure_old_scans_3.ax2.clear() self.toolbar_old_scans_3.update() self.canvas_old_scans_3.draw_idle() self.figure_old_scans_3.ax.grid(alpha=0.4) def reset_data_plots(self): self.push_replot_file.setEnabled(False) self.listWidget_numerator.clear() self.listWidget_denominator.clear() self.bin_data_sets = [] self.interp_data_sets = [] self.handles_interp = [] self.handles_bin = [] self.df = pd.DataFrame([]) self.erase_plots() def questionMessage(self, title, question): reply = QtWidgets.QMessageBox.question( self, title, question, QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No) if reply == QtWidgets.QMessageBox.Yes: return True elif reply == QtWidgets.QMessageBox.No: return False else: return False
class XsampleGui(*uic.loadUiType(ui_path)): def __init__(self, mfcs = [], total_flow_meter = None, rga_channels = [], rga_masses = [], heater_enable1 = [], ghs = [], RE = [], archiver = [], sample_envs_dict=[], *args, **kwargs): super().__init__(*args, **kwargs) self.setupUi(self) self.addCanvas() self.mfcs = mfcs self.total_flow_meter = total_flow_meter self.rga_channels = rga_channels self.rga_masses = rga_masses self.ghs = ghs self.sample_envs_dict = sample_envs_dict self.RE = RE self.archiver = archiver self.push_visualize_program.clicked.connect(self.visualize_program) self.push_clear_program.clicked.connect(self.clear_program) self.push_start_program.clicked.connect(self.start_program) self.push_pause_program.setChecked(0) self.push_pause_program.toggled.connect(self.pause_program) self.push_stop_program.clicked.connect(self.stop_program) self.pid_program = None self.plot_program_flag = False self.program_plot_moving_flag = True self._plot_program_data = None sample_envs_list = [k for k in self.sample_envs_dict.keys()] self.comboBox_sample_envs.addItems(sample_envs_list) self.comboBox_sample_envs.currentIndexChanged.connect(self.sample_env_selected) self.sample_env_selected() self.gas_mapper = {'1': {0: 0, 4: 1, 2: 4, 3: 2, 1: 3}, '2': {0: 0, 2: 1, 3: 2}, '3': {0: 0, 1: 1, 2: 2}, '4': {0: 0, 1: 2, 2: 1}, '5': {0: 0, 1: 1, 2: 2}, } for indx in range(8): getattr(self, f'checkBox_rga{indx+1}').toggled.connect(self.update_status) for indx, rga_mass in enumerate(self.rga_masses): getattr(self, f'spinBox_rga_mass{indx + 1}').setValue(rga_mass.get()) getattr(self, f'spinBox_rga_mass{indx + 1}').valueChanged.connect(self.change_rga_mass) #initializing mobile cart MFC readings for indx_mfc in range(3): mfc_widget = getattr(self, f'spinBox_cart_mfc{indx_mfc+1}_sp') mfc_widget.setValue(self.mfcs[indx_mfc].sp.get()) mfc_widget.editingFinished.connect(self.set_mfc_cart_flow) for indx_ch in range(2): ch = f'{indx_ch + 1}' # setting outlets for outlet in ['reactor', 'exhaust']: rb_outlet = getattr(self, f'radioButton_ch{indx_ch + 1}_{outlet}') if self.ghs['channels'][f'{indx_ch + 1}'][outlet].get(): rb_outlet.setChecked(True) else: rb_outlet.setChecked(False) getattr(self,f'radioButton_ch{indx_ch+1}_reactor').toggled.connect(self.toggle_exhaust_reactor) getattr(self, f'radioButton_ch{indx_ch+1}_exhaust').toggled.connect(self.toggle_exhaust_reactor) getattr(self, f'radioButton_ch{indx_ch + 1}_bypass1').toggled.connect(self.toggle_bypass_bubbler) getattr(self, f'radioButton_ch{indx_ch + 1}_bypass2').toggled.connect(self.toggle_bypass_bubbler) getattr(self, f'radioButton_ch{indx_ch + 1}_bubbler1').toggled.connect(self.toggle_bypass_bubbler) getattr(self, f'radioButton_ch{indx_ch + 1}_bubbler2').toggled.connect(self.toggle_bypass_bubbler) # set signal handling of gas selector widgets for indx_mnf in range(5): gas_selector_widget = getattr(self,f'comboBox_ch{indx_ch+1}_mnf{indx_mnf+1}_gas') gas = self.ghs['manifolds'][f'{indx_mnf+1}']['gas_selector'].get() gas_selector_widget.setCurrentIndex(self.gas_mapper[f'{indx_mnf+1}'][gas]) gas_selector_widget.currentIndexChanged.connect(self.select_gases) # set signal handling of gas channle enable widgets # rb_outlet.setChecked(True) for indx_mnf in range(8): # going over manifold gas enable checkboxes mnf = f'{indx_mnf + 1}' enable_checkBox = getattr(self, f'checkBox_ch{ch}_mnf{mnf}_enable') #print(f' here is the checkbox {enable_checkBox.objectName()}') #checking if the upstream and downstream valves are open and setting checkbox state upstream_vlv_st = self.ghs['channels'][ch][f'mnf{mnf}_vlv_upstream'].get() dnstream_vlv_st = self.ghs['channels'][ch][f'mnf{mnf}_vlv_dnstream'].get() if upstream_vlv_st and dnstream_vlv_st: enable_checkBox.setChecked(True) else: enable_checkBox.setChecked(False) enable_checkBox.stateChanged.connect(self.toggle_channels) #setting MFC widgets to the PV setpoint values value = self.ghs['channels'][ch][f'mfc{indx_mnf + 1}_sp'].get() mfc_sp_object = getattr(self, f'spinBox_ch{ch}_mnf{indx_mnf + 1}_mfc_sp') mfc_sp_object.setValue(value) mfc_sp_object.editingFinished.connect(self.set_flow_rates) self.timer_update_time = QtCore.QTimer(self) self.timer_update_time.setInterval(2000) self.timer_update_time.timeout.connect(self.update_status) self.timer_update_time.singleShot(0, self.update_status) self.timer_update_time.start() self.timer_sample_env_status = QtCore.QTimer(self) self.timer_sample_env_status.setInterval(500) self.timer_sample_env_status.timeout.connect(self.update_sample_env_status) self.timer_sample_env_status.singleShot(0, self.update_sample_env_status) self.timer_sample_env_status.start() def addCanvas(self): self.figure_rga = Figure() self.figure_rga.set_facecolor(color='#efebe7') self.figure_rga.ax = self.figure_rga.add_subplot(111) self.canvas_rga = FigureCanvas(self.figure_rga) self.toolbar_rga = NavigationToolbar(self.canvas_rga, self) self.layout_rga.addWidget(self.canvas_rga) self.layout_rga.addWidget(self.toolbar_rga) self.canvas_rga.draw() self.figure_mfc = Figure() self.figure_mfc.set_facecolor(color='#efebe7') self.figure_mfc.ax = self.figure_mfc.add_subplot(111) self.canvas_mfc = FigureCanvas(self.figure_mfc) self.toolbar_mfc = NavigationToolbar(self.canvas_mfc, self) self.layout_mfc.addWidget(self.canvas_mfc) self.layout_mfc.addWidget(self.toolbar_mfc) self.canvas_mfc.draw() self.figure_temp = Figure() self.figure_temp.set_facecolor(color='#efebe7') self.figure_temp.ax = self.figure_temp.add_subplot(111) self.canvas_temp = FigureCanvas(self.figure_temp) self.toolbar_temp = NavigationToolbar(self.canvas_temp, self) self.layout_temp.addWidget(self.canvas_temp) self.layout_temp.addWidget(self.toolbar_temp) self.canvas_temp.draw() def sample_env_selected(self): _current_key = self.comboBox_sample_envs.currentText() self.current_sample_env = self.sample_envs_dict[_current_key] self.init_table_widget() def init_table_widget(self): # TODO: make the table length correspond to the max length acceptable by the sample environment self.tableWidget_program.setColumnCount(2) self.tableWidget_program.setRowCount(10) setpoint_name = f'{self.current_sample_env.pv_name}\nsetpoint ({self.current_sample_env.pv_units})' self.tableWidget_program.setHorizontalHeaderLabels(('Time intervals (min)', setpoint_name)) def update_ghs_status(self): # update card MFC setpoints and readbacks for indx_mfc in range(3): mfc_rb_widget = getattr(self, f'spinBox_cart_mfc{indx_mfc + 1}_rb') rb = '{:.1f} sccm'.format(self.mfcs[indx_mfc].rb.get()) mfc_rb_widget.setText(rb) mfc_sp_widget = getattr(self, f'spinBox_cart_mfc{indx_mfc + 1}_sp') st = mfc_sp_widget.blockSignals(True) sp = self.mfcs[indx_mfc].sp.get() if not mfc_sp_widget.hasFocus(): mfc_sp_widget.setValue(sp) mfc_sp_widget.blockSignals(st) # Check if the setpoints and readbacks are close status_label = getattr(self, f'label_cart_mfc{indx_mfc + 1}_status') rb = float(re.findall('\d*\.?\d+', rb)[0]) if sp > 0: error = np.abs((rb - sp) / sp) if error > 0.1: status_label.setStyleSheet('background-color: rgb(255,0,0)') elif error > 0.02: status_label.setStyleSheet('background-color: rgb(255,240,24)') else: status_label.setStyleSheet('background-color: rgb(0,255,0)') else: status_label.setStyleSheet('background-color: rgb(171,171,171)') # Check rector/exhaust status for indx_ch in range(2): for outlet in ['reactor', 'exhaust']: status_label = getattr(self, f'label_ch{indx_ch + 1}_{outlet}_status') if self.ghs['channels'][f'{indx_ch + 1}'][outlet].get(): status_label.setStyleSheet('background-color: rgb(0,255,0)') else: status_label.setStyleSheet('background-color: rgb(255,0,0)') for indx_mnf in range(8): mfc_sp_widget = getattr(self, f'spinBox_ch{indx_ch + 1}_mnf{indx_mnf + 1}_mfc_sp') value = "{:.2f} sccm".format(self.ghs['channels'][f'{indx_ch + 1}'][f'mfc{indx_mnf + 1}_rb'].get()) getattr(self, f'label_ch{indx_ch + 1}_mnf{indx_mnf + 1}_mfc_rb').setText(value) mfc_sp_widget = getattr(self, f'spinBox_ch{indx_ch + 1}_mnf{indx_mnf + 1}_mfc_sp') st = mfc_sp_widget.blockSignals(True) value = self.ghs['channels'][f'{indx_ch + 1}'][f'mfc{indx_mnf + 1}_sp'].get() if not mfc_sp_widget.hasFocus(): mfc_sp_widget.setValue(value) mfc_sp_widget.blockSignals(st) sp = self.ghs['channels'][f'{indx_ch + 1}'][f'mfc{indx_mnf + 1}_sp'].get() rb = self.ghs['channels'][f'{indx_ch + 1}'][f'mfc{indx_mnf + 1}_rb'].get() status_label = getattr(self, f'label_ch{indx_ch + 1}_mnf{indx_mnf + 1}_mfc_status') # Check if the setpoints and readbacks are close if sp > 0: error = np.abs((rb - sp) / sp) if error > 0.1: status_label.setStyleSheet('background-color: rgb(255,0,0)') elif error > 0.02: status_label.setStyleSheet('background-color: rgb(255,240,24)') else: status_label.setStyleSheet('background-color: rgb(0,255,0)') else: status_label.setStyleSheet('background-color: rgb(171,171,171)') for indx_ch in range(2): for indx_mnf in range(8): upstream_valve_label = getattr(self, f'label_ch{indx_ch + 1}_valve{indx_mnf + 1}_status') upstream_valve_status = self.ghs['channels'][f'{indx_ch + 1}'][f'mnf{indx_mnf + 1}_vlv_upstream'].get() if upstream_valve_status == 0: upstream_valve_label.setStyleSheet('background-color: rgb(255,0,0)') else: upstream_valve_label.setStyleSheet('background-color: rgb(0,255,0)') if self.checkBox_total_flow_open.isChecked(): self.total_flow_meter.sp.set(100) self.label_total_flow.setText(f'{str(self.total_flow_meter.get().rb)} sccm') def update_sample_env_status(self): sample_env = self.current_sample_env self.label_pv_rb.setText(f'{sample_env.pv_name} RB: {np.round(sample_env.pv.get(), 2)} {sample_env.pv_units}') self.label_pv_sp.setText(f'{sample_env.pv_name} SP: {np.round(sample_env.pv_sp.get(), 2)} {sample_env.pv_units}') self.label_pv_sp_rate.setText(f'{sample_env.pv_name} SP rate: {np.round(sample_env.ramper.pv_sp_rate.get(), 2)} {sample_env.pv_units}/min') self.label_output_rb.setText(f'Output {sample_env.pv_output_name} RB: {np.round(sample_env.pv_output.get(), 2)} {sample_env.pv_output_units}') if sample_env.enabled.get() == 1: self.label_output_pid_status.setStyleSheet('background-color: rgb(255,0,0)') self.label_output_pid_status.setText('ON') else: self.label_output_pid_status.setStyleSheet('background-color: rgb(171,171,171)') self.label_output_pid_status.setText('OFF') if (sample_env.ramper.go.get() == 1) and (sample_env.ramper.pv_pause.get() == 0): self.label_program_status.setStyleSheet('background-color: rgb(255,0,0)') self.label_program_status.setText('ON') elif (sample_env.ramper.go.get() == 1) and (sample_env.ramper.pv_pause.get() == 1): self.label_program_status.setStyleSheet('background-color: rgb(255,240,24)') self.label_program_status.setText('PAUSED') elif sample_env.ramper.go.get() == 0: self.label_program_status.setStyleSheet('background-color: rgb(171,171,171)') self.label_program_status.setText('OFF') def update_plotting_status(self): now = ttime.time() timewindow = self.doubleSpinBox_timewindow.value() data_format = mdates.DateFormatter('%H:%M:%S') some_time_ago = now - 3600 * timewindow df = self.archiver.tables_given_times(some_time_ago, now) self._df_ = df self._xlim_num = [some_time_ago, now] # handling the xlim extension due to the program vizualization if self.plot_program_flag: if self._plot_program_data is not None: self._xlim_num[1] = np.max([self._plot_program_data['time_s'].iloc[-1], self._xlim_num[1]]) _xlim = [ttime.ctime(self._xlim_num[0]), ttime.ctime(self._xlim_num[1])] masses = [] for rga_mass in self.rga_masses: masses.append(str(rga_mass.get())) update_figure([self.figure_rga.ax], self.toolbar_rga, self.canvas_rga) for rga_ch, mass in zip(self.rga_channels, masses): dataset = df[rga_ch.name] indx = rga_ch.name[-1] if getattr(self, f'checkBox_rga{indx}').isChecked(): # put -5 in the winter, -4 in the summer self.figure_rga.ax.plot(dataset['time'] + timedelta(hours=-4), dataset['data'], label=f'{mass} amu') self.figure_rga.ax.grid(alpha=0.4) self.figure_rga.ax.xaxis.set_major_formatter(data_format) self.figure_rga.ax.set_xlim(_xlim) self.figure_rga.ax.autoscale_view(tight=True) self.figure_rga.ax.set_yscale('log') self.figure_rga.tight_layout() self.figure_rga.ax.legend(loc=6) self.canvas_rga.draw_idle() update_figure([self.figure_temp.ax], self.toolbar_temp, self.canvas_temp) dataset_rb = df['temp2'] dataset_sp = df['temp2_sp'] dataset_sp = self._pad_dataset_sp(dataset_sp, dataset_rb['time'].values[-1]) self.figure_temp.ax.plot(dataset_sp['time'] + timedelta(hours=-4), dataset_sp['data'], label='T setpoint') self.figure_temp.ax.plot(dataset_rb['time'] + timedelta(hours=-4), dataset_rb['data'], label='T readback') self.plot_pid_program() self.figure_temp.ax.grid(alpha=0.4) self.figure_temp.ax.xaxis.set_major_formatter(data_format) self.figure_temp.ax.set_xlim(_xlim) self.figure_temp.ax.set_ylim(self.spinBox_temp_range_min.value(), self.spinBox_temp_range_max.value()) self.figure_temp.ax.autoscale_view(tight=True) self.figure_temp.tight_layout() self.figure_temp.ax.legend(loc=6) self.canvas_temp.draw_idle() def _pad_dataset_sp(self, df, latest_time, delta_thresh=15): _time = df['time'].values _data = df['data'].values n_rows = _time.size idxs = np.where(np.diff(_time).astype(int) * 1e-9 > delta_thresh)[0] + 1 time = [] data = [] for idx in range(n_rows): if idx in idxs: insert_time = (_time[idx] - int(0.05*1.0e9)).astype('datetime64[ns]') time.append(insert_time) data.append(_data[idx-1]) time.append(_time[idx]) data.append(_data[idx]) if (time[-1] - latest_time)<0: time.append(latest_time) data.append(data[-1]) df_out = pd.DataFrame({'time' : time, 'data' : data}) return df_out def update_status(self): if self.checkBox_update.isChecked(): self.update_ghs_status() self.update_plotting_status() def read_program_data(self): table = self.tableWidget_program nrows = table.rowCount() times = [] # intervals sps = [] # setpoints for i in range(nrows): this_time = table.item(i, 0) this_sp = table.item(i, 1) if this_time and this_sp: try: times.append(float(this_time.text())) except: message_box('Error', 'Time must be numerical') raise ValueError('time must be numerical') try: sps.append(float(this_sp.text())) except: message_box('Error', 'Temperature must be numerical') raise ValueError('Temperature must be numerical') times = np.cumsum(times) times = np.hstack((0, np.array(times))) * 60 sps = np.hstack((self.current_sample_env.current_pv_reading(), np.array(sps))) print('The parsed program:') for _time, _sp in zip(times, sps): print('time', _time, '\ttemperature', _sp) self.pid_program = {'times' : times, 'setpoints' : sps} def visualize_program(self): self.read_program_data() self.plot_program_flag = True self.program_plot_moving_flag = True self.update_plot_program_data() self.update_status() def update_plot_program_data(self): if self.pid_program is not None: times = (ttime.time() + self.pid_program['times']) datetimes = [datetime.fromtimestamp(i).strftime('%Y-%m-%d %H:%M:%S') for i in times] self._plot_program_data = pd.DataFrame({'time': pd.to_datetime(datetimes, format='%Y-%m-%d %H:%M:%S'), 'data': self.pid_program['setpoints'], 'time_s' : times}) def plot_pid_program(self): if self.plot_program_flag: if self.program_plot_moving_flag: self.update_plot_program_data() if self._plot_program_data is not None: self.figure_temp.ax.plot(self._plot_program_data['time'], self._plot_program_data['data'], 'k:', label='Program Viz') def clear_program(self): self.tableWidget_program.clear() self.init_table_widget() self.plot_program_flag = False self.program_plot_moving_flag = False self._plot_program_data = None self.pid_program = None self.update_status() def start_program(self): # if self.pid_program is None: # self.read_program_data() self.visualize_program() self.program_plot_moving_flag = False self.current_sample_env.ramp_start(self.pid_program['times'].tolist(), self.pid_program['setpoints'].tolist()) def pause_program(self, value): if value == 1: self.current_sample_env.ramp_pause() else: self.current_sample_env.ramp_continue() def stop_program(self): self.current_sample_env.ramp_stop() def change_rga_mass(self): sender_object = QObject().sender() indx = sender_object.objectName()[-1] self.RE(bps.mv(self.rga_masses[int(indx) - 1], sender_object.value())) def set_mfc_cart_flow(self): sender = QObject() sender_object = sender.sender() sender_name = sender_object.objectName() value = sender_object.value() indx_mfc = int(re.findall(r'\d+', sender_name)[0]) self.mfcs[indx_mfc - 1].sp.set(value) def toggle_exhaust_reactor(self): sender = QObject() sender_object = sender.sender() sender_name = sender_object.objectName() ch_num = sender_name[14] if sender_name.endswith('exhaust') and sender_object.isChecked(): self.ghs['channels'][ch_num]['exhaust'].set(1) ttime.sleep(2) self.ghs['channels'][ch_num]['reactor'].set(0) if sender_name.endswith('reactor') and sender_object.isChecked(): self.ghs['channels'][ch_num]['reactor'].set(1) ttime.sleep(2) self.ghs['channels'][ch_num]['exhaust'].set(0) def toggle_bypass_bubbler(self): sender = QObject() sender_object = sender.sender() sender_name = sender_object.objectName() ch_num = sender_name[14] bypass_num = sender_name[-1] if (sender_name.endswith('bypass1') or sender_name.endswith('bypass2')) and sender_object.isChecked(): self.RE(bps.mv(self.ghs['channels'][ch_num][f'bypass{bypass_num}'], 1)) self.RE(bps.mv(self.ghs['channels'][ch_num][f'bubbler{bypass_num}_1'], 0)) self.RE(bps.mv(self.ghs['channels'][ch_num][f'bubbler{bypass_num}_2'], 0)) elif (sender_name.endswith('bubbler1') or sender_name.endswith('bubbler2')) and sender_object.isChecked(): self.RE(bps.mv(self.ghs['channels'][ch_num][f'bypass{bypass_num}'], 0)) self.RE(bps.mv(self.ghs['channels'][ch_num][f'bubbler{bypass_num}_1'], 1)) self.RE(bps.mv(self.ghs['channels'][ch_num][f'bubbler{bypass_num}_2'], 1)) def select_gases(self): sender = QObject() sender_object = sender.sender() sender_name = sender_object.objectName() gas = sender_object.currentText() #print(sender_name) indx_ch, indx_mnf = re.findall(r'\d+', sender_name) gas_command = self.ghs['manifolds'][indx_mnf]['gases'][gas] # print(f'Gas command {gas_command}') self.ghs['manifolds'][indx_mnf]['gas_selector'].set(gas_command) #change the gas selection for the other widget - they both come from the same source sub_dict = {'1':'2','2':'1'} other_selector = getattr(self, f'comboBox_ch{sub_dict[indx_ch]}_mnf{indx_mnf}_gas') #print(other_selector.objectName()) st = other_selector.blockSignals(True) other_selector.setCurrentIndex(sender_object.currentIndex()) other_selector.blockSignals(st) def toggle_channels(self): sender = QObject() sender_object = sender.sender() sender_name = sender_object.objectName() indx_ch, indx_mnf = re.findall(r'\d+', sender_name) if sender_object.isChecked(): self.ghs['channels'][indx_ch][f'mnf{indx_mnf}_vlv_upstream'].set(1) self.ghs['channels'][indx_ch][f'mnf{indx_mnf}_vlv_dnstream'].set(1) else: self.ghs['channels'][indx_ch][f'mnf{indx_mnf}_vlv_upstream'].set(0) self.ghs['channels'][indx_ch][f'mnf{indx_mnf}_vlv_dnstream'].set(0) def set_flow_rates(self): sender = QObject() sender_object = sender.sender() sender_name = sender_object.objectName() # print(sender_name) indx_ch, indx_mnf = re.findall(r'\d+', sender_name) value = sender_object.value() self.ghs['channels'][indx_ch][f'mfc{indx_mnf}_sp'].set(value)
class Spectrum(QtWidgets.QWidget): def __init__(self, beamline, materials, imageviewer): ''' The Spectrum takes in the instances of beamline, materials, and imageviewer created in main.py. This is to track the variables of inputs to be reflected to the spectrum ''' self.beamline = beamline self.materials = materials self.imageviewer = imageviewer super(Spectrum, self).__init__() self.initUI() def initUI(self): ''' The UI initialization ''' self.setGeometry(100, 100, 800, 600) self.center() grid = QtWidgets.QGridLayout() self.setLayout(grid) ''' Creating buttons to generate the plots. We connect the pressing of the buttons to crossSectionalData and AntonCode function for plotting ''' btn1 = QtWidgets.QPushButton('Plot 1: Cross Section (MeV vs Barns) ', self) btn1.resize(btn1.sizeHint()) btn1.clicked.connect(self.crossSectionalData) grid.addWidget(btn1, 5, 0) btn2 = QtWidgets.QPushButton( 'Plot 2: Spectra (Transmission vs Energy)', self) btn2.resize(btn2.sizeHint()) btn2.clicked.connect(self.AntonCode) grid.addWidget(btn2, 5, 1) self.figure = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.figure) grid.addWidget(self.canvas, 3, 0, 1, 2) #self.show() - UNCOMMENT THIS LINE FOR SELF DEBUGGING def crossSectionalData(self): ''' Obtaining the updated parameter inputs from beamline, materials, and imageviewer ''' self.getUpdatedParameters() ''' Plotting initialization ''' self.figure.clf() ax3 = self.figure.add_subplot(111) ''' The plotting function itself ''' x = [i for i in range(0, len(self.imageviewer.files) - 1) ] #len(self.imageviewer.files) y = [self.sum_image_data[i] for i in x] ax3.plot(x, y, 'r.-') ax3.set_title('Cross Section (MeV vs Barns)') self.canvas.draw_idle() def AntonCode(self): ''' Obtaining the updated parameter inputs from beamline, materials, and imageviewer ''' self.getUpdatedParameters() ''' Plotting initialization - there will be 2 graphs on the window ''' self.figure.clf() ax1 = self.figure.add_subplot(211) ''' The plotting function(s) itself (QuickFit) As we are plotting multiple functions in one graph ''' #TODO: Implemenet Anton's codebase onto the graph using sum_image_data x1 = [i for i in range(200)] y1 = [2 for i in x1] ax1.plot(x1, y1, 'b.-') ax1.set_title("Experimental Spectrum") ax1.set_xlabel( "Energy / Time" ) #Energy, Time, or Wavelength - depending on how the user picks it ax1.set_ylabel("Transmission") ax2 = self.figure.add_subplot(212) x2 = [i for i in range(100) ] #pass the x1, y1 values to here for Anton's method #pass anton's method using the global variable fullParameters y2 = [3 for i in x2] ax2.plot(x2, y2, 'b.-') self.canvas.draw_idle() ax2.set_title('Fitting') ax2.set_xlabel("Energy / Time") ax2.set_ylabel("Transmission") def center(self): qr = self.frameGeometry() cp = QtWidgets.QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def getUpdatedParameters(self): ''' Function that obtains the updated inputs from beamline, materials, and image viewer. We call the saveInput functions for all these instances and that is converted into an array called fullParameters above ''' '''IMAGEVIEWER INPUT''' self.imageviewerInput = self.imageviewer.saveInput() #imageviwerInput = [[xmin, xmax], [ymin, ymax], z, sum_image_data] self.xmin = self.imageviewerInput[0][0] self.xmax = self.imageviewerInput[0][1] self.ymin = self.imageviewerInput[1][0] self.ymax = self.imageviewerInput[1][1] self.z = self.imageviewerInput[2] self.sum_image_data = self.imageviewerInput[3] '''BEAMLINE INPUT''' self.beamlineInput = self.beamline.saveInput() #beamlineInput = [flightPath, delayOnTrigger, [minimumEnergyRange, maximumEnergyRange]] self.flightPath = self.beamlineInput[0] #1 Flight Path: L (meters) self.delayOnTrigger = self.beamlineInput[ 1] #2 Delay on trigger: dT (miliseconds) self.energyRange = self.beamlineInput[ 2] #3 Minimum and Maximum Energy Range (eV) '''MATERIALS INPUT''' self.materialsInput = self.materials.saveInput() #materialsInput is a pandas frame with the structure shown below: ''' Element Name | Abundance | Atomic Mass | Atomic Fraction | Density | Thickness | Component Material 1 Material 2 Material 3 Material 4 Material 5 ''' #where you can access the inputs by selecting the coordinates (e.g. materialsInput[0, 1] would return Materials 1's abundance) #Note that not all 5 materials are used, for this instance the frame element is entered 'NaN' #number of assert statements to make sure user input is as desired #TODO: Create assertion tests to catch edge cases for completeness """
class App(QWidget): NumButtons = ['Clear', 'Routing', 'route_in_batch'] NumTextBox = ['initial', 'end', ''] def __init__(self): super(App, self).__init__() self.title = 'Warehouse Management Syetem' self.left = 10 self.top = 10 self.width = 640 self.height = 480 self.initUI() # order info self.max_x = 20 self.max_y = 10 self.x_init = 0 self.y_init = 0 self.x_end = 0 self.y_end = 20 self.oneorder = [] self.optorder = [] self.ordernum = 0 #if no input then plot the first order def initUI(self): self.setWindowTitle(self.title) self.setGeometry(self.left, self.top, self.width, self.height) #button grid = QGridLayout() self.setLayout(grid) self.createVerticalGroupBox() buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.verticalGroupBox) grid.addLayout(buttonLayout, 7, 0) #plot self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) grid.addWidget(self.canvas, 0, 1, 9, 9) # input initial and end position self.textbox1 = QLineEdit(self) self.textbox1.move(20, 20) self.textbox1.resize(100, 30) self.textbox2 = QLineEdit(self) self.textbox2.move(20, 90) self.textbox2.resize(100, 30) self.textbox3 = QLineEdit(self) self.textbox3.move(20, 160) self.textbox3.resize(100, 30) self.textbox4 = QLineEdit(self) self.textbox4.move(20, 230) self.textbox4.resize(100, 30) # Create a button in the window self.button1 = QPushButton('Set initial', self) self.button1.move(20, 50) self.button2 = QPushButton('Set end', self) self.button2.move(20, 120) self.button3 = QPushButton('One order', self) self.button3.move(20, 190) self.button4 = QPushButton('Order #', self) self.button4.move(20, 260) # connect button to function on_click self.button1.clicked.connect(self.on_click1) self.button2.clicked.connect(self.on_click2) self.button3.clicked.connect(self.enterorder_click) self.button4.clicked.connect(self.enterordernumber_click) self.show() # onclick 1 2 set initial and end position def on_click1(self): x_init, y_init = self.textbox1.text().split(',') self.x_init = int(x_init) self.y_init = int(y_init) print('initial x: ', self.x_init, ', y: ', self.y_init) def on_click2(self): x_end, y_end = self.textbox2.text().split(',') self.x_end = int(x_end) self.y_end = int(y_end) print('end point x: ', self.x_end, ', y: ', self.y_end) def enterorder_click(self): self.oneorder = self.textbox3.text().split('\t') print('one order entered:', self.oneorder) def enterordernumber_click(self): self.optorder = [] self.ordernum = int(self.textbox4.text()) print('one order with order number:', self.ordernum) # read in optimized store file line = linecache.getline("optimized2500_1.csv", (self.ordernum - 1) * 8 + 5) line1 = line.rstrip('\n').split('\t') line1 = line1[1:] print(line1) for ele in line1: self.optorder.append(int(ele)) print(self.optorder) def createVerticalGroupBox(self): self.verticalGroupBox = QGroupBox() layout = QVBoxLayout() for i in self.NumButtons: button = QPushButton(i) button.setObjectName(i) layout.addWidget(button) layout.setSpacing(10) self.verticalGroupBox.setLayout(layout) button.clicked.connect(self.submitCommand) def submitCommand(self): eval('self.' + str(self.sender().objectName()) + '()') def Clear(self): #rack position self.figure.clf() ax1 = self.figure.add_subplot(111) for i in range(1, 40, 2): y = [e for e in range(1, 20, 2)] ax1.plot(i * np.ones(len(y)), y, 's', markersize=4) axes1 = plt.gca() axes1.set_ylim([-1, 21]) axes1.set_xlim([-1, 41]) ax1.set_title('Rack Position') self.canvas.draw_idle() def Routing(self): # ax2 = self.figure.add_subplot(111) axes2 = plt.gca() axes2.set_ylim([-1, 21]) axes2.set_xlim([-1, 41]) ax2.set_title('Routing') #process one order if self.oneorder == [] or self.x_init == None or self.y_init == None or self.x_end == None or self.y_init == None: self.x_init = 0 self.y_init = 0 self.x_end = 0 self.y_end = 20 self.oneorder = [181202, 328595, 276157, 296188, 8140, 208299] #[1,45,74] x_temp = self.x_init y_temp = self.y_init oneorder = [] for elem in self.oneorder: oneorder.append(int(elem)) org, origl, opt, min = singleOrder(pathgraph, oneorder, self.x_init, self.y_init, self.x_end, self.y_init) print(org, opt) for item in opt: if item not in loc_dict: print("id not exist") return -1 pro_x = loc_dict[item][0] # x,y coordinates of products pro_y = loc_dict[item][1] if self.x_init < pro_x: des_x = pro_x - 1 # shorter to take from left path of the rack des_y = pro_y # if pro_x == 0: # des_x = pro_x + 1 #can only take from right since its the boundary, say wall # des_y = pro_y # if the product position is west to the current position i.e. init_x > prod_x elif self.x_init > pro_x: des_x = pro_x + 1 # shorter to take from right path of the rack des_y = pro_y # if pro_x == 20: # des_x = pro_x - 1 #can only take from left since its the boundary, say wall # des_y = pro_y else: des_x = self.x_init des_y = pro_y min, traversedpoint = locdistance(pathgraph, des_x, des_y, self.x_init, self.y_init) data = np.array(traversedpoint) plt.plot(data[:, 0], data[:, 1]) self.x_init = des_x self.y_init = des_y min, traversedpoint = locdistance(pathgraph, self.x_end, self.y_end, self.x_init, self.y_init) #to end point data = np.array(traversedpoint) plt.plot(data[:, 0], data[:, 1]) self.x_init = x_temp self.y_init = y_temp #draw order path self.canvas.draw_idle() def route_in_batch(self): ax3 = self.figure.add_subplot(111) axes3 = plt.gca() axes3.set_ylim([-1, 21]) axes3.set_xlim([-1, 41]) ax3.set_title( 'Draw optimized route according to order number in csv file') opt = self.optorder x_temp = self.x_init y_temp = self.y_init for item in opt: if item not in loc_dict: print("id not exist") return -1 pro_x = loc_dict[item][0] # x,y coordinates of products pro_y = loc_dict[item][1] if self.x_init < pro_x: des_x = pro_x - 1 # shorter to take from left path of the rack des_y = pro_y # if pro_x == 0: # des_x = pro_x + 1 #can only take from right since its the boundary, say wall # des_y = pro_y # if the product position is west to the current position i.e. init_x > prod_x elif self.x_init > pro_x: des_x = pro_x + 1 # shorter to take from right path of the rack des_y = pro_y # if pro_x == 20: # des_x = pro_x - 1 #can only take from left since its the boundary, say wall # des_y = pro_y else: des_x = self.x_init des_y = pro_y min, traversedpoint = locdistance(pathgraph, des_x, des_y, self.x_init, self.y_init) data = np.array(traversedpoint) plt.plot(data[:, 0], data[:, 1]) self.x_init = des_x self.y_init = des_y min, traversedpoint = locdistance(pathgraph, self.x_end, self.y_end, self.x_init, self.y_init) #to end point data = np.array(traversedpoint) plt.plot(data[:, 0], data[:, 1]) self.x_init = x_temp self.y_init = y_temp #draw order path # data = np.array([[1, 2], [2, 4], [3, 5], [4, 5]]) # plt.plot(data[:, 0], data[:, 1]) # B = nx.Graph() # B.add_nodes_from([1, 2, 3, 4], bipartite=0) # B.add_nodes_from(['a', 'b', 'c', 'd', 'e'], bipartite=1) # B.add_edges_from([(1, 'a'), (2, 'c'), (3, 'd'), (3, 'e'), (4, 'e'), (4, 'd')]) # # X = set(n for n, d in B.nodes(data=True) if d['bipartite'] == 0) # Y = set(B) - X # # X = sorted(X, reverse=True) # Y = sorted(Y, reverse=True) # # pos = dict() # pos.update((n, (1, i)) for i, n in enumerate(X)) # put nodes from X at x=1 # pos.update((n, (2, i)) for i, n in enumerate(Y)) # put nodes from Y at x=2 # nx.draw(B, pos=pos, with_labels=True) self.canvas.draw_idle()
class GraphWidget(QWidget): def __init__(self, parent, trigger): self.trigger = trigger super(GraphWidget, self).__init__(parent) self.initUI() def initUI(self): self.setGeometry(10, 10, 505, 476) self.vector = None self.node1 = None self.node2 = None vbox = QVBoxLayout() self.setLayout(vbox) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.mpl_connect('button_press_event', self.onclick) self.canvas.mpl_connect('button_release_event', self.onRelease) vbox.addWidget(self.canvas) def draw(self): self.plotGraph() self.show() def export(self): if self.vector != None: self.figure.savefig((self.vector.vectorName + "_Graph.png"), format="PNG") def initializeHelperNodes(self): helperNodeCounter = -1 for i in range(self.vector.vectorDimensions): self.vectorGraph.add_nodes_from([helperNodeCounter]) self.pos[helperNodeCounter] = (i, 0) helperNodeCounter -= 1 self.vectorGraph.add_nodes_from([helperNodeCounter]) self.pos[helperNodeCounter] = (i, 2) helperNodeCounter -= 1 def initializeVector(self, vector): self.vectorGraph = nx.DiGraph() self.vector = vector self.pos = dict() self.initializeHelperNodes() for significantEventId, significantEvent in vector.significantEvents.items( ): self.vectorGraph.add_nodes_from([significantEventId]) self.pos[significantEventId] = significantEvent.position for relationship in list(vector.relationships.values()): self.vectorGraph.add_edges_from([ (relationship.sourceSignificantEventId, relationship.destSignificantEventId) ]) def onclick(self, event): self.node1 = (event.xdata, event.ydata) threshold = 0.10 for key, value in self.vector.significantEvents.items(): xValueDifference = max(value.position[0], self.node1[0]) - min( value.position[0], self.node1[0]) yValueDifference = max(value.position[1], self.node1[1]) - min( value.position[1], self.node1[1]) if xValueDifference <= threshold and yValueDifference <= threshold: self.node1 = {key: self.node1} break def onRelease(self, event): self.node2 = (event.xdata, event.ydata) threshold = 0.10 for key, value in self.vector.significantEvents.items(): xValueDifference = max(value.position[0], self.node2[0]) - min( value.position[0], self.node2[0]) yValueDifference = max(value.position[1], self.node2[1]) - min( value.position[1], self.node2[1]) if xValueDifference <= threshold and yValueDifference <= threshold: self.node2 = {key: self.node2} break if type(self.node2) is not dict and type(self.node1) is dict: node_name = list(self.node1.keys())[0] self.pos[node_name] = (event.xdata, event.ydata) self.vector.significantEvents[node_name].position = (event.xdata, event.ydata) elif type(self.node2) is dict and type(self.node1) is dict: firstNodeName = list(self.node1.keys())[0] secondNodeName = list(self.node2.keys())[0] if firstNodeName != secondNodeName: self.vectorGraph.add_edges_from([(firstNodeName, secondNodeName)]) self.vector.addNewRelationship(firstNodeName, secondNodeName) self.trigger.emit_trigger() else: pass node_sizes = list() for _ in range(len(list(self.pos.keys()))): node_sizes.append(2000) self.node1 = None self.node2 = None self.plotGraph() def plotGraph(self): self.figure.clf() node_sizes = list() node_colors = list() for i in range(len(list(self.pos.keys()))): node_sizes.append(2000) if i < (2 * self.vector.vectorDimensions): node_colors.append("white") else: node_colors.append("blue") nx.draw(self.vectorGraph, node_size=node_sizes, node_color=node_colors, pos=self.pos, with_labels=True, font_color="white") self.canvas.draw_idle() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
class BrowseGraphWidget(BrowseWidget): """ Большой виджет, отвечающий за работу с графом зависимостей. """ # region ToDO # большие фичи интерфейса: # ToDo поиск # ToDo правильный перебор результатов, если они были показаны через контекстное меню в списке, проблема с нулевым индексом # ToDo перенос позиции в результате в класс SearchResult? (чтобы правильно показывать номер позиции в надписи на панели поиска) # ToDo невозможность вызвать контекстное меню на точке отсчета в списке # ToDo спрятанная вершина со спрятанным родителем тоже должна исчезнуть # структура кода: # Область отображения: # ToDo узнать, можно ли добавить зум и другие плюшки # ToDo надо увеличить размер области рисования, чтобы она занимала всё окно # дополнения # ToDo выводить количество объектов в списке в виде Объектов: *, отображается: * # ToDo всплывающие подсказки для кнопок # на будущее # ToDo экспорт графа в другие форматы # endregion def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.current_history_pos = 0 self.pov_history = [] layout = QtWidgets.QVBoxLayout() self.setLayout(layout) self.splitter = QtWidgets.QSplitter() self.layout().addWidget(self.splitter) self._init_draw_area() self._init_control_panel() self._init_node_context_menu() # region initializers def _init_draw_area(self): self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.splitter.addWidget(self.canvas) def _init_control_panel(self): # Панель управления отображением графа и содержащая список объектов. self.control_panel = QtWidgets.QWidget() self.control_panel.setLayout(QtWidgets.QVBoxLayout()) # виджеты панели управления self._init_pov_panel() self._init_dependencies_panel() self._init_list_control_panel() self._init_node_list() self.splitter.addWidget(self.control_panel) def _init_pov_panel(self): # панель для вывода точки отсчёта (point of view) # и перехода между точками отсчёта вперёд-назад grid = QtWidgets.QGridLayout() grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 4) grid.setColumnStretch(2, 1) grid.setColumnStretch(3, 1) grid.setColumnStretch(4, 1) grid.setColumnStretch(5, 1) # иконка точки отсчёта self.pov_icon = QtWidgets.QLabel() grid.addWidget(self.pov_icon, 0, 0) # имя точки отсчёта self.pov_label = QtWidgets.QLabel() grid.addWidget(self.pov_label, 0, 1) # стрелки # в начало self.pov_first = QtWidgets.QPushButton() self.pov_first.setIcon(IconCollection.pixmaps["begin"]) grid.addWidget(self.pov_first, 0, 2) # назад self.pov_back = QtWidgets.QPushButton() self.pov_back.setIcon(IconCollection.pixmaps["back"]) grid.addWidget(self.pov_back, 0, 3) # вперёд self.pov_forward = QtWidgets.QPushButton() self.pov_forward.setIcon(IconCollection.pixmaps["forward"]) grid.addWidget(self.pov_forward, 0, 4) # в конец self.pov_last = QtWidgets.QPushButton() self.pov_last.setIcon(IconCollection.pixmaps["end"]) grid.addWidget(self.pov_last, 0, 5) self.pov_first.clicked.connect( lambda: self._change_pov(self.pov_first)) self.pov_back.clicked.connect(lambda: self._change_pov(self.pov_back)) self.pov_forward.clicked.connect( lambda: self._change_pov(self.pov_forward)) self.pov_last.clicked.connect(lambda: self._change_pov(self.pov_last)) groupbox = QtWidgets.QGroupBox("Точка отсчёта") groupbox.setLayout(grid) groupbox.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) self.control_panel.layout().addWidget(groupbox) def _init_node_context_menu(self): self.node_context_menu = QtWidgets.QMenu() self.node_action_set_pov = QtWidgets.QAction( IconCollection.icons["new_pov"], "Сделать точкой отсчёта") self.node_action_set_pov.triggered.connect(self._switch_to_new_pov) self.node_action_hide = QtWidgets.QAction( IconCollection.icons["invisible"], "Скрыть") self.node_action_hide.triggered.connect(self._hide_node) self.node_action_show = QtWidgets.QAction( IconCollection.icons["visible"], "Показать") self.node_action_show.triggered.connect(self._show_node) self.node_action_rollup = QtWidgets.QAction( IconCollection.icons["invisible"], "Свернуть") self.node_action_rollup.triggered.connect(self._hide_node) self.node_action_expand = QtWidgets.QAction( IconCollection.icons["visible"], "Развернуть") self.node_action_expand.triggered.connect(self._show_node) def _init_dependencies_panel(self): # панель управления подгрузкой зависимостей grid = QtWidgets.QGridLayout() grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 1) grid.setColumnStretch(2, 1) grid.setColumnStretch(3, 4) lb_up = QtWidgets.QLabel("Вверх") lb_down = QtWidgets.QLabel("Вниз") self.spb_up = QtWidgets.QSpinBox() self.spb_down = QtWidgets.QSpinBox() self.spb_up.setRange(0, 100) self.spb_down.setRange(0, 100) self.spb_up.setValue(0) self.spb_down.setValue(3) self.chb_up = QtWidgets.QCheckBox("До конца") self.chb_down = QtWidgets.QCheckBox("До конца") self.bt_load = QtWidgets.QPushButton("Загрузить") self.bt_load.clicked.connect(self._reload_dependencies) grid.addWidget(lb_up, 0, 0) grid.addWidget(self.spb_up, 0, 1) grid.addWidget(self.chb_up, 0, 2) grid.addWidget(lb_down, 1, 0) grid.addWidget(self.spb_down, 1, 1) grid.addWidget(self.chb_down, 1, 2) grid.addWidget(self.bt_load, 0, 3, 2, 1) panel = QtWidgets.QWidget() panel.setLayout(grid) panel.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) self.control_panel.layout().addWidget(panel) def _init_list_control_panel(self): # панель управления списком объектов (поиск и группировка) lb_search = QtWidgets.QLabel("Поиск:") self.le_search = QtWidgets.QLineEdit() self.le_search.returnPressed.connect(self._handle_search) self.chb_grouping = QtWidgets.QCheckBox("Группировка") self.chb_grouping.stateChanged.connect(self._toggle_grouping) self.bt_next_result = QtWidgets.QPushButton() self.bt_next_result.setIcon(IconCollection.pixmaps["down"]) self.bt_next_result.clicked.connect(self._move_to_next_search_result) self.bt_prev_result = QtWidgets.QPushButton() self.bt_prev_result.clicked.connect( self._move_to_previous_search_result) self.bt_prev_result.setIcon(IconCollection.pixmaps["up"]) self.search_result_text = QtWidgets.QLabel("") self.bt_show_hidden_results = QtWidgets.QPushButton("Показать скрытое") self.bt_show_hidden_results.clicked.connect(self._show_hidden_results) self.bt_show_hidden_results.setVisible(False) grid = QtWidgets.QGridLayout() grid.setColumnStretch(0, 1) grid.setColumnStretch(1, 8) grid.setColumnStretch(2, 1) grid.setColumnStretch(3, 1) grid.setColumnStretch(4, 5) grid.setColumnStretch(5, 2) grid.addWidget(lb_search, 0, 0) grid.addWidget(self.le_search, 0, 1) grid.addWidget(self.bt_next_result, 0, 2) grid.addWidget(self.bt_prev_result, 0, 3) grid.addWidget(self.search_result_text, 0, 4) grid.addWidget(self.bt_show_hidden_results, 0, 5) grid.addWidget(self.chb_grouping, 1, 0, 1, 2) panel = QtWidgets.QWidget() panel.setLayout(grid) panel.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) self.control_panel.layout().addWidget(panel) def _init_node_list(self): """ Инициализирует виджеты, отвечающие за вывод списка вершин графа. При включении группировки ставится дерево, при отключении - таблица. """ self.node_list = QtWidgets.QStackedWidget() self.tree_view = QtWidgets.QTreeView() self.tree_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.tree_view.customContextMenuRequested.connect( self._show_node_context_menu) self.table_view = QtWidgets.QTableView() self.table_view.setSelectionMode( QtWidgets.QAbstractItemView.SingleSelection) self.table_view.setSelectionBehavior( QtWidgets.QAbstractItemView.SelectRows) self.table_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.table_view.customContextMenuRequested.connect( self._show_node_context_menu) self.table_view.horizontalHeader().hide() self.table_view.verticalHeader().hide() self.node_list.addWidget(self.tree_view) self.node_list.addWidget(self.table_view) self.node_list.setCurrentIndex(self.node_list.indexOf(self.table_view)) self.control_panel.layout().addWidget(self.node_list) self.number_of_nodes = QtWidgets.QLabel(f"Объектов: ") self.control_panel.layout().addWidget(self.number_of_nodes) # endregion # region utility methods def _show_node_context_menu(self, position): self.node_context_menu.clear() chosen_index = self._active_view.selectionModel().selectedRows()[0] model = self._active_view.model() status = int( model.data( model.index(chosen_index.row(), NodeListColumns.STATUS_COLUMN, chosen_index.parent()))) node_id = int( model.data( model.index(chosen_index.row(), NodeListColumns.ID_COLUMN, chosen_index.parent()))) is_blind = bool( int( model.data( model.index(chosen_index.row(), NodeListColumns.BLIND_COLUMN, chosen_index.parent())))) # для точки отсчёта контекстное меню не выводится if node_id == self.state.pov_id: return self.node_context_menu.addAction(self.node_action_set_pov) # в зависимости от статуса ноды и наличия загруженных потомков # определяем пункты контекстного меню, которые будут # показаны пользователю if status == NodeStatus.VISIBLE: if is_blind: self.node_context_menu.addAction(self.node_action_hide) else: self.node_context_menu.addAction(self.node_action_rollup) elif status == NodeStatus.ROLLED_UP: self.node_context_menu.addAction(self.node_action_expand) # выводим меню self.node_context_menu.exec_( self.table_view.viewport().mapToGlobal(position)) def _process_row_selection(self): chosen_index = self._active_view.selectionModel().currentIndex() model = self._active_view.model() node_id = model.data( model.index(chosen_index.row(), NodeListColumns.ID_COLUMN, chosen_index.parent())) # на выбор стрелки в дереве не реагируем if node_id is None: self._set_selected_node(None) else: node_id = int(node_id) self._set_selected_node(self._storage.get_node_by_id(node_id)) def _set_table_model(self, model): """ Устанавливает табличную модель для виджета со списком вершин графа. """ self.table_view.setModel(model) for column in range(len(NodeListColumns.structure)): self.table_view.setColumnWidth( column, NodeListColumns.structure[column]["width"]) self.table_view.setColumnHidden( column, NodeListColumns.structure[column]["hidden"]) def _set_tree_model(self, model): """ Устанавливает древовидную модель для виджета со списком вершин графа. """ self.tree_view.setModel(model) def _prepare_view(self): # прячем в списке те объекты, которые были скрыты автоматически table_model = self.table_view.model() for row in range(table_model.rowCount()): self.table_view.setRowHidden( row, int( table_model.index(row, NodeListColumns.STATUS_COLUMN).data()) == NodeStatus.AUTO_HIDDEN) # деревянная модель tree_model = self.tree_view.model() stack = [] parent = QtCore.QModelIndex() stack.append(parent) while len(stack) > 0: parent = stack.pop() row = parent.row() # читаем статус вершины, чтобы понять, надо ли прятать её потомков status = tree_model.index(row, NodeListColumns.STATUS_COLUMN, parent.parent()).data() status = int(status) if status is not None else None if tree_model.hasChildren(parent) == False: continue if status in (NodeStatus.ROLLED_UP, NodeStatus.AUTO_HIDDEN): # если вершина спрятана, то прячем её потомков for child_row in range(tree_model.rowCount(parent)): self.tree_view.setRowHidden(child_row, parent, True) else: for child_row in range(tree_model.rowCount(parent)): self.tree_view.setRowHidden(child_row, parent, False) # если нода является видимой в списке, то обрабатываем # её потомков for child_row in range(tree_model.rowCount(parent=parent)): stack.append(tree_model.index(child_row, 0, parent)) self.number_of_nodes.setText( f"Объектов: {self.state.number_of_nodes_in_list}") def _read_graph_from_history(self): """ Читает граф из текущей позиции в истории, заполняет значения виджетов значениями из атрибутов графа и выводит граф в области для отображения. """ self._set_table_model(self.state.table_model) self._set_tree_model(self.state.tree_model) self.chb_grouping.setChecked(self.state.grouping) self._prepare_view() # считываем из текущего графа параметры загрузки зависимостей # и ставим их в элементы управления на форме self.chb_down.setChecked(self.state.reached_bottom_limit) self.chb_up.setChecked(self.state.reached_upper_limit) self.spb_down.setValue(self.state.levels_down) self.spb_up.setValue(self.state.levels_up) # количество объектов (под списком) self.number_of_nodes.setText( f"Объектов: {self.state.number_of_nodes_in_list}") # иконка pov-вершины self.pov_icon.setPixmap( IconCollection.get_pixmap_for_node_class( self.state.pov_node_class)) self.pov_label.setText(self.state.pov_node_label) self._draw_current_graph() def _reload_dependencies(self): """ Подгружает уровни зависимости объекта, изменяет текущий граф, изменяет модели для отображения списка в виде таблицы или дерева. """ levels_up = self.spb_up.value() levels_down = self.spb_down.value() QtGui.QGuiApplication.setOverrideCursor(QtGui.Qt.BusyCursor) self.state.load_dependencies(levels_up, levels_down) self._read_graph_from_history() self._draw_current_graph() QtGui.QGuiApplication.restoreOverrideCursor() def _draw_current_graph(self): """ Отображает текущий граф в области для рисования. """ self.figure.clf() self.state.show_graph() self.canvas.draw_idle() def _change_pov(self, button): """ движение по истории точек отсчёта в зависимости от того, какая кнопка была нажата, двигается вперёд, назад, в начало или в конец; если достигнуто начало истории просмотров, то кнопки "в начало" и "назад" выключаются, если достигнут конец, то выключаются кнопки "Вперёд" и "в конец". """ if button == self.pov_first: self.current_history_pos = 0 elif button == self.pov_back: self.current_history_pos -= 1 elif button == self.pov_forward: self.current_history_pos += 1 elif button == self.pov_last: self.current_history_pos = (len(self.pov_history) - 1) self._toggle_pov_navigation_buttons() self._read_graph_from_history() def _toggle_pov_navigation_buttons(self): not_begin = (self.current_history_pos != 0) not_end = (self.current_history_pos != (len(self.pov_history) - 1)) self.pov_first.setEnabled(not_begin) self.pov_back.setEnabled(not_begin) self.pov_forward.setEnabled(not_end) self.pov_last.setEnabled(not_end) def _toggle_grouping(self): """ Переключает группировку, подменяя виджеты и устанавливая активное представление """ if self.chb_grouping.isChecked(): index = self.node_list.indexOf(self.tree_view) else: index = self.node_list.indexOf(self.table_view) self.node_list.setCurrentIndex(index) self.state.set_grouping_enagled(self.chb_grouping.isChecked()) def _handle_search(self): search_term = self.le_search.text().strip() if search_term == "": QtWidgets.QMessageBox.about(self, "Ошибка", "Введите критерий поиска") return if search_term != self.state.last_search_request: self.state.last_search_request = search_term self.le_search.setText(self.state.last_search_request) self.state.do_search() self._update_search_result() self._focus_on_current_search_result() def _focus_on_current_search_result(self): if not self.state.has_iterable_search_result: return self.search_result_text.setText(str(self.state.search_result)) index = self.state.search_result.get_current_match() self.table_view.selectRow(index.row()) self.table_view.scrollTo(index, QtWidgets.QTableView.PositionAtCenter) def _move_to_next_search_result(self): if not self.state.has_iterable_search_result: return self.state.search_result.to_next() self._focus_on_current_search_result() def _move_to_previous_search_result(self): if not self.state.has_iterable_search_result: return self.state.search_result.to_previous() self._focus_on_current_search_result() def _update_search_result(self): if self.state.search_result is not None: self.search_result_text.setText(str(self.state.search_result)) self.bt_show_hidden_results.setVisible( self.state.search_result.has_hidden) def _show_hidden_results(self): self.state.show_hidden_search_results() self._prepare_view() self._draw_current_graph() def _bind_selection_signals(self): self.table_view.selectionModel().selectionChanged.connect( self._process_row_selection) self.tree_view.selectionModel().selectionChanged.connect( self._process_row_selection) def _switch_to_new_pov(self): self._make_new_pov(self.selected_node) def _make_new_pov(self, pov_node): self.observed_node = pov_node new_point = HistoryPoint(self._storage, pov_node, grouping=self.chb_grouping.isChecked()) self.pov_history.append(new_point) self.current_history_pos = len(self.pov_history) - 1 self._toggle_pov_navigation_buttons() self._set_dependencies_loading_levels() self._reload_dependencies() self._bind_selection_signals() def _hide_node(self): index = self._active_view.selectionModel().currentIndex() self.state.hide_node(index) self._prepare_view() self._draw_current_graph() self._update_search_result() def _show_node(self): index = self._active_view.selectionModel().currentIndex() self.state.show_node(index) self._prepare_view() self._draw_current_graph() self._update_search_result() def _set_dependencies_loading_levels(self): """ По типу ноды определяем рекомендуемое количество уровней зависимостей для загрузки, выставляем виджеты управления в соответствующее положение. """ up, down = self.observed_node.get_recommended_loading_depth() if up == float("inf"): self.chb_up.setChecked(True) else: self.spb_up.setValue(up) if down == float("inf"): self.chb_down.setChecked(True) else: self.spb_down.setValue(down) # endregion # region properties @property def _active_view(self): if self.chb_grouping.isChecked(): return self.tree_view else: return self.table_view @property def state(self): return None if len(self.pov_history) == 0 else self.pov_history[ self.current_history_pos] # endregion # region public methods def query_node_data(self, node): if self._storage is None: return self._make_new_pov(node)
class PrettyWidget(QWidget): def __init__(self, network_info, components_possitions): super(PrettyWidget, self).__init__() font = QFont() font.setPointSize(16) self.network_info = network_info self.height = int(components_possitions["dimensions"]["height"]) self.width = int(components_possitions["dimensions"]["width"]) self.possitions = components_possitions["components"] self.initUI() def initUI(self): self.setGeometry(100, 100, self.height, self.width) self.center() self.setWindowTitle('Network Plot') grid = QGridLayout() self.setLayout(grid) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) grid.addWidget(self.canvas, 0, 2, 9, 9) # Create network graph from network informations g = make_network(self.network_info, self.possitions, self.height, self.width) self.network_info.add_graph(g) # Make subgraph consisting of user components user = [ "\n".join(comp.name.split("_")) for comp in self.network_info.user_components ] user_g = nx.subgraph(g, user) # Create scrollbar with buttons for getting user components informations # Add scrollbar to the left side of the grid self.createVerticalGroupBox(user) buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.verticalGroupBox) grid.addLayout(buttonLayout, 0, 0, 6, 2) # Plot network node_pos = { node[0]: (node[1]['X'], -node[1]['Y']) for node in g.nodes(data=True) } edge_col = [e[2]['attr_dict']['color'] for e in g.edges(data=True)] nx.draw_networkx(g, pos=node_pos, edge_color=edge_col, node_size=500, alpha=.99, node_color='red', with_labels=True, bbox=dict(facecolor="skyblue", edgecolor='black', boxstyle='round,pad=0.2'), node_shape='h') nx.draw_networkx(user_g, pos=node_pos, edge_color=edge_col, node_size=100, alpha=.99, node_color='blue', with_labels=True, bbox=dict(facecolor="r", edgecolor='black', boxstyle='round,pad=0.2'), node_shape='s') labels = nx.get_edge_attributes(g, 'num_connections') plt.title('Network', size=15) plt.axis("off") self.showMaximized() self.canvas.draw_idle() # Create new scrollbar, at the top of the scrollbar add label to describe the actions # For every node in graph, add button to get informations about that node def createVerticalGroupBox(self, graph): scrolllayout = QVBoxLayout() info_label = QLabel() info_label.setAlignment(Qt.AlignCenter) info_label.setText("Press the button to get\ncomponent informations") scrolllayout.addWidget(info_label) scrollwidget = QWidget() scrollwidget.setLayout(scrolllayout) self.verticalGroupBox = QScrollArea() self.verticalGroupBox.setWidgetResizable( True) # Set to make the inner widget resize with scroll area self.verticalGroupBox.setWidget(scrollwidget) for i in graph: i = "_".join(i.split("\n")) groupbox = QPushButton(i) groupbox.setObjectName(i) scrolllayout.addWidget(groupbox) groupbox.clicked.connect(self.submitCommand) # Create popup window, set window size and show the popup def create_popout(self, component): self.exPopup = popupWidget(component) self.exPopup.show() #build and plot network def submitCommand(self): caller_name = self.sender().text() for component in self.network_info.get_components(): if caller_name == component.name: # create_popup(component) self.create_popout(component) break # Possition widget at the center of the screen def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) self.show()
class Ui(QtWidgets.QMainWindow): def __init__(self): super(Ui, self).__init__() uic.loadUi('modus.ui', self) self.setWindowTitle( 'Автоматическая детекция гломерул обонятельной луковицы') self.button = self.findChild(QtWidgets.QPushButton, 'pushButton') self.button_exp = self.findChild(QtWidgets.QPushButton, 'pushButton_2') self.button_file = self.findChild(QtWidgets.QPushButton, 'pushButton_3') self.file = QtWidgets.QFileDialog.getOpenFileName( self, "Выберите файл", None, filter="(*.png *.jpg *.tiff)")[0] log.info(self.file) if not self.file: rep = QtWidgets.QMessageBox.question( self, 'Предупреждение', 'Вы не выбрали файл. Выбрать снова?', QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.Yes) if rep == QtWidgets.QMessageBox.Yes: self.open_file() else: return # Порог self.input_2 = self.findChild(QtWidgets.QDoubleSpinBox, 'doubleSpinBox_2') # Размер self.input_x = self.findChild(QtWidgets.QDoubleSpinBox, 'doubleSpinBox') # label self.label_max = self.findChild(QtWidgets.QLabel, 'label_3') self.label_min = self.findChild(QtWidgets.QLabel, 'label_4') # ver self.lab_ver = self.findChild(QtWidgets.QLabel, 'label_5') self.lab_ver.setText(version) self.fig = Figure(figsize=(10, 4), dpi=100) self.axes = self.fig.add_subplot(131) self.axes1 = self.fig.add_subplot(132) self.axes2 = self.fig.add_subplot(133) self.plot = FigureCanvas(self.fig) self.lay = QtWidgets.QVBoxLayout(self.graph) self.lay.setContentsMargins(0, 0, 0, 0) self.lay.addWidget(self.plot) self.button_exp.clicked.connect(self.export_csv) self.button.clicked.connect(self.update_chart) self.button_file.clicked.connect(self.open_file) self.addToolBar(QtCore.Qt.TopToolBarArea, NT(self.plot, self)) self.update_chart() def open_file(self): self.file = QtWidgets.QFileDialog.getOpenFileName( self, "Выберите файл", filter="(*.png *.jpg *.tiff)")[0] if len(self.file) > 0: self.update_chart() else: return def update_chart(self): rz_x = float(self.input_x.text().replace(',', '.')) img, contours, y_t, x_t, parametr_p, mkm_width, caff, centroids = self.f_dir( p=float(self.input_2.text().replace(',', '.')), rz_x=rz_x, file=self.file) self.axes.cla() self.axes1.cla() self.axes2.cla() self.axes.set_title('Центроиды') self.axes1.set_title('Оригинал') self.axes2.set_title('Контуры - {}'.format(parametr_p)) self.axes.imshow(img) self.axes1.imshow(img) self.axes.scatter(y_t, x_t, s=5, c='red') self.axes2.scatter(y_t, x_t, s=5, c='red') self.axes.set_xlabel('px', fontsize=8) self.axes.set_ylabel('px', fontsize=8) self.axes1.set_xlabel('px', fontsize=8) self.axes1.set_ylabel('px', fontsize=8) self.axes2.set_xlabel('px', fontsize=8) self.axes2.set_ylabel('px', fontsize=8) # длина вектора по координатам # AB = sqrt (bx - ax)^2 + (by-ay)^2 DD_vector = [] for n, contour in enumerate(contours): A_Xmin = min(contour[:, 0]) A_Ymax = max(contour[:, 1]) B_Xmax = max(contour[:, 0]) B_Ymin = min(contour[:, 1]) D_vector = pow((B_Xmax - A_Xmin), 2) + pow( (B_Ymin - A_Ymax), 2) - 1 # D_vector = math.sqrt(D_vector) * caff DD_vector.append(D_vector) self.axes2.plot(contour[:, 1], contour[:, 0], linewidth=2, color='red') log.info("cont === %s", DD_vector) self.axes2.invert_yaxis() self.fig.tight_layout() self.plot.draw_idle() def export_csv(self): rz_x = float(self.input_x.text().replace(',', '.')) img, contours, y_t, x_t, parametr_p, rz_x, rz_y, centroids = self.f_dir( p=float(self.input_2.text().replace(',', '.')), rz_x=rz_x, file=self.file) df = [] for c in contours: for k in c: df.append(k) pd.DataFrame(df, columns=['X', 'Y']).to_excel('contours.xlsx', index=False) pd.DataFrame(centroids, columns=['X', 'Y']).to_excel('centroids.xlsx') def km(self, img, number, g, parametr_p, rz_x): x = g[0] y = g[1] # Если имеется массив центроидов if len(x) > 0 and len(y) > 0: x_t = [] y_t = [] mkm_width, caff = self.rz(1214.6, img, rz_x) # zip (..., ..., img[x, y]) z = [list(hhh) for hhh in zip(x, y)] # elbow method # model = KMeans() # vis = KElbowVisualizer(model, k=(1, 15)) # vis.fit(np.array(z)) # # k = KMeans(n_clusters=vis.elbow_value_).fit(z) af = MeanShift().fit(z) arrayp = [[0]] * len(af.cluster_centers_) for d, c in enumerate(arrayp): kkk = [] for i, m in enumerate(af.labels_): if m == d: kkk.append(z[i]) arrayp[d] = np.array(kkk) hhhhh = len(af.cluster_centers_) DD_vector = [] for n, aaa in enumerate(arrayp): A_Xmin = min(aaa[:, 0]) A_Ymax = max(aaa[:, 1]) B_Xmax = max(aaa[:, 0]) B_Ymin = min(aaa[:, 1]) D_vector = pow((B_Xmax - A_Xmin), 2) + pow( (B_Ymin - A_Ymax), 2) D_vector = math.sqrt(D_vector) * caff DD_vector.append(D_vector) if D_vector <= rz_x: g = aaa[:].tolist() z = [s for s in z if s not in g] img[aaa[:, 0], aaa[:, 1]] = 0 # hhhhh = hhhhh - 1 log.info("img === %s --- centroid === %s ---- cenhhhh ==== %s", DD_vector, len(af.cluster_centers_), hhhhh) # self.label_max.text() contours = measure.find_contours(img, number) # for n, contour in enumerate(contours): # self.axes2.plot(contour[:, 1], contour[:, 0], linewidth=2) if len(z) > 0: x_t = list(af.cluster_centers_[:, 0]) y_t = list(af.cluster_centers_[:, 1]) else: self.label_max.setText('Заданный размер слишком высок') log.info('Параметр порога - {}'.format(parametr_p)) return img, contours, y_t, x_t, parametr_p, mkm_width, caff, af.cluster_centers_ else: log.info("Не можем определить центроиды") def rz(self, mkm, img, rz_x): iw, ih = img.shape[0], img.shape[1] # поиск сколько приходится на 1 пиксель мкм caff = mkm / iw mkm_width = round(caff * rz_x) return mkm_width, caff def f_dir(self, p, rz_x, file): log.info('Поиск центроидов начат') # ЧБ image = color.rgb2gray(io.imread(file)) # pltt.clf() # pltt.imshow(image) # pltt.savefig('1.png') # pltt.clf() # np.savetxt('g.csv', image, delimiter=',', fmt='%.5f') # calculate # fast = image.max() - p # load raze = image <= p image = np.where(raze, 0, image) gosh = np.where(image >= p) fig = self.km(image, number=p, g=gosh, parametr_p=p, rz_x=rz_x) log.info('Поиск центроидов окончен') return fig
class UI_MainWindow(QWidget): def __init__(self): super(UI_MainWindow, self).__init__() font = QFont() font.setPointSize(18) self.initialize_UI() # below sets up the UI def initialize_UI(self): self.the_graph = nx.Graph() self.setGeometry(100, 100, 1000, 800) self.setWindowTitle('Edgeucation') self.center() self.grid = QGridLayout() self.setLayout(self.grid) self.createVerticalBox() # self.createMenu() buttonBunch = QVBoxLayout() buttonBunch.addWidget(self.verticalButtonBox) consoleWidgetMaybe = createConsole(self) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.grid.addWidget(self.canvas, 0, 1, 11, 10) self.grid.addLayout(buttonBunch, 0, 0) self.grid.addWidget(consoleWidgetMaybe['widget'], 11, 1, 12, 10) self.color_map = [1000] self.houseGraphPlotTest() self.show() def createTabBox(self): """ Creates a menu consisting of 2 tabs of buttons. This is where most of the functionality of the program will be accessed from :return: """ self.tabBox = QTabWidget() self.tabBox.setObjectName("tabBox") self.tab1 = QWidget() self.tab1.setObjectName("tab1") self.tab2 = QWidget() self.tab2.setObjectName("tab2") self.tabBox.addTab(self.tab1, "") def createVerticalBox(self): self.verticalButtonBox = QGroupBox() layout = QVBoxLayout() self.addButtons(layout) def addButtons(self, layout): self.redrawGraphButton(layout) self.addNodeButton(layout) self.delNodeButton(layout) self.addEdgeButton(layout) self.delEdgeButton(layout) self.addPathButton(layout) self.trivialGraphButton(layout) self.pathGraphButton(layout) self.houseGraphButton(layout) self.regularGraphButton(layout) self.completeGraphButton(layout) self.exportGraphButton(layout) # Below defines the various buttons, each followed by their functional method def redrawGraphButton(self, layout): button = QPushButton('Redraw Graph') button.setObjectName("ButtonRedrawGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.redrawGraphNormal) def addNodeButton(self, layout): button = QPushButton('Add Node') button.setObjectName("ButtonAddNode") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.addNodeToGraph) def addNodeToGraph(self): self.figure.clf() if nx.is_empty(self.the_graph): self.the_graph.add_node(0) # self.color_map[0] = 'blue' self.the_graph.add_node(list(self.the_graph.nodes)[-1] + 1) # self.color_map[list(self.the_graph.nodes)[-1]] = 'blue' nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def delNodeButton(self, layout): button = QPushButton('Del Node') button.setObjectName("ButtonDelNode") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.removeNodeFromGraph) def removeNodeFromGraph(self): if nx.is_empty(self.the_graph): return i, okPressed = QInputDialog.getInt(self, "Node to delete", "Delete which node?", list(self.the_graph.nodes)[0], list(self.the_graph.nodes)[0], list(self.the_graph.nodes)[-1], 1) if okPressed: self.figure.clf() try: self.the_graph.remove_node(i) except: pass nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def addEdgeButton(self, layout): button = QPushButton('Add Edge') button.setObjectName("ButtonAddEdge") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.addEdgeToGraph) def addEdgeToGraph(self): i, okPressed = QInputDialog.getInt(self, "First Node", "Start at which node?", 0, 0, list(self.the_graph.nodes)[-1] + 1, 1) j, okPressed2 = QInputDialog.getInt(self, "Second Node", "End at which node?", 0, 0, list(self.the_graph.nodes)[-1] + 2, 1) if okPressed and okPressed2: self.figure.clf() self.the_graph.add_edge(i, j) nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def delEdgeButton(self, layout): button = QPushButton('Del Edge') button.setObjectName("ButtonDelEdge") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.removeEdgeFromGraph) def removeEdgeFromGraph(self): if nx.is_empty(self.the_graph): return i, okPressed = QInputDialog.getInt(self, "First Node", "Start at which node?", list(self.the_graph.nodes)[0], list(self.the_graph.nodes)[0], list(self.the_graph.nodes)[-1], 1) j, okPressed2 = QInputDialog.getInt(self, "Second Node", "End at which node?", list(self.the_graph.nodes)[0], list(self.the_graph.nodes)[0], list(self.the_graph.nodes)[-1], 1) if okPressed and okPressed2: self.figure.clf() try: self.the_graph.remove_edge(i, j) except: pass nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def addPathButton(self, layout): button = QPushButton('Add Path') button.setObjectName("ButtonAddPath") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.addPathToGraph) def addPathToGraph(self): i, okPressed = QInputDialog.getInt(self, "Path Generation", "How many nodes in path?", 1, 1, 100, 1) if okPressed: nodesToPath = [] j, okPressed2 = QInputDialog.getInt( self, "Path Generation", "First node in path", 0, 0, list(self.the_graph.nodes)[-1] + 1, 1) nodesToPath.append(j) for k in range(1, i): q, okPressed3 = QInputDialog.getInt( self, "Path Generation", "Next node in path", 0, 0, list(self.the_graph.nodes)[-1] + i, 1) if okPressed3: nodesToPath.append(q) self.figure.clf() for n in range(1, len(nodesToPath)): self.the_graph.add_edge(nodesToPath[n], nodesToPath[n - 1]) nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def trivialGraphButton(self, layout): button = QPushButton('Trivial Graph') button.setObjectName("ButtonTrivialGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.trivialGraph) def trivialGraph(self): self.figure.clf() self.the_graph = nx.trivial_graph() nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def pathGraphButton(self, layout): button = QPushButton('Path Graph') button.setObjectName("ButtonPathGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.pathGraph) def pathGraph(self): i, okPressed = QInputDialog.getInt(self, "Path Graph", "How many nodes in the path?", 1, 1, 2000, 1) if okPressed: self.figure.clf() self.the_graph = nx.path_graph(i) nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def houseGraphButton(self, layout): button = QPushButton('House Graph') button.setObjectName("ButtonHouseGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.houseGraphPlotTest) def regularGraphButton(self, layout): #TODO button = QPushButton('Regular Graph') button.setObjectName("ButtonRegularGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.regularGraph) def regularGraph(self): i, okPressed = QInputDialog.getInt(self, "Regular Graph", "How many nodes in the graph?", 1, 1, 2000, 1) j, okPressed2 = QInputDialog.getInt(self, "Regular Graph", "Regularity:", 0, 0, i - 1, 1) if okPressed and okPressed2: self.figure.clf() try: self.the_graph = nx.random_regular_graph(j, i) except: pass nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def completeGraphButton(self, layout): #TODO button = QPushButton('Complete Graph') button.setObjectName("ButtonCompleteGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.completeGraph) def completeGraph(self): i, okPressed = QInputDialog.getInt(self, "Complete Graph", "How many nodes in the graph?", 1, 1, 2000, 1) if okPressed: self.figure.clf() self.the_graph = nx.complete_graph(i) nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def exportGraphButton(self, layout): button = QPushButton('Export Graph to .png') button.setObjectName("ButtonExportGraph") layout.addWidget(button) layout.setSpacing(10) self.verticalButtonBox.setLayout(layout) button.clicked.connect(self.exportGraph) def exportGraph(self): plt.savefig("ExportedGraph.png", format="PNG") # below are some utility methods def center(self): """ When the app is opened, this will make sure it is center-screen :return: """ qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft()) def houseGraphPlotTest(self): """ Creates a simple house graph then draws it to the canvas. This method is intended for testing purposes. :return: """ self.figure.clf() self.the_graph = nx.house_graph() nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle() def redrawGraphNormal(self): """ clears the canvas, then draws the_graph with basic parameters :return: """ self.figure.clf() nx.draw(self.the_graph, with_labels=True) self.canvas.draw_idle()
class GraphWidget(QWidget): MINIMUM_NODE_SIZE = 1000 STARTING_NODE_SIZE = 2000 MAXIMUM_NODE_SIZE = 5000 MINIMUM_ICON_SIZE = 0.07 STARTING_ICON_SIZE = 0.1 MAXIMUM_ICON_SIZE = 0.15 MINIMUM_FONT_SIZE = 10 STARTING_FONT_SIZE = 12 MAXIMUM_FONT_SIZE = 20 def __init__(self, parent, trigger, clientHandler=None, mutable=True): super(GraphWidget, self).__init__(parent) self.trigger = trigger self.clientHandler = clientHandler if mutable: self.initUI() else: self.initImmutableUI() def initUI(self): self.vector = None self.node1 = None self.node2 = None self.axis1 = None self.axis2 = None self.nodeSize = GraphWidget.STARTING_NODE_SIZE self.fontSize = GraphWidget.STARTING_FONT_SIZE self.iconSize = GraphWidget.STARTING_ICON_SIZE self.iconMapping = dict() self.axisMapping = dict() self.vbox = QVBoxLayout() self.setLayout(self.vbox) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.canvas.mpl_connect('button_press_event', self.onclick) self.canvas.mpl_connect('button_release_event', self.onRelease) self.vbox.addWidget(self.canvas) def initImmutableUI(self): self.vector = None self.nodeSize = GraphWidget.STARTING_NODE_SIZE self.fontSize = GraphWidget.STARTING_FONT_SIZE self.iconSize = GraphWidget.STARTING_ICON_SIZE self.iconMapping = dict() self.axisMapping = dict() self.vbox = QVBoxLayout() self.setLayout(self.vbox) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.vbox.addWidget(self.canvas) def draw(self): self.plotGraph() self.show() def initializeHelperNodes(self): helperNodeCounter = -1 for i in range(self.vector.vectorDimensions): self.vectorGraph.add_nodes_from([helperNodeCounter]) self.pos[helperNodeCounter] = (i, 0) self.nodeLabels[helperNodeCounter] = "" helperNodeCounter -= 1 self.vectorGraph.add_nodes_from([helperNodeCounter]) self.pos[helperNodeCounter] = (i, 2) self.nodeLabels[helperNodeCounter] = "" helperNodeCounter -= 1 def createNodeLabel(self, significantEvent): nodeLabel = " ID: " + str(significantEvent.id) if self.vector.visibility["Name"]: nodeLabel += "\n Name: " + significantEvent.name if self.vector.visibility["Description"]: nodeLabel += "\n Description: " + significantEvent.description if self.vector.visibility["Artifact"]: nodeLabel += "\n Artifact: " + significantEvent.logEntry.artifact if self.vector.visibility["Timestamp"]: nodeLabel += "\n Timestamp: " + significantEvent.logEntry.date if self.vector.visibility["Event Creator"]: nodeLabel += "\n Creator: " + significantEvent.logEntry.creator if self.vector.visibility["Event Type"]: nodeLabel += "\n Type: " + significantEvent.logEntry.eventType return nodeLabel def initializeVector(self, vector): self.vectorGraph = nx.DiGraph() self.vector = vector self.pos = dict() self.nodeLabels = dict() self.iconLabels = dict() self.axisMapping = dict() self.iconMapping = dict() self.edgeLabels = dict() self.invisibleSignificantEvents = set() self.initializeHelperNodes() for significantEventId, significantEvent in vector.significantEvents.items(): if significantEvent.visible: if significantEvent.iconType != Icon.DEFAULT: self.iconMapping[significantEventId] = significantEvent.icon self.iconLabels[significantEventId] = self.createNodeLabel(significantEvent) self.nodeLabels[significantEventId] = "" else: self.nodeLabels[significantEventId] = self.createNodeLabel(significantEvent) self.vectorGraph.add_node(significantEventId) self.pos[significantEventId] = significantEvent.position else: self.invisibleSignificantEvents.add(significantEventId) for relationship in list(vector.relationships.values()): if relationship.sourceSignificantEventId in self.invisibleSignificantEvents or relationship.destSignificantEventId in self.invisibleSignificantEvents: continue self.vectorGraph.add_edges_from([(relationship.sourceSignificantEventId, relationship.destSignificantEventId)]) self.edgeLabels[(relationship.sourceSignificantEventId, relationship.destSignificantEventId)] = relationship.description def onclick(self, event): self.node1 = (event.xdata, event.ydata) self.axis1 = event.inaxes if self.axis1 in self.axisMapping: self.node1 = {self.axisMapping[self.axis1] : self.pos[self.axisMapping[self.axis1]]} return threshold = 0.10 for key, value in self.vector.significantEvents.items(): xValueDifference = max(value.position[0], self.node1[0]) - min(value.position[0], self.node1[0]) yValueDifference = max(value.position[1], self.node1[1]) - min(value.position[1], self.node1[1]) if xValueDifference <= threshold and yValueDifference <= threshold: self.node1 = {key : self.node1} break def onRelease(self, event): self.node2 = (event.xdata, event.ydata) self.axis2 = event.inaxes threshold = 0.10 if self.axis2 not in self.axisMapping: for key, value in self.vector.significantEvents.items(): xValueDifference = max(value.position[0], self.node2[0]) - min(value.position[0], self.node2[0]) yValueDifference = max(value.position[1], self.node2[1]) - min(value.position[1], self.node2[1]) if xValueDifference <= threshold and yValueDifference <= threshold: self.node2 = {key: self.node2} break if type(self.node2) is not dict and type(self.node1) is dict: node_name = list(self.node1.keys())[0] self.pos[node_name] = (event.xdata, event.ydata) self.vector.significantEvents[node_name].position = (event.xdata, event.ydata) self.clientHandler.vectorManager.storeVectors() if self.clientHandler.isLead: self.clientHandler.updateVector(self.vector) elif type(self.node2) is dict and type(self.node1) is dict: firstNodeName = list(self.node1.keys())[0] secondNodeName = list(self.node2.keys())[0] if firstNodeName != secondNodeName: self.vectorGraph.add_edges_from([(firstNodeName, secondNodeName)]) self.vector.addNewRelationship(firstNodeName, secondNodeName) self.trigger.emitRelationshipTableTrigger() else: pass else: self.node2 = {self.axisMapping[self.axis2] : self.pos[self.axisMapping[self.axis2]]} firstNodeName = list(self.node1.keys())[0] secondNodeName = list(self.node2.keys())[0] if firstNodeName != secondNodeName: self.vectorGraph.add_edges_from([(firstNodeName, secondNodeName)]) self.vector.addNewRelationship(firstNodeName, secondNodeName) self.clientHandler.vectorManager.storeVectors() if self.clientHandler.isLead: self.clientHandler.updateVector(self.vector) self.trigger.emitRelationshipTableTrigger() self.axis1 = None self.axis2 = None self.node1 = None self.node2 = None self.plotGraph() def plotGraph(self): self.nodeSizes = list() self.nodeColors = list() for i in list(self.pos.keys()): if i < 0: self.nodeColors.append("white") self.nodeSizes.append(self.STARTING_NODE_SIZE) else: if i in self.iconMapping: self.nodeColors.append("white") elif self.vector.significantEvents[i].logEntry.creator == LogEntry.WHITE_TEAM: self.nodeColors.append("grey") elif self.vector.significantEvents[i].logEntry.creator == LogEntry.BLUE_TEAM: self.nodeColors.append("cyan") elif self.vector.significantEvents[i].logEntry.creator == LogEntry.RED_TEAM: self.nodeColors.append("red") self.nodeSizes.append(self.nodeSize) self.paint() def paint(self): self.figure.clf() nx.draw(self.vectorGraph, node_size=self.nodeSizes, node_color=self.nodeColors, pos=self.pos, font_color="black") nx.draw_networkx_labels(self.vectorGraph, pos=self.pos, labels=self.nodeLabels, font_size=self.fontSize) nx.draw_networkx_edge_labels(self.vectorGraph, pos=self.pos, edge_labels=self.edgeLabels, font_size=self.fontSize) if len(self.iconMapping) > 0: ax = plt.gca() fig = plt.gcf() trans = ax.transData.transform trans2 = fig.transFigure.inverted().transform iconSize = self.iconSize for node in self.vectorGraph: if node in self.iconMapping: (x, y) = self.pos[node] xx, yy = trans((x, y)) xa, ya = trans2((xx, yy)) a = plt.axes([xa - iconSize/2, ya - iconSize/2, iconSize, iconSize]) self.axisMapping[a] = node a.imshow(self.iconMapping[node].graphImage) a.text(0, 0, self.iconLabels[node], fontsize=self.fontSize) a.set_aspect('equal') a.axis('off') ax.axis('off') self.canvas.draw_idle() def maximize(self): if self.vector: self.nodeSize = (self.nodeSize + 300) if self.nodeSize < GraphWidget.MAXIMUM_NODE_SIZE else GraphWidget.MAXIMUM_NODE_SIZE self.fontSize = (self.fontSize + 1) if self.fontSize < GraphWidget.MAXIMUM_FONT_SIZE else GraphWidget.MAXIMUM_FONT_SIZE self.iconSize = (self.iconSize + 0.01) if self.iconSize < GraphWidget.MAXIMUM_ICON_SIZE else GraphWidget.MAXIMUM_ICON_SIZE self.plotGraph() def minimize(self): if self.vector: self.nodeSize = (self.nodeSize - 300) if self.nodeSize > GraphWidget.MINIMUM_NODE_SIZE else GraphWidget.MINIMUM_NODE_SIZE self.fontSize = (self.fontSize - 1) if self.fontSize > GraphWidget.MINIMUM_FONT_SIZE else GraphWidget.MINIMUM_FONT_SIZE self.iconSize = (self.iconSize - 0.01) if self.iconSize > GraphWidget.MINIMUM_ICON_SIZE else GraphWidget.MINIMUM_ICON_SIZE self.plotGraph()
class PrettyWidget(QWidget): NumButtons = ['Subplots', 'QuickestPath', 'MostLikelyPath'] def __init__(self): super(PrettyWidget, self).__init__() font = QFont() font.setPointSize(16) self.initUI() def initUI(self): self.setGeometry(100, 100, 800, 600) self.center() self.setWindowTitle('Network Plot') grid = QGridLayout() self.setLayout(grid) self.createVerticalGroupBox() buttonLayout = QVBoxLayout() buttonLayout.addWidget(self.verticalGroupBox) self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) grid.addWidget(self.canvas, 0, 1, 9, 9) grid.addLayout(buttonLayout, 0, 0) g = makeNetwork() # Plot network node_pos = {node[0]: (node[1]['X'], -node[1]['Y']) for node in g.nodes(data=True)} edge_col = [e[2]['color'] for e in g.edges(data=True)] nx.draw_networkx(g, pos=node_pos, arrows=True, edge_color=edge_col, node_size=2200, alpha=.85, node_color='c', with_labels=True) labels = nx.get_edge_attributes(g, 'num_connections') nx.draw_networkx_edge_labels( g, pos=node_pos, edge_labels=labels, font_color='black', alpha=.2) plt.title('Matt\'s Life', size=15) plt.axis("off") def makeSubplot(name): self.figure.clf() gsub = subgraph(name) node_pos = {node[0]: (node[1]['X'], -node[1]['Y']) for node in gsub.nodes(data=True)} edge_col = [e[2]['color'] for e in gsub.edges(data=True)] nx.draw_networkx(gsub, pos=node_pos, arrows=True, edge_color=edge_col, node_size=2200, alpha=.85, node_color='c', with_labels=True) labels = nx.get_edge_attributes(gsub, 'num_connections') nx.draw_networkx_edge_labels( gsub, pos=node_pos, edge_labels=labels, font_color='black', alpha=.2) plt.title('Matt\'s Life:\n filtered by \'' + name + '\'', size=15) plt.axis("off") self.canvas.draw_idle() def onclick(event): clickX = event.x clickY = event.y # Default event if 93 < clickX < 162 and 427 < clickY < 488: makeSubplot('home') elif 286 < clickX < 354 and 353 < clickY < 423: makeSubplot('ht') elif 529 < clickX < 595 and 437 < clickY < 501: makeSubplot('work') elif 479 < clickX < 551 and 65 < clickY < 137: makeSubplot('coffee') elif 225 < clickX < 295 and 149 < clickY < 220: makeSubplot('daycare') # Making cid an attribute will allow for easy pass through functions self.cid = self.figure.canvas.mpl_connect( 'button_press_event', onclick) self.canvas.draw_idle() def createVerticalGroupBox(self): self.verticalGroupBox = QGroupBox() layout = QVBoxLayout() for i in self.NumButtons: button = QPushButton(i) button.setObjectName(i) layout.addWidget(button) layout.setSpacing(10) self.verticalGroupBox.setLayout(layout) button.clicked.connect(self.submitCommand) def submitCommand(self): eval('self.' + str(self.sender().objectName()) + '()') # build and plot network def Subplots(self): self.figure.clf() # this will allow us to override the existing click command self.figure.canvas.mpl_disconnect(self.cid) g = makeNetwork() # Plot network node_pos = {node[0]: (node[1]['X'], -node[1]['Y']) for node in g.nodes(data=True)} edge_col = [e[2]['color'] for e in g.edges(data=True)] nx.draw_networkx(g, pos=node_pos, arrows=True, edge_color=edge_col, node_size=2200, alpha=.85, node_color='c', with_labels=True) labels = nx.get_edge_attributes(g, 'num_connections') nx.draw_networkx_edge_labels( g, pos=node_pos, edge_labels=labels, font_color='black', alpha=.2) plt.title('Matt\'s Life', size=15) plt.axis("off") def makeSubplot(name): self.figure.clf() gsub = subgraph(name) node_pos = {node[0]: (node[1]['X'], -node[1]['Y']) for node in gsub.nodes(data=True)} edge_col = [e[2]['color'] for e in gsub.edges(data=True)] nx.draw_networkx(gsub, pos=node_pos, arrows=True, edge_color=edge_col, node_size=2200, alpha=.85, node_color='c', with_labels=True) labels = nx.get_edge_attributes(gsub, 'num_connections') nx.draw_networkx_edge_labels( gsub, pos=node_pos, edge_labels=labels, font_color='black', alpha=.2) plt.title('Matt\'s Life:\n filtered by \'' + name + '\'', size=15) plt.axis("off") self.canvas.draw_idle() def onclick(event): clickX = event.x clickY = event.y if 93 < clickX < 162 and 427 < clickY < 488: makeSubplot('home') elif 286 < clickX < 354 and 353 < clickY < 423: makeSubplot('ht') elif 529 < clickX < 595 and 437 < clickY < 501: makeSubplot('work') elif 479 < clickX < 551 and 65 < clickY < 137: makeSubplot('coffee') elif 225 < clickX < 295 and 149 < clickY < 220: makeSubplot('daycare') # Making cid an attribute will allow for easy pass through functions self.cid = self.figure.canvas.mpl_connect( 'button_press_event', onclick) self.canvas.draw_idle() def QuickestPath(self): # this will allow us to override the existing click command self.figure.canvas.mpl_disconnect(self.cid) # Load Data g = makeNetwork() def plotNet(g): self.figure.clf() # Plot network node_pos = {node[0]: (node[1]['X'], -node[1]['Y']) for node in g.nodes(data=True)} edge_col = [e[2]['color'] for e in g.edges(data=True)] nx.draw_networkx(g, pos=node_pos, arrows=True, edge_color=edge_col, node_size=2200, alpha=.85, node_color='c', with_labels=True) labels = nx.get_edge_attributes(g, 'num_connections') nx.draw_networkx_edge_labels( g, pos=node_pos, edge_labels=labels, font_color='black', alpha=.2) plt.title('Matt\'s Life', size=15) plt.axis("off") self.canvas.draw_idle() plotNet(g) # startNodeTracker keeps track of if the click is giving a start node or a destination node self.startNodeTracker = True self.startNode = '' def onclick(event): clickX = event.x clickY = event.y if(self.startNodeTracker): # reset graph plotNet(g) # automatically switch the tracker. Revert later if bad input self.startNodeTracker = False if 93 < clickX < 162 and 427 < clickY < 488: self.startNode = 'home' elif 286 < clickX < 354 and 353 < clickY < 423: self.startNode = 'ht' elif 529 < clickX < 595 and 437 < clickY < 501: self.startNode = 'work' elif 479 < clickX < 551 and 65 < clickY < 137: self.startNode = 'coffee' elif 225 < clickX < 295 and 149 < clickY < 220: self.startNode = 'daycare' # This statement reverts the startNodeTracker if the click did not yield usable input else: self.startNodeTracker = True else: # automatically switch the tracker. Revert later if bad input self.startNodeTracker = True if 93 < clickX < 162 and 427 < clickY < 488: endNode = 'home' elif 286 < clickX < 354 and 353 < clickY < 423: endNode = 'ht' elif 529 < clickX < 595 and 437 < clickY < 501: endNode = 'work' elif 479 < clickX < 551 and 65 < clickY < 137: endNode = 'coffee' elif 225 < clickX < 295 and 149 < clickY < 220: endNode = 'daycare' # This statement reverts the startNodeTracker if the click did not yield usable input else: self.startNodeTracker = False # If user's click was on a destination node if(self.startNodeTracker): gnew = makeNetwork() fastest = nx.shortest_path( gnew, source=self.startNode, target=endNode, weight='ave_time') for i in range(len(fastest)-1): gnew[fastest[i]][fastest[i+1] ]['color'] = 'midnightblue' plotNet(gnew) self.cid = self.figure.canvas.mpl_connect( 'button_press_event', onclick) self.canvas.draw_idle() def MostLikelyPath(self): # this will allow us to override the existing click command self.figure.canvas.mpl_disconnect(self.cid) # Load Data g = makeNetwork() def plotNet(g): self.figure.clf() # Plot network node_pos = {node[0]: (node[1]['X'], -node[1]['Y']) for node in g.nodes(data=True)} edge_col = [e[2]['color'] for e in g.edges(data=True)] nx.draw_networkx(g, pos=node_pos, arrows=True, edge_color=edge_col, node_size=2200, alpha=.85, node_color='c', with_labels=True) labels = nx.get_edge_attributes(g, 'num_connections') nx.draw_networkx_edge_labels( g, pos=node_pos, edge_labels=labels, font_color='black', alpha=.2) plt.title('Matt\'s Life', size=15) plt.axis("off") self.canvas.draw_idle() plotNet(g) # startNodeTracker keeps track of if the click is giving a start node or a destination node self.startNodeTracker = True self.startNode = '' def onclick(event): clickX = event.x clickY = event.y if (self.startNodeTracker): # reset graph plotNet(g) # automatically switch the tracker. Revert later if bad input self.startNodeTracker = False if 93 < clickX < 162 and 427 < clickY < 488: self.startNode = 'home' elif 286 < clickX < 354 and 353 < clickY < 423: self.startNode = 'ht' elif 529 < clickX < 595 and 437 < clickY < 501: self.startNode = 'work' elif 479 < clickX < 551 and 65 < clickY < 137: self.startNode = 'coffee' elif 225 < clickX < 295 and 149 < clickY < 220: self.startNode = 'daycare' # This statement reverts the startNodeTracker if the click did not yield usable input else: self.startNodeTracker = True else: # automatically switch the tracker. Revert later if bad input self.startNodeTracker = True if 93 < clickX < 162 and 427 < clickY < 488: endNode = 'home' elif 286 < clickX < 354 and 353 < clickY < 423: endNode = 'ht' elif 529 < clickX < 595 and 437 < clickY < 501: endNode = 'work' elif 479 < clickX < 551 and 65 < clickY < 137: endNode = 'coffee' elif 225 < clickX < 295 and 149 < clickY < 220: endNode = 'daycare' # This statement reverts the startNodeTracker if the click did not yield usable input else: self.startNodeTracker = False # If user's click was on a destination node if (self.startNodeTracker): gnew = makeNetwork() mostLikely = nx.shortest_path( gnew, source=self.startNode, target=endNode, weight='weight') for i in range(len(mostLikely) - 1): gnew[mostLikely[i]][mostLikely[i + 1] ]['color'] = 'midnightblue' plotNet(gnew) self.cid = self.figure.canvas.mpl_connect( 'button_press_event', onclick) self.canvas.draw_idle() def center(self): qr = self.frameGeometry() cp = QDesktopWidget().availableGeometry().center() qr.moveCenter(cp) self.move(qr.topLeft())
class AppWindow(QMainWindow): def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.set_callback() self.show() self.figure = plt.figure() self.canvas = FigureCanvas(self.figure) self.ui.figure_layout.addWidget(self.canvas) self.ax = self.figure.add_subplot(111) def set_callback(self): self.ui.write_data.clicked.connect(self.read_message) self.ui.te_wave.clicked.connect(self.set_module_TE) self.ui.tm_wave.clicked.connect(self.set_module_TM) self.ui.reflection_coefficient.clicked.connect( self.set_curve_Mode_reflective) self.ui.transmission_coefficient.clicked.connect( self.set_curve_Mode_transmission) def read_message(self): global medium_original, level_number, frequency, miu, ebuxiro, d_each_level medium_original = np.array( self.ui.textEdit_medium_matrix.toPlainText()) level_number = self.ui.line_edit_level_number.text() frequency = self.ui.line_edit_frequency.text() # print(medium_original) medium_original_replace_space = str(medium_original).replace( " ", "").replace("\n", "") medium_matrix = re.findall(r"\d+\.?\d*", medium_original_replace_space) # print(medium_matrix) if (len(medium_matrix) == 0 or len(level_number) == 0 or len(frequency) == 0): self.show_message('请输入正确电磁参数。') return print(medium_matrix) level_number = int(level_number) frequency = int(frequency) if len(medium_matrix) != level_number * 3: self.show_message('请输入正确电磁参数。') return for i in range(level_number): miu.append(float(medium_matrix[i * 3])) ebuxiro.append(float(medium_matrix[i * 3 + 1])) d_each_level.append(float(medium_matrix[1 * 3 + 2])) self.caculate() def caculate(self): global R_TE_current, R_TM_current, T_TE_current, T_TM_current, Z_n1 f = frequency pi = 3.1416 theta1 = np.arange(1, 90) theta = theta1 / 360 * 2 * pi w = f / (2 * pi) k_x = np.sqrt(w**2 * miu[0] * ebuxiro[0]) * np.sin(theta) k_iz = [] for i in range(0, level_number): k_i = np.sqrt(w**2 * miu[i] * ebuxiro[i]) k_iz.append(np.sqrt(k_i**2 - k_x**2)) R_TE = [] T_TE = [] R_TM = [] T_TM = [] for i in range(0, level_number - 1): R_TE.append((miu[i + 1] * k_iz[i] - miu[i] * k_iz[i + 1]) / (miu[i + 1] * k_iz[i] + miu[i] * k_iz[i + 1])) T_TE.append((2 * miu[i + 1] * k_iz[i]) / (miu[i + 1] * k_iz[i] + miu[i] * k_iz[i + 1])) R_TM.append((ebuxiro[i + 1] * k_iz[i] - ebuxiro[i] * k_iz[i + 1]) / (ebuxiro[i + 1] * k_iz[i] + ebuxiro[i] * k_iz[i + 1])) T_TM.append((2 * ebuxiro[i + 1] * k_iz[i]) / (ebuxiro[i + 1] * k_iz[i] + ebuxiro[i] * k_iz[i + 1])) if i == 0: R_TE_current = R_TE[0] R_TM_current = R_TM[0] T_TE_current = T_TE[0] T_TM_current = T_TM[0] continue R_TE_current = (R_TE[i] + R_TE_current * np.exp( 2 * complex(0, 1) * k_iz[i + 1] * (d_each_level[i] - d_each_level[i - 1]))) / ( 1 + R_TE[i] * R_TE_current * np.exp(2 * complex(0, 1) * k_iz[i + 1] * (d_each_level[i] - d_each_level[i - 1]))) R_TM_current = (R_TM[i] + R_TM_current * np.exp( 2 * complex(0, 1) * k_iz[i + 1] * (d_each_level[i] - d_each_level[i - 1]))) / ( 1 + R_TM[i] * R_TM_current * np.exp(2 * complex(0, 1) * k_iz[i + 1] * (d_each_level[i] - d_each_level[i - 1]))) T_TM_current = R_TM_current + 1 T_TE_current = R_TE_current + 1 R_zn = R_TM_current[88] Z_n1 = np.sqrt(miu[0] / ebuxiro[0]) * (1 + R_zn * np.exp( k_iz[0] * (-1) * complex(0, 1))) / (1 - R_zn * np.exp(k_iz[0] * (-1) * complex(0, 1))) Z_ni = np.sqrt(Z_n1[0].real**2 + Z_n1[0].imag**2) print(Z_ni) self.ui.surface_impedance_2.setText(str(Z_ni)) self.ui.surface_impedance_2.repaint() print("miu = ", miu) print("ebuxiro = ", ebuxiro) print("d each level = ", d_each_level) def set_module_TE(self): global wave_Mode wave_Mode = 1 self.ui.config1.setText('TE波') self.ui.config1.repaint() self.figure_plot() def set_module_TM(self): global wave_Mode wave_Mode = 2 self.ui.config1.setText('TM波') self.ui.config1.repaint() self.figure_plot() def set_curve_Mode_reflective(self): global curve_Mode curve_Mode = 1 self.ui.config2.setText('反射系数曲线') self.ui.config2.repaint() self.figure_plot() def set_curve_Mode_transmission(self): global curve_Mode curve_Mode = 2 self.ui.config2.setText('透射系数曲线') self.ui.config2.repaint() self.figure_plot() def figure_plot(self): global wave_Mode, curve_Mode, R_TM, R_TE, T_TM, T_TE, R_TE_current figure_final = [] if wave_Mode == 0 or curve_Mode == 0: return if wave_Mode == 1: if curve_Mode == 1: figure_final = R_TE_current elif curve_Mode == 2: figure_final = T_TE_current elif wave_Mode == 2: if curve_Mode == 1: figure_final = R_TM_current elif curve_Mode == 2: figure_final = T_TM_current print('current config', curve_Mode, wave_Mode) self.ax.clear() self.ax.plot(figure_final) self.canvas.draw_idle() def show_message(self, text): msg = QMessageBox() msg.setText(text) msg.setStandardButtons(QMessageBox.Ok) ret = msg.exec_()
class Ui_MainWindow(QDialog): def __init__(self,parent=None): super(Ui_MainWindow, self).__init__(parent) self.edges = {} self.nodes=set() self.cal_e = [] self.fig = plt.figure() self.canvas = FigureCanvas(self.fig) self.toolbar = NavigationToolbar(self.canvas, self) def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.grah_btn = QtWidgets.QPushButton(self.centralwidget) self.grah_btn.setGeometry(QtCore.QRect(20, 500, 161, 41)) self.grah_btn.setObjectName("grah_btn") self.edge_btn = QtWidgets.QPushButton(self.centralwidget) self.edge_btn.setGeometry(QtCore.QRect(520, 230, 251, 41)) self.edge_btn.setObjectName("edge_btn") self.start_node = QtWidgets.QTextEdit(self.centralwidget) self.start_node.setGeometry(QtCore.QRect(660, 60, 111, 41)) self.start_node.setObjectName("start_node") self.end_node = QtWidgets.QTextEdit(self.centralwidget) self.end_node.setGeometry(QtCore.QRect(660, 110, 111, 41)) self.end_node.setObjectName("end_node") self.cost = QtWidgets.QTextEdit(self.centralwidget) self.cost.setGeometry(QtCore.QRect(660, 160, 111, 41)) self.cost.setObjectName("cost") self.label = QtWidgets.QLabel(self.centralwidget) self.label.setGeometry(QtCore.QRect(550, 60, 91, 31)) self.label.setObjectName("label") self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2.setGeometry(QtCore.QRect(550, 110, 91, 31)) self.label_2.setObjectName("label_2") self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3.setGeometry(QtCore.QRect(550, 160, 91, 31)) self.label_3.setObjectName("label_3") self.tree_btn = QtWidgets.QPushButton(self.centralwidget) self.tree_btn.setGeometry(QtCore.QRect(340, 500, 161, 41)) self.tree_btn.setObjectName("tree_btn") self.root_node = QtWidgets.QTextEdit(self.centralwidget) self.root_node.setGeometry(QtCore.QRect(270, 500, 50, 41)) self.root_node.setObjectName("root_node") self.listWidget = QtWidgets.QListWidget(self.centralwidget) self.listWidget.setGeometry(QtCore.QRect(520, 290, 256, 261)) self.listWidget.setObjectName("listWidget") self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget) self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 491, 471)) self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 26)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.verticalLayout.addWidget(self.canvas) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.grah_btn.setText(_translate("MainWindow", "graph plot")) self.edge_btn.setText(_translate("MainWindow", "node_connect")) self.label.setText(_translate("MainWindow", "시작 노드")) self.label_2.setText(_translate("MainWindow", "끝 노드")) self.label_3.setText(_translate("MainWindow", "COST")) self.tree_btn.setText(_translate("MainWindow", "tree plot")) self.edge_btn.clicked.connect(self.add_edge) self.grah_btn.clicked.connect(self.graph_plot) self.tree_btn.clicked.connect(self.tree_plot) def add_edge(self): s = self.start_node.toPlainText() e = self.end_node.toPlainText() c = int(self.cost.toPlainText()) self.nodes.add(self.start_node.toPlainText()) self.nodes.add(self.end_node.toPlainText()) self.edges.setdefault((s,e),c) self.edges.setdefault((e,s),c) self.cal_e.append((s,e,c)) self.cal_e.append((e,s,c)) print(s,e,c) self.listWidget.addItem(" ".join([s,e,str(c)])) def graph_plot(self): self.fig.clear() self.draw_graph(list(self.edges.keys()),list(self.edges.values())) def tree_plot(self): import re self.fig.clear() p = re.compile(r"[0-9a-zA-Z]+") e = self.edges.keys() root = self.root_node.toPlainText() tree = [] edges = {} for node in sorted(list(self.nodes)): a = str(dijkstra(self.cal_e,root,node)) tree.append( p.findall(a)) print(tree) for path in tree: t_cost = path[0] if len(path[1:])>1: for node in path[1:-1]: edges.setdefault((node,path[path.index(node)+1]),0) edges[(node,path[path.index(node)+1])]=t_cost t_cost = int(t_cost) - self.edges[(node,path[path.index(node)+1])] print(edges) self.fig.clear() self.draw_graph(list(edges.keys()),list(edges.values())) def draw_graph(self,graph,labels=None, graph_layout='shell', node_size=1600, node_color='blue', node_alpha=0.3, node_text_size=12, edge_color='blue', edge_alpha=0.3, edge_tickness=1, edge_text_pos=0.3, text_font='sans-serif'): # create networkx graph G=nx.Graph() # add edges print(graph) for edge in graph: G.add_edge(edge[0], edge[1]) # these are different layouts for the network you may try # shell seems to work best if graph_layout == 'spring': graph_pos=nx.spring_layout(G) elif graph_layout == 'spectral': graph_pos=nx.spectral_layout(G) elif graph_layout == 'random': graph_pos=nx.random_layout(G) else: graph_pos=nx.shell_layout(G) # draw graph nx.draw_networkx_nodes(G,graph_pos,node_size=node_size, alpha=node_alpha, node_color=node_color) nx.draw_networkx_edges(G,graph_pos,width=edge_tickness, alpha=edge_alpha,edge_color=edge_color) nx.draw_networkx_labels(G, graph_pos,font_size=node_text_size, font_family=text_font) if labels is None: labels = range(len(graph)) edge_labels = dict(zip(graph, labels)) nx.draw_networkx_edge_labels(G, graph_pos, edge_labels=edge_labels, label_pos=edge_text_pos) # show graph self.canvas.draw_idle()
class PulseSequenceVisualizer(QtWidgets.QDockWidget): def __init__(self): QtWidgets.QDockWidget.__init__(self, "Pulse Sequence") self.setObjectName("PulseSequenceDock") self.setFeatures(QtWidgets.QDockWidget.NoDockWidgetFeatures) # Initialize self.last_seq_data = None self.last_plot = None self.subscribed = False self.current_box = None self.mpl_connection = None self.main_widget = QtWidgets.QWidget() self.setWidget(self.main_widget) self.create_layout() self.connect_asyncio_server() def connect_asyncio_server(self): self.loop = asyncio.get_event_loop() self.asyncio_server = Server( { "pulse_sequence_visualizer": PulseSequenceVisualizerServer(self), "simulation_logger": simulation_logger }, None, True) self.task = self.loop.create_task( self.asyncio_server.start("::1", 3289)) def create_layout(self): # Creates GUI layout layout = QtGui.QVBoxLayout() plot_layout = self.create_plot_layout() layout.addLayout(plot_layout) self.main_widget.setLayout(layout) def create_plot_layout(self): # Creates empty matplotlib plot layout layout = QtGui.QVBoxLayout() self.fig = Figure() self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self) self.axes = self.fig.add_subplot(111) self.axes.legend(loc='best') self.mpl_toolbar = NavigationToolbar(self.canvas, self) self.axes.set_title('Most Recent Pulse Sequence', fontsize=22) self.axes.set_xlabel('Time (ms)') self.fig.tight_layout() # Create an empty an invisible annotation, which will be moved around and set to visible later when needed self.annot = self.axes.annotate("", xy=(0, 0), xytext=(-0.5, 0.5), textcoords="offset points", bbox=dict(boxstyle="round", fc="w"), horizontalalignment='center', multialignment='left', verticalalignment='center') self.annot.get_bbox_patch().set_alpha(0.8) self.annot.set_visible(False) # Add the canvas to the GUI widget. layout.addWidget(self.mpl_toolbar) layout.addWidget(self.canvas) return layout def on_new_seq(self, dds, ttl, channels, signal_time): # Temporary stop tracking mouse movement if self.mpl_connection: self.canvas.mpl_disconnect(self.mpl_connection) self.last_seq_data = {'DDS': dds, 'TTL': ttl, 'channels': channels} # Create SequenceAnalyzer object instance self.sequence = SequenceAnalyzer(ttl, dds, channels) # Clear the plot of all drawn objects self.clear_plot() # Call the SequenceAnalyzer object's create_full_plot method to draw the plot on the GUI's axes. self.sequence.create_full_plot(self.axes) self.axes.set_title('Most Recent Pulse Sequence, ' + time.strftime('%Y-%m-%d %H:%M:%S', signal_time)) # Draw and reconnect to mouse hover events self.canvas.draw_idle() self.mpl_connection = self.canvas.mpl_connect("motion_notify_event", self.hover) def clear_plot(self): # Remove all lines, boxes, and annotations, except for the hover annotation for child in self.axes.get_children(): if isinstance(child, (matplotlib.lines.Line2D, matplotlib.text.Annotation, matplotlib.collections.PolyCollection)): if child is not self.annot: child.remove() def format_starttime(self, t): # Function for formatting times in the hover annotation if round(1e6 * t) < 1000: return '{:.1f} $\mu$s'.format(1e6 * t) else: return '{:.3f} ms'.format(1e3 * t) def format_duration(self, t): # Function for formatting times in the hover annotation if round(1e6 * t) < 1000: return '%#.4g $\mu$s' % (1e6 * t) else: return '%#.4g ms' % (1e3 * t) def update_annot(self, dds_box): # This function updates the text of the hover annotation. drawx = 1e3 * (dds_box.starttime() + dds_box.duration() / 2.0) drawy = dds_box.offset + dds_box.scale / 2.0 self.annot.xy = (drawx, drawy) text = '{0}\nStart: {1}\nDuration: {2}\n{3:.4f} MHz\n{4:.2f} amp w/att'.format( dds_box.channel, self.format_starttime(dds_box.starttime()), self.format_duration(dds_box.duration()), dds_box.frequency(), dds_box.amplitude()) self.annot.set_text(text) def hover(self, event): # This function is called when the mouse moves # It updates the hover annotation if necessary. (self.last_mouse_x, self.last_mouse_y) = (event.x, event.y) vis = self.annot.get_visible() if event.inaxes == self.axes: for dds_box in self.sequence.dds_boxes: if dds_box.box.contains(event)[0]: if dds_box is not self.current_box: self.current_box = dds_box self.update_annot(dds_box) self.annot.set_visible(True) self.canvas.draw_idle() break else: self.current_box = None if vis: self.annot.set_visible(False) self.canvas.draw_idle() else: self.current_box = None def closeEvent(self, event): self.loop.create_task(self.asyncio_server.stop()) super(PulseSequenceVisualizer, self).closeEvent(event)