11from collections import defaultdict , namedtuple
2+ from contextlib import contextmanager
23from typing import Optional
34from xml .sax .saxutils import escape
45
@@ -171,6 +172,15 @@ def paint(self, painter, _option, _index):
171172 painter .restore ()
172173
173174
175+ @contextmanager
176+ def disconnected_spin (spin ):
177+ spin .blockSignals (True )
178+ try :
179+ yield
180+ finally :
181+ spin .blockSignals (False )
182+
183+
174184N_ITERATIONS = 200
175185
176186
@@ -209,6 +219,12 @@ class Outputs:
209219 ("shape" , "auto_dim" , "spin_x" , "spin_y" , "initialization" , "start" )
210220 )
211221
222+ class Information (OWWidget .Information ):
223+ modified = Msg (
224+ 'The parameter settings have been changed. Press "Start" to '
225+ "rerun with the new settings."
226+ )
227+
212228 class Warning (OWWidget .Warning ):
213229 ignoring_disc_variables = Msg ("SOM ignores categorical variables." )
214230 missing_colors = \
@@ -243,34 +259,48 @@ def __init__(self):
243259 shape = gui .comboBox (
244260 box , self , "" , items = ("Hexagonal grid" , "Square grid" ))
245261 shape .setCurrentIndex (1 - self .hexagonal )
262+ shape .currentIndexChanged .connect (self .on_parameter_change )
246263
247264 box2 = gui .indentedBox (box , 10 )
248265 auto_dim = gui .checkBox (
249266 box2 , self , "auto_dimension" , "Set dimensions automatically" ,
250267 callback = self .on_auto_dimension_changed )
251268 self .manual_box = box3 = gui .hBox (box2 )
252269 spinargs = dict (
253- value = "" , widget = box3 , master = self , minv = 5 , maxv = 100 , step = 5 ,
254- alignment = Qt .AlignRight )
255- spin_x = gui .spin (** spinargs )
256- spin_x .setValue (self .size_x )
270+ value = "" ,
271+ widget = box3 ,
272+ master = self ,
273+ minv = 5 ,
274+ maxv = 100 ,
275+ step = 5 ,
276+ alignment = Qt .AlignRight ,
277+ callback = self .on_parameter_change ,
278+ )
279+ self .spin_x = gui .spin (** spinargs )
280+ with disconnected_spin (self .spin_x ):
281+ self .spin_x .setValue (self .size_x )
257282 gui .widgetLabel (box3 , "×" )
258- spin_y = gui .spin (** spinargs )
259- spin_y .setValue (self .size_y )
283+ self .spin_y = gui .spin (** spinargs )
284+ with disconnected_spin (self .spin_y ):
285+ self .spin_y .setValue (self .size_y )
260286 gui .rubber (box3 )
261287 self .manual_box .setEnabled (not self .auto_dimension )
262288
263289 initialization = gui .comboBox (
264- box , self , "initialization" ,
265- items = ("Initialize with PCA" , "Random initialization" ,
266- "Replicable random" ))
290+ box ,
291+ self ,
292+ "initialization" ,
293+ items = ("Initialize with PCA" , "Random initialization" , "Replicable random" ),
294+ callback = self .on_parameter_change ,
295+ )
267296
268297 start = gui .button (
269298 box , self , "Restart" , callback = self .restart_som_pressed ,
270299 sizePolicy = (QSizePolicy .MinimumExpanding , QSizePolicy .Fixed ))
271300
272301 self .opt_controls = self .OptControls (
273- shape , auto_dim , spin_x , spin_y , initialization , start )
302+ shape , auto_dim , self .spin_x , self .spin_y , initialization , start
303+ )
274304
275305 box = gui .vBox (self .controlArea , "Color" )
276306 gui .comboBox (
@@ -366,7 +396,8 @@ def set_warnings():
366396 self .set_color_bins ()
367397 self .create_legend ()
368398 if invalidated :
369- self .recompute_dimensions ()
399+ with disconnected_spin (self .spin_x ), disconnected_spin (self .spin_y ):
400+ self .recompute_dimensions ()
370401 self .start_som ()
371402 else :
372403 self ._redraw ()
@@ -399,6 +430,7 @@ def on_auto_dimension_changed(self):
399430 dimy = int (5 * np .round (spin_y .value () / 5 ))
400431 spin_x .setValue (dimx )
401432 spin_y .setValue (dimy )
433+ self .on_parameter_change ()
402434
403435 def on_attr_color_change (self ):
404436 self .controls .pie_charts .setEnabled (self .attr_color is not None )
@@ -413,6 +445,9 @@ def on_attr_size_change(self):
413445 def on_pie_chart_change (self ):
414446 self ._redraw ()
415447
448+ def on_parameter_change (self ):
449+ self .Information .modified ()
450+
416451 def clear_selection (self ):
417452 self .selection = None
418453 self .redraw_selection ()
@@ -498,6 +533,7 @@ def redraw_selection(self, marks=None):
498533 cell .setZValue (marked or sel_group )
499534
500535 def restart_som_pressed (self ):
536+ self .Information .modified .clear ()
501537 if self ._optimizer_thread is not None :
502538 self .stop_optimization = True
503539 self ._optimizer .stop_optimization = True
0 commit comments