LaTeX and UML, cont’d

I had to re-write some paper I’m working on that included a good deal of UML diagrams, so I used it as an opportunity to examine Metapost and MetaUML in more depth. Here are the results of the experiment, for those of you who are interested.

From the final result point-of-view, Metapost and MetaUML are amazing. My diagrams were transformed from looking somewhat sluggish to perfectly-aligned, polished top-of-the-line examples. Here’s a before-and-after example:

A class diagram made manually with UMLet

A class diagram made manually with UMLet

The same diagram programmed in Metapost and MetaUML

The same diagram programmed in Metapost and MetaUML

For those of you who can’t see the differences in those tiny images: The second diagram is more compact, better aligned and the elements are positioned more accurately. The gif conversion doesn’t do them justice: The Metapost diagram looks a lot better in print then its counterpart (that, by the way, looks better already then gif-exported diagrams).

From a production point-of-view: Well, Metapost is a programming language. It means you have to code your diagrams. The up side is that the results are more accurate and you can use coding features like loops and subroutines. The down side is that Metapost is, to say the least, an awkward programming language. It’s nothing that resembles a modern interpreter – It’s more like a 1980′s-inspired macro expander. Here’s the code for producing the second diagram, with the macros and definitions that I used for several other diagrams:

input metauml;
 
numeric s;
s := .25in;
 
iAssoc.iFont.scale := .85;
 
vardef Hierarchy(expr st)(suffix root)(text elems) =
	save Subs, s, ss;
	numeric s, ss;
	s := scantokens str st;
	ss := 2*s;
	leftToRight.top(s)(elems);
	Group.Subs(elems);
	topToBottom.midx(ss)(root, Subs);
	drawObject(root);
	drawObjects(Subs);
	forsuffixes S := elems:
		link(inheritance)(pathStepY(S.n, root.s, s));
	endfor;
enddef;
 
def MyClasses =
	Class.A("A")("+a")("+f()", "+g()");
	Class.B("B")("+b")("+f()");
	Class.C("C")("+c")("+f()");
	Class.D("D")("+d")("+g()");
	Class.E("E")("+e")("+g()");
	AbstractClass.StateA("StateA")()("+f()");
	StateA.info.iMethodStack.iPict.iFont.name := metauml_defaultFontOblique;
enddef;
 
beginfig(1);
	save A, StateA, B, C, NA, NB, x, y;
	MyClasses;
	Hierarchy(s)(StateA)(B, C);
	A.ne + (1.25in, 0) = StateA.nw;
	drawObjects(A);
	numeric x, y;
	x1 = xpart A.e;
	x2 = xpart StateA.w;
	y1 = ypart (1/6)[StateA.nw, StateA.sw];
	y2 = ypart (5/6)[StateA.nw, StateA.sw];
	link(association)((x1, y1) -- (x2, y1));
	link(associationUni)((x1, y2) -- (x2, y2));
	item(iAssoc)("a")(obj.sw = (x1, y1) + (3, 3));
	item(iAssoc)("1")(obj.nw = (x1, y1) + (3, -3));
	item(iAssoc)("states")(obj.se = (x2, y1) + (-3, 3));
	item(iAssoc)("*")(obj.ne = (x2, y1) - (3, 3));
	item(iAssoc)("current")(obj.se = (3/4)[(x1, y2), (x2, y2)]);
	item(iAssoc)("1")(obj.ne = (3/4)[(x1, y2), (x2, y2)]);
	Note.NA("current is","in states");
	Note.NB("curent.f();");
	NA.nw = A.se + (6, 5);
	NB.nw = A.sw - (0, .5in);
	drawObjects(NA, NB);
	clink(dashedLink)(A.methodStack.pict[1], NB);
	draw (1/4)[(x1, y2), (x2, y2)] --  NA.n dashed evenly;
endfig;
end

It might look neat to you for two reasons: First, I spent some time polishing this code (I never dreamed that I would one day refactor my diagrams, but I did). Second, the guy who wrote MetaUML is a saint: He did an absolutely fabulous job. He made me believe that the macro-expanding-hack-for-a-language that is Metapost, is actually a classless object-oriented interpreter.

Having said that, you can judge for yourself if coding your diagrams in Metapost is something worth doing. For the long run, creating a codebase of what you want to draw is probably worth doing; On the short term, it can be frustrating.

Posted Sunday, March 22nd, 2009 under Software Engineering.

Tags: ,

4 comments

  1. Maybe it is woth mentioning that UMLet can save the images in eps format, that can be easily inserted into LaTeX documents.

  2. Hi Guy,

    can you, please, elaborate a bit on how you’ve setup MetaPost/MetaUML?

    On Windows, I’ve spent a lot of time due to out-of-date state of MetaUML’s how-tos and website in general is not too informative. Finally, I ended up with TexLive installation, which somehow included the Metapost. But still, making the whole thing to work required me to install Ruby and Perl and make them both available in Path. And after all, I managed to transform website samples to PDFs. You diagram also works fine, but Use Case sample produces errors and the picture is messy in resulting PDF.

    I believe that “coding” the diagrams and integrating them into intranet portals is a right way to go in software companies (I adore the idea of writing diagrams and graphs in wikis via metauml/metapost and graphviz tools). Such diagrams can be easily updated and kept within the version control in a simple way, just like the source code.

    Thanks,
    Andrey

Leave a Reply

Security Code: