I created a code for a plot in Matlab, please see below. My problem is that for many data vectors (i.e. not only revenue and opex, but up to 30 data series), the colors are very similar. I'd be grateful if you refrained from asking why I want to plot 30 colors and assume that I have a reason that would take up too much space to explain in detail.
My question is,...
1) How can I create a non-linear color map for up to 30 different data series? By non-linear I simply mean that the colors have to be as different as possible in order to distinguish them. Feel free to suggest a better term.
Note that this is NOT a duplicate to:
a) this entry because the person there only suggest 7 different colors.
b) or this entry because the person there suggests 20 different colors ("Kelly") and remarks that "note that some yellows are not very contrasting".
I found a Matlab function online that could be helpful, see below. But you can also suggest a different approach. Regarding the function I could not figure out so far two points:
2) What must the format (class and size) of the input variables myColors, centerPoint, cLim, scalingIntensity and inc be (see below)? E.g. I understood that cLim has to be a 2x1 vector; centerPoint, scalingIntensity numerical values.
3) What are reasonable values for these variables, i.e. in what range do they have to be for the code to work?
My code:
clc
clear
close all
revenue = ones(100,1);
opex = -1*ones(100,1);
opex(10:15,1) = 3;
data{1} = revenue;
data{2} = opex;
colors = parula(numel(data));
labels = {'Revenue','Opex'};
for i = 1:numel(data)
dataNeg{i} = data{i};
dataNeg{i}(data{i}>0) = 0;
dataPos{i} = data{i};
dataPos{i}(data{i}<0) = 0;
mdata(i) = nnz(dataPos{i}); % was: mean(data{i});
end;
[~,posOrder] = sort(mdata,'ascend');
[~,negOrder] = sort(mdata,'descend');
yDataPos = [dataPos{posOrder}];
yDataNeg = [dataNeg{negOrder}];
hold on;
bNeg = bar(yDataNeg,'stack');
bPos = bar(yDataPos,'stack');
for i= 1:numel(data)
set(bNeg(i),'FaceColor',colors(negOrder(i),:))
set(bPos(i),'FaceColor',colors(posOrder(i),:))
end;
legend(labels{:});
hold off;
Function for non-linear color map:
function [newMap, ticks, tickLabels] = MC_nonlinearCmap(myColors, centerPoint, cLim, scalingIntensity, inc)
dataMax = cLim(2);
dataMin = cLim(1);
nColors = rows(myColors);
colorIdx = 1:rows(myColors);
colorIdx = colorIdx - (centerPoint-dataMin)*numel(colorIdx)/(dataMax-dataMin); % idx wrt center point
colorIdx = scalingIntensity * colorIdx/max(abs(colorIdx)); % scale the range
colorIdx = sign(colorIdx).*colorIdx.^2;
colorIdx = colorIdx - min(colorIdx);
colorIdx = colorIdx*nColors/max(colorIdx)+1;
newMap = interp1(colorIdx, myColors, 1:nColors);
if nargout > 1
% ticks and tickLabels will mark [centerPoint-inc, ... centerPoint+inc, centerPoint+2*inc]
% on a linear color bar with respect the colors corresponding to the new non-linear colormap
linear_cValues = linspace(cLim(1), cLim(2), nColors);
nonlinear_cValues = interp1(1:nColors, linear_cValues, colorIdx);
tickVals = fliplr(centerPoint:-inc:cLim(1));
tickVals = [tickVals(1:end-1), centerPoint:inc:cLim(2)];
ticks = nan(size(tickVals));
% find what linear_cValues correspond to when nonlinear_cValues==ticks
for i = 1:numel(tickVals)
[~, idx] = min(abs(nonlinear_cValues - tickVals(i)));
ticks(i) = linear_cValues(idx);
end
tickLabels = arrayfun(@num2str, tickVals, 'Uniformoutput', false);
end
end