Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to color surface with stronger contrast

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:

enter image description here

I hope to color the surface with stronger contrast, just as Wikipedia shows enter image description here

The plot in Wikipedia is drawn with Python code:

from mpl_toolkits.mplot3d import Axes3D
from matplotlib import cm
from matplotlib.colors import LogNorm
import 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!

like image 830
Tim Avatar asked Feb 22 '11 04:02

Tim


2 Answers

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:

enter image description here


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

enter image description here

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)]);

enter image description here

This should generally give better contrast than the C = Z default surface coloring.

like image 68
gnovice Avatar answered Oct 06 '22 00:10

gnovice


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.

like image 26
Marcin Avatar answered Oct 06 '22 00:10

Marcin