Inspired by Michael Fogleman's blog post from 2011, here is a Python implementation of his algorithm for generating images which resemble the paintings of Dutch painter Piet Mondrian (1872 - 1944). A slightly different, object-oriented approach will be presented in a subsequent post.

We start with a canvas defined as the unit square $0 \le x \le1$, $0\le y \le 1$ (we will later map co-ordinates on this canvas to an SVG image). A *line* on this canvas is defined by the tuple `(y, (x1,y2))`

in the case of a horizontal line from `(x1,y)`

to `(x2,y)`

and by the tuple `(x, (y1,y2))`

in the case of a vertical line from `(x,y1)`

to `(x,y2)`

. The lines are collected together in two lists associated with a dictionary, keyed by `HORIZONTAL`

and `VERTICAL`

which are the values `True`

and `False`

respectively. We start by setting down boundary lines along the edges of the canvas:

HORIZONTAL, VERTICAL = True, False lines = { HORIZONTAL: [(0, (0,1)), (1, (0,1))], VERTICAL: [(0, (0,1)), (1, (0,1))] }

We add `nlines`

lines in randomly-chosen orientations (horizontal or vertical) by first choosing a random point on an existing randomly-selected line to place the start point, and then finding the set of all the lines that can be reached by a perpendicular line from this point. The end point of our new line is the intersection of the perpendicular line with a randomly-chosen line from this set.

Of course, the first line to be added must cross the entire image:

Subsequent lines may have several choices for their endpoints, however:

To colour the regions defined by the lines, we need to find the *boxes* defined by the intersections: to do this, we first sort the list of horizontal lines by their $y$-coordinate. Next, loop over this list and for each line find all the adjacent vertical lines which intersect it *and extend above it*: this gives the lower corners of the boxes with thier lower edges on this line.

Next follow the vertical lines upwards and find their next intersections with a horizontal line to get the upper corners of the box. The boxes are stored as the tuple of coordinates `(bx1, by1, bx2, by2)`

where `(bx1, by1)`

is the lower lefthand corner and `(bx2, by2)`

is the upper righthand corner.

The box colour is selected at random from a weighted distribution: each colour is associated with a point on a cumulative probability distribution function (cdf) and a number chosen at random from a uniform distribution on [0,1). The value of this number then determines which colour is selected according to which range it falls into in the cdf.

colours = ['blue', 'red', 'yellow', 'white'] colours_cdf = [0.15, 0.3, 0.45, 1.0]

Thus, there is a probability of 0.15 that each of blue, red or yellow will be chosen and a probability of 0.65 for white.

The SVG image is created by rendering a series of coloured rectangles for the "boxes" with `rect`

element, followed by the lines. The canvas coordinates are simply multiplied by the desired SVG image width and height dimensions.

## Comments

Comment deleted 2 years, 9 months ago

## New Comment