Patch performance with caxis?

Is there any way I can improve the performance of patch objects with respect to changing caxis settings or the figure's colourmap?
I have something like the following setup, with an image overlaid by many patch objects (e.g. 60 patch objects, each with ~1300 faces). The patches are all defined with a single colour as [r g b], not indexed into the current colourmap so they do not change with respect to the colourmap or its scaling.
(Note: this is just an example image I created for testing, not my real data, but it should give the idea - the red octagons are patches here)
I wish to be able to change either the underlying image or the colourmap for that image. I have a setup to do this which just replaces the 'CData' of the existing image object for the former meaning that the overlaid patch objects theoretically do not need to be altered at all.
However, the different base images I have are scaled differently so I have to use a caxis instruction after changing the image. This is annoyingly slow to update the image (when I remove the caxis instruction the image updates close to instantaneously). If I don't have the patches overlaid then the image updates almost immediately so it is clearly the patches that are slowing it down.
So is there some setting on patches that I am missing that is causing them to react to the colourmap changing (via caxis or the whole colourmap changing) or is there nothing I can do about this? I had hoped the fact I am setting the patch colour using true [r g b] colour would mean they would be unaffected by caxis type changes and would not need to be redrawn.

3 Comments

I think the whole scene always gets redrawn, regardless of which individual objects need updating (at least that's how it used to work). If your patches never need updating, perhaps you could render them once, then save them to an image (hardcopy function) and then plot them as an image object instead of as patches? (So your scene now consists of a truecolor image with transparency overlayed on a cdata-scaled image) I do this when complex static objects are slowing down my rendering. Not sure if it's appropriate for your actual needs though....
Other idea: if the slowness is in fact linked to updating the cdata of the axes, perhaps plot the patch objects in a separate axes that is overlayed on top of the axes that contains the image? (linked with linkaxes if necessary)
Adam
Adam on 18 Nov 2014
Edited: Adam on 18 Nov 2014
Thanks for the suggestions. I will have a play around with this idea tomorrow. I've never used axes on top of each other before so hadn't thought of that as an option.
The first option is one I have considered, but the patches do need to update regularly in response to other changes so this may not be suitable. It is just changes to the base layer specifically to which they do not need to react.
When the patches themselves actually recalculate I use a drawnow instruction so they appear one after the other which is acceptable for the few seconds they take to all appear, just like a progressbar, but when they are just clogging up the rendering when I change caxis they remain there, I just have a wait those few seconds where it looks like nothing is happening.

Sign in to comment.

 Accepted Answer

Doug Hull
Doug Hull on 18 Nov 2014
Edited: Doug Hull on 18 Nov 2014
Mike Garrity showed me this example earlier with respect to patch:
>> 2.4814 frames per second
>> 20.6223 frames per second
cla
nfaces = 5000;
nsides = 6;
nframes = 20;
ang = linspace(0,2*pi,nsides+1)
x = repmat(cos(ang)',[1 nfaces]);
y = repmat(sin(ang)',[1 nfaces]);
z = repmat([1:nfaces],[(nsides+1) 1]);
xoff = repmat(randn(1,nfaces),[nsides+1, 1]);
yoff = repmat(randn(1,nfaces),[nsides+1, 1]);
h = patch(x+xoff,y+yoff,z,z);
h.FaceColor = 'flat';
h.EdgeColor = 'none';
xlim([-8 8])
ylim([-8 8])
tic
for i=1:nframes
xoff = repmat(randn(1,nfaces),[nsides+1, 1]) / 10;
yoff = repmat(randn(1,nfaces),[nsides+1, 1]) / 10;
h.Vertices = h.Vertices + [xoff(:), yoff(:), zeros(nfaces*(nsides+1),1)];
drawnow;
end
disp([num2str(nframes/toc) ' frames per second'])
f = h.Faces;
if size(f,2) > 3
f2 = [];
f2 = [f2; f(:,1), f(:,2), f(:,3)];
f2 = [f2; f(:,1), f(:,3), f(:,4)];
f2 = [f2; f(:,1), f(:,4), f(:,5)];
f2 = [f2; f(:,1), f(:,5), f(:,6)];
end
h.Faces = f2;
xlim([-8 8])
ylim([-8 8])
tic
for i=1:nframes
xoff = repmat(randn(1,nfaces),[nsides+1, 1]) / 10;
yoff = repmat(randn(1,nfaces),[nsides+1, 1]) / 10;
h.Vertices = h.Vertices + [xoff(:), yoff(:), zeros(nfaces*(nsides+1),1)];
drawnow;
end
disp([num2str(nframes/toc) ' frames per second'])
By simplifying the patches into triangles, things went faster.

5 Comments

Just to give some context here. What Doug is showing here is a technique called "pretriangulating".
What's going on is that you have a bunch of polygons, but the graphics card wants triangles. So when you change the data of the patch object, it needs to convert your polygons into triangles. That can be expensive because it doesn't realize that you've got nice, simple convex polys, so it's running a triangulation algorithm that can handle anything.
But you know more than the patch object does here. You know that you're not changing the shape of the polygons, you're just changing their colors. This means that you can triangulate once and reuse the triangulation. You also know that they're nice, simple convex polygons. Therefore you can easily triangulate those once and reuse them.
The same goes for that example code Doug posted above. That's changing the vertices, but it's adding a constant offset to each polygon. That means that the triangulation isn't changing and we can just do it once. If the shape of the polygons was changing between frames, then we would need to let patch do the triangulation for us.
Does that make sense? I've been planning to do a blog post on this at some point because it's a little complicated, but it is a useful tool to have available when you're performance tuning.
Very interesting! I would love to see a blog post about this.
Thanks for the reply and comments. I will digest this back in work tomorrow morning since I am still on Matlab R2014a at home (and it's evening!!).
Adam
Adam on 19 Nov 2014
Edited: Adam on 19 Nov 2014
I've decided to leave this for now, but this is definitely very interesting and deserving of a blog post for a wider audience.
The example I posted above is rather simpler than my true data which is actually a series of signals for which I wish to fill the peaks down to the zero-crossing line which is where my patches come in.
So I may well try your technique at home if I find some time as triangulating signal data is not too difficult, but it is slightly beyond what I need to solve right now so I can live with this problem that is only really significant is I use an extreme parametrisation.
Thanks again for the input.

Sign in to comment.

More Answers (1)

It might help if you can consolidate your multiple patch objects into one many-faced patch. I've found that this usually speeds up rendering immensely. If the faces have different numbers of vertices, I just pad out by repeating the last one:
xp = [0 0 1 1 0; 1 1.5 2 1 1]';
yp = [0 1 1 0 0; 0 1 0 0 0]';
hp = patch(xp, yp, 'k');
set(hp, 'FaceColor', 'flat', 'FaceVertexCData', [1 0 0; 1 1 0]);

3 Comments

Thanks. I'll have a play around with this tomorrow. Certainly the rendering is slower the more patches I have, although I don't know at the moment how the number of vertices affect the speed (e.g. one patch of 80,000 vertices rather than 60 of 1300 each).
That number shouldn't be a problem... I've used a similar technique to visualize triangular meshes with over 100,000 vertices (and 200,000 faces). Takes a second or two to render initially but it doesn't bog down like a figure will when you have a ton of graphics objects.
Unfortunately in my case this appears to be no faster than using one patch per shape. Maybe the nature of my patches is such that converting them to faces is no help. I had thought though that the much smaller number of graphics objects would help.

Sign in to comment.

Categories

Find more on Graphics Performance in Help Center and File Exchange

Products

Asked:

on 18 Nov 2014

Edited:

on 19 Nov 2014

Community Treasure Hunt

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

Start Hunting!