Skip to content

Commit ba9efa3

Browse files
committed
owheatmap: Serialization of column annotation keys
1 parent 66bc42a commit ba9efa3

File tree

2 files changed

+68
-47
lines changed

2 files changed

+68
-47
lines changed

Orange/widgets/visualize/owheatmap.py

Lines changed: 56 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -184,12 +184,12 @@ class Outputs:
184184
annotation_var = settings.ContextSetting(None)
185185
#: color row annotation
186186
annotation_color_var = settings.ContextSetting(None)
187-
column_annotation_color_key = settings.ContextSetting(None)
187+
column_annotation_color_key: Optional[Tuple[str, str]] = settings.ContextSetting(None)
188188

189189
# Discrete variable used to split that data/heatmaps (vertically)
190190
split_by_var = settings.ContextSetting(None)
191191
# Split heatmap columns by 'key' (horizontal)
192-
split_columns_key = settings.ContextSetting(None)
192+
split_columns_key: Optional[Tuple[str, str]] = settings.ContextSetting(None)
193193
# Selected row/column clustering method (name)
194194
col_clustering_method: str = settings.Setting(Clustering.None_.name)
195195
row_clustering_method: str = settings.Setting(Clustering.None_.name)
@@ -232,11 +232,7 @@ def __init__(self):
232232
self.row_clustering = enum_get(
233233
Clustering, self.row_clustering_method, Clustering.None_)
234234

235-
@self.settingsAboutToBePacked.connect
236-
def _():
237-
self.col_clustering_method = self.col_clustering.name
238-
self.row_clustering_method = self.row_clustering.name
239-
235+
self.settingsAboutToBePacked.connect(self._save_state_for_serialization)
240236
self.keep_aspect = False
241237

242238
#: The original data with all features (retained to
@@ -364,9 +360,9 @@ def _(idx, cb=cb):
364360
)
365361
self.col_split_cb.setModel(self.col_split_model)
366362
self.connect_control(
367-
"split_columns_key", lambda value, cb=cb: cbselect(cb, value)
363+
"split_columns_var", lambda value, cb=cb: cbselect(cb, value)
368364
)
369-
self.split_columns_key = None
365+
self.split_columns_var = None
370366
self.col_split_cb.activated.connect(self.__on_split_cols_activated)
371367
form.addRow("Rows:", self.row_split_cb)
372368
form.addRow("Columns:", self.col_split_cb)
@@ -429,11 +425,11 @@ def _(idx, cb=cb):
429425
)
430426
self.col_side_color_cb.setModel(self.col_side_color_model)
431427
self.connect_control(
432-
"column_annotation_color_key", self.column_annotation_color_key_changed,
428+
"column_annotation_color_var", self.column_annotation_color_var_changed,
433429
)
434-
self.column_annotation_color_key = None
430+
self.column_annotation_color_var = None
435431
self.col_side_color_cb.activated.connect(
436-
self.__set_column_annotation_color_key_index)
432+
self.__set_column_annotation_color_var_index)
437433

438434
cb = gui.comboBox(
439435
None, self, "column_label_pos",
@@ -482,6 +478,19 @@ class HeatmapScene(QGraphicsScene):
482478
)
483479
self.addActions([self.__font_inc, self.__font_dec])
484480

481+
def _save_state_for_serialization(self):
482+
def desc(var: Optional[Variable]) -> Optional[Tuple[str, str]]:
483+
if var is not None:
484+
return type(var).__name__, var.name
485+
else:
486+
return None
487+
488+
self.col_clustering_method = self.col_clustering.name
489+
self.row_clustering_method = self.row_clustering.name
490+
491+
self.column_annotation_color_key = desc(self.column_annotation_color_var)
492+
self.split_columns_key = desc(self.split_columns_var)
493+
485494
@property
486495
def center_palette(self):
487496
palette = self.color_map_widget.currentData()
@@ -534,11 +543,11 @@ def clear(self):
534543
self.row_side_color_model.set_domain(None)
535544
self.col_side_color_model.set_domain(None)
536545
self.annotation_color_var = None
537-
self.column_annotation_color_key = None
546+
self.column_annotation_color_var = None
538547
self.row_split_model.set_domain(None)
539548
self.col_split_model.set_domain(None)
540549
self.split_by_var = None
541-
self.split_columns_key = None
550+
self.split_columns_var = None
542551
self.parts = None
543552
self.clear_scene()
544553
self.selected_rows = []
@@ -629,19 +638,32 @@ def set_dataset(self, data=None):
629638
self.split_by_var = data.domain.class_var
630639
else:
631640
self.split_by_var = None
632-
self.split_columns_key = None
633-
self.column_annotation_color_key = None
641+
self.split_columns_var = None
642+
self.column_annotation_color_var = None
634643
self.openContext(self.input_data)
635644
if self.split_by_var not in self.row_split_model:
636645
self.split_by_var = None
637646

638-
idx = self.col_split_cb.findData(self.split_columns_key, Qt.EditRole)
639-
if idx == -1:
640-
self.split_columns_key = None
647+
def match(desc: Tuple[str, str], source: Iterable[Variable]):
648+
for v in source:
649+
if desc == (type(v).__name__, v.name):
650+
return v
651+
return None
641652

642-
idx = self.col_side_color_cb.findData(self.column_annotation_color_key, Qt.EditRole)
643-
if idx == -1:
644-
self.column_annotation_color_key = None
653+
def is_variable(obj):
654+
return isinstance(obj, Variable)
655+
656+
if self.split_columns_key is not None:
657+
self.split_columns_var = match(
658+
self.split_columns_key,
659+
filter(is_variable, self.col_split_model)
660+
)
661+
662+
if self.column_annotation_color_key is not None:
663+
self.column_annotation_color_var = match(
664+
self.column_annotation_color_key,
665+
filter(is_variable, self.col_side_color_model)
666+
)
645667

646668
self.update_heatmaps()
647669
if data is not None and self.__pending_selection is not None:
@@ -666,11 +688,11 @@ def set_split_variable(self, var):
666688
self.update_heatmaps()
667689

668690
def __on_split_cols_activated(self):
669-
self.set_column_split_key(self.col_split_cb.currentData(Qt.EditRole))
691+
self.set_column_split_var(self.col_split_cb.currentData(Qt.EditRole))
670692

671-
def set_column_split_key(self, key):
672-
if key != self.split_columns_key:
673-
self.split_columns_key = key
693+
def set_column_split_var(self, var: Optional[Variable]):
694+
if var != self.split_columns_var:
695+
self.split_columns_var = var
674696
self.update_heatmaps()
675697

676698
def update_heatmaps(self):
@@ -687,7 +709,7 @@ def update_heatmaps(self):
687709
elif self.merge_kmeans and len(self.data) < 3:
688710
self.Error.not_enough_instances_k_means()
689711
else:
690-
parts = self.construct_heatmaps(self.data, self.split_by_var, self.split_columns_key)
712+
parts = self.construct_heatmaps(self.data, self.split_by_var, self.split_columns_var)
691713
self.construct_heatmaps_scene(parts, self.effective_data)
692714
self.selected_rows = []
693715
else:
@@ -1120,17 +1142,16 @@ def update_row_side_colors(self):
11201142
else:
11211143
widget.setRowSideColorAnnotations(colors[0], colors[1], colors[2].name)
11221144

1123-
def __set_column_annotation_color_key_index(self, index: int):
1145+
def __set_column_annotation_color_var_index(self, index: int):
11241146
key = self.col_side_color_cb.itemData(index, Qt.EditRole)
1125-
self.set_column_annotation_color_key(key)
1147+
self.set_column_annotation_color_var(key)
11261148

1127-
def column_annotation_color_key_changed(self, value):
1149+
def column_annotation_color_var_changed(self, value):
11281150
cbselect(self.col_side_color_cb, value, Qt.EditRole)
11291151

1130-
def set_column_annotation_color_key(self, key):
1131-
if self.column_annotation_color_key != key:
1132-
self.column_annotation_color_key = key
1133-
cbselect(self.col_side_color_cb, key, Qt.EditRole)
1152+
def set_column_annotation_color_var(self, var):
1153+
if self.column_annotation_color_var != var:
1154+
self.column_annotation_color_var = var
11341155
colors = self.column_side_colors()
11351156
if colors is not None:
11361157
self.scene.widget.setColumnSideColorAnnotations(
@@ -1140,7 +1161,7 @@ def set_column_annotation_color_key(self, key):
11401161
self.scene.widget.setColumnSideColorAnnotations(None)
11411162

11421163
def column_side_colors(self):
1143-
var = self.column_annotation_color_key
1164+
var = self.column_annotation_color_var
11441165
if var is None:
11451166
return None
11461167
table = self.col_annot_data

Orange/widgets/visualize/tests/test_owheatmap.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,9 @@ def test_set_split_column_key(self):
236236
data_t = data.transpose(data)
237237
w = self.widget
238238
self.send_signal(self.widget.Inputs.data, data_t, widget=w)
239-
w.set_column_split_key(function)
239+
w.set_column_split_var(function)
240240
self.assertEqual(len(w.parts.columns), len(function.values))
241-
w.set_column_split_key(None)
241+
w.set_column_split_var(None)
242242
self.assertEqual(len(w.parts.columns), 1)
243243

244244
def test_set_split_column_key_missing(self):
@@ -248,11 +248,11 @@ def test_set_split_column_key_missing(self):
248248
function = data.domain["function"]
249249
w = self.widget
250250
self.send_signal(self.widget.Inputs.data, data_t, widget=w)
251-
w.set_column_split_key(function)
251+
w.set_column_split_var(function)
252252
self.assertEqual(len(w.parts.columns), len(function.values) + 1)
253253
ncols = sum(len(p.indices) for p in w.parts.columns)
254254
self.assertEqual(ncols, len(data_t.domain.attributes))
255-
w.set_column_split_key(None)
255+
w.set_column_split_var(None)
256256
self.assertEqual(len(w.parts.columns), 1)
257257

258258
def test_palette_centering(self):
@@ -331,11 +331,11 @@ def test_col_color_annotations(self):
331331
data_t = data.transpose(data)
332332
self.send_signal(widget.Inputs.data, data_t, widget=widget)
333333
# discrete
334-
widget.set_column_annotation_color_key(data.domain["function"])
334+
widget.set_column_annotation_color_var(data.domain["function"])
335335
self.assertTrue(widget.scene.widget.top_side_colors[0].isVisible())
336336
# continuous
337-
widget.set_column_annotation_color_key(data.domain["diau g"])
338-
widget.set_column_annotation_color_key(None)
337+
widget.set_column_annotation_color_var(data.domain["diau g"])
338+
widget.set_column_annotation_color_var(None)
339339
self.assertFalse(widget.scene.widget.top_side_colors[0].isVisible())
340340

341341
def test_col_color_annotations_with_na(self):
@@ -345,16 +345,16 @@ def test_col_color_annotations_with_na(self):
345345
data.metas[:3, -1] = np.nan
346346
data_t = data.transpose(data)
347347
self.send_signal(widget.Inputs.data, data_t, widget=widget)
348-
widget.set_column_annotation_color_key(data.domain["function"])
348+
widget.set_column_annotation_color_var(data.domain["function"])
349349
self.assertTrue(widget.scene.widget.top_side_colors[0].isVisible())
350-
widget.set_column_annotation_color_key(data.domain["diau g"])
350+
widget.set_column_annotation_color_var(data.domain["diau g"])
351351
data.Y[:] = np.nan
352352
data.metas[:, -1] = np.nan
353353
data_t = data.transpose(data)
354354
self.send_signal(widget.Inputs.data, data_t, widget=widget)
355-
widget.set_column_annotation_color_key(data.domain["function"])
356-
widget.set_column_annotation_color_key(data.domain["diau g"])
357-
widget.set_column_annotation_color_key(None)
355+
widget.set_column_annotation_color_var(data.domain["function"])
356+
widget.set_column_annotation_color_var(data.domain["diau g"])
357+
widget.set_column_annotation_color_var(None)
358358
self.assertFalse(widget.scene.widget.top_side_colors[0].isVisible())
359359

360360
def test_summary(self):

0 commit comments

Comments
 (0)