Over the past few years I’ve written quite a few posts with images generated by a library I (now along with many others) wrote. Most famously, this is how I created those factorization diagrams. But I’ve used it in many other posts as well (1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16). I promised to write a post explaining how it works and (more importantly) how you can use it too—and here it is!
My library is called diagrams (a rather generic but nicely descriptive name). As I hope to show you—and as I hope you can see from the above list of posts—it’s really nice for doing all sorts of visualization, for mathematical exploration, and even for creating art with a mathematical bent. It’s not a program for creating images (like Illustrator or Inkscape), but actually a language for describing what you want your images to look like. What makes it really powerful is that it is actually “embedded” in the Haskell programming language—that is, diagrams programs are Haskell programs, written using stuff provided by the diagrams library. To do simple things with diagrams doesn’t actually require knowing much (if any) Haskell, but the full power of Haskell is available to do more sophisticated things.
So, what can it do? Of course, you can make simple shapes like circles, squares, triangles, pentagons, and so on:
> dia = circle 1
You can also make crazier shapes like stars:
> dia = stroke $ star (StarSkip 2) (pentagon 1)
You can specify attributes like fill and line color, line width, or line dashing:
> dia = myStar # lw 0.05 # lc purple # fc yellow # dashing [0.1,0.05] 0 > > myStar = stroke $ star (StarSkip 2) (pentagon 1)
Note in the above example how you can make arbitrary definitions and then reuse them.
You can apply transformations like translation, rotation, scaling, and reflection:
> dia = myStar # scale 2 > ||| myStar # rotateBy (1/19) > ||| myStar # reflectY # translateY 0.5 > > myStar = stroke $ star (StarSkip 2) (pentagon 1)
You can compose multiple diagrams into one by putting them on top of each other or next to each other:
> dia = (circle 1 <> circle 2 <> circle 3) ||| (square 2 === triangle 2)
You can already create some cool pictures just using the above features—and you don’t really have to know any Haskell! But bringing the power of Haskell into the picture lets us accomplish much more. I’ve written about Haskell several times before; if you want to learn more about it, check out Learn You a Haskell. To whet your appetite, here are a few simple examples.
Haskell has a built-in notion of lists. We can create lists of diagrams and lay them out using operations like
> dia = hcat [ circle n # fc blue | n <- [1 .. 5] ]
We can also create shapes from arbitrary paths described using lists of points or vectors, or use paths to position other diagrams:
> myPath = fromVertices [ 0 & 0, 0 & 2, 0.5 & 0.5, 2 & 0 ] > > dart = myPath # close # stroke # rotateBy (-1/6) > > circles = decoratePath myPath (repeat (circle 0.2)) > > dia = dart ||| strutX 2 ||| circles # centerXY
We can write recursive functions to generate diagrams:
> sierpinski 1 = triangle 1 # fc black > sierpinski n = s === (centerX (s ||| s)) > where s = sierpinski (n-1) > > dia = sierpinski 6
There are also a ton of existing Haskell libraries available on http://hackage.haskell.org/, and we can seamlessly integrate any of them with diagrams—though I don’t have a good example off the top of my head.
If you’d like to play around with it, here’s what to do. The first step is to install the Haskell Platform. Once you have that installed, open a terminal/command line, and type
cabal install diagrams
then go get a snack because you might have to wait for a while. But after it finishes you should have diagrams installed! Now take a look at the tutorial and the gallery of examples, and start playing!
After you have finished the tutorial (which really only scratches the surface), there is also an extensive user manual which covers (almost) everything you could want to know about diagrams. If you have questions, there is a mailing list and an IRC channel (
#diagrams on freenode). You’re also welcome to leave questions as comments on this post.
Last but not least, if you’re interested in seeing how it’s all implemented, or even contributing to the project, the source code is all available on github.