예제 #1
1
class matplotlibWidget(QWidget):
    def __init__(self, parent = None):
        QWidget.__init__(self, parent)
        self.canvas = MplCanvas()
        self.gl = QGridLayout()
        alignment = Qt.Alignment()
        self.gl.addWidget(self.canvas,0,0,-1,-1,alignment)

        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()

        # Just some button 

        self.button1 = QPushButton('Zoom')
        self.button1.clicked.connect(self.zoom)

        self.button2 = QPushButton('Pan')
        self.button2.clicked.connect(self.pan)

        self.button3 = QPushButton('Home')
        self.button3.clicked.connect(self.home)

        self.gl.addWidget(self.toolbar,1,0,alignment)
        self.gl.addWidget(self.button1,1,1,alignment)
        self.gl.addWidget(self.button2,1,2,alignment)
        self.gl.addWidget(self.button3,1,3,alignment)

        self.setLayout(self.gl)

    def home(self):
        self.toolbar.home()
    def zoom(self):
        self.toolbar.zoom()
    def pan(self):
        self.toolbar.pan()
예제 #2
0
class MyMplCanvas(FigureCanvas):
    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.axes = fig.add_subplot(111)
        # We want the axes cleared every time plot() is called
        self.axes.hold(False)

        self.compute_initial_figure()

        #
        FigureCanvas.__init__(self, fig)
        self.setParent(parent)
        self.setStyleSheet("{background-color:transparent;border:none;}")

        """FigureCanvas.setSizePolicy(self,
                                   QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)"""

        FigureCanvas.updateGeometry(self)

        self.tootlbar = NavigationToolbar(self, parent)
        self.tootlbar.hide()

        self.fid = 0
        self.data = []
        self.index = []

    def compute_initial_figure(self):
        pass
예제 #3
0
class BoxplotChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("Boxplot Chart"))
        self.figure = plt.figure(figsize=(4, 3))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)
        if not toolbar:
            self.toolbar.hide()

    def show_dataset(self,
                     dataset: typing.Iterable[typing.Iterable[float]],
                     xlabels,
                     ylabel,
                     title=""):
        self.axes.clear()
        self.axes.boxplot(dataset, labels=xlabels)
        self.axes.set_ylabel(ylabel)
        self.axes.set_title(title)
        self.figure.tight_layout()
        self.canvas.draw()
예제 #4
0
class HierarchicalChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("Hierarchical Clustering Chart"))
        self.figure = plt.figure(figsize=(6, 3))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)
        if not toolbar:
            self.toolbar.hide()

    def show_result(self, linkage_matrix: np.ndarray, p=100, **kwargs):
        self.axes.clear()
        res = dendrogram(linkage_matrix,
                         no_labels=False,
                         p=p,
                         truncate_mode='lastp',
                         show_contracted=True,
                         ax=self.axes)
        self.axes.set_title(
            f"{self.tr('Hierarchical clustering chart')} (p={p})")
        self.axes.set_xlabel(self.tr("Sample count/index"))
        self.axes.set_ylabel(self.tr("Distance"))
        self.figure.tight_layout()
        self.canvas.draw()
        return res
예제 #5
0
class SliceWidget(FigureCanvas):
    def __init__(self, parent=None, dpi=100):
        # Create figure and axes, the axes should cover the entire figure size
        figure = Figure(dpi=dpi, frameon=False)
        self.axes = figure.add_axes((0, 0, 1, 1), facecolor='black')

        # Hide the x and y axis, we just want to see the image
        self.axes.get_xaxis().set_visible(True)
        self.axes.get_yaxis().set_visible(True)

        # Initialize the parent FigureCanvas
        FigureCanvas.__init__(self, figure)
        self.setParent(parent)

        # Set background of the widget to be close to black
        # The color is not made actually black so that the user can distinguish the image bounds from the figure bounds
        self.setStyleSheet('background-color: #FFFFFF;')

        # Set widget to have strong focus to receive key press events
        self.setFocusPolicy(Qt.StrongFocus)

        # Create navigation toolbar and hide it
        # We don't want the user to see the toolbar but we are making our own in the user interface that will call
        # functions from the toolbar
        self.toolbar = NavigationToolbar(self, self)
        self.toolbar.hide()

        # Update size policy and geometry
        FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)
예제 #6
0
class MplWidget(MyBaseWidget):
    def __init__(self, dpi=30, parent=None):
        super(MplWidget, self).__init__(parent)

        self.sc = MplCanvas(self, width=3, height=4, dpi=dpi)

        # Create toolbar, passing canvas as first parament, parent (self, the MainWindow) as second.
        self.toolbar = NavigationToolbar(self.sc, self)
        self.toolbar.hide()

        layout = QtWidgets.QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.toolbar)
        layout.addWidget(self.sc)
        # self.setStyleSheet("border: 1px solid red")
        # pal = self.palette()
        # pal.setColor(QPalette.Background, QtCore.Qt.blue)
        # self.setAutoFillBackground(True)
        # self.setPalette(pal)

        #self.setLineWidth(0)
        # self.setContentsMargins(0,0,0,0)
        #self.setFrameStyle(QtWidgets.QFrame.Plain)
        self.setLayout(layout)

        self.sc.mpl_connect('button_press_event', self.onclick)

        #
        # The object attributes
        self.selected_stuff = None
        self.x = None
        self.y = None
        self.ploted_stuff = None

    def onclick(self, event):
        print('Click on matplotlib canvas..', event)

    def size(self) -> QtCore.QSize:
        return QtCore.QSize(100, 100)

    def plot(self, x, y, *args, **kwargs):

        self.x = x
        self.y = y
        self.ploted_stuff = self.sc.axes.plot(x, y, *args, **kwargs)
        self.sc.draw()

    def select_indices(self, idx):
        if self.selected_stuff is not None:
            for s in self.selected_stuff:
                self.selected_stuff.pop().remove()
        if not self.ploted_stuff:
            return
        self.selected_stuff = self.sc.axes.plot(self.x.iloc[idx],
                                                self.y.iloc[idx], 'ro')
        self.sc.draw()

    def mouseDoubleClickEvent(self, a0: QtGui.QMouseEvent) -> None:
        print('Double click on this one.')
예제 #7
0
class LocalizationPlot(FigureCanvas):
    def __init__(self, widget):
        self.widget = widget
        self.fig = Figure(figsize=(200, 100), dpi=100)
        super(LocalizationPlot, self).__init__(self.fig)
        self.axes = self.fig.add_subplot(111)
        self.axes.set(title="Localization")
        self.mlp_bar = NavigationToolbar(self, self.widget)
        self.mlp_bar.hide()
        self.mpl_connect("button_press_event", self.mlp_bar.pan())
        self.mpl_connect("scroll_event", self.zoom)
        self.draw()

    # We only want the latest 80 plot
    # update and cancel the previous one
    def update_plot(self, data):

        xs = []
        ys = []

        for i in range(len(data)):
            xs.append(data[i][0])
            ys.append(data[i][1])
        self.axes.cla()
        self.axes.set(xlabel='x Axis (m)', ylabel='y Axis (m)')

        # # Update the right label
        for i in range(len(xs)):
            self.axes.plot(xs[i], ys[i], '.', color='#00BFFF')
        self.axes.set_xlim([0, 1])
        self.axes.set_ylim([0, 1])
        self.draw()

    def zoom(self, event):
        self.ran = [
            self.axes.get_xlim()[0],
            self.axes.get_xlim()[1],
            self.axes.get_ylim()[0],
            self.axes.get_ylim()[1]
        ]
        if event.button == "up":
            self.ran[0] += 5
            self.ran[1] -= 5
            self.ran[2] += 5
            self.ran[3] -= 5
            self.axes.set_xlim(self.ran[0], self.ran[1])
            self.axes.set_ylim(self.ran[2], self.ran[3])
        else:
            self.ran[0] -= 5
            self.ran[1] += 5
            self.ran[2] -= 5
            self.ran[3] += 5
            self.axes.set_xlim(self.ran[0], self.ran[1])
            self.axes.set_ylim(self.ran[2], self.ran[3])
        self.draw()

    def getrange(self):
        return self.ran
예제 #8
0
class PlotWidget(QtWidgets.QWidget):
    def __init__(self, parent, plot_name):
        super().__init__(parent)
        self.plot_name = plot_name
        self.plot_manager = PlotManager.instance

        self.plot_thread = None

        self.figure = Figure(figsize=(18, 12))
        # self.figure.subplots_adjust(left=0.1, right=0.9,
        #                             bottom=0.1, top=0.9,
        #                             hspace=0.3, wspace=0.3)

        self.canvas = FigureCanvas(self.figure)

        self.toolbar = NavigationToolbar(self.canvas, self)

        main_layout = QtWidgets.QVBoxLayout(self)
        main_layout.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)
        main_layout.setContentsMargins(0, 0, 0, 0)
        main_layout.setSpacing(0)
        main_layout.addWidget(self.toolbar)
        main_layout.addWidget(self.canvas)

    def start_plotting(self):
        self.toolbar.hide()
        self.plot_thread = PlotCreationThread(self, self.figure)
        self.plot_thread.finished.connect(self.on_plot_thread_is_done)

        debug_mode = False  # set to 'True' in order to debug plot creation with embed
        if debug_mode:
            # synchronous plotting (runs in main thread and thus allows debugging)
            self.plot_thread.run()
        else:
            # asynchronous plotting (default):
            self.plot_thread.start(
            )  # start will start thread (and run), but main thread will continue immediately

    def is_busy_plotting(self):
        return self.plot_thread is not None

    @QtCore.pyqtSlot()
    def on_plot_thread_is_done(self):
        self.plot_thread = None
        self.toolbar.show()
        self.plot_manager.add_plot(self)

    def clear_figure(self):
        self.figure.clear()

    def refresh_canvas(self):
        self.canvas.draw()

    def closeEvent(self, close_event):
        self.plot_manager.remove_plot(self)
        super().closeEvent(close_event)
예제 #9
0
class EMMASummaryChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("EMMA Summary Chart"))
        self.figure = plt.figure(figsize=(4, 3))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)

        self.supported_distances = ("1-norm", "2-norm", "3-norm", "4-norm",
                                    "MSE", "log10MSE", "cosine", "angular")
        self.distance_label = QLabel(self.tr("Distance"))
        self.distance_combo_box = QComboBox()
        self.distance_combo_box.addItems(self.supported_distances)
        self.distance_combo_box.setCurrentText("log10MSE")
        self.distance_combo_box.currentIndexChanged.connect(self.update_chart)
        self.main_layout.addWidget(self.distance_label, 2, 0)
        self.main_layout.addWidget(self.distance_combo_box, 2, 1)

        if not toolbar:
            self.toolbar.hide()

        self.results = []

    @property
    def distance(self) -> str:
        return self.distance_combo_box.currentText()

    def update_chart(self):
        self.show_distances(self.results)

    def show_distances(self, results: typing.List[EMMAResult], title=""):
        self.results = results

        n_members_list = [result.n_members for result in results]
        distances = [result.get_distance(self.distance) for result in results]

        self.axes.clear()
        self.axes.plot(n_members_list,
                       distances,
                       c="black",
                       linewidth=2.5,
                       marker=".",
                       ms=8,
                       mfc="black",
                       mew=0.0)
        self.axes.set_xlabel(self.tr("$N_{iterations}$"))
        self.axes.set_ylabel(self.tr("Distance"))
        self.axes.set_title(title)
        self.figure.tight_layout()
        self.canvas.draw()
예제 #10
0
class Window(QtWidgets.QDialog):
    def __init__(self, data, parent=None):
        super(Window, self).__init__(parent)

        self.data = data
        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)

        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()

        self.button = QtWidgets.QPushButton('Plot')
        self.button.clicked.connect(self.plot)

        self.button1 = QtWidgets.QPushButton('Zoom')
        self.button1.clicked.connect(self.zoom)

        self.button2 = QtWidgets.QPushButton('Pan')
        self.button2.clicked.connect(self.pan)

        self.button3 = QtWidgets.QPushButton('Home')
        self.button3.clicked.connect(self.home)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button)
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)
        layout.addWidget(self.button3)

        self.setLayout(layout)

    def home(self):
        self.toolbar.home()

    def zoom(self):
        self.toolbar.zoom()

    def pan(self):
        self.toolbar.pan()

    def plot(self):
        # PlotCanvas(self.data)

        data = self.data
        ax = self.figure.add_subplot(111)
        ax.hold(False)
        ax.set_title("Basic Distribution")

        ax.plot(data, 'r*-')
        self.canvas.draw()
예제 #11
0
class Window(QDialog):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)

        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()

        # Just some button
        self.button = QPushButton('Plot')
        self.button.clicked.connect(self.plot)

        self.button1 = QPushButton('Zoom')
        self.button1.clicked.connect(self.zoom)

        self.button2 = QPushButton('Pan')
        self.button2.clicked.connect(self.pan)

        self.button3 = QPushButton('Home')
        self.button3.clicked.connect(self.home)

        # set the layout
        layout = QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        layout.addWidget(self.button)
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)
        layout.addWidget(self.button3)
        self.setLayout(layout)

    def home(self):
        self.toolbar.home()

    def zoom(self):
        self.toolbar.zoom()

    def pan(self):
        self.toolbar.pan()

    def plot(self):
        ''' plot some random stuff '''
        data = [random.random() for i in range(25)]
        ax = self.figure.add_subplot(111)
        ax.hold(False)
        ax.plot(data, '*-')
        self.canvas.draw()
예제 #12
0
class MatplotlibWidget(Canvas):
    def __init__(self, parent=None):
        figure = Figure(figsize=(4, 3))
        self.ax = figure.add_subplot(111)
        Canvas.__init__(self, figure)
        c = Canvas(Figure())
        self.setParent(parent)
        Canvas.setSizePolicy(self, QSizePolicy.Expanding,
                             QSizePolicy.Expanding)
        Canvas.updateGeometry(self)
        self.figure = figure
        self.ax.grid()
        self.tb = NavTB(self.figure.canvas, parent)
        self.tb.hide()
        self.marker = itertools.cycle(('s', 'v', 'd', 'o', '*', '^', '8'))
예제 #13
0
class MatplotlibWidget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        plt.style.use('dark_background')

        self.canvas = FigureCanvas(Figure())
        self.toolbar = NavigationToolbar(self.canvas, self, coordinates=False)
        self.toolbar.hide()

        vertical_layout = QVBoxLayout()
        vertical_layout.addWidget(self.canvas)
        # vertical_layout.addWidget(self.toolbar)

        self.canvas.axes = self.canvas.figure.add_subplot(111)
        self.setLayout(vertical_layout)
예제 #14
0
class MplWidget(QtGui.QWidget):
    """Widget defined in Qt Designer"""
    def __init__(self, parent=None, height=300, width=300):
        # initialization of Qt MainWindow widget
        QtGui.QWidget.__init__(self, parent)
        # set the canvas to the Matplotlib widget
        self.canvas = MplCanvas()
        # create a vertical box layout
        self.vbl = QtGui.QVBoxLayout()
        self.vbl.setSpacing(0)

        self.ntb = NavigationToolbar(self.canvas, parent)
        self.ntb.hide()
        self.vbl.addWidget(self.ntb)

        # add mpl widget to vertical box
        self.vbl.addWidget(self.canvas)
        # set the layout to the vertical box
        self.setLayout(self.vbl)
        self.setMinimumHeight(height)
        self.setMinimumWidth(width)
예제 #15
0
class PCAResultChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("PCA Result Chart"))
        self.figure = plt.figure(figsize=(6, 4))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)
        if not toolbar:
            self.toolbar.hide()

    def show_result(self, dataset: GrainSizeDataset, transformed: np.ndarray,
                    pca: PCA):
        self.axes.clear()
        # X = dataset.X
        components = pca.components_
        # X_hat = transformed @ components
        # MAD = np.abs(X_hat - X)
        n_samples, n_components = transformed.shape
        n_components_, n_classes = components.shape
        sample_indexes = np.linspace(1, n_samples, n_samples)
        assert n_components == n_components_

        for i in range(n_components):
            self.axes.plot(
                sample_indexes,
                transformed[:, i],
                label=f"PC{i+1} ({pca.explained_variance_ratio_[i]:0.2%})")
        self.axes.set_xlabel(self.tr("Sample index"))
        self.axes.set_ylabel(self.tr("Transformed value"))
        self.axes.set_title(self.tr("Varations of PCs"))
        if n_components < 10:
            self.axes.legend(loc="upper left")
        self.figure.tight_layout()
        self.canvas.draw()
예제 #16
0
class DistanceCurveChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("Distance History"))
        self.figure = plt.figure(figsize=(4, 3))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)
        if not toolbar:
            self.toolbar.hide()

    def show_distance_series(self, series: typing.Iterable[float], title=""):
        self.axes.clear()
        self.axes.plot(series)
        self.axes.set_xlabel(self.tr("Iteration index"))
        self.axes.set_ylabel(self.tr("Distance"))
        self.axes.set_title(title)
        self.figure.tight_layout()
        self.canvas.draw()
예제 #17
0
class Form(QMainWindow, ProgressCallback):
    def __init__(self, ui_file, parent=None):
        super(Form, self).__init__(parent)
        ui_file = QFile(ui_file)
        ui_file.open(QFile.ReadOnly)

        self.communicate = Communicate()
        self.communicate.update_progress.connect(self.emit_progress)
        self.communicate.bundle_result.connect(self.bundle_result)

        self.path = None
        self.graph = None
        self.algorithm = None
        self.thread: Optional[Thread] = None
        self.stopped = False
        self.parameters = AntBundleParameterSettings().getValues()

        loader = QUiLoader()
        self.ui = loader.load(ui_file)
        ui_file.close()

        # Menu bar
        self.ui.menuFileOpen.triggered.connect(self.openFile)
        self.ui.btnSettings.clicked.connect(self.settings)
        self.ui.btnRun.clicked.connect(lambda: self.run(open_file=True))
        self.ui.btnStop.clicked.connect(self.stop)

        # Matplotlib widget
        content = self.ui.widget

        self.canvas = FigureCanvas(Figure((6, 7)))
        self.figure = self.canvas.figure
        self.ax = self.canvas.figure.subplots()
        self.ax.axes.xaxis.set_visible(False)
        self.ax.axes.yaxis.set_visible(False)
        self.ax.text(0.5, 0.5, 'No graph loaded', ha='center', va='center')

        self.ntb = NavigationToolbar(self.canvas, self)
        self.ntb.hide()

        content_box = QVBoxLayout()
        content_box.addWidget(self.canvas)
        content_box.addWidget(self.ntb)

        content.setLayout(content_box)

        self.info: QLabel = self.ui.lblInfo

        self.canvas.draw()
        self.ui.show()

    def settings(self):
        dlg = AntBundleParameterSettings(self.parameters)
        if dlg.exec_() == QDialog.Accepted:
            self.parameters = dlg.getValues()

    def create_bundler(self):
        return AntBundleAlgorithm(
            self.graph, self.create_interpolator(), self.parameters.runs,
            self.parameters.numberOfSegments,
            self.parameters.decreaseByConstant, self.parameters.decreaseFactor,
            self.parameters.randomness, self.parameters.threshold,
            self.parameters.updateDistance, self.parameters.pathExponent)

    def create_interpolator(self):
        return BSplineInterpolate(
            max_degree=self.parameters.splineInterpolationDegree)

    @Slot(float, float, str)
    def emit_progress(self, overall, subtask_progress, subtask_name):
        self.ui.progressBarOverall.setValue(int(overall * 100))
        self.ui.progressBarSub.setValue(int(subtask_progress * 100))
        self.ui.lblSubtask.setText(subtask_name)

    def progress(self, overall, subtask_progress, subtask_name):
        # ask ui thread to handle progress update
        self.communicate.update_progress.emit(overall, subtask_progress,
                                              subtask_name)

    @Slot(BundledGraph, PheromoneField, AntBundleParameters)
    def bundle_result(self, bg: BundledGraph, pf: PheromoneField,
                      parameters: AntBundleParameters):
        dlg = AntBundleOutputWindow(bg, pf, parameters, parent=self)
        dlg.show()

        self.ui.btnRun.setEnabled(True)
        self.ui.btnSettings.setEnabled(True)

    def bundle(self):
        parameters = AntBundleParameters(**self.parameters.__dict__)

        self.algorithm = self.create_bundler()
        self.algorithm.progress_callback = self
        bundled_graph = self.algorithm.bundle()

        if not self.stopped:
            self.communicate.bundle_result.emit(bundled_graph,
                                                self.algorithm.field,
                                                parameters)

        self.communicate.update_progress.emit(0, 0, "Waiting...")

    def run(self, open_file=True):
        if self.path and self.graph:
            self.stopped = False
            self.ui.btnRun.setEnabled(False)
            self.ui.btnSettings.setEnabled(False)

            self.thread = Thread(target=self.bundle)
            self.thread.start()
        elif open_file:
            self.openFile()
            self.run(open_file=False)

    def stop(self):
        if self.thread.is_alive() and self.algorithm:
            if easygui.ynbox('Do you want to terminate?', 'Stop request',
                             ['Yes', 'No']):
                self.stopped = True
                self.algorithm.stop()

                self.ui.btnRun.setEnabled(True)
                self.ui.btnSettings.setEnabled(True)

    def draw(self):
        self.ntb.show()
        self.ax.cla()
        nx.draw_networkx(self.graph,
                         GraphUtils.createPositionDict(self.graph),
                         ax=self.ax,
                         with_labels=False,
                         node_size=100)
        self.ax.set_aspect('equal')
        self.canvas.draw()

    def openFile(self):
        self.path = easygui.fileopenbox()

        if not self.path:
            return

        try:
            g = nx.read_graphml(self.path)
        except (nx.NetworkXError, ElementTree.ParseError) as e:
            error_dialog = QtWidgets.QErrorMessage()
            error_dialog.showMessage(str(e))

            error_dialog.exec_()
            return

        g, success = GraphUtils.sanitize(g)
        if success:
            self.graph = g
            self.setGraphInfo()
            self.draw()
        else:
            self.path = None

    def setGraphInfo(self):
        if not self.graph:
            return

        max_x, max_y, _ = GraphUtils.getGraphFieldShape(self.graph)
        node_count = len(self.graph.nodes)

        self.info.setText(
            f"#nodes: {node_count}\tdimensions: ({max_x}, {max_y})")
예제 #18
0
class window_graph(QDialog):
    def __init__(self,data,Fs,status,methodValues=0,deletedEpochs=0,totalepochs=0):         
        QDialog.__init__(self);
        loadUi('graph.ui',self);
        self.setWindowIcon(QtGui.QIcon("logo.png"))
                
        self.mySignal=data
        self.myFs=Fs
        self.status=status
        self.methodSignal=methodValues
        self.deletedEpochs=deletedEpochs
        self.numEpochs=totalepochs
        
        self.channels, self.points = shape(self.mySignal)
        #self.time_array=arange(0,self.points/self.myFs,1/self.myFs)
        
        self.button_zoom.clicked.connect(self.zoom)
        self.button_pan.clicked.connect(self.pan)
        self.button_home.clicked.connect(self.home)
        
        self.figure = Figure(figsize=(5,4), dpi=100)
        self.canvas = FigureCanvas(self.figure)
        self.axes=self.figure.add_subplot(111)
        self.toolbar=NavigationToolbar(self.canvas,self)
        self.toolbar.hide()
        
        layout=QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        self.field_graph.setLayout(layout)
        self.axes.clear()
        self.canvas.draw()
        self.plot()
        
    def plot(self):
        legends=['Ch 1','Ch 2','Ch 3','Ch 4','Ch 5','Ch 6','Ch 7','Ch 8']
        if self.status==1:
            for c in range(self.channels):
                self.axes.plot(self.mySignal[c,::])
            self.axes.legend(legends)   
            self.axes.set_title('Señal original')
        if self.status==2:
            r=[]
            for c in range(self.channels):
                r.append(c*150)
                self.axes.plot(self.mySignal[c,::]+c*150)
            self.axes.set_yticklabels(legends)
            self.axes.set_yticks(r)
            self.axes.set_title('Señal filtrada')
            
        if self.status==3:
            r=[]
            for c in range(self.channels):
                r.append(c*150)
                self.axes.plot(self.mySignal[c,::]+c*150)
                self.axes.plot(self.methodSignal[c,::]+c*150,'r')
                
            self.axes.set_yticklabels(legends)
            self.axes.set_yticks(r)   
            self.axes.set_title('Eliminación de épocas') 
            msg = QMessageBox(self)
            msg.setIcon(QMessageBox.Information)
            msg.setText("Se eliminaron las épocas : "+'  '.join(str(ep) for ep in self.deletedEpochs))
            msg.setWindowTitle("Épocas eliminadas")
            msg.setInformativeText("Épocas iniciales: "+str(self.numEpochs)+'\tÉpocas restantes: '+str(self.numEpochs-len(self.deletedEpochs)))
            msg.show();

            
        self.axes.set_ylabel('Voltaje [uV]') 
        self.axes.set_xlabel('Muestras')  
        self.axes.grid(True)
        self.axes.set_xlim([0,4000])
        


        self.canvas.draw()
 
    def home(self):
        self.toolbar.home()
    def zoom(self):
        self.toolbar.zoom()
    def pan(self):
        self.toolbar.pan()
예제 #19
0
class Window(QMainWindow):
    def __init__(self, camera=None, calibration=None):

        #Inherit properies from QMainWindow
        super().__init__()

        #Setting geometry attributes of MainWindow
        self.left = 10
        self.top = 10
        self.width = 720
        self.height = 480
        self.project_num = 0
        self.project_name = "Calib_"
        self.project_list = []

        #Design GUI elements
        self.initUI()

        #Declare Camera, calibration instances
        self.camera = camera
        self.calib = calibration
        self.criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER,
                         30, 0.001)

    #GUI elements design
    def initUI(self):

        # Matplotlib figure to draw image frame
        self.figure = plt.figure()

        # Window canvas to host matplotlib figure
        self.canvas = FigureCanvas(self.figure)

        # ToolBar to navigate image frame
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()

        #Setting Title and StatusBar
        self.setWindowTitle('Ứng dụng kiểm chuẩn máy ảnh số phổ thông')
        self.statusBar().showMessage("Trạng thái tác vụ: ")

        #Setting main menu
        mainMenu = self.menuBar()
        fileMenu = mainMenu.addMenu('Thao tác tệp tin')
        toolsMenu = mainMenu.addMenu('Xử lý dữ liệu')
        viewMenu = mainMenu.addMenu('Xem thông tin')
        editMenu = mainMenu.addMenu('Biên tập')
        searchMenu = mainMenu.addMenu('Tìm kiếm')
        helpMenu = mainMenu.addMenu('Trợ giúp')

        #Setting fileMenu
        fileMenu.addAction('Thiết lập dự án mới', self.on_file_setnewproject)
        fileMenu.addAction('Mở kho ảnh', self.on_open_imagestore)

        #Setting ToolsMenu
        toolsMenu.addAction('Tiền xử lý ảnh', self.on_preprocessing_image)
        toolsMenu.addAction('Kiểm chuẩn máy ảnh', self.on_calibrate_image)

        #Setting viewMenu
        viewMenu.addAction('Thông tin dự án', self.on_view_project_info)
        viewMenu.addAction('Dữ liệu kiểm chuẩn', self.on_view_calib_info)

        # Create central Widget
        self.central_widget = QWidget()

        # Just some button
        self.button = QPushButton('Chụp ảnh', self.central_widget)
        self.button1 = QPushButton('Phóng ảnh', self.central_widget)
        self.button2 = QPushButton('Điều hướng ảnh', self.central_widget)
        self.button3 = QPushButton('Về gốc', self.central_widget)

        #Put Buttons to HBoxLayout
        hBox = QHBoxLayout()
        hBox.addWidget(self.button)
        hBox.addWidget(self.button1)
        hBox.addWidget(self.button2)
        hBox.addWidget(self.button3)

        # set QVBoxLayout as the layout
        self.layout = QVBoxLayout(self.central_widget)
        self.layout.addWidget(self.toolbar)
        self.layout.addWidget(self.canvas)

        #Add hBoxLayout to VBoxLayout
        self.layout.addLayout(hBox)

        self.textedit = QTextEdit()
        font = QtGui.QFont()
        font.setPointSize(9)
        self.textedit.setFont(font)
        self.layout.addWidget(self.textedit)

        #Set central widget
        self.setCentralWidget(self.central_widget)

        # Events handling
        self.button.clicked.connect(self.plot)
        self.button1.clicked.connect(self.zoom)
        self.button2.clicked.connect(self.pan)
        self.button3.clicked.connect(self.home)

    #Events processing methods

    # Open image store
    @QtCore.pyqtSlot()
    def on_open_imagestore(self):
        #extract file name in a directory
        self.statusBar().showMessage(
            "Chương trình đang xử lý tác vụ: Mở kho ảnh")
        filepath = QFileDialog().getExistingDirectory(
            self, "Chọn đường dẫn tới kho ảnh")
        if filepath:
            images = Path(filepath).glob('*.jpg')
            imagelist = [str(image) for image in images]
            self.statusBar().showMessage(str("Kho ảnh nằm tại: ") + filepath)
            # check filename list and display first image
            if len(imagelist) > 2:
                #self.calib.imagelist = imagelist
                if self.project_num == 0:
                    self.project_num += 1
                    self.calib.imagelist = imagelist
                    self.calib.project_name = str("Calib_") + str(
                        self.project_num)
                else:
                    self.calib.project_name = str("Calib_") + str(
                        self.project_num)
                    self.project_list.append(self.calib)
                    self.project_num += 1
                    newcalib = Calibration()
                    newcalib.project_num = self.project_num
                    newcalib.imagelist = imagelist
                    self.calib = newcalib

                img = cv2.imread(imagelist[0])
                pic = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
                plt.imshow(pic)
                self.canvas.draw()
            else:
                self.statusBar().showMessage(
                    "Không có ảnh trong thư mục được chọn!")
        else:
            self.statusBar().showMessage(filepath)

    #Setting info for new project
    @QtCore.pyqtSlot()
    def on_file_setnewproject(self):
        self.statusBar().showMessage(
            "Chương trình đang xử lý tác vụ: Thiết lập tham số cho dự án mới")

    #Preprocessing images of current project
    @QtCore.pyqtSlot()
    def on_preprocessing_image(self):

        if len(self.calib.imagelist) > 0:
            self.calib.refresh()
            self.statusBar().showMessage(
                "Chương trình đang xử lý tác vụ: Tiền xử lý ảnh - ")
            #self.textedit.clear()
            self.textedit.append("")
            self.textedit.append("***********************************")
            #self.textedit.append("")
            self.textedit.append(
                str("Tiền xử lý ảnh dự án Calib_") + str(self.project_num) +
                str(":"))
            self.thread_image_preprocessing = Calib_Preprocess_Thread(
                self.calib)
            self.thread_image_preprocessing.sig1.connect(
                self.on_image_preprocessing_display)
            self.thread_image_preprocessing.sig2.connect(
                self.on_image_preprocessed_display)
            self.thread_image_preprocessing.sig3.connect(
                self.on_image_preprocessed_result)
            self.thread_image_preprocessing.start()

    #Calibrate current project
    @QtCore.pyqtSlot()
    def on_calibrate_image(self):
        if self.calib.preprocessing_done == True:
            # Calibrate if calib has not done
            if self.calib.calibrated == False:
                self.thread_calib = Calib_Calibrate_Thread(self.calib)
                self.thread_calib.sig1.connect(self.on_calibtation_processed)
                self.thread_calib.start()

    @QtCore.pyqtSlot()
    def on_view_project_info(self):
        pass

    @QtCore.pyqtSlot()
    def on_view_calib_info(self):
        calib_list = []
        if len(self.project_list) > 0:
            for calib in self.project_list:
                clone_calib = calib.clone()
                calib_list.append(clone_calib)

        if self.calib.calibrated == True:
            clone_calib = self.calib.clone()
            clone_calib.project_name = str("Calib_") + str(self.project_num)
            calib_list.append(clone_calib)

        if len(calib_list) > 0:
            self.calib_info = Total_Calib_Info(calib_list)
            self.calib_info.show()
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Information)
            msg.setText("Chưa có dự án kiểm chuẩn được thực hiện hoàn chỉnh!")
            msg.setWindowTitle("Thông báo")
            msg.exec_()

    def home(self):
        self.toolbar.home()

    def zoom(self):
        self.toolbar.zoom(0.5)

    def pan(self):
        self.toolbar.pan()

    def plot(self):
        #Moving Camera class to a thread and emit signal from that thread
        self.thread1 = Frame_Capture_Thread(self.camera)
        self.thread1.sig1.connect(self.on_frame)
        self.thread1.start()

    def on_frame(self, frame):
        plt.imshow(frame)
        self.canvas.draw()

    #Update current image name being processed: fname is image name obtained from signal sig1 of Calib_Preprocess_Thread
    def on_image_preprocessing_display(self, fname):
        filename = fname.split('\\')[-1]
        filename_message = str(
            "Chương trình đang xử lý tác vụ: Tiền xử lý ảnh - đang xử lý file ảnh: "
        ) + filename
        self.statusBar().showMessage(filename_message)
        self.textedit.append(
            str("Tiền xử lý ảnh - đang xử lý file ảnh: ") + str(filename) +
            str("..."))

    #Update last processed image  on display : pic is image data obtained from signal sig2 of Calib_Preprocess_Thread
    def on_image_preprocessed_display(self, pic):
        plt.imshow(pic)
        self.canvas.draw()

    #Update preprocessing result -
    def on_image_preprocessed_result(self, result):
        redColor = QtGui.QColor(255, 0, 0)
        blackColor = QtGui.QColor(0, 0, 0)
        ret = result[0]
        fname = result[1]
        filename = fname.split('\\')[-1]
        if ret == True:
            self.textedit.setTextColor(blackColor)
            msg = str("Xử lý xong ảnh ") + filename + str(
                " - ảnh hợp lệ cho kiểm chuẩn!")
            self.textedit.append(msg)
        else:
            self.textedit.setTextColor(redColor)
            msg = str("Xử lý xong ảnh ") + filename + str(
                " - ảnh không hợp lệ cho kiểm chuẩn!")
            self.textedit.append(msg)
            self.textedit.setTextColor(blackColor)

        if self.calib.preprocessing_done == True:
            msg = str("Tổng số ảnh tiền xử lý: ") + str(
                self.calib.processed_count)
            self.textedit.append(msg)
            msg = str("Số ảnh hợp lệ cho kiểm chuẩn: ") + str(
                self.calib.validated_count)
            self.textedit.append(msg)
            msg = str("Số ảnh không hợp lệ cho kiểm chuẩn: ") + str(
                self.calib.processed_count - self.calib.validated_count)
            self.textedit.append(msg)
            self.statusBar().showMessage(
                "Hoàn thành tác vụ tiền xử lý ảnh - dự án Calib_" +
                str(self.project_num))

    def on_calibtation_processed(self):
        self.calib.project_name = str("Calib_") + str(self.project_num)
        self.calib_info_window = Calib_Info(self.calib)
        self.calib_info_window.show()
예제 #20
0
class SSUTypicalComponentChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("SSU Typical Component Chart"))
        self.figure = plt.figure(figsize=(6, 3))
        self.clustering_axes = self.figure.add_subplot(1, 2, 1)
        self.component_axes = self.figure.add_subplot(1, 2, 2)
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 4)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 4)
        if not toolbar:
            self.toolbar.hide()
        self.supported_scales = [("log-linear", self.tr("Log-linear")),
                                 ("log", self.tr("Log")),
                                 ("phi", self.tr("φ")),
                                 ("linear", self.tr("Linear"))]
        self.AXIS_LIST = [
            self.tr("Mean [φ]"),
            self.tr("Standard deviation [φ]"),
            self.tr("Skewness"),
            self.tr("Kurtosis")
        ]
        self.x_axis_label = QLabel(self.tr("X Axis"))
        self.x_axis_combo_box = QComboBox()
        self.x_axis_combo_box.addItems(self.AXIS_LIST)
        self.y_axis_label = QLabel(self.tr("Y Axis"))
        self.y_axis_combo_box = QComboBox()
        self.y_axis_combo_box.addItems(self.AXIS_LIST)
        self.y_axis_combo_box.setCurrentIndex(1)
        self.main_layout.addWidget(self.x_axis_label, 2, 0)
        self.main_layout.addWidget(self.x_axis_combo_box, 2, 1)
        self.main_layout.addWidget(self.y_axis_label, 3, 0)
        self.main_layout.addWidget(self.y_axis_combo_box, 3, 1)
        self.scale_label = QLabel(self.tr("Scale"))
        self.scale_combo_box = QComboBox()
        self.scale_combo_box.addItems(
            [name for key, name in self.supported_scales])
        self.main_layout.addWidget(self.scale_label, 2, 2)
        self.main_layout.addWidget(self.scale_combo_box, 2, 3)
        self.min_samples_label = QLabel(self.tr("Minimum Samples"))
        self.min_samples_input = QDoubleSpinBox()
        self.min_samples_input.setRange(0.0001, 0.9999)
        self.min_samples_input.setDecimals(4)
        self.min_samples_input.setSingleStep(0.001)
        self.min_samples_input.setValue(0.03)
        self.min_cluster_size_label = QLabel(self.tr("Minimum Cluster Size"))
        self.min_cluster_size_input = QDoubleSpinBox()
        self.min_cluster_size_input.setRange(0.0001, 0.9999)
        self.min_cluster_size_input.setDecimals(4)
        self.min_cluster_size_input.setSingleStep(0.001)
        self.min_cluster_size_input.setValue(0.1)
        self.xi_label = QLabel(self.tr("xi"))
        self.xi_input = QDoubleSpinBox()
        self.xi_input.setRange(0.0001, 0.9999)
        self.xi_input.setDecimals(4)
        self.xi_input.setSingleStep(0.001)
        self.xi_input.setValue(0.05)
        self.main_layout.addWidget(self.min_samples_label, 3, 2)
        self.main_layout.addWidget(self.min_samples_input, 3, 3)
        self.main_layout.addWidget(self.min_cluster_size_label, 4, 0)
        self.main_layout.addWidget(self.min_cluster_size_input, 4, 1)
        self.main_layout.addWidget(self.xi_label, 4, 2)
        self.main_layout.addWidget(self.xi_input, 4, 3)
        self.update_chart_button = QPushButton(self.tr("Update Chart"))
        self.update_chart_button.clicked.connect(self.update_chart)
        self.save_typical_button = QPushButton(self.tr("Save Typical"))
        self.save_typical_button.setEnabled(False)
        self.save_typical_button.clicked.connect(self.on_save_clicked)
        self.main_layout.addWidget(self.update_chart_button, 5, 0, 1, 2)
        self.main_layout.addWidget(self.save_typical_button, 5, 2, 1, 2)

        self.last_results = None  # type: list[SSUResult]
        self.data_to_clustering = None
        self.stacked_components = None
        self.normal_msg = QMessageBox(self)
        self.file_dialog = QFileDialog(parent=self)

    @property
    def scale(self) -> str:
        index = self.scale_combo_box.currentIndex()
        key, name = self.supported_scales[index]
        return key

    @property
    def transfer(self) -> typing.Callable:
        if self.scale == "log-linear":
            return lambda classes_φ: convert_φ_to_μm(classes_φ)
        elif self.scale == "log":
            return lambda classes_φ: np.log(convert_φ_to_μm(classes_φ))
        elif self.scale == "phi":
            return lambda classes_φ: classes_φ
        elif self.scale == "linear":
            return lambda classes_φ: convert_φ_to_μm(classes_φ)

    @property
    def xlabel(self) -> str:
        if self.scale == "log-linear":
            return self.tr("Grain-size [μm]")
        elif self.scale == "log":
            return self.tr("Ln(grain-size in μm)")
        elif self.scale == "phi":
            return self.tr("Grain-size [φ]")
        elif self.scale == "linear":
            return self.tr("Grain-size [μm]")

    @property
    def ylabel(self) -> str:
        return self.tr("Frequency")

    @property
    def xlog(self) -> bool:
        if self.scale == "log-linear":
            return True
        else:
            return False

    def show_message(self, title: str, message: str):
        self.normal_msg.setWindowTitle(title)
        self.normal_msg.setText(message)
        self.normal_msg.exec_()

    def show_info(self, message: str):
        self.show_message(self.tr("Info"), message)

    def show_warning(self, message: str):
        self.show_message(self.tr("Warning"), message)

    def show_error(self, message: str):
        self.show_message(self.tr("Error"), message)

    def update_chart(self):
        if self.last_results is None:
            return
        x = self.transfer(self.last_results[0].classes_φ)
        self.save_typical_button.setEnabled(True)
        cluster = OPTICS(min_samples=self.min_samples_input.value(),
                         min_cluster_size=self.min_cluster_size_input.value(),
                         xi=self.xi_input.value())
        flags = cluster.fit_predict(self.data_to_clustering)
        cmap = plt.get_cmap()

        self.clustering_axes.clear()
        flag_set = set(flags)
        for flag in flag_set:
            key = np.equal(flags, flag)
            if flag == -1:
                c = "#7a7374"
                label = self.tr("Not clustered")
            else:
                c = cmap(flag)
                label = self.tr("EM{0}").format(flag + 1)
            self.clustering_axes.plot(self.data_to_clustering[key]
                                      [:,
                                       self.x_axis_combo_box.currentIndex()],
                                      self.data_to_clustering[key]
                                      [:,
                                       self.y_axis_combo_box.currentIndex()],
                                      c="#ffffff00",
                                      marker=".",
                                      ms=8,
                                      mfc=c,
                                      mew=0.0,
                                      zorder=flag,
                                      label=label)
        if len(flag_set) < 6:
            self.clustering_axes.legend(loc="upper left")
        self.clustering_axes.set_xlabel(self.x_axis_combo_box.currentText())
        self.clustering_axes.set_ylabel(self.y_axis_combo_box.currentText())
        self.clustering_axes.set_title(self.tr("Clustering of end-members"))

        self.component_axes.clear()
        if self.xlog:
            self.component_axes.set_xscale("log")

        for flag in flag_set:
            if flag == -1:
                c = "#7a7374"
            else:
                c = cmap(flag)
            key = np.equal(flags, flag)
            for distribution in self.stacked_components[key]:
                self.component_axes.plot(x, distribution, c=c, zorder=flag)

            if flag != -1:
                typical = np.mean(self.stacked_components[key], axis=0)
                self.component_axes.plot(x,
                                         typical,
                                         c="black",
                                         zorder=1e10,
                                         ls="--",
                                         linewidth=1)
        self.component_axes.set_title(self.tr("Typical end-members"))
        self.component_axes.set_xlabel(self.xlabel)
        self.component_axes.set_ylabel(self.ylabel)
        self.component_axes.set_xlim(x[0], x[-1])
        self.component_axes.set_ylim(0, None)

        self.figure.tight_layout()
        self.canvas.draw()

    def show_typical(self, results: typing.Iterable[GrainSizeSample]):
        if len(results) == 0:
            return
        keys_to_clustering = ["mean", "std", "skewness", "kurtosis"]
        data_to_clustering = []
        stacked_components = []
        for result in results:
            for component in result.components:
                has_nan = False
                for key in keys_to_clustering:
                    if np.isnan(
                            component.logarithmic_moments[key]) or np.isinf(
                                component.logarithmic_moments[key]):
                        has_nan = True
                        break
                if has_nan:
                    continue
                data_to_clustering.append([
                    component.logarithmic_moments[key]
                    for key in keys_to_clustering
                ])
                stacked_components.append(component.distribution)
        # convert to numpy array
        data_to_clustering = np.array(data_to_clustering)
        stacked_components = np.array(stacked_components)
        self.last_results = results
        self.data_to_clustering = data_to_clustering
        self.stacked_components = stacked_components
        self.update_chart()

    def save_typical(self, filename):
        assert self.last_results is not None
        if len(self.last_results) == 0:
            return
        cluster = OPTICS(min_samples=self.min_samples_input.value(),
                         min_cluster_size=self.min_cluster_size_input.value(),
                         xi=self.xi_input.value())
        classes_μm = self.last_results[0].classes_μm
        flags = cluster.fit_predict(self.data_to_clustering)
        flag_set = set(flags)
        typicals = []
        for flag in flag_set:
            if flag != -1:
                key = np.equal(flags, flag)
                typical = np.mean(self.stacked_components[key], axis=0)
                typicals.append(typical)

        wb = openpyxl.Workbook()
        prepare_styles(wb)
        ws = wb.active
        ws.title = self.tr("README")
        description = \
            """
            This Excel file was generated by QGrain ({0}).

            Please cite:
            Liu, Y., Liu, X., Sun, Y., 2021. QGrain: An open-source and easy-to-use software for the comprehensive analysis of grain size distributions. Sedimentary Geology 423, 105980. https://doi.org/10.1016/j.sedgeo.2021.105980

            It contanins 2 + N_clusters sheets:
            1. The first sheet is the sum distributions of all component clusters.
            2. The second sheet is used to put the component distributions that not in any cluster.
            3. The left sheet is the component distributions of each cluster, separately.

            The clustering algorithm is OPTICS, implemented by scikit-learn.
            https://scikit-learn.org/stable/modules/generated/sklearn.cluster.OPTICS.html

            Clustering algorithm details
                min_samples={1}
                min_cluster_size={2}
                xi={3}
                others=default

            """.format(QGRAIN_VERSION,
                       self.min_samples_input.value(),
                       self.min_cluster_size_input.value(),
                       self.xi_input.value())

        def write(row, col, value, style="normal_light"):
            cell = ws.cell(row + 1, col + 1, value=value)
            cell.style = style

        lines_of_desc = description.split("\n")
        for row, line in enumerate(lines_of_desc):
            write(row, 0, line, style="description")
        ws.column_dimensions[column_to_char(0)].width = 200

        ws = wb.create_sheet(self.tr("Typical Components"))
        write(0, 0, self.tr("Typical Component"), style="header")
        ws.column_dimensions[column_to_char(0)].width = 16
        for col, value in enumerate(classes_μm, 1):
            write(0, col, value, style="header")
            ws.column_dimensions[column_to_char(col)].width = 10
        for row, distribution in enumerate(typicals, 1):
            if row % 2 == 0:
                style = "normal_dark"
            else:
                style = "normal_light"
            write(row, 0, self.tr("Component{0}").format(row), style=style)
            for col, value in enumerate(distribution, 1):
                write(row, col, value, style=style)
            QCoreApplication.processEvents()

        for flag in flag_set:
            if flag == -1:
                ws = wb.create_sheet(self.tr("Not Clustered"), 2)
            else:
                ws = wb.create_sheet(self.tr("Cluster{0}").format(flag + 1))

            write(0, 0, self.tr("Index"), style="header")
            ws.column_dimensions[column_to_char(0)].width = 16
            for col, value in enumerate(classes_μm, 1):
                write(0, col, value, style="header")
                ws.column_dimensions[column_to_char(col)].width = 10
            key = np.equal(flags, flag)
            for row, component in enumerate(self.stacked_components[key], 1):
                if row % 2 == 0:
                    style = "normal_dark"
                else:
                    style = "normal_light"
                write(row, 0, str(row), style=style)
                for col, value in enumerate(component, 1):
                    write(row, col, value, style=style)
                QCoreApplication.processEvents()

        wb.save(filename)
        wb.close()

    def on_save_clicked(self):
        if len(self.last_results) == 0:
            self.show_warning(self.tr("There is not an SSU result."))
            return

        filename, _ = self.file_dialog.getSaveFileName(
            self,
            self.
            tr("Choose a filename to save the typical components of SSU results"
               ), None, f"{self.tr('Microsoft Excel')} (*.xlsx)")
        if filename is None or filename == "":
            return
        try:
            self.save_typical(filename)
            self.show_info(self.tr("The typical components have been saved."))
        except Exception as e:
            self.show_error(
                self.tr("Error raised while saving it to Excel file.\n    {0}"
                        ).format(e.__str__()))
            return
예제 #21
0
class Window(QWidget):
    #Creates an init method. Constructor
    def __init__(self):
        #Super returns the parent object of the class. #Calls the constructor of the QWidget
        super(Window, self).__init__()

        self.initUI()

    def initUI(self):

        #Titles and subtitles test
        self.titleTest = QLabel('<b>TEST</b>')
        self.titleTest.setFont(QFont('SansSerif', 14))
        self.subtitleTest = QLabel('Test selection:')

        #Dropdown test
        directorytestFiles = sorted(os.listdir())
        self.dropDownTest = QComboBox()
        for index in directorytestFiles:
            if index.find('.py') == -1:
                self.dropDownTest.addItem(index)
        self.dropDownTest.activated[str].connect(
            self.open_file)  #Connects the user's choice in the dropdown menu
        self.dropDownTest.setToolTip('List over Testfiles')

        #Textbox
        self.text = QTextEdit(self)
        self.text.hide()

        #SaveButton
        self.saveButton = QPushButton('Save')
        self.saveButton.setToolTip('Press to save the changes')
        self.saveButton.clicked.connect(self.save_text)

        #RunButton
        self.runButton = QPushButton('Run')
        self.runButton.setToolTip('Press to run the testfile')
        self.runButton.clicked.connect(self.run_test)

        #Titles and subtitles analyse
        self.titleAnalyse = QLabel('<b>ANALYSIS</b>')
        self.titleAnalyse.setFont(QFont('SansSerif', 14))
        self.subtitleAnalyse = QLabel('Load test data:')

        #FFT button
        self.fftButton = QCheckBox('FFT')
        self.fftButton.setToolTip('Fast Fourier Transform')

        #Dropdown analyse
        self.dropDownAnalyse = QComboBox()
        #Adds the files in the directory to a list
        directoryFiles = sorted(os.listdir())
        #Adds the text files in the directory to the drop down menu in alphabetical order
        for index in directoryFiles:
            #Ensures that only text files are displayed as options
            if index.find('.txt') != -1:
                self.dropDownAnalyse.addItem(index)
        self.dropDownAnalyse.activated[str].connect(self.plot)

        #For the graph. The figure is where the data is plotted and the canvas is where the figure is displayed.
        self.figure = plt.figure()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)

        self.toolbar.hide()

        #Layout
        #Creates a vertical box layout
        v1Layout = QVBoxLayout()
        #Creates horisontal box layouts
        h1Layout = QHBoxLayout()
        h2Layout = QHBoxLayout()
        h3Layout = QHBoxLayout()

        #Adds the widget for the test title to the vertical box layout
        v1Layout.addWidget(self.titleTest)

        #Adds widgets to the first horisontal layout
        h1Layout.addWidget(self.subtitleTest)
        h1Layout.addWidget(self.dropDownTest)

        #Pushes the widgets to the left corner
        h1Layout.addStretch(1)

        #Adds the first horisontal layout to the vertical layout
        v1Layout.addLayout(h1Layout)
        v1Layout.addWidget(self.text)

        h2Layout.addWidget(self.saveButton)
        h2Layout.addWidget(self.runButton)
        h2Layout.addStretch(1)

        v1Layout.addLayout(h2Layout)
        v1Layout.addWidget(self.titleAnalyse)

        h3Layout.addWidget(self.subtitleAnalyse)
        h3Layout.addWidget(self.dropDownAnalyse)
        h3Layout.addWidget(self.fftButton)
        h3Layout.addStretch(1)

        v1Layout.addLayout(h3Layout)

        #Layout for the graph
        v1Layout.addWidget(self.toolbar)
        v1Layout.addWidget(self.canvas)
        #Sets the font for the Tooltip elements
        QToolTip.setFont(QFont('SansSerif', 10))

        self.setLayout(v1Layout)
        self.setWindowTitle('MIDAS')
        #Shows the window
        self.show()

    #Function for dropdownbox
    def open_file(self, fileName):
        textFile = open(fileName).read()
        self.text.setText(textFile)
        self.text.show()

    #Lets the user save a document in a chosen folder
    def save_text(self):
        #Accesses the file dialog
        filename = QFileDialog.getSaveFileName(self, 'Save file',
                                               os.getenv('HOME'))
        with open(filename[0], 'w') as f:
            my_text = self.text.toPlainText()
            f.write(my_text)

    def run_test(self):
        pass

    #Plots the data (of the file passed as an argument) as a graph
    def plot(self, fileName):
        self.figure.clear()

        #Creates lists for the x and y coordinates
        xList = []
        yList = []

        #Opens and reads the file with the name passed as an argument to the function
        text_file = open(fileName, "r")
        lines = text_file.readlines()
        #Adds the data for the x and y coordinates to the corresponding lists
        for line in lines:
            x, y = line.split(',')
            x = float(x)
            y = float(y)
            xList.append(x)
            yList.append(y)
        text_file.close()

        #Sets the label of the y axis
        plt.ylabel('Voltage(V)')

        #Plots line at y = 0
        plt.axhline(0, color='black', linewidth=0.5)

        self.fftButton.stateChanged.connect(self.fft_function)

        #Sets the label of the x axis and plots either the "regular" graph or the graph after FFT
        if self.fftButton.isChecked():
            plt.xlabel('Frequency (Hz)')
            plt.plot(xList, fft(yList))

        else:
            plt.xlabel('Time (s)')
            plt.plot(xList, yList)

        plt.tight_layout()
        self.canvas.draw()

    def fft_function(self, state):
        pass
        """
class SliceWidget(FigureCanvas):
    def __init__(self, parent=None, dpi=100):
        # Create figure and axes, the axes should cover the entire figure size
        figure = Figure(dpi=dpi, frameon=False)
        self.axes = figure.add_axes((0, 0, 1, 1), facecolor='black')

        # Hide the x and y axis, we just want to see the image
        self.axes.get_xaxis().set_visible(False)
        self.axes.get_yaxis().set_visible(False)

        # Initialize the parent FigureCanvas
        FigureCanvas.__init__(self, figure)
        self.setParent(parent)

        # Set background of the widget to be close to black
        # The color is not made actually black so that the user can distinguish the image bounds from the figure bounds
        self.setStyleSheet('background-color: #222222;')

        # Set widget to have strong focus to receive key press events
        self.setFocusPolicy(Qt.StrongFocus)

        # Create navigation toolbar and hide it
        # We don't want the user to see the toolbar but we are making our own in the user interface that will call
        # functions from the toolbar
        self.toolbar = NavigationToolbar(self, self)
        self.toolbar.hide()

        # Update size policy and geometry
        FigureCanvas.setSizePolicy(self, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        self.isLPS = False
        self.isLAS = False
        self.image = None
        self.sliceNumber = 0
        self.diaphragmAxial = None
        self.umbilicisInferior = None
        self.umbilicisSuperior = None
        self.umbilicisLeft = None
        self.umbilicisRight = None
        self.umbilicisCoronal = None
        self.CATLine = None
        self.leftArmBounds = None
        self.rightArmBounds = None

    def updateFigure(self):
        # Clear the axes
        self.axes.cla()

        # Draw the image if it is set
        if self.image is not None:
            image = self.image[self.sliceNumber, :, :]

            # For viewing, we use right-anterior-superior (RAS) system. This is the same system that PATS uses.
            # For LPS volumes, we reverse the x/y axes to go from LPS to RAS.
            # Also, TTU data is in LAS which is odd but handle that too
            if self.isLPS:
                image = image[::-1, ::-1]
            elif self.isLAS:
                image = image[:, ::-1]

            self.axes.imshow(image, cmap='gray', origin='lower')

        # Draw rectangle on the diaphragm slice
        if self.sliceNumber == self.diaphragmAxial:
            self.axes.add_patch(patches.Rectangle((0, 0), 20, 20, color='purple'))

        # Draw a line where the umbilicis is set to be
        if self.umbilicisInferior is not None and self.umbilicisSuperior is not None and \
                self.umbilicisCoronal is not None and self.umbilicisLeft is not None and \
                self.umbilicisRight is not None:
            if self.umbilicisInferior <= self.sliceNumber <= self.umbilicisSuperior:
                x = self.umbilicisLeft
                y = self.umbilicisCoronal
                width = self.umbilicisRight - x
                height = 1

                self.axes.add_patch(patches.Rectangle((x, y), width, height, color='orange'))

        # Draw lines for the CAT bounding box configuration
        if self.CATLine is not None and len(self.CATLine) > 1:
            startIndex = next((i for i, x in enumerate(self.CATLine) if min(x) != -1), None)

            CATLine = self.CATLine[startIndex:]
            if len(CATLine) > 1 and CATLine[0][0] <= self.sliceNumber <= CATLine[-1][0]:
                posterior = int(np.round(np.interp(self.sliceNumber, np.array([i[0] for i in CATLine]),
                                                   np.array([i[1] for i in CATLine]))))
                anterior = int(np.round(np.interp(self.sliceNumber, np.array([i[0] for i in CATLine]),
                                                  np.array([i[2] for i in CATLine]))))

                x = self.image.shape[2] // 2.5
                y = posterior
                width = 75
                height = 1
                self.axes.add_patch(patches.Rectangle((x, y), width, height, color='red'))

                y = anterior
                self.axes.add_patch(patches.Rectangle((x, y), width, height, color='red'))

        # Draw a line for the left arm bounds at the current slice
        # Only draw if current slice is between smallest and largest bounds
        if self.leftArmBounds is not None and len(self.leftArmBounds) > 0 and \
                (self.leftArmBounds[0][-1] <= self.sliceNumber <= self.leftArmBounds[-1][-1]):
            # Get a list of slice numbers for the left arm bounds
            xp = np.array([i[4] for i in self.leftArmBounds])

            # Get list of x/y coordinates at the slice numbers
            x1p, y1p = np.array([i[0] for i in self.leftArmBounds]), np.array([i[1] for i in self.leftArmBounds])
            x2p, y2p = np.array([i[2] for i in self.leftArmBounds]), np.array([i[3] for i in self.leftArmBounds])

            # Interpolate for given slice between the bounds, round and convert to an integer
            x1, y1 = int(np.round(np.interp(self.sliceNumber, xp, x1p))), \
                     int(np.round(np.interp(self.sliceNumber, xp, y1p)))
            x2, y2 = int(np.round(np.interp(self.sliceNumber, xp, x2p))), \
                     int(np.round(np.interp(self.sliceNumber, xp, y2p)))

            self.axes.plot([x1, x2], [y1, y2], 'g', lw=2.0)

        # Draw a line for the right arm bounds at the current slice
        # Only draw if current slice is between smallest and largest bounds
        if self.rightArmBounds is not None and len(self.rightArmBounds) > 0 and \
                (self.rightArmBounds[0][-1] <= self.sliceNumber <= self.rightArmBounds[-1][-1]):
            # Get a list of slice numbers for the left arm bounds
            xp = np.array([i[4] for i in self.rightArmBounds])

            # Get list of x/y coordinates at the slice numbers
            x1p, y1p = np.array([i[0] for i in self.rightArmBounds]), np.array([i[1] for i in self.rightArmBounds])
            x2p, y2p = np.array([i[2] for i in self.rightArmBounds]), np.array([i[3] for i in self.rightArmBounds])

            # Interpolate for given slice between the bounds, round and convert to an integer
            x1, y1 = int(np.round(np.interp(self.sliceNumber, xp, x1p))), \
                     int(np.round(np.interp(self.sliceNumber, xp, y1p)))
            x2, y2 = int(np.round(np.interp(self.sliceNumber, xp, x2p))), \
                     int(np.round(np.interp(self.sliceNumber, xp, y2p)))

            self.axes.plot([x1, x2], [y1, y2], 'g', lw=1.5)

        # Draw the figure now
        self.draw()
예제 #23
0
class MixedDistributionChart(QDialog):
    def __init__(self, parent=None, show_mode=True, toolbar=False, use_animation=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("Mixed Distribution Chart"))
        self.figure = plt.figure(figsize=(4, 3))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)
        if not toolbar:
            self.toolbar.hide()
        self.supported_scales = [("log-linear", self.tr("Log-linear")),
                                 ("log", self.tr("Log")),
                                 ("phi", self.tr("φ")),
                                 ("linear", self.tr("Linear"))]

        self.scale_label = QLabel(self.tr("Scale"))
        self.scale_combo_box = QComboBox()
        self.scale_combo_box.addItems([name for key, name in self.supported_scales])
        self.scale_combo_box.currentIndexChanged.connect(self.update_chart)
        self.main_layout.addWidget(self.scale_label, 2, 0)
        self.main_layout.addWidget(self.scale_combo_box, 2, 1)
        self.interval_label = QLabel(self.tr("Interval [ms]"))
        self.interval_input = QSpinBox()
        self.interval_input.setRange(0, 10000)
        self.interval_input.setValue(30)
        self.interval_input.valueChanged.connect(self.update_animation)
        self.main_layout.addWidget(self.interval_label, 3, 0)
        self.main_layout.addWidget(self.interval_input, 3, 1)
        self.repeat_check_box = QCheckBox(self.tr("Repeat"))
        self.repeat_check_box.setChecked(False)
        self.repeat_check_box.stateChanged.connect(self.update_animation)
        self.save_button = QPushButton(self.tr("Save"))
        self.save_button.clicked.connect(self.save_animation)
        self.main_layout.addWidget(self.repeat_check_box, 4, 0)
        self.main_layout.addWidget(self.save_button, 4, 1)
        self.show_mode = show_mode
        self.animation = None
        self.last_model = None
        self.last_result = None

        if not use_animation:
            self.interval_label.setVisible(False)
            self.interval_input.setVisible(False)
            self.repeat_check_box.setVisible(False)
            self.save_button.setVisible(False)

        self.normal_msg = QMessageBox(parent=self)
        self.file_dialog = QFileDialog(parent=self)

    @property
    def scale(self) -> str:
        index = self.scale_combo_box.currentIndex()
        key, name = self.supported_scales[index]
        return key

    @property
    def transfer(self) -> typing.Callable:
        if self.scale == "log-linear":
            return lambda classes_φ: convert_φ_to_μm(classes_φ)
        elif self.scale == "log":
            return lambda classes_φ: np.log(convert_φ_to_μm(classes_φ))
        elif self.scale == "phi":
            return lambda classes_φ: classes_φ
        elif self.scale == "linear":
            return lambda classes_φ: convert_φ_to_μm(classes_φ)

    @property
    def xlabel(self) -> str:
        if self.scale == "log-linear":
            return self.tr("Grain-size [μm]")
        elif self.scale == "log":
            return self.tr("Ln(grain-size in μm)")
        elif self.scale == "phi":
            return self.tr("Grain-size [φ]")
        elif self.scale == "linear":
            return self.tr("Grain-size [μm]")

    @property
    def ylabel(self) -> str:
        return self.tr("Frequency")

    @property
    def xlog(self) -> bool:
        if self.scale == "log-linear":
            return True
        else:
            return False

    @property
    def interval(self) -> float:
        return self.interval_input.value()

    @property
    def repeat(self) -> bool:
        return self.repeat_check_box.isChecked()

    def show_demo(self):
        demo_model = get_demo_view_model()
        self.show_model(demo_model)

    def update_chart(self):
        if self.last_model is not None:
            self.show_model(self.last_model)
        elif self.last_result is not None:
            self.show_result(self.last_result)

    def update_animation(self):
        if self.last_result is not None:
            self.show_result(self.last_result)

    def show_model(self, model: SSUViewModel, quick=False):
        if self.animation is not None:
            self.animation._stop()
            self.animation = None
        if not quick:
            self.last_result = None

            self.last_model = model
            self.interval_label.setEnabled(False)
            self.interval_input.setEnabled(False)
            self.repeat_check_box.setEnabled(False)
            self.save_button.setEnabled(False)

            self.axes.clear()
            x = self.transfer(model.classes_φ)
            if self.xlog:
                self.axes.set_xscale("log")
            self.axes.set_title(model.title)
            self.axes.set_xlabel(self.xlabel)
            self.axes.set_ylabel(self.ylabel)
            self.target = self.axes.plot(x, model.target, c="#ffffff00", marker=".", ms=8, mfc="black", mew=0.0, label=self.tr("Target"))[0]
            # scatter can not be modified from the tool bar
            # self.target = self.axes.scatter(x, model.target, c="black", s=1)
            self.axes.set_xlim(x[0], x[-1])
            self.axes.set_ylim(0.0, round(np.max(model.target)*1.2, 2))
            self.mixed = self.axes.plot(x, model.mixed, c="black", label=self.tr("Mixed"))[0]
            self.components = [self.axes.plot(x, distribution*fraction, c=plt.get_cmap()(i), label=model.component_prefix+str(i+1))[0] for i, (distribution, fraction) in enumerate(zip(model.distributions, model.fractions))]
            if self.show_mode:
                modes = [self.transfer(model.classes_φ[np.unravel_index(np.argmax(distribution), distribution.shape)])  for distribution in model.distributions]
                colors = [plt.get_cmap()(i) for i in range(model.n_components)]
                self.vlines = self.axes.vlines(modes, 0.0, round(np.max(model.target)*1.2, 2), colors=colors)
            if model.n_components < 6:
                self.axes.legend(loc="upper left")
            self.figure.tight_layout()
            self.canvas.draw()
        else:
            self.mixed.set_ydata(model.mixed)
            for comp, distribution, fraction in zip(self.components, model.distributions, model.fractions):
                comp.set_ydata(distribution*fraction)
            if self.show_mode:
                modes = [self.transfer(model.classes_φ[np.unravel_index(np.argmax(distribution), distribution.shape)])  for distribution in model.distributions]
                self.vlines.set_offsets(modes)
            self.canvas.draw()

    def show_result(self, result: SSUResult):
        if self.animation is not None:
            self.animation._stop()
            self.animation = None
        self.last_model = None
        self.last_result = result
        self.interval_label.setEnabled(True)
        self.interval_input.setEnabled(True)
        self.repeat_check_box.setEnabled(True)
        self.save_button.setEnabled(True)

        models = iter(result.view_models)
        first = next(models)
        x = self.transfer(first.classes_φ)
        self.axes.cla()
        if self.xlog:
            self.axes.set_xscale("log")
        self.axes.set_title(first.title)
        self.axes.set_xlabel(self.xlabel)
        self.axes.set_ylabel(self.ylabel)
        self.target = self.axes.plot(x, first.target, c="#ffffff00", marker=".", ms=8, mfc="black", mew=0.0)[0]
        self.axes.set_xlim(x[0], x[-1])
        self.axes.set_ylim(0.0, round(np.max(first.target)*1.2, 2))
        self.figure.tight_layout()
        # self.canvas.draw()
        colors = [plt.get_cmap()(i) for i in range(first.n_components)]
        def init():
            model = first
            self.mixed = self.axes.plot(x, model.mixed, c="black")[0]
            self.components = [self.axes.plot(x, distribution*fraction, c=plt.get_cmap()(i))[0] for i, (distribution, fraction) in enumerate(zip(model.distributions, model.fractions))]
            if self.show_mode:
                modes = [self.transfer(model.classes_φ[np.unravel_index(np.argmax(distribution), distribution.shape)])  for distribution in model.distributions]
                self.vlines = self.axes.vlines(modes, 0.0, round(np.max(model.target)*1.2, 2), colors=colors)
            return self.mixed, self.vlines, *self.components
        def animate(current):
            model = current
            self.mixed.set_ydata(current.mixed)
            for line, distribution, fraction in zip(self.components, model.distributions, model.fractions):
                line.set_ydata(distribution*fraction)
            if self.show_mode:
                self.vlines.remove()
                modes = [self.transfer(model.classes_φ[np.unravel_index(np.argmax(distribution), distribution.shape)])  for distribution in model.distributions]
                self.vlines = self.axes.vlines(modes, 0.0, round(np.max(model.target)*1.2, 2), colors=colors)
            return self.mixed, self.vlines, *self.components
        self.animation = FuncAnimation(self.figure, animate, frames=models, init_func=init,
                                       interval=self.interval, blit=True,
                                       repeat=self.repeat, repeat_delay=3.0, save_count=result.n_iterations)

    def save_animation(self):
        if self.last_result is not None:
            filename, format_str = self.file_dialog.getSaveFileName(self, self.tr("Save the animation of this SSU result"), None, self.tr("MPEG-4 Video File (*.mp4);;Graphics Interchange Format (*.gif)"))
            if filename is None or filename == "":
                return
            progress = QProgressDialog(self)
            progress.setRange(0, 100)
            progress.setLabelText(self.tr("Saving Animation [{0} Frames]").format(self.last_result.n_iterations))
            canceled = False
            def save_callback(i, n):
                if progress.wasCanceled():
                    nonlocal canceled
                    canceled = True
                    raise StopIteration()
                progress.setValue((i+1)/n*100)
                QCoreApplication.processEvents()
            self.show_result(self.last_result)
            # plt.rcParams["savefig.dpi"] = 120.0
            if "*.gif" in format_str:
                if not ImageMagickWriter.isAvailable():
                    self.normal_msg.setWindowTitle(self.tr("Error"))
                    self.normal_msg.setText(self.tr("ImageMagick is not installed, please download and install it from its offical website (https://imagemagick.org/index.php)."))
                    self.normal_msg.exec_()
                else:
                    self.animation.save(filename, writer="imagemagick", fps=30, progress_callback=save_callback)
            elif "*.mp4" in format_str:
                if not FFMpegWriter.isAvailable():
                    self.normal_msg.setWindowTitle(self.tr("Error"))
                    self.normal_msg.setText(self.tr("FFMpeg is not installed, please download and install it from its offical website (https://ffmpeg.org/)."))
                    self.normal_msg.exec_()
                else:
                    self.animation.save(filename, writer="ffmpeg", fps=30, progress_callback=save_callback)
            # plt.rcParams["savefig.dpi"] = 300.0
            if not canceled:
                progress.setValue(100)
예제 #24
0
class spectralPattern_window(QDialog):
    def __init__(self,pxx,frequencies,data,Fs):         
        QDialog.__init__(self);
        loadUi('graph_spectral.ui',self);
        self.setWindowIcon(QtGui.QIcon("logo.png"))
        self.label_title.setText('Eliminación de artefactos por espectro de potencia')
        self.label_maxValue.setText('Valor máximo [potencia]')
        
        self.data=data
        self.Fs=Fs
        self.channels,self.points=shape(self.data)
        self.epochs(self.data, self.channels, self.points)
        self.pxx=pxx
        self.frequencies=frequencies
        
        
            
        
        self.button_zoom.clicked.connect(self.zoom)
        self.button_pan.clicked.connect(self.pan)
        self.button_home.clicked.connect(self.home)
        self.button_apply.clicked.connect(self.implementation)
        self.button_cancel.clicked.connect(self.cancelar)
        self.figure = Figure(figsize=(5,4), dpi=100)
        self.canvas = FigureCanvas(self.figure)
        self.axes=self.figure.add_subplot(111)
        self.toolbar=NavigationToolbar(self.canvas,self)
        self.toolbar.hide()
         
        layout=QVBoxLayout()
        layout.addWidget(self.toolbar)
        layout.addWidget(self.canvas)
        self.field_graph.setLayout(layout)
        self.axes.clear()
        self.canvas.draw()
        self.plot()
        
    def cancelar(self):
        spectralPattern_window.close(self);
        
    def home(self):
        self.toolbar.home()
    def zoom(self):
        self.toolbar.zoom()
    def pan(self):
        self.toolbar.pan()
         
    def plot(self):
        legends=['Ch 1','Ch 2','Ch 3','Ch 4','Ch 5','Ch 6','Ch 7','Ch 8']
        r=[]
        
        for c in range(shape(self.pxx)[0]):
            r.append(c*35)
            self.axes.plot(self.frequencies[c,::],sqrt(self.pxx[c,::])+c*35,linewidth=0.5)
        self.axes.set_yticklabels(legends)
        self.axes.set_yticks(r)
        self.axes.grid(True)
        self.axes.set_xlim([0,40])
        self.axes.set_xlabel('Frecuency [Hz]')
        self.axes.set_ylabel('Power density [V^2/Hz]')
        self.axes.set_title('Periodograma de Welch') 
        
    def epochs(self,data,channels,points):
      
        self.filtered_signal=data
        
        self.size_epoch=self.Fs*2
        self.num_epoch=points/self.size_epoch
        delete=points%self.size_epoch
          
        self.filtered_signal=self.filtered_signal[::,0:(points-delete)]
        self.epochs_file=reshape(self.filtered_signal,(channels,int(self.size_epoch),int((points-delete)/self.size_epoch)),order='F')
        return(self.epochs_file)
#         
    def implementation(self):
        max_value=float(self.field_maxValue.text())
        self.myepochs=self.epochs(self.data, self.channels, self.points)
        x,y=spectral_pattern.spectral(self.myepochs, max_value,self.Fs)
        newSignal=reshape(x,(shape(x)[0],shape(x)[1]*shape(x)[2]),order='F')
        self.graph_method = window_graph(self.data, self.Fs,3,newSignal,y,shape(self.myepochs)[2]);
        self.graph_method.show();
class MplGraphQt5Widget(QWidget):
    def __init__(self, parent=None):
        super(MplGraphQt5Widget, self).__init__(parent)

        self.width = 3
        self.height = 3
        self.dpi = 100

        self._dataY = np.array([])
        self._dataX = np.array([])

        self._spCols = 1
        self._spRows = 1
        self.all_sp_axes = []
        self.fig = Figure(figsize=(self.width, self.height), dpi=self.dpi)
        self.all_sp_axes.append(self.fig.add_subplot(self._spCols, self._spRows, 1))
        self.fig.set_frameon(False)
        self.fig.set_tight_layout(True)

        self.canvas = Canvas(self.fig)

        self._navBarOn = False
        self.mpl_toolbar = NavigationToolbar(self.canvas, parent)
        self.mpl_toolbar.dynamic_update()

        self.canvas.mpl_connect('key_press_event', self.on_key_press)
        self.canvas.mpl_connect('button_press_event', self.on_button_press)
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
        self.canvas.setFocusPolicy(Qt.ClickFocus)
        self.canvas.setFocus()

        self.canvas.setParent(parent)
        self.canvas.clearMask()
        self.canvas.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.canvas.updateGeometry()

        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        if not self._navBarOn:
            self.mpl_toolbar.hide()
        self.setLayout(vbox)



    def get_icon(name):
        """Return Matplotlib icon *name*"""
        return QIcon(osp.join(rcParams['datapath'], 'images', name))


    key_pressed = pyqtSignal(object, name='keyPressed')

    def on_key_press(self, event):
        self.key_pressed.emit(event)
        key_press_handler(event, self.canvas, self.mpl_toolbar)

    button_pressed = pyqtSignal(object, name='buttonPressed')

    def on_button_press(self, event):
        self.button_pressed.emit(event)
        key_press_handler(event, self.canvas, self.mpl_toolbar)

    mouse_move = pyqtSignal(object, name='mouseMoved')

    def on_mouse_move(self, event):
        self.mouse_move.emit(event)
        key_press_handler(event, self.canvas, self.mpl_toolbar)


    def generateNewAxes(self):
        for ax in self.all_sp_axes:
            self.fig.delaxes(ax)
        self.all_sp_axes = []
        numOfAxes = (self._spRows*self._spCols)+1
        for i in np.arange(1,numOfAxes):
            self.all_sp_axes.append(self.fig.add_subplot(self._spRows, self._spCols, i))
        self.canvas.setGeometry(100, 100, 300, 300)  #Used to update the new number of axes
        self.canvas.updateGeometry()  #This will bring the size of the canvas back to the original (defined by the vbox)

    spRowsChanged = pyqtSignal(int)

    def getspRows(self):
        return self._spRows

    @pyqtSlot(int)
    def setspRows(self, spRows):
        self._spRows = spRows
        self.generateNewAxes()
        self.spRowsChanged.emit(spRows)

    def resetspRows(self):
        self.setspRows(1)

    spRows = pyqtProperty(int, getspRows, setspRows, resetspRows)

    spColsChanged = pyqtSignal(int)

    def getspCols(self):
        return self._spCols

    @pyqtSlot(int)
    def setspCols(self, spCols):
        self._spCols = spCols
        self.generateNewAxes()
        self.spRowsChanged.emit(spCols)

    def resetspCols(self):
        self.setspCols(1)

    spCols = pyqtProperty(int, getspCols, setspCols, resetspCols)

    dataChanged = pyqtSignal(bool)

    def get_Y_data(self):
        return self._dataY

    @pyqtSlot(int)
    def set_Y_data(self, y_data):
        self._dataY = y_data
        self.dataChanged.emit(True)


    def plot(self, on_axes=0):
        if np.size(self._dataX) == 0:
            self.all_sp_axes[on_axes].plot(self._dataY)
        else:
            self.all_sp_axes[on_axes].plot(self._dataX, self._dataY)

    def getNavBarOn(self):
        return self._navBarOn

    def setNavBarOn(self, navBarOn):
        self._navBarOn = navBarOn
        if not navBarOn:
            self.mpl_toolbar.hide()
        else:
            self.mpl_toolbar.show()

    def resetNavBarOn(self):
        self._navBarOn = True

    navBarOn = pyqtProperty(bool, getNavBarOn, setNavBarOn, resetNavBarOn)

    @pyqtSlot(bool)
    def set_autoscale(self, autoscale):
        for axis in self.all_sp_axes:
            axis.set_autoscale(autoscale)
예제 #26
0
파일: plotwindow.py 프로젝트: pfechd/jabe
class CustomPlot(QDialog):
    """
    Class used to create a plot window

    Data is read from session object
    """

    _colors = ['#FF0000', '#0000FF', '#00FF00', '#00002C', '#FF1AB9',
                '#FFD300', '#005800', '#8484FF', '#9E4F46', '#00FFC1',
                '#008495', '#00007B', '#95D34F', '#F69EDC', '#D312FF']

    def __init__(self, parent, session):
        """
        Create plot window

        :param parent: Parent window object
        :param session: Session object to plot data from
        """

        super(CustomPlot, self).__init__(parent)
        self.amp = []
        self.peak_time = []
        self.fwhm = []
        self.regular = []
        self.smooth = []
        self.sem = []
        self.scroll = 3
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        self.used_colors = []

        self.session = session
        self.fig = plt.figure()

        self.current_ax = self.fig.add_subplot(111)
        self.axes = {}
        self.ax_list = []

        self.add_ax(self.current_ax)

        self.ui.toolButton_anatomy.hide()

        if session.anatomy is not None:
            self.ui.toolButton_anatomy.show()

        self.canvas = FigureCanvas(self.fig)
        self.toolbar = NavigationToolbar(self.canvas, self, coordinates=True)
        self.toolbar.hide()

        self.ui.mplvl.addWidget(self.canvas)

        self.ui.checkBox_fwhm.clicked.connect(self.plot_fwhm)
        self.ui.checkBox_sem.clicked.connect(self.plot_sem)
        self.ui.checkBox_regular.clicked.connect(self.replot)
        self.ui.checkBox_smooth.clicked.connect(self.replot)
        self.ui.checkBox_amp.clicked.connect(self.plot_amplitude)
        self.ui.checkBox_peak.clicked.connect(self.plot_peak)
        self.ui.stimuliBox.currentTextChanged.connect(self.replot)
        self.ui.mean_response_btn.clicked.connect(self.replot)
        self.ui.several_responses_btn.clicked.connect(self.replot)
        self.ui.checkBox_labels.clicked.connect(self.show_legends)
        self.ui.label_size.valueChanged.connect(self.show_legends)

        self.ui.spinBox.valueChanged.connect(self.replot)

        self.ui.toolButton_home.clicked.connect(self.toolbar.home)
        self.ui.toolButton_export.clicked.connect(self.tool_export)
        self.ui.toolButton_pan.clicked.connect(self.toolbar.pan)
        self.ui.toolButton_zoom.clicked.connect(self.toolbar.zoom)
        self.ui.toolButton_anatomy.clicked.connect(self.tool_anatomy)

        self.setWindowTitle('Plot - ' + session.name)
        self.export_window = None
        self.add_stimuli_types()

        # Enable the 'plot several' button if the object has more than 1 child
        children = self.session.children + self.session.sessions
        if children and len(children) > 1:
            self.ui.several_responses_btn.setEnabled(True)
        else:
            self.ui.several_responses_btn.hide()

        self.ui.toolButton_add_subplot.clicked.connect(self.add_subplot)
        self.ui.toolButton_rem_subplot.clicked.connect(self.remove_subplot)

        # Move the subplot to make space for the legend
        self.fig.subplots_adjust(right=0.8)

        self.canvas.mpl_connect('button_press_event', self.click_plot)
        self.fig.tight_layout(pad=2.0)

        # Change default value in smooth wheel if percent is used
        if self.session.get_setting("percent"):
            self.ui.spinBox.setValue(2)

        self.replot()
        self.show()
        self.ui.verticalLayout_3.update()

    def highlight_current_axis(self):
        if self.current_ax is not None:
            for ax in self.axes:
                ax.spines['bottom'].set_color('black')
                ax.spines['top'].set_color('black')
                ax.spines['right'].set_color('black')
                ax.spines['left'].set_color('black')

            self.current_ax.spines['bottom'].set_color('red')
            self.current_ax.spines['top'].set_color('red')
            self.current_ax.spines['right'].set_color('red')
            self.current_ax.spines['left'].set_color('red')

    def add_subplot(self):
        n = len(self.axes)
        i = 0

        for ax in self.ax_list:
            self.fig.delaxes(ax)
            ax.change_geometry(((n + 1) / 2) + (1 * ((n + 1) % 2)), 2,  (i + 1))
            i += 1

        if n == 0:
            new_ax = self.fig.add_subplot(1, 1, 1)
        else:
            for ax in self.ax_list:
                self.fig.add_axes(ax)
            new_ax = self.fig.add_subplot(((n + 1) / 2) + (1 * ((n + 1) % 2)), 2, n + 1)

        self.add_ax(new_ax)

        if len(self.axes) == 1:
            self.current_ax = new_ax
            self.load_ax_settings()
        else:
            self.highlight_current_axis()


        self.fig.tight_layout()
        self.set_allowed_buttons()
        self.canvas.draw()

    def remove_subplot(self):
        self.axes.pop(self.current_ax)
        self.ax_list.remove(self.current_ax)
        self.fig.delaxes(self.current_ax)

        n = len(self.axes)

        if n == 1:
            self.fig.axes[0].change_geometry(1, 1, 1)
        else:
            for i in xrange(n):
                self.fig.axes[i].change_geometry((n / 2) + (1 * (n % 2)), 2,  (i + 1))

        if self.fig.axes:
            self.current_ax = self.fig.axes[0]
            self.load_ax_settings()
        else:
            self.current_ax = None

        self.highlight_current_axis()
        self.set_allowed_buttons()
        self.canvas.draw()

    def add_ax(self, ax):
        if ax is not None:
            self.ax_list.append(ax)
            # Change default value in smooth wheel if percent is used
            smooth = 2 if self.session.get_setting("percent") else 20
            self.axes[ax] = {'plot': 'mean',
                             'data': {'regular': False,
                                      'smooth': False,
                                      'smooth_fact': smooth,
                                      'stimuli_type': 0,
                                      },
                             'settings': {'amp': False,
                                          'peak': False,
                                          'sem': False,
                                          'fwhm': False},
                             'datalog': {'amp_label': '',
                                         'peak_label': '',
                                         'fwhm_label': ''},
                             'used_colors': []
                             }

    def save_ax_settings(self, ax):
        if self.ui.mean_response_btn.isChecked():
            plot = 'mean'
        else:
            plot = 'several'

        if ax is not None:
            self.axes[ax] = {'plot': plot,
                             'data': {'regular': self.ui.checkBox_regular.isChecked(),
                                      'smooth': self.ui.checkBox_smooth.isChecked(),
                                      'smooth_fact': self.ui.spinBox.value(),
                                      'stimuli_type': self.ui.stimuliBox.currentIndex(),
                                      },
                             'settings': {'amp': self.ui.checkBox_amp.isChecked(),
                                          'peak': self.ui.checkBox_peak.isChecked(),
                                          'sem': self.ui.checkBox_sem.isChecked(),
                                          'fwhm': self.ui.checkBox_fwhm.isChecked()},
                             'datalog': {'amp_label': self.ui.amp_label.text(),
                                         'peak_label': self.ui.peak_label.text(),
                                         'fwhm_label': self.ui.fwhm_label.text()},
                             'used_colors': self.used_colors
                             }

    def load_ax_settings(self):
        ax = self.current_ax

        self.ui.mean_response_btn.setChecked(self.axes[ax]['plot'] == 'mean')
        self.ui.several_responses_btn.setChecked(self.axes[ax]['plot'] == 'several')

        self.ui.checkBox_regular.setChecked(self.axes[ax]['data']['regular'])
        self.ui.checkBox_smooth.setChecked(self.axes[ax]['data']['smooth'])

        self.ui.spinBox.blockSignals(True)
        self.ui.spinBox.setValue(self.axes[ax]['data']['smooth_fact'])
        self.ui.spinBox.blockSignals(False)

        self.ui.stimuliBox.blockSignals(True)
        self.ui.stimuliBox.setCurrentIndex(self.axes[ax]['data']['stimuli_type'])
        self.ui.stimuliBox.blockSignals(False)

        self.ui.checkBox_amp.setChecked(self.axes[ax]['settings']['amp'])
        self.ui.checkBox_peak.setChecked(self.axes[ax]['settings']['peak'])
        self.ui.checkBox_sem.setChecked(self.axes[ax]['settings']['sem'])
        self.ui.checkBox_fwhm.setChecked(self.axes[ax]['settings']['fwhm'])

        self.ui.fwhm_label.setText(self.axes[ax]['datalog']['fwhm_label'])
        self.ui.peak_label.setText(self.axes[ax]['datalog']['peak_label'])
        self.ui.amp_label.setText(self.axes[ax]['datalog']['amp_label'])

        self.used_colors = self.axes[ax]['used_colors']

    def click_plot(self, event):
        if event.inaxes:
            self.save_ax_settings(self.current_ax)
            self.current_ax = event.inaxes
            self.load_ax_settings()
            self.set_allowed_buttons()
            self.highlight_current_axis()
            self.canvas.draw()

    def tool_anatomy(self):
         self.anatomy_window = AnatomyWindow(self, self.session)

    def tool_export(self):
        """
        Export button callback. Creates a custom export window
        """
        self.export_window = ExportWindow(self, self.session, self.toolbar, self.ui.stimuliBox.currentText())

    def plot_fwhm(self):
        """
        If fwhm checkbox is checked this function will update fwhm
        span and datalog info.
        If fwhm checkbox is not checked this function will remove 
        fwhm span and datalog info.
        """
        self.remove_fwhm(uncheck=False)
        if not (self.ui.checkBox_smooth.isChecked() \
                or self.ui.checkBox_regular.isChecked()) \
                or self.ui.several_responses_btn.isChecked():
            self.ui.fwhm_label.hide()
            return
        
        if self.ui.checkBox_fwhm.isChecked():
            try:
                fwhm = self.session.get_fwhm(self.ui.stimuliBox.currentText(),
                                      self.ui.spinBox.value())
            except Exception as exc:
                self.ui.checkBox_fwhm.setChecked(False)
                QMessageBox.warning(self, exc.args[0], exc.args[1])
                return
            fwhm_text = ""
            for stimuli_val, values in fwhm.iteritems():
                self.fwhm.append(self.current_ax.axvspan(
                        values[0], values[1], facecolor='g', alpha=0.2))
                fwhm_text += "FWHM " + stimuli_val + " width: " + \
                        str(values[1] - values[0]) + "\n"
            self.ui.fwhm_label.setText(fwhm_text[0:-1])
            self.ui.fwhm_label.show()
        else:
            self.ui.fwhm_label.hide()
        self.canvas.draw()
                
    def replot(self):
        """
        Replot regular and smoothed curve, amplitude, peak and fwhm. 
        Used when changing the data to plot and callback function for
        many checkboxes.
        """
        self.remove_sem()

        self.remove_regular_plots()
        self.plot_regular()
        self.remove_smoothed_plots()
        self.plot_smooth()
        
        self.plot_peak()
        self.plot_amplitude()
        self.plot_fwhm()
        self.plot_sem()
        self.set_allowed_buttons()

    def remove_peak_time(self, uncheck=True):
        if self.peak_time:
            for peak in self.peak_time:
                if peak.axes == self.current_ax:
                    peak.remove()
                    self.ui.peak_label.hide()
                    if uncheck:
                        self.ui.checkBox_peak.setChecked(False)
            self.peak_time = []

    def remove_sem(self):
        if self.sem:
            for sem in self.sem:
                if sem[0].axes == self.current_ax:
                    self.used_colors.remove(sem[0].get_color())
                    sem[0].remove()
                    for line in sem[1]:
                        line.remove()
                    for line in sem[2]:
                        line.remove()

                    self.ui.checkBox_sem.setChecked(False)

    def remove_amplitude(self, uncheck=True):
        if self.amp:
            for amp in self.amp:
                if amp.axes == self.current_ax:
                    amp.remove()
                    self.ui.amp_label.hide()
                    if uncheck:
                        self.ui.checkBox_amp.setChecked(False)
            self.amp = []

    def remove_fwhm(self, uncheck=True):
        if self.fwhm:
            for fwhm in self.fwhm:
                if fwhm.axes == self.current_ax:
                    fwhm.remove()
                    self.ui.fwhm_label.hide()
                    if uncheck:
                        self.ui.checkBox_fwhm.setChecked(False)

    def remove_regular_plots(self):
        if self.regular:
            for axis in self.regular:
                if axis.axes == self.current_ax:
                    self.used_colors.remove(axis.get_color())
                    axis.remove()

    def plot_smooth(self):
        """
        Plot smoothed responses from session object if smoothed checkbox 
        is checked.
        Will otherwise hide smoothed responses
        """

        if self.ui.checkBox_smooth.isChecked() and self.ui.mean_response_btn.isChecked():
            self.current_ax.relim()
            try:
                smooth = self.session.get_smooth(self.ui.spinBox.value())
            except Exception as exc:
                self.ui.checkBox_smooth.setChecked(False)
                QMessageBox.warning(self, exc.args[0], exc.args[1])
                return

            if self.ui.stimuliBox.currentText() == "All":
                for stimuli_type, smoothed_data in smooth.iteritems():
                    axis, = self.current_ax.plot(
                            self.session.get_x_axis(), smoothed_data,
                            color=self.get_color(), label=stimuli_type + ", smoothed")
                    self.smooth.append(axis)
            else:
                stimuli_value = self.ui.stimuliBox.currentText()
                axis, = self.current_ax.plot(
                        self.session.get_x_axis(), smooth[stimuli_value],
                        color=self.get_color(), label=stimuli_value + ", smoothed")
                self.smooth.append(axis)
        else:
            self.remove_smoothed_plots()

        self.show_legends()
        self.set_allowed_buttons()
        self.canvas.draw()

    def remove_smoothed_plots(self):
        if self.smooth:
            for axis in self.smooth:
                if axis.axes == self.current_ax:
                    self.used_colors.remove(axis.get_color())
                    axis.remove()

    def plot_mean(self):
        """
        Plot mean responses from session object if mean checkbox 
        is checked.
        Will otherwise hide mean responses
        """
        if self.ui.checkBox_regular.isChecked():
            self.current_ax.relim()
            mean = self.session.get_mean()
            self.plot_data(mean)

        else:
            self.remove_regular_plots()

        self.show_legends()
        self.canvas.draw()

    def plot_sem(self):
        """
        Standard error of mean checkbox callback. Plot standard error of mean.
        """

        if self.ui.checkBox_sem.isChecked() and self.ui.stimuliBox.currentText() != "All":
            mean = self.session.get_mean()[self.ui.stimuliBox.currentText()]
            x = np.arange(mean.size)*self.session.get_tr()
            self.current_ax.relim()
            sem = self.session.get_sem()
            self.sem.append(self.current_ax.errorbar(x, mean, color=self.get_color(), yerr=sem[self.ui.stimuliBox.currentText()]))
        else:
            self.remove_sem()
        self.canvas.draw()

    def plot_amplitude(self):
        """
        If amplitude checkbox is checked this function will update amplitude
        lines and datalog info.
        If amplitude checkbox is not checked this function will remove 
        amplitude lines and datalog info.
        """
        self.remove_amplitude(uncheck=False)
        if not (self.ui.checkBox_smooth.isChecked() \
                or self.ui.checkBox_regular.isChecked()) \
                or self.ui.several_responses_btn.isChecked():
            self.ui.amp_label.hide()
            return

        if self.ui.checkBox_amp.isChecked():
            try:
                points = self.session.get_peaks(
                        self.ui.spinBox.value(),
                        smooth=self.ui.checkBox_smooth.isChecked())
            except Exception as exc:
                self.ui.checkBox_amp.setChecked(False)
                QMessageBox.warning(self, exc.args[0], exc.args[1])
                return
            amp_text = ""

            if self.ui.stimuliBox.currentText() == "All":
                for stimuli_val, position in points.iteritems():
                    amp_text += self.__plot_amp(stimuli_val, position)
            else:
                stimuli_val = self.ui.stimuliBox.currentText()
                amp_text = self.__plot_amp(stimuli_val, points[stimuli_val])
            self.ui.amp_label.setText(amp_text[0:-1])
            self.ui.amp_label.show()
        else:
            self.ui.amp_label.hide()
        self.canvas.draw()


    def __plot_amp(self, stimuli_val, position):
        self.amp.append(
                self.current_ax.axhline(position[1], color=CustomPlot._colors[-1]))
        if self.ui.checkBox_smooth.isChecked():
            start_value = self.session.get_smooth(self.ui.spinBox.value())[stimuli_val][0]
        else:
            start_value = self.session.get_mean()[stimuli_val][0]
        return "Amplitude " + stimuli_val + ": " + \
                str(position[1] - start_value) + "\n"

    def plot_peak(self):
        """
        If peak checkbox is checked this function will update peak
        lines and datalog info.
        If peak checkbox is not checked this function will remove 
        peak lines and datalog info.
        """
        self.remove_peak_time(uncheck=False)

        if not (self.ui.checkBox_smooth.isChecked() \
                or self.ui.checkBox_regular.isChecked()) \
                or self.ui.several_responses_btn.isChecked():
            self.ui.peak_label.hide()
            return

        if self.ui.checkBox_peak.isChecked():
            try:
                points = self.session.get_peaks(
                        self.ui.spinBox.value(),
                        smooth=self.ui.checkBox_smooth.isChecked())
            except Exception as exc:
                self.ui.checkBox_amp.setChecked(False)
                QMessageBox.warning(self, exc.args[0], exc.args[1])
                return

            peak_text = ""
            if self.ui.stimuliBox.currentText() == "All":
                for stimuli_val, position in points.iteritems():
                    self.peak_time.append(
                            self.current_ax.axvline(position[0], color=CustomPlot._colors[-1]))
                    peak_text += "Peak " + stimuli_val + ": " + \
                            str(position[0]) + "\n"
            else:
                stimuli_val = self.ui.stimuliBox.currentText()
                self.peak_time.append(
                        self.current_ax.axvline(points[stimuli_val][0], color=CustomPlot._colors[-1]))
                peak_text += "Peak " + stimuli_val + ": " + \
                        str(points[stimuli_val][0]) + "\n"
            self.ui.peak_label.setText(peak_text[0:-1])
            self.ui.peak_label.show()
        else:
            self.ui.peak_label.hide()
        self.canvas.draw()

        self.canvas.draw()

    def get_color(self):
        """
        :return: RGB hex string
        """

        for color in CustomPlot._colors:
            if color not in self.used_colors:
                self.used_colors.append(color)
                return color

    def add_stimuli_types(self):
        """
        Add all stimuli types that exists in the data to a combobox
        """
        data = self.session.get_mean()
        if len(data) > 1:
            self.ui.stimuliBox.addItem("All")
        for stimuli_type in data:
            self.ui.stimuliBox.addItem(stimuli_type)

    def plot_several_sessions(self):
        """
        Plot the active object's children, each as a separate plot
        """
        if self.ui.checkBox_regular.isChecked():
            self.remove_smoothed_plots()
            self.current_ax.relim()
            children = self.session.sessions + self.session.children
            for child in children:
                if child.ready_for_calculation(self.session.get_mask(), self.session.get_stimuli()):
                    child_mean = child.get_mean(self.session.get_setting('percent'),
                                                self.session.get_setting('global'),
                                                self.session.get_mask(),
                                                self.session.get_stimuli())
                    self.plot_data(child_mean, child.name)

        else:
            self.remove_regular_plots()

        self.show_legends()
        self.canvas.draw()

    def plot_data(self, data_dict, name = None):
        """
        Plots the data that exists in the dictionary data_dict, depending on stimuli selected
        """
        if self.ui.stimuliBox.currentText() == "All":
            for stimuli_type, stimuli_data in data_dict.iteritems():
                x = np.arange(len(stimuli_data))*self.session.get_tr()
                if name:
                    stimuli_type = name + " - " + stimuli_type
                axis, = self.current_ax.plot(x, stimuli_data, color=self.get_color(), label=stimuli_type)
                self.regular.append(axis)
        else:
            type = self.ui.stimuliBox.currentText()
            if type in data_dict:
                data = data_dict[type]
                x = np.arange(len(data))*self.session.get_tr()
                if name:
                    type = name + " - " + type
                axis, = self.current_ax.plot(x, data, color=self.get_color(), label=type)
                self.regular.append(axis)

    def plot_regular(self):
        """
        Plot either the mean of the object's data, or its children separately,
        depending on if the radiobutton is checked
        """
        if self.ui.mean_response_btn.isChecked():
            self.plot_mean()
        elif not isinstance(self.session, Session):
            self.plot_several_sessions()

        self.set_allowed_buttons()

    def show_legends(self):
        for ax in self.axes:
            handles, labels = ax.get_legend_handles_labels()
            lgd = ax.legend(handles, labels, prop={'size': self.ui.label_size.value()})

            if not handles or not self.ui.checkBox_labels.isChecked():
                lgd.set_visible(False)
            else:
                lgd.set_visible(True)

        if self.ui.checkBox_labels.isChecked():
            self.ui.label_size.setEnabled(True)
        else:
            self.ui.label_size.setEnabled(False)

        self.canvas.draw()

    def set_allowed_buttons(self):
        """
        Enable or disable buttons depending on if they are meaningful in the current situation
        """
        # Enable the buttons if there are exactly 1 regular curve, or if there is one smoothed curve
        if self.current_ax is None:
            self.ui.toolButton_rem_subplot.setEnabled(False)

            self.ui.checkBox_amp.setEnabled(False)
            self.ui.checkBox_fwhm.setEnabled(False)
            self.ui.checkBox_peak.setEnabled(False)
            self.ui.checkBox_sem.setEnabled(False)
            self.ui.checkBox_regular.setEnabled(False)
            self.ui.checkBox_smooth.setEnabled(False)

            self.ui.mean_response_btn.setEnabled(False)
            self.ui.several_responses_btn.setEnabled(False)
            self.ui.spinBox.setEnabled(False)
            self.ui.stimuliBox.setEnabled(False)
        else:
            self.ui.toolButton_rem_subplot.setEnabled(True)
            self.ui.mean_response_btn.setEnabled(True)
            self.ui.several_responses_btn.setEnabled(True)
            self.ui.spinBox.setEnabled(True)
            self.ui.stimuliBox.setEnabled(True)
            self.ui.checkBox_regular.setEnabled(True)

            if not self.ui.several_responses_btn.isChecked() and (self.ui.checkBox_regular.isChecked() or self.ui.checkBox_smooth.isChecked()):
                self.ui.checkBox_amp.setEnabled(True)
                self.ui.checkBox_fwhm.setEnabled(True)

                if self.ui.stimuliBox.currentText() != 'All':
                    self.ui.checkBox_sem.setEnabled(True)
                else:
                    self.ui.checkBox_sem.setEnabled(False)

                self.ui.checkBox_peak.setEnabled(True)
            else:
                self.ui.checkBox_amp.setEnabled(False)
                self.remove_amplitude()
                self.ui.checkBox_fwhm.setEnabled(False)
                self.remove_fwhm()
                self.ui.checkBox_peak.setEnabled(False)
                self.remove_peak_time()
                self.ui.checkBox_sem.setEnabled(False)
                self.remove_sem()

            # Only allow smooth if we are plotting mean
            if self.ui.mean_response_btn.isChecked():
                self.ui.checkBox_smooth.setEnabled(True)
            else:
                self.ui.checkBox_smooth.setEnabled(False)

            if self.ui.checkBox_fwhm.isChecked():
                self.ui.fwhm_label.show()
            else:
                self.ui.fwhm_label.hide()

            if self.ui.checkBox_peak.isChecked():
                self.ui.peak_label.show()
            else:
                self.ui.peak_label.hide()

            if self.ui.checkBox_amp.isChecked():
                self.ui.amp_label.show()
            else:
                self.ui.amp_label.hide()

    def resizeEvent(self, QResizeEvent):
        try:
            self.fig.tight_layout(pad=2.0)
        except:
            pass
예제 #27
0
class ImageViewerWidget(QtWidgets.QWidget):
    """ PyQt Widget holding a matplotlib canvas to visualize and navigate through 3D image data
    """
    def __init__(self,
                 image_data: sitk.Image = None,
                 parent: QtWidgets.QWidget = None):
        """ Constructs the viewer and initializes all controls.

        @param image_data: the SimpleITK image to visualize
        @param QtWidgets.QWidget parent: the widget's parent if used in a full PyQt GUI
        """
        super(ImageViewerWidget, self).__init__(parent)
        if image_data is None:
            # create an empty 3d image
            image_data = sitk.GetImageFromArray(np.zeros((1, 1, 1)))

        # init attributes
        self.image = image_data  # the SimpleITK image in the viewer
        self.image_array = None  # the image as np.array
        self.current_slice = 0

        self.im_plot = None  # storing the mpl plot

        self.current_window = 0
        self.current_level = 0

        self.greyval_range = [0, 0]

        self.masks = {}  # dict with mask as key and its plot as value
        self.markers = []  # list of markers and their pixel coordinates
        self.orientation = SLICE_ORIENTATION_XY  # what dimensions are seen as the plane (values like in VTK)

        # init the MPL canvas
        initial_canvas_size_x = 5  # size in pixels. corresponds to a size of 5x5 inches with 100 dpi
        initial_canvas_size_y = 5
        self.max_resolution = 500
        self.dpi = self.max_resolution // initial_canvas_size_x

        self.canvas = FigureCanvas(
            Figure(figsize=(initial_canvas_size_x, initial_canvas_size_y),
                   dpi=self.dpi,
                   facecolor='black'))

        self.ax = self.canvas.figure.subplots()
        self.ax.axis('off')
        self.canvas.figure.subplots_adjust(0, 0, 1, 1)

        self.marker_plot = self.ax.scatter([], [],
                                           c=ImageMarker.STANDARD_COLOR)

        self.canvas.setParent(self)

        # add a hidden mpl toolbar for panning & zooming functionality
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()

        # define a slider for image slicing
        self.slice_slider = QtWidgets.QSlider(orientation=QtCore.Qt.Vertical,
                                              parent=self)
        self.slice_slider.valueChanged.connect(self.update_slice)

        # define a text field to display image coordinates and one for the current zoom
        bottom_bar_layout = QtWidgets.QHBoxLayout()
        self.pixel_info_label = PixelInfoQLabel(parent=self)
        bottom_bar_layout.addWidget(self.pixel_info_label)

        # layout the QtWidget
        main_layout = QtWidgets.QVBoxLayout()
        image_with_slider_layout = QtWidgets.QHBoxLayout()
        image_with_slider_layout.addWidget(self.canvas)
        image_with_slider_layout.addWidget(self.slice_slider)
        main_layout.addLayout(image_with_slider_layout)
        main_layout.addLayout(bottom_bar_layout)
        self.setLayout(main_layout)

        # set the focus to be on the canvas, so that keyevents get handled by mpl_connect
        self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas.setFocus()

        # prevent the slider from gaining focus
        self.slice_slider.setFocusPolicy(QtCore.Qt.NoFocus)

        # initialize the showing image
        self.init_image()

        # define the interactor for user inputs
        self.interactor_style = ImageViewerInteractor(self)

        # show the widget
        self.show()

    def init_image(self):
        """ Initial call after the image has been set or reset.

        Constructs the image array and plots the middle slice of the image with window/level spanning the whole
        grey value range of the image.
        """
        # DON'T swap axes, in order to keep the fastest dimension of the np array the first
        # -> z-slices are the most performant
        self.image_array = sitk.GetArrayFromImage(self.image)

        # take the middle slice as initial slice shown
        self.current_slice = self.get_slice_dim_size() // 2

        # redraw if there is already a plot
        if self.im_plot is not None:
            self.im_plot.remove()

        self.im_plot = self.ax.imshow(
            self.image_array[index_compatibility(
                get_3d_plane_index(self.current_slice, self.orientation))],
            aspect=get_aspect_ratio_for_plane(self.image.GetSpacing(),
                                              self.orientation,
                                              self.image.GetSize()))

        # set the window/level to span the whole greyvalue range of the image
        min_grey = self.image_array.min()
        max_grey = self.image_array.max()
        self.greyval_range = [min_grey, max_grey]
        self.reset_window_level()

        # init the coordinate label
        initial_coords = [0, 0]
        initial_coords.insert(self.orientation, self.current_slice)
        self.show_pixel_info(initial_coords)

        # init the slider with the correct range
        self.adapt_slider()

    def change_orientation(self, orientation: Union[int, str]):
        """ Change the slicing dimension of the viewer.
        Orientation values are expected as in SLICE_ORIENTATION

        @param orientation:
            either the number corresponding to the slicing dimension or a string of the new plane:
                                'xy' or 2 -> the XY plane is shown;
                                'xz' or 1 -> the XZ plane is shown;
                                'yz' or 0 -> the YZ plane is shown;
        """
        # don't do anything if orientation stays the same
        if orientation == self.orientation:
            return

        if orientation not in SLICE_ORIENTATION.keys(
        ) and orientation not in SLICE_ORIENTATION.values():
            print(
                'Cannot change viewer orientation to {}. Use one of {} or {} respectively.'
                .format(orientation, SLICE_ORIENTATION.keys(),
                        SLICE_ORIENTATION.values()))

        # convert the plane string into the number of the slice dimension
        if isinstance(orientation, str):
            orientation = SLICE_ORIENTATION[orientation]

        self.orientation = orientation

        # make sure the current slice is valid in the new orientation
        if self.current_slice >= self.get_slice_dim_size():
            self.current_slice = self.get_slice_dim_size() - 1

        self.redraw_slice()
        self.adapt_slider()

    def set_window_level(self, window: Union[int, float], level: Union[int,
                                                                       float]):
        """ Window levelling operation on the image.

        @param window: width of the window
        @param level: window center
        """
        if window < 0:
            # set a minimum level (could be even smaller in case of normalized images with values in [0,1])
            window = 1e-5

        self.current_window = window
        self.current_level = level

        half_window = self.current_window / 2
        self.im_plot.set_clim(vmin=self.current_level - half_window,
                              vmax=self.current_level + half_window)
        self.canvas.draw(
        )  # optimizable: only redraw the image, not markers or masks!
        # print('Window: {}, Level: {}'.format(self.current_window, self.current_level))

    def reset_window_level(self):
        """ Set the window/level to span the entire grey value range of the image.
        """
        # reset to cover the entire image range
        window = self.greyval_range[1] - self.greyval_range[0]
        level = self.greyval_range[0] + window / 2
        self.set_window_level(window, level)

    def update_slice(self, new_slice: int):
        """ Sets the current slice and redraws the image

        @param new_slice: the slice index
        """
        # if the index is not in range, change it to the min or max index
        lower = 0
        upper = self.get_slice_dim_size()
        if not lower <= new_slice < upper:
            new_slice = lower if new_slice < lower else upper - 1

        self.current_slice = new_slice
        self.redraw_slice()

    def redraw_slice(self):
        """ Draws the current slice of the image with mask and markers.
        This resets the current zoom factor but not the window/level.
        """
        # here, blitting could increase performance

        img_slice = self.image_array[index_compatibility(
            get_3d_plane_index(slice_index=self.current_slice,
                               orientation=self.orientation))]

        # set extent to be according to dimensions so that nothing gets squished
        y_max, x_max = img_slice.shape
        self.ax.set_xlim([0, x_max])
        self.ax.set_ylim([0, y_max])

        half_window = self.current_window / 2

        # remove the image plot and redraw. this is a little less performant than
        # setting data on the current image plot, but this way the extent is updated correctly
        self.im_plot.remove()
        self.im_plot = self.ax.imshow(
            img_slice,
            vmin=self.current_level - half_window,
            vmax=self.current_level + half_window,
            aspect=get_aspect_ratio_for_plane(self.image.GetSpacing(),
                                              self.orientation,
                                              self.image.GetSize()))

        # update the coordinate text
        self.pixel_info_label.set_coordinate(self.orientation,
                                             self.current_slice)
        self.show_pixel_info(self.pixel_info_label.coords)

        # draw masks and markers
        self.update_masks()
        self.scatter_markers()

        # update the canvas (making sure this is only called once per update for performance)
        self.canvas.draw()

    def get_slice_dim_size(self) -> int:
        """ Get the size of the slicing dimension (found in self.orientation)

        @return: the size of the current slicing dimension
        """
        return self.image.GetSize()[self.orientation]

    def adapt_slider(self):
        """ Call this, if the image slice range or the current slice changed.
        The slider value and range will be adapted to these values
        """
        self.slice_slider.setRange(0, self.get_slice_dim_size() - 1)
        self.slice_slider.setValue(self.current_slice)

    def move_slice(self, delta: int):
        """ Change the current slice by delta steps and then redraw.

        @param delta: the number of steps by which to change the current slice (positive or negative)
        """
        # moves the slider, which in turn changes the slice and redraws the image
        self.slice_slider.setValue(self.current_slice + delta)

    def add_marker(self, position: Sequence[Union[float, int]]):
        """ Adds a marker to the given pixel position, saves and displays it.

        @param position: continuous 3d pixel position of the new marker
        """
        assert len(position) == 3
        marker = ImageMarker(position)
        self.markers.append(marker)

        # only redraw markers, if the new marker is in the current slice
        if round(position[self.orientation]) == self.current_slice:
            self.scatter_markers()
            self.canvas.draw()

    def remove_markers(self, only_last: bool = False):
        """ Remove all (or only the last) markers from the image.
        This does not only apply to visible markers, but markers in all slices.

        @param only_last: if true, only the last marker will be removed; otherwise all markers get removed
        """
        if len(self.markers) == 0:
            return

        if only_last:
            removed_marker = self.markers.pop()
            print('removed marker at {}'.format(removed_marker.pixel_position))
        else:
            self.markers.clear()
            print('removed all markers')

        # redraw markers
        self.scatter_markers()
        self.canvas.draw()

    def scatter_markers(self):
        """ Draw all markers in the current slice on the image.
        Attention: this does not redraw the whole canvas, self.canvas.draw() has to be called separately.
        This way, multiple changes can be drawn at once, for instance after a new slice is shown.
        """
        # determine which markers are found in the current slice
        markers_in_slice = []
        for m in self.markers:
            pixel_pos = np.array(m.pixel_position)
            # choose a marker if the rounded index is the same as the current slice
            if round(pixel_pos[self.orientation]) == self.current_slice:
                # only take the plane coordinates
                markers_in_slice.append(
                    pixel_pos[np.arange(3) != self.orientation])

        if len(markers_in_slice) != 0:
            # combine marker coordinates into one array and and show it in a scatter plot
            np_markers = np.stack(markers_in_slice, axis=1)
            self.marker_plot.set_offsets(np_markers.swapaxes(0, 1))
        else:
            # if no markers are found, clear remove the current plot and replace it with an empty one
            self.marker_plot.remove()
            self.marker_plot = self.ax.scatter([], [],
                                               c=ImageMarker.STANDARD_COLOR,
                                               s=ImageMarker.STANDARD_SIZE)

    def add_mask(self, mask: ImageMask):
        """ Show a mask overlay on top of the current image. The mask has to have the same size, spacing and origin.

        @param mask: the mask to overlay (has to have the same properties as the image)
        """
        if not compatible_metadata(self.image, mask.mask_image):
            return

        # save the mask in the masks dict
        self.masks[mask] = None

        # draw the image
        self.update_masks()
        self.canvas.draw()

    def update_masks(self):
        """ Draw the masks in the current slice as an overlay on top of the image.

        Attention: this does not redraw the whole canvas, self.canvas.draw() has to be called separately.
        This way, multiple changes can be drawn at once, for instance after a new slice is shown.
        """
        # remove old plots
        self.clear_mask_plots()

        # draw each mask (no changes to canvas before canvas.draw() is called)
        for m in self.masks.keys():
            self.masks[m] = add_mask_to_image(
                self.ax,
                m.get_slice(self.current_slice, self.orientation),
                aspect=get_aspect_ratio_for_plane(m.get_spacing(),
                                                  self.orientation,
                                                  self.image.GetSize()),
                alpha=m.alpha,
                color=m.color)

    def clear_mask_plots(self):
        """ Remove all masks from the canvas.
        """
        for m in self.masks.keys():
            try:
                # remove the existing plot
                self.masks[m].remove()
            except AttributeError:
                # if the mask was not there in the previous slice it is None here
                pass

    def set_image(self, image: sitk.Image):
        """ Set the image and show it. This resets all markers and masks previously added to the viewer.

        @param image: the new image to show
        """
        self.image = image

        # remove old masks
        self.clear_mask_plots()
        self.masks.clear()

        # remove old markers
        self.markers.clear()
        self.scatter_markers()

        # draw image and re-init everything else
        self.init_image()

    def show_pixel_info(self, pixel_coords: Sequence[Union[float, int]]):
        """ Show the given coordinates and the corresponding image intensity in a label below the image.
        For instance, this is called whenever whenever the user moves the mouse over the image.

        @param pixel_coords: the (continuous) coordinatates to be displayed in the label
        """
        if pixel_coords is None:
            # remove the label text
            self.pixel_info_label.clear()
        else:
            # take the discrete index
            x, y, z = [int(ind) for ind in pixel_coords]
            try:
                self.pixel_info_label.set_values(x, y, z,
                                                 self.image.GetPixel(x, y, z))
            except (IndexError, RuntimeError, TypeError):
                # gets thrown if x, y, z are out of bounds of the image (this can happen on the edges of the figure)
                return
예제 #28
0
class FrequencyCurveChart(QDialog):
    def __init__(self, parent=None, toolbar=False):
        flags = Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint | Qt.WindowCloseButtonHint
        super().__init__(parent=parent, f=flags)
        self.setWindowTitle(self.tr("Frequency Curve Chart"))
        self.figure = plt.figure(figsize=(4, 3))
        self.axes = self.figure.subplots()
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.main_layout = QGridLayout(self)
        self.main_layout.addWidget(self.toolbar, 0, 0, 1, 2)
        self.main_layout.addWidget(self.canvas, 1, 0, 1, 2)
        if not toolbar:
            self.toolbar.hide()
        self.supported_scales = [("log-linear", self.tr("Log-linear")),
                                 ("log", self.tr("Log")),
                                 ("phi", self.tr("φ")),
                                 ("linear", self.tr("Linear"))]

        self.scale_label = QLabel(self.tr("Scale"))
        self.scale_combo_box = QComboBox()
        self.scale_combo_box.addItems([name for key, name in self.supported_scales])
        self.scale_combo_box.currentIndexChanged.connect(self.update_chart)
        self.main_layout.addWidget(self.scale_label, 2, 0)
        self.main_layout.addWidget(self.scale_combo_box, 2, 1)

        self.last_samples = []
        self.last_max_frequency = 0.0

    @property
    def scale(self) -> str:
        index = self.scale_combo_box.currentIndex()
        key, name = self.supported_scales[index]
        return key

    @property
    def transfer(self) -> typing.Callable:
        if self.scale == "log-linear":
            return lambda classes_φ: convert_φ_to_μm(classes_φ)
        elif self.scale == "log":
            return lambda classes_φ: np.log(convert_φ_to_μm(classes_φ))
        elif self.scale == "phi":
            return lambda classes_φ: classes_φ
        elif self.scale == "linear":
            return lambda classes_φ: convert_φ_to_μm(classes_φ)

    @property
    def xlabel(self) -> str:
        if self.scale == "log-linear":
            return self.tr("Grain-size [μm]")
        elif self.scale == "log":
            return self.tr("Ln(grain-size in μm)")
        elif self.scale == "phi":
            return self.tr("Grain-size [φ]")
        elif self.scale == "linear":
            return self.tr("Grain-size [μm]")

    @property
    def ylabel(self) -> str:
        return self.tr("Frequency")

    @property
    def xlog(self) -> bool:
        if self.scale == "log-linear":
            return True
        else:
            return False

    def update_chart(self):
        self.show_samples(self.last_samples, append=False)

    def show_samples(self, samples: typing.Iterable[GrainSizeSample], append=False, title=None):
        append = append and len(self.last_samples) != 0
        if not append:
            self.axes.clear()
            self.last_samples = []
        max_frequency = self.last_max_frequency
        for i, sample in enumerate(samples):
            self.last_samples.append(sample)
            if i == 0:
                x = self.transfer(sample.classes_φ)
                if not append:
                    if self.xlog:
                        self.axes.set_xscale("log")
                    if title is None:
                        self.axes.set_title(self.tr("Frequency curves of samples"))
                    else:
                        self.axes.set_title(title)
                    self.axes.set_xlabel(self.xlabel)
                    self.axes.set_ylabel(self.ylabel)
                    self.axes.set_xlim(x[0], x[-1])
            self.axes.plot(x, sample.distribution, c="black")
            sample_max_freq = np.max(sample.distribution)
            if sample_max_freq > max_frequency:
                max_frequency = sample_max_freq
        self.axes.set_ylim(0.0, round(max_frequency*1.2, 2))
        self.last_max_frequency = max_frequency
        self.figure.tight_layout()
        self.canvas.draw()
예제 #29
0
class ChromAnalyzer(QtWidgets.QWidget, Ui_ChromAnalyzer):
    def __init__(self, parent=None):
        super(ChromAnalyzer, self).__init__(parent)
        self.setupUi(self)

        self.openChromButton.clicked.connect(self.openchrom)
        self.analyzeButton.clicked.connect(self.analyze)
        self.aboutButton.clicked.connect(self.about)
        self.quitButton.clicked.connect(self.quit)

        self.tablemodel = TableModel(self)
        self.tableView.setModel(self.tablemodel)
        self.tableView.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.tableView.customContextMenuRequested.connect(self.openTableMenu)

        # Add plot
        self.figure = plt.figure(dpi=100)
        self.ax = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()

        # set the layout
        layout_chormatogram = QtWidgets.QVBoxLayout()
        layout_chormatogram.addWidget(self.canvas)
        self.plotterBox.setLayout(layout_chormatogram)

    def keyPressEvent(self, e):
        if (e.modifiers() & QtCore.Qt.ControlModifier):
            if e.key() == QtCore.Qt.Key_C:  #copy
                if len(self.tableView.selectionModel().selectedIndexes()) > 0:
                    previous = self.tableView.selectionModel().selectedIndexes(
                    )[0]
                    columns = []
                    rows = []
                    for index in self.tableView.selectionModel(
                    ).selectedIndexes():
                        if previous.column() != index.column():
                            columns.append(rows)
                            rows = []
                        rows.append(str(index.data().toPyObject()))
                        previous = index
                    columns.append(rows)

                    # add rows and columns to clipboard
                    clipboard = ""
                    nrows = len(columns[0])
                    ncols = len(columns)
                    for r in xrange(nrows):
                        for c in xrange(ncols):
                            clipboard += columns[c][r]
                            if c != (ncols - 1):
                                clipboard += '\t'
                        clipboard += '\n'

                    # copy to the system clipboard
                    sys_clip = QtWidgets.QApplication.clipboard()
                    sys_clip.setText(clipboard)

    def openTableMenu(self, position):
        """ context menu event """
        menu = QtWidgets.QMenu(self)
        exportAction = menu.addAction("Export table as CSV")
        action = menu.exec_(self.tableView.viewport().mapToGlobal(position))
        if action == exportAction:
            fname, _ = QtWidgets.QFileDialog.getSaveFileName(
                self, "Save File", "CSV (*.csv)")
            self.tablemodel.SaveTable(fname)
        else:
            return
        return

    def openchrom(self):
        fname, _ = QtWidgets.QFileDialog.getOpenFileName(self, 'Open file')
        if fname and isfile(fname):
            self.lineEdit.setText(fname)

    def about(self):
        adialog = AboutDialog()
        adialog.changeTitle("ChromAnalyzer")
        adialog.exec_()

    def quit(self):
        QtWidgets.QApplication.quit()

    def analyze(self):
        if self.lineEdit.text() and isfile(self.lineEdit.text()):
            #Clean previous table
            del self.tablemodel.arraydata[:]
            del self.tablemodel.header[:]
            self.tablemodel.clean()

            #set table header
            header = [
                "Peak", "Peak points", "time min", "time max", "Mu1", "Mu2",
                "Area"
            ]
            self.tablemodel.setHeader(header)

            #clean prevoius plot
            self.ax.cla()

            signal = []
            time = []
            f = open(self.lineEdit.text())
            for line in f:
                v = str.split(line.strip(), "\t")
                if len(v) == 2:
                    time.append(float(v[0]))
                    signal.append(float(v[1]))
                else:
                    continue
            f.close()

            #plot entire chromatogram
            self.ax.plot(time, signal, "b")

            #Analyse peaks
            h = self.peakthreshold.value()
            k = self.windowsize.value()

            chrom = ChromAnalysis(time, signal, k, h)
            peaks = chrom.getPeaks()
            peaklst = chrom.peaksplit(peaks)

            nleftpnt = self.leftpoints.value()
            nrightpnt = self.rightpoints.value()
            pn = 1
            for i in range(len(peaklst)):
                time_ = []
                signal_ = []
                #print "-"*10
                chrom.addLeftNpoints(peaklst[i], nleftpnt)
                chrom.addRighNpoints(peaklst[i], nrightpnt)
                for row in peaklst[i]:
                    #print row[0], row[1]
                    time_.append(row[0])
                    signal_.append(row[1])

                if len(time_) > 15:
                    # fill peak detected!
                    self.ax.fill(time_, signal_, zorder=10)
                    self.ax.grid(True, zorder=5)

                    u1 = chrom.Mu1CentralMoment(time_, signal_)
                    u2 = chrom.Mu2CentralMoment(time_, signal_, u1)

                    area = chrom.integrate(signal_, 3)
                    self.tablemodel.addRow(
                        [pn,
                         len(time_),
                         min(time_),
                         max(time_), u1, u2, area])
                    pn += 1

            #self.ax.grid(True, zorder=5)
            plt.xlabel('Time')
            plt.ylabel('Signal')
            self.canvas.draw()
            return
        else:
            return
예제 #30
0
파일: graphics.py 프로젝트: Pymatteo/QtNMR
class Widgetmain(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widgetmain, self).__init__(parent)

        self.figure = Figure()

        # plt.subplots_adjust(left=0.031, right=0.999, top=0.99, bottom=0.03)
        # plt.subplots_adjust(left=0.001, right=0.999, top=0.999, bottom=0.001)

        self.canvas = FigureCanvas(self.figure)

        self.toolbar = NavigationToolbar(self.canvas, self)

        # uncomment for disabling plot toolbar, not recommended
        self.toolbar.hide()

        # set the layout
        self.layout = QtWidgets.QVBoxLayout()
        self.layout.addWidget(self.toolbar)
        self.layout.addWidget(self.canvas)
        self.setLayout(self.layout)

        # set the plot class handlers
        self.wzoom = plot_tools.WheellZoom()
        self.adapt = plot_tools.WindowResize()  # keep tight layout
        self.cursor = plot_tools.SnaptoCursor()
        self.selector = plot_tools.Select()
        self.selection = plot_tools.Selection()
        self.dataplot = None

    def setStatus(self, stat):
        self.statusbar = stat

    def save_plot(self):
        self.toolbar.save_figure()

    def axis_configure(self):
        self.toolbar.edit_parameters()

    def plot(self, xaxis=None, real=None, imag=None, magn=None, hxlimit=None, lxlimit=None, datas=None):

        # self.dataplot.clear()
        # if self.dataplot:
        # self.figure.delaxes(self.dataplot)
        if self.dataplot is None:
            self.dataplot = self.figure.add_subplot(111)
            self.figure.patch.set_facecolor("white")
            self.selector.setAx(self.dataplot, hxlimit, lxlimit, xaxis.size, datas, self.selection)

        # self.dataplot = self.figure.add_subplot(111)
        # self.selector.setAx(self.dataplot, hxlimit, lxlimit, xaxis.size, datas, self.selection)
        self.statusbar.showMessage("Plot updated")
        self.dataplot.hold(False)
        self.dataplot.plot(xaxis, real, "r-", xaxis, imag, "g-", xaxis, magn, "-")

        # uncomment for matlibplot standard cursor
        # cursor = Cursor(dataplot, useblit=True, color='black', linewidth=1 )

        self.wzoom.setAx(self.dataplot, self.selection, datas)
        self.cursor.setAx(datas, self.dataplot, xaxis, real, self.statusbar)
        self.adapt.setAx(self.dataplot, self.figure)
        self.selection.setAx(self.dataplot, datas)

        self.figure.tight_layout()

        # dataplot.set_autoscaley_on(False) for auto x scale

        # setting background color
        # self.figure.patch.set_visible(False)
        # self.figure.patch.set_facecolor('white')

        self.dataplot.set_xlim([lxlimit, hxlimit])

        # uncomment the following line for raw axis label inside plot
        # self.dataplot.tick_params(direction='in', pad=-19)

        # uncomment the following lines to disable plot toolbar mouse coordinates
        # def format_coord(x, y):
        #    return ' '
        # self.dataplot.format_coord = format_coord

        self.canvas.draw()
예제 #31
0
class PyWeramiWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self, filename=None, parent=None):
        super(PyWeramiWindow, self).__init__(parent)
        self.settings = QtCore.QSettings("LX", "pywerami")
        self.setupUi(self)
        self._fig = Figure(facecolor="white")
        self._ax = self._fig.add_subplot(111)

        self._canvas = FigureCanvas(self._fig)
        self._canvas.setParent(self.widget)
        self._canvas.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.matplot.addWidget(self._canvas)
        self.mpl_toolbar = NavigationToolbar(self._canvas, self.widget)
        self.mpl_toolbar.hide()
        self.matplot.addWidget(self.mpl_toolbar)
        self.setWindowTitle('PyWerami')
        window_icon = resource_filename(__name__, 'images/pywerami.png')
        self.setWindowIcon(QtGui.QIcon(window_icon))
        self.about_dialog = AboutDialog(__version__)

        #set combos
        self.cmaps = [
            'viridis', 'inferno', 'plasma', 'magma', 'Blues', 'BuGn', 'BuPu',
            'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', 'PuBu', 'PuBuGn',
            'PuRd', 'Purples', 'RdPu', 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr',
            'YlOrRd', 'afmhot', 'autumn', 'bone', 'cool', 'copper',
            'gist_heat', 'gray', 'hot', 'pink', 'spring', 'summer', 'winter',
            'BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', 'RdBu', 'RdGy',
            'RdYlBu', 'RdYlGn', 'Spectral', 'seismic', 'gist_earth', 'terrain',
            'ocean', 'gist_stern', 'brg', 'CMRmap', 'cubehelix', 'gnuplot',
            'gnuplot2', 'gist_ncar', 'nipy_spectral', 'jet', 'rainbow',
            'gist_rainbow', 'hsv', 'flag', 'prism'
        ]
        self.mapstyle.addItems(self.cmaps)

        # set validators
        self.levelmin.setValidator(QtGui.QDoubleValidator(self.levelmin))
        self.levelmax.setValidator(QtGui.QDoubleValidator(self.levelmax))
        self.levelnum.setValidator(QtGui.QIntValidator(self.levelnum))
        self.levelstep.setValidator(QtGui.QDoubleValidator(self.levelstep))
        self.clipmin.setValidator(QtGui.QDoubleValidator(self.clipmin))
        self.clipmax.setValidator(QtGui.QDoubleValidator(self.clipmax))

        # Set icons in toolbar
        self.actionOpen.setIcon(QtGui.QIcon.fromTheme('document-open'))
        self.actionSave.setIcon(QtGui.QIcon.fromTheme('document-save'))
        self.actionSaveas.setIcon(QtGui.QIcon.fromTheme('document-save-as'))
        self.actionImport.setIcon(
            QtGui.QIcon.fromTheme('x-office-spreadsheet'))
        self.actionHome.setIcon(self.mpl_toolbar._icon('home.png'))
        self.actionPan.setIcon(self.mpl_toolbar._icon('move.png'))
        self.actionZoom.setIcon(self.mpl_toolbar._icon('zoom_to_rect.png'))
        self.actionGrid.setIcon(QtGui.QIcon.fromTheme('format-justify-fill'))
        self.actionAxes.setIcon(
            self.mpl_toolbar._icon('qt4_editor_options.png'))
        self.actionSavefig.setIcon(self.mpl_toolbar._icon('filesave.png'))
        #self.action3D.setIcon(QtGui.QIcon.fromTheme(''))
        self.actionProperties.setIcon(
            QtGui.QIcon.fromTheme('preferences-other'))
        self.actionQuit.setIcon(QtGui.QIcon.fromTheme('application-exit'))
        self.actionAbout.setIcon(QtGui.QIcon.fromTheme('help-about'))

        # connect signals
        self.actionOpen.triggered.connect(self.openProject)
        self.actionSave.triggered.connect(self.saveProject)
        self.actionSaveas.triggered.connect(self.saveProjectAs)
        self.actionImport.triggered.connect(self.import_data)
        self.actionHome.triggered.connect(self.mpl_toolbar.home)
        self.actionPan.triggered.connect(self.plotpan)
        self.actionZoom.triggered.connect(self.plotzoom)
        self.actionGrid.triggered.connect(self.plotgrid)
        self.actionAxes.triggered.connect(self.mpl_toolbar.edit_parameters)
        self.actionSavefig.triggered.connect(self.mpl_toolbar.save_figure)
        self.actionProperties.triggered.connect(self.edit_options)
        self.actionQuit.triggered.connect(self.close)
        self.actionAbout.triggered.connect(self.about_dialog.exec)

        # buttons signals
        self.buttonBox.button(
            QtWidgets.QDialogButtonBox.Apply).clicked.connect(self.apply_props)
        self.buttonBox.button(
            QtWidgets.QDialogButtonBox.RestoreDefaults).clicked.connect(
                self.restore_props)
        self.contcolor.clicked.connect(self.contours_color)
        self.action3D.triggered.connect(self.switch3d)
        # signals to calculate step size
        self.levelmin.editingFinished.connect(self.step_from_levels)
        self.levelmax.editingFinished.connect(self.step_from_levels)
        self.levelnum.editingFinished.connect(self.step_from_levels)
        self.setlevels.toggled.connect(self.step_from_levels)
        # almost done
        self.ready = False
        self.changed = False
        self.project = None

        if filename:
            self.import_data(filename)

        # ready
        self.statusbar.showMessage("Ready", 5000)

    def closeEvent(self, event):
        if self.changed:
            quit_msg = 'Project have been changed. Save ?'
            qb = QtWidgets.QMessageBox
            reply = qb.question(self, 'Message', quit_msg,
                                qb.Cancel | qb.Discard | qb.Save, qb.Save)

            if reply == qb.Save:
                self.do_save()
                if self.project is not None:
                    event.accept()
                else:
                    event.ignore()
            elif reply == qb.Discard:
                event.accept()
            else:
                event.ignore()

    def import_data(self, filename=None):
        if not filename:
            filename = QtWidgets.QFileDialog.getOpenFileName(
                self, "Import data file", ".",
                "Perple_X Table (*.tab *.TAB);;TCInvestigator (*.tci *.TCI)"
            )[0]
        if filename:
            if filename.lower().endswith('.tab'):
                self.data = GridData.from_tab(filename)
            elif filename.lower().endswith('.tci'):
                self.data = GridData.from_tci(filename)
            else:
                raise Exception('Unsupported file format')
            # populate listview and setup properties
            self.datafilename = filename
            self.ready = True
            self.project = None
            self.changed = True
            self.props = {}
            self._model = QtGui.QStandardItemModel(self.listView)
            for var in self.data.dep:
                item = QtGui.QStandardItem(var)
                item.setCheckable(True)
                self._model.appendRow(item)
                self.default_var_props(var)

            self.listView.setModel(self._model)
            self.listView.show()

            # connect listview signals
            self.varSel = self.listView.selectionModel()
            try:
                elf.varSel.selectionChanged.disconnect()
            except Exception:
                pass
            self.varSel.selectionChanged.connect(self.on_var_changed)
            try:
                self._model.itemChanged.disconnect()
            except Exception:
                pass
            self._model.itemChanged.connect(self.plot)

            # all done focus
            self.action3D.setChecked(False)  # no 3d on import
            self.varSel.setCurrentIndex(
                self._model.index(0,
                                  0), QtCore.QItemSelectionModel.ClearAndSelect
                | QtCore.QItemSelectionModel.Rows)
            self.listView.setFocus()
            self.plot()
            self.statusbar.showMessage(
                "Data from {} imported".format(self.data.label), 5000)

    def openProject(self, checked, projfile=None):
        """Open pywerami project
        """
        if self.changed:
            quit_msg = 'Project have been changed. Save ?'
            qb = QtWidgets.QMessageBox
            reply = qb.question(self, 'Message', quit_msg,
                                qb.Discard | qb.Save, qb.Save)

            if reply == qb.Save:
                self.do_save()
        if projfile is None:
            qd = QtWidgets.QFileDialog
            filt = 'pywermi project (*.pwp)'
            projfile = qd.getOpenFileName(self, 'Open project',
                                          os.path.expanduser('~'), filt)[0]
        if os.path.exists(projfile):
            stream = gzip.open(projfile, 'rb')
            data = pickle.load(stream)
            stream.close()
            # set actual working dir in case folder was moved
            self.datafilename = data['datafilename']
            self.import_data(self.datafilename)
            self.props = data['props']
            # all done
            self.ready = True
            self.project = projfile
            self.changed = False
            # all done focus
            self.action3D.setChecked(False)  # no 3d on import
            self.varSel.setCurrentIndex(
                self._model.index(0,
                                  0), QtCore.QItemSelectionModel.ClearAndSelect
                | QtCore.QItemSelectionModel.Rows)
            self.listView.setFocus()
            self.plot()
            self.statusbar.showMessage("Project loaded.", 5000)

    def saveProject(self):
        """Save project
        """
        if self.ready:
            if self.project is None:
                filename = QtWidgets.QFileDialog.getSaveFileName(
                    self, 'Save current project',
                    os.path.dirname(self.datafilename),
                    'pywerami project (*.pwp)')[0]
                if filename:
                    if not filename.lower().endswith('.pwp'):
                        filename = filename + '.pwp'
                    self.project = filename
                    self.do_save()
            else:
                self.do_save()

    def saveProjectAs(self):
        """Save project as
        """
        if self.ready:
            filename = QtWidgets.QFileDialog.getSaveFileName(
                self, 'Save current project as',
                os.path.dirname(self.datafilename),
                'pywerami project (*.pwp)')[0]
            if filename:
                if not filename.lower().endswith('.pwp'):
                    filename = filename + '.pwp'
                self.project = filename
                self.do_save()

    def do_save(self):
        """Do saving of poject
        """
        if self.project:
            # put to dict
            data = {'datafilename': self.datafilename, 'props': self.props}
            # do save
            stream = gzip.open(self.project, 'wb')
            pickle.dump(data, stream)
            stream.close()
            self.changed = False
            self.statusBar().showMessage('Project saved.')

    def contours_color(self):
        if self.ready:
            col = QtWidgets.QColorDialog.getColor()
            if col.isValid():
                self.contcolor.setStyleSheet("background-color: {}".format(
                    col.name()))

    def step_from_levels(self):
        if self.ready:
            if int(self.levelnum.text()) < 2:
                self.levelnum.setText('2')
            if float(self.levelmax.text()) < float(self.levelmin.text()):
                self.levelmin.setText(self.levelmax.text())
            if self.setlevels.isChecked():
                step = (float(self.levelmax.text()) - float(
                    self.levelmin.text())) / (int(self.levelnum.text()) - 1)
                self.levelstep.setText(repr(step))
                self.props[self.var]['step'] = step
                self.changed = True

    def default_var_props(self, var):
        if self.ready:
            data = self.data.get_var(var)
            prop = {}
            #levels
            prop['min'] = data.min()
            prop['max'] = data.max()
            prop['num'] = 10
            prop['step'] = (prop['max'] - prop['min']) / (prop['num'] - 1)
            prop['levels'] = 'num'
            prop['type'] = 'linear'
            #style
            prop['fill'] = False
            prop['opacity'] = 100
            prop['cmap'] = 'viridis'
            prop['contours'] = 'color'
            prop['color'] = '#000000'
            prop['label'] = False
            prop['digits'] = 3
            #processing
            prop['resample'] = 1
            prop['median'] = 1
            prop['gauss'] = 0
            prop['clipmin'] = data.min()
            prop['clipmax'] = data.max()

            self.props[var] = prop

    def set_var_props(self, var):
        if self.ready:
            #levels
            self.levelmin.setText(repr(self.props[var]['min']))
            self.levelmax.setText(repr(self.props[var]['max']))
            self.levelnum.setText(repr(self.props[var]['num']))
            self.levelstep.setText(repr(self.props[var]['step']))
            if self.props[var]['levels'] == 'num':
                self.setlevels.setChecked(True)
            else:
                self.setstep.setChecked(True)
            if self.props[var]['type'] == 'linear':
                self.linlevel.setChecked(True)
            else:
                self.cdflevel.setChecked(True)
            #style
            if self.props[var]['fill']:
                self.fillstyle.setChecked(True)
            else:
                self.fillstyle.setChecked(False)
            self.opacity.setValue(self.props[var]['opacity'])
            self.mapstyle.setCurrentIndex(
                self.cmaps.index(self.props[var]['cmap']))
            self.contcolor.setStyleSheet("background-color: {}".format(
                self.props[var]['color']))
            self.labelDigits.setValue(self.props[var]['digits'])
            if self.props[var]['contours'] == 'map':
                self.contcheckmap.setChecked(True)
            elif self.props[var]['contours'] == 'color':
                self.contcheckcolor.setChecked(True)
            else:
                self.contchecknone.setChecked(True)
            if self.props[var]['label']:
                self.contlabel.setChecked(True)
            else:
                self.contlabel.setChecked(False)
            #processing
            self.resample.setValue(self.props[var]['resample'])
            self.filtersize.setValue(self.props[var]['median'])
            self.filtersigma.setValue(self.props[var]['gauss'])
            self.clipmin.setText(repr(self.props[var]['clipmin']))
            self.clipmax.setText(repr(self.props[var]['clipmax']))

    def on_var_changed(self, selected):
        if self.ready:
            self.var = self.data.dep[selected.indexes()[0].row()]
            self.set_var_props(self.var)
            if self.action3D.isChecked():
                self.plot()

    def apply_props(self):
        if self.ready:
            #levels
            self.props[self.var]['min'] = float(self.levelmin.text())
            self.props[self.var]['max'] = float(self.levelmax.text())
            self.props[self.var]['num'] = int(self.levelnum.text())
            self.props[self.var]['step'] = float(self.levelstep.text())
            if self.setlevels.isChecked():
                self.props[self.var]['levels'] = 'num'
            else:
                self.props[self.var]['levels'] = 'step'
            if self.linlevel.isChecked():
                self.props[self.var]['type'] = 'linear'
            else:
                self.props[self.var]['type'] = 'cdf'
            #style
            if self.fillstyle.isChecked():
                self.props[self.var]['fill'] = True
            else:
                self.props[self.var]['fill'] = False
            self.props[self.var]['opacity'] = self.opacity.value()
            self.props[self.var]['cmap'] = str(self.mapstyle.currentText())
            self.props[self.var]['color'] = str(
                self.contcolor.palette().color(1).name())
            self.props[self.var]['digits'] = self.labelDigits.value()
            if self.contcheckmap.isChecked():
                self.props[self.var]['contours'] = 'map'
            elif self.contcheckcolor.isChecked():
                self.props[self.var]['contours'] = 'color'
            else:
                self.props[self.var]['contours'] = ''
            if self.contlabel.isChecked():
                self.props[self.var]['label'] = True
            else:
                self.props[self.var]['label'] = False
            #processing
            self.props[self.var]['resample'] = self.resample.value()
            self.props[self.var]['median'] = self.filtersize.value()
            self.props[self.var]['gauss'] = self.filtersigma.value()
            self.props[self.var]['clipmin'] = float(self.clipmin.text())
            self.props[self.var]['clipmax'] = float(self.clipmax.text())
            self.changed = True
            self.plot()

    def restore_props(self):
        if self.ready:
            self.default_var_props(self.var)
            self.set_var_props(self.var)
            self.plot()

    def edit_options(self):
        dlg = OptionsForm(self)
        dlg.exec_()

    def plotpan(self):
        self.actionZoom.setChecked(False)
        self.mpl_toolbar.pan()

    def plotzoom(self):
        self.actionPan.setChecked(False)
        self.mpl_toolbar.zoom()

    def plotgrid(self):
        self._ax.grid()
        self._canvas.draw()

    def switch3d(self):
        if self.ready:
            if not self.action3D.isChecked():
                self._fig.clear()
                self._ax = self._fig.add_subplot(111)
            else:
                self._fig.clear()
                self._ax = self._fig.add_subplot(111, projection='3d')
            self.plot()

    def plot(self, item=None):
        if self.ready:
            self._ax.cla()
            if item:
                index = self._model.createIndex(item.row(), item.column())
                if index.isValid():
                    self.listView.setCurrentIndex(index)
            if not self.action3D.isChecked():
                extent = self.data.get_extent()
                i = 0
                while self._model.item(i):
                    if self._model.item(i).checkState():
                        CS = None
                        var = str(self._model.item(i).text())
                        # get data, smooth and clip
                        data = self.data.get_var(var,
                                                 nan=np.float(
                                                     self.settings.value(
                                                         "nan",
                                                         "NaN",
                                                         type=str)))
                        if self.props[var]['resample'] > 1:
                            data = np.ma.array(
                                ndimage.zoom(data.filled(0),
                                             self.props[var]['resample']),
                                mask=ndimage.zoom(data.mask,
                                                  self.props[var]['resample'],
                                                  order=0))
                        if self.props[var]['median'] > 1:
                            data = np.ma.array(ndimage.median_filter(
                                data,
                                size=self.props[var]['median'] *
                                self.props[var]['resample']),
                                               mask=data.mask)
                        if self.props[var]['gauss'] > 0:
                            data = np.ma.array(ndimage.gaussian_filter(
                                data,
                                sigma=self.props[var]['gauss'] *
                                self.props[var]['resample']),
                                               mask=data.mask)
                        data = np.ma.masked_outside(data,
                                                    self.props[var]['clipmin'],
                                                    self.props[var]['clipmax'])
                        if self.props[var]['fill']:
                            self._ax.imshow(
                                data,
                                interpolation='none',
                                origin='lower',
                                extent=extent,
                                aspect='auto',
                                cmap=cm.get_cmap(self.props[var]['cmap']),
                                alpha=self.props[var]['opacity'] / 100.0)
                        if self.props[var]['min'] == self.props[var]['max']:
                            clevels = np.array([self.props[var]['min']])
                        else:
                            if self.props[var]['type'] == 'linear':
                                if self.props[var]['levels'] == 'num':
                                    clevels = np.linspace(
                                        self.props[var]['min'],
                                        self.props[var]['max'],
                                        self.props[var]['num'])
                                else:
                                    # trick to include max in levels
                                    clevels = np.arange(
                                        self.props[var]['min'],
                                        self.props[var]['max'] +
                                        np.finfo(np.float32).eps,
                                        self.props[var]['step'])
                            else:
                                # cdf based on histogram binned acording to the Freedman-Diaconis rule
                                data = np.ma.masked_outside(
                                    data, self.props[var]['min'],
                                    self.props[var]['max'])
                                v = np.sort(data.compressed())
                                IQR = v[int(round(
                                    (v.size - 1) * float(0.75)))] - v[int(
                                        round((v.size - 1) * float(0.25)))]
                                bin_size = 2 * IQR * v.size**(-1.0 / 3)
                                nbins = int(
                                    round(
                                        max(self.props[var]['num'],
                                            (v[-1] - v[0]) /
                                            (bin_size + 0.001))))
                                hist, bin_edges = np.histogram(v, bins=nbins)
                                cdf = np.cumsum(hist)
                                cdfx = np.cumsum(np.diff(
                                    bin_edges)) + bin_edges[:2].sum() / 2
                                #clevels = np.interp(np.linspace(cdf[0],cdf[-1],self.props[var]['num'] + 2)[1:-1], cdf, cdfx)
                                clevels = np.interp(
                                    np.linspace(cdf[0], cdf[-1],
                                                self.props[var]['num']), cdf,
                                    cdfx)
                        clevels = np.round(
                            10**self.props[var]['digits'] *
                            clevels) / 10**self.props[var]['digits']
                        # Contour levels must be increasing
                        clevels = np.append(clevels[:1],
                                            clevels[1:][np.diff(clevels) > 0])
                        if self.props[var]['contours'] == 'map':
                            CS = self._ax.contour(
                                self.data.get_xrange(
                                    self.props[var]['resample']),
                                self.data.get_yrange(
                                    self.props[var]['resample']),
                                data,
                                clevels,
                                cmap=cm.get_cmap(self.props[var]['cmap']))
                        elif self.props[var]['contours'] == 'color':
                            CS = self._ax.contour(
                                self.data.get_xrange(
                                    self.props[var]['resample']),
                                self.data.get_yrange(
                                    self.props[var]['resample']),
                                data,
                                clevels,
                                colors=self.props[var]['color'])
                        if self.props[var]['label'] and CS:
                            self._ax.clabel(CS, fontsize=8, inline=1, fmt='%g')
                    i += 1

                self._ax.axis(extent)
                self._ax.set_title(self.data.label)
            else:
                # get data, smooth and clip
                data = self.data.get_var(self.var)
                if self.props[self.var]['resample'] > 1:
                    data = np.ma.array(
                        ndimage.zoom(data.filled(0),
                                     self.props[self.var]['resample']),
                        mask=ndimage.zoom(data.mask,
                                          self.props[self.var]['resample'],
                                          order=0))
                if self.props[self.var]['median'] > 1:
                    data = np.ma.array(ndimage.median_filter(
                        data,
                        size=self.props[self.var]['median'] *
                        self.props[self.var]['resample']),
                                       mask=data.mask)
                if self.props[self.var]['gauss'] > 0:
                    data = np.ma.array(ndimage.gaussian_filter(
                        data,
                        sigma=self.props[self.var]['gauss'] *
                        self.props[self.var]['resample']),
                                       mask=data.mask)
                data = np.ma.masked_outside(data,
                                            self.props[self.var]['clipmin'],
                                            self.props[self.var]['clipmax'])
                x, y = np.meshgrid(
                    self.data.get_xrange(self.props[self.var]['resample']),
                    self.data.get_yrange(self.props[self.var]['resample']))
                self._ax.plot_surface(
                    x,
                    y,
                    data.filled(np.NaN),
                    vmin=data.min(),
                    vmax=data.max(),
                    cmap=cm.get_cmap(self.props[self.var]['cmap']),
                    linewidth=0.5,
                    alpha=self.props[self.var]['opacity'] / 100.0)
                self._ax.view_init(azim=235, elev=30)

            self._ax.set_xlabel(self.data.ind[self.data.xvar]['name'])
            self._ax.set_ylabel(self.data.ind[self.data.yvar]['name'])
            self._fig.tight_layout()
            self._canvas.draw()
예제 #32
0
class MercuryMonitorApp(QtWidgets.QMainWindow):
    def __init__(self, feed):
        super(self.__class__, self).__init__()
        uic.loadUi(MAIN_UI_PATH, self)

        self.feed = feed

        # create popup Widgets
        self.connection_dialog = ConnectionDialog(self, feed.mercury)
        self.readingsWindow = None

        # create LED indicator
        self.led = LedIndicator(self)
        self.statusbar.addPermanentWidget(self.led)
        self.led.setChecked(False)

        # set up figure for plotting
        self.canvas = MercuryPlotCanvas(self)
        self.gridLayoutCanvas.addWidget(self.canvas)
        self.canvas.draw()

        # adapt text edit colors to graph colors
        self.t1_reading.setStyleSheet('color:rgb%s' %
                                      str(tuple(self.canvas.GREEN * 255)))
        self.gf1_edit.setStyleSheet('color:rgb%s' %
                                    str(tuple(self.canvas.BLUE * 255)))
        self.h1_edit.setStyleSheet('color:rgb%s' %
                                   str(tuple(self.canvas.RED * 255)))
        self.gf1_unit.setStyleSheet('color:rgb%s' %
                                    str(tuple(self.canvas.BLUE * 255)))
        self.h1_unit.setStyleSheet('color:rgb%s' %
                                   str(tuple(self.canvas.RED * 255)))

        # allow panning of plot
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()
        self.toolbar.pan()

        # set up data vectors for plot
        self.xdata = np.array([])
        self.xdata_zero = np.array([])
        self.ydata_tmpr = np.array([])
        self.ydata_gflw = np.array([])
        self.ydata_htr = np.array([])

        # restore previous window geometry
        self.restore_geometry()
        # Connect menu bar actions
        self.set_up_menubar()
        # set input validators for all fields
        self.set_input_validators()

        # check if mercury is connected, connect slots
        self.display_message('Looking for Mercury at %s...' %
                             self.feed.visa_address)
        if self.feed.mercury.connected:
            self.update_gui_connection(connected=True)

        # start (stop) updates of GUI when mercury is connected (disconnected)
        # adjust clickable buttons upon connect / disconnect
        self.feed.connected_signal.connect(self.update_gui_connection)

        # get new readings when available, send as out signals
        self.feed.new_readings_signal.connect(self.fetch_readings)
        # update plot when new data arrives
        self.feed.new_readings_signal.connect(self.update_plot_data)
        # check for overheating when new data arrives
        self.feed.new_readings_signal.connect(self._check_overheat)

        # set up logging to file
        self.setup_logging()

# =================== BASIC UI SETUP ==========================================

    def restore_geometry(self):
        x = CONF.get('Window', 'x')
        y = CONF.get('Window', 'y')
        w = CONF.get('Window', 'width')
        h = CONF.get('Window', 'height')

        self.setGeometry(x, y, w, h)

    def save_geometry(self):
        geo = self.geometry()
        CONF.set('Window', 'height', geo.height())
        CONF.set('Window', 'width', geo.width())
        CONF.set('Window', 'x', geo.x())
        CONF.set('Window', 'y', geo.y())

    def exit_(self):
        self.feed.exit_()
        self.save_geometry()
        self.deleteLater()

    def closeEvent(self, event):
        self.exit_()

    def set_up_menubar(self):
        """
        Connects menu bar items to callbacks, sets their initial activation.
        """
        # connect to callbacks
        self.showLogAction.triggered.connect(self.on_log_clicked)
        self.exitAction.triggered.connect(self.exit_)
        self.readingsAction.triggered.connect(self.on_readings_clicked)
        self.connectAction.triggered.connect(self.feed.connect)
        self.disconnectAction.triggered.connect(self.feed.disconnect)
        self.updateAddressAction.triggered.connect(self.connection_dialog.open)

        # initially disable menu bar items, will be enabled later individually
        self.connectAction.setEnabled(True)
        self.disconnectAction.setEnabled(False)
        self.modulesAction.setEnabled(False)
        self.readingsAction.setEnabled(False)

    @QtCore.Slot(bool)
    def update_gui_connection(self, connected):
        if connected:
            self.display_message('Connection established.')
            self.led.setChecked(True)

            # enable / disable menu bar items
            self.connectAction.setEnabled(False)
            self.disconnectAction.setEnabled(True)
            self.modulesAction.setEnabled(True)
            self.readingsAction.setEnabled(True)

            # connect user input to change mercury settings
            self.t2_edit.returnPressed.connect(self.change_t_setpoint)
            self.r1_edit.returnPressed.connect(self.change_ramp)
            self.r2_checkbox.clicked.connect(self.change_ramp_auto)
            self.gf1_edit.returnPressed.connect(self.change_flow)
            self.gf2_checkbox.clicked.connect(self.change_flow_auto)
            self.h1_edit.returnPressed.connect(self.change_heater)
            self.h2_checkbox.clicked.connect(self.change_heater_auto)

            # set update_plot to be executed every time the slider position changes
            self.horizontalSlider.valueChanged.connect(self.update_plot)

        elif not connected:
            self.display_error('Connection lost.')
            logger.info('Connection to MercuryiTC lost.')
            self.led.setChecked(False)

            # enable / disable menu bar items
            self.connectAction.setEnabled(True)
            self.disconnectAction.setEnabled(False)
            self.modulesAction.setEnabled(False)
            self.readingsAction.setEnabled(False)

            # disconnect user input from mercury
            self.t2_edit.returnPressed.disconnect(self.change_t_setpoint)
            self.r1_edit.returnPressed.disconnect(self.change_ramp)
            self.r2_checkbox.clicked.disconnect(self.change_ramp_auto)
            self.gf1_edit.returnPressed.disconnect(self.change_flow)
            self.gf2_checkbox.clicked.disconnect(self.change_flow_auto)
            self.h1_edit.returnPressed.disconnect(self.change_heater)
            self.h2_checkbox.clicked.disconnect(self.change_heater_auto)

            # disconnect update_plot
            self.horizontalSlider.valueChanged.disconnect(self.update_plot)

    def set_input_validators(self):
        """ Sets validators for input fields"""
        self.t2_edit.setValidator(QtGui.QDoubleValidator())
        self.r1_edit.setValidator(QtGui.QDoubleValidator())
        self.gf1_edit.setValidator(QtGui.QDoubleValidator())
        self.h1_edit.setValidator(QtGui.QDoubleValidator())

    def display_message(self, text):
        self.statusbar.showMessage('%s' % text, 5000)

    def display_error(self, text):
        self.statusbar.showMessage('%s' % text)

    @QtCore.Slot(object)
    def fetch_readings(self, readings):
        """
        Parses readings for the MercuryMonitorApp and updates UI accordingly
        """
        # heater signals
        self.h1_label.setText('Heater, %s V:' % readings['HeaterVolt'])
        self.h1_edit.updateValue(readings['HeaterPercent'])

        is_heater_auto = readings['HeaterAuto'] == 'ON'
        self.h1_edit.setReadOnly(is_heater_auto)
        self.h1_edit.setEnabled(not is_heater_auto)
        self.h2_checkbox.setChecked(is_heater_auto)

        # gas flow signals
        self.gf1_edit.updateValue(readings['FlowPercent'])
        self.gf1_label.setText('Gas flow (min = %s%%):' % readings['FlowMin'])

        is_gf_auto = readings['FlowAuto'] == 'ON'
        self.gf2_checkbox.setChecked(is_gf_auto)
        self.gf1_edit.setEnabled(not is_gf_auto)
        self.gf1_edit.setReadOnly(is_gf_auto)

        # temperature signals
        self.t1_reading.setText('%s K' % round(readings['Temp'], 3))
        self.t2_edit.updateValue(readings['TempSetpoint'])
        self.r1_edit.updateValue(readings['TempRamp'])

        is_ramp_enable = readings['TempRampEnable'] == 'ON'
        self.r2_checkbox.setChecked(is_ramp_enable)

    @QtCore.Slot(object)
    def update_plot_data(self, readings):
        # append data for plotting
        self.xdata = np.append(self.xdata, time.time())
        self.ydata_tmpr = np.append(self.ydata_tmpr, readings['Temp'])
        self.ydata_gflw = np.append(self.ydata_gflw,
                                    readings['FlowPercent'] / 100)
        self.ydata_htr = np.append(self.ydata_htr,
                                   readings['HeaterPercent'] / 100)

        # prevent data vector from exceeding 86400 entries
        self.xdata = self.xdata[-86400:]
        self.ydata_tmpr = self.ydata_tmpr[-86400:]
        self.ydata_gflw = self.ydata_gflw[-86400:]
        self.ydata_htr = self.ydata_htr[-86400:]

        # convert xData to minutes and set current time to t = 0
        self.xdata_zero = (self.xdata - max(self.xdata)) / 60

        self.update_plot()

    @QtCore.Slot()
    def update_plot(self):

        # select data to be plotted
        x_slice = self.xdata_zero >= -self.horizontalSlider.value()
        self.current_xdata = self.xdata_zero[x_slice]
        self.current_ydata_tmpr = self.ydata_tmpr[x_slice]
        self.current_ydata_gflw = self.ydata_gflw[x_slice]
        self.current_ydata_htr = self.ydata_htr[x_slice]

        # determine first plotted data point
        if self.current_xdata.size == 0:
            x_min = -self.horizontalSlider.value()
        else:
            x_min = max(-self.horizontalSlider.value(), self.current_xdata[0])

        # update plot
        self.canvas.update_plot(self.current_xdata, self.current_ydata_tmpr,
                                self.current_ydata_gflw,
                                self.current_ydata_htr, x_min)

        # update label
        self.timeLabel.setText('Show last %s min' %
                               self.horizontalSlider.value())

# =================== LOGGING DATA ============================================

    def setup_logging(self):
        """
        Set up logging of temperature history to files.
        Save temperature history to log file at '~/.CustomXepr/LOG_FILES/'
        after every 10 min.
        """
        # find user home directory
        home_path = os.path.expanduser('~')
        self.logging_path = os.path.join(home_path, '.mercurygui', 'LOG_FILES')

        # create folder '~/.CustomXepr/LOG_FILES' if not present
        if not os.path.exists(self.logging_path):
            os.makedirs(self.logging_path)
        # set logging file path
        self.log_file = os.path.join(
            self.logging_path,
            'temperature_log ' + time.strftime("%Y-%m-%d_%H-%M-%S") + '.txt')

        t_save = 10  # time interval to save temperature data in min
        self.new_file = True  # create new log file for every new start
        self.save_timer = QtCore.QTimer()
        self.save_timer.setInterval(t_save * 60 * 1000)
        self.save_timer.setSingleShot(False)  # set to reoccur
        self.save_timer.timeout.connect(self.log_temperature_data)
        self.save_timer.start()

    def save_temperature_data(self, path=None):
        # prompt user for file path if not given
        if path is None:
            text = 'Select path for temperature data file:'
            path = QtWidgets.QFileDialog.getSaveFileName(caption=text)
            path = path[0]

        if not path.endswith('.txt'):
            path += '.txt'

        title = 'temperature trace, saved on ' + time.strftime(
            '%d/%m/%Y') + '\n'
        heater_vlim = self.feed.heater.vlim
        header = '\t'.join([
            'Time (sec)', 'Temperature (K)',
            'Heater (%% of %sV)' % heater_vlim, 'Gas flow (%)'
        ])

        data_matrix = np.concatenate(
            (self.xdata[:, np.newaxis], self.ydata_tmpr[:, np.newaxis],
             self.ydata_htr[:, np.newaxis], self.ydata_gflw[:, np.newaxis]),
            axis=1)

        # noinspection PyTypeChecker
        np.savetxt(path, data_matrix, delimiter='\t', header=title + header)

    def log_temperature_data(self):
        # save temperature data to log file
        if self.feed.mercury.connected:
            self.save_temperature_data(self.log_file)

# =================== CALLBACKS FOR SETTING CHANGES ===========================

    @QtCore.Slot()
    def change_t_setpoint(self):
        new_t = self.t2_edit.value()

        if 3.5 < new_t < 300:
            self.display_message('T_setpoint = %s K' % new_t)
            self.feed.control.t_setpoint = new_t
        else:
            self.display_error('Error: Only temperature setpoints between ' +
                               '3.5 K and 300 K allowed.')

    @QtCore.Slot()
    def change_ramp(self):
        self.feed.control.ramp = self.r1_edit.value()
        self.display_message('Ramp = %s K/min' % self.r1_edit.value())

    @QtCore.Slot(bool)
    def change_ramp_auto(self, checked):
        if checked:
            self.feed.control.ramp_enable = 'ON'
            self.display_message('Ramp is turned ON')
        else:
            self.feed.control.ramp_enable = 'OFF'
            self.display_message('Ramp is turned OFF')

    @QtCore.Slot()
    def change_flow(self):
        self.feed.control.flow = self.gf1_edit.value()
        self.display_message('Gas flow  = %s%%' % self.gf1_edit.value())

    @QtCore.Slot(bool)
    def change_flow_auto(self, checked):
        if checked:
            self.feed.control.flow_auto = 'ON'
            self.display_message('Gas flow is automatically controlled.')
            self.gf1_edit.setReadOnly(True)
            self.gf1_edit.setEnabled(False)
        else:
            self.feed.control.flow_auto = 'OFF'
            self.display_message('Gas flow is manually controlled.')
            self.gf1_edit.setReadOnly(False)
            self.gf1_edit.setEnabled(True)

    @QtCore.Slot()
    def change_heater(self):
        self.feed.control.heater = self.h1_edit.value()
        self.display_message('Heater power  = %s%%' % self.h1_edit.value())

    @QtCore.Slot(bool)
    def change_heater_auto(self, checked):
        if checked:
            self.feed.control.heater_auto = 'ON'
            self.display_message('Heater is automatically controlled.')
            self.h1_edit.setReadOnly(True)
            self.h1_edit.setEnabled(False)
        else:
            self.feed.control.heater_auto = 'OFF'
            self.display_message('Heater is manually controlled.')
            self.h1_edit.setReadOnly(False)
            self.h1_edit.setEnabled(True)

    @QtCore.Slot(object)
    def _check_overheat(self, readings):
        if readings['Temp'] > 310:
            self.display_error('Over temperature!')
            self.feed.control.heater_auto = 'OFF'
            self.feed.control.heater = 0

# ========================== CALLBACKS FOR MENU BAR ===========================

    @QtCore.Slot()
    def on_readings_clicked(self):
        # create readings overview window if not present
        if self.readingsWindow is None:
            self.readingsWindow = ReadingsOverview(self.feed.mercury)
        # show it
        self.readingsWindow.show()

    @QtCore.Slot()
    def on_log_clicked(self):
        """
        Opens directory with log files with current log file selected.
        """

        if platform.system() == 'Windows':
            os.startfile(self.logging_path)
        elif platform.system() == 'Darwin':
            subprocess.Popen(['open', self.logging_path])
        else:
            subprocess.Popen(['xdg-open', self.logging_path])
예제 #33
0
파일: plotmaps.py 프로젝트: prklVIP/PyLSS
class PlotMaps(QtWidgets.QDialog, Ui_PlotMaps):
    def __init__(self, modellst, type="sel", parent=None):
        QtWidgets.QDialog.__init__(self, parent)
        self.setupUi(self)

        # Create the plot
        #self.figure = plt.figure()
        self.figure, self.axes = plt.subplots(nrows=3, ncols=1)
        self.canvas = FigureCanvas(self.figure)
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()
        # set the layout
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.canvas)
        self.plotterBox.setLayout(layout)
        self.closeButton.clicked.connect(self.close_)

        if type == "sel":
            self.modelBox.currentIndexChanged.connect(self.plotselectivitymap)
        else:
            self.modelBox.currentIndexChanged.connect(self.plotresolutionmap)

        self.modellst = modellst
        for model in self.modellst:
            self.modelBox.addItem(model.modname)

    def close_(self):
        self.reject()

    def plotchromatogram(self):
        ''' plot some random stuff '''
        data = [random.random() for i in range(25)]
        ax = self.figure.add_subplot(111)
        ax.hold(False)
        ax.plot(data, '*-')
        self.canvas.draw()

    def plotresolutionmap(self):
        indx = self.modelBox.currentIndex()
        if indx >= 0 and indx < len(self.modellst):
            lss = self.modellst[indx].lss
            flow_sofware = self.modellst[indx].flow
            v_m = self.modellst[indx].v_m
            v_d = self.modellst[indx].v_d
            c_particle = self.modellst[indx].c_particle
            c_length = self.modellst[indx].c_length

            opt = OptSep(v_m, v_d, flow_sofware, lss)
            opt.c_particle = c_particle
            opt.c_length = c_length
            [gcondlst, reslst, trlst] = opt.getResMapPlot("lss",
                                                          float(flow_sofware),
                                                          g_start_min=0.00,
                                                          g_start_max=0.30,
                                                          g_stop_min=0.50,
                                                          g_stop_max=1.0,
                                                          time_grad_min=2,
                                                          time_grad_max=60)

            #Plot resolution map
            x = []
            y_gsteepness = []
            y_final_b = []
            y_tg = []
            z = []
            for i in range(len(gcondlst)):
                #gcondlst.append([init_b, final_b, tg, self.flow, lowest_alpha])
                x.append(float(gcondlst[i][0]) * 100)
                y_gsteepness.append(
                    float((gcondlst[i][1] - gcondlst[i][0]) /
                          gcondlst[i][2]))  # alpha
                y_final_b.append(float(gcondlst[i][1]) * 100)  # final b
                y_tg.append(float(gcondlst[i][2]))  # tg
                z.append(float(gcondlst[i][-1]))

            x = np.asarray(x)
            y_gsteepness = np.asarray(y_gsteepness)
            y_final_b = np.asarray(y_final_b)
            y_tg = np.asarray(y_tg)
            z = np.asarray(z)

            # Set up a regular grid of interpolation points
            npoints = 500
            xi, yi_gsteepness = np.linspace(x.min(), x.max(),
                                            npoints), np.linspace(
                                                y_gsteepness.min(),
                                                y_gsteepness.max(), npoints)
            xi, yi_gsteepness = np.meshgrid(xi, yi_gsteepness)

            xi, yi_final_b = np.linspace(x.min(), x.max(),
                                         npoints), np.linspace(
                                             y_final_b.min(), y_final_b.max(),
                                             npoints)
            xi, yi_final_b = np.meshgrid(xi, yi_final_b)

            xi, yi_tg = np.linspace(x.min(), x.max(), npoints), np.linspace(
                y_tg.min(), y_tg.max(), npoints)
            xi, yi_tg = np.meshgrid(xi, yi_tg)

            # Interpolate
            #rbf = scipy.interpolate.Rbf(x, y, z, function='linear')
            #zi = rbf(xi, yi)

            zi_gsteepness = scipy.interpolate.griddata((x, y_gsteepness),
                                                       z, (xi, yi_gsteepness),
                                                       method='linear')
            zi_final_b = scipy.interpolate.griddata((x, y_final_b),
                                                    z, (xi, yi_final_b),
                                                    method='linear')
            zi_tg = scipy.interpolate.griddata((x, y_tg),
                                               z, (xi, yi_tg),
                                               method='linear')

            #f, axarr = plt.subplots(3, sharex=True)
            #axes = self.figure.add_subplot(nrows=3, ncols=1)

            im = self.axes.flat[0].imshow(zi_gsteepness,
                                          vmin=z.min(),
                                          vmax=z.max(),
                                          origin='lower',
                                          extent=[
                                              x.min(),
                                              x.max(),
                                              y_gsteepness.min(),
                                              y_gsteepness.max()
                                          ],
                                          aspect='auto')
            self.axes.flat[0].set_xlabel('Initial B (%)')
            self.axes.flat[0].set_ylabel('Gradient steepness')

            im = self.axes.flat[1].imshow(
                zi_final_b,
                vmin=z.min(),
                vmax=z.max(),
                origin='lower',
                extent=[x.min(),
                        x.max(),
                        y_final_b.min(),
                        y_final_b.max()],
                aspect='auto')

            self.axes.flat[1].set_xlabel('Initial B (%)')
            self.axes.flat[1].set_ylabel('Final B (%)')

            im = self.axes.flat[2].imshow(
                zi_tg,
                vmin=z.min(),
                vmax=z.max(),
                origin='lower',
                extent=[x.min(), x.max(),
                        y_tg.min(), y_tg.max()],
                aspect='auto')

            self.axes.flat[2].set_xlabel('Initial B (%)')
            self.axes.flat[2].set_ylabel('Time gradient (min)')

            self.figure.colorbar(im, ax=self.axes.ravel().tolist())
            self.canvas.draw()

    def plotselectivitymap(self):
        plt.cla()
        indx = self.modelBox.currentIndex()
        if indx >= 0 and indx < len(self.modellst):
            lss = self.modellst[indx].lss
            flow_sofware = self.modellst[indx].flow
            v_m = self.modellst[indx].v_m
            v_d = self.modellst[indx].v_d

            opt = OptSep(v_m, v_d, flow_sofware, lss)
            [gcondlst, sellst, trlst] = opt.getSelMapPlot("lss",
                                                          float(flow_sofware),
                                                          g_start_min=0.00,
                                                          g_start_max=0.30,
                                                          g_stop_min=0.50,
                                                          g_stop_max=1.0,
                                                          time_grad_min=2,
                                                          time_grad_max=60)

            #Plot selectivity map
            x = []
            y_gsteepness = []
            y_final_b = []
            y_tg = []
            z = []
            for i in range(len(gcondlst)):
                #gcondlst.append([init_b, final_b, tg, self.flow, lowest_alpha])
                x.append(float(gcondlst[i][0]) * 100)
                y_gsteepness.append(
                    float((gcondlst[i][1] - gcondlst[i][0]) / gcondlst[i][2] +
                          1))  # alpha
                y_final_b.append(float(gcondlst[i][1]) * 100)  # final b
                y_tg.append(float(gcondlst[i][2]))  # tg
                z.append(float(gcondlst[i][-1]))

            x = np.asarray(x)
            y_gsteepness = np.asarray(y_gsteepness)
            y_final_b = np.asarray(y_final_b)
            y_tg = np.asarray(y_tg)
            z = np.asarray(z)

            # Set up a regular grid of interpolation points
            npoints = 500
            xi, yi_gsteepness = np.linspace(x.min(), x.max(),
                                            npoints), np.linspace(
                                                y_gsteepness.min(),
                                                y_gsteepness.max(), npoints)
            xi, yi_gsteepness = np.meshgrid(xi, yi_gsteepness)

            xi, yi_final_b = np.linspace(x.min(), x.max(),
                                         npoints), np.linspace(
                                             y_final_b.min(), y_final_b.max(),
                                             npoints)
            xi, yi_final_b = np.meshgrid(xi, yi_final_b)

            xi, yi_tg = np.linspace(x.min(), x.max(), npoints), np.linspace(
                y_tg.min(), y_tg.max(), npoints)
            xi, yi_tg = np.meshgrid(xi, yi_tg)

            # Interpolate
            #rbf = scipy.interpolate.Rbf(x, y, z, function='linear')
            #zi = rbf(xi, yi)

            zi_gsteepness = scipy.interpolate.griddata((x, y_gsteepness),
                                                       z, (xi, yi_gsteepness),
                                                       method='linear')
            zi_final_b = scipy.interpolate.griddata((x, y_final_b),
                                                    z, (xi, yi_final_b),
                                                    method='linear')
            zi_tg = scipy.interpolate.griddata((x, y_tg),
                                               z, (xi, yi_tg),
                                               method='linear')

            #f, axarr = plt.subplots(3, sharex=True)
            #axes = self.figure.add_subplot(nrows=3, ncols=1)

            im = self.axes.flat[0].imshow(zi_gsteepness,
                                          vmin=z.min(),
                                          vmax=z.max(),
                                          origin='lower',
                                          extent=[
                                              x.min(),
                                              x.max(),
                                              y_gsteepness.min(),
                                              y_gsteepness.max()
                                          ],
                                          aspect='auto')
            self.axes.flat[0].set_xlabel('Initial B (%)')
            self.axes.flat[0].set_ylabel('Gradient steepness')

            im = self.axes.flat[1].imshow(
                zi_final_b,
                vmin=z.min(),
                vmax=z.max(),
                origin='lower',
                extent=[x.min(),
                        x.max(),
                        y_final_b.min(),
                        y_final_b.max()],
                aspect='auto')

            self.axes.flat[1].set_xlabel('Initial B (%)')
            self.axes.flat[1].set_ylabel('Final B (%)')

            im = self.axes.flat[2].imshow(
                zi_tg,
                vmin=z.min(),
                vmax=z.max(),
                origin='lower',
                extent=[x.min(), x.max(),
                        y_tg.min(), y_tg.max()],
                aspect='auto')

            self.axes.flat[2].set_xlabel('Initial B (%)')
            self.axes.flat[2].set_ylabel('Time gradient (min)')

            self.figure.colorbar(im, ax=self.axes.ravel().tolist())
            self.canvas.draw()
예제 #34
0
파일: design.py 프로젝트: jimhendy/DataView
class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName(_fromUtf8("Data View"))
        #MainWindow.resize(539, 600)
        
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName(_fromUtf8("centralwidget"))

        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
        self.splitter = QtWidgets.QSplitter(self.centralwidget)
        self.splitter.setOrientation(QtCore.Qt.Horizontal)
        self.splitter.setObjectName(_fromUtf8("splitter"))        

        # File navigation
        self.fileSystemModel = QtWidgets.QDirModel(self.splitter)
        self.fileSystemModel.setObjectName(_fromUtf8("fileSystemModel"))
        currentDir = str(QtCore.QDir.currentPath())
        index = self.fileSystemModel.index(currentDir)
        self.treeView = QtWidgets.QTreeView(self.splitter)
        self.treeView.setObjectName(_fromUtf8("treeView"))
        self.treeView.setModel(self.fileSystemModel)
        if len(sys.argv)>1:
            self.currentFile = currentDir + '/' + sys.argv[1]
        else:
            self.currentFile = None
        self.recursive_expand( index, self.treeView )
        tVheader = self.treeView.header()
        for i in range(1,4): tVheader.hideSection(i)
        self.treeView.doubleClicked.connect(self.on_treeView_doubleClicked)

        # Plots tab
        self.tabWidget = QtWidgets.QTabWidget(self.splitter)
        self.tabWidget.setObjectName(_fromUtf8("tabWidget"))
        self.tab = QtWidgets.QWidget()
        self.tab.setObjectName(_fromUtf8("tab"))
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab)
        self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2"))
        self.figure = plt.figure(figsize=(15,5))    
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setObjectName(_fromUtf8("canvas"))
        self.toolbar = NavigationToolbar(self.canvas, self)
        self.toolbar.hide()
        self.verticalLayout_2.addWidget(self.canvas)

        # Plot buttons
        self.horizontalLayout = QtWidgets.QHBoxLayout()
        self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout_plotButtons"))
        self.plotTypeCombo = QtWidgets.QComboBox(self.tab)
        self.plotTypeCombo.setObjectName(_fromUtf8("plotTypeCombo"))
        self.plotTypeCombo.currentIndexChanged.connect(self.ChangePlotType)
        self.horizontalLayout.addWidget(self.plotTypeCombo)
        self.btnPlot = QtWidgets.QPushButton(self.tab)
        self.btnPlot.setObjectName(_fromUtf8("btnPlot"))
        self.btnPlot.clicked.connect(self.drawPlot)
        self.horizontalLayout.addWidget(self.btnPlot)
        self.btnZoom = QtWidgets.QPushButton(self.tab)
        self.btnZoom.setObjectName(_fromUtf8("btnZoom"))
        self.btnZoom.clicked.connect(self.plotZoom)
        self.horizontalLayout.addWidget(self.btnZoom)
        self.btnPan = QtWidgets.QPushButton(self.tab)
        self.btnPan.setObjectName(_fromUtf8("btnPan"))
        self.btnPan.clicked.connect(self.plotPan)
        self.horizontalLayout.addWidget(self.btnPan)
        self.btnHome = QtWidgets.QPushButton(self.tab)
        self.btnHome.setObjectName(_fromUtf8("btnHome"))
        self.btnHome.clicked.connect(self.plotHome)
        self.horizontalLayout.addWidget(self.btnHome)
        self.verticalLayout_2.addLayout(self.horizontalLayout)

        # x axis options
        self.horizontalLayout_xAxis = QtWidgets.QHBoxLayout()
        self.horizontalLayout_xAxis.setObjectName(_fromUtf8("horizontalLayout_xAxis"))
        self.xColSelect = QtWidgets.QComboBox(self.tab)
        self.xColSelect.setObjectName(_fromUtf8("xColSelect"))
        self.xColSelect.currentIndexChanged.connect(self.ResetUserSelections)
        self.horizontalLayout_xAxis.addWidget(self.xColSelect)
        self.horizontalLayout_xAxis.setStretchFactor(self.xColSelect,2)
        self.xbinsLabel = QtWidgets.QLabel(self.tab)
        self.xbinsLabel.setText("X Bins:")
        self.horizontalLayout_xAxis.addWidget( self.xbinsLabel )
        self.xnBinsSpin = QtWidgets.QSpinBox(self.tab)
        self.xnBinsSpin.setObjectName(_fromUtf8("xnBinsSpin"))
        self.xnBinsSpin.valueChanged.connect(self.XChangeBinning)
        self.xnBinsSpin.setRange(1,10000)
        self.horizontalLayout_xAxis.addWidget( self.xnBinsSpin )
        self.horizontalLayout_xAxis.setStretchFactor(self.xnBinsSpin,2)
        self.xminLabel = QtWidgets.QLabel(self.tab)
        self.xminLabel.setText("X Min:")
        self.horizontalLayout_xAxis.addWidget( self.xminLabel )
        self.xnMinSpin = QtWidgets.QDoubleSpinBox(self.tab)
        self.xnMinSpin.setObjectName(_fromUtf8("xnMinSpin"))
        self.xnMinSpin.valueChanged.connect(self.XChangeMin)
        self.xnMinSpin.setRange( -1e20, 1e20 )
        self.horizontalLayout_xAxis.addWidget( self.xnMinSpin )
        self.horizontalLayout_xAxis.setStretchFactor(self.xnMinSpin,2)
        self.xmaxLabel = QtWidgets.QLabel(self.tab)
        self.xmaxLabel.setText("X Max:")
        self.horizontalLayout_xAxis.addWidget( self.xmaxLabel )
        self.xnMaxSpin = QtWidgets.QDoubleSpinBox(self.tab)
        self.xnMaxSpin.setObjectName(_fromUtf8("xnMaxSpin"))
        self.xnMaxSpin.setRange( -1e20, 1e20 )
        self.xnMaxSpin.valueChanged.connect(self.XChangeMax)
        self.horizontalLayout_xAxis.addWidget( self.xnMaxSpin )
        self.horizontalLayout_xAxis.setStretchFactor(self.xnMaxSpin,2)
        self.xTypeCombo = QtWidgets.QComboBox(self.tab)
        self.xTypeCombo.setObjectName(_fromUtf8("xTypeCombo"))
        self.xTypeCombo.addItems( ['int','float','str','datetime'] )
        self.xTypeCombo.currentIndexChanged.connect(self.ChangeXDataType)
        self.horizontalLayout_xAxis.addWidget(self.xTypeCombo)
        self.horizontalLayout_xAxis.setStretchFactor(self.xTypeCombo,2)
        self.verticalLayout_2.addLayout(self.horizontalLayout_xAxis )
        
        # y axis options
        self.horizontalLayout_yAxis = QtWidgets.QHBoxLayout()
        self.horizontalLayout_yAxis.setObjectName(_fromUtf8("horizontalLayout_yAxis"))
        self.yColSelect = QtWidgets.QComboBox(self.tab)
        self.yColSelect.setObjectName(_fromUtf8("yColSelect"))
        self.yColSelect.currentIndexChanged.connect(self.ResetUserSelections)
        self.horizontalLayout_yAxis.addWidget(self.yColSelect)
        self.horizontalLayout_yAxis.setStretchFactor(self.yColSelect,2)
        self.ybinsLabel = QtWidgets.QLabel(self.tab)
        self.ybinsLabel.setText("Y Bins:")
        self.horizontalLayout_yAxis.addWidget( self.ybinsLabel )
        self.ynBinsSpin = QtWidgets.QSpinBox(self.tab)
        self.ynBinsSpin.setObjectName(_fromUtf8("ynBinsSpin"))
        self.ynBinsSpin.valueChanged.connect(self.YChangeBinning)
        self.horizontalLayout_yAxis.addWidget( self.ynBinsSpin )
        self.horizontalLayout_yAxis.setStretchFactor(self.ynBinsSpin,2)
        self.yminLabel = QtWidgets.QLabel(self.tab)
        self.yminLabel.setText("Y Min:")
        self.horizontalLayout_yAxis.addWidget( self.yminLabel )
        self.ynMinSpin = QtWidgets.QDoubleSpinBox(self.tab)
        self.ynMinSpin.setObjectName(_fromUtf8("ynMinSpin"))
        self.ynMinSpin.setRange( -1e20, 1e20 )
        self.ynMinSpin.valueChanged.connect(self.YChangeMin)
        self.horizontalLayout_yAxis.addWidget( self.ynMinSpin )
        self.horizontalLayout_yAxis.setStretchFactor(self.ynMinSpin,2)
        self.ymaxLabel = QtWidgets.QLabel(self.tab)
        self.ymaxLabel.setText("Y Max:")
        self.horizontalLayout_yAxis.addWidget( self.ymaxLabel )
        self.ynMaxSpin = QtWidgets.QDoubleSpinBox(self.tab)
        self.ynMaxSpin.setObjectName(_fromUtf8("ynMaxSpin"))
        self.ynMaxSpin.setRange( -1e20, 1e20 )
        self.ynMaxSpin.valueChanged.connect(self.YChangeMax)
        self.horizontalLayout_yAxis.addWidget( self.ynMaxSpin )
        self.horizontalLayout_yAxis.setStretchFactor(self.ynMaxSpin,2)
        self.yTypeCombo = QtWidgets.QComboBox(self.tab)
        self.yTypeCombo.setObjectName(_fromUtf8("yTypeCombo"))
        self.yTypeCombo.addItems( ['int','float','str','datetime'] )
        self.yTypeCombo.currentIndexChanged.connect(self.ChangeYDataType)
        self.horizontalLayout_yAxis.addWidget(self.yTypeCombo)
        self.horizontalLayout_yAxis.setStretchFactor(self.yTypeCombo,2)
        #self.verticalLayout_2.addLayout(self.horizontalLayout_yAxis )
        self.yAxisItems = [ self.yColSelect, self.ybinsLabel, self.ynBinsSpin, self.yminLabel, self.ynMinSpin,
                            self.ymaxLabel, self.ynMaxSpin, self.yTypeCombo ]

        self.binningChoices = [ self.ybinsLabel, self.ynBinsSpin, self.xbinsLabel, self.xnBinsSpin ]
        
        # Data tab
        self.tabWidget.addTab(self.tab, _fromUtf8(""))
        self.tab_2 = QtWidgets.QWidget()
        self.tab_2.setObjectName(_fromUtf8("tab_2"))
        self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.tab_2)
        self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3"))
        self.tableView = QtWidgets.QTableView(self.tab_2)
        self.tableView.setObjectName(_fromUtf8("tableView"))
        self.verticalLayout_3.addWidget(self.tableView)
        
        # Filter text entry
        self.filterHorLayout = QtWidgets.QHBoxLayout()
        self.filterHorLayout.setObjectName(_fromUtf8("filterHorLayout"))
        self.filterBox = QtWidgets.QLineEdit(self.centralwidget)
        self.filterBox.setObjectName(_fromUtf8("filterBox"))
        self.btnFilter = QtWidgets.QPushButton(self.centralwidget)
        self.btnFilter.setObjectName(_fromUtf8("btnFilter"))
        self.btnFilter.clicked.connect(self.updateTable)
        self.filterHorLayout.addWidget(self.filterBox)
        self.filterHorLayout.addWidget(self.btnFilter)
        self.verticalLayout.addLayout(self.filterHorLayout)
        
        # Setup
        self.treeView.raise_()
        self.tabWidget.addTab(self.tab_2, _fromUtf8(""))
        self.verticalLayout.addWidget(self.splitter)
        self.splitter.setStretchFactor(1, 2)
        self.centralwidget.showFullScreen()
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName(_fromUtf8("statusbar"))
        MainWindow.setStatusBar(self.statusbar)

        # Set the default picture
        import matplotlib.image as mpimg
        img=mpimg.imread(r'H:\stash_projects\DataView\PandaViz.jpg')
        plt.imshow(img)

        self.hdfStore = None
        self.plotTypeCombo.addItems( ['Scatter','Line','Hist','Hist2d'] )
        self.userxBinning = False
        self.userxMax = False
        self.userxMin = False
        self.useryBinning = False
        self.useryMax = False
        self.useryMin = False        
        self.fileName = ""
        self.df = None
        self.orig_df = None
        self.filterStr = None
        self.lastFilterStr = None
        
        self.retranslateUi(MainWindow)
        self.tabWidget.setCurrentIndex(0)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)
       
        if self.currentFile is not None:

            if len(self.currentFile.split( r':' )) > 1:
                self.currentFile = self.currentFile.split( r':' )[1][-1] + r':' + self.currentFile.split( r':' )[2] 
            
            self.treeView.setCurrentIndex( self.fileSystemModel.index( self.currentFile ) )
            self.recursive_expand( index, self.treeView )
            #self.on_treeView_doubleClicked(  self.fileSystemModel.index( self.currentFile ) )
            self.on_treeView_doubleClicked(self.fileSystemModel.index( self.currentFile ) ,self.currentFile )
        
    def setupCsv(self):
        self.data()
        self.columns = self.df.columns.tolist()
        self.xColSelect.clear()
        self.xColSelect.addItems( self.columns )
        self.yColSelect.clear()
        self.yColSelect.addItems( self.columns )
        self.xTypeCombo.Text = str(self.df[ self.columns[0] ].dtype)
        self.updateTable()

    def setupH5(self):
        self.h5keys = self.hdfStore.keys()
        if len(self.h5keys) > 1:
            self.chosen_h5key = str( SelectDialog.SelectDialog.getOptions( self.h5keys ) )
        else:
            self.chosen_h5key = ""
        if self.chosen_h5key == "":
            self.orig_df = self.hdfStore[ self.h5keys[0] ]
        else:
            self.orig_df = self.hdfStore[ self.chosen_h5key ]
        self.setupCsv()

    def plotLine(self):
        if self.data() is None: return
        plt.clf()
        xCol = str( self.xColSelect.currentText() )
        yCol = str( self.yColSelect.currentText() )
        ax = plt.gca()
        ax.plot( self.df[ xCol ].tolist(), self.df[ yCol ].tolist(), label=xCol + ' v ' + yCol )
        if self.userxMin or self.userxMax or self.useryMin or self.useryMax:
            ax.set_xlim( self.xnMinSpin.value(), self.xnMaxSpin.value() )
            ax.set_ylim( self.ynMinSpin.value(), self.ynMaxSpin.value() )
        else:
            self.xnMinSpin.setValue( ax.get_xlim()[0] )
            self.xnMaxSpin.setValue( ax.get_xlim()[1] )
            self.ynMinSpin.setValue( ax.get_ylim()[0] )
            self.ynMaxSpin.setValue( ax.get_ylim()[1] )            
        ax.set_xlabel( xCol )
        ax.set_ylabel( yCol )
        self.canvas.draw()
        
    def plotHist(self):
        if self.data() is None: return
        plt.clf()
        col = str( self.xColSelect.currentText() )
        if self.userxBinning: bins = self.xnBinsSpin.value()
        else: bins = 10

        if not self.userxBinning: self.xnBinsSpin.setValue( bins )

        if self.userxMin:
            Min = self.xnMinSpin.value()
        else:
            Min = self.df[col].min()
            try: self.xnMinSpin.setValue( Min )
            except: self.xnMinSpin.setValue( 0. )
        if self.userxMax:
            Max = self.xnMaxSpin.value()
        else:
            Max = self.df[col].max()
            try: self.xnMaxSpin.setValue( Max )
            except: self.xnMaxSpin.setValue( 0. )
                    
        plt.hist( sorted(self.df[ col ].tolist()), bins=bins, range=(Min,Max) )
        plt.xlabel( col )
        self.canvas.draw()
        
    def plotScatter(self):
        if self.data() is None: return
        plt.clf()
        xCol = str( self.xColSelect.currentText() )
        yCol = str( self.yColSelect.currentText() )
        ax = plt.gca()
        ax.scatter( self.df[ xCol ].tolist(), self.df[ yCol ].tolist(), label=xCol + ' v ' + yCol )
        if self.userxMin or self.userxMax or self.useryMin or self.useryMax:
            ax.set_xlim( self.xnMinSpin.value(), self.xnMaxSpin.value() )
            ax.set_ylim( self.ynMinSpin.value(), self.ynMaxSpin.value() )
        else:
            self.xnMinSpin.setValue( ax.get_xlim()[0] )
            self.xnMaxSpin.setValue( ax.get_xlim()[1] )
            self.ynMinSpin.setValue( ax.get_ylim()[0] )
            self.ynMaxSpin.setValue( ax.get_ylim()[1] )            
        ax.set_xlabel( xCol )
        ax.set_ylabel( yCol )
        self.canvas.draw()

    def plotHist2d(self):
        if self.data() is None: return
        plt.clf()
        xCol = str( self.xColSelect.currentText() )
        yCol = str( self.yColSelect.currentText() )
        ax = plt.gca()
        if self.userxBinning: bins = self.xnBinsSpin.value()
        else: bins = 10
        ax.hist2d( self.df[xCol].tolist(), self.df[yCol].tolist(), bins=bins )
        if not self.userxBinning: self.xnBinsSpin.setValue( bins )
        if not self.userxMin:
            self.xnMinSpin.setValue( ax.get_xlim()[0] )
        else:
            ax.set_xlim([self.xnMinSpin.value(), ax.get_xlim()[1] ] )
        if not self.userxMax:
            self.xnMaxSpin.setValue( ax.get_xlim()[1] )
        else:
            ax.set_xlim([ax.get_xlim()[0], self.xnMaxSpin.value() ] )
        if not self.useryMin:
            self.ynMinSpin.setValue( ax.get_ylim()[0] )
        else:
            ax.set_ylim([self.ynMinSpin.value(), ax.get_ylim()[1] ] )
        if not self.useryMax:
            self.ynMaxSpin.setValue( ax.get_ylim()[1] )
        else:
            ax.set_ylim([ax.get_ylim()[0], self.ynMaxSpin.value() ] )
        plt.xlabel( xCol )
        plt.ylabel( yCol )
        self.canvas.draw()

        
    def data(self):
        if self.orig_df is None: return None
        self.filterStr = str(self.filterBox.text())
        if self.filterStr is not None and self.filterStr != "":
            if self.filterStr != self.lastFilterStr:
                try:
                    exec("self.df = self.orig_df[" +  self.filterStr.replace("df","self.orig_df") + "]" )
                    self.lastFilterStr = self.filterStr
                except Exception as e:
                    msg = QMessageBox()
                    msg.setIcon(QMessageBox.Warning)
                    msg.setText("Filtering failed")
                    msg.setWindowTitle("Error")
                    msg.setDetailedText( str(e) )
                    msg.setStandardButtons(QMessageBox.Ok)
                    msg.exec_()
                    pass
                pass
            pass
        else:
            self.df = self.orig_df
        return True
    
    def updateTable(self):
        if self.data() is None: return
        header = self.columns
        tm = MyTableModel.MyTableModel(self.df.values, header, self)
        self.tableView.setModel(tm)
        vh = self.tableView.verticalHeader()
        vh.setVisible(False)
        hh = self.tableView.horizontalHeader()
        hh.setStretchLastSection(True)
        self.tableView.setSortingEnabled(True)
        #self.tableView.sortByColumn(0);
        tm.sort( 0,  Qt.AscendingOrder )
        
    def plotZoom(self): self.toolbar.zoom()
    def plotPan(self): self.toolbar.pan()
    def plotHome(self): self.toolbar.home()
        
    def on_treeView_doubleClicked(self, index, fileName = '' ):
        if fileName == '':
            fileName = str(index.model().filePath(index))
            
        if self.fileName == fileName: return

        if self.hdfStore is not None:
            self.hdfStore.close()
            
        if fileName.endswith( ".csv" ):
            self.hdfStore = None
            self.fileName = fileName
            self.isCsv = True
            self.isH5 = False
            self.orig_df = pd.read_csv( fileName )
            self.setupCsv()
        elif fileName.endswith(".h5"):
            self.fileName = fileName
            self.isCsv = False
            self.isH5 = True
            self.hdfStore = pd.HDFStore( fileName, 'r' )
            self.setupH5()
        
    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(_translate("MainWindow", "PandaViz", None))
        import os.path as osp
        path = osp.join(osp.dirname(sys.modules[__name__].__file__), 'PandaViz.jpg')
        MainWindow.setWindowIcon(QIcon(path))
        self.btnZoom.setText(_translate("MainWindow", "Zoom", None))
        self.btnPlot.setText(_translate("MainWindow", "Draw", None))
        self.btnPan.setText(_translate("MainWindow", "Pan", None))
        self.btnHome.setText(_translate("MainWindow", "Reset", None))
        self.btnFilter.setText(_translate("MainWindow","Update Table", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Plot", None))
        self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Data", None))

    def recursive_expand(self, index, treeView):
        treeView.expand( index )
        parent = index.parent()
        if parent != index:
            self.recursive_expand( parent, treeView )


    def drawPlot(self):
        pType = self.plotTypeCombo.currentText()
        if pType == 'Scatter': self.plotScatter()
        elif pType == 'Hist': self.plotHist()
        elif pType == 'Hist2d': self.plotHist2d()
        elif pType == 'Line': self.plotLine()

    def ChangeXDataType(self):
        if self.data() is None: return
        col = str( self.xColSelect.currentText() )
        changeType = str( self.xTypeCombo.currentText() )
        try:
            if changeType == 'datetime':
                self.df[ col ] = pd.to_datetime( self.df[ col ])
            else:
                exec("self.df[ col ] = self.df[ col ].astype("+ changeType + ")")
        except Exception as e:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("Type Conversion Failed")
            msg.setWindowTitle("Error")
            msg.setDetailedText( str(e) )
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
            pass
        pass

    def ChangeYDataType(self):
        if self.data() is None: return
        col = str( self.yColSelect.currentText() )
        changeType = str( self.yTypeCombo.currentText() )
        try:
            if changeType == 'datetime':
                self.df[ col ] = pd.to_datetime( self.df[ col ])
            else:
                exec("self.df[ col ] = self.df[ col ].astype("+ changeType + ")")
        except Exception as e:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Warning)
            msg.setText("Type Conversion Failed")
            msg.setWindowTitle("Error")
            msg.setDetailedText( str(e) )
            msg.setStandardButtons(QMessageBox.Ok)
            msg.exec_()
            pass
        pass
    
    def ChangePlotType(self):
        self.userBinning = False
        pType = self.plotTypeCombo.currentText()
        if pType == 'Scatter' or pType == 'Line' or pType == 'Hist2d':
            [ x.show() for x in self.yAxisItems ]
            found = False
            for i in range( self.verticalLayout_2.count() ):
                if self.verticalLayout_2.itemAt(i) == self.horizontalLayout_yAxis: found=True
            if not found: self.verticalLayout_2.addLayout( self.horizontalLayout_yAxis )
            if pType == 'Scatter' or pType == 'Line':
                [ x.hide() for x in self.binningChoices ]
            else:
                [ x.show() for x in self.binningChoices ]
        else:
            [ x.show() for x in self.binningChoices ]
            [ x.hide() for x in self.yAxisItems ]
            for i in range( self.verticalLayout_2.count() ):
                if self.verticalLayout_2.itemAt(i) == self.horizontalLayout_yAxis:
                    self.verticalLayout_2.removeItem( self.horizontalLayout_yAxis )
        self.verticalLayout_2.update()


    def XChangeBinning(self): self.userxBinning = True
    def YChangeBinning(self): self.useryBinning = True
    def XChangeMax(self): self.userxMax = True
    def YChangeMax(self): self.useryMax = True
    def XChangeMin(self): self.userxMin = True
    def YChangeMin(self): self.useryMin = True

    def ResetUserSelections(self):
        self.userxMin = False
        self.useryMin = False
        self.userxMax = False
        self.useryMax = False
        self.userxBinning = False
        self.useryBinning = False
class SliceWidget(FigureCanvas):
    def __init__(self, parent=None, dpi=100):
        fig = Figure(dpi=dpi)
        self.axes = fig.add_subplot(111)

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        fig.tight_layout()

        self.toolbar = NavigationToolbar(self, self)
        self.toolbar.hide()

        self.mpl_connect('motion_notify_event', self.mouseMoved)

        FigureCanvas.setSizePolicy(self,
                                   QtWidgets.QSizePolicy.Expanding,
                                   QtWidgets.QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        self.locationLabel = None
        self.image = None
        self.sliceNumber = 0
        self.diaphragmAxial = None
        self.umbilicisInferior = None
        self.umbilicisSuperior = None
        self.umbilicisLeft = None
        self.umbilicisRight = None
        self.umbilicisCoronal = None
        self.CATLine = None

    def updateFigure(self):
        self.axes.cla()

        if self.image is not None:
            self.axes.imshow(self.image[:, :, self.sliceNumber], cmap="gray")

        if self.sliceNumber == self.diaphragmAxial:
            self.axes.add_patch(patches.Rectangle((0, 0), 20, 20, color='purple'))

        if self.umbilicisInferior is not None:
            if self.umbilicisInferior <= self.sliceNumber <= self.umbilicisSuperior:
                x = self.umbilicisLeft
                y = self.umbilicisCoronal
                width = 1
                height = self.umbilicisRight - x

                self.axes.add_patch(patches.Rectangle((y, x), width, height, color='orange'))

        if self.CATLine is not None and len(self.CATLine) > 1:
            startIndex = next((i for i, x in enumerate(self.CATLine) if min(x) != -1), None)

            CATLine = self.CATLine[startIndex:]
            if len(CATLine) > 1 and CATLine[0][0] <= self.sliceNumber <= CATLine[-1][0]:
                posterior = int(np.round(np.interp(self.sliceNumber, np.array([i[0] for i in CATLine]),
                                                   np.array([i[1] for i in CATLine]))))
                anterior = int(np.round(np.interp(self.sliceNumber, np.array([i[0] for i in CATLine]),
                                                  np.array([i[2] for i in CATLine]))))

                x = self.image.shape[0] // 3
                y = posterior
                width = 1
                height = 75
                self.axes.add_patch(patches.Rectangle((y, x), width, height, color='red'))

                y = anterior
                self.axes.add_patch(patches.Rectangle((y, x), width, height, color='red'))

        self.draw()

    def mouseMoved(self, event):
        if self.locationLabel is not None and event.inaxes:
            x, y, z = event.xdata, event.ydata, self.sliceNumber
        else:
            x, y, z = 0, 0, self.sliceNumber

        self.locationLabel.setText("(%i, %i, %i)" % (x, y, z))
예제 #36
0
class MinWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MinWindow, self).__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        # self.ui.setupUi(self)
        self.center()
        self.on_draw()
        self.load_event()

    def on_draw(self):
        self.draw_all_stack_tab()
        self.set_all_stack_tab_toolbar()
        pass

    def load_event(self):
        self.event_with_buttons()
        pass

    def draw_all_stack_tab(self):
        # 绘制所有图像
        # 添加到stack_tabWidget上

        # 创建matplot画布
        self.tab1 = PlotCanvas(self, width=9, height=6, dpi=100)
        self.tab2 = PlotCanvas(self, width=9, height=6, dpi=100)
        self.tab3 = PlotCanvas(self, width=9, height=6, dpi=100)
        # mpl.draw_one_line()

        # 加载数据
        # 在不同的画布上画出来
        # 将所有f分页加入到tabWidget上
        lines = load_all_lines()

        self.tab1.draw_one_line(lines[0])
        self.tab2.draw_one_line(lines[1])
        self.tab3.draw_one_line(lines[2])

        # 将所有的tab添加到stack_tabWidget上
        self.ui.stack_tabWidget.addTab(self.tab1, 'td=0.12')
        self.ui.stack_tabWidget.addTab(self.tab2, 'td=0.144')
        self.ui.stack_tabWidget.addTab(self.tab3, 'td=0.176')
        pass

    def set_all_stack_tab_toolbar(self):
        # 添加图像的工具栏 所有的工具栏用容器toolbar_stackedWidget保存
        self.tab1_ntb = NavigationToolbar(self.tab1, self.ui.page)  # 添加完整的 toolbar
        self.tab2_ntb = NavigationToolbar(self.tab2, self.ui.page)  # 添加完整的 toolbar
        self.tab3_ntb = NavigationToolbar(self.tab3, self.ui.page)  # 添加完整的 toolbar

        self.tab1.mpl_nav_toolbar = self.tab1_ntb
        self.tab2.mpl_nav_toolbar = self.tab2_ntb
        self.tab3.mpl_nav_toolbar = self.tab3_ntb
        # log('设置了的')
        # 隐藏当前的toolbar
        self.tab1_ntb.hide()
        self.tab2_ntb.hide()
        self.tab3_ntb.hide()

    def set_button_tip(self, button, tip=None):
        # 设置左下角显示button 的提示
        if tip is not None:
            button.setToolTip(tip)
            button.setStatusTip(tip)
        pass

    def event_with_buttons(self):
        # button绑定事件
        # self.ui.reset_Button.clocked()
        # 点击按钮 保存当前图像
        self.ui.save_pushButton.clicked.connect(self.toolbar_save_plot)

        self.ui.reset_Button.clicked.connect(self.toolbar_home)

        self.ui.forward_Button.clicked.connect(self.toolbar_forward)

        self.ui.back_Button.clicked.connect(self.toolbar_back)
        self.ui.zoom_pushButton.clicked.connect(self.toolbar_zoom)
        self.ui.pan_pushButton.clicked.connect(self.toolbar_pan)

        self.set_button_tip(self.ui.save_pushButton, '点击保存 快捷键Ctrl + S')
        self.set_button_tip(self.ui.reset_Button, '显示图像最初的样子')

        self.set_button_tip(self.ui.forward_Button, '返回上一步图像')
        self.set_button_tip(self.ui.back_Button, '返回下一步图像')
        self.set_button_tip(self.ui.zoom_pushButton, '选中放大图像')
        self.set_button_tip(self.ui.pan_pushButton, '选中图像 可拖动查看细节')



        # 给菜单按钮添加绑定事件
        # QtCore.QMetaObject.connectSlotsByName(self)
        save_file_action = self.create_action("&保存图像",
                                              shortcut="Ctrl+S", slot=self.toolbar_save_plot,
                                              tip="Save the plot")
        quit_action = self.create_action("&Quit", slot=self.close,
                                         shortcut="Ctrl+Q", tip="Close the application")

        self.add_actions(self.ui.file_menu,
                         (save_file_action, None, quit_action))
        pass

    def toolbar_set_curt(self):
        # self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar

        pass

    def create_action(self, text, slot=None, shortcut=None,
                      icon=None, tip=None, checkable=False,
                      signal="triggered()"):
        # 创建事件
        action = QAction(text, self)
        if icon is not None:
            # action.setIcon(QIcon(":/%s.png" % button_icon))
            pass
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            # bottons = QPushButton(text, self)
            # bottons.setti
            action.setStatusTip(tip)
        if slot is not None:
            action.triggered.connect(slot)
        if checkable:
            action.setCheckable(True)
        return action

    def add_actions(self, target, actions):
        # 添加事件
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)

    def center(self):
        # 设置主窗口在屏幕中间
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        # from utils import log
        # log('screen.width ({})  size.width({})'.format(screen.width(), size.width()))
        self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

    def toolbar_save_plot(self):
        # 保存当前图像
        log('点击了保存')
        # 给button设置tips

        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.save_figure()
        # log('点击了保存啊')
        pass

    def toolbar_zoom(self):
        # 放大当前图像
        log('点击了放大')
        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.zoom()

    def toolbar_back(self):
        # 显示前一步操作的图像
        log("点击了前进")
        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.back()

    def toolbar_forward(self):
        # 显示前一步操作的图像
        log("点击了上一步")
        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.forward()

    def toolbar_edit_parameters(self):
        # 编辑图像的参数

        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.edit_parameters()

    def toolbar_pan(self):
        #
        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.pan()

    def toolbar_edit_parameters(self):
        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.edit_parameters()

    def toolbar_home(self):
        log('点击了重置')
        self.ui.stack_tabWidget.currentWidget().mpl_nav_toolbar.home()
예제 #37
0
class PIVPlot(QtWidgets.QWidget):
    def __init__(self, parent=QtWidgets.QWidget, main_class=None):
        super(PIVPlot, self).__init__(parent)
        self.figure = Figure()
        self.figure.patch.set_facecolor((0.94117647, 0.94117647, 0.94117647))

        # the canvas is where the graph and the tool bar is
        self.piv_canvas = FigureCanvas(self.figure)

        self.piv_tool_bar = NavigationToolbar(self.piv_canvas, self)
        self.piv_tool_bar.hide()

        self.main_class = main_class
        # the piv_images_list is where the images are saved
        self.piv_images_list = []

        # the list where the results of the piv are saved
        self.piv_results_list = []
        self.ax = self.figure.add_subplot(111)

        # self.zoom_ax = self.figure.add_subplot(221)
        # self.zoom_ax.axis('off')
        self.xy_zoom = [[None, None], [None, None]]

        self.zoom_rectangle = None

        self.cid = None
        self.bit = '8 bit'
        self.current_image = 1

        self.canvas_layout = QtWidgets.QGridLayout(parent)
        self.canvas_layout.addWidget(self.piv_canvas)

    # function that shows the chosen image
    def show_plot(self, image_number, bit, change_number=False):
        self.ax.clear()
        self.bit = bit
        self.current_image = image_number
        """
        if self.bit == "8 bit":
            if self.piv_images_list[image_number][3]:
                self.ax.quiver(self.piv_images_list[image_number][3][0],
                               max(self.piv_images_list[image_number][3][1].flatten()) -
                               self.piv_images_list[image_number][3][1],
                               self.piv_images_list[image_number][3][2], self.piv_images_list[image_number][3][3],
                               color='b', pivot='middle')
                self.ax.quiver(self.piv_images_list[image_number][3][0][self.piv_images_list[image_number][3][4]],
                               max(self.piv_images_list[image_number][3][1][
                                       self.piv_images_list[image_number][3][4]].flatten()) -
                               self.piv_images_list[image_number][3][1][self.piv_images_list[image_number][3][4]],
                               self.piv_images_list[image_number][3][2][self.piv_images_list[image_number][3][4]],
                               self.piv_images_list[image_number][3][3][self.piv_images_list[image_number][3][4]],
                               color='r',
                               pivot='middle')

            self.ax.imshow(np.uint8(self.piv_images_list[image_number][2]), cmap=plt.cm.gray)
            self.ax.axis('off')
        
            self.zoom_ax.imshow(np.uint8(self.piv_images_list[image_number][2]), cmap=plt.cm.gray)
            self.zoom_ax.axis('off')
            if self.xy_zoom[0][0] != None:
            self.zoom_ax.set_xlim(self.xy_zoom[0][0], self.xy_zoom[0][1])
            self.zoom_ax.set_ylim(self.xy_zoom[1][0], self.xy_zoom[1][1])
            """
        if self.piv_images_list[image_number][3]:

            self.ax.quiver(self.piv_images_list[image_number][3][0],
                           self.piv_images_list[image_number][3][1],
                           self.piv_images_list[image_number][3][2],
                           self.piv_images_list[image_number][3][3],
                           color='b',
                           pivot='middle')
            try:
                self.ax.quiver(
                    self.piv_images_list[image_number][3][0][
                        self.piv_images_list[image_number][3][4]],
                    max(self.piv_images_list[image_number][3][1][
                        self.piv_images_list[image_number][3][4]].flatten()) -
                    self.piv_images_list[image_number][3][1][
                        self.piv_images_list[image_number][3][4]],
                    self.piv_images_list[image_number][3][2][
                        self.piv_images_list[image_number][3][4]],
                    self.piv_images_list[image_number][3][3][
                        self.piv_images_list[image_number][3][4]],
                    color='r',
                    pivot='middle')
            except ValueError:
                self.ax.quiver(self.piv_images_list[image_number][3][0][
                    self.piv_images_list[image_number][3][4]],
                               0 - self.piv_images_list[image_number][3][1][
                                   self.piv_images_list[image_number][3][4]],
                               self.piv_images_list[image_number][3][2][
                                   self.piv_images_list[image_number][3][4]],
                               self.piv_images_list[image_number][3][3][
                                   self.piv_images_list[image_number][3][4]],
                               color='r',
                               pivot='middle')

        if self.bit == "8 bit":
            self.ax.imshow(np.uint8(self.piv_images_list[image_number][2]),
                           cmap=plt.cm.gray,
                           origin="upper")
        else:
            self.ax.imshow(np.uint16(self.piv_images_list[image_number][2]),
                           cmap=plt.cm.gray,
                           origin="upper")
        self.ax.axis('off')
        """
        self.zoom_ax.imshow(np.uint16(self.piv_images_list[image_number][2]), cmap=plt.cm.gray)
        self.zoom_ax.axis('off')
        if self.xy_zoom[0][0] != None:
        self.zoom_ax.set_xlim(self.xy_zoom[0][0], self.xy_zoom[0][1])
        self.zoom_ax.set_ylim(self.xy_zoom[1][0], self.xy_zoom[1][1])
        """

        if self.xy_zoom[0][0] == 0 and self.xy_zoom[0][1] == len(
                self.piv_images_list[0][2]
            [0]) and self.xy_zoom[1][0] == 0 and self.xy_zoom[1][1] == len(
                self.piv_images_list[0][2]):
            self.zoom_rectangle = Rectangle(
                (self.xy_zoom[0][0], self.xy_zoom[1][0]),
                abs(self.xy_zoom[0][1] - self.xy_zoom[0][0]),
                abs(self.xy_zoom[1][1] - self.xy_zoom[1][0]),
                facecolor='none',
                alpha=0.1,
                edgecolor='none',
                linewidth=1,
                fill=False)

        elif not self.xy_zoom[0][0] == None:
            self.zoom_rectangle = Rectangle(
                (self.xy_zoom[0][0], self.xy_zoom[1][0]),
                abs(self.xy_zoom[0][1] - self.xy_zoom[0][0]),
                abs(self.xy_zoom[1][1] - self.xy_zoom[1][0]),
                facecolor='none',
                alpha=0.6,
                linestyle='-',
                edgecolor='white',
                linewidth=2,
                fill=True)
            self.ax.add_patch(self.zoom_rectangle)
        if change_number:
            self.main_class.current_image_number.setText(str(image_number + 1))
        self.piv_canvas.draw()

    # function to add an image
    def add_image(self, image_path, bit):
        self.bit = bit
        if self.bit == "8 bit":
            self.piv_images_list.append([
                image_path,
                QtCore.QFileInfo(image_path).fileName(),
                np.uint8(tools.imread(image_path)), None, None
            ])
        else:
            self.piv_images_list.append([
                image_path,
                QtCore.QFileInfo(image_path).fileName(),
                np.uint16(tools.imread(image_path)), None, None
            ])

    @staticmethod
    def invert(img_read, is_bmp, bit):
        if is_bmp:
            # for i in range(len(img_read)):
            # for j in range(len(img_read[i])):
            img_read = 255 - img_read
        else:
            # for i in range(len(img_read)):
            #    for j in range(len(img_read[i])):
            img_read = 1.0 - img_read  # it's not 0.255
        if bit == "8 bit":
            return np.uint8(img_read)
        else:
            return np.uint16(img_read)

    def ROI_buttons(self, is_select):
        if is_select:
            self.rs = RectangleSelector(self.ax,
                                        self.zoom,
                                        drawtype='box',
                                        useblit=False,
                                        button=[1],
                                        spancoords='pixels',
                                        interactive=False,
                                        rectprops=dict(alpha=0.6,
                                                       linestyle='-',
                                                       edgecolor='white',
                                                       linewidth=2))
        else:
            self.xy_zoom[0][0] = 0  # top left / x1
            self.xy_zoom[0][1] = len(
                self.piv_images_list[0][2][0])  # top right / x2
            self.xy_zoom[1][0] = 0  # bottom left/ y1
            self.xy_zoom[1][1] = len(
                self.piv_images_list[0][2])  # bottom right/ y2
            self.reset_piv()
        self.show_plot(self.current_image, self.bit)

    def zoom(self, click_point, release_point):
        x1, y1 = click_point.xdata, click_point.ydata
        x2, y2 = release_point.xdata, release_point.ydata
        self.xy_zoom[0][0] = min([x1, x2])
        self.xy_zoom[0][1] = max([x1, x2])
        self.xy_zoom[1][0] = min([y1, y2])
        self.xy_zoom[1][1] = max([y1, y2])
        self.rs = None
        self.show_plot(self.current_image, self.bit)

    def reset_piv(self):
        for i in range(len(self.piv_images_list)):
            self.piv_images_list[i][3] = None