Repository: biolab/orange3

Issue:
Header type annotation (colours) not saved correctly
Colours are not saved/reloaded correctly. I tried to set colours for a categorical feature and then saved the file with header type annotation.  Upon importing the new file into the Orange the data does not have correct colours. The colours from the saved data are loaded correctly in terms of hues, but the categorical instances are mixed between the categories. 
![Screenshot from 2020-03-09 13-32-24](https://user-images.githubusercontent.com/47607471/76213504-1da90580-620b-11ea-9b27-955ac9d524b5.png)



Discussion:
@Hrovatin, I can't reproduce, but I think I know what's wrong. Please check whether #4535 fixes it.
Reading my previous comment, I see it sounds very wrong. I can't reproduce *the bug you encountered*, but I think I know what's wrong *with Orange*.

Resolving patch:
diff --git a/Orange/widgets/visualize/utils/widget.py b/Orange/widgets/visualize/utils/widget.py
--- a/Orange/widgets/visualize/utils/widget.py
+++ b/Orange/widgets/visualize/utils/widget.py
@@ -16,6 +16,7 @@
 from Orange.widgets.settings import (
     Setting, ContextSetting, DomainContextHandler, SettingProvider
 )
+from Orange.widgets.utils import colorpalettes
 from Orange.widgets.utils.annotated_data import (
     create_annotated_table, ANNOTATED_DATA_SIGNAL_NAME, create_groups_table
 )
@@ -222,7 +223,17 @@ def get_palette(self):
         This method must be overridden if the widget offers coloring that is
         not based on attribute values.
         """
-        return self.attr_color and self.attr_color.palette
+        attr = self.attr_color
+        if not attr:
+            return None
+        palette = attr.palette
+        if attr.is_discrete and len(attr.values) >= MAX_COLORS:
+            values = self.get_color_labels()
+            colors = [palette.palette[attr.to_val(value)]
+                      for value in values[:-1]] + [[192, 192, 192]]
+
+            palette = colorpalettes.DiscretePalette.from_colors(colors)
+        return palette
 
     def can_draw_density(self):
         """


Test patch:
diff --git a/Orange/widgets/visualize/tests/test_owprojectionwidget.py b/Orange/widgets/visualize/tests/test_owprojectionwidget.py
--- a/Orange/widgets/visualize/tests/test_owprojectionwidget.py
+++ b/Orange/widgets/visualize/tests/test_owprojectionwidget.py
@@ -11,7 +11,9 @@
 from Orange.widgets.tests.base import (
     WidgetTest, WidgetOutputsTestMixin, ProjectionWidgetTestMixin
 )
-from Orange.widgets.utils.colorpalettes import ContinuousPalettes
+from Orange.widgets.utils.colorpalettes import (
+    ContinuousPalettes, DiscretePalette
+)
 from Orange.widgets.visualize.utils.widget import (
     OWDataProjectionWidget, OWProjectionWidgetBase
 )
@@ -113,6 +115,33 @@ def test_get_tooltip(self):
                         and "3" in widget.get_tooltip([0, 1]))
         self.assertEqual(widget.get_tooltip([]), "")
 
+    def test_get_palette(self):
+        widget = self.widget
+
+        widget.attr_color = None
+        self.assertIsNone(widget.get_palette())
+
+        var = ContinuousVariable("v")
+        var.palette = Mock()
+        widget.attr_color = var
+        self.assertIs(widget.get_palette(), var.palette)
+
+        var = DiscreteVariable("v", values=tuple("abc"))
+        var.palette = Mock()
+        widget.attr_color = var
+        self.assertIs(widget.get_palette(), var.palette)
+
+        values = tuple("abcdefghijklmn")
+        merged = ["a", "c", "d", "h", "n", "Others"]
+        var = DiscreteVariable("v", values=values)
+        var.palette = DiscretePalette(
+            "foo", "bar", [[i] * 3 for i, _ in enumerate(values)])
+        widget.get_color_labels = lambda: merged
+        widget.attr_color = var
+        np.testing.assert_equal(
+            widget.get_palette().palette[:-1],
+            [[var.values.index(label)] * 3 for label in merged[:-1]])
+
 
 class TestableDataProjectionWidget(OWDataProjectionWidget):
     def get_embedding(self):