Ned Batchelder
Ned Batchelder

Reputation: 375922

How to make a checkerboard in numpy?

I'm using numpy to initialize a pixel array to a gray checkerboard (the classic representation for "no pixels", or transparent). It seems like there ought to be a whizzy way to do it with numpy's amazing array assignment/slicing/dicing operations, but this is the best I've come up with:

w, h = 600, 800
sq = 15    # width of each checker-square
pix = numpy.zeros((w, h, 3), dtype=numpy.uint8)
# Make a checkerboard
row = [[(0x99,0x99,0x99),(0xAA,0xAA,0xAA)][(i//sq)%2] for i in range(w)]
pix[[i for i in range(h) if (i//sq)%2 == 0]] = row
row = [[(0xAA,0xAA,0xAA),(0x99,0x99,0x99)][(i//sq)%2] for i in range(w)]
pix[[i for i in range(h) if (i//sq)%2 == 1]] = row

It works, but I was hoping for something simpler.

Upvotes: 33

Views: 48821

Answers (29)

cottontail
cottontail

Reputation: 23361

Since numpy 1.20.0, we can use sliding_window_view method in its stride_tricks module. The idea is to view an array that looks like 0,1,0,1,0,1 with a moving window of size w. So to get a h x w checkerboard, we need an initial array of length h+w-1. Since this is a view, it uses very little memory (only the original array of length h+w-1 is read into memory).

def checkerboard(h, w):
    return np.lib.stride_tricks.sliding_window_view(np.arange(w+h-1) % 2, w)

checkerboard(4,4)           # a 4x4 checkerboard

array([[0, 1, 0, 1],
       [1, 0, 1, 0],
       [0, 1, 0, 1],
       [1, 0, 1, 0]], dtype=int32)

This is also much faster than the other options on this page too. Adding this function into the perfplot construction in Nico's answer produces the following graph. As you can see, it has a greater overhead than the others but for larger sizes, it's much faster (used numpy 1.25.2 on Python 3.10.12).

perfplot

Upvotes: 2

telliott99
telliott99

Reputation: 7927

Can't you use hstack and vstack? See here. Like this:

>>> import numpy as np
>>> b = np.array([0]*4)
>>> b.shape = (2,2)
>>> w = b + 0xAA
>>> r1 = np.hstack((b,w,b,w,b,w,b))
>>> r2 = np.hstack((w,b,w,b,w,b,w))
>>> board = np.vstack((r1,r2,r1,r2,r1,r2,r1))

Upvotes: 3

Mohit Lamba
Mohit Lamba

Reputation: 1403

Here is a generalisation to falko's answer

import numpy as np

def checkerboard(width,sq):
    '''
    width --> the checkerboard will be of size width x width
    sq ---> each square inside the checkerboard will be of size sq x sq
    '''
    rep = int(width/(2*sq))
    return np.kron([[1, 0] * rep, [0, 1] * rep] * rep, np.ones((sq, sq))).astype(np.uint8)

x = checkerboard(width=8,sq=4)
print(x)
print('checkerboard is of size ',x.shape)

which gives the following output

[[1 1 1 1 0 0 0 0]
 [1 1 1 1 0 0 0 0]
 [1 1 1 1 0 0 0 0]
 [1 1 1 1 0 0 0 0]
 [0 0 0 0 1 1 1 1]
 [0 0 0 0 1 1 1 1]
 [0 0 0 0 1 1 1 1]
 [0 0 0 0 1 1 1 1]]
checkerboard is of size  (8, 8)

Upvotes: 0

Allohvk
Allohvk

Reputation: 1374

Given odd or even 'n', below approach generates "arr" in the checkerboard pattern and does not use loops. If n is odd, this is extremely straightforward to use. If n is even, we generate the checkerboard for n-1 and then add an extra row and column.

rows = n-1 if n%2 == 0 else n
arr=(rows*rows)//2*[0,1]
arr.extend([0])
arr = np.reshape(arr, (rows,rows))

if n%2 == 0:
    extra = (n//2*[1,0])
    arr = np.concatenate((arr, np.reshape(extra[:-1], (1,n-1))))
    arr = np.concatenate((arr, np.reshape(extra, (n,1))), 1)

Upvotes: 0

Nico Schlömer
Nico Schlömer

Reputation: 58881

A perfplot analysis shows that the best (fastest, most readable, memory-efficient) solution is via slicing,

def slicing(n):
    A = np.zeros((n, n), dtype=int)
    A[1::2, ::2] = 1
    A[::2, 1::2] = 1
    return A

The stacking solution is a bit faster large matrices, but arguably less well readable. The top-voted answer is also the slowest.

enter image description here

Code to reproduce the plot:

import numpy as np
import perfplot


def indices(n):
    return np.indices((n, n)).sum(axis=0) % 2


def slicing(n):
    A = np.zeros((n, n), dtype=int)
    A[1::2, ::2] = 1
    A[::2, 1::2] = 1
    return A


def tile(n):
    return np.tile([[0, 1], [1, 0]], (n // 2, n // 2))


def stacking(n):
    row0 = np.array(n // 2 * [0, 1] + (n % 2) * [0])
    row1 = row0 ^ 1
    return np.array(n // 2 * [row0, row1] + (n % 2) * [row0])


def ogrid(n):
    coords = np.ogrid[0:n, 0:n]
    return (coords[0] + coords[1]) % 2


b = perfplot.bench(
    setup=lambda n: n,
    kernels=[slicing, indices, tile, stacking, ogrid],
    n_range=[2 ** k for k in range(14)],
    xlabel="n",
)
b.save("out.png")
b.show()

Upvotes: 4

Farhood ET
Farhood ET

Reputation: 1551

Based on Eelco Hoogendoorn's answer, if you want a checkerboard with various tile sizes you can use this:

def checkerboard(shape, tile_size):
    return (np.indices(shape) // tile_size).sum(axis=0) % 2

Upvotes: 3

priya_03
priya_03

Reputation: 61

You can use the step of start:stop:step for slicing method to update a matrix horizontally and vertically: Here x[1::2, ::2] picks every other element starting from the first element on the row and for every second row of the matrix.

import numpy as np
print("Checkerboard pattern:")
x = np.zeros((8,8),dtype=int)
# (odd_rows, even_columns)
x[1::2,::2] = 1
# (even_rows, odd_columns)
x[::2,1::2] = 1
print(x)

Upvotes: 6

shubham
shubham

Reputation: 21

Replace n with an even number and you will get the answer.

import numpy as np
b = np.array([[0,1],[1,0]])
np.tile(b,(n, n))

Upvotes: 2

pranjul gupta
pranjul gupta

Reputation: 61

You can use Numpy's tile function to get checkerboard array of size n*m where n and m should be even numbers for the right result...

def CreateCheckboard(n,m):
    list_0_1 = np.array([ [ 0, 1], [ 1, 0] ])
    checkerboard = np.tile(list_0_1, ( n//2, m//2)) 
    print(checkerboard.shape)
    return checkerboard
CreateCheckboard(4,6)

which gives the output:

(4, 6)
array([[0, 1, 0, 1, 0, 1],
       [1, 0, 1, 0, 1, 0],
       [0, 1, 0, 1, 0, 1],
       [1, 0, 1, 0, 1, 0]])

Upvotes: 6

Blubberguy22
Blubberguy22

Reputation: 1332

For those wanting arbitrarily sized squares/rectangles:

import numpy as np
# if you want X squares per axis, do squaresize=[i//X for i in boardsize]
def checkerboard(boardsize, squaresize):
    return np.fromfunction(lambda i, j: (i//squaresize[0])%2 != (j//squaresize[1])%2, boardsize).astype(int)

print(checkerboard((10,15), (2,3)))
[[0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
 [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
 [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
 [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
 [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
 [1 1 1 0 0 0 1 1 1 0 0 0 1 1 1]
 [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]
 [0 0 0 1 1 1 0 0 0 1 1 1 0 0 0]]

Upvotes: 3

import numpy as np
n = int(input())
arr = ([0, 1], [1,0])
print(np.tile(arr, (n//2,n//2)))

For input 6, output:

   [[0 1 0 1 0 1]
    [1 0 1 0 1 0]
    [0 1 0 1 0 1]
    [1 0 1 0 1 0]
    [0 1 0 1 0 1]
    [1 0 1 0 1 0]]

Upvotes: 1

Madhav
Madhav

Reputation: 1

Here is the solution using tile function in numpy.

import numpy as np

x = np.array([[0, 1], [1, 0]])
check = np.tile(x, (n//2, n//2))
# Print the created matrix
print(check)
  1. for input 2, the Output is
     [[0 1]
     [1 0]]
  1. for input 4, the Output is
     [[0 1 0 1] 
     [1 0 1 0]
     [0 1 0 1]
     [1 0 1 0]]

Upvotes: 0

Seth Johnson
Seth Johnson

Reputation: 15192

Very very late, but I needed a solution that allows for a non-unit checker size on an arbitrarily sized checkerboard. Here's a simple and fast solution:

import numpy as np

def checkerboard(shape, dw):
    """Create checkerboard pattern, each square having width ``dw``.

    Returns a numpy boolean array.
    """
    # Create individual block
    block = np.zeros((dw * 2, dw * 2), dtype=bool)
    block[dw:, :dw] = 1
    block[:dw, dw:] = 1

    # Tile until we exceed the size of the mask, then trim
    repeat = (np.array(shape) + dw * 2) // np.array(block.shape)
    trim = tuple(slice(None, s) for s in shape)
    checkers = np.tile(block, repeat)[trim]

    assert checkers.shape == shape
    return checkers

To convert the checkerboard squares to colors, you could do:

checkers = checkerboard(shape, dw)
img = np.empty_like(checkers, dtype=np.uint8)
img[checkers] = 0xAA
img[~checkers] = 0x99

Upvotes: 1

Eric Dumasia
Eric Dumasia

Reputation: 1

n = int(input())
import numpy as np
a = np.array([0])
x = np.tile(a,(n,n))
x[1::2, ::2] = 1
x[::2, 1::2] = 1
print(x)

I guess this works perfectly well using numpy.tile( ) function.

Upvotes: 0

Rohit Nigam
Rohit Nigam

Reputation: 1

Suppose we need a patter with length and breadth (even number) as l, b.

base_matrix = np.array([[0,1],[1,0]])

As this base matrix, which would be used as a tile already has length and breadth of 2 X 2, we would need to divide by 2.

print np.tile(base_matrix, (l / 2, b / 2))

print (np.tile(base,(4/2,6/2)))
[[0 1 0 1 0 1]
 [1 0 1 0 1 0]
 [0 1 0 1 0 1]
 [1 0 1 0 1 0]]

Upvotes: 0

Viru1987
Viru1987

Reputation: 13

Simplest way to write checkboard matrix using tile()

array = np.tile([0,1],n//2)
array1 = np.tile([1,0],n//2)
finalArray = np.array([array, array1], np.int32)
finalArray = np.tile(finalArray,(n//2,1))

Upvotes: 0

NanoBennett
NanoBennett

Reputation: 1890

Here's a numpy solution with some checking to make sure that the width and height are evenly divisible by the square size.

def make_checkerboard(w, h, sq, fore_color, back_color):
    """
    Creates a checkerboard pattern image
    :param w: The width of the image desired
    :param h: The height of the image desired
    :param sq: The size of the square for the checker pattern
    :param fore_color: The foreground color
    :param back_color: The background color
    :return:
    """
    w_rem = np.mod(w, sq)
    h_rem = np.mod(w, sq)
    if w_rem != 0 or h_rem != 0:
        raise ValueError('Width or height is not evenly divisible by square '
                         'size.')
    img = np.zeros((h, w, 3), dtype='uint8')
    x_divs = w // sq
    y_divs = h // sq
    fore_tile = np.ones((sq, sq, 3), dtype='uint8')
    fore_tile *= np.array([[fore_color]], dtype='uint8')
    back_tile = np.ones((sq, sq, 3), dtype='uint8')
    back_tile *= np.array([[back_color]], dtype='uint8')
    for y in np.arange(y_divs):
        if np.mod(y, 2):
            b = back_tile
            f = fore_tile
        else:
            b = fore_tile
            f = back_tile
        for x in np.arange(x_divs):
            if np.mod(x, 2) == 0:
                img[y * sq:y * sq + sq, x * sq:x * sq + sq] = f
            else:
                img[y * sq:y * sq + sq, x * sq:x * sq + sq] = b
    return img

Upvotes: -1

Leena Vashistha
Leena Vashistha

Reputation: 27

Using tile function :

import numpy as np
n = int(input())
x = np.tile(arr,(n,n//2))
x[1::2, 0::2] = 1
x[0::2, 1::2] = 1
print(x)

Upvotes: 1

mohi1618
mohi1618

Reputation: 33

n = int(input())
import numpy as np
m=int(n/2)
a=np.array(([0,1]*m+[1,0]*m)*m).reshape((n,n))

print (a)

So if input is n = 4 then output would be like:

[[0 1 0 1]
 [1 0 1 0]
 [0 1 0 1]
 [1 0 1 0]]

Upvotes: 0

Adarsh Somasundar
Adarsh Somasundar

Reputation: 76

Simplest implementation of the same.

import numpy as np

n = int(input())
checkerboard = np.tile(np.array([[0,1],[1,0]]), (n//2, n//2))
print(checkerboard)

Upvotes: 0

Geoff Langenderfer
Geoff Langenderfer

Reputation: 946

import numpy as np

a=np.array(([1,0]*4+[0,1]*4)*4).reshape((8,8))
print(a)


[[1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]]

Upvotes: 2

Eelco Hoogendoorn
Eelco Hoogendoorn

Reputation: 10769

def checkerboard(shape):
    return np.indices(shape).sum(axis=0) % 2

Most compact, probably the fastest, and also the only solution posted that generalizes to n-dimensions.

Upvotes: 41

doug
doug

Reputation: 70068

this ought to do it

any size checkerboard you want (just pass in width and height, as w, h); also i have hard-coded cell height/width to 1, though of course this could also be parameterized so that an arbitrary value is passed in:

>>> import numpy as NP

>>> def build_checkerboard(w, h) :
      re = NP.r_[ w*[0,1] ]              # even-numbered rows
      ro = NP.r_[ w*[1,0] ]              # odd-numbered rows
      return NP.row_stack(h*(re, ro))


>>> checkerboard = build_checkerboard(5, 5)

>>> checkerboard
 Out[3]: array([[0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
               [0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
               [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]])

with this 2D array, it's simple to render an image of a checkerboard, like so:

>>> import matplotlib.pyplot as PLT

>>> fig, ax = PLT.subplots()
>>> ax.imshow(checkerboard, cmap=PLT.cm.gray, interpolation='nearest')
>>> PLT.show()

Upvotes: 15

Falko
Falko

Reputation: 17907

I'd use the Kronecker product kron:

np.kron([[1, 0] * 4, [0, 1] * 4] * 4, np.ones((10, 10)))

The checkerboard in this example has 2*4=8 fields of size 10x10 in each direction.

Upvotes: 25

unutbu
unutbu

Reputation: 880677

Here's another way to do it using ogrid which is a bit faster:

import numpy as np
import Image

w, h = 600, 800
sq = 15
color1 = (0xFF, 0x80, 0x00)
color2 = (0x80, 0xFF, 0x00)

def use_ogrid():
    coords = np.ogrid[0:w, 0:h]
    idx = (coords[0] // sq + coords[1] // sq) % 2
    vals = np.array([color1, color2], dtype=np.uint8)
    img = vals[idx]
    return img

def use_fromfunction():
    img = np.zeros((w, h, 3), dtype=np.uint8)
    c = np.fromfunction(lambda x, y: ((x // sq) + (y // sq)) % 2, (w, h))
    img[c == 0] = color1
    img[c == 1] = color2
    return img

if __name__ == '__main__':
    for f in (use_ogrid, use_fromfunction):
        img = f()
        pilImage = Image.fromarray(img, 'RGB')
        pilImage.save('{0}.png'.format(f.func_name))

Here are the timeit results:

% python -mtimeit -s"import test" "test.use_fromfunction()"
10 loops, best of 3: 307 msec per loop
% python -mtimeit -s"import test" "test.use_ogrid()"
10 loops, best of 3: 129 msec per loop

Upvotes: 7

Ben Kirwin
Ben Kirwin

Reputation: 164

Late, but for posterity:

def check(w, h, c0, c1, blocksize):
  tile = np.array([[c0,c1],[c1,c0]]).repeat(blocksize, axis=0).repeat(blocksize, axis=1)
  grid = np.tile(tile, ( h/(2*blocksize)+1, w/(2*blocksize)+1, 1))
  return grid[:h,:w]

Upvotes: 5

pizzaslice
pizzaslice

Reputation: 11

I modified hass's answer as follows.

import math
import numpy as np

def checkerboard(w, h, c0, c1, blocksize):
        tile = np.array([[c0,c1],[c1,c0]]).repeat(blocksize, axis=0).repeat(blocksize, axis=1)
        grid = np.tile(tile,(int(math.ceil((h+0.0)/(2*blocksize))),int(math.ceil((w+0.0)/(2*blocksize)))))
        return grid[:h,:w]

Upvotes: 1

shelper
shelper

Reputation: 10583

I recently want the same function and i modified doug's answer a little bit as follows:

def gen_checkerboard(grid_num, grid_size):
    row_even = grid_num/2 * [0,1]
    row_odd = grid_num/2 * [1,0]
    checkerboard = numpy.row_stack(grid_num/2*(row_even, row_odd))
    return checkerboard.repeat(grid_size, axis = 0).repeat(grid_size, axis = 1)

Upvotes: 0

Ned Batchelder
Ned Batchelder

Reputation: 375922

I'm not sure if this is better than what I had:

c = numpy.fromfunction(lambda x,y: ((x//sq) + (y//sq)) % 2, (w,h))
self.chex = numpy.array((w,h,3))
self.chex[c == 0] = (0xAA, 0xAA, 0xAA)
self.chex[c == 1] = (0x99, 0x99, 0x99)

Upvotes: 4

Related Questions