Intermittent bug in levelsplot()
Sometimes levelsplot() throws the follow errors when mouse is moved over figure window:
Invalid or deleted object. Error in levelsplot Error while evaluating Figure WindowButtonMotionFcn
No lines are highlited, of course. The bug does not seem to be reproducible. I cannot find unambiguous conditions when it occurs, but such behaviour is kept until MATLAB rebooting.
This is likely due to the persistent variable hPrevLine in the function windowButtonMotionFcn. There might be situations where the object referenced by hPrevLine is no longer valid.
Can you find a way to reproduce this error?
The issue arises from a timing mismatch between the WindowButtonMotionFcn callback and the lifecycle of MATLAB graphic objects. Closing the figure or clearing objects while the callback runs causes an "Invalid or deleted object" error when accessing deleted objects.
The root cause is a persistent variable storing a handle to a deleted object. Eliminating the persistent variable and using findobj to dynamically retrieve objects during each callback ensures operations are performed only on existing objects, preventing errors and improving robustness. MATLAB strongly discourages the use of persistent variables due to risks of unintended global modifications or leaks into other functions. Passing parameters between functions is generally safer and more convenient.
Here is an example of the fixed code:
%------------------------------------------------------------------------------- function windowButtonMotionFcn(~,~,~)
% Line width settings hoverLineWidth = 2; defaultLineWidth = 0.5;
% Get object under mouse pointer hObj = hittest(); if isempty(hObj), return; end
% Get parent axes hParent = ancestor(hObj,'axes'); if isempty(hParent), return; end
% Reset all previously highlighted lines to default width hFig = ancestor(hObj,'figure'); allLines = findobj(hFig,'-property','LineWidth','-and',{'Tag','level','-or','Tag','transition'}); set(allLines,'LineWidth',defaultLineWidth);
% Generate information string based on object type switch hObj.Tag case 'level' infostr = sprintf(' level %d',hObj.UserData); hObj.LineWidth = hoverLineWidth; case 'transition' infostr = sprintf(' transition %d-%d: %0.2f mT, relative intensity %0.4f ',... hObj.UserData(1),hObj.UserData(2),hObj.UserData(3),hObj.UserData(4)); hObj.LineWidth = hoverLineWidth; case 'line' infostr = sprintf(' transition %d-%d: %0.2f mT, relative intensity %0.4f ',... hObj.UserData(1),hObj.UserData(2),hObj.UserData(3),hObj.UserData(4)); hObj.LineWidth = hoverLineWidth; otherwise infostr = ''; end
% Display information text hText = findobj(hParent,'Tag','infotext'); if ~isempty(hText) set(hText,'String',infostr); % Update text position to keep it visible after zooming if ~isempty(infostr) hText.Position(1:2) = [hParent.XLim(1) hParent.YLim(1)]; end end
end