Allow for nested properties in list form when using \override.
[lilypond.git] / scm / graphviz.scm
blobc2801633a80dc4e70d86cfc1b451957a5f05a715
1 ;;;; graphviz.scm -- utilities for creating graphviz output
2 ;;;;
3 ;;;;  source file of the GNU LilyPond music typesetter
4 ;;;;
5 ;;;; (c) 2007 Joe Neeman <joeneeman@gmail.com>
8 (define-module (scm graphviz)
9   #:use-module (lily)
10   #:export
11   (make-empty-graph add-node add-edge add-cluster
12                     graph-write
13                     ))
15 (define graph-type (make-record-type "graph" '(nodes edges clusters name)))
17 (define make-graph (record-constructor graph-type))
18 (define (make-empty-graph name) (make-graph '() '() '() name))
20 (define nodes (record-accessor graph-type 'nodes))
21 (define edges (record-accessor graph-type 'edges))
22 (define clusters (record-accessor graph-type 'clusters))
23 (define set-nodes! (record-modifier graph-type 'nodes))
24 (define set-edges! (record-modifier graph-type 'edges))
25 (define set-clusters! (record-modifier graph-type 'clusters))
27 (define (add-cluster graph node-id cluster-name)
28   (let* ((cs (clusters graph))
29          (cluster (assq cluster-name cs))
30          (already-in-cluster (if cluster
31                                  (cdr cluster)
32                                  '())))
33     (set-clusters! graph (assq-set! cs
34                                     cluster-name
35                                     (cons node-id already-in-cluster)))))
37 (define (add-node graph label . cluster-name)
38   (let* ((ns (nodes graph))
39          (id (length ns)))
40     (set-nodes! graph (assq-set! ns id label))
41     (if (and (not (null? cluster-name))
42              (string? (car cluster-name)))
43         (add-cluster graph id (car cluster-name)))
44     id))
46 (define (add-edge graph node1 node2)
47   (set-edges! graph (cons `(,node1 . ,node2) (edges graph))))
49 (define (graph-write graph out)
50   (let ((ns (nodes graph))
51         (es (edges graph))
52         (cs (clusters graph)))
53     (ly:message (format (_ "Writing graph `~a'...") (port-filename out)))
54     (display "digraph G {\nrankdir=\"LR\"\nnode [shape=rectangle]\n" out)
55     (map (lambda (n) (display (format "~a [label=\"~a\"]\n" (car n) (cdr n)) out))
56          ns)
57     (map (lambda (e) (display (format "~a -> ~a\n" (car e) (cdr e)) out))
58          es)
59     (map (lambda (c)
60           (display (format "subgraph cluster_~a {\nlabel= \"~a\"\ncolor=blue\n"
61                            (string-filter (car c) char-alphabetic?)
62                            (car c))
63                    out)
64           (map (lambda (n) (display (format "~a\n" n) out)) (cdr c))
65           (display "}\n" out))
66          cs)
67     (display "}" out)))