Exemple #1
0
    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)
Exemple #2
0
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
Exemple #4
0
 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))
Exemple #5
0
 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))
Exemple #6
0
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')
Exemple #7
0
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')
Exemple #8
0
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())
Exemple #11
0
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
Exemple #12
0
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()
Exemple #14
0
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)
Exemple #15
0
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())
Exemple #16
0
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()
Exemple #17
0
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
Exemple #19
0
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)
Exemple #20
0
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()
Exemple #22
0
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())
Exemple #23
0
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)
Exemple #24
0
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()
Exemple #25
0
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()
Exemple #27
0
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)