Increase the plotting performance in the MATLAB level (drawmode/ optimizing rendering/ down sampling etc)

154 views (last 30 days)
Problem statement: Increase the plotting performance in the MATLAB level (drawmode/ optimizing rendering/ down sampling etc)
Background: We are working on a MATLAB based framework for analysis and visualization of data. The information that we use for plotting is very huge. The number of data points are in the range of ~10E7 or more and we are facing MATLAB performance issues when we zoom/pan/maximize/minimize. We urgently need to improve the performance. The requirement is to have the complete information in the plot but the end user chooses to enable or disable particular lines based on the need. As a framework owner we do not have any control on the number of data points that are used for the plot or remove the overlapping points.
Bottom line is we cannot modify the data to be plotted so we will continue to have huge number of points. We can only try from the MATLAB layer to increase the performance as requested above.
Please help us to improve the performance with your experience. Looking forward for your answers.
Thanks, Dhanya

Answers (10)

Yair Altman
Yair Altman on 6 Nov 2015
Edited: Yair Altman on 6 Nov 2015
Matlab's new graphics engine ("HG2", introduced in R2014b) indeed degraded the performance for plotting numerous data points, compared to the earlier HG1 (R2014a and earlier). Still, this does not mean that you must give up on HG2's better visualization. There are multiple things that you can do to improve the performance and reactivity of your graphics, to the point where performance is no longer a limiting factor and you just keep HG2's better visualization.
In addition to the pointers by Walter and Mike, here are some additional resources that you may find useful (apologies for the plugs, but this is one of my main topics of ongoing research...):
The last article in particular details several techniques that I usedin a situation very similar to yours. In addition to those techniques, some additional techniques for speeding up graphic objects creation that I’ve found useful over the years include:
  • Avoid plotting non-visible elements, including elements that are outside the current axes limits, or have their Visible property set to ‘off’ or have a color that is the same as the axes background color.
  • Avoid plotting overlapped elements, esp. those that are occluded by non-transparent patches, or lines having the same coordinates.
  • Reduce the number of plotted objects by combining lines, patches etc. into a single object using data concatenation, with NaN values as separators.
  • Avoid using the scatter function with fewer than 100 data points – instead, duplicate these points so that scatter will work with more than 100 points, where vectorization kicks in ( details ), or even better: use line rather than scatter.
  • Use low-level rather than high-level plotting functions – i.e., line instead of scatter/plot/plot3; surface instead of surf.
  • Avoid creating straight line with multiple data points – instead, only keep the end-points for plotting such lines. I find that this is a very common use-case, which is often overlooked and could have a significant performance impact.
  • Avoid using plot markers if possible, and use simple markers if this cannot be avoided. Various markers have different performance impacts in various situations, but ‘.’ and ‘o’ are typically faster than others.
  • Use the plot function’s input triplets format, rather than multiple calls to plot. For example:
plot(data1x,data1y,'r', data2x,data2y,'g', data3x,data3y,'b', ...);
  • Set the axes properties to static values before plotting, in order to avoid run-time dynamic computation and update of things like the limits, tick-marks etc.
  • Avoid creating legends or colorbars initially – let the user create them by clicking the corresponding toolbar icon if needed. Legends and colorbars take a second or more to create and can often be avoided in the initial display. If this cannot be avoided, then at least create static legends /colorbars.
  • Only call drawnow once you’ve finished plotting. I’ve seen numerous cases where users call drawnow within the plotting loop and this has a horrendous performance impact. However, note that in some cases drawnow is very important ( example1, example2 ).
  • Generate the plot while the figure is hidden.
  • Data-reduce the plotted data. We can program this ourselves, or use former MathWorker Tucker McClure’s reduce_plot utility (a POTW selection) to do it for us. Data reduction is especially important when displaying images that do not need to be zoomed-in, but also significantly improves zooming and panning speed.
  • Cast image data to uint8 before using image or imagesc to display the image.
  • Avoid clearing/deleting and then recreating the axes when we need to replot – instead, just delete the relevant axes children objects and replot in the existing axes.
  • Avoid using the axes function to set the focus on a specific axes – instead, set the figure’s CurrentAxes property, or pass the axes handle directly to the plotting function.
  7 Comments
Róbert Kakonyi
Róbert Kakonyi on 6 Apr 2021
Edited: Walter Roberson on 29 Mar 2023
Dear Yair,
Where to send the beer for this tip? I already have your book. :)
"Reduce the number of plotted objects by combining lines, patches etc. into a single object using data concatenation, with NaN values as separators."
Róbert
Slow: (hard to rotate even the plot)
rowIndexes = (90:-1:1)';
figure
hold all
for idxFrame = 1:size(MaskEvaluationResultsTable,1)
temp = MaskEvaluationResultsTable.LeftAndRightLine{idxFrame};
isSel = ~isnan(temp(:,1));
isSel(2:4:end) = false;
isSel(3:4:end) = false;
isSel(4:4:end) = false;
if any(isSel(:))
plot3(temp(isSel,1),rowIndexes(isSel),repmat(idxFrame,sum(isSel),1))
plot3(temp(isSel,2),rowIndexes(isSel),repmat(idxFrame,sum(isSel),1))
end
end
set(gca,'YDir','Reverse')
% % set(gcf,'Renderer','painters')
% % set(gca,'SortMethod','childorder')
grid on
Super fast:
rowIndexes = rowIndexes = (90:-1:1)';
xValsL = [];
xValsR = [];
yVals = [];
zVals = [];
for idxFrame = 1:size(MaskEvaluationResultsTable,1)
temp = MaskEvaluationResultsTable.LeftAndRightLine{idxFrame};
isSel = ~isnan(temp(:,1));
xValsL = [xValsL;temp(isSel,1);nan];
xValsR = [xValsR;temp(isSel,2);nan];
yVals = [yVals;rowIndexes(isSel);nan];
zVals = [zVals;repmat(idxFrame,sum(isSel),1);nan];
end
figure
plot3(xValsL,yVals,zVals,'r')
hold all
plot3(xValsR,yVals,zVals,'g')
set(gca,'YDir','Reverse')
Stats:
>> size(MaskEvaluationResultsTable,1)
ans =
2236
>> size(xValsL)
ans =
112756 1
Javier Necochea
Javier Necochea on 29 Mar 2023
Stopped by ti thank you!
The "surf" vs "surface" difference is massive!! Two orders of magnitude better in time performance.

Sign in to comment.


Walter Roberson
Walter Roberson on 5 Nov 2015
A lot depends upon the release you are using, and the operating system, and the graphics cards, and some of the fine details of the plot commands used. You have not given information on any of those.
However, the way you are describing your situation, it appears that at most you have control over the minimum MATLAB software release used, and that you have no control over anything else, especially not what plot commands are actually used. Under those circumstances, your requirements are not feasible.
If, on the other hand, the user-supplied data is passed to your routines and you have control over exactly how it is displayed, then you do have control over the number of data points plotted, which makes a big big difference in the feasibility.
A key trick here is that Zoom and Pan both have a Pre-Action Callback (and a Post-Action Callback too.) This allows you to filter the data to be plotted to only submit to the graphics system the data points that would be visible and of meaningful contribution with the current view and display resolution: when you get the zoom or pan request, you compute what would be in the new view and you submit that to the graphic system.

Mike Garrity
Mike Garrity on 5 Nov 2015
There isn't a "one size fits all" answer for this. We'd need to know more about what you're doing.
The first step is to use the profiler and see what it tells you. Another step would be to read some of things I've posted on the subject on the MATLAB Graphics blog. In particular, there were a number of good suggestions in the comments thread for this post. And of course, creating a simplified version of your case and posting it here would give people something concrete to comment on.

Jan
Jan on 8 Nov 2015
Edited: Jan on 8 Nov 2015
You wrote:
As a framework owner we do not have any control on the number of
data points that are used for the plot or remove the overlapping points.
I think, this is the core problem, and not Matlab's performance.
You cannot display 1e8 points on a LCD screen, because this exhausts the number of available pixels. Trying to squeeze subpixel information in a plot is a waste of time.
Human cannot perceive such an information density also. Beside the technical and psychological limitations, the performance might be a secondary problem only.
The Douglas-Peucker method allows to reduce the information without loosing important details depending on the resolution of the display and the receiving human. See also: FEX: Plot (Big) (suggested by Yair already as "reduce_plot").
  1 Comment
Mike Garrity
Mike Garrity on 9 Nov 2015
MATLAB's line object actually does reduce the number of points before sending them to the graphics card. It's not Douglas-Peucker. It's a very old bit of MATLAB code which is designed to be particularly good at the most common MATLAB plots. In particular, it's really careful about not losing the details of narrow peaks. Also, it's a sweep method rather than a recursive subdivision method because that often works better with MATLAB's memory management. You're right that there are cases where something like Douglas-Peucker is a more appropriate choice, but in many cases I think that you'll find that the default curve thinning is actually the right choice.
If you look at the graphs at the end of this post on the MATLAB Graphics blog, you can see how the different chart types scale with the number of datapoints. As you can see, in R2014b that became quite a bit better for most of the charts. In particular, look at area and scatter. They had terrible scaling characteristics in earlier releases.
We focused pretty closely on getting the slope of those curves down on the right side of that chart. But as you can see, on the left hand side things aren't as good. That's the case that Yair's talking about above. There's a constant cost for things like object creation. For a large amount of data, that gets amortized, but when the amount of data is small, you can clearly see that cost. We're continuing to work on improving that part. A lot of it is just that the old object creation code had gotten lots of tiny performance tweaks for more than 20 years, and it's going to take some time to catch up with it.
One really interesting thing on those two charts is that the curve for plot doesn't really look very different. There's that constant offset again, but the slopes of the right hand sides are nearly identical. That's because a lot of the large data optimizations like the curve thinning that I described earlier were already part of plot's line object in earlier releases. We've basically been focused on getting all of the other objects caught up to that one on performance scaling.
I do have another post about performance coming to the MATLAB Graphics blog soon. This one's going to focus on memory consumption, which is another important factor to consider here. Way back when I used to design graphics hardware, I used to say that it was really just advanced memory system design. Getting enough compute was usually the easiest part of designing a balanced pipeline.

Sign in to comment.


Dhanya
Dhanya on 9 Nov 2015
Thanks to all for the overwhelming answers for this post. I'll get back to you with more specific details of our problem.

Bruno Luong
Bruno Luong on 9 Nov 2015
Edited: Bruno Luong on 9 Nov 2015
I would like to submit another issue with HG2 performance that is blocking in my case.
Context: I have a high speed camera that acquires some kind of gray images with a speed of about 100 FPS.
Goal: I want to plot an image as fast as I can with some other basic information overlaying on the image.
The plot is carried out by a function "Update_Plot" called in a continuous loop.
Essentially this function does nothing but a bunch of SET commands on an existing objects, and terminates with a drawnow(). To fix an idea, the objects consist of 1 image of about 500 x 200 in resolution, 15 texts, and 25 lines. It does not use any factory smoothing capability. There is no graphical object creation in the function.
If an camera images is received during this function is invoked it will be throw away. So the display speed depends only on the capability of MATLAB of updating as fast as it can of the graph.
Here is the results, carefully measured:
  • R2014A (HG1) 27 FPS, smooth display
  • R2015B (HG2) 11 FPS, important jitter in the display
They are performed on the same computer: Win64, Windows 10 OS, i7 4500 dual core laptop, latest Nvidia driver.
Here is a test on another computer with: Win64, Windows 7 OS, i7 3960 desktop, Nvidia graphic card and driver.
  • R2012A (HG1) 54 FPS, smooth display
As you can see, performance on HG2 is quite low and the jitter creates uncomfortable visual effects for users. This issue is very problematic on our SW development roadmap, we can no longer ensure our soft work reliable on latest HW and SW.
I'm not sure what I could do to get the performance back.
For now we are stuck with an old MATLAB versions, but trend of using Windows 10 and new HW by our clients tells me that this solution can be used for a short time (1-2 year). So this cause me a big concern about the future.
  9 Comments
Bruno Luong
Bruno Luong on 13 Nov 2015
Mike,
1. is there anyway to get some profiling details of a DRAWNOW command? 2. What is the recommendation of when using DRAWNOW, when using REFRESHDATA?
Mike Garrity
Mike Garrity on 13 Nov 2015
> 1. is there anyway to get some profiling details of a DRAWNOW command?
Currently no. Our support team has some profiling tools, but they're definitely not ready for prime time. But sending them repro steps for some interesting cases should help us figure out what we need to do to get them ready for prime time. So I would encourage you to do that.
> 2. What is the recommendation of when using DRAWNOW, when using REFRESHDATA?
The refreshdata function is a fairly specialized beast. Really its only job is for the case where you've got a plot that you created with something like the plot browser, so that it has a reference to the variables you created from, and the values of those variables changed. In this case, the plot doesn't know because of MATLAB's copy-on-write memory management. So the refreshdata function tells them to check for updates.
The drawnow function is much more general purpose. In fact, as you saw here, it's probably trying to do too many jobs. The description on the doc page is about the best we have. Basically drawnow is the gatekeeper for the connection between MATLAB's compute thread(s) and its rendering thread(s). So its controlling any communication that has to cross between them. That includes updates to objects being drawn, mouse events, window resizes, and various notifications from the operating system.

Sign in to comment.


Bruno Luong
Bruno Luong on 9 Nov 2015
Sorry for cross posting, but we somehow pinpoint to the fact that MATLAB handle poorly some latest/advanced drivers
To Mike: I will try to make a minimal example, but as you have seen, the issue is also somewhat related to HW and drivers, so you might see something difference than with my setup.
  5 Comments
timo
timo on 11 Nov 2015
Edited: timo on 11 Nov 2015
Here is Mathworks answer. Basically they say , downgrade the driver or live with it ! WTF
Technical Support Case #01600806
"I believe you were aware of the graphics driver issue. One possible solution would be reverting to an older version of the driver that should work correctly. Drivers with version 344 and above have performance issues while drivers with versions 341 and below do not. We suspect that there has been some major change made by NVIDIA for version 344 since they still keep version 341 and release security fixes for it. If you couldn't downgrade the driver, we couldn't do too much in this case. I'm afraid you would need to run this on another computer. I'm sorry about that."
Ps: My parallel toolbox CUDA doesnt work with that old driver , so for me 2 toolboxes are becoming useless -parallel toolbox and -simulink 3d animation (try vrmemb demo and see it locks the PC)
timo
timo on 11 Nov 2015
My GPU is fully supported by the NVIDIA driver
Vendor: 'NVIDIA Corporation'
Renderer: 'GeForce GTX 770M/PCIe/SSE2'
RendererDriverVersion: '10.18.13.5891'
RendererDriverReleaseDate: '05-Nov-2015'
MaxTextureSize: 16384
Visual: 'Visual 0x07, (RGBA 32 bits (8 8 8 8), Z depth 16 bits, Hardware acceleration, Double buffer, Antialias 8 samples)'
Software: 'false'
HardwareSupportLevel: 'full'
SupportsGraphicsSmoothing: 1
SupportsDepthPeelTransparency: 1
SupportsAlignVertexCenters: 1
Extensions: {322x1 cell}
MaxFrameBufferSize: 16384

Sign in to comment.


Bruno Luong
Bruno Luong on 11 Nov 2015
There is a hope that TMW might able to fix it, since HG1 can handle well new driver.
  2 Comments
Mike Garrity
Mike Garrity on 11 Nov 2015
Bruno, did you delete the comment I was responding to in my last comment above? That's really not a good practice.
And no, the fact that HG1 worked on a card with an unsupported driver doesn't tell you much. When nVidia's drivers find an unsupported card, they pass through the calls which that card supports and emulate the others using a software implementation. It's quite likely that HG1 didn't use any features which were outside the subset that it could pass through, while HG2 is using some feature that is emulated. We can't know that we should not use this feature in this case because the driver tells us it is a supported feature.
Bruno Luong
Bruno Luong on 13 Nov 2015
Edited: Bruno Luong on 13 Nov 2015
No, I did not delete anything, at least not intentionally. It might be possible that I make a mistake. I'm still not very familiar with ANSWER interface.
Sorry if I did.
Edit: I'm sure I did not since I can only see [Delete] over my own posts

Sign in to comment.


Bruno Luong
Bruno Luong on 11 Nov 2015
On my LAPTOP with Nvidia GF 730M I can't get the FPS above 12, regardless the driver (up to 385.91 where I install about a week).
Things is we never have to care about that kind of "details" with HG1. It's kind of scary now that we have to look at HW and driver, and I can hardly enforce my clients to follow such restrictive PC requirement. And even if we select the best HW and drivers there are still some significant drop up of graphical rendering between HG1 and HG2, at least for my application.
  1 Comment
Mike Garrity
Mike Garrity on 11 Nov 2015
Again, it would really be helpful if you could pass along some details of your application. I'd love to see what the bottleneck is. It would also help us in developing tools to make this sort of analysis easier for users to do themselves.
And yes, we are aware of the tradeoffs in taking advantage of new graphics features. We feel quite a bit of angst every time we add something which isn't available on all cards. But we also have to pay attention to the fact that some users have bought powerful cards with a lot of capabilities that they would like to take advantage of from within MATLAB.

Sign in to comment.


Xiangrui Li
Xiangrui Li on 4 Jan 2018
Edited: Xiangrui Li on 4 Jan 2018
I found this thread while looking for solutions to speed up patch update. My figure has four patches, each with ~32k vertices. Even after I avoid patch overlays by combining into one patch at each axis, the figure update still takes ~600 ms while my computation takes only ~20 ms. This is measured as following after updating data:
set(hPatch, 'FaceVertexData', updatedData);
tic; drawnow; toc
I tried various ways recommended by Matlab and above tips, including changing axis mode to manual, doubleBuffer off for figure, flat faces instead of interp faces, and uint8 rather than single FaceVertexData. None of these gives significant speedup in my case.
The only effective way I found so far is to change VertexNormalsMode from default 'auto' to 'manual'. This reduces ~600 ms to ~200 ms. This is against the documentation, since I create patch by setting Faces and Vertices only, so rely on 'auto' VertexNormals. It will fail normally, but my trick is to 'drawnow' once after setting Faces and Vertices, then change VertexNormalsMode to 'manual'. 200 ms is still sluggish visually, but it is the best I have for now.
Note that this behavior is consistent among Windows/Linux/OSX and multiple Matlab versions I have tested.
  1 Comment
Walter Roberson
Walter Roberson on 4 Jan 2018
tic; drawnow; toc measures the time it takes to submit the graphics commands to the multithreaded graphics back-end; that back-end will then proceed asynchronously to update the screen as it computes what should be displayed.

Sign in to comment.

Categories

Find more on Graphics Performance in Help Center and File Exchange

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!