Repository: biolab/orange3

Issue:
Tree Viewer: a way to show variable names
<!-- 
Thanks for taking the time to report a bug!
If you're raising an issue about an add-on (i.e., installed via Options > Add-ons), raise an issue in the relevant add-on's issue tracker instead. See: https://github.com/biolab?q=orange3
To fix the bug, we need to be able to reproduce it. Please answer the following questions to the best of your ability.
-->


**What's wrong?**
<!-- Be specific, clear, and concise. Include screenshots if relevant. -->
<!-- If you're getting an error message, copy it, and enclose it with three backticks (```). -->
It is difficult to see long variable names in Tree Viewer. I absolutely love the fact that the tooltips of children show a summary of the Tree (they show splits). So showing variable names if hovering over them would probably conflict with existing tooltips.

Can we think of a solution?




**How can we reproduce the problem?** 
<!-- Upload a zip with the .ows file and data. -->
<!-- Describe the steps (open this widget, click there, then add this...) -->
Datasets (HDI) - Tree (predict a continent or a Cluster) - Tree Viewer
<img width="865" alt="Screen Shot 2022-03-03 at 20 42 02" src="https://user-images.githubusercontent.com/12524972/156640576-ec4431cf-bfcd-4728-b02e-b23dbe6891d3.png">




**What's your environment?**
<!-- To find your Orange version, see "Help → About → Version" or `Orange.version.full_version` in code -->
- Operating system: OSX
- Orange version: 3.32.dev
- How you installed Orange: pip



Discussion:

Resolving patch:
diff --git a/Orange/widgets/visualize/owtreeviewer.py b/Orange/widgets/visualize/owtreeviewer.py
--- a/Orange/widgets/visualize/owtreeviewer.py
+++ b/Orange/widgets/visualize/owtreeviewer.py
@@ -1,4 +1,6 @@
 """Widget for visualization of tree models"""
+from html import escape
+
 import numpy as np
 
 from AnyQt.QtWidgets import (
@@ -18,6 +20,7 @@
     GraphicsNode, GraphicsEdge, OWTreeViewer2D
 from Orange.widgets.utils import to_html
 from Orange.data import Table
+from Orange.util import color_to_hex
 
 from Orange.widgets.settings import ContextSetting, ClassValuesContextHandler, \
     Setting
@@ -325,9 +328,36 @@ def walkcreate(self, node, parent=None):
         return node_obj
 
     def node_tooltip(self, node):
-        return "<p>" + "<br>".join(
-            to_html(str(rule))
-            for rule in self.tree_adapter.rules(node.node_inst)) + "</p>"
+        # We uses <br/> and &nbsp: styling of <li> in Qt doesn't work well
+        indent = "&nbsp;&nbsp;&nbsp;"
+        nbp = "<p style='white-space:pre'>"
+
+        rule = "<br/>".join(f"{indent}– {to_html(str(rule))}"
+                            for rule in self.tree_adapter.rules(node.node_inst))
+        if rule:
+            rule = f"<p><b>Selection</b></p><p>{rule}</p>"
+
+        distr = self.tree_adapter.get_distribution(node.node_inst)[0]
+        class_var = self.domain.class_var
+        name = escape(class_var.name)
+        if self.domain.class_var.is_discrete:
+            total = float(sum(distr)) or 1
+            content = f"{nbp}<b>Distribution of</b> '{name}'</p><p>" \
+                + "<br/>".join(
+                    f"{indent}<span style='color: {color_to_hex(color)}'>◼</span> "
+                    f"{escape(value)}: {prop:g} ({prop / total * 100:.1f} %)"
+                    for value, color, prop
+                    in zip(class_var.values, class_var.colors, distr)) \
+                + "</p>"
+        else:
+            mean, var = distr
+            content = f"{nbp}{class_var.name} = {mean:.3g} ± {var:.3g}<br/>" + \
+                f"({self.tree_adapter.num_samples(node.node_inst)} instances)</p>"
+
+        split = self._update_node_info_attr_name(node, "")
+        if split:
+            split = f"<p style='white-space:pre'><b>Next split: </b>{split}</p>"
+        return "<hr/>".join(filter(None, (rule, content, split)))
 
     def update_selection(self):
         if self.model is None:
diff --git a/Orange/widgets/visualize/owtreeviewer2d.py b/Orange/widgets/visualize/owtreeviewer2d.py
--- a/Orange/widgets/visualize/owtreeviewer2d.py
+++ b/Orange/widgets/visualize/owtreeviewer2d.py
@@ -418,6 +418,10 @@ def __init__(self):
 
         self.scene = TreeGraphicsScene(self)
         self.scene_view = TreeGraphicsView(self.scene)
+        self.scene_view.setStyleSheet("""QToolTip { padding: 3px;
+                                                    border: 1px solid #C0C0C0;
+                                      }""")
+
         self.scene_view.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
         self.mainArea.layout().addWidget(self.scene_view)
         self.toggle_zoom_slider()


Test patch: