squirreltown
Posts: 10
Joined: Mon Jan 23, 2017 2:08 am

pygame colors

Thu Mar 16, 2017 5:52 pm

I'm modifying this: http://pygame.org/project-colors-1930-.html. It creates a 768x768 screen of 64x64 color swatches. However, there are many duplicate colors which i am trying to avoid.
this is the function that gives each thumbnail it's color, I've added a list of colors chosen to compare to, t.color_bg is the color variable:

Code: Select all

def start(self, search="light"):
        """creates initial grid, with default search. """
        if VERBOSE: print ("start( search={} )".format(search))
        self.thumbs = []
        
        thumb_w, thumb_h = 64, 64
        numx = self.width / thumb_w
        numy = self.height / thumb_h
        self.caption_prepend(search)
        self.thumbs = []

        self.usedclr = [(0,0,0,0)]                      ## added

        for y in range(int(numy)):
            for x in range(int(numx)):
                t = Thumbnail(width=self.thumb_w)                
                if search: t.color_bg = random_color(search)
                # else: t.color_bg = Color('gray')

                t.color_bg = sortdupes(self, t, search)  ## added
                self.usedclr.append(t.color_bg)          ## added

                t.fill()                
                t.move(thumb_w * x, thumb_h * y)                                                
                self.thumbs.append(t)
And this function to do the comparing:

Code: Select all

def sortdupes(self, t, search):
        for i in range(len(self.usedclr)):
            if self.usedclr[i] == t.color_bg:
                print("DUPE")
                t.color_bg = random_color(search)
                continue
        return t.color_bg  
So, I want sortdupes() to run through the list, if it finds a dupe, get another color and start comparing again, if it's not on the list it returns the color.
It appears to be working, as it prints "DUPE" many times and eventually returns.
However I am still ending up with 100 dupes out of 145 colors.
Very new to python/pygame so I must be missing something but can't see it, thanks.

User avatar
paddyg
Posts: 2555
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: pygame colors

Thu Mar 16, 2017 11:50 pm

If you want to avoid duplicates but want random looking colours from a given palette, say, you can generate the swatches in ascending order then shuffle them, along the lines of

Code: Select all

import random
r1, r2, r_step = 100, 255, 2
g1, g2, g_step = 150, 200, 1
b1, b2, b_step = 50, 190, 2
swatches = [[r, g, b] for r in range(r1, r2, r_step) for g in range(g1, g2, g_step) for b in range(b1, b2, b_step)]
random.shuffle(swatches)
swatches = swatches[:144]
where the step values stop making the array to shuffle too large. Obviously you would put in variables rather than 144 etc.

EDIT P.S.

In python you can do away with the old fashioned for loop using an index to an array and iterate over the values like

Code: Select all

for clr in self.usedclr:
  if clr == t.color_bg:
However it is MUCH more efficient and easier to understand to simply use the 'thing in list' syntax

Code: Select all

def sortdupes(self, t, search):
    while t.color_bg in self.usedclr:
        print("DUPE")
        t.color_bg = random_color(search)
    return t.color_bg
not checked but you can see the kind of thing I mean
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

squirreltown
Posts: 10
Joined: Mon Jan 23, 2017 2:08 am

Re: pygame colors

Fri Mar 17, 2017 4:00 am

Thank you paddyg! I just learned about 5 things and you solved the problem that was going to come after this one. Most appreciated.

ghp
Posts: 1516
Joined: Wed Jun 12, 2013 12:41 pm
Location: Stuttgart Germany
Contact: Website

Re: pygame colors

Fri Mar 17, 2017 7:32 am

Hello,
in python, there are 'set' available "A set object is an unordered collection of distinct hashable objects". So whatever you add to the collection, the underlying implementation ensures that dup elements are rejected.
See example:

Code: Select all

#numeric
a = set()
a.add(1); a.add(2); a.add(3)
a.add(1); a.add(2); a.add(3)
print (a)
#string
b= set()
b.add('a');b.add('b');b.add('c')
b.add('a');b.add('b');b.add('c')
print (b)
This makes coding sometimes a bit easier.
Regards,
Gerhard

User avatar
paddyg
Posts: 2555
Joined: Sat Jan 28, 2012 11:57 am
Location: UK

Re: pygame colors

Fri Mar 17, 2017 10:39 am

As Gerhard says the python 'set' is very useful for avoiding duplicates. There are a couple of problems in your case because you can't make a set from lists (because they're mutable) and if you tried to get round it by having a simple class to hold the RGB list i.e. your Thumbnail, then all the instances of the class would be different instances even if they held the same RGB values so the set might hold duplicates.

You could make your set

Code: Select all

self.usedclr = set((0, 0, 0, 0))
while len(self.usedclr) < 145:
    self.usedclr.add(random_color(search))
BUT you now have a bit of a complication 'yielding' values from your set to allocate to your thumbs in your nested for loops. Look up 'generator' functions and the built in 'next' function.

However you can do something very similar to set using the dict (which I think set uses internally) and making the key from the RGB, a bit like this.

Code: Select all

        self.thumbs = {}

        for y in range(int(numy)):
            for x in range(int(numx)):
                t = Thumbnail(width=self.thumb_w)
                c = random_color(search) ############ NB assuming your function generates tuples
                while c in self.thumbs or c == (0, 0, 0, 0):
                    c = random_color(search)        
                t.color_bg = c
                t.fill()               
                t.move(thumb_w * x, thumb_h * y)                                               
                self.thumbs[c] = t ########### this adds or overwrites entry with key c
An issue you now have, that might be relevant, is accessing the thumb at location x,y which could be solved by having an index dict in parallel
self.thumbs_index[(x,y)] = t
also https://groups.google.com/forum/?hl=en-GB&fromgroups=#!forum/pi3d

Return to “Python”