Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cl.interp throwing "IndexError: list index out of range" #6

Closed
spalaciob opened this issue Mar 9, 2016 · 8 comments
Closed

cl.interp throwing "IndexError: list index out of range" #6

spalaciob opened this issue Mar 9, 2016 · 8 comments
Milestone

Comments

@spalaciob
Copy link

Trying to use cl.interp function. It throws an IndexError depending on the length of the new color list.
Steps to reproduce:

>>> colors = ['rgb(27,158,119)',
 'rgb(217,95,2)',
 'rgb(117,112,179)',
 'rgb(231,41,138)',
 'rgb(102,166,30)',
 'rgb(230,171,2)',
 'rgb(166,118,29)']
>>> works = cl.interp(colors, 10)
>>> fails = cl.interp(colors, 11)
/usr/local/lib/python2.7/dist-packages/colorlover/__init__.pyc in interp(scl, r)
   1821         c_i = int(i*math.floor(SCL_FI)/round(r[-1])) # start color index
   1822         hsl_o = rgb_to_hsl( scl[c_i] ) # convert rgb to hls
-> 1823         hsl_f = rgb_to_hsl( scl[c_i+1] )
   1824         section_min = c_i*r[-1]/SCL_FI
   1825         section_max = (c_i+1)*(r[-1]/SCL_FI)

IndexError: list index out of range

The problem is that c_i can round to len(scl)-1 depending on the length of r, hence scl[c_i+1] will end up being out of bounds. A naive solution would imply checking for that specific corner case (I'm sure there's a more elegant way though).

@garyfeng
Copy link

+1. The following gives the same error message as above, but n=28 works.

colorList = cl.to_hsl( cl.interp( cl.scales['11']['div']['RdYlBu'], 21) ) 

garyfeng pushed a commit to garyfeng/colorlover that referenced this issue Apr 26, 2016
@garyfeng
Copy link

Quick fix, as suggested by @spalaciob

    for i in r:
        # garyfeng: c_i could be rounded up so scl[c_i+1] will go off range
        #c_i = int(i*math.floor(SCL_FI)/round(r[-1])) # start color index
        c_i = int(math.floor(i*math.floor(SCL_FI)/round(r[-1]))) # start color index
        hsl_o = rgb_to_hsl( scl[c_i] ) # convert rgb to hls
        hsl_f = rgb_to_hsl( scl[c_i+1] ) if c_i < len(scl)-1 else hsl_o
        section_min = c_i*r[-1]/SCL_FI
        section_max = (c_i+1)*(r[-1]/SCL_FI)
        fraction = (i-section_min)/(section_max-section_min)
        hsl = interp3( fraction, hsl_o, hsl_f )
        c.append( 'hsl'+str(hsl) )

@garyfeng
Copy link

garyfeng commented Apr 27, 2016

Forget the above code. It masks #6 and doesn't fix #7. The math is not right.

This is much better, fixing both #6 and #7, although some of the color interpolation is odd. Here we show the math, where we wish to map len(scl)- intervals to r-1 intervals. We want to make sure c_i never goes out of bound.

scl = cl.scales['3']['div']['RdYlBu']
SCL_FI = len(scl)-1
r=25
r = [x*1.0*SCL_FI/r for x in range(r)] if isinstance( r, int ) else r
for i in r:
    c_i = int(math.floor(i))
    section_min = math.floor(i)
    section_max = math.ceil(i)
    fraction = (i-section_min) #/(section_max-section_min)

    print (i, c_i, section_min, section_max, fraction) 

which gives:

(0.0, 0, 0.0, 0.0, 0.0)
(0.08, 0, 0.0, 1.0, 0.08)
(0.16, 0, 0.0, 1.0, 0.16)
(0.24, 0, 0.0, 1.0, 0.24)
(0.32, 0, 0.0, 1.0, 0.32)
(0.4, 0, 0.0, 1.0, 0.4)
(0.48, 0, 0.0, 1.0, 0.48)
(0.56, 0, 0.0, 1.0, 0.56)
(0.64, 0, 0.0, 1.0, 0.64)
(0.72, 0, 0.0, 1.0, 0.72)
(0.8, 0, 0.0, 1.0, 0.8)
(0.88, 0, 0.0, 1.0, 0.88)
(0.96, 0, 0.0, 1.0, 0.96)
(1.04, 1, 1.0, 2.0, 0.040000000000000036)
(1.12, 1, 1.0, 2.0, 0.1200000000000001)
(1.2, 1, 1.0, 2.0, 0.19999999999999996)
(1.28, 1, 1.0, 2.0, 0.28)
(1.36, 1, 1.0, 2.0, 0.3600000000000001)
(1.44, 1, 1.0, 2.0, 0.43999999999999995)
(1.52, 1, 1.0, 2.0, 0.52)
(1.6, 1, 1.0, 2.0, 0.6000000000000001)
(1.68, 1, 1.0, 2.0, 0.6799999999999999)
(1.76, 1, 1.0, 2.0, 0.76)
(1.84, 1, 1.0, 2.0, 0.8400000000000001)
(1.92, 1, 1.0, 2.0, 0.9199999999999999)

The corresponding code to replace interp():

def interp(scl, r):
    ''' Interpolate a color scale "scl" to a new one with length "r"
        Fun usage in IPython notebook:
        HTML( to_html( to_hsl( interp( cl.scales['11']['qual']['Paired'], 5000 ) ) ) ) '''
    c = []
    SCL_FI = len(scl)-1 # final index of color scale
    # garyfeng:
    # the following line is buggy.
    # r = [x * 0.1 for x in range(r)] if isinstance( r, int ) else r
    r = [x*1.0*SCL_FI/r for x in range(r)] if isinstance( r, int ) else r
    # end garyfeng

    scl = to_numeric( scl )

    def interp3(fraction, start, end):
        ''' Interpolate between values of 2, 3-member tuples '''
        def intp(f, s, e):
            return s + (e - s)*f
        return tuple([intp(fraction, start[i], end[i]) for i in range(3)])

    def rgb_to_hsl(rgb):
        ''' Adapted from M Bostock's RGB to HSL converter in d3.js
            https://github.com/mbostock/d3/blob/master/src/color/rgb.js '''
        r,g,b = float(rgb[0])/255.0,\
                float(rgb[1])/255.0,\
                float(rgb[2])/255.0
        mx = max(r, g, b)
        mn = min(r, g, b)
        h = s = l = (mx + mn) / 2
        if mx == mn: # achromatic
            h = 0
            s = 0 if l > 0 and l < 1 else h
        else:
            d = mx - mn;
            s =  d / (mx + mn) if l < 0.5 else d / (2 - mx - mn)
            if mx == r:
                h = (g - b) / d + ( 6 if g < b else 0 )
            elif mx == g:
                h = (b - r) / d + 2
            else:
                h = r - g / d + 4

        return (int(round(h*60,4)), int(round(s*100,4)), int(round(l*100,4)))

    for i in r:
        # garyfeng: c_i could be rounded up so scl[c_i+1] will go off range
        #c_i = int(i*math.floor(SCL_FI)/round(r[-1])) # start color index
        #c_i = int(math.floor(i*math.floor(SCL_FI)/round(r[-1]))) # start color index
        #c_i = if c_i < len(scl)-1 else hsl_o

        c_i = int(math.floor(i))
        section_min = math.floor(i)
        section_max = math.ceil(i)
        fraction = (i-section_min) #/(section_max-section_min)

        hsl_o = rgb_to_hsl( scl[c_i] ) # convert rgb to hls
        hsl_f = rgb_to_hsl( scl[c_i+1] )
        #section_min = c_i*r[-1]/SCL_FI
        #section_max = (c_i+1)*(r[-1]/SCL_FI)
        #fraction = (i-section_min)/(section_max-section_min)
        hsl = interp3( fraction, hsl_o, hsl_f )
        c.append( 'hsl'+str(hsl) )

    return to_hsl( c )

@warpedgeoid
Copy link

I've just posted a duplicate as #13 .

@adavidzh
Copy link

adavidzh commented Nov 5, 2017

Right now this problem is still in production.
If this was merged and fixed, can someone please make a new release in pypi? The present release (0.2.1) is from 2015: https://pypi.python.org/pypi/colorlover

@minroh
Copy link

minroh commented Aug 7, 2018

I am having the same problem with colorlover version 0.2.1

colors = cl.interp(cl.scales['7']['qual']['Set2'], 61)

60 works, 68 works, some numbers in between do not work... Hope this gets fixed someday.

c:\users\user\appdata\local\programs\python\python36\lib\site-packages\colorlover_init_.py in interp(scl, r)
1821 c_i = int(imath.floor(SCL_FI)/round(r[-1])) # start color index
1822 hsl_o = rgb_to_hsl( scl[c_i] ) # convert rgb to hls
-> 1823 hsl_f = rgb_to_hsl( scl[c_i+1] )
1824 section_min = c_i
r[-1]/SCL_FI
1825 section_max = (c_i+1)*(r[-1]/SCL_FI)

IndexError: list index out of range

@kengz
Copy link

kengz commented Nov 12, 2018

this is not released, but one way around it is to install from source, the latest commit (locking version for safety). Then you'll get the updated interp function

pip install git+https://github.com/jackparmer/colorlover.git@d63b098530458223a985bef804ded0c9be9b00b2

@jonmmease jonmmease added this to the 0.3 milestone Jan 18, 2019
@jonmmease
Copy link
Contributor

Fixed by #9 and will be released in version 0.3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants