2

I have the following list of 10 colors:

public static readonly IList<Brush> lineColors = new ReadOnlyCollection<Brush>
        (new List<Brush> { 
            new SolidColorBrush(Color.FromRgb(35, 31, 32)),
            new SolidColorBrush(Color.FromRgb(64, 64, 66)),
            new SolidColorBrush(Color.FromRgb(89, 89, 91)),
            new SolidColorBrush(Color.FromRgb(110, 111, 113)),
            new SolidColorBrush(Color.FromRgb(129, 130, 132)),
            new SolidColorBrush(Color.FromRgb(148, 149, 153)),
            new SolidColorBrush(Color.FromRgb(168, 169, 173)),
            new SolidColorBrush(Color.FromRgb(189, 190, 193)),
            new SolidColorBrush(Color.FromRgb(210, 211, 213)),
            new SolidColorBrush(Color.FromRgb(231, 231, 232))
        });

Now I also have a range from 1 to n. I'd like to map these value equally to this 10 colors so that the smallest value is the first color and the highest value is mapped to the last color. All the other colors should cover an equal distance in the value range.

How to do that?

I think this will maybe do it:

int position = Math.floor( value / ((max - min) / lineColors.Count));
lineColors.ElementAt(position);

But I'm not sure if this is valid for all possibilities and if there isn't a simpler solution.

2 Answers2

4

Mapping values can be expressed with a linear function: f(x) = ax + b

Both your ranges provide points on that function from which it can be calculated.
f(1) = 0
f(n) = 9 | The highest index in a list of ten colours.

0 = a * 1 + b
9 = a * n + b

9 = a * (n - 1)
a = 9 / (n - 1)
=> b = -9 / (n - 1)

=> f(x) = 9 / ( n - 1) * (x - 1)

The problem here is that if you round that right away less values will be mapped to 0 and 9 because the rounding range is only 0.5 (from 0 to 0.5 and from 8.5 to 9), so you could stretch the range and shift it back by 0.5 to account for that.

private int MapValue(int value, int n)
{
    int output = (int)Math.Round((10.0 / (n - 1) * (value - 1)) - 0.5, 0);
    if (output == -1) return 0;
    else return output;
}
H.B.
  • 166,899
  • 29
  • 327
  • 400
  • Thanks. This works for me. Now I encountered another problem. I one example I have the range 0 to 1116. However most values or between 0 and 50 or maybe 0 and 100. So nevertheless most values are mapped to the same color. How can i avoid that such outliers tamper with my mapping? – RoflcoptrException Feb 05 '11 at 21:23
  • The equation is for input ranges 1 to n, as you stated in your question, if your range now starts with 0 that will lead to inaccuracies. Besides that there is a base-inaccuracy from rounding. I tried mapping a range from 1 up to 1116 and there is only a difference of one value in stripe length for the different indices, so there is no major divergence. – H.B. Feb 06 '11 at 01:47
1

You didn't introduce value, min and max -- I'm assuming that min and max are the minimum and maximum, respectively, of the range of numbers you want to be able to map (in your textual exposition of the problem, that would mean min = 1 and max = n), and that value is the value you're trying to map.

Your suggested solution contains a couple of problems:

a) You need to substract min from value, too.
b) If these variables are declared as integers (which I imagine they would be), the division results will get truncated.
c) If value is max, you want lineColors.Count - 1, not lineColors.Count.
d) By using floor, you introduce an asymmetry -- a range of values is mapped to the lowest colour, but only max is mapped to the highest colour. It seems preferable to use round instead to treat both ends of the spectrum the same.

So a solution would be:

int position = Math.round ((value - min) / ((max - min) / (lineColors.Count - 1.))); lineColors.ElementAt(position);

(The decimal point on "1." forces all arithmetic to be floating-point.)

joriki
  • 617
  • 5
  • 14
  • Sry but this doesn't really work for me with the decimal points and also your values are out of the range. – RoflcoptrException Feb 05 '11 at 16:40
  • In which sense does the decimal point not work for you? I see from H.B.'s answer that you may need a cast to (int) in the end. I don't see how the values can be out of range -- if you put in min, you get 0; if you put in max, you get lineColors.Count - 1 -- please give an example where the values are out of range. – joriki Feb 05 '11 at 18:47