florian berger

Creating Simple SVG from Python

There are several options to generate simple SVG output from Python programs. This article compares the pySVG and svgwrite modules.

Creating Simple SVG from Python

There are several options to generate simple SVG output from Python programs. This article compares the pySVG and svgwrite modules.

Since I am planning to write a specialised graphics converter that outputs SVG, I browsed the Python Package Index for modules that ease the creation of dead simple SVG documents. There were two candidates that I've taken a closer look at: pySVG and svgwrite.

The Setting

As my goal will be very simple SVG output, mainly consisting of rectangles, I had two clear demands for an SVG module:

  1. It must be simple to figure out how to use the module for simple shapes.
  2. Once that is done, it still has to be easy and straightforward to use.

So, this is not a general comparison, and might not be applicable to other cases.

pySVG

pySVG has been written by Kerim Mansour, who is a Java developer (and, I have to admit here already, it shows).

The website has an introduction, a feature list and the license, but sadly neither example code nor a tutorial nor documentation, so one has to fetch the package and dig through that to figure out how it works and whether it's useful.

Unpacking the archive yields a "doc" and a "src" folder and the "setup.py" script. There is no README for an instroduction or a quick start. The "doc" folder contains a tutorial in legacy Microsoft Word ".doc" format which showcases the library, including screenshots. More useful for getting started is the "src/tests/" folder which holds some example scripts.

pySVG is a Python package with 14 modules. The functionality is scattered all over these modules, which is why the author does a funky import dance in every example script:

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 *

This is bad practice times two: first, starting out it is not easy to figure out what acutally needs to be imported; second, this either forces the user to have blind faith that the imported symbols will not clash with the local namespace (see the Python docs), or use explicit imports like

import pysvg.structure

and subsequently bloat the code with long.traversals.along.the.modules like pysvg.structure.svg.

Still, using the tutorial and examples it is not too hard to figure out how to build simple documents. Here is my example:

import pysvg.structure
import pysvg.builders
import pysvg.text

svg_document = pysvg.structure.svg()

shape_builder = pysvg.builders.ShapeBuilder()

svg_document.addElement(shape_builder.createRect(0, 0,
                                                 "200px", "100px",
                                                 strokewidth = 1,
                                                 stroke = "black",
                                                 fill = "rgb(255, 255, 0)"))

svg_document.addElement(pysvg.text.text("Hello World",
                                        x = 210, y = 110))

print(svg_document.getXML())

svg_document.save("test-pysvg.svg")

ShapeBuilder is a class that eases creation of shapes with reasonable default styles. The method naming would benefit from a look at PEP 8. pySVG's approach to document creation is straightforward, but it leaves me wanting more; it is simply not very pythonic, it rather feels like the Java way of doing things.

The source code documentation and thus pydoc output are mediocre, mostly due to a lot of imports and inheritance. For example, the g element in pysvg.structure inherits from 7 classes:

class g(BaseElement, CoreAttrib, ConditionalAttrib, StyleAttrib, ExternalAttrib, PresentationAttributes_All, GraphicalEventsAttrib):
    """
    Class representing the g element of an svg doc.
    """

The package author uses Python 2.6 and has not tested any other version.

svgwrite

svgwrite is a tool by Manfred Moitzi, whose main project currently is the [ezodf] Python package.

The Package Index site has installation details and a pointer to the documentation, and also a nice little example which gives a taste of what to expect.

After unpacking, the svgwrite directory contains the folders "examples", "tests" and "svgwrite", as well as the files "NEWS.TXT", "README.txt", "LICENSE.TXT" and "setup.py". The "README.txt" has the same contents as the homepage in the Package Index. Apart from some examples there is no local documentation, but the docs at http://packages.python.org/svgwrite are pretty well written and organized. They start with an overview and a short example.

svgwrite is the only module that needs to be imported. An SVG document is created by instantiating the Drawing class. Strangely, the functions to create objects that represents SVG elements are arranged as methods of the Drawing class. Anyway, with that out of the way it is not too hard to replicate the above example:

import svgwrite

svg_document = svgwrite.Drawing(filename = "test-svgwrite.svg",
                                size = ("800px", "600px"))

svg_document.add(svg_document.rect(insert = (0, 0),
                                   size = ("200px", "100px"),
                                   stroke_width = "1",
                                   stroke = "black",
                                   fill = "rgb(255,255,0)"))

svg_document.add(svg_document.text("Hello World",
                                   insert = (210, 110)))

print(svg_document.tostring())

svg_document.save()

Class and method naming feels right at home. It is a neat feature that all SVG element attributes can be appended to the __init__() call as named parameters. It took me some try and error though to figure out what becomes of the dash in stroke-width (hint: an underscore). Also, the SVG checks that are implemented in svgwrite seem a little too strict, for example it will reject rgb(255, 255, 0) as a color string because of the whitespace, although this is explicitly allowed in the SVG spec. Still, svgwrite feels more pythonic than pySVG; observe, for example, the tuples used for sizes and coordinates.

The source code is cleanly organised, with excellent docstrings, making pydoc browsing and enjoyment. The online documentation could use little improvements here and there, for example it took a while to find out which parameters could be used for SVG elements (here is a list, but it does not document the dash issue) or how a color must be written (using the rgb function).

svgwrite is labeled to be compatible with Python 2.5, 2.6, 2.7 and 3.1.

Conclusion

pySVG and svgwrite take the same approach to creating a SVG document: there is a class for the document (svg / Drawing) with a method to add elements (addElement() / add()), a method to print the SVG data (getXML() / tostring()) and save an SVG file (save(filename) / save()). To someone who needs a module to write SVG quickly, svgwrite feels a little more accessible because of the simple import and the good documentation. At a glance, pySVG strill looks promising in terms of more sophisticated features; should I need those one day, I will be back with a report.