Say that I have a matrix Z
with some values, and I want to illustrate it by a plotting the values in Z
by height. The first solution comes to mind is a surface, but using surf
and similar functions with small matrices doesn't look good.
So I thought about using something like a 3D bar plot with bar3
. But the problem is that this function always sets the color by the group and not by height, and I can't get it to do so.
Here is an example:
Z = peaks(5);
subplot 121
surf(Z)
title('Surface look bad')
subplot 122
bar3(Z)
title('The color is not by height')
I tried to look for the color properties in the handles returned by bar3
(like CData
and FaceColor
) but got lost with all the values and how they relate to the bars themselves.
Ultimately, I would like to have a general solution that for 2 matrices Z
and C
I can create a 3D bar plot with bars in height given by Z
and color given by C
.
How can I do so?
The function
bar3
returns a surface object, one for each group (i.e. one for each color), so all the bars in one group are essentially plotted as one 'broken' surface. This is explained very good in this answer, so I won't repeat it here.Instead, I'll get to the solution for this specific problem. The relevant property of the surface is
CData
. When we create the bar plot, each surface'sCData
is assigned with a matrix in some size (we'll get to this) that is all equal one value. A different value for each surface. This is how the figure as a whole translates its color map to the color of the groups.As written above (and elaborated in the linked answer), each group represented by a surface, so it takes a whole matrix to define the color at each point of the surface. The first thing we want to do is to get this matrix size:
CData
has always 4 columns (see here why), and the number of rows is always 6*number of groups. This is because it takes 5 vertices to create one closed rectangle with an area object (the last vertex is like the first one) and one line is for spacing between the bars with NaNs, so they will look separated.Next, we need to enlarge our original colormap (which is the same size of
Z
) to fitCData
in the right way. Essentially, we just want to repeat the same value for all vertices that belong to the same bar. AssumingZ
is also our color data (i.e. we color by height) we do:Now we need to split our
z_color
to different cells in the number of our groups. Each cell will contain the coloring data for one surface object:And finally, we apply the new color data to the bar plot:
As a bonus, if we want to remove all zero values from our bar, it can be done easily by setting them to NaN:
All the above could be boiled down to this handy function:
Example of usage:
Result:
While I find EBH's solution aesthetically more pleasing, here there is a simpler solution: interpolation
This is a partial answer.
The case of using the bar height as color is covered by the official MATLAB documentation. Essentially the example code boils down to:
All you need to do afterwards is make sure that the
colormap
is the one you want.