add visualiser

This commit is contained in:
Riviera Taylor 2024-10-30 12:07:23 +01:00
parent 82daab9b7a
commit 5345d65940
5 changed files with 524 additions and 0 deletions

8
visualiser/main.css Normal file
View File

@ -0,0 +1,8 @@
.center {
display: block;
margin-left: auto;
margin-top: auto;
margin-bottom: auto;
margin-right: auto;
height: 100vh;
}

63
visualiser/main.dot Normal file
View File

@ -0,0 +1,63 @@
graph {
fan_one [shape=circle, style=filled, fillcolor=FAN_ONE,label="",color=FAN_ONE]
fan_two [shape=circle, style=filled, fillcolor=FAN_TWO,label="",color=FAN_TWO]
radio_one [shape=invtrapezium,style=filled,fillcolor=RADIO_ONE,label="",color=RADIO_ONE]
lamp_one [shape=cylinder,style=filled,fillcolor=LAMP_ONE,label="",color=LAMP_ONE]
lamp_two [shape=cylinder,style=filled,fillcolor=LAMP_TWO,label="",color=LAMP_TWO]
printer_one [shape=box,style=filled,fillcolor=PRINTER_ONE,label="",color=PRINTER_ONE]
printer_two [shape=box,style=filled,fillcolor=PRINTER_TWO,label="",color=PRINTER_TWO]
fan_one -- fan_two [color=FAN_ONE_FAN_TWO]
fan_one -- radio_one [color=FAN_ONE_RADIO_ONE]
fan_one -- lamp_one [color=FAN_ONE_LAMP_ONE]
fan_one -- lamp_two [color=FAN_ONE_LAMP_TWO]
fan_one -- printer_one [color=FAN_ONE_PRINTER_ONE]
fan_one -- printer_two [color=FAN_ONE_PRINTER_TWO]
fan_two -- radio_one [color=FAN_TWO_RADIO_ONE]
fan_two -- lamp_one [color=FAN_TWO_LAMP_ONE]
fan_two -- lamp_two [color=FAN_TWO_LAMP_TWO]
fan_two -- printer_one [color=FAN_TWO_PRINTER_ONE]
fan_two -- printer_two [color=FAN_TWO_PRINTER_TWO]
radio_one -- lamp_one [color=RADIO_ONE_LAMP_ONE]
radio_one -- lamp_two [color=RADIO_ONE_LAMP_TWO]
radio_one -- printer_one [color=RADIO_ONE_PRINTER_ONE]
radio_one -- printer_two [color=RADIO_ONE_PRINTER_TWO]
lamp_one -- lamp_two [color=LAMP_ONE_LAMP_TWO]
lamp_one -- printer_one [color=LAMP_ONE_PRINTER_ONE]
lamp_one -- printer_two [color=LAMP_ONE_PRINTER_TWO]
lamp_two -- printer_one [color=LAMP_TWO_PRINTER_ONE]
lamp_two -- printer_two [color=LAMP_TWO_PRINTER_TWO]
printer_one -- printer_two [color=PRINTER_ONE_PRINTER_TWO]
// printer_two -- printer_one [color=PRINTER_ONE_PRINTER_TWO]
// printer_two -- lamp_two [color=LAMP_TWO_PRINTER_TWO]
// printer_two -- lamp_one [color=LAMP_ONE_PRINTER_TWO]
// printer_two -- radio_one [color=RADIO_ONE_PRINTER_TWO]
// printer_two -- fan_two [color=FAN_TWO_PRINTER_TWO]
// printer_two -- fan_one [color=FAN_ONE_PRINTER_TWO]
// printer_one -- lamp_two [color=LAMP_TWO_PRINTER_ONE]
// printer_one -- lamp_one [color=LAMP_ONE_PRINTER_ONE]
// printer_one -- radio_one [color=RADIO_ONE_PRINTER_ONE]
// printer_one -- fan_two [color=FAN_TWO_PRINTER_ONE]
// printer_one -- fan_one [color=FAN_ONE_PRINTER_ONE]
// lamp_two -- lamp_one [color=LAMP_ONE_LAMP_TWO]
// lamp_two -- radio_one [color=RADIO_ONE_LAMP_TWO]
// lamp_two -- fan_two [color=FAN_TWO_LAMP_TWO]
// lamp_two -- fan_one [color=FAN_ONE_LAMP_TWO]
// lamp_one -- radio_one [color=RADIO_ONE_LAMP_ONE]
// lamp_one -- fan_two [color=FAN_TWO_LAMP_ONE]
// lamp_one -- fan_one [color=FAN_ONE_LAMP_ONE]
// radio_one -- fan_two [color=FAN_TWO_RADIO_ONE]
// radio_one -- fan_one [color=FAN_ONE_RADIO_ONE]
// fan_two -- fan_one [color=FAN_ONE_FAN_TWO]
}

281
visualiser/main.el Normal file
View File

@ -0,0 +1,281 @@
(require 'dash)
(require 'mqtt-mode)
;; (toggle-debug-on-error)
(setq mqtt-host "mqtt.klank.school")
(setq mqtt-port 7000)
;; directory variables
(defconst graphviz-command "circo")
(defconst graph-output-format "svg")
(defconst graph-dir "graphs/")
(defconst image-dir (concat graph-output-format "s/"))
(defconst working-directory "/home/riviera/XPUB2/public-moment/performance/")
;; colors
;; (defconst on-color "black" "The default color for objects which are active")
(defconst off-color "invis" "The default color for objects which are not active")
(defvar colors '("black" "red" "green" "blue" "magenta" "yellow" "orange" "purple" "cyan")
"colors for the nodes and edges to choose from")
;;; nodes
;; default colors
(defvar fan-one-color off-color)
(defvar fan-two-color off-color)
(defvar radio-one-color off-color)
(defvar lamp-one-color off-color)
(defvar lamp-two-color off-color)
(defvar printer-one-color off-color)
(defvar printer-two-color off-color)
;;; edges
;; default colors
(defvar fan-one-fan-two-color off-color)
(defvar fan-one-radio-one-color off-color)
(defvar fan-one-lamp-one-color off-color)
(defvar fan-one-lamp-two-color off-color)
(defvar fan-one-printer-one-color off-color)
(defvar fan-one-printer-two-color off-color)
(defvar fan-two-radio-one-color off-color)
(defvar fan-two-lamp-one-color off-color)
(defvar fan-two-lamp-two-color off-color)
(defvar fan-two-printer-one-color off-color)
(defvar fan-two-printer-two-color off-color)
(defvar radio-one-lamp-one-color off-color)
(defvar radio-one-lamp-two-color off-color)
(defvar radio-one-printer-one-color off-color)
(defvar radio-one-printer-two-color off-color)
(defvar lamp-one-lamp-two-color off-color)
(defvar lamp-one-printer-one-color off-color)
(defvar lamp-one-printer-two-color off-color)
(defvar lamp-two-printer-one-color off-color)
(defvar lamp-two-printer-two-color off-color)
(defvar printer-one-printer-two-color off-color)
(setq snapshot 10000)
(defun turn-object-on (object)
"Turn an object on"
nil
nil
(setq on-color (elt colors (random (length colors))))
(cond ((equal object 'fan-one)
(setq fan-one-color on-color)
(format-graph))
((equal object 'fan-two)
(setq fan-two-color on-color)
(format-graph))
((equal object 'lamp-one)
(setq lamp-one-color on-color)
(format-graph))
((equal object 'lamp-two)
(setq lamp-two-color on-color)
(format-graph))
((equal object 'radio-one)
(setq radio-one-color on-color)
(format-graph))
((equal object 'printer-one)
(setq printer-one-color on-color)
(format-graph))
((equal object 'printer-two)
(setq printer-two-color on-color)
(format-graph))))
(defun turn-object-off (object)
"Turn an object off"
nil
nil
(cond ((equal object 'fan-one)
(setq fan-one-color off-color)
(format-graph))
((equal object 'fan-two)
(setq fan-two-color off-color)
(format-graph))
((equal object 'lamp-one)
(setq lamp-one-color off-color)
(format-graph))
((equal object 'lamp-two)
(setq lamp-two-color off-color)
(format-graph))
((equal object 'radio-one)
(setq radio-one-color off-color)
(format-graph))
((equal object 'printer-one)
(setq printer-one-color off-color)
(format-graph))
((equal object 'printer-two)
(setq printer-one-color off-color)
(format-graph))))
(defun graph-write-file-quietly ()
"Write the graph buffer to a graphviz file quietly"
(let ((inhibit-message t))
(write-file (concat working-directory graph-dir "graph" (number-to-string snapshot) ".dot") t)))
(defun format-graph-image-numbered ()
"format the numbered image of the graph quietly, for the .gif"
(let ((inhibit-message t))
(shell-command
(concat graphviz-command " -T" graph-output-format " "
working-directory graph-dir (concat "graph" (number-to-string snapshot) ".dot")
" -o "
working-directory image-dir
(concat "graph" (number-to-string snapshot) "." graph-output-format)))))
(defun format-graph-image-main ()
"format the image of the main graph quietly"
nil
nil
(let ((inhibit-message t))
(shell-command
(concat graphviz-command " -T" graph-output-format " "
working-directory graph-dir (concat "graph" (number-to-string snapshot) ".dot")
" -o "
working-directory "main." graph-output-format
))))
(defun format-graph ()
"Series of functions to format the graph to display in the browser
and ultimately turn into a .gif"
nil
nil
;; preprocess graph
(shell-command (concat "cpp -DFAN_ONE=" fan-one-color " "
"-DFAN_TWO=" fan-two-color " "
"-DRADIO_ONE=" radio-one-color " "
"-DLAMP_ONE=" lamp-one-color " "
"-DLAMP_TWO=" lamp-two-color " "
"-DPRINTER_ONE=" printer-one-color " "
"-DPRINTER_TWO=" printer-two-color " "
"-DFAN_ONE_FAN_TWO=" fan-one-fan-two-color " "
"-DFAN_ONE_RADIO_ONE=" fan-one-radio-one-color " "
"-DFAN_ONE_LAMP_ONE=" fan-one-lamp-one-color " "
"-DFAN_ONE_LAMP_TWO=" fan-one-lamp-two-color " "
"-DFAN_ONE_PRINTER_ONE=" fan-one-printer-one-color " "
"-DFAN_ONE_PRINTER_TWO=" fan-one-printer-two-color " "
"-DFAN_TWO_RADIO_ONE=" fan-two-radio-one-color " "
"-DFAN_TWO_LAMP_ONE=" fan-two-lamp-one-color " "
"-DFAN_TWO_LAMP_TWO=" fan-two-lamp-two-color " "
"-DFAN_TWO_PRINTER_ONE=" fan-two-printer-one-color " "
"-DFAN_TWO_PRINTER_TWO=" fan-two-printer-two-color " "
"-DRADIO_ONE_LAMP_ONE=" radio-one-lamp-one-color " "
"-DRADIO_ONE_LAMP_TWO=" radio-one-lamp-two-color " "
"-DRADIO_ONE_PRINTER_ONE=" radio-one-printer-one-color " "
"-DRADIO_ONE_PRINTER_TWO=" radio-one-printer-two-color " "
"-DLAMP_ONE_LAMP_TWO=" lamp-one-lamp-two-color " "
"-DLAMP_ONE_PRINTER_ONE=" lamp-one-printer-one-color " "
"-DLAMP_ONE_PRINTER_TWO=" lamp-one-printer-two-color " "
"-DLAMP_TWO_PRINTER_ONE=" lamp-two-printer-one-color " "
"-DLAMP_TWO_PRINTER_TWO=" lamp-two-printer-two-color " "
"-DPRINTER_ONE_PRINTER_TWO=" printer-one-printer-two-color " "
working-directory "main.dot")
(concat "graph" (number-to-string snapshot) ".dot") "*Error*")
(switch-to-buffer-other-window
(concat "graph" (number-to-string snapshot) ".dot"))
(set-mark (point))
(forward-line 6)
(kill-region 0 (point) t)
(graph-write-file-quietly)
;; create a backup of the graph, for the .gif
(format-graph-image-numbered)
;; change main.png for displaying in the browser
(format-graph-image-main)
(setq snapshot (+ snapshot 1)))
;; (illuminate-edges '("transform" "printer" "one" "fan" "two") "1")
(defun illuminate-edges (topic payload)
"Function to illuminate the edges of the graph"
nil
nil
(setq on-color (elt colors (random (length colors))))
(let ((payload (string-limit payload 1)))
(let ((from-object (string-join (list (cadr topic) (caddr topic)) "-"))
(to-object (string-join (list (cadddr topic) (car (last topic))) "-")))
(message "From: %s" from-object)
(message "To: %s" to-object)
(when (string-equal payload "1")
(set (intern (concat from-object "-" to-object "-color")) on-color)
(set (intern (concat to-object "-" from-object "-color")) on-color))
(when (string-equal payload "0")
(set (intern (concat from-object "-" to-object "-color")) off-color)
(set (intern (concat to-object "-" from-object "-color")) off-color))
(format-graph))))
(defun illuminate-nodes (topic payload)
"Function to illuminate the nodes on the graph, a decision tree"
nil
nil
(setq on-color (elt colors (random (length colors))))
(let ((payload (string-limit payload 1)))
;;(message "Topic: %s. Payload %s." topic payload)
(cond ((and (member "fan" topic) (member "one" topic) (string-equal "1" payload))
(turn-object-on 'fan-one)
(message "Fan one turns on"))
((and (member "fan" topic) (member "one" topic) (string-equal "0" payload))
(message "Fan one turns off")
(turn-object-off 'fan-one))
((and (member "fan" topic) (member "two" topic) (string-equal "1" payload))
(message "Fan two turns on")
(turn-object-on 'fan-two))
((and (member "fan" topic) (member "two" topic) (string-equal "0" payload))
(message "Fan two turns off")
(turn-object-off 'fan-two))
((and (member "lamp" topic) (member "one" topic) (string-equal "1" payload))
(message "Lamp one turns on")
(turn-object-on 'lamp-one))
((and (member "lamp" topic) (member "one" topic) (string-equal "0" payload))
(message "Lamp one turns off")
(turn-object-off 'lamp-one))
((and (member "lamp" topic) (member "two" topic) (string-equal "1" payload))
(message "lamp two turns on")
(turn-object-on 'lamp-two))
((and (member "lamp" topic) (member "two" topic) (string-equal "0" payload))
(message "lamp two turns off")
(turn-object-off 'lamp-two))
((and (member "radio" topic) (member "one" topic) (string-equal "1" payload))
(turn-object-on 'radio-one))
((and (member "radio" topic) (member "one" topic) (string-equal "0" payload))
(turn-object-off 'radio-one))
((and (member "printer" topic) (member "one" topic) (string-equal "2" payload))
(turn-object-on 'printer-one))
((and (member "printer" topic) (member "one" topic) (string-equal "1" payload))
(turn-object-on 'printer-one))
((and (member "printer" topic) (member "one" topic) (string-equal "0" payload))
(turn-object-off 'printer-one))
((and (member "printer" topic) (member "two" topic) (string-equal "2" payload))
(turn-object-on 'printer-two))
((and (member "printer" topic) (member "two" topic) (string-equal "1" payload))
(turn-object-on 'printer-two))
((and (member "printer" topic) (member "two" topic) (string-equal "0" payload))
(turn-object-off 'printer-two)))))
;; printers
(add-to-list 'mqtt-message-receive-functions
(lambda (msg)
"Functions to execute on recieving a message"
nil
(let ((m (string-split msg " ")))
(let ((msg-car (car m))
(payload (cdr m)))
(let ((topic (string-split msg-car "/")))
;; (message "Topic: %s. Payload %s" topic payload)
(cond ((member "transform" topic)
(illuminate-edges topic (car payload)))
((member "main" topic)
(illuminate-nodes topic (car payload)))
;; ((member "gesture" topic)
;; (display-gesture))
))))))
(format-graph)
(start-process-shell-command "browser" nil (concat "firefox " working-directory "main.html --kiosk"))
(mqtt-start-consumer)

18
visualiser/main.html Normal file
View File

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="main.css">
<title></title>
</head>
<body>
<img class="center" src="main.svg">
</body>
<script>
setTimeout(() => { window.location.reload(); }, 1000);
</script>
</html>

154
visualiser/main.svg Normal file
View File

@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 12.1.2 (0)
-->
<!-- Pages: 1 -->
<svg width="320pt" height="318pt"
viewBox="0.00 0.00 319.85 317.71" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 313.71)">
<polygon fill="white" stroke="none" points="-4,4 -4,-313.71 315.85,-313.71 315.85,4 -4,4"/>
<!-- fan_one -->
<g id="node1" class="node">
<title>fan_one</title>
<ellipse fill="yellow" stroke="yellow" cx="241" cy="-45.11" rx="18" ry="18"/>
</g>
<!-- fan_two -->
<g id="node2" class="node">
<title>fan_two</title>
<ellipse fill="blue" stroke="blue" cx="293.85" cy="-154.86" rx="18" ry="18"/>
</g>
<!-- fan_one&#45;&#45;fan_two -->
<g id="edge1" class="edge">
<title>fan_one&#45;&#45;fan_two</title>
<path fill="none" stroke="none" d="M248.79,-61.3C258.73,-81.93 275.81,-117.4 285.84,-138.24"/>
</g>
<!-- radio_one -->
<g id="node3" class="node">
<title>radio_one</title>
<polygon fill="none" stroke="none" points="11.23,-75.95 42.77,-75.95 54,-111.95 0,-111.95 11.23,-75.95"/>
</g>
<!-- fan_one&#45;&#45;radio_one -->
<g id="edge2" class="edge">
<title>fan_one&#45;&#45;radio_one</title>
<path fill="none" stroke="none" d="M223.12,-49.19C183.54,-58.22 88.74,-79.86 47.14,-89.35"/>
</g>
<!-- lamp_one -->
<g id="node4" class="node">
<title>lamp_one</title>
<path fill="orange" stroke="orange" d="M54,-230.49C54,-232.29 41.9,-233.76 27,-233.76 12.1,-233.76 0,-232.29 0,-230.49 0,-230.49 0,-201.03 0,-201.03 0,-199.23 12.1,-197.76 27,-197.76 41.9,-197.76 54,-199.23 54,-201.03 54,-201.03 54,-230.49 54,-230.49"/>
<path fill="none" stroke="orange" d="M54,-230.49C54,-228.68 41.9,-227.22 27,-227.22 12.1,-227.22 0,-228.68 0,-230.49"/>
</g>
<!-- fan_one&#45;&#45;lamp_one -->
<g id="edge3" class="edge">
<title>fan_one&#45;&#45;lamp_one</title>
<path fill="none" stroke="purple" d="M226.62,-56.57C189.98,-85.79 92.88,-163.22 49.04,-198.19"/>
</g>
<!-- lamp_two -->
<g id="node5" class="node">
<title>lamp_two</title>
<path fill="none" stroke="none" d="M149.24,-306.44C149.24,-308.24 137.14,-309.71 122.24,-309.71 107.34,-309.71 95.24,-308.24 95.24,-306.44 95.24,-306.44 95.24,-276.98 95.24,-276.98 95.24,-275.18 107.34,-273.71 122.24,-273.71 137.14,-273.71 149.24,-275.18 149.24,-276.98 149.24,-276.98 149.24,-306.44 149.24,-306.44"/>
<path fill="none" stroke="none" d="M149.24,-306.44C149.24,-304.63 137.14,-303.16 122.24,-303.16 107.34,-303.16 95.24,-304.63 95.24,-306.44"/>
</g>
<!-- fan_one&#45;&#45;lamp_two -->
<g id="edge4" class="edge">
<title>fan_one&#45;&#45;lamp_two</title>
<path fill="none" stroke="none" d="M233.02,-61.67C211.7,-105.95 153.48,-226.82 131.14,-273.23"/>
</g>
<!-- printer_one -->
<g id="node6" class="node">
<title>printer_one</title>
<polygon fill="none" stroke="none" points="268,-282.6 214,-282.6 214,-246.6 268,-246.6 268,-282.6"/>
</g>
<!-- fan_one&#45;&#45;printer_one -->
<g id="edge5" class="edge">
<title>fan_one&#45;&#45;printer_one</title>
<path fill="none" stroke="none" d="M241,-63.44C241,-104.76 241,-204.75 241,-246.17"/>
</g>
<!-- printer_two -->
<g id="node7" class="node">
<title>printer_two</title>
<polygon fill="purple" stroke="purple" points="149.24,-36 95.24,-36 95.24,0 149.24,0 149.24,-36"/>
</g>
<!-- fan_one&#45;&#45;printer_two -->
<g id="edge6" class="edge">
<title>fan_one&#45;&#45;printer_two</title>
<path fill="none" stroke="none" d="M223.22,-41.05C203.67,-36.59 172.05,-29.37 149.4,-24.2"/>
</g>
<!-- fan_two&#45;&#45;radio_one -->
<g id="edge7" class="edge">
<title>fan_two&#45;&#45;radio_one</title>
<path fill="none" stroke="none" d="M275.92,-150.76C229.07,-140.07 102.91,-111.28 50.42,-99.29"/>
</g>
<!-- fan_two&#45;&#45;lamp_one -->
<g id="edge8" class="edge">
<title>fan_two&#45;&#45;lamp_one</title>
<path fill="none" stroke="none" d="M275.92,-158.95C230.23,-169.37 109.16,-197.01 54.48,-209.49"/>
</g>
<!-- fan_two&#45;&#45;lamp_two -->
<g id="edge9" class="edge">
<title>fan_two&#45;&#45;lamp_two</title>
<path fill="none" stroke="none" d="M279.51,-166.29C249.46,-190.25 179.73,-245.86 144.07,-274.3"/>
</g>
<!-- fan_two&#45;&#45;printer_one -->
<g id="edge10" class="edge">
<title>fan_two&#45;&#45;printer_one</title>
<path fill="none" stroke="none" d="M286.05,-171.05C276.4,-191.08 260.01,-225.11 249.89,-246.14"/>
</g>
<!-- fan_two&#45;&#45;printer_two -->
<g id="edge11" class="edge">
<title>fan_two&#45;&#45;printer_two</title>
<path fill="none" stroke="none" d="M279.51,-143.42C249.79,-119.72 181.22,-65.03 145.23,-36.34"/>
</g>
<!-- radio_one&#45;&#45;lamp_one -->
<g id="edge12" class="edge">
<title>radio_one&#45;&#45;lamp_one</title>
<path fill="none" stroke="none" d="M27,-112.19C27,-135.15 27,-174.38 27,-197.4"/>
</g>
<!-- radio_one&#45;&#45;lamp_two -->
<g id="edge13" class="edge">
<title>radio_one&#45;&#45;lamp_two</title>
<path fill="none" stroke="none" d="M35.79,-112.2C53.89,-149.78 95.13,-235.43 113.33,-273.22"/>
</g>
<!-- radio_one&#45;&#45;printer_one -->
<g id="edge14" class="edge">
<title>radio_one&#45;&#45;printer_one</title>
<path fill="none" stroke="none" d="M49.9,-112.21C90.98,-144.97 176.74,-213.36 217.94,-246.21"/>
</g>
<!-- radio_one&#45;&#45;printer_two -->
<g id="edge15" class="edge">
<title>radio_one&#45;&#45;printer_two</title>
<path fill="none" stroke="none" d="M44.47,-80.02C59.83,-67.77 82.29,-49.85 99.13,-36.42"/>
</g>
<!-- lamp_one&#45;&#45;lamp_two -->
<g id="edge16" class="edge">
<title>lamp_one&#45;&#45;lamp_two</title>
<path fill="none" stroke="none" d="M49.09,-233.38C64.47,-245.65 84.91,-261.94 100.27,-274.19"/>
</g>
<!-- lamp_one&#45;&#45;printer_one -->
<g id="edge17" class="edge">
<title>lamp_one&#45;&#45;printer_one</title>
<path fill="none" stroke="none" d="M54.1,-221.95C95.15,-231.32 172.66,-249.01 213.78,-258.39"/>
</g>
<!-- lamp_one&#45;&#45;printer_two -->
<g id="edge18" class="edge">
<title>lamp_one&#45;&#45;printer_two</title>
<path fill="none" stroke="none" d="M35.79,-197.51C53.89,-159.93 95.13,-74.28 113.33,-36.49"/>
</g>
<!-- lamp_two&#45;&#45;printer_one -->
<g id="edge19" class="edge">
<title>lamp_two&#45;&#45;printer_one</title>
<path fill="none" stroke="none" d="M149.48,-285.49C168.79,-281.08 194.59,-275.2 213.88,-270.79"/>
</g>
<!-- lamp_two&#45;&#45;printer_two -->
<g id="edge20" class="edge">
<title>lamp_two&#45;&#45;printer_two</title>
<path fill="none" stroke="none" d="M122.24,-273.33C122.24,-223.46 122.24,-86.07 122.24,-36.3"/>
</g>
<!-- printer_one&#45;&#45;printer_two -->
<g id="edge21" class="edge">
<title>printer_one&#45;&#45;printer_two</title>
<path fill="none" stroke="none" d="M232.26,-246.47C210.35,-200.98 153.24,-82.37 131.14,-36.5"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.6 KiB