SVG figures with Cupid

Sunday 26 January 2014This is close to 11 years old. Be careful.

When I wrote Facts and myths about Python names and values, I included figures drawn with Graphviz. I made a light wrapper to help, but the figures were mostly just Graphviz. For example, this code:

g = CogGraphviz()
g.codelabel("nums = [1, 2, 3]")
g.dot("""
    nums [NAMEATTRS]
    list1 [shape=record, label="{<0>|<1>|<2>}"]
    nums -> list1:0
    subgraph nums {
        rankdir=LR;
        1 [INTATTRS]
        2 [INTATTRS]
        3 [INTATTRS]
        }
    list1:0 -> 1
    list1:1 -> 2
    list1:2 -> 3
    """)
g.img(alt="nums refers to a list, which refers to ints")

produced this figure:

A list of three numbers

The beauty of Graphviz is that you describe the topology of your graph, and it lays it out for you. The problem is, if you care about the layout, it is very difficult to control. Why are the 1, 2, 3 where they are? How do I move them? I couldn’t figure it out. And I wanted to have new shapes, and control where the lines joined, etc.

So I wrote a library called Cupid to help me make the figures the way I wanted them. Cupid is an API that generates SVG figures. Half of it is generic “place this rectangle here” kinds of SVG operations, and half is very specific to the names-and-values diagrams I wanted to create.

Now to make that same figure, I use this code:

fig = start_figure(title="nums refers to a list, which refers to ints")
fig.top_code("nums = [1, 2, 3]")
n_nums = fig.auto_name("nums")
l_nums = fig.list(length=3, pos=fig.val_for_name(n_nums))
fig.reference(n_nums, l_nums[0])
y_ints = fig.y+10
for i in range(3):
    i_num = fig.int(top=(l_nums[1].cx+(i-1)*35, y_ints), text=str(i+1))
    fig.connect(
        l_nums[i].center, 90, i_num.north, 90,
        start_marker=fig.DOT, class_="arrow"
    )
finish_figure(fig)
nums refers to a list, which refers to intsnums123nums = [1, 2, 3]

The new code is more complicated than the old code, but I can predict what it will do, and if I want it to do something new, I can extend Cupid.

Cupid isn’t the handiest thing, but I can make it do what I want. This is my way with this site: I want it the way I want it, I enjoy writing the tools that let me make it that way, and I don’t mind writing code to produce figures when other people would use a mouse.

Comments

[gravatar]
Are you aware of dpic (https://ece.uwaterloo.ca/~aplevich/dpic/) which takes the pic language (from troff) as input, and produces a variety of outputs, including svg?
[gravatar]
@Paul, I was not aware of it. It looks incredibly powerful! I will remember it for when I outgrow Cupid. :)
[gravatar]
Carlos Andrés Rocha 1:25 AM on 27 Jan 2014
Nice! I wonder where the name came from? Is it because of the arrows?

TikZ is a similar package that I have used in the past. It is based on LaTex. There are some really nice examples out there:
http://www.texample.net/tikz/examples/tcp-state-machine/
[gravatar]
If you don't want to write a svg generator then look at SvgWrite
http://packages.python.org/svgwrite/ You would still have to create the specifics on how you want the figures but the python to svg is already written and tested. More example svgwrite python programs and svg are at
https://docs.google.com/folder/d/0BwFQiTKfux0qY1Y2d1hRdndtSEk/edit
[gravatar]
@Lawrence: I neglected to mention it, but Cupid uses svgwrite!

Add a comment:

Ignore this:
Leave this empty:
Name is required. Either email or web are required. Email won't be displayed and I won't spam you. Your web site won't be indexed by search engines.
Don't put anything here:
Leave this empty:
Comment text is Markdown.