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.
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, 'NewDataCursorOnClick',false); % Note: the optional @setDataTipTxt is used to customize the data-tip's appearance % 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(hDatatip,'UIContextMenu',get(cursorMode,'UIContextMenu')); set(hDatatip,'HandleVisibility','off'); set(hDatatip,'Host',hTarget); set(hDatatip,'ViewStyle','datatip'); % Set the data-tip orientation to top-right rather than auto set(hDatatip,'OrientationMode','manual'); set(hDatatip,'Orientation','top-right'); % 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 = graphics.datacursormanager >> cursorMode.DataCursors ans = graphics.datatip: 2-by-1 >> cursorMode.CurrentDataCursor ans = graphics.datatip >> 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):
graphics.datacursormanager
:
- CurrentDataCursor
- DataCursors
- Debug
- DefaultExportVarName
- DefaultPanelPosition
- EnableAxesStacking
- EnableZStacking
- ExternalListeners
- HiddenUpdateFcn
- NewDataCursorOnClick
- OriginalRenderer
- OriginalRendererMode
- PanelDatatipHandle
- PanelHandle
- PanelTextHandle
- UIContextMenu
- UIState
- ZStackMinimum
graphics.datatip
:
- 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 cursorMode.removeDataCursor(cursorMode.CurrentDataCursor) % Delete all data-tips cursorMode.removeAllDataCursors()
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.
Related posts:
- Draggable plot data-tips Matlab's standard plot data-tips can be customized to enable dragging, without being limitted to be adjacent to their data-point. ...
- Accessing plot brushed data Plot data brushing can be accessed programmatically using very simple pure-Matlab code...
- Plot LineSmoothing property LineSmoothing is a hidden and undocumented plot line property that creates anti-aliased (smooth unpixelized) lines in Matlab plots...
- Plot LimInclude properties The plot objects' XLimInclude, YLimInclude, ZLimInclude, ALimInclude and CLimInclude properties are an important feature, that has both functional and performance implications....