-1

I've made this function gradient(iteration) which returns the list of HSL values in order. Now the problem is I can't figure out how to calculate the step difference to keep the length of the list returned by the function = no of iteration. (len(gradient(1000)) == 1000)

Here is the gradient() function:

def gradient(iteration):
    """This function returns a list of HSL values
    of all the colors in an order."""

    ops = { '+': lambda c, step: min(1.0, c + step),
            '-': lambda c, step: max(0.0, c - step)}

    index = 0
    operation = '+'
    rgb, _list = [1.0, 0.0, 0.0], []
    combo = ((2,1,0), (2,0,1), (0,2,1), (0,1,2), (1,0,2), (1,2,0))
    step = 1 if iteration > get_len(1/255) else int(get_len(1/255)/iteration)
    step /= 200

    for i in range(iteration):
        if (rgb[combo[index][1]] == 1.0 and operation == '+') or \
           (rgb[combo[index][1]] == 0.0 and operation == '-'):
            operation = '-' if operation == '+' else '+'
            index += 1
            if len(combo)-1 <= index: break#index = 0
        rgb[combo[index][1]] = ops[operation](rgb[combo[index][1]], step)
        _list.append(rgb)
    return _list

What I've tried so far:

  1. I made a get_len function which will give the total length of the list given according to the step parameter. The plan is to try to find the exact step value by the value returned by get_len.

    def get_len(step):
        c = 1
        v = 1.0
        while True:
            v = max(0.0, v - step)
            if v == 0.0: break
            c += 1
        return c*5
    
  2. I further tried to correct the calculation for step and got very close with this.

    step = 1 if iteration > get_len(1/255) else int(get_len(1/255)/iteration)
    step /= 200
    

To understand better what I'm trying to deal with, run this code

# i and len(gradient(i)) should be equal.
for i in range(1,100):
    print(i, len(gradient(i)))

For example:-

Thie image is of 159 iterations.

This image is of 509 iterations.

Basically I'm trying to alter the length of the gradient bar but with any integer value given to the gradient(iteration) function.

Saad
  • 3,340
  • 2
  • 10
  • 32
  • "but the calculations are not right." How so? Did you get too many or too few elements? – MisterMiyagi Jun 17 '20 at 18:10
  • Does this answer your question? [Is floating point math broken?](https://stackoverflow.com/questions/588004/is-floating-point-math-broken) – MisterMiyagi Jun 17 '20 at 18:11
  • @MisterMiyagi: I mean the value I get for `step` is not correct to give me the same amount of output. Lets us if `iteration=1000` it will give me like 5 output values instead they should be 1000 the same as iteration. Also, *is floating-point math broken?* the question does not solve my problem. – Saad Jun 17 '20 at 18:22

1 Answers1

1

The code is close, but the error, I believe, comes from an overcomplication of how you are thinking of step. This value simply needs to be the right number to go from 0 to 1 and vice versa for each combo you have hardcoded. Your get_len function performs the following operation: (step + 1) * 5, then you take this value and try to approximate the correct step size given iteration. This can be reduced to len(combo) / iteration, which will give you the right number of steps when you use your +/- operations. This is easier to see with the code I think.

def gradient(iteration):
    """This function returns a list of HSL values
    of all the colors in an order."""

    ops = { '+': lambda c, step: min(1.0, c + step),
            '-': lambda c, step: max(0.0, c - step)}

    index = 0
    operation = '+'
    rgb, _list = [1.0, 0.0, 0.0], []
    combo = ((2,1,0), (2,0,1), (0,2,1), (0,1,2), (1,0,2), (1,2,0)) 

    step = len(combo) / iteration  # The right calculation

    for i in range(iteration):
        if (rgb[combo[index][1]] == 1.0 and operation == '+') or \
           (rgb[combo[index][1]] == 0.0 and operation == '-'):
            operation = '-' if operation == '+' else '+'
            index += 1
            if len(combo) <= index:  # Check isn't needed, but here for sanity
                print('Break with index', index)
                break
        rgb[combo[index][1]] = ops[operation](rgb[combo[index][1]], step)
        _list.append(rgb.copy())  # Make a copy to prevent mutation!
    return _list

To check correctness, run the following and you will see that the print statement in the break does not trigger, no do you get an AssertionError.

for i in range(1,100):
    assert i == len(gradient(i))

Note that I made two corrections to your original code - the break statement had the len(index) - 1 which is incorrect, and a append a copy of rgb to the _list so you don't end up with the same RGB value over and over.

I think this answers your question, let me know otherwise.

craymichael
  • 4,578
  • 1
  • 15
  • 24
  • Ah! I feel so stupid now, I was stressing my brain so much these past two days and it was this simple. Also, now it makes sense with `len(combo)` than subtracting -1 from it which was not even giving the complete colors. Thanks a lot. – Saad Jun 19 '20 at 18:36
  • 1
    No problem, you were 99% of the way there, haha. Glad I could help! – craymichael Jun 19 '20 at 18:40