Controlling plot data-tips

Plot data tips are a great visualization aid for Matlab plots. They enable users to interactively click on a plot location and see a tool-tip that contains the clicked location’s coordinates. The displayed tooltip text is even customizable using documented properties of the datacursormode object.

plot data tips

plot data tips

A client has recently asked me to automatically display an attached data-tip to the last data point of a plotted time series of values. The idea was to immediately see what the latest value of the data series is.

Unfortunately, the official documentation clearly says that:

You place data tips only by clicking data objects on graphs. You cannot place them programmatically (by executing code to position a data cursor).

Well, this has never stopped us before, has it?

Creating new data tips

Under the hood, data tips use a data-cursor mode, which shares many similarities in behavior and programming code with the other plot modes (zoom, pan, data-brushing, etc.). At any one time, only a single such mode can be active in any figure window (this is a known limitation of the design). The code itself it actually quite complex and handles numerous edge-cases. Understanding it by simply reading the code (under %matlabroot%\toolbox\matlab\graphics\) is actually pretty difficult. A much easier way to understand the programming flow is to liberally distribute breakpoints (start in datacursormode.m) and interactively activate the functionality, then debug the code step-by-step.

Luckily, it turns out that the code to create a new data-tip is actually quite simple: first get the data-cursor mode object, then create a new data tip using the mode’s createDatatip() method, update some data-tip properties and finally update the data-tip’s position:

% First plot the data
hLine = plot(xdata, ydata);
% First get the figure's data-cursor mode, activate it, and set some of its properties
cursorMode = datacursormode(gcf);
set(cursorMode, 'enable','on', 'UpdateFcn',@setDataTipTxt);
% Note: the optional @setDataTipTxt is used to customize the data-tip's content text
% Note: the following code was adapted from %matlabroot%\toolbox\matlab\graphics\datacursormode.m
% Create a new data tip
hTarget = handle(hLine);
hDatatip = cursorMode.createDatatip(hTarget);
% Create a copy of the context menu for the datatip:
% Set the data-tip orientation to top-right rather than auto
% Update the datatip marker appearance
set(hDatatip, 'MarkerSize',5, 'MarkerFaceColor','none', ...
              'MarkerEdgeColor','k', 'Marker','o', 'HitTest','off');
% Move the datatip to the right-most data vertex point
position = [xdata(end),ydata(end),1; xdata(end),ydata(end),-1];
update(hDatatip, position);

Note: If you don’t like messing with the code, consider using Tim Farajian’s MakeDataTip utility, which basically does all this behind the scenes. It is much easier to use as a stand-alone utility, although it does not give you the flexiblility with all the data-tip properties as in the code above.

Updating an existing data tip

To modify the appearance of a data-tip, we first need to get access to the hDatatip object that we created earlier, either programmatically, or interactively (or both). Since we can access pre-stored handles only of programmatically-created (not interactively-created) data-tips, we need to use a different method. There are actually two ways to do this:

The basic way is to search the relevant axes for objects that have Tag=’DataTipMarker’. For each data-tip, we will get two such handles: one for the marker (Type=’line’) and the other for the text box tooltip (Type=’text’). We can use these to update (for example) the marker size, color and style; and the text’s font, border and colors.

A better way is to access the graphics.datatip object itself. This can be done using two hidden properties of the datacursormode object:

% Get the list of all data-tips in the current figure
>> cursorMode = datacursormode(gcf)
cursorMode =
>> cursorMode.DataCursors
ans =
	graphics.datatip: 2-by-1
>> cursorMode.CurrentDataCursor
ans =
>> cursorMode.CurrentDataCursor.get
            Annotation: [1x1 hg.Annotation]
           DisplayName: ''
           HitTestArea: 'off'
          BeingDeleted: 'off'
         ButtonDownFcn: []
              Children: [2x1 double]
              Clipping: 'on'
             CreateFcn: []
             DeleteFcn: []
            BusyAction: 'queue'
      HandleVisibility: 'off'
               HitTest: 'off'
         Interruptible: 'on'
                Parent: 492.005493164063
    SelectionHighlight: 'on'
                   Tag: ''
                  Type: 'hggroup'
              UserData: []
              Selected: 'off'
             FontAngle: 'normal'
              FontName: 'Helvetica'
              FontSize: 8
             FontUnits: 'points'
            FontWeight: 'normal'
             EdgeColor: [0.8 0.8 0.8]
       BackgroundColor: [1 1 0.933333333333333]
             TextColor: [0 0 0]
                Marker: 'o'
            MarkerSize: 5
       MarkerEdgeColor: 'k'
       MarkerFaceColor: 'none'
       MarkerEraseMode: 'normal'
             Draggable: 'on'
                String: {'Date: 01/09/11'  'Value: 573.24'}
               Visible: 'on'
             StringFcn: []
             UpdateFcn: []
         UIContextMenu: [1x1 uicontextmenu]
                  Host: [1x1 graph2d.lineseries]
           Interpolate: 'off'

We can see that the returned graphics.datatip object includes properties of both the text-box and the marker, making it easy to modify. Moreover, we can use its aforementioned update method to move the datatip to a different plot position (see example in the code above). In addition, we can also use the self-explanatory getCursorInfo(), getaxes(), makeCurrent(), movetofront() methods, and a few others.

Cursor mode and data-tip properties

The graphics.datacursormanager and the graphics.datatip objects have several public properties that we can use:

>> cursorMode.get
              Enable: 'off'
    SnapToDataVertex: 'on'
        DisplayStyle: 'datatip'
           UpdateFcn: @setDataTipTxt
              Figure: [1x1 figure]
>> cursorMode.CurrentDataCursor.get
            Annotation: [1x1 hg.Annotation]
           DisplayName: ''
           HitTestArea: 'off'
      ... % See the list above

Both these objects have plenty of additional hidden properties. You can inspect them using my uiinspect utility. Here is a brief list for reference (R2011b):


  • CurrentDataCursor
  • DataCursors
  • Debug
  • DefaultExportVarName
  • DefaultPanelPosition
  • EnableAxesStacking
  • EnableZStacking
  • ExternalListeners
  • HiddenUpdateFcn
  • NewDataCursorOnClick
  • OriginalRenderer
  • OriginalRendererMode
  • PanelDatatipHandle
  • PanelHandle
  • PanelTextHandle
  • UIContextMenu
  • UIState
  • ZStackMinimum


  • ALimInclude
  • ApplicationData
  • Behavior
  • CLimInclude
  • DataCursorHandle
  • DataManagerHandle
  • Debug
  • DoThrowStartDragEvent
  • EmptyArgUpdateFcn
  • EnableAxesStacking
  • EnableZStacking
  • EraseMode
  • EventObject
  • ExternalListenerHandles
  • HelpTopicKey
  • HostAxes
  • HostListenerHandles
  • IncludeRenderer
  • Invalid
  • IsDeserializing
  • MarkerHandle
  • MarkerHandleButtonDownFcn
  • Orientation
  • OrientationMode
  • OrientationPropertyListener
  • OriginalDoubleBufferState
  • PixelBounds
  • PointsOffset
  • Position
  • SelfListenerHandles
  • Serializable
  • TextBoxHandle
  • TextBoxHandleButtonDownFcn
  • Version
  • ViewStyle
  • XLimInclude
  • YLimInclude
  • ZLimInclude
  • ZStackMinimum
  • uistate

As can be seen, if we really want, we can always use the MarkerHandle or TextBoxHandle directly.

Deleting data tips

To delete a specific data-tip, simply call the cursor mode’s removeDataCursor() method; to delete all data-tips, call its removeAllDataCursors() method:

% Delete the current data-tip
% Delete all data-tips

Have you used plot data-tips in some nifty way? If so, please share your experience in a comment below.

p.s. – did you notice that Java was not mentioned anywhere above? Mode managers use pure-Matlab functionality.

Categories: Handle graphics, Hidden property, Medium risk of breaking in future versions, Stock Matlab function, Undocumented feature, Undocumented function

Tags: , , , , ,

Bookmark and SharePrint Print

81 Responses to Controlling plot data-tips

  1. Isaac says:

    I have used programmable datatips to pull various extrema and their time hacks off a telemetry stream during V&V of flight software. It is VERY useful. I did not know about the other properties you’ve shown above — very cool. Thanks!

    • Dani says:

      Hi Isaac! I just arrived to this post ,and what a surprise, because I use all this tips for flight test software aswell (data processing of flight parameters)!! He he he we all arrive to the same places….True Story XD

      Amazing work Mr. Altman by the way!!

  2. K says:


    Thanks very much for this useful article!

    I have a small problem I was hoping you can help me resolve. When I use your code above, the datatip is displayed in the right location on the curve, but instead of having the X and Y values, it contains a message that says “Error in datacursor datatip string function”. I tried updating the “String” field of hDatatip, but that doesn’t seem to help.

    I would really appreciate any suggestions!

    Thank you,

  3. Dènis Riedijk says:

    I have used this as a custom tooltip for a patch object. (Depending on position above the patch, a different tooltip needs to be displayed)
    Just initialise the hDataTip hidden and without a cursor and set a timer for making it visible (and reset the timer in a windowbuttonmotionfcn so it displays after your mouse hovers for a certain amount of seconds)

    cursorMode = datacursormode(figureHandle);
    set(cursorMode, 'UpdateFcn',@setDataTipTxt, 'SnapToDataVertex', 'off', 'NewDataCursorOnClick',false);
    hDatatip = cursorMode.createDatatip(handle(patchHandle));
    set(hDatatip,'Host',handle(patchHandle), 'ViewStyle','datatip','OrientationMode','manual','Orientation','top-right');
    set(hDatatip, 'MarkerFaceColor','none', 'MarkerEdgeColor','none', 'HitTest','off', 'Visible', 'off');

    To use this as a tooltip, you might need to additionally do the following to make sure your clicks arrive at the right object and not at the datacursor or textbox:

    set(0,'ShowHiddenHandles', 'on');
    set(get(hDatatip,'Children'), 'HitTest','off'); % Otherwise our clicks end up in the default callbacks of data-tips.
    set(0,'ShowHiddenHandles', 'off');
  4. John says:

    Great tip, thanks a lot! The following line doesn’t seem to work in Matlab r2011b, but removing it works just fine:

    set(cursorMode, 'enable','on', 'UpdateFcn',@setDataTipTxt, 'NewDataCursorOnClick',false);

    I used it to find and mark phase and gain margin on a Bode plot.

  5. Felipe says:

    How can I pass a third argument to @setDataTipTxt?

    I have a graph with several plots, each of them comes from a different source file. I want the datatip to tell me (X,Y) plus the name of the source file. For that reason, I was willing to pass a third argument with the name of the source file. Am I on the right way?

    great blog.
    thank you.

    • @Felipe – you can do it like this:

      set(cursorMode, 'UpdateFcn',{@setDataTipTxt,sourceFilename});
    • Felipe says:

      @Yair, thanks for your answer.

      I’d tried what you told me, but it seems there is a problem when appending sourceFilename to the output cell array of @setDataTipTxt. I’ve tried several ways but always get the same message: “Error in custom datatip string function”.

      Do you have any idea why this is happening?

      Thanks again.

    • It means that you have an error in your setDataTipTxt function. Put a breakpoint there (or a try-catch block) to see exactly where and why.

    • Felipe says:

      Hi Jair,

      I believe my setDataTipTxt function is OK, I made it in the same way as it is explained in this blog:

      I even made the same experiment (changing ‘Y’ for ‘$’) and everything seems fine. The problem begins when I try to append sourceFilename to the cell array output of setDataTipTxt

      Do you have any idea why this may be happening? do you know any other turnaround?

      Thanks a lot for your help.

    • @Felipe – you probably forgot to declare the extra parameter(s) properly. See here.

  6. Apn says:

    Hello Yair,

    I’m new to matlab so this is likely to be a very basic question but I haven’t been able to find an answer so far. Maybe you can help.

    The question is: How can I make a datatip display full integer value?

    My X values are in the range 0 to 1500000
    When I make a datatip it displays:
    X: 3.669e+05
    Y: 17

    I would like it to be:
    X: 366915
    Y: 17

    Is that possible?

    Any help will be appreciated.


  7. Pingback: Handle Graphics Behavior | Undocumented Matlab

  8. Dani says:

    Hi Yair,
    First off, I’m fairly new to Matlab but I love your blog – its super informative and I’m looking forward to getting more practice so I can appreciate it more!
    I was hoping you could help me with a minor predicament. I’m using the data cursor for its point selection property but would rather the textbox not be displayed at all. I’ve tried almost everything, including suppressing it in the updateFcn callback using:

    function output_txt = getRidofTextBox(obj,event_obj, datapointhandle)
    h = get(datapointhandle, 'DataCursors');
    j = get(h, 'TextBoxHandle');
    set(j, 'Visible', 'off');

    but this doesn’t work, since it would appear the property just gets reset in a later callback. I’m running out of ideas and was hoping you would be able to point me in the right direction.

    • Yair Altman says:

      @Dani – try setting the output_txt to ” (empty), and datapointhandle.CurrentDataCursor‘s BackgroundColor and EdgeColor properties to ‘w’ (or rather, to your axes’ BackgroundColor)

    • Dani says:

      Thanks for looking into it! Unfortunately I’ve tried the empty string and I either get the warning ‘Error in custom datatip string function’, or it defaults back to a previous allowable value. Switching the box to white also doesn’t solve the problem since its still displayed on top of the plot – unless I misunderstood your advice. Thanks anyways!

    • @Dani – an error means that you have some Matlab error in your callback function, and then Matlab automatically defaults back to the default. Anyway, if an empty string is not allowed, you can always try a sting containing a single space character. The data-tip box will then be so small that the obstruction of the plot data will probably be unnoticed.

  9. Ben says:

    What is the proper way to create a datatip in window (instead of datatip) mode programmatically?

    I’ve tried this function based on your code and it works except I get tooltips instead of data in the window:

    function hDatatip = CustomDataTip(hObj, index, callbackhand)
        cursorMode = datacursormode(ancestor(hObj, 'figure'));
        % enable datatips
        datacursormode on;
        set(cursorMode, 'updatefcn', callbackhand);
        set(cursorMode, 'NewDataCursorOnClick', false);
        set(cursorMode, 'DisplayStyle', 'window');
        % Delete all data-tips
        hDatatip = createDatatip(cursorMode, hObj);
        % adjust properties
        set(hDatatip, 'UIContextMenu', get(cursorMode, 'UIContextMenu'));
        set(hDatatip, 'HandleVisibility', 'off');
        set(hDatatip, 'Host', hObj);
        set(cursorMode, 'DisplayStyle', 'window');
        %set(get(hDatatip,'TextBoxHandle'), 'Visible', 'off');
        % create datatip
        xData = get(hObj, 'XData');
        yData = get(hObj, 'YData');
        pos = [xData(index) yData(index)];
        set(get(hDatatip, 'DataCursor'), 'DataIndex', index, 'TargetPoint', pos);
        set(hDatatip, 'Position', pos);
    • Ben says:

      Hi, I just figured I’d report back, I think I figured it out (please excuse the ugly code, I’m sure this can be made much cleaner, but it seems to work). All off the functions called I simply stole verbatim from datacursormode.m and pasted into the same file as this function.

      function hDatatip = CustomDataTip(hObj, index, callbackhand) 
          cursorMode = datacursormode(ancestor(hObj, 'figure'));
          hMode = getuimode(ancestor(hObj, 'figure'), 'Exploration.Datacursor');
          hTool = localGetObj(hMode);
          % enable datatips
          set(cursorMode, 'enable','on', 'UpdateFcn',callbackhand, 'NewDataCursorOnClick',false);
          % Delete all data-tips
          hDatatip = createDatatip(cursorMode, hObj);
          % adjust properties
          set(hDatatip, 'UIContextMenu', get(cursorMode, 'UIContextMenu'));
          set(hDatatip, 'HandleVisibility', 'off');
          set(hDatatip, 'Host', hObj);
          set(cursorMode, 'DisplayStyle', 'window');
          % set up listener to datatip
          h = handle.listener(hDatatip, 'UpdateCursor', {@localUpdatePanel,hTool});
          % Listen to datatip existence and feed to panel
          h = handle.listener(hDatatip, 'ObjectBeingDestroyed', {@localUpdatePanel,hTool});
          set(get(hDatatip,'TextBoxHandle'), 'Visible', 'off');
          % Update string in panel
          % create datatip
          xData = get(hObj, 'XData');
          yData = get(hObj, 'YData');
          pos = [xData(index) yData(index)];
          set(get(hDatatip, 'DataCursor'), 'DataIndex', index, 'TargetPoint', pos);
          set(hDatatip, 'Position', pos);
  10. Werner says:

    I’ve used your datatip “undocumented documentation” and it helped me a lot with enhancing the information extraction from graphics. However, the datatips have an unexpected behavior on mac users, which makes it bottom of the ylabel text, complicating their visualization. I’ve managed to solve this issue explicitly overriding the position of the ylabel to a z value lower than the datatip one, but now my ylabel will move around when I zoom or pan my axis. I over-read the ActionPostCallback function from the zoom and pan handles, to replace the position after there where a change on the axis, but this creates an effect like the one you explained here:

    By chance, do you know any event listener that is linked to the axis label, or to movement on the axis, so that I can solve this issue without seeing my axis label flying around my figure until mouse is released? More details available here:

    Thank you very much, and congratulations for this site, it is very useful!

  11. Julien says:

    I massively abuse of the handle.listener syntax to listen to property changes of UDD objects. Could you give an example of what the equivalent syntax looks like in HG2 ?
    Moreover, do you know if the same handle.listener syntax still works in HG2 to listen to java events ?
    Thanks !

  12. Pingback: Draggable plot data-tips | Undocumented Matlab

  13. Franko says:

    The graphics.datacursormode object has an UpdateFcn handle. Opening graphics.datatip.updatestring.m reveals that the graphics.datatip object itself has an UpdateFcn. The latter is more useful because the cursorMode UpdateFcn is called as

    myUpdateFcn([], hDatatipEvent);

    whereas the datatip object’s UpdateFcn is called as

    myUpdateFcn(hDatatip, hDatatipEvent);

    So, potentially you can have different datatips with different UpdateFcn in the same figure. This is useful for advanced visualization involving multiple datatips in the same figure.

  14. Graham says:

    Great article Yair, a nice insight into the workings of data tips. Is there any way you know in which HTML can be included in data tips?
    I’m running R2011b & interested in being able to provide links with matlab: href to trigger some activity.

    I’ve tried the simple way of just outputting HTML from the UpdateFcn (as below) but without any success

    txt = sprintf('<a href="why" rel="nofollow">Link to data</a>');
  15. Jon says:

    Hi Yair,

    I used this excellent writeup to create custom tooltips for a bunch of figures. Everything mostly works, but the above method fails in one case, and I have no idea why.

    Briefly: I create a single empty figure and set its WindowButtonDownFcn property to @myMagnifyFcn. I then plot nine subplots (arranged as 3×3) into that figure. The helper script myMagnifyFcn determines which of the subplots receives a mouse click, then creates a new figure and copies just that axes into it (using findobj, etc.). This much works just fine.

    I then attempt to create the “custom tooltip” functionality for the latter (one-axes) figure as per your example, namely:

    cursormodeMagnifiedFig = datacursormode(gcf);
    set (cursormodeMagnifiedFig, 'NewDataCursorOnClick', true, 'SnapToDataVertex', on, 'UpdateFcn' {@myToolTipFcn, arg1, arg2, arg3});

    This is exactly the same code that I have working for other figures. But in this case, even though I can toggle the data cursor button in the latter figure just fine, @myToolTipFcn never seems to get called — I put a debug print statement at the top and it never executes.

    I’m wondering if there is something scope-related that causes the above to fail. As I said, the datacursormode stuff works just fine for all the other figures I create in my parent script. Furthermore, I examined the contents of cursormodeMagnifiedFig in the debugger — it turns up as a graphics.datacursormanager object, just like the corresponding cursormodeFig does with all my “regular” figures, and the contents are identical in all cases — so I’m confident that the arguments to UpdateFcn (= myToolTipFcn) are getting passed correctly.

    I’m stuck because I can’t figure out (no pun intended) how to debug what Matlab is doing — it simply doesn’t fire the helper function and fails silently. Can you suggest any good way to debug the datacursormode process?

    Thanks very much in advance (for this post specifically and for the blog in general),


    • @Jon – your gcf probably points to another figure handle. Try using the actual figure handle rather than gcf – if it’s a hidden handle then gcf will not return it.

    • Jon says:

      Hi Yair,

      Thanks for the quick response. I had a hunch that might be an issue, but wrote “gcf” in my code snippet above for brevity. Since that apparently _does_ make a difference, I should clarify that the actual setup in myMagnifyFcn is

      h_magnifiedFig = figure('tag', 'magnifiedAxes', 'keyPressFcn', get(hobj, 'keyPressFcn'), 'Name', 'Magnified Axes');
      cursormodeMagnifiedFig = datacursormode(h_magnifiedFig);
      set (cursormodeMagnifiedFig, 'NewDataCursorOnClick', ...);

      … and it is this setup that doesn’t work. I’m really baffled as to how else to debug this.

      FWIW, I’m stuck using a R2006b on this project. Seems much more likely that it’s my fault and not Matlab’s, but any chance this could be an HG-related bug?


      p.s. Sorry about the double post earlier, and thanks for cleaning it up.

    • Try adding a drawnow; pause(0.1); after the figure creation and before you retrieve datacursormode, maybe it will help. I no longer have access to R2006b (too old) so I can’t test. Good luck!

    • Jon says:

      Tried that but no luck. Argh.

      FWIW, checked that gcf, h_magnifiedFig, and get(gca,’Parent’) [where gca is the axes copied into the magnified figure] are all equal to one another — so the issue isn’t with operating on the wrong (or hidden) figure handle.

      Anyway, I will try digging a bit further with the debugger and maybe ask over at the newsgroup to see if anyone else has an idea. In any case, I will report back if I ever get to the bottom of this.

      Thanks again,


  16. Jon says:

    I think I’ve found a solution. Following up here as promised, in the unlikely event someone else runs into this (obscure?) issue.

    In my @myMagnifyFcn callback, the relevant part of the code to copy the clicked-upon axes and its contents to the new empty figure window is as follows:

    % Find all axes that are just axes (as opposed to legends, colorbars, etc.)
    figAxes = findobj(hObject, 'type', 'axes', '-not', 'tag', 'legend', '-not', 'tag', 'Colorbar');
    indAxes = find(figAxes == gco);
    % Assuming the click uniquely selects a particular axes, copy it to a new figure along with its contents
    if length(indAxes) == 1,
        h_magnifiedFig = figure('tag', 'magnifiedAxes', 'keyPressFcn', get(hobj, 'keyPressFcn'), 'Name', 'Magnified Axes');
        zoomedAxes = copyobj(figAxes(indAxes), h_magnifiedFig);

    (Note that legends and colorbars are handled separately later in the function, since I’ve found that COPYOBJ does not seem to handle them correctly, at least on R2006b.)

    The problem is that COPYOBJ either also mis-copies the ‘hittest’ property of some (all?) objects, or else they are not inherited automatically from the parent figure. This causes subsequent mouse clicks into the new (“magnified”) figure to be ignored, so they fail to fire the callback.

    So, after all that, the solution to this problem seems to be a one-liner(!) following the COPYOBJ statement:


    and some small tweaks to the code that assembles the tooltip text (which are specific to my setup, so I’ll skip them here).

    Hope this helps someone in the future. Thanks again, Yair, for doing all the heavy lifting.


  17. Jon says:

    One more…

    I have a callback function outputTxt = myCallback(obj, eventObj) to create customized datatips as described here, but I need to limit that behavior to only work for certain objects (specifically, plotted data points only, and not other lines showing mean, standard deviation, etc.).

    I’m able to check which object is clicked selected with the data cursor by looking at the properties of clickedObj = get(eventObj, ‘target’). But even if I set outputTxt = {”}, I still get a (default) data tip. I would like to cleanly delete this.

    The “Deleting data tips” section above shows how to do this from the parent script, but I’m wondering if it is possible to do this _from within the callback_. The variable obj is empty, while eventObj (whose class is graphics.datatipevent) has two properties, Target (a handle) and Position (a 2×1 matrix) — neither of which points to the datacursormode object used in the example. As a last resort, I tried executing this inside the callback:

    dummy = datacursormode(gcf);

    … and that sort of works, except that sometimes it deletes not only the desired (errant) data tip but also other (valid) ones already created in the same figure, which should all be left alone.

    Any suggestions would be most welcome.



  18. Mahmoud says:

    Thanks Dr.Yair Altman for your really nice tutorial.
    I am writing a program with 4-context menus; one of them is related to datacursor mode, I can switch between any of them except datacursormode one, I CANNOT Switch it off, So pleae how to do it in some example demo?
    Thanks in advance

    • @Mahmoud – I am not sure I understand your problem exactly. If you’d like me to look at your code, please contact me via email (the link is at the top left of every page here) for a short consultancy.

    • Mahmoud says:
      function CursorMode_Off_test
         close all, clear all, clc;
         hLine = plot(xdata, ydata);
         hcmenu = uicontextmenu;
         h1=uimenu(hcmenu,'label','Line Style');
         hcb1 = ['set(gco,''LineStyle'',''--'')'];
         hcb2 = ['set(gco,''LineStyle'','':'')'];
         hcb3 = ['set(gco,''LineStyle'',''-'')'];
         hcb_r = ['set(gco,''color'',''r'')'];
         hcb_g = ['set(gco,''color'',''g'')'];
         hcb_b = ['set(gco,''color'',''b'')'];
         hcb_B = ['set(gco,''color'',''k'')'];
         item1 = uimenu(h1,'Label','dashed','Callback',hcb1);
         item2 = uimenu(h1,'Label','dotted','Callback',hcb2);
         item3 = uimenu(h1,'Label','solid','Callback',hcb3);
         item4 = uimenu(h2,'Label','red','Callback',hcb_r);
         item5 = uimenu(h2,'Label','green','Callback',hcb_g);
         item6 = uimenu(h2,'Label','blue','Callback',hcb_b);
         item7 = uimenu(h2,'Label','black','Callback',hcb_B);
         %How to turn on/off this menu and keep other menus work
         item8 = uimenu(hcmenu,'Label','Cursor Mode','Callback',@update_FCN_call);
         hlines = findall(hax,'Type','line');
         for line = 1:length(hlines)
      function update_FCN_call(~,~)
          cursormode = datacursormode(gcf);
          set(cursormode,'enable','on','UpdateFcn', @myupdatefcn);
      function cp = myupdatefcn(obj,event_obj)
          pos = get(event_obj,'Position');
          cp = {['X: ',num2str(pos(1))], ...
                ['Y: ',num2str(pos(2))]};
  19. Rick says:

    I create a plot and set the data cursor properties in a function using:

    dcm_obj = datacursormode(gcf);
    set(dcm_obj,'DisplayStyle','datatip', ...
      'SnapToDataVertex','on', 'Enable','on', ...

    I then attempt to change the font to ‘FixedWidth’ (so my formatted strings all line up) by using:


    However, when I use the data cursor, everything is as it should be except the font is still the default ‘Helvetica’. If I call this code from the command line it works fine. Any ideas what is wrong?

    • @Rick – this is possibly an internal Matlab bug. Try using an explicit font name (e.g. ‘Courier New’) or use HTML formatting in your string (e.g., ‘my data tip string here…’)

  20. Yaroslav says:

    I have noticed that some properties change their enumeration values between HG1 and HG2. For example the 'Orientation' field changes from 'top-right' to a simple 'topright' etc. Perhaps it is worth mentioning it both in the current article and in hg2-update.

    On another notice, in some cases using HG2 the data-tips are created (and changed programmatically) faster. They have also a much richer data-tip display (using TeX syntax and notation). It seems that MathWorks makes some really good job under the hood…

  21. xiaojidan says:

    Do you know how to add two different markers on two ends of a line?

  22. bash0r says:

    I’m plotting an image in MATLAB using imagesc and then selecting points with the datacursormode.
    I’d like to any select point on the image not only the pixels itself.
    That’s why I always used ‘SnapToDataVertex’, ‘off’ in MATLAB R2014a.

    After switching to MATLAB R2014b. The cursor nethertheless snaps to the data vertex.

    dcm_obj = datacursormode(h);
    set(dcm_obj, 'DisplayStyle', 'datatip', 'SnapToDataVertex', 'off', 'Enable', 'on');

    I can only select pixel (e.g. X=75 Y=122) but I have to be able to select points in the sub-pixel region (e.g. X=75.25 Y=122.78).
    Has something changed in R2014b? How can I achieve the old behavior?

    Thanks in advance!

    • @bash0r – this looks like a Matlab bug to me. I suggest that you contact to report it

    • bash0r says:

      I have contacted the MATLAB support:

      “In R2014b, MATLAB has a new graphic handle system, so the image is visualized in a different way, which affect the behavior of setting ‘SnapToDataVertex’ ‘off’. If you are plotting lines, you can still have the same behavior.”

      The support is looking for a workaround to achieve my task and has additionally contacted the development team.

      I’ll keep you guys posted.

  23. bash0r says:

    I’ve received an answer from the MATLAB support and they have sent a workaround for MATLAB R2014b to get the exact cursor location on an image.
    Maybe someone is also in desperate need of this functionality :)

    load clown % load any image data (here: stored in variable X)
    h = figure(1);
    s = surf(zeros(size(X)+1), X, 'FaceColor', 'flat', 'EdgeColor', 'none'); % plot the image points as a surface
    set(gca, 'YDir', 'reverse')
    view(gca, 2)
    axis(gca, 'tight') 
    dcm_obj = datacursormode(h); 
    set(dcm_obj, 'DisplayStyle', 'datatip', 'SnapToDataVertex', 'off', 'Enable', 'on');
  24. skratch says:

    I just updated to R2014b and I’m having problems with code that just worked yesterday before the update. I used the top portion of code on this page to make a function createDataCursor(figureHandle,plotHandle,xcoord,ycoord). After the update, ‘NewDataCursorOnClick’, ‘ViewStyle’, and update pop up with errors that they don’t work for data tips:

    The name 'NewDataCursorOnClick' is not an accessible property for an instance of class
    There is no ViewStyle property on the PointDataTip class.
    Undefined function 'update' for input arguments of type ''.

    The Matlab documentation says, “You place data tips only by clicking data objects on graphs. You cannot place them programmatically (by executing code to position a data cursor).” I don’t know if it always said that or if that’s updated language as of R2014a/b. The first two errors are not a big deal, but I don’t know what to do about “update” no longer working. How do I update the position of the data tip to a new location?
    Sample of my function below:

    function output_args = createDataCursor(figureHandle,plotHandle,xcoord,ycoord)
       cursorMode = datacursormode(figureHandle);
       set(cursorMode, 'enable','on', 'UpdateFcn',@setDataTipTxt)
       set(hDatatip, 'UIContextMenu', get(cursorMode,'UIContextMenu'));
       set(hDatatip, 'HandleVisibility','off');
       set(hDatatip, 'Host',hTarget);
       % set(hDatatip, 'ViewStyle','datatip');
       set(hDatatip, 'MarkerSize',5, 'MarkerFaceColor','none', 'MarkerEdgeColor','k', 'Marker','o', 'HitTest','off');
    • Yair Altman says:

      If you read the article you’d see that the Matlab warning has always been there. R2014b introduced a major overhaul of the entire graphics system (a.k.a. HG2), and this functionality has changed with it. It can still be accessed programmatically, it’s just that the programmatic interface has changed. This is always a risk when using undocumented features such as the ones explained in this blog. You cannot expect them to remain unchanged forever…

      You’d need to dig a bit to find out the required changes in 14b – I’m too busy working on other things now and do not expect to look into this in the near future. If you find anything useful, come back here and post it for the benefit of other readers.

      Good luck!

    • Will says:

      In HG2, the data tip object has Cursor property, which itself has a Position property. Setting this property to a new location updates the position of the data tip, i.e.:

      hDatatip.Cursor.Position = [xcoord, ycoord];
    • Will says:

      Note that unlike with the previous update() method, setting the value of hDatatip.Cursor.Position only triggers the UpdateFcn() callback if the value is not equal to the current position.

  25. John P says:

    I’m trying to copy an existing figure to a newly created figure.
    say.. i’ve just created a figure with a few subplots and added a bunch of datacursors. call it “old_fig”.

    %old_fig = a bunch of subplots etc...
    new_fig = figure;

    this copies everything except for the datacursors.

    Does anyone know how to copy the datacursors over also?


  26. MU says:

    Hi Yair

    Many thanks for the excellent article.

    I was wondering if in the datacursor mode, instead of showing the standard datatip, there is an efficient way to draw a vertical line that passes through the graph and intersects the y-value at/above/below the click position.

    Many thanks,

  27. Jason says:

    I changed the font in my data tip to Courier New. This works great when the data tip display style is ‘Data Tip’…..but the appearance of the font reverts to Helvetica when the display style is ‘window’ even though cursorMode.DisplayStyle still shows Courier New.

    Any thoughts on why the appearance would change between the two display styles?

    I change the font from within the data tip function:

    function output_txt = track_assess_ppi_data_tip(obj,event_obj)
        cursorMode = datacursormode(gcf);
        cursorMode.CurrentDataCursor.FontName ='Courier New';
    • Jason says:

      Never mind……figured it out.

      When you switch from the ‘Data Tip’ display style to the ‘window’ display style, the original data tip object still remains but ‘visible’ is turned ‘off’.

      Then a panel is created to hold the same content that is in the data tip.
      I was able to find the handle for that panel and set its font to ‘Courier New.’
      Code is below:

      function output_txt = track_assess_ppi_data_tip(obj,event_obj)
         cursorMode = datacursormode(gcf);
         cursorMode.DisplayStyle = 'window';
         cursorMode.CurrentDataCursor.FontName ='Courier New';  % this does the data tip
         my_figpanel = findall(gcf,'Tag','figpanel:text field');
         set(my_figpanel,'FontName','Courier New')
  28. Nick Gianopoulos says:


    I’m sorry if this is a repeat question as I feel somebody probably has asked it before, but I’ve scoured this thread and still haven’t found the answer to my question. I’m using trisurf(tri,x,y,z,c) to plot a 3D color plot. The datatip function by default displays X Y Z using the Position property of of the event_obj. However, I looked through your list of the hidden properties of the event_obj but couldn’t find one that referred to the argument passed to the color input. I’d like to be able to edit the datatip function to show X,Y,Z,and Heat (which is what the color represents in my case).



    • @Nick – all you need to do is to set a custom UpdateFcn callback function for the cursorMode object (in my post it was @setDataTipTxt). This callback function should have the simple following signature:

      function outputTxt = setDataTipTxt(hObject, eventObj)

      within this callback function, eventObj.Target will be the handle of the surface object, and eventObj.Position will be the data-tip’s X,Y,Z data coordinates. Use these coordinates (which correspond to a single point in the surface object’s XData,YData,ZData properties) to extract the corresponding C value from the surface object’s CData property (which has the same matrix size as ZData, thus enabling easy match). Then combine X,Y,Z,C into a string that you will set in outputTxt. That’s it. See the datacursormode documentation for details.

    • Nick Gianopoulos says:

      @Yair, Worked beautifully – Thanks!

  29. Hans says:


    I need to write the x axis difference between two or 4 datatips on the plot like legend.
    Text function writes everytime as I zoom in.

    Questions :

    1) if marker one is the reference and if there is 4 markers, I need to calculate 3 distance w.r.t. marker one.
    2) How to plot these mentioned 3 distances on the plot( by zooming into plot it will stay as legend )

    I appreciated too much for your help.


  30. Andrew says:


    Did MATLAB recently change the syntax to this? I am trying to get access to the current list of datacursors programatically, but nothing I have tried seems to work.

    >> cursorMode = datacursormode(handles.figure1)
    cursorMode = 
      DataCursorManager with properties:
            SnapToDataVertex: 'on'
                DisplayStyle: 'datatip'
        DefaultExportVarName: 'cursor_info'
                   UpdateFcn: @dynamicDateTicks/dateTip
                      Enable: 'off'
                      Figure: [1x1 Figure]

    So not nearly as many properties are listed as above. Then, the next call to get the current data cursors does not work anymore

    >> dcm.DataCursors
    No appropriate method, property, or field 'DataCursors' for class

    I am trying to make a GUI which gets the xy data from all plotted datacursors. I have not figured out how to do this programmatically unless I am creating the datatips programmatically and then storing them in my own cells. Currently, I have to have the user “export cursor data to workspace” by right clicking the datatip and doing it manually. This is rather clunky.

    Any suggestions are appreciated – thanks!

    • Andrew says:

      I figured it out…actually found it elsewhere but then realized it is mentioned in this original post as well. You can still use getcursorinfo(dcmObject) to get a list of all data cursors.

    • yes, this post was originally posted in 2011, more than 5 years ago – Matlab has changed a lot since then, including an entirely revised graphics system (HG2). The current data cursor object is similar, but not identical, to the one mentioned in the post. So if you just figure out how the property names have changed you could probably do everything now much as you could back in 2011. For example, the current data-cursor object can be gotten via cursorMode.CurrentCursor instead of using CurrentDataCursor.

  31. Michael says:

    Dear Yair
    I would like to make some of the lines on the plot “unaccessible” / “invisible” for the datacursor mode
    (Thus, I want the possibility to place the data cursor only on part of the lines that appear on the plot).
    How can I do that, please?
    Thank You

  32. Sanwal Yousaf says:

    Hey Dr. Altman,
    This is a great tutorial though i am trying to adjust it to my script. I have a figure with 13 subplots in it that each have boxplot representation of the data that i am working with. I am trying to modify the data tip text for the outliers so that i can use the Observation row value that is displayed in the data tip. I want to introduce another value in the datatip that takes the value of Observation Row as displayed in the data tip and use it to display the subject number that is stored in a separate matrix that is generated before the boxplots are plotted. I am using Matlab R2013a and i am trying to adjust your code to my script and i am getting an error that reads:

    No appropriate method, property, or field CreateDatatip for class graphics.datacursormanager.

    for the following line of code:

    hDatatip = cursorMode.CreateDatatip(hTarget);

    I am still in work of adjusting this to my script, here are some adjustments that i have made so far:

    cursorMode = datacursormode(gcf);
    set(cursorMode, 'enable', 'on', 'UpdateFcn', @revealData);
    hTarget= handle(gcf);
    hDatatip = cursorMode.CreateDatatip(hTarget);
    %Create a copy of teh context menu for the data tip
    %set the data-tip orientation to top-right rather than auto
    set(hDatatip, 'OrientationMode', 'manual');
    set(hDatatip, 'Orientation', 'top-right');
    %update the data tip marker appearence
    set(hDataip, 'MarkerSize', 5, 'MarkerFaceColor', 'none',...
                 'MarkerEdgeColor', 'k', 'Marker', 'o', 'HitTest', 'off');
    %Move the data tip to the right most data vertex point
    position = [X(end),dataExtract(end),1; X(end),dataExtract(end),-1];
    update(hDatatip, position);

    Here is my update function

    function txt = revealData(~, event_obj)
        %Customizes the text of data tips
        pos = get(event_obj, 'Position');
        pos1 = pos(1);
        pos2 = pos(2);
        txt = {['Outlier Value', num2str(pos(1))],...
               ['SubName', mat(pos2).name]};

    I am also linking my Matlab Answers post which has an image of the subplots that i am refering to.

    I would greatly appreciate any help i can get.

    P.S. Sorry if the indenting looks poor, i already made sure that indenting wasn’t the problem!!

  33. gep says:


    Is it possible to maintain the hittest property of a figure after enabling datacursormode?

    f = figure('WindowButtonUpFcn',@(~,~)disp('UP!!'));
    z = peaks;
    dcm_obj = datacursormode(f);

    Thank you

    • gep says:

      To answer myself in case someone stumbles upon:

      add this snippet inside your datacursor update function,

      hManager = uigetmodemanager(h_fig);
          set(hManager.WindowListenerHandles, 'Enable', 'off');  % HG1
          [hManager.WindowListenerHandles.Enabled] = deal(false);  % HG2

      followed by setting any figure callbacks you want to survive while datacursor mode is enabled

      @Yair, I am almost certain that I have read it in one of your answers somewhere but I have forgotten about it.
      Hard to keep track of all the hacks:)

    • gep says:

      ah yes.. i have stolen this hack years ago:)

  34. Mike Papadopoulos says:

    Using MATLAB 2018b, I have been able to change the EdgeColor and TextColor of the datatip, but the BackgroundColor will not update properly. Specifically the BackgroundColor property of the datatip object changes to the correct RGB triplet but the actual Background color of the datatip does not change. Any Thoughts?

    • @Mike – you can modify the tip background via the TipHandle and/or BackgroundAlpha:

      hDataTip.TipHandle.FaceColor = 'm';  % or: [1,0,1]
      hDataTip.BackgroundAlpha = 0.65;
  35. Jacopo Remondina says:

    Hi, I’m working with MATLAB R2019a – update 4 (the latest one I think), and I would like to know if there are some updates on how these features work.
    Actually some of the functionalities are still correct/working, like querying for the datacursormode (or manager) and set the update string function, but other (like querying for all the datacursor objects) seems broken. I also noticed that maybe the object itself is a bit different. Here are the outputs I’ve got at the prompt:

    >> dcm=datacursormode(figHandle)
    dcm = 
      DataCursorManager with properties:
            SnapToDataVertex: 'on'
                DisplayStyle: 'datatip'
        DefaultExportVarName: 'cursor_info'
                 Interpreter: 'tex'
                   UpdateFcn: @(varargin)obj.manageDatatips(varargin{:})
                      Enable: 'on'
                      Figure: [1×1 Figure]
    >> dcm.DataCursors
    Unrecognized method, property, or field 'DataCursors' for class ''.

    In particular, I would like to know if there is a way to change the default aspect of the markers for a given figure, since the workaround I’ve found is to change each property (marker shape, size, edge color, face color,…), then force an update (with pause), then change another property and so on.
    This method has however few drawbacks:
    -first, the middle step settings flash on the screen (and without the pause command between them, they are not accepted);
    -second the changes are only temporary and I should update them every time the markers are drawn again, including during the resize of the figure/axes

    I tried to have a look with the getundoc function, but I couldn’t really find anything useful.

    • @Jacopo – in R2019a the property is called PointDataCursors. Since it’s a private property of the datacursoremode, you cannot access it directly. Instead, use struct(dcm).PointDataCursors. I am not aware of a way to change the data-cursor defaults – perhaps there is a way, I just never bothered to look for one.

  36. CW says:

    Hi. I have a contour plot with multiple data sets plotted on it, i.e…

    [cs1,h1] = contour(x1,y1,z1);
    hold on;
    [cs2,h2] = contour(x2,y2,z2);
    [cs3,h3] = contour(x3,y3,z3);

    Generally with data cursor, I’d have to click around in the plot to get the data cursor to show each of the z1, z2, z3 data separately, along with its legend entry, hoping I click on the exact contour I want.

    I would like to see if there’s a way to use myupdatefnc to show all 3 z data values at a particular x,y position in a single data cursor. Do you know if this is possible? Thank you!

    • CW says:

      Also to clarify, this is within a GUI, which allows users the ability to choose which of a set of, say, 10 types of data they want, as many as they want, to be plotted. So an automatic way of doing this, rather than passing in 3 specific data sets and pulling them out manually based on the current x,y would be helpful.

    • @Aselia/CW – In your updateFcn(~,eventData) function, you can fetch the clicked position via eventData.Position and based on this position you can compose your custom datatip text (which is returned as the output of updateFcn). Simply find a way to get the contours data accessible in your updateFcn (there are multiple ways to do this, all of them pretty standard/documented) and you’re basically done.

    • CW says:

      I was able to get the contour data accessible within myupdatefnc, however I noticed that eventData.Position returns the absolute x,y position, whereas my contour z data might have a certain step size between data points such that the absolute x,y position doesn’t access the array correctly. Is there a way to do this without also pulling in my original x,y vectors, step size, etc and doing all the math myself? Doing the math and pulling the data in is fine…just wanted to avoid the extra bulk if possible.

  37. Leandro de Oliveira says:

    My contribuition to create new datatip

    clear all
    close all
    x = 0:0.1:10;
    y = sin(x);
    h = figure(1);
    hObj = plot(x,y);
    index = [25 75 100];
    hold on
    for i = 1:3
        cursorMode = datacursormode(h);
        hDatatip = cursorMode.createDatatip(hObj);
        pos = [x(index(i)) y(index(i))];
        set(get(hDatatip,'DataCursor'), 'DataIndex',index(i), 'TargetPoint',pos);
        set(hDatatip, 'Position', pos);
    hold off

Leave a Reply

Your email address will not be published. Required fields are marked *