Accessing plot brushed data

A few days ago, a reader of the Matlab Desktop blog asked whether it is possible to store plot brushed data in a separate variable for later processing. Data Brushing, first introduced in R2008a, enables interactive selection and marking of plot data points. The brushed data can then be stored in a variable using the context (right-click) menu, or the figure’s Tools/Brushing menu.

Saving brushed data to a variable

Saving brushed data to a variable

The said reader has specifically wanted programmatic access, rather than interactivity. The official answer is that data brushing was designed to be an interactive tool, and so this cannot be done. However, this has never stopped us before. So off I went to launch my favorite inspection tool, the UIInspect utility on the figure above (UIInspect will be described in a near-future article), which can be recreated with the following simple code:

t=0:0.2:25; plot(t,sin(t),'.-');
% Now brush some data points...
uiinspect(gca);

UIInspect-ion of a data-brushed plot

UIInspect-ion of a data-brushed plot (click for details)

A couple of alternative answers to the reader’s question were immediately apparent:

Directly accessing brushed data

First, we notice that data brushing added data-brushing context menus, both of which are called BrushSeriesContextMenu (the duplication is an internal Matlab bug, that does not affect usability as far as I can tell).

Also, an invisible scribe overlay axes has been added to hold the new annotations (data brushing is considered an annotation; scribe axes deserve a separate article, which they will indeed get someday).

More importantly for our needs, we see a new line item called ‘Brushing’, which displays the red lines and data points that we seek. We can now easily get the brushed data using this line’s XData and YData properties: non-brushed data points simply have NaN values:

UIInspect-ion of the data-brushing line

UIInspect-ion of the data-brushing line

hBrushLine = findall(gca,'tag','Brushing');
brushedData = get(hBrushLine, {'Xdata','Ydata'});
brushedIdx = ~isnan(brushedData{1});
brushedXData = brushedData{1}(brushedIdx);
brushedYData = brushedData{2}(brushedIdx);
% and similarly for ZData in 3D plots

Accessing brushing callbacks

Yet another way of approaching the problem is to use the available callback functions built-into the data-brushing functionality. We can access either the BrushSeriesContextMenu or the figure’s Tools/Brushing menu. I will leave the former (context-menu) approach as an exercise to the reader, and just describe the figure’s menu approach.

As I have already explained in a dedicated article, figure menu-bar actions are accessible via their handles, and we can retrieve that using a unique tag (well, most of the time – read that article for details). In our case, the Tools/Brushing/Create-new-variable menu item has the unique tag ‘figDataManagerNewVar’. So let’s use it:

>> hNewVarMenuItem = findall(gcf,'tag','figDataManagerNewVar')
hNewVarMenuItem =
          742.000244140625
 
>> hNewVarCallback = get(hNewVarMenuItem,'callback')
hNewVarCallback = 
    @datamanager.newvar
 
>> hNewVarCallback(gcf)   % activate the callback
% => set 'ans' as the new variable holding the brushed data
 
>> ans
ans =
                       6.4         0.116549204850494
                       6.6         0.311541363513379
                       6.8         0.494113351138609
                         7         0.656986598718789
                       7.2         0.793667863849153
                       7.4         0.898708095811627
                       7.6         0.967919672031486
                       7.8         0.998543345374605
                       ...         ...

Of course, we could also have gone the hard way, via the scribe axes and the annotations route. For masochistic people like me it could even be a worthwhile challenge. But for all other normal people, why bother when there are such simple alternatives, if we only knew how to find them. :-)

Related posts:

  1. Controlling plot data-tips Data-tips are an extremely useful plotting tool that can easily be controlled programmatically....
  2. 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. ...
  3. Performance: accessing handle properties Handle object property access (get/set) performance can be significantly improved using dot-notation. ...
  4. Accessing the Matlab Editor The Matlab Editor can be accessed programmatically, for a wide variety of possible uses - this article shows how....
  5. Editbox data input validation Undocumented features of Matlab editbox uicontrols enable immediate user-input data validation...
  6. Bar plot customizations Matlab bar charts can be customized in various nifty ways. ...

Categories: Figure window, Handle graphics, Low risk of breaking in future versions, Undocumented feature

Tags: , , , , , ,

Bookmark and SharePrint Print

11 Responses to Accessing plot brushed data

  1. lux says:

    Very useful!
    I tried it and I have a question.
    How can I change the characteristics of the brushing line in a plot (width, size of markers) permanently?
    I want these to be valid for every plot I edit and use the brush mode.
    I see the default settings are widthline 2.5 pixels and marker’s size 6 for the brushline.
    Thank you!

    • @Lux – unfortunately, brushed lines are implemented in Matlab as simple line plots. Therefore, they share the same default characteristics as the standard line plots and so you cannot change them only for brushed lines.

      You can change the defaults for all lines using:

      set(0,'DefaultLineMarkerSize',10);  % 6 => 10
      set(0,'DefaultLineLineWidth', 4);  % 2.5 => 4
    • lux says:

      Thank you! It worked.
      I created an m file with these two commands and I put it in the target in the shortcut tab of Matlab properties
      (matlab icon, right click, properties) so as the settings to be adjusted automatically every time I start Matlab.

  2. Amol says:

    Amazing.. thanks.. solved a problem that had been vexing me for too long..

  3. marco says:

    hello, really usefull!!
    only one question: suppose I have like 4 plot in a panel, with overlapped axes on left and right (each plot is a class with linked data….etc etc). Now i have like 7 or more lines with a specific tag (like: line1,line2,line3…). If I brush the ‘line2′ ‘line4′ and ‘line6′, and then I use: hBrushLine = findall(handleOfFigure,’tag’,'Brushing’), how can I understand to which line is referred the brush?
    Is there a method to set the tag to the brushing object when it is created? like: brushLine2….

    hope I was clear
    thank you very much!!
    marco

    • Here’s a way to directly access the brushing lineseries handle of a plot lineseries:

      appdata = getappdata(line1);
      brushingHandle = appdata.Brushing__.SelectionHandles;

      This works on the R2011b pre-release that I’m currently using – I’m not sure if it also works on older releases.

  4. H├ęctor says:

    I didn’t know anything about data brushing, It’s quite useful, and makes my job much more simple. Thanks again for your posts.

  5. Pingback: Controlling plot data-tips | Undocumented Matlab

  6. James says:

    I am developing a GUI for viewing large amounts of data: currently about 250 plots, but this will go up. I have two axes in this figure with many other options. I plot all data sets in the upper plot during initialization and then use the ‘Visible’ option for determining which plots are seen. When I click one of these plots in the upper axis it appears in the lower axis. In this lower axis the user has the option to select a peak using brushing. The brushed data is then fit to some function. At this point I would like to remove the brushed data programmatically. To do this I get the function handle for the ‘Clear all brushing’ item in the uicontextmenu that pops up when you right-click on brushed data:

    %Get the callbacks to the context menu options
    BrushingCallbacks = get(get(findall(gcf,'tag','BrushSeriesContextMenu'),'children'),'callback')
    BrushingCallbacks = 
        {2x1 cell}
        [function_handle]
        @datamanager.paste 
        @datamanager.newvar
        {3x1 cell}
        {3x1 cell}
        '' 
    %the first cell area has the function handle to the 'clear all brushing', as far as I know.
    ClearBrushingData = BrushingCallbacks{1}{2}; %assign the function handle
    ClearBrushingData(gcf); %clear all brushed data

    This, however, is not working. Any suggestions would be greatly appreciated.

    • @James – try using the hgfeval function rather than invoking the callback function directly

    • James says:

      hgfeval worked very nicely, thank you! In the end, I found it was a bit faster to have the user select a region of interest (ROI) using ginput and then use a function called “draggable.m”–from the FEX–to make the ROI movable in the axis. I am very glad to know of hgfeval for the future though!

Leave a Reply

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

*

<pre lang="matlab">
a = magic(3);
sum(a)
</pre>