# Twenty things to do with a python script

With a deferential bow to Seymour Papert & Cynthia Solomon's Twenty Things to do with a computer (1971), here a selected listing of Python recipes that represent a range possible Media Design explorations that need not involve many lines of code.

Papert & Solomon were key figures as early as the 1970s in the development of school curricula for using computers in the classroom. Through the development of the programming language LOGO, and the concept of turtle graphics, they promoted a constructivist approach to using programming to teach other concepts. In this approach, the computer provides a means of making "microworlds" in which typically "abstract" concepts (such as geometry and differential equations) can be approached in a concrete and (virtually) hands-on way rather than as abstract principles typical of convention maths teaching.

The python programming language has been used for many years as part of the PZI Media Design curriculum. Echoing the constructivism of Papert & Solomon, programming is used in the course to get "hands on" experience with the substance of software and digital media.

<slidy theme="aa" />

## Make a turtle

```import turtle
import random

def Poly(n,x):
angle = 360/n
for i in range(n):
turtle.forward(x)
turtle.left(angle)

def makeFlower(p):
for i in range(12):
Poly(9,p)
turtle.left(30)

def makeTriple():
turtle.speed(44)
for i in range(3):
i = (i+1)*5
turtle.color(random.random(),random.random(),random.random())
makeFlower(i)

xa = -255
y = -244
numberColumns = 5
numberRows = 5
turtle.penup()
turtle.setpos(xa,y)

for i in range(numberRows):
for c in range(numberColumns):
c=(c+1)*100
makeTriple()
turtle.penup()
turtle.sety(y+c)
turtle.pendown()
i=(i+1)*100
turtle.penup()
turtle.setpos(xa+i,y)
turtle.pendown()
```

## Create an Inkscape plugin to draw turtle graphics

The same "turtle" code as above is now performed in the context of the SVG editor Inkscape. The "Seymour" python plugin code emulates the interface of the turtle graphics module rendering the same movements now as SVG paths and groups. The resulting graphic can be further manipulated (as points & paths) using Inkscape's full graphical interface and toolset.

See Seymour

```#!/usr/bin/env python
#-*- coding:utf-8 -*-
"""
Copyright 2013, Piet Zwart Institute, MA Media Design
http://pzwart3.wdka.hro.nl/wiki/

Z2qpXooo2i+=|aaZW1n2vYwn###ovi>=||=;:;::+=|||{?VTSUQWWBBW#ZWWmmWmWmmWmWmBmW#QWQQ
ZoSXXX2!==>{av1XTTTYX#WTY+..."!""!<%|=========|*nSou3vSZVZXA#WWmBBWWWmmBWWBmWWQQ
W#oX2ov%%nnZX1|++<loG?.=;<_%|_,._,..+*~=i>==|==+;:==||{SYH\$QWWBWWBWmWWWWmWBWWWQQ
#ZXXo{vnuvnvI+=::vnS(:i|v%;::::=====|=|===|||==+===::=={uwm#mWWWmmWWBWWmWWWmBQQQ
U2XYo2Iov%|i++:.=i%X:=|+: :;:;==v%lvvvvvvlvs%avv|=====+|YWBWWWWWWWWmQWmWBWWBWQQQ
#XoooIi>|=~-:+ ;:=v(:|---:===|ivvnoX2XoXSoXo1aaunvvsi==:=)3WWWWWBBBWmWBWWWWmQWQQ
#XSZ1>)}+=|=;:}"|=|>=;. .;=||ivnoXXXXXZZZXqomX2ouXS2Xo;==;=lXWBWWWWWBWBWWWWmQWQQ
mX1%**=::`:.__;=-=>:::.:==+<svoXZXXZZZSqw#XXnwXXd&SqXXS>::+={S##WWWBWWBWWBWWWWQQ
Wnz||is,=;=._|::_=- -::==+|iIo2XXXXmwmZZZYodXmXXSo#Y1i|||:==|{IXZ\$WQBWWBWWWmWQQQ
1vs>>=:=|==||=ia+`  .:==++vvvSoXXZX22Y1qu#XXXSoZX1l|+iivv>:=|={*mw#mWQmQWmWWWWQQ
|%iawu2!3e(v>"'      -=|>|ivvSeXoZXXSXXXZ#XXwXX1|<ivdXXXXo>:;;iII####WWBWWWWBQQQ
<|2YI>+={1o+ _  .-..._==<v}1ou1XwoZZZXZZZZXZXXonowmZZZXXX#X,:;=|liYXXX#mWBWBWQQQ
|uni>>|=ii3;;+,._- .==|%{iv1uSSX2XZXXZXXXo2XoS2Xm#ZZZ1+{i*SX; ==|i%*YoX###WmWWQQ
Iiv>|<;=||<-:.:=.;;=<iii{%1SooSS2li|ivooXn2ooXX#Z#X2|==-%IISo,--=i=|=InXZ##WmQQQ
|=iii>+||+=::=::=;==|||%vv1****+=+|aommmmXoXXXZZ#SXioZaw|vo#Xo   --==<||*A###WQQ
i|==||(=|=>-.-::-=;+||ii%|++++|vuoXZZ#Z#Z##ZZXXZooe+){suq##XXZo ...;;+<i%|?9\$WWQ
l|||i=>|>|..:.:;::==|=i||+=|invoXSZZXXXoXnSnn32ZX1|IvvXXXXX#XZ#c .-:::=|3ns%>2AW
vi|i+|=<+:.:.:::;===|||>|ivno2X2***}|**I1ii|iinmXZwunoXX#XXXXXUZc :;:::<=%YoowzY
n}ii||>:;::.-::;:===|||i|lo2SS}|<%.-:=%"!+||ilnSX#Z##XXS22SXXZ#ZX;--:===i<=i3#Zo
os%|l+=:;==:-::::=;+|=|iivno2c|ioXaa%|i%Ii|ilvnSSXXXZZ#XmXXZ#U###m;:.::||i|l>i3\$
1|}=>==;=:;:;.:.:;==||iiivno2%=+{*IvuXXoovnvvnooo2SXXZZZXZX#U###ZZc:-:;:||ovsvvv
1i>|==|==;.==;...::|+|i|Ilvnnvvno2XXXXX#XvnvononvooXXZZZ##Xu1XX##Zo;-.:.:+*1l3qv
1|==|++|;;:.::.:  :-+|||ivvvoonooooXZZZX1ooo21IIIvnXXXX#XZ#2Il?SXZX(.: ;::iwwIXw
o%i=<==>::::: .: ...:=||ilvnn222XSXXXSnoS2SSo|<vvv2S2XXXmm#`--==<Xov;.:..:|*SlBh
pvi>=|=:==.....- ..  -;=|ilvnnoSo2ooXSSSoSXZn>|oSXno2oXXZZ'  ..:.:{1=-:.:=||SXQW
X|li>||=;=:..... -     :+||lvnnn2o2SS2XXXXX2vii|!+---"!!+-   ._...<l=-..-::)Y1#B
Xvii||===;:.=:...       -=||ivvnno2oXXXXXXZ1|===. .      ..._/====i|;   .::=+nWW
mZs|v|+=|==::... .   .    :==Iivvnno2S2XXXX>==::..    -:=oe" :<vvi>:: .   ;||ivd
Qm2vi%i|%;;;:;.:        .  :=|<vv1vvo2XSXX1==:.  ._;=_:-"=...=vIni>:.   ..:=)2v|
WWZzi|<v||=+:==.;.. .     ..-:=||lIvvnno2n>=.. .:=|+'_:-;..;|invnv:. `   ..=%nIi
Qmwouc|vi<|+:<:: :. .   .     .-:=||iiInvI|:....;:..:====|ivnzi+|i;.   .:-=;=|i|
QW#XS}ii%%||=|=:..-_ -         ..-===+|ii||=:.:=i||||||ilIv}|` _i|:- ...;:==ivl=
Qmov%svvu%i==|=::   . :          ..:-;=+|===:;:=|ivIvvIl|=+;  =i==.  ..:==||{nc;
QWmmZm#2n>|><<>=:.  .::-             -.:-:-:-::==<i|ivlii|>= ==:..  :==::=%o|*1>
QQ#mmWTon=Ivil==:.    =                . .-..- - :-++<|>|<=;:;:       -=<|Inoai_
QQQQQeXeniIi|I==:. .   : .                  -.  . : :-::.-.:.- .      .;+lXXQ#mB
QQQQQQWscs=|(>===:  :.::..   .                 ..... -.. ...      .  ====iinodWm
QQQQQQk2oi|+i>><:.::=..<;_:.. .                -  -  ..;:  . .    ..::+i|vwumQmW
QQQQQBdW#Xviii|=|<=_.:||%%===;;..    .        -...:-, .:::...:   :=;==|<vnmmQWWT
"""

import sys, os
if os.path.exists('/usr/share/inkscape/extensions'):
sys.path.append('/usr/share/inkscape/extensions') # or another path, as necessary
from simplestyle import *
import random, math, uuid
import inkex

defaultpathstyles = {
'fill':'none',
'fill-rule':'evenodd',
'stroke':'#000000',
'stroke-width':'1px',
'stroke-linecap':'butt',
'stroke-linejoin':'miter',
'stroke-opacity':'1'
}

#################################

def colorval (f):
if (type(f) == float):
if f>= 0 and f<1:
f = math.floor(256*f)
else:
f = math.floor(f)
return f
def rgb (r, g, b):
return '#%02x%02x%02x' % (colorval(r),colorval(g),colorval(b))

# <path style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="%s" />
def pointstodata (points):
try:
data = "M %0.6f,%0.6f" % points[0]
for p in points[1:]:
data += " L %0.6f,%0.6f" % p
return data
except IndexError:
return ""

def collecttext (elt):
ret = elt.text or ""
ret += "\n".join([collecttext(child) for child in elt])
return ret

#################################

class Turtle (object):
def __init__(self, x=0.0, y=0.0, heading=0.0, pendown=True, layer=None):
self.x = x
self.y = y
self.homex = x
self.homey = y
self._pendown = False
self.points = []
self.stack = []
self.lastpath = None
if layer is not None:
self.stack.append(layer)
self.styles = {}
if pendown:
self.pendown()

def forward (self, steps):
if self._pendown:
self.points.append((self.x, self.y))
fd = forward

def backward (self, steps):
self.forward(-steps)
bk = backward
back = backward

def right (self, d):
d = (d/180.0)*math.pi
rt = right

def left (self, d):
d = (d/180.0)*math.pi
lt = left

def goto(self, x, y):
self.x = x
self.y = y
setpos = goto
setposition = goto

def setx (self, x):
self.x = x

def sety (self, y):
self.y = y

def home(self):
self.x = homex
self.y = homey

pass
def dot(self, size=None, *color):
pass
def stamp(self):
pass
def clearstamp(self, stampid):
pass
def clearstamps(self, n=None):
pass
def undo(self):
pass
def speed(self, speed=None):
pass

def pendown (self):
if not self._pendown:
self._pendown = True
self.points.append((self.x, self.y))
pd = pendown

def penup (self):
if self._pendown:
self._pendown = False
if len(self.points) and len(self.stack):
# http://stackoverflow.com/questions/1551666/how-can-2-python-dictionaries-become-1/1551878#1551878
styles =  dict(defaultpathstyles, **self.styles)
path.set('style', formatStyle(styles))
path.set('d', pointstodata(self.points))
self.stack[-1].append(path)
self.lastpath = path
self.points = []
pu = penup

def ensure_id (self, elt):
try:
ret = elt.attrib['id']
except KeyError:
ret = "seymour-"+uuid.uuid1().hex
elt.attrib['id'] = ret

return ret

def text (self, text):
if self.lastpath != None:
# assert False, str(self.lastpath.attrib.keys())
textPath.text = text
textelt.append(textPath)
self.stack[-1].append(textelt)
else:
textelt.text = text
self.stack[-1].append(textelt)

def color (self, *args):
if len(args) == 3:
r, g, b = args
self.styles['stroke'] = rgb(r, g, b)

elif len(args) == 1:
r, g, b = args[0]
self.styles['stroke'] = rgb(r, g, b)

def startgroup (self, id=None):
""" special to SVG"""
if id is not None:
g.set('id', str(id))
self.stack[-1].append(g)
self.stack.append(g)

def endgroup (self):
""" special to SVG"""
self.stack.pop()

def exitonclick (self):
self.penup()
pass

#########################################################
# The Inkscape Effect interface

class SeymourEffect(inkex.Effect):
def __init__(self):
inkex.Effect.__init__(self)
# http://docs.python.org/lib/module-optparse.html
type = 'string', dest = 'layer', default = 'Seymour output',
help = 'name of layer for output')

def effect (self):
svg = self.document.getroot()
# svg = self.document.xpath('//svg:svg', namespace = inkex.NSS)[0]
for id, code in self.selected.iteritems():
try:
# code = self.document.xpath("//*[@id='%s']" % codeid)[0]
src = collecttext(code)
# print src

width = inkex.unittouu(svg.get('width'))
height = inkex.unittouu(svg.attrib['height'])
outputlayer = inkex.etree.SubElement(svg, 'g')

turtle = Turtle(x=width/2, y=height/2, layer=outputlayer)
d = {'turtle': turtle}
# turtle.export_to_dict(d)
# d['rgb'] = rgb
exec src in d
except IndexError:
pass

##############################################################################
# This file can be directly applied to an SVG on the commandline using:
# python seymour.py path/to/your.svg

if __name__ == "__main__":
effect = SeymourEffect()
effect.affect()
```

## Generate an animation with "raw" images

Python is used to output the raw bytes of uncompressed images and assembled together to make an animation.

 ```import struct, sys width = 320 height = 240 header = struct.pack("= 200: r = 5*(float(frame)) g = y/4+2*(float(frame)) b = 3*(float(frame)) a = 255 elif y <= 75: r = (x+y)/4+(float(frame)/totalframes) g = y+2*(float(frame)) b = y+2*(float(frame)) a = 255 else: r = 5+5*(float(frame)/totalframes) g = y-2*(float(frame)) b = 4*(float(frame)) a = 255 out.write(struct.pack('B', b)) out.write(struct.pack('B', g)) out.write(struct.pack('B', r)) out.write(struct.pack('B', a)) out.close() ```

```import struct, sys

width = 320
height = 240
xWhite = 0

totalframes = 25
for frame in xrange(totalframes):
frame = frame+1
out = open("frames/frame%02d.tga" % frame, "wb")

for y in xrange(height):
for x in xrange(width):
xWhite = xWhite +1
if (frame != 1 and xWhite%frame == 0):
r = 255
g = 255
b = 255
a = 255
else:
r = 0
g = 0
b = 0
a = 255
out.write(struct.pack('B', b))
out.write(struct.pack('B', g))
out.write(struct.pack('B', r))
out.write(struct.pack('B', a))

out.close()
```
 ```import math, struct, sys from math import * tau = 2 * pi #computes distance from (x1,y1) to (x2,y2) def dist(x1, y1, x2, y2): return sqrt(float((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2))) width = 320 height = 240 nFrames = 25 header = struct.pack("= 2 else primaryColor * 36 if primaryColor > 0.2 else abs(cos(5.0*dist(x + sin(offset*tau), y + 25*sin(offset*tau), width / 2, -2000) / 4.0)) * 24 b = abs(primaryColor + abs(cos(2000*offset*tau + dist(x + sin(offset*tau), y + sin(offset*tau), width / 2, -2000) / 8.0))) * 48 a = 255 output.write(struct.pack('BBBB', b, g, r, a)) output.close() ```

Sources: Mihail, Lucia, Tamas

## Generate tactical hybrid texts

Uses: NLTK

Source: Femke Snelting, EmmaWoodhouse.odt

## Programmatically Manipulate Typefaces

Uses: FontForge and robofab

## Spider texts and extract strategic search patterns

```ective enforcement of intellectual property rights is critical to sustaining e
or the enforcement of intellectual property rights , taking into account diffe
procedures to enforce intellectual property rights do not themselves become ba
em of infringement of intellectual property rights , including infringement ta
ensive enforcement of intellectual property rights than is required by this Ag
etween enforcement of intellectual property rights and enforcement of law in g
lability and Scope of Intellectual property Rights 1 . This Agreement shall be
, and maintenance of intellectual property rights . 2 . This Agreement does n
ures where a right in intellectual property is not protected under its laws an
rk for Enforcement of Intellectual property Rights ) are invoked ; ACTA / en 7
calendar days ; ( h ) intellectual property refers to all categories of intell
to all categories of intellectual property that are the subject of Sections 1
rk for Enforcement of Intellectual property Rights ) are invoked ; ACTA / en 8
g to assert rights in intellectual property ; ( m ) territory , for the purpos
rk for Enforcement of Intellectual property Rights ), means the customs territ
- Related Aspects of Intellectual property Rights , contained in Annex 1C to
RK FOR ENFORCEMENT OF INTELLECTUAL property RIGHTS SECTION 1 GENERAL OBLIGATIO
ct of infringement of intellectual property rights covered by this Agreement ,
he enforcement of any intellectual property right as specified in this Section
ng the enforcement of intellectual property rights , its judicial authorities
he infringement of an intellectual property right from entering into the chann
ng the enforcement of intellectual property rights , its judicial authorities
s for infringement of intellectual property rights , a Party ' s judicial auth
the right holder ' s intellectual property right in question and actually ass
horization to use the intellectual property right in question . ACTA / en 14 A
```

The text of the proposed ACTA treaty is subjected to an algorithmic reading using NLTK's concordance function.

```import nltk
corpus_root='/path/to/your/texts'
acta=nltk.text.Text(wordlists.words('ACTA.txt'))
```
```import sys, nltk
corpus_root=sys.argv[1]
print corpus_root
interesting=['property','intellectual','right','measure','protection']
for fileid in corpus.fileids():
text=nltk.text.Text(corpus.words(fileid))
text.concordance('ACTA')
```

Uses: NLTK

## Run a web server to share files on your local network

```python -m SimpleHTTPServer
```

In a time when the terms of "sharing" become increasingly contested and dictated by platforms vying for our personal data and attention, this simple one-liner, which shares the current directory (and potentially sub-directories) on one's local network takes on a political dimension. I share therefore I am!

Python 3 Version:

```python -m http.server 8888 &
```

## Permute the spellings of search terms

A course exercise using python to permute the letters of a text string is later developed into a browser plugin exploring strategic uses of misspellings used by various communities to evade censorship when using search engines.

Source: Linda Hilfling, the experiments were developed later into the Misspelling generator browser plugin & project

## Create a pataphysical search engine

A Python CGI that applies an algorithm developed by Oulipo (Ouvroir de littérature potentielle; or "workshop of potential literature") practitioners to a search request producing a détournement of the search engine.

```african
africans
afro
afros
aft
afterbirth
aftercare
aftereffect
```
```    def getNewQuery (self, theQuery, theNounsFile) :
myNounsFile = open("nouns.txt", 'r')
myNounsList = []
for myLines in myNounsFile :
myNoun = myLines.strip()
myNounsList.append(myNoun)
myQuery = nltk.word_tokenize(theQuery)
myNewQuery = ""
for myWord in myQuery :
try :
myIndex = myNounsList.index(myWord.lower())
myNewQuery += " " + myNounsList[(myIndex + 7) % len(myNounsList)]
except :
myNewQuery += " " + myWord
myNewQuery = myNewQuery[1:]
myPattern = re.compile("\"\ ([^\"]+[.]?)\ \"")
myNewQuery = re.sub(myPattern, "\"\\1\"", myNewQuery)
return myNewQuery
```

Uses: NLTK

Source: Sebastian Schmieg & Silvio Lorusso

## Create a Traceroute Map

Using the commandline traceroute command and a geoip database, python is used to translate the hops of a network transaction into a geographic journey that retraces an imperial history of telecommunications.

```# imports the geoip database and the sys function
import pygeoip, sys, string

# creates a variable called "filename" that equals the first thing that
# has been put after the execution of "routetodot[dot]py"
filename = sys.argv[1]

#creates a variable of the geoip database from the file "GeoIP.dat"
GEOIP = pygeoip.Database('GeoIP.dat')

#create a variable called lastIp

lastNUM = None
# create a variable "line" from every line in the "filename"
# split this "line" into a variable called "data"
# check if "data" starts and ends with "(" ")"
# if so create a variable called "ip" that is "data" without "()"
# look up "ip" in the "GEOIP" variable
# checks if "a.country" returns none, it is then printed as "localhost"
# prints the variables "lastIp" and "ip"
# changes "lastIp" into "ip"
lineNUM = 0;
labels = "";
connections = "";
colorsbycountry = dict(US='blue',NL='orange',DE='grey',CN='red',localhost='pink',IE='green',FR='purple',GB='crimson', EU='sienna' )
colors = '"0.8396,0.4862,1.0" "0.8396,0.4862,0.8"  "0.8396,0.4862,0.6" "0.8396,0.4862,0.4" "0.8396,0.4862,0.2" "0.8396,0.4862,0.0"'.split()

nodenamebyip = {}
nodenum=0
lastip = None

colorindex=0;
for line in open(filename):
parts = line.split()
NUM = parts[0]
lineNUM +=1
for data in parts:
#line[1]
if data.startswith("(") and data.endswith(")"):
ip= data.strip("()")
a= GEOIP.lookup(ip)

if a.country == None:
a.country = "localhost"

if a.country not in colorsbycountry:
colorsbycountry[a.country] = colors[colorindex]
colorindex+=1

labelcolor = colorsbycountry[a.country]

if ip not in nodenamebyip:
nodenum+=1
nodenamebyip[ip] = "node"+str(nodenum)
# first time, print label

nn = nodenamebyip[ip]
#labels+= nn +' [label="'+ip+' '+a.country+'" fontcolor="'+labelcolor+'" style="filled"]\n'
#labels+= str(lineNUM)+' [label="'+ip+' '+a.country+'" fontcolor='+labelcolor+' style=filled]\n'
labels+= str(lineNUM)+' [label="'+ip+' '+a.country+'" fillcolor='+labelcolor+']\n'

if lastNUM != None:
connections+= str(lastNUM)+"->"+str(lineNUM)+'\n'
#	connections+= nodenamesbyip[lastip]+"->"+nodenamesbyip[ip]+'\n'

lastNUM = lineNUM
lastip = ip

graphname = filename;
if graphname.endswith(".txt"):
graphname = graphname.strip(".txt")

print "digraph iptrace {\n bgcolor = grey; \n node [shape=rect, fontname=Arial, fontcolor=white, style=filled] \n edge [style=dotted] \n"
print 'label=','"'+graphname+'"'
print labels
print connections
print "}"
```

Uses: pygeoip

Source: Roel Roscam Abbing, Documentation

## Create an alternative social network based on scraping supermarket loyalty card data

An installation interface that creates an alternative social network based on scraping a major Grocery chain's customer loyalty website.

## Create a custom joystick sound recorder

A joystick and laptop become a custom recording and playback device for making and live mixing field recordings.

Uses: pygame

## Slice & reorder an audio file by predominant frequency

Long format diary cassette recordings are sliced into 1/10th second intervals and sorted by predominant frequency. The resulting sorted pieces are reassembled producing a new recording that reveals aspects of the original recording through an algorithmic ordering.

```#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys, argparse

parser = argparse.ArgumentParser(description="Dumps spectral analysis of audio using gstreamer")
parser.add_argument('--interval', default=0.1, type=float, help="interval duration (in seconds)")
parser.add_argument('--bands', default=128, type=int, help="number of bands to split the spectrum")
parser.add_argument('path', help="audio filename to analyze (wav format only)")

args = parser.parse_args()
inpath = args.path
AUDIOFREQ = args.freq          # MAX FREQ OF ANALYSIS
INTERVAL_SECS = args.interval
INTERVAL = int(INTERVAL_SECS * 10**9) # DURATION OF "FRAMES" in nanoseconds / audio chunks to process
BANDS = args.bands # 128                 # SPLIT THE SPECTRUM UP INTO THIS MANY BANDS
NANOS = float(10**9)
GST_MESSAGE_EOS = (1 << 0)   # couldn't find this in gst package (wtf!)

import gst, pygst, struct, gobject

# alternative pipeline for live analysis
# listener_desc = 'autoaudiosrc ! spectrum interval={1} bands={2} ! fakesink'
listener_desc = 'filesrc location="{0}" ! wavparse ! spectrum interval={1} bands={2} ! fakesink'
listener_desc = listener_desc.format(inpath, INTERVAL, BANDS)

# (pmin, pmax) = (None, None)
def listener_on_message (bus, message, data):
global pmin, pmax
s = message.structure
if s:
msgname = s.get_name()
if msgname == "spectrum":
secs = s['timestamp'] / NANOS
#            print ("%0.1f-%0.1f\t"%(secs, secs + INTERVAL_SECS)) + ("\t".join([str(x) for x in s['magnitude']]))
print '"{0}",{1:0.3f},{2:0.3f},'.format(args.path, secs, secs + INTERVAL_SECS) + (",".join(["{0:0.3f}".format(x) for x in s['magnitude']]))
else:
# print dir(message), message, message.type
if message.type & GST_MESSAGE_EOS:
listener.set_state(gst.STATE_NULL)
sys.exit(0)
return True

freqs = []
for i in range(BANDS):
freqs.append( ((AUDIOFREQ / 2.0) * i + AUDIOFREQ / 4.0) / BANDS )

#print "source\tin\tout\t", "\t".join([str(x) for x in freqs])

labels = []
for i in range(BANDS):
if i == 0:
fromfreq = 0.0
else:
fromfreq = freqs[i-1]
labels.append('"({0:0.0f}-{1:0.0f})"'.format(fromfreq, freqs[i]))
print '"source","in","out",'+(",".join(labels))

listener = gst.parse_launch(listener_desc)
mainloop = gobject.MainLoop()
listener.set_state(gst.STATE_PLAYING)

try:
mainloop.run()
except: # an interruption from Ctrl-C
pass
```

Uses: gstreamer

## 3D Cloud computing with Blender

A mod of the above script...

```# The following function is adapted from
# Nick Keeline "Cloud Generator" addNewObject
# from object_cloud_gen.py (an addon that comes with the Blender 2.6 package)
# from : http://bathatmedia.blogspot.be/

def duplicateObject(scene, name, copyobj):

# Create new mesh
mesh = bpy.data.meshes.new(name)

# Create new object associated with the mesh
ob_new = bpy.data.objects.new(name, mesh)

# Copy data block from the old object into the new object
ob_new.data = copyobj.data.copy()
ob_new.scale = copyobj.scale
ob_new.location = copyobj.location
ob_new.rotation_euler = copyobj.rotation_euler

# Link new object to the given scene and select it
ob_new.select = True

return ob_new
```

## Create a dotcom index using letter permuations

Permutations are used to generate all possible short 2 and 3 letter domain names. The result is output as an HTML page with working links so that the names can be interactively tested and explored.

```from itertools import product
chars = "abcdefghijklmnopqrstuvwxyz1234567890-"
for n in xrange(253):
for comb in product(chars, repeat=n):
i = ''.join(comb)
print 'http://www.'+i+'.com'
```

Source: User:Roelroscama, Documentation

## Filter a subtitle file to highlight the unique words of a spoken text (Disappearance)

A script processes the titles of an interview, transcribed using the SRT format. As words repeat, they become blanked out, providing a subtle visualisation contrasting the novel and repetitive aspects of a speaker's language.

```#! /usr/bin/env python
# Copyright 2010 the Active Archives contributors.
# See the file AUTHORS for more details.

# This program is free software: you can redistribute it and/or modify
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import sys
import re
from optparse import OptionParser
from textwrap import dedent

# inits usage and arguments
usage = "usage: %prog in.srt > out.srt"
parser = OptionParser(usage=usage)
(options, args) = parser.parse_args()

# checks the arguments length
if len(args) != 1:
parser.error("incorrect number of arguments")

# opens the subtitle file and reads its content
try:
f = open(args[0], 'r')
except IOError:
sys.exit(dedent("""\
Error: I can't open your subtitle file.
Are you sure it exists?\
"""))
else:
f.close()

pattern = re.compile(r'[a-zA-Z]+', re.UNICODE)  # creates a pattern to search words

used_words = []
new_text = ""
previous_end = 0

# replaces all the occurrences of the words but the first one
for match in pattern.finditer(subtitles):
new_text += subtitles[previous_end:match.start()]
word = match.group()
if word.lower() in used_words:
#new_text += "*{w}*".format(w=word)
#new_text += "<del>{w}</del>".format(w=word)
#new_text += "--{w}--".format(w=word)
new_text += "{w}".format(w="".ljust(len(word), " "))
else:
new_text += word
used_words.append(word.lower())
previous_end = match.end()
new_text += subtitles[previous_end:len(subtitles)]
print(new_text)
```

Uses: SRT, mplayer

Source: Alexandre Leray and Stéphanie_Vilayphiou

## Create generative fugues

```#!/usr/bin/env python

import random

fugue = {}
fugue = {
"/l2/d4":["/l2/a4", "/l2/c+4"],
"/l2/a4": ["/l2/f4"],
"/l2/f4": ["/l2/d4", "/l8/f4"],
"/l2/c+4": ["/l4/d4"],
"/l4/d4": ["/l4/e4"],
"/l4/e4": ["/l2/f4"],
"/l8/f4": ["/l8/g4","/l8/e4"],
"/l8/g4": ["/l8/f4"],
"/l8/e4": ["/l2/d4"]
}

#here we print / place the timidity structure
print """
\$time_sig 4/4
\$tempo 220
}
@body {
@channel 1 {
\$patch 1
\$octave 4
\$length 16
"""

tone = "/l2/d4"
for x in range(64):
print tone
#this new variable tone is overwriting the old tone! => variable as empty bowl symbolism
tone = random.choice(fugue[tone])

#here we print / place the timidity structure
print """
}
}
"""
```

Users: midge

## Use open clip art and a loop to make a book of patterns

```
print """<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg"
width="200px" height="50px"
viewBox="0 0 200 50"
zoomAndPan="disable" >"""

# vertical amount of elements
veramo = 20

# ydist increases the vertical distance
ydist = 10

for z in range(veramo):
transf = "transform=\"translate({0},{1})\">".format(0,z*ydist)
print "<g " + transf
# horizontal amount of elements
horamo = 20
# ydist2 increases the vertical distance
ydist2 = 10
# xdist increases the horizontal distance
xdist2 = 10
for x in range(horamo):
transf = "transform=\"translate({0},{1})\"".format(x*xdist,x*ydist2)
print "<rect " + transf + """ x="0" y="0" width="10" height="10" fill="black" />
print "</g>"

print "</svg>"
```

Uses: SVG, Inkscape

## Generating Outline Fonts with 5 Lines of Code

```import fontforge
font = fontforge.open('douar.sfd')
for glyph in font:
font[glyph].stroke('circular',  30, 'square', 'bevel', ('cleanup',))
font.generate('douar-new.ttf')
```

Uses: FontForge

## Create interactive vector graphics

Uses: Shoebot (http://shoebot.net/)

Source: Stuart Axon and Ricardo Lafuente

## Other Modules to check out...

• Manipulate images with PIL
• use reportlab to generate a paginated PDF
• use subprocess to run FFMPEG and scrape audio/video info using a regular expression
• use html5lib to scrape HTML
• use glob to process a folder full of files
• use urllib2, urlparse and html5lib to spider HTML
• use json to parse results from web APIs
• use optparse to make a self-documenting command line utility
• use random to work with some noise
• use datetime to work easily with dates and intervals
• use OSC to talk to control other (realtime) programs
• use uuid to generate unique ids
• use zipfile
• use xml to read and extract data from an XML source
• generating an epub...