Repository: biolab/orange3

Issue:
Heat Map: don't show bow attributes if flag hidden=True
<!-- 
Thanks for taking the time to submit a feature request!
For the best chance at our team considering your request, please answer the following questions to the best of your ability.
-->

- [ ] **What's your use case?**
<!-- In other words, what's your pain point? -->
<!-- Is your request related to a problem, or perhaps a frustration? -->
<!-- Tell us the story that led you to write this request. -->
Some visualization widgets will ignore bow attributes if they have a hidden=True flag (in attributes of attributes). Heat Map would benefit from the same setup: ignoring bow attributes (and showing just sentiment, topics, etc.).




- [ ] **What's your proposed solution?**
<!-- Be specific, clear, and concise. -->
Add the same option as Box Plot has it for hiding bow attributes.




- [ ] **Are there any alternative solutions?**

Keep it as is.







Discussion:
What do you think @PrimozGodec?
Hmm, it is a difficult one. On one side it would be nice to be consistent and remove hidden attributes. On the other side, what if someone wants to see embeddings on the heatmap. Then she/he would need to go through each attribute in the edit domain and change `hidden` attribute to `False`.

Another solution would be to remove hidden attributes from the heatmap and add a checkbox to the embedding widgets same as in the Bag of words widget.

I am actually more for this second option. This way we give the user the option to hide some attributes and still he can check embeddings with the heatmap.
Right, I forgot embeddings are also hidden. Yes, this would make sense - adding a checkbox to Doc Emb would make the most sense. And of course hiding hidden attributes in Heat Map.
I think this was the proposed solution:
- Add a checkbox to Document Embedding with the option to hide/unhide bow attributes (see BoW for example).
- Hide "hidden" attributes in Heat Map (as in Box Plot).

Resolving patch:
diff --git a/Orange/widgets/visualize/owheatmap.py b/Orange/widgets/visualize/owheatmap.py
--- a/Orange/widgets/visualize/owheatmap.py
+++ b/Orange/widgets/visualize/owheatmap.py
@@ -229,8 +229,8 @@ def __init__(self):
         #: 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
+        #: The effective data stripped of discrete features and hidden
+        #: attributes, and often merged using k-means
         self.data = None
         self.effective_data = None
         #: Source of column annotations (derived from self.data)
@@ -602,13 +602,16 @@ def set_dataset(self, data=None):
             self.Error.no_continuous()
             input_data = data = None
 
-        # Data contains some discrete attributes which must be filtered
+        # Data contains some discrete or hidden attributes which must be
+        # filtered
         if data is not None and \
-                any(var.is_discrete for var in data.domain.attributes):
+                any(var.is_discrete or var.attributes.get('hidden', False)
+                    for var in data.domain.attributes):
             ndisc = sum(var.is_discrete for var in data.domain.attributes)
             data = data.transform(
                 Domain([var for var in data.domain.attributes
-                        if var.is_continuous],
+                        if var.is_continuous and
+                        not var.attributes.get('hidden', False)],
                        data.domain.class_vars,
                        data.domain.metas))
             if not data.domain.attributes:
@@ -689,7 +692,11 @@ def set_column_split_var(self, var: Optional[Variable]):
     def update_heatmaps(self):
         if self.data is not None:
             self.clear_scene()
-            self.clear_messages()
+            self.Error.clear()
+            self.Warning.clear()
+            self.Information.row_clust.clear()
+            self.Information.col_clust.clear()
+            self.Information.sampled.clear()
             if self.col_clustering != Clustering.None_ and \
                     len(self.data.domain.attributes) < 2:
                 self.Error.not_enough_features()


Test patch:
diff --git a/Orange/widgets/visualize/tests/test_owheatmap.py b/Orange/widgets/visualize/tests/test_owheatmap.py
--- a/Orange/widgets/visualize/tests/test_owheatmap.py
+++ b/Orange/widgets/visualize/tests/test_owheatmap.py
@@ -29,16 +29,16 @@ def setUpClass(cls):
         super().setUpClass()
         WidgetOutputsTestMixin.init(cls)
 
-        cls.housing = Table("housing")
-        cls.titanic = Table("titanic")
-        cls.brown_selected = Table("brown-selected")
-
         cls.signal_name = "Data"
         cls.signal_data = cls.data
 
     def setUp(self):
         self.widget = self.create_widget(OWHeatMap)  # type: OWHeatMap
 
+        self.housing = Table("housing")
+        self.titanic = Table("titanic")
+        self.brown_selected = Table("brown-selected")
+
     def test_input_data(self):
         """Check widget's data with data on the input"""
         for data in (self.data, self.housing):
@@ -72,6 +72,9 @@ def test_information_message(self):
         self.assertFalse(self.widget.Information.active)
         self.send_signal(self.widget.Inputs.data, data[:21])
         self.assertTrue(self.widget.Information.active)
+        data = Table("heart_disease.tab")[:10]
+        self.send_signal(self.widget.Inputs.data, data)
+        self.assertTrue(self.widget.Information.discrete_ignored.is_shown())
 
     def test_settings_changed(self):
         self.send_signal(self.widget.Inputs.data, self.data)
@@ -396,6 +399,14 @@ def test_col_color_annotations_with_na(self):
         widget.set_column_annotation_color_var(None)
         self.assertFalse(widget.scene.widget.top_side_colors[0].isVisible())
 
+    def test_data_with_hidden(self):
+        w = self.widget
+        housing = self.housing.copy()
+        housing.domain.attributes[0].attributes["hidden"] = True
+        self.send_signal(self.widget.Inputs.data, housing)
+        self.assertEqual(len(w.effective_data.domain.attributes),
+                         len(housing.domain.attributes) - 1)
+
 
 if __name__ == "__main__":
     unittest.main()