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.