In Matlab, I am trying to plot a function on 2-dim Euclidean space with following code
s=.05;
x=[-2:s:2+s];
y=[-1:s:3+s];
[X,Y]=meshgrid(x,y);
Z=(1.-X).^2 + 100.*(Y-X.*X).^2;
surf(X,Y,Z)
colormap jet
Here is what my plot look like:
I hope to color the surface with stronger contrast, just as Wikipedia shows
The plot in Wikipedia is drawn with Python code:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.colors import LogNorm
impo开发者_如何学Gort matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = Axes3D(fig, azim = -128, elev = 43)
s = .05
X = np.arange(-2, 2.+s, s)
Y = np.arange(-1, 3.+s, s)
X, Y = np.meshgrid(X, Y)
Z = (1.-X)**2 + 100.*(Y-X*X)**2
ax.plot_surface(X, Y, Z, rstride = 1, cstride = 1, norm = LogNorm(), cmap = cm.jet)
plt.xlabel("x")
plt.ylabel("y")
plt.show()
My Matlab code and the Wikipedia Python code seem to both use "jet" as colormap, but their actual mappings of height value to color are different. So I was wondering how I can get similar coloring in Matlab?
Thanks and regards!
You can achieve a similar appearance by:
- Setting the
'EdgeColor'
property of the surface object to'none'
to remove edge coloring. - Modifying the
'CData'
property of the surface to mimic the log-scaling of the color data in the Python code.
Here's how you can modify your code:
s = .05;
x = [-2:s:2+s];
y = [-1:s:3+s];
[X, Y] = meshgrid(x, y);
Z = (1.-X).^2 + 100.*(Y-X.*X).^2;
minZ = min(Z(:)); % Find minimum value of Z
maxZ = max(Z(:)); % Find maximum value of Z
C = minZ+(maxZ-minZ).*log(1+Z-minZ)./log(1+maxZ-minZ); % Create a log-scaled
% set of color data
surf(X, Y, Z, C, 'EdgeColor', 'none');
colormap jet
And here's the resulting plot:
How the log-scaling works...
The log-scaled Z
data which is used to produce the color data C
causes the red-orange range of the jet color map to be used by more surface points, improving the contrast for this particular surface. The way this works can be visualized with this simple example:
x = 0:5:100; % Create a range of values from 0 to 100
plot(x, x, 'b-*'); % Plot the values as a straight line (y = x) in blue
hold on; % Add to the plot
plot(x, 100.*log(1+x)./log(101), 'r-*'); % Plot a log-scaled version of x in red
colorbar % Display the default jet color map, for comparison
The original blue points are evenly distributed across the range of colors they correspond to in the color bar on the right. When log-scaled, these points are shifted upward to the red line. Notice how this results in a reduced density of points in the lower blue-green range and an increased density of points in the red-orange range.
Getting better contrast in general...
For the particular surface used here log-scaling of the color data helps use a greater range of the color map across all the points on the surface. Since there are many points at lower height (i.e. color index) values, the log-scaling spreads these low points out more to use a wider range of colors in the large trough of the surface.
However, if you want to improve the contrast for an arbitrary surface by making better use of the range of your color map, log-scaling won't always work. A general solution that may work better is to sort all of the height values for your surface in ascending order, then map these to a linear range that spans your entire color map. Here's what you would get if you do this for your above surface:
C = Z;
[~, index] = sort(C(:));
C(index) = 1:numel(index);
h = surf(X, Y, Z, C, 'EdgeColor', 'none');
colormap jet
caxis([1 numel(index)]);
This should generally give better contrast than the C = Z
default surface coloring.
Straight out of the help page for colormap:
Files in the color folder generate a number of colormaps. Each file accepts the colormap size as an argument. For example,
colormap(hsv(128)) creates an hsv colormap with 128 colors. If you do not specify a size, a colormap the same size as the current colormap is created.
I've used this feature to change the range of colors to make a better use of the available spectrum.
精彩评论