1

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
LenaH
  • 313
  • 2
  • 14
  • 1
    "I've found code online, help me make it work" is not really a question suitable for Stack Overflow... It would be much better if you showed a [mcve] of the sort of thing you're plotting, with or without using the above function you found, then explaining (or showing) why this isn't suitable, and where you're stuck trying to improve it. – Wolfie Jul 22 '19 at 07:31
  • Dear Wolfie, I thought it would be useful for you to have a code to start from, therefore I posted the function. However, I of course also responded to your comment, and edited my post by including the plot that I have so far. I am looking forward to your answer. – LenaH Jul 22 '19 at 07:52
  • 1
    Non linear ? Non linear in terms of what ? The lightness ? The euclidian distance between each 3D point formed by the RGB color ? Or are you talking about discret colormap ? – obchardon Jul 22 '19 at 08:14
  • By non-linear color map I mean that the colors have to be as different as possible from each other in order to distinguish them, please see my edit above. If you have another approach than the one suggested that works, feel free to use it. – LenaH Jul 22 '19 at 08:33
  • [This question](https://stackoverflow.com/questions/470690/how-to-automatically-generate-n-distinct-colors) may offer some insight. – beaker Jul 22 '19 at 16:56
  • @beaker This is actually a Java related question, not Matlab. – LenaH Jul 22 '19 at 19:33
  • 1
    But @beaker's linked Q&A does have a nice list of 22 colors that are easily differentiable (termed Kelly's). That has nothing to do with Java or MATLAB. All you need to do is plot each line in a different one of those 22 colors and you're done. – Cris Luengo Jul 22 '19 at 19:46
  • 1
    @LenaH Which is why I suggested that it might offer some insight rather than marking it as a duplicate. Java colors are the same as MATLAB colors, only the representation differs. And once you understand how to select the colors, the coding is the easy part. – beaker Jul 22 '19 at 20:05
  • 1
    A good solution is given in [this answer](https://stackoverflow.com/a/22029354/52738) to a [closely-related duplicate](https://stackoverflow.com/q/2028818/52738). – gnovice Jul 22 '19 at 20:46
  • @gnovice I have explained in the edited post why my question is not a duplicate to either of the posts. beaker's link is useful once knowing that I can transform Java colors to Matlab and I could then implement it but does anybody have a longer list of colors that goes up to 30? – LenaH Jul 23 '19 at 06:54
  • You've explained why the existing answers to the duplicate question are unsatisfactory, but it's still a duplicate. See https://meta.stackexchange.com/questions/190532/unsatisfactory-answer-to-question – Sneftel Jul 23 '19 at 10:39
  • 1
    @LenaH: The linked duplicate doesn't suggest only 7 colors. The OP there had a solution for 7 already (the default) but needed a way to get more. The [answer there from chappjc](https://stackoverflow.com/a/22029354/52738), which I mention in my previous comment, provides a solution to generate `N` distinct colors, and should satisfy what you're looking for. – gnovice Jul 23 '19 at 14:02
  • @gnovice, ah right, I only looked in the accepted answer. Thanks, that's much better! – LenaH Jul 23 '19 at 21:40

0 Answers0