@@ -80,7 +80,7 @@ class OWtSNE(OWDataProjectionWidget):
8080 embedding_variables_names = ("t-SNE-x" , "t-SNE-y" )
8181
8282 #: Runtime state
83- Running , Finished , Waiting = 1 , 2 , 3
83+ Running , Finished , Waiting , Pending = 1 , 2 , 3 , 4
8484
8585 class Outputs (OWDataProjectionWidget .Outputs ):
8686 preprocessor = Output ("Preprocessor" , Preprocess )
@@ -98,6 +98,7 @@ def __init__(self):
9898 self .pca_data = None
9999 self .projection = None
100100 self .tsne_runner = None
101+ self .tsne_iterator = None
101102 self .__update_loop = None
102103 # timer for scheduling updates
103104 self .__timer = QTimer (self , singleShot = True , interval = 1 ,
@@ -120,31 +121,42 @@ def _add_controls_start_box(self):
120121 )
121122
122123 self .perplexity_spin = gui .spin (
123- box , self , "perplexity" , 1 , 500 , step = 1 , alignment = Qt .AlignRight )
124+ box , self , "perplexity" , 1 , 500 , step = 1 , alignment = Qt .AlignRight ,
125+ callback = self ._params_changed
126+ )
124127 form .addRow ("Perplexity:" , self .perplexity_spin )
128+ self .perplexity_spin .setEnabled (not self .multiscale )
125129 form .addRow (gui .checkBox (
126130 box , self , "multiscale" , label = "Preserve global structure" ,
127131 callback = self ._multiscale_changed
128132 ))
129- self ._multiscale_changed ()
130133
131134 sbe = gui .hBox (self .controlArea , False , addToLayout = False )
132135 gui .hSlider (
133- sbe , self , "exaggeration" , minValue = 1 , maxValue = 4 , step = 1 )
136+ sbe , self , "exaggeration" , minValue = 1 , maxValue = 4 , step = 1 ,
137+ callback = self ._params_changed
138+ )
134139 form .addRow ("Exaggeration:" , sbe )
135140
136141 sbp = gui .hBox (self .controlArea , False , addToLayout = False )
137142 gui .hSlider (
138- sbp , self , "pca_components" , minValue = 2 , maxValue = 50 , step = 1 )
143+ sbp , self , "pca_components" , minValue = 2 , maxValue = 50 , step = 1 ,
144+ callback = self ._params_changed
145+ )
139146 form .addRow ("PCA components:" , sbp )
140147
141148 box .layout ().addLayout (form )
142149
143150 gui .separator (box , 10 )
144151 self .runbutton = gui .button (box , self , "Run" , callback = self ._toggle_run )
145152
153+ def _params_changed (self ):
154+ self .__state = OWtSNE .Finished
155+ self .__set_update_loop (None )
156+
146157 def _multiscale_changed (self ):
147158 self .perplexity_spin .setEnabled (not self .multiscale )
159+ self ._params_changed ()
148160
149161 def check_data (self ):
150162 def error (err ):
@@ -179,6 +191,8 @@ def _toggle_run(self):
179191 if self .__state == OWtSNE .Running :
180192 self .stop ()
181193 self .commit ()
194+ elif self .__state == OWtSNE .Pending :
195+ self .resume ()
182196 else :
183197 self .start ()
184198
@@ -189,8 +203,11 @@ def start(self):
189203 self .__start ()
190204
191205 def stop (self ):
192- if self .__state == OWtSNE .Running :
193- self .__set_update_loop (None )
206+ self .__state = OWtSNE .Pending
207+ self .__set_update_loop (None )
208+
209+ def resume (self ):
210+ self .__set_update_loop (self .tsne_iterator )
194211
195212 def pca_preprocessing (self ):
196213 if self .pca_data is not None and \
@@ -231,13 +248,14 @@ def __start(self):
231248 )(self .pca_data )
232249
233250 self .tsne_runner = TSNERunner (self .projection , step_size = 50 )
234-
235- self .__set_update_loop (self .tsne_runner . run_optimization () )
251+ self . tsne_iterator = self . tsne_runner . run_optimization ()
252+ self .__set_update_loop (self .tsne_iterator )
236253 self .progressBarInit (processEvents = None )
237254
238255 def __set_update_loop (self , loop ):
239256 if self .__update_loop is not None :
240- self .__update_loop .close ()
257+ if self .__state in (OWtSNE .Finished , OWtSNE .Waiting ):
258+ self .__update_loop .close ()
241259 self .__update_loop = None
242260 self .progressBarFinished (processEvents = None )
243261
@@ -253,8 +271,10 @@ def __set_update_loop(self, loop):
253271 else :
254272 self .setBlocking (False )
255273 self .setStatusMessage ("" )
256- self .runbutton .setText ("Start" )
257- self .__state = OWtSNE .Finished
274+ if self .__state in (OWtSNE .Finished , OWtSNE .Waiting ):
275+ self .runbutton .setText ("Start" )
276+ if self .__state == OWtSNE .Pending :
277+ self .runbutton .setText ("Resume" )
258278 self .__timer .stop ()
259279
260280 def __next_step (self ):
@@ -271,13 +291,16 @@ def __next_step(self):
271291 projection , progress = next (self .__update_loop )
272292 assert self .__update_loop is loop
273293 except StopIteration :
294+ self .__state = OWtSNE .Finished
274295 self .__set_update_loop (None )
275296 self .unconditional_commit ()
276297 except MemoryError :
277298 self .Error .out_of_memory ()
299+ self .__state = OWtSNE .Finished
278300 self .__set_update_loop (None )
279301 except Exception as exc :
280302 self .Error .optimization_error (str (exc ))
303+ self .__state = OWtSNE .Finished
281304 self .__set_update_loop (None )
282305 else :
283306 self .progressBarSet (100.0 * progress , processEvents = None )
@@ -319,8 +342,8 @@ def send_preprocessor(self):
319342
320343 def clear (self ):
321344 super ().clear ()
322- self .__set_update_loop (None )
323345 self .__state = OWtSNE .Waiting
346+ self .__set_update_loop (None )
324347 self .pca_data = None
325348 self .projection = None
326349
0 commit comments