How to keep indexed colors of patches, when switching to Face-Vertex syntax.

33 views (last 30 days)
I'm trying to translate some code from the patch(X,Y,Z,... syntax to the patch("Faces",...,"Vertices",... syntax. I want to preserve direct mapping from the colormap. In the example code below, how should the patch call in the true branch be changed to mimic the results of the patch call in the false branch?
function patchComparison(useFaceVertex)
faces = { [0,0,0;
1.5,0,0;
1.5,1.5,0;
0,1.5,0] ;
[2,0,1;
4,0,1;
3,sqrt(3),1] ;
[1,2,2;
2,3,2;
1,4,2;
0,3,2]};
figure;
for index = 1 : size(faces,1)
ddata = faces{index};
if useFaceVertex
patch("Faces", 1:size(ddata,1), "Vertices", ddata, ...
"FaceVertexCData", index, "FaceColor", 'flat', ...
"CDataMapping", 'direct', "FaceVertexCDataMode", "manual");
else
patch(ddata(:,1), ddata(:,2), ddata(:,3), index);
end
end
end
  1 Comment
Stephen23
Stephen23 on 3 Dec 2025 at 10:23
Edited: Stephen23 on 3 Dec 2025 at 13:40
Original colors:
faces = {...
[0,0,0; 1.5,0,0; 1.5,1.5,0; 0,1.5,0];...
[2,0,1; 4,0,1; 3,sqrt(3),1];...
[1,2,2; 2,3,2; 1,4,2; 0,3,2]};
% Left
subplot(1,2,1);
for index = 1:size(faces,1)
ddata = faces{index};
patch(ddata(:,1), ddata(:,2), ddata(:,3), index);
end
view(3)
title('Original: X, Y, Z, C');
% Right
subplot(1,2,2);
for index = 1:size(faces,1)
ddata = faces{index};
patch("Faces", 1:size(ddata,1), "Vertices", ddata, ...
"FaceVertexCData", index, "FaceColor", 'flat', ...
"CDataMapping", 'direct',...
"FaceVertexCDataMode", "manual");
end
view(3);
title('Faces & Vertices (direct)');
Note that even though they look the same color, those shapes on the right actually are different colors, corresponding to the colormap rows 1, 2, & 3 (due to the "direct" mapping). We can confirm this quite easily:
pah = gca().Children;
cmap = colormap(gca);
cmap(3:-1:1,:)
ans = 3×3
0.2464 0.1569 0.6847 0.2444 0.1534 0.6728 0.2422 0.1504 0.6603
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
for k = 1:numel(pah)
x = pah(k).FaceVertexCData;
cmap(x,:)
end
ans = 1×3
0.2464 0.1569 0.6847
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1×3
0.2444 0.1534 0.6728
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
ans = 1×3
0.2422 0.1504 0.6603
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>

Sign in to comment.

Accepted Answer

Stephen23
Stephen23 on 3 Dec 2025 at 9:19
Edited: Stephen23 on 3 Dec 2025 at 9:25
Solution:
Use "scaled" in place of "direct":
patch("Faces", 1:size(ddata,1), "Vertices", ddata, ...
"FaceVertexCData", index, ...
"FaceColor", 'flat', ...
"CDataMapping", 'scaled', ... <--------- this here !
"FaceVertexCDataMode", "manual");
Explanation
When translating from patch(X,Y,Z,C) to patch('Faces',F,'Vertices',V) with scalar color values, the key is understanding how MATLAB interprets color data differently in each case.
The original code was
patch(ddata(:,1), ddata(:,2), ddata(:,3), index);
By default this uses CDataMapping set to 'scaled', which means the color values are scaled to span the colormap based on the axes color limits (CLim). When you have values 1, 2, and 3 across multiple patches, MATLAB automatically scales these to map to different colors across the colormap.
The correct translation is:
patch("Faces", 1:size(ddata,1), "Vertices", ddata, ...
"FaceVertexCData", index, ...
"FaceColor", 'flat', ...
"CDataMapping", 'scaled', ... <--------- this here !
"FaceVertexCDataMode", "manual");
The critical points are:
  1. Use FaceVertexCData with a scalar value (index) to specify one color per patch face
  2. Set FaceColor to 'flat' for uniform face coloring
  3. Set CDataMapping to 'scaled' (not 'direct') to match the default behavior of patch(X,Y,Z,C)
  4. Set FaceVertexCDataMode to 'manual' to prevent automatic color assignment via SeriesIndex. Because we already set FaceVertexCData this should change automatically, but it does not hurt the code clarity to set it explicitly.
If you mistakenly set CDataMapping to 'direct' then the values 1, 2, 3 are interpreted as direct indices into the colormap. Since the first few entries in most colormaps (like parula) are very similar colors, all patches appear nearly the same color. With 'scaled' mapping, MATLAB scales the range of values (1 to 3) to span a wider portion of the colormap, producing visually distinct colors.
  3 Comments
John
John on 3 Dec 2025 at 15:56
Thank you. That's a good explanation. (Bonus points for putting the two plots side by side! Makes for a nice presentation.)
Curiosity question: When does scaling happen? If an additional call to patch is made with a larger value for C than all previous calls, I would assume the colors of all patches would change?
Stephen23
Stephen23 on 3 Dec 2025 at 17:01
Edited: Stephen23 on 3 Dec 2025 at 19:52
"When does scaling happen?"
humm... I don't really know what kind of magic is going on here. I guess that "scaled" is always subject to change, depending on any future data. You could try your example loop with PAUSE and DRAWNOW to see when the change actually occur.
"If an additional call to patch is made with a larger value for C than all previous calls, I would assume the colors of all patches would change?"
I guess so, as that is effectively all your loop is doing. If you want exact control over the colors you could build an appropriate colormap (e.g. with exactly three colors for your example) and use "direct".

Sign in to comment.

More Answers (0)

Categories

Find more on Color and Styling in Help Center and File Exchange

Products


Release

R2025a

Community Treasure Hunt

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

Start Hunting!