@@ -34,9 +34,16 @@ class Inputs:
3434 class Outputs :
3535 distances = Output ("Distances" , Orange .misc .DistMatrix , dynamic = False )
3636
37- axis = settings .Setting (0 )
38- metric_idx = settings .Setting (0 )
39- autocommit = settings .Setting (True )
37+ settings_version = 2
38+
39+ axis = settings .Setting (0 ) # type: int
40+ metric_idx = settings .Setting (0 ) # type: int
41+
42+ #: Use normalized distances if the metric supports it.
43+ #: The default is `True`, expect when restoring from old pre v2 settings
44+ #: (see `migrate_settings`).
45+ normalized_dist = settings .Setting (True ) # type: bool
46+ autocommit = settings .Setting (True ) # type: bool
4047
4148 want_main_area = False
4249 buttons_area_orientation = Qt .Vertical
@@ -59,11 +66,21 @@ def __init__(self):
5966 gui .radioButtons (self .controlArea , self , "axis" , ["Rows" , "Columns" ],
6067 box = "Distances between" , callback = self ._invalidate
6168 )
62- self .metrics_combo = gui .comboBox (self .controlArea , self , "metric_idx" ,
63- box = "Distance Metric" ,
64- items = [m [0 ] for m in METRICS ],
65- callback = self ._invalidate
66- )
69+ box = gui .widgetBox (self .controlArea , "Distance Metric" )
70+ self .metrics_combo = gui .comboBox (
71+ box , self , "metric_idx" ,
72+ items = [m [0 ] for m in METRICS ],
73+ callback = self ._metric_changed
74+ )
75+ self .normalization_check = gui .checkBox (
76+ box , self , "normalized_dist" , "Normalized" ,
77+ callback = self ._invalidate ,
78+ tooltip = ("All dimensions are (implicitly) scaled to a common"
79+ "scale to normalize the influence across the domain." )
80+ )
81+ _ , metric = METRICS [self .metric_idx ]
82+ self .normalization_check .setEnabled (metric .supports_normalization )
83+
6784 gui .auto_commit (self .controlArea , self , "autocommit" , "Apply" )
6885 self .layout ().setSizeConstraint (self .layout ().SetFixedSize )
6986
@@ -118,7 +135,11 @@ def _fix_missing():
118135 if check () is False :
119136 return
120137 try :
121- return metric (data , axis = 1 - self .axis , impute = True )
138+ if metric .supports_normalization and self .normalized_dist :
139+ return metric (data , axis = 1 - self .axis , impute = True ,
140+ normalize = True )
141+ else :
142+ return metric (data , axis = 1 - self .axis , impute = True )
122143 except ValueError as e :
123144 self .Error .distances_value_error (e )
124145 except MemoryError :
@@ -127,9 +148,21 @@ def _fix_missing():
127148 def _invalidate (self ):
128149 self .commit ()
129150
151+ def _metric_changed (self ):
152+ metric = METRICS [self .metric_idx ][1 ]
153+ self .normalization_check .setEnabled (metric .supports_normalization )
154+ self ._invalidate ()
155+
130156 def send_report (self ):
131157 # pylint: disable=invalid-sequence-index
132158 self .report_items ((
133159 ("Distances Between" , ["Rows" , "Columns" ][self .axis ]),
134160 ("Metric" , METRICS [self .metric_idx ][0 ])
135161 ))
162+
163+ @classmethod
164+ def migrate_settings (cls , settings , version ):
165+ if version is None or version < 2 and "normalized_dist" not in settings :
166+ # normalize_dist is set to False when restoring settings from
167+ # an older version to preserve old semantics.
168+ settings ["normalized_dist" ] = False
0 commit comments