What exactly is this 3D object inside my axis and how to attach it to a colormap?

1 view (last 30 days)
I have a figure that was generated by a collaborator, and it's a result of some kind of integration with COMSOL, a software for doing simulations. The simulation was done in COMSOL, and the output is generated as a .fig file so it can be viewed in Matlab. This is what I get (though I removed the x and y-axis labels):
I can't quite figure out exactly what kind object (is that the correct terminology?) is actually inside the axis. Because it looks like a surface plot in the sense that I can look at the 3D structure from any angle. But when I try to change the colormap, only the color bar changes. From browsing other questions, etc., my understanding is that only some objects that can be inside an axis are actually tied to a colormap. And a surface plot is one of them. But if this is not a surface plot, then what is it? How can it still have a 3D shape?
And--more importantly for practical purposes--how do I force it to use a colormap which I can then control and change? Ultimately I want to manipulate the colors to make it match the coloring scheme in my other figures.
EDIT: attached figure file

Accepted Answer

Stephen23 on 8 May 2020
Edited: Stephen23 on 11 May 2020
That figure contains four objects, the fourth one listed is the main axes:
>> fgh = openfig('Resultplot_ID3.fig');
>> fgh.Children
ans =
4x1 graphics array:
Toolbar (plotnavigation)
Menu (&COMSOL)
Axes (Surface: Displacement field, Z component (m))
The main axes has just one child object, which is a patch object:
>> pah = fgh.Children(4).Children;
>> pah.Type
ans =
Patches have several ways of defining their colors based on the axes colormap, explained here:
But the patch in your figure does not use any of those. It uses what the MATLAB documentation calls "truecolor", where the color is explicitly defined using RGB values, and has absolutely nothing to do with the axes colormap.
>> size(pah.CData) % truecolor (i.e. RGB), nothing to do with the colormap!
ans =
3 114912 3
You can read more about how that works in the patch documentation, e.g.:
"... how to attach it to a colormap?"
The answer is that you would have to replace the truecolor RGB values in CData and/or FaceVertexCData with indices into the colormap, following the array sizes given in the documentation. Unfortunately MATLAB makes it a bit tricky to get the original colormap data (does anyone know a better way?), but the rest is quite simple:
>> warning off
>> S = load('Resultplot_ID3.fig','-mat'); % import as a structure
>> warning on
>> old = S.hgS_070000.children(2).properties.Colormap; % old colormap
>> image(permute(old,[3,1,2])) % optional: view the colormap
>> [idx,idy] = ismember(pah.FaceVertexCData,old,'rows'); % indices of patch colors in colormap
>> all(idx) % check that all colors used in patch exist in colormap
ans =
>> pah.FaceVertexCData = idy; % replace truecolor with indices
>> pah.CDataMapping = 'direct';
Now the patch colors are "attached" to the colormap, exactly as you requested. This only needs to be done once: after that you can simply change the figure colormap to any which has 256 colors, e.g.:
>> colormap(fgh,autumn(256)) % any colormap you want, must be 256 colors!
Alternatively you could have to update the CData and/or the FaceVertexCdata properties with new RGB values, but this requires updating those arrays everytime you want to change the colormap (i.e. it does not actually "attach" the patch colors to the colormap as you request).
  1 Comment
Alexei M
Alexei M on 12 May 2020
This is great, thank you! This method does mess up the scale by the color bar, which represented units of length. But I guess what you said at the end about updating CData/FaceVertexCdata properties would prevent that. Oh well, this works for me--I'm doing image editing later anyway, so the changed scale values can be redone.

Sign in to comment.

More Answers (1)

Ameer Hamza
Ameer Hamza on 8 May 2020
Edited: Ameer Hamza on 9 May 2020
I am not sure why anyone would use patches instead of a surface object to make such a plot. However, the following shows a simple way to modify the "colormap" of the patches and colorbar
fig = openfig('Resultplot_ID3.fig');
p = findobj(fig, 'type', 'patch');
[clrs, ~, idx] = unique(p.FaceVertexCData, 'rows');
new_colormap = cool; % <<==== new colormap name. It you make a custom colormap, it must have 256 RGB colors
new_colormap(171:end,:) = flipud(new_colormap(171:end,:));
p.FaceVertexCData = new_colormap(idx, :);
Note: As pointed out by Stephen in the comments, the output of unique() is not necessarily an ordered colormap. For the figure you attached in the question, there was just a single discontinuity, so fixing it was easy. However, for a general case, you need another method to first arrange the output of unique() into a colormap. One interesting method is to use HSV colorspace as described here: https://stackoverflow.com/questions/2245842/sorting-colors-in-matlab
Also read the following links

Sign in to comment.





Community Treasure Hunt

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

Start Hunting!