Generating an SVG travel plan with Python

This is a quick one. I wanted to make a program to draw a graphic describing a trip I am planning. I decided I wanted to make a Python script to output an SVG file, that I could easily edit on inkscape later. I used the pySVG module for that.

The graphic is like this: Bars represent when I am where. The vertical axis represent the city, and the horizontal axis is the time. Vertical lines show the day transitions, and the surrounding solid vertical bars in the background show when it is day and night, to help me plan when I am going to be sleeping at an hotel.

Linking these bars are lines, that represent the transportation via airplane, bus, train, etc. The limits of the bars, and the lines, are the time of departure and arrival of these transportations. Near the lines there are comments, with a description of this locomotion (i.e. plane flight code). Here is the result…

This is a renderized PNG, of course… Unfortunately WordPress doesn’t support svg! 😦

The input I used to produce this image was

Sampa       30/1/2011 21:10 31/1/2011 11:50 Amsterdam   KLM 792
Amsterdam   31/1/2011 13:10 31/1/2011 14:40 Praga       Czech A 4629
Praga       31/1/2011 16:30 31/1/2011 18:30 Plzen       Trem
Plzen       04/2/2011 10:00 04/2/2011 12:00 Praga       Trem
Praga       05/2/2011 11:00 05/2/2011 12:40 Amsterdam   KLM 1352
Amsterdam   07/2/2011 10:10 07/2/2011 19:10 Sampa       KLM 791

And here is the code. I parsed the input with normal Python tools, and used the datetime module to make calculations with the dates. All the times must be converted to seconds since a reference, and then to image coordinates… Note that in Python 2.7 it seems there is an easier way to make this conversion, instead of using that datetomm function.

The code is really ugly, I really did it all in a hurry. Not sure what is the best way to improve it. But I hope it’s not difficult to understand… I took a lot from the pyGTK examples.

from pysvg.structure import *
from pysvg.core import *
from pysvg.shape import *
from pysvg.text import *

from pysvg.builders import *#ShapeBuilder

import datetime as dt
import re


def datetomm(td):
    return 5*100e-6 * (td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6

class Stay:
    def __init__(self,mySVG, sb,base,loc, ini,end):
        self.mySVG = mySVG
        self.sb = sb
        self.base=base

        self.ini=ini
        self.end=end
        self.loc=loc

    def draw(self):
        ptini = datetomm(self.ini-base)
        ptend = datetomm(self.end-base)

        pty = 20+self.loc*40

        mySVG.addElement(sb.createRect(ptini, pty, ptend-ptini, 20,fill='#66c'))

class Trip:
    def __init__(self, mySVG,sb,base,  loca, locb, ini,end,comment ):
        self.mySVG = mySVG
        self.sb = sb
        self.base=base
        
        self.ini=ini
        self.end=end
        self.loca=loca
        self.locb=locb
        self.comment =comment

    def draw(self):
        ptini = datetomm(self.ini-base)
        ptend = datetomm(self.end-base)

        ptya = 20+self.loca*40
        ptyb = 20+self.locb*40

        if ptya<ptyb:
            ptya+=20
        else:
            ptyb+=20
            
        mySVG.addElement( sb.createLine(ptini, ptya, ptend, ptyb, strokewidth=2) )

        ty = (ptya+ptyb)/2 +5
        tx = (ptini+ptend)/2+4
        t=text(self.comment, x=tx,y=ty)

        t.set_style("font-family:FreeSans;font-weight:bold;font-size:11px")

        mySVG.addElement( t )

  
if __name__ == '__main__': 
    mySVG=svg(0,0, width="26cm", height="17cm")

    sb =ShapeBuilder()

    base = dt.datetime(2011,1,30)
    ###########################################################################
    ## Desenha fundo colorido
    w = datetomm( dt.timedelta(0.25)  )
    for dia in range(11):
        xx = datetomm( dt.timedelta(dia)  )

        rec=sb.createRect(xx-w, 0, 2*w, 200, fill='#aaa', stroke='none')
        mySVG.addElement( rec )
        rec=sb.createRect(xx+w, 0, 2*w, 200, fill='#eee', stroke='none')
        mySVG.addElement( rec )


    ###########################################################################
    ## Desenha risquinhos
    w = datetomm( dt.timedelta(0.25)  )
    for dia in range(11):
        xx = datetomm( dt.timedelta(dia)  )
        lin=sb.createLine(xx, 0, xx, 200, strokewidth=1)
        lin.set_style("stroke:black;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:2,2;stroke-dashoffset:0")
        mySVG.addElement( lin )

    ###########################################################################
    ## Desenha risquinhos horiz
    w = datetomm( dt.timedelta(0.25)  )
    for ll in range(4):
        loc = 20+ll*40+18
        lin=sb.createLine(0, loc, 500, loc, strokewidth=1)
        lin.set_style("stroke:gray;stroke-width:1;")
        mySVG.addElement( lin )


    ###########################################################################
    ## Lê todas viagens do arquivo com especificações
    stL = []
    trL = []
    locs={}

    fi = open('/home/nlw/viagens.txt')

    oldini=dt.datetime(2011,1,30)
    olddest='Sampa'
    for ll in fi.readlines():
        orig, dia1, hora1, dia2, hora2, dest, comment = \
              re.split(' +', ll.strip(), 6)

        if not orig in locs:
            locs[orig] = len(locs)
        if not dest in locs:
            locs[dest] = len(locs)

        d1,m1,y1 = [int(x) for x in dia1.split('/')]
        H1,M1    = [int(x) for x in hora1.split(':')]
        d2,m2,y2 = [int(x) for x in dia2.split('/')]
        H2,M2    = [int(x) for x in hora2.split(':')]
        
        stL.append(Stay(mySVG, sb, base,
                        locs[olddest], oldini, dt.datetime(y1,m1,d1,H1,M1) ) )
        trL.append(Trip(mySVG, sb, base,
                        locs[orig], locs[dest], dt.datetime(y1,m1,d1,H1,M1), dt.datetime(y2,m2,d2,H2,M2), comment ) )
        oldini=dt.datetime(y2,m2,d2,H2,M2)
        olddest=dest
        #stL.append(Stay(locs[orig], dt.datetime(y1,m1,d1,H1,M1),dt.datetime(y2,m2,d2,H2,M2) ) )

        #### Desenha a "viagem"
        

    stL.append(Stay(mySVG, sb, base,
                    locs[olddest], oldini, dt.datetime(2011,2,9) ) )

    for st in stL:
        st.draw( )
    for tr in trL:
        tr.draw( )


    ## Write place names
    for k in locs:
        print k,locs[k]

        tx=datetomm(dt.datetime(2011,2,10)-base)
        ty = 20+locs[k]*40+15

        t=text(k, x=tx,y=ty)

        t.set_style("font-family:FreeSans;font-weight:bold;font-size:14px")
        mySVG.addElement(t)

    #### Save the SVG file
    mySVG.save('./output.svg')

So that’s it… Have fun using this code for anything, and if you are going to travel, have fun there too! 🙂

Advertisements

One thought on “Generating an SVG travel plan with Python

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s