Twenty things to do with a python script

From XPUB & Lens-Based wiki

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

TurtleGrid.png

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()

Source: Lidia Pereira, Turtle Graphics Exercises

Create an Inkscape plugin to draw turtle graphics

LidiaTurtleGraphicsInkscape.png

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/
Released under a GPL3 license, see LICENSE

#XSS2qwXBUYv%s+<>dqw6wmq2om#HH$wac=:;==|i|nYUWQQW$WQQQWmBQmWBQWWBWQWWWmBBWWmQQQQ
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.heading = heading
        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):
        self.x += math.cos(self.heading) * steps
        self.y -= math.sin(self.heading) * 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
        self.heading -= d
    rt = right

    def left (self, d):
        d = (d/180.0)*math.pi
        self.heading += d
    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 setheading(self, d):
        self.heading = (d/180.0)*math.pi
    seth = setheading
    face = setheading

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

    def circle(self, radius, extent=None, steps=None):
        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):
                path = inkex.etree.Element(inkex.addNS('path', 'svg'))
                # 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:
            textelt = inkex.etree.Element(inkex.addNS('text', 'svg'))
            textPath = inkex.etree.Element(inkex.addNS('textPath', 'svg'))
            # assert False, str(self.lastpath.attrib.keys())
            textPath.attrib[inkex.addNS('href', 'xlink')] = '#'+self.ensure_id(self.lastpath)
            textPath.text = text
            textelt.append(textPath)
            self.stack[-1].append(textelt)
        else:
            textelt = inkex.etree.Element(inkex.addNS('text', 'svg'))
            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"""
        g = inkex.etree.Element(inkex.addNS('g', '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
        self.OptionParser.add_option('-l', '--layer', action = 'store',
          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')
                outputlayer.set(inkex.addNS('label', 'inkscape'), self.options.layer)
                outputlayer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
                
                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.

Mishopyanim.gif
import struct, sys
 
width = 320 
 
height = 240 
 
header = struct.pack("<BBBHHBHHHHBB",0,0,2,0,0,8,0,0,width,height,32,1<<5)
 
totalframes = 25
 
for frame in xrange(totalframes):
    out = open("frame_%02d.tga" % frame, "wb")
    out.write(header)
    for y in xrange(height):
        for x in xrange(width):
            if y >= 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()

Lucia gif.gifFrames lucia.gif

import struct, sys
 
width = 320
height = 240
xWhite = 0
header = struct.pack("<BBBHHBHHHHBB",0,0,2,0,0,8,0,0,width,height,32,1<<5)

 
totalframes = 25
for frame in xrange(totalframes):
    frame = frame+1
    out = open("frames/frame%02d.tga" % frame, "wb")
    out.write(header)
 
    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()
Plasma.gif
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("<BBBHHBHHHHBB",0,0,2,0,0,8,0,0,width,height,32,1<<5)

for frame in xrange(nFrames):
    output = open("frames/frame%02d.tga" % frame, "wb")
    output.write(header)
 
    for y in xrange(height):
        for x in xrange(width):
            offset = frame * (1.0 / nFrames)
            primaryColor = abs(sin((0.2)*tau + (x) / (4.0+8.0*sin((0.2)*pi)))
                + cos((0.2)*tau + (x+y) / (6.0+16.0*cos((0.2)*tau)))
                + sin(dist(x, y, 32*sin(offset*tau)+96, 32*cos(offset*tau)+height / 2) / 24.0) # orbit 1 on left side 
                + sin(dist(x, y, 32*cos(offset*tau) + width-96, 32*sin(offset*tau)+height / 2) / 8.0) # orbit 2 on right side
                )
            r = abs(primaryColor - abs(cos(dist(x + sin(offset*tau), y + 25*sin(offset*tau), width / 2, -2000) / 4.0))) * 48
            g = primaryColor * 48 if primaryColor >= 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

SocialNetworkingWithEmmaWoodhouse.png

Facebook's Terms of Service is crossed with Jane Austen's Emma to produce a hybrid social protocol

Uses: NLTK

Source: Femke Snelting, EmmaWoodhouse.odt

Programmatically Manipulate Typefaces

EricSchrijverProgrammaticallyManipulatingTypfaces.png

Uses: FontForge and robofab

Source: Eric Schrijver, http://i.liketightpants.net/and/programmatically-manipulating-typefaces

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
nltk.download()
corpus_root='/path/to/your/texts'
wordlists=PlaintextCorpusReader(corpus_root,'.*')
acta=nltk.text.Text(wordlists.words('ACTA.txt'))
import sys, nltk
from nltk.corpus import PlaintextCorpusReader
corpus_root=sys.argv[1]
print corpus_root
corpus=PlaintextCorpusReader(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

Source: Nicolas Malevé, http://vj13.constantvzw.org/live/deskcam/

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 &

See Also: Serve.py

Permute the spellings of search terms

LindaHilflingMisspellingGenerator.png

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

GooglePlus7Search.png

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

GooglePlus7Results.png

Uses: NLTK

Source: Sebastian Schmieg & Silvio Lorusso

Create a Traceroute Map

1 week browsing.png

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

http://vimeo.com/50859298

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

Source: Birgit Bachler, http://www.birgitbachler.com/portfolio/?p=506

Create a custom joystick sound recorder

RugzakPeterWestenberg.jpg

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

Uses: pygame

Source: Peter Westenberg, http://www.deschaarbeeksetaal.be/p/rugzak/

Slice & reorder an audio file by predominant frequency

DataradioSpectrumSortPlayers.png

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('--freq', default=44100, type=int, help="audio frequency")
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 )

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

# RANGE HEADERS
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)
listener.get_bus().add_watch(listener_on_message, None)
mainloop = gobject.MainLoop()
listener.set_state(gst.STATE_PLAYING)
 
try:
    mainloop.run()
except: # an interruption from Ctrl-C
    pass

Uses: gstreamer

Source: Nicolas Malevé and Michael Murtaugh, Full documentation & pipeline

3D Cloud computing with Blender

http://vimeo.com/10850063

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
    scene.objects.link(ob_new)
    ob_new.select = True
 
    return ob_new

Source: Julien Deswaef, Brussels Blender Group

Create a dotcom index using letter permuations

Screen shot 2013-04-02 at 11.52.28 AM.png

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)

IMG_1940.JPG

http://activearchives.org/wiki/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
# it under the terms of the GNU General Public License as published by
# 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:
    subtitles = f.read()
    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

Scetchbook2011-02 markov.jpg

File:Fugue 01 20110608.oggFile:Fugue 04 20110530.oggFile:Fugue 01-octave4 20110608.ogg

#!/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 """
@head {
    $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

Source: Natasa Siencnik User:Natasa_Siencnik/prototyping/markov

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

Amanofmanyparts.gif

 
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"
     xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
	 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

Source: Silvio Lorusso, A man of many parts

Generating Outline Fonts with 5 Lines of Code

Douar-outline-1024x640.png

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

Source: Ricardo Lafuente, http://blog.manufacturaindependente.org/2011/02/generating-outline-fonts-with-5-lines-of-code/

Create interactive vector graphics

http://www.stuartaxon.com/2013/03/20/natural-movement-in-python-part-3-particles/#more-331

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...