@@ -241,6 +241,8 @@ def _add_controls_optimization(self):
241241 sizePolicy = (QSizePolicy .MinimumExpanding , QSizePolicy .Fixed ),
242242 callback = self .__refresh_rate_combo_changed ),
243243 1 , 1 )
244+ self .stress_label = QLabel ("Kruskal Stress: -" )
245+ grid .addWidget (self .stress_label , 2 , 0 , 1 , 3 )
244246
245247 def __refresh_rate_combo_changed (self ):
246248 if self .task is not None :
@@ -392,17 +394,30 @@ def on_partial_result(self, result: Result):
392394 if need_update :
393395 self .graph .update_coordinates ()
394396 self .graph .update_density ()
397+ self .update_stress ()
395398
396399 def on_done (self , result : Result ):
397400 assert isinstance (result .embedding , np .ndarray )
398401 assert len (result .embedding ) == len (self .effective_matrix )
399402 self .embedding = result .embedding
400403 self .graph .update_coordinates ()
401404 self .graph .update_density ()
405+ self .update_stress ()
402406 self .run_button .setText ("Start" )
403407 self .step_button .setEnabled (True )
404408 self .commit .deferred ()
405409
410+ def update_stress (self ):
411+ if self .embedding is None or self .effective_matrix is None :
412+ self .stress_label .setText (f"Kruskal Stress: -" )
413+ return
414+
415+ actual = scipy .spatial .distance .pdist (self .embedding )
416+ actual = scipy .spatial .distance .squareform (actual )
417+ stress = np .sqrt (np .sum ((actual - self .effective_matrix ) ** 2 )
418+ / (np .sum (self .effective_matrix ** 2 ) or 1 ))
419+ self .stress_label .setText (f"Kruskal Stress: { stress :.3f} " )
420+
406421 def on_exception (self , ex : Exception ):
407422 if isinstance (ex , MemoryError ):
408423 self .Error .out_of_memory ()
@@ -436,6 +451,7 @@ def jitter_coord(part):
436451 # (Random or PCA), restarting the optimization if necessary.
437452 if self .effective_matrix is None :
438453 self .graph .reset_graph ()
454+ self .update_stress ()
439455 return
440456
441457 X = self .effective_matrix
@@ -451,6 +467,8 @@ def jitter_coord(part):
451467 # restart the optimization if it was interrupted.
452468 if self .task is not None :
453469 self ._run ()
470+ else :
471+ self .update_stress ()
454472
455473 def handleNewSignals (self ):
456474 self ._initialize ()
0 commit comments