ipythonblocks

This is a demo of the ipythonblocks module available at https://github.com/jiffyclub/ipythonblocks. ipythonblocks provides a BlockGrid object whose representation is an HTML table. Individual table cells are represented by Block objects that have .red, .green, and .blue attributes by which the color of that cell can be specified.

ipythonblocks is a teaching tool that allows students to experiment with Python flow control concepts and immediately see the effects of their code represented in a colorful, attractive way. BlockGrid objects can be indexed and sliced like 2D NumPy arrays making them good practice for learning how to access arrays.

In [1]:
from ipythonblocks import BlockGrid
In [2]:
grid = BlockGrid(10, 10, fill=(123, 234, 123))
In [3]:
grid
Out[3]:
In [4]:
grid[0, 0]
Out[4]:

BlockGrid objects support iteration for quick access to individual blocks. Blocks have .row and .col attributes (zero-based) to help track where in the grid you are. The individual color channels on each Block can be modified directly.

In [5]:
for block in grid:
    if block.row % 2 == 0 and block.col % 3 == 0:
        block.red = 0
        block.green = 0
        block.blue = 0
grid
Out[5]:

BlockGrid objects have .height and .width attributes to facilitate loops over the grid. Individual Blocks can be accessed via Python- or NumPy-like indexing.

In [6]:
for r in range(grid.height):
    for c in range(grid.width):
        sq = grid[r, c]
        sq.red = 100
        
        if r % 2 == 0:
            sq.green = 15
        else:
            sq.green = 255
        
        if c % 2 == 0:
            sq.blue = 15
        else:
            sq.blue = 255

The BlockGrid.show() method can also be used to display the grid or individual blocks.

In [7]:
grid.show()
In [8]:
grid[5, 5].show()

Slicing a BlockGrid returns a new BlockGrid object that is a view of the original, much like NumPy arrays.

In [9]:
sub_grid = grid[:, 5]
sub_grid.show()
In [10]:
for block in sub_grid:
    block.red = 255
In [11]:
sub_grid
Out[11]:
In [12]:
grid
Out[12]:

Slicing can be used with iteration to work on a sub-grid. The Block.set_colors method can be used to update all the colors at once.

In [13]:
for block in grid[2:6, 2:4]:
    block.set_colors(245, 178, 34)
grid
Out[13]:

Like NumPy arrays, the BlockGrid.copy() method can be used to get a completely independent copy of the grid or slice.

In [14]:
sub_copy = grid[3:-3, 3:-3].copy()
sub_copy.show()
In [15]:
sub_copy[:] = (0, 0, 0)
sub_copy.show()
In [16]:
grid
Out[16]:

Blocks can also be modified by assigning RGB tuples. This type of assignment can be used on individual blocks, or on slices to change many blocks at once.

In [17]:
grid[5] = (0, 0, 0)
grid.show()
In [18]:
grid[:, 5] = (255, 0, 0)
grid.show()
In [19]:
grid[-3:, -3:] = (0, 124, 124)
grid.show()
In [20]:
grid[1, 1] = (255, 255, 255)
grid.show()
In [21]:
grid[:, :] = (123, 234, 123)
grid.show()

The displayed size of blocks (in pixels) can be controlled with the block_size keyword, allowing some flexibility in how many blocks can comfortably fit on the screen.

In [22]:
grid = BlockGrid(50, 50, block_size=5)
grid
Out[22]:

The block display size can be modified at any time by changing the BlockGrid.block_size attribute.

In [23]:
grid.block_size = 2
grid
Out[23]:

And the grid lines between individual cells can be toggled by setting the BlockGrid.lines_on attribute.

In [24]:
grid.lines_on = False
grid
Out[24]: