99from PyQt5 .QtGui import QFont
1010from PyQt5 .QtWidgets import QHBoxLayout , QLabel , QProgressBar , QVBoxLayout , QWidget
1111
12+ from ..logging_utils import get_sweep_logger
13+
1214# Configure PyQtGraph for better performance
1315pg .setConfigOptions (
1416 antialias = False , # Disable antialiasing for better performance
@@ -82,6 +84,7 @@ def __init__(self, sweep, plot_bin=1):
8284 self .last_pass = False
8385 self .figs_set = False
8486 self .kill_flag = False
87+ self .logger = getattr (sweep , "logger" , None ) or get_sweep_logger ("plotter" )
8588
8689 # PyQtGraph-specific attributes
8790 self .widget = None
@@ -284,7 +287,11 @@ def create_figs(self):
284287 self .widget .closeEvent = self .handle_close
285288
286289 # Show the widget
287- self .widget .show ()
290+ try :
291+ self .widget .show ()
292+ except Exception as e :
293+ self ._disable_plotting (f"Plotter widget failed to show: { e } " )
294+ return
288295
289296 @pyqtSlot (object , int )
290297 def add_data (self , data , direction ):
@@ -297,11 +304,16 @@ def add_data(self, data, direction):
297304 direction:
298305 The direction of the sweep (0 or 1).
299306 """
300- self .data_queue .append ((data , direction ))
307+ if self .kill_flag :
308+ return
309+ try :
310+ self .data_queue .append ((data , direction ))
301311
302- # Only update plots when we have enough data points or it's been a while
303- # This prevents excessive update calls that slow down the plotting
304- self .update_plots (force = data is None )
312+ # Only update plots when we have enough data points or it's been a while
313+ # This prevents excessive update calls that slow down the plotting
314+ self .update_plots (force = data is None )
315+ except Exception as e :
316+ self ._disable_plotting (f"Plotter add_data failed: { e } " )
305317
306318 @pyqtSlot (bool )
307319 def update_plots (self , force = False ):
@@ -313,79 +325,83 @@ def update_plots(self, force=False):
313325 force:
314326 If True, process all queued data immediately.
315327 """
316- if not self .figs_set :
317- return
318-
319- # Check if we should update - either we have enough data or force is True
320- if len (self .data_queue ) < self .plot_bin and not force :
328+ if not self .figs_set or self .kill_flag :
321329 return
322-
323- # Process all queued data at once for better performance
324- while len (self .data_queue ) > 0 :
325- temp = self .data_queue .popleft ()
326- if temp [0 ] is None :
327- break
328- data = deque (temp [0 ])
329- direction = temp [1 ]
330-
331- # Get time data
332- time_data = data .popleft ()
333-
334- # Handle set parameter plot
335- set_param_data = None
336- if self .sweep .set_param is not None :
337- set_param_data = data .popleft ()
338-
339- # Add to set parameter data arrays
340- # Ensure scalars by flattening any arrays
341- time_val = time_data [1 ]
342- if hasattr (time_val , "flatten" ):
343- time_val = float (np .array (time_val ).flatten ()[0 ])
344-
345- set_val = set_param_data [1 ]
346- if hasattr (set_val , "flatten" ):
347- set_val = float (np .array (set_val ).flatten ()[0 ])
348-
349- self .set_data_arrays ["x" ].append (time_val )
350- self .set_data_arrays ["y" ].append (set_val )
351-
352- # Determine x-axis data for followed parameters
353- x_data_value = (
354- time_data [1 ]
355- if self .sweep .x_axis == 1
356- else (
357- set_param_data [1 ]
358- if self .sweep .set_param is not None
359- else time_data [1 ]
330+ try :
331+ # Check if we should update - either we have enough data or force is True
332+ if len (self .data_queue ) < self .plot_bin and not force :
333+ return
334+
335+ # Process all queued data at once for better performance
336+ while len (self .data_queue ) > 0 :
337+ temp = self .data_queue .popleft ()
338+ if temp [0 ] is None :
339+ break
340+ data = deque (temp [0 ])
341+ direction = temp [1 ]
342+
343+ # Get time data
344+ time_data = data .popleft ()
345+
346+ # Handle set parameter plot
347+ set_param_data = None
348+ if self .sweep .set_param is not None :
349+ set_param_data = data .popleft ()
350+
351+ # Add to set parameter data arrays
352+ # Ensure scalars by flattening any arrays
353+ time_val = time_data [1 ]
354+ if hasattr (time_val , "flatten" ):
355+ time_val = float (np .array (time_val ).flatten ()[0 ])
356+
357+ set_val = set_param_data [1 ]
358+ if hasattr (set_val , "flatten" ):
359+ set_val = float (np .array (set_val ).flatten ()[0 ])
360+
361+ self .set_data_arrays ["x" ].append (time_val )
362+ self .set_data_arrays ["y" ].append (set_val )
363+
364+ # Determine x-axis data for followed parameters
365+ x_data_value = (
366+ time_data [1 ]
367+ if self .sweep .x_axis == 1
368+ else (
369+ set_param_data [1 ]
370+ if self .sweep .set_param is not None
371+ else time_data [1 ]
372+ )
360373 )
361- )
362- # Ensure x_data_value is scalar
363- if hasattr (x_data_value , "flatten" ):
364- x_data_value = float (np .array (x_data_value ).flatten ()[0 ])
374+ # Ensure x_data_value is scalar
375+ if hasattr (x_data_value , "flatten" ):
376+ x_data_value = float (np .array (x_data_value ).flatten ()[0 ])
365377
366- # Add data to arrays for followed parameters
367- for i , data_pair in enumerate (data ):
368- param = self .sweep ._params [i ]
378+ # Add data to arrays for followed parameters
379+ for i , data_pair in enumerate (data ):
380+ param = self .sweep ._params [i ]
369381
370- if param in self .data_arrays :
371- direction_key = "forward" if direction == 0 else "backward"
382+ if param in self .data_arrays :
383+ direction_key = "forward" if direction == 0 else "backward"
372384
373- # Ensure y_data is scalar
374- y_value = data_pair [1 ]
375- if hasattr (y_value , "flatten" ):
376- y_value = float (np .array (y_value ).flatten ()[0 ])
385+ # Ensure y_data is scalar
386+ y_value = data_pair [1 ]
387+ if hasattr (y_value , "flatten" ):
388+ y_value = float (np .array (y_value ).flatten ()[0 ])
377389
378- self .data_arrays [param ][direction_key ]["x" ].append (x_data_value )
379- self .data_arrays [param ][direction_key ]["y" ].append (y_value )
390+ self .data_arrays [param ][direction_key ]["x" ].append (x_data_value )
391+ self .data_arrays [param ][direction_key ]["y" ].append (y_value )
380392
381- # Now update all plots at once (much more efficient)
382- self ._update_plot_displays ()
383- self .update_progress_widgets ()
393+ # Now update all plots at once (much more efficient)
394+ self ._update_plot_displays ()
395+ self .update_progress_widgets ()
396+ except Exception as e :
397+ self ._disable_plotting (f"Plotter update_plots failed: { e } " )
384398
385399 def _update_plot_displays (self ):
386400 """Efficiently updates all plot displays using stored data arrays.
387401 Optimized for large datasets - converts to numpy arrays efficiently.
388402 """
403+ if self .kill_flag :
404+ return
389405 # Update set parameter plot
390406 if self .sweep .set_param is not None and self .set_plot_item is not None :
391407 if self .set_data_arrays ["x" ] and self .set_data_arrays ["y" ]:
@@ -497,6 +513,23 @@ def get_plot_data(self, param_index):
497513 }
498514 return None
499515
516+ def _disable_plotting (self , reason : str ):
517+ """Disable plotting after an exception and log the error."""
518+ try :
519+ self .logger .error (reason , exc_info = True )
520+ except Exception :
521+ pass
522+ self .kill_flag = True
523+ try :
524+ self .sweep .plot_data = False
525+ except Exception :
526+ pass
527+ try :
528+ if self .figs_set :
529+ self .clear ()
530+ except Exception :
531+ pass
532+
500533 @pyqtSlot ()
501534 def run (self ):
502535 """Creates figures if they have not already been set."""
0 commit comments