3

I'm trying to reuse the solution at the end of How to automatically generate N "distinct" colors? using Python 2.7.

Unfortunately, the code below never returns, since even though islice() requests the first 100 iterations, it seems that the inner-map calls like

gethsvs = lambda: flatten(itertools.imap(genhsv, getfracs()))

force getting all iterations. Instead of passing the number of iterations to all lambda functions, is there a way to make an islice() call at the main code, as below, but making it get only the first 100 iterations in all inner maps as well?

import colorsys, itertools, numpy as np
from fractions import Fraction

def zenos_dichotomy():
    '''
http://en.wikipedia.org/wiki/1/2_%2B_1/4_%2B_1/8_%2B_1/16_%2B_%C2%B7_%C2%B7_%C2%B7
    '''
    for k in itertools.count():
        yield Fraction(1, 2 ** k)

def getfracs():
    '''
    [Fraction(0, 1), Fraction(1, 2), Fraction(1, 4), Fraction(3, 4), Fraction(1, 8), Fraction(3, 8), Fraction(5, 8), Fraction(7, 8), Fraction(1, 16), Fraction(3, 16), ...]
    [0.0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 0.0625, 0.1875, ...]
    '''
    yield 0
    for k in zenos_dichotomy():
        i = k.denominator # [1,2,4,8,16,...]
        for j in range(1, i, 2):
            yield Fraction(j, i)

'''Can be used for the v in hsv to map linear values 0..1 to something that looks equidistant.'''
bias = lambda x: (np.sqrt(x / 3) / Fraction(2, 3) + Fraction(1, 3)) / Fraction(6, 5)

def genhsv(h):
    for s in [Fraction(6, 10)]: # optionally use range
        for v in [Fraction(8, 10), Fraction(5, 10)]: # could use range too
            yield (h, s, v) # use bias for v here if you use range

genrgb = lambda x: colorsys.hsv_to_rgb(*x)
flatten = itertools.chain.from_iterable
gethsvs = lambda: flatten(itertools.imap(genhsv, getfracs()))
getrgbs = lambda: itertools.imap(genrgb, gethsvs())

def genhtml(x):
    uint8tuple = itertools.imap(lambda y: int(y * 255), x)
    return 'rgb({},{},{})'.format(*uint8tuple)

gethtmlcolors = lambda: map(genhtml, getrgbs())

if __name__ == '__main__':
    print(list(itertools.islice(gethtmlcolors(), 100)))
Community
  • 1
  • 1
Oren
  • 335
  • 1
  • 2
  • 7
  • some advice - you should probably wrap all this into a class, and use self param to pass arguments and variables back and forth, so you can have a class variable of the number of iterations you want shared with all the slicing and methods you want. – Inbar Rose Jan 14 '13 at 15:57

1 Answers1

2

You are using map() instead of itertools.imap() in your gethtmlcolors lambda:

gethtmlcolors = lambda: map(genhtml, getrgbs())

In python 2, map() will try and process all elements of the input iterable. Change that to use imap() and everything works:

gethtmlcolors = lambda: itertools.imap(genhtml, getrgbs())
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343