I recently consulted to a client who wanted to display an interactive plot with numerous data points that kept updating in real-time. Matlab’s standard plotting functions simply could not keep up with the rate of data change. Today, I want to share a couple of very simple undocumented hacks that significantly improve plotting performance and fixed my problem.
I begin by stating the obvious: whenever possible, try to vectorize your code, preallocate the data and other performance-improving techniques suggested by Matlab. Unfortunately, sometimes (as in my specific case above) all these cannot help. Even in such cases, we can still find important performance tricks, such as these:
Performance hack #1: manual limits
Whenever Matlab updates plot data, it checks whether any modification needs to be done to any of its limits. This computation-intensive task is done for any limit that is set to ‘Auto’ mode, which is the default axes limits mode. If instead we manually set the axes limits to the requested range, Matlab skips these checks, enabling much faster plotting performance.
Let us simulate the situation by adding 500 data points to a plot, one at a time:
>> x=0:0.02:10; y=sin(x); >> clf; cla; tic; >> drawnow; plot(x(1),y(1)); hold on; legend data; >> for idx = 1 : length(x); plot(x(idx),y(idx)); drawnow; end; >> toc Elapsed time is 21.583668 seconds.
And now let’s use static axes limits:
>> x=0:0.02:10; y=sin(x); >> clf; cla; tic; drawnow; >> plot(x(1),y(1)); hold on; legend data; >> xlim([0,10]); ylim([-1,1]); % static limits >> for idx = 1 : length(x); plot(x(idx),y(idx)); drawnow; end; >> toc Elapsed time is 16.863090 seconds.
Note that this trick is the basis for the performance improvement that occurs when using the plot’s undocumented set of LimInclude properties.
Of course, setting manual limits prevents the axes limits from growing and shrinking automatically with the data, which can actually be a very useful feature sometimes. But if performance is important, we now know that we have this tool to improve it.
Performance hack #2: static legend
Hack #1 gave us a 22% performance boost, but we can do much better. Running the profiler on the code above we see that much of the time is spent recomputing the legend. Looking inside the legend code (specifically, the legendcolorbarlayout function), we detect several short-circuits that we can use to make the legend static and prevent recomputation:
>> x=0:0.02:10; y=sin(x); >> clf; cla; tic; drawnow; >> plot(x(1),y(1)); hold on; legend data; >> xlim([0,10]); ylim([-1,1]); % static limits >> % Static legend >> set(gca,'LegendColorbarListeners',); >> setappdata(gca,'LegendColorbarManualSpace',1); >> setappdata(gca,'LegendColorbarReclaimSpace',1); >> for idx = 1 : length(x); plot(x(idx),y(idx)); drawnow; end; >> toc Elapsed time is 5.209053 seconds.
Now this is much much better – a 76% performance boost compared to the original plot (i.e., 4 times faster!). Of course, it prevents the legend from being dynamically updated. Sometimes we actually wish for this dynamic effect (last year I explained how to use the legend’s undocumented -DynamicLegend feature for even greater dynamic control). But when performance is important, we can still display a legend without its usual performance cost.
In conclusion, I have demonstrated that Matlab performance can often be improved significantly, even in the absence of any vectorization, by simply understanding the internal mechanisms and bypassing those which are irrelevant in our specific case.
Have you found other similar performance hacks? If so, please share them in the comments section below.
I agree with Perttu. Whenever I want performance, I manually set the xdata and ydata. This doesn’t cause any of the automagic stuff (like limit picking and legend setting) to happen.
My spectrum scope on the file exchange shows this coding pattern, including tracking limits to make sure data isn’t cut off.
For comparison, your last code gives for me: 4.42 seconds, by replacing plot with line in for loop times to 4.0 seconds. In general line is more “raw” and thus faster than plot. However, nothing beats direct modification of the first plots x/ydata:
But obviously the result is not the same, since there is now only one line object instead of 501 that your code creates.
I have had similar experiences to the previous commenter. For updating an existing plot, it’s always much faster to modify the properties of an existing object than delete old ones and create new ones (as is done in repeated calls to plot). I would also add that in a large GUI with many graphics objects, calls to “gca”, “gco” and “gcf” start to slow down considerably, so it’s always better to store the handles in advance and avoid calling any of those functions to get the handles, particularly for operations that are being done repeatedly inside loops.
First off – thanks.
Second – did you ever happen to need to “plot” icons instead of the usual circle/triangle markers?
I need to show icons (e.g. picture of a house, or a car) on the axes that behave like markers: not change size on zoom, and stay at the same axes coordinates.
Could you suggest how to do that?