Skip to content
Sample of Line Arrangements (Mohr)

generative_pioneers · mohr_line_arrangement

Line Arrangements (Mohr)

Manfred Mohr's 1969 plotter 'Line Arrangements': a fixed grid of columns and rows, each carrying a small set of nearly-parallel lines whose exact positions are random within the cell, overlaid with a layer of 45° diagonals whose length, position and orientation are independently random. The piece reads as a structural score — vertical and horizontal scaffolding first, then a tilted second voice — that establishes the same 'abstract text' Mohr described in his P-021 family of algorithmic drawings at Vincennes in 1969/70.

Original: https://emohr.com/sc69-73/vfile_random69.html

▶ Try the live demo (JS port) ▶ Run reference.py via Pyodide 10 formulas have instant JS ports. The Pyodide path runs the actual Python in your browser — first load is ~6 MB, then instant.

Family
generative_pioneers
Source
generative pioneers
Evolution
static_arrangement
Render
ink_lines_on_paper
Complexity
low
Agents
0
Year
1969
Author
Manfred Mohr

Math essence

For each of n_columns grid cells we drop h_lines_per_col vertical segments inside the cell with a uniform random horizontal offset jitter·cell_width and random vertical trim; symmetrically for n_rows. A second pass draws d_lines_total segments at ±45° with uniformly random centers and uniformly random lengths in [0.04·dim, 0.42·dim].

Parameters

Name Type Default Range Description
dim int 512 200–1200 Square canvas side length
n_columns int 12 4–32 Number of vertical grid columns
n_rows int 12 4–32 Number of horizontal grid rows
h_lines_per_col int 3 1–8 Vertical strokes per column
v_lines_per_row int 3 1–8 Horizontal strokes per row
d_lines_total int 24 0–200 Number of 45° diagonal strokes
jitter float 0.35 0–1 Within-cell random offset (fraction of cell size)
thickness float 1.2 0.5–3 Effective ink line thickness
bg_color tuple 245,240,230 null–null Background RGB
line_color tuple 15,15,20 null–null Ink line RGB
seed int null 0–999999 RNG seed

Reference

First 60 lines of reference.py. Full source: library_external/generative_pioneers/mohr_line_arrangement/reference.py

from __future__ import annotations

from typing import ClassVar

import imageio.v2 as imageio
import numpy as np


class MohrLineArrangement:
    family: ClassVar[str] = "generative_pioneers"
    sketch: ClassVar[str] = "mohr_line_arrangement"

    def __init__(
        self,
        dim: int = 512,
        n_columns: int = 12,
        n_rows: int = 12,
        h_lines_per_col: int = 3,
        v_lines_per_row: int = 3,
        d_lines_total: int = 24,
        jitter: float = 0.35,
        thickness: float = 1.2,
        bg_color: tuple[int, int, int] = (245, 240, 230),
        line_color: tuple[int, int, int] = (15, 15, 20),
        seed: int | None = None,
    ) -> None:
        self.dim = dim
        self.n_columns = n_columns
        self.n_rows = n_rows
        self.h_lines_per_col = h_lines_per_col
        self.v_lines_per_row = v_lines_per_row
        self.d_lines_total = d_lines_total
        self.jitter = jitter
        self.thickness = thickness
        self.bg_color = np.array(bg_color, dtype=np.uint8)
        self.line_color = np.array(line_color, dtype=np.uint8)
        self._seed = seed
        self.rng = np.random.default_rng(seed)
        self.canvas = np.full((dim, dim, 3), self.bg_color, dtype=np.uint8)
        self.time = 0
        self._dirty = True

    def reset(self, seed: int | None = None) -> None:
        if seed is not None:
            self._seed = seed
        self.rng = np.random.default_rng(self._seed)
        self.canvas = np.full((self.dim, self.dim, 3), self.bg_color, dtype=np.uint8)
        self.time = 0
        self._dirty = True

    def _draw_segment(
        self,
        x0: float,
        y0: float,
        x1: float,
        y1: float,
        color: np.ndarray,
        thickness: float,
    ) -> None:
        d = float(np.hypot(x1 - x0, y1 - y0))

Try running it locally

The reference implementation is self-contained Python with numpy. Install the package and run:

python library_external/generative_pioneers/mohr_line_arrangement/reference.py

Need help? See Learn for the standard environment setup, or Playground for an in-browser sketchbook.

More from generative pioneers

Sample of Interruptions (Molnár)

Interruptions (Molnár)

generative_pioneers · molnar_interruptions

Vera Molnár's 1968 'Interruptions' series: a regular grid of rectangle cells where each cell's four border edges are drawn independently, each with its own random probability of being omitted.

View →
Sample of Paint by Numbers (Haeberli)

Paint by Numbers (Haeberli)

generative_pioneers · haeberli_painterly

Paul Haeberli's 1990 SIGGRAPH 'Paint by Numbers' — the founding paper of stroke-based rendering.

View →
Sample of Plotter Trajectories (Hébert)

Plotter Trajectories (Hébert)

generative_pioneers · hebert_plotter_trajectory

Jean-Pierre Hébert's plotter-trajectory idiom — parametric Lissajous-like curves drawn over multiple passes, each pass slightly phase-shifted, each segment modulated by the local velocity of the pen so that slow regions lay down heavier pigment and fast regions trace a ghost line.

View →
Sample of Walk-through-Raster (Nake)

Walk-through-Raster (Nake)

generative_pioneers · nake_walk_sequence

Frieder Nake's 1966 'Walk-through-Raster' program (Algol 60 on a Telefunken TR4, plotted on a ZUSE Graphomat Z64): a repertoire of six signs — empty, vshort, vlong, hshort, hlong, dot — is sampled into a Markov chain whose transition probabilities vary with chain position so that 'vertical strokes are high at the chain's middle, empties dominate at the ends'.

View →

See all generative_pioneers artworks →