def update_label_with_slider(label: QLabel, slider: QSlider):
    if label.display_as_percentage:
        min_value = slider.minimum()
        percentage = (slider.value() - min_value) / (slider.maximum() - min_value)
        label.setText(f"{percentage * 100: 3.0f}%")
    else:
        label.setText(str(slider.value()))
示例#2
0
class ApplicationWindow(QMainWindow):
    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.column_names = ["Column A", "Column B", "Column C"]

        # Central widget
        self._main = QWidget()
        self.setCentralWidget(self._main)

        # Main menu bar
        self.menu = self.menuBar()
        self.menu_file = self.menu.addMenu("File")
        exit = QAction("Exit", self, triggered=qApp.quit)
        self.menu_file.addAction(exit)

        self.menu_about = self.menu.addMenu("&About")
        about = QAction("About Qt", self, shortcut=QKeySequence(QKeySequence.HelpContents),
                        triggered=qApp.aboutQt)
        self.menu_about.addAction(about)

        # Figure (Left)
        self.fig = Figure(figsize=(5, 3))
        self.canvas = FigureCanvas(self.fig)

        # Sliders (Left)
        self.slider_azim = QSlider(minimum=0, maximum=360, orientation=Qt.Horizontal)
        self.slider_elev = QSlider(minimum=0, maximum=360, orientation=Qt.Horizontal)

        self.slider_azim_layout = QHBoxLayout()
        self.slider_azim_layout.addWidget(QLabel("{}".format(self.slider_azim.minimum())))
        self.slider_azim_layout.addWidget(self.slider_azim)
        self.slider_azim_layout.addWidget(QLabel("{}".format(self.slider_azim.maximum())))

        self.slider_elev_layout = QHBoxLayout()
        self.slider_elev_layout.addWidget(QLabel("{}".format(self.slider_elev.minimum())))
        self.slider_elev_layout.addWidget(self.slider_elev)
        self.slider_elev_layout.addWidget(QLabel("{}".format(self.slider_elev.maximum())))

        # Table (Right)
        self.table = QTableWidget()
        header = self.table.horizontalHeader()
        header.setSectionResizeMode(QHeaderView.Stretch)

        # ComboBox (Right)
        self.combo = QComboBox()
        self.combo.addItems(["Wired", "Surface", "Triangular Surface", "Sphere"])

        # Right layout
        rlayout = QVBoxLayout()
        rlayout.setContentsMargins(1, 1, 1, 1)
        rlayout.addWidget(QLabel("Plot type:"))
        rlayout.addWidget(self.combo)
        rlayout.addWidget(self.table)

        # Left layout
        llayout = QVBoxLayout()
        rlayout.setContentsMargins(1, 1, 1, 1)
        llayout.addWidget(self.canvas, 88)
        llayout.addWidget(QLabel("Azimuth:"), 1)
        llayout.addLayout(self.slider_azim_layout, 5)
        llayout.addWidget(QLabel("Elevation:"), 1)
        llayout.addLayout(self.slider_elev_layout, 5)

        # Main layout
        layout = QHBoxLayout(self._main)
        layout.addLayout(llayout, 70)
        layout.addLayout(rlayout, 30)

        # Signal and Slots connections
        self.combo.currentTextChanged.connect(self.combo_option)
        self.slider_azim.valueChanged.connect(self.rotate_azim)
        self.slider_elev.valueChanged.connect(self.rotate_elev)

        # Initial setup
        self.plot_wire()
        self._ax.view_init(30, 30)
        self.slider_azim.setValue(30)
        self.slider_elev.setValue(30)
        self.fig.canvas.mpl_connect("button_release_event", self.on_click)

    # Matplotlib slot method
    def on_click(self, event):
        azim, elev = self._ax.azim, self._ax.elev
        self.slider_azim.setValue(azim + 180)
        self.slider_elev.setValue(elev + 180)

    # Utils methods

    def set_table_data(self, X, Y, Z):
        for i in range(len(X)):
            self.table.setItem(i, 0, QTableWidgetItem("{:.2f}".format(X[i])))
            self.table.setItem(i, 1, QTableWidgetItem("{:.2f}".format(Y[i])))
            self.table.setItem(i, 2, QTableWidgetItem("{:.2f}".format(Z[i])))

    def set_canvas_table_configuration(self, row_count, data):
        self.fig.set_canvas(self.canvas)
        self._ax = self.canvas.figure.add_subplot(projection="3d")

        self._ax.set_xlabel(self.column_names[0])
        self._ax.set_ylabel(self.column_names[1])
        self._ax.set_zlabel(self.column_names[2])

        self.table.setRowCount(row_count)
        self.table.setColumnCount(3)
        self.table.setHorizontalHeaderLabels(self.column_names)
        self.set_table_data(data[0], data[1], data[2])

    # Plot methods

    def plot_wire(self):
        # Data
        self.X, self.Y, self.Z = axes3d.get_test_data(0.03)

        self.set_canvas_table_configuration(len(self.X[0]), (self.X[0], self.Y[0], self.Z[0]))
        self._ax.plot_wireframe(self.X, self.Y, self.Z, rstride=10, cstride=10, cmap="viridis")
        self.canvas.draw()

    def plot_surface(self):
        # Data
        self.X, self.Y = np.meshgrid(np.linspace(-6, 6, 30), np.linspace(-6, 6, 30))
        self.Z = np.sin(np.sqrt(self.X ** 2 + self.Y ** 2))

        self.set_canvas_table_configuration(len(self.X[0]), (self.X[0], self.Y[0], self.Z[0]))
        self._ax.plot_surface(self.X, self.Y, self.Z,
                              rstride=1, cstride=1, cmap="viridis", edgecolor="none")
        self.canvas.draw()

    def plot_triangular_surface(self):
        # Data
        radii = np.linspace(0.125, 1.0, 8)
        angles = np.linspace(0, 2 * np.pi, 36, endpoint=False)[..., np.newaxis]
        self.X = np.append(0, (radii * np.cos(angles)).flatten())
        self.Y = np.append(0, (radii * np.sin(angles)).flatten())
        self.Z = np.sin(-self.X * self.Y)

        self.set_canvas_table_configuration(len(self.X), (self.X, self.Y, self.Z))
        self._ax.plot_trisurf(self.X, self.Y, self.Z, linewidth=0.2, antialiased=True)
        self.canvas.draw()

    def plot_sphere(self):
        # Data
        u = np.linspace(0, 2 * np.pi, 100)
        v = np.linspace(0, np.pi, 100)
        self.X = 10 * np.outer(np.cos(u), np.sin(v))
        self.Y = 10 * np.outer(np.sin(u), np.sin(v))
        self.Z = 9 * np.outer(np.ones(np.size(u)), np.cos(v))

        self.set_canvas_table_configuration(len(self.X), (self.X[0], self.Y[0], self.Z[0]))
        self._ax.plot_surface(self.X, self.Y, self.Z)
        self.canvas.draw()

    # Slots

    @Slot()
    def combo_option(self, text):
        if text == "Wired":
            self.plot_wire()
        elif text == "Surface":
            self.plot_surface()
        elif text == "Triangular Surface":
            self.plot_triangular_surface()
        elif text == "Sphere":
            self.plot_sphere()

    @Slot()
    def rotate_azim(self, value):
        self._ax.view_init(self._ax.elev, value)
        self.fig.set_canvas(self.canvas)
        self.canvas.draw()

    @Slot()
    def rotate_elev(self, value):
        self._ax.view_init(value, self._ax.azim)
        self.fig.set_canvas(self.canvas)
        self.canvas.draw()
示例#3
0
class _InputHeader(QGroupBox):
    def __init__(self, parent, header):
        super().__init__(parent)
        self.header = header
        self.header_index, _ = self.parent().table.model_c.metadata_c.get_header_meta(self.header["name"])

        self.setStyleSheet(styles.filter_line_edit)

        # LAYOUTS
        self.grid = QGridLayout()
        self.v_layout = QVBoxLayout()
        self.h_layout = QHBoxLayout()

        # FIELDS
        self.header_label = QLabel(f'{self.header["name"]} : ', self)
        self.header_label.setFixedWidth(100)

        self.input = QLineEdit(self)
        self.input.setMaxLength(self.header["data_type"]["max_value"])
        self.input.setPlaceholderText(str(self.parent().table.model_c.get_common_values(header["name"])))

        self.exact = QCheckBox("Exact", self)
        self.exact.setToolTip(f"Value in '{self.header['name']}' must be exacly '{self.input.text()}'")
        self.exact.stateChanged.connect(self.exact_checked)

        # SLIDER SET UP
        self.slider = None

        if self.header["data_type"]["type"] == "int":
            self.slider = QSlider(Qt.Horizontal, self)
            (self.slider.min_v, self.slider.max_v) = self.parent().table.get_min_max(self.header["name"])
            self.slider.setMinimum(self.slider.min_v)
            self.slider.setMaximum(self.slider.max_v)
            self.slider.valueChanged.connect(self.slider_value_changed)
            self.slider.hint = QLabel(f'{self.slider.minimum()} - {self.slider.value()}', self)

        # SET UP
        self.h_layout.addWidget(self.input)
        self.h_layout.addWidget(self.exact)

        self.v_layout.addLayout(self.h_layout)
        if self.slider is not None:
            self.v_layout.addWidget(self.slider.hint)
            self.v_layout.addWidget(self.slider)

        self.grid.addWidget(self.header_label, 0, 0)
        self.grid.addLayout(self.v_layout, 0, 1)

        self.setLayout(self.grid)

    def get_condition(self):
        if self.input.text() == "" and self.slider is None:
            return None

        if self.slider is not None:
            if self.input.text() == "" and \
                    (self.slider.value() == self.slider.maximum() or
                     self.slider.value() == self.slider.minimum()):
                return None

        return {
            "header_name": self.header["name"],
            "value": self.input.text(),
            "exact": self.exact.isChecked(),
            "header_meta": {
                "index": self.header_index,
                "meta": self.header
            },
            "value_additional_info": {
                "contains": not self.exact.isChecked(),
                "min_value": self.slider.min_v if self.slider is not None else "",
                "max_value": self.slider.value() if self.slider is not None else ""
            }
        }

    def exact_checked(self):
        if self.slider is None:
            return
        self.slider.hide() if self.exact.isChecked() else self.slider.show()

    def slider_value_changed(self):
        self.slider.hint.setText(f'{self.slider.minimum()} - {self.slider.value()}')
示例#4
0
class _RemoveNanEditor(AbsOperationEditor):
    _baseText = {
        0: 'Remove with more than: <b>{}</b> nan',
        1: 'Remove with more than: <b>{}%</b> nan'
    }

    def __init__(self, mode: str, parent: QWidget = None):
        """ Builds the editor

        :param mode: one of 'col' or 'row'
        :param parent: a parent widget

        """
        self.__mode: str = mode
        super().__init__(parent)

    def editorBody(self) -> QWidget:
        self.__group = QButtonGroup()
        self.__group.setExclusive(True)
        lab = QLabel('Choose how to remove:')
        self.__group.addButton(QRadioButton('By number'), id=0)
        self.__group.addButton(QRadioButton('By percentage'), id=1)
        self.__currId = None

        self.__summaryLabel = QLabel()
        self.__slider = QSlider(Qt.Horizontal, self)
        self.__slider.setMinimum(0)
        self.__slider.setTracking(True)
        self.__slider.setSingleStep(1)

        self.__numBox = QSpinBox()
        self.__numBox.setMinimum(0)
        self.__numBox.setMaximum(10000000)

        radioLayout = QHBoxLayout()
        radioLayout.addWidget(self.__group.button(0))
        radioLayout.addWidget(self.__group.button(1))
        self.__bodyLayout = QVBoxLayout()
        self.__bodyLayout.addWidget(lab)
        self.__bodyLayout.addLayout(radioLayout)
        self.__bodyLayout.addSpacing(20)
        self.__bodyLayout.addWidget(QLabel('Move the slider to set removal parameter:'))
        self.__bodyLayout.addSpacing(10)
        self.__bodyLayout.addWidget(self.__slider if self.__mode == 'row' else self.__numBox)
        self.__bodyLayout.addWidget(self.__summaryLabel)

        self.__group.buttonClicked[int].connect(self._toggleMode)
        # Both are connected, only one is shown
        self.__slider.valueChanged.connect(self._onValueChanged)
        self.__numBox.valueChanged[int].connect(self._onValueChanged)
        # Set a default button and label text
        self.__group.button(0).click()
        self.__summaryLabel.setText(self._baseText[0].format(self.__slider.minimum()))

        body = QWidget()
        body.setLayout(self.__bodyLayout)
        return body

    @Slot(int)
    def _toggleMode(self, bid: int) -> None:
        # NOTE: could be refactored
        if bid == self.__currId:
            return
        self.__currId = bid
        if bid == 0:
            if not (self.inputShapes and self.inputShapes[0]) and self.__mode == 'row':
                self.__slider.setDisabled(True)
                self._onValueChanged(self.__slider.value())
            elif not self.__slider.isEnabled():
                self.__slider.setEnabled(True)
            else:
                if self.__mode == 'row':
                    self.__slider.setMaximum(self.inputShapes[0].nColumns)
                    self._onValueChanged(self.__slider.value())
                else:
                    self.__bodyLayout.replaceWidget(self.__slider, self.__numBox)
                    self.__slider.hide()
                    self.__numBox.show()
                    self._onValueChanged(self.__numBox.value())
        else:
            if self.__mode == 'row':
                if not self.__slider.isEnabled():
                    self.__slider.setEnabled(True)
            else:
                self.__bodyLayout.replaceWidget(self.__numBox, self.__slider)
                self.__numBox.hide()
                self.__slider.show()
            self._onValueChanged(self.__slider.value())
            self.__slider.setMaximum(100)

    @Slot(int)
    def _onValueChanged(self, value: int):
        self.__summaryLabel.setText(self._baseText[self.__currId].format(value))

    def getOptions(self) -> Iterable:
        if self.__group.checkedId() == 0:
            # By number
            return None, self.__slider.value() if self.__mode == 'row' else self.__numBox.value()
        else:
            # By perc
            return self.__slider.value() / 100, None

    def setOptions(self, percentage: float, number: int) -> None:
        if percentage is not None:
            self.__group.button(1).click()
            self.__slider.setValue(percentage * 100)
        elif number is not None:
            self.__group.button(0).click()
            self.__slider.setValue(number) if self.__mode == 'row' else self.__numBox.setValue(number)
        else:
            # Both None
            self.__slider.setValue(0)
            self.__numBox.setValue(0)

    def refresh(self) -> None:
        if self.__mode == 'row' and self.__group.checkedId() == 0:
            self.__slider.setMaximum(self.inputShapes[0].nColumns)
            self.__slider.setEnabled(True)