Repository: biolab/orange3

Issue:
by default display labels in the distance matrix
**What's your use case?**

By default, Distance Matrix enumerates columns and rows. If labels are provided, one would expect that that would be the default setting. Now that the hierarchical clustering is changed similarly, we could make the Distance Matrix behave like this as well.

**What's your proposed solution?**
When the input data contains a label (a single string-typed meta feature), Distance Matrix should display these labels for default. Perhaps copy the solution from the new version of Hierarchical Clustering.

![image](https://user-images.githubusercontent.com/726604/204520909-9c2bc4e8-fdb9-44c8-9f7a-aa7239645c0f.png)


Discussion:

Resolving patch:
diff --git a/Orange/widgets/unsupervised/owdistancematrix.py b/Orange/widgets/unsupervised/owdistancematrix.py
--- a/Orange/widgets/unsupervised/owdistancematrix.py
+++ b/Orange/widgets/unsupervised/owdistancematrix.py
@@ -252,8 +252,7 @@ def set_distances(self, distances):
         elif isinstance(items, Table):
             annotations.extend(
                 itertools.chain(items.domain.variables, items.domain.metas))
-            if items.domain.class_var:
-                pending_idx = 2 + len(items.domain.attributes)
+            pending_idx = annotations.index(self._choose_label(items))
         self.annot_combo.model()[:] = annotations
         self.annotation_idx = pending_idx
 
@@ -263,6 +262,14 @@ def set_distances(self, distances):
             self.tableview.resizeColumnsToContents()
         self.commit.now()
 
+    @staticmethod
+    def _choose_label(data: Table):
+        attr = max((attr for attr in data.domain.metas
+                    if isinstance(attr, StringVariable)),
+                   key=lambda x: len(set(data.get_column(x))),
+                   default=None)
+        return attr or data.domain.class_var or "Enumerate"
+
     def _invalidate_annotations(self):
         if self.distances is not None:
             self._update_labels()


Test patch:
diff --git a/Orange/widgets/unsupervised/tests/test_owdistancematrix.py b/Orange/widgets/unsupervised/tests/test_owdistancematrix.py
--- a/Orange/widgets/unsupervised/tests/test_owdistancematrix.py
+++ b/Orange/widgets/unsupervised/tests/test_owdistancematrix.py
@@ -84,6 +84,30 @@ def test_num_meta_labels(self):
         ac.activated.emit(idx)
         self.assertEqual(self.widget.tablemodel.labels, ["1", "?"])
 
+    def test_choose_label(self):
+        self.assertIs(OWDistanceMatrix._choose_label(self.iris),
+                      self.iris.domain.class_var)
+
+        domain = Domain([ContinuousVariable(x) for x in "xyz"],
+                        ContinuousVariable("t"),
+                        [ContinuousVariable("m")] +
+                        [StringVariable(c) for c in "abc"]
+                        )
+        data = Table.from_numpy(
+            domain,
+            np.zeros((4, 3), dtype=float),
+            np.arange(4, dtype=float),
+            np.array([[0, "a", "a", "a"],
+                      [1, "b", "b", "b"],
+                      [2, "a", "c", "b"],
+                      [0, "b", "a", "a"]])
+        )
+        self.assertIs(OWDistanceMatrix._choose_label(data),
+                      domain.metas[2])
+        domain2 = Domain(domain.attributes, domain.class_var, domain.metas[:-2])
+        self.assertIs(OWDistanceMatrix._choose_label(data.transform(domain2)),
+                      domain.metas[1])
+
 
 class TestDelegates(GuiTest):
     def test_delegate(self):