Beispiel #1
0
class CircleFitResults(QGroupBox):
    """
    The tree displaying the Circle Fit results and the parameters used for
    automatically fitting the circle.

    Attributes
    ----------
    sig_selected_peak_changed : pyqtSignal(int)
        The signal emitted when the selected peak is changed.
    sig_recalculate_fit : pyqtSignal
        Signal emitted when the fit is forced to be recalculated.
    sig_add_new_peak : pyqtSignal
        Signal emitted when a new peak is added.
    sig_manual_parameter_change : pyqtSignal
        Signal emitted when a parameter is changed by hand.
    """

    sig_selected_peak_changed = pyqtSignal(int)
    sig_recalculate_fit = pyqtSignal()
    sig_add_new_peak = pyqtSignal()
    sig_manual_parameter_change = pyqtSignal()

    def __init__(self, parent=None):
        super().__init__("Results", parent)

        self.channels = []
        self.num_peaks = 0

        self.init_ui()

    def init_ui(self):
        # # Tree for values
        self.tree = QTreeWidget()
        self.tree.setHeaderLabels([
            "Name", "Frequency (Hz)", "Damping ratio", "Amplitude",
            "Phase (deg)", "Select"
        ])

        self.tree.setStyleSheet("QTreeWidget::item:has-children "
                                "{ background-color : palette(mid);}")

        # # Tree for autofit parameters
        self.autofit_tree = QTreeWidget()
        self.autofit_tree.setHeaderLabels([
            "Name", "Frequency (Hz)", "Damping ratio", "Amplitude",
            "Phase (deg)", "Select"
        ])

        self.autofit_tree.hide()
        self.autofit_tree.setStyleSheet("QTreeWidget::item:has-children "
                                        "{ background-color : palette(mid);}")

        # Connect the two trees together, so the views look identical
        self.autofit_tree.itemCollapsed.connect(self.on_item_collapsed)
        self.autofit_tree.itemExpanded.connect(self.on_item_expanded)
        self.tree.itemCollapsed.connect(self.on_item_collapsed)
        self.tree.itemExpanded.connect(self.on_item_expanded)

        # # Controls
        self.add_peak_btn = QPushButton("Add new peak", self)
        self.add_peak_btn.clicked.connect(self.add_peak)

        self.delete_selected_btn = QPushButton("Delete selected", self)
        self.delete_selected_btn.clicked.connect(self.delete_selected)

        self.view_autofit_btn = QPushButton("View autofit parameters", self)
        self.view_autofit_btn.clicked.connect(self.toggle_view)

        self.reset_to_autofit_btn = QPushButton("Reset all to auto", self)
        self.reset_to_autofit_btn.clicked.connect(self.reset_to_autofit)
        self.reset_to_autofit_btn.hide()

        controls1 = QGridLayout()
        controls1.addWidget(self.add_peak_btn, 0, 0)
        controls1.setColumnStretch(1, 1)
        controls1.addWidget(self.delete_selected_btn, 0, 2)

        controls2 = QGridLayout()
        controls2.setColumnStretch(0, 1)
        controls2.addWidget(self.reset_to_autofit_btn, 0, 1)
        controls2.addWidget(self.view_autofit_btn, 0, 2)

        # # Layout
        layout = QGridLayout()
        layout.addLayout(controls2, 0, 0)
        layout.addWidget(self.tree, 1, 0)
        layout.addWidget(self.autofit_tree, 1, 0)
        layout.addLayout(controls1, 2, 0)

        self.setLayout(layout)

    def add_peak(self):
        """Add a top-level item for a new peak to the tree, with children for
        each channel."""
        # Create the parent item for the peak
        peak_item = QTreeWidgetItem(
            self.tree, ["Peak {}".format(self.num_peaks), "", "", "", "", ""])
        autofit_peak_item = QTreeWidgetItem(
            self.autofit_tree,
            ["Peak {}".format(self.num_peaks), "", "", "", "", ""])

        # Put a radio button in column 5 in the tree
        radio_btn = QRadioButton()
        radio_btn.toggled.connect(self.on_selected_peak_changed)
        self.tree.setItemWidget(peak_item, 5, radio_btn)
        radio_btn.setChecked(True)

        for col in [1, 2, 3, 4]:
            # Put comboboxes in the autofit tree
            combobox = QComboBox()
            combobox.addItems(["Auto", "Manual"])
            combobox.currentIndexChanged.connect(self.update_peak_average)
            self.autofit_tree.setItemWidget(autofit_peak_item, col, combobox)

        # Put spinboxes in the tree
        freq_spinbox = QDoubleSpinBox()
        freq_spinbox.setRange(0, 9e99)
        freq_spinbox.valueChanged.connect(
            self.sig_manual_parameter_change.emit)
        self.tree.setItemWidget(peak_item, 1, freq_spinbox)
        damping_spinbox = QDoubleSpinBox()
        damping_spinbox.setRange(0, 9e99)
        damping_spinbox.setDecimals(5)
        damping_spinbox.setSingleStep(0.00001)
        damping_spinbox.valueChanged.connect(
            self.sig_manual_parameter_change.emit)
        self.tree.setItemWidget(peak_item, 2, damping_spinbox)
        amp_spinbox = QDoubleSpinBox()
        amp_spinbox.setRange(0, 9e99)
        amp_spinbox.valueChanged.connect(self.sig_manual_parameter_change.emit)
        self.tree.setItemWidget(peak_item, 3, amp_spinbox)
        phase_spinbox = QDoubleSpinBox()
        phase_spinbox.setRange(-180, 180)
        phase_spinbox.valueChanged.connect(
            self.sig_manual_parameter_change.emit)
        phase_spinbox.setWrapping(True)
        self.tree.setItemWidget(peak_item, 4, phase_spinbox)

        # Create the child items for each channel for this peak if there's
        # more than one channel
        if len(self.channels) > 1:
            for channel in self.channels:
                channel_item = QTreeWidgetItem(
                    peak_item, [channel.name, "", "", "", "", ""])
                autofit_channel_item = QTreeWidgetItem(
                    autofit_peak_item, [channel.name, "", "", "", "", ""])
                for col in [1, 2, 3, 4]:
                    # Put comboboxes in the autofit tree
                    combobox = QComboBox()
                    combobox.addItems(["Auto", "Manual"])
                    combobox.currentIndexChanged.connect(
                        self.update_peak_average)
                    self.autofit_tree.setItemWidget(autofit_channel_item, col,
                                                    combobox)

                freq_spinbox = QDoubleSpinBox()
                freq_spinbox.setRange(0, 9e99)
                freq_spinbox.valueChanged.connect(
                    self.sig_manual_parameter_change.emit)
                freq_spinbox.valueChanged.connect(self.update_peak_average)
                self.tree.setItemWidget(channel_item, 1, freq_spinbox)
                damping_spinbox = QDoubleSpinBox()
                damping_spinbox.setRange(0, 9e99)
                damping_spinbox.setDecimals(5)
                damping_spinbox.setSingleStep(0.00001)
                damping_spinbox.valueChanged.connect(
                    self.sig_manual_parameter_change.emit)
                damping_spinbox.valueChanged.connect(self.update_peak_average)
                self.tree.setItemWidget(channel_item, 2, damping_spinbox)
                amp_spinbox = QDoubleSpinBox()
                amp_spinbox.setRange(0, 9e99)
                amp_spinbox.valueChanged.connect(
                    self.sig_manual_parameter_change.emit)
                amp_spinbox.valueChanged.connect(self.update_peak_average)
                self.tree.setItemWidget(channel_item, 3, amp_spinbox)
                phase_spinbox = QDoubleSpinBox()
                phase_spinbox.setRange(-180, 180)
                phase_spinbox.setWrapping(True)
                phase_spinbox.valueChanged.connect(
                    self.sig_manual_parameter_change.emit)
                phase_spinbox.valueChanged.connect(self.update_peak_average)
                self.tree.setItemWidget(channel_item, 4, phase_spinbox)

        # Register that we've added another peak
        self.num_peaks += 1
        self.sig_add_new_peak.emit()

    def delete_selected(self):
        """Delete the item that is currently selected."""
        for i in range(self.tree.topLevelItemCount()):
            # If the radio button is checked
            peak_item = self.tree.topLevelItem(i)
            if peak_item is not None:
                if self.tree.itemWidget(peak_item, 5).isChecked():
                    # Delete this item
                    self.tree.takeTopLevelItem(i)
                    self.autofit_tree.takeTopLevelItem(i)
                    # self.num_peaks -= 1

    def toggle_view(self):
        if self.tree.isVisible():
            self.tree.hide()
            self.autofit_tree.show()
            self.reset_to_autofit_btn.show()
            self.view_autofit_btn.setText("View parameter values")
        else:
            self.tree.show()
            self.autofit_tree.hide()
            self.reset_to_autofit_btn.hide()
            self.view_autofit_btn.setText("View autofit parameters")

    def on_item_collapsed(self, item):
        index = self.sender().indexOfTopLevelItem(item)
        self.tree.collapseItem(self.tree.topLevelItem(index))
        self.autofit_tree.collapseItem(self.autofit_tree.topLevelItem(index))

    def on_item_expanded(self, item):
        index = self.sender().indexOfTopLevelItem(item)
        self.tree.expandItem(self.tree.topLevelItem(index))
        self.autofit_tree.expandItem(self.autofit_tree.topLevelItem(index))

    def on_selected_peak_changed(self, checked):
        for i in range(self.tree.topLevelItemCount()):
            # If the radio button in this row is the sender
            peak_item = self.tree.topLevelItem(i)
            if peak_item is not None:
                if self.tree.itemWidget(peak_item, 5) == self.sender():
                    if checked:
                        print("Selected peak: " + str(i))
                        self.sig_selected_peak_changed.emit(i)

    def reset_to_autofit(self):
        """Reset all parameters to be automatically adjusted."""
        for peak_number in range(self.num_peaks):
            peak_item = self.autofit_tree.topLevelItem(peak_number)

            for col in [1, 2, 3, 4]:
                self.autofit_tree.itemWidget(peak_item, col).setCurrentIndex(0)

            if len(self.channels) > 1:
                for channel_number in range(len(self.channels)):
                    channel_item = peak_item.child(channel_number)
                    for col in [1, 2, 3, 4]:
                        self.autofit_tree.itemWidget(channel_item,
                                                     col).setCurrentIndex(0)

        self.sig_recalculate_fit.emit()

    def update_peak_average(self):
        """Set the parameter values displayed for the peak to the average of
        all the channel values for each parameter."""
        for peak_number in range(self.num_peaks):
            # Get the peak item
            peak_item = self.tree.topLevelItem(peak_number)
            autofit_item = self.autofit_tree.topLevelItem(peak_number)

            if peak_item is not None:
                # Find the average values of all the channels
                avg_freq = 0
                avg_damping = 0
                avg_amplitude = 0
                avg_phase_deg = 0

                for channel_number in range(len(self.channels)):
                    avg_freq += self.get_frequency(peak_number, channel_number)
                    avg_damping += self.get_damping(peak_number,
                                                    channel_number)
                    avg_amplitude += self.get_amplitude(
                        peak_number, channel_number)
                    avg_phase_deg += self.get_phase_deg(
                        peak_number, channel_number)

                avg_freq /= len(self.channels)
                avg_damping /= len(self.channels)
                avg_amplitude /= len(self.channels)
                avg_phase_deg /= len(self.channels)

                # Set the peak item to display the averages
                if self.autofit_tree.itemWidget(autofit_item,
                                                1).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 1).setValue(avg_freq)
                if self.autofit_tree.itemWidget(autofit_item,
                                                2).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 2).setValue(avg_damping)
                if self.autofit_tree.itemWidget(autofit_item,
                                                3).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 3).setValue(avg_amplitude)
                if self.autofit_tree.itemWidget(autofit_item,
                                                4).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 4).setValue(avg_phase_deg)

    def get_frequency(self, peak_number, channel_number=None):
        """Return the resonant frequency (Hz) of the peak given by
        *peak_number*. If *channel_number* is given, return the resonant
        frequency of the given peak in the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            spinbox = self.tree.itemWidget(channel_item, 1)
            return spinbox.value()
        else:
            return 0

    def get_omega(self, peak_number, channel_number=None):
        """Return the resonant frequency (rads) of the peak given by
        *peak_number*. If *channel_number* is given, return the resonant
        frequency of the given peak in the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            spinbox = self.tree.itemWidget(channel_item, 1)
            return spinbox.value() * 2 * np.pi
        else:
            return 0

    def get_damping(self, peak_number, channel_number=None):
        """Return the damping ratio of the peak given by *peak_number*. If
        *channel_number* is given, return the damping ratio of the given peak
        in the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            spinbox = self.tree.itemWidget(channel_item, 2)
            return spinbox.value()
        else:
            return 0

    def get_amplitude(self, peak_number, channel_number=None):
        """Return the amplitude of the peak given by *peak_number*. If
        *channel_number* is given, return the amplitude of the given peak in
        the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            spinbox = self.tree.itemWidget(channel_item, 3)
            return spinbox.value()
        else:
            return 0

    def get_phase_deg(self, peak_number, channel_number=None):
        """Return the phase (deg) of the peak given by *peak_number*. If
        *channel_number* is given, return the phase of the given peak in the
        given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            spinbox = self.tree.itemWidget(channel_item, 4)
            return spinbox.value()
        else:
            return 0

    def get_phase_rad(self, peak_number, channel_number=None):
        """Return the phase (rad) of the peak given by *peak_number*. If
        *channel_number* is given, return the phase of the given peak in the
        given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            spinbox = self.tree.itemWidget(channel_item, 4)
            return np.deg2rad(spinbox.value())
        else:
            return 0

    def set_frequency(self, peak_number, channel_number=None, value=0):
        """Set the frequency (Hz) of a given peak to *value*. If *channel_number* is
        given, set the frequency of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            if autofit_peak_item.childCount():
                autofit_channel_item = autofit_peak_item.child(channel_number)
            else:
                autofit_channel_item = autofit_peak_item
            # Set the value only if the combobox is set to autofit
            combobox = \
                self.autofit_tree.itemWidget(autofit_channel_item, 1)
            if combobox.currentText() == "Auto":
                spinbox = self.tree.itemWidget(channel_item, 1)
                spinbox.setValue(value)

    def set_omega(self, peak_number, channel_number=None, value=0):
        """Set the frequency (rad) of a given peak to *value*. If *channel_number* is
        given, set the frequency of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            if autofit_peak_item.childCount():
                autofit_channel_item = autofit_peak_item.child(channel_number)
            else:
                autofit_channel_item = autofit_peak_item
            # Set the value only if the combobox is set to autofit
            combobox = \
                self.autofit_tree.itemWidget(autofit_channel_item, 1)
            if combobox.currentText() == "Auto":
                spinbox = self.tree.itemWidget(channel_item, 1)
                spinbox.setValue(value / (2 * np.pi))

    def set_damping(self, peak_number, channel_number=None, value=0):
        """Set the damping ratio of a given peak to *value*. If *channel_number* is
        given, set the damping ratio of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            if autofit_peak_item.childCount():
                autofit_channel_item = autofit_peak_item.child(channel_number)
            else:
                autofit_channel_item = autofit_peak_item
            # Set the value only if the combobox is set to autofit
            combobox = \
                self.autofit_tree.itemWidget(autofit_channel_item, 2)
            if combobox.currentText() == "Auto":
                spinbox = self.tree.itemWidget(channel_item, 2)
                spinbox.setValue(value)

    def set_amplitude(self, peak_number, channel_number=None, value=0):
        """Set the amplitude of a given peak to *value*. If *channel_number* is
        given, set the amplitude of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            if autofit_peak_item.childCount():
                autofit_channel_item = autofit_peak_item.child(channel_number)
            else:
                autofit_channel_item = autofit_peak_item
            # Set the value only if the combobox is set to autofit
            combobox = \
                self.autofit_tree.itemWidget(autofit_channel_item, 3)
            if combobox.currentText() == "Auto":
                spinbox = self.tree.itemWidget(channel_item, 3)
                spinbox.setValue(value)

    def set_phase_deg(self, peak_number, channel_number=None, value=0):
        """Set the phase of a given peak to *value*. If *channel_number* is
        given, set the phase of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            if autofit_peak_item.childCount():
                autofit_channel_item = autofit_peak_item.child(channel_number)
            else:
                autofit_channel_item = autofit_peak_item
            # Set the value only if the combobox is set to autofit
            combobox = \
                self.autofit_tree.itemWidget(autofit_channel_item, 4)
            if combobox.currentText() == "Auto":
                spinbox = self.tree.itemWidget(channel_item, 4)
                spinbox.setValue(value)

    def set_phase_rad(self, peak_number, channel_number=None, value=0):
        """Set the phase of a given peak to *value*. If *channel_number* is
        given, set the phase of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            if peak_item.childCount():
                channel_item = peak_item.child(channel_number)
            else:
                channel_item = peak_item
            if autofit_peak_item.childCount():
                autofit_channel_item = autofit_peak_item.child(channel_number)
            else:
                autofit_channel_item = autofit_peak_item
            # Set the value only if the combobox is set to autofit
            combobox = \
                self.autofit_tree.itemWidget(autofit_channel_item, 4)
            if combobox.currentText() == "Auto":
                spinbox = self.tree.itemWidget(channel_item, 4)
                spinbox.setValue(np.rad2deg(value))
Beispiel #2
0
class TreeSymbolsWidget(QDialog):
    """Class of Dialog for Tree Symbols"""
    dockWidget = pyqtSignal("QObject*")
    undockWidget = pyqtSignal()
    changeTitle = pyqtSignal(str)
    def __init__(self, parent=None):
        super(TreeSymbolsWidget, self).__init__(parent,
                                                Qt.WindowStaysOnTopHint)
        vbox = QVBoxLayout(self)
        vbox.setContentsMargins(0, 0, 0, 0)
        vbox.setSpacing(0)
        self.tree = QTreeWidget()
        vbox.addWidget(self.tree)
        self.tree.header().setHidden(True)
        self.tree.setSelectionMode(QAbstractItemView.SingleSelection)
        self.tree.setAnimated(True)
        self.tree.header().setHorizontalScrollMode(
            QAbstractItemView.ScrollPerPixel)
        self.tree.header().setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.tree.header().setStretchLastSection(False)
        self.actualSymbols = ('', {})
        self.docstrings = {}
        self.collapsedItems = {}

        self.tree.itemClicked['QTreeWidgetItem*', int].connect(self._go_to_definition)
        # self.tree.itemActivated['QTreeWidgetItem*', int].connect(self._go_to_definition)
        self.tree.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested['const QPoint &'].connect(self._menu_context_tree)
        self.tree.itemCollapsed['QTreeWidgetItem*'].connect(self._item_collapsed)
        self.tree.itemExpanded['QTreeWidgetItem*'].connect(self._item_expanded)

        IDE.register_service('symbols_explorer', self)
        ExplorerContainer.register_tab(translations.TR_TAB_SYMBOLS, self)

    def install_tab(self):
        """Connect signals for goingdown"""
        ide = IDE.getInstance()
        ide.goingDown.connect(self.close)

    def _menu_context_tree(self, point):
        """Context menu"""
        index = self.tree.indexAt(point)
        if not index.isValid():
            return

        menu = QMenu(self)
        f_all = menu.addAction(translations.TR_FOLD_ALL)
        u_all = menu.addAction(translations.TR_UNFOLD_ALL)
        menu.addSeparator()
        u_class = menu.addAction(translations.TR_UNFOLD_CLASSES)
        u_class_method = menu.addAction(
            translations.TR_UNFOLD_CLASSES_AND_METHODS)
        u_class_attr = menu.addAction(
            translations.TR_UNFOLD_CLASSES_AND_ATTRIBUTES)
        menu.addSeparator()
        #save_state = menu.addAction(self.tr("Save State"))

        f_all.triggered['bool'].connect(lambda s: self.tree.collapseAll())
        u_all.triggered['bool'].connect(lambda s: self.tree.expandAll())
        u_class.triggered['bool'].connect(self._unfold_class)
        u_class_method.triggered['bool'].connect(self._unfold_class_method)
        u_class_attr.triggered['bool'].connect(self._unfold_class_attribute)
        #self.connect(save_state, SIGNAL("triggered()"),
            #self._save_symbols_state)

        menu.exec_(QCursor.pos())

    def _get_classes_root(self):
        """Return the root of classes"""
        class_root = None
        for i in range(self.tree.topLevelItemCount()):
            item = self.tree.topLevelItem(i)
            if item.isClass and not item.isClickable:
                class_root = item
                break
        return class_root

    def _unfold_class(self):
        """Method to Unfold Classes"""
        self.tree.collapseAll()
        classes_root = self._get_classes_root()
        if not classes_root:
            return

        classes_root.setExpanded(True)

    def _unfold_class_method(self):
        """Method to Unfold Methods"""
        self.tree.expandAll()
        classes_root = self._get_classes_root()
        if not classes_root:
            return
        #for each class!
        for i in range(classes_root.childCount()):
            class_item = classes_root.child(i)
            #for each attribute or functions
            for j in range(class_item.childCount()):
                item = class_item.child(j)
                #METHODS ROOT!!
                if not item.isMethod and not item.isClickable:
                    item.setExpanded(False)
                    break

    def _unfold_class_attribute(self):
        """Method to Unfold Attributes"""
        self.tree.expandAll()
        classes_root = self._get_classes_root()
        if not classes_root:
            return
        #for each class!
        for i in range(classes_root.childCount()):
            class_item = classes_root.child(i)
            #for each attribute or functions
            for j in range(class_item.childCount()):
                item = class_item.child(j)
                #ATTRIBUTES ROOT!!
                if not item.isAttribute and not item.isClickable:
                    item.setExpanded(False)
                    break

    def _save_symbols_state(self):
        """Method to Save a persistent Symbols state"""
        #filename = self.actualSymbols[0]
        #TODO: persist self.collapsedItems[filename] in QSettings
        pass

    def _get_expand(self, item):
        """
        Returns True or False to be used as setExpanded() with the items
        It method is based on the click that the user made in the tree
        """
        name = self._get_unique_name(item)
        filename = self.actualSymbols[0]
        collapsed_items = self.collapsedItems.get(filename, [])
        can_check = (not item.isClickable) or item.isClass or item.isMethod
        if can_check and name in collapsed_items:
            return False
        return True

    @staticmethod
    def _get_unique_name(item):
        """
        Returns a string used as unique name
        """
        # className_Attributes/className_Functions
        parent = item.parent()
        if parent:
            return "%s_%s" % (parent.text(0), item.text(0))
        return "_%s" % item.text(0)

    def update_symbols_tree(self, symbols, filename='', parent=None):
        """Method to Update the symbols on the Tree"""
        TIP = "{} {}"
        if not parent:
            if filename == self.actualSymbols[0] and \
                    self.actualSymbols[1] and not symbols:
                return

            if symbols == self.actualSymbols[1]:
                # Nothing new then return
                return

            # we have new symbols refresh it
            self.tree.clear()
            self.actualSymbols = (filename, symbols)
            self.docstrings = symbols.get('docstrings', {})
            parent = self.tree

        if 'attributes' in symbols:
            # print("\nsymbols['attributes']", symbols['attributes'])
            globalAttribute = ItemTree(parent, [translations.TR_ATTRIBUTES])
            globalAttribute.isClickable = False
            globalAttribute.isAttribute = True
            globalAttribute.setExpanded(self._get_expand(globalAttribute))
            globalAttribute.setToolTip(
                0, TIP.format(len(symbols['attributes']),
                              translations.TR_ATTRIBUTES))
            for glob in sorted(symbols['attributes']):
                globItem = ItemTree(globalAttribute, [glob],
                                    lineno=symbols['attributes'][glob])
                globItem.isAttribute = True
                globItem.setIcon(0, QIcon(":img/attribute"))
                globItem.setExpanded(self._get_expand(globItem))

        if 'functions' in symbols and symbols['functions']:
            functionsItem = ItemTree(parent, [translations.TR_FUNCTIONS])
            functionsItem.isClickable = False
            functionsItem.isMethod = True
            functionsItem.setExpanded(self._get_expand(functionsItem))
            functionsItem.setToolTip(0, TIP.format(len(symbols['functions']),
                                                   translations.TR_FUNCTIONS))
            for func in sorted(symbols['functions']):
                item = ItemTree(functionsItem, [func],
                                lineno=symbols['functions'][func]['lineno'])
                tooltip = self.create_tooltip(
                    func, symbols['functions'][func]['lineno'])
                item.isMethod = True
                item.setIcon(0, QIcon(":img/function"))
                item.setToolTip(0, tooltip)
                item.setExpanded(self._get_expand(item))
                self.update_symbols_tree(
                    symbols['functions'][func]['functions'], parent=item)
        if 'classes' in symbols and symbols['classes']:
            classItem = ItemTree(parent, [translations.TR_CLASSES])
            classItem.isClickable = False
            classItem.isClass = True
            classItem.setExpanded(self._get_expand(classItem))
            classItem.setToolTip(0, TIP.format(len(symbols['classes']),
                                               translations.TR_CLASSES))
            for claz in sorted(symbols['classes']):
                line_number = symbols['classes'][claz]['lineno']
                item = ItemTree(classItem, [claz], lineno=line_number)
                item.isClass = True
                tooltip = self.create_tooltip(claz, line_number)
                item.setToolTip(0, tooltip)
                item.setIcon(0, QIcon(":img/class"))
                item.setExpanded(self._get_expand(item))
                self.update_symbols_tree(symbols['classes'][claz]['members'],
                                         parent=item)

    def _go_to_definition(self, item):
        """Takes and item object and goes to definition on the editor"""
        main_container = IDE.get_service('main_container')
        print("\nprimero al clickear pas por aca!!", item.text(0))
        if item.isClickable and main_container:
            # main_container.editor_go_to_line(item.lineno - 1, True)
            main_container.editor_go_to_symbol_line(item.lineno - 1, item.text(0), True)

    def create_tooltip(self, name, lineno):
        """Takes a name and line number and returns a tooltip"""
        doc = self.docstrings.get(lineno, None)
        if doc is None:
            doc = ''
        else:
            doc = '\n' + doc
        tooltip = name + doc
        return tooltip

    def _item_collapsed(self, item):
        """When item collapsed"""
        self.tree.collapseItem(item)

        can_check = (not item.isClickable) or item.isClass or item.isMethod
        if can_check:
            n = self._get_unique_name(item)
            filename = self.actualSymbols[0]
            self.collapsedItems.setdefault(filename, [])
            if not n in self.collapsedItems[filename]:
                self.collapsedItems[filename].append(n)

    def _item_expanded(self, item):
        """When item expanded"""
        self.tree.expandItem(item)

        n = self._get_unique_name(item)
        filename = self.actualSymbols[0]
        if n in self.collapsedItems.get(filename, []):
            self.collapsedItems[filename].remove(n)
            if not len(self.collapsedItems[filename]):
                # no more items, free space
                del self.collapsedItems[filename]

    def clean(self):
        """
        Reset the tree and reset attributes
        """
        self.tree.clear()
        self.collapsedItems = {}

    def reject(self):
        if self.parent() is None:
            self.dockWidget.emit(self)

    def closeEvent(self, event):
        """On Close event handling"""
        self.dockWidget.emit(self)
        event.ignore()
Beispiel #3
0
class CircleFitTree(QGroupBox):
    """
    The tree displaying the Circle Fit results and the parameters used for
    automatically fitting the circle.

    Attributes
    ----------
    sig_selected_peak_changed : pyqtSignal(int)
        The signal emitted when the selected peak is changed.
    """

    sig_selected_peak_changed = pyqtSignal(int)

    def __init__(self, parent=None, channelset=None):
        super().__init__("Results", parent)

        # TODO
        if channelset is None:
            self.num_channels = 5
        else:
            self.num_channels = len(channelset)

        self.num_peaks = 0

        self.init_ui()

    def init_ui(self):
        # # Tree for values
        self.tree = QTreeWidget()
        self.tree.setHeaderLabels([
            "Name", "Frequency", "Damping ratio", "Amplitude", "Phase",
            "Select"
        ])
        self.tree.setStyleSheet(
            "QTreeWidget::item:has-children { background-color : palette(mid);}"
        )

        # # Tree for autofit parameters
        self.autofit_tree = QTreeWidget()
        self.autofit_tree.setHeaderLabels([
            "Name", "Frequency", "Damping ratio", "Amplitude", "Phase",
            "Select"
        ])
        self.autofit_tree.hide()
        self.autofit_tree.setStyleSheet(
            "QTreeWidget::item:has-children { background-color : palette(mid);}"
        )

        # Connect the two trees together, so the views look identical
        self.autofit_tree.itemCollapsed.connect(self.on_item_collapsed)
        self.autofit_tree.itemExpanded.connect(self.on_item_expanded)
        self.tree.itemCollapsed.connect(self.on_item_collapsed)
        self.tree.itemExpanded.connect(self.on_item_expanded)

        # # Controls
        self.add_peak_btn = QPushButton("Add new peak", self)
        self.add_peak_btn.clicked.connect(self.add_peak)

        self.delete_selected_btn = QPushButton("Delete selected", self)
        self.delete_selected_btn.clicked.connect(self.delete_selected)

        self.view_autofit_btn = QPushButton("View autofit parameters", self)
        self.view_autofit_btn.clicked.connect(self.toggle_view)

        self.reset_to_autofit_btn = QPushButton("Reset all to auto", self)
        self.reset_to_autofit_btn.clicked.connect(self.reset_to_autofit)
        self.reset_to_autofit_btn.hide()

        controls1 = QGridLayout()
        controls1.addWidget(self.add_peak_btn, 0, 0)
        controls1.setColumnStretch(1, 1)
        controls1.addWidget(self.delete_selected_btn, 0, 2)

        controls2 = QGridLayout()
        controls2.setColumnStretch(0, 1)
        controls2.addWidget(self.reset_to_autofit_btn, 0, 1)
        controls2.addWidget(self.view_autofit_btn, 0, 2)

        # # Layout
        layout = QGridLayout()
        layout.addLayout(controls2, 0, 0)
        layout.addWidget(self.tree, 1, 0)
        layout.addWidget(self.autofit_tree, 1, 0)
        layout.addLayout(controls1, 2, 0)

        self.setLayout(layout)

    def add_peak(self):
        """Add a top-level item for a new peak to the tree, with children for
        each channel."""
        # Create the parent item for the peak
        peak_item = QTreeWidgetItem(
            self.tree, ["Peak {}".format(self.num_peaks), "", "", "", "", ""])
        autofit_peak_item = QTreeWidgetItem(
            self.autofit_tree,
            ["Peak {}".format(self.num_peaks), "", "", "", "", ""])

        # Put a radio button in column 5 in the tree
        radio_btn = QRadioButton()
        radio_btn.toggled.connect(self.on_selected_peak_changed)
        self.tree.setItemWidget(peak_item, 5, radio_btn)
        radio_btn.setChecked(True)

        for col in [1, 2, 3, 4]:
            # Put spinboxes in the tree
            spinbox = QDoubleSpinBox()
            self.tree.setItemWidget(peak_item, col, spinbox)
            # Put comboboxes in the autofit tree
            combobox = QComboBox()
            combobox.addItems(["Auto", "Manual"])
            combobox.currentIndexChanged.connect(self.update_peak_average)
            self.autofit_tree.setItemWidget(autofit_peak_item, col, combobox)

        # Create the child items for each channel for this peak if there's
        # more than one channel
        if self.num_channels > 1:
            for i in range(self.num_channels):
                channel_item = QTreeWidgetItem(
                    peak_item, ["Channel {}".format(i), "", "", "", "", ""])
                autofit_channel_item = QTreeWidgetItem(
                    autofit_peak_item,
                    ["Channel {}".format(i), "", "", "", "", ""])
                for col in [1, 2, 3, 4]:
                    # Put spinboxes in the tree
                    spinbox = QDoubleSpinBox()
                    spinbox.valueChanged.connect(self.update_peak_average)
                    self.tree.setItemWidget(channel_item, col, spinbox)
                    # Put comboboxes in the autofit tree
                    combobox = QComboBox()
                    combobox.addItems(["Auto", "Manual"])
                    combobox.currentIndexChanged.connect(
                        self.update_peak_average)
                    self.autofit_tree.setItemWidget(autofit_channel_item, col,
                                                    combobox)

        # Register that we've added another peak
        self.num_peaks += 1

    def delete_selected(self):
        """Delete the item that is currently selected."""
        for i in range(self.tree.topLevelItemCount()):
            # If the radio button is checked
            peak_item = self.tree.topLevelItem(i)
            if peak_item is not None:
                if self.tree.itemWidget(peak_item, 5).isChecked():
                    # Delete this item
                    self.tree.takeTopLevelItem(i)
                    self.autofit_tree.takeTopLevelItem(i)
                    #self.num_peaks -= 1

    def toggle_view(self):
        if self.tree.isVisible():
            self.tree.hide()
            self.autofit_tree.show()
            self.reset_to_autofit_btn.show()
            self.view_autofit_btn.setText("View parameter values")
        else:
            self.tree.show()
            self.autofit_tree.hide()
            self.reset_to_autofit_btn.hide()
            self.view_autofit_btn.setText("View autofit parameters")

    def on_item_collapsed(self, item):
        index = self.sender().indexOfTopLevelItem(item)
        self.tree.collapseItem(self.tree.topLevelItem(index))
        self.autofit_tree.collapseItem(self.autofit_tree.topLevelItem(index))

    def on_item_expanded(self, item):
        index = self.sender().indexOfTopLevelItem(item)
        self.tree.expandItem(self.tree.topLevelItem(index))
        self.autofit_tree.expandItem(self.autofit_tree.topLevelItem(index))

    def on_selected_peak_changed(self, checked):
        for i in range(self.tree.topLevelItemCount()):
            # If the radio button in this row is the sender
            peak_item = self.tree.topLevelItem(i)
            if peak_item is not None:
                if self.tree.itemWidget(peak_item, 5) == self.sender():
                    if checked:
                        print("Selected: " + str(i))
                        self.sig_selected_peak_changed.emit(i)

    def reset_to_autofit(self):
        """Reset all parameters to be automatically adjusted."""
        for peak_number in range(self.num_peaks):
            peak_item = self.autofit_tree.topLevelItem(peak_number)

            for col in [1, 2, 3, 4]:
                self.autofit_tree.itemWidget(peak_item, col).setCurrentIndex(0)

            if self.num_channels > 1:
                for channel_number in range(self.num_channels):
                    channel_item = peak_item.child(channel_number)
                    for col in [1, 2, 3, 4]:
                        self.autofit_tree.itemWidget(channel_item,
                                                     col).setCurrentIndex(0)

    def update_peak_average(self):
        """Set the parameter values displayed for the peak to the average of
        all the channel values for each parameter."""
        for peak_number in range(self.num_peaks):
            # Get the peak item
            peak_item = self.tree.topLevelItem(peak_number)
            autofit_item = self.autofit_tree.topLevelItem(peak_number)

            if peak_item is not None:
                # Find the average values of all the channels
                avg_frequency = 0
                avg_damping = 0
                avg_amplitude = 0
                avg_phase = 0

                for channel_number in range(self.num_channels):
                    avg_frequency += self.get_frequency(
                        peak_number, channel_number)
                    avg_damping += self.get_damping(peak_number,
                                                    channel_number)
                    avg_amplitude += self.get_amplitude(
                        peak_number, channel_number)
                    avg_phase += self.get_phase(peak_number, channel_number)

                avg_frequency /= self.num_channels
                avg_damping /= self.num_channels
                avg_amplitude /= self.num_channels
                avg_phase /= self.num_channels

                # Set the peak item to display the averages
                if self.autofit_tree.itemWidget(autofit_item,
                                                1).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 1).setValue(avg_frequency)
                if self.autofit_tree.itemWidget(autofit_item,
                                                2).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 2).setValue(avg_damping)
                if self.autofit_tree.itemWidget(autofit_item,
                                                3).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 3).setValue(avg_amplitude)
                if self.autofit_tree.itemWidget(autofit_item,
                                                4).currentText() == "Auto":
                    self.tree.itemWidget(peak_item, 4).setValue(avg_phase)

    def get_frequency(self, peak_number, channel_number=None):
        """Return the resonant frequency of the peak given by
        *peak_number*. If *channel_number* is given, return the resonant
        frequency of the given peak in the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if channel_number is None:
                spinbox = self.tree.itemWidget(peak_item, 1)
                return spinbox.value()
            else:
                channel_item = peak_item.child(channel_number)
                spinbox = self.tree.itemWidget(channel_item, 1)
                return spinbox.value()
        else:
            return 0

    def get_damping(self, peak_number, channel_number=None):
        """Return the damping ratio of the peak given by *peak_number*. If
        *channel_number* is given, return the damping ratio of the given peak
        in the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if channel_number is None:
                spinbox = self.tree.itemWidget(peak_item, 2)
                return spinbox.value()
            else:
                channel_item = peak_item.child(channel_number)
                spinbox = self.tree.itemWidget(channel_item, 2)
                return spinbox.value()
        else:
            return 0

    def get_amplitude(self, peak_number, channel_number=None):
        """Return the amplitude of the peak given by *peak_number*. If
        *channel_number* is given, return the amplitude of the given peak in
        the given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if channel_number is None:
                spinbox = self.tree.itemWidget(peak_item, 3)
                return spinbox.value()
            else:
                channel_item = peak_item.child(channel_number)
                spinbox = self.tree.itemWidget(channel_item, 3)
                return spinbox.value()
        else:
            return 0

    def get_phase(self, peak_number, channel_number=None):
        """Return the phase of the peak given by *peak_number*. If
        *channel_number* is given, return the phase of the given peak in the
        given channel."""
        peak_item = self.tree.topLevelItem(peak_number)
        if peak_item is not None:
            if channel_number is None:
                spinbox = self.tree.itemWidget(peak_item, 4)
                return spinbox.value()
            else:
                channel_item = peak_item.child(channel_number)
                spinbox = self.tree.itemWidget(channel_item, 4)
                return spinbox.value()
        else:
            return 0

    def get_parameter_values(self, peak_number, channel_number=None):
        """Returns a dict of the parameter values of a peak. If
        *channel_number* is given, return a dict of the parameter values of the
        peak for the given channel."""
        if channel_number is None:
            return {
                "frequency": self.get_frequency(peak_number),
                "damping": self.get_damping(peak_number),
                "amplitude": self.get_amplitude(peak_number),
                "phase": self.get_phase(peak_number)
            }
        else:
            return \
                {"frequency": self.get_frequency(peak_number, channel_number),
                 "damping": self.get_damping(peak_number, channel_number),
                 "amplitude": self.get_amplitude(peak_number, channel_number),
                 "phase": self.get_phase(peak_number, channel_number)}

    def set_frequency(self, peak_number, channel_number=None, value=0):
        """Set the frequency of a given peak to *value*. If *channel_number* is
        given, set the frequency of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            # If they have children
            if channel_number is not None:
                # Get the channel items
                channel_item = peak_item.child(channel_number)
                autofit_channel_item = autofit_peak_item.child(channel_number)
                # Set the value only if the combobox is set to autofit
                combobox = \
                    self.autofit_tree.itemWidget(autofit_channel_item, 1)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(channel_item, 1)
                    spinbox.setValue(value)
            else:
                # Set the value only if the combobox is set to autofit
                combobox = self.autofit_tree.itemWidget(autofit_peak_item, 1)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(peak_item, 1)
                    spinbox.setValue(value)

    def set_damping(self, peak_number, channel_number=None, value=0):
        """Set the damping ratio of a given peak to *value*. If *channel_number* is
        given, set the damping ratio of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            # If they have children
            if channel_number is not None:
                # Get the channel items
                channel_item = peak_item.child(channel_number)
                autofit_channel_item = autofit_peak_item.child(channel_number)
                # Set the value only if the combobox is set to autofit
                combobox = \
                    self.autofit_tree.itemWidget(autofit_channel_item, 2)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(channel_item, 2)
                    spinbox.setValue(value)
            else:
                # Set the value only if the combobox is set to autofit
                combobox = self.autofit_tree.itemWidget(autofit_peak_item, 2)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(peak_item, 2)
                    spinbox.setValue(value)

    def set_amplitude(self, peak_number, channel_number=None, value=0):
        """Set the amplitude of a given peak to *value*. If *channel_number* is
        given, set the amplitude of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            # If they have children
            if channel_number is not None:
                # Get the channel items
                channel_item = peak_item.child(channel_number)
                autofit_channel_item = autofit_peak_item.child(channel_number)
                # Set the value only if the combobox is set to autofit
                combobox = \
                    self.autofit_tree.itemWidget(autofit_channel_item, 3)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(channel_item, 3)
                    spinbox.setValue(value)
            else:
                # Set the value only if the combobox is set to autofit
                combobox = self.autofit_tree.itemWidget(autofit_peak_item, 3)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(peak_item, 3)
                    spinbox.setValue(value)

    def set_phase(self, peak_number, channel_number=None, value=0):
        """Set the phase of a given peak to *value*. If *channel_number* is
        given, set the phase of the given peak in the given channel."""
        # Get the top level items
        peak_item = self.tree.topLevelItem(peak_number)
        autofit_peak_item = self.autofit_tree.topLevelItem(peak_number)
        # Check they exist
        if peak_item is not None:
            # If they have children
            if channel_number is not None:
                # Get the channel items
                channel_item = peak_item.child(channel_number)
                autofit_channel_item = autofit_peak_item.child(channel_number)
                # Set the value only if the combobox is set to autofit
                combobox = \
                    self.autofit_tree.itemWidget(autofit_channel_item, 4)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(channel_item, 4)
                    spinbox.setValue(value)
            else:
                # Set the value only if the combobox is set to autofit
                combobox = self.autofit_tree.itemWidget(autofit_peak_item, 4)
                if combobox.currentText() == "Auto":
                    spinbox = self.tree.itemWidget(peak_item, 4)
                    spinbox.setValue(value)

    def set_parameter_values(self,
                             peak_number,
                             channel_number=None,
                             channel_values={}):
        """Set the parameter values for a given peak to those given in
        *channel_values*. If *channel_number* is given, set the values of the
        given peak in the given channel."""
        if "frequency" in channel_values.keys():
            self.set_frequency(peak_number, channel_number,
                               channel_values["frequency"])
        if "damping" in channel_values.keys():
            self.set_damping(peak_number, channel_number,
                             channel_values["damping"])
        if "amplitude" in channel_values.keys():
            self.set_amplitude(peak_number, channel_number,
                               channel_values["amplitude"])
        if "phase" in channel_values.keys():
            self.set_phase(peak_number, channel_number,
                           channel_values["phase"])