2

I am trying to draw these pretty boxes but instead of drawing them vertically, I want each box to overwrite the previous, so it looks like one box with changing colours every .5 seconds

I am using Jupyter notebooks and Python 3.6.

I have read about 50 similar questions and answers but can't get it to display as desired. Anyone who can help please?

from PIL import Image
import random
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow, show, clf

sq_size = 20
num_squares = 5
im_size = sq_size * num_squares

im = Image.new('RGB', (im_size, im_size), color = 'white')

pix = im.load()

#Create new colourful boxes 4 times
for _ in range(4):

    startx, starty = 0, 0

    #move to the right place to plot each small square
    for i in range(num_squares):
        startx += sq_size
        for j in range(num_squares):
            starty += sq_size
            rshade = np.random.randint(0, 256)
            gshade = np.random.randint(0, 256)
            bshade = np.random.randint(0, 256)

            #plot each small square
            for x in range(sq_size):
                for y in range(sq_size):
                    value = (rshade, gshade, bshade)
                    pix[(startx + x) % im_size, (starty + y) % im_size] = value 

    plt.imshow(im)
    plt.show()

    time.sleep(.5)

Currently this plots as follows...

enter image description here

but I want each box to overwrite the previous, so it looks like one box with changing colours every .5 seconds

6
  • Try putting plt.show() outside the for loop at the end Commented Aug 22, 2018 at 20:37
  • That just shows the final plot. I want each of the plots to show every .5 seconds. Like the one plot is animated Commented Aug 22, 2018 at 20:40
  • 1
    Why don't you use animate to create an animation Commented Aug 22, 2018 at 20:53
  • 1
    Take a look at link It does exactly what you want, using matplotlib.animation Commented Aug 22, 2018 at 21:40
  • I appreciate the help but that link doesn't animate anything on my macbook or on Google Colab. Commented Aug 23, 2018 at 7:36

1 Answer 1

1

OK. I found a solution. it is based on https://matplotlib.org/examples/animation/dynamic_image2.html

from PIL import Image
import random
import time
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow, show
import matplotlib.animation as animation

%matplotlib notebook

def next_shape(im, num_squares, sq_size):
    pix = im.load()

    #initialise plot location
    startx, starty = 0, 0

    for i in range(num_squares):
        startx += sq_size
        for j in range(num_squares):
            starty += sq_size
            rshade = np.random.randint(0, 256)
            gshade = np.random.randint(0, 256)
            bshade = np.random.randint(0, 256)

            for x in range(sq_size):
                for y in range(sq_size):
                    value = (rshade, gshade, bshade)
                    pix[(startx + x) % im_size, (starty + y) % im_size] = value 

    #return list of pixel tuples
    return list(im.getdata())

# First set up the figure, the axis, and the plot element we want to animate
sq_size = 20
num_squares = 5

#create a figure to animate
fig = plt.figure()

#create the image withi the figure to animate
im_size = sq_size * num_squares
im = Image.new('RGB', (im_size, im_size))

#create a list to store all the images in the format of a list of RGB pixels
im_list_pix = []

#generate a bunch of images in the form of a list of RGB pixels
for pic in range(10):
    im_list_pix.append(next_shape(im, 5, 20))

#create a list to store images converted from RGB pixel tuples to image format
img_array = []

#convert list of pixel tuples back to image
for i, v in enumerate(im_list_pix):
    im = Image.new('RGB', (100, 100))
    #put the pixel data into the image container
    im.putdata(im_list_pix[i])

    im = plt.imshow(im)
    img_array.append([im])  

ani = animation.ArtistAnimation(fig, img_array, interval=500)

plt.show()

It took me a long time to work out the square brackets in ...

img_array.append([im])

... is crucial. It must be the way matplotlib.animate parses the list.

I hope this is useful for others wanting to pay with matplot.animate and have some fun creating art.

PS - thank you to the commenters who pointed me towards matplotlib.animate and thanks also to the author of this great blog post that gave me some clues and also shows how far you can push this stuff http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.