How to color surface with stronger contrast

2024/4/15 2:07:54

In Matlab, I am trying to plot a function on 2-dim Euclidean space with following code

Z=(1.-X).^2 + 100.*(Y-X.*X).^2;
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 npfig = 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")

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:

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.

Related Q&A

How to know that the interpreter is Jython or CPython in the code? [duplicate]

This question already has answers here:Can I detect if my code is running on cPython or Jython?(5 answers)Closed 9 years ago.Is there a way to detect that the interpreter that executes the code is Jyt…

Regular expression - replace all spaces in beginning of line with periods

I dont care if I achieve this through vim, sed, awk, python etc. I tried in all, could not get it done.For an input like this:top f1 f2 f3sub1 f1 f2 f3sub2 f1 f2 …

Writing append only gzipped log files in Python

I am building a service where I log plain text format logs from several sources (one file per source). I do not intend to rotate these logs as they must be around forever.To make these forever around f…

How to configure bokeh plot to have responsive width and fixed height

I use bokeh embedded via the components function. Acutally I use :plot.sizing_mode = "scale_width"Which scales according to the width and maintains the aspect ratio. But I would like to have …

Matplotlib show multiple images with for loop [duplicate]

This question already has an answer here:Can I generate and show a different image during each loop?(1 answer)Closed 8 years ago.I want to display multiple figure in Matplotlib. Heres my code:for i in…

How do I efficiently fill a file with null data from python?

I need to create files of arbitrary size that contain no data. The are potentially quite large. While I could just loop through and write a single null character until Ive reached the file size, that s…

Setting specific permission in amazon s3 boto bucket

I have a bucket called ben-bucket inside that bucket I have multiple files. I want to be able to set permissions for each file URL. Im not too sure but Im assuming if I wanted URL for each file inside …

Create new column in dataframe with match values from other dataframe

Have two dataframes, one has few information (df1) and other has all data (df2). What I am trying to create in a new column in df1 that finds the Total2 values and populates the new column accordingly…

MYSQL- python pip install error

I tried to get build an app on Django and I wanted to use MySQL as the database. After setting up the right, I tried to migrate. Then I got the obvious error saying that MySQL is not instal…

How to do a boxplot with individual data points using seaborn

I have a box plot that I create using the following command: sns.boxplot(y=points_per_block, x=block, data=data, hue=habit_trial)So the different colors represent whether the trial was a habit trial or…