Here's the solution I came up with, to use SVG through PySVG. It's pure-Python and so doesn't require any extra libraries, which is always a pain when dealing with graphics.
I used the code below to generate an SVG file, which was converted to the above PNG with Inkscape:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Insert description here | |
""" | |
import random | |
import pdb | |
##from pysvg.filter import * | |
##from pysvg.gradient import * | |
##from pysvg.linking import * | |
##from pysvg.script import * | |
##from pysvg.shape import * | |
##from pysvg.structure import * | |
##from pysvg.style import * | |
from pysvg.text import * | |
from pysvg.builders import svg, ShapeBuilder, StyleBuilder | |
class Drawing(object): | |
def __init__(self): | |
self.canvas = svg() | |
def rectangle(self, *args, **kwargs): | |
"""0, 0, 400, 200, 12, 12, strokewidth=2, stroke='navy')""" | |
sb = ShapeBuilder() | |
rect = sb.createRect(*args, **kwargs) | |
self.canvas.addElement(rect) | |
def line(self, *args, **kwargs): | |
"""0, 0, 400, 200, strokewidth=2, stroke='navy')""" | |
sb = ShapeBuilder() | |
line = sb.createLine(*args, **kwargs) | |
self.canvas.addElement(line) | |
def text(self, x, y, line, color="blue"): | |
sb = StyleBuilder() | |
sb.setFontFamily(fontfamily="Verdana") | |
sb.setFontSize('5em') | |
sb.setFilling(color) | |
t1 = text(line, x, y) | |
t1.set_style(sb.getStyle()) | |
self.canvas.addElement(t1) | |
def arrow(self, x, y, width, height, forward=True, stroke="blue", fill="blue", strokewidth=1): | |
sb = ShapeBuilder() | |
arrowshape = [(0, 0), (width, 0), (width, -height*0.2), | |
(width*1.2, height*0.5), (width, height*1.2), (width, height), (0, height)] | |
if not forward: # Change the direction | |
arrowshape = [(width*1.2 - a, b) for (a, b) in arrowshape] | |
arrowshape = [(a+x, b+y) for (a, b) in arrowshape] # Translate the arrow | |
pl = sb.createPolygon(points=sb.convertTupleArrayToPoints(arrowshape),strokewidth=strokewidth, stroke=stroke, fill=fill) | |
self.canvas.addElement(pl) | |
def save(self, filename): | |
self.canvas.save(filename) | |
def main(): | |
data = [["1","G","9","NUK", "3"], ["1","3","G","9", "NUK"]] | |
genenames = set(data[0]) | set(data[1]) | |
positions = {} | |
for genename in genenames: | |
pos = [] | |
for i in range(2): | |
if genename in data[i]: | |
pos.append(data[i].index(genename) + 1) | |
else: | |
pos.append(0) | |
positions[genename] = pos | |
drawing = Drawing() | |
for genename in genenames: | |
pos = positions[genename] | |
for i in range(2): | |
p = pos[i] | |
drawing.rectangle(p*100, i*100, 60, 20, 5, 5, strokewidth=1, fill="red", stroke="navy") | |
drawing.text(p*100+5, i*100+13, genename) | |
drawing.arrow(p*100, (i+2)*100, 60, 20, fill="red", forward=(random.random() > 0.5)) | |
drawing.line(pos[0]*100+30, 0*100+20, | |
pos[1]*100+30, 1*100, | |
strokewidth="1", stroke="black") | |
drawing.save('genes.svg') | |
if __name__ == "__main__": | |
main() |