Search code examples
matlabcallbackmatlab-figuredatatip

Incorrect datatip label during slow datacursormode callback


It is fairly easy to add a custom datatip

f = figure();
plot( 1:100, sort(rand(100,1)) );
dc = datacursormode( f );
set( dc, 'UpdateFcn', @onDataCursorUpdate );

function txt = onDataCursorUpdate( tip, evt )
    txt = {sprintf( 'X: %g', tip.Position(1) ), ...
           sprintf( 'Y: %g', tip.Position(2) )};
end

But the update function might take a while to fetch the datatip info.

In my case, the data I want to include in txt has to be fetched from a database query. I realise that this is inefficient from a performance standpoint, but it is much more memory efficient than storing all possible datatip attributes in memory!

function txt = onDataCursorUpdate( tip, evt )
    info = mySlowQuery( tip.Position ); % fetch some data about this point
    txt = {sprintf( 'X: %g', tip.Position(1) ), ...
           sprintf( 'Y: %g', tip.Position(2) ), ...
           sprintf( 'Info: %s', info )};
end

This query may take minutes(!), and unfortunately MATLAB updates the position of the datatip before updating the label, so you can end up with the following sequence of events:

issue

Is there a way to prevent this happening, so there is no period when the label is incorrect?


Solution

  • You can directly interact with the datatip at the start of the callback to clear the label, then run the body of the callback. The output txt still automatically gets assigned to the datatip String property, but you can manually change it earlier in the function:

    function txt = onDataCursorUpdate( tip, evt )
        % Clear the string first, use "loading..." as placeholder text
        txt = {sprintf( 'X: %g', tip.Position(1) ), ...
               sprintf( 'Y: %g', tip.Position(2) ), ...
               'Info: loading...'};
        tip.String = txt;
        % Now run the slow update
        info = mySlowQuery( tip.Position ); % fetch some data about this point
        txt = {sprintf( 'X: %g', tip.Position(1) ), ...
               sprintf( 'Y: %g', tip.Position(2) ), ...
               sprintf( 'Info: %s', info )};
    end