Repository: biolab/orange3

Issue:
Nomogram: scale not showing for normalized continuous variables
<!-- 
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 (```). -->
When passing normalized data to Logistic Regression and then to Nomogram, Nomogram fails to show the scale for continuous data.
It happens for Normalize and Impute preprocessors.
Coefficients look ok.
Naive Bayes is ok.

<img width="805" alt="Screen Shot 2021-03-18 at 16 32 37" src="https://user-images.githubusercontent.com/12524972/111652702-9459e500-8807-11eb-9782-e1e60262b7a3.png">



- [ ] **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...) -->
File (heart-disease) - Preprocess (normalize or impute) - Logistic Regression - Nomogram.




- [ ] **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.29.dev
- How you installed Orange: git



Discussion:

Resolving patch:
diff --git a/Orange/widgets/visualize/ownomogram.py b/Orange/widgets/visualize/ownomogram.py
--- a/Orange/widgets/visualize/ownomogram.py
+++ b/Orange/widgets/visualize/ownomogram.py
@@ -1285,6 +1285,7 @@ def reconstruct_domain(original, preprocessed):
         for attr in preprocessed.attributes:
             cv = attr._compute_value.variable._compute_value
             var = cv.variable if cv else original[attr.name]
+            var = original[var.name] if var.name in original else attr
             if var in attrs:    # the reason for OrderedDict
                 continue
             attrs[var] = None   # we only need keys


Test patch:
diff --git a/Orange/widgets/visualize/tests/test_ownomogram.py b/Orange/widgets/visualize/tests/test_ownomogram.py
--- a/Orange/widgets/visualize/tests/test_ownomogram.py
+++ b/Orange/widgets/visualize/tests/test_ownomogram.py
@@ -13,6 +13,7 @@
 from Orange.classification import (
     NaiveBayesLearner, LogisticRegressionLearner, MajorityLearner
 )
+from Orange.preprocess import Scale, Continuize
 from Orange.tests import test_filename
 from Orange.widgets.tests.base import WidgetTest
 from Orange.widgets.utils.state_summary import format_summary_details
@@ -306,6 +307,28 @@ def test_dots_stop_flashing(self):
         anim = animator._GraphicsColorAnimator__animation
         self.assertNotEqual(anim.state(), QPropertyAnimation.Running)
 
+    def test_reconstruct_domain(self):
+        data = Table("heart_disease")
+        cls = LogisticRegressionLearner()(data)
+        domain = OWNomogram.reconstruct_domain(cls.original_domain, cls.domain)
+        transformed_data = cls.original_data.transform(domain)
+        self.assertEqual(transformed_data.X.shape, data.X.shape)
+        self.assertFalse(np.isnan(transformed_data.X[0]).any())
+
+        scaled_data = Scale()(data)
+        cls = LogisticRegressionLearner()(scaled_data)
+        domain = OWNomogram.reconstruct_domain(cls.original_domain, cls.domain)
+        transformed_data = cls.original_data.transform(domain)
+        self.assertEqual(transformed_data.X.shape, scaled_data.X.shape)
+        self.assertFalse(np.isnan(transformed_data.X[0]).any())
+
+        disc_data = Continuize()(data)
+        cls = LogisticRegressionLearner()(disc_data)
+        domain = OWNomogram.reconstruct_domain(cls.original_domain, cls.domain)
+        transformed_data = cls.original_data.transform(domain)
+        self.assertEqual(transformed_data.X.shape, disc_data.X.shape)
+        self.assertFalse(np.isnan(transformed_data.X[0]).any())
+
 
 if __name__ == "__main__":
     unittest.main()