3

I'm new at Python, trying to fill a canvas with random pixels. Could someone tell me why it's doing horizontal stripes?

import tkinter
from random  import randint
from binascii import  hexlify
class App:
    def __init__(self, t):
        x=200
        y=200
        xy=x*y
        b=b'#000000 '
        s=bytearray(b*xy)
        c = tkinter.Canvas(t, width=x, height=y);
        self.i = tkinter.PhotoImage(width=x,height=y)
        for k in range (0,8*xy,8):
          s[k+1:k+7]=hexlify(bytes([randint(0,255) for i in range(3)]))
        print (s[:100])      
        pixels=s.decode("ascii")                                        
        self.i.put(pixels,(0,0,x,y))
        print (len(s),xy*8)
        c.create_image(0, 0, image = self.i, anchor=tkinter.NW)
        c.pack()

t = tkinter.Tk()
a = App(t)    
t.mainloop()

Which gives e.g.:

Window full of colourful stripes

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Antoni Gual Via
  • 714
  • 1
  • 6
  • 14
  • 1
    That seems quite complex. What debugging have you done so far? – jonrsharpe Apr 21 '15 at 14:02
  • Your code gives an error. How are you possibly getting it to draw a horizontal line? – Bryan Oakley Apr 21 '15 at 14:07
  • Why do you do the `k` loop in chunks of 8? Does that mean you are filling the image in 8-pixel sections? – Brian L Apr 21 '15 at 14:09
  • I would try refactoring to meet `pep8` with a checker like [this one](http://pep8online.com/) so that the code is cleaner and easier to read. – rickcnagy Apr 21 '15 at 14:10
  • @BryanOakley ran OK for me - what error did you get? – jonrsharpe Apr 21 '15 at 14:20
  • I was trying to get random pixels, not stripes.As I see it I´m not filling whole lines of the byte array in the same color, this is why the result puzzles me. I'm trying to see how fast it can be made, my idea was to fill a predimensioned string wit the 7chars hex color codes reauired by PhotoImage . As Python strings are inmutable i fill a bytearray and convert it to string. – Antoni Gual Via Apr 21 '15 at 14:39
  • @jonrsharpe: I get "can't parse color "#5b3135355b323....." with several screenfuls of digits. Probably due to me trying to run with python 2.7 – Bryan Oakley Apr 21 '15 at 15:30

1 Answers1

3

I would suggest you do something a bit simpler, e.g.:

class App:

    def __init__(self, t, w=200, h=200):
        self.image = tkinter.PhotoImage(width=w, height=h)  # create empty image
        for x in range(w):  # iterate over width
            for y in range(h):  # and height
                rgb = [randint(0, 255) for _ in range(3)]  # generate one pixel
                self.image.put("#{:02x}{:02x}{:02x}".format(*rgb), (y, x))  # add pixel
        c = tkinter.Canvas(t, width=w, height=h);
        c.create_image(0, 0, image=self.image, anchor=tkinter.NW)
        c.pack()

This is much easier to understand, and gives me:

Windowful of fuzzy colours

which I suspect is what you were hoping for.


To reduce the number of image.puts, note that the format for data is (for a 2x2 black image):

'{#000000 #000000} {#000000 #000000}'

You could therefore use:

self.image = tkinter.PhotoImage(width=w, height=h)
lines = []
for _ in range(h):
    line = []
    for _ in range(w):
        rgb = [randint(0, 255) for _ in range(3)]
        line.append("#{:02x}{:02x}{:02x}".format(*rgb))
    lines.append('{{{}}}'.format(' '.join(line)))
self.image.put(' '.join(lines))

which only has one image.put (see e.g. Why is Photoimage put slow?) and gives a similar-looking image. Your image was stripy because it was interpreting each pixel colour as a line colour, as you hadn't included the '{' and '}' for each line.

Community
  • 1
  • 1
jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • Yes, this is the visual result I wanted, only I was trying to speed it up bt usin as few puts as possible. When I increase the canvas size to 800x600 it becomes noticeable. – Antoni Gual Via Apr 21 '15 at 14:49
  • 1
    @AntoniGualVia I see; I've added a more efficient (but still fairly readable) example. Note that if you have a specific goal (e.g. minimising `put`s) it's very helpful to include that in your question. – jonrsharpe Apr 21 '15 at 14:57
  • I think You have answered my question! So curly braces are required to delimit the data for each line! An additional question: where can I find the specs for the put format? I was doing it by trial and error..... – Antoni Gual Via Apr 21 '15 at 15:12
  • 1
    @AntoniGualVia Tkinter is based on Tcl/Tk, so you can look at e.g. http://www.tcl.tk/man/tcl8.4/TkCmd/photo.htm#M30. This site is also handy: http://tkinter.unpythonic.net/wiki/PhotoImage – jonrsharpe Apr 21 '15 at 15:18
  • My little Mandelbrot demo works surprisingli fast. I posted the code in a fitting thread, http://stackoverflow.com/a/29800526/1955444 – Antoni Gual Via Apr 22 '15 at 14:56