A couple of years ago, I was asked by a client to figure out a way to make Matlab plot data-tips movable. The problem was that he had a very crowded plot and Matlab’s standard data-tips are displayed immediately adjacent to the data, thereby overlapping the plot parts. Matlab’s standard data-tips enable dragging to a very limited extent (only to the 4 corners of the data-point), and in any case the displayed textbox remains directly attached to the data point.
So I developed a small utility for my client that solves this problem. I then forgot all about it until a few days ago when I came across it again. Yesterday I uploaded this draggableDataTips utility to the File Exchange, where you can download it.
draggableDataTips enables the user to interactively drag any newly-created data-tip, anywhere in the Matlab figure. A dashed line connects the dragged data-tip with the original data point. Simple, intuitive, and effective. At 300 lines, the draggableDataTips.m source code is compact and easy to follow, and you’re welcome to take a look and further customize this utility for your specific needs.
Technical implementation
The implementation of draggableDataTips relies on undocumented aspects of the data-cursor object exposed via the datacursormode function. I have already shown how these can be used to customize and control data-tips programmatically (rather than interactively). For draggableDataTips, we first get the cursor object’s meta-data classhandle (a schema.class object), then use it to find the meta-data for its hidden CurrentDataCursor property (a schema.prop object). There is also a more direct approach, using the findprop function.
Whichever alternative we choose, we finally use this object to set the property’s SetFunction meta-property. Quite straight-forward, I should say:
% Get the cursor-mode object cursorObj = datacursormode(hFig); % Alternative #1: the indirect route to the meta-property ch = classhandle(cursorObj); hPropIdx = strcmpi(get(ch.Properties,'Name'), 'CurrentDataCursor'); hProp = ch.Properties(hPropIdx); % Alternative #2: the direct approach hProp = findprop(cursorObj, 'CurrentDataCursor'); % Update the meta-property to use a custom function whenever new data-tips are created hProp.SetFunction = @installNewMoveFcn;
This has the effect that all new data-tips that will be created from then on will call our custom installNewMoveFcn function when the data-tip object is created. This installNewMoveFcn function, in turn, simply replaces the data-tips standard default callback for mouse movement (which is used while dragging), to a new custom function textBoxUpdateFcn:
% Install a replacement callback function for datatip textbox mouse movement function hDataTip = installNewMoveFcn(cursorObj, hDataTip) srcObjs = get(hDataTip.SelfListenerHandles,'SourceObject'); for srcIdx = 1 : length(srcObjs) if strcmpi(srcObjs{srcIdx}.Name,'Orientation') hDataTip.SelfListenerHandles(srcIdx).Callback = @textBoxUpdateFcn; hDataTip.MarkerHandle.Marker = 'none'; break; end end end
The textBoxUpdateFcn function basically moves the datatip textbox to the new mouse location, without limiting its positions as Matlab’s standard default callback function did. A dashed connector line is then drawn to connect the center of the textbox with the data-point. It’s a bit long to include here, but interested readers are welcome to look at the code (lines #99 onward in draggableDataTips.m).
As can be seen from the screenshot above, standard and draggable data-tips can be used in the same plot. This is done by simply turning the draggability functionality on and off by draggableDataTips before creating a new data-tip (using either alt-click or programmatically):
draggableDataTips on % or: draggableDataTips('on') or: draggableDataTips(true) draggableDataTips off % or: draggableDataTips('off') or: draggableDataTips(false)
Notes:
- The actual code of draggableDataTips naturally contains more sanity checks, exception handling etc. I have only presented the core code in the snippets above, but you should always include such extra checks in any real-life program.
- There is a minor bug that causes the connector line to be on top of the box rather than beneath it, but aside from this all works ok. For some reason, uistack did not work. If anyone has a fix for this bug, please let me know.
- Did you notice that Java was not mentioned anywhere above? Mode managers, such as the data-cursor mode, use pure-Matlab functionality.
HG2
Unfortunately, when I tested draggableDataTips on HG2, Matlab’s upcoming new graphics engine, the utility failed. Data-cursors have undergone a significant reengineering in HG2 (about time!), causing multiple properties and methods to change names and functionality. But this could be overcome (see lines #43-53 in draggableDataTips.m).
However, I could not overcome the apparent fact that unlike HG1 (or more specifically, schema objects, that HG1 uses for its data-tips functionality), in HG2 (or rather, MCOS class objects) we cannot override an object’s meta-properties, specifically its SetMethod (which is the MCOS equivalent of schema.prop‘s SetFunction meta-property).
So for the moment, draggableDataTips does not work on HG2. I hope to find a solution for this by the time HG2 launches. If anyone finds a fix for the problem, please let me know. If I ever find or receive a fix, I will update this post with the relevant technical details.
For the moment there is no rush, since HG2 is still relatively far away in the distant future, and draggableDataTips works splendidly in the current HG1.
Have you used plot data-tips in some nifty way? If so, please share your experience in a comment below.
Related posts:
- Controlling plot data-tips Data-tips are an extremely useful plotting tool that can easily be controlled programmatically....
- Accessing plot brushed data Plot data brushing can be accessed programmatically using very simple pure-Matlab code...
- Plot LimInclude properties The plot objects' XLimInclude, YLimInclude, ZLimInclude, ALimInclude and CLimInclude properties are an important feature, that has both functional and performance implications....
- Undocumented scatter plot jitter Matlab's scatter plot can automatically jitter data to enable better visualization of distribution density. ...