In Release 2008a, we added the ability to link plots to source data. With this feature, you tie a plot to a particular value in the workspace. When that value changes, the plot is automatically updated, with no further intervention on your part.
For this release, we’ve made a short video tutorial explaining how to use this feature, with a particularly useful application: watching your variables change during a debugging session. The second half of the video covers another new feature, data brushing, which is a topic for a later post.
One use not covered in the video is for observing real-time data. A while back I wrote a program to monitor incoming bytes from the serial port and update a graph with that data: a serial “oscilliscope”, if you will. In order to achieve smooth scrolling, instead of re-plotting the data, I modified the axes’ Xdata and Ydata properties whenever there were
BytesAvailable. This was a cumbersome hack.
The following real-time example uses the yahoo function from the Datafeed Toolbox. The same principles can be applied to any asynchronous callback in MATLAB, such as the above-mentioned BytesAvailableFcn for a serial object, most of the objects from the Data, Instrument, or Image Acquisition Toolboxes, Simulink and the target link toolboxes, or even a GUI control callback. This code uses a timer object to query AT&T’s stock price every 10 seconds, and adds that value to an array in the workspace.
Because the plot is linked to the data, the plot automatically updates to reflect the new value, thus giving us a real-time stock ticker.
close all;delete(timerfindall);clear all; Connect = yahoo; %Datafeed Toolbox function val=; time=; t = timer('TimerFcn',... ['data = fetch(Connect, ''t'',''last'');'... 'val(end+1) = data.last;'... 'time(end+1)=rem(now,1);'] ,... 'Period', 10,'ExecutionMode','fixedRate'); start(t) %start the timer %unambiguously set the source data plot(time,val,'XDataSource','time','YDataSource','val') title('Price of AT&T') linkdata on %link the the data to the plot
Watching a stock fluctuate over a few minutes isn’t generally exciting, but you get the idea. What’s the big deal, then? I think this feature is best for when we don’t know when the data is going to change (but that it will), or when you want change the data iteratively and interactively without having to do a lot of retyping, as in the following example.
I like linking for situations where one is tinkering around with a variable in the command window. For me this is usually applying different filters to some data until I get the parameters just right. For instance, let’s say I have some data and I want to tweak filter coefficients until I get the desired response on my data. The following example requires the Signal Processing Toolbox.
First let’s set up the data:
t = linspace(0,6*pi,100); x = sawtooth(t); %sawtooth wave - Signal Processing Toolbox function y = x; plot(abs(fft(y)))
This time let’s use the GUI to set the YDataSource by clicking the link button: . Then, click the “fix it” link (1) in the message bar, and then enter a fft expression in the YDataSource field (2).
Now let’s try out a 2nd-order butterworth filter. We won’t have to manually re-FFT or re-plot the new output:
[a,b]=butter(2,0.1); %Signal Processing Toolbox function y = filter(a,b,x);
Close, but not quite, so I’ll try upping the order to 4:
[a,b] = butter(4,0.1); y=filter(a,b,x)
Good enough! Of course I could have just as easily put the whole filter expression in my YDataSource instead, saving me an extra line.
I invite you to let us know what other creative uses for this you come up with. Do I hear animation?
22 CommentsOldest to Newest
Thanks for the quick tutorial. I do have one question about implementation: In terms of performance, how does this compare to other methods of updating plots? Does waiting on changes to the data suck up resources? Is it faster, slower, or equivalent to using set(h,’YData’)? How complex can the commands used to link the data be? Can I use a conditional statement which only updates the linked data if it has been at least X seconds since the last update, etc?
Linked plots respond to changes in workspace variable(s) with a lag of up to 0.5 seconds between the variable change and when the plot is redrawn. This is the same event coalescing mechanism that is used by the Variable Editor and Workspace Browser to minimize any performance impact. The drawback, of course, is that linked plots are not ideal for animation of fast changing data. For animation you are definitely better off using (h,’YData’) directly on the graphics. Enabling users to configure the latency between variable changes and plot updates is an intriguing idea. Perhaps it’s an option that could be added as a preference.
To really get the benefit of linked data in a command window tweaking session, I would like an option to have the figure window be “always on top”. I know what you’re going to say: “dock the figure”, but then it’s too small! (Some of us have not graduated to 30in flat screens yet.) Sometimes all you need is one line of the command window to type in, and the rest of the screen for the figure, and you don’t feel like “designing” a desktop layout. I think a “always on top” button in the figure window would be great.
MATLAB does not have an always on top feature for figure windows.
I suggest you request an enhancement from our web form (requires login):
If it would work for you, I can suggest some code that would bring the window back to the front every time the data changes.
I found a submission to File Exchange called setWindowOnTop that does exactly that. Looking at the code I have no idea how it works. I’ll request the enhancement though because I think it can become a very popular button on the figure window.
linkdata seems like the better solution for the update requirements of the yahoo connection, but your original approach sounds better for the ‘serial oscilloscope’ job, giving more immediate updates. Calling it a ‘cumbersome hack’ seems a bit harsh. :-) Is that code available anywhere ?
Unfortunately I don’t have a version of that code that meets my standards for sharing, however the basic idea is this:
Set the bytes available callback of the serial object to a sub-function which contains code such as:
x_vector(end+1) = x_vector(end)+1; y_vector(end+1) = fread(s,1); %read in data set(plot_line_handle,'Xdata',x_vector,'Ydata',y_vector);
In this case I’m just updating the line object and not the whole plot. The first time through I create a new plot with:
plot_line_handle = plot(0,y_0);
I am trying to write a program to let users to select points from a figure (say, I have 100 points with x and y variables) using the new data brushing function, then when the user delete the brushed points, these points will also be deleted from the original variables x, y.
So my question is: is it possible to return the indices of the brushed data so that I can update x and y when the points are deleted? When using linkdata and databrush, I can clearly see that the selected points are highlighted in variable editor window, so it seems possible to do that. However, neither linkdata and databrush does not provide an output variable to store the indices of the brushed variable. Is there a way to get around this? Thanks.
I am not sure what is you are ultimately looking for. If you brush a linked plot, the changes are reflected in the originating workspace variables. If you want to know what changed, you can retain an original (non-linked) copy of that data and use set functions to find the indices that changed.
Thanks, Mike. I found that the deleted values are actually filled with NaNs. The variable size didn’t change, so I mistakenly thought the variables didn’t change.
I still have questions in accessing the brushed data in a function.
The function I write is like this
function h = deleteData()
x = 1:100; y = 1:100;
h = plot(x,y,’.',’XDataSource’,'x’,'YDataSource’,'y’);
Then, I call this function
h = deleteData();
and interactively delete some points, now, I want to access the points left in the figure,
x_remain = get(h,’XData’);
y_remain = get(h,’YData’);
x_remain and y_remain are still the same as the original x and y.
Is there a way to access the points that remain in the figure? Thanks.
If I run your code:
h = deleteData(); origX=get(h,'XData') origY = get(h,'YData')
Remove some points with the data brush tool, and then follow up with:
x_reamin=get(h,'Xdata') y_remain = get(h,'YData'); whos
You can see that the x_remain vector is smaller than the xOrig vector.
I run the same code. x_remain is the same as origX although y_remain is different from origY.
Not sure what is wrong…
I am not able to help you further debug in this way. If you have maintenance on your license, you can contact tech support and perhaps someone there can walk through it with you. http://www.mathworks.com/support/service_requests/contact_support.do
It doesn’t seem possible to do linkdata for images – which is a great shame! Is this in the pipeline?
For Chee’s example, I’m not sure exactly why “x_remain” has not changed, but I would recommend removing the call to “linkdata on” from the deleteData function. It creates a dynamic link between the graphics and the variables “x”,”y” in the current workspace. When execution passes from the deleteData functional workspace back to the base workspace, those variables may no longer exist or may have changed, potentially causing the plot to update to reflect the changes.
For Greg’s point about linkdata for images, we agree that this would be good to do, and it definitely adds weight to the idea to hear customers ask for it specifically.
Timer and Dynamic Images
Give snapshots of the working program showing its proper work for testing examples – 5-6 snapshots
I am not sure what you are asking for. I think this may be it… a sample output from my timer example?
How do i retrive brushed data?
For e.g. I have a plot and use the brush tool to select some points on the plot how do i get access to data selected?
Thanks in advance
You can access the brushed data through the “BrushData” instance property of the graphic objects being brushed. For example:
plot(randn(100,1)); % Brush some data, then get the line on the plot l = get(gca,'children'); % Get the BrushData instance prop for the line get(l,'BrushData')
Note that the “BrushData” property is *not* documented. That means that the name or data type may change in a future release so don’t depend on it.
I used brush and link to set some data points to NaN, my original data is a 480*2 matrix, and I took its first column as x, second column as y to plot. like, plot(ROT_cap(:,1),ROT_cap(:,2),’o')
since I just want to set the second column of selected points to NaN, I only set link with second column, but it turned out the two columns were changed.
Is this just the way it should be? Thanks!
This is the correct behavior since:
- the x and y variables are two columns of the same variable
- brushing linked variables always applies to entire rows
We think you can do what you want by creating two different variables, one for each column and then only linking one of them as follows:
x = rand(10,1); y = randn(10,1); plot(x,y); linkdata
- Click on the Edit… link of the linked plot bar to ensure that only one of the variables (say x) is linked
- Brush the points of interest and replace them with NaN
- NaNs should only be added to the linked variable (x)
So, to reiterate, the x & y values should be in separate variables.