#| simple-header
-$Id: graphviz-support.lisp,v 1.7 2005/06/21 20:51:51 moody Exp $
-
-Copyright 1992 - 2005 Experimental Knowledge Systems Lab,
-University of Massachusetts Amherst MA, 01003-4610
-Professor Paul Cohen, Director
-
-Author: Gary King, Levente Mészáros, Attila Lendvai
+Author: Gary King, Levente Mészáros, Attila Lendvai
DISCUSSION
This file contains the stuff that does not depend on cl-graphviz.
|#
-(in-package metabang.graph)
-
-(export '(
- print-dot-key-value
- *dot-graph-attributes*
- ))
+(in-package #:metabang.graph)
;;; ---------------------------------------------------------------------------
;
; "GRAPHVIZ".
;
(defmethod graph->dot ((g basic-graph) (stream stream)
- &key
+ &key
(graph-formatter 'graph->dot-properties)
(vertex-key 'vertex-id)
(vertex-labeler nil)
(vertex-formatter 'vertex->dot)
- (edge-key nil)
(edge-labeler 'princ)
- (edge-formatter 'edge->dot))
- (format stream "~A G {~%graph " (if (contains-undirected-edge-p g) "graph" "digraph"))
+ (edge-formatter 'edge->dot)
+ &allow-other-keys)
+ (format stream "~A G {~%graph "
+ (if (contains-undirected-edge-p g) "graph" "digraph"))
(format stream "[")
(funcall graph-formatter g stream)
(format stream "];")
(princ " [" stream)
(when (and directed? directed-edge-tag)
(princ directed-edge-tag stream))
- (when edge-key
+ (when edge-labeler
(princ "label=\"" stream)
(funcall edge-labeler e stream)
(princ "\"," stream))
(iterate-vertexes
g
(lambda (v)
+ ;(spy v)
(iterate-edges
v
(lambda (e)
+ ;(spy e (undirected-edge-p e) (item-at-1 edges e))
(when (and (undirected-edge-p e)
(not (item-at-1 edges e)))
(setf (item-at-1 edges e) t)
'((:size coordinate)
(:bb bounding-box)
(:page text)
+ (:dpi float)
(:ratio (:fill :compress :auto)) ;; Could actually be a float number too
(:margin float)
(:nodesep float)
(:ranksep float)
(:ordering (:out))
+ (:overlap text)
(:rankdir ("LR" "RL" "BT"))
(:pagedir text)
(:rank (:same :min :max))
(:mclimit float)
(:layers text)
(:color text)
- (:bgcolor text)))
+ (:bgcolor text)
+ (:fontname text)))
(defparameter *dot-vertex-attributes*
'((:pos coordinate)
(:height float)
(:width float)
+ (:margin float)
(:fixed-size boolean)
(:label text)
(:shape (:record :plaintext :ellipse :circle :egg :triangle :box
:doublecircle))
(:fontsize integer)
(:fontname text)
+ (:fontcolor text)
(:color text)
(:fillcolor text)
(:style (:filled :solid :dashed :dotted :bold :invis))
- (:layer text)))
+ (:layer text)
+ (:url text)
+ (:peripheries integer)))
(defparameter *dot-edge-attributes*
'((:pos spline)
(:export-p t))
(defclass* dot-graph-mixin (dot-attributes-mixin) ()
- (:export-p t))
+ (:export-p t)
+ (:default-initargs
+ :vertex-class 'dot-vertex
+ :directed-edge-class 'dot-directed-edge
+ :undirected-edge-class 'dot-edge))
(defclass* dot-vertex-mixin (dot-attributes-mixin) ()
(:export-p t))
(defclass* dot-edge-mixin (dot-attributes-mixin) ()
(defclass* dot-graph (dot-graph-mixin graph-container)
()
- (:default-initargs
- :vertex-class 'dot-vertex
- :directed-edge-class 'dot-directed-edge
- :undirected-edge-class 'dot-edge)
(:export-p t))
(defclass* dot-vertex (dot-vertex-mixin graph-container-vertex) ()
(:export-p t))
-(defmethod (setf dot-attribute-value) :before (value (attr symbol) (thing dot-attributes-mixin))
+(defmethod (setf dot-attribute-value)
+ :before (value (attr symbol) (thing dot-attributes-mixin))
+ (declare (ignore value))
(ensure-valid-dot-attribute attr thing))
-(defmethod (setf dot-attribute-value) (value (attr symbol) (thing dot-attributes-mixin))
+(defmethod (setf dot-attribute-value)
+ (value (attr symbol) (thing dot-attributes-mixin))
(setf (getf (dot-attributes thing) attr) value))
(defmethod dot-attribute-value ((attr symbol) (thing dot-attributes-mixin))
(getf (dot-attributes thing) attr))
+(defmacro defpixel-inch-accessors (name attr type)
+ (let ((actual-name (form-symbol name (symbol-name '-in-pixels))))
+ `(progn
+ (eval-always (export ',actual-name))
+ (defmethod ,actual-name ((thing ,type))
+ "Return the attribute in pixels assuming 72 dpi"
+ (when (dot-attribute-value ,attr thing)
+ (* 72 (dot-attribute-value ,attr thing))))
+ (defmethod (setf ,actual-name) (value (thing ,type))
+ "Set the attribute in pixels assuming 72 dpi"
+ (setf (dot-attribute-value ,attr thing)
+ (coerce (/ value 72) 'double-float))))))
+
+(defpixel-inch-accessors width :width dot-vertex-mixin)
+(defpixel-inch-accessors height :height dot-vertex-mixin)
+
+
(defmethod graph->dot-properties ((graph dot-graph-mixin) (stream t))
(loop for (name value) on (dot-attributes graph) by #'cddr
do
- (print-dot-key-value name value *dot-graph-attributes* stream)
- (format stream " ;~%")))
+ (print-dot-key-value name value *dot-graph-attributes* stream)))
(defmethod vertex->dot ((vertex dot-vertex-mixin) (stream t))
(format-dot-attributes vertex *dot-vertex-attributes* stream))
(destructuring-bind (key value-type)
(or (assoc key dot-attributes)
(error "Invalid attribute ~S" key))
- (format stream "~a=~a" (string-downcase key)
+ (write-name-for-dot key stream)
+ (format stream "=~a"
(etypecase value-type
((member coordinate)
(with-output-to-string (str)
((member text)
(textify value))
((member float)
- (coerce value 'single-float))
+ ;; graphviz does not support the 1.2e-3 format
+ (with-output-to-string (str)
+ (format str "~,f" (coerce value 'single-float))))
(list
(unless (member value value-type :test 'equal)
(error "Invalid value for ~S: ~S is not one of ~S"
(string-downcase value)
value))))))
+(defmethod write-name-for-dot (attribute stream)
+ (format stream "~(~A~)" attribute))
+
+(defmethod write-name-for-dot ((attribute (eql :url)) stream)
+ (format stream "URL"))
+
(defun textify (object)
(let ((string (princ-to-string object)))
(with-output-to-string (stream)
(defmethod graph->dot-external ((g basic-graph) file-name &key (type :ps))
"Generate an external represenation of a graph to a file, by running
the program in *dot-path*."
+ (declare (ignorable file-name))
(let ((dot-string (graph->dot g nil))
(dot-type (concatenate 'string "-T" (string-downcase (symbol-name type)))))
+ (declare (ignorable dot-string dot-type))
#+lispworks (with-open-stream
(s (sys:open-pipe (concatenate 'string *dot-path* " -Tpng -o" file-name)
:direction :input))
#-(or sbcl lispworks)
(error "Don't know how to execute a program on this platform")))
-;;; ---------------------------------------------------------------------------
-;
+;;;
; Test dot external
-;
+
+#+test
(defun test-dot-external ()
(let* ((g (make-graph 'dot-graph))
(v1 (add-vertex g 'a :dot-attributes '(:shape :box