# Plotting A Large Number Of Patches

5 views (last 30 days)
Edited: ADSW121365 on 19 Oct 2020
There are a few older topics on this, but nothing I could find which is directly relevent I don't think. I'm utilising a modified version of: Olivier (2020). PLOTCUBE ( https://www.mathworks.com/matlabcentral/fileexchange/15161-plotcube ), MATLAB Central File Exchange to plot some images of a cubic discretisation e.g:
function PLOTTER(Coords,objprop)
for index = 1:length(Coords.Lo.X(:))
plotcube([Coords.dX;Coords.dY;Coords.dZ]'...
,[Coords.Lo.X(index);Coords.Lo.Y(index);Coords.Lo.Z(index)]',...
.5,objprop(index)); hold on;
%Object Prop Defines Colormap
end
end
function plotcube(varargin)
% PLOTCUBE - Display a 3D-cube in the current axes
%
% PLOTCUBE(EDGES,ORIGIN,ALPHA,COLOR) displays a 3D-cube in the current axes
% with the following properties:
% * EDGES : 3-elements vector that defines the length of cube edges
% * ORIGIN: 3-elements vector that defines the start point of the cube
% * ALPHA : scalar that defines the transparency of the cube faces (from 0
% to 1)
% * COLOR : 3-elements vector that defines the faces color of the cube
%
% Example:
% >> plotcube([5 5 5],[ 2 2 2],.8,[1 0 0]);
% >> plotcube([5 5 5],[10 10 10],.8,[0 1 0]);
% >> plotcube([5 5 5],[20 20 20],.8,[0 0 1]);
% Default input arguments
inArgs = { ...
[10 56 100] , ... % Default edge sizes (x,y and z)
[10 10 10] , ... % Default coordinates of the origin point of the cube
.7 , ... % Default alpha value for the cube's faces
[1 0 0] ... % Default Color for the cube
};
% Replace default input arguments by input values
inArgs(1:nargin) = varargin;
% Create all variables
[edges,origin,alpha,clr] = deal(inArgs{:});
XYZ = { ...
[0 0 0 0] [0 0 1 1] [0 1 1 0] ; ...
[1 1 1 1] [0 0 1 1] [0 1 1 0] ; ...
[0 1 1 0] [0 0 0 0] [0 0 1 1] ; ...
[0 1 1 0] [1 1 1 1] [0 0 1 1] ; ...
[0 1 1 0] [0 0 1 1] [0 0 0 0] ; ...
[0 1 1 0] [0 0 1 1] [1 1 1 1] ...
};
XYZ = mat2cell(...
cellfun( @(x,y,z) x*y+z , ...
XYZ , ...
repmat(mat2cell(edges,1,[1 1 1]),6,1) , ...
repmat(mat2cell(origin,1,[1 1 1]),6,1) , ...
'UniformOutput',false), ...
6,[1 1 1]);
cellfun(@patch,XYZ{1},XYZ{2},XYZ{3},...
repmat({clr},6,1),...
repmat({'FaceAlpha'},6,1),...
repmat({alpha},6,1)...
);
view(3);
I'm encountering two issues, both which I believe are related to the fact I'm rendering this using many patches.
First, if I have a large number of cubes, I'm no longer able to interact with the figure (but there's no obvious CPU/GPU strain either: 4690K 4.7GHz overclock + GTX 1060).
Secondly, when I'm comparing a large number of algorithms i.e producing many plots, I'm finding MATLAB crashes or encounters low-level graphics errors once I reach around 30 plots (216 cubes per plot).
I think this is likely poor coding/utilisation of MATLAB visualisation abilities rather than a case of MATLAB being unable to achieve my intention. Any thoughts on a more efficient way to render these plots, particularily for larger numbers of cubes would be greatly appreciated, noting the transpancy of the cubes is important to be able to visulise any internal structures.

Kelly Kearney on 16 Oct 2020
Creating a single multi-faceted patch is much, much more efficient than plotting lots of single-face patches. In the figure you show, you're plotting 216 cubes, with 6 faces each, for a total of 1296 faces. Using the code above, you're creating that many individual patch objects, and each one comes with a lot of graphics overhead.
Instead, plot one patch with 1296 faces:
XYZ = { ...
[0 0 0 0] [0 0 1 1] [0 1 1 0] ; ...
[1 1 1 1] [0 0 1 1] [0 1 1 0] ; ...
[0 1 1 0] [0 0 0 0] [0 0 1 1] ; ...
[0 1 1 0] [1 1 1 1] [0 0 1 1] ; ...
[0 1 1 0] [0 0 1 1] [0 0 0 0] ; ...
[0 1 1 0] [0 0 1 1] [1 1 1 1] ...
};
% Faces for a single unit cube (6 faces)
xcube = cat(1, XYZ{:,1})';
ycube = cat(1, XYZ{:,2})';
zcube = cat(1, XYZ{:,3})';
% Many cubes
[x0, y0, z0] = ndgrid(1:6); % corner coordinates
col = zeros(size(x0)); % color index
col(:,:,end) = 2;
xall = arrayfun(@(a) a+xcube, x0(:), 'uni', 0);
yall = arrayfun(@(a) a+ycube, y0(:), 'uni', 0);
zall = arrayfun(@(a) a+zcube, z0(:), 'uni', 0);
xall = cat(2, xall{:});
yall = cat(2, yall{:});
zall = cat(2, zall{:});
col = kron(col(:)', ones(1,6)); % expand colors to all 6 faces
% Plot
p = patch(xall, yall, zall, col, 'facealpha', 0.1);
view(3);

I'm trying to work with this method to create the functionality I currently use with and could use a little more direction if that's possible. I wrote a function using your code above (the plot is phenomenally better as you'd likely expect):
function plotcube_2v(x0,y0,z0,col,alpha)
%plotcube_2v: Takes Corner Coordinates [x0,y0,z0], edge lengths of cubes dX dY dZ and a colormap col
% Ref: Kelly Kearney on 16 Oct 2020 at 22:49 https://uk.mathworks.com/matlabcentral/answers/614643-plotting-a-large-number-of-patches
% Faces for a single unit cube (6 faces)
XYZ = { ...
[0 0 0 0] [0 0 1 1] [0 1 1 0] ; ...
[1 1 1 1] [0 0 1 1] [0 1 1 0] ; ...
[0 1 1 0] [0 0 0 0] [0 0 1 1] ; ...
[0 1 1 0] [1 1 1 1] [0 0 1 1] ; ...
[0 1 1 0] [0 0 1 1] [0 0 0 0] ; ...
[0 1 1 0] [0 0 1 1] [1 1 1 1] ...
};
xcube = cat(1, XYZ{:,1})';
ycube = cat(1, XYZ{:,2})';
zcube = cat(1, XYZ{:,3})';
xall = arrayfun(@(a) a+xcube, x0(:), 'uni', 0);
yall = arrayfun(@(a) a+ycube, y0(:), 'uni', 0);
zall = arrayfun(@(a) a+zcube, z0(:), 'uni', 0);
xall = cat(2, xall{:});
yall = cat(2, yall{:});
zall = cat(2, zall{:});
col = kron(col(:)', ones(1,6)); % expand colors to all 6 faces
p = patch(xall, yall, zall, col, 'facealpha', alpha);
view(3);
end
This however doesn't perform quite as I'd hoped. Using the same coordinates as in my previous method (Uniform_Cube_Mesh attached, .Lo.X gives bottom corner X coordinates etc) I get a figure with spaces between my cubes:
I can 'bodge' fix this by changing:
xall = arrayfun(@(a) a+xcube, x0(:)./dX(:), 'uni', 0);
yall = arrayfun(@(a) a+ycube, y0(:)./dY(:), 'uni', 0);
zall = arrayfun(@(a) a+zcube, z0(:)./dZ(:), 'uni', 0);
However if I try a varied grid (Varied_Cubes_Mesh attached, same structure) I would expect a figure:
I'm aware this is because my bodge fix isn't the actual solution. I've been working on this since your previous reply but am struggling to fix the error.
Kelly Kearney on 19 Oct 2020
Just looking at it quickly (haven't tested the code), I would suggest updating the xall/yall/zall equation to:
xall = arrayfun(@(a,b) a+xcube.*b, x0(:), dx(:), 'uni', 0);
where dx is an array the same size as x0, specifying the length of each cube in the x direction. And repeat the same for the y and z dimensions.
Worked like a charm, thanks so much! I can plot 216000 cubes and still manipulate my figure!

R2020a

### Community Treasure Hunt

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

Start Hunting!