This Python + Pygame program draws the trace of 4 decaying sine waves, 2 per axis, with rainbow colours. It generates a sequence of random harmonographs.
A harmonograph is a mechanical device typically seen in science museums, that has two or more pendulae with attached pens, that can draw on a sheet of paper. The pendulae are set in motion and the pen draws pretty patterns on the paper. This is easily simulated in a computer program, by plotting orthogonal sine waves acting together on a drawing point. This generates Lissajous figures, which are decayed to make a pleasing nesting of ‘parallel’ lines, like you might see on bank notes.
It’s fast, and can be set to go much faster (or slower) if you want. Tip: set the display window to fullscreen. MIT license; download from GitHub
#!/usr/bin/python ''' Spectral Harmonographs Copyright 2014 Alan Richmond (Tuxar.uk) ''' print("Quit: q key, Screenshot: spacebar") import pygame, sys, random as r from pygame.locals import * from math import pi, sin, cos, exp # EDIT THESE: width,height=1280,720 # YouTube HD width,height=1920,1080 # my left monitor width,height=1280,1024 # my right monitor width,height=1680,1050 # Lucy's monitor width,height=1200,800 #width,height=2560,1440 # YT channel art dd=0.99995 # decay factor dt=0.02 # time increment speed=200 # yes, speed hui=57*2 # Hue increment hue,sat,val,aaa=0,100,100,0 sd=0.005 # frequency spread (from integer) mx=4 # max range for amplitudes and frequencies print("Hit SPACE to save") def check_event(): global save for event in pygame.event.get(): if event.type == QUIT: sys.exit() elif event.type == KEYDOWN and event.key == K_q: sys.exit() elif event.type == KEYDOWN and event.key == K_SPACE: save=True print("Saving when finished...") def scale(length): while True: a1,a2=r.randint(-mx,mx),r.randint(-mx,mx) max=abs(a1)+abs(a2) if max > 0: break return a1,a2,length/(2*max) steps=0 pygame.init() pygame.event.set_allowed([QUIT, KEYDOWN]) screen = pygame.display.set_mode((width,height),DOUBLEBUF) screen.set_alpha(None) #fg=pygame.Color(0,0,0,0) #fg=(0,0,0) fg=(255,255,255) save=False while True: # Amplitudes and scales ax1,ax2,xscale=scale(width) ay1,ay2,yscale=scale(height) fx1, fx2 = r.randint(1,mx) + r.gauss(0,sd), r.randint(1,mx) + r.gauss(0,sd) fy1, fy2 = r.randint(1,mx) + r.gauss(0,sd), r.randint(1,mx) + r.gauss(0,sd) px1, px2 = r.uniform(0,2*pi), r.uniform(0,2*pi) py1, py2 = r.uniform(0,2*pi), r.uniform(0,2*pi) print(ax1,ax2,ay1,ay2) print(fx1,fx2,fy1,fy2) print(px1,px2,py1,py2) dec=1.0 t=0.0 # angle for sin first=True while dec > 0.015: # calculate next x,y point along line x = xscale * dec * (ax1*sin(t * fx1 + px1) + ax2*sin(t * fx2 + px2)) + width/2 y = yscale * dec * (ay1*sin(t * fy1 + py1) + ay2*sin(t * fy2 + py2)) + height/2 dec*=dd # decay if not first: # ignore any complaint about prev_x,y being undefined # fg.hsva=(hue,sat,val,aaa) # hue = (hue + dt*hui) % 360 # cycle hue pygame.draw.aaline(screen, fg, (x, y), (prev_x, prev_y), 1) else: first=False prev_x = x # save x,y for next line segment start prev_y = y if steps%speed==0: pygame.display.update() steps+=1 t+=dt # increment angle for sin check_event() if save: # parameters are encoded into filename pars='shg-{0}_{1}-{2}_{3}-{4}_{5}'.format(ax1,ax2,fx1,fx2,px1,px2) pygame.image.save(screen, pars+'.jpg') print("Saved as "+pars+'.jpg') save=False screen.fill((0,0,0)) # screen.fill((255,255,255))
You may need to install python and/or pygame, e.g. on Ubuntu/Debian style linuxes:
sudo apt-get install pygame
sudo apt-get install python
Go to the directory you saved it in and make it executable, then run it:
chmod +x harmonograph.py
./harmonograph.py
Set the display window to fullscreen (right click on title bar, maybe it’s under More Actions?).
[welcomewikilite wikiurl=”https://en.wikipedia.org/wiki/Harmonograph” sections=”Short description” settings=””]
gives me syntax error in line 40 at the semi-colon between amp and gt 🙁
The wordpress plugin for Python has a habit of changing ‘>’ to ‘&’…
I’ve changed the code, and another one further down, please try again
and forgive my late reply. Sorry.
Hi there,
just stumbled across this page here and wanted to mention something. The code above is working….partially. All lines appear white. However, the code on the Github is missing the parentesis on all print commands, after adding these I was able to get the images as shown here (with colored lines).
On a first glance I couldn’t find the mistake for the missing color in the code on this page, but I’ll have a closer look soon.
Best regards and thank you for this beautiful example
– Chris