- Undocumented Matlab - https://undocumentedmatlab.com -

Accessing plot brushed data

Posted By Yair Altman On October 6, 2010 | 25 Comments

A few days ago, a reader of the Matlab Desktop blog asked [1] whether it is possible to store plot brushed data in a separate variable for later processing. Data Brushing [2], 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 [3] 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 [4]
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 [5], 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. πŸ™‚

Updates for HG2 (R2014b+)

In HG2 (R2014b+), findall(gca,'tag','Brushing') returns empty data since the way that brushed data is stored has changed. You can access the brushing data using the plot line’s hidden BrushHandles property, as follows:

hLine = plot(...);
hBrushHandles = hLine.BrushHandles;
hBrushChildrenHandles = hBrushHandles.Children;  % Marker, LineStrip

I described the new Marker objects here [6], and LineStrip objects here [7]. The brushed vertex data can be retrieved from either of them. For example:

>> hBrushChildrenHandles(1).VertextData
ans =
     1     2     3     4   % X-data of 4 data points
     1     2     3     4   % Y-data of 4 data points
     0     0     0     0   % Z-data of 4 data points

If you only need the brushed data points (not the handles for the Markers and LineStrip, you can get them directly from the line handle, using the hidden BrushData property:

>> brushedIdx = logical(hLine.BrushData);  % logical array
>> brushedXData = hLine.XData(brushedIdx);
>> brushedYData = hLine.YData(brushedIdx)
brushedYData =
     1     2     3     4

Addendum 28 Feb, 2018: MathWorks posted an official post on Matlab Answers that references the BrushData functionality – see here [8].

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


25 Comments (Open | Close)

25 Comments To "Accessing plot brushed data"

#1 Comment By lux On March 3, 2011 @ 17:14

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!

#2 Comment By Yair Altman On March 4, 2011 @ 01:24

@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

#3 Comment By lux On March 4, 2011 @ 06:36

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.

#4 Comment By Amol On April 11, 2011 @ 02:40

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

#5 Comment By marco On July 7, 2011 @ 02:43

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

#6 Comment By Yair Altman On July 7, 2011 @ 14:23

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.

#7 Comment By HΓ©ctor On August 17, 2011 @ 06:33

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

#8 Pingback By Controlling plot data-tips | Undocumented Matlab On September 14, 2011 @ 13:44

[…] data-cursor mode 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 […]

#9 Comment By James On June 20, 2012 @ 20:43

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.

#10 Comment By Yair Altman On June 21, 2012 @ 11:05

@James – try using the [15] rather than invoking the callback function directly

#11 Comment By James On June 27, 2012 @ 20:52

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!

#12 Comment By max On August 1, 2014 @ 06:44

Hi i was wondering how the access to the brushed data works when the brush is used multiple times. It seems to me that

hBrushLine = findall(gca,'tag','Brushing');
brushedData = get(hBrushLine, {'Xdata','Ydata'});
brushedIdx = ~isnan(brushedData{1});
brushedXData = brushedData{1}(brushedIdx);
brushedYData = brushedData{2}(brushedIdx);

only gives the brush indices of the most recent brush usage.
Lets say you have one (or multiple) curve in a plot like:

figure; plot([1:100],[1:100],'*')

and you use the brush twice to delete the first ten and the last ten points. I would like to access the XData and YData of the still visible datapoints. The mentioned code only gives the most recent usage of the brushed data (so in this example the deleted last 10 points). I couldn’t see so far how i can access all the brush instances.

How does this scale if you have n curves?

figure; plot([1:100],[1:100],'*'); hold on; 
plot([1:100],2*[1:100],'*'); 
plot([1:100],3*[1:100],'*');
...

Thanks a lot

#13 Comment By bash0r On February 3, 2015 @ 12:35

Since Matlab R2014b this method doesn’t seem to work anymore.

hBrushLine is empty after running the following code:

hBrushLine = findall(gca,'tag','Brushing');

best regards

#14 Comment By Yair Altman On February 3, 2015 @ 13:02

@bash0r – in HG2 (R2014b+), you can access the brushing data using the plot line’s hidden BrushHandles property, as follows:

hBrushHandles = hLine.BrushHandles;
hBrushChildrenHandles = hBrushHandles.Children;  % Marker, LineStrip

I described the new Marker objects [16], and LineStrip objects [17]. The brushed vertex data can be retrieved from either of them. For example:

>> hBrushChildrenHandles(1).VertextData
ans = 
     1     2     3     4   % X-data of 4 data points
     1     2     3     4   % Y-data of 4 data points
     0     0     0     0   % Z-data of 4 data points

If you only need the brushed data points (not the handles for the Markers and LineStrip, you can get them directly from the line handle, using the hidden BrushData property:

>> brushedIdx = logical(hLine.BrushData);  % logical array
>> brushedXData = hLine.XData(brushedIdx);
>> brushedYData = hLine.YData(brushedIdx)
brushedYData =
     1     2     3     4

#15 Comment By Rahul On March 4, 2017 @ 14:34

i try this for getting the brush data in matlab 15b but it is now working.
why?.

#16 Comment By Yair Altman On March 4, 2017 @ 19:53

@Rahul – the code that I posted above works well even in R2016b

#17 Comment By colin On March 1, 2015 @ 13:36

Great article! Any suggestions for setting the brush data programmatically? For example, to display all the points that meet a certain criteria?

#18 Comment By Bill On February 18, 2016 @ 16:07

You can set the brush data using the set command with your line handle, just like you would set the XData or YData.

set(hLine,'BrushData',xxx)

#19 Comment By Nimrod Geffen On August 20, 2015 @ 03:04

Shalom Yair!
I have a GUI that I would like to have the interactive option of deleting scatter points with Brush function. My code is:

h = brush;
set(h, 'Enable', 'on', 'color', 'c');
pause
brushedIdx = logical(handles.hScatter.BrushData);  % handles.hScatter is the scatter plot handle
brushedXData = hLine.XData(brushedIdx);

It seems like the pause is just not working. If I debug and put a breakpoint after the pause it jumps right to it without letting me grab the brush data.

I used brush with pause in matlab 2013 (with the findall(gca,’tag’,’Brushing’); to get the brush data) and it worked fine. I’ll mention that the GUI is a child GUI and it has uiwait in the openning function (Maybe it is related but in matlab 2013 it did’nt bother).

Thank you very much for your help!

Nimrod

#20 Comment By Bill On February 18, 2016 @ 16:05

Thanks! What a great article. Your update in the comments for R2104b+ saved me. How do you find hidden line properties like BrushData?

#21 Comment By Yair Altman On February 18, 2016 @ 19:23

@Bill – [18]

#22 Comment By Eric On April 21, 2017 @ 22:35

@Yair Altman
findall(gca,’tag’,’Brushing’) returns zero on my machine. I’m using R2016b.

#23 Comment By Yair Altman On April 22, 2017 @ 23:32

@Eric – see my comment above: [19]

#24 Comment By ZR On September 8, 2017 @ 16:21

Hello,
Is there a way to access brushed data for Scatters in Matlab 2015b? I was able to get it to work in 2012a using your first method described above, but your method described in “Updates for HG2 (R2014b+)” doesn’t seem to work. I tried the following, with the following results:

>> hl.BrushHandles
No appropriate method, property, or field 'BrushHandles' for class 'matlab.graphics.axis.Axes'.
 
>> get(hl,'BrushData')
Error using matlab.graphics.axis.Axes/get
There is no BrushData property on the Axes class.

Just to reiterate, this is specifically for scatters, not plots.

Thanks!

#25 Comment By Yair Altman On September 25, 2017 @ 13:59

@ZR – if you read my article carefully you will see that BrushHandles and BrushData are properties of the line object (which is returned by the plot or line or scatter functions) – not of the axes object.


Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/accessing-plot-brushed-data

URLs in this post:

[1] asked: http://blogs.mathworks.com/desktop/2008/05/12/brush-up-on-your-data/#comment-7364

[2] Data Brushing: http://www.mathworks.com/help/techdoc/data_analysis/brh7_p3-1.html#brh7_p3-3

[3] UIInspect utility: http://www.mathworks.com/matlabcentral/fileexchange/17935-uiinspect-display-methods-properties-callbacks-of-an-object

[4] Image: http://undocumentedmatlab.com/images/Brushing2a.png

[5] dedicated article: http://undocumentedmatlab.com/blog/modifying-default-toolbar-menubar-actions/

[6] here: http://undocumentedmatlab.com/blog/plot-markers-transparency-and-color-gradient

[7] here: http://undocumentedmatlab.com/blog/customizing-axes-rulers#Axle

[8] see here: https://www.mathworks.com/matlabcentral/answers/385226-how-to-use-the-data-brush-tool-to-automatically-save-selected-points-in-multiple-line-plots

[9] Accessing hidden HG2 plot functionality : https://undocumentedmatlab.com/articles/hidden-hg2-plot-functionality

[10] Draggable plot data-tips : https://undocumentedmatlab.com/articles/draggable-plot-data-tips

[11] Controlling plot data-tips : https://undocumentedmatlab.com/articles/controlling-plot-data-tips

[12] Plot LimInclude properties : https://undocumentedmatlab.com/articles/plot-liminclude-properties

[13] Undocumented plot marker types : https://undocumentedmatlab.com/articles/undocumented-plot-marker-types

[14] Performance: accessing handle properties : https://undocumentedmatlab.com/articles/performance-accessing-handle-properties

[15] : https://undocumentedmatlab.com/blog/hgfeval/

[16] : https://undocumentedmatlab.com/blog/plot-markers-transparency-and-color-gradient

[17] : https://undocumentedmatlab.com/blog/customizing-axes-rulers#Axle

[18] : https://undocumentedmatlab.com/blog/getundoc-get-undocumented-object-properties

[19] : https://undocumentedmatlab.com/blog/accessing-plot-brushed-data#comment-345181

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.