Can you build reusable styles in GraphViz?
Asked Answered
S

6

47

I'm using graphviz to create flow charts. I change the styles every time by setting node and edge attributes:

node[shape="box", 
     style="filled, rounded", 
     fillcolor=lightyellow, 
     fontname="Verdana", 
     fontsize=9, 
     penwidth=.5, 
     color="gray83"]
   start, end;

It's a bit painful to include this and other similar declarations for parallelograms, rectangles, diamonds, etc.

I'd like to be able to reference a re-usable style document instead of copying and pasting into each .dot file.

Is there a standard way to do this? I could potentially build a shell script or a python script that would do this for me, but it seems like the functionality should already be there.

Softwood answered 3/12, 2014 at 2:6 Comment(0)
W
56

"Sometimes the answer is 'no'."

So, no. GraphViz lacks the notion of "named styles" seen in word processors like Microsoft Word and LibreOffice, and lacks the style "class" notion from HTML and CSS. Its formatting attributes are more primitive and, in many cases, must be explicitly stated.

You can set some defaults, as in its finite state machine example:

node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8;
node [shape = circle];

Here you get defaulting to the shape of a circle (the last shape defined), with explicit calling out of a handful of nodes that are previously declared under a previous default (doublecircle). This is a convenience for some designs, but it requires a good degree of preplanning (e.g. of the order items are declared). You can sometimes use the subgraph feature to help organize defaults by group, as this Stack Overflow answer shows.

But defaults are a small comfort to those of us used to expressive, simple type mechanisms. A look at the rest of the documentation confirms that, while you can use some HTML-styling elements for text, e.g., they are restricted to HTML tags such as <b> and <i>. This is primitive HTML styling circa 2001, prior to the spread of quality CSS.

Don't be fooled by the stylesheet attribute, either; it's only for SVG output, and is disappointingly much less general and valuable than it first seems.

So, long story short, "no." GraphViz has no built-in reusable style elements. If you want that, you will have to build that separately using a program, a macro-preproessor, or the like. Sorry!

Wileywilfong answered 3/12, 2014 at 2:35 Comment(0)
M
9

Yes it does.

Use the class attribute in nodes or edges. Use the stylesheet attribute in the graph (or pass -Gstylesheet=whatever.css in the CLI.

The stylesheet is normal CSS. Classes wok just like in HTML.

You do need very latest graphviz for this to work.

Example:

https://ralsina.gitlab.io/boxes-book/part3/git_3.svg

If you look at the source you will see it loads https://ralsina.gitlab.io/boxes-book/styles/forest.css which has all the styles.

It works for SVG output (which is the good output ;-)

Marsland answered 22/4, 2018 at 23:48 Comment(1)
Links appear to be out of date as the graph shows but the stylesheet cannot be found so your example doesn't seem to workRefutative
A
6

(1) It's possible with annoying workarounds similar to the answer:

// define some nodes which shall have common style properties:
myNode1, myNode2, myNode3 [shape="box", style="filled, rounded", ...]

// now you can define custom style properties for each node, f.e. the labels
myNode1 [label="my fancy label for node 1"]
myNode2 [label="my fancy label for node 2"]

// you can then define another common style for other nodes:
myHexNode1, myHexNode2 [shape="hexagon", ...]

// now you can define custom style properties for each node, f.e. the lables
myHexNode1 [label="my hexnode 1 text"]
myHexNode2 [label="my hexnode 2 text"]

// and now the edges
myNode1 -> myHexNode1 -> myNode2 -> myHexNode2;

(2) By grouping elements in subgraph and defining the style properties locally within the subgraph as described in this answer.

(3) There has been a very nice feature request here which already describes the syntax. Anyway, at the moment nobody is working on it and it does not look like to be started soon.

Finally, this looks like this:

enter image description here

Anemometry answered 28/12, 2019 at 12:51 Comment(4)
I don't think this works. I'm getting a syntax error (at least on WebGraphViz) for the comma-separated list of nodes from your line 2.Skirt
@O.R.Mapper: just remove the , ... in line 2 and 9. These are just place holder for further properties you need.Anemometry
I didn't have those. It rather seemed that Graphviz couldn't cope with myNode1, myNode2, myNode3 when I tried before.Skirt
You are right. On WebGraphViz it does not work. On my PC it works with graphViz 2.40.1-2. I get rounded nodes and hexagonal nodes as expected. Added the generated image now.Anemometry
V
5

Yes you can, but not using GraphViz alone.

As stated before, the C preprocessor can be used to create some pretty good templates.

Example DOT file:

#define _STR(x) #x
#define STR(x) _STR(x)

#define STYLE1 shape="box",style="filled, rounded", fillcolor=lightyellow
#define _STYLE2_l(A,B) {{<ia>|<ib>}|A|B}
#define STYLE2(A,B) shape="record" label=STR(_STYLE2_l(A,B))

digraph Orthogonal {
    graph [rankdir=LR];

    a[STYLE1,label="a"];
    b[STYLE2(B1,B2)];
    c[STYLE1,label="c"];
    d[STYLE2(D1,D2)];

    a->b:ia;
    c->d:ib;
    b->c;
    b->d:ia;
}

Two style templates have been created. "STYLE1" is simply replaced by it's definition during preprocessing. "STYLE2" is a little more complex and shows the use of paramters/arguments within a template. It is constructed out of several macros.

The file can be rendered using:

cpp graph_file.gv | dot -Tpng >out.png

All output modes should work. This is the result:

Example Graph

Voorhis answered 1/7, 2020 at 9:27 Comment(1)
While i agree this is a great solution. But i cant help but wonder if this might create problems somewhere. Especially when the cpp manual warns people not to do this.. The C preprocessor is intended to be used only with C, C++, and Objective-C source code. In the past, it has been abused as a general text processor. It will choke on input which does not obey C's lexical rules. For example, apostrophes will be interpreted as the beginning of character constants, and cause errors. I think an answer based on m4 like this will be better.Baleen
L
1

Not directly in Graphviz, but the Excel to Grapvhiz Relationship Visualizer can do this according to it's featurelist on Sourceforge:

...
Style editor for visually defining Node, Edge, and Cluster attributes
Saves style definitions by name for reuse, and include predefined flowchart shapes
...

On the same Sourceforge page there's a screenshot showing this functionality:

enter image description here

Loreenlorelei answered 7/7, 2020 at 19:50 Comment(0)
G
0

You can use a c preprocessor and #include

Some c preprocessors will output will generates line starting with # to indicate original line numbers but GraphViz are OK with those. From GraphViz doc "The DOT language": ... In addition, a line beginning with a '#' character is considered a line output from a C preprocessor (e.g., # 34 to indicate line 34 ) and discarded.

Girlhood answered 27/4, 2018 at 17:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.