Nonlinear colormap for data that diverges

I have data that goes through divergences where the Z value goes from approximately -4000 to 4000 very rapidly in certain regions, but the vast majority of the data is near zero. In the picture below, to be able to see what is going on I had to scale most of the color values to near zero to properly see what is happening. But in doing so, most of the colors are in the tiny sliver near zero and the red and blue take up the rest. I would like to nonlinearly scale the colorbar to be able to see all of the colors being used and greatly shrink the red and blue color part of the bar, with leaving the raw data as is if possible. It would also be nice if the colorbar ticks would vary nonlinear as well, instead of being forced to have a set number between consecutive ticks.
%Simple Model of divergent data
X = linspace(-2,2,501) + 0.002;
Y = linspace(-2,2,501) + 0.002;
%Function with Positive and Negative Divergence, and most values near 0
Z = zeros(501,501);
for i=1:length(X)
for j=1:length(Y)
Z(i,j) = 1/((X(i) - 1)^2 + (Y(j) - 1)^2) - 1/((X(i) + 1)^2 + (Y(j) + 1)^2) + 5*(cos(X(i))+sin(Y(i)));
end
end
%Setting the colormap
factor = 0.3;
cmap = jet(1000);
map = 999*rescale(1000./(1+exp(-factor*([1:1000]-500))));
cmap2 = cmap(1+fix(map),:);
figure('Position',[200,100,1500,730]);
ax=axes;
[X,Y] = meshgrid(X,Y);
surf(X,Y,Z,'linestyle','none');
a = colorbar;
set(ax,'colormap',cmap2)
view([0,90])

 Akzeptierte Antwort

Voss
Voss am 10 Feb. 2024
Bearbeitet: Voss am 11 Feb. 2024
How about something like this:
%Simple Model of divergent data
X = linspace(-2,2,801) + 0.002;
Y = linspace(-2,2,501) + 0.002;
%Function with Positive and Negative Divergence, and most values near 0
Z = 1./((X - 1).^2 + (Y.' - 1).^2) - 1./((X + 1).^2 + (Y.' + 1).^2) + 5*(cos(X)+sin(Y.'));
Z_scaled = sign(Z).*log10(1+abs(Z));
figure('Position',[200,100,1500,730]);
surf(X,Y,Z_scaled,'LineStyle','none')
view(2)
colormap(jet(1000))
cb = colorbar();
tl = [-10.^(5:-1:1) 0 10.^(1:5)];
cb.Ticks = sign(tl).*log10(1+abs(tl));
cb.TickLabels = tl;
Edited to use Z_scaled = sign(Z).*log10(1+abs(Z)); instead of Z_scaled = sign(Z).*log10(abs(Z));

6 Kommentare

Jared Erb
Jared Erb am 11 Feb. 2024
Thanks for your response. This doesn't quite work, as I dont want the values near 0 to be enhanced due to the log10 making very small numbers large. However having Z_scaled = sign(Z).*log10(1+abs(Z)) works farily well, and is definitely an improvement over what I was doing. But is there any way to have the colorbar values not be logarithmic scaling, and instead a different nonlinear function? I would like to have more color variation focused on the small values, as let's say for all values above 200 and below -200 I would like them to be the same color, because as they diverge so rapidly dedicating colors to the high values is a waste. Currently with your response, for the values I care about (let's say between -10 and 10) there isn't much visibility for how they are changing, and I would like to allocate more of the color range to the values I am more interested in. Having a logarithmic scale would also be fine if there is still a way to allocate more colors to values near 0, and away from extreme values.
Voss
Voss am 11 Feb. 2024
Bearbeitet: Voss am 11 Feb. 2024
How about something like this?
%Simple Model of divergent data
X = linspace(-2,2,801) + 0.002;
Y = linspace(-2,2,501) + 0.002;
%Function with Positive and Negative Divergence, and most values near 0
Z = 1./((X - 1).^2 + (Y.' - 1).^2) - 1./((X + 1).^2 + (Y.' + 1).^2) + 5*(cos(X)+sin(Y.'));
Z_scaled = scaleZ(Z);
figure('Position',[200,100,1500,730]);
surf(X,Y,Z_scaled,'LineStyle','none')
view(2)
colormap(jet(1000))
cb = colorbar();
clim(scaleZ([-200 200]))
tl = [1 2 3 4 6 8 10 20 30 40 50 200];
tl = [-tl(end:-1:1) 0 tl];
cb.Ticks = scaleZ(tl);
cb.TickLabels = tl;
function out = scaleZ(in)
out = sign(in).*log10(1+abs(in));
end
You can change the scaleZ function to use whatever you want, and you can adjust the colorbar ticks/tick-labels as well by changing tl.
Jared Erb
Jared Erb am 11 Feb. 2024
Is it possible to keep the original limits while still having more colors focused on small values?
Voss
Voss am 11 Feb. 2024
Bearbeitet: Voss am 11 Feb. 2024
%Simple Model of divergent data
X = linspace(-2,2,801) + 0.002;
Y = linspace(-2,2,501) + 0.002;
%Function with Positive and Negative Divergence, and most values near 0
Z = 1./((X - 1).^2 + (Y.' - 1).^2) - 1./((X + 1).^2 + (Y.' + 1).^2) + 5*(cos(X)+sin(Y.'));
Z_scaled = scaleZ(Z);
figure('Position',[200,100,1500,730]);
surf(X,Y,Z_scaled,'LineStyle','none')
view(2)
max_Z_val = 200;
n_colors = 1000;
cmap = jet(n_colors);
n_new = n_colors*max(abs(clim()))/scaleZ(max_Z_val);
n_add = round((n_new-n_colors)/2);
cmap = cmap([ones(1,n_add) 1:end end*ones(1,n_add)],:);
colormap(cmap)
cb = colorbar();
tl = [1 5 10 25 50 200 1e3 1e4 1e5];
tl = [-tl(end:-1:1) 0 tl];
cb.Ticks = scaleZ(tl);
cb.TickLabels = tl;
function out = scaleZ(in)
out = sign(in).*log10(1+abs(in));
end
Jared Erb
Jared Erb am 11 Feb. 2024
Yes, this is exactly what I wanted! Thank you so very much for all your help!
Voss
Voss am 11 Feb. 2024
You're welcome!

Melden Sie sich an, um zu kommentieren.

Weitere Antworten (1)

Morgan
Morgan am 10 Feb. 2024
Would something like this work for you?
% CALCULATE MESHGRID
xa = linspace(-2,2,501) + 0.002;
ya = linspace(-2,2,501) + 0.002;
[X,Y] = meshgrid(xa,ya);
% CALCULATE Z
Z = 1./((X - 1).^2 + (Y - 1).^2) - 1./((X + 1).^2 + (Y + 1).^2) + 5*(cos(X)+sin(Y));
% SCALE Z
ZS = sign(Z).*abs(log10(Z));
surf(X,Y,ZS)
axis equal tight
shading interp
colorbar;
view([ 0 90 ])

3 Kommentare

Jared Erb
Jared Erb am 10 Feb. 2024
I would like the limits of the colorbar to still be the same as they were originally, so not really. It would be best if there was just a way to scale the colorbar values nonlinearly with keeping the plot coloring the same. I also tried scaling with a signedlog10 (sign(Z).*(log10(1+abs(Z)/))) previously, and the scaling doesn't work properly for that either. Thanks for the response though.
Morgan
Morgan am 10 Feb. 2024
Something like this, then?
Jared Erb
Jared Erb am 10 Feb. 2024
Unforunately that doesn't work for negative values, but I would like to have a nonlinearity that isn't log based, as I couldn't get any log scaling to work correctly.

Melden Sie sich an, um zu kommentieren.

Kategorien

Mehr zu Data Distribution Plots finden Sie in Hilfe-Center und File Exchange

Produkte

Version

R2022a

Gefragt:

am 10 Feb. 2024

Kommentiert:

am 11 Feb. 2024

Community Treasure Hunt

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

Start Hunting!

Translated by