def test_center_changed(self): w = ColorGradientSelection(center=42) changed = QSignalSpy(w.centerChanged) w.center_edit.setText("41") w.center_edit.editingFinished.emit() self.assertEqual(w.center(), 41) self.assertEqual(list(changed), [[41]])
def test_center_changed(self): w = ColorGradientSelection(center=42) changed = QSignalSpy(w.centerChanged) ledit = w.center_edit.lineEdit() ledit.selectAll() QTest.keyClicks(ledit, "41") QTest.keyClick(ledit, Qt.Key_Return) self.assertEqual(w.center(), 41.0) self.assertEqual(list(changed), [[41.0]])
def test_constructor(self): w = ColorGradientSelection(thresholds=(0.1, 0.9)) self.assertEqual(w.thresholds(), (0.1, 0.9)) w = ColorGradientSelection(thresholds=(-0.1, 1.1)) self.assertEqual(w.thresholds(), (0.0, 1.0)) w = ColorGradientSelection(thresholds=(1.0, 0.0)) self.assertEqual(w.thresholds(), (1.0, 1.0))
def test_setModel(self): w = ColorGradientSelection() model = QStringListModel(["A", "B"]) w.setModel(model) self.assertIs(w.model(), model) self.assertEqual(w.findData("B", Qt.DisplayRole), 1) current = QSignalSpy(w.currentIndexChanged) w.setCurrentIndex(1) self.assertEqual(w.currentIndex(), 1) self.assertSequenceEqual(list(current), [[1]])
def test_slider_move(self): w = ColorGradientSelection() w.adjustSize() w.setThresholds(0.5, 0.5) changed = QSignalSpy(w.thresholdsChanged) sl, sh = w.slider_low, w.slider_high sl.triggerAction(sl.SliderToMinimum) self.assertEqual(len(changed), 1) low, high = changed[-1] self.assertLessEqual(low, high) self.assertEqual(low, 0.0) sl.triggerAction(sl.SliderToMaximum) self.assertEqual(len(changed), 2) low, high = changed[-1] self.assertLessEqual(low, high) self.assertEqual(low, 1.0) sh.triggerAction(sl.SliderToMinimum) self.assertEqual(len(changed), 3) low, high = changed[-1] self.assertLessEqual(low, high) self.assertEqual(high, 0.0)
def test_center_visibility(self): w = ColorGradientSelection(center=0) w.center_box.setVisible = Mock() model = itemmodels.ContinuousPalettesModel() w.setModel(model) for row in range(model.rowCount(QModelIndex())): palette = model.data(model.index(row, 0), Qt.UserRole) if palette: if palette.flags & palette.Diverging: diverging = row else: nondiverging = row w.setCurrentIndex(diverging) w.center_box.setVisible.assert_called_with(True) w.setCurrentIndex(nondiverging) w.center_box.setVisible.assert_called_with(False) w.setCurrentIndex(diverging) w.center_box.setVisible.assert_called_with(True) w = ColorGradientSelection() self.assertIsNone(w.center_box)
def test_center(self): w = ColorGradientSelection(center=42) self.assertEqual(w.center(), 42) w.setCenter(40) self.assertEqual(w.center(), 40)
def test_thresholds(self): w = ColorGradientSelection() w.setThresholds(0.2, 0.8) self.assertEqual(w.thresholds(), (0.2, 0.8)) w.setThresholds(0.5, 0.5) self.assertEqual(w.thresholds(), (0.5, 0.5)) w.setThresholds(0.5, np.nextafter(0.5, 0)) self.assertEqual(w.thresholds(), (0.5, 0.5)) w.setThresholds(-1, 2) self.assertEqual(w.thresholds(), (0., 1.)) w.setThresholds(0.1, 0.0) self.assertEqual(w.thresholds(), (0.1, 0.1)) w.setThresholdLow(0.2) self.assertEqual(w.thresholds(), (0.2, 0.2)) self.assertEqual(w.thresholdLow(), 0.2) w.setThresholdHigh(0.1) self.assertEqual(w.thresholdHigh(), 0.1) self.assertEqual(w.thresholds(), (0.1, 0.1))
def __init__(self): super().__init__() self.matrix = None self._matrix_range = 0. self._tree = None self._ordered_tree = None self._sorted_matrix = None self._sort_indices = None self._selection = None self.sorting_cb = gui.comboBox( self.controlArea, self, "sorting", box="Element Sorting", items=["None", "Clustering", "Clustering with ordered leaves"], callback=self._invalidate_ordering) box = gui.vBox(self.controlArea, "Colors") self.color_map_widget = cmw = ColorGradientSelection( thresholds=(self.color_low, self.color_high), ) model = itemmodels.ContinuousPalettesModel(parent=self) cmw.setModel(model) idx = cmw.findData(self.palette_name, model.KeyRole) if idx != -1: cmw.setCurrentIndex(idx) cmw.activated.connect(self._update_color) def _set_thresholds(low, high): self.color_low, self.color_high = low, high self._update_color() cmw.thresholdsChanged.connect(_set_thresholds) box.layout().addWidget(self.color_map_widget) self.annot_combo = gui.comboBox(self.controlArea, self, "annotation_idx", box="Annotations", contentsLength=12, searchable=True, callback=self._invalidate_annotations) self.annot_combo.setModel(itemmodels.VariableListModel()) self.annot_combo.model()[:] = ["None", "Enumeration"] gui.rubber(self.controlArea) gui.auto_send(self.buttonsArea, self, "autocommit") self.view = GraphicsView(background=None) self.mainArea.layout().addWidget(self.view) self.grid_widget = pg.GraphicsWidget() self.grid = QGraphicsGridLayout() self.grid_widget.setLayout(self.grid) self.gradient_legend = GradientLegendWidget(0, 1, self._color_map()) self.gradient_legend.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.gradient_legend.setMaximumWidth(250) self.grid.addItem(self.gradient_legend, 0, 1) self.viewbox = pg.ViewBox(enableMouse=False, enableMenu=False) self.viewbox.setAcceptedMouseButtons(Qt.NoButton) self.viewbox.setAcceptHoverEvents(False) self.grid.addItem(self.viewbox, 2, 1) self.left_dendrogram = DendrogramWidget( self.grid_widget, orientation=DendrogramWidget.Left, selectionMode=DendrogramWidget.NoSelection, hoverHighlightEnabled=False) self.left_dendrogram.setAcceptedMouseButtons(Qt.NoButton) self.left_dendrogram.setAcceptHoverEvents(False) self.top_dendrogram = DendrogramWidget( self.grid_widget, orientation=DendrogramWidget.Top, selectionMode=DendrogramWidget.NoSelection, hoverHighlightEnabled=False) self.top_dendrogram.setAcceptedMouseButtons(Qt.NoButton) self.top_dendrogram.setAcceptHoverEvents(False) self.grid.addItem(self.left_dendrogram, 2, 0) self.grid.addItem(self.top_dendrogram, 1, 1) self.right_labels = TextList(alignment=Qt.AlignLeft | Qt.AlignVCenter, sizePolicy=QSizePolicy( QSizePolicy.Fixed, QSizePolicy.Expanding)) self.bottom_labels = TextList( orientation=Qt.Horizontal, alignment=Qt.AlignRight | Qt.AlignVCenter, sizePolicy=QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)) self.grid.addItem(self.right_labels, 2, 2) self.grid.addItem(self.bottom_labels, 3, 1) self.view.setCentralItem(self.grid_widget) self.gradient_legend.hide() self.left_dendrogram.hide() self.top_dendrogram.hide() self.right_labels.hide() self.bottom_labels.hide() self.matrix_item = None self.dendrogram = None self.settingsAboutToBePacked.connect(self.pack_settings)
def __init__(self): super().__init__() self.__pending_selection = self.selected_rows # A kingdom for a save_state/restore_state self.col_clustering = enum_get( Clustering, self.col_clustering_method, Clustering.None_) self.row_clustering = enum_get( Clustering, self.row_clustering_method, Clustering.None_) @self.settingsAboutToBePacked.connect def _(): self.col_clustering_method = self.col_clustering.name self.row_clustering_method = self.row_clustering.name self.keep_aspect = False #: The original data with all features (retained to #: preserve the domain on the output) self.input_data = None #: The effective data striped of discrete features, and often #: merged using k-means self.data = None self.effective_data = None #: kmeans model used to merge rows of input_data self.kmeans_model = None #: merge indices derived from kmeans #: a list (len==k) of int ndarray where the i-th item contains #: the indices which merge the input_data into the heatmap row i self.merge_indices = None self.parts: Optional[Parts] = None self.__rows_cache = {} self.__columns_cache = {} self.info.set_input_summary(self.info.NoInput) self.info.set_output_summary(self.info.NoOutput) # GUI definition colorbox = gui.vBox(self.controlArea, "Color") self.color_map_widget = cmw = ColorGradientSelection( thresholds=(self.threshold_low, self.threshold_high), ) model = itemmodels.ContinuousPalettesModel(parent=self) cmw.setModel(model) idx = cmw.findData(self.palette_name, model.KeyRole) if idx != -1: cmw.setCurrentIndex(idx) cmw.activated.connect(self.update_color_schema) def _set_thresholds(low, high): self.threshold_low, self.threshold_high = low, high self.update_color_schema() cmw.thresholdsChanged.connect(_set_thresholds) colorbox.layout().addWidget(self.color_map_widget) mergebox = gui.vBox(self.controlArea, "Merge",) gui.checkBox(mergebox, self, "merge_kmeans", "Merge by k-means", callback=self.__update_row_clustering) ibox = gui.indentedBox(mergebox) gui.spin(ibox, self, "merge_kmeans_k", minv=5, maxv=500, label="Clusters:", keyboardTracking=False, callbackOnReturn=True, callback=self.update_merge) cluster_box = gui.vBox(self.controlArea, "Clustering") # Row clustering self.row_cluster_cb = cb = ComboBox() cb.setModel(create_list_model(ClusteringModelData, self)) cbselect(cb, self.row_clustering, ClusteringRole) self.connect_control( "row_clustering", lambda value, cb=cb: cbselect(cb, value, ClusteringRole) ) @cb.activated.connect def _(idx, cb=cb): self.set_row_clustering(cb.itemData(idx, ClusteringRole)) # Column clustering self.col_cluster_cb = cb = ComboBox() cb.setModel(create_list_model(ClusteringModelData, self)) cbselect(cb, self.col_clustering, ClusteringRole) self.connect_control( "col_clustering", lambda value, cb=cb: cbselect(cb, value, ClusteringRole) ) @cb.activated.connect def _(idx, cb=cb): self.set_col_clustering(cb.itemData(idx, ClusteringRole)) form = QFormLayout( labelAlignment=Qt.AlignLeft, formAlignment=Qt.AlignLeft, fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow, ) form.addRow("Rows:", self.row_cluster_cb) form.addRow("Columns:", self.col_cluster_cb) cluster_box.layout().addLayout(form) box = gui.vBox(self.controlArea, "Split By") self.row_split_model = DomainModel( placeholder="(None)", valid_types=(Orange.data.DiscreteVariable,), parent=self, ) self.row_split_cb = cb = ComboBoxSearch( enabled=not self.merge_kmeans, sizeAdjustPolicy=ComboBox.AdjustToMinimumContentsLengthWithIcon, minimumContentsLength=14, toolTip="Split the heatmap vertically by a categorical column" ) self.row_split_cb.setModel(self.row_split_model) self.connect_control( "split_by_var", lambda value, cb=cb: cbselect(cb, value) ) self.connect_control( "merge_kmeans", self.row_split_cb.setDisabled ) self.split_by_var = None self.row_split_cb.activated.connect( self.__on_split_rows_activated ) box.layout().addWidget(self.row_split_cb) box = gui.vBox(self.controlArea, 'Annotation && Legends') gui.checkBox(box, self, 'legend', 'Show legend', callback=self.update_legend) gui.checkBox(box, self, 'averages', 'Stripes with averages', callback=self.update_averages_stripe) annotbox = QGroupBox("Row Annotations", flat=True) form = QFormLayout( annotbox, formAlignment=Qt.AlignLeft, labelAlignment=Qt.AlignLeft, fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow ) self.annotation_model = DomainModel(placeholder="(None)") self.annotation_text_cb = ComboBoxSearch( minimumContentsLength=12, sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength ) self.annotation_text_cb.setModel(self.annotation_model) self.annotation_text_cb.activated.connect(self.set_annotation_var) self.connect_control("annotation_var", self.annotation_var_changed) self.row_side_color_model = DomainModel( order=(DomainModel.CLASSES, DomainModel.Separator, DomainModel.METAS), placeholder="(None)", valid_types=DomainModel.PRIMITIVE, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled, parent=self, ) self.row_side_color_cb = ComboBoxSearch( sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength, minimumContentsLength=12 ) self.row_side_color_cb.setModel(self.row_side_color_model) self.row_side_color_cb.activated.connect(self.set_annotation_color_var) self.connect_control("annotation_color_var", self.annotation_color_var_changed) form.addRow("Text", self.annotation_text_cb) form.addRow("Color", self.row_side_color_cb) box.layout().addWidget(annotbox) posbox = gui.vBox(box, "Column Labels Position", addSpace=False) posbox.setFlat(True) cb = gui.comboBox( posbox, self, "column_label_pos", callback=self.update_column_annotations) cb.setModel(create_list_model(ColumnLabelsPosData, parent=self)) cb.setCurrentIndex(self.column_label_pos) gui.checkBox(self.controlArea, self, "keep_aspect", "Keep aspect ratio", box="Resize", callback=self.__aspect_mode_changed) gui.rubber(self.controlArea) gui.auto_send(self.controlArea, self, "auto_commit") # Scene with heatmap class HeatmapScene(QGraphicsScene): widget: Optional[HeatmapGridWidget] = None self.scene = self.scene = HeatmapScene(parent=self) self.view = GraphicsView( self.scene, verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOn, viewportUpdateMode=QGraphicsView.FullViewportUpdate, widgetResizable=True, ) self.view.setContextMenuPolicy(Qt.CustomContextMenu) self.view.customContextMenuRequested.connect( self._on_view_context_menu ) self.mainArea.layout().addWidget(self.view) self.selected_rows = [] self.__font_inc = QAction( "Increase Font", self, shortcut=QKeySequence("ctrl+>")) self.__font_dec = QAction( "Decrease Font", self, shortcut=QKeySequence("ctrl+<")) self.__font_inc.triggered.connect(lambda: self.__adjust_font_size(1)) self.__font_dec.triggered.connect(lambda: self.__adjust_font_size(-1)) if hasattr(QAction, "setShortcutVisibleInContextMenu"): apply_all( [self.__font_inc, self.__font_dec], lambda a: a.setShortcutVisibleInContextMenu(True) ) self.addActions([self.__font_inc, self.__font_dec])