Skip to content

Commit 1cd96ba

Browse files
committed
owheatmap: Add column color annotations
1 parent eab555b commit 1cd96ba

File tree

2 files changed

+71
-7
lines changed

2 files changed

+71
-7
lines changed

Orange/widgets/visualize/owheatmap.py

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
from AnyQt.QtCore import Qt, QSize, QRectF, QObject
1818

1919
from orangewidget.utils.combobox import ComboBox, ComboBoxSearch
20-
from Orange.data import Domain, Table, Variable, DiscreteVariable
20+
from Orange.data import Domain, Table, Variable, DiscreteVariable, \
21+
ContinuousVariable
2122
from Orange.data.sql.table import SqlTable
2223
import Orange.distance
2324

@@ -412,13 +413,36 @@ def _(idx, cb=cb):
412413
form.addRow("Text", self.annotation_text_cb)
413414
form.addRow("Color", self.row_side_color_cb)
414415
box.layout().addWidget(annotbox)
415-
posbox = gui.vBox(box, "Column Labels Position", addSpace=False)
416-
posbox.setFlat(True)
416+
annotbox = QGroupBox("Column annotations", flat=True)
417+
form = QFormLayout(
418+
annotbox,
419+
formAlignment=Qt.AlignLeft,
420+
labelAlignment=Qt.AlignLeft,
421+
fieldGrowthPolicy=QFormLayout.AllNonFixedFieldsGrow
422+
)
423+
self.col_side_color_model = DomainModel(
424+
placeholder="(None)",
425+
valid_types=(DiscreteVariable, ContinuousVariable),
426+
parent=self
427+
)
428+
self.col_side_color_cb = cb = ComboBoxSearch(
429+
sizeAdjustPolicy=QComboBox.AdjustToMinimumContentsLength,
430+
minimumContentsLength=12
431+
)
432+
self.col_side_color_cb.setModel(self.col_side_color_model)
433+
self.column_annotation_color_var = None
434+
self.col_side_color_cb.activated.connect(self.__set_column_annotation_color_key_index)
435+
# posbox = gui.vBox(box, "Column Labels Position", addSpace=False)
436+
# posbox.setFlat(True)
417437
cb = gui.comboBox(
418-
posbox, self, "column_label_pos",
438+
None, self, "column_label_pos",
419439
callback=self.update_column_annotations)
420440
cb.setModel(create_list_model(ColumnLabelsPosData, parent=self))
421441
cb.setCurrentIndex(self.column_label_pos)
442+
form.addRow("Color", self.col_side_color_cb)
443+
form.addRow("Label position", cb)
444+
box.layout().addWidget(annotbox)
445+
422446
gui.checkBox(self.controlArea, self, "keep_aspect",
423447
"Keep aspect ratio", box="Resize",
424448
callback=self.__aspect_mode_changed)
@@ -596,7 +620,7 @@ def set_dataset(self, data=None):
596620
self.row_split_model.set_domain(data.domain)
597621
self.col_annot_data = data.transpose(data[:0].transform(Domain(data.domain.attributes)))
598622
self.col_split_model.set_domain(self.col_annot_data.domain)
599-
623+
self.col_side_color_model.set_domain(self.col_annot_data.domain)
600624
if data.domain.has_discrete_class:
601625
self.split_by_var = data.domain.class_var
602626
else:
@@ -633,7 +657,7 @@ def set_split_variable(self, var):
633657
self.update_heatmaps()
634658

635659
def __on_split_cols_activated(self):
636-
self.set_column_split_key(self.col_split_cb.currentData(Qt.UserRole))
660+
self.set_column_split_key(self.col_split_cb.currentData(Qt.EditRole))
637661

638662
def set_column_split_key(self, key):
639663
if key != self.split_columns_key:
@@ -812,7 +836,9 @@ def construct_heatmaps(self, data, group_var=None, column_split_key=None) -> 'Pa
812836

813837
self.__update_clustering_enable_state(effective_data)
814838

815-
parts = self._make_parts(effective_data, group_var, column_split_key)
839+
parts = self._make_parts(
840+
effective_data, group_var,
841+
column_split_key.name if column_split_key is not None else None)
816842
# Restore/update the row/columns items descriptions from cache if
817843
# available
818844
rows_cache_key = (group_var,
@@ -882,9 +908,15 @@ def setup_scene(self, parts, data):
882908
col_names=columns,
883909
)
884910
widget.setHeatmaps(parts)
911+
885912
side = self.row_side_colors()
886913
if side is not None:
887914
widget.setRowSideColorAnnotations(side[0], side[1], name=side[2].name)
915+
916+
side = self.column_side_colors()
917+
if side is not None:
918+
widget.setColumnSideColorAnnotations(side[0], side[1], name=side[2].name)
919+
888920
widget.setColumnLabelsPosition(self._column_label_pos)
889921
widget.setAspectRatioMode(
890922
Qt.KeepAspectRatio if self.keep_aspect else Qt.IgnoreAspectRatio
@@ -1111,6 +1143,28 @@ def _colorize(self, var: Variable, data: np.ndarray) -> Tuple[np.ndarray, ColorM
11111143
else:
11121144
raise TypeError
11131145

1146+
def __set_column_annotation_color_key_index(self, index):
1147+
self.column_annotation_color_var = self.col_side_color_cb.itemData(index, Qt.EditRole)
1148+
colors = self.column_side_colors()
1149+
if colors is not None:
1150+
self.scene.widget.setColumnSideColorAnnotations(
1151+
colors[0], colors[1], colors[2].name,
1152+
)
1153+
else:
1154+
self.scene.widget.setColumnSideColorAnnotations(None)
1155+
1156+
def column_side_colors(self):
1157+
var = self.column_annotation_color_var
1158+
if var is None:
1159+
return None
1160+
table = self.col_annot_data
1161+
var = table.domain[var]
1162+
column_data = column_data_from_table(table, var)
1163+
data, colormap = self._colorize(var, column_data)
1164+
if var.is_continuous:
1165+
colormap.span = (np.nanmin(column_data), np.nanmax(column_data))
1166+
return data, colormap, var
1167+
11141168
def update_column_annotations(self):
11151169
widget = self.scene.widget
11161170
if self.data is not None and widget is not None:

Orange/widgets/visualize/utils/heatmap.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,16 @@ def setHeatmaps(self, parts: 'Parts') -> None:
564564
self.TopLabelsRow, RightLabelColumn - 1,
565565
)
566566

567+
col_color_annotation_header = QGraphicsSimpleTextItem("", self)
568+
grid.addItem(SimpleLayoutItem(
569+
col_color_annotation_header, anchor=(1, 1), anchorItem=(1, 1),
570+
resizeContents=True,
571+
aspectMode=Qt.KeepAspectRatio,
572+
sizePolicy=QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred),
573+
),
574+
TopAnnotationRow, 0, 1, Col0, alignment=Qt.AlignRight
575+
)
576+
567577
legend = GradientLegendWidget(
568578
parts.span[0], parts.span[1],
569579
colormap,

0 commit comments

Comments
 (0)