Question about speeding up line plotting

12 views (last 30 days)
Brian
Brian on 24 Feb 2016
Commented: Mike Garrity on 25 Feb 2016
Hello, thanks for reading this,
What I do currently in some MATLAB code is plot3 a series of lines, defined by a beginning and end point. I have 3d coordinate info stored in a nx3 pt matrix, and the connectivity information stored in a mx2 matrix. The data can look something like:
ptMx = [-0.0004 0.0003 1.9039
-0.0004 0.0003 1.1424
-0.1502 0.0001 0.6856
0.1397 0.0004 0.6853];
faceMx = [1 2
2 3
2 4]
So point 1 is connected to point 2, 2 to 3, and 2 to 4. I plot these with the following code:
for i=1:size(faceMx,1)
hold on
plot3([ptMx(faceMx(i,1),1) ptMx(faceMx(i,2),1)], ...
[ptMx(faceMx(i,1),2) ptMx(faceMx(i,2),2)], ...
[ptMx(faceMx(i,1),3) ptMx(faceMx(i,2),3)])
end
So as you can see, I go through every element and hold on a plot3 line. My problem is this can take a very large amount of time, and it makes rotating/translating the plot very slow. Is there a better/faster way to draw a series of lines this way?
Thanks!
EDIT: I know I can switch plot3 to line to speed this up a little bit, I was hoping if there was a better way available. Sometimes, I can be plotting up to 50k lines, and during these times patches of surface meshes with triangle patches with a similar number is many times faster.

Accepted Answer

Mike Garrity
Mike Garrity on 24 Feb 2016
I did a post on the MATLAB Graphics blog a while back about this.
Basically you want to batch your graphics up into bigger chunks. The graphics card is really best when it's getting hundreds or thousands of lines per object. You really don't need to change the type of graphics object in this case though. Just use nans to combine disjoint strips together.
Your example would look something like this:
nlines = size(faceMx,1);
x = zeros(3,nlines);
y = zeros(3,nlines);
z = zeros(3,nlines);
for i=1:nlines
x(:,i) = [ptMx(faceMx(i,1),1); ptMx(faceMx(i,2),1); nan];
y(:,i) = [ptMx(faceMx(i,1),2); ptMx(faceMx(i,2),2); nan];
z(:,i) = [ptMx(faceMx(i,1),3); ptMx(faceMx(i,2),3); nan];
end
plot3(x(:),y(:),z(:))
I'm assuming here that nlines is actually much larger than 3. As you can see from the performance charts in that blog post, you're not really going to see benefits from this approach until the number of line segments is quite large.
Also, be sure to check out the comments at the end of that blog post. Several readers made very good suggestions on how to improve your graphics performance.
  6 Comments
Mike Garrity
Mike Garrity on 25 Feb 2016
I'm not sure that anyone thinks that patch is simpler than line. It's interface is a bit complicated. On the other hand, all of those features do give you more control. For example, if I combine multiple segments into one line object, then they're all going to get the same color. But if I do the same thing with a patch object, then I can control the colors of the individual segments. Unfortunately, linewidth per segment is not one of the features that patch gives you. As you said, you could use patch to turn each segment into a tube, and that would give you that control. But that's going to be a bit complicated, and I'm note sure I would want to guess whether the performance would really be better once you got the tubes looking just the way you liked.
There's one trick we do in some of the charting objects which you might be able to use here. If you're only using a couple of different line widths, you could create one line object for each, and then keep adding the next segment to the right object. There's a bit of bookkeeping involved, but if it could get you down from thousands of objects to half a dozen, it might be worth it.

Sign in to comment.

More Answers (1)

Walter Roberson
Walter Roberson on 24 Feb 2016
You should be using patch() with ptMx as all your vertices, and your first row of your Faces list would be [1 2 3 4] . That would produce a closed face; if you want an open face then add a vertex at nan as the list
ptMx = [nan nan nan
-0.0004 0.0003 1.9039
-0.0004 0.0003 1.1424
-0.1502 0.0001 0.6856
0.1397 0.0004 0.6853];
faces [2 3 4 5 1; .... ]
  1 Comment
Brian
Brian on 24 Feb 2016
I'm a little bit confused how to make this work programmatically. Can you give me an example I can follow? I will test it when I get in to lab.
I've gotten patch to work in the past by defining points and faces, this was with 3-point faces to make triangles. I got that to work in the past via:
a = patch('XData', ..., 'YData', ..., 'ZData', ..., 'Faces', ...);
I haven't tried it, but would it work this way for lines with 2 point faces?

Sign in to comment.

Community Treasure Hunt

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

Start Hunting!