Codebase list python-graphviz / ba6b6ad
Import upstream version 0.16+git20210515.1.bb1af2e Debian Janitor 2 years ago
84 changed file(s) with 9218 addition(s) and 7424 deletion(s). Raw diff Collapse all Expand all
0 Changelog
1 =========
2
3
4 Version 0.14.2
5 --------------
6
7 Adapt `graphviz.version()` to support the Graphviz Release version entry format
8 introduced with `2.44.2` (`version()` is needed to run the tests).
9
10
11 Version 0.14.1
12 --------------
13
14 Document the colon-separated ``node[:port[:compass]]`` format used for ``tail``
15 and ``head`` points in the ``edge()``- and ``edges()``-methods (PR Michał
16 Góral).
17
18
19 Version 0.14
20 ------------
21
22 Improve handling of escaped quotes (``\"``). Different from other layout engine
23 escapes sequences such as ``\l`` and ``\N`` (which are passed on as is by
24 default), there is no use case for backslash-escaping a literal quote character
25 because escaping of quotes is done by this library. Therefore, a
26 backslash-escaped quote (e.g. in ``label='\\"'``) is now treated the same as a
27 plain unescaped quote, i.e. both ``label='"'`` and ``label='\\"'`` produce
28 the same DOT source ``[label="\""]`` (a label that renders as a literal quote).
29 Before this change, use of ``'\\"'`` could break the quoting mechanism creating
30 invalid or unintended DOT, possibly leading to syntax errors from the rendering
31 process.
32
33 Add notebook section to documentation.
34
35 Add ``sphinx.ext.viewcode`` to docs (note that this currently lacks links for
36 methods, so that not all of the code is linked; use the source repo for reading
37 on).
38
39 Improve test and doc building config.
40
41
42 Version 0.13.2
43 --------------
44
45 Fix missing support for four-part versions in ``graphviz.version()``.
46
47
48
49 Version 0.13.1
50 --------------
51
52 Tag Python 3.8 support.
53
54 Fix quoting for non-ASCII numerals.
55
56
57 Version 0.13
58 ------------
59
60 Add explicit support for layout engine escape sequences such as ``\l`` and
61 ``\N``. These already worked implicitly before but where broken by backslash
62 escaping in ``0.12``, which is reverted by this release. Escaping now resembles
63 the stdlib ``re`` module: literal backslashes need to be escaped (doubled),
64 which is most conveniently done by using raw string literals for strings that
65 use escape sequences (including escaped backslashes), e.g. ``label=r'\\'``.
66
67 Add ``escape()`` function (resembling ``re.escape()``) for disabling all
68 meta-characters in a string for rendering.
69
70 Use ``logging`` in example notebook, add notebooks demonstrating layout engines
71 and escape sequence usage, improve tests with parametrization.
72
73
74 Version 0.12
75 ------------
76
77 Fix missing escaping of backslashes, e.g. in labels (pull request DNGros).
78
79 Add ``quiet`` argument to standalone ``view()`` function, and ``quiet_view``
80 argument on ``.render()`` and ``.view()`` methods. Supresses the ``stderr``
81 output of started viewer processes (unavailable on Windows).
82
83 Add basic debug logging via the stdlib ``logging`` module.
84
85 Reformatted some examples, improved tests by using autospec for mocks.
86
87
88 Version 0.11.1
89 --------------
90
91 Include ``stderr`` in ``str()`` of raised ``subprocess.CalledProcessError``.
92
93
94 Version 0.11
95 ------------
96
97 Add ``quiet`` argument to ``.render()`` and ``.pipe()`` methods of ``Graph``,
98 ``Digraph``, and ``Source`` objects, allowing to suppress ``stderr`` of the
99 layout subprocess (parity with stand-alone ``render()`` and ``pipe()``
100 functions).
101
102 The rendering process for ``render()`` methods and stand-alone function is now
103 started from the directory of the rendered dot source file. This allows to
104 render graph descriptions that use relative paths inline (e.g. for referring to
105 image files to be included) by using paths relative to the source file
106 location. Previously, such relative paths would need to be given relative to
107 the directory from which ``render()`` was started, so this change is backwards
108 incompatible for code that relied on the previous behaviour.
109
110 Drop Python 3.4 support.
111
112
113 Version 0.10.1
114 --------------
115
116 Fix broken renderer argument in ``pipe()`` method and function.
117
118
119 Version 0.10
120 ------------
121
122 Add ``format`` argument to ``Graph/Digraph.render()``. This follows stand-alone
123 ``render()`` function and mirrors the ``Graph/Digraph.pipe()`` method (usually,
124 ``format`` is set on the instance).
125
126 Add ``renderer`` and ``formatter`` arguments to ``Graph/Digraph.render()`` and
127 ``pipe()`` methods, as well as stand-alone ``render()`` and ``pipe()`` functions.
128
129
130 Version 0.9
131 -----------
132
133 Use ``sys.stderr`` to write stderr output from rendering process to stderr
134 (instead of file descriptor inheritance). Ensures stderr is passed in special
135 environments such as IDLE.
136
137 Suppress rendering process ``stdout`` in ``render()``.
138
139 Make ``quiet=True`` also suppress ``stderr`` on success of ``render()`` and
140 ``pipe()`` (exit-status ``0``).
141
142 Include ``stderr`` from rendering process in ``CalledProcessError`` exception.
143
144
145 Version 0.8.4
146 -------------
147
148 Tag Python 3.7 support (work around subprocess ``close_fds`` issue on Windows).
149
150
151 Version 0.8.3
152 -------------
153
154 Fix compatibility with ``python -OO``.
155
156
157 Version 0.8.2
158 -------------
159
160 Add ``nohtml()`` to support labels of the form ``'<...>'`` (disabling their default
161 treatment as HTML strings).
162
163 Make default ``'utf-8'`` ``encoding`` more visible.
164
165 Set ``encoding = locale.getpreferredencoding()`` when ``encoding`` argument/property is
166 set to ``None`` explicitly (follow stdlib ``io.open()`` behaviour).
167
168
169 Version 0.8.1
170 -------------
171
172 Add ``Source.from_file()``-classmethod (simpler in-line SVG display of ready-made
173 .gv files within Jupyter).
174
175 Drop Python 3.3 support.
176
177
178 Version 0.8
179 -----------
180
181 Add ``clear()``-method for ``Graph`` and ``Digraph``.
182
183 Add ``grapviz.version()`` function.
184
185 Drop dot source extra indent for edge statements following dotguide examples.
186
187 Include LICENSE file in wheel.
188
189
190 Version 0.7.1
191 -------------
192
193 Fix ``TypeError`` in ``graphviz.pipe()`` with invalid dot code under Python 3.
194
195 Add ``copy()``-method for ``Graph``, ``Digraph``, and ``Source``.
196
197 Add ``graphviz.render(..., quiet=True)``.
198
199 Fix ``graphivz.view()`` exception on unsupported platform.
200
201 Raise a dedicated ``RuntimeError`` subclass ``graphviz.ExecutableNotFound`` when the
202 Graphviz executables are not found.
203
204 Port tests from ``nose/unittest`` to ``pytest``, extend, use mocks.
205
206
207 Version 0.7
208 -----------
209
210 Support setting top-level attrs with ``g.attr(key=value)``.
211
212 Add context manager usage of ``subgraph()`` for adding a subgraph in a with-block.
213
214 Add json-based output formats to known ``FORMATS`` (Graphviz 2.40+).
215
216 Drop extra indent level for DOT source with nonempty ``graph/node/edge_attr``.
217
218 Add a final newline to a saved DOT source file if it does not end with one.
219
220 Raise ``subprocess.CalledProcessError`` on non-zero exit status from rendering.
221
222 Raise early when adding a ``subgraph()`` with ``strict=True`` (avoid DOT syntax error).
223
224 Make undocumented ``quote()``, ``quote_edge()``, and ``attributes()`` methods private.
225
226
227 Version 0.6
228 -----------
229
230 Drop Python 2.6 support (use ``graphviz<0.6`` there).
231
232 Improve tests for ``mkdirs()``.
233
234 Better document adding custom DOT using the ``body`` attribute.
235
236 Add ``view()``-support for FreeBSD (pull request Julien Gamba).
237
238
239 Version 0.5.2
240 -------------
241
242 Add ``ENGINES`` and ``FORMATS`` to the documented public API.
243
244
245 Version 0.5.1
246 -------------
247
248 Fixed PY3 compatibility.
249
250
251 Version 0.5
252 -----------
253
254 Add low-level functions ``render()``, ``pipe()``, and ``view()`` for directly working with
255 existing files and strings.
256
257 Support all ``render()``-arguments in the ``view()``-short-cut-method.
258
259
260 Version 0.4.10
261 --------------
262
263 Added ``'patchwork'`` engine.
264
265
266 Version 0.4.9
267 -------------
268
269 Add support for ``strict`` graphs and digraphs.
270
271 Hide ``render/pipe()`` subprocess console window on Windows when invoked from
272 non-console process (e.g. from IDLE).
273
274 Improve documentation markup/wording.
275
276 Make ``TestNoent`` more robust.
277
278
279 Version 0.4.8
280 -------------
281
282 Make ``_repr_svg_()`` available on ``Source`` (pull request RafalSkolasinski).
283
284
285 Version 0.4.7
286 -------------
287
288 Fixed ``view()``-method on Linux under Python 3 (pull request Antony Lee).
289
290
291 Version 0.4.6
292 -------------
293
294 Fixed ``view()``-method on Linux and Darwin (pull request Eric L. Frederich).
295
296
297 Version 0.4.5
298 -------------
299
300 Added example for HTML-like labels (``structs.py``).
301
302 Added ``Source`` class for rendering verbatim DOT source code.
303
304 Added Python 2.6 support (pull request Jim Crist).
305
306
307 Version 0.4.4
308 -------------
309
310 Added the ``pipe()``-method directly returning the ``stdout`` of rendering.
311
312 Added ``_repr_svg_()`` for inline rendering in IPython notebooks.
313
314
315 Version 0.4.3
316 -------------
317
318 Added examples generating some of the graphs from the Graphviz Gallery.
319
320 Added sphinx-based API documentation.
321
322
323 Version 0.4.2
324 -------------
325
326 Added support for HTML-like labels.
327
328
329 Version 0.4.1
330 -------------
331
332 Added support for less common output formats. Removed dropped formats (``'dia'``, ``'pcl'``).
333
334 Added ``'osage'`` layout engine.
335
336 Documented ``format`` and ``engine`` options in the README.
337
338 The ``view()`` convenience method now returns the result file name (like render()).
339
340
341 Version 0.4
342 -----------
343
344 Added ``attr()`` method for inline switching of node/edge attributes.
345
346 Added ``subgraph()`` method (obsoletes separate ``Subgraph`` class).
347
348 Add ``cleanup`` option to ``render()``.
349
350 Replaced ``dry`` option on ``render()`` with separate ``save()`` method.
351
352 Removed undocumented ``append()`` and ``extend()`` methods (if needed, the ``body``
353 attribute can be edited directly).
354
355
356 Version 0.3.5
357 -------------
358
359 Skip empty ``comment`` when creating DOT source.
360
361 Document ``graph_attr``, ``node_attr``, and ``edge_attr`` in the README.
362
363 More informative exception when Graphviz executables cannot be called.
364
365
366 Version 0.3.4
367 -------------
368
369 Fixed missing identifier quoting for DOT keywords (thanks to Paulo Urio).
370
371
372 Version 0.3.3
373 -------------
374
375 Made ``format`` and ``engine`` case-insensitive.
376
377
378 Version 0.3.2
379 -------------
380
381 Indent ``graph_attr``, ``node_attr``, and ``edge_attr`` lines, adapt nodes and edges.
382
383
384 Version 0.3.1
385 -------------
386
387 Fixed ``view()`` failing on paths with forward slashes on Windows.
388
389
390 Version 0.3
391 -----------
392
393 Added Python 3.3+ support.
394
395 Made attributes order stable (sorting plain dicts).
396
397 Fixed edgeop in undirected graphs.
398
399
400 Version 0.2.2
401 -------------
402
403 Support pdf opening on Linux.
404
405 Fixed rendering filenames w/spaces.
406
407
408 Version 0.2.1
409 -------------
410
411 Fixed rendering on Mac OS X.
412
413
414 Version 0.2
415 -----------
416
417 Added format selection, use ``'PDF``' as default.
418 Added engines selection, use ``'dot'`` as default.
419 Added source encoding, use ``'UTF-8'`` as default.
420
421 Changed constructor arguments order, removed ``compile()`` and ``save()``-method,
422 reimplemented compilation in ``render()`` method, make interface more similar to
423 gv.3python (backwards incompatible change).
424
425 Double-quote-sign escaping, attribute list quoting.
426
427 ``mkdirs()`` now correctly supports current directory filenames.
428
429
430 Version 0.1.1
431 -------------
432
433 Removed automatic ``'-'`` to ``'&minus;'`` replacement from labels.
434
435 Fixed documentation typos.
436
437
438 Version 0.1
439 -----------
440
441 First public release.
0 Changelog
1 =========
2
3
4 Version 0.17 (in development)
5 -----------------------------
6
7 Drop Python 2 support.
8
9
10 Version 0.16
11 ------------
12
13 Add ``.unflatten()`` method to ``Graph``, ``Digraph``, and ``Source``. Add
14 standalone ``unflatten()``.
15
16 Make ``Source.__str__()`` return the ``.source`` instead of the ``repr()``
17 (like ``Graph`` and ``Digraph``).
18
19 Render with ``dot -K<engine> ...`` instead of ``<engine> ...`` internally
20 (work around `upstream issue
21 <https://gitlab.com/graphviz/graphviz/-/issues/1753>`_).
22
23 Add documentation hint to archived upstream version for Windows.
24
25 Re-render most documentation graphs with Graphviz 2.44.1.
26
27
28 Version 0.15
29 ------------
30
31 ``Graph`` and ``Digraph`` instances created via the context-manager returned
32 by ``subgraph()`` now (re)use ``directory``, ``format``, ``engine``, and
33 ``encoding`` from the parent instead of using defaults (behavioral change).
34 Note that these attributes are only relevant when rendering the
35 subgraph independently (i.e. as a stand-alone graph) from within the
36 ``with``-block, which was previously underdocumented (PR BMaxV). To reflect that
37 the DOT language does not allow subgraph statements to specify ``strict``
38 (i.e. no way to override the setting of the containing graph), instances
39 created via the context-manager are now ``strict=None`` instead of ``False``
40 (so they continue to render stand-alone as non-strict by default).
41
42 Drop Python 3.5 support and tag Python 3.9 support.
43
44 Add documentation link to new upstream installation procedure for Windows.
45
46
47 Version 0.14.2
48 --------------
49
50 Adapt ``graphviz.version()`` to support the Graphviz Release version entry
51 format introduced with ``2.44.2`` (``version()`` is needed to run the tests).
52
53
54 Version 0.14.1
55 --------------
56
57 Document the colon-separated ``node[:port[:compass]]`` format used for ``tail``
58 and ``head`` points in the ``edge()``- and ``edges()``-methods (PR Michał
59 Góral).
60
61
62 Version 0.14
63 ------------
64
65 Improve handling of escaped quotes (``\"``). Different from other layout engine
66 escapes sequences such as ``\l`` and ``\N`` (which are passed on as is by
67 default), there is no use case for backslash-escaping a literal quote character
68 because escaping of quotes is done by this library. Therefore, a
69 backslash-escaped quote (e.g. in ``label='\\"'``) is now treated the same as a
70 plain unescaped quote, i.e. both ``label='"'`` and ``label='\\"'`` produce
71 the same DOT source ``[label="\""]`` (a label that renders as a literal quote).
72 Before this change, use of ``'\\"'`` could break the quoting mechanism creating
73 invalid or unintended DOT, possibly leading to syntax errors from the rendering
74 process.
75
76 Add notebook section to documentation.
77
78 Add ``sphinx.ext.viewcode`` to docs (note that this currently lacks links for
79 methods, so that not all of the code is linked; use the source repo for reading
80 on).
81
82 Improve test and doc building config.
83
84
85 Version 0.13.2
86 --------------
87
88 Fix missing support for four-part versions in ``graphviz.version()``.
89
90
91
92 Version 0.13.1
93 --------------
94
95 Tag Python 3.8 support.
96
97 Fix quoting for non-ASCII numerals.
98
99
100 Version 0.13
101 ------------
102
103 Add explicit support for layout engine escape sequences such as ``\l`` and
104 ``\N``. These already worked implicitly before but where broken by backslash
105 escaping in ``0.12``, which is reverted by this release. Escaping now resembles
106 the stdlib ``re`` module: literal backslashes need to be escaped (doubled),
107 which is most conveniently done by using raw string literals for strings that
108 use escape sequences (including escaped backslashes), e.g. ``label=r'\\'``.
109
110 Add ``escape()`` function (resembling ``re.escape()``) for disabling all
111 meta-characters in a string for rendering.
112
113 Use ``logging`` in example notebook, add notebooks demonstrating layout engines
114 and escape sequence usage, improve tests with parametrization.
115
116
117 Version 0.12
118 ------------
119
120 Fix missing escaping of backslashes, e.g. in labels (pull request DNGros).
121
122 Add ``quiet`` argument to standalone ``view()`` function, and ``quiet_view``
123 argument on ``.render()`` and ``.view()`` methods. Supresses the ``stderr``
124 output of started viewer processes (unavailable on Windows).
125
126 Add basic debug logging via the stdlib ``logging`` module.
127
128 Reformatted some examples, improved tests by using autospec for mocks.
129
130
131 Version 0.11.1
132 --------------
133
134 Include ``stderr`` in ``str()`` of raised ``subprocess.CalledProcessError``.
135
136
137 Version 0.11
138 ------------
139
140 Add ``quiet`` argument to ``.render()`` and ``.pipe()`` methods of ``Graph``,
141 ``Digraph``, and ``Source`` objects, allowing to suppress ``stderr`` of the
142 layout subprocess (parity with stand-alone ``render()`` and ``pipe()``
143 functions).
144
145 The rendering process for ``render()`` methods and stand-alone function is now
146 started from the directory of the rendered dot source file. This allows to
147 render graph descriptions that use relative paths inline (e.g. for referring to
148 image files to be included) by using paths relative to the source file
149 location. Previously, such relative paths would need to be given relative to
150 the directory from which ``render()`` was started, so this change is backwards
151 incompatible for code that relied on the previous behaviour.
152
153 Drop Python 3.4 support.
154
155
156 Version 0.10.1
157 --------------
158
159 Fix broken renderer argument in ``pipe()`` method and function.
160
161
162 Version 0.10
163 ------------
164
165 Add ``format`` argument to ``Graph/Digraph.render()``. This follows stand-alone
166 ``render()`` function and mirrors the ``Graph/Digraph.pipe()`` method (usually,
167 ``format`` is set on the instance).
168
169 Add ``renderer`` and ``formatter`` arguments to ``Graph/Digraph.render()`` and
170 ``pipe()`` methods, as well as stand-alone ``render()`` and ``pipe()`` functions.
171
172
173 Version 0.9
174 -----------
175
176 Use ``sys.stderr`` to write stderr output from rendering process to stderr
177 (instead of file descriptor inheritance). Ensures stderr is passed in special
178 environments such as IDLE.
179
180 Suppress rendering process ``stdout`` in ``render()``.
181
182 Make ``quiet=True`` also suppress ``stderr`` on success of ``render()`` and
183 ``pipe()`` (exit-status ``0``).
184
185 Include ``stderr`` from rendering process in ``CalledProcessError`` exception.
186
187
188 Version 0.8.4
189 -------------
190
191 Tag Python 3.7 support (work around subprocess ``close_fds`` issue on Windows).
192
193
194 Version 0.8.3
195 -------------
196
197 Fix compatibility with ``python -OO``.
198
199
200 Version 0.8.2
201 -------------
202
203 Add ``nohtml()`` to support labels of the form ``'<...>'`` (disabling their default
204 treatment as HTML strings).
205
206 Make default ``'utf-8'`` ``encoding`` more visible.
207
208 Set ``encoding = locale.getpreferredencoding()`` when ``encoding`` argument/property is
209 set to ``None`` explicitly (follow stdlib ``io.open()`` behaviour).
210
211
212 Version 0.8.1
213 -------------
214
215 Add ``Source.from_file()``-classmethod (simpler in-line SVG display of ready-made
216 .gv files within Jupyter).
217
218 Drop Python 3.3 support.
219
220
221 Version 0.8
222 -----------
223
224 Add ``clear()``-method for ``Graph`` and ``Digraph``.
225
226 Add ``grapviz.version()`` function.
227
228 Drop dot source extra indent for edge statements following dotguide examples.
229
230 Include LICENSE file in wheel.
231
232
233 Version 0.7.1
234 -------------
235
236 Fix ``TypeError`` in ``graphviz.pipe()`` with invalid dot code under Python 3.
237
238 Add ``copy()``-method for ``Graph``, ``Digraph``, and ``Source``.
239
240 Add ``graphviz.render(..., quiet=True)``.
241
242 Fix ``graphivz.view()`` exception on unsupported platform.
243
244 Raise a dedicated ``RuntimeError`` subclass ``graphviz.ExecutableNotFound`` when the
245 Graphviz executables are not found.
246
247 Port tests from ``nose/unittest`` to ``pytest``, extend, use mocks.
248
249
250 Version 0.7
251 -----------
252
253 Support setting top-level attrs with ``g.attr(key=value)``.
254
255 Add context manager usage of ``subgraph()`` for adding a subgraph in a with-block.
256
257 Add json-based output formats to known ``FORMATS`` (Graphviz 2.40+).
258
259 Drop extra indent level for DOT source with nonempty ``graph/node/edge_attr``.
260
261 Add a final newline to a saved DOT source file if it does not end with one.
262
263 Raise ``subprocess.CalledProcessError`` on non-zero exit status from rendering.
264
265 Raise early when adding a ``subgraph()`` with ``strict=True`` (avoid DOT syntax error).
266
267 Make undocumented ``quote()``, ``quote_edge()``, and ``attributes()`` methods private.
268
269
270 Version 0.6
271 -----------
272
273 Drop Python 2.6 support (use ``graphviz<0.6`` there).
274
275 Improve tests for ``mkdirs()``.
276
277 Better document adding custom DOT using the ``body`` attribute.
278
279 Add ``view()``-support for FreeBSD (pull request Julien Gamba).
280
281
282 Version 0.5.2
283 -------------
284
285 Add ``ENGINES`` and ``FORMATS`` to the documented public API.
286
287
288 Version 0.5.1
289 -------------
290
291 Fixed PY3 compatibility.
292
293
294 Version 0.5
295 -----------
296
297 Add low-level functions ``render()``, ``pipe()``, and ``view()`` for directly working with
298 existing files and strings.
299
300 Support all ``render()``-arguments in the ``view()``-short-cut-method.
301
302
303 Version 0.4.10
304 --------------
305
306 Added ``'patchwork'`` engine.
307
308
309 Version 0.4.9
310 -------------
311
312 Add support for ``strict`` graphs and digraphs.
313
314 Hide ``render/pipe()`` subprocess console window on Windows when invoked from
315 non-console process (e.g. from IDLE).
316
317 Improve documentation markup/wording.
318
319 Make ``TestNoent`` more robust.
320
321
322 Version 0.4.8
323 -------------
324
325 Make ``_repr_svg_()`` available on ``Source`` (pull request RafalSkolasinski).
326
327
328 Version 0.4.7
329 -------------
330
331 Fixed ``view()``-method on Linux under Python 3 (pull request Antony Lee).
332
333
334 Version 0.4.6
335 -------------
336
337 Fixed ``view()``-method on Linux and Darwin (pull request Eric L. Frederich).
338
339
340 Version 0.4.5
341 -------------
342
343 Added example for HTML-like labels (``structs.py``).
344
345 Added ``Source`` class for rendering verbatim DOT source code.
346
347 Added Python 2.6 support (pull request Jim Crist).
348
349
350 Version 0.4.4
351 -------------
352
353 Added the ``pipe()``-method directly returning the ``stdout`` of rendering.
354
355 Added ``_repr_svg_()`` for inline rendering in IPython notebooks.
356
357
358 Version 0.4.3
359 -------------
360
361 Added examples generating some of the graphs from the Graphviz Gallery.
362
363 Added sphinx-based API documentation.
364
365
366 Version 0.4.2
367 -------------
368
369 Added support for HTML-like labels.
370
371
372 Version 0.4.1
373 -------------
374
375 Added support for less common output formats. Removed dropped formats (``'dia'``, ``'pcl'``).
376
377 Added ``'osage'`` layout engine.
378
379 Documented ``format`` and ``engine`` options in the README.
380
381 The ``view()`` convenience method now returns the result file name (like render()).
382
383
384 Version 0.4
385 -----------
386
387 Added ``attr()`` method for inline switching of node/edge attributes.
388
389 Added ``subgraph()`` method (obsoletes separate ``Subgraph`` class).
390
391 Add ``cleanup`` option to ``render()``.
392
393 Replaced ``dry`` option on ``render()`` with separate ``save()`` method.
394
395 Removed undocumented ``append()`` and ``extend()`` methods (if needed, the ``body``
396 attribute can be edited directly).
397
398
399 Version 0.3.5
400 -------------
401
402 Skip empty ``comment`` when creating DOT source.
403
404 Document ``graph_attr``, ``node_attr``, and ``edge_attr`` in the README.
405
406 More informative exception when Graphviz executables cannot be called.
407
408
409 Version 0.3.4
410 -------------
411
412 Fixed missing identifier quoting for DOT keywords (thanks to Paulo Urio).
413
414
415 Version 0.3.3
416 -------------
417
418 Made ``format`` and ``engine`` case-insensitive.
419
420
421 Version 0.3.2
422 -------------
423
424 Indent ``graph_attr``, ``node_attr``, and ``edge_attr`` lines, adapt nodes and edges.
425
426
427 Version 0.3.1
428 -------------
429
430 Fixed ``view()`` failing on paths with forward slashes on Windows.
431
432
433 Version 0.3
434 -----------
435
436 Added Python 3.3+ support.
437
438 Made attributes order stable (sorting plain dicts).
439
440 Fixed edgeop in undirected graphs.
441
442
443 Version 0.2.2
444 -------------
445
446 Support pdf opening on Linux.
447
448 Fixed rendering filenames w/spaces.
449
450
451 Version 0.2.1
452 -------------
453
454 Fixed rendering on Mac OS X.
455
456
457 Version 0.2
458 -----------
459
460 Added format selection, use ``'PDF``' as default.
461 Added engines selection, use ``'dot'`` as default.
462 Added source encoding, use ``'UTF-8'`` as default.
463
464 Changed constructor arguments order, removed ``compile()`` and ``save()``-method,
465 reimplemented compilation in ``render()`` method, make interface more similar to
466 gv.3python (backwards incompatible change).
467
468 Double-quote-sign escaping, attribute list quoting.
469
470 ``mkdirs()`` now correctly supports current directory filenames.
471
472
473 Version 0.1.1
474 -------------
475
476 Removed automatic ``'-'`` to ``'&minus;'`` replacement from labels.
477
478 Fixed documentation typos.
479
480
481 Version 0.1
482 -----------
483
484 First public release.
0 The MIT License (MIT)
1
2 Copyright (c) 2013-2020 Sebastian Bank
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
0 The MIT License (MIT)
1
2 Copyright (c) 2013-2021 Sebastian Bank
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
0 include README.rst LICENSE.txt CHANGES.txt
1 include requirements.txt
2 include run-tests.py try-examples.py
3 include tox.ini
4 recursive-include tests *.py *.png
5 recursive-include examples *.py *.ipynb
6 recursive-include docs *.rst *.txt *.py *.png *.svg
7 prune docs/_build
0 include README.rst LICENSE.txt CHANGES.txt
1 include requirements.txt
2 include run-tests.py try-examples.py
3 include tox.ini
4 recursive-include tests *.py *.png
5 recursive-include examples *.py *.ipynb
6 recursive-include docs *.rst *.txt *.py *.png *.svg
7 prune docs/_build
+212
-189
PKG-INFO less more
0 Metadata-Version: 2.1
1 Name: graphviz
2 Version: 0.14.2
3 Summary: Simple Python interface for Graphviz
4 Home-page: https://github.com/xflr6/graphviz
5 Author: Sebastian Bank
6 Author-email: sebastian.bank@uni-leipzig.de
7 License: MIT
8 Project-URL: Documentation, https://graphviz.readthedocs.io
9 Project-URL: Changelog, https://graphviz.readthedocs.io/en/latest/changelog.html
10 Project-URL: Issue Tracker, https://github.com/xflr6/graphviz/issues
11 Description: Graphviz
12 ========
13
14 |PyPI version| |License| |Supported Python| |Format|
15
16 |Travis| |Codecov| |Readthedocs-stable| |Readthedocs-latest|
17
18 This package facilitates the creation and rendering of graph descriptions in
19 the DOT_ language of the Graphviz_ graph drawing software (`master repo`_) from
20 Python.
21
22 Create a graph object, assemble the graph by adding nodes and edges, and
23 retrieve its DOT source code string. Save the source code to a file and render
24 it with the Graphviz installation of your system.
25
26 Use the ``view`` option/method to directly inspect the resulting (PDF, PNG,
27 SVG, etc.) file with its default application. Graphs can also be rendered
28 and displayed within `Jupyter notebooks`_ (formerly known as
29 `IPython notebooks`_, example_) as well as the `Jupyter Qt Console`_.
30
31
32 Links
33 -----
34
35 - GitHub: https://github.com/xflr6/graphviz
36 - PyPI: https://pypi.org/project/graphviz/
37 - Documentation: https://graphviz.readthedocs.io
38 - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html
39 - Issue Tracker: https://github.com/xflr6/graphviz/issues
40 - Download: https://pypi.org/project/graphviz/#files
41
42
43 Installation
44 ------------
45
46 This package runs under Python 2.7, and 3.5+, use pip_ to install:
47
48 .. code:: bash
49
50 $ pip install graphviz
51
52 To render the generated DOT source code, you also need to install Graphviz
53 (`download page`_).
54
55 Make sure that the directory containing the ``dot`` executable is on your
56 systems' path.
57
58
59 Quickstart
60 ----------
61
62 Create a graph object:
63
64 .. code:: python
65
66 >>> from graphviz import Digraph
67
68 >>> dot = Digraph(comment='The Round Table')
69
70 >>> dot #doctest: +ELLIPSIS
71 <graphviz.dot.Digraph object at 0x...>
72
73 Add nodes and edges:
74
75 .. code:: python
76
77 >>> dot.node('A', 'King Arthur')
78 >>> dot.node('B', 'Sir Bedevere the Wise')
79 >>> dot.node('L', 'Sir Lancelot the Brave')
80
81 >>> dot.edges(['AB', 'AL'])
82 >>> dot.edge('B', 'L', constraint='false')
83
84 Check the generated source code:
85
86 .. code:: python
87
88 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
89 // The Round Table
90 digraph {
91 A [label="King Arthur"]
92 B [label="Sir Bedevere the Wise"]
93 L [label="Sir Lancelot the Brave"]
94 A -> B
95 A -> L
96 B -> L [constraint=false]
97 }
98
99 Save and render the source code, optionally view the result:
100
101 .. code:: python
102
103 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
104 'test-output/round-table.gv.pdf'
105
106 .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png
107 :align: center
108
109
110 See also
111 --------
112
113 - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG
114 - graphviz-python_ |--| official Python bindings (documentation_)
115 - pydot_ |--| stable pure-Python approach, requires pyparsing
116
117
118 License
119 -------
120
121 This package is distributed under the `MIT license`_.
122
123
124 .. _pip: https://pip.readthedocs.io
125 .. _Graphviz: https://www.graphviz.org
126 .. _master repo: https://gitlab.com/graphviz/graphviz/
127 .. _download page: https://www.graphviz.org/download/
128 .. _DOT: https://www.graphviz.org/doc/info/lang.html
129 .. _Jupyter notebooks: https://jupyter.org
130 .. _IPython notebooks: https://ipython.org/notebook.html
131 .. _example: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb
132 .. _Jupyter Qt Console: https://qtconsole.readthedocs.io
133
134 .. _pygraphviz: https://pypi.org/project/pygraphviz/
135 .. _graphviz-python: https://pypi.org/project/graphviz-python/
136 .. _documentation: https://www.graphviz.org/pdf/gv.3python.pdf
137 .. _pydot: https://pypi.org/project/pydot/
138
139 .. _MIT license: https://opensource.org/licenses/MIT
140
141
142 .. |--| unicode:: U+2013
143
144
145 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg
146 :target: https://pypi.org/project/graphviz/
147 :alt: Latest PyPI Version
148 .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg
149 :target: https://pypi.org/project/graphviz/
150 :alt: License
151 .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg
152 :target: https://pypi.org/project/graphviz/
153 :alt: Supported Python Versions
154 .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg
155 :target: https://pypi.org/project/graphviz/
156 :alt: Format
157
158 .. |Travis| image:: https://travis-ci.org/xflr6/graphviz.svg?branch=master
159 :target: https://travis-ci.org/xflr6/graphviz
160 :alt: Travis
161 .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg
162 :target: https://codecov.io/gh/xflr6/graphviz
163 :alt: Codecov
164 .. |Readthedocs-stable| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable
165 :target: https://graphviz.readthedocs.io/en/stable/?badge=stable
166 :alt: Readthedocs stable
167 .. |Readthedocs-latest| image:: https://readthedocs.org/projects/graphviz/badge/?version=latest
168 :target: https://graphviz.readthedocs.io/en/latest/?badge=latest
169 :alt: Readthedocs latest
170 Keywords: graph visualization dot render
171 Platform: any
172 Classifier: Development Status :: 4 - Beta
173 Classifier: Intended Audience :: Developers
174 Classifier: Intended Audience :: Science/Research
175 Classifier: License :: OSI Approved :: MIT License
176 Classifier: Operating System :: OS Independent
177 Classifier: Programming Language :: Python :: 2
178 Classifier: Programming Language :: Python :: 2.7
179 Classifier: Programming Language :: Python :: 3
180 Classifier: Programming Language :: Python :: 3.5
181 Classifier: Programming Language :: Python :: 3.6
182 Classifier: Programming Language :: Python :: 3.7
183 Classifier: Programming Language :: Python :: 3.8
184 Classifier: Topic :: Scientific/Engineering :: Visualization
185 Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*
186 Provides-Extra: dev
187 Provides-Extra: test
188 Provides-Extra: docs
0 Metadata-Version: 2.1
1 Name: graphviz
2 Version: 0.17.dev0
3 Summary: Simple Python interface for Graphviz
4 Home-page: https://github.com/xflr6/graphviz
5 Author: Sebastian Bank
6 Author-email: sebastian.bank@uni-leipzig.de
7 License: MIT
8 Project-URL: Documentation, https://graphviz.readthedocs.io
9 Project-URL: Changelog, https://graphviz.readthedocs.io/en/latest/changelog.html
10 Project-URL: Issue Tracker, https://github.com/xflr6/graphviz/issues
11 Project-URL: CI, https://travis-ci.org/xflr6/graphviz
12 Project-URL: Coverage, https://codecov.io/gh/xflr6/graphviz
13 Description: Graphviz
14 ========
15
16 |PyPI version| |License| |Supported Python| |Format|
17
18 |Travis| |Codecov| |Readthedocs-stable| |Readthedocs-latest|
19
20 This package facilitates the creation and rendering of graph descriptions in
21 the DOT_ language of the Graphviz_ graph drawing software (`upstream repo`_)
22 from Python.
23
24 Create a graph object, assemble the graph by adding nodes and edges, and
25 retrieve its DOT source code string. Save the source code to a file and render
26 it with the Graphviz installation of your system.
27
28 Use the ``view`` option/method to directly inspect the resulting (PDF, PNG,
29 SVG, etc.) file with its default application. Graphs can also be rendered
30 and displayed within `Jupyter notebooks`_ (formerly known as
31 `IPython notebooks`_,
32 `example <notebook_>`_, `nbviewer <notebook-nbviewer_>`_)
33 as well as the `Jupyter QtConsole`_.
34
35
36 Links
37 -----
38
39 - GitHub: https://github.com/xflr6/graphviz
40 - PyPI: https://pypi.org/project/graphviz/
41 - Documentation: https://graphviz.readthedocs.io
42 - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html
43 - Issue Tracker: https://github.com/xflr6/graphviz/issues
44 - Download: https://pypi.org/project/graphviz/#files
45
46
47 Installation
48 ------------
49
50 This package runs under Python 3.6+, use pip_ to install:
51
52 .. code:: bash
53
54 $ pip install graphviz
55
56 To render the generated DOT source code, you also need to install Graphviz_
57 (`download page <upstream-download_>`_,
58 `archived versions <upstream-archived_>`_,
59 `installation procedure for Windows <upstream-windows_>`_).
60
61 Make sure that the directory containing the ``dot`` executable is on your
62 systems' path.
63
64 Anaconda_: see the conda-forge_ package
65 `conda-forge/python-graphviz <conda-forge-python-graphviz_>`_
66 (`feedstock <conda-forge-python-graphviz-feedstock_>`_),
67 which should automatically ``conda install``
68 `conda-forge/graphviz <conda-forge-graphviz_>`_
69 (`feedstock <conda-forge-graphviz-feedstock_>`_) as dependency.
70
71
72 Quickstart
73 ----------
74
75 Create a graph object:
76
77 .. code:: python
78
79 >>> import graphviz
80 >>> dot = graphviz.Digraph(comment='The Round Table')
81 >>> dot #doctest: +ELLIPSIS
82 <graphviz.dot.Digraph object at 0x...>
83
84 Add nodes and edges:
85
86 .. code:: python
87
88 >>> dot.node('A', 'King Arthur')
89 >>> dot.node('B', 'Sir Bedevere the Wise')
90 >>> dot.node('L', 'Sir Lancelot the Brave')
91
92 >>> dot.edges(['AB', 'AL'])
93 >>> dot.edge('B', 'L', constraint='false')
94
95 Check the generated source code:
96
97 .. code:: python
98
99 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
100 // The Round Table
101 digraph {
102 A [label="King Arthur"]
103 B [label="Sir Bedevere the Wise"]
104 L [label="Sir Lancelot the Brave"]
105 A -> B
106 A -> L
107 B -> L [constraint=false]
108 }
109
110 Save and render the source code, optionally view the result:
111
112 .. code:: python
113
114 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
115 'test-output/round-table.gv.pdf'
116
117 .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png
118 :align: center
119
120
121 See also
122 --------
123
124 - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG
125 - graphviz-python_ |--| official Python bindings
126 (`documentation <graphviz-python-docs_>`_)
127 - pydot_ |--| stable pure-Python approach, requires pyparsing
128
129
130 License
131 -------
132
133 This package is distributed under the `MIT license`_.
134
135
136 .. _Graphviz: https://www.graphviz.org
137 .. _DOT: https://www.graphviz.org/doc/info/lang.html
138 .. _upstream repo: https://gitlab.com/graphviz/graphviz/
139 .. _upstream-download: https://www.graphviz.org/download/
140 .. _upstream-archived: https://www2.graphviz.org/Archive/stable/
141 .. _upstream-windows: https://forum.graphviz.org/t/new-simplified-installation-procedure-on-windows/224
142
143 .. _pip: https://pip.readthedocs.io
144
145 .. _Jupyter notebooks: https://jupyter.org
146 .. _IPython notebooks: https://ipython.org/notebook.html
147 .. _Jupyter QtConsole: https://qtconsole.readthedocs.io
148
149 .. _notebook: https://github.com/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
150 .. _notebook-nbviewer: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
151
152 .. _Anaconda: https://docs.anaconda.com/anaconda/install/
153 .. _conda-forge: https://conda-forge.org
154 .. _conda-forge-python-graphviz: https://anaconda.org/conda-forge/python-graphviz
155 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
156 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
157 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
158
159 .. _pygraphviz: https://pypi.org/project/pygraphviz/
160 .. _graphviz-python: https://pypi.org/project/graphviz-python/
161 .. _graphviz-python-docs: https://www.graphviz.org/pdf/gv.3python.pdf
162 .. _pydot: https://pypi.org/project/pydot/
163
164 .. _MIT license: https://opensource.org/licenses/MIT
165
166
167 .. |--| unicode:: U+2013
168
169
170 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg
171 :target: https://pypi.org/project/graphviz/
172 :alt: Latest PyPI Version
173 .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg
174 :target: https://pypi.org/project/graphviz/
175 :alt: License
176 .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg
177 :target: https://pypi.org/project/graphviz/
178 :alt: Supported Python Versions
179 .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg
180 :target: https://pypi.org/project/graphviz/
181 :alt: Format
182
183 .. |Travis| image:: https://travis-ci.org/xflr6/graphviz.svg?branch=master
184 :target: https://travis-ci.org/xflr6/graphviz
185 :alt: Travis
186 .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg
187 :target: https://codecov.io/gh/xflr6/graphviz
188 :alt: Codecov
189 .. |Readthedocs-stable| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable
190 :target: https://graphviz.readthedocs.io/en/stable/?badge=stable
191 :alt: Readthedocs stable
192 .. |Readthedocs-latest| image:: https://readthedocs.org/projects/graphviz/badge/?version=latest
193 :target: https://graphviz.readthedocs.io/en/latest/?badge=latest
194 :alt: Readthedocs latest
195 Keywords: graph visualization dot render
196 Platform: any
197 Classifier: Development Status :: 4 - Beta
198 Classifier: Intended Audience :: Developers
199 Classifier: Intended Audience :: Science/Research
200 Classifier: License :: OSI Approved :: MIT License
201 Classifier: Operating System :: OS Independent
202 Classifier: Programming Language :: Python :: 3
203 Classifier: Programming Language :: Python :: 3.6
204 Classifier: Programming Language :: Python :: 3.7
205 Classifier: Programming Language :: Python :: 3.8
206 Classifier: Programming Language :: Python :: 3.9
207 Classifier: Topic :: Scientific/Engineering :: Visualization
208 Requires-Python: >=3.6
209 Provides-Extra: dev
210 Provides-Extra: docs
211 Provides-Extra: test
0 Graphviz
1 ========
2
3 |PyPI version| |License| |Supported Python| |Format|
4
5 |Travis| |Codecov| |Readthedocs-stable| |Readthedocs-latest|
6
7 This package facilitates the creation and rendering of graph descriptions in
8 the DOT_ language of the Graphviz_ graph drawing software (`master repo`_) from
9 Python.
10
11 Create a graph object, assemble the graph by adding nodes and edges, and
12 retrieve its DOT source code string. Save the source code to a file and render
13 it with the Graphviz installation of your system.
14
15 Use the ``view`` option/method to directly inspect the resulting (PDF, PNG,
16 SVG, etc.) file with its default application. Graphs can also be rendered
17 and displayed within `Jupyter notebooks`_ (formerly known as
18 `IPython notebooks`_, example_) as well as the `Jupyter Qt Console`_.
19
20
21 Links
22 -----
23
24 - GitHub: https://github.com/xflr6/graphviz
25 - PyPI: https://pypi.org/project/graphviz/
26 - Documentation: https://graphviz.readthedocs.io
27 - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html
28 - Issue Tracker: https://github.com/xflr6/graphviz/issues
29 - Download: https://pypi.org/project/graphviz/#files
30
31
32 Installation
33 ------------
34
35 This package runs under Python 2.7, and 3.5+, use pip_ to install:
36
37 .. code:: bash
38
39 $ pip install graphviz
40
41 To render the generated DOT source code, you also need to install Graphviz
42 (`download page`_).
43
44 Make sure that the directory containing the ``dot`` executable is on your
45 systems' path.
46
47
48 Quickstart
49 ----------
50
51 Create a graph object:
52
53 .. code:: python
54
55 >>> from graphviz import Digraph
56
57 >>> dot = Digraph(comment='The Round Table')
58
59 >>> dot #doctest: +ELLIPSIS
60 <graphviz.dot.Digraph object at 0x...>
61
62 Add nodes and edges:
63
64 .. code:: python
65
66 >>> dot.node('A', 'King Arthur')
67 >>> dot.node('B', 'Sir Bedevere the Wise')
68 >>> dot.node('L', 'Sir Lancelot the Brave')
69
70 >>> dot.edges(['AB', 'AL'])
71 >>> dot.edge('B', 'L', constraint='false')
72
73 Check the generated source code:
74
75 .. code:: python
76
77 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
78 // The Round Table
79 digraph {
80 A [label="King Arthur"]
81 B [label="Sir Bedevere the Wise"]
82 L [label="Sir Lancelot the Brave"]
83 A -> B
84 A -> L
85 B -> L [constraint=false]
86 }
87
88 Save and render the source code, optionally view the result:
89
90 .. code:: python
91
92 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
93 'test-output/round-table.gv.pdf'
94
95 .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png
96 :align: center
97
98
99 See also
100 --------
101
102 - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG
103 - graphviz-python_ |--| official Python bindings (documentation_)
104 - pydot_ |--| stable pure-Python approach, requires pyparsing
105
106
107 License
108 -------
109
110 This package is distributed under the `MIT license`_.
111
112
113 .. _pip: https://pip.readthedocs.io
114 .. _Graphviz: https://www.graphviz.org
115 .. _master repo: https://gitlab.com/graphviz/graphviz/
116 .. _download page: https://www.graphviz.org/download/
117 .. _DOT: https://www.graphviz.org/doc/info/lang.html
118 .. _Jupyter notebooks: https://jupyter.org
119 .. _IPython notebooks: https://ipython.org/notebook.html
120 .. _example: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb
121 .. _Jupyter Qt Console: https://qtconsole.readthedocs.io
122
123 .. _pygraphviz: https://pypi.org/project/pygraphviz/
124 .. _graphviz-python: https://pypi.org/project/graphviz-python/
125 .. _documentation: https://www.graphviz.org/pdf/gv.3python.pdf
126 .. _pydot: https://pypi.org/project/pydot/
127
128 .. _MIT license: https://opensource.org/licenses/MIT
129
130
131 .. |--| unicode:: U+2013
132
133
134 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg
135 :target: https://pypi.org/project/graphviz/
136 :alt: Latest PyPI Version
137 .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg
138 :target: https://pypi.org/project/graphviz/
139 :alt: License
140 .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg
141 :target: https://pypi.org/project/graphviz/
142 :alt: Supported Python Versions
143 .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg
144 :target: https://pypi.org/project/graphviz/
145 :alt: Format
146
147 .. |Travis| image:: https://travis-ci.org/xflr6/graphviz.svg?branch=master
148 :target: https://travis-ci.org/xflr6/graphviz
149 :alt: Travis
150 .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg
151 :target: https://codecov.io/gh/xflr6/graphviz
152 :alt: Codecov
153 .. |Readthedocs-stable| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable
154 :target: https://graphviz.readthedocs.io/en/stable/?badge=stable
155 :alt: Readthedocs stable
156 .. |Readthedocs-latest| image:: https://readthedocs.org/projects/graphviz/badge/?version=latest
157 :target: https://graphviz.readthedocs.io/en/latest/?badge=latest
0 Graphviz
1 ========
2
3 |PyPI version| |License| |Supported Python| |Format|
4
5 |Travis| |Codecov| |Readthedocs-stable| |Readthedocs-latest|
6
7 This package facilitates the creation and rendering of graph descriptions in
8 the DOT_ language of the Graphviz_ graph drawing software (`upstream repo`_)
9 from Python.
10
11 Create a graph object, assemble the graph by adding nodes and edges, and
12 retrieve its DOT source code string. Save the source code to a file and render
13 it with the Graphviz installation of your system.
14
15 Use the ``view`` option/method to directly inspect the resulting (PDF, PNG,
16 SVG, etc.) file with its default application. Graphs can also be rendered
17 and displayed within `Jupyter notebooks`_ (formerly known as
18 `IPython notebooks`_,
19 `example <notebook_>`_, `nbviewer <notebook-nbviewer_>`_)
20 as well as the `Jupyter QtConsole`_.
21
22
23 Links
24 -----
25
26 - GitHub: https://github.com/xflr6/graphviz
27 - PyPI: https://pypi.org/project/graphviz/
28 - Documentation: https://graphviz.readthedocs.io
29 - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html
30 - Issue Tracker: https://github.com/xflr6/graphviz/issues
31 - Download: https://pypi.org/project/graphviz/#files
32
33
34 Installation
35 ------------
36
37 This package runs under Python 3.6+, use pip_ to install:
38
39 .. code:: bash
40
41 $ pip install graphviz
42
43 To render the generated DOT source code, you also need to install Graphviz_
44 (`download page <upstream-download_>`_,
45 `archived versions <upstream-archived_>`_,
46 `installation procedure for Windows <upstream-windows_>`_).
47
48 Make sure that the directory containing the ``dot`` executable is on your
49 systems' path.
50
51 Anaconda_: see the conda-forge_ package
52 `conda-forge/python-graphviz <conda-forge-python-graphviz_>`_
53 (`feedstock <conda-forge-python-graphviz-feedstock_>`_),
54 which should automatically ``conda install``
55 `conda-forge/graphviz <conda-forge-graphviz_>`_
56 (`feedstock <conda-forge-graphviz-feedstock_>`_) as dependency.
57
58
59 Quickstart
60 ----------
61
62 Create a graph object:
63
64 .. code:: python
65
66 >>> import graphviz
67 >>> dot = graphviz.Digraph(comment='The Round Table')
68 >>> dot #doctest: +ELLIPSIS
69 <graphviz.dot.Digraph object at 0x...>
70
71 Add nodes and edges:
72
73 .. code:: python
74
75 >>> dot.node('A', 'King Arthur')
76 >>> dot.node('B', 'Sir Bedevere the Wise')
77 >>> dot.node('L', 'Sir Lancelot the Brave')
78
79 >>> dot.edges(['AB', 'AL'])
80 >>> dot.edge('B', 'L', constraint='false')
81
82 Check the generated source code:
83
84 .. code:: python
85
86 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
87 // The Round Table
88 digraph {
89 A [label="King Arthur"]
90 B [label="Sir Bedevere the Wise"]
91 L [label="Sir Lancelot the Brave"]
92 A -> B
93 A -> L
94 B -> L [constraint=false]
95 }
96
97 Save and render the source code, optionally view the result:
98
99 .. code:: python
100
101 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
102 'test-output/round-table.gv.pdf'
103
104 .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png
105 :align: center
106
107
108 See also
109 --------
110
111 - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG
112 - graphviz-python_ |--| official Python bindings
113 (`documentation <graphviz-python-docs_>`_)
114 - pydot_ |--| stable pure-Python approach, requires pyparsing
115
116
117 License
118 -------
119
120 This package is distributed under the `MIT license`_.
121
122
123 .. _Graphviz: https://www.graphviz.org
124 .. _DOT: https://www.graphviz.org/doc/info/lang.html
125 .. _upstream repo: https://gitlab.com/graphviz/graphviz/
126 .. _upstream-download: https://www.graphviz.org/download/
127 .. _upstream-archived: https://www2.graphviz.org/Archive/stable/
128 .. _upstream-windows: https://forum.graphviz.org/t/new-simplified-installation-procedure-on-windows/224
129
130 .. _pip: https://pip.readthedocs.io
131
132 .. _Jupyter notebooks: https://jupyter.org
133 .. _IPython notebooks: https://ipython.org/notebook.html
134 .. _Jupyter QtConsole: https://qtconsole.readthedocs.io
135
136 .. _notebook: https://github.com/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
137 .. _notebook-nbviewer: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
138
139 .. _Anaconda: https://docs.anaconda.com/anaconda/install/
140 .. _conda-forge: https://conda-forge.org
141 .. _conda-forge-python-graphviz: https://anaconda.org/conda-forge/python-graphviz
142 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
143 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
144 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
145
146 .. _pygraphviz: https://pypi.org/project/pygraphviz/
147 .. _graphviz-python: https://pypi.org/project/graphviz-python/
148 .. _graphviz-python-docs: https://www.graphviz.org/pdf/gv.3python.pdf
149 .. _pydot: https://pypi.org/project/pydot/
150
151 .. _MIT license: https://opensource.org/licenses/MIT
152
153
154 .. |--| unicode:: U+2013
155
156
157 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg
158 :target: https://pypi.org/project/graphviz/
159 :alt: Latest PyPI Version
160 .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg
161 :target: https://pypi.org/project/graphviz/
162 :alt: License
163 .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg
164 :target: https://pypi.org/project/graphviz/
165 :alt: Supported Python Versions
166 .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg
167 :target: https://pypi.org/project/graphviz/
168 :alt: Format
169
170 .. |Travis| image:: https://travis-ci.org/xflr6/graphviz.svg?branch=master
171 :target: https://travis-ci.org/xflr6/graphviz
172 :alt: Travis
173 .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg
174 :target: https://codecov.io/gh/xflr6/graphviz
175 :alt: Codecov
176 .. |Readthedocs-stable| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable
177 :target: https://graphviz.readthedocs.io/en/stable/?badge=stable
178 :alt: Readthedocs stable
179 .. |Readthedocs-latest| image:: https://readthedocs.org/projects/graphviz/badge/?version=latest
180 :target: https://graphviz.readthedocs.io/en/latest/?badge=latest
158181 :alt: Readthedocs latest
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="851pt" height="257pt"
7 viewBox="0.00 0.00 851.00 256.89" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 252.887)">
9 <title>G</title>
10 <polygon fill="blue" stroke="none" points="-4,4 -4,-252.887 847,-252.887 847,4 -4,4"/>
11 <g id="clust1" class="cluster"><title>cluster_1</title>
12 <polygon fill="blue" stroke="black" points="46,-132.993 46,-240.887 794,-240.887 794,-132.993 46,-132.993"/>
13 <text text-anchor="middle" x="420" y="-225.687" font-family="Times New Roman,serif" font-size="14.00" fill="white">Linear Angle Variations (white to black gradient)</text>
14 </g>
15 <g id="clust2" class="cluster"><title>cluster_2</title>
16 <polygon fill="blue" stroke="black" points="8,-8 8,-124.993 835,-124.993 835,-8 8,-8"/>
17 <text text-anchor="middle" x="421.5" y="-109.793" font-family="Times New Roman,serif" font-size="14.00" fill="white">Radial Angle Variations (white to black gradient)</text>
18 </g>
19 <!-- n9 -->
20 <g id="node1" class="node"><title>n9</title>
21 <defs>
22 <linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="717.606" y1="-175.44" x2="786.394" y2="-175.44" >
23 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
24 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
25 </linearGradient>
26 </defs>
27 <ellipse fill="url(#l_0)" stroke="black" cx="752" cy="-175.44" rx="34.394" ry="34.394"/>
28 <text text-anchor="middle" x="752" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n9:360</text>
29 </g>
30 <!-- n8 -->
31 <g id="node2" class="node"><title>n8</title>
32 <defs>
33 <linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="640.68" y1="-199.76" x2="689.32" y2="-151.12" >
34 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
35 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
36 </linearGradient>
37 </defs>
38 <ellipse fill="url(#l_1)" stroke="black" cx="665" cy="-175.44" rx="34.394" ry="34.394"/>
39 <text text-anchor="middle" x="665" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n8:315</text>
40 </g>
41 <!-- n7 -->
42 <g id="node3" class="node"><title>n7</title>
43 <defs>
44 <linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="578" y1="-209.834" x2="578" y2="-141.046" >
45 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
46 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
47 </linearGradient>
48 </defs>
49 <ellipse fill="url(#l_2)" stroke="black" cx="578" cy="-175.44" rx="34.394" ry="34.394"/>
50 <text text-anchor="middle" x="578" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n7:270</text>
51 </g>
52 <!-- n6 -->
53 <g id="node4" class="node"><title>n6</title>
54 <defs>
55 <linearGradient id="l_3" gradientUnits="userSpaceOnUse" x1="515.32" y1="-199.76" x2="466.68" y2="-151.12" >
56 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
57 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
58 </linearGradient>
59 </defs>
60 <ellipse fill="url(#l_3)" stroke="black" cx="491" cy="-175.44" rx="34.394" ry="34.394"/>
61 <text text-anchor="middle" x="491" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n6:225</text>
62 </g>
63 <!-- n5 -->
64 <g id="node5" class="node"><title>n5</title>
65 <defs>
66 <linearGradient id="l_4" gradientUnits="userSpaceOnUse" x1="438.394" y1="-175.44" x2="369.606" y2="-175.44" >
67 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
68 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
69 </linearGradient>
70 </defs>
71 <ellipse fill="url(#l_4)" stroke="black" cx="404" cy="-175.44" rx="34.394" ry="34.394"/>
72 <text text-anchor="middle" x="404" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n5:180</text>
73 </g>
74 <!-- n14 -->
75 <g id="node14" class="node"><title>n14</title>
76 <defs>
77 <radialGradient id="r_0" cx="50%" cy="50%" r="75%" fx="0%" fy="50%">
78 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
79 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
80 </radialGradient>
81 </defs>
82 <ellipse fill="url(#r_0)" stroke="black" cx="404" cy="-54.9965" rx="38.9931" ry="38.9931"/>
83 <text text-anchor="middle" x="404" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n14:180</text>
84 </g>
85 <!-- n5&#45;&gt;n14 -->
86 <g id="edge1" class="edge"><title>n5&#45;&gt;n14</title>
87 <path fill="none" stroke="black" d="M404,-140.816C404,-129.488 404,-116.613 404,-104.378"/>
88 <polygon fill="black" stroke="black" points="407.5,-104.298 404,-94.2984 400.5,-104.298 407.5,-104.298"/>
89 </g>
90 <!-- n4 -->
91 <g id="node6" class="node"><title>n4</title>
92 <defs>
93 <linearGradient id="l_5" gradientUnits="userSpaceOnUse" x1="341.32" y1="-151.12" x2="292.68" y2="-199.76" >
94 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
95 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
96 </linearGradient>
97 </defs>
98 <ellipse fill="url(#l_5)" stroke="black" cx="317" cy="-175.44" rx="34.394" ry="34.394"/>
99 <text text-anchor="middle" x="317" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n4:135</text>
100 </g>
101 <!-- n3 -->
102 <g id="node7" class="node"><title>n3</title>
103 <defs>
104 <linearGradient id="l_6" gradientUnits="userSpaceOnUse" x1="234" y1="-144.845" x2="234" y2="-206.035" >
105 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
106 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
107 </linearGradient>
108 </defs>
109 <ellipse fill="url(#l_6)" stroke="black" cx="234" cy="-175.44" rx="30.5947" ry="30.5947"/>
110 <text text-anchor="middle" x="234" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n3:90</text>
111 </g>
112 <!-- n2 -->
113 <g id="node8" class="node"><title>n2</title>
114 <defs>
115 <linearGradient id="l_7" gradientUnits="userSpaceOnUse" x1="133.366" y1="-153.806" x2="176.634" y2="-197.074" >
116 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
117 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
118 </linearGradient>
119 </defs>
120 <ellipse fill="url(#l_7)" stroke="black" cx="155" cy="-175.44" rx="30.5947" ry="30.5947"/>
121 <text text-anchor="middle" x="155" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n2:45</text>
122 </g>
123 <!-- n1 -->
124 <g id="node9" class="node"><title>n1</title>
125 <defs>
126 <linearGradient id="l_8" gradientUnits="userSpaceOnUse" x1="54.0046" y1="-175.44" x2="105.995" y2="-175.44" >
127 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
128 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
129 </linearGradient>
130 </defs>
131 <ellipse fill="url(#l_8)" stroke="black" cx="80" cy="-175.44" rx="25.9954" ry="25.9954"/>
132 <text text-anchor="middle" x="80" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n1:0</text>
133 </g>
134 <!-- n18 -->
135 <g id="node10" class="node"><title>n18</title>
136 <defs>
137 <radialGradient id="r_1" cx="50%" cy="50%" r="75%" fx="99%" fy="49%">
138 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
139 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
140 </radialGradient>
141 </defs>
142 <ellipse fill="url(#r_1)" stroke="black" cx="788" cy="-54.9965" rx="38.9931" ry="38.9931"/>
143 <text text-anchor="middle" x="788" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n18:360</text>
144 </g>
145 <!-- n17 -->
146 <g id="node11" class="node"><title>n17</title>
147 <defs>
148 <radialGradient id="r_2" cx="50%" cy="50%" r="75%" fx="85%" fy="85%">
149 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
150 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
151 </radialGradient>
152 </defs>
153 <ellipse fill="url(#r_2)" stroke="black" cx="692" cy="-54.9965" rx="38.9931" ry="38.9931"/>
154 <text text-anchor="middle" x="692" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n17:315</text>
155 </g>
156 <!-- n16 -->
157 <g id="node12" class="node"><title>n16</title>
158 <defs>
159 <radialGradient id="r_3" cx="50%" cy="50%" r="75%" fx="50%" fy="100%">
160 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
161 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
162 </radialGradient>
163 </defs>
164 <ellipse fill="url(#r_3)" stroke="black" cx="596" cy="-54.9965" rx="38.9931" ry="38.9931"/>
165 <text text-anchor="middle" x="596" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n16:270</text>
166 </g>
167 <!-- n15 -->
168 <g id="node13" class="node"><title>n15</title>
169 <defs>
170 <radialGradient id="r_4" cx="50%" cy="50%" r="75%" fx="14%" fy="85%">
171 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
172 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
173 </radialGradient>
174 </defs>
175 <ellipse fill="url(#r_4)" stroke="black" cx="500" cy="-54.9965" rx="38.9931" ry="38.9931"/>
176 <text text-anchor="middle" x="500" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n15:225</text>
177 </g>
178 <!-- n13 -->
179 <g id="node15" class="node"><title>n13</title>
180 <defs>
181 <radialGradient id="r_5" cx="50%" cy="50%" r="75%" fx="14%" fy="14%">
182 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
183 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
184 </radialGradient>
185 </defs>
186 <ellipse fill="url(#r_5)" stroke="black" cx="308" cy="-54.9965" rx="38.9931" ry="38.9931"/>
187 <text text-anchor="middle" x="308" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n13:135</text>
188 </g>
189 <!-- n12 -->
190 <g id="node16" class="node"><title>n12</title>
191 <defs>
192 <radialGradient id="r_6" cx="50%" cy="50%" r="75%" fx="49%" fy="0%">
193 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
194 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
195 </radialGradient>
196 </defs>
197 <ellipse fill="url(#r_6)" stroke="black" cx="217" cy="-54.9965" rx="34.394" ry="34.394"/>
198 <text text-anchor="middle" x="217" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n12:90</text>
199 </g>
200 <!-- n11 -->
201 <g id="node17" class="node"><title>n11</title>
202 <defs>
203 <radialGradient id="r_7" cx="50%" cy="50%" r="75%" fx="85%" fy="14%">
204 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
205 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
206 </radialGradient>
207 </defs>
208 <ellipse fill="url(#r_7)" stroke="black" cx="130" cy="-54.9965" rx="34.394" ry="34.394"/>
209 <text text-anchor="middle" x="130" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n11:45</text>
210 </g>
211 <!-- n10 -->
212 <g id="node18" class="node"><title>n10</title>
213 <defs>
214 <radialGradient id="r_8" cx="50%" cy="50%" r="75%" fx="50%" fy="50%">
215 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
216 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
217 </radialGradient>
218 </defs>
219 <ellipse fill="url(#r_8)" stroke="black" cx="47" cy="-54.9965" rx="30.5947" ry="30.5947"/>
220 <text text-anchor="middle" x="47" y="-51.2965" font-family="Times New Roman,serif" font-size="14.00">n10:0</text>
221 </g>
222 </g>
223 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="851pt" height="257pt"
7 viewBox="0.00 0.00 851.00 256.89" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 252.89)">
9 <title>G</title>
10 <polygon fill="blue" stroke="transparent" points="-4,4 -4,-252.89 847,-252.89 847,4 -4,4"/>
11 <g id="clust1" class="cluster">
12 <title>cluster_1</title>
13 <polygon fill="blue" stroke="black" points="46,-132.99 46,-240.89 794,-240.89 794,-132.99 46,-132.99"/>
14 <text text-anchor="middle" x="420" y="-225.69" font-family="Times New Roman,serif" font-size="14.00" fill="white">Linear Angle Variations (white to black gradient)</text>
15 </g>
16 <g id="clust2" class="cluster">
17 <title>cluster_2</title>
18 <polygon fill="blue" stroke="black" points="8,-8 8,-124.99 835,-124.99 835,-8 8,-8"/>
19 <text text-anchor="middle" x="421.5" y="-109.79" font-family="Times New Roman,serif" font-size="14.00" fill="white">Radial Angle Variations (white to black gradient)</text>
20 </g>
21 <!-- n9 -->
22 <g id="node1" class="node">
23 <title>n9</title>
24 <defs>
25 <linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="717.61" y1="-175.44" x2="786.39" y2="-175.44" >
26 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
27 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
28 </linearGradient>
29 </defs>
30 <ellipse fill="url(#l_0)" stroke="black" cx="752" cy="-175.44" rx="34.39" ry="34.39"/>
31 <text text-anchor="middle" x="752" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n9:360</text>
32 </g>
33 <!-- n8 -->
34 <g id="node2" class="node">
35 <title>n8</title>
36 <defs>
37 <linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="640.68" y1="-199.76" x2="689.32" y2="-151.12" >
38 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
39 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
40 </linearGradient>
41 </defs>
42 <ellipse fill="url(#l_1)" stroke="black" cx="665" cy="-175.44" rx="34.39" ry="34.39"/>
43 <text text-anchor="middle" x="665" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n8:315</text>
44 </g>
45 <!-- n7 -->
46 <g id="node3" class="node">
47 <title>n7</title>
48 <defs>
49 <linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="578" y1="-209.83" x2="578" y2="-141.05" >
50 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
51 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
52 </linearGradient>
53 </defs>
54 <ellipse fill="url(#l_2)" stroke="black" cx="578" cy="-175.44" rx="34.39" ry="34.39"/>
55 <text text-anchor="middle" x="578" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n7:270</text>
56 </g>
57 <!-- n6 -->
58 <g id="node4" class="node">
59 <title>n6</title>
60 <defs>
61 <linearGradient id="l_3" gradientUnits="userSpaceOnUse" x1="515.32" y1="-199.76" x2="466.68" y2="-151.12" >
62 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
63 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
64 </linearGradient>
65 </defs>
66 <ellipse fill="url(#l_3)" stroke="black" cx="491" cy="-175.44" rx="34.39" ry="34.39"/>
67 <text text-anchor="middle" x="491" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n6:225</text>
68 </g>
69 <!-- n5 -->
70 <g id="node5" class="node">
71 <title>n5</title>
72 <defs>
73 <linearGradient id="l_4" gradientUnits="userSpaceOnUse" x1="438.39" y1="-175.44" x2="369.61" y2="-175.44" >
74 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
75 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
76 </linearGradient>
77 </defs>
78 <ellipse fill="url(#l_4)" stroke="black" cx="404" cy="-175.44" rx="34.39" ry="34.39"/>
79 <text text-anchor="middle" x="404" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n5:180</text>
80 </g>
81 <!-- n14 -->
82 <g id="node14" class="node">
83 <title>n14</title>
84 <defs>
85 <radialGradient id="r_0" cx="50%" cy="50%" r="75%" fx="0%" fy="50%">
86 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
87 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
88 </radialGradient>
89 </defs>
90 <ellipse fill="url(#r_0)" stroke="black" cx="404" cy="-55" rx="38.99" ry="38.99"/>
91 <text text-anchor="middle" x="404" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n14:180</text>
92 </g>
93 <!-- n5&#45;&gt;n14 -->
94 <g id="edge1" class="edge">
95 <title>n5&#45;&gt;n14</title>
96 <path fill="none" stroke="black" d="M404,-140.82C404,-129.49 404,-116.61 404,-104.38"/>
97 <polygon fill="black" stroke="black" points="407.5,-104.3 404,-94.3 400.5,-104.3 407.5,-104.3"/>
98 </g>
99 <!-- n4 -->
100 <g id="node6" class="node">
101 <title>n4</title>
102 <defs>
103 <linearGradient id="l_5" gradientUnits="userSpaceOnUse" x1="341.32" y1="-151.12" x2="292.68" y2="-199.76" >
104 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
105 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
106 </linearGradient>
107 </defs>
108 <ellipse fill="url(#l_5)" stroke="black" cx="317" cy="-175.44" rx="34.39" ry="34.39"/>
109 <text text-anchor="middle" x="317" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n4:135</text>
110 </g>
111 <!-- n3 -->
112 <g id="node7" class="node">
113 <title>n3</title>
114 <defs>
115 <linearGradient id="l_6" gradientUnits="userSpaceOnUse" x1="234" y1="-144.85" x2="234" y2="-206.03" >
116 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
117 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
118 </linearGradient>
119 </defs>
120 <ellipse fill="url(#l_6)" stroke="black" cx="234" cy="-175.44" rx="30.59" ry="30.59"/>
121 <text text-anchor="middle" x="234" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n3:90</text>
122 </g>
123 <!-- n2 -->
124 <g id="node8" class="node">
125 <title>n2</title>
126 <defs>
127 <linearGradient id="l_7" gradientUnits="userSpaceOnUse" x1="133.37" y1="-153.81" x2="176.63" y2="-197.07" >
128 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
129 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
130 </linearGradient>
131 </defs>
132 <ellipse fill="url(#l_7)" stroke="black" cx="155" cy="-175.44" rx="30.59" ry="30.59"/>
133 <text text-anchor="middle" x="155" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n2:45</text>
134 </g>
135 <!-- n1 -->
136 <g id="node9" class="node">
137 <title>n1</title>
138 <defs>
139 <linearGradient id="l_8" gradientUnits="userSpaceOnUse" x1="54" y1="-175.44" x2="106" y2="-175.44" >
140 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
141 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
142 </linearGradient>
143 </defs>
144 <ellipse fill="url(#l_8)" stroke="black" cx="80" cy="-175.44" rx="26" ry="26"/>
145 <text text-anchor="middle" x="80" y="-171.74" font-family="Times New Roman,serif" font-size="14.00">n1:0</text>
146 </g>
147 <!-- n18 -->
148 <g id="node10" class="node">
149 <title>n18</title>
150 <defs>
151 <radialGradient id="r_1" cx="50%" cy="50%" r="75%" fx="99%" fy="49%">
152 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
153 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
154 </radialGradient>
155 </defs>
156 <ellipse fill="url(#r_1)" stroke="black" cx="788" cy="-55" rx="38.99" ry="38.99"/>
157 <text text-anchor="middle" x="788" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n18:360</text>
158 </g>
159 <!-- n17 -->
160 <g id="node11" class="node">
161 <title>n17</title>
162 <defs>
163 <radialGradient id="r_2" cx="50%" cy="50%" r="75%" fx="85%" fy="85%">
164 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
165 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
166 </radialGradient>
167 </defs>
168 <ellipse fill="url(#r_2)" stroke="black" cx="692" cy="-55" rx="38.99" ry="38.99"/>
169 <text text-anchor="middle" x="692" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n17:315</text>
170 </g>
171 <!-- n16 -->
172 <g id="node12" class="node">
173 <title>n16</title>
174 <defs>
175 <radialGradient id="r_3" cx="50%" cy="50%" r="75%" fx="50%" fy="100%">
176 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
177 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
178 </radialGradient>
179 </defs>
180 <ellipse fill="url(#r_3)" stroke="black" cx="596" cy="-55" rx="38.99" ry="38.99"/>
181 <text text-anchor="middle" x="596" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n16:270</text>
182 </g>
183 <!-- n15 -->
184 <g id="node13" class="node">
185 <title>n15</title>
186 <defs>
187 <radialGradient id="r_4" cx="50%" cy="50%" r="75%" fx="14%" fy="85%">
188 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
189 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
190 </radialGradient>
191 </defs>
192 <ellipse fill="url(#r_4)" stroke="black" cx="500" cy="-55" rx="38.99" ry="38.99"/>
193 <text text-anchor="middle" x="500" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n15:225</text>
194 </g>
195 <!-- n13 -->
196 <g id="node15" class="node">
197 <title>n13</title>
198 <defs>
199 <radialGradient id="r_5" cx="50%" cy="50%" r="75%" fx="14%" fy="14%">
200 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
201 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
202 </radialGradient>
203 </defs>
204 <ellipse fill="url(#r_5)" stroke="black" cx="308" cy="-55" rx="38.99" ry="38.99"/>
205 <text text-anchor="middle" x="308" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n13:135</text>
206 </g>
207 <!-- n12 -->
208 <g id="node16" class="node">
209 <title>n12</title>
210 <defs>
211 <radialGradient id="r_6" cx="50%" cy="50%" r="75%" fx="49%" fy="0%">
212 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
213 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
214 </radialGradient>
215 </defs>
216 <ellipse fill="url(#r_6)" stroke="black" cx="217" cy="-55" rx="34.39" ry="34.39"/>
217 <text text-anchor="middle" x="217" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n12:90</text>
218 </g>
219 <!-- n11 -->
220 <g id="node17" class="node">
221 <title>n11</title>
222 <defs>
223 <radialGradient id="r_7" cx="50%" cy="50%" r="75%" fx="85%" fy="14%">
224 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
225 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
226 </radialGradient>
227 </defs>
228 <ellipse fill="url(#r_7)" stroke="black" cx="130" cy="-55" rx="34.39" ry="34.39"/>
229 <text text-anchor="middle" x="130" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n11:45</text>
230 </g>
231 <!-- n10 -->
232 <g id="node18" class="node">
233 <title>n10</title>
234 <defs>
235 <radialGradient id="r_8" cx="50%" cy="50%" r="75%" fx="50%" fy="50%">
236 <stop offset="0" style="stop-color:white;stop-opacity:1.;"/>
237 <stop offset="1" style="stop-color:black;stop-opacity:1.;"/>
238 </radialGradient>
239 </defs>
240 <ellipse fill="url(#r_8)" stroke="black" cx="47" cy="-55" rx="30.59" ry="30.59"/>
241 <text text-anchor="middle" x="47" y="-51.3" font-family="Times New Roman,serif" font-size="14.00">n10:0</text>
242 </g>
243 </g>
244 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: g Pages: 1 -->
6 <svg width="368pt" height="212pt"
7 viewBox="0.00 0.00 368.00 212.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 208)">
9 <title>g</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-208 364,-208 364,4 -4,4"/>
11 <!-- node0 -->
12 <g id="node1" class="node"><title>node0</title>
13 <polygon fill="none" stroke="black" points="167.5,-180.5 167.5,-203.5 234.5,-203.5 234.5,-180.5 167.5,-180.5"/>
14 <text text-anchor="middle" x="177.5" y="-188.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
15 <polyline fill="none" stroke="black" points="187.5,-180.5 187.5,-203.5 "/>
16 <text text-anchor="middle" x="201" y="-188.3" font-family="Times New Roman,serif" font-size="14.00">G</text>
17 <polyline fill="none" stroke="black" points="214.5,-180.5 214.5,-203.5 "/>
18 <text text-anchor="middle" x="224.5" y="-188.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
19 </g>
20 <!-- node1 -->
21 <g id="node2" class="node"><title>node1</title>
22 <polygon fill="none" stroke="black" points="103.5,-120.5 103.5,-143.5 168.5,-143.5 168.5,-120.5 103.5,-120.5"/>
23 <text text-anchor="middle" x="113.5" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
24 <polyline fill="none" stroke="black" points="123.5,-120.5 123.5,-143.5 "/>
25 <text text-anchor="middle" x="136" y="-128.3" font-family="Times New Roman,serif" font-size="14.00">E</text>
26 <polyline fill="none" stroke="black" points="148.5,-120.5 148.5,-143.5 "/>
27 <text text-anchor="middle" x="158.5" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
28 </g>
29 <!-- node0&#45;&gt;node1 -->
30 <g id="edge2" class="edge"><title>node0:f0&#45;&gt;node1:f1</title>
31 <path fill="none" stroke="black" d="M177,-180C177,-159.918 148.883,-165.039 139.217,-153.62"/>
32 <polygon fill="black" stroke="black" points="142.491,-152.374 136,-144 135.852,-154.594 142.491,-152.374"/>
33 </g>
34 <!-- node4 -->
35 <g id="node5" class="node"><title>node4</title>
36 <polygon fill="none" stroke="black" points="233,-120.5 233,-143.5 299,-143.5 299,-120.5 233,-120.5"/>
37 <text text-anchor="middle" x="243" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
38 <polyline fill="none" stroke="black" points="253,-120.5 253,-143.5 "/>
39 <text text-anchor="middle" x="266" y="-128.3" font-family="Times New Roman,serif" font-size="14.00">R</text>
40 <polyline fill="none" stroke="black" points="279,-120.5 279,-143.5 "/>
41 <text text-anchor="middle" x="289" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
42 </g>
43 <!-- node0&#45;&gt;node4 -->
44 <g id="edge1" class="edge"><title>node0:f2&#45;&gt;node4:f1</title>
45 <path fill="none" stroke="black" d="M225,-180C225,-159.918 253.117,-165.039 262.783,-153.62"/>
46 <polygon fill="black" stroke="black" points="266.148,-154.594 266,-144 259.509,-152.374 266.148,-154.594"/>
47 </g>
48 <!-- node2 -->
49 <g id="node3" class="node"><title>node2</title>
50 <polygon fill="none" stroke="black" points="42,-60.5 42,-83.5 108,-83.5 108,-60.5 42,-60.5"/>
51 <text text-anchor="middle" x="52" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
52 <polyline fill="none" stroke="black" points="62,-60.5 62,-83.5 "/>
53 <text text-anchor="middle" x="75" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">B</text>
54 <polyline fill="none" stroke="black" points="88,-60.5 88,-83.5 "/>
55 <text text-anchor="middle" x="98" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
56 </g>
57 <!-- node1&#45;&gt;node2 -->
58 <g id="edge3" class="edge"><title>node1:f0&#45;&gt;node2:f1</title>
59 <path fill="none" stroke="black" d="M113,-120C113,-100.916 87.4293,-104.572 78.2399,-93.6598"/>
60 <polygon fill="black" stroke="black" points="81.4983,-92.368 75,-84 74.8616,-94.5939 81.4983,-92.368"/>
61 </g>
62 <!-- node3 -->
63 <g id="node4" class="node"><title>node3</title>
64 <polygon fill="none" stroke="black" points="126.5,-60.5 126.5,-83.5 191.5,-83.5 191.5,-60.5 126.5,-60.5"/>
65 <text text-anchor="middle" x="136.5" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
66 <polyline fill="none" stroke="black" points="146.5,-60.5 146.5,-83.5 "/>
67 <text text-anchor="middle" x="159" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">F</text>
68 <polyline fill="none" stroke="black" points="171.5,-60.5 171.5,-83.5 "/>
69 <text text-anchor="middle" x="181.5" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
70 </g>
71 <!-- node1&#45;&gt;node3 -->
72 <g id="edge4" class="edge"><title>node1:f2&#45;&gt;node3:f1</title>
73 <path fill="none" stroke="black" d="M159,-120C159,-108 159,-102.75 159,-94.125"/>
74 <polygon fill="black" stroke="black" points="162.5,-94 159,-84 155.5,-94 162.5,-94"/>
75 </g>
76 <!-- node7 -->
77 <g id="node8" class="node"><title>node7</title>
78 <polygon fill="none" stroke="black" points="0,-0.5 0,-23.5 66,-23.5 66,-0.5 0,-0.5"/>
79 <text text-anchor="middle" x="10" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
80 <polyline fill="none" stroke="black" points="20,-0.5 20,-23.5 "/>
81 <text text-anchor="middle" x="33" y="-8.3" font-family="Times New Roman,serif" font-size="14.00">A</text>
82 <polyline fill="none" stroke="black" points="46,-0.5 46,-23.5 "/>
83 <text text-anchor="middle" x="56" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
84 </g>
85 <!-- node2&#45;&gt;node7 -->
86 <g id="edge6" class="edge"><title>node2:f0&#45;&gt;node7:f1</title>
87 <path fill="none" stroke="black" d="M52,-60C52,-46.0072 40.6341,-42.9467 35.4839,-33.9075"/>
88 <polygon fill="black" stroke="black" points="38.8268,-32.8486 33,-24 32.037,-34.551 38.8268,-32.8486"/>
89 </g>
90 <!-- node8 -->
91 <g id="node9" class="node"><title>node8</title>
92 <polygon fill="none" stroke="black" points="84,-0.5 84,-23.5 150,-23.5 150,-0.5 84,-0.5"/>
93 <text text-anchor="middle" x="94" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
94 <polyline fill="none" stroke="black" points="104,-0.5 104,-23.5 "/>
95 <text text-anchor="middle" x="117" y="-8.3" font-family="Times New Roman,serif" font-size="14.00">C</text>
96 <polyline fill="none" stroke="black" points="130,-0.5 130,-23.5 "/>
97 <text text-anchor="middle" x="140" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
98 </g>
99 <!-- node2&#45;&gt;node8 -->
100 <g id="edge5" class="edge"><title>node2:f2&#45;&gt;node8:f1</title>
101 <path fill="none" stroke="black" d="M98,-60C98,-46.0072 109.366,-42.9467 114.516,-33.9075"/>
102 <polygon fill="black" stroke="black" points="117.963,-34.551 117,-24 111.173,-32.8486 117.963,-34.551"/>
103 </g>
104 <!-- node5 -->
105 <g id="node6" class="node"><title>node5</title>
106 <polygon fill="none" stroke="black" points="210,-60.5 210,-83.5 276,-83.5 276,-60.5 210,-60.5"/>
107 <text text-anchor="middle" x="220" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
108 <polyline fill="none" stroke="black" points="230,-60.5 230,-83.5 "/>
109 <text text-anchor="middle" x="243" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">H</text>
110 <polyline fill="none" stroke="black" points="256,-60.5 256,-83.5 "/>
111 <text text-anchor="middle" x="266" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
112 </g>
113 <!-- node4&#45;&gt;node5 -->
114 <g id="edge8" class="edge"><title>node4:f0&#45;&gt;node5:f1</title>
115 <path fill="none" stroke="black" d="M243,-120C243,-108 243,-102.75 243,-94.125"/>
116 <polygon fill="black" stroke="black" points="246.5,-94 243,-84 239.5,-94 246.5,-94"/>
117 </g>
118 <!-- node6 -->
119 <g id="node7" class="node"><title>node6</title>
120 <polygon fill="none" stroke="black" points="294,-60.5 294,-83.5 360,-83.5 360,-60.5 294,-60.5"/>
121 <text text-anchor="middle" x="304" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
122 <polyline fill="none" stroke="black" points="314,-60.5 314,-83.5 "/>
123 <text text-anchor="middle" x="327" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">Y</text>
124 <polyline fill="none" stroke="black" points="340,-60.5 340,-83.5 "/>
125 <text text-anchor="middle" x="350" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
126 </g>
127 <!-- node4&#45;&gt;node6 -->
128 <g id="edge7" class="edge"><title>node4:f2&#45;&gt;node6:f1</title>
129 <path fill="none" stroke="black" d="M289,-120C289,-100.916 314.571,-104.572 323.76,-93.6598"/>
130 <polygon fill="black" stroke="black" points="327.138,-94.5939 327,-84 320.502,-92.368 327.138,-94.5939"/>
131 </g>
132 </g>
133 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: g Pages: 1 -->
6 <svg width="368pt" height="212pt"
7 viewBox="0.00 0.00 368.00 212.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 208)">
9 <title>g</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-208 364,-208 364,4 -4,4"/>
11 <!-- node0 -->
12 <g id="node1" class="node">
13 <title>node0</title>
14 <polygon fill="none" stroke="black" points="167.5,-180.5 167.5,-203.5 234.5,-203.5 234.5,-180.5 167.5,-180.5"/>
15 <text text-anchor="middle" x="177.5" y="-188.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
16 <polyline fill="none" stroke="black" points="187.5,-180.5 187.5,-203.5 "/>
17 <text text-anchor="middle" x="201" y="-188.3" font-family="Times New Roman,serif" font-size="14.00">G</text>
18 <polyline fill="none" stroke="black" points="214.5,-180.5 214.5,-203.5 "/>
19 <text text-anchor="middle" x="224.5" y="-188.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
20 </g>
21 <!-- node1 -->
22 <g id="node2" class="node">
23 <title>node1</title>
24 <polygon fill="none" stroke="black" points="103.5,-120.5 103.5,-143.5 168.5,-143.5 168.5,-120.5 103.5,-120.5"/>
25 <text text-anchor="middle" x="113.5" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
26 <polyline fill="none" stroke="black" points="123.5,-120.5 123.5,-143.5 "/>
27 <text text-anchor="middle" x="136" y="-128.3" font-family="Times New Roman,serif" font-size="14.00">E</text>
28 <polyline fill="none" stroke="black" points="148.5,-120.5 148.5,-143.5 "/>
29 <text text-anchor="middle" x="158.5" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
30 </g>
31 <!-- node0&#45;&gt;node1 -->
32 <g id="edge2" class="edge">
33 <title>node0:f0&#45;&gt;node1:f1</title>
34 <path fill="none" stroke="black" d="M177,-180C177,-159.92 148.88,-165.04 139.22,-153.62"/>
35 <polygon fill="black" stroke="black" points="142.49,-152.37 136,-144 135.85,-154.59 142.49,-152.37"/>
36 </g>
37 <!-- node4 -->
38 <g id="node5" class="node">
39 <title>node4</title>
40 <polygon fill="none" stroke="black" points="233,-120.5 233,-143.5 299,-143.5 299,-120.5 233,-120.5"/>
41 <text text-anchor="middle" x="243" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
42 <polyline fill="none" stroke="black" points="253,-120.5 253,-143.5 "/>
43 <text text-anchor="middle" x="266" y="-128.3" font-family="Times New Roman,serif" font-size="14.00">R</text>
44 <polyline fill="none" stroke="black" points="279,-120.5 279,-143.5 "/>
45 <text text-anchor="middle" x="289" y="-128.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
46 </g>
47 <!-- node0&#45;&gt;node4 -->
48 <g id="edge1" class="edge">
49 <title>node0:f2&#45;&gt;node4:f1</title>
50 <path fill="none" stroke="black" d="M225,-180C225,-159.92 253.12,-165.04 262.78,-153.62"/>
51 <polygon fill="black" stroke="black" points="266.15,-154.59 266,-144 259.51,-152.37 266.15,-154.59"/>
52 </g>
53 <!-- node2 -->
54 <g id="node3" class="node">
55 <title>node2</title>
56 <polygon fill="none" stroke="black" points="42,-60.5 42,-83.5 108,-83.5 108,-60.5 42,-60.5"/>
57 <text text-anchor="middle" x="52" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
58 <polyline fill="none" stroke="black" points="62,-60.5 62,-83.5 "/>
59 <text text-anchor="middle" x="75" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">B</text>
60 <polyline fill="none" stroke="black" points="88,-60.5 88,-83.5 "/>
61 <text text-anchor="middle" x="98" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
62 </g>
63 <!-- node1&#45;&gt;node2 -->
64 <g id="edge3" class="edge">
65 <title>node1:f0&#45;&gt;node2:f1</title>
66 <path fill="none" stroke="black" d="M113,-120C113,-100.92 87.43,-104.57 78.24,-93.66"/>
67 <polygon fill="black" stroke="black" points="81.5,-92.37 75,-84 74.86,-94.59 81.5,-92.37"/>
68 </g>
69 <!-- node3 -->
70 <g id="node4" class="node">
71 <title>node3</title>
72 <polygon fill="none" stroke="black" points="126.5,-60.5 126.5,-83.5 191.5,-83.5 191.5,-60.5 126.5,-60.5"/>
73 <text text-anchor="middle" x="136.5" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
74 <polyline fill="none" stroke="black" points="146.5,-60.5 146.5,-83.5 "/>
75 <text text-anchor="middle" x="159" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">F</text>
76 <polyline fill="none" stroke="black" points="171.5,-60.5 171.5,-83.5 "/>
77 <text text-anchor="middle" x="181.5" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
78 </g>
79 <!-- node1&#45;&gt;node3 -->
80 <g id="edge4" class="edge">
81 <title>node1:f2&#45;&gt;node3:f1</title>
82 <path fill="none" stroke="black" d="M159,-120C159,-108 159,-102.75 159,-94.13"/>
83 <polygon fill="black" stroke="black" points="162.5,-94 159,-84 155.5,-94 162.5,-94"/>
84 </g>
85 <!-- node7 -->
86 <g id="node8" class="node">
87 <title>node7</title>
88 <polygon fill="none" stroke="black" points="0,-0.5 0,-23.5 66,-23.5 66,-0.5 0,-0.5"/>
89 <text text-anchor="middle" x="10" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
90 <polyline fill="none" stroke="black" points="20,-0.5 20,-23.5 "/>
91 <text text-anchor="middle" x="33" y="-8.3" font-family="Times New Roman,serif" font-size="14.00">A</text>
92 <polyline fill="none" stroke="black" points="46,-0.5 46,-23.5 "/>
93 <text text-anchor="middle" x="56" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
94 </g>
95 <!-- node2&#45;&gt;node7 -->
96 <g id="edge6" class="edge">
97 <title>node2:f0&#45;&gt;node7:f1</title>
98 <path fill="none" stroke="black" d="M52,-60C52,-46.01 40.63,-42.95 35.48,-33.91"/>
99 <polygon fill="black" stroke="black" points="38.83,-32.85 33,-24 32.04,-34.55 38.83,-32.85"/>
100 </g>
101 <!-- node8 -->
102 <g id="node9" class="node">
103 <title>node8</title>
104 <polygon fill="none" stroke="black" points="84,-0.5 84,-23.5 150,-23.5 150,-0.5 84,-0.5"/>
105 <text text-anchor="middle" x="94" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
106 <polyline fill="none" stroke="black" points="104,-0.5 104,-23.5 "/>
107 <text text-anchor="middle" x="117" y="-8.3" font-family="Times New Roman,serif" font-size="14.00">C</text>
108 <polyline fill="none" stroke="black" points="130,-0.5 130,-23.5 "/>
109 <text text-anchor="middle" x="140" y="-8.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
110 </g>
111 <!-- node2&#45;&gt;node8 -->
112 <g id="edge5" class="edge">
113 <title>node2:f2&#45;&gt;node8:f1</title>
114 <path fill="none" stroke="black" d="M98,-60C98,-46.01 109.37,-42.95 114.52,-33.91"/>
115 <polygon fill="black" stroke="black" points="117.96,-34.55 117,-24 111.17,-32.85 117.96,-34.55"/>
116 </g>
117 <!-- node5 -->
118 <g id="node6" class="node">
119 <title>node5</title>
120 <polygon fill="none" stroke="black" points="210,-60.5 210,-83.5 276,-83.5 276,-60.5 210,-60.5"/>
121 <text text-anchor="middle" x="220" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
122 <polyline fill="none" stroke="black" points="230,-60.5 230,-83.5 "/>
123 <text text-anchor="middle" x="243" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">H</text>
124 <polyline fill="none" stroke="black" points="256,-60.5 256,-83.5 "/>
125 <text text-anchor="middle" x="266" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
126 </g>
127 <!-- node4&#45;&gt;node5 -->
128 <g id="edge8" class="edge">
129 <title>node4:f0&#45;&gt;node5:f1</title>
130 <path fill="none" stroke="black" d="M243,-120C243,-108 243,-102.75 243,-94.13"/>
131 <polygon fill="black" stroke="black" points="246.5,-94 243,-84 239.5,-94 246.5,-94"/>
132 </g>
133 <!-- node6 -->
134 <g id="node7" class="node">
135 <title>node6</title>
136 <polygon fill="none" stroke="black" points="294,-60.5 294,-83.5 360,-83.5 360,-60.5 294,-60.5"/>
137 <text text-anchor="middle" x="304" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
138 <polyline fill="none" stroke="black" points="314,-60.5 314,-83.5 "/>
139 <text text-anchor="middle" x="327" y="-68.3" font-family="Times New Roman,serif" font-size="14.00">Y</text>
140 <polyline fill="none" stroke="black" points="340,-60.5 340,-83.5 "/>
141 <text text-anchor="middle" x="350" y="-68.3" font-family="Times New Roman,serif" font-size="14.00"> </text>
142 </g>
143 <!-- node4&#45;&gt;node6 -->
144 <g id="edge7" class="edge">
145 <title>node4:f2&#45;&gt;node6:f1</title>
146 <path fill="none" stroke="black" d="M289,-120C289,-100.92 314.57,-104.57 323.76,-93.66"/>
147 <polygon fill="black" stroke="black" points="327.14,-94.59 327,-84 320.5,-92.37 327.14,-94.59"/>
148 </g>
149 </g>
150 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="224pt" height="408pt"
7 viewBox="0.00 0.00 224.00 408.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 404)">
9 <title>G</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-404 220,-404 220,4 -4,4"/>
11 <g id="clust1" class="cluster"><title>cluster_0</title>
12 <polygon fill="lightgrey" stroke="lightgrey" points="8,-65 8,-356 98,-356 98,-65 8,-65"/>
13 <text text-anchor="middle" x="53" y="-340.8" font-family="Times New Roman,serif" font-size="14.00">process #1</text>
14 </g>
15 <g id="clust2" class="cluster"><title>cluster_1</title>
16 <polygon fill="none" stroke="blue" points="129,-65 129,-356 208,-356 208,-65 129,-65"/>
17 <text text-anchor="middle" x="168.5" y="-340.8" font-family="Times New Roman,serif" font-size="14.00">process #2</text>
18 </g>
19 <!-- a0 -->
20 <g id="node1" class="node"><title>a0</title>
21 <ellipse fill="white" stroke="white" cx="63" cy="-307" rx="27" ry="18"/>
22 <text text-anchor="middle" x="63" y="-303.3" font-family="Times New Roman,serif" font-size="14.00">a0</text>
23 </g>
24 <!-- a1 -->
25 <g id="node2" class="node"><title>a1</title>
26 <ellipse fill="white" stroke="white" cx="63" cy="-235" rx="27" ry="18"/>
27 <text text-anchor="middle" x="63" y="-231.3" font-family="Times New Roman,serif" font-size="14.00">a1</text>
28 </g>
29 <!-- a0&#45;&gt;a1 -->
30 <g id="edge1" class="edge"><title>a0&#45;&gt;a1</title>
31 <path fill="none" stroke="black" d="M63,-288.697C63,-280.983 63,-271.712 63,-263.112"/>
32 <polygon fill="black" stroke="black" points="66.5001,-263.104 63,-253.104 59.5001,-263.104 66.5001,-263.104"/>
33 </g>
34 <!-- a2 -->
35 <g id="node3" class="node"><title>a2</title>
36 <ellipse fill="white" stroke="white" cx="63" cy="-163" rx="27" ry="18"/>
37 <text text-anchor="middle" x="63" y="-159.3" font-family="Times New Roman,serif" font-size="14.00">a2</text>
38 </g>
39 <!-- a1&#45;&gt;a2 -->
40 <g id="edge2" class="edge"><title>a1&#45;&gt;a2</title>
41 <path fill="none" stroke="black" d="M63,-216.697C63,-208.983 63,-199.712 63,-191.112"/>
42 <polygon fill="black" stroke="black" points="66.5001,-191.104 63,-181.104 59.5001,-191.104 66.5001,-191.104"/>
43 </g>
44 <!-- b3 -->
45 <g id="node8" class="node"><title>b3</title>
46 <ellipse fill="lightgrey" stroke="black" cx="164" cy="-91" rx="27" ry="18"/>
47 <text text-anchor="middle" x="164" y="-87.3" font-family="Times New Roman,serif" font-size="14.00">b3</text>
48 </g>
49 <!-- a1&#45;&gt;b3 -->
50 <g id="edge9" class="edge"><title>a1&#45;&gt;b3</title>
51 <path fill="none" stroke="black" d="M74.001,-218.533C91.6079,-193.779 126.245,-145.081 147.038,-115.847"/>
52 <polygon fill="black" stroke="black" points="150.069,-117.625 153.013,-107.448 144.364,-113.568 150.069,-117.625"/>
53 </g>
54 <!-- a3 -->
55 <g id="node4" class="node"><title>a3</title>
56 <ellipse fill="white" stroke="white" cx="63" cy="-91" rx="27" ry="18"/>
57 <text text-anchor="middle" x="63" y="-87.3" font-family="Times New Roman,serif" font-size="14.00">a3</text>
58 </g>
59 <!-- a2&#45;&gt;a3 -->
60 <g id="edge3" class="edge"><title>a2&#45;&gt;a3</title>
61 <path fill="none" stroke="black" d="M63,-144.697C63,-136.983 63,-127.712 63,-119.112"/>
62 <polygon fill="black" stroke="black" points="66.5001,-119.104 63,-109.104 59.5001,-119.104 66.5001,-119.104"/>
63 </g>
64 <!-- a3&#45;&gt;a0 -->
65 <g id="edge11" class="edge"><title>a3&#45;&gt;a0</title>
66 <path fill="none" stroke="black" d="M49.2496,-106.931C41.0392,-116.9 31.381,-130.753 27,-145 12.8916,-190.88 12.8916,-207.12 27,-253 30.2858,-263.685 36.5399,-274.149 42.9254,-282.919"/>
67 <polygon fill="black" stroke="black" points="40.354,-285.314 49.2496,-291.069 45.8844,-281.023 40.354,-285.314"/>
68 </g>
69 <!-- end -->
70 <g id="node10" class="node"><title>end</title>
71 <polygon fill="none" stroke="black" points="131.5,-37 94.5,-37 94.5,-0 131.5,-0 131.5,-37"/>
72 <polyline fill="none" stroke="black" points="106.5,-37 94.5,-25 "/>
73 <polyline fill="none" stroke="black" points="94.5,-12 106.5,-0 "/>
74 <polyline fill="none" stroke="black" points="119.5,-0 131.5,-12 "/>
75 <polyline fill="none" stroke="black" points="131.5,-25 119.5,-37 "/>
76 <text text-anchor="middle" x="113" y="-14.8" font-family="Times New Roman,serif" font-size="14.00">end</text>
77 </g>
78 <!-- a3&#45;&gt;end -->
79 <g id="edge12" class="edge"><title>a3&#45;&gt;end</title>
80 <path fill="none" stroke="black" d="M74.0966,-74.3538C80.1492,-65.8197 87.7959,-55.0378 94.7049,-45.2961"/>
81 <polygon fill="black" stroke="black" points="97.5978,-47.2672 100.528,-37.0856 91.888,-43.2177 97.5978,-47.2672"/>
82 </g>
83 <!-- b0 -->
84 <g id="node5" class="node"><title>b0</title>
85 <ellipse fill="lightgrey" stroke="black" cx="168" cy="-307" rx="27" ry="18"/>
86 <text text-anchor="middle" x="168" y="-303.3" font-family="Times New Roman,serif" font-size="14.00">b0</text>
87 </g>
88 <!-- b1 -->
89 <g id="node6" class="node"><title>b1</title>
90 <ellipse fill="lightgrey" stroke="black" cx="170" cy="-235" rx="27" ry="18"/>
91 <text text-anchor="middle" x="170" y="-231.3" font-family="Times New Roman,serif" font-size="14.00">b1</text>
92 </g>
93 <!-- b0&#45;&gt;b1 -->
94 <g id="edge4" class="edge"><title>b0&#45;&gt;b1</title>
95 <path fill="none" stroke="black" d="M168.494,-288.697C168.715,-280.983 168.98,-271.712 169.225,-263.112"/>
96 <polygon fill="black" stroke="black" points="172.724,-263.2 169.511,-253.104 165.727,-263 172.724,-263.2"/>
97 </g>
98 <!-- b2 -->
99 <g id="node7" class="node"><title>b2</title>
100 <ellipse fill="lightgrey" stroke="black" cx="173" cy="-163" rx="27" ry="18"/>
101 <text text-anchor="middle" x="173" y="-159.3" font-family="Times New Roman,serif" font-size="14.00">b2</text>
102 </g>
103 <!-- b1&#45;&gt;b2 -->
104 <g id="edge5" class="edge"><title>b1&#45;&gt;b2</title>
105 <path fill="none" stroke="black" d="M170.742,-216.697C171.072,-208.983 171.469,-199.712 171.838,-191.112"/>
106 <polygon fill="black" stroke="black" points="175.335,-191.245 172.267,-181.104 168.342,-190.945 175.335,-191.245"/>
107 </g>
108 <!-- b2&#45;&gt;a3 -->
109 <g id="edge10" class="edge"><title>b2&#45;&gt;a3</title>
110 <path fill="none" stroke="black" d="M153.839,-149.807C136.331,-138.665 110.241,-122.062 90.5068,-109.504"/>
111 <polygon fill="black" stroke="black" points="92.2567,-106.469 81.941,-104.053 88.4985,-112.375 92.2567,-106.469"/>
112 </g>
113 <!-- b2&#45;&gt;b3 -->
114 <g id="edge6" class="edge"><title>b2&#45;&gt;b3</title>
115 <path fill="none" stroke="black" d="M170.821,-145.055C169.83,-137.346 168.632,-128.027 167.518,-119.364"/>
116 <polygon fill="black" stroke="black" points="170.968,-118.747 166.221,-109.275 164.025,-119.64 170.968,-118.747"/>
117 </g>
118 <!-- b3&#45;&gt;end -->
119 <g id="edge13" class="edge"><title>b3&#45;&gt;end</title>
120 <path fill="none" stroke="black" d="M152.681,-74.3538C146.508,-65.8197 138.708,-55.0378 131.661,-45.2961"/>
121 <polygon fill="black" stroke="black" points="134.419,-43.1364 125.721,-37.0856 128.747,-47.2393 134.419,-43.1364"/>
122 </g>
123 <!-- start -->
124 <g id="node9" class="node"><title>start</title>
125 <polygon fill="none" stroke="black" points="115,-400 77.1282,-382 115,-364 152.872,-382 115,-400"/>
126 <polyline fill="none" stroke="black" points="87.9663,-387.151 87.9663,-376.849 "/>
127 <polyline fill="none" stroke="black" points="104.162,-369.151 125.838,-369.151 "/>
128 <polyline fill="none" stroke="black" points="142.034,-376.849 142.034,-387.151 "/>
129 <polyline fill="none" stroke="black" points="125.838,-394.849 104.162,-394.849 "/>
130 <text text-anchor="middle" x="115" y="-378.3" font-family="Times New Roman,serif" font-size="14.00">start</text>
131 </g>
132 <!-- start&#45;&gt;a0 -->
133 <g id="edge7" class="edge"><title>start&#45;&gt;a0</title>
134 <path fill="none" stroke="black" d="M105.942,-368.284C98.8241,-358.292 88.7051,-344.086 80.0777,-331.974"/>
135 <polygon fill="black" stroke="black" points="82.776,-329.73 74.1234,-323.616 77.0746,-333.791 82.776,-329.73"/>
136 </g>
137 <!-- start&#45;&gt;b0 -->
138 <g id="edge8" class="edge"><title>start&#45;&gt;b0</title>
139 <path fill="none" stroke="black" d="M124.232,-368.284C131.487,-358.292 141.801,-344.086 150.594,-331.974"/>
140 <polygon fill="black" stroke="black" points="153.62,-333.764 156.663,-323.616 147.955,-329.651 153.62,-333.764"/>
141 </g>
142 </g>
143 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="224pt" height="408pt"
7 viewBox="0.00 0.00 224.00 408.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 404)">
9 <title>G</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-404 220,-404 220,4 -4,4"/>
11 <g id="clust1" class="cluster">
12 <title>cluster_0</title>
13 <polygon fill="lightgrey" stroke="lightgrey" points="8,-65 8,-356 98,-356 98,-65 8,-65"/>
14 <text text-anchor="middle" x="53" y="-340.8" font-family="Times New Roman,serif" font-size="14.00">process #1</text>
15 </g>
16 <g id="clust2" class="cluster">
17 <title>cluster_1</title>
18 <polygon fill="none" stroke="blue" points="129,-65 129,-356 208,-356 208,-65 129,-65"/>
19 <text text-anchor="middle" x="168.5" y="-340.8" font-family="Times New Roman,serif" font-size="14.00">process #2</text>
20 </g>
21 <!-- a0 -->
22 <g id="node1" class="node">
23 <title>a0</title>
24 <ellipse fill="white" stroke="white" cx="63" cy="-307" rx="27" ry="18"/>
25 <text text-anchor="middle" x="63" y="-303.3" font-family="Times New Roman,serif" font-size="14.00">a0</text>
26 </g>
27 <!-- a1 -->
28 <g id="node2" class="node">
29 <title>a1</title>
30 <ellipse fill="white" stroke="white" cx="63" cy="-235" rx="27" ry="18"/>
31 <text text-anchor="middle" x="63" y="-231.3" font-family="Times New Roman,serif" font-size="14.00">a1</text>
32 </g>
33 <!-- a0&#45;&gt;a1 -->
34 <g id="edge1" class="edge">
35 <title>a0&#45;&gt;a1</title>
36 <path fill="none" stroke="black" d="M63,-288.7C63,-280.98 63,-271.71 63,-263.11"/>
37 <polygon fill="black" stroke="black" points="66.5,-263.1 63,-253.1 59.5,-263.1 66.5,-263.1"/>
38 </g>
39 <!-- a2 -->
40 <g id="node3" class="node">
41 <title>a2</title>
42 <ellipse fill="white" stroke="white" cx="63" cy="-163" rx="27" ry="18"/>
43 <text text-anchor="middle" x="63" y="-159.3" font-family="Times New Roman,serif" font-size="14.00">a2</text>
44 </g>
45 <!-- a1&#45;&gt;a2 -->
46 <g id="edge2" class="edge">
47 <title>a1&#45;&gt;a2</title>
48 <path fill="none" stroke="black" d="M63,-216.7C63,-208.98 63,-199.71 63,-191.11"/>
49 <polygon fill="black" stroke="black" points="66.5,-191.1 63,-181.1 59.5,-191.1 66.5,-191.1"/>
50 </g>
51 <!-- b3 -->
52 <g id="node8" class="node">
53 <title>b3</title>
54 <ellipse fill="lightgrey" stroke="black" cx="164" cy="-91" rx="27" ry="18"/>
55 <text text-anchor="middle" x="164" y="-87.3" font-family="Times New Roman,serif" font-size="14.00">b3</text>
56 </g>
57 <!-- a1&#45;&gt;b3 -->
58 <g id="edge9" class="edge">
59 <title>a1&#45;&gt;b3</title>
60 <path fill="none" stroke="black" d="M74,-218.53C91.61,-193.78 126.25,-145.08 147.04,-115.85"/>
61 <polygon fill="black" stroke="black" points="150.07,-117.63 153.01,-107.45 144.36,-113.57 150.07,-117.63"/>
62 </g>
63 <!-- a3 -->
64 <g id="node4" class="node">
65 <title>a3</title>
66 <ellipse fill="white" stroke="white" cx="63" cy="-91" rx="27" ry="18"/>
67 <text text-anchor="middle" x="63" y="-87.3" font-family="Times New Roman,serif" font-size="14.00">a3</text>
68 </g>
69 <!-- a2&#45;&gt;a3 -->
70 <g id="edge3" class="edge">
71 <title>a2&#45;&gt;a3</title>
72 <path fill="none" stroke="black" d="M63,-144.7C63,-136.98 63,-127.71 63,-119.11"/>
73 <polygon fill="black" stroke="black" points="66.5,-119.1 63,-109.1 59.5,-119.1 66.5,-119.1"/>
74 </g>
75 <!-- a3&#45;&gt;a0 -->
76 <g id="edge11" class="edge">
77 <title>a3&#45;&gt;a0</title>
78 <path fill="none" stroke="black" d="M49.25,-106.93C41.04,-116.9 31.38,-130.75 27,-145 12.89,-190.88 12.89,-207.12 27,-253 30.29,-263.69 36.54,-274.15 42.93,-282.92"/>
79 <polygon fill="black" stroke="black" points="40.35,-285.31 49.25,-291.07 45.88,-281.02 40.35,-285.31"/>
80 </g>
81 <!-- end -->
82 <g id="node10" class="node">
83 <title>end</title>
84 <polygon fill="none" stroke="black" points="131.5,-37 94.5,-37 94.5,0 131.5,0 131.5,-37"/>
85 <polyline fill="none" stroke="black" points="106.5,-37 94.5,-25 "/>
86 <polyline fill="none" stroke="black" points="94.5,-12 106.5,0 "/>
87 <polyline fill="none" stroke="black" points="119.5,0 131.5,-12 "/>
88 <polyline fill="none" stroke="black" points="131.5,-25 119.5,-37 "/>
89 <text text-anchor="middle" x="113" y="-14.8" font-family="Times New Roman,serif" font-size="14.00">end</text>
90 </g>
91 <!-- a3&#45;&gt;end -->
92 <g id="edge12" class="edge">
93 <title>a3&#45;&gt;end</title>
94 <path fill="none" stroke="black" d="M74.1,-74.35C80.15,-65.82 87.8,-55.04 94.7,-45.3"/>
95 <polygon fill="black" stroke="black" points="97.6,-47.27 100.53,-37.09 91.89,-43.22 97.6,-47.27"/>
96 </g>
97 <!-- b0 -->
98 <g id="node5" class="node">
99 <title>b0</title>
100 <ellipse fill="lightgrey" stroke="black" cx="164" cy="-307" rx="27" ry="18"/>
101 <text text-anchor="middle" x="164" y="-303.3" font-family="Times New Roman,serif" font-size="14.00">b0</text>
102 </g>
103 <!-- b1 -->
104 <g id="node6" class="node">
105 <title>b1</title>
106 <ellipse fill="lightgrey" stroke="black" cx="168" cy="-235" rx="27" ry="18"/>
107 <text text-anchor="middle" x="168" y="-231.3" font-family="Times New Roman,serif" font-size="14.00">b1</text>
108 </g>
109 <!-- b0&#45;&gt;b1 -->
110 <g id="edge4" class="edge">
111 <title>b0&#45;&gt;b1</title>
112 <path fill="none" stroke="black" d="M164.99,-288.7C165.43,-280.98 165.96,-271.71 166.45,-263.11"/>
113 <polygon fill="black" stroke="black" points="169.95,-263.29 167.02,-253.1 162.96,-262.89 169.95,-263.29"/>
114 </g>
115 <!-- b2 -->
116 <g id="node7" class="node">
117 <title>b2</title>
118 <ellipse fill="lightgrey" stroke="black" cx="173" cy="-163" rx="27" ry="18"/>
119 <text text-anchor="middle" x="173" y="-159.3" font-family="Times New Roman,serif" font-size="14.00">b2</text>
120 </g>
121 <!-- b1&#45;&gt;b2 -->
122 <g id="edge5" class="edge">
123 <title>b1&#45;&gt;b2</title>
124 <path fill="none" stroke="black" d="M169.24,-216.7C169.79,-208.98 170.45,-199.71 171.06,-191.11"/>
125 <polygon fill="black" stroke="black" points="174.56,-191.33 171.78,-181.1 167.57,-190.83 174.56,-191.33"/>
126 </g>
127 <!-- b2&#45;&gt;a3 -->
128 <g id="edge10" class="edge">
129 <title>b2&#45;&gt;a3</title>
130 <path fill="none" stroke="black" d="M153.84,-149.81C136.33,-138.67 110.24,-122.06 90.51,-109.5"/>
131 <polygon fill="black" stroke="black" points="92.26,-106.47 81.94,-104.05 88.5,-112.37 92.26,-106.47"/>
132 </g>
133 <!-- b2&#45;&gt;b3 -->
134 <g id="edge6" class="edge">
135 <title>b2&#45;&gt;b3</title>
136 <path fill="none" stroke="black" d="M170.82,-145.05C169.83,-137.35 168.63,-128.03 167.52,-119.36"/>
137 <polygon fill="black" stroke="black" points="170.97,-118.75 166.22,-109.28 164.02,-119.64 170.97,-118.75"/>
138 </g>
139 <!-- b3&#45;&gt;end -->
140 <g id="edge13" class="edge">
141 <title>b3&#45;&gt;end</title>
142 <path fill="none" stroke="black" d="M152.68,-74.35C146.51,-65.82 138.71,-55.04 131.66,-45.3"/>
143 <polygon fill="black" stroke="black" points="134.42,-43.14 125.72,-37.09 128.75,-47.24 134.42,-43.14"/>
144 </g>
145 <!-- start -->
146 <g id="node9" class="node">
147 <title>start</title>
148 <polygon fill="none" stroke="black" points="113,-400 75.13,-382 113,-364 150.87,-382 113,-400"/>
149 <polyline fill="none" stroke="black" points="85.97,-387.15 85.97,-376.85 "/>
150 <polyline fill="none" stroke="black" points="102.16,-369.15 123.84,-369.15 "/>
151 <polyline fill="none" stroke="black" points="140.03,-376.85 140.03,-387.15 "/>
152 <polyline fill="none" stroke="black" points="123.84,-394.85 102.16,-394.85 "/>
153 <text text-anchor="middle" x="113" y="-378.3" font-family="Times New Roman,serif" font-size="14.00">start</text>
154 </g>
155 <!-- start&#45;&gt;a0 -->
156 <g id="edge7" class="edge">
157 <title>start&#45;&gt;a0</title>
158 <path fill="none" stroke="black" d="M104.06,-367.95C97.23,-357.98 87.64,-343.97 79.44,-332"/>
159 <polygon fill="black" stroke="black" points="82.31,-330 73.78,-323.73 76.54,-333.96 82.31,-330"/>
160 </g>
161 <!-- start&#45;&gt;b0 -->
162 <g id="edge8" class="edge">
163 <title>start&#45;&gt;b0</title>
164 <path fill="none" stroke="black" d="M122.12,-367.95C129.08,-357.98 138.87,-343.97 147.23,-332"/>
165 <polygon fill="black" stroke="black" points="150.15,-333.93 153.01,-323.73 144.41,-329.92 150.15,-333.93"/>
166 </g>
167 </g>
168 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="222pt" height="364pt"
7 viewBox="0.00 0.00 222.00 364.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 360)">
9 <title>G</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-360 218,-360 218,4 -4,4"/>
11 <g id="clust1" class="cluster"><title>cluster0</title>
12 <polygon fill="none" stroke="black" points="64,-152 64,-348 206,-348 206,-152 64,-152"/>
13 </g>
14 <g id="clust2" class="cluster"><title>cluster1</title>
15 <polygon fill="none" stroke="black" points="64,-8 64,-132 206,-132 206,-8 64,-8"/>
16 </g>
17 <!-- a -->
18 <g id="node1" class="node"><title>a</title>
19 <ellipse fill="none" stroke="black" cx="135" cy="-322" rx="27" ry="18"/>
20 <text text-anchor="middle" x="135" y="-318.3" font-family="Times New Roman,serif" font-size="14.00">a</text>
21 </g>
22 <!-- b -->
23 <g id="node2" class="node"><title>b</title>
24 <ellipse fill="none" stroke="black" cx="99" cy="-250" rx="27" ry="18"/>
25 <text text-anchor="middle" x="99" y="-246.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
26 </g>
27 <!-- a&#45;&gt;b -->
28 <g id="edge1" class="edge"><title>a&#45;&gt;b</title>
29 <path fill="none" stroke="black" d="M126.65,-304.765C122.288,-296.283 116.853,-285.714 111.959,-276.197"/>
30 <polygon fill="black" stroke="black" points="114.99,-274.439 107.304,-267.147 108.765,-277.641 114.99,-274.439"/>
31 </g>
32 <!-- c -->
33 <g id="node3" class="node"><title>c</title>
34 <ellipse fill="none" stroke="black" cx="171" cy="-250" rx="27" ry="18"/>
35 <text text-anchor="middle" x="171" y="-246.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
36 </g>
37 <!-- a&#45;&gt;c -->
38 <g id="edge2" class="edge"><title>a&#45;&gt;c</title>
39 <path fill="none" stroke="black" d="M143.35,-304.765C147.712,-296.283 153.147,-285.714 158.041,-276.197"/>
40 <polygon fill="black" stroke="black" points="161.235,-277.641 162.696,-267.147 155.01,-274.439 161.235,-277.641"/>
41 </g>
42 <!-- d -->
43 <g id="node4" class="node"><title>d</title>
44 <ellipse fill="none" stroke="black" cx="99" cy="-178" rx="27" ry="18"/>
45 <text text-anchor="middle" x="99" y="-174.3" font-family="Times New Roman,serif" font-size="14.00">d</text>
46 </g>
47 <!-- b&#45;&gt;d -->
48 <g id="edge3" class="edge"><title>b&#45;&gt;d</title>
49 <path fill="none" stroke="black" d="M99,-231.697C99,-223.983 99,-214.712 99,-206.112"/>
50 <polygon fill="black" stroke="black" points="102.5,-206.104 99,-196.104 95.5001,-206.104 102.5,-206.104"/>
51 </g>
52 <!-- f -->
53 <g id="node7" class="node"><title>f</title>
54 <ellipse fill="none" stroke="black" cx="99" cy="-34" rx="27" ry="18"/>
55 <text text-anchor="middle" x="99" y="-30.3" font-family="Times New Roman,serif" font-size="14.00">f</text>
56 </g>
57 <!-- b&#45;&gt;f -->
58 <g id="edge7" class="edge"><title>b&#45;&gt;f</title>
59 <path fill="none" stroke="black" d="M112.75,-234.069C120.961,-224.1 130.619,-210.247 135,-196 142.052,-173.066 145.58,-157.538 145.581,-142.011"/>
60 <polygon fill="black" stroke="black" points="149.063,-141.547 145.075,-131.731 142.071,-141.891 149.063,-141.547"/>
61 </g>
62 <!-- c&#45;&gt;d -->
63 <g id="edge4" class="edge"><title>c&#45;&gt;d</title>
64 <path fill="none" stroke="black" d="M156.43,-234.834C146.25,-224.938 132.476,-211.546 120.969,-200.359"/>
65 <polygon fill="black" stroke="black" points="123.405,-197.846 113.796,-193.385 118.526,-202.865 123.405,-197.846"/>
66 </g>
67 <!-- e -->
68 <g id="node5" class="node"><title>e</title>
69 <ellipse fill="none" stroke="black" cx="99" cy="-106" rx="27" ry="18"/>
70 <text text-anchor="middle" x="99" y="-102.3" font-family="Times New Roman,serif" font-size="14.00">e</text>
71 </g>
72 <!-- c&#45;&gt;e -->
73 <g id="edge10" class="edge"><title>c&#45;&gt;e</title>
74 <path fill="none" stroke="black" d="M135,-152C130.703,-144.409 125.157,-136.769 119.712,-129.993"/>
75 <polygon fill="black" stroke="black" points="122.073,-127.362 112.969,-121.943 116.707,-131.857 122.073,-127.362"/>
76 </g>
77 <!-- g -->
78 <g id="node6" class="node"><title>g</title>
79 <ellipse fill="none" stroke="black" cx="171" cy="-34" rx="27" ry="18"/>
80 <text text-anchor="middle" x="171" y="-30.3" font-family="Times New Roman,serif" font-size="14.00">g</text>
81 </g>
82 <!-- c&#45;&gt;g -->
83 <g id="edge9" class="edge"><title>c&#45;&gt;g</title>
84 <path fill="none" stroke="black" d="M171,-152.011C171,-148.759 171,-145.494 171,-142.23"/>
85 <polygon fill="black" stroke="black" points="174.5,-141.93 171,-131.93 167.5,-141.93 174.5,-141.93"/>
86 </g>
87 <!-- d&#45;&gt;e -->
88 <g id="edge8" class="edge"><title>d&#45;&gt;e</title>
89 <path fill="none" stroke="black" d="M99,-159.697C99,-151.983 99,-142.712 99,-134.112"/>
90 <polygon fill="black" stroke="black" points="102.5,-134.104 99,-124.104 95.5001,-134.104 102.5,-134.104"/>
91 </g>
92 <!-- h -->
93 <g id="node8" class="node"><title>h</title>
94 <ellipse fill="none" stroke="black" cx="27" cy="-106" rx="27" ry="18"/>
95 <text text-anchor="middle" x="27" y="-102.3" font-family="Times New Roman,serif" font-size="14.00">h</text>
96 </g>
97 <!-- d&#45;&gt;h -->
98 <g id="edge11" class="edge"><title>d&#45;&gt;h</title>
99 <path fill="none" stroke="black" d="M84.4297,-162.834C74.2501,-152.938 60.4761,-139.546 48.9694,-128.359"/>
100 <polygon fill="black" stroke="black" points="51.4055,-125.846 41.7957,-121.385 46.5259,-130.865 51.4055,-125.846"/>
101 </g>
102 <!-- e&#45;&gt;g -->
103 <g id="edge5" class="edge"><title>e&#45;&gt;g</title>
104 <path fill="none" stroke="black" d="M113.57,-90.8345C123.75,-80.9376 137.524,-67.5462 149.031,-56.3591"/>
105 <polygon fill="black" stroke="black" points="151.474,-58.865 156.204,-49.3847 146.595,-53.8461 151.474,-58.865"/>
106 </g>
107 <!-- e&#45;&gt;f -->
108 <g id="edge6" class="edge"><title>e&#45;&gt;f</title>
109 <path fill="none" stroke="black" d="M99,-87.6966C99,-79.9827 99,-70.7125 99,-62.1124"/>
110 <polygon fill="black" stroke="black" points="102.5,-62.1043 99,-52.1043 95.5001,-62.1044 102.5,-62.1043"/>
111 </g>
112 </g>
113 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="222pt" height="364pt"
7 viewBox="0.00 0.00 222.00 364.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 360)">
9 <title>G</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-360 218,-360 218,4 -4,4"/>
11 <g id="clust1" class="cluster">
12 <title>cluster0</title>
13 <polygon fill="none" stroke="black" points="64,-152 64,-348 206,-348 206,-152 64,-152"/>
14 </g>
15 <g id="clust2" class="cluster">
16 <title>cluster1</title>
17 <polygon fill="none" stroke="black" points="64,-8 64,-132 206,-132 206,-8 64,-8"/>
18 </g>
19 <!-- a -->
20 <g id="node1" class="node">
21 <title>a</title>
22 <ellipse fill="none" stroke="black" cx="135" cy="-322" rx="27" ry="18"/>
23 <text text-anchor="middle" x="135" y="-318.3" font-family="Times New Roman,serif" font-size="14.00">a</text>
24 </g>
25 <!-- b -->
26 <g id="node2" class="node">
27 <title>b</title>
28 <ellipse fill="none" stroke="black" cx="99" cy="-250" rx="27" ry="18"/>
29 <text text-anchor="middle" x="99" y="-246.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
30 </g>
31 <!-- a&#45;&gt;b -->
32 <g id="edge1" class="edge">
33 <title>a&#45;&gt;b</title>
34 <path fill="none" stroke="black" d="M126.65,-304.76C122.29,-296.28 116.85,-285.71 111.96,-276.2"/>
35 <polygon fill="black" stroke="black" points="114.99,-274.44 107.3,-267.15 108.77,-277.64 114.99,-274.44"/>
36 </g>
37 <!-- c -->
38 <g id="node3" class="node">
39 <title>c</title>
40 <ellipse fill="none" stroke="black" cx="171" cy="-250" rx="27" ry="18"/>
41 <text text-anchor="middle" x="171" y="-246.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
42 </g>
43 <!-- a&#45;&gt;c -->
44 <g id="edge2" class="edge">
45 <title>a&#45;&gt;c</title>
46 <path fill="none" stroke="black" d="M143.35,-304.76C147.71,-296.28 153.15,-285.71 158.04,-276.2"/>
47 <polygon fill="black" stroke="black" points="161.23,-277.64 162.7,-267.15 155.01,-274.44 161.23,-277.64"/>
48 </g>
49 <!-- d -->
50 <g id="node4" class="node">
51 <title>d</title>
52 <ellipse fill="none" stroke="black" cx="99" cy="-178" rx="27" ry="18"/>
53 <text text-anchor="middle" x="99" y="-174.3" font-family="Times New Roman,serif" font-size="14.00">d</text>
54 </g>
55 <!-- b&#45;&gt;d -->
56 <g id="edge3" class="edge">
57 <title>b&#45;&gt;d</title>
58 <path fill="none" stroke="black" d="M99,-231.7C99,-223.98 99,-214.71 99,-206.11"/>
59 <polygon fill="black" stroke="black" points="102.5,-206.1 99,-196.1 95.5,-206.1 102.5,-206.1"/>
60 </g>
61 <!-- f -->
62 <g id="node7" class="node">
63 <title>f</title>
64 <ellipse fill="none" stroke="black" cx="99" cy="-34" rx="27" ry="18"/>
65 <text text-anchor="middle" x="99" y="-30.3" font-family="Times New Roman,serif" font-size="14.00">f</text>
66 </g>
67 <!-- b&#45;&gt;f -->
68 <g id="edge7" class="edge">
69 <title>b&#45;&gt;f</title>
70 <path fill="none" stroke="black" d="M112.75,-234.07C120.96,-224.1 130.62,-210.25 135,-196 142.02,-173.17 145.55,-157.68 145.58,-142.23"/>
71 <polygon fill="black" stroke="black" points="149.07,-141.82 145.1,-132 142.07,-142.15 149.07,-141.82"/>
72 </g>
73 <!-- c&#45;&gt;d -->
74 <g id="edge4" class="edge">
75 <title>c&#45;&gt;d</title>
76 <path fill="none" stroke="black" d="M156.43,-234.83C146.25,-224.94 132.48,-211.55 120.97,-200.36"/>
77 <polygon fill="black" stroke="black" points="123.41,-197.85 113.8,-193.38 118.53,-202.87 123.41,-197.85"/>
78 </g>
79 <!-- e -->
80 <g id="node5" class="node">
81 <title>e</title>
82 <ellipse fill="none" stroke="black" cx="99" cy="-106" rx="27" ry="18"/>
83 <text text-anchor="middle" x="99" y="-102.3" font-family="Times New Roman,serif" font-size="14.00">e</text>
84 </g>
85 <!-- c&#45;&gt;e -->
86 <g id="edge10" class="edge">
87 <title>c&#45;&gt;e</title>
88 <path fill="none" stroke="black" d="M135,-152C130.7,-144.41 125.16,-136.77 119.71,-129.99"/>
89 <polygon fill="black" stroke="black" points="122.07,-127.36 112.97,-121.94 116.71,-131.86 122.07,-127.36"/>
90 </g>
91 <!-- g -->
92 <g id="node6" class="node">
93 <title>g</title>
94 <ellipse fill="none" stroke="black" cx="171" cy="-34" rx="27" ry="18"/>
95 <text text-anchor="middle" x="171" y="-30.3" font-family="Times New Roman,serif" font-size="14.00">g</text>
96 </g>
97 <!-- c&#45;&gt;g -->
98 <g id="edge9" class="edge">
99 <title>c&#45;&gt;g</title>
100 <path fill="none" stroke="black" d="M171,-152C171,-148.77 171,-145.53 171,-142.29"/>
101 <polygon fill="black" stroke="black" points="174.5,-141.99 171,-132 167.5,-142 174.5,-141.99"/>
102 </g>
103 <!-- d&#45;&gt;e -->
104 <g id="edge8" class="edge">
105 <title>d&#45;&gt;e</title>
106 <path fill="none" stroke="black" d="M99,-159.7C99,-151.98 99,-142.71 99,-134.11"/>
107 <polygon fill="black" stroke="black" points="102.5,-134.1 99,-124.1 95.5,-134.1 102.5,-134.1"/>
108 </g>
109 <!-- h -->
110 <g id="node8" class="node">
111 <title>h</title>
112 <ellipse fill="none" stroke="black" cx="27" cy="-106" rx="27" ry="18"/>
113 <text text-anchor="middle" x="27" y="-102.3" font-family="Times New Roman,serif" font-size="14.00">h</text>
114 </g>
115 <!-- d&#45;&gt;h -->
116 <g id="edge11" class="edge">
117 <title>d&#45;&gt;h</title>
118 <path fill="none" stroke="black" d="M84.43,-162.83C74.25,-152.94 60.48,-139.55 48.97,-128.36"/>
119 <polygon fill="black" stroke="black" points="51.41,-125.85 41.8,-121.38 46.53,-130.87 51.41,-125.85"/>
120 </g>
121 <!-- e&#45;&gt;g -->
122 <g id="edge5" class="edge">
123 <title>e&#45;&gt;g</title>
124 <path fill="none" stroke="black" d="M113.57,-90.83C123.75,-80.94 137.52,-67.55 149.03,-56.36"/>
125 <polygon fill="black" stroke="black" points="151.47,-58.87 156.2,-49.38 146.59,-53.85 151.47,-58.87"/>
126 </g>
127 <!-- e&#45;&gt;f -->
128 <g id="edge6" class="edge">
129 <title>e&#45;&gt;f</title>
130 <path fill="none" stroke="black" d="M99,-87.7C99,-79.98 99,-70.71 99,-62.11"/>
131 <polygon fill="black" stroke="black" points="102.5,-62.1 99,-52.1 95.5,-62.1 102.5,-62.1"/>
132 </g>
133 </g>
134 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: %3 Pages: 1 -->
6 <svg width="62pt" height="44pt"
7 viewBox="0.00 0.00 62.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
9 <title>%3</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-40 58,-40 58,4 -4,4"/>
11 <!-- diamond -->
12 <g id="node1" class="node"><title>diamond</title>
13 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
14 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">&lt;&gt;</text>
15 </g>
16 </g>
17 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="62pt" height="44pt"
7 viewBox="0.00 0.00 62.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-40 58,-40 58,4 -4,4"/>
10 <!-- diamond -->
11 <g id="node1" class="node">
12 <title>diamond</title>
13 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
14 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">&lt;&gt;</text>
15 </g>
16 </g>
17 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: ER Pages: 1 -->
6 <svg width="352pt" height="436pt"
7 viewBox="0.00 0.00 351.54 436.37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(158.439 174.559)">
9 <title>ER</title>
10 <polygon fill="white" stroke="none" points="-158.439,261.813 -158.439,-174.559 193.1,-174.559 193.1,261.813 -158.439,261.813"/>
11 <text text-anchor="middle" x="17.3304" y="225.813" font-family="Times New Roman,serif" font-size="20.00">Entity Relation Diagram</text>
12 <text text-anchor="middle" x="17.3304" y="247.813" font-family="Times New Roman,serif" font-size="20.00">drawn by NEATO</text>
13 <!-- course -->
14 <g id="node1" class="node"><title>course</title>
15 <polygon fill="none" stroke="black" points="113.543,-48.4456 59.5425,-48.4456 59.5425,-12.4456 113.543,-12.4456 113.543,-48.4456"/>
16 <text text-anchor="middle" x="86.5425" y="-26.7456" font-family="Times New Roman,serif" font-size="14.00">course</text>
17 </g>
18 <!-- C&#45;I -->
19 <g id="node10" class="node"><title>C&#45;I</title>
20 <polygon fill="lightgrey" stroke="lightgrey" points="33.7217,-114.449 1.37974,-96.4492 33.7217,-78.4492 66.0636,-96.4492 33.7217,-114.449"/>
21 <text text-anchor="middle" x="33.7217" y="-92.7492" font-family="Times New Roman,serif" font-size="14.00">C&#45;I</text>
22 </g>
23 <!-- course&#45;&#45;C&#45;I -->
24 <g id="edge3" class="edge"><title>course&#45;&#45;C&#45;I</title>
25 <path fill="none" stroke="black" d="M72.109,-48.4814C63.1897,-59.6267 51.9583,-73.6612 43.953,-83.6643"/>
26 <text text-anchor="middle" x="54.531" y="-54.8729" font-family="Times New Roman,serif" font-size="14.00">n</text>
27 </g>
28 <!-- institute -->
29 <g id="node2" class="node"><title>institute</title>
30 <polygon fill="none" stroke="black" points="-18.75,-105.706 -77.75,-105.706 -77.75,-69.7063 -18.75,-69.7063 -18.75,-105.706"/>
31 <text text-anchor="middle" x="-48.25" y="-84.0063" font-family="Times New Roman,serif" font-size="14.00">institute</text>
32 </g>
33 <!-- name1 -->
34 <g id="node5" class="node"><title>name1</title>
35 <ellipse fill="none" stroke="black" cx="-92.878" cy="-152.559" rx="29.795" ry="18"/>
36 <text text-anchor="middle" x="-92.878" y="-148.859" font-family="Times New Roman,serif" font-size="14.00">name</text>
37 </g>
38 <!-- institute&#45;&#45;name1 -->
39 <g id="edge5" class="edge"><title>institute&#45;&#45;name1</title>
40 <path fill="none" stroke="black" d="M-60.6814,-105.771C-67.1807,-115.216 -75.0819,-126.698 -81.4304,-135.924"/>
41 </g>
42 <!-- S&#45;I -->
43 <g id="node12" class="node"><title>S&#45;I</title>
44 <polygon fill="lightgrey" stroke="lightgrey" points="-77.1806,-28.8586 -108.185,-10.8586 -77.1806,7.14139 -46.176,-10.8586 -77.1806,-28.8586"/>
45 <text text-anchor="middle" x="-77.1806" y="-7.15861" font-family="Times New Roman,serif" font-size="14.00">S&#45;I</text>
46 </g>
47 <!-- institute&#45;&#45;S&#45;I -->
48 <g id="edge6" class="edge"><title>institute&#45;&#45;S&#45;I</title>
49 <path fill="none" stroke="black" d="M-55.1061,-69.4945C-60.119,-56.1791 -66.8361,-38.3367 -71.5392,-25.8438"/>
50 <text text-anchor="middle" x="-66.8227" y="-51.4691" font-family="Times New Roman,serif" font-size="14.00">1</text>
51 </g>
52 <!-- student -->
53 <g id="node3" class="node"><title>student</title>
54 <polygon fill="none" stroke="black" points="-13.1816,48.1705 -70.1816,48.1705 -70.1816,84.1705 -13.1816,84.1705 -13.1816,48.1705"/>
55 <text text-anchor="middle" x="-41.6816" y="69.8705" font-family="Times New Roman,serif" font-size="14.00">student</text>
56 </g>
57 <!-- name2 -->
58 <g id="node6" class="node"><title>name2</title>
59 <ellipse fill="none" stroke="black" cx="-124.542" cy="77.2328" rx="29.795" ry="18"/>
60 <text text-anchor="middle" x="-124.542" y="80.9328" font-family="Times New Roman,serif" font-size="14.00">name</text>
61 </g>
62 <!-- student&#45;&#45;name2 -->
63 <g id="edge9" class="edge"><title>student&#45;&#45;name2</title>
64 <path fill="none" stroke="black" d="M-70.1973,69.9775C-78.2492,71.0525 -87.0242,72.224 -95.1278,73.3059"/>
65 </g>
66 <!-- grade -->
67 <g id="node8" class="node"><title>grade</title>
68 <ellipse fill="none" stroke="black" cx="-1.75067" cy="139.813" rx="30.5947" ry="18"/>
69 <text text-anchor="middle" x="-1.75067" y="143.513" font-family="Times New Roman,serif" font-size="14.00">grade</text>
70 </g>
71 <!-- student&#45;&#45;grade -->
72 <g id="edge8" class="edge"><title>student&#45;&#45;grade</title>
73 <path fill="none" stroke="black" d="M-31.811,84.3743C-25.5291,95.9597 -17.4379,110.882 -11.2327,122.326"/>
74 </g>
75 <!-- number -->
76 <g id="node9" class="node"><title>number</title>
77 <ellipse fill="none" stroke="black" cx="-77.7046" cy="138.365" rx="38.1938" ry="18"/>
78 <text text-anchor="middle" x="-77.7046" y="142.065" font-family="Times New Roman,serif" font-size="14.00">number</text>
79 </g>
80 <!-- student&#45;&#45;number -->
81 <g id="edge10" class="edge"><title>student&#45;&#45;number</title>
82 <path fill="none" stroke="black" d="M-50.7717,84.3881C-56.2742,95.4158 -63.2629,109.422 -68.7422,120.403"/>
83 </g>
84 <!-- S&#45;C -->
85 <g id="node11" class="node"><title>S&#45;C</title>
86 <polygon fill="lightgrey" stroke="lightgrey" points="38.268,20.0101 2.57309,38.0101 38.268,56.0101 73.9629,38.0101 38.268,20.0101"/>
87 <text text-anchor="middle" x="38.268" y="41.7101" font-family="Times New Roman,serif" font-size="14.00">S&#45;C</text>
88 </g>
89 <!-- student&#45;&#45;S&#45;C -->
90 <g id="edge11" class="edge"><title>student&#45;&#45;S&#45;C</title>
91 <path fill="none" stroke="black" d="M-12.8179,56.0039C-2.97784,52.538 7.83799,48.7284 16.9742,45.5103"/>
92 <text text-anchor="middle" x="-3.42185" y="46.9571" font-family="Times New Roman,serif" font-size="14.00">m</text>
93 </g>
94 <!-- name0 -->
95 <g id="node4" class="node"><title>name0</title>
96 <ellipse fill="none" stroke="black" cx="144.953" cy="-86.1968" rx="29.795" ry="18"/>
97 <text text-anchor="middle" x="144.953" y="-82.4968" font-family="Times New Roman,serif" font-size="14.00">name</text>
98 </g>
99 <!-- name0&#45;&#45;course -->
100 <g id="edge1" class="edge"><title>name0&#45;&#45;course</title>
101 <path fill="none" stroke="black" d="M128.992,-70.9625C121.831,-64.1276 113.322,-56.0064 105.81,-48.8358"/>
102 </g>
103 <!-- code -->
104 <g id="node7" class="node"><title>code</title>
105 <ellipse fill="none" stroke="black" cx="160.502" cy="4.62428" rx="28.6953" ry="18"/>
106 <text text-anchor="middle" x="160.502" y="8.32428" font-family="Times New Roman,serif" font-size="14.00">code</text>
107 </g>
108 <!-- code&#45;&#45;course -->
109 <g id="edge2" class="edge"><title>code&#45;&#45;course</title>
110 <path fill="none" stroke="black" d="M137.506,-6.27983C129.958,-9.8589 121.499,-13.8702 113.674,-17.5806"/>
111 </g>
112 <!-- C&#45;I&#45;&#45;institute -->
113 <g id="edge4" class="edge"><title>C&#45;I&#45;&#45;institute</title>
114 <path fill="none" stroke="black" d="M6.42628,-93.5379C-1.58435,-92.6835 -10.3833,-91.7451 -18.5368,-90.8754"/>
115 <text text-anchor="middle" x="-9.55527" y="-96.0067" font-family="Times New Roman,serif" font-size="14.00">1</text>
116 </g>
117 <!-- S&#45;C&#45;&#45;course -->
118 <g id="edge12" class="edge"><title>S&#45;C&#45;&#45;course</title>
119 <path fill="none" stroke="black" d="M47.8055,24.4854C55.2245,13.9649 65.5912,-0.735636 73.7336,-12.2819"/>
120 <text text-anchor="middle" x="57.2695" y="2.30178" font-family="Times New Roman,serif" font-size="14.00">n</text>
121 </g>
122 <!-- S&#45;I&#45;&#45;student -->
123 <g id="edge7" class="edge"><title>S&#45;I&#45;&#45;student</title>
124 <path fill="none" stroke="black" d="M-70.5035,3.62997C-64.7192,16.1813 -56.3228,34.4006 -50.0831,47.9401"/>
125 <text text-anchor="middle" x="-63.7933" y="21.985" font-family="Times New Roman,serif" font-size="14.00">n</text>
126 </g>
127 </g>
128 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: ER Pages: 1 -->
6 <svg width="352pt" height="436pt"
7 viewBox="0.00 0.00 351.54 436.37" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 432.37)">
9 <title>ER</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-432.37 347.54,-432.37 347.54,4 -4,4"/>
11 <text text-anchor="middle" x="171.77" y="-32" font-family="Times New Roman,serif" font-size="20.00">Entity Relation Diagram</text>
12 <text text-anchor="middle" x="171.77" y="-10" font-family="Times New Roman,serif" font-size="20.00">drawn by NEATO</text>
13 <!-- course -->
14 <g id="node1" class="node">
15 <title>course</title>
16 <polygon fill="none" stroke="black" points="267.98,-306.26 213.98,-306.26 213.98,-270.26 267.98,-270.26 267.98,-306.26"/>
17 <text text-anchor="middle" x="240.98" y="-284.56" font-family="Times New Roman,serif" font-size="14.00">course</text>
18 </g>
19 <!-- C&#45;I -->
20 <g id="node10" class="node">
21 <title>C&#45;I</title>
22 <polygon fill="lightgrey" stroke="lightgrey" points="188.16,-372.26 155.82,-354.26 188.16,-336.26 220.5,-354.26 188.16,-372.26"/>
23 <text text-anchor="middle" x="188.16" y="-350.56" font-family="Times New Roman,serif" font-size="14.00">C&#45;I</text>
24 </g>
25 <!-- course&#45;&#45;C&#45;I -->
26 <g id="edge3" class="edge">
27 <title>course&#45;&#45;C&#45;I</title>
28 <path fill="none" stroke="black" d="M226.55,-306.29C217.63,-317.44 206.4,-331.47 198.39,-341.48"/>
29 <text text-anchor="middle" x="208.97" y="-312.69" font-family="Times New Roman,serif" font-size="14.00">n</text>
30 </g>
31 <!-- institute -->
32 <g id="node2" class="node">
33 <title>institute</title>
34 <polygon fill="none" stroke="black" points="135.69,-363.52 76.69,-363.52 76.69,-327.52 135.69,-327.52 135.69,-363.52"/>
35 <text text-anchor="middle" x="106.19" y="-341.82" font-family="Times New Roman,serif" font-size="14.00">institute</text>
36 </g>
37 <!-- name1 -->
38 <g id="node5" class="node">
39 <title>name1</title>
40 <ellipse fill="none" stroke="black" cx="61.56" cy="-410.37" rx="29.8" ry="18"/>
41 <text text-anchor="middle" x="61.56" y="-406.67" font-family="Times New Roman,serif" font-size="14.00">name</text>
42 </g>
43 <!-- institute&#45;&#45;name1 -->
44 <g id="edge5" class="edge">
45 <title>institute&#45;&#45;name1</title>
46 <path fill="none" stroke="black" d="M93.76,-363.58C87.26,-373.03 79.36,-384.51 73.01,-393.74"/>
47 </g>
48 <!-- S&#45;I -->
49 <g id="node12" class="node">
50 <title>S&#45;I</title>
51 <polygon fill="lightgrey" stroke="lightgrey" points="77.26,-286.67 46.25,-268.67 77.26,-250.67 108.26,-268.67 77.26,-286.67"/>
52 <text text-anchor="middle" x="77.26" y="-264.97" font-family="Times New Roman,serif" font-size="14.00">S&#45;I</text>
53 </g>
54 <!-- institute&#45;&#45;S&#45;I -->
55 <g id="edge6" class="edge">
56 <title>institute&#45;&#45;S&#45;I</title>
57 <path fill="none" stroke="black" d="M99.33,-327.31C94.32,-313.99 87.6,-296.15 82.9,-283.66"/>
58 <text text-anchor="middle" x="87.62" y="-309.28" font-family="Times New Roman,serif" font-size="14.00">1</text>
59 </g>
60 <!-- student -->
61 <g id="node3" class="node">
62 <title>student</title>
63 <polygon fill="none" stroke="black" points="141.26,-209.64 84.26,-209.64 84.26,-173.64 141.26,-173.64 141.26,-209.64"/>
64 <text text-anchor="middle" x="112.76" y="-187.94" font-family="Times New Roman,serif" font-size="14.00">student</text>
65 </g>
66 <!-- name2 -->
67 <g id="node6" class="node">
68 <title>name2</title>
69 <ellipse fill="none" stroke="black" cx="29.9" cy="-180.58" rx="29.8" ry="18"/>
70 <text text-anchor="middle" x="29.9" y="-176.88" font-family="Times New Roman,serif" font-size="14.00">name</text>
71 </g>
72 <!-- student&#45;&#45;name2 -->
73 <g id="edge9" class="edge">
74 <title>student&#45;&#45;name2</title>
75 <path fill="none" stroke="black" d="M84.24,-187.84C76.19,-186.76 67.41,-185.59 59.31,-184.51"/>
76 </g>
77 <!-- grade -->
78 <g id="node8" class="node">
79 <title>grade</title>
80 <ellipse fill="none" stroke="black" cx="152.69" cy="-118" rx="30.59" ry="18"/>
81 <text text-anchor="middle" x="152.69" y="-114.3" font-family="Times New Roman,serif" font-size="14.00">grade</text>
82 </g>
83 <!-- student&#45;&#45;grade -->
84 <g id="edge8" class="edge">
85 <title>student&#45;&#45;grade</title>
86 <path fill="none" stroke="black" d="M122.63,-173.44C128.91,-161.85 137,-146.93 143.21,-135.49"/>
87 </g>
88 <!-- number -->
89 <g id="node9" class="node">
90 <title>number</title>
91 <ellipse fill="none" stroke="black" cx="76.73" cy="-119.45" rx="38.19" ry="18"/>
92 <text text-anchor="middle" x="76.73" y="-115.75" font-family="Times New Roman,serif" font-size="14.00">number</text>
93 </g>
94 <!-- student&#45;&#45;number -->
95 <g id="edge10" class="edge">
96 <title>student&#45;&#45;number</title>
97 <path fill="none" stroke="black" d="M103.67,-173.43C98.16,-162.4 91.18,-148.39 85.7,-137.41"/>
98 </g>
99 <!-- S&#45;C -->
100 <g id="node11" class="node">
101 <title>S&#45;C</title>
102 <polygon fill="lightgrey" stroke="lightgrey" points="192.71,-237.8 157.01,-219.8 192.71,-201.8 228.4,-219.8 192.71,-237.8"/>
103 <text text-anchor="middle" x="192.71" y="-216.1" font-family="Times New Roman,serif" font-size="14.00">S&#45;C</text>
104 </g>
105 <!-- student&#45;&#45;S&#45;C -->
106 <g id="edge11" class="edge">
107 <title>student&#45;&#45;S&#45;C</title>
108 <path fill="none" stroke="black" d="M141.62,-201.81C151.46,-205.28 162.28,-209.08 171.41,-212.3"/>
109 <text text-anchor="middle" x="151.02" y="-210.86" font-family="Times New Roman,serif" font-size="14.00">m</text>
110 </g>
111 <!-- name0 -->
112 <g id="node4" class="node">
113 <title>name0</title>
114 <ellipse fill="none" stroke="black" cx="299.39" cy="-344.01" rx="29.8" ry="18"/>
115 <text text-anchor="middle" x="299.39" y="-340.31" font-family="Times New Roman,serif" font-size="14.00">name</text>
116 </g>
117 <!-- name0&#45;&#45;course -->
118 <g id="edge1" class="edge">
119 <title>name0&#45;&#45;course</title>
120 <path fill="none" stroke="black" d="M283.43,-328.78C276.27,-321.94 267.76,-313.82 260.25,-306.65"/>
121 </g>
122 <!-- code -->
123 <g id="node7" class="node">
124 <title>code</title>
125 <ellipse fill="none" stroke="black" cx="314.94" cy="-253.19" rx="28.7" ry="18"/>
126 <text text-anchor="middle" x="314.94" y="-249.49" font-family="Times New Roman,serif" font-size="14.00">code</text>
127 </g>
128 <!-- code&#45;&#45;course -->
129 <g id="edge2" class="edge">
130 <title>code&#45;&#45;course</title>
131 <path fill="none" stroke="black" d="M291.95,-264.09C284.4,-267.67 275.94,-271.68 268.11,-275.39"/>
132 </g>
133 <!-- C&#45;I&#45;&#45;institute -->
134 <g id="edge4" class="edge">
135 <title>C&#45;I&#45;&#45;institute</title>
136 <path fill="none" stroke="black" d="M160.87,-351.35C152.85,-350.5 144.06,-349.56 135.9,-348.69"/>
137 <text text-anchor="middle" x="144.88" y="-353.82" font-family="Times New Roman,serif" font-size="14.00">1</text>
138 </g>
139 <!-- S&#45;C&#45;&#45;course -->
140 <g id="edge12" class="edge">
141 <title>S&#45;C&#45;&#45;course</title>
142 <path fill="none" stroke="black" d="M202.24,-233.33C209.66,-243.85 220.03,-258.55 228.17,-270.1"/>
143 <text text-anchor="middle" x="211.71" y="-255.51" font-family="Times New Roman,serif" font-size="14.00">n</text>
144 </g>
145 <!-- S&#45;I&#45;&#45;student -->
146 <g id="edge7" class="edge">
147 <title>S&#45;I&#45;&#45;student</title>
148 <path fill="none" stroke="black" d="M83.94,-254.18C89.72,-241.63 98.12,-223.41 104.36,-209.87"/>
149 <text text-anchor="middle" x="90.65" y="-235.83" font-family="Times New Roman,serif" font-size="14.00">n</text>
150 </g>
151 </g>
152 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: %3 Pages: 1 -->
6 <svg width="170pt" height="83pt"
7 viewBox="0.00 0.00 170.25 82.95" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 78.9533)">
9 <title>%3</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-78.9533 166.255,-78.9533 166.255,4 -4,4"/>
11 <!-- backslash -->
12 <g id="node1" class="node"><title>backslash</title>
13 <ellipse fill="none" stroke="black" cx="27" cy="-37.4767" rx="27" ry="18"/>
14 <text text-anchor="middle" x="27" y="-33.7767" font-family="Times New Roman,serif" font-size="14.00">\</text>
15 </g>
16 <!-- multi_line -->
17 <g id="node2" class="node"><title>multi_line</title>
18 <ellipse fill="none" stroke="black" cx="117" cy="-37.4767" rx="45.011" ry="37.4533"/>
19 <text text-anchor="middle" x="117" y="-48.7767" font-family="Times New Roman,serif" font-size="14.00">centered</text>
20 <text text-anchor="start" x="93" y="-33.7767" font-family="Times New Roman,serif" font-size="14.00">left</text>
21 <text text-anchor="end" x="141" y="-18.7767" font-family="Times New Roman,serif" font-size="14.00">right</text>
22 </g>
23 </g>
24 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="170pt" height="83pt"
7 viewBox="0.00 0.00 170.25 82.95" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 78.95)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-78.95 166.25,-78.95 166.25,4 -4,4"/>
10 <!-- backslash -->
11 <g id="node1" class="node">
12 <title>backslash</title>
13 <ellipse fill="none" stroke="black" cx="27" cy="-37.48" rx="27" ry="18"/>
14 <text text-anchor="middle" x="27" y="-33.78" font-family="Times New Roman,serif" font-size="14.00">\</text>
15 </g>
16 <!-- multi_line -->
17 <g id="node2" class="node">
18 <title>multi_line</title>
19 <ellipse fill="none" stroke="black" cx="117" cy="-37.48" rx="45.01" ry="37.45"/>
20 <text text-anchor="middle" x="117" y="-48.78" font-family="Times New Roman,serif" font-size="14.00">centered</text>
21 <text text-anchor="start" x="93" y="-33.78" font-family="Times New Roman,serif" font-size="14.00">left</text>
22 <text text-anchor="end" x="141" y="-18.78" font-family="Times New Roman,serif" font-size="14.00">right</text>
23 </g>
24 </g>
25 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="358pt" height="228pt"
7 viewBox="0.00 0.00 358.00 228.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 224)">
9 <title>G</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-224 354,-224 354,4 -4,4"/>
11 <g id="clust1" class="cluster"><title>clusterA</title>
12 <polygon fill="none" stroke="black" points="-0.286448,0.321491 -0.286448,-114.679 205.714,-114.679 205.714,0.321491 -0.286448,0.321491"/>
13 </g>
14 <g id="clust2" class="cluster"><title>clusterC</title>
15 <polygon fill="none" stroke="black" points="20.8944,-7.98378 20.8944,-106.984 91.8944,-106.984 91.8944,-7.98378 20.8944,-7.98378"/>
16 </g>
17 <g id="clust3" class="cluster"><title>clusterB</title>
18 <polygon fill="none" stroke="black" points="173.23,-122.813 173.23,-219.813 284.23,-219.813 284.23,-122.813 173.23,-122.813"/>
19 </g>
20 <!-- e -->
21 <g id="node1" class="node"><title>e</title>
22 <ellipse fill="none" stroke="black" cx="322.521" cy="-65.7223" rx="27" ry="18"/>
23 <text text-anchor="middle" x="322.521" y="-62.0223" font-family="Times New Roman,serif" font-size="14.00">e</text>
24 </g>
25 <!-- __0:clusterB -->
26 <!-- e&#45;&#45;__0:clusterB -->
27 <g id="edge7" class="edge"><title>e&#45;&#45;__0:clusterB</title>
28 <path fill="none" stroke="black" d="M308.682,-81.3026C298.898,-92.3171 285.209,-107.728 271.92,-122.69"/>
29 </g>
30 <!-- a -->
31 <g id="node2" class="node"><title>a</title>
32 <ellipse fill="none" stroke="black" cx="134.278" cy="-26.0511" rx="27" ry="18"/>
33 <text text-anchor="middle" x="134.278" y="-22.3511" font-family="Times New Roman,serif" font-size="14.00">a</text>
34 </g>
35 <!-- b -->
36 <g id="node3" class="node"><title>b</title>
37 <ellipse fill="none" stroke="black" cx="170.748" cy="-72.6047" rx="27" ry="18"/>
38 <text text-anchor="middle" x="170.748" y="-68.9047" font-family="Times New Roman,serif" font-size="14.00">b</text>
39 </g>
40 <!-- a&#45;&#45;b -->
41 <g id="edge1" class="edge"><title>a&#45;&#45;b</title>
42 <path fill="none" stroke="black" d="M146.829,-42.0722C150.455,-46.7013 154.415,-51.7557 158.05,-56.396"/>
43 </g>
44 <!-- C -->
45 <g id="node4" class="node"><title>C</title>
46 <ellipse fill="none" stroke="black" cx="55.9968" cy="-80.5593" rx="27" ry="18"/>
47 <text text-anchor="middle" x="55.9968" y="-76.8593" font-family="Times New Roman,serif" font-size="14.00">C</text>
48 </g>
49 <!-- D -->
50 <g id="node5" class="node"><title>D</title>
51 <ellipse fill="none" stroke="black" cx="56.7927" cy="-34.0413" rx="27" ry="18"/>
52 <text text-anchor="middle" x="56.7927" y="-30.3413" font-family="Times New Roman,serif" font-size="14.00">D</text>
53 </g>
54 <!-- C&#45;&#45;D -->
55 <g id="edge2" class="edge"><title>C&#45;&#45;D</title>
56 <path fill="none" stroke="black" d="M56.3068,-62.441C56.3644,-59.0736 56.4246,-55.5549 56.4823,-52.1866"/>
57 </g>
58 <!-- d -->
59 <g id="node6" class="node"><title>d</title>
60 <ellipse fill="none" stroke="black" cx="207.825" cy="-148.66" rx="27" ry="18"/>
61 <text text-anchor="middle" x="207.825" y="-144.96" font-family="Times New Roman,serif" font-size="14.00">d</text>
62 </g>
63 <!-- d&#45;&#45;D -->
64 <g id="edge4" class="edge"><title>d&#45;&#45;D</title>
65 <path fill="none" stroke="black" d="M189.906,-135.062C160.839,-113.002 103.74,-69.67 74.6878,-47.622"/>
66 </g>
67 <!-- f -->
68 <g id="node7" class="node"><title>f</title>
69 <ellipse fill="none" stroke="black" cx="249.356" cy="-193.971" rx="27" ry="18"/>
70 <text text-anchor="middle" x="249.356" y="-190.271" font-family="Times New Roman,serif" font-size="14.00">f</text>
71 </g>
72 <!-- d&#45;&#45;f -->
73 <g id="edge3" class="edge"><title>d&#45;&#45;f</title>
74 <path fill="none" stroke="black" d="M222.117,-164.254C226.341,-168.861 230.961,-173.902 235.177,-178.502"/>
75 </g>
76 <!-- __1:clusterC -->
77 <!-- __2:clusterB -->
78 <!-- __1:clusterC&#45;&#45;__2:clusterB -->
79 <g id="edge8" class="edge"><title>__1:clusterC&#45;&#45;__2:clusterB</title>
80 <path fill="none" stroke="black" d="M92.1025,-81.0693C115.468,-96.5027 146.478,-116.984 173.047,-134.534"/>
81 </g>
82 </g>
83 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="376pt" height="298pt"
7 viewBox="0.00 0.00 376.00 298.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 294)">
9 <title>G</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-294 372,-294 372,4 -4,4"/>
11 <g id="clust1" class="cluster">
12 <title>clusterA</title>
13 <polygon fill="none" stroke="black" points="0.02,0.36 0.02,-214.64 187.02,-214.64 187.02,0.36 0.02,0.36"/>
14 </g>
15 <g id="clust2" class="cluster">
16 <title>clusterC</title>
17 <polygon fill="none" stroke="black" points="108.23,-107.64 108.23,-206.64 179.23,-206.64 179.23,-107.64 108.23,-107.64"/>
18 </g>
19 <g id="clust3" class="cluster">
20 <title>clusterB</title>
21 <polygon fill="none" stroke="black" points="200.19,-193.25 200.19,-290.25 311.19,-290.25 311.19,-193.25 200.19,-193.25"/>
22 </g>
23 <!-- e -->
24 <g id="node1" class="node">
25 <title>e</title>
26 <ellipse fill="none" stroke="black" cx="340.72" cy="-129.63" rx="27" ry="18"/>
27 <text text-anchor="middle" x="340.72" y="-125.93" font-family="Times New Roman,serif" font-size="14.00">e</text>
28 </g>
29 <!-- __0:clusterB -->
30 <!-- e&#45;&#45;__0:clusterB -->
31 <g id="edge7" class="edge">
32 <title>e&#45;&#45;__0:clusterB</title>
33 <path fill="none" stroke="black" d="M328.53,-145.69C319.07,-158.17 305.43,-176.15 292.51,-193.19"/>
34 </g>
35 <!-- a -->
36 <g id="node2" class="node">
37 <title>a</title>
38 <ellipse fill="none" stroke="black" cx="34.58" cy="-26.01" rx="27" ry="18"/>
39 <text text-anchor="middle" x="34.58" y="-22.31" font-family="Times New Roman,serif" font-size="14.00">a</text>
40 </g>
41 <!-- b -->
42 <g id="node3" class="node">
43 <title>b</title>
44 <ellipse fill="none" stroke="black" cx="71.05" cy="-72.56" rx="27" ry="18"/>
45 <text text-anchor="middle" x="71.05" y="-68.86" font-family="Times New Roman,serif" font-size="14.00">b</text>
46 </g>
47 <!-- a&#45;&#45;b -->
48 <g id="edge1" class="edge">
49 <title>a&#45;&#45;b</title>
50 <path fill="none" stroke="black" d="M47.13,-42.03C50.76,-46.66 54.72,-51.71 58.36,-56.36"/>
51 </g>
52 <!-- C -->
53 <g id="node4" class="node">
54 <title>C</title>
55 <ellipse fill="none" stroke="black" cx="143.34" cy="-180.22" rx="27" ry="18"/>
56 <text text-anchor="middle" x="143.34" y="-176.52" font-family="Times New Roman,serif" font-size="14.00">C</text>
57 </g>
58 <!-- D -->
59 <g id="node5" class="node">
60 <title>D</title>
61 <ellipse fill="none" stroke="black" cx="144.13" cy="-133.7" rx="27" ry="18"/>
62 <text text-anchor="middle" x="144.13" y="-130" font-family="Times New Roman,serif" font-size="14.00">D</text>
63 </g>
64 <!-- C&#45;&#45;D -->
65 <g id="edge2" class="edge">
66 <title>C&#45;&#45;D</title>
67 <path fill="none" stroke="black" d="M143.65,-162.1C143.7,-158.73 143.76,-155.21 143.82,-151.85"/>
68 </g>
69 <!-- d -->
70 <g id="node6" class="node">
71 <title>d</title>
72 <ellipse fill="none" stroke="black" cx="234.78" cy="-219.09" rx="27" ry="18"/>
73 <text text-anchor="middle" x="234.78" y="-215.39" font-family="Times New Roman,serif" font-size="14.00">d</text>
74 </g>
75 <!-- d&#45;&#45;D -->
76 <g id="edge4" class="edge">
77 <title>d&#45;&#45;D</title>
78 <path fill="none" stroke="black" d="M218.99,-204.22C202.35,-188.55 176.31,-164.01 159.74,-148.4"/>
79 </g>
80 <!-- f -->
81 <g id="node7" class="node">
82 <title>f</title>
83 <ellipse fill="none" stroke="black" cx="276.31" cy="-264.41" rx="27" ry="18"/>
84 <text text-anchor="middle" x="276.31" y="-260.71" font-family="Times New Roman,serif" font-size="14.00">f</text>
85 </g>
86 <!-- d&#45;&#45;f -->
87 <g id="edge3" class="edge">
88 <title>d&#45;&#45;f</title>
89 <path fill="none" stroke="black" d="M249.08,-234.69C253.3,-239.3 257.92,-244.34 262.14,-248.94"/>
90 </g>
91 <!-- __1:clusterC -->
92 <!-- __2:clusterB -->
93 <!-- __1:clusterC&#45;&#45;__2:clusterB -->
94 <g id="edge8" class="edge">
95 <title>__1:clusterC&#45;&#45;__2:clusterB</title>
96 <path fill="none" stroke="black" d="M179.47,-184.14C185.99,-189.08 192.94,-194.33 199.89,-199.58"/>
97 </g>
98 </g>
99 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: finite_state_machine Pages: 1 -->
6 <svg width="576pt" height="258pt"
7 viewBox="0.00 0.00 576.00 258.45" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(0.769883 0.769883) rotate(0) translate(4 331.694)">
9 <title>finite_state_machine</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-331.694 744.166,-331.694 744.166,4 -4,4"/>
11 <!-- LR_0 -->
12 <g id="node1" class="node"><title>LR_0</title>
13 <ellipse fill="none" stroke="black" cx="35.8472" cy="-106.847" rx="31.712" ry="31.712"/>
14 <ellipse fill="none" stroke="black" cx="35.8472" cy="-106.847" rx="35.695" ry="35.695"/>
15 <text text-anchor="middle" x="35.8472" y="-103.147" font-family="Times New Roman,serif" font-size="14.00">LR_0</text>
16 </g>
17 <!-- LR_2 -->
18 <g id="node5" class="node"><title>LR_2</title>
19 <ellipse fill="none" stroke="black" cx="174.542" cy="-146.847" rx="31.6951" ry="31.6951"/>
20 <text text-anchor="middle" x="174.542" y="-143.147" font-family="Times New Roman,serif" font-size="14.00">LR_2</text>
21 </g>
22 <!-- LR_0&#45;&gt;LR_2 -->
23 <g id="edge1" class="edge"><title>LR_0&#45;&gt;LR_2</title>
24 <path fill="none" stroke="black" d="M70.6368,-116.735C89.8449,-122.356 113.995,-129.422 134.071,-135.297"/>
25 <polygon fill="black" stroke="black" points="133.274,-138.711 143.855,-138.16 135.24,-131.992 133.274,-138.711"/>
26 <text text-anchor="middle" x="107.194" y="-135.647" font-family="Times New Roman,serif" font-size="14.00">SS(B)</text>
27 </g>
28 <!-- LR_1 -->
29 <g id="node6" class="node"><title>LR_1</title>
30 <ellipse fill="none" stroke="black" cx="174.542" cy="-54.8472" rx="31.6951" ry="31.6951"/>
31 <text text-anchor="middle" x="174.542" y="-51.1472" font-family="Times New Roman,serif" font-size="14.00">LR_1</text>
32 </g>
33 <!-- LR_0&#45;&gt;LR_1 -->
34 <g id="edge2" class="edge"><title>LR_0&#45;&gt;LR_1</title>
35 <path fill="none" stroke="black" d="M69.5889,-94.3919C89.2263,-86.9216 114.304,-77.3816 134.909,-69.5435"/>
36 <polygon fill="black" stroke="black" points="136.22,-72.7895 144.322,-65.9626 133.731,-66.2469 136.22,-72.7895"/>
37 <text text-anchor="middle" x="107.194" y="-89.6472" font-family="Times New Roman,serif" font-size="14.00">SS(S)</text>
38 </g>
39 <!-- LR_3 -->
40 <g id="node2" class="node"><title>LR_3</title>
41 <ellipse fill="none" stroke="black" cx="323.236" cy="-35.8472" rx="31.712" ry="31.712"/>
42 <ellipse fill="none" stroke="black" cx="323.236" cy="-35.8472" rx="35.695" ry="35.695"/>
43 <text text-anchor="middle" x="323.236" y="-32.1472" font-family="Times New Roman,serif" font-size="14.00">LR_3</text>
44 </g>
45 <!-- LR_4 -->
46 <g id="node3" class="node"><title>LR_4</title>
47 <ellipse fill="none" stroke="black" cx="323.236" cy="-291.847" rx="31.712" ry="31.712"/>
48 <ellipse fill="none" stroke="black" cx="323.236" cy="-291.847" rx="35.695" ry="35.695"/>
49 <text text-anchor="middle" x="323.236" y="-288.147" font-family="Times New Roman,serif" font-size="14.00">LR_4</text>
50 </g>
51 <!-- LR_8 -->
52 <g id="node4" class="node"><title>LR_8</title>
53 <ellipse fill="none" stroke="black" cx="704.319" cy="-147.847" rx="31.712" ry="31.712"/>
54 <ellipse fill="none" stroke="black" cx="704.319" cy="-147.847" rx="35.695" ry="35.695"/>
55 <text text-anchor="middle" x="704.319" y="-144.147" font-family="Times New Roman,serif" font-size="14.00">LR_8</text>
56 </g>
57 <!-- LR_6 -->
58 <g id="node7" class="node"><title>LR_6</title>
59 <ellipse fill="none" stroke="black" cx="323.236" cy="-172.847" rx="31.6951" ry="31.6951"/>
60 <text text-anchor="middle" x="323.236" y="-169.147" font-family="Times New Roman,serif" font-size="14.00">LR_6</text>
61 </g>
62 <!-- LR_8&#45;&gt;LR_6 -->
63 <g id="edge13" class="edge"><title>LR_8&#45;&gt;LR_6</title>
64 <path fill="none" stroke="black" d="M669.127,-154.782C625.934,-163.158 549.217,-176.756 482.777,-181.847 454.552,-184.01 447.36,-183.186 419.083,-181.847 401.296,-181.005 381.696,-179.28 364.953,-177.563"/>
65 <polygon fill="black" stroke="black" points="365.251,-174.075 354.939,-176.503 364.515,-181.036 365.251,-174.075"/>
66 <text text-anchor="middle" x="513.277" y="-184.647" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
67 </g>
68 <!-- LR_5 -->
69 <g id="node8" class="node"><title>LR_5</title>
70 <ellipse fill="none" stroke="black" cx="450.93" cy="-107.847" rx="31.6951" ry="31.6951"/>
71 <text text-anchor="middle" x="450.93" y="-104.147" font-family="Times New Roman,serif" font-size="14.00">LR_5</text>
72 </g>
73 <!-- LR_8&#45;&gt;LR_5 -->
74 <g id="edge14" class="edge"><title>LR_8&#45;&gt;LR_5</title>
75 <path fill="none" stroke="black" d="M668.545,-142.414C628.191,-136.095 559.65,-125.319 500.777,-115.847 498.086,-115.414 495.312,-114.966 492.517,-114.512"/>
76 <polygon fill="black" stroke="black" points="492.845,-111.02 482.413,-112.867 491.72,-117.929 492.845,-111.02"/>
77 <text text-anchor="middle" x="575.625" y="-137.647" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
78 </g>
79 <!-- LR_2&#45;&gt;LR_4 -->
80 <g id="edge6" class="edge"><title>LR_2&#45;&gt;LR_4</title>
81 <path fill="none" stroke="black" d="M197.821,-168.87C222.322,-193.087 261.915,-232.223 289.846,-259.831"/>
82 <polygon fill="black" stroke="black" points="287.463,-262.397 297.035,-266.938 292.384,-257.418 287.463,-262.397"/>
83 <text text-anchor="middle" x="246.889" y="-239.647" font-family="Times New Roman,serif" font-size="14.00">S(A)</text>
84 </g>
85 <!-- LR_2&#45;&gt;LR_6 -->
86 <g id="edge4" class="edge"><title>LR_2&#45;&gt;LR_6</title>
87 <path fill="none" stroke="black" d="M205.937,-152.234C227.893,-156.126 257.777,-161.422 281.754,-165.672"/>
88 <polygon fill="black" stroke="black" points="281.17,-169.123 291.628,-167.422 282.392,-162.231 281.17,-169.123"/>
89 <text text-anchor="middle" x="246.889" y="-167.647" font-family="Times New Roman,serif" font-size="14.00">SS(b)</text>
90 </g>
91 <!-- LR_2&#45;&gt;LR_5 -->
92 <g id="edge5" class="edge"><title>LR_2&#45;&gt;LR_5</title>
93 <path fill="none" stroke="black" d="M205.087,-137.127C227.428,-130.219 259.001,-121.39 287.389,-116.847 328.309,-110.299 375.679,-108.299 408.684,-107.786"/>
94 <polygon fill="black" stroke="black" points="408.911,-111.284 418.87,-107.668 408.829,-104.284 408.911,-111.284"/>
95 <text text-anchor="middle" x="323.236" y="-120.647" font-family="Times New Roman,serif" font-size="14.00">SS(a)</text>
96 </g>
97 <!-- LR_1&#45;&gt;LR_3 -->
98 <g id="edge3" class="edge"><title>LR_1&#45;&gt;LR_3</title>
99 <path fill="none" stroke="black" d="M206.293,-50.8642C226.839,-48.2031 254.208,-44.6582 277.196,-41.6808"/>
100 <polygon fill="black" stroke="black" points="277.941,-45.1136 287.409,-40.358 277.042,-38.1716 277.941,-45.1136"/>
101 <text text-anchor="middle" x="246.889" y="-52.6472" font-family="Times New Roman,serif" font-size="14.00">S($end)</text>
102 </g>
103 <!-- LR_6&#45;&gt;LR_6 -->
104 <g id="edge9" class="edge"><title>LR_6&#45;&gt;LR_6</title>
105 <path fill="none" stroke="black" d="M311.262,-202.528C310.87,-213.589 314.861,-222.694 323.236,-222.694 328.863,-222.694 332.511,-218.584 334.18,-212.532"/>
106 <polygon fill="black" stroke="black" points="337.667,-212.834 335.21,-202.528 330.704,-212.117 337.667,-212.834"/>
107 <text text-anchor="middle" x="323.236" y="-226.494" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
108 </g>
109 <!-- LR_6&#45;&gt;LR_5 -->
110 <g id="edge10" class="edge"><title>LR_6&#45;&gt;LR_5</title>
111 <path fill="none" stroke="black" d="M351.82,-158.583C369.912,-149.227 393.768,-136.89 413.426,-126.724"/>
112 <polygon fill="black" stroke="black" points="415.136,-129.781 422.41,-122.078 411.92,-123.563 415.136,-129.781"/>
113 <text text-anchor="middle" x="389.083" y="-148.647" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
114 </g>
115 <!-- LR_5&#45;&gt;LR_5 -->
116 <g id="edge8" class="edge"><title>LR_5&#45;&gt;LR_5</title>
117 <path fill="none" stroke="black" d="M439.691,-138.022C439.45,-148.859 443.196,-157.694 450.93,-157.694 456.006,-157.694 459.364,-153.889 461.005,-148.211"/>
118 <polygon fill="black" stroke="black" points="464.511,-148.355 462.169,-138.022 457.556,-147.56 464.511,-148.355"/>
119 <text text-anchor="middle" x="450.93" y="-161.494" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
120 </g>
121 <!-- LR_7 -->
122 <g id="node9" class="node"><title>LR_7</title>
123 <ellipse fill="none" stroke="black" cx="575.625" cy="-79.8472" rx="31.6951" ry="31.6951"/>
124 <text text-anchor="middle" x="575.625" y="-76.1472" font-family="Times New Roman,serif" font-size="14.00">LR_7</text>
125 </g>
126 <!-- LR_5&#45;&gt;LR_7 -->
127 <g id="edge7" class="edge"><title>LR_5&#45;&gt;LR_7</title>
128 <path fill="none" stroke="black" d="M482.259,-100.926C497.891,-97.3585 517.169,-92.959 534.063,-89.1037"/>
129 <polygon fill="black" stroke="black" points="535.249,-92.4232 544.219,-86.7859 533.691,-85.5986 535.249,-92.4232"/>
130 <text text-anchor="middle" x="513.277" y="-100.647" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
131 </g>
132 <!-- LR_7&#45;&gt;LR_8 -->
133 <g id="edge11" class="edge"><title>LR_7&#45;&gt;LR_8</title>
134 <path fill="none" stroke="black" d="M604.384,-94.3732C618.255,-101.666 635.28,-110.668 650.472,-118.847 654.739,-121.145 659.192,-123.56 663.624,-125.976"/>
135 <polygon fill="black" stroke="black" points="662.172,-129.17 672.625,-130.896 665.529,-123.028 662.172,-129.17"/>
136 <text text-anchor="middle" x="637.972" y="-122.647" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
137 </g>
138 <!-- LR_7&#45;&gt;LR_5 -->
139 <g id="edge12" class="edge"><title>LR_7&#45;&gt;LR_5</title>
140 <path fill="none" stroke="black" d="M544.569,-71.6302C530.928,-69.2535 514.755,-68.3565 500.777,-72.8472 494.781,-74.7738 488.895,-77.7384 483.403,-81.1443"/>
141 <polygon fill="black" stroke="black" points="481.431,-78.2524 475.135,-86.7737 485.371,-84.0385 481.431,-78.2524"/>
142 <text text-anchor="middle" x="513.277" y="-76.6472" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
143 </g>
144 </g>
145 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: finite_state_machine Pages: 1 -->
6 <svg width="576pt" height="258pt"
7 viewBox="0.00 0.00 576.00 258.45" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(0.77 0.77) rotate(0) translate(4 331.69)">
9 <title>finite_state_machine</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-331.69 744.17,-331.69 744.17,4 -4,4"/>
11 <!-- LR_0 -->
12 <g id="node1" class="node">
13 <title>LR_0</title>
14 <ellipse fill="none" stroke="black" cx="35.85" cy="-83.85" rx="31.71" ry="31.71"/>
15 <ellipse fill="none" stroke="black" cx="35.85" cy="-83.85" rx="35.69" ry="35.69"/>
16 <text text-anchor="middle" x="35.85" y="-80.15" font-family="Times New Roman,serif" font-size="14.00">LR_0</text>
17 </g>
18 <!-- LR_2 -->
19 <g id="node5" class="node">
20 <title>LR_2</title>
21 <ellipse fill="none" stroke="black" cx="174.54" cy="-151.85" rx="31.7" ry="31.7"/>
22 <text text-anchor="middle" x="174.54" y="-148.15" font-family="Times New Roman,serif" font-size="14.00">LR_2</text>
23 </g>
24 <!-- LR_0&#45;&gt;LR_2 -->
25 <g id="edge1" class="edge">
26 <title>LR_0&#45;&gt;LR_2</title>
27 <path fill="none" stroke="black" d="M68.21,-99.45C88.53,-109.56 115.1,-122.77 136.47,-133.4"/>
28 <polygon fill="black" stroke="black" points="135.06,-136.61 145.58,-137.94 138.18,-130.35 135.06,-136.61"/>
29 <text text-anchor="middle" x="107.19" y="-129.65" font-family="Times New Roman,serif" font-size="14.00">SS(B)</text>
30 </g>
31 <!-- LR_1 -->
32 <g id="node6" class="node">
33 <title>LR_1</title>
34 <ellipse fill="none" stroke="black" cx="174.54" cy="-42.85" rx="31.7" ry="31.7"/>
35 <text text-anchor="middle" x="174.54" y="-39.15" font-family="Times New Roman,serif" font-size="14.00">LR_1</text>
36 </g>
37 <!-- LR_0&#45;&gt;LR_1 -->
38 <g id="edge2" class="edge">
39 <title>LR_0&#45;&gt;LR_1</title>
40 <path fill="none" stroke="black" d="M70.29,-73.82C89.49,-68.06 113.72,-60.79 133.88,-54.74"/>
41 <polygon fill="black" stroke="black" points="135.13,-58.02 143.7,-51.8 133.12,-51.32 135.13,-58.02"/>
42 <text text-anchor="middle" x="107.19" y="-71.65" font-family="Times New Roman,serif" font-size="14.00">SS(S)</text>
43 </g>
44 <!-- LR_3 -->
45 <g id="node2" class="node">
46 <title>LR_3</title>
47 <ellipse fill="none" stroke="black" cx="323.24" cy="-35.85" rx="31.71" ry="31.71"/>
48 <ellipse fill="none" stroke="black" cx="323.24" cy="-35.85" rx="35.69" ry="35.69"/>
49 <text text-anchor="middle" x="323.24" y="-32.15" font-family="Times New Roman,serif" font-size="14.00">LR_3</text>
50 </g>
51 <!-- LR_4 -->
52 <g id="node3" class="node">
53 <title>LR_4</title>
54 <ellipse fill="none" stroke="black" cx="323.24" cy="-291.85" rx="31.71" ry="31.71"/>
55 <ellipse fill="none" stroke="black" cx="323.24" cy="-291.85" rx="35.69" ry="35.69"/>
56 <text text-anchor="middle" x="323.24" y="-288.15" font-family="Times New Roman,serif" font-size="14.00">LR_4</text>
57 </g>
58 <!-- LR_8 -->
59 <g id="node4" class="node">
60 <title>LR_8</title>
61 <ellipse fill="none" stroke="black" cx="704.32" cy="-152.85" rx="31.71" ry="31.71"/>
62 <ellipse fill="none" stroke="black" cx="704.32" cy="-152.85" rx="35.69" ry="35.69"/>
63 <text text-anchor="middle" x="704.32" y="-149.15" font-family="Times New Roman,serif" font-size="14.00">LR_8</text>
64 </g>
65 <!-- LR_6 -->
66 <g id="node7" class="node">
67 <title>LR_6</title>
68 <ellipse fill="none" stroke="black" cx="323.24" cy="-172.85" rx="31.7" ry="31.7"/>
69 <text text-anchor="middle" x="323.24" y="-169.15" font-family="Times New Roman,serif" font-size="14.00">LR_6</text>
70 </g>
71 <!-- LR_8&#45;&gt;LR_6 -->
72 <g id="edge13" class="edge">
73 <title>LR_8&#45;&gt;LR_6</title>
74 <path fill="none" stroke="black" d="M668.7,-158.83C625.38,-165.98 548.87,-177.52 482.78,-181.85 454.53,-183.7 447.36,-183.19 419.08,-181.85 401.3,-181.01 381.7,-179.28 364.95,-177.56"/>
75 <polygon fill="black" stroke="black" points="365.25,-174.07 354.94,-176.5 364.51,-181.04 365.25,-174.07"/>
76 <text text-anchor="middle" x="513.28" y="-183.65" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
77 </g>
78 <!-- LR_5 -->
79 <g id="node8" class="node">
80 <title>LR_5</title>
81 <ellipse fill="none" stroke="black" cx="450.93" cy="-107.85" rx="31.7" ry="31.7"/>
82 <text text-anchor="middle" x="450.93" y="-104.15" font-family="Times New Roman,serif" font-size="14.00">LR_5</text>
83 </g>
84 <!-- LR_8&#45;&gt;LR_5 -->
85 <g id="edge14" class="edge">
86 <title>LR_8&#45;&gt;LR_5</title>
87 <path fill="none" stroke="black" d="M668.83,-147.36C628.46,-140.82 559.62,-129.34 500.78,-117.85 497.99,-117.3 495.11,-116.73 492.22,-116.15"/>
88 <polygon fill="black" stroke="black" points="492.89,-112.72 482.4,-114.17 491.51,-119.58 492.89,-112.72"/>
89 <text text-anchor="middle" x="575.62" y="-139.65" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
90 </g>
91 <!-- LR_2&#45;&gt;LR_4 -->
92 <g id="edge6" class="edge">
93 <title>LR_2&#45;&gt;LR_4</title>
94 <path fill="none" stroke="black" d="M198.14,-173.42C222.46,-196.62 261.37,-233.76 289.13,-260.26"/>
95 <polygon fill="black" stroke="black" points="287,-263.06 296.65,-267.43 291.83,-257.99 287,-263.06"/>
96 <text text-anchor="middle" x="246.89" y="-241.65" font-family="Times New Roman,serif" font-size="14.00">S(A)</text>
97 </g>
98 <!-- LR_2&#45;&gt;LR_6 -->
99 <g id="edge4" class="edge">
100 <title>LR_2&#45;&gt;LR_6</title>
101 <path fill="none" stroke="black" d="M206.29,-156.25C228.1,-159.37 257.6,-163.59 281.38,-167"/>
102 <polygon fill="black" stroke="black" points="281.13,-170.5 291.52,-168.45 282.12,-163.57 281.13,-170.5"/>
103 <text text-anchor="middle" x="246.89" y="-167.65" font-family="Times New Roman,serif" font-size="14.00">SS(b)</text>
104 </g>
105 <!-- LR_2&#45;&gt;LR_5 -->
106 <g id="edge5" class="edge">
107 <title>LR_2&#45;&gt;LR_5</title>
108 <path fill="none" stroke="black" d="M204.48,-140.61C226.77,-132.49 258.56,-122.07 287.39,-116.85 328.17,-109.46 375.56,-107.58 408.61,-107.32"/>
109 <polygon fill="black" stroke="black" points="408.82,-110.82 418.81,-107.29 408.8,-103.82 408.82,-110.82"/>
110 <text text-anchor="middle" x="323.24" y="-120.65" font-family="Times New Roman,serif" font-size="14.00">SS(a)</text>
111 </g>
112 <!-- LR_1&#45;&gt;LR_3 -->
113 <g id="edge3" class="edge">
114 <title>LR_1&#45;&gt;LR_3</title>
115 <path fill="none" stroke="black" d="M206.65,-41.36C227.15,-40.38 254.31,-39.09 277.16,-38"/>
116 <polygon fill="black" stroke="black" points="277.49,-41.49 287.31,-37.51 277.16,-34.49 277.49,-41.49"/>
117 <text text-anchor="middle" x="246.89" y="-44.65" font-family="Times New Roman,serif" font-size="14.00">S($end)</text>
118 </g>
119 <!-- LR_6&#45;&gt;LR_6 -->
120 <g id="edge9" class="edge">
121 <title>LR_6&#45;&gt;LR_6</title>
122 <path fill="none" stroke="black" d="M311.26,-202.53C310.87,-213.59 314.86,-222.69 323.24,-222.69 328.86,-222.69 332.51,-218.58 334.18,-212.53"/>
123 <polygon fill="black" stroke="black" points="337.67,-212.83 335.21,-202.53 330.7,-212.12 337.67,-212.83"/>
124 <text text-anchor="middle" x="323.24" y="-226.49" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
125 </g>
126 <!-- LR_6&#45;&gt;LR_5 -->
127 <g id="edge10" class="edge">
128 <title>LR_6&#45;&gt;LR_5</title>
129 <path fill="none" stroke="black" d="M351.82,-158.58C369.91,-149.23 393.77,-136.89 413.43,-126.72"/>
130 <polygon fill="black" stroke="black" points="415.14,-129.78 422.41,-122.08 411.92,-123.56 415.14,-129.78"/>
131 <text text-anchor="middle" x="389.08" y="-147.65" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
132 </g>
133 <!-- LR_5&#45;&gt;LR_5 -->
134 <g id="edge8" class="edge">
135 <title>LR_5&#45;&gt;LR_5</title>
136 <path fill="none" stroke="black" d="M439.69,-138.02C439.45,-148.86 443.2,-157.69 450.93,-157.69 456.01,-157.69 459.36,-153.89 461,-148.21"/>
137 <polygon fill="black" stroke="black" points="464.51,-148.35 462.17,-138.02 457.56,-147.56 464.51,-148.35"/>
138 <text text-anchor="middle" x="450.93" y="-161.49" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
139 </g>
140 <!-- LR_7 -->
141 <g id="node9" class="node">
142 <title>LR_7</title>
143 <ellipse fill="none" stroke="black" cx="575.62" cy="-84.85" rx="31.7" ry="31.7"/>
144 <text text-anchor="middle" x="575.62" y="-81.15" font-family="Times New Roman,serif" font-size="14.00">LR_7</text>
145 </g>
146 <!-- LR_5&#45;&gt;LR_7 -->
147 <g id="edge7" class="edge">
148 <title>LR_5&#45;&gt;LR_7</title>
149 <path fill="none" stroke="black" d="M482.57,-102.1C498.09,-99.19 517.14,-95.62 533.88,-92.49"/>
150 <polygon fill="black" stroke="black" points="534.76,-95.88 543.95,-90.6 533.47,-89 534.76,-95.88"/>
151 <text text-anchor="middle" x="513.28" y="-102.65" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
152 </g>
153 <!-- LR_7&#45;&gt;LR_8 -->
154 <g id="edge11" class="edge">
155 <title>LR_7&#45;&gt;LR_8</title>
156 <path fill="none" stroke="black" d="M604.38,-99.37C618.26,-106.67 635.28,-115.67 650.47,-123.85 654.74,-126.14 659.19,-128.56 663.62,-130.98"/>
157 <polygon fill="black" stroke="black" points="662.17,-134.17 672.62,-135.9 665.53,-128.03 662.17,-134.17"/>
158 <text text-anchor="middle" x="637.97" y="-127.65" font-family="Times New Roman,serif" font-size="14.00">S(b)</text>
159 </g>
160 <!-- LR_7&#45;&gt;LR_5 -->
161 <g id="edge12" class="edge">
162 <title>LR_7&#45;&gt;LR_5</title>
163 <path fill="none" stroke="black" d="M545.05,-75.8C531.36,-72.99 515.01,-71.6 500.78,-75.85 495.43,-77.44 490.13,-79.83 485.1,-82.59"/>
164 <polygon fill="black" stroke="black" points="483.11,-79.7 476.38,-87.89 486.75,-85.69 483.11,-79.7"/>
165 <text text-anchor="middle" x="513.28" y="-79.65" font-family="Times New Roman,serif" font-size="14.00">S(a)</text>
166 </g>
167 </g>
168 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="94pt" height="122pt"
7 viewBox="0.00 0.00 94.00 122.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 118)">
9 <title>G</title>
10 <defs>
11 <linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="-4" y1="-57" x2="90" y2="-57" >
12 <stop offset="0" style="stop-color:purple;stop-opacity:1.;"/>
13 <stop offset="1" style="stop-color:pink;stop-opacity:1.;"/>
14 </linearGradient>
15 </defs>
16 <polygon fill="url(#l_0)" stroke="none" points="-4,4 -4,-118 90,-118 90,4 -4,4"/>
17 <text text-anchor="middle" x="43" y="-7.8" font-family="Times New Roman,serif" font-size="14.00" fill="white">agraph</text>
18 <g id="clust1" class="cluster"><title>cluster1</title>
19 <defs>
20 <linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="43" y1="-106" x2="43" y2="-31" >
21 <stop offset="0" style="stop-color:blue;stop-opacity:1.;"/>
22 <stop offset="1" style="stop-color:cyan;stop-opacity:1.;"/>
23 </linearGradient>
24 </defs>
25 <polygon fill="url(#l_1)" stroke="black" points="8,-31 8,-106 78,-106 78,-31 8,-31"/>
26 <text text-anchor="middle" x="43" y="-90.8" font-family="Times New Roman,serif" font-size="14.00" fill="white">acluster</text>
27 </g>
28 <!-- anode -->
29 <g id="node1" class="node"><title>anode</title>
30 <defs>
31 <linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="43" y1="-39" x2="43" y2="-75" >
32 <stop offset="0" style="stop-color:red;stop-opacity:1.;"/>
33 <stop offset="1" style="stop-color:yellow;stop-opacity:1.;"/>
34 </linearGradient>
35 </defs>
36 <polygon fill="url(#l_2)" stroke="black" points="70,-75 16,-75 16,-39 70,-39 70,-75"/>
37 <text text-anchor="middle" x="43" y="-53.3" font-family="Times New Roman,serif" font-size="14.00">anode</text>
38 </g>
39 </g>
40 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="94pt" height="122pt"
7 viewBox="0.00 0.00 94.00 122.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 118)">
9 <title>G</title>
10 <defs>
11 <linearGradient id="l_0" gradientUnits="userSpaceOnUse" x1="-4" y1="-57" x2="90" y2="-57" >
12 <stop offset="0" style="stop-color:purple;stop-opacity:1.;"/>
13 <stop offset="1" style="stop-color:pink;stop-opacity:1.;"/>
14 </linearGradient>
15 </defs>
16 <polygon fill="url(#l_0)" stroke="transparent" points="-4,4 -4,-118 90,-118 90,4 -4,4"/>
17 <text text-anchor="middle" x="43" y="-7.8" font-family="Times New Roman,serif" font-size="14.00" fill="white">agraph</text>
18 <g id="clust1" class="cluster">
19 <title>cluster1</title>
20 <defs>
21 <linearGradient id="l_1" gradientUnits="userSpaceOnUse" x1="43" y1="-106" x2="43" y2="-31" >
22 <stop offset="0" style="stop-color:blue;stop-opacity:1.;"/>
23 <stop offset="1" style="stop-color:cyan;stop-opacity:1.;"/>
24 </linearGradient>
25 </defs>
26 <polygon fill="url(#l_1)" stroke="black" points="8,-31 8,-106 78,-106 78,-31 8,-31"/>
27 <text text-anchor="middle" x="43" y="-90.8" font-family="Times New Roman,serif" font-size="14.00" fill="white">acluster</text>
28 </g>
29 <!-- anode -->
30 <g id="node1" class="node">
31 <title>anode</title>
32 <defs>
33 <linearGradient id="l_2" gradientUnits="userSpaceOnUse" x1="43" y1="-39" x2="43" y2="-75" >
34 <stop offset="0" style="stop-color:red;stop-opacity:1.;"/>
35 <stop offset="1" style="stop-color:yellow;stop-opacity:1.;"/>
36 </linearGradient>
37 </defs>
38 <polygon fill="url(#l_2)" stroke="black" points="70,-75 16,-75 16,-39 70,-39 70,-75"/>
39 <text text-anchor="middle" x="43" y="-53.3" font-family="Times New Roman,serif" font-size="14.00">anode</text>
40 </g>
41 </g>
42 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="77pt" height="116pt"
7 viewBox="0.00 0.00 76.89 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
9 <title>G</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-112 72.8939,-112 72.8939,4 -4,4"/>
11 <!-- Hello -->
12 <g id="node1" class="node"><title>Hello</title>
13 <ellipse fill="none" stroke="black" cx="34.4469" cy="-90" rx="29.795" ry="18"/>
14 <text text-anchor="middle" x="34.4469" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">Hello</text>
15 </g>
16 <!-- World -->
17 <g id="node2" class="node"><title>World</title>
18 <ellipse fill="none" stroke="black" cx="34.4469" cy="-18" rx="34.394" ry="18"/>
19 <text text-anchor="middle" x="34.4469" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">World</text>
20 </g>
21 <!-- Hello&#45;&gt;World -->
22 <g id="edge1" class="edge"><title>Hello&#45;&gt;World</title>
23 <path fill="none" stroke="black" d="M34.4469,-71.6966C34.4469,-63.9827 34.4469,-54.7125 34.4469,-46.1124"/>
24 <polygon fill="black" stroke="black" points="37.947,-46.1043 34.4469,-36.1043 30.947,-46.1044 37.947,-46.1043"/>
25 </g>
26 </g>
27 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="77pt" height="116pt"
7 viewBox="0.00 0.00 76.89 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
9 <title>G</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-112 72.89,-112 72.89,4 -4,4"/>
11 <!-- Hello -->
12 <g id="node1" class="node">
13 <title>Hello</title>
14 <ellipse fill="none" stroke="black" cx="34.45" cy="-90" rx="29.8" ry="18"/>
15 <text text-anchor="middle" x="34.45" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">Hello</text>
16 </g>
17 <!-- World -->
18 <g id="node2" class="node">
19 <title>World</title>
20 <ellipse fill="none" stroke="black" cx="34.45" cy="-18" rx="34.39" ry="18"/>
21 <text text-anchor="middle" x="34.45" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">World</text>
22 </g>
23 <!-- Hello&#45;&gt;World -->
24 <g id="edge1" class="edge">
25 <title>Hello&#45;&gt;World</title>
26 <path fill="none" stroke="black" d="M34.45,-71.7C34.45,-63.98 34.45,-54.71 34.45,-46.11"/>
27 <polygon fill="black" stroke="black" points="37.95,-46.1 34.45,-36.1 30.95,-46.1 37.95,-46.1"/>
28 </g>
29 </g>
30 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: the holy hand grenade Pages: 1 -->
6 <svg width="332pt" height="44pt"
7 viewBox="0.00 0.00 332.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
9 <title>the holy hand grenade</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-40 328,-40 328,4 -4,4"/>
11 <!-- 1 -->
12 <g id="node1" class="node"><title>1</title>
13 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
14 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">1</text>
15 </g>
16 <!-- 2 -->
17 <g id="node2" class="node"><title>2</title>
18 <ellipse fill="none" stroke="black" cx="117" cy="-18" rx="27" ry="18"/>
19 <text text-anchor="middle" x="117" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">2</text>
20 </g>
21 <!-- 1&#45;&gt;2 -->
22 <g id="edge1" class="edge"><title>1&#45;&gt;2</title>
23 <path fill="none" stroke="black" d="M54.4029,-18C62.3932,-18 71.3106,-18 79.8241,-18"/>
24 <polygon fill="black" stroke="black" points="79.919,-21.5001 89.919,-18 79.919,-14.5001 79.919,-21.5001"/>
25 </g>
26 <!-- 3 -->
27 <g id="node3" class="node"><title>3</title>
28 <ellipse fill="none" stroke="black" cx="207" cy="-18" rx="27" ry="18"/>
29 <text text-anchor="middle" x="207" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">3</text>
30 </g>
31 <!-- 2&#45;&gt;3 -->
32 <g id="edge2" class="edge"><title>2&#45;&gt;3</title>
33 <path fill="none" stroke="black" d="M144.403,-18C152.393,-18 161.311,-18 169.824,-18"/>
34 <polygon fill="black" stroke="black" points="169.919,-21.5001 179.919,-18 169.919,-14.5001 169.919,-21.5001"/>
35 </g>
36 <!-- lob -->
37 <g id="node4" class="node"><title>lob</title>
38 <ellipse fill="none" stroke="black" cx="297" cy="-18" rx="27" ry="18"/>
39 <text text-anchor="middle" x="297" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">lob</text>
40 </g>
41 <!-- 3&#45;&gt;lob -->
42 <g id="edge3" class="edge"><title>3&#45;&gt;lob</title>
43 <path fill="none" stroke="black" d="M234.403,-18C242.393,-18 251.311,-18 259.824,-18"/>
44 <polygon fill="black" stroke="black" points="259.919,-21.5001 269.919,-18 259.919,-14.5001 259.919,-21.5001"/>
45 </g>
46 </g>
47 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: the holy hand grenade Pages: 1 -->
6 <svg width="332pt" height="44pt"
7 viewBox="0.00 0.00 332.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
9 <title>the holy hand grenade</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-40 328,-40 328,4 -4,4"/>
11 <!-- 1 -->
12 <g id="node1" class="node">
13 <title>1</title>
14 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
15 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">1</text>
16 </g>
17 <!-- 2 -->
18 <g id="node2" class="node">
19 <title>2</title>
20 <ellipse fill="none" stroke="black" cx="117" cy="-18" rx="27" ry="18"/>
21 <text text-anchor="middle" x="117" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">2</text>
22 </g>
23 <!-- 1&#45;&gt;2 -->
24 <g id="edge1" class="edge">
25 <title>1&#45;&gt;2</title>
26 <path fill="none" stroke="black" d="M54.4,-18C62.39,-18 71.31,-18 79.82,-18"/>
27 <polygon fill="black" stroke="black" points="79.92,-21.5 89.92,-18 79.92,-14.5 79.92,-21.5"/>
28 </g>
29 <!-- 3 -->
30 <g id="node3" class="node">
31 <title>3</title>
32 <ellipse fill="none" stroke="black" cx="207" cy="-18" rx="27" ry="18"/>
33 <text text-anchor="middle" x="207" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">3</text>
34 </g>
35 <!-- 2&#45;&gt;3 -->
36 <g id="edge2" class="edge">
37 <title>2&#45;&gt;3</title>
38 <path fill="none" stroke="black" d="M144.4,-18C152.39,-18 161.31,-18 169.82,-18"/>
39 <polygon fill="black" stroke="black" points="169.92,-21.5 179.92,-18 169.92,-14.5 169.92,-21.5"/>
40 </g>
41 <!-- lob -->
42 <g id="node4" class="node">
43 <title>lob</title>
44 <ellipse fill="none" stroke="black" cx="297" cy="-18" rx="27" ry="18"/>
45 <text text-anchor="middle" x="297" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">lob</text>
46 </g>
47 <!-- 3&#45;&gt;lob -->
48 <g id="edge3" class="edge">
49 <title>3&#45;&gt;lob</title>
50 <path fill="none" stroke="black" d="M234.4,-18C242.39,-18 251.31,-18 259.82,-18"/>
51 <polygon fill="black" stroke="black" points="259.92,-21.5 269.92,-18 259.92,-14.5 259.92,-21.5"/>
52 </g>
53 </g>
54 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: html_table Pages: 1 -->
6 <svg width="120pt" height="57pt"
7 viewBox="0.00 0.00 119.72 57.50" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 53.4975)">
9 <title>html_table</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-53.4975 115.723,-53.4975 115.723,4 -4,4"/>
11 <!-- tab -->
12 <g id="node1" class="node"><title>tab</title>
13 <ellipse fill="none" stroke="black" cx="55.8614" cy="-24.7487" rx="55.7232" ry="25"/>
14 <polygon fill="none" stroke="black" points="27.8614,-13.7487 27.8614,-34.7487 51.8614,-34.7487 51.8614,-13.7487 27.8614,-13.7487"/>
15 <text text-anchor="start" x="30.8614" y="-20.5487" font-family="Times New Roman,serif" font-size="14.00">left</text>
16 <polygon fill="none" stroke="black" points="53.8614,-13.7487 53.8614,-34.7487 84.8614,-34.7487 84.8614,-13.7487 53.8614,-13.7487"/>
17 <text text-anchor="start" x="56.8614" y="-20.5487" font-family="Times New Roman,serif" font-size="14.00">right</text>
18 <polygon fill="none" stroke="black" points="24.3614,-11.2487 24.3614,-38.2487 87.3614,-38.2487 87.3614,-11.2487 24.3614,-11.2487"/>
19 </g>
20 </g>
21 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: html_table Pages: 1 -->
6 <svg width="120pt" height="57pt"
7 viewBox="0.00 0.00 119.72 57.50" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 53.5)">
9 <title>html_table</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-53.5 115.72,-53.5 115.72,4 -4,4"/>
11 <!-- tab -->
12 <g id="node1" class="node">
13 <title>tab</title>
14 <ellipse fill="none" stroke="black" cx="55.86" cy="-24.75" rx="55.72" ry="25"/>
15 <polygon fill="none" stroke="black" points="27.86,-13.75 27.86,-34.75 51.86,-34.75 51.86,-13.75 27.86,-13.75"/>
16 <text text-anchor="start" x="30.86" y="-20.55" font-family="Times New Roman,serif" font-size="14.00">left</text>
17 <polygon fill="none" stroke="black" points="53.86,-13.75 53.86,-34.75 84.86,-34.75 84.86,-13.75 53.86,-13.75"/>
18 <text text-anchor="start" x="56.86" y="-20.55" font-family="Times New Roman,serif" font-size="14.00">right</text>
19 <polygon fill="none" stroke="black" points="24.36,-11.25 24.36,-38.25 87.36,-38.25 87.36,-11.25 24.36,-11.25"/>
20 </g>
21 </g>
22 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: ni Pages: 1 -->
6 <svg width="522pt" height="105pt"
7 viewBox="0.00 0.00 522.37 105.43" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 101.43)">
9 <title>ni</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-101.43 518.374,-101.43 518.374,4 -4,4"/>
11 <!-- 1 -->
12 <g id="node1" class="node"><title>1</title>
13 <polygon fill="none" stroke="black" points="36,-60.7148 0,-60.7148 0,-36.7148 36,-36.7148 36,-30.7148 54,-48.7148 36,-66.7148 36,-60.7148"/>
14 <text text-anchor="middle" x="27" y="-45.0148" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
15 </g>
16 <!-- 2 -->
17 <g id="node2" class="node"><title>2</title>
18 <polygon fill="none" stroke="black" points="126,-60.7148 90,-60.7148 90,-36.7148 126,-36.7148 126,-30.7148 144,-48.7148 126,-66.7148 126,-60.7148"/>
19 <text text-anchor="middle" x="117" y="-45.0148" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
20 </g>
21 <!-- 1&#45;&#45;2 -->
22 <g id="edge1" class="edge"><title>1&#45;&#45;2</title>
23 <path fill="none" stroke="black" d="M54.4029,-48.7148C65.6421,-48.7148 78.7152,-48.7148 89.919,-48.7148"/>
24 </g>
25 <!-- 3 -->
26 <g id="node3" class="node"><title>3</title>
27 <polygon fill="none" stroke="black" points="211.426,-30.7641 213.202,-30.8627 214.96,-31.0101 216.692,-31.2061 218.391,-31.4501 220.052,-31.7414 221.666,-32.0792 223.228,-32.4627 224.732,-32.8907 226.172,-33.362 227.543,-33.8754 228.841,-34.4295 230.061,-35.0228 231.198,-35.6536 232.251,-36.3202 233.215,-37.0207 234.089,-37.7533 234.87,-38.516 235.558,-39.3066 236.151,-40.123 236.649,-40.9629 237.052,-41.8241 237.361,-42.7042 237.576,-43.6008 237.699,-44.5113 237.732,-45.4334 237.678,-46.3645 237.537,-47.302 237.315,-48.2434 237.012,-49.1861 236.633,-50.1275 236.182,-51.0651 235.662,-51.9961 235.076,-52.9182 234.429,-53.8288 233.724,-54.7254 232.966,-55.6054 232.158,-56.4666 231.305,-57.3066 230.409,-58.123 229.476,-58.9136 228.507,-59.6762 227.508,-60.4089 226.48,-61.1094 225.428,-61.776 224.353,-62.4068 223.26,-63 222.149,-63.5541 221.024,-64.0676 219.886,-64.5389 218.737,-64.9669 217.58,-65.3503 216.415,-65.6881 215.244,-65.9795 214.069,-66.2234 212.889,-66.4194 211.706,-66.5669 210.522,-66.6654 209.336,-66.7148 208.15,-66.7148 206.965,-66.6654 205.78,-66.5669 204.598,-66.4194 203.418,-66.2234 202.243,-65.9795 201.072,-65.6881 199.907,-65.3503 198.75,-64.9669 197.601,-64.5389 196.463,-64.0676 195.338,-63.5541 194.227,-63 193.134,-62.4068 192.059,-61.776 191.007,-61.1094 189.979,-60.4089 188.98,-59.6762 188.011,-58.9136 187.078,-58.123 186.182,-57.3066 185.329,-56.4666 184.521,-55.6054 183.763,-54.7254 183.058,-53.8288 182.411,-52.9182 181.825,-51.9961 181.305,-51.0651 180.853,-50.1275 180.475,-49.1861 180.172,-48.2434 179.949,-47.302 179.809,-46.3645 179.754,-45.4334 179.788,-44.5113 179.911,-43.6008 180.126,-42.7042 180.435,-41.8241 180.838,-40.9629 181.336,-40.123 181.929,-39.3066 182.617,-38.516 183.398,-37.7533 184.272,-37.0207 185.236,-36.3202 186.289,-35.6536 187.426,-35.0228 188.646,-34.4295 189.943,-33.8754 191.315,-33.362 192.755,-32.8907 194.259,-32.4627 195.821,-32.0792 197.435,-31.7414 199.095,-31.4501 200.795,-31.2061 202.527,-31.0101 204.285,-30.8627 206.061,-30.7641 207.848,-30.7148 209.639,-30.7148 211.426,-30.7641"/>
28 <text text-anchor="middle" x="208.743" y="-45.0148" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
29 </g>
30 <!-- 2&#45;&#45;3 -->
31 <g id="edge2" class="edge"><title>2&#45;&#45;3</title>
32 <path fill="none" stroke="black" d="M144.441,-48.7148C155.712,-48.7148 168.861,-48.7148 180.246,-48.7148"/>
33 </g>
34 <!-- 4 -->
35 <g id="node4" class="node"><title>4</title>
36 <polygon fill="none" stroke="black" points="376.153,-60.2657 336.853,-60.2657 324.709,-97.6453 312.564,-60.2657 273.264,-60.2657 305.059,-37.1639 292.914,0.215733 324.709,-22.8861 356.503,0.215733 344.359,-37.1639 376.153,-60.2657"/>
37 <text text-anchor="middle" x="324.709" y="-45.0148" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
38 </g>
39 <!-- 3&#45;&#45;4 -->
40 <g id="edge3" class="edge"><title>3&#45;&#45;4</title>
41 <path fill="none" stroke="black" d="M237.331,-48.7148C252.878,-48.7148 272.445,-48.7148 289.022,-48.7148"/>
42 </g>
43 <!-- 5 -->
44 <g id="node5" class="node"><title>5</title>
45 <polygon fill="none" stroke="black" points="514.597,-60.2657 475.297,-60.2657 463.152,-97.6453 451.008,-60.2657 411.708,-60.2657 443.502,-37.1639 431.358,0.215733 463.152,-22.8861 494.947,0.215733 482.802,-37.1639 514.597,-60.2657"/>
46 <text text-anchor="middle" x="463.152" y="-45.0148" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
47 </g>
48 <!-- 4&#45;&#45;5 -->
49 <g id="edge4" class="edge"><title>4&#45;&#45;5</title>
50 <path fill="none" stroke="black" d="M360.139,-48.7148C380.823,-48.7148 407.051,-48.7148 427.733,-48.7148"/>
51 </g>
52 </g>
53 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: ni Pages: 1 -->
6 <svg width="522pt" height="105pt"
7 viewBox="0.00 0.00 522.37 105.43" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 101.43)">
9 <title>ni</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-101.43 518.37,-101.43 518.37,4 -4,4"/>
11 <!-- 1 -->
12 <g id="node1" class="node">
13 <title>1</title>
14 <polygon fill="none" stroke="black" points="36,-60.71 0,-60.71 0,-36.71 36,-36.71 36,-30.71 54,-48.71 36,-66.71 36,-60.71"/>
15 <text text-anchor="middle" x="27" y="-45.01" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
16 </g>
17 <!-- 2 -->
18 <g id="node2" class="node">
19 <title>2</title>
20 <polygon fill="none" stroke="black" points="126,-60.71 90,-60.71 90,-36.71 126,-36.71 126,-30.71 144,-48.71 126,-66.71 126,-60.71"/>
21 <text text-anchor="middle" x="117" y="-45.01" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
22 </g>
23 <!-- 1&#45;&#45;2 -->
24 <g id="edge1" class="edge">
25 <title>1&#45;&#45;2</title>
26 <path fill="none" stroke="black" d="M54.4,-48.71C65.64,-48.71 78.72,-48.71 89.92,-48.71"/>
27 </g>
28 <!-- 3 -->
29 <g id="node3" class="node">
30 <title>3</title>
31 <polygon fill="none" stroke="black" points="211.43,-30.76 213.2,-30.86 214.96,-31.01 216.69,-31.21 218.39,-31.45 220.05,-31.74 221.67,-32.08 223.23,-32.46 224.73,-32.89 226.17,-33.36 227.54,-33.88 228.84,-34.43 230.06,-35.02 231.2,-35.65 232.25,-36.32 233.22,-37.02 234.09,-37.75 234.87,-38.52 235.56,-39.31 236.15,-40.12 236.65,-40.96 237.05,-41.82 237.36,-42.7 237.58,-43.6 237.7,-44.51 237.73,-45.43 237.68,-46.36 237.54,-47.3 237.31,-48.24 237.01,-49.19 236.63,-50.13 236.18,-51.07 235.66,-52 235.08,-52.92 234.43,-53.83 233.72,-54.73 232.97,-55.61 232.16,-56.47 231.3,-57.31 230.41,-58.12 229.48,-58.91 228.51,-59.68 227.51,-60.41 226.48,-61.11 225.43,-61.78 224.35,-62.41 223.26,-63 222.15,-63.55 221.02,-64.07 219.89,-64.54 218.74,-64.97 217.58,-65.35 216.42,-65.69 215.24,-65.98 214.07,-66.22 212.89,-66.42 211.71,-66.57 210.52,-66.67 209.34,-66.71 208.15,-66.71 206.96,-66.67 205.78,-66.57 204.6,-66.42 203.42,-66.22 202.24,-65.98 201.07,-65.69 199.91,-65.35 198.75,-64.97 197.6,-64.54 196.46,-64.07 195.34,-63.55 194.23,-63 193.13,-62.41 192.06,-61.78 191.01,-61.11 189.98,-60.41 188.98,-59.68 188.01,-58.91 187.08,-58.12 186.18,-57.31 185.33,-56.47 184.52,-55.61 183.76,-54.73 183.06,-53.83 182.41,-52.92 181.83,-52 181.3,-51.07 180.85,-50.13 180.47,-49.19 180.17,-48.24 179.95,-47.3 179.81,-46.36 179.75,-45.43 179.79,-44.51 179.91,-43.6 180.13,-42.7 180.43,-41.82 180.84,-40.96 181.34,-40.12 181.93,-39.31 182.62,-38.52 183.4,-37.75 184.27,-37.02 185.24,-36.32 186.29,-35.65 187.43,-35.02 188.65,-34.43 189.94,-33.88 191.31,-33.36 192.75,-32.89 194.26,-32.46 195.82,-32.08 197.44,-31.74 199.1,-31.45 200.79,-31.21 202.53,-31.01 204.28,-30.86 206.06,-30.76 207.85,-30.71 209.64,-30.71 211.43,-30.76"/>
32 <text text-anchor="middle" x="208.74" y="-45.01" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
33 </g>
34 <!-- 2&#45;&#45;3 -->
35 <g id="edge2" class="edge">
36 <title>2&#45;&#45;3</title>
37 <path fill="none" stroke="black" d="M144.44,-48.71C155.71,-48.71 168.86,-48.71 180.25,-48.71"/>
38 </g>
39 <!-- 4 -->
40 <g id="node4" class="node">
41 <title>4</title>
42 <polygon fill="none" stroke="black" points="376.15,-60.27 336.85,-60.27 324.71,-97.65 312.56,-60.27 273.26,-60.27 305.06,-37.16 292.91,0.22 324.71,-22.89 356.5,0.22 344.36,-37.16 376.15,-60.27"/>
43 <text text-anchor="middle" x="324.71" y="-45.01" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
44 </g>
45 <!-- 3&#45;&#45;4 -->
46 <g id="edge3" class="edge">
47 <title>3&#45;&#45;4</title>
48 <path fill="none" stroke="black" d="M237.33,-48.71C252.88,-48.71 272.44,-48.71 289.02,-48.71"/>
49 </g>
50 <!-- 5 -->
51 <g id="node5" class="node">
52 <title>5</title>
53 <polygon fill="none" stroke="black" points="514.6,-60.27 475.3,-60.27 463.15,-97.65 451.01,-60.27 411.71,-60.27 443.5,-37.16 431.36,0.22 463.15,-22.89 494.95,0.22 482.8,-37.16 514.6,-60.27"/>
54 <text text-anchor="middle" x="463.15" y="-45.01" font-family="Times New Roman,serif" font-size="14.00">Ni!</text>
55 </g>
56 <!-- 4&#45;&#45;5 -->
57 <g id="edge4" class="edge">
58 <title>4&#45;&#45;5</title>
59 <path fill="none" stroke="black" d="M360.14,-48.71C380.82,-48.71 407.05,-48.71 427.73,-48.71"/>
60 </g>
61 </g>
62 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: pet&#45;shop Pages: 1 -->
6 <svg width="152pt" height="44pt"
7 viewBox="0.00 0.00 152.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
9 <title>pet&#45;shop</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-40 148,-40 148,4 -4,4"/>
11 <!-- parrot -->
12 <g id="node1" class="node"><title>parrot</title>
13 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">parrot</text>
14 </g>
15 <!-- dead -->
16 <g id="node2" class="node"><title>dead</title>
17 <text text-anchor="middle" x="117" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">dead</text>
18 </g>
19 <!-- parrot&#45;&gt;dead -->
20 <g id="edge1" class="edge"><title>parrot&#45;&gt;dead</title>
21 <path fill="none" stroke="black" d="M54.4029,-18C59.32,-18 64.5882,-18 69.8973,-18"/>
22 <polygon fill="black" stroke="black" points="89.919,-18 69.919,-27.0001 79.919,-18 69.919,-18.0001 69.919,-18.0001 69.919,-18.0001 79.919,-18 69.9189,-9.0001 89.919,-18 89.919,-18"/>
23 </g>
24 </g>
25 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: pet&#45;shop Pages: 1 -->
6 <svg width="152pt" height="44pt"
7 viewBox="0.00 0.00 152.00 44.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 40)">
9 <title>pet&#45;shop</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-40 148,-40 148,4 -4,4"/>
11 <!-- parrot -->
12 <g id="node1" class="node">
13 <title>parrot</title>
14 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">parrot</text>
15 </g>
16 <!-- dead -->
17 <g id="node2" class="node">
18 <title>dead</title>
19 <text text-anchor="middle" x="117" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">dead</text>
20 </g>
21 <!-- parrot&#45;&gt;dead -->
22 <g id="edge1" class="edge">
23 <title>parrot&#45;&gt;dead</title>
24 <path fill="none" stroke="black" d="M54.4,-18C59.32,-18 64.59,-18 69.9,-18"/>
25 <polygon fill="black" stroke="black" points="89.92,-18 69.92,-27 79.92,-18 69.92,-18 69.92,-18 69.92,-18 79.92,-18 69.92,-9 89.92,-18 89.92,-18"/>
26 </g>
27 </g>
28 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="693pt" height="252pt"
7 viewBox="0.00 0.00 693.30 251.93" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 247.926)">
9 <title>G</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-247.926 689.304,-247.926 689.304,4 -4,4"/>
11 <!-- run -->
12 <g id="node1" class="node"><title>run</title>
13 <ellipse fill="none" stroke="black" cx="156.628" cy="-113.566" rx="27" ry="18"/>
14 <text text-anchor="middle" x="156.628" y="-109.866" font-family="Times New Roman,serif" font-size="14.00">run</text>
15 </g>
16 <!-- intr -->
17 <g id="node2" class="node"><title>intr</title>
18 <ellipse fill="none" stroke="black" cx="34.2576" cy="-75.4583" rx="27" ry="18"/>
19 <text text-anchor="middle" x="34.2576" y="-71.7583" font-family="Times New Roman,serif" font-size="14.00">intr</text>
20 </g>
21 <!-- run&#45;&#45;intr -->
22 <g id="edge1" class="edge"><title>run&#45;&#45;intr</title>
23 <path fill="none" stroke="black" d="M132.159,-105.946C110.955,-99.3429 80.4171,-89.8329 59.104,-83.1958"/>
24 </g>
25 <!-- kernel -->
26 <g id="node4" class="node"><title>kernel</title>
27 <ellipse fill="none" stroke="black" cx="350.756" cy="-125.195" rx="32.4942" ry="18"/>
28 <text text-anchor="middle" x="350.756" y="-121.495" font-family="Times New Roman,serif" font-size="14.00">kernel</text>
29 </g>
30 <!-- run&#45;&#45;kernel -->
31 <g id="edge4" class="edge"><title>run&#45;&#45;kernel</title>
32 <path fill="none" stroke="black" d="M183.621,-115.183C218.834,-117.292 280.394,-120.98 318.168,-123.243"/>
33 </g>
34 <!-- runbl -->
35 <g id="node3" class="node"><title>runbl</title>
36 <ellipse fill="none" stroke="black" cx="29.2474" cy="-153.272" rx="29.4969" ry="18"/>
37 <text text-anchor="middle" x="29.2474" y="-149.572" font-family="Times New Roman,serif" font-size="14.00">runbl</text>
38 </g>
39 <!-- intr&#45;&#45;runbl -->
40 <g id="edge2" class="edge"><title>intr&#45;&#45;runbl</title>
41 <path fill="none" stroke="black" d="M33.0956,-93.5059C32.2919,-105.987 31.2265,-122.534 30.4205,-135.053"/>
42 </g>
43 <!-- runbl&#45;&#45;run -->
44 <g id="edge3" class="edge"><title>runbl&#45;&#45;run</title>
45 <path fill="none" stroke="black" d="M55.6408,-145.045C78.0854,-138.049 110.071,-128.078 131.997,-121.244"/>
46 </g>
47 <!-- zombie -->
48 <g id="node5" class="node"><title>zombie</title>
49 <ellipse fill="none" stroke="black" cx="294.131" cy="-221.131" rx="37.0935" ry="18"/>
50 <text text-anchor="middle" x="294.131" y="-217.431" font-family="Times New Roman,serif" font-size="14.00">zombie</text>
51 </g>
52 <!-- kernel&#45;&#45;zombie -->
53 <g id="edge5" class="edge"><title>kernel&#45;&#45;zombie</title>
54 <path fill="none" stroke="black" d="M340.633,-142.346C330.389,-159.701 314.638,-186.388 304.357,-203.804"/>
55 </g>
56 <!-- sleep -->
57 <g id="node6" class="node"><title>sleep</title>
58 <ellipse fill="none" stroke="black" cx="482.705" cy="-58.875" rx="29.4969" ry="18"/>
59 <text text-anchor="middle" x="482.705" y="-55.175" font-family="Times New Roman,serif" font-size="14.00">sleep</text>
60 </g>
61 <!-- kernel&#45;&#45;sleep -->
62 <g id="edge6" class="edge"><title>kernel&#45;&#45;sleep</title>
63 <path fill="none" stroke="black" d="M374.958,-113.031C399.212,-100.84 436.262,-82.2182 459.98,-70.297"/>
64 </g>
65 <!-- runmem -->
66 <g id="node7" class="node"><title>runmem</title>
67 <ellipse fill="none" stroke="black" cx="519.307" cy="-154.788" rx="40.0939" ry="18"/>
68 <text text-anchor="middle" x="519.307" y="-151.088" font-family="Times New Roman,serif" font-size="14.00">runmem</text>
69 </g>
70 <!-- kernel&#45;&#45;runmem -->
71 <g id="edge7" class="edge"><title>kernel&#45;&#45;runmem</title>
72 <path fill="none" stroke="black" d="M382.064,-130.692C410.244,-135.639 451.711,-142.92 481.684,-148.182"/>
73 </g>
74 <!-- sleep&#45;&#45;runmem -->
75 <g id="edge13" class="edge"><title>sleep&#45;&#45;runmem</title>
76 <path fill="none" stroke="black" d="M489.419,-76.4669C495.981,-93.6645 505.922,-119.712 512.512,-136.983"/>
77 </g>
78 <!-- swap -->
79 <g id="node8" class="node"><title>swap</title>
80 <ellipse fill="none" stroke="black" cx="611.563" cy="-18" rx="29.795" ry="18"/>
81 <text text-anchor="middle" x="611.563" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">swap</text>
82 </g>
83 <!-- sleep&#45;&#45;swap -->
84 <g id="edge8" class="edge"><title>sleep&#45;&#45;swap</title>
85 <path fill="none" stroke="black" d="M508.782,-50.6033C530.991,-43.5583 562.759,-33.481 585.083,-26.3997"/>
86 </g>
87 <!-- runswap -->
88 <g id="node9" class="node"><title>runswap</title>
89 <ellipse fill="none" stroke="black" cx="643.708" cy="-126.795" rx="41.6928" ry="18"/>
90 <text text-anchor="middle" x="643.708" y="-123.095" font-family="Times New Roman,serif" font-size="14.00">runswap</text>
91 </g>
92 <!-- swap&#45;&#45;runswap -->
93 <g id="edge9" class="edge"><title>swap&#45;&#45;runswap</title>
94 <path fill="none" stroke="black" d="M616.871,-35.9653C622.827,-56.1233 632.433,-88.6343 638.392,-108.803"/>
95 </g>
96 <!-- runswap&#45;&#45;runmem -->
97 <g id="edge11" class="edge"><title>runswap&#45;&#45;runmem</title>
98 <path fill="none" stroke="black" d="M606.72,-135.118C590.534,-138.76 571.605,-143.02 555.509,-146.642"/>
99 </g>
100 <!-- new -->
101 <g id="node10" class="node"><title>new</title>
102 <ellipse fill="none" stroke="black" cx="630.999" cy="-225.926" rx="27" ry="18"/>
103 <text text-anchor="middle" x="630.999" y="-222.226" font-family="Times New Roman,serif" font-size="14.00">new</text>
104 </g>
105 <!-- runswap&#45;&#45;new -->
106 <g id="edge10" class="edge"><title>runswap&#45;&#45;new</title>
107 <path fill="none" stroke="black" d="M641.377,-144.977C639.084,-162.864 635.603,-190.013 633.315,-207.859"/>
108 </g>
109 <!-- new&#45;&#45;runmem -->
110 <g id="edge12" class="edge"><title>new&#45;&#45;runmem</title>
111 <path fill="none" stroke="black" d="M611.288,-213.372C592.124,-201.166 563.012,-182.624 542.688,-169.68"/>
112 </g>
113 </g>
114 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: G Pages: 1 -->
6 <svg width="693pt" height="252pt"
7 viewBox="0.00 0.00 693.30 251.93" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 247.926)">
9 <title>G</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-247.926 689.304,-247.926 689.304,4 -4,4"/>
11 <!-- run -->
12 <g id="node1" class="node"><title>run</title>
13 <ellipse fill="none" stroke="black" cx="156.628" cy="-113.566" rx="27" ry="18"/>
14 <text text-anchor="middle" x="156.628" y="-109.866" font-family="Times New Roman,serif" font-size="14.00">run</text>
15 </g>
16 <!-- intr -->
17 <g id="node2" class="node"><title>intr</title>
18 <ellipse fill="none" stroke="black" cx="34.2576" cy="-75.4583" rx="27" ry="18"/>
19 <text text-anchor="middle" x="34.2576" y="-71.7583" font-family="Times New Roman,serif" font-size="14.00">intr</text>
20 </g>
21 <!-- run&#45;&#45;intr -->
22 <g id="edge1" class="edge"><title>run&#45;&#45;intr</title>
23 <path fill="none" stroke="black" d="M132.159,-105.946C110.955,-99.3429 80.4171,-89.8329 59.104,-83.1958"/>
24 </g>
25 <!-- kernel -->
26 <g id="node4" class="node"><title>kernel</title>
27 <ellipse fill="none" stroke="black" cx="350.756" cy="-125.195" rx="32.4942" ry="18"/>
28 <text text-anchor="middle" x="350.756" y="-121.495" font-family="Times New Roman,serif" font-size="14.00">kernel</text>
29 </g>
30 <!-- run&#45;&#45;kernel -->
31 <g id="edge4" class="edge"><title>run&#45;&#45;kernel</title>
32 <path fill="none" stroke="black" d="M183.621,-115.183C218.834,-117.292 280.394,-120.98 318.168,-123.243"/>
33 </g>
34 <!-- runbl -->
35 <g id="node3" class="node"><title>runbl</title>
36 <ellipse fill="none" stroke="black" cx="29.2474" cy="-153.272" rx="29.4969" ry="18"/>
37 <text text-anchor="middle" x="29.2474" y="-149.572" font-family="Times New Roman,serif" font-size="14.00">runbl</text>
38 </g>
39 <!-- intr&#45;&#45;runbl -->
40 <g id="edge2" class="edge"><title>intr&#45;&#45;runbl</title>
41 <path fill="none" stroke="black" d="M33.0956,-93.5059C32.2919,-105.987 31.2265,-122.534 30.4205,-135.053"/>
42 </g>
43 <!-- runbl&#45;&#45;run -->
44 <g id="edge3" class="edge"><title>runbl&#45;&#45;run</title>
45 <path fill="none" stroke="black" d="M55.6408,-145.045C78.0854,-138.049 110.071,-128.078 131.997,-121.244"/>
46 </g>
47 <!-- zombie -->
48 <g id="node5" class="node"><title>zombie</title>
49 <ellipse fill="none" stroke="black" cx="294.131" cy="-221.131" rx="37.0935" ry="18"/>
50 <text text-anchor="middle" x="294.131" y="-217.431" font-family="Times New Roman,serif" font-size="14.00">zombie</text>
51 </g>
52 <!-- kernel&#45;&#45;zombie -->
53 <g id="edge5" class="edge"><title>kernel&#45;&#45;zombie</title>
54 <path fill="none" stroke="black" d="M340.633,-142.346C330.389,-159.701 314.638,-186.388 304.357,-203.804"/>
55 </g>
56 <!-- sleep -->
57 <g id="node6" class="node"><title>sleep</title>
58 <ellipse fill="none" stroke="black" cx="482.705" cy="-58.875" rx="29.4969" ry="18"/>
59 <text text-anchor="middle" x="482.705" y="-55.175" font-family="Times New Roman,serif" font-size="14.00">sleep</text>
60 </g>
61 <!-- kernel&#45;&#45;sleep -->
62 <g id="edge6" class="edge"><title>kernel&#45;&#45;sleep</title>
63 <path fill="none" stroke="black" d="M374.958,-113.031C399.212,-100.84 436.262,-82.2182 459.98,-70.297"/>
64 </g>
65 <!-- runmem -->
66 <g id="node7" class="node"><title>runmem</title>
67 <ellipse fill="none" stroke="black" cx="519.307" cy="-154.788" rx="40.0939" ry="18"/>
68 <text text-anchor="middle" x="519.307" y="-151.088" font-family="Times New Roman,serif" font-size="14.00">runmem</text>
69 </g>
70 <!-- kernel&#45;&#45;runmem -->
71 <g id="edge7" class="edge"><title>kernel&#45;&#45;runmem</title>
72 <path fill="none" stroke="black" d="M382.064,-130.692C410.244,-135.639 451.711,-142.92 481.684,-148.182"/>
73 </g>
74 <!-- sleep&#45;&#45;runmem -->
75 <g id="edge13" class="edge"><title>sleep&#45;&#45;runmem</title>
76 <path fill="none" stroke="black" d="M489.419,-76.4669C495.981,-93.6645 505.922,-119.712 512.512,-136.983"/>
77 </g>
78 <!-- swap -->
79 <g id="node8" class="node"><title>swap</title>
80 <ellipse fill="none" stroke="black" cx="611.563" cy="-18" rx="29.795" ry="18"/>
81 <text text-anchor="middle" x="611.563" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">swap</text>
82 </g>
83 <!-- sleep&#45;&#45;swap -->
84 <g id="edge8" class="edge"><title>sleep&#45;&#45;swap</title>
85 <path fill="none" stroke="black" d="M508.782,-50.6033C530.991,-43.5583 562.759,-33.481 585.083,-26.3997"/>
86 </g>
87 <!-- runswap -->
88 <g id="node9" class="node"><title>runswap</title>
89 <ellipse fill="none" stroke="black" cx="643.708" cy="-126.795" rx="41.6928" ry="18"/>
90 <text text-anchor="middle" x="643.708" y="-123.095" font-family="Times New Roman,serif" font-size="14.00">runswap</text>
91 </g>
92 <!-- swap&#45;&#45;runswap -->
93 <g id="edge9" class="edge"><title>swap&#45;&#45;runswap</title>
94 <path fill="none" stroke="black" d="M616.871,-35.9653C622.827,-56.1233 632.433,-88.6343 638.392,-108.803"/>
95 </g>
96 <!-- runswap&#45;&#45;runmem -->
97 <g id="edge11" class="edge"><title>runswap&#45;&#45;runmem</title>
98 <path fill="none" stroke="black" d="M606.72,-135.118C590.534,-138.76 571.605,-143.02 555.509,-146.642"/>
99 </g>
100 <!-- new -->
101 <g id="node10" class="node"><title>new</title>
102 <ellipse fill="none" stroke="black" cx="630.999" cy="-225.926" rx="27" ry="18"/>
103 <text text-anchor="middle" x="630.999" y="-222.226" font-family="Times New Roman,serif" font-size="14.00">new</text>
104 </g>
105 <!-- runswap&#45;&#45;new -->
106 <g id="edge10" class="edge"><title>runswap&#45;&#45;new</title>
107 <path fill="none" stroke="black" d="M641.377,-144.977C639.084,-162.864 635.603,-190.013 633.315,-207.859"/>
108 </g>
109 <!-- new&#45;&#45;runmem -->
110 <g id="edge12" class="edge"><title>new&#45;&#45;runmem</title>
111 <path fill="none" stroke="black" d="M611.288,-213.372C592.124,-201.166 563.012,-182.624 542.688,-169.68"/>
112 </g>
113 </g>
114 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: %3 Pages: 1 -->
6 <svg width="206pt" height="188pt"
7 viewBox="0.00 0.00 206.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
9 <title>%3</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-184 202,-184 202,4 -4,4"/>
11 <!-- A -->
12 <g id="node1" class="node"><title>A</title>
13 <ellipse fill="none" stroke="black" cx="72" cy="-162" rx="27" ry="18"/>
14 <text text-anchor="middle" x="72" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">A</text>
15 </g>
16 <!-- C -->
17 <g id="node3" class="node"><title>C</title>
18 <ellipse fill="none" stroke="black" cx="36" cy="-90" rx="27" ry="18"/>
19 <text text-anchor="middle" x="36" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">C</text>
20 </g>
21 <!-- A&#45;&gt;C -->
22 <g id="edge2" class="edge"><title>A&#45;&gt;C</title>
23 <path fill="none" stroke="black" d="M63.6504,-144.765C59.2885,-136.283 53.8531,-125.714 48.9587,-116.197"/>
24 <polygon fill="black" stroke="black" points="51.9904,-114.439 44.3043,-107.147 45.7654,-117.641 51.9904,-114.439"/>
25 </g>
26 <!-- B -->
27 <g id="node4" class="node"><title>B</title>
28 <ellipse fill="none" stroke="black" cx="99" cy="-18" rx="27" ry="18"/>
29 <text text-anchor="middle" x="99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">B</text>
30 </g>
31 <!-- A&#45;&gt;B -->
32 <g id="edge1" class="edge"><title>A&#45;&gt;B</title>
33 <path fill="none" stroke="black" d="M75.2568,-143.871C79.8585,-119.67 88.312,-75.2108 93.7914,-46.3932"/>
34 <polygon fill="black" stroke="black" points="97.302,-46.6671 95.7316,-36.1893 90.4252,-45.3594 97.302,-46.6671"/>
35 </g>
36 <!-- X -->
37 <g id="node2" class="node"><title>X</title>
38 <ellipse fill="none" stroke="black" cx="171" cy="-162" rx="27" ry="18"/>
39 <text text-anchor="middle" x="171" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">X</text>
40 </g>
41 <!-- Y -->
42 <g id="node6" class="node"><title>Y</title>
43 <ellipse fill="none" stroke="black" cx="171" cy="-18" rx="27" ry="18"/>
44 <text text-anchor="middle" x="171" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Y</text>
45 </g>
46 <!-- X&#45;&gt;Y -->
47 <g id="edge4" class="edge"><title>X&#45;&gt;Y</title>
48 <path fill="none" stroke="black" d="M171,-143.871C171,-119.67 171,-75.2108 171,-46.3932"/>
49 <polygon fill="black" stroke="black" points="174.5,-46.1892 171,-36.1893 167.5,-46.1893 174.5,-46.1892"/>
50 </g>
51 <!-- D -->
52 <g id="node5" class="node"><title>D</title>
53 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
54 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">D</text>
55 </g>
56 <!-- C&#45;&gt;D -->
57 <g id="edge3" class="edge"><title>C&#45;&gt;D</title>
58 <path fill="none" stroke="black" d="M33.8214,-72.055C32.8302,-64.3456 31.632,-55.0269 30.5183,-46.3642"/>
59 <polygon fill="black" stroke="black" points="33.9678,-45.7473 29.2211,-36.2753 27.025,-46.64 33.9678,-45.7473"/>
60 </g>
61 </g>
62 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="206pt" height="188pt"
7 viewBox="0.00 0.00 206.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-184 202,-184 202,4 -4,4"/>
10 <!-- A -->
11 <g id="node1" class="node">
12 <title>A</title>
13 <ellipse fill="none" stroke="black" cx="72" cy="-162" rx="27" ry="18"/>
14 <text text-anchor="middle" x="72" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">A</text>
15 </g>
16 <!-- C -->
17 <g id="node3" class="node">
18 <title>C</title>
19 <ellipse fill="none" stroke="black" cx="36" cy="-90" rx="27" ry="18"/>
20 <text text-anchor="middle" x="36" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">C</text>
21 </g>
22 <!-- A&#45;&gt;C -->
23 <g id="edge2" class="edge">
24 <title>A&#45;&gt;C</title>
25 <path fill="none" stroke="black" d="M63.65,-144.76C59.29,-136.28 53.85,-125.71 48.96,-116.2"/>
26 <polygon fill="black" stroke="black" points="51.99,-114.44 44.3,-107.15 45.77,-117.64 51.99,-114.44"/>
27 </g>
28 <!-- B -->
29 <g id="node4" class="node">
30 <title>B</title>
31 <ellipse fill="none" stroke="black" cx="99" cy="-18" rx="27" ry="18"/>
32 <text text-anchor="middle" x="99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">B</text>
33 </g>
34 <!-- A&#45;&gt;B -->
35 <g id="edge1" class="edge">
36 <title>A&#45;&gt;B</title>
37 <path fill="none" stroke="black" d="M75.26,-143.87C79.86,-119.67 88.31,-75.21 93.79,-46.39"/>
38 <polygon fill="black" stroke="black" points="97.3,-46.67 95.73,-36.19 90.43,-45.36 97.3,-46.67"/>
39 </g>
40 <!-- X -->
41 <g id="node2" class="node">
42 <title>X</title>
43 <ellipse fill="none" stroke="black" cx="171" cy="-162" rx="27" ry="18"/>
44 <text text-anchor="middle" x="171" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">X</text>
45 </g>
46 <!-- Y -->
47 <g id="node6" class="node">
48 <title>Y</title>
49 <ellipse fill="none" stroke="black" cx="171" cy="-18" rx="27" ry="18"/>
50 <text text-anchor="middle" x="171" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Y</text>
51 </g>
52 <!-- X&#45;&gt;Y -->
53 <g id="edge4" class="edge">
54 <title>X&#45;&gt;Y</title>
55 <path fill="none" stroke="black" d="M171,-143.87C171,-119.67 171,-75.21 171,-46.39"/>
56 <polygon fill="black" stroke="black" points="174.5,-46.19 171,-36.19 167.5,-46.19 174.5,-46.19"/>
57 </g>
58 <!-- D -->
59 <g id="node5" class="node">
60 <title>D</title>
61 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
62 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">D</text>
63 </g>
64 <!-- C&#45;&gt;D -->
65 <g id="edge3" class="edge">
66 <title>C&#45;&gt;D</title>
67 <path fill="none" stroke="black" d="M33.82,-72.05C32.83,-64.35 31.63,-55.03 30.52,-46.36"/>
68 <polygon fill="black" stroke="black" points="33.97,-45.75 29.22,-36.28 27.02,-46.64 33.97,-45.75"/>
69 </g>
70 </g>
71 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: %3 Pages: 1 -->
6 <svg width="390pt" height="116pt"
7 viewBox="0.00 0.00 389.98 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
9 <title>%3</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-112 385.984,-112 385.984,4 -4,4"/>
11 <!-- A -->
12 <g id="node1" class="node"><title>A</title>
13 <ellipse fill="none" stroke="black" cx="190.992" cy="-90" rx="53.8905" ry="18"/>
14 <text text-anchor="middle" x="190.992" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">King Arthur</text>
15 </g>
16 <!-- B -->
17 <g id="node2" class="node"><title>B</title>
18 <ellipse fill="none" stroke="black" cx="90.9919" cy="-18" rx="90.9839" ry="18"/>
19 <text text-anchor="middle" x="90.9919" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Sir Bedevere the Wise</text>
20 </g>
21 <!-- A&#45;&gt;B -->
22 <g id="edge1" class="edge"><title>A&#45;&gt;B</title>
23 <path fill="none" stroke="black" d="M168.799,-73.4647C155.331,-64.0371 137.916,-51.8466 122.977,-41.3897"/>
24 <polygon fill="black" stroke="black" points="124.716,-38.3345 114.516,-35.4672 120.702,-44.0692 124.716,-38.3345"/>
25 </g>
26 <!-- L -->
27 <g id="node3" class="node"><title>L</title>
28 <ellipse fill="none" stroke="black" cx="290.992" cy="-18" rx="90.9839" ry="18"/>
29 <text text-anchor="middle" x="290.992" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Sir Lancelot the Brave</text>
30 </g>
31 <!-- A&#45;&gt;L -->
32 <g id="edge2" class="edge"><title>A&#45;&gt;L</title>
33 <path fill="none" stroke="black" d="M213.185,-73.4647C226.653,-64.0371 244.068,-51.8466 259.007,-41.3897"/>
34 <polygon fill="black" stroke="black" points="261.282,-44.0692 267.467,-35.4672 257.268,-38.3345 261.282,-44.0692"/>
35 </g>
36 <!-- B&#45;&gt;L -->
37 <g id="edge3" class="edge"><title>B&#45;&gt;L</title>
38 <path fill="none" stroke="black" d="M182.008,-18C184.615,-18 187.223,-18 189.83,-18"/>
39 <polygon fill="black" stroke="black" points="189.888,-21.5001 199.888,-18 189.888,-14.5001 189.888,-21.5001"/>
40 </g>
41 </g>
42 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="390pt" height="116pt"
7 viewBox="0.00 0.00 389.98 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-112 385.98,-112 385.98,4 -4,4"/>
10 <!-- A -->
11 <g id="node1" class="node">
12 <title>A</title>
13 <ellipse fill="none" stroke="black" cx="190.99" cy="-90" rx="53.89" ry="18"/>
14 <text text-anchor="middle" x="190.99" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">King Arthur</text>
15 </g>
16 <!-- B -->
17 <g id="node2" class="node">
18 <title>B</title>
19 <ellipse fill="none" stroke="black" cx="90.99" cy="-18" rx="90.98" ry="18"/>
20 <text text-anchor="middle" x="90.99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Sir Bedevere the Wise</text>
21 </g>
22 <!-- A&#45;&gt;B -->
23 <g id="edge1" class="edge">
24 <title>A&#45;&gt;B</title>
25 <path fill="none" stroke="black" d="M168.8,-73.46C155.33,-64.04 137.92,-51.85 122.98,-41.39"/>
26 <polygon fill="black" stroke="black" points="124.72,-38.33 114.52,-35.47 120.7,-44.07 124.72,-38.33"/>
27 </g>
28 <!-- L -->
29 <g id="node3" class="node">
30 <title>L</title>
31 <ellipse fill="none" stroke="black" cx="290.99" cy="-18" rx="90.98" ry="18"/>
32 <text text-anchor="middle" x="290.99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">Sir Lancelot the Brave</text>
33 </g>
34 <!-- A&#45;&gt;L -->
35 <g id="edge2" class="edge">
36 <title>A&#45;&gt;L</title>
37 <path fill="none" stroke="black" d="M213.19,-73.46C226.65,-64.04 244.07,-51.85 259.01,-41.39"/>
38 <polygon fill="black" stroke="black" points="261.28,-44.07 267.47,-35.47 257.27,-38.33 261.28,-44.07"/>
39 </g>
40 <!-- B&#45;&gt;L -->
41 <g id="edge3" class="edge">
42 <title>B&#45;&gt;L</title>
43 <path fill="none" stroke="black" d="M182.01,-18C184.62,-18 187.22,-18 189.83,-18"/>
44 <polygon fill="black" stroke="black" points="189.89,-21.5 199.89,-18 189.89,-14.5 189.89,-21.5"/>
45 </g>
46 </g>
47 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: structs Pages: 1 -->
6 <svg width="242pt" height="163pt"
7 viewBox="0.00 0.00 242.00 163.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 159)">
9 <title>structs</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-159 238,-159 238,4 -4,4"/>
11 <!-- struct1 -->
12 <g id="node1" class="node"><title>struct1</title>
13 <polygon fill="none" stroke="black" points="28.5,-126 28.5,-147 52.5,-147 52.5,-126 28.5,-126"/>
14 <text text-anchor="start" x="31.5" y="-132.8" font-family="Times New Roman,serif" font-size="14.00">left</text>
15 <polygon fill="none" stroke="black" points="52.5,-126 52.5,-147 96.5,-147 96.5,-126 52.5,-126"/>
16 <text text-anchor="start" x="55.5" y="-132.8" font-family="Times New Roman,serif" font-size="14.00">middle</text>
17 <polygon fill="none" stroke="black" points="96.5,-126 96.5,-147 127.5,-147 127.5,-126 96.5,-126"/>
18 <text text-anchor="start" x="99.5" y="-132.8" font-family="Times New Roman,serif" font-size="14.00">right</text>
19 </g>
20 <!-- struct2 -->
21 <g id="node2" class="node"><title>struct2</title>
22 <polygon fill="none" stroke="black" points="8.5,-30.5 8.5,-51.5 35.5,-51.5 35.5,-30.5 8.5,-30.5"/>
23 <text text-anchor="start" x="11.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">one</text>
24 <polygon fill="none" stroke="black" points="35.5,-30.5 35.5,-51.5 63.5,-51.5 63.5,-30.5 35.5,-30.5"/>
25 <text text-anchor="start" x="38.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">two</text>
26 </g>
27 <!-- struct1&#45;&gt;struct2 -->
28 <g id="edge1" class="edge"><title>struct1:f1&#45;&gt;struct2:f0</title>
29 <path fill="none" stroke="black" d="M74.5,-125C74.5,-88.8278 30.9717,-91.4553 22.8101,-62.558"/>
30 <polygon fill="black" stroke="black" points="26.2624,-61.9641 21.5,-52.5 19.3211,-62.8683 26.2624,-61.9641"/>
31 </g>
32 <!-- struct3 -->
33 <g id="node3" class="node"><title>struct3</title>
34 <polygon fill="none" stroke="black" points="97.5,-3.5 97.5,-78.5 140.5,-78.5 140.5,-3.5 97.5,-3.5"/>
35 <text text-anchor="start" x="105.5" y="-44.8" font-family="Times New Roman,serif" font-size="14.00">hello</text>
36 <text text-anchor="start" x="102.5" y="-29.8" font-family="Times New Roman,serif" font-size="14.00">world</text>
37 <polygon fill="none" stroke="black" points="140.5,-53.5 140.5,-78.5 192.5,-78.5 192.5,-53.5 140.5,-53.5"/>
38 <text text-anchor="start" x="162.5" y="-62.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
39 <polygon fill="none" stroke="black" points="192.5,-3.5 192.5,-78.5 209.5,-78.5 209.5,-3.5 192.5,-3.5"/>
40 <text text-anchor="start" x="197.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">g</text>
41 <polygon fill="none" stroke="black" points="209.5,-3.5 209.5,-78.5 226.5,-78.5 226.5,-3.5 209.5,-3.5"/>
42 <text text-anchor="start" x="214.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">h</text>
43 <polygon fill="none" stroke="black" points="140.5,-28.5 140.5,-53.5 157.5,-53.5 157.5,-28.5 140.5,-28.5"/>
44 <text text-anchor="start" x="145.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
45 <polygon fill="none" stroke="black" points="157.5,-28.5 157.5,-53.5 175.5,-53.5 175.5,-28.5 157.5,-28.5"/>
46 <text text-anchor="start" x="162.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">d</text>
47 <polygon fill="none" stroke="black" points="175.5,-28.5 175.5,-53.5 192.5,-53.5 192.5,-28.5 175.5,-28.5"/>
48 <text text-anchor="start" x="180.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">e</text>
49 <polygon fill="none" stroke="black" points="140.5,-3.5 140.5,-28.5 192.5,-28.5 192.5,-3.5 140.5,-3.5"/>
50 <text text-anchor="start" x="164" y="-12.3" font-family="Times New Roman,serif" font-size="14.00">f</text>
51 </g>
52 <!-- struct1&#45;&gt;struct3 -->
53 <g id="edge2" class="edge"><title>struct1:f2&#45;&gt;struct3:here</title>
54 <path fill="none" stroke="black" d="M112.5,-125C112.5,-97.3617 133.618,-71.6361 149.442,-56.2398"/>
55 <polygon fill="black" stroke="black" points="152.121,-58.5299 157.094,-49.1746 147.372,-53.3868 152.121,-58.5299"/>
56 </g>
57 </g>
58 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: structs Pages: 1 -->
6 <svg width="242pt" height="163pt"
7 viewBox="0.00 0.00 242.00 163.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 159)">
9 <title>structs</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-159 238,-159 238,4 -4,4"/>
11 <!-- struct1 -->
12 <g id="node1" class="node">
13 <title>struct1</title>
14 <polygon fill="none" stroke="black" points="28.5,-126 28.5,-147 52.5,-147 52.5,-126 28.5,-126"/>
15 <text text-anchor="start" x="31.5" y="-132.8" font-family="Times New Roman,serif" font-size="14.00">left</text>
16 <polygon fill="none" stroke="black" points="52.5,-126 52.5,-147 96.5,-147 96.5,-126 52.5,-126"/>
17 <text text-anchor="start" x="55.5" y="-132.8" font-family="Times New Roman,serif" font-size="14.00">middle</text>
18 <polygon fill="none" stroke="black" points="96.5,-126 96.5,-147 127.5,-147 127.5,-126 96.5,-126"/>
19 <text text-anchor="start" x="99.5" y="-132.8" font-family="Times New Roman,serif" font-size="14.00">right</text>
20 </g>
21 <!-- struct2 -->
22 <g id="node2" class="node">
23 <title>struct2</title>
24 <polygon fill="none" stroke="black" points="8.5,-30.5 8.5,-51.5 35.5,-51.5 35.5,-30.5 8.5,-30.5"/>
25 <text text-anchor="start" x="11.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">one</text>
26 <polygon fill="none" stroke="black" points="35.5,-30.5 35.5,-51.5 63.5,-51.5 63.5,-30.5 35.5,-30.5"/>
27 <text text-anchor="start" x="38.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">two</text>
28 </g>
29 <!-- struct1&#45;&gt;struct2 -->
30 <g id="edge1" class="edge">
31 <title>struct1:f1&#45;&gt;struct2:f0</title>
32 <path fill="none" stroke="black" d="M74.5,-125C74.5,-88.83 30.97,-91.46 22.81,-62.56"/>
33 <polygon fill="black" stroke="black" points="26.26,-61.96 21.5,-52.5 19.32,-62.87 26.26,-61.96"/>
34 </g>
35 <!-- struct3 -->
36 <g id="node3" class="node">
37 <title>struct3</title>
38 <polygon fill="none" stroke="black" points="97.5,-3.5 97.5,-78.5 140.5,-78.5 140.5,-3.5 97.5,-3.5"/>
39 <text text-anchor="start" x="105.5" y="-44.8" font-family="Times New Roman,serif" font-size="14.00">hello</text>
40 <text text-anchor="start" x="102.5" y="-29.8" font-family="Times New Roman,serif" font-size="14.00">world</text>
41 <polygon fill="none" stroke="black" points="140.5,-53.5 140.5,-78.5 192.5,-78.5 192.5,-53.5 140.5,-53.5"/>
42 <text text-anchor="start" x="162.5" y="-62.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
43 <polygon fill="none" stroke="black" points="192.5,-3.5 192.5,-78.5 209.5,-78.5 209.5,-3.5 192.5,-3.5"/>
44 <text text-anchor="start" x="197.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">g</text>
45 <polygon fill="none" stroke="black" points="209.5,-3.5 209.5,-78.5 226.5,-78.5 226.5,-3.5 209.5,-3.5"/>
46 <text text-anchor="start" x="214.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">h</text>
47 <polygon fill="none" stroke="black" points="140.5,-28.5 140.5,-53.5 157.5,-53.5 157.5,-28.5 140.5,-28.5"/>
48 <text text-anchor="start" x="145.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
49 <polygon fill="none" stroke="black" points="157.5,-28.5 157.5,-53.5 175.5,-53.5 175.5,-28.5 157.5,-28.5"/>
50 <text text-anchor="start" x="162.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">d</text>
51 <polygon fill="none" stroke="black" points="175.5,-28.5 175.5,-53.5 192.5,-53.5 192.5,-28.5 175.5,-28.5"/>
52 <text text-anchor="start" x="180.5" y="-37.3" font-family="Times New Roman,serif" font-size="14.00">e</text>
53 <polygon fill="none" stroke="black" points="140.5,-3.5 140.5,-28.5 192.5,-28.5 192.5,-3.5 140.5,-3.5"/>
54 <text text-anchor="start" x="164" y="-12.3" font-family="Times New Roman,serif" font-size="14.00">f</text>
55 </g>
56 <!-- struct1&#45;&gt;struct3 -->
57 <g id="edge2" class="edge">
58 <title>struct1:f2&#45;&gt;struct3:here</title>
59 <path fill="none" stroke="black" d="M112.5,-125C112.5,-97.36 133.62,-71.64 149.44,-56.24"/>
60 <polygon fill="black" stroke="black" points="152.12,-58.53 157.09,-49.17 147.37,-53.39 152.12,-58.53"/>
61 </g>
62 </g>
63 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: structs Pages: 1 -->
6 <svg width="266pt" height="151pt"
7 viewBox="0.00 0.00 266.00 151.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 147)">
9 <title>structs</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-147 262,-147 262,4 -4,4"/>
11 <!-- struct1 -->
12 <g id="node1" class="node"><title>struct1</title>
13 <polygon fill="none" stroke="black" points="13,-106.5 13,-142.5 142,-142.5 142,-106.5 13,-106.5"/>
14 <text text-anchor="middle" x="30" y="-120.8" font-family="Times New Roman,serif" font-size="14.00">left</text>
15 <polyline fill="none" stroke="black" points="47,-106.5 47,-142.5 "/>
16 <text text-anchor="middle" x="74" y="-120.8" font-family="Times New Roman,serif" font-size="14.00">middle</text>
17 <polyline fill="none" stroke="black" points="101,-106.5 101,-142.5 "/>
18 <text text-anchor="middle" x="121.5" y="-120.8" font-family="Times New Roman,serif" font-size="14.00">right</text>
19 </g>
20 <!-- struct2 -->
21 <g id="node2" class="node"><title>struct2</title>
22 <polygon fill="none" stroke="black" points="0,-17 0,-53 75,-53 75,-17 0,-17"/>
23 <text text-anchor="middle" x="18.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">one</text>
24 <polyline fill="none" stroke="black" points="37,-17 37,-53 "/>
25 <text text-anchor="middle" x="56" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">two</text>
26 </g>
27 <!-- struct1&#45;&gt;struct2 -->
28 <g id="edge1" class="edge"><title>struct1:f1&#45;&gt;struct2:f0</title>
29 <path fill="none" stroke="black" d="M73.5,-106C73.5,-76.3021 30.6353,-84.7306 20.5889,-63.9686"/>
30 <polygon fill="black" stroke="black" points="23.9766,-63.0696 18.5,-54 17.1254,-64.5053 23.9766,-63.0696"/>
31 </g>
32 <!-- struct3 -->
33 <g id="node3" class="node"><title>struct3</title>
34 <polygon fill="none" stroke="black" points="93,-0.5 93,-69.5 258,-69.5 258,-0.5 93,-0.5"/>
35 <text text-anchor="middle" x="117.5" y="-38.8" font-family="Times New Roman,serif" font-size="14.00">hello</text>
36 <text text-anchor="middle" x="117.5" y="-23.8" font-family="Times New Roman,serif" font-size="14.00">world</text>
37 <polyline fill="none" stroke="black" points="142,-0.5 142,-69.5 "/>
38 <text text-anchor="middle" x="177" y="-54.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
39 <polyline fill="none" stroke="black" points="142,-46.5 212,-46.5 "/>
40 <text text-anchor="middle" x="153.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
41 <polyline fill="none" stroke="black" points="165,-23.5 165,-46.5 "/>
42 <text text-anchor="middle" x="177" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">d</text>
43 <polyline fill="none" stroke="black" points="189,-23.5 189,-46.5 "/>
44 <text text-anchor="middle" x="200.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">e</text>
45 <polyline fill="none" stroke="black" points="142,-23.5 212,-23.5 "/>
46 <text text-anchor="middle" x="177" y="-8.3" font-family="Times New Roman,serif" font-size="14.00">f</text>
47 <polyline fill="none" stroke="black" points="212,-0.5 212,-69.5 "/>
48 <text text-anchor="middle" x="223.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">g</text>
49 <polyline fill="none" stroke="black" points="235,-0.5 235,-69.5 "/>
50 <text text-anchor="middle" x="246.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">h</text>
51 </g>
52 <!-- struct1&#45;&gt;struct3 -->
53 <g id="edge2" class="edge"><title>struct1:f2&#45;&gt;struct3:here</title>
54 <path fill="none" stroke="black" d="M121.5,-106C121.5,-93.9252 141.72,-70.7257 157.86,-54.1308"/>
55 <polygon fill="black" stroke="black" points="160.784,-56.1535 165.349,-46.5925 155.818,-51.22 160.784,-56.1535"/>
56 </g>
57 </g>
58 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: structs Pages: 1 -->
6 <svg width="266pt" height="151pt"
7 viewBox="0.00 0.00 266.00 151.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 147)">
9 <title>structs</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-147 262,-147 262,4 -4,4"/>
11 <!-- struct1 -->
12 <g id="node1" class="node">
13 <title>struct1</title>
14 <polygon fill="none" stroke="black" points="13,-106.5 13,-142.5 142,-142.5 142,-106.5 13,-106.5"/>
15 <text text-anchor="middle" x="30" y="-120.8" font-family="Times New Roman,serif" font-size="14.00">left</text>
16 <polyline fill="none" stroke="black" points="47,-106.5 47,-142.5 "/>
17 <text text-anchor="middle" x="74" y="-120.8" font-family="Times New Roman,serif" font-size="14.00">middle</text>
18 <polyline fill="none" stroke="black" points="101,-106.5 101,-142.5 "/>
19 <text text-anchor="middle" x="121.5" y="-120.8" font-family="Times New Roman,serif" font-size="14.00">right</text>
20 </g>
21 <!-- struct2 -->
22 <g id="node2" class="node">
23 <title>struct2</title>
24 <polygon fill="none" stroke="black" points="0,-17 0,-53 75,-53 75,-17 0,-17"/>
25 <text text-anchor="middle" x="18.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">one</text>
26 <polyline fill="none" stroke="black" points="37,-17 37,-53 "/>
27 <text text-anchor="middle" x="56" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">two</text>
28 </g>
29 <!-- struct1&#45;&gt;struct2 -->
30 <g id="edge1" class="edge">
31 <title>struct1:f1&#45;&gt;struct2:f0</title>
32 <path fill="none" stroke="black" d="M73.5,-106C73.5,-76.3 30.64,-84.73 20.59,-63.97"/>
33 <polygon fill="black" stroke="black" points="23.98,-63.07 18.5,-54 17.13,-64.51 23.98,-63.07"/>
34 </g>
35 <!-- struct3 -->
36 <g id="node3" class="node">
37 <title>struct3</title>
38 <polygon fill="none" stroke="black" points="93,-0.5 93,-69.5 258,-69.5 258,-0.5 93,-0.5"/>
39 <text text-anchor="middle" x="117.5" y="-38.8" font-family="Times New Roman,serif" font-size="14.00">hello</text>
40 <text text-anchor="middle" x="117.5" y="-23.8" font-family="Times New Roman,serif" font-size="14.00">world</text>
41 <polyline fill="none" stroke="black" points="142,-0.5 142,-69.5 "/>
42 <text text-anchor="middle" x="177" y="-54.3" font-family="Times New Roman,serif" font-size="14.00">b</text>
43 <polyline fill="none" stroke="black" points="142,-46.5 212,-46.5 "/>
44 <text text-anchor="middle" x="153.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">c</text>
45 <polyline fill="none" stroke="black" points="165,-23.5 165,-46.5 "/>
46 <text text-anchor="middle" x="177" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">d</text>
47 <polyline fill="none" stroke="black" points="189,-23.5 189,-46.5 "/>
48 <text text-anchor="middle" x="200.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">e</text>
49 <polyline fill="none" stroke="black" points="142,-23.5 212,-23.5 "/>
50 <text text-anchor="middle" x="177" y="-8.3" font-family="Times New Roman,serif" font-size="14.00">f</text>
51 <polyline fill="none" stroke="black" points="212,-0.5 212,-69.5 "/>
52 <text text-anchor="middle" x="223.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">g</text>
53 <polyline fill="none" stroke="black" points="235,-0.5 235,-69.5 "/>
54 <text text-anchor="middle" x="246.5" y="-31.3" font-family="Times New Roman,serif" font-size="14.00">h</text>
55 </g>
56 <!-- struct1&#45;&gt;struct3 -->
57 <g id="edge2" class="edge">
58 <title>struct1:f2&#45;&gt;struct3:here</title>
59 <path fill="none" stroke="black" d="M121.5,-106C121.5,-93.93 141.72,-70.73 157.86,-54.13"/>
60 <polygon fill="black" stroke="black" points="160.78,-56.15 165.35,-46.59 155.82,-51.22 160.78,-56.15"/>
61 </g>
62 </g>
63 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: TrafficLights Pages: 1 -->
6 <svg width="383pt" height="484pt"
7 viewBox="0.00 0.00 382.57 483.82" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(190.909 224.889)">
9 <title>TrafficLights</title>
10 <polygon fill="white" stroke="none" points="-190.909,258.936 -190.909,-224.889 191.659,-224.889 191.659,258.936 -190.909,258.936"/>
11 <text text-anchor="middle" x="0.3752" y="234.536" font-family="Times New Roman,serif" font-size="12.00">PetriNet Model TrafficLights</text>
12 <text text-anchor="middle" x="0.3752" y="247.536" font-family="Times New Roman,serif" font-size="12.00">Extracted from ConceptBase and layed out by Graphviz</text>
13 <!-- gy2 -->
14 <g id="node1" class="node"><title>gy2</title>
15 <polygon fill="none" stroke="black" points="-74.6078,164.183 -128.608,164.183 -128.608,200.183 -74.6078,200.183 -74.6078,164.183"/>
16 <text text-anchor="middle" x="-101.608" y="185.883" font-family="Times New Roman,serif" font-size="14.00">gy2</text>
17 </g>
18 <!-- yellow2 -->
19 <g id="node8" class="node"><title>yellow2</title>
20 <ellipse fill="none" stroke="black" cx="-154.409" cy="108.683" rx="32.5" ry="32.5"/>
21 <text text-anchor="middle" x="-154.409" y="112.383" font-family="Times New Roman,serif" font-size="14.00">yellow2</text>
22 </g>
23 <!-- gy2&#45;&gt;yellow2 -->
24 <g id="edge1" class="edge"><title>gy2&#45;&gt;yellow2</title>
25 <path fill="none" stroke="black" d="M-114.66,164.014C-119.137,157.781 -124.31,150.581 -129.413,143.477"/>
26 <polygon fill="black" stroke="black" points="-132.334,145.411 -135.325,135.248 -126.648,141.327 -132.334,145.411"/>
27 </g>
28 <!-- yr2 -->
29 <g id="node2" class="node"><title>yr2</title>
30 <polygon fill="none" stroke="black" points="-88.9729,12.4915 -142.973,12.4915 -142.973,48.4915 -88.9729,48.4915 -88.9729,12.4915"/>
31 <text text-anchor="middle" x="-115.973" y="34.1915" font-family="Times New Roman,serif" font-size="14.00">yr2</text>
32 </g>
33 <!-- red2 -->
34 <g id="node9" class="node"><title>red2</title>
35 <ellipse fill="none" stroke="black" cx="-42.9405" cy="75.0428" rx="32.5" ry="32.5"/>
36 <text text-anchor="middle" x="-42.9405" y="78.7428" font-family="Times New Roman,serif" font-size="14.00">red2</text>
37 </g>
38 <!-- yr2&#45;&gt;red2 -->
39 <g id="edge4" class="edge"><title>yr2&#45;&gt;red2</title>
40 <path fill="none" stroke="black" d="M-88.7783,47.0808C-85.7671,48.9177 -82.6653,50.8099 -79.5624,52.7027"/>
41 <polygon fill="black" stroke="black" points="-77.6039,49.7975 -70.8896,57.9933 -81.2493,55.7734 -77.6039,49.7975"/>
42 </g>
43 <!-- safe1 -->
44 <g id="node14" class="node"><title>safe1</title>
45 <ellipse fill="none" stroke="black" cx="-101.65" cy="-57.2197" rx="32.5" ry="32.5"/>
46 <text text-anchor="middle" x="-101.65" y="-53.5197" font-family="Times New Roman,serif" font-size="14.00">safe1</text>
47 </g>
48 <!-- yr2&#45;&gt;safe1 -->
49 <g id="edge3" class="edge"><title>yr2&#45;&gt;safe1</title>
50 <path fill="none" stroke="black" d="M-113.005,12.3177C-111.704,4.34801 -110.117,-5.36876 -108.548,-14.9818"/>
51 <polygon fill="black" stroke="black" points="-111.996,-15.5791 -106.931,-24.8844 -105.088,-14.451 -111.996,-15.5791"/>
52 </g>
53 <!-- rg2 -->
54 <g id="node3" class="node"><title>rg2</title>
55 <polygon fill="none" stroke="black" points="60.3716,96.0559 6.37158,96.0559 6.37158,132.056 60.3716,132.056 60.3716,96.0559"/>
56 <text text-anchor="middle" x="33.3716" y="117.756" font-family="Times New Roman,serif" font-size="14.00">rg2</text>
57 </g>
58 <!-- green2 -->
59 <g id="node7" class="node"><title>green2</title>
60 <ellipse fill="none" stroke="black" cx="-11.442" cy="188.436" rx="32.5" ry="32.5"/>
61 <text text-anchor="middle" x="-11.442" y="192.136" font-family="Times New Roman,serif" font-size="14.00">green2</text>
62 </g>
63 <!-- rg2&#45;&gt;green2 -->
64 <g id="edge2" class="edge"><title>rg2&#45;&gt;green2</title>
65 <path fill="none" stroke="black" d="M22.5235,132.061C18.9172,138.047 14.7608,144.945 10.6202,151.818"/>
66 <polygon fill="black" stroke="black" points="13.5849,153.679 5.42628,160.438 7.58907,150.067 13.5849,153.679"/>
67 </g>
68 <!-- gy1 -->
69 <g id="node4" class="node"><title>gy1</title>
70 <polygon fill="none" stroke="black" points="130.086,-199.367 76.0863,-199.367 76.0863,-163.367 130.086,-163.367 130.086,-199.367"/>
71 <text text-anchor="middle" x="103.086" y="-177.667" font-family="Times New Roman,serif" font-size="14.00">gy1</text>
72 </g>
73 <!-- yellow1 -->
74 <g id="node12" class="node"><title>yellow1</title>
75 <ellipse fill="none" stroke="black" cx="155.159" cy="-107.511" rx="32.5" ry="32.5"/>
76 <text text-anchor="middle" x="155.159" y="-103.811" font-family="Times New Roman,serif" font-size="14.00">yellow1</text>
77 </g>
78 <!-- gy1&#45;&gt;yellow1 -->
79 <g id="edge9" class="edge"><title>gy1&#45;&gt;yellow1</title>
80 <path fill="none" stroke="black" d="M115.958,-163.11C120.374,-156.847 125.476,-149.611 130.508,-142.474"/>
81 <polygon fill="black" stroke="black" points="133.437,-144.394 136.339,-134.204 127.716,-140.36 133.437,-144.394"/>
82 </g>
83 <!-- yr1 -->
84 <g id="node5" class="node"><title>yr1</title>
85 <polygon fill="none" stroke="black" points="141.759,-48.6674 87.7594,-48.6674 87.7594,-12.6674 141.759,-12.6674 141.759,-48.6674"/>
86 <text text-anchor="middle" x="114.759" y="-26.9674" font-family="Times New Roman,serif" font-size="14.00">yr1</text>
87 </g>
88 <!-- safe2 -->
89 <g id="node10" class="node"><title>safe2</title>
90 <ellipse fill="none" stroke="black" cx="101.139" cy="56.9206" rx="32.5" ry="32.5"/>
91 <text text-anchor="middle" x="101.139" y="60.6206" font-family="Times New Roman,serif" font-size="14.00">safe2</text>
92 </g>
93 <!-- yr1&#45;&gt;safe2 -->
94 <g id="edge11" class="edge"><title>yr1&#45;&gt;safe2</title>
95 <path fill="none" stroke="black" d="M111.937,-12.5191C110.7,-4.56061 109.191,5.14249 107.698,14.742"/>
96 <polygon fill="black" stroke="black" points="111.155,15.2873 106.16,24.6306 104.238,14.2116 111.155,15.2873"/>
97 </g>
98 <!-- red1 -->
99 <g id="node13" class="node"><title>red1</title>
100 <ellipse fill="none" stroke="black" cx="41.7812" cy="-75.623" rx="32.5" ry="32.5"/>
101 <text text-anchor="middle" x="41.7812" y="-71.923" font-family="Times New Roman,serif" font-size="14.00">red1</text>
102 </g>
103 <!-- yr1&#45;&gt;red1 -->
104 <g id="edge12" class="edge"><title>yr1&#45;&gt;red1</title>
105 <path fill="none" stroke="black" d="M87.585,-47.4072C84.5761,-49.2608 81.4765,-51.1701 78.376,-53.0801"/>
106 <polygon fill="black" stroke="black" points="76.3881,-50.1939 69.7096,-58.4187 80.0595,-56.1538 76.3881,-50.1939"/>
107 </g>
108 <!-- rg1 -->
109 <g id="node6" class="node"><title>rg1</title>
110 <polygon fill="none" stroke="black" points="-7.14375,-133.035 -61.1437,-133.035 -61.1437,-97.0355 -7.14375,-97.0355 -7.14375,-133.035"/>
111 <text text-anchor="middle" x="-34.1437" y="-111.335" font-family="Times New Roman,serif" font-size="14.00">rg1</text>
112 </g>
113 <!-- green1 -->
114 <g id="node11" class="node"><title>green1</title>
115 <ellipse fill="none" stroke="black" cx="12.8698" cy="-188.389" rx="32.5" ry="32.5"/>
116 <text text-anchor="middle" x="12.8698" y="-184.689" font-family="Times New Roman,serif" font-size="14.00">green1</text>
117 </g>
118 <!-- rg1&#45;&gt;green1 -->
119 <g id="edge10" class="edge"><title>rg1&#45;&gt;green1</title>
120 <path fill="none" stroke="black" d="M-22.5224,-133.168C-18.8584,-138.885 -14.6715,-145.417 -10.4908,-151.94"/>
121 <polygon fill="black" stroke="black" points="-13.1861,-154.221 -4.84329,-160.752 -7.29262,-150.444 -13.1861,-154.221"/>
122 </g>
123 <!-- green2&#45;&gt;gy2 -->
124 <g id="edge6" class="edge"><title>green2&#45;&gt;gy2</title>
125 <path fill="none" stroke="black" d="M-43.9939,186.178C-50.5484,185.724 -57.4867,185.243 -64.1919,184.778"/>
126 <polygon fill="black" stroke="black" points="-64.7142,188.25 -74.4481,184.066 -64.2299,181.267 -64.7142,188.25"/>
127 </g>
128 <!-- yellow2&#45;&gt;yr2 -->
129 <g id="edge7" class="edge"><title>yellow2&#45;&gt;yr2</title>
130 <path fill="none" stroke="black" d="M-139.878,79.1223C-136.429,72.1055 -132.765,64.6522 -129.369,57.7438"/>
131 <polygon fill="black" stroke="black" points="-132.502,56.1834 -124.949,48.7531 -126.22,59.2715 -132.502,56.1834"/>
132 </g>
133 <!-- red2&#45;&gt;rg2 -->
134 <g id="edge8" class="edge"><title>red2&#45;&gt;rg2</title>
135 <path fill="none" stroke="black" d="M-13.6545,90.0147C-10.0687,91.8479 -6.37215,93.7377 -2.70142,95.6143"/>
136 <polygon fill="black" stroke="black" points="-1.01848,92.5437 6.29223,100.212 -4.20489,98.7765 -1.01848,92.5437"/>
137 </g>
138 <!-- safe2&#45;&gt;rg2 -->
139 <g id="edge5" class="edge"><title>safe2&#45;&gt;rg2</title>
140 <path fill="none" stroke="black" d="M76.2895,77.8712C71.9454,81.5338 67.3876,85.3766 62.9312,89.1338"/>
141 <polygon fill="black" stroke="black" points="64.9887,91.9771 55.0873,95.7471 60.4766,86.6253 64.9887,91.9771"/>
142 </g>
143 <!-- green1&#45;&gt;gy1 -->
144 <g id="edge14" class="edge"><title>green1&#45;&gt;gy1</title>
145 <path fill="none" stroke="black" d="M45.44,-185.854C51.9982,-185.343 58.9404,-184.803 65.6494,-184.281"/>
146 <polygon fill="black" stroke="black" points="66.2131,-187.747 75.9113,-183.482 65.6698,-180.769 66.2131,-187.747"/>
147 </g>
148 <!-- yellow1&#45;&gt;yr1 -->
149 <g id="edge15" class="edge"><title>yellow1&#45;&gt;yr1</title>
150 <path fill="none" stroke="black" d="M139.886,-78.46C136.403,-71.8351 132.712,-64.8142 129.262,-58.2527"/>
151 <polygon fill="black" stroke="black" points="132.184,-56.2899 124.433,-49.0673 125.988,-59.5474 132.184,-56.2899"/>
152 </g>
153 <!-- red1&#45;&gt;rg1 -->
154 <g id="edge16" class="edge"><title>red1&#45;&gt;rg1</title>
155 <path fill="none" stroke="black" d="M12.6438,-90.7482C9.2669,-92.5011 5.7914,-94.3053 2.33239,-96.1008"/>
156 <polygon fill="black" stroke="black" points="0.556638,-93.0791 -6.70627,-100.793 3.78173,-99.2919 0.556638,-93.0791"/>
157 </g>
158 <!-- safe1&#45;&gt;rg1 -->
159 <g id="edge13" class="edge"><title>safe1&#45;&gt;rg1</title>
160 <path fill="none" stroke="black" d="M-76.8968,-78.4199C-72.3648,-82.3013 -67.5992,-86.3827 -62.9608,-90.3553"/>
161 <polygon fill="black" stroke="black" points="-65.2102,-93.037 -55.3383,-96.8835 -60.6568,-87.7203 -65.2102,-93.037"/>
162 </g>
163 </g>
164 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: TrafficLights Pages: 1 -->
6 <svg width="368pt" height="466pt"
7 viewBox="0.00 0.00 367.63 465.64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 461.64)">
9 <title>TrafficLights</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-461.64 363.63,-461.64 363.63,4 -4,4"/>
11 <text text-anchor="middle" x="179.81" y="-20.4" font-family="Times New Roman,serif" font-size="12.00">PetriNet Model TrafficLights</text>
12 <text text-anchor="middle" x="179.81" y="-7.4" font-family="Times New Roman,serif" font-size="12.00">Extracted from ConceptBase and layed out by Graphviz</text>
13 <!-- gy2 -->
14 <g id="node1" class="node">
15 <title>gy2</title>
16 <polygon fill="none" stroke="black" points="109.75,-90.45 55.75,-90.45 55.75,-54.45 109.75,-54.45 109.75,-90.45"/>
17 <text text-anchor="middle" x="82.75" y="-68.75" font-family="Times New Roman,serif" font-size="14.00">gy2</text>
18 </g>
19 <!-- yellow2 -->
20 <g id="node8" class="node">
21 <title>yellow2</title>
22 <ellipse fill="none" stroke="black" cx="32.5" cy="-142.4" rx="32.5" ry="32.5"/>
23 <text text-anchor="middle" x="32.5" y="-138.7" font-family="Times New Roman,serif" font-size="14.00">yellow2</text>
24 </g>
25 <!-- gy2&#45;&gt;yellow2 -->
26 <g id="edge1" class="edge">
27 <title>gy2&#45;&gt;yellow2</title>
28 <path fill="none" stroke="black" d="M69.81,-90.47C65.97,-95.81 61.63,-101.85 57.31,-107.87"/>
29 <polygon fill="black" stroke="black" points="54.45,-105.84 51.46,-116.01 60.14,-109.93 54.45,-105.84"/>
30 </g>
31 <!-- yr2 -->
32 <g id="node2" class="node">
33 <title>yr2</title>
34 <polygon fill="none" stroke="black" points="96.08,-234.82 42.08,-234.82 42.08,-198.82 96.08,-198.82 96.08,-234.82"/>
35 <text text-anchor="middle" x="69.08" y="-213.12" font-family="Times New Roman,serif" font-size="14.00">yr2</text>
36 </g>
37 <!-- red2 -->
38 <g id="node9" class="node">
39 <title>red2</title>
40 <ellipse fill="none" stroke="black" cx="138.59" cy="-174.42" rx="32.5" ry="32.5"/>
41 <text text-anchor="middle" x="138.59" y="-170.72" font-family="Times New Roman,serif" font-size="14.00">red2</text>
42 </g>
43 <!-- yr2&#45;&gt;red2 -->
44 <g id="edge4" class="edge">
45 <title>yr2&#45;&gt;red2</title>
46 <path fill="none" stroke="black" d="M96.15,-200.31C98.07,-199.13 100.03,-197.94 101.99,-196.75"/>
47 <polygon fill="black" stroke="black" points="103.84,-199.71 110.56,-191.52 100.2,-193.74 103.84,-199.71"/>
48 </g>
49 <!-- safe1 -->
50 <g id="node14" class="node">
51 <title>safe1</title>
52 <ellipse fill="none" stroke="black" cx="82.71" cy="-300.3" rx="32.5" ry="32.5"/>
53 <text text-anchor="middle" x="82.71" y="-296.6" font-family="Times New Roman,serif" font-size="14.00">safe1</text>
54 </g>
55 <!-- yr2&#45;&gt;safe1 -->
56 <g id="edge3" class="edge">
57 <title>yr2&#45;&gt;safe1</title>
58 <path fill="none" stroke="black" d="M72.04,-234.93C73.16,-241.82 74.5,-249.99 75.83,-258.17"/>
59 <polygon fill="black" stroke="black" points="72.39,-258.78 77.45,-268.08 79.29,-257.65 72.39,-258.78"/>
60 </g>
61 <!-- rg2 -->
62 <g id="node3" class="node">
63 <title>rg2</title>
64 <polygon fill="none" stroke="black" points="238.22,-155.29 184.22,-155.29 184.22,-119.29 238.22,-119.29 238.22,-155.29"/>
65 <text text-anchor="middle" x="211.22" y="-133.59" font-family="Times New Roman,serif" font-size="14.00">rg2</text>
66 </g>
67 <!-- green2 -->
68 <g id="node7" class="node">
69 <title>green2</title>
70 <ellipse fill="none" stroke="black" cx="168.57" cy="-66.5" rx="32.5" ry="32.5"/>
71 <text text-anchor="middle" x="168.57" y="-62.8" font-family="Times New Roman,serif" font-size="14.00">green2</text>
72 </g>
73 <!-- rg2&#45;&gt;green2 -->
74 <g id="edge2" class="edge">
75 <title>rg2&#45;&gt;green2</title>
76 <path fill="none" stroke="black" d="M200.23,-119.06C197.29,-114.17 193.99,-108.7 190.67,-103.18"/>
77 <polygon fill="black" stroke="black" points="193.63,-101.32 185.48,-94.57 187.64,-104.94 193.63,-101.32"/>
78 </g>
79 <!-- gy1 -->
80 <g id="node4" class="node">
81 <title>gy1</title>
82 <polygon fill="none" stroke="black" points="304.57,-436.45 250.57,-436.45 250.57,-400.45 304.57,-400.45 304.57,-436.45"/>
83 <text text-anchor="middle" x="277.57" y="-414.75" font-family="Times New Roman,serif" font-size="14.00">gy1</text>
84 </g>
85 <!-- yellow1 -->
86 <g id="node12" class="node">
87 <title>yellow1</title>
88 <ellipse fill="none" stroke="black" cx="327.13" cy="-348.16" rx="32.5" ry="32.5"/>
89 <text text-anchor="middle" x="327.13" y="-344.46" font-family="Times New Roman,serif" font-size="14.00">yellow1</text>
90 </g>
91 <!-- gy1&#45;&gt;yellow1 -->
92 <g id="edge9" class="edge">
93 <title>gy1&#45;&gt;yellow1</title>
94 <path fill="none" stroke="black" d="M290.33,-400.35C293.99,-395.16 298.11,-389.31 302.24,-383.46"/>
95 <polygon fill="black" stroke="black" points="305.33,-385.14 308.24,-374.95 299.61,-381.11 305.33,-385.14"/>
96 </g>
97 <!-- yr1 -->
98 <g id="node5" class="node">
99 <title>yr1</title>
100 <polygon fill="none" stroke="black" points="315.68,-293.03 261.68,-293.03 261.68,-257.03 315.68,-257.03 315.68,-293.03"/>
101 <text text-anchor="middle" x="288.68" y="-271.33" font-family="Times New Roman,serif" font-size="14.00">yr1</text>
102 </g>
103 <!-- safe2 -->
104 <g id="node10" class="node">
105 <title>safe2</title>
106 <ellipse fill="none" stroke="black" cx="275.71" cy="-191.67" rx="32.5" ry="32.5"/>
107 <text text-anchor="middle" x="275.71" y="-187.97" font-family="Times New Roman,serif" font-size="14.00">safe2</text>
108 </g>
109 <!-- yr1&#45;&gt;safe2 -->
110 <g id="edge11" class="edge">
111 <title>yr1&#45;&gt;safe2</title>
112 <path fill="none" stroke="black" d="M285.86,-256.94C284.79,-250.06 283.53,-241.91 282.25,-233.73"/>
113 <polygon fill="black" stroke="black" points="285.71,-233.18 280.72,-223.84 278.79,-234.26 285.71,-233.18"/>
114 </g>
115 <!-- red1 -->
116 <g id="node13" class="node">
117 <title>red1</title>
118 <ellipse fill="none" stroke="black" cx="219.22" cy="-317.81" rx="32.5" ry="32.5"/>
119 <text text-anchor="middle" x="219.22" y="-314.11" font-family="Times New Roman,serif" font-size="14.00">red1</text>
120 </g>
121 <!-- yr1&#45;&gt;red1 -->
122 <g id="edge12" class="edge">
123 <title>yr1&#45;&gt;red1</title>
124 <path fill="none" stroke="black" d="M261.62,-291.69C259.71,-292.87 257.75,-294.08 255.79,-295.28"/>
125 <polygon fill="black" stroke="black" points="253.91,-292.33 247.23,-300.56 257.58,-298.29 253.91,-292.33"/>
126 </g>
127 <!-- rg1 -->
128 <g id="node6" class="node">
129 <title>rg1</title>
130 <polygon fill="none" stroke="black" points="173.96,-373.32 119.96,-373.32 119.96,-337.32 173.96,-337.32 173.96,-373.32"/>
131 <text text-anchor="middle" x="146.96" y="-351.62" font-family="Times New Roman,serif" font-size="14.00">rg1</text>
132 </g>
133 <!-- green1 -->
134 <g id="node11" class="node">
135 <title>green1</title>
136 <ellipse fill="none" stroke="black" cx="191.7" cy="-425.14" rx="32.5" ry="32.5"/>
137 <text text-anchor="middle" x="191.7" y="-421.44" font-family="Times New Roman,serif" font-size="14.00">green1</text>
138 </g>
139 <!-- rg1&#45;&gt;green1 -->
140 <g id="edge10" class="edge">
141 <title>rg1&#45;&gt;green1</title>
142 <path fill="none" stroke="black" d="M158.72,-373.67C161.81,-378.49 165.25,-383.87 168.72,-389.27"/>
143 <polygon fill="black" stroke="black" points="165.79,-391.19 174.13,-397.72 171.68,-387.41 165.79,-391.19"/>
144 </g>
145 <!-- green2&#45;&gt;gy2 -->
146 <g id="edge6" class="edge">
147 <title>green2&#45;&gt;gy2</title>
148 <path fill="none" stroke="black" d="M136.12,-68.75C130.86,-69.11 125.37,-69.5 120,-69.87"/>
149 <polygon fill="black" stroke="black" points="119.65,-66.38 109.92,-70.57 120.14,-73.37 119.65,-66.38"/>
150 </g>
151 <!-- yellow2&#45;&gt;yr2 -->
152 <g id="edge7" class="edge">
153 <title>yellow2&#45;&gt;yr2</title>
154 <path fill="none" stroke="black" d="M46.96,-171.81C49.82,-177.64 52.82,-183.74 55.65,-189.5"/>
155 <polygon fill="black" stroke="black" points="52.65,-191.33 60.2,-198.76 58.93,-188.24 52.65,-191.33"/>
156 </g>
157 <!-- red2&#45;&gt;rg2 -->
158 <g id="edge8" class="edge">
159 <title>red2&#45;&gt;rg2</title>
160 <path fill="none" stroke="black" d="M167.71,-159.53C170.06,-158.33 172.45,-157.11 174.84,-155.89"/>
161 <polygon fill="black" stroke="black" points="176.66,-158.89 183.97,-151.22 173.48,-152.65 176.66,-158.89"/>
162 </g>
163 <!-- safe2&#45;&gt;rg2 -->
164 <g id="edge5" class="edge">
165 <title>safe2&#45;&gt;rg2</title>
166 <path fill="none" stroke="black" d="M250.59,-170.49C247.25,-167.67 243.8,-164.76 240.4,-161.89"/>
167 <polygon fill="black" stroke="black" points="242.51,-159.1 232.61,-155.33 238,-164.45 242.51,-159.1"/>
168 </g>
169 <!-- green1&#45;&gt;gy1 -->
170 <g id="edge14" class="edge">
171 <title>green1&#45;&gt;gy1</title>
172 <path fill="none" stroke="black" d="M224.17,-422.61C229.43,-422.2 234.92,-421.77 240.29,-421.35"/>
173 <polygon fill="black" stroke="black" points="240.68,-424.83 250.38,-420.57 240.14,-417.86 240.68,-424.83"/>
174 </g>
175 <!-- yellow1&#45;&gt;yr1 -->
176 <g id="edge15" class="edge">
177 <title>yellow1&#45;&gt;yr1</title>
178 <path fill="none" stroke="black" d="M311.93,-319.26C308.97,-313.63 305.88,-307.75 302.95,-302.18"/>
179 <polygon fill="black" stroke="black" points="305.98,-300.43 298.23,-293.21 299.79,-303.69 305.98,-300.43"/>
180 </g>
181 <!-- red1&#45;&gt;rg1 -->
182 <g id="edge16" class="edge">
183 <title>red1&#45;&gt;rg1</title>
184 <path fill="none" stroke="black" d="M190.25,-332.85C187.91,-334.07 185.53,-335.3 183.15,-336.54"/>
185 <polygon fill="black" stroke="black" points="181.33,-333.54 174.07,-341.25 184.55,-339.75 181.33,-333.54"/>
186 </g>
187 <!-- safe1&#45;&gt;rg1 -->
188 <g id="edge13" class="edge">
189 <title>safe1&#45;&gt;rg1</title>
190 <path fill="none" stroke="black" d="M107.74,-321.73C111.07,-324.58 114.5,-327.53 117.89,-330.43"/>
191 <polygon fill="black" stroke="black" points="115.78,-333.23 125.65,-337.07 120.33,-327.91 115.78,-333.23"/>
192 </g>
193 </g>
194 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.38.0 (20140413.2041)
4 -->
5 <!-- Title: unix Pages: 1 -->
6 <svg width="432pt" height="345pt"
7 viewBox="0.00 0.00 432.00 344.66" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(0.451132 0.451132) rotate(0) translate(4 760)">
9 <title>unix</title>
10 <polygon fill="white" stroke="none" points="-4,4 -4,-760 953.592,-760 953.592,4 -4,4"/>
11 <!-- 5th Edition -->
12 <g id="node1" class="node"><title>5th Edition</title>
13 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="581.247" cy="-738" rx="50.0912" ry="18"/>
14 <text text-anchor="middle" x="581.247" y="-734.3" font-family="Times New Roman,serif" font-size="14.00">5th Edition</text>
15 </g>
16 <!-- 6th Edition -->
17 <g id="node2" class="node"><title>6th Edition</title>
18 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="425.247" cy="-666" rx="50.0912" ry="18"/>
19 <text text-anchor="middle" x="425.247" y="-662.3" font-family="Times New Roman,serif" font-size="14.00">6th Edition</text>
20 </g>
21 <!-- 5th Edition&#45;&gt;6th Edition -->
22 <g id="edge1" class="edge"><title>5th Edition&#45;&gt;6th Edition</title>
23 <path fill="none" stroke="black" d="M551.169,-723.503C526.458,-712.415 491.271,-696.626 464.372,-684.556"/>
24 <polygon fill="black" stroke="black" points="465.79,-681.356 455.233,-680.455 462.924,-687.743 465.79,-681.356"/>
25 </g>
26 <!-- PWB 1.0 -->
27 <g id="node3" class="node"><title>PWB 1.0</title>
28 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="677.247" cy="-666" rx="44.393" ry="18"/>
29 <text text-anchor="middle" x="677.247" y="-662.3" font-family="Times New Roman,serif" font-size="14.00">PWB 1.0</text>
30 </g>
31 <!-- 5th Edition&#45;&gt;PWB 1.0 -->
32 <g id="edge2" class="edge"><title>5th Edition&#45;&gt;PWB 1.0</title>
33 <path fill="none" stroke="black" d="M602.553,-721.465C616.036,-711.633 633.641,-698.797 648.372,-688.055"/>
34 <polygon fill="black" stroke="black" points="650.642,-690.731 656.66,-682.011 646.518,-685.075 650.642,-690.731"/>
35 </g>
36 <!-- LSX -->
37 <g id="node4" class="node"><title>LSX</title>
38 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="587.247" cy="-594" rx="27.8951" ry="18"/>
39 <text text-anchor="middle" x="587.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">LSX</text>
40 </g>
41 <!-- 6th Edition&#45;&gt;LSX -->
42 <g id="edge3" class="edge"><title>6th Edition&#45;&gt;LSX</title>
43 <path fill="none" stroke="black" d="M456.695,-651.97C482.04,-641.396 518.551,-625.998 550.247,-612 552.042,-611.208 553.882,-610.387 555.737,-609.554"/>
44 <polygon fill="black" stroke="black" points="557.331,-612.675 564.991,-605.355 554.438,-606.3 557.331,-612.675"/>
45 </g>
46 <!-- 1 BSD -->
47 <g id="node5" class="node"><title>1 BSD</title>
48 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="127.247" cy="-594" rx="35.194" ry="18"/>
49 <text text-anchor="middle" x="127.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">1 BSD</text>
50 </g>
51 <!-- 6th Edition&#45;&gt;1 BSD -->
52 <g id="edge4" class="edge"><title>6th Edition&#45;&gt;1 BSD</title>
53 <path fill="none" stroke="black" d="M384.437,-655.414C327.595,-642.061 225.177,-618.004 168.239,-604.629"/>
54 <polygon fill="black" stroke="black" points="169.03,-601.219 158.494,-602.34 167.429,-608.034 169.03,-601.219"/>
55 </g>
56 <!-- Mini Unix -->
57 <g id="node6" class="node"><title>Mini Unix</title>
58 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="365.247" cy="-594" rx="46.2923" ry="18"/>
59 <text text-anchor="middle" x="365.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">Mini Unix</text>
60 </g>
61 <!-- 6th Edition&#45;&gt;Mini Unix -->
62 <g id="edge5" class="edge"><title>6th Edition&#45;&gt;Mini Unix</title>
63 <path fill="none" stroke="black" d="M411.028,-648.411C403.556,-639.693 394.258,-628.845 385.997,-619.208"/>
64 <polygon fill="black" stroke="black" points="388.53,-616.785 379.365,-611.47 383.215,-621.34 388.53,-616.785"/>
65 </g>
66 <!-- Wollongong -->
67 <g id="node7" class="node"><title>Wollongong</title>
68 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="485.247" cy="-594" rx="55.7903" ry="18"/>
69 <text text-anchor="middle" x="485.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">Wollongong</text>
70 </g>
71 <!-- 6th Edition&#45;&gt;Wollongong -->
72 <g id="edge6" class="edge"><title>6th Edition&#45;&gt;Wollongong</title>
73 <path fill="none" stroke="black" d="M439.467,-648.411C446.939,-639.693 456.237,-628.845 464.498,-619.208"/>
74 <polygon fill="black" stroke="black" points="467.28,-621.34 471.13,-611.47 461.965,-616.785 467.28,-621.34"/>
75 </g>
76 <!-- Interdata -->
77 <g id="node8" class="node"><title>Interdata</title>
78 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="259.247" cy="-594" rx="42.4939" ry="18"/>
79 <text text-anchor="middle" x="259.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">Interdata</text>
80 </g>
81 <!-- 6th Edition&#45;&gt;Interdata -->
82 <g id="edge7" class="edge"><title>6th Edition&#45;&gt;Interdata</title>
83 <path fill="none" stroke="black" d="M394.024,-651.834C366.685,-640.305 326.868,-623.515 297.598,-611.172"/>
84 <polygon fill="black" stroke="black" points="298.683,-607.831 288.109,-607.171 295.963,-614.281 298.683,-607.831"/>
85 </g>
86 <!-- PWB 1.2 -->
87 <g id="node28" class="node"><title>PWB 1.2</title>
88 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="677.247" cy="-594" rx="44.393" ry="18"/>
89 <text text-anchor="middle" x="677.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">PWB 1.2</text>
90 </g>
91 <!-- PWB 1.0&#45;&gt;PWB 1.2 -->
92 <g id="edge31" class="edge"><title>PWB 1.0&#45;&gt;PWB 1.2</title>
93 <path fill="none" stroke="black" d="M677.247,-647.697C677.247,-639.983 677.247,-630.712 677.247,-622.112"/>
94 <polygon fill="black" stroke="black" points="680.748,-622.104 677.247,-612.104 673.748,-622.104 680.748,-622.104"/>
95 </g>
96 <!-- USG 1.0 -->
97 <g id="node29" class="node"><title>USG 1.0</title>
98 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="782.247" cy="-594" rx="42.7926" ry="18"/>
99 <text text-anchor="middle" x="782.247" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">USG 1.0</text>
100 </g>
101 <!-- PWB 1.0&#45;&gt;USG 1.0 -->
102 <g id="edge32" class="edge"><title>PWB 1.0&#45;&gt;USG 1.0</title>
103 <path fill="none" stroke="black" d="M699.259,-650.326C714.519,-640.152 735.039,-626.472 751.856,-615.261"/>
104 <polygon fill="black" stroke="black" points="753.886,-618.114 760.265,-609.655 750.003,-612.29 753.886,-618.114"/>
105 </g>
106 <!-- 2 BSD -->
107 <g id="node19" class="node"><title>2 BSD</title>
108 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="89.2474" cy="-234" rx="35.194" ry="18"/>
109 <text text-anchor="middle" x="89.2474" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">2 BSD</text>
110 </g>
111 <!-- 1 BSD&#45;&gt;2 BSD -->
112 <g id="edge19" class="edge"><title>1 BSD&#45;&gt;2 BSD</title>
113 <path fill="none" stroke="black" d="M122.111,-576.134C114.533,-549.719 101.247,-496.865 101.247,-451 101.247,-451 101.247,-451 101.247,-377 101.247,-336.853 96.426,-290.548 92.8954,-262.022"/>
114 <polygon fill="black" stroke="black" points="96.3555,-261.487 91.6182,-252.01 89.4118,-262.373 96.3555,-261.487"/>
115 </g>
116 <!-- Unix/TS 3.0 -->
117 <g id="node9" class="node"><title>Unix/TS 3.0</title>
118 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="617.247" cy="-378" rx="55.4913" ry="18"/>
119 <text text-anchor="middle" x="617.247" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">Unix/TS 3.0</text>
120 </g>
121 <!-- Interdata&#45;&gt;Unix/TS 3.0 -->
122 <g id="edge8" class="edge"><title>Interdata&#45;&gt;Unix/TS 3.0</title>
123 <path fill="none" stroke="black" d="M282.737,-578.959C344.347,-542.13 510.807,-442.627 583.035,-399.451"/>
124 <polygon fill="black" stroke="black" points="584.982,-402.365 591.77,-394.229 581.391,-396.356 584.982,-402.365"/>
125 </g>
126 <!-- PWB 2.0 -->
127 <g id="node10" class="node"><title>PWB 2.0</title>
128 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="560.247" cy="-522" rx="44.393" ry="18"/>
129 <text text-anchor="middle" x="560.247" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">PWB 2.0</text>
130 </g>
131 <!-- Interdata&#45;&gt;PWB 2.0 -->
132 <g id="edge9" class="edge"><title>Interdata&#45;&gt;PWB 2.0</title>
133 <path fill="none" stroke="black" d="M290.605,-581.802C297.053,-579.71 303.833,-577.662 310.247,-576 394.292,-554.222 417.818,-560.235 502.247,-540 506.852,-538.896 511.635,-537.654 516.392,-536.355"/>
134 <polygon fill="black" stroke="black" points="517.371,-539.715 526.05,-533.638 515.476,-532.977 517.371,-539.715"/>
135 </g>
136 <!-- 7th Edition -->
137 <g id="node11" class="node"><title>7th Edition</title>
138 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="259.247" cy="-522" rx="50.0912" ry="18"/>
139 <text text-anchor="middle" x="259.247" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">7th Edition</text>
140 </g>
141 <!-- Interdata&#45;&gt;7th Edition -->
142 <g id="edge10" class="edge"><title>Interdata&#45;&gt;7th Edition</title>
143 <path fill="none" stroke="black" d="M259.247,-575.697C259.247,-567.983 259.247,-558.712 259.247,-550.112"/>
144 <polygon fill="black" stroke="black" points="262.748,-550.104 259.247,-540.104 255.748,-550.104 262.748,-550.104"/>
145 </g>
146 <!-- TS 4.0 -->
147 <g id="node38" class="node"><title>TS 4.0</title>
148 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="671.247" cy="-234" rx="35.9954" ry="18"/>
149 <text text-anchor="middle" x="671.247" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">TS 4.0</text>
150 </g>
151 <!-- Unix/TS 3.0&#45;&gt;TS 4.0 -->
152 <g id="edge44" class="edge"><title>Unix/TS 3.0&#45;&gt;TS 4.0</title>
153 <path fill="none" stroke="black" d="M623.761,-359.871C633.096,-335.325 650.355,-289.938 661.296,-261.17"/>
154 <polygon fill="black" stroke="black" points="664.595,-262.339 664.878,-251.748 658.052,-259.851 664.595,-262.339"/>
155 </g>
156 <!-- PWB 2.0&#45;&gt;Unix/TS 3.0 -->
157 <g id="edge42" class="edge"><title>PWB 2.0&#45;&gt;Unix/TS 3.0</title>
158 <path fill="none" stroke="black" d="M557.747,-503.773C555.824,-485.212 554.991,-455.216 565.247,-432 570.375,-420.393 579.248,-409.876 588.228,-401.327"/>
159 <polygon fill="black" stroke="black" points="590.597,-403.904 595.716,-394.627 585.929,-398.687 590.597,-403.904"/>
160 </g>
161 <!-- 8th Edition -->
162 <g id="node12" class="node"><title>8th Edition</title>
163 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="460.247" cy="-162" rx="50.0912" ry="18"/>
164 <text text-anchor="middle" x="460.247" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">8th Edition</text>
165 </g>
166 <!-- 7th Edition&#45;&gt;8th Edition -->
167 <g id="edge11" class="edge"><title>7th Edition&#45;&gt;8th Edition</title>
168 <path fill="none" stroke="black" d="M302.4,-512.879C347.423,-503.537 413.844,-487.017 431.247,-468 458.553,-438.161 450.247,-419.447 450.247,-379 450.247,-379 450.247,-379 450.247,-305 450.247,-264.897 454.265,-218.58 457.207,-190.04"/>
169 <polygon fill="black" stroke="black" points="460.696,-190.336 458.272,-180.022 453.735,-189.596 460.696,-190.336"/>
170 </g>
171 <!-- 32V -->
172 <g id="node13" class="node"><title>32V</title>
173 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="395.247" cy="-450" rx="27" ry="18"/>
174 <text text-anchor="middle" x="395.247" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">32V</text>
175 </g>
176 <!-- 7th Edition&#45;&gt;32V -->
177 <g id="edge12" class="edge"><title>7th Edition&#45;&gt;32V</title>
178 <path fill="none" stroke="black" d="M286.769,-506.834C309.554,-495.107 341.871,-478.473 365.3,-466.414"/>
179 <polygon fill="black" stroke="black" points="367.14,-469.403 374.43,-461.715 363.937,-463.179 367.14,-469.403"/>
180 </g>
181 <!-- V7M -->
182 <g id="node14" class="node"><title>V7M</title>
183 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="29.2474" cy="-378" rx="29.4969" ry="18"/>
184 <text text-anchor="middle" x="29.2474" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">V7M</text>
185 </g>
186 <!-- 7th Edition&#45;&gt;V7M -->
187 <g id="edge13" class="edge"><title>7th Edition&#45;&gt;V7M</title>
188 <path fill="none" stroke="black" d="M224.899,-508.836C199.981,-499.335 165.933,-484.928 138.247,-468 106.089,-448.337 73.1008,-420.047 51.9643,-400.672"/>
189 <polygon fill="black" stroke="black" points="54.1816,-397.955 44.4703,-393.719 49.4206,-403.086 54.1816,-397.955"/>
190 </g>
191 <!-- Ultrix&#45;11 -->
192 <g id="node15" class="node"><title>Ultrix&#45;11</title>
193 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="120.247" cy="-90" rx="42.4939" ry="18"/>
194 <text text-anchor="middle" x="120.247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">Ultrix&#45;11</text>
195 </g>
196 <!-- 7th Edition&#45;&gt;Ultrix&#45;11 -->
197 <g id="edge14" class="edge"><title>7th Edition&#45;&gt;Ultrix&#45;11</title>
198 <path fill="none" stroke="black" d="M225.626,-508.64C206.847,-500.043 184.606,-486.731 171.247,-468 147.762,-435.07 152.247,-419.447 152.247,-379 152.247,-379 152.247,-379 152.247,-233 152.247,-192.037 139.418,-146.018 130.006,-117.768"/>
199 <polygon fill="black" stroke="black" points="133.281,-116.528 126.723,-108.207 126.66,-118.801 133.281,-116.528"/>
200 </g>
201 <!-- Xenix -->
202 <g id="node16" class="node"><title>Xenix</title>
203 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="212.247" cy="-450" rx="31.6951" ry="18"/>
204 <text text-anchor="middle" x="212.247" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">Xenix</text>
205 </g>
206 <!-- 7th Edition&#45;&gt;Xenix -->
207 <g id="edge15" class="edge"><title>7th Edition&#45;&gt;Xenix</title>
208 <path fill="none" stroke="black" d="M248.109,-504.411C242.29,-495.744 235.057,-484.971 228.614,-475.375"/>
209 <polygon fill="black" stroke="black" points="231.462,-473.339 222.982,-466.988 225.651,-477.241 231.462,-473.339"/>
210 </g>
211 <!-- UniPlus+ -->
212 <g id="node17" class="node"><title>UniPlus+</title>
213 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="306.247" cy="-450" rx="44.393" ry="18"/>
214 <text text-anchor="middle" x="306.247" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">UniPlus+</text>
215 </g>
216 <!-- 7th Edition&#45;&gt;UniPlus+ -->
217 <g id="edge16" class="edge"><title>7th Edition&#45;&gt;UniPlus+</title>
218 <path fill="none" stroke="black" d="M270.386,-504.411C276.122,-495.868 283.232,-485.278 289.604,-475.787"/>
219 <polygon fill="black" stroke="black" points="292.52,-477.723 295.189,-467.47 286.709,-473.821 292.52,-477.723"/>
220 </g>
221 <!-- 9th Edition -->
222 <g id="node18" class="node"><title>9th Edition</title>
223 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="536.247" cy="-90" rx="50.0912" ry="18"/>
224 <text text-anchor="middle" x="536.247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">9th Edition</text>
225 </g>
226 <!-- 8th Edition&#45;&gt;9th Edition -->
227 <g id="edge18" class="edge"><title>8th Edition&#45;&gt;9th Edition</title>
228 <path fill="none" stroke="black" d="M477.874,-144.765C487.825,-135.6 500.421,-123.998 511.364,-113.919"/>
229 <polygon fill="black" stroke="black" points="513.994,-116.255 518.978,-106.906 509.251,-111.106 513.994,-116.255"/>
230 </g>
231 <!-- 3 BSD -->
232 <g id="node22" class="node"><title>3 BSD</title>
233 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="375.247" cy="-378" rx="35.194" ry="18"/>
234 <text text-anchor="middle" x="375.247" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">3 BSD</text>
235 </g>
236 <!-- 32V&#45;&gt;3 BSD -->
237 <g id="edge23" class="edge"><title>32V&#45;&gt;3 BSD</title>
238 <path fill="none" stroke="black" d="M390.406,-432.055C388.179,-424.261 385.482,-414.822 382.984,-406.079"/>
239 <polygon fill="black" stroke="black" points="386.296,-404.929 380.183,-396.275 379.565,-406.852 386.296,-404.929"/>
240 </g>
241 <!-- V7M&#45;&gt;Ultrix&#45;11 -->
242 <g id="edge17" class="edge"><title>V7M&#45;&gt;Ultrix&#45;11</title>
243 <path fill="none" stroke="black" d="M28.521,-359.567C27.8007,-329.461 28.6491,-266.131 45.2474,-216 57.7873,-178.126 83.3227,-139.498 101.094,-115.406"/>
244 <polygon fill="black" stroke="black" points="104.039,-117.312 107.251,-107.216 98.4443,-113.105 104.039,-117.312"/>
245 </g>
246 <!-- 2.8 BSD -->
247 <g id="node20" class="node"><title>2.8 BSD</title>
248 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="222.247" cy="-162" rx="42.4939" ry="18"/>
249 <text text-anchor="middle" x="222.247" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">2.8 BSD</text>
250 </g>
251 <!-- 2 BSD&#45;&gt;2.8 BSD -->
252 <g id="edge20" class="edge"><title>2 BSD&#45;&gt;2.8 BSD</title>
253 <path fill="none" stroke="black" d="M113.025,-220.485C133.737,-209.584 164.038,-193.637 187.473,-181.302"/>
254 <polygon fill="black" stroke="black" points="189.185,-184.357 196.404,-176.602 185.925,-178.162 189.185,-184.357"/>
255 </g>
256 <!-- 2.8 BSD&#45;&gt;Ultrix&#45;11 -->
257 <g id="edge21" class="edge"><title>2.8 BSD&#45;&gt;Ultrix&#45;11</title>
258 <path fill="none" stroke="black" d="M200.616,-146.155C185.912,-136.064 166.268,-122.583 150.081,-111.474"/>
259 <polygon fill="black" stroke="black" points="151.724,-108.356 141.498,-105.584 147.763,-114.128 151.724,-108.356"/>
260 </g>
261 <!-- 2.9 BSD -->
262 <g id="node21" class="node"><title>2.9 BSD</title>
263 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="222.247" cy="-90" rx="42.4939" ry="18"/>
264 <text text-anchor="middle" x="222.247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">2.9 BSD</text>
265 </g>
266 <!-- 2.8 BSD&#45;&gt;2.9 BSD -->
267 <g id="edge22" class="edge"><title>2.8 BSD&#45;&gt;2.9 BSD</title>
268 <path fill="none" stroke="black" d="M222.247,-143.697C222.247,-135.983 222.247,-126.712 222.247,-118.112"/>
269 <polygon fill="black" stroke="black" points="225.748,-118.104 222.247,-108.104 218.748,-118.104 225.748,-118.104"/>
270 </g>
271 <!-- 4 BSD -->
272 <g id="node23" class="node"><title>4 BSD</title>
273 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="372.247" cy="-306" rx="35.194" ry="18"/>
274 <text text-anchor="middle" x="372.247" y="-302.3" font-family="Times New Roman,serif" font-size="14.00">4 BSD</text>
275 </g>
276 <!-- 3 BSD&#45;&gt;4 BSD -->
277 <g id="edge24" class="edge"><title>3 BSD&#45;&gt;4 BSD</title>
278 <path fill="none" stroke="black" d="M374.506,-359.697C374.175,-351.983 373.778,-342.712 373.409,-334.112"/>
279 <polygon fill="black" stroke="black" points="376.906,-333.945 372.98,-324.104 369.912,-334.245 376.906,-333.945"/>
280 </g>
281 <!-- 4.1 BSD -->
282 <g id="node24" class="node"><title>4.1 BSD</title>
283 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="370.247" cy="-234" rx="42.4939" ry="18"/>
284 <text text-anchor="middle" x="370.247" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">4.1 BSD</text>
285 </g>
286 <!-- 4 BSD&#45;&gt;4.1 BSD -->
287 <g id="edge25" class="edge"><title>4 BSD&#45;&gt;4.1 BSD</title>
288 <path fill="none" stroke="black" d="M371.753,-287.697C371.533,-279.983 371.268,-270.712 371.022,-262.112"/>
289 <polygon fill="black" stroke="black" points="374.52,-262 370.736,-252.104 367.523,-262.2 374.52,-262"/>
290 </g>
291 <!-- 4.1 BSD&#45;&gt;8th Edition -->
292 <g id="edge28" class="edge"><title>4.1 BSD&#45;&gt;8th Edition</title>
293 <path fill="none" stroke="black" d="M389.776,-217.811C402.106,-208.221 418.241,-195.672 431.959,-185.002"/>
294 <polygon fill="black" stroke="black" points="434.389,-187.546 440.134,-178.644 430.091,-182.021 434.389,-187.546"/>
295 </g>
296 <!-- 4.1 BSD&#45;&gt;2.8 BSD -->
297 <g id="edge27" class="edge"><title>4.1 BSD&#45;&gt;2.8 BSD</title>
298 <path fill="none" stroke="black" d="M343.102,-220.161C319.393,-208.947 284.783,-192.578 258.671,-180.227"/>
299 <polygon fill="black" stroke="black" points="260.007,-176.988 249.471,-175.876 257.014,-183.316 260.007,-176.988"/>
300 </g>
301 <!-- 4.2 BSD -->
302 <g id="node25" class="node"><title>4.2 BSD</title>
303 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="350.247" cy="-162" rx="42.4939" ry="18"/>
304 <text text-anchor="middle" x="350.247" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">4.2 BSD</text>
305 </g>
306 <!-- 4.1 BSD&#45;&gt;4.2 BSD -->
307 <g id="edge26" class="edge"><title>4.1 BSD&#45;&gt;4.2 BSD</title>
308 <path fill="none" stroke="black" d="M365.406,-216.055C363.179,-208.261 360.482,-198.822 357.984,-190.079"/>
309 <polygon fill="black" stroke="black" points="361.296,-188.929 355.183,-180.275 354.565,-190.852 361.296,-188.929"/>
310 </g>
311 <!-- 4.3 BSD -->
312 <g id="node26" class="node"><title>4.3 BSD</title>
313 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="426.247" cy="-90" rx="42.4939" ry="18"/>
314 <text text-anchor="middle" x="426.247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">4.3 BSD</text>
315 </g>
316 <!-- 4.2 BSD&#45;&gt;4.3 BSD -->
317 <g id="edge29" class="edge"><title>4.2 BSD&#45;&gt;4.3 BSD</title>
318 <path fill="none" stroke="black" d="M367.114,-145.465C377.276,-136.105 390.395,-124.022 401.693,-113.616"/>
319 <polygon fill="black" stroke="black" points="404.181,-116.083 409.165,-106.734 399.438,-110.934 404.181,-116.083"/>
320 </g>
321 <!-- Ultrix&#45;32 -->
322 <g id="node27" class="node"><title>Ultrix&#45;32</title>
323 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="324.247" cy="-90" rx="42.4939" ry="18"/>
324 <text text-anchor="middle" x="324.247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">Ultrix&#45;32</text>
325 </g>
326 <!-- 4.2 BSD&#45;&gt;Ultrix&#45;32 -->
327 <g id="edge30" class="edge"><title>4.2 BSD&#45;&gt;Ultrix&#45;32</title>
328 <path fill="none" stroke="black" d="M343.954,-144.055C341.027,-136.176 337.476,-126.617 334.199,-117.794"/>
329 <polygon fill="black" stroke="black" points="337.427,-116.431 330.664,-108.275 330.865,-118.868 337.427,-116.431"/>
330 </g>
331 <!-- PWB 1.2&#45;&gt;PWB 2.0 -->
332 <g id="edge33" class="edge"><title>PWB 1.2&#45;&gt;PWB 2.0</title>
333 <path fill="none" stroke="black" d="M653.288,-578.666C635.858,-568.237 612.055,-553.996 592.888,-542.529"/>
334 <polygon fill="black" stroke="black" points="594.553,-539.446 584.174,-537.315 590.959,-545.453 594.553,-539.446"/>
335 </g>
336 <!-- CB Unix 1 -->
337 <g id="node30" class="node"><title>CB Unix 1</title>
338 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="834.247" cy="-522" rx="49.2915" ry="18"/>
339 <text text-anchor="middle" x="834.247" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">CB Unix 1</text>
340 </g>
341 <!-- USG 1.0&#45;&gt;CB Unix 1 -->
342 <g id="edge34" class="edge"><title>USG 1.0&#45;&gt;CB Unix 1</title>
343 <path fill="none" stroke="black" d="M794.571,-576.411C800.917,-567.868 808.783,-557.278 815.834,-547.787"/>
344 <polygon fill="black" stroke="black" points="818.859,-549.585 822.013,-539.47 813.24,-545.41 818.859,-549.585"/>
345 </g>
346 <!-- USG 2.0 -->
347 <g id="node31" class="node"><title>USG 2.0</title>
348 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="700.247" cy="-522" rx="42.7926" ry="18"/>
349 <text text-anchor="middle" x="700.247" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">USG 2.0</text>
350 </g>
351 <!-- USG 1.0&#45;&gt;USG 2.0 -->
352 <g id="edge35" class="edge"><title>USG 1.0&#45;&gt;USG 2.0</title>
353 <path fill="none" stroke="black" d="M764.049,-577.465C752.902,-567.949 738.458,-555.619 726.132,-545.097"/>
354 <polygon fill="black" stroke="black" points="728.273,-542.323 718.395,-538.492 723.728,-547.646 728.273,-542.323"/>
355 </g>
356 <!-- CB Unix 2 -->
357 <g id="node32" class="node"><title>CB Unix 2</title>
358 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="856.247" cy="-450" rx="49.2915" ry="18"/>
359 <text text-anchor="middle" x="856.247" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">CB Unix 2</text>
360 </g>
361 <!-- CB Unix 1&#45;&gt;CB Unix 2 -->
362 <g id="edge36" class="edge"><title>CB Unix 1&#45;&gt;CB Unix 2</title>
363 <path fill="none" stroke="black" d="M839.573,-504.055C842.023,-496.261 844.989,-486.822 847.737,-478.079"/>
364 <polygon fill="black" stroke="black" points="851.159,-478.865 850.818,-468.275 844.481,-476.766 851.159,-478.865"/>
365 </g>
366 <!-- USG 3.0 -->
367 <g id="node36" class="node"><title>USG 3.0</title>
368 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="617.247" cy="-450" rx="42.7926" ry="18"/>
369 <text text-anchor="middle" x="617.247" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">USG 3.0</text>
370 </g>
371 <!-- USG 2.0&#45;&gt;USG 3.0 -->
372 <g id="edge40" class="edge"><title>USG 2.0&#45;&gt;USG 3.0</title>
373 <path fill="none" stroke="black" d="M681.827,-505.465C670.544,-495.949 655.924,-483.619 643.448,-473.097"/>
374 <polygon fill="black" stroke="black" points="645.517,-470.263 635.616,-466.492 641.004,-475.614 645.517,-470.263"/>
375 </g>
376 <!-- CB Unix 3 -->
377 <g id="node33" class="node"><title>CB Unix 3</title>
378 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="798.247" cy="-378" rx="49.2915" ry="18"/>
379 <text text-anchor="middle" x="798.247" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">CB Unix 3</text>
380 </g>
381 <!-- CB Unix 2&#45;&gt;CB Unix 3 -->
382 <g id="edge37" class="edge"><title>CB Unix 2&#45;&gt;CB Unix 3</title>
383 <path fill="none" stroke="black" d="M842.502,-432.411C835.279,-423.693 826.291,-412.845 818.305,-403.208"/>
384 <polygon fill="black" stroke="black" points="820.969,-400.937 811.894,-395.47 815.579,-405.403 820.969,-400.937"/>
385 </g>
386 <!-- Unix/TS++ -->
387 <g id="node34" class="node"><title>Unix/TS++</title>
388 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="751.247" cy="-306" rx="51.9908" ry="18"/>
389 <text text-anchor="middle" x="751.247" y="-302.3" font-family="Times New Roman,serif" font-size="14.00">Unix/TS++</text>
390 </g>
391 <!-- CB Unix 3&#45;&gt;Unix/TS++ -->
392 <g id="edge38" class="edge"><title>CB Unix 3&#45;&gt;Unix/TS++</title>
393 <path fill="none" stroke="black" d="M787.109,-360.411C781.514,-352.077 774.611,-341.797 768.361,-332.488"/>
394 <polygon fill="black" stroke="black" points="771.112,-330.307 762.632,-323.956 765.301,-334.209 771.112,-330.307"/>
395 </g>
396 <!-- PDP&#45;11 Sys V -->
397 <g id="node35" class="node"><title>PDP&#45;11 Sys V</title>
398 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="885.247" cy="-306" rx="64.189" ry="18"/>
399 <text text-anchor="middle" x="885.247" y="-302.3" font-family="Times New Roman,serif" font-size="14.00">PDP&#45;11 Sys V</text>
400 </g>
401 <!-- CB Unix 3&#45;&gt;PDP&#45;11 Sys V -->
402 <g id="edge39" class="edge"><title>CB Unix 3&#45;&gt;PDP&#45;11 Sys V</title>
403 <path fill="none" stroke="black" d="M817.989,-361.116C829.504,-351.851 844.223,-340.008 856.955,-329.764"/>
404 <polygon fill="black" stroke="black" points="859.383,-332.303 864.98,-323.307 854.995,-326.849 859.383,-332.303"/>
405 </g>
406 <!-- CB Unix 3&#45;&gt;TS 4.0 -->
407 <g id="edge46" class="edge"><title>CB Unix 3&#45;&gt;TS 4.0</title>
408 <path fill="none" stroke="black" d="M758.713,-367.042C735.388,-359.15 707.204,-345.738 690.247,-324 676.618,-306.528 672.22,-281.486 671.029,-262.414"/>
409 <polygon fill="black" stroke="black" points="674.52,-262.113 670.656,-252.248 667.525,-262.37 674.52,-262.113"/>
410 </g>
411 <!-- Unix/TS++&#45;&gt;TS 4.0 -->
412 <g id="edge45" class="edge"><title>Unix/TS++&#45;&gt;TS 4.0</title>
413 <path fill="none" stroke="black" d="M733.094,-289.116C722.052,-279.454 707.805,-266.988 695.769,-256.456"/>
414 <polygon fill="black" stroke="black" points="698.065,-253.815 688.235,-249.864 693.456,-259.083 698.065,-253.815"/>
415 </g>
416 <!-- USG 3.0&#45;&gt;Unix/TS 3.0 -->
417 <g id="edge41" class="edge"><title>USG 3.0&#45;&gt;Unix/TS 3.0</title>
418 <path fill="none" stroke="black" d="M617.247,-431.697C617.247,-423.983 617.247,-414.712 617.247,-406.112"/>
419 <polygon fill="black" stroke="black" points="620.748,-406.104 617.247,-396.104 613.748,-406.104 620.748,-406.104"/>
420 </g>
421 <!-- Unix/TS 1.0 -->
422 <g id="node37" class="node"><title>Unix/TS 1.0</title>
423 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="733.247" cy="-450" rx="55.4913" ry="18"/>
424 <text text-anchor="middle" x="733.247" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">Unix/TS 1.0</text>
425 </g>
426 <!-- Unix/TS 1.0&#45;&gt;Unix/TS 3.0 -->
427 <g id="edge43" class="edge"><title>Unix/TS 1.0&#45;&gt;Unix/TS 3.0</title>
428 <path fill="none" stroke="black" d="M708.077,-433.811C691.356,-423.721 669.207,-410.355 650.968,-399.348"/>
429 <polygon fill="black" stroke="black" points="652.739,-396.329 642.369,-394.159 649.122,-402.323 652.739,-396.329"/>
430 </g>
431 <!-- System V.0 -->
432 <g id="node39" class="node"><title>System V.0</title>
433 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="671.247" cy="-162" rx="53.0913" ry="18"/>
434 <text text-anchor="middle" x="671.247" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">System V.0</text>
435 </g>
436 <!-- TS 4.0&#45;&gt;System V.0 -->
437 <g id="edge47" class="edge"><title>TS 4.0&#45;&gt;System V.0</title>
438 <path fill="none" stroke="black" d="M671.247,-215.697C671.247,-207.983 671.247,-198.712 671.247,-190.112"/>
439 <polygon fill="black" stroke="black" points="674.748,-190.104 671.247,-180.104 667.748,-190.104 674.748,-190.104"/>
440 </g>
441 <!-- System V.2 -->
442 <g id="node40" class="node"><title>System V.2</title>
443 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="671.247" cy="-90" rx="53.0913" ry="18"/>
444 <text text-anchor="middle" x="671.247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">System V.2</text>
445 </g>
446 <!-- System V.0&#45;&gt;System V.2 -->
447 <g id="edge48" class="edge"><title>System V.0&#45;&gt;System V.2</title>
448 <path fill="none" stroke="black" d="M671.247,-143.697C671.247,-135.983 671.247,-126.712 671.247,-118.112"/>
449 <polygon fill="black" stroke="black" points="674.748,-118.104 671.247,-108.104 667.748,-118.104 674.748,-118.104"/>
450 </g>
451 <!-- System V.3 -->
452 <g id="node41" class="node"><title>System V.3</title>
453 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="671.247" cy="-18" rx="53.0913" ry="18"/>
454 <text text-anchor="middle" x="671.247" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">System V.3</text>
455 </g>
456 <!-- System V.2&#45;&gt;System V.3 -->
457 <g id="edge49" class="edge"><title>System V.2&#45;&gt;System V.3</title>
458 <path fill="none" stroke="black" d="M671.247,-71.6966C671.247,-63.9827 671.247,-54.7125 671.247,-46.1124"/>
459 <polygon fill="black" stroke="black" points="674.748,-46.1043 671.247,-36.1043 667.748,-46.1044 674.748,-46.1043"/>
460 </g>
461 </g>
462 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Title: unix Pages: 1 -->
6 <svg width="432pt" height="339pt"
7 viewBox="0.00 0.00 432.00 339.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(0.44 0.44) rotate(0) translate(4 760)">
9 <title>unix</title>
10 <polygon fill="white" stroke="transparent" points="-4,4 -4,-760 969.59,-760 969.59,4 -4,4"/>
11 <!-- 5th Edition -->
12 <g id="node1" class="node">
13 <title>5th Edition</title>
14 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="511.25" cy="-738" rx="50.09" ry="18"/>
15 <text text-anchor="middle" x="511.25" y="-734.3" font-family="Times New Roman,serif" font-size="14.00">5th Edition</text>
16 </g>
17 <!-- 6th Edition -->
18 <g id="node2" class="node">
19 <title>6th Edition</title>
20 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="415.25" cy="-666" rx="50.09" ry="18"/>
21 <text text-anchor="middle" x="415.25" y="-662.3" font-family="Times New Roman,serif" font-size="14.00">6th Edition</text>
22 </g>
23 <!-- 5th Edition&#45;&gt;6th Edition -->
24 <g id="edge1" class="edge">
25 <title>5th Edition&#45;&gt;6th Edition</title>
26 <path fill="none" stroke="black" d="M489.94,-721.46C476.64,-711.77 459.34,-699.15 444.73,-688.5"/>
27 <polygon fill="black" stroke="black" points="446.64,-685.56 436.49,-682.49 442.51,-691.21 446.64,-685.56"/>
28 </g>
29 <!-- PWB 1.0 -->
30 <g id="node3" class="node">
31 <title>PWB 1.0</title>
32 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="667.25" cy="-666" rx="44.39" ry="18"/>
33 <text text-anchor="middle" x="667.25" y="-662.3" font-family="Times New Roman,serif" font-size="14.00">PWB 1.0</text>
34 </g>
35 <!-- 5th Edition&#45;&gt;PWB 1.0 -->
36 <g id="edge2" class="edge">
37 <title>5th Edition&#45;&gt;PWB 1.0</title>
38 <path fill="none" stroke="black" d="M541.33,-723.5C566.43,-712.24 602.35,-696.12 629.41,-683.98"/>
39 <polygon fill="black" stroke="black" points="630.89,-687.15 638.58,-679.86 628.02,-680.77 630.89,-687.15"/>
40 </g>
41 <!-- LSX -->
42 <g id="node4" class="node">
43 <title>LSX</title>
44 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="577.25" cy="-594" rx="27.9" ry="18"/>
45 <text text-anchor="middle" x="577.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">LSX</text>
46 </g>
47 <!-- 6th Edition&#45;&gt;LSX -->
48 <g id="edge3" class="edge">
49 <title>6th Edition&#45;&gt;LSX</title>
50 <path fill="none" stroke="black" d="M446.69,-651.97C472.04,-641.4 508.55,-626 540.25,-612 542.04,-611.21 543.88,-610.39 545.74,-609.55"/>
51 <polygon fill="black" stroke="black" points="547.33,-612.67 554.99,-605.36 544.44,-606.3 547.33,-612.67"/>
52 </g>
53 <!-- 1 BSD -->
54 <g id="node5" class="node">
55 <title>1 BSD</title>
56 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="120.25" cy="-594" rx="35.19" ry="18"/>
57 <text text-anchor="middle" x="120.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">1 BSD</text>
58 </g>
59 <!-- 6th Edition&#45;&gt;1 BSD -->
60 <g id="edge4" class="edge">
61 <title>6th Edition&#45;&gt;1 BSD</title>
62 <path fill="none" stroke="black" d="M374.54,-655.34C318.44,-642.03 217.93,-618.18 161.53,-604.8"/>
63 <polygon fill="black" stroke="black" points="162.07,-601.33 151.53,-602.42 160.46,-608.14 162.07,-601.33"/>
64 </g>
65 <!-- Mini Unix -->
66 <g id="node6" class="node">
67 <title>Mini Unix</title>
68 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="355.25" cy="-594" rx="46.29" ry="18"/>
69 <text text-anchor="middle" x="355.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">Mini Unix</text>
70 </g>
71 <!-- 6th Edition&#45;&gt;Mini Unix -->
72 <g id="edge5" class="edge">
73 <title>6th Edition&#45;&gt;Mini Unix</title>
74 <path fill="none" stroke="black" d="M401.03,-648.41C393.56,-639.69 384.26,-628.85 376,-619.21"/>
75 <polygon fill="black" stroke="black" points="378.53,-616.78 369.36,-611.47 373.22,-621.34 378.53,-616.78"/>
76 </g>
77 <!-- Wollongong -->
78 <g id="node7" class="node">
79 <title>Wollongong</title>
80 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="475.25" cy="-594" rx="55.79" ry="18"/>
81 <text text-anchor="middle" x="475.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">Wollongong</text>
82 </g>
83 <!-- 6th Edition&#45;&gt;Wollongong -->
84 <g id="edge6" class="edge">
85 <title>6th Edition&#45;&gt;Wollongong</title>
86 <path fill="none" stroke="black" d="M429.47,-648.41C436.94,-639.69 446.24,-628.85 454.5,-619.21"/>
87 <polygon fill="black" stroke="black" points="457.28,-621.34 461.13,-611.47 451.96,-616.78 457.28,-621.34"/>
88 </g>
89 <!-- Interdata -->
90 <g id="node8" class="node">
91 <title>Interdata</title>
92 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="249.25" cy="-594" rx="42.49" ry="18"/>
93 <text text-anchor="middle" x="249.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">Interdata</text>
94 </g>
95 <!-- 6th Edition&#45;&gt;Interdata -->
96 <g id="edge7" class="edge">
97 <title>6th Edition&#45;&gt;Interdata</title>
98 <path fill="none" stroke="black" d="M384.02,-651.83C356.69,-640.31 316.87,-623.51 287.6,-611.17"/>
99 <polygon fill="black" stroke="black" points="288.68,-607.83 278.11,-607.17 285.96,-614.28 288.68,-607.83"/>
100 </g>
101 <!-- PWB 1.2 -->
102 <g id="node28" class="node">
103 <title>PWB 1.2</title>
104 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="667.25" cy="-594" rx="44.39" ry="18"/>
105 <text text-anchor="middle" x="667.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">PWB 1.2</text>
106 </g>
107 <!-- PWB 1.0&#45;&gt;PWB 1.2 -->
108 <g id="edge31" class="edge">
109 <title>PWB 1.0&#45;&gt;PWB 1.2</title>
110 <path fill="none" stroke="black" d="M667.25,-647.7C667.25,-639.98 667.25,-630.71 667.25,-622.11"/>
111 <polygon fill="black" stroke="black" points="670.75,-622.1 667.25,-612.1 663.75,-622.1 670.75,-622.1"/>
112 </g>
113 <!-- USG 1.0 -->
114 <g id="node29" class="node">
115 <title>USG 1.0</title>
116 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="772.25" cy="-594" rx="42.79" ry="18"/>
117 <text text-anchor="middle" x="772.25" y="-590.3" font-family="Times New Roman,serif" font-size="14.00">USG 1.0</text>
118 </g>
119 <!-- PWB 1.0&#45;&gt;USG 1.0 -->
120 <g id="edge32" class="edge">
121 <title>PWB 1.0&#45;&gt;USG 1.0</title>
122 <path fill="none" stroke="black" d="M689.26,-650.33C704.52,-640.15 725.04,-626.47 741.86,-615.26"/>
123 <polygon fill="black" stroke="black" points="743.89,-618.11 750.26,-609.65 740,-612.29 743.89,-618.11"/>
124 </g>
125 <!-- 2 BSD -->
126 <g id="node19" class="node">
127 <title>2 BSD</title>
128 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="77.25" cy="-234" rx="35.19" ry="18"/>
129 <text text-anchor="middle" x="77.25" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">2 BSD</text>
130 </g>
131 <!-- 1 BSD&#45;&gt;2 BSD -->
132 <g id="edge19" class="edge">
133 <title>1 BSD&#45;&gt;2 BSD</title>
134 <path fill="none" stroke="black" d="M114.12,-576.21C105.09,-549.9 89.25,-497.18 89.25,-451 89.25,-451 89.25,-451 89.25,-377 89.25,-336.85 84.43,-290.55 80.9,-262.02"/>
135 <polygon fill="black" stroke="black" points="84.36,-261.49 79.62,-252.01 77.41,-262.37 84.36,-261.49"/>
136 </g>
137 <!-- Unix/TS 3.0 -->
138 <g id="node9" class="node">
139 <title>Unix/TS 3.0</title>
140 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="602.25" cy="-378" rx="55.49" ry="18"/>
141 <text text-anchor="middle" x="602.25" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">Unix/TS 3.0</text>
142 </g>
143 <!-- Interdata&#45;&gt;Unix/TS 3.0 -->
144 <g id="edge8" class="edge">
145 <title>Interdata&#45;&gt;Unix/TS 3.0</title>
146 <path fill="none" stroke="black" d="M272.68,-578.79C333.67,-541.82 497.51,-442.49 568.59,-399.41"/>
147 <polygon fill="black" stroke="black" points="570.44,-402.37 577.18,-394.2 566.81,-396.39 570.44,-402.37"/>
148 </g>
149 <!-- PWB 2.0 -->
150 <g id="node10" class="node">
151 <title>PWB 2.0</title>
152 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="548.25" cy="-522" rx="44.39" ry="18"/>
153 <text text-anchor="middle" x="548.25" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">PWB 2.0</text>
154 </g>
155 <!-- Interdata&#45;&gt;PWB 2.0 -->
156 <g id="edge9" class="edge">
157 <title>Interdata&#45;&gt;PWB 2.0</title>
158 <path fill="none" stroke="black" d="M280.61,-581.81C287.06,-579.72 293.83,-577.67 300.25,-576 383.43,-554.36 406.69,-560.11 490.25,-540 494.85,-538.89 499.63,-537.65 504.39,-536.35"/>
159 <polygon fill="black" stroke="black" points="505.37,-539.71 514.05,-533.63 503.47,-532.97 505.37,-539.71"/>
160 </g>
161 <!-- 7th Edition -->
162 <g id="node11" class="node">
163 <title>7th Edition</title>
164 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="249.25" cy="-522" rx="50.09" ry="18"/>
165 <text text-anchor="middle" x="249.25" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">7th Edition</text>
166 </g>
167 <!-- Interdata&#45;&gt;7th Edition -->
168 <g id="edge10" class="edge">
169 <title>Interdata&#45;&gt;7th Edition</title>
170 <path fill="none" stroke="black" d="M249.25,-575.7C249.25,-567.98 249.25,-558.71 249.25,-550.11"/>
171 <polygon fill="black" stroke="black" points="252.75,-550.1 249.25,-540.1 245.75,-550.1 252.75,-550.1"/>
172 </g>
173 <!-- TS 4.0 -->
174 <g id="node38" class="node">
175 <title>TS 4.0</title>
176 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="687.25" cy="-234" rx="36" ry="18"/>
177 <text text-anchor="middle" x="687.25" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">TS 4.0</text>
178 </g>
179 <!-- Unix/TS 3.0&#45;&gt;TS 4.0 -->
180 <g id="edge44" class="edge">
181 <title>Unix/TS 3.0&#45;&gt;TS 4.0</title>
182 <path fill="none" stroke="black" d="M612.33,-360.15C627.17,-335.36 655,-288.88 672.24,-260.07"/>
183 <polygon fill="black" stroke="black" points="675.31,-261.76 677.44,-251.39 669.3,-258.17 675.31,-261.76"/>
184 </g>
185 <!-- PWB 2.0&#45;&gt;Unix/TS 3.0 -->
186 <g id="edge42" class="edge">
187 <title>PWB 2.0&#45;&gt;Unix/TS 3.0</title>
188 <path fill="none" stroke="black" d="M545.02,-503.83C542.35,-485.31 540.4,-455.35 550.25,-432 555.14,-420.4 563.87,-409.94 572.79,-401.43"/>
189 <polygon fill="black" stroke="black" points="575.13,-404.04 580.25,-394.77 570.46,-398.82 575.13,-404.04"/>
190 </g>
191 <!-- 8th Edition -->
192 <g id="node12" class="node">
193 <title>8th Edition</title>
194 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="448.25" cy="-162" rx="50.09" ry="18"/>
195 <text text-anchor="middle" x="448.25" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">8th Edition</text>
196 </g>
197 <!-- 7th Edition&#45;&gt;8th Edition -->
198 <g id="edge11" class="edge">
199 <title>7th Edition&#45;&gt;8th Edition</title>
200 <path fill="none" stroke="black" d="M292.31,-512.73C336.8,-503.31 402.11,-486.79 419.25,-468 446.5,-438.12 438.25,-419.45 438.25,-379 438.25,-379 438.25,-379 438.25,-305 438.25,-264.9 442.27,-218.58 445.21,-190.04"/>
201 <polygon fill="black" stroke="black" points="448.7,-190.34 446.27,-180.02 441.73,-189.6 448.7,-190.34"/>
202 </g>
203 <!-- 32V -->
204 <g id="node13" class="node">
205 <title>32V</title>
206 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="383.25" cy="-450" rx="27" ry="18"/>
207 <text text-anchor="middle" x="383.25" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">32V</text>
208 </g>
209 <!-- 7th Edition&#45;&gt;32V -->
210 <g id="edge12" class="edge">
211 <title>7th Edition&#45;&gt;32V</title>
212 <path fill="none" stroke="black" d="M276.36,-506.83C298.81,-495.11 330.66,-478.47 353.74,-466.41"/>
213 <polygon fill="black" stroke="black" points="355.49,-469.45 362.74,-461.71 352.25,-463.24 355.49,-469.45"/>
214 </g>
215 <!-- V7M -->
216 <g id="node14" class="node">
217 <title>V7M</title>
218 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="29.25" cy="-378" rx="29.5" ry="18"/>
219 <text text-anchor="middle" x="29.25" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">V7M</text>
220 </g>
221 <!-- 7th Edition&#45;&gt;V7M -->
222 <g id="edge13" class="edge">
223 <title>7th Edition&#45;&gt;V7M</title>
224 <path fill="none" stroke="black" d="M213.74,-509.31C188.29,-500.09 153.77,-485.82 126.25,-468 97.08,-449.11 68.34,-421.26 49.81,-401.76"/>
225 <polygon fill="black" stroke="black" points="52.15,-399.14 42.76,-394.22 47.03,-403.92 52.15,-399.14"/>
226 </g>
227 <!-- Ultrix&#45;11 -->
228 <g id="node15" class="node">
229 <title>Ultrix&#45;11</title>
230 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="108.25" cy="-90" rx="42.49" ry="18"/>
231 <text text-anchor="middle" x="108.25" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">Ultrix&#45;11</text>
232 </g>
233 <!-- 7th Edition&#45;&gt;Ultrix&#45;11 -->
234 <g id="edge14" class="edge">
235 <title>7th Edition&#45;&gt;Ultrix&#45;11</title>
236 <path fill="none" stroke="black" d="M214.87,-508.82C195.67,-500.29 172.92,-486.98 159.25,-468 135.6,-435.19 140.25,-419.45 140.25,-379 140.25,-379 140.25,-379 140.25,-233 140.25,-192.04 127.42,-146.02 118.01,-117.77"/>
237 <polygon fill="black" stroke="black" points="121.28,-116.53 114.72,-108.21 114.66,-118.8 121.28,-116.53"/>
238 </g>
239 <!-- Xenix -->
240 <g id="node16" class="node">
241 <title>Xenix</title>
242 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="200.25" cy="-450" rx="31.7" ry="18"/>
243 <text text-anchor="middle" x="200.25" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">Xenix</text>
244 </g>
245 <!-- 7th Edition&#45;&gt;Xenix -->
246 <g id="edge15" class="edge">
247 <title>7th Edition&#45;&gt;Xenix</title>
248 <path fill="none" stroke="black" d="M237.64,-504.41C231.57,-495.74 224.03,-484.97 217.31,-475.38"/>
249 <polygon fill="black" stroke="black" points="220.04,-473.17 211.44,-466.99 214.31,-477.19 220.04,-473.17"/>
250 </g>
251 <!-- UniPlus+ -->
252 <g id="node17" class="node">
253 <title>UniPlus+</title>
254 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="294.25" cy="-450" rx="44.39" ry="18"/>
255 <text text-anchor="middle" x="294.25" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">UniPlus+</text>
256 </g>
257 <!-- 7th Edition&#45;&gt;UniPlus+ -->
258 <g id="edge16" class="edge">
259 <title>7th Edition&#45;&gt;UniPlus+</title>
260 <path fill="none" stroke="black" d="M259.91,-504.41C265.27,-496.08 271.88,-485.8 277.86,-476.49"/>
261 <polygon fill="black" stroke="black" points="280.88,-478.26 283.35,-467.96 275,-474.48 280.88,-478.26"/>
262 </g>
263 <!-- 9th Edition -->
264 <g id="node18" class="node">
265 <title>9th Edition</title>
266 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="524.25" cy="-90" rx="50.09" ry="18"/>
267 <text text-anchor="middle" x="524.25" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">9th Edition</text>
268 </g>
269 <!-- 8th Edition&#45;&gt;9th Edition -->
270 <g id="edge18" class="edge">
271 <title>8th Edition&#45;&gt;9th Edition</title>
272 <path fill="none" stroke="black" d="M465.87,-144.76C475.82,-135.6 488.42,-124 499.36,-113.92"/>
273 <polygon fill="black" stroke="black" points="501.99,-116.26 506.98,-106.91 497.25,-111.11 501.99,-116.26"/>
274 </g>
275 <!-- 3 BSD -->
276 <g id="node22" class="node">
277 <title>3 BSD</title>
278 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="372.25" cy="-378" rx="35.19" ry="18"/>
279 <text text-anchor="middle" x="372.25" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">3 BSD</text>
280 </g>
281 <!-- 32V&#45;&gt;3 BSD -->
282 <g id="edge23" class="edge">
283 <title>32V&#45;&gt;3 BSD</title>
284 <path fill="none" stroke="black" d="M380.58,-432.05C379.37,-424.35 377.91,-415.03 376.55,-406.36"/>
285 <polygon fill="black" stroke="black" points="379.97,-405.61 374.96,-396.28 373.06,-406.7 379.97,-405.61"/>
286 </g>
287 <!-- V7M&#45;&gt;Ultrix&#45;11 -->
288 <g id="edge17" class="edge">
289 <title>V7M&#45;&gt;Ultrix&#45;11</title>
290 <path fill="none" stroke="black" d="M26.84,-359.64C23.3,-329.65 18.59,-266.48 33.25,-216 44.37,-177.69 70.24,-139.16 88.47,-115.21"/>
291 <polygon fill="black" stroke="black" points="91.42,-117.12 94.8,-107.07 85.89,-112.82 91.42,-117.12"/>
292 </g>
293 <!-- 2.8 BSD -->
294 <g id="node20" class="node">
295 <title>2.8 BSD</title>
296 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="210.25" cy="-162" rx="42.49" ry="18"/>
297 <text text-anchor="middle" x="210.25" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">2.8 BSD</text>
298 </g>
299 <!-- 2 BSD&#45;&gt;2.8 BSD -->
300 <g id="edge20" class="edge">
301 <title>2 BSD&#45;&gt;2.8 BSD</title>
302 <path fill="none" stroke="black" d="M101.03,-220.49C121.74,-209.58 152.04,-193.64 175.47,-181.3"/>
303 <polygon fill="black" stroke="black" points="177.18,-184.36 184.4,-176.6 173.92,-178.16 177.18,-184.36"/>
304 </g>
305 <!-- 2.8 BSD&#45;&gt;Ultrix&#45;11 -->
306 <g id="edge21" class="edge">
307 <title>2.8 BSD&#45;&gt;Ultrix&#45;11</title>
308 <path fill="none" stroke="black" d="M188.62,-146.15C173.91,-136.06 154.27,-122.58 138.08,-111.47"/>
309 <polygon fill="black" stroke="black" points="139.72,-108.36 129.5,-105.58 135.76,-114.13 139.72,-108.36"/>
310 </g>
311 <!-- 2.9 BSD -->
312 <g id="node21" class="node">
313 <title>2.9 BSD</title>
314 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="210.25" cy="-90" rx="42.49" ry="18"/>
315 <text text-anchor="middle" x="210.25" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">2.9 BSD</text>
316 </g>
317 <!-- 2.8 BSD&#45;&gt;2.9 BSD -->
318 <g id="edge22" class="edge">
319 <title>2.8 BSD&#45;&gt;2.9 BSD</title>
320 <path fill="none" stroke="black" d="M210.25,-143.7C210.25,-135.98 210.25,-126.71 210.25,-118.11"/>
321 <polygon fill="black" stroke="black" points="213.75,-118.1 210.25,-108.1 206.75,-118.1 213.75,-118.1"/>
322 </g>
323 <!-- 4 BSD -->
324 <g id="node23" class="node">
325 <title>4 BSD</title>
326 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="360.25" cy="-306" rx="35.19" ry="18"/>
327 <text text-anchor="middle" x="360.25" y="-302.3" font-family="Times New Roman,serif" font-size="14.00">4 BSD</text>
328 </g>
329 <!-- 3 BSD&#45;&gt;4 BSD -->
330 <g id="edge24" class="edge">
331 <title>3 BSD&#45;&gt;4 BSD</title>
332 <path fill="none" stroke="black" d="M369.34,-360.05C368.02,-352.35 366.42,-343.03 364.94,-334.36"/>
333 <polygon fill="black" stroke="black" points="368.35,-333.54 363.21,-324.28 361.45,-334.72 368.35,-333.54"/>
334 </g>
335 <!-- 4.1 BSD -->
336 <g id="node24" class="node">
337 <title>4.1 BSD</title>
338 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="358.25" cy="-234" rx="42.49" ry="18"/>
339 <text text-anchor="middle" x="358.25" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">4.1 BSD</text>
340 </g>
341 <!-- 4 BSD&#45;&gt;4.1 BSD -->
342 <g id="edge25" class="edge">
343 <title>4 BSD&#45;&gt;4.1 BSD</title>
344 <path fill="none" stroke="black" d="M359.75,-287.7C359.53,-279.98 359.27,-270.71 359.02,-262.11"/>
345 <polygon fill="black" stroke="black" points="362.52,-262 358.74,-252.1 355.52,-262.2 362.52,-262"/>
346 </g>
347 <!-- 4.1 BSD&#45;&gt;8th Edition -->
348 <g id="edge28" class="edge">
349 <title>4.1 BSD&#45;&gt;8th Edition</title>
350 <path fill="none" stroke="black" d="M377.78,-217.81C390.11,-208.22 406.24,-195.67 419.96,-185"/>
351 <polygon fill="black" stroke="black" points="422.39,-187.55 428.13,-178.64 418.09,-182.02 422.39,-187.55"/>
352 </g>
353 <!-- 4.1 BSD&#45;&gt;2.8 BSD -->
354 <g id="edge27" class="edge">
355 <title>4.1 BSD&#45;&gt;2.8 BSD</title>
356 <path fill="none" stroke="black" d="M331.1,-220.16C307.39,-208.95 272.78,-192.58 246.67,-180.23"/>
357 <polygon fill="black" stroke="black" points="248.01,-176.99 237.47,-175.88 245.01,-183.32 248.01,-176.99"/>
358 </g>
359 <!-- 4.2 BSD -->
360 <g id="node25" class="node">
361 <title>4.2 BSD</title>
362 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="338.25" cy="-162" rx="42.49" ry="18"/>
363 <text text-anchor="middle" x="338.25" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">4.2 BSD</text>
364 </g>
365 <!-- 4.1 BSD&#45;&gt;4.2 BSD -->
366 <g id="edge26" class="edge">
367 <title>4.1 BSD&#45;&gt;4.2 BSD</title>
368 <path fill="none" stroke="black" d="M353.41,-216.05C351.18,-208.26 348.48,-198.82 345.98,-190.08"/>
369 <polygon fill="black" stroke="black" points="349.3,-188.93 343.18,-180.28 342.57,-190.85 349.3,-188.93"/>
370 </g>
371 <!-- 4.3 BSD -->
372 <g id="node26" class="node">
373 <title>4.3 BSD</title>
374 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="414.25" cy="-90" rx="42.49" ry="18"/>
375 <text text-anchor="middle" x="414.25" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">4.3 BSD</text>
376 </g>
377 <!-- 4.2 BSD&#45;&gt;4.3 BSD -->
378 <g id="edge29" class="edge">
379 <title>4.2 BSD&#45;&gt;4.3 BSD</title>
380 <path fill="none" stroke="black" d="M355.11,-145.46C365.28,-136.11 378.39,-124.02 389.69,-113.62"/>
381 <polygon fill="black" stroke="black" points="392.18,-116.08 397.16,-106.73 387.44,-110.93 392.18,-116.08"/>
382 </g>
383 <!-- Ultrix&#45;32 -->
384 <g id="node27" class="node">
385 <title>Ultrix&#45;32</title>
386 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="312.25" cy="-90" rx="42.49" ry="18"/>
387 <text text-anchor="middle" x="312.25" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">Ultrix&#45;32</text>
388 </g>
389 <!-- 4.2 BSD&#45;&gt;Ultrix&#45;32 -->
390 <g id="edge30" class="edge">
391 <title>4.2 BSD&#45;&gt;Ultrix&#45;32</title>
392 <path fill="none" stroke="black" d="M331.95,-144.05C329.03,-136.18 325.48,-126.62 322.2,-117.79"/>
393 <polygon fill="black" stroke="black" points="325.43,-116.43 318.66,-108.28 318.86,-118.87 325.43,-116.43"/>
394 </g>
395 <!-- PWB 1.2&#45;&gt;PWB 2.0 -->
396 <g id="edge33" class="edge">
397 <title>PWB 1.2&#45;&gt;PWB 2.0</title>
398 <path fill="none" stroke="black" d="M643.17,-578.83C625.26,-568.3 600.63,-553.81 580.95,-542.24"/>
399 <polygon fill="black" stroke="black" points="582.69,-539.2 572.29,-537.14 579.14,-545.23 582.69,-539.2"/>
400 </g>
401 <!-- CB Unix 1 -->
402 <g id="node30" class="node">
403 <title>CB Unix 1</title>
404 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="803.25" cy="-522" rx="49.29" ry="18"/>
405 <text text-anchor="middle" x="803.25" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">CB Unix 1</text>
406 </g>
407 <!-- USG 1.0&#45;&gt;CB Unix 1 -->
408 <g id="edge34" class="edge">
409 <title>USG 1.0&#45;&gt;CB Unix 1</title>
410 <path fill="none" stroke="black" d="M779.75,-576.05C783.28,-568.09 787.57,-558.41 791.51,-549.51"/>
411 <polygon fill="black" stroke="black" points="794.75,-550.84 795.6,-540.28 788.35,-548 794.75,-550.84"/>
412 </g>
413 <!-- USG 2.0 -->
414 <g id="node31" class="node">
415 <title>USG 2.0</title>
416 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="680.25" cy="-522" rx="42.79" ry="18"/>
417 <text text-anchor="middle" x="680.25" y="-518.3" font-family="Times New Roman,serif" font-size="14.00">USG 2.0</text>
418 </g>
419 <!-- USG 1.0&#45;&gt;USG 2.0 -->
420 <g id="edge35" class="edge">
421 <title>USG 1.0&#45;&gt;USG 2.0</title>
422 <path fill="none" stroke="black" d="M752.28,-577.81C739.39,-568 722.41,-555.08 708.18,-544.25"/>
423 <polygon fill="black" stroke="black" points="710.25,-541.43 700.17,-538.16 706.01,-547 710.25,-541.43"/>
424 </g>
425 <!-- CB Unix 2 -->
426 <g id="node32" class="node">
427 <title>CB Unix 2</title>
428 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="841.25" cy="-450" rx="49.29" ry="18"/>
429 <text text-anchor="middle" x="841.25" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">CB Unix 2</text>
430 </g>
431 <!-- CB Unix 1&#45;&gt;CB Unix 2 -->
432 <g id="edge36" class="edge">
433 <title>CB Unix 1&#45;&gt;CB Unix 2</title>
434 <path fill="none" stroke="black" d="M812.45,-504.05C816.88,-495.89 822.3,-485.91 827.23,-476.82"/>
435 <polygon fill="black" stroke="black" points="830.44,-478.25 832.13,-467.79 824.29,-474.91 830.44,-478.25"/>
436 </g>
437 <!-- USG 3.0 -->
438 <g id="node36" class="node">
439 <title>USG 3.0</title>
440 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="602.25" cy="-450" rx="42.79" ry="18"/>
441 <text text-anchor="middle" x="602.25" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">USG 3.0</text>
442 </g>
443 <!-- USG 2.0&#45;&gt;USG 3.0 -->
444 <g id="edge40" class="edge">
445 <title>USG 2.0&#45;&gt;USG 3.0</title>
446 <path fill="none" stroke="black" d="M662.94,-505.46C652.43,-496.04 638.86,-483.85 627.21,-473.4"/>
447 <polygon fill="black" stroke="black" points="629.29,-470.57 619.51,-466.49 624.61,-475.78 629.29,-470.57"/>
448 </g>
449 <!-- CB Unix 3 -->
450 <g id="node33" class="node">
451 <title>CB Unix 3</title>
452 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="783.25" cy="-378" rx="49.29" ry="18"/>
453 <text text-anchor="middle" x="783.25" y="-374.3" font-family="Times New Roman,serif" font-size="14.00">CB Unix 3</text>
454 </g>
455 <!-- CB Unix 2&#45;&gt;CB Unix 3 -->
456 <g id="edge37" class="edge">
457 <title>CB Unix 2&#45;&gt;CB Unix 3</title>
458 <path fill="none" stroke="black" d="M827.5,-432.41C820.28,-423.69 811.29,-412.85 803.31,-403.21"/>
459 <polygon fill="black" stroke="black" points="805.97,-400.94 796.89,-395.47 800.58,-405.4 805.97,-400.94"/>
460 </g>
461 <!-- Unix/TS++ -->
462 <g id="node34" class="node">
463 <title>Unix/TS++</title>
464 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="767.25" cy="-306" rx="51.99" ry="18"/>
465 <text text-anchor="middle" x="767.25" y="-302.3" font-family="Times New Roman,serif" font-size="14.00">Unix/TS++</text>
466 </g>
467 <!-- CB Unix 3&#45;&gt;Unix/TS++ -->
468 <g id="edge38" class="edge">
469 <title>CB Unix 3&#45;&gt;Unix/TS++</title>
470 <path fill="none" stroke="black" d="M779.37,-360.05C777.59,-352.26 775.44,-342.82 773.44,-334.08"/>
471 <polygon fill="black" stroke="black" points="776.84,-333.24 771.2,-324.28 770.01,-334.8 776.84,-333.24"/>
472 </g>
473 <!-- PDP&#45;11 Sys V -->
474 <g id="node35" class="node">
475 <title>PDP&#45;11 Sys V</title>
476 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="901.25" cy="-306" rx="64.19" ry="18"/>
477 <text text-anchor="middle" x="901.25" y="-302.3" font-family="Times New Roman,serif" font-size="14.00">PDP&#45;11 Sys V</text>
478 </g>
479 <!-- CB Unix 3&#45;&gt;PDP&#45;11 Sys V -->
480 <g id="edge39" class="edge">
481 <title>CB Unix 3&#45;&gt;PDP&#45;11 Sys V</title>
482 <path fill="none" stroke="black" d="M807.98,-362.33C824.83,-352.33 847.37,-338.96 866.07,-327.87"/>
483 <polygon fill="black" stroke="black" points="868.09,-330.74 874.9,-322.63 864.52,-324.72 868.09,-330.74"/>
484 </g>
485 <!-- CB Unix 3&#45;&gt;TS 4.0 -->
486 <g id="edge46" class="edge">
487 <title>CB Unix 3&#45;&gt;TS 4.0</title>
488 <path fill="none" stroke="black" d="M753.4,-363.45C737.04,-354.52 717.79,-341.27 706.25,-324 694.01,-305.69 689.46,-280.92 687.86,-262.17"/>
489 <polygon fill="black" stroke="black" points="691.36,-261.94 687.24,-252.18 684.37,-262.38 691.36,-261.94"/>
490 </g>
491 <!-- Unix/TS++&#45;&gt;TS 4.0 -->
492 <g id="edge45" class="edge">
493 <title>Unix/TS++&#45;&gt;TS 4.0</title>
494 <path fill="none" stroke="black" d="M749.09,-289.12C738.05,-279.45 723.8,-266.99 711.77,-256.46"/>
495 <polygon fill="black" stroke="black" points="714.07,-253.81 704.23,-249.86 709.46,-259.08 714.07,-253.81"/>
496 </g>
497 <!-- USG 3.0&#45;&gt;Unix/TS 3.0 -->
498 <g id="edge41" class="edge">
499 <title>USG 3.0&#45;&gt;Unix/TS 3.0</title>
500 <path fill="none" stroke="black" d="M602.25,-431.7C602.25,-423.98 602.25,-414.71 602.25,-406.11"/>
501 <polygon fill="black" stroke="black" points="605.75,-406.1 602.25,-396.1 598.75,-406.1 605.75,-406.1"/>
502 </g>
503 <!-- Unix/TS 1.0 -->
504 <g id="node37" class="node">
505 <title>Unix/TS 1.0</title>
506 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="718.25" cy="-450" rx="55.49" ry="18"/>
507 <text text-anchor="middle" x="718.25" y="-446.3" font-family="Times New Roman,serif" font-size="14.00">Unix/TS 1.0</text>
508 </g>
509 <!-- Unix/TS 1.0&#45;&gt;Unix/TS 3.0 -->
510 <g id="edge43" class="edge">
511 <title>Unix/TS 1.0&#45;&gt;Unix/TS 3.0</title>
512 <path fill="none" stroke="black" d="M693.08,-433.81C676.36,-423.72 654.21,-410.36 635.97,-399.35"/>
513 <polygon fill="black" stroke="black" points="637.74,-396.33 627.37,-394.16 634.12,-402.32 637.74,-396.33"/>
514 </g>
515 <!-- System V.0 -->
516 <g id="node39" class="node">
517 <title>System V.0</title>
518 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="687.25" cy="-162" rx="53.09" ry="18"/>
519 <text text-anchor="middle" x="687.25" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">System V.0</text>
520 </g>
521 <!-- TS 4.0&#45;&gt;System V.0 -->
522 <g id="edge47" class="edge">
523 <title>TS 4.0&#45;&gt;System V.0</title>
524 <path fill="none" stroke="black" d="M687.25,-215.7C687.25,-207.98 687.25,-198.71 687.25,-190.11"/>
525 <polygon fill="black" stroke="black" points="690.75,-190.1 687.25,-180.1 683.75,-190.1 690.75,-190.1"/>
526 </g>
527 <!-- System V.2 -->
528 <g id="node40" class="node">
529 <title>System V.2</title>
530 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="687.25" cy="-90" rx="53.09" ry="18"/>
531 <text text-anchor="middle" x="687.25" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">System V.2</text>
532 </g>
533 <!-- System V.0&#45;&gt;System V.2 -->
534 <g id="edge48" class="edge">
535 <title>System V.0&#45;&gt;System V.2</title>
536 <path fill="none" stroke="black" d="M687.25,-143.7C687.25,-135.98 687.25,-126.71 687.25,-118.11"/>
537 <polygon fill="black" stroke="black" points="690.75,-118.1 687.25,-108.1 683.75,-118.1 690.75,-118.1"/>
538 </g>
539 <!-- System V.3 -->
540 <g id="node41" class="node">
541 <title>System V.3</title>
542 <ellipse fill="#b2dfee" stroke="#b2dfee" cx="687.25" cy="-18" rx="53.09" ry="18"/>
543 <text text-anchor="middle" x="687.25" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">System V.3</text>
544 </g>
545 <!-- System V.2&#45;&gt;System V.3 -->
546 <g id="edge49" class="edge">
547 <title>System V.2&#45;&gt;System V.3</title>
548 <path fill="none" stroke="black" d="M687.25,-71.7C687.25,-63.98 687.25,-54.71 687.25,-46.11"/>
549 <polygon fill="black" stroke="black" points="690.75,-46.1 687.25,-36.1 683.75,-46.1 690.75,-46.1"/>
550 </g>
551 </g>
552 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="502pt" height="188pt"
7 viewBox="0.00 0.00 502.00 188.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 184)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-184 498,-184 498,4 -4,4"/>
10 <!-- 0 -->
11 <g id="node1" class="node">
12 <title>0</title>
13 <ellipse fill="none" stroke="black" cx="247" cy="-162" rx="27" ry="18"/>
14 <text text-anchor="middle" x="247" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">0</text>
15 </g>
16 <!-- 1 -->
17 <g id="node2" class="node">
18 <title>1</title>
19 <ellipse fill="none" stroke="black" cx="27" cy="-90" rx="27" ry="18"/>
20 <text text-anchor="middle" x="27" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">1</text>
21 </g>
22 <!-- 0&#45;&gt;1 -->
23 <g id="edge1" class="edge">
24 <title>0&#45;&gt;1</title>
25 <path fill="none" stroke="black" d="M222.13,-154.52C187.31,-145.26 122.23,-127.21 68,-108 64.88,-106.89 61.65,-105.68 58.43,-104.42"/>
26 <polygon fill="black" stroke="black" points="59.55,-101.1 48.96,-100.61 56.93,-107.59 59.55,-101.1"/>
27 </g>
28 <!-- 2 -->
29 <g id="node3" class="node">
30 <title>2</title>
31 <ellipse fill="none" stroke="black" cx="82" cy="-18" rx="27" ry="18"/>
32 <text text-anchor="middle" x="82" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">2</text>
33 </g>
34 <!-- 0&#45;&gt;2 -->
35 <g id="edge2" class="edge">
36 <title>0&#45;&gt;2</title>
37 <path fill="none" stroke="black" d="M220.28,-158.96C187.22,-154.95 131.55,-143.08 101,-108 86.29,-91.11 82.05,-65.64 81.19,-46.27"/>
38 <polygon fill="black" stroke="black" points="84.69,-46.16 81.01,-36.22 77.69,-46.28 84.69,-46.16"/>
39 </g>
40 <!-- 3 -->
41 <g id="node4" class="node">
42 <title>3</title>
43 <ellipse fill="none" stroke="black" cx="137" cy="-90" rx="27" ry="18"/>
44 <text text-anchor="middle" x="137" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">3</text>
45 </g>
46 <!-- 0&#45;&gt;3 -->
47 <g id="edge3" class="edge">
48 <title>0&#45;&gt;3</title>
49 <path fill="none" stroke="black" d="M227.84,-148.81C210.33,-137.67 184.24,-121.06 164.51,-108.5"/>
50 <polygon fill="black" stroke="black" points="166.26,-105.47 155.94,-103.05 162.5,-111.37 166.26,-105.47"/>
51 </g>
52 <!-- 4 -->
53 <g id="node5" class="node">
54 <title>4</title>
55 <ellipse fill="none" stroke="black" cx="192" cy="-18" rx="27" ry="18"/>
56 <text text-anchor="middle" x="192" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">4</text>
57 </g>
58 <!-- 0&#45;&gt;4 -->
59 <g id="edge4" class="edge">
60 <title>0&#45;&gt;4</title>
61 <path fill="none" stroke="black" d="M234.25,-145.7C226.44,-135.59 216.85,-121.71 211,-108 202.54,-88.17 197.7,-64.2 195.02,-46.13"/>
62 <polygon fill="black" stroke="black" points="198.46,-45.43 193.66,-35.99 191.52,-46.37 198.46,-45.43"/>
63 </g>
64 <!-- 5 -->
65 <g id="node6" class="node">
66 <title>5</title>
67 <ellipse fill="none" stroke="black" cx="247" cy="-90" rx="27" ry="18"/>
68 <text text-anchor="middle" x="247" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">5</text>
69 </g>
70 <!-- 0&#45;&gt;5 -->
71 <g id="edge5" class="edge">
72 <title>0&#45;&gt;5</title>
73 <path fill="none" stroke="black" d="M247,-143.7C247,-135.98 247,-126.71 247,-118.11"/>
74 <polygon fill="black" stroke="black" points="250.5,-118.1 247,-108.1 243.5,-118.1 250.5,-118.1"/>
75 </g>
76 <!-- 6 -->
77 <g id="node7" class="node">
78 <title>6</title>
79 <ellipse fill="none" stroke="black" cx="302" cy="-18" rx="27" ry="18"/>
80 <text text-anchor="middle" x="302" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">6</text>
81 </g>
82 <!-- 0&#45;&gt;6 -->
83 <g id="edge6" class="edge">
84 <title>0&#45;&gt;6</title>
85 <path fill="none" stroke="black" d="M259.75,-145.7C267.56,-135.59 277.15,-121.71 283,-108 291.46,-88.17 296.3,-64.2 298.98,-46.13"/>
86 <polygon fill="black" stroke="black" points="302.48,-46.37 300.34,-35.99 295.54,-45.43 302.48,-46.37"/>
87 </g>
88 <!-- 7 -->
89 <g id="node8" class="node">
90 <title>7</title>
91 <ellipse fill="none" stroke="black" cx="357" cy="-90" rx="27" ry="18"/>
92 <text text-anchor="middle" x="357" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">7</text>
93 </g>
94 <!-- 0&#45;&gt;7 -->
95 <g id="edge7" class="edge">
96 <title>0&#45;&gt;7</title>
97 <path fill="none" stroke="black" d="M266.16,-148.81C283.67,-137.67 309.76,-121.06 329.49,-108.5"/>
98 <polygon fill="black" stroke="black" points="331.5,-111.37 338.06,-103.05 327.74,-105.47 331.5,-111.37"/>
99 </g>
100 <!-- 8 -->
101 <g id="node9" class="node">
102 <title>8</title>
103 <ellipse fill="none" stroke="black" cx="412" cy="-18" rx="27" ry="18"/>
104 <text text-anchor="middle" x="412" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">8</text>
105 </g>
106 <!-- 0&#45;&gt;8 -->
107 <g id="edge8" class="edge">
108 <title>0&#45;&gt;8</title>
109 <path fill="none" stroke="black" d="M273.72,-158.96C306.78,-154.95 362.45,-143.08 393,-108 407.71,-91.11 411.95,-65.64 412.81,-46.27"/>
110 <polygon fill="black" stroke="black" points="416.31,-46.28 412.99,-36.22 409.31,-46.16 416.31,-46.28"/>
111 </g>
112 <!-- 9 -->
113 <g id="node10" class="node">
114 <title>9</title>
115 <ellipse fill="none" stroke="black" cx="467" cy="-90" rx="27" ry="18"/>
116 <text text-anchor="middle" x="467" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">9</text>
117 </g>
118 <!-- 0&#45;&gt;9 -->
119 <g id="edge9" class="edge">
120 <title>0&#45;&gt;9</title>
121 <path fill="none" stroke="black" d="M271.87,-154.52C306.69,-145.26 371.77,-127.21 426,-108 429.12,-106.89 432.35,-105.68 435.57,-104.42"/>
122 <polygon fill="black" stroke="black" points="437.07,-107.59 445.04,-100.61 434.45,-101.1 437.07,-107.59"/>
123 </g>
124 </g>
125 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="476pt" height="260pt"
7 viewBox="0.00 0.00 476.00 260.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 256)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-256 472,-256 472,4 -4,4"/>
10 <!-- 0 -->
11 <g id="node1" class="node">
12 <title>0</title>
13 <ellipse fill="none" stroke="black" cx="238" cy="-234" rx="27" ry="18"/>
14 <text text-anchor="middle" x="238" y="-230.3" font-family="Times New Roman,serif" font-size="14.00">0</text>
15 </g>
16 <!-- 1 -->
17 <g id="node2" class="node">
18 <title>1</title>
19 <ellipse fill="none" stroke="black" cx="27" cy="-162" rx="27" ry="18"/>
20 <text text-anchor="middle" x="27" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">1</text>
21 </g>
22 <!-- 0&#45;&gt;1 -->
23 <g id="edge1" class="edge">
24 <title>0&#45;&gt;1</title>
25 <path fill="none" stroke="black" d="M213.56,-226.14C180.32,-216.64 119.16,-198.54 68,-180 64.88,-178.87 61.66,-177.64 58.45,-176.38"/>
26 <polygon fill="black" stroke="black" points="59.57,-173.06 48.99,-172.55 56.94,-179.54 59.57,-173.06"/>
27 </g>
28 <!-- 2 -->
29 <g id="node3" class="node">
30 <title>2</title>
31 <ellipse fill="none" stroke="black" cx="73" cy="-90" rx="27" ry="18"/>
32 <text text-anchor="middle" x="73" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">2</text>
33 </g>
34 <!-- 0&#45;&gt;2 -->
35 <g id="edge2" class="edge">
36 <title>0&#45;&gt;2</title>
37 <path fill="none" stroke="black" d="M212.13,-227.76C184.67,-220.99 141.52,-206.77 114,-180 96.53,-163.01 85.77,-137.16 79.69,-117.7"/>
38 <polygon fill="black" stroke="black" points="82.99,-116.53 76.85,-107.91 76.27,-118.48 82.99,-116.53"/>
39 </g>
40 <!-- 3 -->
41 <g id="node4" class="node">
42 <title>3</title>
43 <ellipse fill="none" stroke="black" cx="128" cy="-18" rx="27" ry="18"/>
44 <text text-anchor="middle" x="128" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">3</text>
45 </g>
46 <!-- 0&#45;&gt;3 -->
47 <g id="edge3" class="edge">
48 <title>0&#45;&gt;3</title>
49 <path fill="none" stroke="black" d="M213.94,-225.83C192.62,-218.13 162.54,-203.7 147,-180 120.4,-139.44 121,-80.52 124.24,-46.34"/>
50 <polygon fill="black" stroke="black" points="127.74,-46.49 125.35,-36.17 120.79,-45.73 127.74,-46.49"/>
51 </g>
52 <!-- 4 -->
53 <g id="node5" class="node">
54 <title>4</title>
55 <ellipse fill="none" stroke="black" cx="183" cy="-162" rx="27" ry="18"/>
56 <text text-anchor="middle" x="183" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">4</text>
57 </g>
58 <!-- 0&#45;&gt;4 -->
59 <g id="edge4" class="edge">
60 <title>0&#45;&gt;4</title>
61 <path fill="none" stroke="black" d="M226.07,-217.81C218.79,-208.55 209.34,-196.52 201.15,-186.09"/>
62 <polygon fill="black" stroke="black" points="203.84,-183.86 194.91,-178.16 198.34,-188.18 203.84,-183.86"/>
63 </g>
64 <!-- 5 -->
65 <g id="node6" class="node">
66 <title>5</title>
67 <ellipse fill="none" stroke="black" cx="221" cy="-90" rx="27" ry="18"/>
68 <text text-anchor="middle" x="221" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">5</text>
69 </g>
70 <!-- 0&#45;&gt;5 -->
71 <g id="edge5" class="edge">
72 <title>0&#45;&gt;5</title>
73 <path fill="none" stroke="black" d="M235.95,-215.87C233.05,-191.67 227.73,-147.21 224.28,-118.39"/>
74 <polygon fill="black" stroke="black" points="227.72,-117.7 223.06,-108.19 220.77,-118.53 227.72,-117.7"/>
75 </g>
76 <!-- 6 -->
77 <g id="node7" class="node">
78 <title>6</title>
79 <ellipse fill="none" stroke="black" cx="276" cy="-18" rx="27" ry="18"/>
80 <text text-anchor="middle" x="276" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">6</text>
81 </g>
82 <!-- 0&#45;&gt;6 -->
83 <g id="edge6" class="edge">
84 <title>0&#45;&gt;6</title>
85 <path fill="none" stroke="black" d="M241.05,-215.85C247.63,-178.74 263.26,-90.75 271.2,-46.05"/>
86 <polygon fill="black" stroke="black" points="274.69,-46.39 272.99,-35.94 267.8,-45.17 274.69,-46.39"/>
87 </g>
88 <!-- 7 -->
89 <g id="node8" class="node">
90 <title>7</title>
91 <ellipse fill="none" stroke="black" cx="331" cy="-162" rx="27" ry="18"/>
92 <text text-anchor="middle" x="331" y="-158.3" font-family="Times New Roman,serif" font-size="14.00">7</text>
93 </g>
94 <!-- 0&#45;&gt;7 -->
95 <g id="edge7" class="edge">
96 <title>0&#45;&gt;7</title>
97 <path fill="none" stroke="black" d="M255.49,-219.83C269.52,-209.27 289.42,-194.3 305.26,-182.37"/>
98 <polygon fill="black" stroke="black" points="307.7,-184.92 313.59,-176.11 303.49,-179.32 307.7,-184.92"/>
99 </g>
100 <!-- 8 -->
101 <g id="node9" class="node">
102 <title>8</title>
103 <ellipse fill="none" stroke="black" cx="386" cy="-90" rx="27" ry="18"/>
104 <text text-anchor="middle" x="386" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">8</text>
105 </g>
106 <!-- 0&#45;&gt;8 -->
107 <g id="edge8" class="edge">
108 <title>0&#45;&gt;8</title>
109 <path fill="none" stroke="black" d="M264.27,-229.54C293.8,-224.21 341.01,-211.13 367,-180 381.29,-162.89 385.6,-137.6 386.59,-118.35"/>
110 <polygon fill="black" stroke="black" points="390.09,-118.18 386.84,-108.1 383.09,-118.01 390.09,-118.18"/>
111 </g>
112 <!-- 9 -->
113 <g id="node10" class="node">
114 <title>9</title>
115 <ellipse fill="none" stroke="black" cx="441" cy="-18" rx="27" ry="18"/>
116 <text text-anchor="middle" x="441" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">9</text>
117 </g>
118 <!-- 0&#45;&gt;9 -->
119 <g id="edge9" class="edge">
120 <title>0&#45;&gt;9</title>
121 <path fill="none" stroke="black" d="M264.41,-230.07C297.34,-225.13 353.59,-212.29 389,-180 427.16,-145.21 437.43,-82.27 440.12,-46.25"/>
122 <polygon fill="black" stroke="black" points="443.63,-46.19 440.74,-36 436.64,-45.77 443.63,-46.19"/>
123 </g>
124 </g>
125 </svg>
0 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
1 <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
2 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3 <!-- Generated by graphviz version 2.44.1 (20200629.0846)
4 -->
5 <!-- Pages: 1 -->
6 <svg width="638pt" height="116pt"
7 viewBox="0.00 0.00 638.00 116.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
8 <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 112)">
9 <polygon fill="white" stroke="transparent" points="-4,4 -4,-112 634,-112 634,4 -4,4"/>
10 <!-- 0 -->
11 <g id="node1" class="node">
12 <title>0</title>
13 <ellipse fill="none" stroke="black" cx="315" cy="-90" rx="27" ry="18"/>
14 <text text-anchor="middle" x="315" y="-86.3" font-family="Times New Roman,serif" font-size="14.00">0</text>
15 </g>
16 <!-- 1 -->
17 <g id="node2" class="node">
18 <title>1</title>
19 <ellipse fill="none" stroke="black" cx="27" cy="-18" rx="27" ry="18"/>
20 <text text-anchor="middle" x="27" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">1</text>
21 </g>
22 <!-- 0&#45;&gt;1 -->
23 <g id="edge1" class="edge">
24 <title>0&#45;&gt;1</title>
25 <path fill="none" stroke="black" d="M288.71,-85.54C242.28,-78.98 143.09,-62.92 63,-36 61.08,-35.36 59.14,-34.64 57.19,-33.87"/>
26 <polygon fill="black" stroke="black" points="58.17,-30.48 47.6,-29.74 55.4,-36.91 58.17,-30.48"/>
27 </g>
28 <!-- 2 -->
29 <g id="node3" class="node">
30 <title>2</title>
31 <ellipse fill="none" stroke="black" cx="99" cy="-18" rx="27" ry="18"/>
32 <text text-anchor="middle" x="99" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">2</text>
33 </g>
34 <!-- 0&#45;&gt;2 -->
35 <g id="edge2" class="edge">
36 <title>0&#45;&gt;2</title>
37 <path fill="none" stroke="black" d="M289.85,-82.91C254.68,-74.1 189.04,-56.57 135,-36 133.16,-35.3 131.28,-34.54 129.4,-33.75"/>
38 <polygon fill="black" stroke="black" points="130.64,-30.48 120.08,-29.62 127.81,-36.88 130.64,-30.48"/>
39 </g>
40 <!-- 3 -->
41 <g id="node4" class="node">
42 <title>3</title>
43 <ellipse fill="none" stroke="black" cx="171" cy="-18" rx="27" ry="18"/>
44 <text text-anchor="middle" x="171" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">3</text>
45 </g>
46 <!-- 0&#45;&gt;3 -->
47 <g id="edge3" class="edge">
48 <title>0&#45;&gt;3</title>
49 <path fill="none" stroke="black" d="M293.75,-78.67C269.4,-66.83 229.28,-47.33 201.57,-33.86"/>
50 <polygon fill="black" stroke="black" points="202.86,-30.6 192.33,-29.37 199.8,-36.89 202.86,-30.6"/>
51 </g>
52 <!-- 4 -->
53 <g id="node5" class="node">
54 <title>4</title>
55 <ellipse fill="none" stroke="black" cx="243" cy="-18" rx="27" ry="18"/>
56 <text text-anchor="middle" x="243" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">4</text>
57 </g>
58 <!-- 0&#45;&gt;4 -->
59 <g id="edge4" class="edge">
60 <title>0&#45;&gt;4</title>
61 <path fill="none" stroke="black" d="M300.43,-74.83C290.25,-64.94 276.48,-51.55 264.97,-40.36"/>
62 <polygon fill="black" stroke="black" points="267.41,-37.85 257.8,-33.38 262.53,-42.87 267.41,-37.85"/>
63 </g>
64 <!-- 5 -->
65 <g id="node6" class="node">
66 <title>5</title>
67 <ellipse fill="none" stroke="black" cx="315" cy="-18" rx="27" ry="18"/>
68 <text text-anchor="middle" x="315" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">5</text>
69 </g>
70 <!-- 0&#45;&gt;5 -->
71 <g id="edge5" class="edge">
72 <title>0&#45;&gt;5</title>
73 <path fill="none" stroke="black" d="M315,-71.7C315,-63.98 315,-54.71 315,-46.11"/>
74 <polygon fill="black" stroke="black" points="318.5,-46.1 315,-36.1 311.5,-46.1 318.5,-46.1"/>
75 </g>
76 <!-- 6 -->
77 <g id="node7" class="node">
78 <title>6</title>
79 <ellipse fill="none" stroke="black" cx="387" cy="-18" rx="27" ry="18"/>
80 <text text-anchor="middle" x="387" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">6</text>
81 </g>
82 <!-- 0&#45;&gt;6 -->
83 <g id="edge6" class="edge">
84 <title>0&#45;&gt;6</title>
85 <path fill="none" stroke="black" d="M329.57,-74.83C339.75,-64.94 353.52,-51.55 365.03,-40.36"/>
86 <polygon fill="black" stroke="black" points="367.47,-42.87 372.2,-33.38 362.59,-37.85 367.47,-42.87"/>
87 </g>
88 <!-- 7 -->
89 <g id="node8" class="node">
90 <title>7</title>
91 <ellipse fill="none" stroke="black" cx="459" cy="-18" rx="27" ry="18"/>
92 <text text-anchor="middle" x="459" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">7</text>
93 </g>
94 <!-- 0&#45;&gt;7 -->
95 <g id="edge7" class="edge">
96 <title>0&#45;&gt;7</title>
97 <path fill="none" stroke="black" d="M336.25,-78.67C360.6,-66.83 400.72,-47.33 428.43,-33.86"/>
98 <polygon fill="black" stroke="black" points="430.2,-36.89 437.67,-29.37 427.14,-30.6 430.2,-36.89"/>
99 </g>
100 <!-- 8 -->
101 <g id="node9" class="node">
102 <title>8</title>
103 <ellipse fill="none" stroke="black" cx="531" cy="-18" rx="27" ry="18"/>
104 <text text-anchor="middle" x="531" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">8</text>
105 </g>
106 <!-- 0&#45;&gt;8 -->
107 <g id="edge8" class="edge">
108 <title>0&#45;&gt;8</title>
109 <path fill="none" stroke="black" d="M340.15,-82.91C375.32,-74.1 440.96,-56.57 495,-36 496.84,-35.3 498.72,-34.54 500.6,-33.75"/>
110 <polygon fill="black" stroke="black" points="502.19,-36.88 509.92,-29.62 499.36,-30.48 502.19,-36.88"/>
111 </g>
112 <!-- 9 -->
113 <g id="node10" class="node">
114 <title>9</title>
115 <ellipse fill="none" stroke="black" cx="603" cy="-18" rx="27" ry="18"/>
116 <text text-anchor="middle" x="603" y="-14.3" font-family="Times New Roman,serif" font-size="14.00">9</text>
117 </g>
118 <!-- 0&#45;&gt;9 -->
119 <g id="edge9" class="edge">
120 <title>0&#45;&gt;9</title>
121 <path fill="none" stroke="black" d="M341.29,-85.54C387.72,-78.98 486.91,-62.92 567,-36 568.92,-35.36 570.86,-34.64 572.81,-33.87"/>
122 <polygon fill="black" stroke="black" points="574.6,-36.91 582.4,-29.74 571.83,-30.48 574.6,-36.91"/>
123 </g>
124 </g>
125 </svg>
0 .. _api:
1
2 API Reference
3 =============
4
5 .. autosummary::
6 :nosignatures:
7
8 ~graphviz.Graph
9 ~graphviz.Digraph
10 ~graphviz.Source
11 graphviz.render
12 graphviz.pipe
13 graphviz.view
14
15 .. note::
16
17 The two main classes :class:`.Graph` and :class:`.Digraph` (for creating
18 `undirected` vs. `directed` graphs) have exactly the same API.
19 Their division reflects the fact that both graph types cannot be mixed.
20
21
22 Graph
23 -----
24
25 .. autoclass:: graphviz.Graph
26 :members:
27 source,
28 node, edge, edges, attr, subgraph,
29 format, engine, encoding,
30 clear, copy, pipe, save, render, view,
31 directed
32
33
34 Digraph
35 -------
36
37 .. autoclass:: graphviz.Digraph
38 :members:
39 source,
40 node, edge, edges, attr, subgraph,
41 format, engine, encoding,
42 clear, copy, pipe, save, render, view,
43 directed
44
45
46 Source
47 ------
48
49 .. autoclass:: graphviz.Source
50 :members:
51 format, engine, encoding,
52 copy, pipe, save, render, view,
53 from_file, source
54
55
56 Low-level functions
57 -------------------
58
59 The functions in this section are provided to work directly with existing
60 files and strings instead of using the object-oriented DOT creation methods
61 documented above.
62
63 .. autofunction:: graphviz.render
64 .. autofunction:: graphviz.pipe
65 .. autofunction:: graphviz.view
66
67
68 Other
69 -----
70
71 .. autodata:: graphviz.ExecutableNotFound
72 :annotation:
73
74 .. autodata:: graphviz.RequiredArgumentError
75 :annotation:
76
77 .. autofunction:: graphviz.version
78
79 .. autofunction:: graphviz.escape
80
81 .. autofunction:: graphviz.nohtml
82
83 Manually maintained whitelists (see https://graphviz.gitlab.io/_pages/pdf/dot.1.pdf,
84 http://www.graphviz.org/doc/info/output.html, and ``dot -T:`` output):
85
86 .. autodata:: graphviz.ENGINES
87 :annotation:
88
89 .. autodata:: graphviz.FORMATS
90 :annotation:
91
92 .. autodata:: graphviz.RENDERERS
93 :annotation:
94
95 .. autodata:: graphviz.FORMATTERS
96 :annotation:
0 .. _api:
1
2 API Reference
3 =============
4
5 .. autosummary::
6 :nosignatures:
7
8 ~graphviz.Graph
9 ~graphviz.Digraph
10 ~graphviz.Source
11 graphviz.render
12 graphviz.pipe
13 graphviz.unflatten
14 graphviz.view
15
16 .. note::
17
18 The two main classes :class:`.Graph` and :class:`.Digraph` (for creating
19 `undirected` vs. `directed` graphs) have exactly the same API.
20 Their division reflects the fact that both graph types cannot be mixed.
21
22
23 Graph
24 -----
25
26 .. autoclass:: graphviz.Graph
27 :members:
28 source,
29 node, edge, edges, attr, subgraph,
30 format, engine, encoding,
31 clear, copy, unflatten, pipe, save, render, view,
32 directed
33
34
35 Digraph
36 -------
37
38 .. autoclass:: graphviz.Digraph
39 :members:
40 source,
41 node, edge, edges, attr, subgraph,
42 format, engine, encoding,
43 clear, copy, unflatten, pipe, save, render, view,
44 directed
45
46
47 Source
48 ------
49
50 .. autoclass:: graphviz.Source
51 :members:
52 source,
53 format, engine, encoding,
54 copy, unflatten, pipe, save, render, view,
55 from_file
56
57
58 Low-level functions
59 -------------------
60
61 The functions in this section are provided to work directly with existing
62 files and strings instead of using the object-oriented DOT creation methods
63 documented above.
64
65 .. autofunction:: graphviz.render
66 .. autofunction:: graphviz.pipe
67 .. autofunction:: graphviz.unflatten
68 .. autofunction:: graphviz.view
69
70
71 Other
72 -----
73
74 .. autodata:: graphviz.ExecutableNotFound
75 :annotation:
76
77 .. autodata:: graphviz.RequiredArgumentError
78 :annotation:
79
80 .. autofunction:: graphviz.version
81
82 .. autofunction:: graphviz.escape
83
84 .. autofunction:: graphviz.nohtml
85
86 Manually maintained whitelists (see https://graphviz.gitlab.io/_pages/pdf/dot.1.pdf,
87 http://www.graphviz.org/doc/info/output.html, and ``dot -T:`` output):
88
89 .. autodata:: graphviz.ENGINES
90 :annotation:
91
92 .. autodata:: graphviz.FORMATS
93 :annotation:
94
95 .. autodata:: graphviz.RENDERERS
96 :annotation:
97
98 .. autodata:: graphviz.FORMATTERS
99 :annotation:
0 .. _changelog:
1
2 .. include:: ../CHANGES.txt
0 .. _changelog:
1
2 .. include:: ../CHANGES.txt
0 # -*- coding: utf-8 -*-
1 #
2 # Configuration file for the Sphinx documentation builder.
3 #
4 # This file does only contain a selection of the most common options. For a
5 # full list see the documentation:
6 # http://www.sphinx-doc.org/en/master/config
7
8 # -- Path setup --------------------------------------------------------------
9
10 # If extensions (or modules to document with autodoc) are in another directory,
11 # add these directories to sys.path here. If the directory is relative to the
12 # documentation root, use os.path.abspath to make it absolute, like shown here.
13 #
14 import os
15 import sys
16 sys.path.insert(0, os.path.abspath(os.pardir))
17 import graphviz
18
19
20 # -- Project information -----------------------------------------------------
21
22 project = 'graphviz'
23 copyright = '2013-2020, Sebastian Bank'
24 author = 'Sebastian Bank'
25
26 # The short X.Y version
27 version = '0.14.2'
28 # The full version, including alpha/beta/rc tags
29 release = version
30
31
32 # -- General configuration ---------------------------------------------------
33
34 # If your documentation needs a minimal Sphinx version, state it here.
35 #
36 # needs_sphinx = '1.0'
37
38 # Add any Sphinx extension module names here, as strings. They can be
39 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 # ones.
41 extensions = [
42 'sphinx.ext.autodoc',
43 'sphinx.ext.autosummary',
44 'sphinx.ext.intersphinx',
45 'sphinx.ext.napoleon',
46 'sphinx.ext.viewcode',
47 ]
48
49 # Add any paths that contain templates here, relative to this directory.
50 templates_path = ['_templates']
51
52 # The suffix(es) of source filenames.
53 # You can specify multiple suffix as a list of string:
54 #
55 # source_suffix = ['.rst', '.md']
56 source_suffix = '.rst'
57
58 # The master toctree document.
59 master_doc = 'index'
60
61 # The language for content autogenerated by Sphinx. Refer to documentation
62 # for a list of supported languages.
63 #
64 # This is also used if you do content translation via gettext catalogs.
65 # Usually you set "language" from the command line for these cases.
66 language = None
67
68 # List of patterns, relative to source directory, that match files and
69 # directories to ignore when looking for source files.
70 # This pattern also affects html_static_path and html_extra_path .
71 exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
72
73 # The name of the Pygments (syntax highlighting) style to use.
74 pygments_style = 'sphinx'
75
76
77 # -- Options for HTML output -------------------------------------------------
78
79 # The theme to use for HTML and HTML Help pages. See the documentation for
80 # a list of builtin themes.
81 #
82 on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
83 if not on_rtd:
84 import sphinx_rtd_theme
85 html_theme = 'sphinx_rtd_theme'
86 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
87
88 # Theme options are theme-specific and customize the look and feel of a theme
89 # further. For a list of options available for each theme, see the
90 # documentation.
91 #
92 # html_theme_options = {}
93
94 # Add any paths that contain custom static files (such as style sheets) here,
95 # relative to this directory. They are copied after the builtin static files,
96 # so a file named "default.css" will overwrite the builtin "default.css".
97 html_static_path = ['_static']
98
99 # Custom sidebar templates, must be a dictionary that maps document names
100 # to template names.
101 #
102 # The default sidebars (for documents that don't match any pattern) are
103 # defined by theme itself. Builtin themes are using these templates by
104 # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
105 # 'searchbox.html']``.
106 #
107 # html_sidebars = {}
108
109
110 # -- Options for HTMLHelp output ---------------------------------------------
111
112 # Output file base name for HTML help builder.
113 htmlhelp_basename = 'graphvizdoc'
114
115
116 # -- Options for LaTeX output ------------------------------------------------
117
118 latex_elements = {
119 # The paper size ('letterpaper' or 'a4paper').
120 #
121 # 'papersize': 'letterpaper',
122
123 # The font size ('10pt', '11pt' or '12pt').
124 #
125 # 'pointsize': '10pt',
126
127 # Additional stuff for the LaTeX preamble.
128 #
129 # 'preamble': '',
130
131 # Latex figure (float) alignment
132 #
133 # 'figure_align': 'htbp',
134 }
135
136 # Grouping the document tree into LaTeX files. List of tuples
137 # (source start file, target name, title,
138 # author, documentclass [howto, manual, or own class]).
139 latex_documents = [
140 (master_doc, 'graphviz.tex', 'graphviz Documentation',
141 'Sebastian Bank', 'manual'),
142 ]
143
144
145 # -- Options for manual page output ------------------------------------------
146
147 # One entry per manual page. List of tuples
148 # (source start file, name, description, authors, manual section).
149 man_pages = [
150 (master_doc, 'graphviz', 'graphviz Documentation',
151 [author], 1)
152 ]
153
154
155 # -- Options for Texinfo output ----------------------------------------------
156
157 # Grouping the document tree into Texinfo files. List of tuples
158 # (source start file, target name, title, author,
159 # dir menu entry, description, category)
160 texinfo_documents = [
161 (master_doc, 'graphviz', 'graphviz Documentation',
162 author, 'graphviz', 'One line description of project.',
163 'Miscellaneous'),
164 ]
165
166
167 # -- Extension configuration -------------------------------------------------
168
169 # -- Options for intersphinx extension ---------------------------------------
170
171 # Example configuration for intersphinx: refer to the Python standard library.
172 intersphinx_mapping = {
173 'py': ('https://docs.python.org/2', None),
174 'py3': ('https://docs.python.org/3', None),
175 }
176
177 # monkey patch, see https://github.com/sphinx-doc/sphinx/issues/2044
178 from sphinx.ext.autodoc import ClassLevelDocumenter, InstanceAttributeDocumenter
179
180 def add_directive_header(self, sig):
181 ClassLevelDocumenter.add_directive_header(self, sig)
182
183 InstanceAttributeDocumenter.add_directive_header = add_directive_header
0 # -*- coding: utf-8 -*-
1 #
2 # Configuration file for the Sphinx documentation builder.
3 #
4 # This file does only contain a selection of the most common options. For a
5 # full list see the documentation:
6 # http://www.sphinx-doc.org/en/master/config
7
8 # -- Path setup --------------------------------------------------------------
9
10 # If extensions (or modules to document with autodoc) are in another directory,
11 # add these directories to sys.path here. If the directory is relative to the
12 # documentation root, use os.path.abspath to make it absolute, like shown here.
13 #
14 import os
15 import sys
16 sys.path.insert(0, os.path.abspath(os.pardir))
17 import graphviz
18
19
20 # -- Project information -----------------------------------------------------
21
22 project = 'graphviz'
23 copyright = '2013-2021, Sebastian Bank'
24 author = 'Sebastian Bank'
25
26 # The short X.Y version
27 version = '0.17.dev0'
28 # The full version, including alpha/beta/rc tags
29 release = version
30
31
32 # -- General configuration ---------------------------------------------------
33
34 # If your documentation needs a minimal Sphinx version, state it here.
35 #
36 # needs_sphinx = '1.0'
37
38 # Add any Sphinx extension module names here, as strings. They can be
39 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
40 # ones.
41 extensions = [
42 'sphinx.ext.autodoc',
43 'sphinx.ext.autosummary',
44 'sphinx.ext.intersphinx',
45 'sphinx.ext.napoleon',
46 'sphinx_autodoc_typehints', # https://github.com/agronholm/sphinx-autodoc-typehints/issues/15
47 'sphinx.ext.viewcode',
48 ]
49
50 # Add any paths that contain templates here, relative to this directory.
51 templates_path = ['_templates']
52
53 # The suffix(es) of source filenames.
54 # You can specify multiple suffix as a list of string:
55 #
56 # source_suffix = ['.rst', '.md']
57 source_suffix = '.rst'
58
59 # The master toctree document.
60 master_doc = 'index'
61
62 # The language for content autogenerated by Sphinx. Refer to documentation
63 # for a list of supported languages.
64 #
65 # This is also used if you do content translation via gettext catalogs.
66 # Usually you set "language" from the command line for these cases.
67 language = None
68
69 # List of patterns, relative to source directory, that match files and
70 # directories to ignore when looking for source files.
71 # This pattern also affects html_static_path and html_extra_path .
72 exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
73
74 # The name of the Pygments (syntax highlighting) style to use.
75 pygments_style = 'sphinx'
76
77
78 # -- Options for HTML output -------------------------------------------------
79
80 # The theme to use for HTML and HTML Help pages. See the documentation for
81 # a list of builtin themes.
82 #
83 on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
84 if not on_rtd:
85 import sphinx_rtd_theme
86 html_theme = 'sphinx_rtd_theme'
87 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
88
89 # Theme options are theme-specific and customize the look and feel of a theme
90 # further. For a list of options available for each theme, see the
91 # documentation.
92 #
93 # html_theme_options = {}
94
95 # Add any paths that contain custom static files (such as style sheets) here,
96 # relative to this directory. They are copied after the builtin static files,
97 # so a file named "default.css" will overwrite the builtin "default.css".
98 html_static_path = ['_static']
99
100 # Custom sidebar templates, must be a dictionary that maps document names
101 # to template names.
102 #
103 # The default sidebars (for documents that don't match any pattern) are
104 # defined by theme itself. Builtin themes are using these templates by
105 # default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
106 # 'searchbox.html']``.
107 #
108 # html_sidebars = {}
109
110
111 # -- Options for HTMLHelp output ---------------------------------------------
112
113 # Output file base name for HTML help builder.
114 htmlhelp_basename = 'graphvizdoc'
115
116
117 # -- Options for LaTeX output ------------------------------------------------
118
119 latex_elements = {
120 # The paper size ('letterpaper' or 'a4paper').
121 #
122 # 'papersize': 'letterpaper',
123
124 # The font size ('10pt', '11pt' or '12pt').
125 #
126 # 'pointsize': '10pt',
127
128 # Additional stuff for the LaTeX preamble.
129 #
130 # 'preamble': '',
131
132 # Latex figure (float) alignment
133 #
134 # 'figure_align': 'htbp',
135 }
136
137 # Grouping the document tree into LaTeX files. List of tuples
138 # (source start file, target name, title,
139 # author, documentclass [howto, manual, or own class]).
140 latex_documents = [
141 (master_doc, 'graphviz.tex', 'graphviz Documentation',
142 'Sebastian Bank', 'manual'),
143 ]
144
145
146 # -- Options for manual page output ------------------------------------------
147
148 # One entry per manual page. List of tuples
149 # (source start file, name, description, authors, manual section).
150 man_pages = [
151 (master_doc, 'graphviz', 'graphviz Documentation',
152 [author], 1)
153 ]
154
155
156 # -- Options for Texinfo output ----------------------------------------------
157
158 # Grouping the document tree into Texinfo files. List of tuples
159 # (source start file, target name, title, author,
160 # dir menu entry, description, category)
161 texinfo_documents = [
162 (master_doc, 'graphviz', 'graphviz Documentation',
163 author, 'graphviz', 'One line description of project.',
164 'Miscellaneous'),
165 ]
166
167
168 # -- Extension configuration -------------------------------------------------
169
170 # -- Options for intersphinx extension ---------------------------------------
171
172 # Example configuration for intersphinx: refer to the Python standard library.
173 intersphinx_mapping = {
174 'py': ('https://docs.python.org/2', None),
175 'py3': ('https://docs.python.org/3', None),
176 }
177
178 # monkey patch, see https://github.com/sphinx-doc/sphinx/issues/2044
179 from sphinx.ext.autodoc import ClassLevelDocumenter, InstanceAttributeDocumenter
180
181 def add_directive_header(self, sig):
182 ClassLevelDocumenter.add_directive_header(self, sig)
183
184 InstanceAttributeDocumenter.add_directive_header = add_directive_header
0 .. _examples:
1
2 Examples
3 ========
4
5 The following code examples are included in the ``examples/`` directory of the
6 `source repository/distribution`__. Most of them recreate examples from the
7 `graphviz.org gallery`__ or the `graphviz.org documentation`__.
8
9 .. __: https://github.com/xflr6/graphviz/tree/master/examples/
10 .. __: http://www.graphviz.org/gallery/
11 .. __: http://www.graphviz.org/documentation/
12
13
14 hello.py
15 --------
16
17 .. literalinclude:: ../examples/hello.py
18 :lines: 2-
19
20 .. image:: _static/hello.svg
21 :align: center
22
23
24 process.py
25 ----------
26
27 .. literalinclude:: ../examples/process.py
28 :lines: 2-
29
30 .. image:: _static/process.svg
31 :align: center
32
33
34 fsm.py
35 ------
36
37 .. literalinclude:: ../examples/fsm.py
38 :lines: 2-
39
40 .. image:: _static/fsm.svg
41 :align: center
42
43
44 .. _cluster.py:
45
46 cluster.py
47 ----------
48
49 .. literalinclude:: ../examples/cluster.py
50 :lines: 2-
51
52 .. image:: _static/cluster.svg
53 :align: center
54
55
56 er.py
57 -----
58
59 .. literalinclude:: ../examples/er.py
60 :lines: 2-
61
62 .. image:: _static/er.svg
63 :align: center
64
65
66 unix.py
67 -------
68
69 .. literalinclude:: ../examples/unix.py
70 :lines: 2-
71
72 .. image:: _static/unix.svg
73 :align: center
74
75
76 structs.py
77 ----------
78
79 .. literalinclude:: ../examples/structs.py
80 :lines: 2-
81
82 .. image:: _static/structs.svg
83 :align: center
84
85
86 structs_revisited.py
87 --------------------
88
89 .. literalinclude:: ../examples/structs_revisited.py
90 :lines: 2-
91
92 .. image:: _static/structs_revisited.svg
93 :align: center
94
95
96 .. _btree.py:
97
98 btree.py
99 --------
100
101 .. literalinclude:: ../examples/btree.py
102 :lines: 2-
103
104 .. image:: _static/btree.svg
105 :align: center
106
107
108 traffic_lights.py
109 -----------------
110 .. literalinclude:: ../examples/traffic_lights.py
111 :lines: 2-
112
113 .. image:: _static/traffic_lights.svg
114 :align: center
115
116
117 fdpclust.py
118 -----------
119 .. literalinclude:: ../examples/fdpclust.py
120 :lines: 2-
121
122 .. image:: _static/fdpclust.svg
123 :align: center
124
125
126 cluster_edge.py
127 ---------------
128 .. literalinclude:: ../examples/cluster_edge.py
129 :lines: 2-
130
131 .. image:: _static/cluster_edge.svg
132 :align: center
133
134
135 g_c_n.py
136 --------
137 .. literalinclude:: ../examples/g_c_n.py
138 :lines: 2-
139
140 .. image:: _static/g_c_n.svg
141 :align: center
142
143
144 angles.py
145 ---------
146 .. literalinclude:: ../examples/angles.py
147 :lines: 2-
148
149 .. image:: _static/angles.svg
150 :align: center
151
152
153 .. _rank_same.py:
154
155 rank_same.py
156 ------------
157 .. literalinclude:: ../examples/rank_same.py
158 :lines: 2-
159
160 .. image:: _static/rank_same.svg
161 :align: center
0 .. _examples:
1
2 Examples
3 ========
4
5 The following code examples are included in the ``examples/`` directory of the
6 `source repository/distribution`__. Most of them recreate examples from the
7 `graphviz.org gallery`__ or the `graphviz.org documentation`__.
8
9 .. __: https://github.com/xflr6/graphviz/tree/master/examples/
10 .. __: http://www.graphviz.org/gallery/
11 .. __: http://www.graphviz.org/documentation/
12
13
14 hello.py
15 --------
16
17 .. literalinclude:: ../examples/hello.py
18 :lines: 3-
19
20 .. image:: _static/hello.svg
21 :align: center
22
23
24 process.py
25 ----------
26
27 .. literalinclude:: ../examples/process.py
28 :lines: 3-
29
30 .. image:: _static/process.svg
31 :align: center
32
33
34 fsm.py
35 ------
36
37 .. literalinclude:: ../examples/fsm.py
38 :lines: 3-
39
40 .. image:: _static/fsm.svg
41 :align: center
42
43
44 .. _cluster.py:
45
46 cluster.py
47 ----------
48
49 .. literalinclude:: ../examples/cluster.py
50 :lines: 3-
51
52 .. image:: _static/cluster.svg
53 :align: center
54
55
56 er.py
57 -----
58
59 .. literalinclude:: ../examples/er.py
60 :lines: 3-
61
62 .. image:: _static/er.svg
63 :align: center
64
65
66 unix.py
67 -------
68
69 .. literalinclude:: ../examples/unix.py
70 :lines: 3-
71
72 .. image:: _static/unix.svg
73 :align: center
74
75
76 structs.py
77 ----------
78
79 .. literalinclude:: ../examples/structs.py
80 :lines: 3-
81
82 .. image:: _static/structs.svg
83 :align: center
84
85
86 structs_revisited.py
87 --------------------
88
89 .. literalinclude:: ../examples/structs_revisited.py
90 :lines: 3-
91
92 .. image:: _static/structs_revisited.svg
93 :align: center
94
95
96 .. _btree.py:
97
98 btree.py
99 --------
100
101 .. literalinclude:: ../examples/btree.py
102 :lines: 3-
103
104 .. image:: _static/btree.svg
105 :align: center
106
107
108 traffic_lights.py
109 -----------------
110 .. literalinclude:: ../examples/traffic_lights.py
111 :lines: 3-
112
113 .. image:: _static/traffic_lights.svg
114 :align: center
115
116
117 fdpclust.py
118 -----------
119 .. literalinclude:: ../examples/fdpclust.py
120 :lines: 3-
121
122 .. image:: _static/fdpclust.svg
123 :align: center
124
125
126 cluster_edge.py
127 ---------------
128 .. literalinclude:: ../examples/cluster_edge.py
129 :lines: 3-
130
131 .. image:: _static/cluster_edge.svg
132 :align: center
133
134
135 g_c_n.py
136 --------
137 .. literalinclude:: ../examples/g_c_n.py
138 :lines: 3-
139
140 .. image:: _static/g_c_n.svg
141 :align: center
142
143
144 angles.py
145 ---------
146 .. literalinclude:: ../examples/angles.py
147 :lines: 3-
148
149 .. image:: _static/angles.svg
150 :align: center
151
152
153 .. _rank_same.py:
154
155 rank_same.py
156 ------------
157 .. literalinclude:: ../examples/rank_same.py
158 :lines: 3-
159
160 .. image:: _static/rank_same.svg
161 :align: center
0 .. graphviz documentation master file
1
2 .. include:: ../README.rst
3
4
5 User Guide
6 ==========
7
8 .. toctree::
9 :maxdepth: 2
10
11 manual
12
13
14 Examples
15 ========
16
17 .. toctree::
18 :maxdepth: 2
19
20 examples
21
22
23 Notebooks
24 =========
25
26 .. toctree::
27 :maxdepth: 2
28
29 notebooks
30
31
32 API Reference
33 =============
34
35 .. toctree::
36 :maxdepth: 2
37
38 api
39
40
41 Project Info
42 ============
43
44 .. toctree::
45 :maxdepth: 2
46
47 changelog
48 license
0 .. graphviz documentation master file
1
2 .. include:: ../README.rst
3
4
5 User Guide
6 ==========
7
8 .. toctree::
9 :maxdepth: 2
10
11 manual
12
13
14 Examples
15 ========
16
17 .. toctree::
18 :maxdepth: 2
19
20 examples
21
22
23 Notebooks
24 =========
25
26 .. toctree::
27 :maxdepth: 2
28
29 notebooks
30
31
32 API Reference
33 =============
34
35 .. toctree::
36 :maxdepth: 2
37
38 api
39
40
41 Project Info
42 ============
43
44 .. toctree::
45 :maxdepth: 2
46
47 changelog
48 license
0 .. _license:
1
2 License
3 =======
4
5 .. include:: ../LICENSE.txt
0 .. _license:
1
2 License
3 =======
4
5 .. include:: ../LICENSE.txt
0 .. _manual:
1
2 User Guide
3 ==========
4
5
6 Installation
7 ------------
8
9 :mod:`graphviz` provides a simple pure-Python interface for the Graphviz_
10 graph-drawing software. It runs under Python 2.7 and 3.5+. To install it
11 with pip_ run the following:
12
13 .. code:: bash
14
15 $ pip install graphviz
16
17 For a system-wide install, this typically requires administrator access. For an
18 isolated install, you can run the same inside a virtualenv_ or a
19 :mod:`py3:venv` (Python 3 only).
20
21 The only dependency is a working installation of Graphviz (`download page`_).
22
23 After installing Graphviz, make sure that its ``bin/`` subdirectory containing
24 the layout commands for rendering graph descriptions (``dot``, ``circo``,
25 ``neato``, etc.) is on your systems' path: On the command-line, ``dot -V``
26 should print the version of your Graphiz installation.
27
28
29 Basic usage
30 -----------
31
32 The :mod:`graphviz` module provides two classes: :class:`.Graph` and
33 :class:`.Digraph`. They create graph descriptions in the DOT_ language for
34 undirected and directed graphs respectively. They have the same
35 :ref:`API <api>`.
36
37 Create a graph by instantiating a new :class:`.Graph` or
38 :class:`.Digraph` object:
39
40 .. code:: python
41
42 >>> from graphviz import Digraph
43
44 >>> dot = Digraph(comment='The Round Table')
45
46 >>> dot #doctest: +ELLIPSIS
47 <graphviz.dot.Digraph object at 0x...>
48
49 Their constructors allow to set the graph's :attr:`~.Graph.name`, the
50 :attr:`~.Graph.filename` for the DOT source and the rendered graph, a
51 :attr:`~.Graph.comment` for the first source code line, etc.
52
53 Add nodes and edges to the graph object using its :meth:`~.Graph.node` and
54 :meth:`~.Graph.edge`- or :meth:`~.Graph.edges`-methods:
55
56 .. code:: python
57
58 >>> dot.node('A', 'King Arthur')
59 >>> dot.node('B', 'Sir Bedevere the Wise')
60 >>> dot.node('L', 'Sir Lancelot the Brave')
61
62 >>> dot.edges(['AB', 'AL'])
63 >>> dot.edge('B', 'L', constraint='false')
64
65 The :meth:`~.Graph.node`-method takes a ``name`` identifier as first argument
66 and an optional ``label``. The :meth:`~.Graph.edge`-method takes the names of
67 start node and end node, while :meth:`~.Graph.edges` takes an iterable of
68 name pairs. Keyword arguments are turned into (node and edge) attributes (see
69 `Graphviz docs <appearance_>`_ on available attributes).
70
71 Check the generated source code:
72
73 .. code:: python
74
75 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
76 // The Round Table
77 digraph {
78 A [label="King Arthur"]
79 B [label="Sir Bedevere the Wise"]
80 L [label="Sir Lancelot the Brave"]
81 A -> B
82 A -> L
83 B -> L [constraint=false]
84 }
85
86 Use the :meth:`~.Graph.render`-method to save the source code and render it with the
87 default layout program (``dot``, see below for using `other layout commands
88 <Engines_>`_).
89
90 .. code:: python
91
92 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
93 'test-output/round-table.gv.pdf'
94
95 .. image:: _static/round-table.svg
96 :align: center
97
98 Passing ``view=True`` will automatically open the resulting (PDF, PNG, SVG,
99 etc.) file with your system's default viewer application for the file type.
100
101
102 Formats
103 -------
104
105 To use a different `output file format`_ than the default PDF, use the
106 :attr:`~.Graph.format` argument when creating your :class:`.Graph` or
107 :class:`.Digraph` object:
108
109 .. code:: python
110
111 >>> from graphviz import Graph
112
113 >>> g = Graph(format='png')
114
115 You can also change the :attr:`~.Graph.format` attribute on an existing graph
116 object:
117
118 .. code:: python
119
120 >>> dot.format = 'svg'
121
122 >>> dot.render() # doctest: +SKIP
123 'test-output/round-table.gv.svg'
124
125
126 Piped output
127 ------------
128
129 To directly access the results from the Graphviz rendering command (e.g.
130 ``dot``) as binary data string from within Python instead of writing to a file,
131 use the :meth:`~.Graph.pipe`-method of your :class:`.Graph` or
132 :class:`.Digraph` object:
133
134 .. code:: python
135
136 >>> h = Graph('hello', format='svg')
137
138 >>> h.edge('Hello', 'World')
139
140 >>> print(h.pipe().decode('utf-8')) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
141 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
142 <!DOCTYPE svg
143 ...
144 </svg>
145
146 Note that :meth:`~.Graph.pipe` returns the raw ``stdout`` from the rendering
147 command (``str`` on Python 2, ``bytes`` on Python 3): When piping into
148 plain-text formats like ``'svg'`` or ``'plain'``, you usually want to decode
149 the return value as shown above.
150
151 .. note::
152
153 The output for :meth:`~.Graph.pipe` is buffered in memory, so do not use
154 this method if the data size is large.
155
156
157 Jupyter notebooks
158 -----------------
159
160 :class:`.Graph` and :class:`.Digraph` objects have a
161 :meth:`~.Graph._repr_svg_`-method so they can be rendered and displayed
162 directly inside a `Jupyter notebook`_. For an example, check the
163 ``examples/notebook.ipynb`` file in the
164 `source repository/distribution <notebook.ipynb_>`_ (or the same rendered
165 within nbviewer_).
166
167 This also allows direct displaying within the `Jupyter Qt Console`_ (e.g.
168 `the one <spyderconsole_>`_ inside `Spyder IDE`_):
169
170 .. image:: _static/qtconsole.png
171 :align: center
172
173
174 Styling
175 -------
176
177 Use the :attr:`~.Graph.graph_attr`, :attr:`~.Graph.node_attr`, and
178 :attr:`~.Graph.edge_attr` arguments to change the default appearance_ of your
179 graph, nodes, and edges.
180
181 .. code:: python
182
183 >>> ps = Digraph(name='pet-shop', node_attr={'shape': 'plaintext'})
184
185 >>> ps.node('parrot')
186 >>> ps.node('dead')
187 >>> ps.edge('parrot', 'dead')
188
189 After creation, they can be edited on the graph object:
190
191 .. code:: python
192
193 >>> ps.graph_attr['rankdir'] = 'LR'
194 >>> ps.edge_attr.update(arrowhead='vee', arrowsize='2')
195
196 >>> print(ps.source) # doctest: +NORMALIZE_WHITESPACE
197 digraph "pet-shop" {
198 graph [rankdir=LR]
199 node [shape=plaintext]
200 edge [arrowhead=vee arrowsize=2]
201 parrot
202 dead
203 parrot -> dead
204 }
205
206 .. image:: _static/pet-shop.svg
207 :align: center
208
209
210 .. _attributes:
211
212 Attributes
213 ----------
214
215 To directly add attritbute statements (affecting all following graph, node, or
216 edge items within the same (sub-)graph), use the :meth:`~.Graph.attr`-method
217 with the target as first argument:
218
219 .. code:: python
220
221 >>> ni = Graph('ni')
222
223 >>> ni.attr('node', shape='rarrow')
224 >>> ni.node('1', 'Ni!')
225 >>> ni.node('2', 'Ni!')
226
227 >>> ni.node('3', 'Ni!', shape='egg')
228
229 >>> ni.attr('node', shape='star')
230 >>> ni.node('4', 'Ni!')
231 >>> ni.node('5', 'Ni!')
232
233 By omitting its first argument, you can use it to set arbitrary attributes as
234 key-value pairs targeting the current (sub-)graph (e.g. for ``rankdir``,
235 ``label``, or setting ``rank='same'`` within a subgraph context,
236 :ref:`example <rank_same.py>`):
237
238 .. code:: python
239
240 >>> ni.attr(rankdir='LR')
241
242 >>> ni.edges(['12', '23', '34', '45'])
243 >>> print(ni.source) # doctest: +NORMALIZE_WHITESPACE
244 graph ni {
245 node [shape=rarrow]
246 1 [label="Ni!"]
247 2 [label="Ni!"]
248 3 [label="Ni!" shape=egg]
249 node [shape=star]
250 4 [label="Ni!"]
251 5 [label="Ni!"]
252 rankdir=LR
253 1 -- 2
254 2 -- 3
255 3 -- 4
256 4 -- 5
257 }
258
259 .. image:: _static/ni.svg
260 :align: center
261
262
263 .. _ports:
264
265 Node ports & compass
266 --------------------
267
268 The :meth:`~.Graph.edge`- and :meth:`~.Graph.edges`-methods use the
269 colon-separated format ``node[:port[:compass]]`` for ``tail`` and ``head``
270 nodes. This allows to specify an optional node ``port`` plus an optional
271 ``compass`` point the edge should aim at for the given tail or head node
272 (:ref:`example <btree.py>`).
273
274 As colons are used to indicate ``port`` and ``compass``, node names with
275 literal colon(s) (``:``) are not supported. Note that there is no such
276 restriction for the ``label`` argument, so you can work around by choosing a
277 colon-free ``name`` together with the wanted ``label``:
278
279 .. code:: python
280
281 >>> cpp = Digraph('C++')
282
283 >>> cpp.node('A', 'std::string')
284 >>> cpp.node('B', '"spam"')
285
286 >>> cpp.edge('A', 'B')
287
288 >>> print(cpp.source) # doctest: +NORMALIZE_WHITESPACE
289 digraph "C++" {
290 A [label="std::string"]
291 B [label="\"spam\""]
292 A -> B
293 }
294
295
296 Backslash escapes
297 -----------------
298
299 The Graphviz layout engine supports a number of
300 `escape sequences <escString_>`_ such as ``\n``, ``\l``, ``\r`` (for multi-line
301 labels: centered, left-justified, right-justified) and ``\N``, ``\G``, ``\L``
302 (expanded to the current node name, graph name, object label). To be able to
303 use them from this library (e.g. for labels), strings with backslashes are
304 passed on as is. This means that literal backslashes need to be escaped
305 (doubled) by the user. As the backslash is also special in Python string
306 literals, a second level of doubling is needed (e.g. ``label='\\\\'``). This
307 kind of doubling can be avoided by using `raw string literals`_ (``r'...'``)
308 instead (same solution as proposed for the stdlib :mod:`re` module):
309
310 .. code:: python
311
312 >>> e = Digraph()
313 >>> e.node('backslash', label=r'\\')
314 >>> e.node('multi_line', label=r'centered\nleft\lright\r')
315 >>> print(e.source) # doctest: +NORMALIZE_WHITESPACE
316 digraph {
317 backslash [label="\\"]
318 multi_line [label="centered\nleft\lright\r"]
319 }
320
321 .. image:: _static/escapes.svg
322 :align: center
323
324 To disable any special character meaning in a string (e.g. from user input to
325 be rendered literally), use the :func:`.escape` function (cf. the
326 :func:`re.escape` function):
327
328 .. code:: python
329
330 >>> from graphviz import escape
331 >>> bs = Digraph()
332 >>> bs.node(escape('\\'))
333 >>> print(bs.source) # doctest: +NORMALIZE_WHITESPACE
334 digraph {
335 "\\"
336 }
337
338 .. note::
339
340 To prevent breaking the internal quoting mechanism, the special meaning of
341 ``\"`` as a backslash-escaped quote has been disabled since version
342 ``0.14``. E.g. both ``label='"'`` and ``label='\\"'`` now produce the same
343 DOT source ``[label="\""]`` (a label that renders as a literal quote).
344
345
346 Quoting and HTML-like labels
347 ----------------------------
348
349 The graph-building methods of :class:`.Graph` and :class:`.Digraph` objects
350 automatically take care of quoting (and escaping quotes)
351 `where needed <DOT_>`_ (whitespace, keywords, double quotes, etc.):
352
353 .. code:: python
354
355 >>> q = Digraph()
356 >>> q.edge('spam', 'eggs eggs')
357 >>> q.edge('node', '"here\'s a quote"')
358 >>> print(q.source) # doctest: +NORMALIZE_WHITESPACE
359 digraph {
360 spam -> "eggs eggs"
361 "node" -> "\"here's a quote\""
362 }
363
364 If a string starts with ``'<'`` and ends with ``'>'``, it is passed on as is,
365 without quoting/escaping: The content between the angle brackets is treated by
366 the engine as special **HTML string** that can be used for `HTML-like labels`_:
367
368 .. code:: python
369
370 >>> h = Graph('html_table')
371 >>> h.node('tab', label='''<<TABLE>
372 ... <TR>
373 ... <TD>left</TD>
374 ... <TD>right</TD>
375 ... </TR>
376 ... </TABLE>>''')
377
378 .. image:: _static/html_table.svg
379 :align: center
380
381 For strings that should literally begin with ``'<'`` and end with ``'>'``, use
382 the :func:`.nohtml` function to disable the special meaning of angled
383 parenthesis and apply normal quoting/escaping (before ``0.8.2``, the only
384 workaround was to add leading or trailing space, e.g. ``label=' <>'``):
385
386 .. code:: python
387
388 >>> from graphviz import nohtml
389 >>> d = Digraph(format='svg')
390 >>> d.node('diamond', label=nohtml('<>'))
391 >>> print(d.source) # doctest: +NORMALIZE_WHITESPACE
392 digraph {
393 diamond [label="<>"]
394 }
395
396 .. image:: _static/diamond.svg
397 :align: center
398
399
400 .. _subgraphs:
401
402 Subgraphs & clusters
403 --------------------
404
405 :class:`.Graph` and :class:`.Digraph` objects have a
406 :meth:`~.Graph.subgraph`-method for adding a subgraph to an instance.
407
408 There are two ways to use it: Either with a ready-made graph object of the same
409 kind as the only argument (whose content is added as a subgraph) or omitting
410 the ``graph`` argument (returning a context manager for defining the subgraph
411 content more elegantly within a ``with``-block).
412
413 First usage option, with ``graph`` as the only argument:
414
415 .. code:: python
416
417 >>> p = Graph(name='parent')
418 >>> p.edge('spam', 'eggs')
419
420 >>> c = Graph(name='child', node_attr={'shape': 'box'})
421 >>> c.edge('foo', 'bar')
422
423 >>> p.subgraph(c)
424
425 Second usage, with a ``with``-block (omitting the ``graph`` argument):
426
427 .. code:: python
428
429 >>> p = Graph(name='parent')
430 >>> p.edge('spam', 'eggs')
431
432 >>> with p.subgraph(name='child', node_attr={'shape': 'box'}) as c:
433 ... c.edge('foo', 'bar')
434
435 Both produce the same result:
436
437 .. code:: python
438
439 >>> print(p.source) # doctest: +NORMALIZE_WHITESPACE
440 graph parent {
441 spam -- eggs
442 subgraph child {
443 node [shape=box]
444 foo -- bar
445 }
446 }
447
448 .. note::
449
450 If the ``name`` of a subgraph begins with ``'cluster'`` (all lowercase) the
451 layout engine will treat it as a special cluster subgraph
452 (:ref:`example <cluster.py>`). Also see the `Subgraphs and Clusters`
453 section of `the DOT language documentation <DOT_>`_.
454
455
456 Engines
457 -------
458
459 To use a different layout command than the default ``dot`` when rendering your
460 graph, use the :attr:`~.Graph.engine` argument when creating your graph.
461
462 .. code:: python
463
464 >>> g = Graph(engine='neato')
465
466 You can also change the :attr:`~.Graph.engine` attribute of an existing
467 instance:
468
469 .. code:: python
470
471 >>> dot.engine = 'circo'
472
473
474 Custom DOT statements
475 ---------------------
476
477 To add arbitrary statements to the created DOT_ source, use the
478 :attr:`~.Graph.body` attribute of the :class:`.Graph` or :class:`.Digraph`
479 object. It holds the verbatim list of lines to be written to the source file.
480 Use its ``append()``- or ``extend()``-method:
481
482 .. code:: python
483
484 >>> rt = Digraph(comment='The Round Table')
485
486 >>> rt.body.append('\t"King Arthur" -> {\n\t\t"Sir Bedevere", "Sir Lancelot"\n\t}')
487 >>> rt.edge('Sir Bedevere', 'Sir Lancelot', constraint='false')
488
489 >>> print(rt.source) # doctest: +NORMALIZE_WHITESPACE
490 // The Round Table
491 digraph {
492 "King Arthur" -> {
493 "Sir Bedevere", "Sir Lancelot"
494 }
495 "Sir Bedevere" -> "Sir Lancelot" [constraint=false]
496 }
497
498 Note that you might need to correctly quote/escape identifiers and strings
499 containing whitespace or other special characters when using this method.
500
501
502 Using raw DOT
503 -------------
504
505 To render a ready-made DOT source code string (instead of assembling one with
506 the higher-level interface of :class:`.Graph` or :class:`.Digraph`), create a
507 :class:`.Source` object holding your DOT string:
508
509 .. code:: python
510
511 >>> from graphviz import Source
512
513 >>> src = Source('digraph "the holy hand grenade" { rankdir=LR; 1 -> 2 -> 3 -> lob }')
514
515 >>> src #doctest: +ELLIPSIS
516 <graphviz.files.Source object at 0x...>
517
518 Use the :meth:`~.Source.render`-method to save and render it:
519
520 .. code:: python
521
522 >>> src.render('test-output/holy-grenade.gv', view=True) # doctest: +SKIP
523 'test-output/holy-grenade.gv.pdf'
524
525 .. image:: _static/holy-grenade.svg
526 :align: center
527
528 Apart from the missing editing methods, :class:`.Source` objects are the same
529 as the higher-level graph objects (:meth:`~.Source.pipe`-method,
530 :attr:`~.Source.format`, :attr:`~.Source.engine`, Jupyter notebook repr, etc.),
531 see above.
532
533
534 Existing files
535 --------------
536
537 To directly render an existing DOT source file (e.g. created with other tools),
538 you can use the :func:`graphviz.render` function.
539
540 .. code:: python
541
542 >>> from graphviz import render
543
544 >>> render('dot', 'png', 'test-output/holy-grenade.gv') # doctest: +SKIP
545 'test-output/holy-grenade.gv.png'
546
547 To directly display the graph of an existing DOT source file inside a
548 Jupyter `notebook <Jupyter notebook_>`_ or `Qt Console <Jupyter Qt Console_>`_,
549 you can use the :meth:`.Source.from_file`-classmethod (alternate constructor):
550
551 .. image:: _static/qtconsole-source.png
552 :align: center
553
554 Note that if you call :meth:`~.Source.render` or :meth:`~.Source.view` on the
555 returned :class:`.Source` object, it will still :meth:`~.Source.save` as usual
556 (i.e. write the content read into :attr:`~.Source.source` back into the file).
557 You can use :func:`graphviz.render` and :func:`graphiz.view` to directly work
558 on files in case you need to avoid this round-trip.
559
560
561 Integration with viewers
562 ------------------------
563
564 On platforms such as Windows, viewer programs opened by rendering with
565 ``view=True`` or the :meth:`~.Graph.view`-method might lock the (PDF, PNG,
566 etc.) file for as long as the viewer is open (blocking re-rendering it with a
567 ``Permission denied`` error). You can use the :func:`~tempfile.mktemp` function
568 from the stdlib :mod:`tempfile` module to render to a different file for each
569 invocation to avoid needing to close the viewer window each time within such an
570 incremental workflow (and also preserve its intermediate steps):
571
572 .. code:: python
573
574 >>> import tempfile
575
576 >>> g = Graph()
577 >>> g.node('spam')
578
579 >>> g.view(tempfile.mktemp('.gv')) # doctest: +SKIP
580 'C:\\Users\\User\\AppData\\Local\\Temp\\tmp3aoie8d0.gv.pdf'
581
582 >>> g.view(tempfile.mktemp('.gv')) # doctest: +SKIP
583 'C:\\Users\\User\\AppData\\Local\\Temp\\tmphh4ig7a_.gv.pdf'
584
585 Other options are viewers that `support live updates`_ or using the Jupyter
586 `notebook <Jupyter notebook_>`_ or `Qt Console <Jupyter Qt Console_>`_ to
587 display the current version of the rendered graph in repeated add/render/view
588 cycles.
589
590
591 .. _pip: https://pip.readthedocs.io
592 .. _virtualenv: https://virtualenv.pypa.io
593
594 .. _Graphviz: https://www.graphviz.org
595 .. _download page: https://www.graphviz.org/download/
596 .. _DOT: https://www.graphviz.org/doc/info/lang.html
597 .. _output file format: https://www.graphviz.org/doc/info/output.html
598 .. _appearance: https://www.graphviz.org/doc/info/attrs.html
599 .. _escString: https://www.graphviz.org/doc/info/attrs.html#k:escString
600 .. _raw string literals: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
601 .. _HTML-like labels: https://graphviz.gitlab.io/_pages/doc/info/shapes.html#html
602
603 .. _Jupyter notebook: https://jupyter.org
604 .. _notebook.ipynb: https://github.com/xflr6/graphviz/blob/master/examples/notebook.ipynb
605 .. _nbviewer: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb
606 .. _Jupyter Qt Console: https://qtconsole.readthedocs.io
607 .. _spyderconsole: https://docs.spyder-ide.org/ipythonconsole.html
608 .. _Spyder IDE: https://github.com/spyder-ide/spyder
609 .. _support live updates: https://superuser.com/questions/599442/pdf-viewer-that-handles-live-updating-of-pdf-doesnt-lock-the-file
0 .. _manual:
1
2 User Guide
3 ==========
4
5
6 Installation
7 ------------
8
9 :mod:`graphviz` provides a simple pure-Python interface for the Graphviz_
10 graph-drawing software. It runs under Python 3.6+. To install it with pip_, run
11 the following:
12
13 .. code:: bash
14
15 $ pip install graphviz
16
17 For a system-wide install, this typically requires administrator access. For an
18 isolated install, you can run the same inside a :mod:`py3:venv` or a
19 virtualenv_.
20
21 The only dependency is a working installation of Graphviz_
22 (`download page <upstream-download_>`_,
23 `archived versions <upstream-archived_>`_,
24 `installation procedure for Windows <upstream-windows_>`_).
25
26 After installing Graphviz, make sure that its ``bin/`` subdirectory containing
27 the layout commands for rendering graph descriptions (``dot``, ``circo``,
28 ``neato``, etc.) is on your systems' path: On the command-line, ``dot -V``
29 should print the version of your Graphiz installation.
30
31 .. hint::
32
33 Windows users might want to check the status of known issues
34 (gvedit.exe__, sfdp__, commands__) and consider trying an older archived
35 version as a workaround (e.g. graphviz-2.38.msi__).
36
37 __ https://gitlab.com/graphviz/graphviz/-/issues/1816
38 __ https://gitlab.com/graphviz/graphviz/-/issues/1269
39 __ https://gitlab.com/graphviz/graphviz/-/issues/1753
40 __ https://www2.graphviz.org/Archive/stable/windows/graphviz-2.38.msi
41
42 Anaconda_: see the conda-forge_ package
43 `conda-forge/python-graphviz <conda-forge-python-graphviz_>`_
44 (`feedstock <conda-forge-python-graphviz-feedstock_>`_),
45 which should automatically ``conda install``
46 `conda-forge/graphviz <conda-forge-graphviz_>`_
47 (`feedstock <conda-forge-graphviz-feedstock_>`_) as dependency.
48
49
50 Basic usage
51 -----------
52
53 The :mod:`graphviz` module provides two classes: :class:`.Graph` and
54 :class:`.Digraph`. They create graph descriptions in the DOT_ language for
55 undirected and directed graphs respectively. They have the same
56 :ref:`API <api>`.
57
58 Create a graph by instantiating a new :class:`.Graph` or
59 :class:`.Digraph` object:
60
61 .. code:: python
62
63 >>> import graphviz
64
65 >>> dot = graphviz.Digraph(comment='The Round Table')
66
67 >>> dot #doctest: +ELLIPSIS
68 <graphviz.dot.Digraph object at 0x...>
69
70 Their constructors allow to set the graph's :attr:`~.Graph.name`, the
71 :attr:`~.Graph.filename` for the DOT source and the rendered graph, a
72 :attr:`~.Graph.comment` for the first source code line, etc.
73
74 Add nodes and edges to the graph object using its :meth:`~.Graph.node` and
75 :meth:`~.Graph.edge`- or :meth:`~.Graph.edges`-methods:
76
77 .. code:: python
78
79 >>> dot.node('A', 'King Arthur')
80 >>> dot.node('B', 'Sir Bedevere the Wise')
81 >>> dot.node('L', 'Sir Lancelot the Brave')
82
83 >>> dot.edges(['AB', 'AL'])
84 >>> dot.edge('B', 'L', constraint='false')
85
86 The :meth:`~.Graph.node`-method takes a ``name`` identifier as first argument
87 and an optional ``label``. The :meth:`~.Graph.edge`-method takes the names of
88 start node and end node, while :meth:`~.Graph.edges` takes an iterable of
89 name pairs. Keyword arguments are turned into (node and edge) attributes (see
90 `Graphviz docs <appearance_>`_ on available attributes).
91
92 Check the generated source code:
93
94 .. code:: python
95
96 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
97 // The Round Table
98 digraph {
99 A [label="King Arthur"]
100 B [label="Sir Bedevere the Wise"]
101 L [label="Sir Lancelot the Brave"]
102 A -> B
103 A -> L
104 B -> L [constraint=false]
105 }
106
107 Use the :meth:`~.Graph.render`-method to save the source code and render it with the
108 default layout program (``dot``, see below for using `other layout commands
109 <Engines_>`_).
110
111 .. code:: python
112
113 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
114 'test-output/round-table.gv.pdf'
115
116 .. image:: _static/round-table.svg
117 :align: center
118
119 Passing ``view=True`` will automatically open the resulting (PDF, PNG, SVG,
120 etc.) file with your system's default viewer application for the file type.
121
122
123 Formats
124 -------
125
126 To use a different `output file format`_ than the default PDF, use the
127 :attr:`~.Graph.format` argument when creating your :class:`.Graph` or
128 :class:`.Digraph` object:
129
130 .. code:: python
131
132 >>> g = graphviz.Graph(format='png')
133
134 You can also change the :attr:`~.Graph.format` attribute on an existing graph
135 object:
136
137 .. code:: python
138
139 >>> dot.format = 'svg'
140
141 >>> dot.render() # doctest: +SKIP
142 'test-output/round-table.gv.svg'
143
144
145 Piped output
146 ------------
147
148 To directly access the results from the Graphviz rendering command (e.g.
149 ``dot``) as binary data string from within Python instead of writing to a file,
150 use the :meth:`~.Graph.pipe`-method of your :class:`.Graph` or
151 :class:`.Digraph` object:
152
153 .. code:: python
154
155 >>> h = graphviz.Graph('hello', format='svg')
156
157 >>> h.edge('Hello', 'World')
158
159 >>> print(h.pipe().decode('utf-8')) # doctest: +NORMALIZE_WHITESPACE +ELLIPSIS
160 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
161 <!DOCTYPE svg
162 ...
163 </svg>
164
165 Note that :meth:`~.Graph.pipe` returns the raw ``stdout`` from the rendering
166 command (``str`` on Python 2, ``bytes`` on Python 3): When piping into
167 plain-text formats like ``'svg'`` or ``'plain'``, you usually want to decode
168 the return value as shown above.
169
170 .. note::
171
172 The output for :meth:`~.Graph.pipe` is buffered in memory, so do not use
173 this method if the data size is large.
174
175
176 Jupyter notebooks
177 -----------------
178
179 :class:`.Graph` and :class:`.Digraph` objects have a
180 :meth:`~.Graph._repr_svg_`-method so they can be rendered and displayed
181 directly inside a `Jupyter notebook`_. For an example, check the
182 ``examples/graphviz-notebook.ipynb`` file in the
183 `source repository/distribution <graphviz-notebook.ipynb_>`_ (or the same
184 rendered within nbviewer_).
185
186 This also allows direct displaying within the `Jupyter Qt Console`_ (e.g.
187 `the one <spyderconsole_>`_ inside `Spyder IDE`_):
188
189 .. image:: _static/qtconsole.png
190 :align: center
191
192
193 Styling
194 -------
195
196 Use the :attr:`~.Graph.graph_attr`, :attr:`~.Graph.node_attr`, and
197 :attr:`~.Graph.edge_attr` arguments to change the default appearance_ of your
198 graph, nodes, and edges.
199
200 .. code:: python
201
202 >>> ps = graphviz.Digraph(name='pet-shop', node_attr={'shape': 'plaintext'})
203
204 >>> ps.node('parrot')
205 >>> ps.node('dead')
206 >>> ps.edge('parrot', 'dead')
207
208 After creation, they can be edited on the graph object:
209
210 .. code:: python
211
212 >>> ps.graph_attr['rankdir'] = 'LR'
213 >>> ps.edge_attr.update(arrowhead='vee', arrowsize='2')
214
215 >>> print(ps.source) # doctest: +NORMALIZE_WHITESPACE
216 digraph "pet-shop" {
217 graph [rankdir=LR]
218 node [shape=plaintext]
219 edge [arrowhead=vee arrowsize=2]
220 parrot
221 dead
222 parrot -> dead
223 }
224
225 .. image:: _static/pet-shop.svg
226 :align: center
227
228
229 .. _attributes:
230
231 Attributes
232 ----------
233
234 To directly add attritbute statements (affecting all following graph, node, or
235 edge items within the same (sub-)graph), use the :meth:`~.Graph.attr`-method
236 with the target as first argument:
237
238 .. code:: python
239
240 >>> ni = graphviz.Graph('ni')
241
242 >>> ni.attr('node', shape='rarrow')
243 >>> ni.node('1', 'Ni!')
244 >>> ni.node('2', 'Ni!')
245
246 >>> ni.node('3', 'Ni!', shape='egg')
247
248 >>> ni.attr('node', shape='star')
249 >>> ni.node('4', 'Ni!')
250 >>> ni.node('5', 'Ni!')
251
252 By omitting its first argument, you can use it to set arbitrary attributes as
253 key-value pairs targeting the current (sub-)graph (e.g. for ``rankdir``,
254 ``label``, or setting ``rank='same'`` within a subgraph context,
255 :ref:`example <rank_same.py>`):
256
257 .. code:: python
258
259 >>> ni.attr(rankdir='LR')
260
261 >>> ni.edges(['12', '23', '34', '45'])
262
263 >>> print(ni.source) # doctest: +NORMALIZE_WHITESPACE
264 graph ni {
265 node [shape=rarrow]
266 1 [label="Ni!"]
267 2 [label="Ni!"]
268 3 [label="Ni!" shape=egg]
269 node [shape=star]
270 4 [label="Ni!"]
271 5 [label="Ni!"]
272 rankdir=LR
273 1 -- 2
274 2 -- 3
275 3 -- 4
276 4 -- 5
277 }
278
279 .. image:: _static/ni.svg
280 :align: center
281
282
283 .. _ports:
284
285 Node ports & compass
286 --------------------
287
288 The :meth:`~.Graph.edge`- and :meth:`~.Graph.edges`-methods use the
289 colon-separated format ``node[:port[:compass]]`` for ``tail`` and ``head``
290 nodes. This allows to specify an optional node ``port`` plus an optional
291 ``compass`` point the edge should aim at for the given tail or head node
292 (:ref:`example <btree.py>`).
293
294 As colons are used to indicate ``port`` and ``compass``, node names with
295 literal colon(s) (``:``) are not supported. Note that there is no such
296 restriction for the ``label`` argument, so you can work around by choosing a
297 colon-free ``name`` together with the wanted ``label``:
298
299 .. code:: python
300
301 >>> cpp = graphviz.Digraph('C++')
302
303 >>> cpp.node('A', 'std::string')
304 >>> cpp.node('B', '"spam"')
305
306 >>> cpp.edge('A', 'B')
307
308 >>> print(cpp.source) # doctest: +NORMALIZE_WHITESPACE
309 digraph "C++" {
310 A [label="std::string"]
311 B [label="\"spam\""]
312 A -> B
313 }
314
315
316 Backslash escapes
317 -----------------
318
319 The Graphviz layout engine supports a number of
320 `escape sequences <escString_>`_ such as ``\n``, ``\l``, ``\r`` (for multi-line
321 labels: centered, left-justified, right-justified) and ``\N``, ``\G``, ``\L``
322 (expanded to the current node name, graph name, object label). To be able to
323 use them from this library (e.g. for labels), strings with backslashes are
324 passed on as is. This means that literal backslashes need to be escaped
325 (doubled) by the user. As the backslash is also special in Python string
326 literals, a second level of doubling is needed (e.g. ``label='\\\\'``). This
327 kind of doubling can be avoided by using `raw string literals`_ (``r'...'``)
328 instead (same solution as proposed for the stdlib :mod:`re` module):
329
330 .. code:: python
331
332 >>> e = graphviz.Digraph()
333
334 >>> e.node('backslash', label=r'\\')
335 >>> e.node('multi_line', label=r'centered\nleft\lright\r')
336
337 >>> print(e.source) # doctest: +NORMALIZE_WHITESPACE
338 digraph {
339 backslash [label="\\"]
340 multi_line [label="centered\nleft\lright\r"]
341 }
342
343 .. image:: _static/escapes.svg
344 :align: center
345
346 To disable any special character meaning in a string (e.g. from user input to
347 be rendered literally), use the :func:`.escape` function (cf. the
348 :func:`re.escape` function):
349
350 .. code:: python
351
352 >>> bs = graphviz.Digraph()
353
354 >>> bs.node(graphviz.escape('\\'))
355
356 >>> print(bs.source) # doctest: +NORMALIZE_WHITESPACE
357 digraph {
358 "\\"
359 }
360
361 .. note::
362
363 To prevent breaking the internal quoting mechanism, the special meaning of
364 ``\"`` as a backslash-escaped quote has been disabled since version
365 ``0.14``. E.g. both ``label='"'`` and ``label='\\"'`` now produce the same
366 DOT source ``[label="\""]`` (a label that renders as a literal quote).
367
368
369 Quoting and HTML-like labels
370 ----------------------------
371
372 The graph-building methods of :class:`.Graph` and :class:`.Digraph` objects
373 automatically take care of quoting (and escaping quotes)
374 `where needed <DOT_>`_ (whitespace, keywords, double quotes, etc.):
375
376 .. code:: python
377
378 >>> q = graphviz.Digraph()
379
380 >>> q.edge('spam', 'eggs eggs')
381 >>> q.edge('node', '"here\'s a quote"')
382
383 >>> print(q.source) # doctest: +NORMALIZE_WHITESPACE
384 digraph {
385 spam -> "eggs eggs"
386 "node" -> "\"here's a quote\""
387 }
388
389 If a string starts with ``'<'`` and ends with ``'>'``, it is passed on as is,
390 without quoting/escaping: The content between the angle brackets is treated by
391 the engine as special **HTML string** that can be used for `HTML-like labels`_:
392
393 .. code:: python
394
395 >>> h = graphviz.Graph('html_table')
396
397 >>> h.node('tab', label='''<<TABLE>
398 ... <TR>
399 ... <TD>left</TD>
400 ... <TD>right</TD>
401 ... </TR>
402 ... </TABLE>>''')
403
404 .. image:: _static/html_table.svg
405 :align: center
406
407 For strings that should literally begin with ``'<'`` and end with ``'>'``, use
408 the :func:`.nohtml` function to disable the special meaning of angled
409 parenthesis and apply normal quoting/escaping (before ``0.8.2``, the only
410 workaround was to add leading or trailing space, e.g. ``label=' <>'``):
411
412 .. code:: python
413
414 >>> d = graphviz.Digraph(format='svg')
415
416 >>> d.node('diamond', label=graphviz.nohtml('<>'))
417
418 >>> print(d.source) # doctest: +NORMALIZE_WHITESPACE
419 digraph {
420 diamond [label="<>"]
421 }
422
423 .. image:: _static/diamond.svg
424 :align: center
425
426
427 .. _subgraphs:
428
429 Subgraphs & clusters
430 --------------------
431
432 :class:`.Graph` and :class:`.Digraph` objects have a
433 :meth:`~.Graph.subgraph`-method for adding a subgraph to an instance.
434
435 There are two ways to use it: Either with a ready-made graph object of the same
436 kind as the only argument (whose content is added as a subgraph) or omitting
437 the ``graph`` argument (returning a context manager for defining the subgraph
438 content more elegantly within a ``with``-block).
439
440 First usage option, with ``graph`` as the only argument:
441
442 .. code:: python
443
444 >>> p = graphviz.Graph(name='parent')
445 >>> p.edge('spam', 'eggs')
446
447 >>> c = graphviz.Graph(name='child', node_attr={'shape': 'box'})
448 >>> c.edge('foo', 'bar')
449
450 >>> p.subgraph(c)
451
452 Second usage, with a ``with``-block (omitting the ``graph`` argument):
453
454 .. code:: python
455
456 >>> p = graphviz.Graph(name='parent')
457 >>> p.edge('spam', 'eggs')
458
459 >>> with p.subgraph(name='child', node_attr={'shape': 'box'}) as c:
460 ... c.edge('foo', 'bar')
461
462 Both produce the same result:
463
464 .. code:: python
465
466 >>> print(p.source) # doctest: +NORMALIZE_WHITESPACE
467 graph parent {
468 spam -- eggs
469 subgraph child {
470 node [shape=box]
471 foo -- bar
472 }
473 }
474
475 .. note::
476
477 If the ``name`` of a subgraph begins with ``'cluster'`` (all lowercase) the
478 layout engine will treat it as a special cluster subgraph
479 (:ref:`example <cluster.py>`). Also see the `Subgraphs and Clusters`
480 section of `the DOT language documentation <DOT_>`_.
481
482 When :meth:`~.Graph.subgraph` is used as a context manager, the new graph
483 instance is created with ``strict=None`` and the parent graph's values for
484 ``directory``, ``format``, ``engine``, and ``encoding``. Note that these
485 attributes are only relevant when rendering the subgraph independently
486 (i.e. as a stand-alone graph) from within the ``with``-block:
487
488 .. code:: python
489
490 >>> p = graphviz.Graph(name='parent')
491
492 >>> with p.subgraph(name='child') as c:
493 ... c.edge('bacon', 'eggs')
494 ... c.render() # doctest: +SKIP
495 'child.gv.pdf'
496
497
498 Engines
499 -------
500
501 To use a different layout command than the default ``dot`` when rendering your
502 graph, use the :attr:`~.Graph.engine` argument when creating your graph.
503
504 .. code:: python
505
506 >>> g = graphviz.Graph(engine='neato')
507
508 You can also change the :attr:`~.Graph.engine` attribute of an existing
509 instance:
510
511 .. code:: python
512
513 >>> dot.engine = 'circo'
514
515
516 Unflatten
517 ---------
518
519 To prepocess the DOT_ source of a :class:`.Graph` or :class:`.Digraph` with
520 the unflatten_ preprocessor (`PDF <unflatten_pdf_>`_), use the
521 :meth:`~.Graph.unflatten`-method.
522
523 .. code:: python
524
525 >>> w = graphviz.Digraph()
526
527 >>> w.edges(('0', str(i)) for i in range(1, 10))
528
529 >>> w.view() # doctest: +SKIP
530
531 .. image:: _static/wide.svg
532 :align: center
533
534 unflatten_ is used to improve the aspect ratio of graphs having many leaves or
535 disconnected nodes.
536
537 .. code:: python
538
539 >>> u = w.unflatten(stagger=3)
540
541 >>> u.view() # doctest: +SKIP
542
543 .. image:: _static/wide-unflatten-stagger-3.svg
544 :align: center
545
546 The method returns a :class:`.Source` object that you can
547 :meth:`~.Source.render`, :meth:`~.Source.view`, etc. with the same API
548 (minus modification, see details `below <Using raw DOT_>`_).
549
550 .. code:: python
551
552 >>> u = w.unflatten(stagger=2)
553
554 >>> u.view() # doctest: +SKIP
555
556 .. image:: _static/wide-unflatten-stagger-2.svg
557 :align: center
558
559
560 Custom DOT statements
561 ---------------------
562
563 To add arbitrary statements to the created DOT_ source, use the
564 :attr:`~.Graph.body` attribute of the :class:`.Graph` or :class:`.Digraph`
565 object. It holds the verbatim list of lines to be written to the source file.
566 Use its ``append()``- or ``extend()``-method:
567
568 .. code:: python
569
570 >>> rt = graphviz.Digraph(comment='The Round Table')
571
572 >>> rt.body.append('\t"King Arthur" -> {\n\t\t"Sir Bedevere", "Sir Lancelot"\n\t}')
573 >>> rt.edge('Sir Bedevere', 'Sir Lancelot', constraint='false')
574
575 >>> print(rt.source) # doctest: +NORMALIZE_WHITESPACE
576 // The Round Table
577 digraph {
578 "King Arthur" -> {
579 "Sir Bedevere", "Sir Lancelot"
580 }
581 "Sir Bedevere" -> "Sir Lancelot" [constraint=false]
582 }
583
584 Note that you might need to correctly quote/escape identifiers and strings
585 containing whitespace or other special characters when using this method.
586
587
588 Using raw DOT
589 -------------
590
591 To render a ready-made DOT source code string (instead of assembling one with
592 the higher-level interface of :class:`.Graph` or :class:`.Digraph`), create a
593 :class:`.Source` object holding your DOT string:
594
595 .. code:: python
596
597 >>> src = graphviz.Source('digraph "the holy hand grenade" { rankdir=LR; 1 -> 2 -> 3 -> lob }')
598
599 >>> src #doctest: +ELLIPSIS
600 <graphviz.files.Source object at 0x...>
601
602 Use the :meth:`~.Source.render`-method to save and render it:
603
604 .. code:: python
605
606 >>> src.render('test-output/holy-grenade.gv', view=True) # doctest: +SKIP
607 'test-output/holy-grenade.gv.pdf'
608
609 .. image:: _static/holy-grenade.svg
610 :align: center
611
612 Apart from the missing editing methods, :class:`.Source` objects are the same
613 as the higher-level graph objects (:meth:`~.Source.pipe`-method,
614 :attr:`~.Source.format`, :attr:`~.Source.engine`, Jupyter notebook repr, etc.),
615 see above.
616
617
618 Existing files
619 --------------
620
621 To directly render an existing DOT source file (e.g. created with other tools),
622 you can use the :func:`graphviz.render` function.
623
624 .. code:: python
625
626 >>> graphviz.render('dot', 'png', 'test-output/holy-grenade.gv') # doctest: +SKIP
627 'test-output/holy-grenade.gv.png'
628
629 To directly display the graph of an existing DOT source file inside a
630 Jupyter `notebook <Jupyter notebook_>`_ or `Qt Console <Jupyter Qt Console_>`_,
631 you can use the :meth:`.Source.from_file`-classmethod (alternate constructor):
632
633 .. image:: _static/qtconsole-source.png
634 :align: center
635
636 Note that if you call :meth:`~.Source.render` or :meth:`~.Source.view` on the
637 returned :class:`.Source` object, it will still :meth:`~.Source.save` as usual
638 (i.e. write the content read into :attr:`~.Source.source` back into the file).
639 You can use :func:`graphviz.render` and :func:`graphiz.view` to directly work
640 on files in case you need to avoid this round-trip.
641
642
643 Integration with viewers
644 ------------------------
645
646 On platforms such as Windows, viewer programs opened by rendering with
647 ``view=True`` or the :meth:`~.Graph.view`-method might lock the (PDF, PNG,
648 etc.) file for as long as the viewer is open (blocking re-rendering it with a
649 ``Permission denied`` error). You can use the :func:`~tempfile.mktemp` function
650 from the stdlib :mod:`tempfile` module to render to a different file for each
651 invocation to avoid needing to close the viewer window each time within such an
652 incremental workflow (and also preserve its intermediate steps):
653
654 .. code:: python
655
656 >>> import tempfile
657
658 >>> g = graphviz.Graph()
659
660 >>> g.node('spam')
661
662 >>> g.view(tempfile.mktemp('.gv')) # doctest: +SKIP
663 'C:\\Users\\User\\AppData\\Local\\Temp\\tmp3aoie8d0.gv.pdf'
664
665 >>> g.view(tempfile.mktemp('.gv')) # doctest: +SKIP
666 'C:\\Users\\User\\AppData\\Local\\Temp\\tmphh4ig7a_.gv.pdf'
667
668 Other options are viewers that `support live updates`_ or using the Jupyter
669 `notebook <Jupyter notebook_>`_ or `Qt Console <Jupyter Qt Console_>`_ to
670 display the current version of the rendered graph in repeated add/render/view
671 cycles.
672
673
674 .. _Graphviz: https://www.graphviz.org
675 .. _DOT: https://www.graphviz.org/doc/info/lang.html
676 .. _DOT: https://www.graphviz.org/doc/info/lang.html
677 .. _upstream repo: https://gitlab.com/graphviz/graphviz/
678 .. _upstream-download: https://www.graphviz.org/download/
679 .. _upstream-archived: https://www2.graphviz.org/Archive/stable/
680 .. _upstream-windows: https://forum.graphviz.org/t/new-simplified-installation-procedure-on-windows/224
681
682 .. _pip: https://pip.readthedocs.io
683 .. _virtualenv: https://virtualenv.pypa.io
684
685 .. _Anaconda: https://docs.anaconda.com/anaconda/install/
686 .. _conda-forge: https://conda-forge.org
687 .. _conda-forge-python-graphviz: https://anaconda.org/conda-forge/python-graphviz
688 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
689 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
690 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
691
692 .. _output file format: https://www.graphviz.org/doc/info/output.html
693 .. _appearance: https://www.graphviz.org/doc/info/attrs.html
694 .. _escString: https://www.graphviz.org/doc/info/attrs.html#k:escString
695 .. _raw string literals: https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
696 .. _HTML-like labels: https://graphviz.gitlab.io/_pages/doc/info/shapes.html#html
697 .. _unflatten: https://linux.die.net/man/1/unflatten
698 .. _unflatten_pdf: https://www.graphviz.org/pdf/unflatten.1.pdf
699 .. _Jupyter notebook: https://jupyter.org
700 .. _graphviz-notebook.ipynb: https://github.com/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
701 .. _nbviewer: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
702 .. _Jupyter Qt Console: https://qtconsole.readthedocs.io
703 .. _spyderconsole: https://docs.spyder-ide.org/ipythonconsole.html
704 .. _Spyder IDE: https://github.com/spyder-ide/spyder
705 .. _support live updates: https://superuser.com/questions/599442/pdf-viewer-that-handles-live-updating-of-pdf-doesnt-lock-the-file
0 .. _notebooks:
1
2 Notebooks
3 =========
4
5 - Render gallery examples with logging: notebook.ipynb_
6 - Engine comparison: graphviz-engines.ipynb_
7 - Verify escaping and quoting: graphviz-escapes.ipynb_
8
9
10 .. _notebook.ipynb: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb
11 .. _graphviz-engines.ipynb: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-engines.ipynb
0 .. _notebooks:
1
2 Notebooks
3 =========
4
5 - Render gallery examples with logging: graphviz-notebook.ipynb_
6 - Engine comparison: graphviz-engines.ipynb_
7 - Verify escaping and quoting: graphviz-escapes.ipynb_
8
9
10 .. _graphviz-notebook.ipynb: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
11 .. _graphviz-engines.ipynb: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-engines.ipynb
1212 .. _graphviz-escapes.ipynb: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-escapes.ipynb
docs/pet-shop.png less more
Binary diff not shown
Binary diff not shown
0 #!/usr/bin/env python
1 # angles.py - http://www.graphviz.org/Gallery/gradient/angles.html
2
3 from graphviz import Digraph
4
5 g = Digraph('G', filename='angles.gv')
6 g.attr(bgcolor='blue')
7
8 with g.subgraph(name='cluster_1') as c:
9 c.attr(fontcolor='white')
10 c.attr('node', shape='circle', style='filled', fillcolor='white:black',
11 gradientangle='360', label='n9:360', fontcolor='black')
12 c.node('n9')
13 for i, a in zip(range(8, 0, -1), range(360 - 45, -1, -45)):
14 c.attr('node', gradientangle='%d' % a, label='n%d:%d' % (i, a))
15 c.node('n%d' % i)
16 c.attr(label='Linear Angle Variations (white to black gradient)')
17
18 with g.subgraph(name='cluster_2') as c:
19 c.attr(fontcolor='white')
20 c.attr('node', shape='circle', style='radial', fillcolor='white:black',
21 gradientangle='360', label='n18:360', fontcolor='black')
22 c.node('n18')
23 for i, a in zip(range(17, 9, -1), range(360 - 45, -1, -45)):
24 c.attr('node', gradientangle='%d' % a, label='n%d:%d' % (i, a))
25 c.node('n%d' % i)
26 c.attr(label='Radial Angle Variations (white to black gradient)')
27
28 g.edge('n5', 'n14')
29
30 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/Gallery/gradient/angles.html"""
3
4 import graphviz
5
6 g = graphviz.Digraph('G', filename='angles.gv')
7 g.attr(bgcolor='blue')
8
9 with g.subgraph(name='cluster_1') as c:
10 c.attr(fontcolor='white')
11 c.attr('node', shape='circle', style='filled', fillcolor='white:black',
12 gradientangle='360', label='n9:360', fontcolor='black')
13 c.node('n9')
14 for i, a in zip(range(8, 0, -1), range(360 - 45, -1, -45)):
15 c.attr('node', gradientangle=f'{a:d}', label=f'n{i:d}:{a:d}')
16 c.node(f'n{i:d}')
17 c.attr(label='Linear Angle Variations (white to black gradient)')
18
19 with g.subgraph(name='cluster_2') as c:
20 c.attr(fontcolor='white')
21 c.attr('node', shape='circle', style='radial', fillcolor='white:black',
22 gradientangle='360', label='n18:360', fontcolor='black')
23 c.node('n18')
24 for i, a in zip(range(17, 9, -1), range(360 - 45, -1, -45)):
25 c.attr('node', gradientangle=f'{a:d}', label=f'n{i:d}:{a:d}')
26 c.node(f'n{i:d}')
27 c.attr(label='Radial Angle Variations (white to black gradient)')
28
29 g.edge('n5', 'n14')
30
31 g.view()
0 #!/usr/bin/env python
1 # btree.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 13
2
3 from graphviz import Digraph, nohtml
4
5 g = Digraph('g', filename='btree.gv',
6 node_attr={'shape': 'record', 'height': '.1'})
7
8 g.node('node0', nohtml('<f0> |<f1> G|<f2>'))
9 g.node('node1', nohtml('<f0> |<f1> E|<f2>'))
10 g.node('node2', nohtml('<f0> |<f1> B|<f2>'))
11 g.node('node3', nohtml('<f0> |<f1> F|<f2>'))
12 g.node('node4', nohtml('<f0> |<f1> R|<f2>'))
13 g.node('node5', nohtml('<f0> |<f1> H|<f2>'))
14 g.node('node6', nohtml('<f0> |<f1> Y|<f2>'))
15 g.node('node7', nohtml('<f0> |<f1> A|<f2>'))
16 g.node('node8', nohtml('<f0> |<f1> C|<f2>'))
17
18 g.edge('node0:f2', 'node4:f1')
19 g.edge('node0:f0', 'node1:f1')
20 g.edge('node1:f0', 'node2:f1')
21 g.edge('node1:f2', 'node3:f1')
22 g.edge('node2:f2', 'node8:f1')
23 g.edge('node2:f0', 'node7:f1')
24 g.edge('node4:f2', 'node6:f1')
25 g.edge('node4:f0', 'node5:f1')
26
27 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/pdf/dotguide.pdf, Figure 13"""
3
4 import graphviz
5 from graphviz import nohtml
6
7 g = graphviz.Digraph('g', filename='btree.gv',
8 node_attr={'shape': 'record', 'height': '.1'})
9
10 g.node('node0', nohtml('<f0> |<f1> G|<f2>'))
11 g.node('node1', nohtml('<f0> |<f1> E|<f2>'))
12 g.node('node2', nohtml('<f0> |<f1> B|<f2>'))
13 g.node('node3', nohtml('<f0> |<f1> F|<f2>'))
14 g.node('node4', nohtml('<f0> |<f1> R|<f2>'))
15 g.node('node5', nohtml('<f0> |<f1> H|<f2>'))
16 g.node('node6', nohtml('<f0> |<f1> Y|<f2>'))
17 g.node('node7', nohtml('<f0> |<f1> A|<f2>'))
18 g.node('node8', nohtml('<f0> |<f1> C|<f2>'))
19
20 g.edge('node0:f2', 'node4:f1')
21 g.edge('node0:f0', 'node1:f1')
22 g.edge('node1:f0', 'node2:f1')
23 g.edge('node1:f2', 'node3:f1')
24 g.edge('node2:f2', 'node8:f1')
25 g.edge('node2:f0', 'node7:f1')
26 g.edge('node4:f2', 'node6:f1')
27 g.edge('node4:f0', 'node5:f1')
28
29 g.view()
0 #!/usr/bin/env python
1 # cluster.py - http://www.graphviz.org/content/cluster
2
3 from graphviz import Digraph
4
5 g = Digraph('G', filename='cluster.gv')
6
7 # NOTE: the subgraph name needs to begin with 'cluster' (all lowercase)
8 # so that Graphviz recognizes it as a special cluster subgraph
9
10 with g.subgraph(name='cluster_0') as c:
11 c.attr(style='filled', color='lightgrey')
12 c.node_attr.update(style='filled', color='white')
13 c.edges([('a0', 'a1'), ('a1', 'a2'), ('a2', 'a3')])
14 c.attr(label='process #1')
15
16 with g.subgraph(name='cluster_1') as c:
17 c.attr(color='blue')
18 c.node_attr['style'] = 'filled'
19 c.edges([('b0', 'b1'), ('b1', 'b2'), ('b2', 'b3')])
20 c.attr(label='process #2')
21
22 g.edge('start', 'a0')
23 g.edge('start', 'b0')
24 g.edge('a1', 'b3')
25 g.edge('b2', 'a3')
26 g.edge('a3', 'a0')
27 g.edge('a3', 'end')
28 g.edge('b3', 'end')
29
30 g.node('start', shape='Mdiamond')
31 g.node('end', shape='Msquare')
32
33 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/cluster"""
3
4 from graphviz import Digraph
5
6 g = Digraph('G', filename='cluster.gv')
7
8 # NOTE: the subgraph name needs to begin with 'cluster' (all lowercase)
9 # so that Graphviz recognizes it as a special cluster subgraph
10
11 with g.subgraph(name='cluster_0') as c:
12 c.attr(style='filled', color='lightgrey')
13 c.node_attr.update(style='filled', color='white')
14 c.edges([('a0', 'a1'), ('a1', 'a2'), ('a2', 'a3')])
15 c.attr(label='process #1')
16
17 with g.subgraph(name='cluster_1') as c:
18 c.attr(color='blue')
19 c.node_attr['style'] = 'filled'
20 c.edges([('b0', 'b1'), ('b1', 'b2'), ('b2', 'b3')])
21 c.attr(label='process #2')
22
23 g.edge('start', 'a0')
24 g.edge('start', 'b0')
25 g.edge('a1', 'b3')
26 g.edge('b2', 'a3')
27 g.edge('a3', 'a0')
28 g.edge('a3', 'end')
29 g.edge('b3', 'end')
30
31 g.node('start', shape='Mdiamond')
32 g.node('end', shape='Msquare')
33
34 g.view()
0 #!/usr/bin/env python
1 # cluster_edge.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 20
2
3 from graphviz import Digraph
4
5 g = Digraph('G', filename='cluster_edge.gv')
6 g.attr(compound='true')
7
8 with g.subgraph(name='cluster0') as c:
9 c.edges(['ab', 'ac', 'bd', 'cd'])
10
11 with g.subgraph(name='cluster1') as c:
12 c.edges(['eg', 'ef'])
13
14 g.edge('b', 'f', lhead='cluster1')
15 g.edge('d', 'e')
16 g.edge('c', 'g', ltail='cluster0', lhead='cluster1')
17 g.edge('c', 'e', ltail='cluster0')
18 g.edge('d', 'h')
19
20 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/pdf/dotguide.pdf, Figure 20"""
3
4 import graphviz
5
6 g = graphviz.Digraph('G', filename='cluster_edge.gv')
7 g.attr(compound='true')
8
9 with g.subgraph(name='cluster0') as c:
10 c.edges(['ab', 'ac', 'bd', 'cd'])
11
12 with g.subgraph(name='cluster1') as c:
13 c.edges(['eg', 'ef'])
14
15 g.edge('b', 'f', lhead='cluster1')
16 g.edge('d', 'e')
17 g.edge('c', 'g', ltail='cluster0', lhead='cluster1')
18 g.edge('c', 'e', ltail='cluster0')
19 g.edge('d', 'h')
20
21 g.view()
0 #!/usr/bin/env python
1 # er.py - http://www.graphviz.org/content/ER
2
3 from graphviz import Graph
4
5 e = Graph('ER', filename='er.gv', engine='neato')
6
7 e.attr('node', shape='box')
8 e.node('course')
9 e.node('institute')
10 e.node('student')
11
12 e.attr('node', shape='ellipse')
13 e.node('name0', label='name')
14 e.node('name1', label='name')
15 e.node('name2', label='name')
16 e.node('code')
17 e.node('grade')
18 e.node('number')
19
20 e.attr('node', shape='diamond', style='filled', color='lightgrey')
21 e.node('C-I')
22 e.node('S-C')
23 e.node('S-I')
24
25 e.edge('name0', 'course')
26 e.edge('code', 'course')
27 e.edge('course', 'C-I', label='n', len='1.00')
28 e.edge('C-I', 'institute', label='1', len='1.00')
29 e.edge('institute', 'name1')
30 e.edge('institute', 'S-I', label='1', len='1.00')
31 e.edge('S-I', 'student', label='n', len='1.00')
32 e.edge('student', 'grade')
33 e.edge('student', 'name2')
34 e.edge('student', 'number')
35 e.edge('student', 'S-C', label='m', len='1.00')
36 e.edge('S-C', 'course', label='n', len='1.00')
37
38 e.attr(label=r'\n\nEntity Relation Diagram\ndrawn by NEATO')
39 e.attr(fontsize='20')
40
41 e.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/ER"""
3
4 import graphviz
5
6 e = graphviz.Graph('ER', filename='er.gv', engine='neato')
7
8 e.attr('node', shape='box')
9 e.node('course')
10 e.node('institute')
11 e.node('student')
12
13 e.attr('node', shape='ellipse')
14 e.node('name0', label='name')
15 e.node('name1', label='name')
16 e.node('name2', label='name')
17 e.node('code')
18 e.node('grade')
19 e.node('number')
20
21 e.attr('node', shape='diamond', style='filled', color='lightgrey')
22 e.node('C-I')
23 e.node('S-C')
24 e.node('S-I')
25
26 e.edge('name0', 'course')
27 e.edge('code', 'course')
28 e.edge('course', 'C-I', label='n', len='1.00')
29 e.edge('C-I', 'institute', label='1', len='1.00')
30 e.edge('institute', 'name1')
31 e.edge('institute', 'S-I', label='1', len='1.00')
32 e.edge('S-I', 'student', label='n', len='1.00')
33 e.edge('student', 'grade')
34 e.edge('student', 'name2')
35 e.edge('student', 'number')
36 e.edge('student', 'S-C', label='m', len='1.00')
37 e.edge('S-C', 'course', label='n', len='1.00')
38
39 e.attr(label=r'\n\nEntity Relation Diagram\ndrawn by NEATO')
40 e.attr(fontsize='20')
41
42 e.view()
0 #!/usr/bin/env python
1 # fdpclust.py - http://www.graphviz.org/content/fdpclust
2
3 from graphviz import Graph
4
5 g = Graph('G', filename='fdpclust.gv', engine='fdp')
6
7 g.node('e')
8
9 with g.subgraph(name='clusterA') as a:
10 a.edge('a', 'b')
11 with a.subgraph(name='clusterC') as c:
12 c.edge('C', 'D')
13
14 with g.subgraph(name='clusterB') as b:
15 b.edge('d', 'f')
16
17 g.edge('d', 'D')
18 g.edge('e', 'clusterB')
19 g.edge('clusterC', 'clusterB')
20
21 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/fdpclust"""
3
4 import graphviz
5
6 g = graphviz.Graph('G', filename='fdpclust.gv', engine='fdp')
7
8 g.node('e')
9
10 with g.subgraph(name='clusterA') as a:
11 a.edge('a', 'b')
12 with a.subgraph(name='clusterC') as c:
13 c.edge('C', 'D')
14
15 with g.subgraph(name='clusterB') as b:
16 b.edge('d', 'f')
17
18 g.edge('d', 'D')
19 g.edge('e', 'clusterB')
20 g.edge('clusterC', 'clusterB')
21
22 g.view()
0 #!/usr/bin/env python
1 # fsm.py - http://www.graphviz.org/content/fsm
2
3 from graphviz import Digraph
4
5 f = Digraph('finite_state_machine', filename='fsm.gv')
6 f.attr(rankdir='LR', size='8,5')
7
8 f.attr('node', shape='doublecircle')
9 f.node('LR_0')
10 f.node('LR_3')
11 f.node('LR_4')
12 f.node('LR_8')
13
14 f.attr('node', shape='circle')
15 f.edge('LR_0', 'LR_2', label='SS(B)')
16 f.edge('LR_0', 'LR_1', label='SS(S)')
17 f.edge('LR_1', 'LR_3', label='S($end)')
18 f.edge('LR_2', 'LR_6', label='SS(b)')
19 f.edge('LR_2', 'LR_5', label='SS(a)')
20 f.edge('LR_2', 'LR_4', label='S(A)')
21 f.edge('LR_5', 'LR_7', label='S(b)')
22 f.edge('LR_5', 'LR_5', label='S(a)')
23 f.edge('LR_6', 'LR_6', label='S(b)')
24 f.edge('LR_6', 'LR_5', label='S(a)')
25 f.edge('LR_7', 'LR_8', label='S(b)')
26 f.edge('LR_7', 'LR_5', label='S(a)')
27 f.edge('LR_8', 'LR_6', label='S(b)')
28 f.edge('LR_8', 'LR_5', label='S(a)')
29
30 f.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/fsm"""
3
4 import graphviz
5
6 f = graphviz.Digraph('finite_state_machine', filename='fsm.gv')
7 f.attr(rankdir='LR', size='8,5')
8
9 f.attr('node', shape='doublecircle')
10 f.node('LR_0')
11 f.node('LR_3')
12 f.node('LR_4')
13 f.node('LR_8')
14
15 f.attr('node', shape='circle')
16 f.edge('LR_0', 'LR_2', label='SS(B)')
17 f.edge('LR_0', 'LR_1', label='SS(S)')
18 f.edge('LR_1', 'LR_3', label='S($end)')
19 f.edge('LR_2', 'LR_6', label='SS(b)')
20 f.edge('LR_2', 'LR_5', label='SS(a)')
21 f.edge('LR_2', 'LR_4', label='S(A)')
22 f.edge('LR_5', 'LR_7', label='S(b)')
23 f.edge('LR_5', 'LR_5', label='S(a)')
24 f.edge('LR_6', 'LR_6', label='S(b)')
25 f.edge('LR_6', 'LR_5', label='S(a)')
26 f.edge('LR_7', 'LR_8', label='S(b)')
27 f.edge('LR_7', 'LR_5', label='S(a)')
28 f.edge('LR_8', 'LR_6', label='S(b)')
29 f.edge('LR_8', 'LR_5', label='S(a)')
30
31 f.view()
0 #!/usr/bin/env python
1 # http://www.graphviz.org/Gallery/gradient/g_c_n.html
2
3 from graphviz import Graph
4
5 g = Graph('G', filename='g_c_n.gv')
6 g.attr(bgcolor='purple:pink', label='agraph', fontcolor='white')
7
8 with g.subgraph(name='cluster1') as c:
9 c.attr(fillcolor='blue:cyan', label='acluster', fontcolor='white',
10 style='filled', gradientangle='270')
11 c.attr('node', shape='box', fillcolor='red:yellow',
12 style='filled', gradientangle='90')
13 c.node('anode')
14
15 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/Gallery/gradient/g_c_n.html"""
3
4 import graphviz
5
6 g = graphviz.Graph('G', filename='g_c_n.gv')
7 g.attr(bgcolor='purple:pink', label='agraph', fontcolor='white')
8
9 with g.subgraph(name='cluster1') as c:
10 c.attr(fillcolor='blue:cyan', label='acluster', fontcolor='white',
11 style='filled', gradientangle='270')
12 c.attr('node', shape='box', fillcolor='red:yellow',
13 style='filled', gradientangle='90')
14 c.node('anode')
15
16 g.view()
6161 "</svg>\r\n"
6262 ],
6363 "text/plain": [
64 "<graphviz.dot.Digraph at 0x525b188>"
64 "<graphviz.dot.Digraph at 0x4f7ebb0>"
6565 ]
6666 },
6767 "metadata": {},
123123 "</svg>\r\n"
124124 ],
125125 "text/plain": [
126 "<graphviz.dot.Digraph at 0x525b188>"
126 "<graphviz.dot.Digraph at 0x4f7ebb0>"
127127 ]
128128 },
129129 "metadata": {},
185185 "</svg>\r\n"
186186 ],
187187 "text/plain": [
188 "<graphviz.dot.Digraph at 0x525b188>"
188 "<graphviz.dot.Digraph at 0x4f7ebb0>"
189189 ]
190190 },
191191 "metadata": {},
247247 "</svg>\r\n"
248248 ],
249249 "text/plain": [
250 "<graphviz.dot.Digraph at 0x525b188>"
250 "<graphviz.dot.Digraph at 0x4f7ebb0>"
251251 ]
252252 },
253253 "metadata": {},
309309 "</svg>\r\n"
310310 ],
311311 "text/plain": [
312 "<graphviz.dot.Digraph at 0x525b188>"
312 "<graphviz.dot.Digraph at 0x4f7ebb0>"
313313 ]
314314 },
315315 "metadata": {},
356356 "</svg>\r\n"
357357 ],
358358 "text/plain": [
359 "<graphviz.dot.Digraph at 0x525b188>"
359 "<graphviz.dot.Digraph at 0x4f7ebb0>"
360360 ]
361361 },
362362 "metadata": {},
418418 "</svg>\r\n"
419419 ],
420420 "text/plain": [
421 "<graphviz.dot.Digraph at 0x525b188>"
421 "<graphviz.dot.Digraph at 0x4f7ebb0>"
422422 ]
423423 },
424424 "metadata": {},
480480 "</svg>\r\n"
481481 ],
482482 "text/plain": [
483 "<graphviz.dot.Digraph at 0x525b188>"
483 "<graphviz.dot.Digraph at 0x4f7ebb0>"
484484 ]
485485 },
486486 "metadata": {},
495495 }
496496 ],
497497 "source": [
498 "%cd -q ..\n",
499 "\n",
498500 "from IPython.display import display\n",
499501 "\n",
500502 "import graphviz\n",
526528 "name": "python",
527529 "nbconvert_exporter": "python",
528530 "pygments_lexer": "ipython3",
529 "version": "3.7.4"
531 "version": "3.8.7"
530532 }
531533 },
532534 "nbformat": 4,
3636 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
3737 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
3838 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
39 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
40 " -->\r\n",
41 "<!-- Title: %3 Pages: 1 -->\r\n",
39 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
40 " -->\r\n",
41 "<!-- Pages: 1 -->\r\n",
4242 "<svg width=\"62pt\" height=\"44pt\"\r\n",
4343 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
4444 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
45 "<title>%3</title>\r\n",
46 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\r\n",
47 "<!-- A -->\r\n",
48 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
45 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\r\n",
46 "<!-- A -->\r\n",
47 "<g id=\"node1\" class=\"node\">\r\n",
48 "<title>A</title>\r\n",
4949 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
5050 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">&quot;</text>\r\n",
5151 "</g>\r\n",
5353 "</svg>\r\n"
5454 ],
5555 "text/plain": [
56 "<graphviz.dot.Digraph at 0x4f041f0>"
56 "<graphviz.dot.Digraph at 0x50015b0>"
5757 ]
5858 },
5959 "execution_count": 2,
8585 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
8686 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
8787 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
88 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
89 " -->\r\n",
90 "<!-- Title: %3 Pages: 1 -->\r\n",
88 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
89 " -->\r\n",
90 "<!-- Pages: 1 -->\r\n",
9191 "<svg width=\"62pt\" height=\"44pt\"\r\n",
9292 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
9393 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
94 "<title>%3</title>\r\n",
95 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\r\n",
96 "<!-- A -->\r\n",
97 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
94 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\r\n",
95 "<!-- A -->\r\n",
96 "<g id=\"node1\" class=\"node\">\r\n",
97 "<title>A</title>\r\n",
9898 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
9999 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">\\</text>\r\n",
100100 "</g>\r\n",
102102 "</svg>\r\n"
103103 ],
104104 "text/plain": [
105 "<graphviz.dot.Digraph at 0x4efdac0>"
105 "<graphviz.dot.Digraph at 0x4fdbbb0>"
106106 ]
107107 },
108108 "execution_count": 3,
134134 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
135135 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
136136 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
137 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
138 " -->\r\n",
139 "<!-- Title: %3 Pages: 1 -->\r\n",
137 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
138 " -->\r\n",
139 "<!-- Pages: 1 -->\r\n",
140140 "<svg width=\"62pt\" height=\"44pt\"\r\n",
141141 " viewBox=\"0.00 0.00 62.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
142142 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
143 "<title>%3</title>\r\n",
144 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\r\n",
145 "<!-- A -->\r\n",
146 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
143 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 58,-40 58,4 -4,4\"/>\r\n",
144 "<!-- A -->\r\n",
145 "<g id=\"node1\" class=\"node\">\r\n",
146 "<title>A</title>\r\n",
147147 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
148148 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">\\&quot;</text>\r\n",
149149 "</g>\r\n",
151151 "</svg>\r\n"
152152 ],
153153 "text/plain": [
154 "<graphviz.dot.Digraph at 0x4ee4c70>"
154 "<graphviz.dot.Digraph at 0x4fd8af0>"
155155 ]
156156 },
157157 "execution_count": 4,
190190 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
191191 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
192192 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
193 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
194 " -->\r\n",
195 "<!-- Title: %3 Pages: 1 -->\r\n",
193 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
194 " -->\r\n",
195 "<!-- Pages: 1 -->\r\n",
196196 "<svg width=\"87pt\" height=\"44pt\"\r\n",
197197 " viewBox=\"0.00 0.00 87.29 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
198198 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
199 "<title>%3</title>\r\n",
200 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 83.293,-40 83.293,4 -4,4\"/>\r\n",
201 "<!-- A -->\r\n",
202 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
203 "<ellipse fill=\"none\" stroke=\"black\" cx=\"39.6465\" cy=\"-18\" rx=\"39.7935\" ry=\"18\"/>\r\n",
204 "<text text-anchor=\"middle\" x=\"39.6465\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">node: A</text>\r\n",
205 "</g>\r\n",
206 "</g>\r\n",
207 "</svg>\r\n"
208 ],
209 "text/plain": [
210 "<graphviz.dot.Digraph at 0x514f400>"
199 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 83.29,-40 83.29,4 -4,4\"/>\r\n",
200 "<!-- A -->\r\n",
201 "<g id=\"node1\" class=\"node\">\r\n",
202 "<title>A</title>\r\n",
203 "<ellipse fill=\"none\" stroke=\"black\" cx=\"39.65\" cy=\"-18\" rx=\"39.79\" ry=\"18\"/>\r\n",
204 "<text text-anchor=\"middle\" x=\"39.65\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">node: A</text>\r\n",
205 "</g>\r\n",
206 "</g>\r\n",
207 "</svg>\r\n"
208 ],
209 "text/plain": [
210 "<graphviz.dot.Digraph at 0x5016b50>"
211211 ]
212212 },
213213 "execution_count": 5,
239239 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
240240 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
241241 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
242 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
242 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
243243 " -->\r\n",
244244 "<!-- Title: spam Pages: 1 -->\r\n",
245245 "<svg width=\"118pt\" height=\"44pt\"\r\n",
246246 " viewBox=\"0.00 0.00 118.49 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
247247 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
248248 "<title>spam</title>\r\n",
249 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 114.49,-40 114.49,4 -4,4\"/>\r\n",
250 "<!-- A -->\r\n",
251 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
252 "<ellipse fill=\"none\" stroke=\"black\" cx=\"55.2451\" cy=\"-18\" rx=\"55.4913\" ry=\"18\"/>\r\n",
253 "<text text-anchor=\"middle\" x=\"55.2451\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">graph: spam</text>\r\n",
254 "</g>\r\n",
255 "</g>\r\n",
256 "</svg>\r\n"
257 ],
258 "text/plain": [
259 "<graphviz.dot.Digraph at 0x514f3d0>"
249 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 114.49,-40 114.49,4 -4,4\"/>\r\n",
250 "<!-- A -->\r\n",
251 "<g id=\"node1\" class=\"node\">\r\n",
252 "<title>A</title>\r\n",
253 "<ellipse fill=\"none\" stroke=\"black\" cx=\"55.25\" cy=\"-18\" rx=\"55.49\" ry=\"18\"/>\r\n",
254 "<text text-anchor=\"middle\" x=\"55.25\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">graph: spam</text>\r\n",
255 "</g>\r\n",
256 "</g>\r\n",
257 "</svg>\r\n"
258 ],
259 "text/plain": [
260 "<graphviz.dot.Digraph at 0x4fb0e80>"
260261 ]
261262 },
262263 "execution_count": 6,
288289 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
289290 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
290291 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
291 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
292 " -->\r\n",
293 "<!-- Title: %3 Pages: 1 -->\r\n",
292 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
293 " -->\r\n",
294 "<!-- Pages: 1 -->\r\n",
294295 "<svg width=\"69pt\" height=\"44pt\"\r\n",
295296 " viewBox=\"0.00 0.00 69.09 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
296297 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
297 "<title>%3</title>\r\n",
298 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 65.0946,-40 65.0946,4 -4,4\"/>\r\n",
299 "<!-- A -->\r\n",
300 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
298 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 65.09,-40 65.09,4 -4,4\"/>\r\n",
299 "<!-- A -->\r\n",
300 "<g id=\"node1\" class=\"node\">\r\n",
301 "<title>A</title>\r\n",
301302 "<g id=\"a_node1\"><a xlink:href=\"https://example.org/spam\" xlink:title=\"spam\">\r\n",
302 "<ellipse fill=\"none\" stroke=\"black\" cx=\"30.5473\" cy=\"-18\" rx=\"30.5947\" ry=\"18\"/>\r\n",
303 "<text text-anchor=\"middle\" x=\"30.5473\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">spam</text>\r\n",
303 "<ellipse fill=\"none\" stroke=\"black\" cx=\"30.55\" cy=\"-18\" rx=\"30.59\" ry=\"18\"/>\r\n",
304 "<text text-anchor=\"middle\" x=\"30.55\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">spam</text>\r\n",
304305 "</a>\r\n",
305306 "</g>\r\n",
306307 "</g>\r\n",
308309 "</svg>\r\n"
309310 ],
310311 "text/plain": [
311 "<graphviz.dot.Digraph at 0x514fd30>"
312 "<graphviz.dot.Digraph at 0x5001a00>"
312313 ]
313314 },
314315 "execution_count": 7,
340341 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
341342 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
342343 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
343 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
344 " -->\r\n",
345 "<!-- Title: %3 Pages: 1 -->\r\n",
344 "<!-- Generated by graphviz version 2.44.1 (20200629.0846)\r\n",
345 " -->\r\n",
346 "<!-- Pages: 1 -->\r\n",
346347 "<svg width=\"99pt\" height=\"83pt\"\r\n",
347348 " viewBox=\"0.00 0.00 98.51 82.95\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
348 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 78.9533)\">\r\n",
349 "<title>%3</title>\r\n",
350 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-78.9533 94.5097,-78.9533 94.5097,4 -4,4\"/>\r\n",
351 "<!-- A -->\r\n",
352 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
353 "<ellipse fill=\"none\" stroke=\"black\" cx=\"45.2548\" cy=\"-37.4767\" rx=\"45.011\" ry=\"37.4533\"/>\r\n",
354 "<text text-anchor=\"middle\" x=\"45.2548\" y=\"-48.7767\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">centered</text>\r\n",
355 "<text text-anchor=\"start\" x=\"21.2548\" y=\"-33.7767\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">left</text>\r\n",
356 "<text text-anchor=\"end\" x=\"69.2548\" y=\"-18.7767\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">right</text>\r\n",
357 "</g>\r\n",
358 "</g>\r\n",
359 "</svg>\r\n"
360 ],
361 "text/plain": [
362 "<graphviz.dot.Digraph at 0x4f04a90>"
349 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 78.95)\">\r\n",
350 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-78.95 94.51,-78.95 94.51,4 -4,4\"/>\r\n",
351 "<!-- A -->\r\n",
352 "<g id=\"node1\" class=\"node\">\r\n",
353 "<title>A</title>\r\n",
354 "<ellipse fill=\"none\" stroke=\"black\" cx=\"45.25\" cy=\"-37.48\" rx=\"45.01\" ry=\"37.45\"/>\r\n",
355 "<text text-anchor=\"middle\" x=\"45.25\" y=\"-48.78\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">centered</text>\r\n",
356 "<text text-anchor=\"start\" x=\"21.25\" y=\"-33.78\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">left</text>\r\n",
357 "<text text-anchor=\"end\" x=\"69.25\" y=\"-18.78\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">right</text>\r\n",
358 "</g>\r\n",
359 "</g>\r\n",
360 "</svg>\r\n"
361 ],
362 "text/plain": [
363 "<graphviz.dot.Digraph at 0x4fd8550>"
363364 ]
364365 },
365366 "execution_count": 8,
388389 "name": "python",
389390 "nbconvert_exporter": "python",
390391 "pygments_lexer": "ipython3",
391 "version": "3.8.2"
392 "version": "3.8.7"
392393 }
393394 },
394395 "nbformat": 4,
0 {
1 "cells": [
2 {
3 "cell_type": "code",
4 "execution_count": 1,
5 "metadata": {},
6 "outputs": [
7 {
8 "data": {
9 "text/plain": [
10 "'0.16'"
11 ]
12 },
13 "execution_count": 1,
14 "metadata": {},
15 "output_type": "execute_result"
16 }
17 ],
18 "source": [
19 "import logging\n",
20 "\n",
21 "import graphviz\n",
22 "\n",
23 "logging.basicConfig(format='[%(levelname)s@%(name)s] %(message)s', level=logging.DEBUG)\n",
24 "\n",
25 "graphviz.__version__"
26 ]
27 },
28 {
29 "cell_type": "code",
30 "execution_count": 2,
31 "metadata": {},
32 "outputs": [
33 {
34 "name": "stderr",
35 "output_type": "stream",
36 "text": [
37 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
38 ]
39 },
40 {
41 "data": {
42 "image/svg+xml": [
43 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
44 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
45 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
46 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
47 " -->\r\n",
48 "<!-- Pages: 1 -->\r\n",
49 "<svg width=\"390pt\" height=\"116pt\"\r\n",
50 " viewBox=\"0.00 0.00 389.98 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
51 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\r\n",
52 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 385.98,-112 385.98,4 -4,4\"/>\r\n",
53 "<!-- A -->\r\n",
54 "<g id=\"node1\" class=\"node\">\r\n",
55 "<title>A</title>\r\n",
56 "<ellipse fill=\"none\" stroke=\"black\" cx=\"190.99\" cy=\"-90\" rx=\"53.89\" ry=\"18\"/>\r\n",
57 "<text text-anchor=\"middle\" x=\"190.99\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">King Arthur</text>\r\n",
58 "</g>\r\n",
59 "<!-- B -->\r\n",
60 "<g id=\"node2\" class=\"node\">\r\n",
61 "<title>B</title>\r\n",
62 "<ellipse fill=\"none\" stroke=\"black\" cx=\"90.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\r\n",
63 "<text text-anchor=\"middle\" x=\"90.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Bedevere the Wise</text>\r\n",
64 "</g>\r\n",
65 "<!-- A&#45;&gt;B -->\r\n",
66 "<g id=\"edge1\" class=\"edge\">\r\n",
67 "<title>A&#45;&gt;B</title>\r\n",
68 "<path fill=\"none\" stroke=\"black\" d=\"M168.8,-73.46C155.33,-64.04 137.92,-51.85 122.98,-41.39\"/>\r\n",
69 "<polygon fill=\"black\" stroke=\"black\" points=\"124.72,-38.33 114.52,-35.47 120.7,-44.07 124.72,-38.33\"/>\r\n",
70 "</g>\r\n",
71 "<!-- L -->\r\n",
72 "<g id=\"node3\" class=\"node\">\r\n",
73 "<title>L</title>\r\n",
74 "<ellipse fill=\"none\" stroke=\"black\" cx=\"290.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\r\n",
75 "<text text-anchor=\"middle\" x=\"290.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Lancelot the Brave</text>\r\n",
76 "</g>\r\n",
77 "<!-- A&#45;&gt;L -->\r\n",
78 "<g id=\"edge2\" class=\"edge\">\r\n",
79 "<title>A&#45;&gt;L</title>\r\n",
80 "<path fill=\"none\" stroke=\"black\" d=\"M213.19,-73.46C226.65,-64.04 244.07,-51.85 259.01,-41.39\"/>\r\n",
81 "<polygon fill=\"black\" stroke=\"black\" points=\"261.28,-44.07 267.47,-35.47 257.27,-38.33 261.28,-44.07\"/>\r\n",
82 "</g>\r\n",
83 "<!-- B&#45;&gt;L -->\r\n",
84 "<g id=\"edge3\" class=\"edge\">\r\n",
85 "<title>B&#45;&gt;L</title>\r\n",
86 "<path fill=\"none\" stroke=\"black\" d=\"M182.01,-18C184.62,-18 187.22,-18 189.83,-18\"/>\r\n",
87 "<polygon fill=\"black\" stroke=\"black\" points=\"189.89,-21.5 199.89,-18 189.89,-14.5 189.89,-21.5\"/>\r\n",
88 "</g>\r\n",
89 "</g>\r\n",
90 "</svg>\r\n"
91 ],
92 "text/plain": [
93 "<graphviz.dot.Digraph at 0x1c71cc84970>"
94 ]
95 },
96 "execution_count": 2,
97 "metadata": {},
98 "output_type": "execute_result"
99 }
100 ],
101 "source": [
102 "dot = graphviz.Digraph(comment='The Round Table')\n",
103 "\n",
104 "dot.node('A', 'King Arthur')\n",
105 "dot.node('B', 'Sir Bedevere the Wise')\n",
106 "dot.node('L', 'Sir Lancelot the Brave')\n",
107 "\n",
108 "dot.edges(['AB', 'AL'])\n",
109 "dot.edge('B', 'L', constraint='false')\n",
110 "\n",
111 "dot"
112 ]
113 },
114 {
115 "cell_type": "code",
116 "execution_count": 3,
117 "metadata": {},
118 "outputs": [
119 {
120 "name": "stderr",
121 "output_type": "stream",
122 "text": [
123 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
124 ]
125 },
126 {
127 "data": {
128 "image/svg+xml": [
129 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
130 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
131 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
132 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
133 " -->\r\n",
134 "<!-- Title: the holy hand grenade Pages: 1 -->\r\n",
135 "<svg width=\"332pt\" height=\"44pt\"\r\n",
136 " viewBox=\"0.00 0.00 332.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
137 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
138 "<title>the holy hand grenade</title>\r\n",
139 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 328,-40 328,4 -4,4\"/>\r\n",
140 "<!-- 1 -->\r\n",
141 "<g id=\"node1\" class=\"node\">\r\n",
142 "<title>1</title>\r\n",
143 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
144 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">1</text>\r\n",
145 "</g>\r\n",
146 "<!-- 2 -->\r\n",
147 "<g id=\"node2\" class=\"node\">\r\n",
148 "<title>2</title>\r\n",
149 "<ellipse fill=\"none\" stroke=\"black\" cx=\"117\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
150 "<text text-anchor=\"middle\" x=\"117\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">2</text>\r\n",
151 "</g>\r\n",
152 "<!-- 1&#45;&gt;2 -->\r\n",
153 "<g id=\"edge1\" class=\"edge\">\r\n",
154 "<title>1&#45;&gt;2</title>\r\n",
155 "<path fill=\"none\" stroke=\"black\" d=\"M54.4,-18C62.39,-18 71.31,-18 79.82,-18\"/>\r\n",
156 "<polygon fill=\"black\" stroke=\"black\" points=\"79.92,-21.5 89.92,-18 79.92,-14.5 79.92,-21.5\"/>\r\n",
157 "</g>\r\n",
158 "<!-- 3 -->\r\n",
159 "<g id=\"node3\" class=\"node\">\r\n",
160 "<title>3</title>\r\n",
161 "<ellipse fill=\"none\" stroke=\"black\" cx=\"207\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
162 "<text text-anchor=\"middle\" x=\"207\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">3</text>\r\n",
163 "</g>\r\n",
164 "<!-- 2&#45;&gt;3 -->\r\n",
165 "<g id=\"edge2\" class=\"edge\">\r\n",
166 "<title>2&#45;&gt;3</title>\r\n",
167 "<path fill=\"none\" stroke=\"black\" d=\"M144.4,-18C152.39,-18 161.31,-18 169.82,-18\"/>\r\n",
168 "<polygon fill=\"black\" stroke=\"black\" points=\"169.92,-21.5 179.92,-18 169.92,-14.5 169.92,-21.5\"/>\r\n",
169 "</g>\r\n",
170 "<!-- lob -->\r\n",
171 "<g id=\"node4\" class=\"node\">\r\n",
172 "<title>lob</title>\r\n",
173 "<ellipse fill=\"none\" stroke=\"black\" cx=\"297\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
174 "<text text-anchor=\"middle\" x=\"297\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">lob</text>\r\n",
175 "</g>\r\n",
176 "<!-- 3&#45;&gt;lob -->\r\n",
177 "<g id=\"edge3\" class=\"edge\">\r\n",
178 "<title>3&#45;&gt;lob</title>\r\n",
179 "<path fill=\"none\" stroke=\"black\" d=\"M234.4,-18C242.39,-18 251.31,-18 259.82,-18\"/>\r\n",
180 "<polygon fill=\"black\" stroke=\"black\" points=\"259.92,-21.5 269.92,-18 259.92,-14.5 259.92,-21.5\"/>\r\n",
181 "</g>\r\n",
182 "</g>\r\n",
183 "</svg>\r\n"
184 ],
185 "text/plain": [
186 "<graphviz.files.Source at 0x1c71cde6d60>"
187 ]
188 },
189 "execution_count": 3,
190 "metadata": {},
191 "output_type": "execute_result"
192 }
193 ],
194 "source": [
195 "src = graphviz.Source('digraph \"the holy hand grenade\" { rankdir=LR; 1 -> 2 -> 3 -> lob }')\n",
196 "src"
197 ]
198 },
199 {
200 "cell_type": "code",
201 "execution_count": 4,
202 "metadata": {},
203 "outputs": [
204 {
205 "name": "stderr",
206 "output_type": "stream",
207 "text": [
208 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
209 ]
210 },
211 {
212 "data": {
213 "image/svg+xml": [
214 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
215 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
216 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
217 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
218 " -->\r\n",
219 "<!-- Title: finite_state_machine Pages: 1 -->\r\n",
220 "<svg width=\"576pt\" height=\"258pt\"\r\n",
221 " viewBox=\"0.00 0.00 576.00 258.45\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
222 "<g id=\"graph0\" class=\"graph\" transform=\"scale(0.77 0.77) rotate(0) translate(4 331.69)\">\r\n",
223 "<title>finite_state_machine</title>\r\n",
224 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-331.69 744.17,-331.69 744.17,4 -4,4\"/>\r\n",
225 "<!-- LR_0 -->\r\n",
226 "<g id=\"node1\" class=\"node\">\r\n",
227 "<title>LR_0</title>\r\n",
228 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.85\" cy=\"-83.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
229 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.85\" cy=\"-83.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
230 "<text text-anchor=\"middle\" x=\"35.85\" y=\"-80.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_0</text>\r\n",
231 "</g>\r\n",
232 "<!-- LR_2 -->\r\n",
233 "<g id=\"node5\" class=\"node\">\r\n",
234 "<title>LR_2</title>\r\n",
235 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.54\" cy=\"-151.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
236 "<text text-anchor=\"middle\" x=\"174.54\" y=\"-148.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_2</text>\r\n",
237 "</g>\r\n",
238 "<!-- LR_0&#45;&gt;LR_2 -->\r\n",
239 "<g id=\"edge1\" class=\"edge\">\r\n",
240 "<title>LR_0&#45;&gt;LR_2</title>\r\n",
241 "<path fill=\"none\" stroke=\"black\" d=\"M68.21,-99.45C88.53,-109.56 115.1,-122.77 136.47,-133.4\"/>\r\n",
242 "<polygon fill=\"black\" stroke=\"black\" points=\"135.06,-136.61 145.58,-137.94 138.18,-130.35 135.06,-136.61\"/>\r\n",
243 "<text text-anchor=\"middle\" x=\"107.19\" y=\"-129.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(B)</text>\r\n",
244 "</g>\r\n",
245 "<!-- LR_1 -->\r\n",
246 "<g id=\"node6\" class=\"node\">\r\n",
247 "<title>LR_1</title>\r\n",
248 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.54\" cy=\"-42.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
249 "<text text-anchor=\"middle\" x=\"174.54\" y=\"-39.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_1</text>\r\n",
250 "</g>\r\n",
251 "<!-- LR_0&#45;&gt;LR_1 -->\r\n",
252 "<g id=\"edge2\" class=\"edge\">\r\n",
253 "<title>LR_0&#45;&gt;LR_1</title>\r\n",
254 "<path fill=\"none\" stroke=\"black\" d=\"M70.29,-73.82C89.49,-68.06 113.72,-60.79 133.88,-54.74\"/>\r\n",
255 "<polygon fill=\"black\" stroke=\"black\" points=\"135.13,-58.02 143.7,-51.8 133.12,-51.32 135.13,-58.02\"/>\r\n",
256 "<text text-anchor=\"middle\" x=\"107.19\" y=\"-71.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(S)</text>\r\n",
257 "</g>\r\n",
258 "<!-- LR_3 -->\r\n",
259 "<g id=\"node2\" class=\"node\">\r\n",
260 "<title>LR_3</title>\r\n",
261 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-35.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
262 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-35.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
263 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-32.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_3</text>\r\n",
264 "</g>\r\n",
265 "<!-- LR_4 -->\r\n",
266 "<g id=\"node3\" class=\"node\">\r\n",
267 "<title>LR_4</title>\r\n",
268 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-291.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
269 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-291.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
270 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-288.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_4</text>\r\n",
271 "</g>\r\n",
272 "<!-- LR_8 -->\r\n",
273 "<g id=\"node4\" class=\"node\">\r\n",
274 "<title>LR_8</title>\r\n",
275 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.32\" cy=\"-152.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
276 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.32\" cy=\"-152.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
277 "<text text-anchor=\"middle\" x=\"704.32\" y=\"-149.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_8</text>\r\n",
278 "</g>\r\n",
279 "<!-- LR_6 -->\r\n",
280 "<g id=\"node7\" class=\"node\">\r\n",
281 "<title>LR_6</title>\r\n",
282 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-172.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
283 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-169.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_6</text>\r\n",
284 "</g>\r\n",
285 "<!-- LR_8&#45;&gt;LR_6 -->\r\n",
286 "<g id=\"edge13\" class=\"edge\">\r\n",
287 "<title>LR_8&#45;&gt;LR_6</title>\r\n",
288 "<path fill=\"none\" stroke=\"black\" d=\"M668.7,-158.83C625.38,-165.98 548.87,-177.52 482.78,-181.85 454.53,-183.7 447.36,-183.19 419.08,-181.85 401.3,-181.01 381.7,-179.28 364.95,-177.56\"/>\r\n",
289 "<polygon fill=\"black\" stroke=\"black\" points=\"365.25,-174.07 354.94,-176.5 364.51,-181.04 365.25,-174.07\"/>\r\n",
290 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-183.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
291 "</g>\r\n",
292 "<!-- LR_5 -->\r\n",
293 "<g id=\"node8\" class=\"node\">\r\n",
294 "<title>LR_5</title>\r\n",
295 "<ellipse fill=\"none\" stroke=\"black\" cx=\"450.93\" cy=\"-107.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
296 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-104.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_5</text>\r\n",
297 "</g>\r\n",
298 "<!-- LR_8&#45;&gt;LR_5 -->\r\n",
299 "<g id=\"edge14\" class=\"edge\">\r\n",
300 "<title>LR_8&#45;&gt;LR_5</title>\r\n",
301 "<path fill=\"none\" stroke=\"black\" d=\"M668.83,-147.36C628.46,-140.82 559.62,-129.34 500.78,-117.85 497.99,-117.3 495.11,-116.73 492.22,-116.15\"/>\r\n",
302 "<polygon fill=\"black\" stroke=\"black\" points=\"492.89,-112.72 482.4,-114.17 491.51,-119.58 492.89,-112.72\"/>\r\n",
303 "<text text-anchor=\"middle\" x=\"575.62\" y=\"-139.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
304 "</g>\r\n",
305 "<!-- LR_2&#45;&gt;LR_4 -->\r\n",
306 "<g id=\"edge6\" class=\"edge\">\r\n",
307 "<title>LR_2&#45;&gt;LR_4</title>\r\n",
308 "<path fill=\"none\" stroke=\"black\" d=\"M198.14,-173.42C222.46,-196.62 261.37,-233.76 289.13,-260.26\"/>\r\n",
309 "<polygon fill=\"black\" stroke=\"black\" points=\"287,-263.06 296.65,-267.43 291.83,-257.99 287,-263.06\"/>\r\n",
310 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-241.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(A)</text>\r\n",
311 "</g>\r\n",
312 "<!-- LR_2&#45;&gt;LR_6 -->\r\n",
313 "<g id=\"edge4\" class=\"edge\">\r\n",
314 "<title>LR_2&#45;&gt;LR_6</title>\r\n",
315 "<path fill=\"none\" stroke=\"black\" d=\"M206.29,-156.25C228.1,-159.37 257.6,-163.59 281.38,-167\"/>\r\n",
316 "<polygon fill=\"black\" stroke=\"black\" points=\"281.13,-170.5 291.52,-168.45 282.12,-163.57 281.13,-170.5\"/>\r\n",
317 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-167.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(b)</text>\r\n",
318 "</g>\r\n",
319 "<!-- LR_2&#45;&gt;LR_5 -->\r\n",
320 "<g id=\"edge5\" class=\"edge\">\r\n",
321 "<title>LR_2&#45;&gt;LR_5</title>\r\n",
322 "<path fill=\"none\" stroke=\"black\" d=\"M204.48,-140.61C226.77,-132.49 258.56,-122.07 287.39,-116.85 328.17,-109.46 375.56,-107.58 408.61,-107.32\"/>\r\n",
323 "<polygon fill=\"black\" stroke=\"black\" points=\"408.82,-110.82 418.81,-107.29 408.8,-103.82 408.82,-110.82\"/>\r\n",
324 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-120.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(a)</text>\r\n",
325 "</g>\r\n",
326 "<!-- LR_1&#45;&gt;LR_3 -->\r\n",
327 "<g id=\"edge3\" class=\"edge\">\r\n",
328 "<title>LR_1&#45;&gt;LR_3</title>\r\n",
329 "<path fill=\"none\" stroke=\"black\" d=\"M206.65,-41.36C227.15,-40.38 254.31,-39.09 277.16,-38\"/>\r\n",
330 "<polygon fill=\"black\" stroke=\"black\" points=\"277.49,-41.49 287.31,-37.51 277.16,-34.49 277.49,-41.49\"/>\r\n",
331 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-44.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S($end)</text>\r\n",
332 "</g>\r\n",
333 "<!-- LR_6&#45;&gt;LR_6 -->\r\n",
334 "<g id=\"edge9\" class=\"edge\">\r\n",
335 "<title>LR_6&#45;&gt;LR_6</title>\r\n",
336 "<path fill=\"none\" stroke=\"black\" d=\"M311.26,-202.53C310.87,-213.59 314.86,-222.69 323.24,-222.69 328.86,-222.69 332.51,-218.58 334.18,-212.53\"/>\r\n",
337 "<polygon fill=\"black\" stroke=\"black\" points=\"337.67,-212.83 335.21,-202.53 330.7,-212.12 337.67,-212.83\"/>\r\n",
338 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-226.49\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
339 "</g>\r\n",
340 "<!-- LR_6&#45;&gt;LR_5 -->\r\n",
341 "<g id=\"edge10\" class=\"edge\">\r\n",
342 "<title>LR_6&#45;&gt;LR_5</title>\r\n",
343 "<path fill=\"none\" stroke=\"black\" d=\"M351.82,-158.58C369.91,-149.23 393.77,-136.89 413.43,-126.72\"/>\r\n",
344 "<polygon fill=\"black\" stroke=\"black\" points=\"415.14,-129.78 422.41,-122.08 411.92,-123.56 415.14,-129.78\"/>\r\n",
345 "<text text-anchor=\"middle\" x=\"389.08\" y=\"-147.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
346 "</g>\r\n",
347 "<!-- LR_5&#45;&gt;LR_5 -->\r\n",
348 "<g id=\"edge8\" class=\"edge\">\r\n",
349 "<title>LR_5&#45;&gt;LR_5</title>\r\n",
350 "<path fill=\"none\" stroke=\"black\" d=\"M439.69,-138.02C439.45,-148.86 443.2,-157.69 450.93,-157.69 456.01,-157.69 459.36,-153.89 461,-148.21\"/>\r\n",
351 "<polygon fill=\"black\" stroke=\"black\" points=\"464.51,-148.35 462.17,-138.02 457.56,-147.56 464.51,-148.35\"/>\r\n",
352 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-161.49\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
353 "</g>\r\n",
354 "<!-- LR_7 -->\r\n",
355 "<g id=\"node9\" class=\"node\">\r\n",
356 "<title>LR_7</title>\r\n",
357 "<ellipse fill=\"none\" stroke=\"black\" cx=\"575.62\" cy=\"-84.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
358 "<text text-anchor=\"middle\" x=\"575.62\" y=\"-81.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_7</text>\r\n",
359 "</g>\r\n",
360 "<!-- LR_5&#45;&gt;LR_7 -->\r\n",
361 "<g id=\"edge7\" class=\"edge\">\r\n",
362 "<title>LR_5&#45;&gt;LR_7</title>\r\n",
363 "<path fill=\"none\" stroke=\"black\" d=\"M482.57,-102.1C498.09,-99.19 517.14,-95.62 533.88,-92.49\"/>\r\n",
364 "<polygon fill=\"black\" stroke=\"black\" points=\"534.76,-95.88 543.95,-90.6 533.47,-89 534.76,-95.88\"/>\r\n",
365 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-102.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
366 "</g>\r\n",
367 "<!-- LR_7&#45;&gt;LR_8 -->\r\n",
368 "<g id=\"edge11\" class=\"edge\">\r\n",
369 "<title>LR_7&#45;&gt;LR_8</title>\r\n",
370 "<path fill=\"none\" stroke=\"black\" d=\"M604.38,-99.37C618.26,-106.67 635.28,-115.67 650.47,-123.85 654.74,-126.14 659.19,-128.56 663.62,-130.98\"/>\r\n",
371 "<polygon fill=\"black\" stroke=\"black\" points=\"662.17,-134.17 672.62,-135.9 665.53,-128.03 662.17,-134.17\"/>\r\n",
372 "<text text-anchor=\"middle\" x=\"637.97\" y=\"-127.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
373 "</g>\r\n",
374 "<!-- LR_7&#45;&gt;LR_5 -->\r\n",
375 "<g id=\"edge12\" class=\"edge\">\r\n",
376 "<title>LR_7&#45;&gt;LR_5</title>\r\n",
377 "<path fill=\"none\" stroke=\"black\" d=\"M545.05,-75.8C531.36,-72.99 515.01,-71.6 500.78,-75.85 495.43,-77.44 490.13,-79.83 485.1,-82.59\"/>\r\n",
378 "<polygon fill=\"black\" stroke=\"black\" points=\"483.11,-79.7 476.38,-87.89 486.75,-85.69 483.11,-79.7\"/>\r\n",
379 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-79.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
380 "</g>\r\n",
381 "</g>\r\n",
382 "</svg>\r\n"
383 ],
384 "text/plain": [
385 "<graphviz.dot.Digraph at 0x1c71cdf0220>"
386 ]
387 },
388 "execution_count": 4,
389 "metadata": {},
390 "output_type": "execute_result"
391 }
392 ],
393 "source": [
394 "# http://www.graphviz.org/content/fsm\n",
395 "\n",
396 "f = graphviz.Digraph('finite_state_machine', filename='fsm.gv')\n",
397 "f.attr(rankdir='LR', size='8,5')\n",
398 "\n",
399 "f.attr('node', shape='doublecircle')\n",
400 "f.node('LR_0')\n",
401 "f.node('LR_3')\n",
402 "f.node('LR_4')\n",
403 "f.node('LR_8')\n",
404 "\n",
405 "f.attr('node', shape='circle')\n",
406 "f.edge('LR_0', 'LR_2', label='SS(B)')\n",
407 "f.edge('LR_0', 'LR_1', label='SS(S)')\n",
408 "f.edge('LR_1', 'LR_3', label='S($end)')\n",
409 "f.edge('LR_2', 'LR_6', label='SS(b)')\n",
410 "f.edge('LR_2', 'LR_5', label='SS(a)')\n",
411 "f.edge('LR_2', 'LR_4', label='S(A)')\n",
412 "f.edge('LR_5', 'LR_7', label='S(b)')\n",
413 "f.edge('LR_5', 'LR_5', label='S(a)')\n",
414 "f.edge('LR_6', 'LR_6', label='S(b)')\n",
415 "f.edge('LR_6', 'LR_5', label='S(a)')\n",
416 "f.edge('LR_7', 'LR_8', label='S(b)')\n",
417 "f.edge('LR_7', 'LR_5', label='S(a)')\n",
418 "f.edge('LR_8', 'LR_6', label='S(b)')\n",
419 "f.edge('LR_8', 'LR_5', label='S(a)')\n",
420 "\n",
421 "f"
422 ]
423 },
424 {
425 "cell_type": "code",
426 "execution_count": 5,
427 "metadata": {},
428 "outputs": [
429 {
430 "name": "stderr",
431 "output_type": "stream",
432 "text": [
433 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
434 ]
435 },
436 {
437 "data": {
438 "image/svg+xml": [
439 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
440 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
441 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
442 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
443 " -->\r\n",
444 "<!-- Title: G Pages: 1 -->\r\n",
445 "<svg width=\"222pt\" height=\"364pt\"\r\n",
446 " viewBox=\"0.00 0.00 222.00 364.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
447 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 360)\">\r\n",
448 "<title>G</title>\r\n",
449 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-360 218,-360 218,4 -4,4\"/>\r\n",
450 "<g id=\"clust1\" class=\"cluster\">\r\n",
451 "<title>cluster0</title>\r\n",
452 "<polygon fill=\"none\" stroke=\"black\" points=\"64,-152 64,-348 206,-348 206,-152 64,-152\"/>\r\n",
453 "</g>\r\n",
454 "<g id=\"clust2\" class=\"cluster\">\r\n",
455 "<title>cluster1</title>\r\n",
456 "<polygon fill=\"none\" stroke=\"black\" points=\"64,-8 64,-132 206,-132 206,-8 64,-8\"/>\r\n",
457 "</g>\r\n",
458 "<!-- a -->\r\n",
459 "<g id=\"node1\" class=\"node\">\r\n",
460 "<title>a</title>\r\n",
461 "<ellipse fill=\"none\" stroke=\"black\" cx=\"135\" cy=\"-322\" rx=\"27\" ry=\"18\"/>\r\n",
462 "<text text-anchor=\"middle\" x=\"135\" y=\"-318.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">a</text>\r\n",
463 "</g>\r\n",
464 "<!-- b -->\r\n",
465 "<g id=\"node2\" class=\"node\">\r\n",
466 "<title>b</title>\r\n",
467 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\r\n",
468 "<text text-anchor=\"middle\" x=\"99\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">b</text>\r\n",
469 "</g>\r\n",
470 "<!-- a&#45;&gt;b -->\r\n",
471 "<g id=\"edge1\" class=\"edge\">\r\n",
472 "<title>a&#45;&gt;b</title>\r\n",
473 "<path fill=\"none\" stroke=\"black\" d=\"M126.65,-304.76C122.29,-296.28 116.85,-285.71 111.96,-276.2\"/>\r\n",
474 "<polygon fill=\"black\" stroke=\"black\" points=\"114.99,-274.44 107.3,-267.15 108.77,-277.64 114.99,-274.44\"/>\r\n",
475 "</g>\r\n",
476 "<!-- c -->\r\n",
477 "<g id=\"node3\" class=\"node\">\r\n",
478 "<title>c</title>\r\n",
479 "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\r\n",
480 "<text text-anchor=\"middle\" x=\"171\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">c</text>\r\n",
481 "</g>\r\n",
482 "<!-- a&#45;&gt;c -->\r\n",
483 "<g id=\"edge2\" class=\"edge\">\r\n",
484 "<title>a&#45;&gt;c</title>\r\n",
485 "<path fill=\"none\" stroke=\"black\" d=\"M143.35,-304.76C147.71,-296.28 153.15,-285.71 158.04,-276.2\"/>\r\n",
486 "<polygon fill=\"black\" stroke=\"black\" points=\"161.23,-277.64 162.7,-267.15 155.01,-274.44 161.23,-277.64\"/>\r\n",
487 "</g>\r\n",
488 "<!-- d -->\r\n",
489 "<g id=\"node4\" class=\"node\">\r\n",
490 "<title>d</title>\r\n",
491 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-178\" rx=\"27\" ry=\"18\"/>\r\n",
492 "<text text-anchor=\"middle\" x=\"99\" y=\"-174.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">d</text>\r\n",
493 "</g>\r\n",
494 "<!-- b&#45;&gt;d -->\r\n",
495 "<g id=\"edge3\" class=\"edge\">\r\n",
496 "<title>b&#45;&gt;d</title>\r\n",
497 "<path fill=\"none\" stroke=\"black\" d=\"M99,-231.7C99,-223.98 99,-214.71 99,-206.11\"/>\r\n",
498 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-206.1 99,-196.1 95.5,-206.1 102.5,-206.1\"/>\r\n",
499 "</g>\r\n",
500 "<!-- f -->\r\n",
501 "<g id=\"node7\" class=\"node\">\r\n",
502 "<title>f</title>\r\n",
503 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\r\n",
504 "<text text-anchor=\"middle\" x=\"99\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">f</text>\r\n",
505 "</g>\r\n",
506 "<!-- b&#45;&gt;f -->\r\n",
507 "<g id=\"edge7\" class=\"edge\">\r\n",
508 "<title>b&#45;&gt;f</title>\r\n",
509 "<path fill=\"none\" stroke=\"black\" d=\"M112.75,-234.07C120.96,-224.1 130.62,-210.25 135,-196 142.02,-173.17 145.55,-157.68 145.58,-142.23\"/>\r\n",
510 "<polygon fill=\"black\" stroke=\"black\" points=\"149.07,-141.82 145.1,-132 142.07,-142.15 149.07,-141.82\"/>\r\n",
511 "</g>\r\n",
512 "<!-- c&#45;&gt;d -->\r\n",
513 "<g id=\"edge4\" class=\"edge\">\r\n",
514 "<title>c&#45;&gt;d</title>\r\n",
515 "<path fill=\"none\" stroke=\"black\" d=\"M156.43,-234.83C146.25,-224.94 132.48,-211.55 120.97,-200.36\"/>\r\n",
516 "<polygon fill=\"black\" stroke=\"black\" points=\"123.41,-197.85 113.8,-193.38 118.53,-202.87 123.41,-197.85\"/>\r\n",
517 "</g>\r\n",
518 "<!-- e -->\r\n",
519 "<g id=\"node5\" class=\"node\">\r\n",
520 "<title>e</title>\r\n",
521 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\r\n",
522 "<text text-anchor=\"middle\" x=\"99\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">e</text>\r\n",
523 "</g>\r\n",
524 "<!-- c&#45;&gt;e -->\r\n",
525 "<g id=\"edge10\" class=\"edge\">\r\n",
526 "<title>c&#45;&gt;e</title>\r\n",
527 "<path fill=\"none\" stroke=\"black\" d=\"M135,-152C130.7,-144.41 125.16,-136.77 119.71,-129.99\"/>\r\n",
528 "<polygon fill=\"black\" stroke=\"black\" points=\"122.07,-127.36 112.97,-121.94 116.71,-131.86 122.07,-127.36\"/>\r\n",
529 "</g>\r\n",
530 "<!-- g -->\r\n",
531 "<g id=\"node6\" class=\"node\">\r\n",
532 "<title>g</title>\r\n",
533 "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\r\n",
534 "<text text-anchor=\"middle\" x=\"171\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">g</text>\r\n",
535 "</g>\r\n",
536 "<!-- c&#45;&gt;g -->\r\n",
537 "<g id=\"edge9\" class=\"edge\">\r\n",
538 "<title>c&#45;&gt;g</title>\r\n",
539 "<path fill=\"none\" stroke=\"black\" d=\"M171,-152C171,-148.77 171,-145.53 171,-142.29\"/>\r\n",
540 "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-141.99 171,-132 167.5,-142 174.5,-141.99\"/>\r\n",
541 "</g>\r\n",
542 "<!-- d&#45;&gt;e -->\r\n",
543 "<g id=\"edge8\" class=\"edge\">\r\n",
544 "<title>d&#45;&gt;e</title>\r\n",
545 "<path fill=\"none\" stroke=\"black\" d=\"M99,-159.7C99,-151.98 99,-142.71 99,-134.11\"/>\r\n",
546 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-134.1 99,-124.1 95.5,-134.1 102.5,-134.1\"/>\r\n",
547 "</g>\r\n",
548 "<!-- h -->\r\n",
549 "<g id=\"node8\" class=\"node\">\r\n",
550 "<title>h</title>\r\n",
551 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\r\n",
552 "<text text-anchor=\"middle\" x=\"27\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">h</text>\r\n",
553 "</g>\r\n",
554 "<!-- d&#45;&gt;h -->\r\n",
555 "<g id=\"edge11\" class=\"edge\">\r\n",
556 "<title>d&#45;&gt;h</title>\r\n",
557 "<path fill=\"none\" stroke=\"black\" d=\"M84.43,-162.83C74.25,-152.94 60.48,-139.55 48.97,-128.36\"/>\r\n",
558 "<polygon fill=\"black\" stroke=\"black\" points=\"51.41,-125.85 41.8,-121.38 46.53,-130.87 51.41,-125.85\"/>\r\n",
559 "</g>\r\n",
560 "<!-- e&#45;&gt;g -->\r\n",
561 "<g id=\"edge5\" class=\"edge\">\r\n",
562 "<title>e&#45;&gt;g</title>\r\n",
563 "<path fill=\"none\" stroke=\"black\" d=\"M113.57,-90.83C123.75,-80.94 137.52,-67.55 149.03,-56.36\"/>\r\n",
564 "<polygon fill=\"black\" stroke=\"black\" points=\"151.47,-58.87 156.2,-49.38 146.59,-53.85 151.47,-58.87\"/>\r\n",
565 "</g>\r\n",
566 "<!-- e&#45;&gt;f -->\r\n",
567 "<g id=\"edge6\" class=\"edge\">\r\n",
568 "<title>e&#45;&gt;f</title>\r\n",
569 "<path fill=\"none\" stroke=\"black\" d=\"M99,-87.7C99,-79.98 99,-70.71 99,-62.11\"/>\r\n",
570 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-62.1 99,-52.1 95.5,-62.1 102.5,-62.1\"/>\r\n",
571 "</g>\r\n",
572 "</g>\r\n",
573 "</svg>\r\n"
574 ],
575 "text/plain": [
576 "<graphviz.dot.Digraph at 0x1c71cdf19d0>"
577 ]
578 },
579 "execution_count": 5,
580 "metadata": {},
581 "output_type": "execute_result"
582 }
583 ],
584 "source": [
585 "# http://www.graphviz.org/pdf/dotguide.pdf, Figure 20\n",
586 "\n",
587 "g = graphviz.Digraph('G', filename='cluster_edge.gv')\n",
588 "g.attr(compound='true')\n",
589 "\n",
590 "with g.subgraph(name='cluster0') as c:\n",
591 " c.edges(['ab', 'ac', 'bd', 'cd'])\n",
592 "\n",
593 "with g.subgraph(name='cluster1') as c:\n",
594 " c.edges(['eg', 'ef'])\n",
595 "\n",
596 "g.edge('b', 'f', lhead='cluster1')\n",
597 "g.edge('d', 'e')\n",
598 "g.edge('c', 'g', ltail='cluster0', lhead='cluster1')\n",
599 "g.edge('c', 'e', ltail='cluster0')\n",
600 "g.edge('d', 'h')\n",
601 "\n",
602 "g"
603 ]
604 }
605 ],
606 "metadata": {
607 "kernelspec": {
608 "display_name": "Python 3",
609 "language": "python",
610 "name": "python3"
611 },
612 "language_info": {
613 "codemirror_mode": {
614 "name": "ipython",
615 "version": 3
616 },
617 "file_extension": ".py",
618 "mimetype": "text/x-python",
619 "name": "python",
620 "nbconvert_exporter": "python",
621 "pygments_lexer": "ipython3",
622 "version": "3.9.4"
623 }
624 },
625 "nbformat": 4,
626 "nbformat_minor": 1
627 }
0 #!/usr/bin/env python
1 # hello.py - http://www.graphviz.org/content/hello
2
3 from graphviz import Digraph
4
5 g = Digraph('G', filename='hello.gv')
6
7 g.edge('Hello', 'World')
8
9 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/hello"""
3
4 import graphviz
5
6 g = graphviz.Digraph('G', filename='hello.gv')
7
8 g.edge('Hello', 'World')
9
10 g.view()
33 "cell_type": "code",
44 "execution_count": 1,
55 "metadata": {},
6 "outputs": [],
6 "outputs": [
7 {
8 "data": {
9 "text/plain": [
10 "'0.16'"
11 ]
12 },
13 "execution_count": 1,
14 "metadata": {},
15 "output_type": "execute_result"
16 }
17 ],
718 "source": [
819 "import logging\n",
920 "\n",
10 "logging.basicConfig(format='[%(levelname)s@%(name)s] %(message)s', level=logging.DEBUG)"
21 "import graphviz\n",
22 "\n",
23 "logging.basicConfig(format='[%(levelname)s@%(name)s] %(message)s', level=logging.DEBUG)\n",
24 "\n",
25 "graphviz.__version__"
1126 ]
1227 },
1328 {
1934 "name": "stderr",
2035 "output_type": "stream",
2136 "text": [
22 "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n"
37 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
2338 ]
2439 },
2540 {
2843 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
2944 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
3045 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
31 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
46 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
3247 " -->\r\n",
33 "<!-- Title: %3 Pages: 1 -->\r\n",
48 "<!-- Pages: 1 -->\r\n",
3449 "<svg width=\"390pt\" height=\"116pt\"\r\n",
3550 " viewBox=\"0.00 0.00 389.98 116.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
3651 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 112)\">\r\n",
37 "<title>%3</title>\r\n",
38 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-112 385.984,-112 385.984,4 -4,4\"/>\r\n",
52 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-112 385.98,-112 385.98,4 -4,4\"/>\r\n",
3953 "<!-- A -->\r\n",
40 "<g id=\"node1\" class=\"node\"><title>A</title>\r\n",
41 "<ellipse fill=\"none\" stroke=\"black\" cx=\"190.992\" cy=\"-90\" rx=\"53.8905\" ry=\"18\"/>\r\n",
42 "<text text-anchor=\"middle\" x=\"190.992\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">King Arthur</text>\r\n",
54 "<g id=\"node1\" class=\"node\">\r\n",
55 "<title>A</title>\r\n",
56 "<ellipse fill=\"none\" stroke=\"black\" cx=\"190.99\" cy=\"-90\" rx=\"53.89\" ry=\"18\"/>\r\n",
57 "<text text-anchor=\"middle\" x=\"190.99\" y=\"-86.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">King Arthur</text>\r\n",
4358 "</g>\r\n",
4459 "<!-- B -->\r\n",
45 "<g id=\"node2\" class=\"node\"><title>B</title>\r\n",
46 "<ellipse fill=\"none\" stroke=\"black\" cx=\"90.9919\" cy=\"-18\" rx=\"90.9839\" ry=\"18\"/>\r\n",
47 "<text text-anchor=\"middle\" x=\"90.9919\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Bedevere the Wise</text>\r\n",
60 "<g id=\"node2\" class=\"node\">\r\n",
61 "<title>B</title>\r\n",
62 "<ellipse fill=\"none\" stroke=\"black\" cx=\"90.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\r\n",
63 "<text text-anchor=\"middle\" x=\"90.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Bedevere the Wise</text>\r\n",
4864 "</g>\r\n",
4965 "<!-- A&#45;&gt;B -->\r\n",
50 "<g id=\"edge1\" class=\"edge\"><title>A&#45;&gt;B</title>\r\n",
51 "<path fill=\"none\" stroke=\"black\" d=\"M168.799,-73.4647C155.331,-64.0371 137.916,-51.8466 122.977,-41.3897\"/>\r\n",
52 "<polygon fill=\"black\" stroke=\"black\" points=\"124.716,-38.3345 114.516,-35.4672 120.702,-44.0692 124.716,-38.3345\"/>\r\n",
66 "<g id=\"edge1\" class=\"edge\">\r\n",
67 "<title>A&#45;&gt;B</title>\r\n",
68 "<path fill=\"none\" stroke=\"black\" d=\"M168.8,-73.46C155.33,-64.04 137.92,-51.85 122.98,-41.39\"/>\r\n",
69 "<polygon fill=\"black\" stroke=\"black\" points=\"124.72,-38.33 114.52,-35.47 120.7,-44.07 124.72,-38.33\"/>\r\n",
5370 "</g>\r\n",
5471 "<!-- L -->\r\n",
55 "<g id=\"node3\" class=\"node\"><title>L</title>\r\n",
56 "<ellipse fill=\"none\" stroke=\"black\" cx=\"290.992\" cy=\"-18\" rx=\"90.9839\" ry=\"18\"/>\r\n",
57 "<text text-anchor=\"middle\" x=\"290.992\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Lancelot the Brave</text>\r\n",
72 "<g id=\"node3\" class=\"node\">\r\n",
73 "<title>L</title>\r\n",
74 "<ellipse fill=\"none\" stroke=\"black\" cx=\"290.99\" cy=\"-18\" rx=\"90.98\" ry=\"18\"/>\r\n",
75 "<text text-anchor=\"middle\" x=\"290.99\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">Sir Lancelot the Brave</text>\r\n",
5876 "</g>\r\n",
5977 "<!-- A&#45;&gt;L -->\r\n",
60 "<g id=\"edge2\" class=\"edge\"><title>A&#45;&gt;L</title>\r\n",
61 "<path fill=\"none\" stroke=\"black\" d=\"M213.185,-73.4647C226.653,-64.0371 244.068,-51.8466 259.007,-41.3897\"/>\r\n",
62 "<polygon fill=\"black\" stroke=\"black\" points=\"261.282,-44.0692 267.467,-35.4672 257.268,-38.3345 261.282,-44.0692\"/>\r\n",
78 "<g id=\"edge2\" class=\"edge\">\r\n",
79 "<title>A&#45;&gt;L</title>\r\n",
80 "<path fill=\"none\" stroke=\"black\" d=\"M213.19,-73.46C226.65,-64.04 244.07,-51.85 259.01,-41.39\"/>\r\n",
81 "<polygon fill=\"black\" stroke=\"black\" points=\"261.28,-44.07 267.47,-35.47 257.27,-38.33 261.28,-44.07\"/>\r\n",
6382 "</g>\r\n",
6483 "<!-- B&#45;&gt;L -->\r\n",
65 "<g id=\"edge3\" class=\"edge\"><title>B&#45;&gt;L</title>\r\n",
66 "<path fill=\"none\" stroke=\"black\" d=\"M182.008,-18C184.615,-18 187.223,-18 189.83,-18\"/>\r\n",
67 "<polygon fill=\"black\" stroke=\"black\" points=\"189.888,-21.5001 199.888,-18 189.888,-14.5001 189.888,-21.5001\"/>\r\n",
84 "<g id=\"edge3\" class=\"edge\">\r\n",
85 "<title>B&#45;&gt;L</title>\r\n",
86 "<path fill=\"none\" stroke=\"black\" d=\"M182.01,-18C184.62,-18 187.22,-18 189.83,-18\"/>\r\n",
87 "<polygon fill=\"black\" stroke=\"black\" points=\"189.89,-21.5 199.89,-18 189.89,-14.5 189.89,-21.5\"/>\r\n",
6888 "</g>\r\n",
6989 "</g>\r\n",
7090 "</svg>\r\n"
7191 ],
7292 "text/plain": [
73 "<graphviz.dot.Digraph at 0x505fcc8>"
93 "<graphviz.dot.Digraph at 0x1c71cc84970>"
7494 ]
7595 },
7696 "execution_count": 2,
7999 }
80100 ],
81101 "source": [
82 "from graphviz import Digraph\n",
83 "\n",
84 "dot = Digraph(comment='The Round Table')\n",
102 "dot = graphviz.Digraph(comment='The Round Table')\n",
85103 "\n",
86104 "dot.node('A', 'King Arthur')\n",
87105 "dot.node('B', 'Sir Bedevere the Wise')\n",
102120 "name": "stderr",
103121 "output_type": "stream",
104122 "text": [
105 "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n"
123 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
106124 ]
107125 },
108126 {
111129 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
112130 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
113131 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
114 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
132 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
115133 " -->\r\n",
116134 "<!-- Title: the holy hand grenade Pages: 1 -->\r\n",
117135 "<svg width=\"332pt\" height=\"44pt\"\r\n",
118136 " viewBox=\"0.00 0.00 332.00 44.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
119137 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n",
120138 "<title>the holy hand grenade</title>\r\n",
121 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-40 328,-40 328,4 -4,4\"/>\r\n",
139 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-40 328,-40 328,4 -4,4\"/>\r\n",
122140 "<!-- 1 -->\r\n",
123 "<g id=\"node1\" class=\"node\"><title>1</title>\r\n",
141 "<g id=\"node1\" class=\"node\">\r\n",
142 "<title>1</title>\r\n",
124143 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
125144 "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">1</text>\r\n",
126145 "</g>\r\n",
127146 "<!-- 2 -->\r\n",
128 "<g id=\"node2\" class=\"node\"><title>2</title>\r\n",
147 "<g id=\"node2\" class=\"node\">\r\n",
148 "<title>2</title>\r\n",
129149 "<ellipse fill=\"none\" stroke=\"black\" cx=\"117\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
130150 "<text text-anchor=\"middle\" x=\"117\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">2</text>\r\n",
131151 "</g>\r\n",
132152 "<!-- 1&#45;&gt;2 -->\r\n",
133 "<g id=\"edge1\" class=\"edge\"><title>1&#45;&gt;2</title>\r\n",
134 "<path fill=\"none\" stroke=\"black\" d=\"M54.4029,-18C62.3932,-18 71.3106,-18 79.8241,-18\"/>\r\n",
135 "<polygon fill=\"black\" stroke=\"black\" points=\"79.919,-21.5001 89.919,-18 79.919,-14.5001 79.919,-21.5001\"/>\r\n",
153 "<g id=\"edge1\" class=\"edge\">\r\n",
154 "<title>1&#45;&gt;2</title>\r\n",
155 "<path fill=\"none\" stroke=\"black\" d=\"M54.4,-18C62.39,-18 71.31,-18 79.82,-18\"/>\r\n",
156 "<polygon fill=\"black\" stroke=\"black\" points=\"79.92,-21.5 89.92,-18 79.92,-14.5 79.92,-21.5\"/>\r\n",
136157 "</g>\r\n",
137158 "<!-- 3 -->\r\n",
138 "<g id=\"node3\" class=\"node\"><title>3</title>\r\n",
159 "<g id=\"node3\" class=\"node\">\r\n",
160 "<title>3</title>\r\n",
139161 "<ellipse fill=\"none\" stroke=\"black\" cx=\"207\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
140162 "<text text-anchor=\"middle\" x=\"207\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">3</text>\r\n",
141163 "</g>\r\n",
142164 "<!-- 2&#45;&gt;3 -->\r\n",
143 "<g id=\"edge2\" class=\"edge\"><title>2&#45;&gt;3</title>\r\n",
144 "<path fill=\"none\" stroke=\"black\" d=\"M144.403,-18C152.393,-18 161.311,-18 169.824,-18\"/>\r\n",
145 "<polygon fill=\"black\" stroke=\"black\" points=\"169.919,-21.5001 179.919,-18 169.919,-14.5001 169.919,-21.5001\"/>\r\n",
165 "<g id=\"edge2\" class=\"edge\">\r\n",
166 "<title>2&#45;&gt;3</title>\r\n",
167 "<path fill=\"none\" stroke=\"black\" d=\"M144.4,-18C152.39,-18 161.31,-18 169.82,-18\"/>\r\n",
168 "<polygon fill=\"black\" stroke=\"black\" points=\"169.92,-21.5 179.92,-18 169.92,-14.5 169.92,-21.5\"/>\r\n",
146169 "</g>\r\n",
147170 "<!-- lob -->\r\n",
148 "<g id=\"node4\" class=\"node\"><title>lob</title>\r\n",
171 "<g id=\"node4\" class=\"node\">\r\n",
172 "<title>lob</title>\r\n",
149173 "<ellipse fill=\"none\" stroke=\"black\" cx=\"297\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n",
150174 "<text text-anchor=\"middle\" x=\"297\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">lob</text>\r\n",
151175 "</g>\r\n",
152176 "<!-- 3&#45;&gt;lob -->\r\n",
153 "<g id=\"edge3\" class=\"edge\"><title>3&#45;&gt;lob</title>\r\n",
154 "<path fill=\"none\" stroke=\"black\" d=\"M234.403,-18C242.393,-18 251.311,-18 259.824,-18\"/>\r\n",
155 "<polygon fill=\"black\" stroke=\"black\" points=\"259.919,-21.5001 269.919,-18 259.919,-14.5001 259.919,-21.5001\"/>\r\n",
177 "<g id=\"edge3\" class=\"edge\">\r\n",
178 "<title>3&#45;&gt;lob</title>\r\n",
179 "<path fill=\"none\" stroke=\"black\" d=\"M234.4,-18C242.39,-18 251.31,-18 259.82,-18\"/>\r\n",
180 "<polygon fill=\"black\" stroke=\"black\" points=\"259.92,-21.5 269.92,-18 259.92,-14.5 259.92,-21.5\"/>\r\n",
156181 "</g>\r\n",
157182 "</g>\r\n",
158183 "</svg>\r\n"
159184 ],
160185 "text/plain": [
161 "<graphviz.files.Source at 0x505f808>"
186 "<graphviz.files.Source at 0x1c71cde6d60>"
162187 ]
163188 },
164189 "execution_count": 3,
167192 }
168193 ],
169194 "source": [
170 "from graphviz import Source\n",
171 "\n",
172 "src = Source('digraph \"the holy hand grenade\" { rankdir=LR; 1 -> 2 -> 3 -> lob }')\n",
195 "src = graphviz.Source('digraph \"the holy hand grenade\" { rankdir=LR; 1 -> 2 -> 3 -> lob }')\n",
173196 "src"
174197 ]
175198 },
182205 "name": "stderr",
183206 "output_type": "stream",
184207 "text": [
185 "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n"
208 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
186209 ]
187210 },
188211 {
191214 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
192215 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
193216 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
194 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
217 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
195218 " -->\r\n",
196219 "<!-- Title: finite_state_machine Pages: 1 -->\r\n",
197220 "<svg width=\"576pt\" height=\"258pt\"\r\n",
198221 " viewBox=\"0.00 0.00 576.00 258.45\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
199 "<g id=\"graph0\" class=\"graph\" transform=\"scale(0.769883 0.769883) rotate(0) translate(4 331.694)\">\r\n",
222 "<g id=\"graph0\" class=\"graph\" transform=\"scale(0.77 0.77) rotate(0) translate(4 331.69)\">\r\n",
200223 "<title>finite_state_machine</title>\r\n",
201 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-331.694 744.166,-331.694 744.166,4 -4,4\"/>\r\n",
224 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-331.69 744.17,-331.69 744.17,4 -4,4\"/>\r\n",
202225 "<!-- LR_0 -->\r\n",
203 "<g id=\"node1\" class=\"node\"><title>LR_0</title>\r\n",
204 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.8472\" cy=\"-106.847\" rx=\"31.712\" ry=\"31.712\"/>\r\n",
205 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.8472\" cy=\"-106.847\" rx=\"35.695\" ry=\"35.695\"/>\r\n",
206 "<text text-anchor=\"middle\" x=\"35.8472\" y=\"-103.147\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_0</text>\r\n",
226 "<g id=\"node1\" class=\"node\">\r\n",
227 "<title>LR_0</title>\r\n",
228 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.85\" cy=\"-83.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
229 "<ellipse fill=\"none\" stroke=\"black\" cx=\"35.85\" cy=\"-83.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
230 "<text text-anchor=\"middle\" x=\"35.85\" y=\"-80.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_0</text>\r\n",
207231 "</g>\r\n",
208232 "<!-- LR_2 -->\r\n",
209 "<g id=\"node5\" class=\"node\"><title>LR_2</title>\r\n",
210 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.542\" cy=\"-146.847\" rx=\"31.6951\" ry=\"31.6951\"/>\r\n",
211 "<text text-anchor=\"middle\" x=\"174.542\" y=\"-143.147\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_2</text>\r\n",
233 "<g id=\"node5\" class=\"node\">\r\n",
234 "<title>LR_2</title>\r\n",
235 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.54\" cy=\"-151.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
236 "<text text-anchor=\"middle\" x=\"174.54\" y=\"-148.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_2</text>\r\n",
212237 "</g>\r\n",
213238 "<!-- LR_0&#45;&gt;LR_2 -->\r\n",
214 "<g id=\"edge1\" class=\"edge\"><title>LR_0&#45;&gt;LR_2</title>\r\n",
215 "<path fill=\"none\" stroke=\"black\" d=\"M70.6368,-116.735C89.8449,-122.356 113.995,-129.422 134.071,-135.297\"/>\r\n",
216 "<polygon fill=\"black\" stroke=\"black\" points=\"133.274,-138.711 143.855,-138.16 135.24,-131.992 133.274,-138.711\"/>\r\n",
217 "<text text-anchor=\"middle\" x=\"107.194\" y=\"-135.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(B)</text>\r\n",
239 "<g id=\"edge1\" class=\"edge\">\r\n",
240 "<title>LR_0&#45;&gt;LR_2</title>\r\n",
241 "<path fill=\"none\" stroke=\"black\" d=\"M68.21,-99.45C88.53,-109.56 115.1,-122.77 136.47,-133.4\"/>\r\n",
242 "<polygon fill=\"black\" stroke=\"black\" points=\"135.06,-136.61 145.58,-137.94 138.18,-130.35 135.06,-136.61\"/>\r\n",
243 "<text text-anchor=\"middle\" x=\"107.19\" y=\"-129.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(B)</text>\r\n",
218244 "</g>\r\n",
219245 "<!-- LR_1 -->\r\n",
220 "<g id=\"node6\" class=\"node\"><title>LR_1</title>\r\n",
221 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.542\" cy=\"-54.8472\" rx=\"31.6951\" ry=\"31.6951\"/>\r\n",
222 "<text text-anchor=\"middle\" x=\"174.542\" y=\"-51.1472\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_1</text>\r\n",
246 "<g id=\"node6\" class=\"node\">\r\n",
247 "<title>LR_1</title>\r\n",
248 "<ellipse fill=\"none\" stroke=\"black\" cx=\"174.54\" cy=\"-42.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
249 "<text text-anchor=\"middle\" x=\"174.54\" y=\"-39.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_1</text>\r\n",
223250 "</g>\r\n",
224251 "<!-- LR_0&#45;&gt;LR_1 -->\r\n",
225 "<g id=\"edge2\" class=\"edge\"><title>LR_0&#45;&gt;LR_1</title>\r\n",
226 "<path fill=\"none\" stroke=\"black\" d=\"M69.5889,-94.3919C89.2263,-86.9216 114.304,-77.3816 134.909,-69.5435\"/>\r\n",
227 "<polygon fill=\"black\" stroke=\"black\" points=\"136.22,-72.7895 144.322,-65.9626 133.731,-66.2469 136.22,-72.7895\"/>\r\n",
228 "<text text-anchor=\"middle\" x=\"107.194\" y=\"-89.6472\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(S)</text>\r\n",
252 "<g id=\"edge2\" class=\"edge\">\r\n",
253 "<title>LR_0&#45;&gt;LR_1</title>\r\n",
254 "<path fill=\"none\" stroke=\"black\" d=\"M70.29,-73.82C89.49,-68.06 113.72,-60.79 133.88,-54.74\"/>\r\n",
255 "<polygon fill=\"black\" stroke=\"black\" points=\"135.13,-58.02 143.7,-51.8 133.12,-51.32 135.13,-58.02\"/>\r\n",
256 "<text text-anchor=\"middle\" x=\"107.19\" y=\"-71.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(S)</text>\r\n",
229257 "</g>\r\n",
230258 "<!-- LR_3 -->\r\n",
231 "<g id=\"node2\" class=\"node\"><title>LR_3</title>\r\n",
232 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.236\" cy=\"-35.8472\" rx=\"31.712\" ry=\"31.712\"/>\r\n",
233 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.236\" cy=\"-35.8472\" rx=\"35.695\" ry=\"35.695\"/>\r\n",
234 "<text text-anchor=\"middle\" x=\"323.236\" y=\"-32.1472\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_3</text>\r\n",
259 "<g id=\"node2\" class=\"node\">\r\n",
260 "<title>LR_3</title>\r\n",
261 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-35.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
262 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-35.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
263 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-32.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_3</text>\r\n",
235264 "</g>\r\n",
236265 "<!-- LR_4 -->\r\n",
237 "<g id=\"node3\" class=\"node\"><title>LR_4</title>\r\n",
238 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.236\" cy=\"-291.847\" rx=\"31.712\" ry=\"31.712\"/>\r\n",
239 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.236\" cy=\"-291.847\" rx=\"35.695\" ry=\"35.695\"/>\r\n",
240 "<text text-anchor=\"middle\" x=\"323.236\" y=\"-288.147\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_4</text>\r\n",
266 "<g id=\"node3\" class=\"node\">\r\n",
267 "<title>LR_4</title>\r\n",
268 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-291.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
269 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-291.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
270 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-288.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_4</text>\r\n",
241271 "</g>\r\n",
242272 "<!-- LR_8 -->\r\n",
243 "<g id=\"node4\" class=\"node\"><title>LR_8</title>\r\n",
244 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.319\" cy=\"-147.847\" rx=\"31.712\" ry=\"31.712\"/>\r\n",
245 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.319\" cy=\"-147.847\" rx=\"35.695\" ry=\"35.695\"/>\r\n",
246 "<text text-anchor=\"middle\" x=\"704.319\" y=\"-144.147\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_8</text>\r\n",
273 "<g id=\"node4\" class=\"node\">\r\n",
274 "<title>LR_8</title>\r\n",
275 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.32\" cy=\"-152.85\" rx=\"31.71\" ry=\"31.71\"/>\r\n",
276 "<ellipse fill=\"none\" stroke=\"black\" cx=\"704.32\" cy=\"-152.85\" rx=\"35.69\" ry=\"35.69\"/>\r\n",
277 "<text text-anchor=\"middle\" x=\"704.32\" y=\"-149.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_8</text>\r\n",
247278 "</g>\r\n",
248279 "<!-- LR_6 -->\r\n",
249 "<g id=\"node7\" class=\"node\"><title>LR_6</title>\r\n",
250 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.236\" cy=\"-172.847\" rx=\"31.6951\" ry=\"31.6951\"/>\r\n",
251 "<text text-anchor=\"middle\" x=\"323.236\" y=\"-169.147\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_6</text>\r\n",
280 "<g id=\"node7\" class=\"node\">\r\n",
281 "<title>LR_6</title>\r\n",
282 "<ellipse fill=\"none\" stroke=\"black\" cx=\"323.24\" cy=\"-172.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
283 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-169.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_6</text>\r\n",
252284 "</g>\r\n",
253285 "<!-- LR_8&#45;&gt;LR_6 -->\r\n",
254 "<g id=\"edge13\" class=\"edge\"><title>LR_8&#45;&gt;LR_6</title>\r\n",
255 "<path fill=\"none\" stroke=\"black\" d=\"M669.127,-154.782C625.934,-163.158 549.217,-176.756 482.777,-181.847 454.552,-184.01 447.36,-183.186 419.083,-181.847 401.296,-181.005 381.696,-179.28 364.953,-177.563\"/>\r\n",
256 "<polygon fill=\"black\" stroke=\"black\" points=\"365.251,-174.075 354.939,-176.503 364.515,-181.036 365.251,-174.075\"/>\r\n",
257 "<text text-anchor=\"middle\" x=\"513.277\" y=\"-184.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
286 "<g id=\"edge13\" class=\"edge\">\r\n",
287 "<title>LR_8&#45;&gt;LR_6</title>\r\n",
288 "<path fill=\"none\" stroke=\"black\" d=\"M668.7,-158.83C625.38,-165.98 548.87,-177.52 482.78,-181.85 454.53,-183.7 447.36,-183.19 419.08,-181.85 401.3,-181.01 381.7,-179.28 364.95,-177.56\"/>\r\n",
289 "<polygon fill=\"black\" stroke=\"black\" points=\"365.25,-174.07 354.94,-176.5 364.51,-181.04 365.25,-174.07\"/>\r\n",
290 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-183.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
258291 "</g>\r\n",
259292 "<!-- LR_5 -->\r\n",
260 "<g id=\"node8\" class=\"node\"><title>LR_5</title>\r\n",
261 "<ellipse fill=\"none\" stroke=\"black\" cx=\"450.93\" cy=\"-107.847\" rx=\"31.6951\" ry=\"31.6951\"/>\r\n",
262 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-104.147\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_5</text>\r\n",
293 "<g id=\"node8\" class=\"node\">\r\n",
294 "<title>LR_5</title>\r\n",
295 "<ellipse fill=\"none\" stroke=\"black\" cx=\"450.93\" cy=\"-107.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
296 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-104.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_5</text>\r\n",
263297 "</g>\r\n",
264298 "<!-- LR_8&#45;&gt;LR_5 -->\r\n",
265 "<g id=\"edge14\" class=\"edge\"><title>LR_8&#45;&gt;LR_5</title>\r\n",
266 "<path fill=\"none\" stroke=\"black\" d=\"M668.545,-142.414C628.191,-136.095 559.65,-125.319 500.777,-115.847 498.086,-115.414 495.312,-114.966 492.517,-114.512\"/>\r\n",
267 "<polygon fill=\"black\" stroke=\"black\" points=\"492.845,-111.02 482.413,-112.867 491.72,-117.929 492.845,-111.02\"/>\r\n",
268 "<text text-anchor=\"middle\" x=\"575.625\" y=\"-137.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
299 "<g id=\"edge14\" class=\"edge\">\r\n",
300 "<title>LR_8&#45;&gt;LR_5</title>\r\n",
301 "<path fill=\"none\" stroke=\"black\" d=\"M668.83,-147.36C628.46,-140.82 559.62,-129.34 500.78,-117.85 497.99,-117.3 495.11,-116.73 492.22,-116.15\"/>\r\n",
302 "<polygon fill=\"black\" stroke=\"black\" points=\"492.89,-112.72 482.4,-114.17 491.51,-119.58 492.89,-112.72\"/>\r\n",
303 "<text text-anchor=\"middle\" x=\"575.62\" y=\"-139.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
269304 "</g>\r\n",
270305 "<!-- LR_2&#45;&gt;LR_4 -->\r\n",
271 "<g id=\"edge6\" class=\"edge\"><title>LR_2&#45;&gt;LR_4</title>\r\n",
272 "<path fill=\"none\" stroke=\"black\" d=\"M197.821,-168.87C222.322,-193.087 261.915,-232.223 289.846,-259.831\"/>\r\n",
273 "<polygon fill=\"black\" stroke=\"black\" points=\"287.463,-262.397 297.035,-266.938 292.384,-257.418 287.463,-262.397\"/>\r\n",
274 "<text text-anchor=\"middle\" x=\"246.889\" y=\"-239.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(A)</text>\r\n",
306 "<g id=\"edge6\" class=\"edge\">\r\n",
307 "<title>LR_2&#45;&gt;LR_4</title>\r\n",
308 "<path fill=\"none\" stroke=\"black\" d=\"M198.14,-173.42C222.46,-196.62 261.37,-233.76 289.13,-260.26\"/>\r\n",
309 "<polygon fill=\"black\" stroke=\"black\" points=\"287,-263.06 296.65,-267.43 291.83,-257.99 287,-263.06\"/>\r\n",
310 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-241.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(A)</text>\r\n",
275311 "</g>\r\n",
276312 "<!-- LR_2&#45;&gt;LR_6 -->\r\n",
277 "<g id=\"edge4\" class=\"edge\"><title>LR_2&#45;&gt;LR_6</title>\r\n",
278 "<path fill=\"none\" stroke=\"black\" d=\"M205.937,-152.234C227.893,-156.126 257.777,-161.422 281.754,-165.672\"/>\r\n",
279 "<polygon fill=\"black\" stroke=\"black\" points=\"281.17,-169.123 291.628,-167.422 282.392,-162.231 281.17,-169.123\"/>\r\n",
280 "<text text-anchor=\"middle\" x=\"246.889\" y=\"-167.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(b)</text>\r\n",
313 "<g id=\"edge4\" class=\"edge\">\r\n",
314 "<title>LR_2&#45;&gt;LR_6</title>\r\n",
315 "<path fill=\"none\" stroke=\"black\" d=\"M206.29,-156.25C228.1,-159.37 257.6,-163.59 281.38,-167\"/>\r\n",
316 "<polygon fill=\"black\" stroke=\"black\" points=\"281.13,-170.5 291.52,-168.45 282.12,-163.57 281.13,-170.5\"/>\r\n",
317 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-167.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(b)</text>\r\n",
281318 "</g>\r\n",
282319 "<!-- LR_2&#45;&gt;LR_5 -->\r\n",
283 "<g id=\"edge5\" class=\"edge\"><title>LR_2&#45;&gt;LR_5</title>\r\n",
284 "<path fill=\"none\" stroke=\"black\" d=\"M205.087,-137.127C227.428,-130.219 259.001,-121.39 287.389,-116.847 328.309,-110.299 375.679,-108.299 408.684,-107.786\"/>\r\n",
285 "<polygon fill=\"black\" stroke=\"black\" points=\"408.911,-111.284 418.87,-107.668 408.829,-104.284 408.911,-111.284\"/>\r\n",
286 "<text text-anchor=\"middle\" x=\"323.236\" y=\"-120.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(a)</text>\r\n",
320 "<g id=\"edge5\" class=\"edge\">\r\n",
321 "<title>LR_2&#45;&gt;LR_5</title>\r\n",
322 "<path fill=\"none\" stroke=\"black\" d=\"M204.48,-140.61C226.77,-132.49 258.56,-122.07 287.39,-116.85 328.17,-109.46 375.56,-107.58 408.61,-107.32\"/>\r\n",
323 "<polygon fill=\"black\" stroke=\"black\" points=\"408.82,-110.82 418.81,-107.29 408.8,-103.82 408.82,-110.82\"/>\r\n",
324 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-120.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">SS(a)</text>\r\n",
287325 "</g>\r\n",
288326 "<!-- LR_1&#45;&gt;LR_3 -->\r\n",
289 "<g id=\"edge3\" class=\"edge\"><title>LR_1&#45;&gt;LR_3</title>\r\n",
290 "<path fill=\"none\" stroke=\"black\" d=\"M206.293,-50.8642C226.839,-48.2031 254.208,-44.6582 277.196,-41.6808\"/>\r\n",
291 "<polygon fill=\"black\" stroke=\"black\" points=\"277.941,-45.1136 287.409,-40.358 277.042,-38.1716 277.941,-45.1136\"/>\r\n",
292 "<text text-anchor=\"middle\" x=\"246.889\" y=\"-52.6472\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S($end)</text>\r\n",
327 "<g id=\"edge3\" class=\"edge\">\r\n",
328 "<title>LR_1&#45;&gt;LR_3</title>\r\n",
329 "<path fill=\"none\" stroke=\"black\" d=\"M206.65,-41.36C227.15,-40.38 254.31,-39.09 277.16,-38\"/>\r\n",
330 "<polygon fill=\"black\" stroke=\"black\" points=\"277.49,-41.49 287.31,-37.51 277.16,-34.49 277.49,-41.49\"/>\r\n",
331 "<text text-anchor=\"middle\" x=\"246.89\" y=\"-44.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S($end)</text>\r\n",
293332 "</g>\r\n",
294333 "<!-- LR_6&#45;&gt;LR_6 -->\r\n",
295 "<g id=\"edge9\" class=\"edge\"><title>LR_6&#45;&gt;LR_6</title>\r\n",
296 "<path fill=\"none\" stroke=\"black\" d=\"M311.262,-202.528C310.87,-213.589 314.861,-222.694 323.236,-222.694 328.863,-222.694 332.511,-218.584 334.18,-212.532\"/>\r\n",
297 "<polygon fill=\"black\" stroke=\"black\" points=\"337.667,-212.834 335.21,-202.528 330.704,-212.117 337.667,-212.834\"/>\r\n",
298 "<text text-anchor=\"middle\" x=\"323.236\" y=\"-226.494\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
334 "<g id=\"edge9\" class=\"edge\">\r\n",
335 "<title>LR_6&#45;&gt;LR_6</title>\r\n",
336 "<path fill=\"none\" stroke=\"black\" d=\"M311.26,-202.53C310.87,-213.59 314.86,-222.69 323.24,-222.69 328.86,-222.69 332.51,-218.58 334.18,-212.53\"/>\r\n",
337 "<polygon fill=\"black\" stroke=\"black\" points=\"337.67,-212.83 335.21,-202.53 330.7,-212.12 337.67,-212.83\"/>\r\n",
338 "<text text-anchor=\"middle\" x=\"323.24\" y=\"-226.49\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
299339 "</g>\r\n",
300340 "<!-- LR_6&#45;&gt;LR_5 -->\r\n",
301 "<g id=\"edge10\" class=\"edge\"><title>LR_6&#45;&gt;LR_5</title>\r\n",
302 "<path fill=\"none\" stroke=\"black\" d=\"M351.82,-158.583C369.912,-149.227 393.768,-136.89 413.426,-126.724\"/>\r\n",
303 "<polygon fill=\"black\" stroke=\"black\" points=\"415.136,-129.781 422.41,-122.078 411.92,-123.563 415.136,-129.781\"/>\r\n",
304 "<text text-anchor=\"middle\" x=\"389.083\" y=\"-148.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
341 "<g id=\"edge10\" class=\"edge\">\r\n",
342 "<title>LR_6&#45;&gt;LR_5</title>\r\n",
343 "<path fill=\"none\" stroke=\"black\" d=\"M351.82,-158.58C369.91,-149.23 393.77,-136.89 413.43,-126.72\"/>\r\n",
344 "<polygon fill=\"black\" stroke=\"black\" points=\"415.14,-129.78 422.41,-122.08 411.92,-123.56 415.14,-129.78\"/>\r\n",
345 "<text text-anchor=\"middle\" x=\"389.08\" y=\"-147.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
305346 "</g>\r\n",
306347 "<!-- LR_5&#45;&gt;LR_5 -->\r\n",
307 "<g id=\"edge8\" class=\"edge\"><title>LR_5&#45;&gt;LR_5</title>\r\n",
308 "<path fill=\"none\" stroke=\"black\" d=\"M439.691,-138.022C439.45,-148.859 443.196,-157.694 450.93,-157.694 456.006,-157.694 459.364,-153.889 461.005,-148.211\"/>\r\n",
309 "<polygon fill=\"black\" stroke=\"black\" points=\"464.511,-148.355 462.169,-138.022 457.556,-147.56 464.511,-148.355\"/>\r\n",
310 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-161.494\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
348 "<g id=\"edge8\" class=\"edge\">\r\n",
349 "<title>LR_5&#45;&gt;LR_5</title>\r\n",
350 "<path fill=\"none\" stroke=\"black\" d=\"M439.69,-138.02C439.45,-148.86 443.2,-157.69 450.93,-157.69 456.01,-157.69 459.36,-153.89 461,-148.21\"/>\r\n",
351 "<polygon fill=\"black\" stroke=\"black\" points=\"464.51,-148.35 462.17,-138.02 457.56,-147.56 464.51,-148.35\"/>\r\n",
352 "<text text-anchor=\"middle\" x=\"450.93\" y=\"-161.49\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
311353 "</g>\r\n",
312354 "<!-- LR_7 -->\r\n",
313 "<g id=\"node9\" class=\"node\"><title>LR_7</title>\r\n",
314 "<ellipse fill=\"none\" stroke=\"black\" cx=\"575.625\" cy=\"-79.8472\" rx=\"31.6951\" ry=\"31.6951\"/>\r\n",
315 "<text text-anchor=\"middle\" x=\"575.625\" y=\"-76.1472\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_7</text>\r\n",
355 "<g id=\"node9\" class=\"node\">\r\n",
356 "<title>LR_7</title>\r\n",
357 "<ellipse fill=\"none\" stroke=\"black\" cx=\"575.62\" cy=\"-84.85\" rx=\"31.7\" ry=\"31.7\"/>\r\n",
358 "<text text-anchor=\"middle\" x=\"575.62\" y=\"-81.15\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">LR_7</text>\r\n",
316359 "</g>\r\n",
317360 "<!-- LR_5&#45;&gt;LR_7 -->\r\n",
318 "<g id=\"edge7\" class=\"edge\"><title>LR_5&#45;&gt;LR_7</title>\r\n",
319 "<path fill=\"none\" stroke=\"black\" d=\"M482.259,-100.926C497.891,-97.3585 517.169,-92.959 534.063,-89.1037\"/>\r\n",
320 "<polygon fill=\"black\" stroke=\"black\" points=\"535.249,-92.4232 544.219,-86.7859 533.691,-85.5986 535.249,-92.4232\"/>\r\n",
321 "<text text-anchor=\"middle\" x=\"513.277\" y=\"-100.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
361 "<g id=\"edge7\" class=\"edge\">\r\n",
362 "<title>LR_5&#45;&gt;LR_7</title>\r\n",
363 "<path fill=\"none\" stroke=\"black\" d=\"M482.57,-102.1C498.09,-99.19 517.14,-95.62 533.88,-92.49\"/>\r\n",
364 "<polygon fill=\"black\" stroke=\"black\" points=\"534.76,-95.88 543.95,-90.6 533.47,-89 534.76,-95.88\"/>\r\n",
365 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-102.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
322366 "</g>\r\n",
323367 "<!-- LR_7&#45;&gt;LR_8 -->\r\n",
324 "<g id=\"edge11\" class=\"edge\"><title>LR_7&#45;&gt;LR_8</title>\r\n",
325 "<path fill=\"none\" stroke=\"black\" d=\"M604.384,-94.3732C618.255,-101.666 635.28,-110.668 650.472,-118.847 654.739,-121.145 659.192,-123.56 663.624,-125.976\"/>\r\n",
326 "<polygon fill=\"black\" stroke=\"black\" points=\"662.172,-129.17 672.625,-130.896 665.529,-123.028 662.172,-129.17\"/>\r\n",
327 "<text text-anchor=\"middle\" x=\"637.972\" y=\"-122.647\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
368 "<g id=\"edge11\" class=\"edge\">\r\n",
369 "<title>LR_7&#45;&gt;LR_8</title>\r\n",
370 "<path fill=\"none\" stroke=\"black\" d=\"M604.38,-99.37C618.26,-106.67 635.28,-115.67 650.47,-123.85 654.74,-126.14 659.19,-128.56 663.62,-130.98\"/>\r\n",
371 "<polygon fill=\"black\" stroke=\"black\" points=\"662.17,-134.17 672.62,-135.9 665.53,-128.03 662.17,-134.17\"/>\r\n",
372 "<text text-anchor=\"middle\" x=\"637.97\" y=\"-127.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(b)</text>\r\n",
328373 "</g>\r\n",
329374 "<!-- LR_7&#45;&gt;LR_5 -->\r\n",
330 "<g id=\"edge12\" class=\"edge\"><title>LR_7&#45;&gt;LR_5</title>\r\n",
331 "<path fill=\"none\" stroke=\"black\" d=\"M544.569,-71.6302C530.928,-69.2535 514.755,-68.3565 500.777,-72.8472 494.781,-74.7738 488.895,-77.7384 483.403,-81.1443\"/>\r\n",
332 "<polygon fill=\"black\" stroke=\"black\" points=\"481.431,-78.2524 475.135,-86.7737 485.371,-84.0385 481.431,-78.2524\"/>\r\n",
333 "<text text-anchor=\"middle\" x=\"513.277\" y=\"-76.6472\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
375 "<g id=\"edge12\" class=\"edge\">\r\n",
376 "<title>LR_7&#45;&gt;LR_5</title>\r\n",
377 "<path fill=\"none\" stroke=\"black\" d=\"M545.05,-75.8C531.36,-72.99 515.01,-71.6 500.78,-75.85 495.43,-77.44 490.13,-79.83 485.1,-82.59\"/>\r\n",
378 "<polygon fill=\"black\" stroke=\"black\" points=\"483.11,-79.7 476.38,-87.89 486.75,-85.69 483.11,-79.7\"/>\r\n",
379 "<text text-anchor=\"middle\" x=\"513.28\" y=\"-79.65\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">S(a)</text>\r\n",
334380 "</g>\r\n",
335381 "</g>\r\n",
336382 "</svg>\r\n"
337383 ],
338384 "text/plain": [
339 "<graphviz.dot.Digraph at 0x5090888>"
385 "<graphviz.dot.Digraph at 0x1c71cdf0220>"
340386 ]
341387 },
342388 "execution_count": 4,
347393 "source": [
348394 "# http://www.graphviz.org/content/fsm\n",
349395 "\n",
350 "from graphviz import Digraph\n",
351 "\n",
352 "f = Digraph('finite_state_machine', filename='fsm.gv')\n",
396 "f = graphviz.Digraph('finite_state_machine', filename='fsm.gv')\n",
353397 "f.attr(rankdir='LR', size='8,5')\n",
354398 "\n",
355399 "f.attr('node', shape='doublecircle')\n",
386430 "name": "stderr",
387431 "output_type": "stream",
388432 "text": [
389 "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n"
433 "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n"
390434 ]
391435 },
392436 {
395439 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n",
396440 "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n",
397441 " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\r\n",
398 "<!-- Generated by graphviz version 2.38.0 (20140413.2041)\r\n",
442 "<!-- Generated by graphviz version 2.46.1 (20210213.1702)\r\n",
399443 " -->\r\n",
400444 "<!-- Title: G Pages: 1 -->\r\n",
401445 "<svg width=\"222pt\" height=\"364pt\"\r\n",
402446 " viewBox=\"0.00 0.00 222.00 364.00\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\r\n",
403447 "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 360)\">\r\n",
404448 "<title>G</title>\r\n",
405 "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-360 218,-360 218,4 -4,4\"/>\r\n",
406 "<g id=\"clust1\" class=\"cluster\"><title>cluster0</title>\r\n",
449 "<polygon fill=\"white\" stroke=\"transparent\" points=\"-4,4 -4,-360 218,-360 218,4 -4,4\"/>\r\n",
450 "<g id=\"clust1\" class=\"cluster\">\r\n",
451 "<title>cluster0</title>\r\n",
407452 "<polygon fill=\"none\" stroke=\"black\" points=\"64,-152 64,-348 206,-348 206,-152 64,-152\"/>\r\n",
408453 "</g>\r\n",
409 "<g id=\"clust2\" class=\"cluster\"><title>cluster1</title>\r\n",
454 "<g id=\"clust2\" class=\"cluster\">\r\n",
455 "<title>cluster1</title>\r\n",
410456 "<polygon fill=\"none\" stroke=\"black\" points=\"64,-8 64,-132 206,-132 206,-8 64,-8\"/>\r\n",
411457 "</g>\r\n",
412458 "<!-- a -->\r\n",
413 "<g id=\"node1\" class=\"node\"><title>a</title>\r\n",
459 "<g id=\"node1\" class=\"node\">\r\n",
460 "<title>a</title>\r\n",
414461 "<ellipse fill=\"none\" stroke=\"black\" cx=\"135\" cy=\"-322\" rx=\"27\" ry=\"18\"/>\r\n",
415462 "<text text-anchor=\"middle\" x=\"135\" y=\"-318.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">a</text>\r\n",
416463 "</g>\r\n",
417464 "<!-- b -->\r\n",
418 "<g id=\"node2\" class=\"node\"><title>b</title>\r\n",
465 "<g id=\"node2\" class=\"node\">\r\n",
466 "<title>b</title>\r\n",
419467 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\r\n",
420468 "<text text-anchor=\"middle\" x=\"99\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">b</text>\r\n",
421469 "</g>\r\n",
422470 "<!-- a&#45;&gt;b -->\r\n",
423 "<g id=\"edge1\" class=\"edge\"><title>a&#45;&gt;b</title>\r\n",
424 "<path fill=\"none\" stroke=\"black\" d=\"M126.65,-304.765C122.288,-296.283 116.853,-285.714 111.959,-276.197\"/>\r\n",
425 "<polygon fill=\"black\" stroke=\"black\" points=\"114.99,-274.439 107.304,-267.147 108.765,-277.641 114.99,-274.439\"/>\r\n",
471 "<g id=\"edge1\" class=\"edge\">\r\n",
472 "<title>a&#45;&gt;b</title>\r\n",
473 "<path fill=\"none\" stroke=\"black\" d=\"M126.65,-304.76C122.29,-296.28 116.85,-285.71 111.96,-276.2\"/>\r\n",
474 "<polygon fill=\"black\" stroke=\"black\" points=\"114.99,-274.44 107.3,-267.15 108.77,-277.64 114.99,-274.44\"/>\r\n",
426475 "</g>\r\n",
427476 "<!-- c -->\r\n",
428 "<g id=\"node3\" class=\"node\"><title>c</title>\r\n",
477 "<g id=\"node3\" class=\"node\">\r\n",
478 "<title>c</title>\r\n",
429479 "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\r\n",
430480 "<text text-anchor=\"middle\" x=\"171\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">c</text>\r\n",
431481 "</g>\r\n",
432482 "<!-- a&#45;&gt;c -->\r\n",
433 "<g id=\"edge2\" class=\"edge\"><title>a&#45;&gt;c</title>\r\n",
434 "<path fill=\"none\" stroke=\"black\" d=\"M143.35,-304.765C147.712,-296.283 153.147,-285.714 158.041,-276.197\"/>\r\n",
435 "<polygon fill=\"black\" stroke=\"black\" points=\"161.235,-277.641 162.696,-267.147 155.01,-274.439 161.235,-277.641\"/>\r\n",
483 "<g id=\"edge2\" class=\"edge\">\r\n",
484 "<title>a&#45;&gt;c</title>\r\n",
485 "<path fill=\"none\" stroke=\"black\" d=\"M143.35,-304.76C147.71,-296.28 153.15,-285.71 158.04,-276.2\"/>\r\n",
486 "<polygon fill=\"black\" stroke=\"black\" points=\"161.23,-277.64 162.7,-267.15 155.01,-274.44 161.23,-277.64\"/>\r\n",
436487 "</g>\r\n",
437488 "<!-- d -->\r\n",
438 "<g id=\"node4\" class=\"node\"><title>d</title>\r\n",
489 "<g id=\"node4\" class=\"node\">\r\n",
490 "<title>d</title>\r\n",
439491 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-178\" rx=\"27\" ry=\"18\"/>\r\n",
440492 "<text text-anchor=\"middle\" x=\"99\" y=\"-174.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">d</text>\r\n",
441493 "</g>\r\n",
442494 "<!-- b&#45;&gt;d -->\r\n",
443 "<g id=\"edge3\" class=\"edge\"><title>b&#45;&gt;d</title>\r\n",
444 "<path fill=\"none\" stroke=\"black\" d=\"M99,-231.697C99,-223.983 99,-214.712 99,-206.112\"/>\r\n",
445 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-206.104 99,-196.104 95.5001,-206.104 102.5,-206.104\"/>\r\n",
495 "<g id=\"edge3\" class=\"edge\">\r\n",
496 "<title>b&#45;&gt;d</title>\r\n",
497 "<path fill=\"none\" stroke=\"black\" d=\"M99,-231.7C99,-223.98 99,-214.71 99,-206.11\"/>\r\n",
498 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-206.1 99,-196.1 95.5,-206.1 102.5,-206.1\"/>\r\n",
446499 "</g>\r\n",
447500 "<!-- f -->\r\n",
448 "<g id=\"node7\" class=\"node\"><title>f</title>\r\n",
501 "<g id=\"node7\" class=\"node\">\r\n",
502 "<title>f</title>\r\n",
449503 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\r\n",
450504 "<text text-anchor=\"middle\" x=\"99\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">f</text>\r\n",
451505 "</g>\r\n",
452506 "<!-- b&#45;&gt;f -->\r\n",
453 "<g id=\"edge7\" class=\"edge\"><title>b&#45;&gt;f</title>\r\n",
454 "<path fill=\"none\" stroke=\"black\" d=\"M112.75,-234.069C120.961,-224.1 130.619,-210.247 135,-196 142.052,-173.066 145.58,-157.538 145.581,-142.011\"/>\r\n",
455 "<polygon fill=\"black\" stroke=\"black\" points=\"149.063,-141.547 145.075,-131.731 142.071,-141.891 149.063,-141.547\"/>\r\n",
507 "<g id=\"edge7\" class=\"edge\">\r\n",
508 "<title>b&#45;&gt;f</title>\r\n",
509 "<path fill=\"none\" stroke=\"black\" d=\"M112.75,-234.07C120.96,-224.1 130.62,-210.25 135,-196 142.02,-173.17 145.55,-157.68 145.58,-142.23\"/>\r\n",
510 "<polygon fill=\"black\" stroke=\"black\" points=\"149.07,-141.82 145.1,-132 142.07,-142.15 149.07,-141.82\"/>\r\n",
456511 "</g>\r\n",
457512 "<!-- c&#45;&gt;d -->\r\n",
458 "<g id=\"edge4\" class=\"edge\"><title>c&#45;&gt;d</title>\r\n",
459 "<path fill=\"none\" stroke=\"black\" d=\"M156.43,-234.834C146.25,-224.938 132.476,-211.546 120.969,-200.359\"/>\r\n",
460 "<polygon fill=\"black\" stroke=\"black\" points=\"123.405,-197.846 113.796,-193.385 118.526,-202.865 123.405,-197.846\"/>\r\n",
513 "<g id=\"edge4\" class=\"edge\">\r\n",
514 "<title>c&#45;&gt;d</title>\r\n",
515 "<path fill=\"none\" stroke=\"black\" d=\"M156.43,-234.83C146.25,-224.94 132.48,-211.55 120.97,-200.36\"/>\r\n",
516 "<polygon fill=\"black\" stroke=\"black\" points=\"123.41,-197.85 113.8,-193.38 118.53,-202.87 123.41,-197.85\"/>\r\n",
461517 "</g>\r\n",
462518 "<!-- e -->\r\n",
463 "<g id=\"node5\" class=\"node\"><title>e</title>\r\n",
519 "<g id=\"node5\" class=\"node\">\r\n",
520 "<title>e</title>\r\n",
464521 "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\r\n",
465522 "<text text-anchor=\"middle\" x=\"99\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">e</text>\r\n",
466523 "</g>\r\n",
467524 "<!-- c&#45;&gt;e -->\r\n",
468 "<g id=\"edge10\" class=\"edge\"><title>c&#45;&gt;e</title>\r\n",
469 "<path fill=\"none\" stroke=\"black\" d=\"M135,-152C130.703,-144.409 125.157,-136.769 119.712,-129.993\"/>\r\n",
470 "<polygon fill=\"black\" stroke=\"black\" points=\"122.073,-127.362 112.969,-121.943 116.707,-131.857 122.073,-127.362\"/>\r\n",
525 "<g id=\"edge10\" class=\"edge\">\r\n",
526 "<title>c&#45;&gt;e</title>\r\n",
527 "<path fill=\"none\" stroke=\"black\" d=\"M135,-152C130.7,-144.41 125.16,-136.77 119.71,-129.99\"/>\r\n",
528 "<polygon fill=\"black\" stroke=\"black\" points=\"122.07,-127.36 112.97,-121.94 116.71,-131.86 122.07,-127.36\"/>\r\n",
471529 "</g>\r\n",
472530 "<!-- g -->\r\n",
473 "<g id=\"node6\" class=\"node\"><title>g</title>\r\n",
531 "<g id=\"node6\" class=\"node\">\r\n",
532 "<title>g</title>\r\n",
474533 "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\r\n",
475534 "<text text-anchor=\"middle\" x=\"171\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">g</text>\r\n",
476535 "</g>\r\n",
477536 "<!-- c&#45;&gt;g -->\r\n",
478 "<g id=\"edge9\" class=\"edge\"><title>c&#45;&gt;g</title>\r\n",
479 "<path fill=\"none\" stroke=\"black\" d=\"M171,-152.011C171,-148.759 171,-145.494 171,-142.23\"/>\r\n",
480 "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-141.93 171,-131.93 167.5,-141.93 174.5,-141.93\"/>\r\n",
537 "<g id=\"edge9\" class=\"edge\">\r\n",
538 "<title>c&#45;&gt;g</title>\r\n",
539 "<path fill=\"none\" stroke=\"black\" d=\"M171,-152C171,-148.77 171,-145.53 171,-142.29\"/>\r\n",
540 "<polygon fill=\"black\" stroke=\"black\" points=\"174.5,-141.99 171,-132 167.5,-142 174.5,-141.99\"/>\r\n",
481541 "</g>\r\n",
482542 "<!-- d&#45;&gt;e -->\r\n",
483 "<g id=\"edge8\" class=\"edge\"><title>d&#45;&gt;e</title>\r\n",
484 "<path fill=\"none\" stroke=\"black\" d=\"M99,-159.697C99,-151.983 99,-142.712 99,-134.112\"/>\r\n",
485 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-134.104 99,-124.104 95.5001,-134.104 102.5,-134.104\"/>\r\n",
543 "<g id=\"edge8\" class=\"edge\">\r\n",
544 "<title>d&#45;&gt;e</title>\r\n",
545 "<path fill=\"none\" stroke=\"black\" d=\"M99,-159.7C99,-151.98 99,-142.71 99,-134.11\"/>\r\n",
546 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-134.1 99,-124.1 95.5,-134.1 102.5,-134.1\"/>\r\n",
486547 "</g>\r\n",
487548 "<!-- h -->\r\n",
488 "<g id=\"node8\" class=\"node\"><title>h</title>\r\n",
549 "<g id=\"node8\" class=\"node\">\r\n",
550 "<title>h</title>\r\n",
489551 "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\r\n",
490552 "<text text-anchor=\"middle\" x=\"27\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">h</text>\r\n",
491553 "</g>\r\n",
492554 "<!-- d&#45;&gt;h -->\r\n",
493 "<g id=\"edge11\" class=\"edge\"><title>d&#45;&gt;h</title>\r\n",
494 "<path fill=\"none\" stroke=\"black\" d=\"M84.4297,-162.834C74.2501,-152.938 60.4761,-139.546 48.9694,-128.359\"/>\r\n",
495 "<polygon fill=\"black\" stroke=\"black\" points=\"51.4055,-125.846 41.7957,-121.385 46.5259,-130.865 51.4055,-125.846\"/>\r\n",
555 "<g id=\"edge11\" class=\"edge\">\r\n",
556 "<title>d&#45;&gt;h</title>\r\n",
557 "<path fill=\"none\" stroke=\"black\" d=\"M84.43,-162.83C74.25,-152.94 60.48,-139.55 48.97,-128.36\"/>\r\n",
558 "<polygon fill=\"black\" stroke=\"black\" points=\"51.41,-125.85 41.8,-121.38 46.53,-130.87 51.41,-125.85\"/>\r\n",
496559 "</g>\r\n",
497560 "<!-- e&#45;&gt;g -->\r\n",
498 "<g id=\"edge5\" class=\"edge\"><title>e&#45;&gt;g</title>\r\n",
499 "<path fill=\"none\" stroke=\"black\" d=\"M113.57,-90.8345C123.75,-80.9376 137.524,-67.5462 149.031,-56.3591\"/>\r\n",
500 "<polygon fill=\"black\" stroke=\"black\" points=\"151.474,-58.865 156.204,-49.3847 146.595,-53.8461 151.474,-58.865\"/>\r\n",
561 "<g id=\"edge5\" class=\"edge\">\r\n",
562 "<title>e&#45;&gt;g</title>\r\n",
563 "<path fill=\"none\" stroke=\"black\" d=\"M113.57,-90.83C123.75,-80.94 137.52,-67.55 149.03,-56.36\"/>\r\n",
564 "<polygon fill=\"black\" stroke=\"black\" points=\"151.47,-58.87 156.2,-49.38 146.59,-53.85 151.47,-58.87\"/>\r\n",
501565 "</g>\r\n",
502566 "<!-- e&#45;&gt;f -->\r\n",
503 "<g id=\"edge6\" class=\"edge\"><title>e&#45;&gt;f</title>\r\n",
504 "<path fill=\"none\" stroke=\"black\" d=\"M99,-87.6966C99,-79.9827 99,-70.7125 99,-62.1124\"/>\r\n",
505 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-62.1043 99,-52.1043 95.5001,-62.1044 102.5,-62.1043\"/>\r\n",
567 "<g id=\"edge6\" class=\"edge\">\r\n",
568 "<title>e&#45;&gt;f</title>\r\n",
569 "<path fill=\"none\" stroke=\"black\" d=\"M99,-87.7C99,-79.98 99,-70.71 99,-62.11\"/>\r\n",
570 "<polygon fill=\"black\" stroke=\"black\" points=\"102.5,-62.1 99,-52.1 95.5,-62.1 102.5,-62.1\"/>\r\n",
506571 "</g>\r\n",
507572 "</g>\r\n",
508573 "</svg>\r\n"
509574 ],
510575 "text/plain": [
511 "<graphviz.dot.Digraph at 0x5094308>"
576 "<graphviz.dot.Digraph at 0x1c71cdf19d0>"
512577 ]
513578 },
514579 "execution_count": 5,
517582 }
518583 ],
519584 "source": [
520 "# http://www.graphviz.org/pdf/dotguide.pdf Figure 20\n",
521 "\n",
522 "from graphviz import Digraph\n",
523 "\n",
524 "g = Digraph('G', filename='cluster_edge.gv')\n",
585 "# http://www.graphviz.org/pdf/dotguide.pdf, Figure 20\n",
586 "\n",
587 "g = graphviz.Digraph('G', filename='cluster_edge.gv')\n",
525588 "g.attr(compound='true')\n",
526589 "\n",
527590 "with g.subgraph(name='cluster0') as c:\n",
556619 "name": "python",
557620 "nbconvert_exporter": "python",
558621 "pygments_lexer": "ipython3",
559 "version": "3.7.4"
622 "version": "3.9.4"
560623 }
561624 },
562625 "nbformat": 4,
0 #!/usr/bin/env python
1 # process.py - http://www.graphviz.org/content/process
2
3 from graphviz import Graph
4
5 g = Graph('G', filename='process.gv', engine='sfdp')
6
7 g.edge('run', 'intr')
8 g.edge('intr', 'runbl')
9 g.edge('runbl', 'run')
10 g.edge('run', 'kernel')
11 g.edge('kernel', 'zombie')
12 g.edge('kernel', 'sleep')
13 g.edge('kernel', 'runmem')
14 g.edge('sleep', 'swap')
15 g.edge('swap', 'runswap')
16 g.edge('runswap', 'new')
17 g.edge('runswap', 'runmem')
18 g.edge('new', 'runmem')
19 g.edge('sleep', 'runmem')
20
21 g.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/process"""
3
4 import graphviz
5
6 g = graphviz.Graph('G', filename='process.gv', engine='sfdp')
7
8 g.edge('run', 'intr')
9 g.edge('intr', 'runbl')
10 g.edge('runbl', 'run')
11 g.edge('run', 'kernel')
12 g.edge('kernel', 'zombie')
13 g.edge('kernel', 'sleep')
14 g.edge('kernel', 'runmem')
15 g.edge('sleep', 'swap')
16 g.edge('swap', 'runswap')
17 g.edge('runswap', 'new')
18 g.edge('runswap', 'runmem')
19 g.edge('new', 'runmem')
20 g.edge('sleep', 'runmem')
21
22 g.view()
0 #!/usr/bin/env python
1 # https://stackoverflow.com/questions/25734244/how-do-i-place-nodes-on-the-same-level-in-dot
2
3 import graphviz
4
5 d = graphviz.Digraph(filename='rank_same.gv')
6
7 with d.subgraph() as s:
8 s.attr(rank='same')
9 s.node('A')
10 s.node('X')
11
12 d.node('C')
13
14 with d.subgraph() as s:
15 s.attr(rank='same')
16 s.node('B')
17 s.node('D')
18 s.node('Y')
19
20 d.edges(['AB', 'AC', 'CD', 'XY'])
21
22 d.view()
0 #!/usr/bin/env python3
1
2 """https://stackoverflow.com/questions/25734244/how-do-i-place-nodes-on-the-same-level-in-dot"""
3
4 import graphviz
5
6 d = graphviz.Digraph(filename='rank_same.gv')
7
8 with d.subgraph() as s:
9 s.attr(rank='same')
10 s.node('A')
11 s.node('X')
12
13 d.node('C')
14
15 with d.subgraph() as s:
16 s.attr(rank='same')
17 s.node('B')
18 s.node('D')
19 s.node('Y')
20
21 d.edges(['AB', 'AC', 'CD', 'XY'])
22
23 d.view()
0 #!/usr/bin/env python
1 # structs.py - http://www.graphviz.org/doc/info/shapes.html#html
2
3 from graphviz import Digraph
4
5 s = Digraph('structs', node_attr={'shape': 'plaintext'})
6
7 s.node('struct1', '''<
8 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
9 <TR>
10 <TD>left</TD>
11 <TD PORT="f1">middle</TD>
12 <TD PORT="f2">right</TD>
13 </TR>
14 </TABLE>>''')
15 s.node('struct2', '''<
16 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
17 <TR>
18 <TD PORT="f0">one</TD>
19 <TD>two</TD>
20 </TR>
21 </TABLE>>''')
22 s.node('struct3', '''<
23 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
24 <TR>
25 <TD ROWSPAN="3">hello<BR/>world</TD>
26 <TD COLSPAN="3">b</TD>
27 <TD ROWSPAN="3">g</TD>
28 <TD ROWSPAN="3">h</TD>
29 </TR>
30 <TR>
31 <TD>c</TD>
32 <TD PORT="here">d</TD>
33 <TD>e</TD>
34 </TR>
35 <TR>
36 <TD COLSPAN="3">f</TD>
37 </TR>
38 </TABLE>>''')
39
40 s.edges([('struct1:f1', 'struct2:f0'), ('struct1:f2', 'struct3:here')])
41
42 s.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/doc/info/shapes.html#html"""
3
4 import graphviz
5
6 s = graphviz.Digraph('structs', node_attr={'shape': 'plaintext'})
7
8 s.node('struct1', '''<
9 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
10 <TR>
11 <TD>left</TD>
12 <TD PORT="f1">middle</TD>
13 <TD PORT="f2">right</TD>
14 </TR>
15 </TABLE>>''')
16 s.node('struct2', '''<
17 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
18 <TR>
19 <TD PORT="f0">one</TD>
20 <TD>two</TD>
21 </TR>
22 </TABLE>>''')
23 s.node('struct3', '''<
24 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
25 <TR>
26 <TD ROWSPAN="3">hello<BR/>world</TD>
27 <TD COLSPAN="3">b</TD>
28 <TD ROWSPAN="3">g</TD>
29 <TD ROWSPAN="3">h</TD>
30 </TR>
31 <TR>
32 <TD>c</TD>
33 <TD PORT="here">d</TD>
34 <TD>e</TD>
35 </TR>
36 <TR>
37 <TD COLSPAN="3">f</TD>
38 </TR>
39 </TABLE>>''')
40
41 s.edges([('struct1:f1', 'struct2:f0'), ('struct1:f2', 'struct3:here')])
42
43 s.view()
0 #!/usr/bin/env python
1 # structs_revisited.py - http://www.graphviz.org/pdf/dotguide.pdf Figure 12
2
3 from graphviz import Digraph
4
5 s = Digraph('structs', filename='structs_revisited.gv',
6 node_attr={'shape': 'record'})
7
8 s.node('struct1', '<f0> left|<f1> middle|<f2> right')
9 s.node('struct2', '<f0> one|<f1> two')
10 s.node('struct3', r'hello\nworld |{ b |{c|<here> d|e}| f}| g | h')
11
12 s.edges([('struct1:f1', 'struct2:f0'), ('struct1:f2', 'struct3:here')])
13
14 s.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/pdf/dotguide.pdf, Figure 12"""
3
4 import graphviz
5
6 s = graphviz.Digraph('structs', filename='structs_revisited.gv',
7 node_attr={'shape': 'record'})
8
9 s.node('struct1', '<f0> left|<f1> middle|<f2> right')
10 s.node('struct2', '<f0> one|<f1> two')
11 s.node('struct3', r'hello\nworld |{ b |{c|<here> d|e}| f}| g | h')
12
13 s.edges([('struct1:f1', 'struct2:f0'), ('struct1:f2', 'struct3:here')])
14
15 s.view()
0 #!/usr/bin/env python
1 # traffic_lights.py - http://www.graphviz.org/content/traffic_lights
2
3 from graphviz import Digraph
4
5 t = Digraph('TrafficLights', filename='traffic_lights.gv', engine='neato')
6
7 t.attr('node', shape='box')
8 for i in (2, 1):
9 t.node('gy%d' % i)
10 t.node('yr%d' % i)
11 t.node('rg%d' % i)
12
13 t.attr('node', shape='circle', fixedsize='true', width='0.9')
14 for i in (2, 1):
15 t.node('green%d' % i)
16 t.node('yellow%d' % i)
17 t.node('red%d' % i)
18 t.node('safe%d' % i)
19
20 for i, j in [(2, 1), (1, 2)]:
21 t.edge('gy%d' % i, 'yellow%d' % i)
22 t.edge('rg%d' % i, 'green%d' % i)
23 t.edge('yr%d' % i, 'safe%d' % j)
24 t.edge('yr%d' % i, 'red%d' % i)
25 t.edge('safe%d' % i, 'rg%d' % i)
26 t.edge('green%d' % i, 'gy%d' % i)
27 t.edge('yellow%d' % i, 'yr%d' % i)
28 t.edge('red%d' % i, 'rg%d' % i)
29
30 t.attr(overlap='false')
31 t.attr(label=r'PetriNet Model TrafficLights\n'
32 r'Extracted from ConceptBase and layed out by Graphviz')
33 t.attr(fontsize='12')
34
35 t.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/traffic_lights"""
3
4 import graphviz
5
6 t = graphviz.Digraph('TrafficLights', filename='traffic_lights.gv',
7 engine='neato')
8
9 t.attr('node', shape='box')
10 for i in (2, 1):
11 t.node(f'gy{i:d}')
12 t.node(f'yr{i:d}')
13 t.node(f'rg{i:d}')
14
15 t.attr('node', shape='circle', fixedsize='true', width='0.9')
16 for i in (2, 1):
17 t.node(f'green{i:d}')
18 t.node(f'yellow{i:d}')
19 t.node(f'red{i:d}')
20 t.node(f'safe{i:d}')
21
22 for i, j in [(2, 1), (1, 2)]:
23 t.edge(f'gy{i:d}', f'yellow{i:d}')
24 t.edge(f'rg{i:d}', f'green{i:d}')
25 t.edge(f'yr{i:d}', f'safe{j:d}')
26 t.edge(f'yr{i:d}', f'red{i:d}')
27 t.edge(f'safe{i:d}', f'rg{i:d}')
28 t.edge(f'green{i:d}', f'gy{i:d}')
29 t.edge(f'yellow{i:d}', f'yr{i:d}')
30 t.edge(f'red{i:d}', f'rg{i:d}')
31
32 t.attr(overlap='false')
33 t.attr(label=r'PetriNet Model TrafficLights\n'
34 r'Extracted from ConceptBase and layed out by Graphviz')
35 t.attr(fontsize='12')
36
37 t.view()
0 #!/usr/bin/env python
1 # unix.py - http://www.graphviz.org/content/unix
2
3 from graphviz import Digraph
4
5 u = Digraph('unix', filename='unix.gv',
6 node_attr={'color': 'lightblue2', 'style': 'filled'})
7 u.attr(size='6,6')
8
9 u.edge('5th Edition', '6th Edition')
10 u.edge('5th Edition', 'PWB 1.0')
11 u.edge('6th Edition', 'LSX')
12 u.edge('6th Edition', '1 BSD')
13 u.edge('6th Edition', 'Mini Unix')
14 u.edge('6th Edition', 'Wollongong')
15 u.edge('6th Edition', 'Interdata')
16 u.edge('Interdata', 'Unix/TS 3.0')
17 u.edge('Interdata', 'PWB 2.0')
18 u.edge('Interdata', '7th Edition')
19 u.edge('7th Edition', '8th Edition')
20 u.edge('7th Edition', '32V')
21 u.edge('7th Edition', 'V7M')
22 u.edge('7th Edition', 'Ultrix-11')
23 u.edge('7th Edition', 'Xenix')
24 u.edge('7th Edition', 'UniPlus+')
25 u.edge('V7M', 'Ultrix-11')
26 u.edge('8th Edition', '9th Edition')
27 u.edge('1 BSD', '2 BSD')
28 u.edge('2 BSD', '2.8 BSD')
29 u.edge('2.8 BSD', 'Ultrix-11')
30 u.edge('2.8 BSD', '2.9 BSD')
31 u.edge('32V', '3 BSD')
32 u.edge('3 BSD', '4 BSD')
33 u.edge('4 BSD', '4.1 BSD')
34 u.edge('4.1 BSD', '4.2 BSD')
35 u.edge('4.1 BSD', '2.8 BSD')
36 u.edge('4.1 BSD', '8th Edition')
37 u.edge('4.2 BSD', '4.3 BSD')
38 u.edge('4.2 BSD', 'Ultrix-32')
39 u.edge('PWB 1.0', 'PWB 1.2')
40 u.edge('PWB 1.0', 'USG 1.0')
41 u.edge('PWB 1.2', 'PWB 2.0')
42 u.edge('USG 1.0', 'CB Unix 1')
43 u.edge('USG 1.0', 'USG 2.0')
44 u.edge('CB Unix 1', 'CB Unix 2')
45 u.edge('CB Unix 2', 'CB Unix 3')
46 u.edge('CB Unix 3', 'Unix/TS++')
47 u.edge('CB Unix 3', 'PDP-11 Sys V')
48 u.edge('USG 2.0', 'USG 3.0')
49 u.edge('USG 3.0', 'Unix/TS 3.0')
50 u.edge('PWB 2.0', 'Unix/TS 3.0')
51 u.edge('Unix/TS 1.0', 'Unix/TS 3.0')
52 u.edge('Unix/TS 3.0', 'TS 4.0')
53 u.edge('Unix/TS++', 'TS 4.0')
54 u.edge('CB Unix 3', 'TS 4.0')
55 u.edge('TS 4.0', 'System V.0')
56 u.edge('System V.0', 'System V.2')
57 u.edge('System V.2', 'System V.3')
58
59 u.view()
0 #!/usr/bin/env python3
1
2 """http://www.graphviz.org/content/unix"""
3
4 import graphviz
5
6 u = graphviz.Digraph('unix', filename='unix.gv',
7 node_attr={'color': 'lightblue2', 'style': 'filled'})
8 u.attr(size='6,6')
9
10 u.edge('5th Edition', '6th Edition')
11 u.edge('5th Edition', 'PWB 1.0')
12 u.edge('6th Edition', 'LSX')
13 u.edge('6th Edition', '1 BSD')
14 u.edge('6th Edition', 'Mini Unix')
15 u.edge('6th Edition', 'Wollongong')
16 u.edge('6th Edition', 'Interdata')
17 u.edge('Interdata', 'Unix/TS 3.0')
18 u.edge('Interdata', 'PWB 2.0')
19 u.edge('Interdata', '7th Edition')
20 u.edge('7th Edition', '8th Edition')
21 u.edge('7th Edition', '32V')
22 u.edge('7th Edition', 'V7M')
23 u.edge('7th Edition', 'Ultrix-11')
24 u.edge('7th Edition', 'Xenix')
25 u.edge('7th Edition', 'UniPlus+')
26 u.edge('V7M', 'Ultrix-11')
27 u.edge('8th Edition', '9th Edition')
28 u.edge('1 BSD', '2 BSD')
29 u.edge('2 BSD', '2.8 BSD')
30 u.edge('2.8 BSD', 'Ultrix-11')
31 u.edge('2.8 BSD', '2.9 BSD')
32 u.edge('32V', '3 BSD')
33 u.edge('3 BSD', '4 BSD')
34 u.edge('4 BSD', '4.1 BSD')
35 u.edge('4.1 BSD', '4.2 BSD')
36 u.edge('4.1 BSD', '2.8 BSD')
37 u.edge('4.1 BSD', '8th Edition')
38 u.edge('4.2 BSD', '4.3 BSD')
39 u.edge('4.2 BSD', 'Ultrix-32')
40 u.edge('PWB 1.0', 'PWB 1.2')
41 u.edge('PWB 1.0', 'USG 1.0')
42 u.edge('PWB 1.2', 'PWB 2.0')
43 u.edge('USG 1.0', 'CB Unix 1')
44 u.edge('USG 1.0', 'USG 2.0')
45 u.edge('CB Unix 1', 'CB Unix 2')
46 u.edge('CB Unix 2', 'CB Unix 3')
47 u.edge('CB Unix 3', 'Unix/TS++')
48 u.edge('CB Unix 3', 'PDP-11 Sys V')
49 u.edge('USG 2.0', 'USG 3.0')
50 u.edge('USG 3.0', 'Unix/TS 3.0')
51 u.edge('PWB 2.0', 'Unix/TS 3.0')
52 u.edge('Unix/TS 1.0', 'Unix/TS 3.0')
53 u.edge('Unix/TS 3.0', 'TS 4.0')
54 u.edge('Unix/TS++', 'TS 4.0')
55 u.edge('CB Unix 3', 'TS 4.0')
56 u.edge('TS 4.0', 'System V.0')
57 u.edge('System V.0', 'System V.2')
58 u.edge('System V.2', 'System V.3')
59
60 u.view()
0 # graphviz - create dot, save, render, view
1
2 """Assemble DOT source code and render it with Graphviz.
3
4 >>> dot = Digraph(comment='The Round Table')
5
6 >>> dot.node('A', 'King Arthur')
7 >>> dot.node('B', 'Sir Bedevere the Wise')
8 >>> dot.node('L', 'Sir Lancelot the Brave')
9
10 >>> dot.edges(['AB', 'AL'])
11
12 >>> dot.edge('B', 'L', constraint='false')
13
14 >>> print(dot) #doctest: +NORMALIZE_WHITESPACE
15 // The Round Table
16 digraph {
17 A [label="King Arthur"]
18 B [label="Sir Bedevere the Wise"]
19 L [label="Sir Lancelot the Brave"]
20 A -> B
21 A -> L
22 B -> L [constraint=false]
23 }
24 """
25
26 from .dot import Graph, Digraph
27 from .files import Source
28 from .lang import escape, nohtml
29 from .backend import (render, pipe, version, view,
30 ENGINES, FORMATS, RENDERERS, FORMATTERS,
31 ExecutableNotFound, RequiredArgumentError)
32
33 __all__ = [
34 'Graph', 'Digraph',
35 'Source',
36 'escape', 'nohtml',
37 'render', 'pipe', 'version', 'view',
38 'ENGINES', 'FORMATS', 'RENDERERS', 'FORMATTERS',
39 'ExecutableNotFound', 'RequiredArgumentError',
40 ]
41
42 __title__ = 'graphviz'
43 __version__ = '0.14.2'
44 __author__ = 'Sebastian Bank <sebastian.bank@uni-leipzig.de>'
45 __license__ = 'MIT, see LICENSE.txt'
46 __copyright__ = 'Copyright (c) 2013-2020 Sebastian Bank'
47
48 #: Set of known layout commands used for rendering (``'dot'``, ``'neato'``, ...)
49 ENGINES = ENGINES
50
51 #: Set of known output formats for rendering (``'pdf'``, ``'png'``, ...)
52 FORMATS = FORMATS
53
54 #: Set of known output formatters for rendering (``'cairo'``, ``'gd'``, ...)
55 FORMATTERS = FORMATTERS
56
57 #: Set of known output renderers for rendering (``'cairo'``, ``'gd'``, ...)
58 RENDERERS = RENDERERS
59
60 ExecutableNotFound = ExecutableNotFound
61
62 RequiredArgumentError = RequiredArgumentError
0 # graphviz - create dot, save, render, view
1
2 """Assemble DOT source code and render it with Graphviz.
3
4 >>> import graphviz
5 >>> dot = graphviz.Digraph(comment='The Round Table')
6
7 >>> dot.node('A', 'King Arthur')
8 >>> dot.node('B', 'Sir Bedevere the Wise')
9 >>> dot.node('L', 'Sir Lancelot the Brave')
10
11 >>> dot.edges(['AB', 'AL'])
12
13 >>> dot.edge('B', 'L', constraint='false')
14
15 >>> print(dot) #doctest: +NORMALIZE_WHITESPACE
16 // The Round Table
17 digraph {
18 A [label="King Arthur"]
19 B [label="Sir Bedevere the Wise"]
20 L [label="Sir Lancelot the Brave"]
21 A -> B
22 A -> L
23 B -> L [constraint=false]
24 }
25 """
26
27 from .backend import (render, pipe, unflatten, version, view,
28 ENGINES, FORMATS, RENDERERS, FORMATTERS,
29 ExecutableNotFound, RequiredArgumentError)
30 from .dot import Graph, Digraph
31 from .files import Source
32 from .lang import escape, nohtml
33
34 __all__ = ['Graph', 'Digraph',
35 'Source',
36 'escape', 'nohtml',
37 'render', 'pipe', 'unflatten', 'version', 'view',
38 'ENGINES', 'FORMATS', 'RENDERERS', 'FORMATTERS',
39 'ExecutableNotFound', 'RequiredArgumentError']
40
41 __title__ = 'graphviz'
42 __version__ = '0.17.dev0'
43 __author__ = 'Sebastian Bank <sebastian.bank@uni-leipzig.de>'
44 __license__ = 'MIT, see LICENSE.txt'
45 __copyright__ = 'Copyright (c) 2013-2021 Sebastian Bank'
46
47 #: :class:`set` of known layout commands used for rendering (``'dot'``, ``'neato'``, ...)
48 ENGINES = ENGINES
49
50 #: :class:`set` of known output formats for rendering (``'pdf'``, ``'png'``, ...)
51 FORMATS = FORMATS
52
53 #: :class:`set` of known output formatters for rendering (``'cairo'``, ``'gd'``, ...)
54 FORMATTERS = FORMATTERS
55
56 #: :class:`set` of known output renderers for rendering (``'cairo'``, ``'gd'``, ...)
57 RENDERERS = RENDERERS
58
59 ExecutableNotFound = ExecutableNotFound
60
61 RequiredArgumentError = RequiredArgumentError
+0
-69
graphviz/_compat.py less more
0 # _compat.py - Python 2/3 compatibility
1
2 import os
3 import sys
4 import operator
5 import subprocess
6
7 PY2 = (sys.version_info.major == 2)
8
9
10 if PY2:
11 string_classes = (str, unicode) # needed individually for sublassing
12 text_type = unicode
13
14 iteritems = operator.methodcaller('iteritems')
15
16 def makedirs(name, mode=0o777, exist_ok=False):
17 try:
18 os.makedirs(name, mode)
19 except OSError:
20 if not exist_ok or not os.path.isdir(name):
21 raise
22
23 def stderr_write_bytes(data, flush=False):
24 """Write data str to sys.stderr (flush if requested)."""
25 sys.stderr.write(data)
26 if flush:
27 sys.stderr.flush()
28
29 def Popen_stderr_devnull(*args, **kwargs): # noqa: N802
30 with open(os.devnull, 'w') as f:
31 return subprocess.Popen(*args, stderr=f, **kwargs)
32
33 class CalledProcessError(subprocess.CalledProcessError):
34
35 def __init__(self, returncode, cmd, output=None, stderr=None):
36 super(CalledProcessError, self).__init__(returncode, cmd, output)
37 self.stderr = stderr
38
39 @property # pragma: no cover
40 def stdout(self):
41 return self.output
42
43 @stdout.setter # pragma: no cover
44 def stdout(self, value):
45 self.output = value
46
47
48 else:
49 string_classes = (str,)
50 text_type = str
51
52 def iteritems(d):
53 return iter(d.items())
54
55 def makedirs(name, mode=0o777, exist_ok=False): # allow os.makedirs mocking
56 return os.makedirs(name, mode, exist_ok=exist_ok)
57
58 def stderr_write_bytes(data, flush=False):
59 """Encode data str and write to sys.stderr (flush if requested)."""
60 encoding = sys.stderr.encoding or sys.getdefaultencoding()
61 sys.stderr.write(data.decode(encoding))
62 if flush:
63 sys.stderr.flush()
64
65 def Popen_stderr_devnull(*args, **kwargs): # noqa: N802
66 return subprocess.Popen(*args, stderr=subprocess.DEVNULL, **kwargs)
67
68 CalledProcessError = subprocess.CalledProcessError
0 # backend.py - execute rendering, open files in viewer
1
2 import os
3 import re
4 import errno
5 import logging
6 import platform
7 import subprocess
8
9 from . import _compat
10
11 from . import tools
12
13 __all__ = [
14 'render', 'pipe', 'version', 'view',
15 'ENGINES', 'FORMATS', 'RENDERERS', 'FORMATTERS',
16 'ExecutableNotFound', 'RequiredArgumentError',
17 ]
18
19 ENGINES = { # http://www.graphviz.org/pdf/dot.1.pdf
20 'dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage',
21 }
22
23 FORMATS = { # http://www.graphviz.org/doc/info/output.html
24 'bmp',
25 'canon', 'dot', 'gv', 'xdot', 'xdot1.2', 'xdot1.4',
26 'cgimage',
27 'cmap',
28 'eps',
29 'exr',
30 'fig',
31 'gd', 'gd2',
32 'gif',
33 'gtk',
34 'ico',
35 'imap', 'cmapx',
36 'imap_np', 'cmapx_np',
37 'ismap',
38 'jp2',
39 'jpg', 'jpeg', 'jpe',
40 'json', 'json0', 'dot_json', 'xdot_json', # Graphviz 2.40
41 'pct', 'pict',
42 'pdf',
43 'pic',
44 'plain', 'plain-ext',
45 'png',
46 'pov',
47 'ps',
48 'ps2',
49 'psd',
50 'sgi',
51 'svg', 'svgz',
52 'tga',
53 'tif', 'tiff',
54 'tk',
55 'vml', 'vmlz',
56 'vrml',
57 'wbmp',
58 'webp',
59 'xlib',
60 'x11',
61 }
62
63 RENDERERS = { # $ dot -T:
64 'cairo',
65 'dot',
66 'fig',
67 'gd',
68 'gdiplus',
69 'map',
70 'pic',
71 'pov',
72 'ps',
73 'svg',
74 'tk',
75 'vml',
76 'vrml',
77 'xdot',
78 }
79
80 FORMATTERS = {'cairo', 'core', 'gd', 'gdiplus', 'gdwbmp', 'xlib'}
81
82 PLATFORM = platform.system().lower()
83
84
85 log = logging.getLogger(__name__)
86
87
88 class ExecutableNotFound(RuntimeError):
89 """Exception raised if the Graphviz executable is not found."""
90
91 _msg = ('failed to execute %r, '
92 'make sure the Graphviz executables are on your systems\' PATH')
93
94 def __init__(self, args):
95 super(ExecutableNotFound, self).__init__(self._msg % args)
96
97
98 class RequiredArgumentError(Exception):
99 """Exception raised if a required argument is missing."""
100
101
102 class CalledProcessError(_compat.CalledProcessError):
103
104 def __str__(self):
105 s = super(CalledProcessError, self).__str__()
106 return '%s [stderr: %r]' % (s, self.stderr)
107
108
109 def command(engine, format_, filepath=None, renderer=None, formatter=None):
110 """Return args list for ``subprocess.Popen`` and name of the rendered file."""
111 if formatter is not None and renderer is None:
112 raise RequiredArgumentError('formatter given without renderer')
113
114 if engine not in ENGINES:
115 raise ValueError('unknown engine: %r' % engine)
116 if format_ not in FORMATS:
117 raise ValueError('unknown format: %r' % format_)
118 if renderer is not None and renderer not in RENDERERS:
119 raise ValueError('unknown renderer: %r' % renderer)
120 if formatter is not None and formatter not in FORMATTERS:
121 raise ValueError('unknown formatter: %r' % formatter)
122
123 output_format = [f for f in (format_, renderer, formatter) if f is not None]
124 cmd = [engine, '-T%s' % ':'.join(output_format)]
125
126 if filepath is None:
127 rendered = None
128 else:
129 cmd.extend(['-O', filepath])
130 suffix = '.'.join(reversed(output_format))
131 rendered = '%s.%s' % (filepath, suffix)
132
133 return cmd, rendered
134
135
136 if PLATFORM == 'windows': # pragma: no cover
137 def get_startupinfo():
138 """Return subprocess.STARTUPINFO instance hiding the console window."""
139 startupinfo = subprocess.STARTUPINFO()
140 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
141 startupinfo.wShowWindow = subprocess.SW_HIDE
142 return startupinfo
143 else:
144 def get_startupinfo():
145 """Return None for startupinfo argument of ``subprocess.Popen``."""
146 return None
147
148
149 def run(cmd, input=None, capture_output=False, check=False, encoding=None,
150 quiet=False, **kwargs):
151 """Run the command described by cmd and return its (stdout, stderr) tuple."""
152 log.debug('run %r', cmd)
153
154 if input is not None:
155 kwargs['stdin'] = subprocess.PIPE
156 if encoding is not None:
157 input = input.encode(encoding)
158
159 if capture_output:
160 kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
161
162 try:
163 proc = subprocess.Popen(cmd, startupinfo=get_startupinfo(), **kwargs)
164 except OSError as e:
165 if e.errno == errno.ENOENT:
166 raise ExecutableNotFound(cmd)
167 else:
168 raise
169
170 out, err = proc.communicate(input)
171
172 if not quiet and err:
173 _compat.stderr_write_bytes(err, flush=True)
174
175 if encoding is not None:
176 if out is not None:
177 out = out.decode(encoding)
178 if err is not None:
179 err = err.decode(encoding)
180
181 if check and proc.returncode:
182 raise CalledProcessError(proc.returncode, cmd,
183 output=out, stderr=err)
184
185 return out, err
186
187
188 def render(engine, format, filepath, renderer=None, formatter=None, quiet=False):
189 """Render file with Graphviz ``engine`` into ``format``, return result filename.
190
191 Args:
192 engine: The layout commmand used for rendering (``'dot'``, ``'neato'``, ...).
193 format: The output format used for rendering (``'pdf'``, ``'png'``, ...).
194 filepath: Path to the DOT source file to render.
195 renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
196 formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
197 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
198 Returns:
199 The (possibly relative) path of the rendered file.
200 Raises:
201 ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter`` are not known.
202 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
203 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
204 subprocess.CalledProcessError: If the exit status is non-zero.
205
206 The layout command is started from the directory of ``filepath``, so that
207 references to external files (e.g. ``[image=...]``) can be given as paths
208 relative to the DOT source file.
209 """
210 dirname, filename = os.path.split(filepath)
211 del filepath
212
213 cmd, rendered = command(engine, format, filename, renderer, formatter)
214 if dirname:
215 cwd = dirname
216 rendered = os.path.join(dirname, rendered)
217 else:
218 cwd = None
219
220 run(cmd, capture_output=True, cwd=cwd, check=True, quiet=quiet)
221 return rendered
222
223
224 def pipe(engine, format, data, renderer=None, formatter=None, quiet=False):
225 """Return ``data`` piped through Graphviz ``engine`` into ``format``.
226
227 Args:
228 engine: The layout commmand used for rendering (``'dot'``, ``'neato'``, ...).
229 format: The output format used for rendering (``'pdf'``, ``'png'``, ...).
230 data: The binary (encoded) DOT source string to render.
231 renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
232 formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
233 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
234 Returns:
235 Binary (encoded) stdout of the layout command.
236 Raises:
237 ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter`` are not known.
238 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
239 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
240 subprocess.CalledProcessError: If the exit status is non-zero.
241 """
242 cmd, _ = command(engine, format, None, renderer, formatter)
243 out, _ = run(cmd, input=data, capture_output=True, check=True, quiet=quiet)
244 return out
245
246
247 def version():
248 """Return the version number tuple from the ``stderr`` output of ``dot -V``.
249
250 Returns:
251 Two, three, or four ``int`` version ``tuple``.
252 Raises:
253 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
254 subprocess.CalledProcessError: If the exit status is non-zero.
255 RuntimmeError: If the output cannot be parsed into a version number.
256
257 Note:
258 Ignores the ``~dev.<YYYYmmdd.HHMM>`` portion of development versions.
259
260 See also Graphviz Release version entry format:
261 https://gitlab.com/graphviz/graphviz/-/blob/f94e91ba819cef51a4b9dcb2d76153684d06a913/gen_version.py#L17-20
262 """
263 cmd = ['dot', '-V']
264 out, _ = run(cmd, check=True, encoding='ascii',
265 stdout=subprocess.PIPE,
266 stderr=subprocess.STDOUT)
267
268 ma = re.search(r'graphviz version'
269 r' '
270 r'(\d+)\.(\d+)'
271 r'(?:\.(\d+)'
272 r'(?:'
273 r'~dev\.\d{8}\.\d{4}'
274 r'|'
275 r'\.(\d+)'
276 r')?'
277 r')?'
278 r' ', out)
279 if ma is None:
280 raise RuntimeError('cannot parse %r output: %r' % (cmd, out))
281
282 return tuple(int(d) for d in ma.groups() if d is not None)
283
284
285 def view(filepath, quiet=False):
286 """Open filepath with its default viewing application (platform-specific).
287
288 Args:
289 filepath: Path to the file to open in viewer.
290 quiet (bool): Suppress ``stderr`` output from the viewer process
291 (ineffective on Windows).
292 Raises:
293 RuntimeError: If the current platform is not supported.
294
295 Note:
296 There is no option to wait for the application to close, and no way
297 to retrieve the application's exit status.
298 """
299 try:
300 view_func = getattr(view, PLATFORM)
301 except AttributeError:
302 raise RuntimeError('platform %r not supported' % PLATFORM)
303 view_func(filepath, quiet)
304
305
306 @tools.attach(view, 'darwin')
307 def view_darwin(filepath, quiet):
308 """Open filepath with its default application (mac)."""
309 cmd = ['open', filepath]
310 log.debug('view: %r', cmd)
311 popen_func = _compat.Popen_stderr_devnull if quiet else subprocess.Popen
312 popen_func(cmd)
313
314
315 @tools.attach(view, 'linux')
316 @tools.attach(view, 'freebsd')
317 def view_unixoid(filepath, quiet):
318 """Open filepath in the user's preferred application (linux, freebsd)."""
319 cmd = ['xdg-open', filepath]
320 log.debug('view: %r', cmd)
321 popen_func = _compat.Popen_stderr_devnull if quiet else subprocess.Popen
322 popen_func(cmd)
323
324
325 @tools.attach(view, 'windows')
326 def view_windows(filepath, quiet):
327 """Start filepath with its associated application (windows)."""
328 # TODO: implement quiet=True
329 filepath = os.path.normpath(filepath)
330 log.debug('view: %r', filepath)
331 os.startfile(filepath)
0 """Execute rendering subprocesses and open files in viewer."""
1
2 import errno
3 import logging
4 import os
5 import platform
6 import re
7 import subprocess
8 import sys
9 import typing
10
11 from . import tools
12
13 __all__ = ['render', 'pipe', 'unflatten', 'version', 'view',
14 'ENGINES', 'FORMATS', 'RENDERERS', 'FORMATTERS',
15 'ExecutableNotFound', 'RequiredArgumentError']
16
17 ENGINES = { # http://www.graphviz.org/pdf/dot.1.pdf
18 'dot', 'neato', 'twopi', 'circo', 'fdp', 'sfdp', 'patchwork', 'osage',
19 }
20
21 FORMATS = { # http://www.graphviz.org/doc/info/output.html
22 'bmp',
23 'canon', 'dot', 'gv', 'xdot', 'xdot1.2', 'xdot1.4',
24 'cgimage',
25 'cmap',
26 'eps',
27 'exr',
28 'fig',
29 'gd', 'gd2',
30 'gif',
31 'gtk',
32 'ico',
33 'imap', 'cmapx',
34 'imap_np', 'cmapx_np',
35 'ismap',
36 'jp2',
37 'jpg', 'jpeg', 'jpe',
38 'json', 'json0', 'dot_json', 'xdot_json', # Graphviz 2.40
39 'pct', 'pict',
40 'pdf',
41 'pic',
42 'plain', 'plain-ext',
43 'png',
44 'pov',
45 'ps',
46 'ps2',
47 'psd',
48 'sgi',
49 'svg', 'svgz',
50 'tga',
51 'tif', 'tiff',
52 'tk',
53 'vml', 'vmlz',
54 'vrml',
55 'wbmp',
56 'webp',
57 'xlib',
58 'x11',
59 }
60
61 RENDERERS = { # $ dot -T:
62 'cairo',
63 'dot',
64 'fig',
65 'gd',
66 'gdiplus',
67 'map',
68 'pic',
69 'pov',
70 'ps',
71 'svg',
72 'tk',
73 'vml',
74 'vrml',
75 'xdot',
76 }
77
78 FORMATTERS = {'cairo', 'core', 'gd', 'gdiplus', 'gdwbmp', 'xlib'}
79
80 ENCODING = 'utf-8'
81
82 PLATFORM = platform.system().lower()
83
84
85 log = logging.getLogger(__name__)
86
87
88 class ExecutableNotFound(RuntimeError):
89 """Exception raised if the Graphviz executable is not found."""
90
91 _msg = ('failed to execute {!r}, '
92 'make sure the Graphviz executables are on your systems\' PATH')
93
94 def __init__(self, args):
95 super().__init__(self._msg.format(*args))
96
97
98 class RequiredArgumentError(Exception):
99 """Exception raised if a required argument is missing (i.e. ``None``)."""
100
101
102 class CalledProcessError(subprocess.CalledProcessError):
103
104 def __str__(self):
105 s = super().__str__()
106 return f'{s} [stderr: {self.stderr!r}]'
107
108
109 def command(engine: str, format_: str, filepath=None,
110 renderer: typing.Optional[str] = None,
111 formatter: typing.Optional[str] = None):
112 """Return args list for ``subprocess.Popen`` and name of the rendered file."""
113 if formatter is not None and renderer is None:
114 raise RequiredArgumentError('formatter given without renderer')
115
116 if engine not in ENGINES:
117 raise ValueError(f'unknown engine: {engine!r}')
118 if format_ not in FORMATS:
119 raise ValueError(f'unknown format: {format_!r}')
120 if renderer is not None and renderer not in RENDERERS:
121 raise ValueError(f'unknown renderer: {renderer!r}')
122 if formatter is not None and formatter not in FORMATTERS:
123 raise ValueError(f'unknown formatter: {formatter!r}')
124
125 output_format = [f for f in (format_, renderer, formatter) if f is not None]
126 cmd = ['dot', '-K%s' % engine, '-T%s' % ':'.join(output_format)]
127
128 if filepath is None:
129 rendered = None
130 else:
131 cmd.extend(['-O', filepath])
132 suffix = '.'.join(reversed(output_format))
133 rendered = f'{filepath}.{suffix}'
134
135 return cmd, rendered
136
137
138 if PLATFORM == 'windows': # pragma: no cover
139 def get_startupinfo():
140 """Return subprocess.STARTUPINFO instance hiding the console window."""
141 startupinfo = subprocess.STARTUPINFO()
142 startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
143 startupinfo.wShowWindow = subprocess.SW_HIDE
144 return startupinfo
145 else:
146 def get_startupinfo():
147 """Return None for startupinfo argument of ``subprocess.Popen``."""
148 return None
149
150
151 def run(cmd, input=None,
152 capture_output: bool = False,
153 check: bool = False,
154 encoding: typing.Optional[str] = None,
155 quiet: bool = False,
156 **kwargs) -> typing.Tuple:
157 """Run the command described by cmd and return its ``(stdout, stderr)`` tuple."""
158 log.debug('run %r', cmd)
159
160 if input is not None:
161 kwargs['stdin'] = subprocess.PIPE
162 if encoding is not None:
163 input = input.encode(encoding)
164
165 if capture_output: # Python 3.6 compat
166 kwargs['stdout'] = kwargs['stderr'] = subprocess.PIPE
167
168 try:
169 proc = subprocess.Popen(cmd, startupinfo=get_startupinfo(), **kwargs)
170 except OSError as e:
171 if e.errno == errno.ENOENT:
172 raise ExecutableNotFound(cmd) from e
173 else:
174 raise
175
176 out, err = proc.communicate(input)
177
178 if not quiet and err:
179 err_encoding = sys.stderr.encoding or sys.getdefaultencoding()
180 sys.stderr.write(err.decode(err_encoding))
181 sys.stderr.flush()
182
183 if encoding is not None:
184 if out is not None:
185 out = out.decode(encoding)
186 if err is not None:
187 err = err.decode(encoding)
188
189 if check and proc.returncode:
190 raise CalledProcessError(proc.returncode, cmd,
191 output=out, stderr=err)
192
193 return out, err
194
195
196 def render(engine: str, format: str, filepath,
197 renderer: typing.Optional[str] = None,
198 formatter: typing.Optional[str] = None,
199 quiet: bool = False) -> str:
200 """Render file with Graphviz ``engine`` into ``format``, return result filename.
201
202 Args:
203 engine: Layout commmand for rendering (``'dot'``, ``'neato'``, ...).
204 format: Output format for rendering (``'pdf'``, ``'png'``, ...).
205 filepath: Path to the DOT source file to render.
206 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
207 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
208 quiet: Suppress ``stderr`` output from the layout subprocess.
209
210 Returns:
211 The (possibly relative) path of the rendered file.
212
213 Raises:
214 ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter`` are not known.
215 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
216 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
217 subprocess.CalledProcessError: If the exit status is non-zero.
218
219 Note:
220 The layout command is started from the directory of ``filepath``, so that
221 references to external files (e.g. ``[image=...]``) can be given as paths
222 relative to the DOT source file.
223 """
224 dirname, filename = os.path.split(filepath)
225 del filepath
226
227 cmd, rendered = command(engine, format, filename, renderer, formatter)
228 if dirname:
229 cwd = dirname
230 rendered = os.path.join(dirname, rendered)
231 else:
232 cwd = None
233
234 run(cmd, capture_output=True, cwd=cwd, check=True, quiet=quiet)
235 return rendered
236
237
238 def pipe(engine: str, format: str, data: bytes,
239 renderer: typing.Optional[str] = None,
240 formatter: typing.Optional[str] = None,
241 quiet: bool = False) -> bytes:
242 """Return ``data`` piped through Graphviz ``engine`` into ``format``.
243
244 Args:
245 engine: Layout commmand for rendering (``'dot'``, ``'neato'``, ...).
246 format: Output format for rendering (``'pdf'``, ``'png'``, ...).
247 data: Binary (encoded) DOT source string to render.
248 renderer: Output renderer (``'cairo'``, ``'gd'``, ...).
249 formatter: Output formatter (``'cairo'``, ``'gd'``, ...).
250 quiet: Suppress ``stderr`` output from the layout subprocess.
251
252 Returns:
253 Binary (encoded) stdout of the layout command.
254
255 Raises:
256 ValueError: If ``engine``, ``format``, ``renderer``, or ``formatter`` are not known.
257 graphviz.RequiredArgumentError: If ``formatter`` is given but no ``renderer``.
258 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
259 subprocess.CalledProcessError: If the exit status is non-zero.
260
261 Example:
262 >>> import graphviz
263 >>> graphviz.pipe('dot', 'svg', b'graph { hello -- world }')
264 b'<?xml version=...'
265 """
266 cmd, _ = command(engine, format, None, renderer, formatter)
267 out, _ = run(cmd, input=data, capture_output=True, check=True, quiet=quiet)
268 return out
269
270
271 def unflatten(source: str,
272 stagger: typing.Optional[int] = None,
273 fanout: bool = False,
274 chain: typing.Optional[int] = None,
275 encoding: str = ENCODING) -> str:
276 """Return DOT ``source`` piped through Graphviz *unflatten* preprocessor.
277
278 Args:
279 source: DOT source to process (improve layout aspect ratio).
280 stagger: Stagger the minimum length of leaf edges between 1 and this small integer.
281 fanout: Fanout nodes with indegree = outdegree = 1 when staggering (requires ``stagger``).
282 chain: Form disconnected nodes into chains of up to this many nodes.
283 encoding: Encoding to encode unflatten stdin and decode its stdout.
284
285 Returns:
286 Decoded stdout of the Graphviz unflatten command.
287
288 Raises:
289 graphviz.RequiredArgumentError: If ``fanout`` is given but no ``stagger``.
290 graphviz.ExecutableNotFound: If the Graphviz unflatten executable is not found.
291 subprocess.CalledProcessError: If the exit status is non-zero.
292
293 See also:
294 https://www.graphviz.org/pdf/unflatten.1.pdf
295 """
296 if fanout and stagger is None:
297 raise RequiredArgumentError('fanout given without stagger')
298
299 cmd = ['unflatten']
300 if stagger is not None:
301 cmd += ['-l', str(stagger)]
302 if fanout:
303 cmd.append('-f')
304 if chain is not None:
305 cmd += ['-c', str(chain)]
306
307 out, _ = run(cmd, input=source, capture_output=True, encoding=encoding)
308 return out
309
310
311 def version() -> typing.Tuple[int, ...]:
312 """Return the version number tuple from the ``stderr`` output of ``dot -V``.
313
314 Returns:
315 Two, three, or four ``int`` version ``tuple``.
316
317 Raises:
318 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
319 subprocess.CalledProcessError: If the exit status is non-zero.
320 RuntimeError: If the output cannot be parsed into a version number.
321
322 Example:
323 >>> import graphviz
324 >>> graphviz.version()
325 (...)
326
327 Note:
328 Ignores the ``~dev.<YYYYmmdd.HHMM>`` portion of development versions.
329
330 See also:
331 Graphviz Release version entry format:
332 https://gitlab.com/graphviz/graphviz/-/blob/f94e91ba819cef51a4b9dcb2d76153684d06a913/gen_version.py#L17-20
333 """
334 cmd = ['dot', '-V']
335 out, _ = run(cmd, check=True, encoding='ascii',
336 stdout=subprocess.PIPE,
337 stderr=subprocess.STDOUT)
338
339 ma = re.search(r'graphviz version'
340 r' '
341 r'(\d+)\.(\d+)'
342 r'(?:\.(\d+)'
343 r'(?:'
344 r'~dev\.\d{8}\.\d{4}'
345 r'|'
346 r'\.(\d+)'
347 r')?'
348 r')?'
349 r' ', out)
350 if ma is None:
351 raise RuntimeError(f'cannot parse {cmd!r} output: {out!r}')
352
353 return tuple(int(d) for d in ma.groups() if d is not None)
354
355
356 def view(filepath, quiet: bool = False) -> None:
357 """Open filepath with its default viewing application (platform-specific).
358
359 Args:
360 filepath: Path to the file to open in viewer.
361 quiet: Suppress ``stderr`` output from the viewer process
362 (ineffective on Windows).
363
364 Returns:
365 ``None``
366
367 Raises:
368 RuntimeError: If the current platform is not supported.
369
370 Note:
371 There is no option to wait for the application to close, and no way
372 to retrieve the application's exit status.
373 """
374 try:
375 view_func = getattr(view, PLATFORM)
376 except AttributeError:
377 raise RuntimeError(f'platform {PLATFORM!r} not supported')
378 view_func(filepath, quiet=quiet)
379
380
381 @tools.attach(view, 'darwin')
382 def view_darwin(filepath, *, quiet: bool) -> None:
383 """Open filepath with its default application (mac)."""
384 cmd = ['open', filepath]
385 log.debug('view: %r', cmd)
386 kwargs = {'stderr': subprocess.DEVNULL} if quiet else {}
387 subprocess.Popen(cmd, **kwargs)
388
389
390 @tools.attach(view, 'linux')
391 @tools.attach(view, 'freebsd')
392 def view_unixoid(filepath, *, quiet: bool) -> None:
393 """Open filepath in the user's preferred application (linux, freebsd)."""
394 cmd = ['xdg-open', filepath]
395 log.debug('view: %r', cmd)
396 kwargs = {'stderr': subprocess.DEVNULL} if quiet else {}
397 subprocess.Popen(cmd, **kwargs)
398
399
400 @tools.attach(view, 'windows')
401 def view_windows(filepath, *, quiet: bool) -> None:
402 """Start filepath with its associated application (windows)."""
403 # TODO: implement quiet=True
404 filepath = os.path.normpath(filepath)
405 log.debug('view: %r', filepath)
406 os.startfile(filepath)
0 # dot.py - create dot code
1
2 r"""Assemble DOT source code objects.
3
4 >>> dot = Graph(comment=u'M\xf8nti Pyth\xf8n ik den H\xf8lie Grailen')
5
6 >>> dot.node(u'M\xf8\xf8se')
7 >>> dot.node('trained_by', u'trained by')
8 >>> dot.node('tutte', u'TUTTE HERMSGERVORDENBROTBORDA')
9
10 >>> dot.edge(u'M\xf8\xf8se', 'trained_by')
11 >>> dot.edge('trained_by', 'tutte')
12
13 >>> dot.node_attr['shape'] = 'rectangle'
14
15 >>> print(dot.source.replace(u'\xf8', '0')) #doctest: +NORMALIZE_WHITESPACE
16 // M0nti Pyth0n ik den H0lie Grailen
17 graph {
18 node [shape=rectangle]
19 "M00se"
20 trained_by [label="trained by"]
21 tutte [label="TUTTE HERMSGERVORDENBROTBORDA"]
22 "M00se" -- trained_by
23 trained_by -- tutte
24 }
25
26 >>> dot.view('test-output/m00se.gv') # doctest: +SKIP
27 'test-output/m00se.gv.pdf'
28 """
29
30 from . import lang
31 from . import files
32
33 __all__ = ['Graph', 'Digraph']
34
35
36 class Dot(files.File):
37 """Assemble, save, and render DOT source code, open result in viewer."""
38
39 _comment = '// %s'
40 _subgraph = 'subgraph %s{'
41 _subgraph_plain = '%s{'
42 _node = _attr = '\t%s%s'
43 _attr_plain = _attr % ('%s', '')
44 _tail = '}'
45
46 _quote = staticmethod(lang.quote)
47 _quote_edge = staticmethod(lang.quote_edge)
48
49 _a_list = staticmethod(lang.a_list)
50 _attr_list = staticmethod(lang.attr_list)
51
52 def __init__(self, name=None, comment=None,
53 filename=None, directory=None,
54 format=None, engine=None, encoding=files.ENCODING,
55 graph_attr=None, node_attr=None, edge_attr=None, body=None,
56 strict=False):
57 self.name = name
58 self.comment = comment
59
60 super(Dot, self).__init__(filename, directory, format, engine, encoding)
61
62 self.graph_attr = dict(graph_attr) if graph_attr is not None else {}
63 self.node_attr = dict(node_attr) if node_attr is not None else {}
64 self.edge_attr = dict(edge_attr) if edge_attr is not None else {}
65
66 self.body = list(body) if body is not None else []
67
68 self.strict = strict
69
70 def _kwargs(self):
71 result = super(Dot, self)._kwargs()
72 result.update(name=self.name,
73 comment=self.comment,
74 graph_attr=dict(self.graph_attr),
75 node_attr=dict(self.node_attr),
76 edge_attr=dict(self.edge_attr),
77 body=list(self.body),
78 strict=self.strict)
79 return result
80
81 def clear(self, keep_attrs=False):
82 """Reset content to an empty body, clear graph/node/egde_attr mappings.
83
84 Args:
85 keep_attrs (bool): preserve graph/node/egde_attr mappings
86 """
87 if not keep_attrs:
88 for a in (self.graph_attr, self.node_attr, self.edge_attr):
89 a.clear()
90 del self.body[:]
91
92 def __iter__(self, subgraph=False):
93 """Yield the DOT source code line by line (as graph or subgraph)."""
94 if self.comment:
95 yield self._comment % self.comment
96
97 if subgraph:
98 if self.strict:
99 raise ValueError('subgraphs cannot be strict')
100 head = self._subgraph if self.name else self._subgraph_plain
101 else:
102 head = self._head_strict if self.strict else self._head
103 yield head % (self._quote(self.name) + ' ' if self.name else '')
104
105 for kw in ('graph', 'node', 'edge'):
106 attrs = getattr(self, '%s_attr' % kw)
107 if attrs:
108 yield self._attr % (kw, self._attr_list(None, attrs))
109
110 for line in self.body:
111 yield line
112
113 yield self._tail
114
115 def __str__(self):
116 """The DOT source code as string."""
117 return '\n'.join(self)
118
119 source = property(__str__, doc=__str__.__doc__)
120
121 def node(self, name, label=None, _attributes=None, **attrs):
122 """Create a node.
123
124 Args:
125 name: Unique identifier for the node inside the source.
126 label: Caption to be displayed (defaults to the node ``name``).
127 attrs: Any additional node attributes (must be strings).
128 """
129 name = self._quote(name)
130 attr_list = self._attr_list(label, attrs, _attributes)
131 line = self._node % (name, attr_list)
132 self.body.append(line)
133
134 def edge(self, tail_name, head_name, label=None, _attributes=None, **attrs):
135 """Create an edge between two nodes.
136
137 Args:
138 tail_name: Start node identifier (format: ``node[:port[:compass]]``).
139 head_name: End node identifier (format: ``node[:port[:compass]]``).
140 label: Caption to be displayed near the edge.
141 attrs: Any additional edge attributes (must be strings).
142
143 Note:
144 The ``tail_name`` and ``head_name`` strings are separated by
145 (optional) colon(s) into ``node`` name, ``port`` name, and
146 ``compass`` (e.g. ``sw``).
147 See :ref:`details in the User Guide <ports>`.
148 """
149 tail_name = self._quote_edge(tail_name)
150 head_name = self._quote_edge(head_name)
151 attr_list = self._attr_list(label, attrs, _attributes)
152 line = self._edge % (tail_name, head_name, attr_list)
153 self.body.append(line)
154
155 def edges(self, tail_head_iter):
156 """Create a bunch of edges.
157
158 Args:
159 tail_head_iter: Iterable of ``(tail_name, head_name)`` pairs (format:``node[:port[:compass]]``).
160
161
162 Note:
163 The ``tail_name`` and ``head_name`` strings are separated by
164 (optional) colon(s) into ``node`` name, ``port`` name, and
165 ``compass`` (e.g. ``sw``).
166 See :ref:`details in the User Guide <ports>`.
167 """
168 edge = self._edge_plain
169 quote = self._quote_edge
170 lines = (edge % (quote(t), quote(h)) for t, h in tail_head_iter)
171 self.body.extend(lines)
172
173 def attr(self, kw=None, _attributes=None, **attrs):
174 """Add a general or graph/node/edge attribute statement.
175
176 Args:
177 kw: Attributes target (``None`` or ``'graph'``, ``'node'``, ``'edge'``).
178 attrs: Attributes to be set (must be strings, may be empty).
179
180 See the :ref:`usage examples in the User Guide <attributes>`.
181 """
182 if kw is not None and kw.lower() not in ('graph', 'node', 'edge'):
183 raise ValueError('attr statement must target graph, node, or edge: '
184 '%r' % kw)
185 if attrs or _attributes:
186 if kw is None:
187 a_list = self._a_list(None, attrs, _attributes)
188 line = self._attr_plain % a_list
189 else:
190 attr_list = self._attr_list(None, attrs, _attributes)
191 line = self._attr % (kw, attr_list)
192 self.body.append(line)
193
194 def subgraph(self, graph=None, name=None, comment=None,
195 graph_attr=None, node_attr=None, edge_attr=None, body=None):
196 """Add the current content of the given sole ``graph`` argument as subgraph \
197 or return a context manager returning a new graph instance created \
198 with the given (``name``, ``comment``, etc.) arguments whose content is \
199 added as subgraph when leaving the context manager's ``with``-block.
200
201 Args:
202 graph: An instance of the same kind (:class:`.Graph`, :class:`.Digraph`)
203 as the current graph (sole argument in non-with-block use).
204 name: Subgraph name (``with``-block use).
205 comment: Subgraph comment (``with``-block use).
206 graph_attr: Subgraph-level attribute-value mapping (``with``-block use).
207 node_attr: Node-level attribute-value mapping (``with``-block use).
208 edge_attr: Edge-level attribute-value mapping (``with``-block use).
209 body: Verbatim lines to add to the subgraph ``body`` (``with``-block use).
210
211 See the :ref:`usage examples in the User Guide <subgraphs>`.
212
213 Note:
214 If the ``name`` of the subgraph begins with ``'cluster'`` (all lowercase)
215 the layout engine will treat it as a special cluster subgraph.
216 """
217 if graph is None:
218 return SubgraphContext(self, {'name': name,
219 'comment': comment,
220 'graph_attr': graph_attr,
221 'node_attr': node_attr,
222 'edge_attr': edge_attr,
223 'body': body})
224
225 args = [name, comment, graph_attr, node_attr, edge_attr, body]
226 if not all(a is None for a in args):
227 raise ValueError('graph must be sole argument of subgraph()')
228
229 if graph.directed != self.directed:
230 raise ValueError('%r cannot add subgraph of different kind:'
231 ' %r' % (self, graph))
232
233 lines = ['\t' + line for line in graph.__iter__(subgraph=True)]
234 self.body.extend(lines)
235
236
237 class SubgraphContext(object):
238 """Return a blank instance of the parent and add as subgraph on exit."""
239
240 def __init__(self, parent, kwargs):
241 self.parent = parent
242 self.graph = parent.__class__(**kwargs)
243
244 def __enter__(self):
245 return self.graph
246
247 def __exit__(self, type_, value, traceback):
248 if type_ is None:
249 self.parent.subgraph(self.graph)
250
251
252 class Graph(Dot):
253 """Graph source code in the DOT language.
254
255 Args:
256 name: Graph name used in the source code.
257 comment: Comment added to the first line of the source.
258 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``).
259 directory: (Sub)directory for source saving and rendering.
260 format: Rendering output format (``'pdf'``, ``'png'``, ...).
261 engine: Layout command used (``'dot'``, ``'neato'``, ...).
262 encoding: Encoding for saving the source.
263 graph_attr: Mapping of ``(attribute, value)`` pairs for the graph.
264 node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes.
265 edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges.
266 body: Iterable of verbatim lines to add to the graph ``body``.
267 strict (bool): Rendering should merge multi-edges.
268
269 Note:
270 All parameters are `optional` and can be changed under their
271 corresponding attribute name after instance creation.
272 """
273
274 _head = 'graph %s{'
275 _head_strict = 'strict %s' % _head
276 _edge = '\t%s -- %s%s'
277 _edge_plain = _edge % ('%s', '%s', '')
278
279 @property
280 def directed(self):
281 """``False``"""
282 return False
283
284
285 class Digraph(Dot):
286 """Directed graph source code in the DOT language."""
287
288 if Graph.__doc__ is not None:
289 __doc__ += Graph.__doc__.partition('.')[2]
290
291 _head = 'digraph %s{'
292 _head_strict = 'strict %s' % _head
293 _edge = '\t%s -> %s%s'
294 _edge_plain = _edge % ('%s', '%s', '')
295
296 @property
297 def directed(self):
298 """``True``"""
299 return True
0 # dot.py - create dot code
1
2 r"""Assemble DOT source code objects.
3
4 >>> import graphviz
5 >>> dot = graphviz.Graph(comment='M\xf8nti Pyth\xf8n ik den H\xf8lie Grailen')
6
7 >>> dot.node('M\xf8\xf8se')
8 >>> dot.node('trained_by', 'trained by')
9 >>> dot.node('tutte', 'TUTTE HERMSGERVORDENBROTBORDA')
10
11 >>> dot.edge('M\xf8\xf8se', 'trained_by')
12 >>> dot.edge('trained_by', 'tutte')
13
14 >>> dot.node_attr['shape'] = 'rectangle'
15
16 >>> print(dot.source.replace('\xf8', '0')) #doctest: +NORMALIZE_WHITESPACE
17 // M0nti Pyth0n ik den H0lie Grailen
18 graph {
19 node [shape=rectangle]
20 "M00se"
21 trained_by [label="trained by"]
22 tutte [label="TUTTE HERMSGERVORDENBROTBORDA"]
23 "M00se" -- trained_by
24 trained_by -- tutte
25 }
26
27 >>> dot.view('test-output/m00se.gv') # doctest: +SKIP
28 'test-output/m00se.gv.pdf'
29 """
30
31 from . import backend
32 from . import files
33 from . import lang
34
35 __all__ = ['Graph', 'Digraph']
36
37
38 class Dot(files.File):
39 """Assemble, save, and render DOT source code, open result in viewer."""
40
41 _comment = '// %s'
42 _subgraph = 'subgraph %s{'
43 _subgraph_plain = '%s{'
44 _node = _attr = '\t%s%s'
45 _attr_plain = _attr % ('%s', '')
46 _tail = '}'
47
48 _quote = staticmethod(lang.quote)
49 _quote_edge = staticmethod(lang.quote_edge)
50
51 _a_list = staticmethod(lang.a_list)
52 _attr_list = staticmethod(lang.attr_list)
53
54 def __init__(self, name=None, comment=None,
55 filename=None, directory=None,
56 format=None, engine=None, encoding=backend.ENCODING,
57 graph_attr=None, node_attr=None, edge_attr=None, body=None,
58 strict=False):
59 self.name = name
60 self.comment = comment
61
62 super().__init__(filename, directory, format, engine, encoding)
63
64 self.graph_attr = dict(graph_attr) if graph_attr is not None else {}
65 self.node_attr = dict(node_attr) if node_attr is not None else {}
66 self.edge_attr = dict(edge_attr) if edge_attr is not None else {}
67
68 self.body = list(body) if body is not None else []
69
70 self.strict = strict
71
72 def _kwargs(self):
73 result = super()._kwargs()
74 result.update(name=self.name,
75 comment=self.comment,
76 graph_attr=dict(self.graph_attr),
77 node_attr=dict(self.node_attr),
78 edge_attr=dict(self.edge_attr),
79 body=list(self.body),
80 strict=self.strict)
81 return result
82
83 def clear(self, keep_attrs=False):
84 """Reset content to an empty body, clear graph/node/egde_attr mappings.
85
86 Args:
87 keep_attrs (bool): preserve graph/node/egde_attr mappings
88 """
89 if not keep_attrs:
90 for a in (self.graph_attr, self.node_attr, self.edge_attr):
91 a.clear()
92 del self.body[:]
93
94 def __iter__(self, subgraph=False):
95 """Yield the DOT source code line by line (as graph or subgraph)."""
96 if self.comment:
97 yield self._comment % self.comment
98
99 if subgraph:
100 if self.strict:
101 raise ValueError('subgraphs cannot be strict')
102 head = self._subgraph if self.name else self._subgraph_plain
103 else:
104 head = self._head_strict if self.strict else self._head
105 yield head % (self._quote(self.name) + ' ' if self.name else '')
106
107 for kw in ('graph', 'node', 'edge'):
108 attrs = getattr(self, f'{kw}_attr')
109 if attrs:
110 yield self._attr % (kw, self._attr_list(None, attrs))
111
112 for line in self.body:
113 yield line
114
115 yield self._tail
116
117 @property
118 def source(self):
119 """The DOT source code as string."""
120 return '\n'.join(self)
121
122 def node(self, name, label=None, _attributes=None, **attrs):
123 """Create a node.
124
125 Args:
126 name: Unique identifier for the node inside the source.
127 label: Caption to be displayed (defaults to the node ``name``).
128 attrs: Any additional node attributes (must be strings).
129 """
130 name = self._quote(name)
131 attr_list = self._attr_list(label, attrs, _attributes)
132 line = self._node % (name, attr_list)
133 self.body.append(line)
134
135 def edge(self, tail_name, head_name, label=None, _attributes=None, **attrs):
136 """Create an edge between two nodes.
137
138 Args:
139 tail_name: Start node identifier (format: ``node[:port[:compass]]``).
140 head_name: End node identifier (format: ``node[:port[:compass]]``).
141 label: Caption to be displayed near the edge.
142 attrs: Any additional edge attributes (must be strings).
143
144 Note:
145 The ``tail_name`` and ``head_name`` strings are separated by
146 (optional) colon(s) into ``node`` name, ``port`` name, and
147 ``compass`` (e.g. ``sw``).
148 See :ref:`details in the User Guide <ports>`.
149 """
150 tail_name = self._quote_edge(tail_name)
151 head_name = self._quote_edge(head_name)
152 attr_list = self._attr_list(label, attrs, _attributes)
153 line = self._edge % (tail_name, head_name, attr_list)
154 self.body.append(line)
155
156 def edges(self, tail_head_iter):
157 """Create a bunch of edges.
158
159 Args:
160 tail_head_iter: Iterable of ``(tail_name, head_name)`` pairs
161 (format:``node[:port[:compass]]``).
162
163
164 Note:
165 The ``tail_name`` and ``head_name`` strings are separated by
166 (optional) colon(s) into ``node`` name, ``port`` name, and
167 ``compass`` (e.g. ``sw``).
168 See :ref:`details in the User Guide <ports>`.
169 """
170 edge = self._edge_plain
171 quote = self._quote_edge
172 lines = (edge % (quote(t), quote(h)) for t, h in tail_head_iter)
173 self.body.extend(lines)
174
175 def attr(self, kw=None, _attributes=None, **attrs):
176 """Add a general or graph/node/edge attribute statement.
177
178 Args:
179 kw: Attributes target (``None`` or ``'graph'``, ``'node'``, ``'edge'``).
180 attrs: Attributes to be set (must be strings, may be empty).
181
182 See the :ref:`usage examples in the User Guide <attributes>`.
183 """
184 if kw is not None and kw.lower() not in ('graph', 'node', 'edge'):
185 raise ValueError('attr statement must target graph, node, or edge:'
186 f' {kw!r}')
187 if attrs or _attributes:
188 if kw is None:
189 a_list = self._a_list(None, attrs, _attributes)
190 line = self._attr_plain % a_list
191 else:
192 attr_list = self._attr_list(None, attrs, _attributes)
193 line = self._attr % (kw, attr_list)
194 self.body.append(line)
195
196 def subgraph(self, graph=None, name=None, comment=None,
197 graph_attr=None, node_attr=None, edge_attr=None, body=None):
198 """Add the current content of the given sole ``graph`` argument as subgraph \
199 or return a context manager returning a new graph instance created \
200 with the given (``name``, ``comment``, etc.) arguments whose content is \
201 added as subgraph when leaving the context manager's ``with``-block.
202
203 Args:
204 graph: An instance of the same kind (:class:`.Graph`, :class:`.Digraph`)
205 as the current graph (sole argument in non-with-block use).
206 name: Subgraph name (``with``-block use).
207 comment: Subgraph comment (``with``-block use).
208 graph_attr: Subgraph-level attribute-value mapping (``with``-block use).
209 node_attr: Node-level attribute-value mapping (``with``-block use).
210 edge_attr: Edge-level attribute-value mapping (``with``-block use).
211 body: Verbatim lines to add to the subgraph ``body`` (``with``-block use).
212
213 See the :ref:`usage examples in the User Guide <subgraphs>`.
214
215 When used as a context manager, the returned new graph instance uses
216 ``strict=None`` and the parent graph's values for ``directory``,
217 ``format``, ``engine``, and ``encoding`` by default.
218
219 Note:
220 If the ``name`` of the subgraph begins with ``'cluster'`` (all lowercase)
221 the layout engine will treat it as a special cluster subgraph.
222 """
223 if graph is None:
224 return SubgraphContext(self, {'name': name,
225 'comment': comment,
226 'directory': self.directory,
227 'format': self.format,
228 'engine': self.engine,
229 'encoding': self.encoding,
230 'graph_attr': graph_attr,
231 'node_attr': node_attr,
232 'edge_attr': edge_attr,
233 'body': body,
234 'strict': None})
235
236 args = [name, comment, graph_attr, node_attr, edge_attr, body]
237 if not all(a is None for a in args):
238 raise ValueError('graph must be sole argument of subgraph()')
239
240 if graph.directed != self.directed:
241 raise ValueError(f'{self!r} cannot add subgraph of different kind:'
242 f' {graph!r}')
243
244 lines = ['\t' + line for line in graph.__iter__(subgraph=True)]
245 self.body.extend(lines)
246
247
248 class SubgraphContext(object):
249 """Return a blank instance of the parent and add as subgraph on exit."""
250
251 def __init__(self, parent, kwargs):
252 self.parent = parent
253 self.graph = parent.__class__(**kwargs)
254
255 def __enter__(self):
256 return self.graph
257
258 def __exit__(self, type_, value, traceback):
259 if type_ is None:
260 self.parent.subgraph(self.graph)
261
262
263 class Graph(Dot):
264 """Graph source code in the DOT language.
265
266 Args:
267 name: Graph name used in the source code.
268 comment: Comment added to the first line of the source.
269 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``).
270 directory: (Sub)directory for source saving and rendering.
271 format: Rendering output format (``'pdf'``, ``'png'``, ...).
272 engine: Layout command used (``'dot'``, ``'neato'``, ...).
273 encoding: Encoding for saving the source.
274 graph_attr: Mapping of ``(attribute, value)`` pairs for the graph.
275 node_attr: Mapping of ``(attribute, value)`` pairs set for all nodes.
276 edge_attr: Mapping of ``(attribute, value)`` pairs set for all edges.
277 body: Iterable of verbatim lines to add to the graph ``body``.
278 strict (bool): Rendering should merge multi-edges.
279
280 Note:
281 All parameters are `optional` and can be changed under their
282 corresponding attribute name after instance creation.
283 """
284
285 _head = 'graph %s{'
286 _head_strict = 'strict %s' % _head
287 _edge = '\t%s -- %s%s'
288 _edge_plain = _edge % ('%s', '%s', '')
289
290 @property
291 def directed(self):
292 """``False``"""
293 return False
294
295
296 class Digraph(Dot):
297 """Directed graph source code in the DOT language."""
298
299 if Graph.__doc__ is not None:
300 __doc__ += Graph.__doc__.partition('.')[2]
301
302 _head = 'digraph %s{'
303 _head_strict = 'strict %s' % _head
304 _edge = '\t%s -> %s%s'
305 _edge_plain = _edge % ('%s', '%s', '')
306
307 @property
308 def directed(self):
309 """``True``"""
310 return True
0 # files.py - save, render, view
1
2 """Save DOT code objects, render with Graphviz dot, and open in viewer."""
3
4 import os
5 import io
6 import codecs
7 import locale
8 import logging
9
10 from ._compat import text_type
11
12 from . import backend
13 from . import tools
14
15 __all__ = ['File', 'Source']
16
17 ENCODING = 'utf-8'
18
19
20 log = logging.getLogger(__name__)
21
22
23 class Base(object):
24
25 _format = 'pdf'
26 _engine = 'dot'
27 _encoding = ENCODING
28
29 @property
30 def format(self):
31 """The output format used for rendering (``'pdf'``, ``'png'``, ...)."""
32 return self._format
33
34 @format.setter
35 def format(self, format):
36 format = format.lower()
37 if format not in backend.FORMATS:
38 raise ValueError('unknown format: %r' % format)
39 self._format = format
40
41 @property
42 def engine(self):
43 """The layout commmand used for rendering (``'dot'``, ``'neato'``, ...)."""
44 return self._engine
45
46 @engine.setter
47 def engine(self, engine):
48 engine = engine.lower()
49 if engine not in backend.ENGINES:
50 raise ValueError('unknown engine: %r' % engine)
51 self._engine = engine
52
53 @property
54 def encoding(self):
55 """The encoding for the saved source file."""
56 return self._encoding
57
58 @encoding.setter
59 def encoding(self, encoding):
60 if encoding is None:
61 encoding = locale.getpreferredencoding()
62 codecs.lookup(encoding) # raise early
63 self._encoding = encoding
64
65 def copy(self):
66 """Return a copied instance of the object.
67
68 Returns:
69 An independent copy of the current object.
70 """
71 kwargs = self._kwargs()
72 return self.__class__(**kwargs)
73
74 def _kwargs(self):
75 ns = self.__dict__
76 return {a[1:]: ns[a] for a in ('_format', '_engine', '_encoding')
77 if a in ns}
78
79
80 class File(Base):
81
82 directory = ''
83
84 _default_extension = 'gv'
85
86 def __init__(self, filename=None, directory=None,
87 format=None, engine=None, encoding=ENCODING):
88 if filename is None:
89 name = getattr(self, 'name', None) or self.__class__.__name__
90 filename = '%s.%s' % (name, self._default_extension)
91 self.filename = filename
92
93 if directory is not None:
94 self.directory = directory
95
96 if format is not None:
97 self.format = format
98
99 if engine is not None:
100 self.engine = engine
101
102 self.encoding = encoding
103
104 def _kwargs(self):
105 result = super(File, self)._kwargs()
106 result['filename'] = self.filename
107 if 'directory' in self.__dict__:
108 result['directory'] = self.directory
109 return result
110
111 def _repr_svg_(self):
112 return self.pipe(format='svg').decode(self._encoding)
113
114 def pipe(self, format=None, renderer=None, formatter=None, quiet=False):
115 """Return the source piped through the Graphviz layout command.
116
117 Args:
118 format: The output format used for rendering (``'pdf'``, ``'png'``, etc.).
119 renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
120 formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
121 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
122 Returns:
123 Binary (encoded) stdout of the layout command.
124 Raises:
125 ValueError: If ``format``, ``renderer``, or ``formatter`` are not known.
126 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
127 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
128 subprocess.CalledProcessError: If the exit status is non-zero.
129 """
130 if format is None:
131 format = self._format
132
133 data = text_type(self.source).encode(self._encoding)
134
135 out = backend.pipe(self._engine, format, data,
136 renderer=renderer, formatter=formatter,
137 quiet=quiet)
138
139 return out
140
141 @property
142 def filepath(self):
143 return os.path.join(self.directory, self.filename)
144
145 def save(self, filename=None, directory=None):
146 """Save the DOT source to file. Ensure the file ends with a newline.
147
148 Args:
149 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
150 directory: (Sub)directory for source saving and rendering.
151 Returns:
152 The (possibly relative) path of the saved source file.
153 """
154 if filename is not None:
155 self.filename = filename
156 if directory is not None:
157 self.directory = directory
158
159 filepath = self.filepath
160 tools.mkdirs(filepath)
161
162 data = text_type(self.source)
163
164 log.debug('write %d bytes to %r', len(data), filepath)
165 with io.open(filepath, 'w', encoding=self.encoding) as fd:
166 fd.write(data)
167 if not data.endswith(u'\n'):
168 fd.write(u'\n')
169
170 return filepath
171
172 def render(self, filename=None, directory=None, view=False, cleanup=False,
173 format=None, renderer=None, formatter=None,
174 quiet=False, quiet_view=False):
175 """Save the source to file and render with the Graphviz engine.
176
177 Args:
178 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
179 directory: (Sub)directory for source saving and rendering.
180 view (bool): Open the rendered result with the default application.
181 cleanup (bool): Delete the source file after rendering.
182 format: The output format used for rendering (``'pdf'``, ``'png'``, etc.).
183 renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
184 formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
185 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
186 quiet_view (bool): Suppress ``stderr`` output from the viewer process
187 (implies ``view=True``, ineffective on Windows).
188 Returns:
189 The (possibly relative) path of the rendered file.
190 Raises:
191 ValueError: If ``format``, ``renderer``, or ``formatter`` are not known.
192 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
193 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
194 subprocess.CalledProcessError: If the exit status is non-zero.
195 RuntimeError: If viewer opening is requested but not supported.
196
197 The layout command is started from the directory of ``filepath``, so that
198 references to external files (e.g. ``[image=...]``) can be given as paths
199 relative to the DOT source file.
200 """
201 filepath = self.save(filename, directory)
202
203 if format is None:
204 format = self._format
205
206 rendered = backend.render(self._engine, format, filepath,
207 renderer=renderer, formatter=formatter,
208 quiet=quiet)
209
210 if cleanup:
211 log.debug('delete %r', filepath)
212 os.remove(filepath)
213
214 if quiet_view or view:
215 self._view(rendered, self._format, quiet_view)
216
217 return rendered
218
219 def view(self, filename=None, directory=None, cleanup=False,
220 quiet=False, quiet_view=False):
221 """Save the source to file, open the rendered result in a viewer.
222
223 Args:
224 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
225 directory: (Sub)directory for source saving and rendering.
226 cleanup (bool): Delete the source file after rendering.
227 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
228 quiet_view (bool): Suppress ``stderr`` output from the viewer process
229 (ineffective on Windows).
230 Returns:
231 The (possibly relative) path of the rendered file.
232 Raises:
233 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
234 subprocess.CalledProcessError: If the exit status is non-zero.
235 RuntimeError: If opening the viewer is not supported.
236
237 Short-cut method for calling :meth:`.render` with ``view=True``.
238
239 Note:
240 There is no option to wait for the application to close, and no way
241 to retrieve the application's exit status.
242 """
243 return self.render(filename=filename, directory=directory,
244 view=True, cleanup=cleanup,
245 quiet=quiet, quiet_view=quiet_view)
246
247 def _view(self, filepath, format, quiet):
248 """Start the right viewer based on file format and platform."""
249 methodnames = [
250 '_view_%s_%s' % (format, backend.PLATFORM),
251 '_view_%s' % backend.PLATFORM,
252 ]
253 for name in methodnames:
254 view_method = getattr(self, name, None)
255 if view_method is not None:
256 break
257 else:
258 raise RuntimeError('%r has no built-in viewer support for %r'
259 ' on %r platform' % (self.__class__, format,
260 backend.PLATFORM))
261 view_method(filepath, quiet)
262
263 _view_darwin = staticmethod(backend.view.darwin)
264 _view_freebsd = staticmethod(backend.view.freebsd)
265 _view_linux = staticmethod(backend.view.linux)
266 _view_windows = staticmethod(backend.view.windows)
267
268
269 class Source(File):
270 """Verbatim DOT source code string to be rendered by Graphviz.
271
272 Args:
273 source: The verbatim DOT source code string.
274 filename: Filename for saving the source (defaults to ``'Source.gv'``).
275 directory: (Sub)directory for source saving and rendering.
276 format: Rendering output format (``'pdf'``, ``'png'``, ...).
277 engine: Layout command used (``'dot'``, ``'neato'``, ...).
278 encoding: Encoding for saving the source.
279
280 Note:
281 All parameters except ``source`` are optional. All of them can be changed
282 under their corresponding attribute name after instance creation.
283 """
284
285 @classmethod
286 def from_file(cls, filename, directory=None,
287 format=None, engine=None, encoding=ENCODING):
288 """Return an instance with the source string read from the given file.
289
290 Args:
291 filename: Filename for loading/saving the source.
292 directory: (Sub)directory for source loading/saving and rendering.
293 format: Rendering output format (``'pdf'``, ``'png'``, ...).
294 engine: Layout command used (``'dot'``, ``'neato'``, ...).
295 encoding: Encoding for loading/saving the source.
296 """
297 filepath = os.path.join(directory or '', filename)
298 if encoding is None:
299 encoding = locale.getpreferredencoding()
300 log.debug('read %r with encoding %r', filepath, encoding)
301 with io.open(filepath, encoding=encoding) as fd:
302 source = fd.read()
303 return cls(source, filename, directory, format, engine, encoding)
304
305 def __init__(self, source, filename=None, directory=None,
306 format=None, engine=None, encoding=ENCODING):
307 super(Source, self).__init__(filename, directory,
308 format, engine, encoding)
309 self.source = source #: The verbatim DOT source code string.
310
311 def _kwargs(self):
312 result = super(Source, self)._kwargs()
313 result['source'] = self.source
314 return result
0 # files.py - save, render, view
1
2 """Save DOT code objects, render with Graphviz dot, and open in viewer."""
3
4 import codecs
5 import locale
6 import logging
7 import os
8
9 from . import backend
10 from . import tools
11
12 __all__ = ['File', 'Source']
13
14
15 log = logging.getLogger(__name__)
16
17
18 class Base(object):
19
20 _engine = 'dot'
21
22 _format = 'pdf'
23
24 _encoding = backend.ENCODING
25
26 @property
27 def engine(self):
28 """The layout commmand used for rendering (``'dot'``, ``'neato'``, ...)."""
29 return self._engine
30
31 @engine.setter
32 def engine(self, engine):
33 engine = engine.lower()
34 if engine not in backend.ENGINES:
35 raise ValueError(f'unknown engine: {engine!r}')
36 self._engine = engine
37
38 @property
39 def format(self):
40 """The output format used for rendering (``'pdf'``, ``'png'``, ...)."""
41 return self._format
42
43 @format.setter
44 def format(self, format):
45 format = format.lower()
46 if format not in backend.FORMATS:
47 raise ValueError(f'unknown format: {format!r}')
48 self._format = format
49
50 @property
51 def encoding(self):
52 """The encoding for the saved source file."""
53 return self._encoding
54
55 @encoding.setter
56 def encoding(self, encoding):
57 if encoding is None:
58 encoding = locale.getpreferredencoding()
59 codecs.lookup(encoding) # raise early
60 self._encoding = encoding
61
62 def copy(self):
63 """Return a copied instance of the object.
64
65 Returns:
66 An independent copy of the current object.
67 """
68 kwargs = self._kwargs()
69 return self.__class__(**kwargs)
70
71 def _kwargs(self):
72 ns = self.__dict__
73 return {a[1:]: ns[a] for a in ('_format', '_engine', '_encoding')
74 if a in ns}
75
76
77 class File(Base):
78
79 directory = ''
80
81 _default_extension = 'gv'
82
83 def __init__(self, filename=None, directory=None,
84 format=None, engine=None, encoding=backend.ENCODING):
85 if filename is None:
86 name = getattr(self, 'name', None) or self.__class__.__name__
87 filename = f'{name}.{self._default_extension}'
88 self.filename = filename
89
90 if directory is not None:
91 self.directory = directory
92
93 if format is not None:
94 self.format = format
95
96 if engine is not None:
97 self.engine = engine
98
99 self.encoding = encoding
100
101 def _kwargs(self):
102 result = super()._kwargs()
103 result['filename'] = self.filename
104 if 'directory' in self.__dict__:
105 result['directory'] = self.directory
106 return result
107
108 def __str__(self):
109 """The DOT source code as string."""
110 return self.source
111
112 def unflatten(self, stagger=None, fanout=False, chain=None):
113 """Return a new :class:`.Source` instance with the source piped through the Graphviz *unflatten* preprocessor.
114
115 Args:
116 stagger (int): Stagger the minimum length of leaf edges between 1 and this small integer.
117 fanout (bool): Fanout nodes with indegree = outdegree = 1 when staggering (requires ``stagger``).
118 chain (int): Form disconnected nodes into chains of up to this many nodes.
119
120 Returns:
121 Source: Prepocessed DOT source code (improved layout aspect ratio).
122
123 Raises:
124 graphviz.RequiredArgumentError: If ``fanout`` is given but ``stagger`` is None.
125 graphviz.ExecutableNotFound: If the Graphviz unflatten executable is not found.
126 subprocess.CalledProcessError: If the exit status is non-zero.
127
128 See also:
129 https://www.graphviz.org/pdf/unflatten.1.pdf
130 """
131 out = backend.unflatten(self.source,
132 stagger=stagger, fanout=fanout, chain=chain,
133 encoding=self._encoding)
134 return Source(out,
135 filename=self.filename, directory=self.directory,
136 format=self._format, engine=self._engine,
137 encoding=self._encoding)
138
139 def _repr_svg_(self):
140 return self.pipe(format='svg').decode(self._encoding)
141
142 def pipe(self, format=None, renderer=None, formatter=None, quiet=False):
143 """Return the source piped through the Graphviz layout command.
144
145 Args:
146 format: The output format used for rendering (``'pdf'``, ``'png'``, etc.).
147 renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
148 formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
149 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
150
151 Returns:
152 Binary (encoded) stdout of the layout command.
153
154 Raises:
155 ValueError: If ``format``, ``renderer``, or ``formatter`` are not known.
156 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
157 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
158 subprocess.CalledProcessError: If the exit status is non-zero.
159 """
160 if format is None:
161 format = self._format
162
163 data = self.source.encode(self._encoding)
164
165 out = backend.pipe(self._engine, format, data,
166 renderer=renderer, formatter=formatter,
167 quiet=quiet)
168
169 return out
170
171 @property
172 def filepath(self):
173 return os.path.join(self.directory, self.filename)
174
175 def save(self, filename=None, directory=None):
176 """Save the DOT source to file. Ensure the file ends with a newline.
177
178 Args:
179 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
180 directory: (Sub)directory for source saving and rendering.
181
182 Returns:
183 The (possibly relative) path of the saved source file.
184 """
185 if filename is not None:
186 self.filename = filename
187 if directory is not None:
188 self.directory = directory
189
190 filepath = self.filepath
191 tools.mkdirs(filepath)
192
193 log.debug('write %d bytes to %r', len(self.source), filepath)
194 with open(filepath, 'w', encoding=self.encoding) as fd:
195 fd.write(self.source)
196 if not self.source.endswith('\n'):
197 fd.write('\n')
198
199 return filepath
200
201 def render(self, filename=None, directory=None, view=False, cleanup=False,
202 format=None, renderer=None, formatter=None,
203 quiet=False, quiet_view=False):
204 """Save the source to file and render with the Graphviz engine.
205
206 Args:
207 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
208 directory: (Sub)directory for source saving and rendering.
209 view (bool): Open the rendered result with the default application.
210 cleanup (bool): Delete the source file after rendering.
211 format: The output format used for rendering (``'pdf'``, ``'png'``, etc.).
212 renderer: The output renderer used for rendering (``'cairo'``, ``'gd'``, ...).
213 formatter: The output formatter used for rendering (``'cairo'``, ``'gd'``, ...).
214 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
215 quiet_view (bool): Suppress ``stderr`` output from the viewer process
216 (implies ``view=True``, ineffective on Windows).
217
218 Returns:
219 The (possibly relative) path of the rendered file.
220
221 Raises:
222 ValueError: If ``format``, ``renderer``, or ``formatter`` are not known.
223 graphviz.RequiredArgumentError: If ``formatter`` is given but ``renderer`` is None.
224 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
225 subprocess.CalledProcessError: If the exit status is non-zero.
226 RuntimeError: If viewer opening is requested but not supported.
227
228 The layout command is started from the directory of ``filepath``, so that
229 references to external files (e.g. ``[image=...]``) can be given as paths
230 relative to the DOT source file.
231 """
232 filepath = self.save(filename, directory)
233
234 if format is None:
235 format = self._format
236
237 rendered = backend.render(self._engine, format, filepath,
238 renderer=renderer, formatter=formatter,
239 quiet=quiet)
240
241 if cleanup:
242 log.debug('delete %r', filepath)
243 os.remove(filepath)
244
245 if quiet_view or view:
246 self._view(rendered, self._format, quiet_view)
247
248 return rendered
249
250 def view(self, filename=None, directory=None, cleanup=False,
251 quiet=False, quiet_view=False):
252 """Save the source to file, open the rendered result in a viewer.
253
254 Args:
255 filename: Filename for saving the source (defaults to ``name`` + ``'.gv'``)
256 directory: (Sub)directory for source saving and rendering.
257 cleanup (bool): Delete the source file after rendering.
258 quiet (bool): Suppress ``stderr`` output from the layout subprocess.
259 quiet_view (bool): Suppress ``stderr`` output from the viewer process
260 (ineffective on Windows).
261
262 Returns:
263 The (possibly relative) path of the rendered file.
264
265 Raises:
266 graphviz.ExecutableNotFound: If the Graphviz executable is not found.
267 subprocess.CalledProcessError: If the exit status is non-zero.
268 RuntimeError: If opening the viewer is not supported.
269
270 Short-cut method for calling :meth:`.render` with ``view=True``.
271
272 Note:
273 There is no option to wait for the application to close, and no way
274 to retrieve the application's exit status.
275 """
276 return self.render(filename=filename, directory=directory,
277 view=True, cleanup=cleanup,
278 quiet=quiet, quiet_view=quiet_view)
279
280 def _view(self, filepath, format, quiet):
281 """Start the right viewer based on file format and platform."""
282 methodnames = [
283 f'_view_{format}_{backend.PLATFORM}',
284 f'_view_{backend.PLATFORM}',
285 ]
286 for name in methodnames:
287 view_method = getattr(self, name, None)
288 if view_method is not None:
289 break
290 else:
291 raise RuntimeError(f'{self.__class__!r} has no built-in viewer'
292 f' support for {format!r}'
293 f' on {backend.PLATFORM!r} platform')
294 view_method(filepath, quiet=quiet)
295
296 _view_darwin = staticmethod(backend.view.darwin)
297 _view_freebsd = staticmethod(backend.view.freebsd)
298 _view_linux = staticmethod(backend.view.linux)
299 _view_windows = staticmethod(backend.view.windows)
300
301
302 class Source(File):
303 """Verbatim DOT source code string to be rendered by Graphviz.
304
305 Args:
306 source: The verbatim DOT source code string.
307 filename: Filename for saving the source (defaults to ``'Source.gv'``).
308 directory: (Sub)directory for source saving and rendering.
309 format: Rendering output format (``'pdf'``, ``'png'``, ...).
310 engine: Layout command used (``'dot'``, ``'neato'``, ...).
311 encoding: Encoding for saving the source.
312
313 Note:
314 All parameters except ``source`` are optional. All of them can be changed
315 under their corresponding attribute name after instance creation.
316 """
317
318 @classmethod
319 def from_file(cls, filename, directory=None,
320 format=None, engine=None, encoding=backend.ENCODING):
321 """Return an instance with the source string read from the given file.
322
323 Args:
324 filename: Filename for loading/saving the source.
325 directory: (Sub)directory for source loading/saving and rendering.
326 format: Rendering output format (``'pdf'``, ``'png'``, ...).
327 engine: Layout command used (``'dot'``, ``'neato'``, ...).
328 encoding: Encoding for loading/saving the source.
329 """
330 filepath = os.path.join(directory or '', filename)
331 if encoding is None:
332 encoding = locale.getpreferredencoding()
333 log.debug('read %r with encoding %r', filepath, encoding)
334 with open(filepath, encoding=encoding) as fd:
335 source = fd.read()
336 return cls(source, filename, directory, format, engine, encoding)
337
338 def __init__(self, source, filename=None, directory=None,
339 format=None, engine=None, encoding=backend.ENCODING):
340 super().__init__(filename, directory, format, engine, encoding)
341 self.source = source #: The verbatim DOT source code string.
342
343 def _kwargs(self):
344 result = super()._kwargs()
345 result['source'] = self.source
346 return result
0 # lang.py - dot language creation helpers
1
2 """Quote strings to be valid DOT identifiers, assemble attribute lists."""
3
4 import re
5 import collections
6 import functools
7
8 from . import _compat
9
10 from . import tools
11
12 __all__ = ['quote', 'quote_edge', 'a_list', 'attr_list', 'escape', 'nohtml']
13
14 # https://www.graphviz.org/doc/info/lang.html
15 # https://www.graphviz.org/doc/info/attrs.html#k:escString
16
17 HTML_STRING = re.compile(r'<.*>$', re.DOTALL)
18
19 ID = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*|-?(\.[0-9]+|[0-9]+(\.[0-9]*)?))$')
20
21 KEYWORDS = {'node', 'edge', 'graph', 'digraph', 'subgraph', 'strict'}
22
23 COMPASS = {'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'c', '_'} # TODO
24
25 QUOTE_OPTIONAL_BACKSLASHES = re.compile(r'(?P<bs>(?:\\\\)*)'
26 r'\\?(?P<quote>")')
27
28 ESCAPE_UNESCAPED_QUOTES = functools.partial(QUOTE_OPTIONAL_BACKSLASHES.sub,
29 r'\g<bs>\\\g<quote>')
30
31
32 def quote(identifier,
33 is_html_string=HTML_STRING.match,
34 is_valid_id=ID.match, dot_keywords=KEYWORDS,
35 escape_unescaped_quotes=ESCAPE_UNESCAPED_QUOTES):
36 r"""Return DOT identifier from string, quote if needed.
37
38 >>> quote('')
39 '""'
40
41 >>> quote('spam')
42 'spam'
43
44 >>> quote('spam spam')
45 '"spam spam"'
46
47 >>> quote('-4.2')
48 '-4.2'
49
50 >>> quote('.42')
51 '.42'
52
53 >>> quote('<<b>spam</b>>')
54 '<<b>spam</b>>'
55
56 >>> quote(nohtml('<>'))
57 '"<>"'
58
59 >>> print(quote('"'))
60 "\""
61
62 >>> print(quote('\\"'))
63 "\""
64
65 >>> print(quote('\\\\"'))
66 "\\\""
67
68 >>> print(quote('\\\\\\"'))
69 "\\\""
70 """
71 if is_html_string(identifier) and not isinstance(identifier, NoHtml):
72 pass
73 elif not is_valid_id(identifier) or identifier.lower() in dot_keywords:
74 return '"%s"' % escape_unescaped_quotes(identifier)
75 return identifier
76
77
78 def quote_edge(identifier):
79 """Return DOT edge statement node_id from string, quote if needed.
80
81 >>> quote_edge('spam')
82 'spam'
83
84 >>> quote_edge('spam spam:eggs eggs')
85 '"spam spam":"eggs eggs"'
86
87 >>> quote_edge('spam:eggs:s')
88 'spam:eggs:s'
89 """
90 node, _, rest = identifier.partition(':')
91 parts = [quote(node)]
92 if rest:
93 port, _, compass = rest.partition(':')
94 parts.append(quote(port))
95 if compass:
96 parts.append(compass)
97 return ':'.join(parts)
98
99
100 def a_list(label=None, kwargs=None, attributes=None):
101 """Return assembled DOT a_list string.
102
103 >>> a_list('spam', {'spam': None, 'ham': 'ham ham', 'eggs': ''})
104 'label=spam eggs="" ham="ham ham"'
105 """
106 result = ['label=%s' % quote(label)] if label is not None else []
107 if kwargs:
108 items = ['%s=%s' % (quote(k), quote(v))
109 for k, v in tools.mapping_items(kwargs) if v is not None]
110 result.extend(items)
111 if attributes:
112 if hasattr(attributes, 'items'):
113 attributes = tools.mapping_items(attributes)
114 items = ['%s=%s' % (quote(k), quote(v))
115 for k, v in attributes if v is not None]
116 result.extend(items)
117 return ' '.join(result)
118
119
120 def attr_list(label=None, kwargs=None, attributes=None):
121 """Return assembled DOT attribute list string.
122
123 Sorts ``kwargs`` and ``attributes`` if they are plain dicts (to avoid
124 unpredictable order from hash randomization in Python 3 versions).
125
126 >>> attr_list()
127 ''
128
129 >>> attr_list('spam spam', kwargs={'eggs': 'eggs', 'ham': 'ham ham'})
130 ' [label="spam spam" eggs=eggs ham="ham ham"]'
131
132 >>> attr_list(kwargs={'spam': None, 'eggs': ''})
133 ' [eggs=""]'
134 """
135 content = a_list(label, kwargs, attributes)
136 if not content:
137 return ''
138 return ' [%s]' % content
139
140
141 def escape(s):
142 r"""Return ``s`` as literal disabling special meaning of backslashes and ``'<...>'``.
143
144 see also https://www.graphviz.org/doc/info/attrs.html#k:escString
145
146 Args:
147 s: String in which backslashes and ``'<...>'`` should be treated as literal.
148 Raises:
149 TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2.
150
151 >>> print(escape(r'\l'))
152 \\l
153 """
154 return nohtml(s.replace('\\', '\\\\'))
155
156
157 class NoHtml(object):
158 """Mixin for string subclasses disabling fall-through of ``'<...>'``."""
159
160 __slots__ = ()
161
162 _doc = "%s subclass that does not treat ``'<...>'`` as DOT HTML string."
163
164 @classmethod
165 def _subcls(cls, other):
166 name = '%s_%s' % (cls.__name__, other.__name__)
167 bases = (other, cls)
168 ns = {'__doc__': cls._doc % other.__name__}
169 return type(name, bases, ns)
170
171
172 NOHTML = collections.OrderedDict((c, NoHtml._subcls(c)) for c in _compat.string_classes)
173
174
175 def nohtml(s):
176 """Return copy of ``s`` that will not treat ``'<...>'`` as DOT HTML string in quoting.
177
178 Args:
179 s: String in which leading ``'<'`` and trailing ``'>'`` should be treated as literal.
180 Raises:
181 TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2.
182
183 >>> quote('<>-*-<>')
184 '<>-*-<>'
185
186 >>> quote(nohtml('<>-*-<>'))
187 '"<>-*-<>"'
188 """
189 try:
190 subcls = NOHTML[type(s)]
191 except KeyError:
192 raise TypeError('%r does not have one of the required types:'
193 ' %r' % (s, list(NOHTML)))
194 return subcls(s)
0 # lang.py - dot language creation helpers
1
2 """Quote strings to be valid DOT identifiers, assemble attribute lists."""
3
4 import functools
5 import re
6 import typing
7
8 from . import tools
9
10 __all__ = ['quote', 'quote_edge',
11 'a_list', 'attr_list',
12 'escape', 'nohtml']
13
14 # https://www.graphviz.org/doc/info/lang.html
15 # https://www.graphviz.org/doc/info/attrs.html#k:escString
16
17 HTML_STRING = re.compile(r'<.*>$', re.DOTALL)
18
19 ID = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*|-?(\.[0-9]+|[0-9]+(\.[0-9]*)?))$')
20
21 KEYWORDS = {'node', 'edge', 'graph', 'digraph', 'subgraph', 'strict'}
22
23 COMPASS = {'n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw', 'c', '_'} # TODO
24
25 QUOTE_OPTIONAL_BACKSLASHES = re.compile(r'(?P<bs>(?:\\\\)*)'
26 r'\\?(?P<quote>")')
27
28 ESCAPE_UNESCAPED_QUOTES = functools.partial(QUOTE_OPTIONAL_BACKSLASHES.sub,
29 r'\g<bs>\\\g<quote>')
30
31
32 def quote(identifier: str,
33 is_html_string=HTML_STRING.match,
34 is_valid_id=ID.match,
35 dot_keywords=KEYWORDS,
36 escape_unescaped_quotes=ESCAPE_UNESCAPED_QUOTES) -> str:
37 r"""Return DOT identifier from string, quote if needed.
38
39 >>> quote('')
40 '""'
41
42 >>> quote('spam')
43 'spam'
44
45 >>> quote('spam spam')
46 '"spam spam"'
47
48 >>> quote('-4.2')
49 '-4.2'
50
51 >>> quote('.42')
52 '.42'
53
54 >>> quote('<<b>spam</b>>')
55 '<<b>spam</b>>'
56
57 >>> quote(nohtml('<>'))
58 '"<>"'
59
60 >>> print(quote('"'))
61 "\""
62
63 >>> print(quote('\\"'))
64 "\""
65
66 >>> print(quote('\\\\"'))
67 "\\\""
68
69 >>> print(quote('\\\\\\"'))
70 "\\\""
71 """
72 if is_html_string(identifier) and not isinstance(identifier, NoHtml):
73 pass
74 elif not is_valid_id(identifier) or identifier.lower() in dot_keywords:
75 return f'"{escape_unescaped_quotes(identifier)}"'
76 return identifier
77
78
79 def quote_edge(identifier: str) -> str:
80 """Return DOT edge statement node_id from string, quote if needed.
81
82 >>> quote_edge('spam')
83 'spam'
84
85 >>> quote_edge('spam spam:eggs eggs')
86 '"spam spam":"eggs eggs"'
87
88 >>> quote_edge('spam:eggs:s')
89 'spam:eggs:s'
90 """
91 node, _, rest = identifier.partition(':')
92 parts = [quote(node)]
93 if rest:
94 port, _, compass = rest.partition(':')
95 parts.append(quote(port))
96 if compass:
97 parts.append(compass)
98 return ':'.join(parts)
99
100
101 def a_list(label: typing.Optional[str] = None,
102 kwargs=None, attributes=None) -> str:
103 """Return assembled DOT a_list string.
104
105 >>> a_list('spam', {'spam': None, 'ham': 'ham ham', 'eggs': ''})
106 'label=spam eggs="" ham="ham ham"'
107 """
108 result = [f'label={quote(label)}'] if label is not None else []
109 if kwargs:
110 items = [f'{quote(k)}={quote(v)}'
111 for k, v in tools.mapping_items(kwargs) if v is not None]
112 result.extend(items)
113 if attributes:
114 if hasattr(attributes, 'items'):
115 attributes = tools.mapping_items(attributes)
116 items = [f'{quote(k)}={quote(v)}'
117 for k, v in attributes if v is not None]
118 result.extend(items)
119 return ' '.join(result)
120
121
122 def attr_list(label: typing.Optional[str] = None,
123 kwargs=None, attributes=None) -> str:
124 """Return assembled DOT attribute list string.
125
126 Sorts ``kwargs`` and ``attributes`` if they are plain dicts (to avoid
127 unpredictable order from hash randomization in Python 3 versions).
128
129 >>> attr_list()
130 ''
131
132 >>> attr_list('spam spam', kwargs={'eggs': 'eggs', 'ham': 'ham ham'})
133 ' [label="spam spam" eggs=eggs ham="ham ham"]'
134
135 >>> attr_list(kwargs={'spam': None, 'eggs': ''})
136 ' [eggs=""]'
137 """
138 content = a_list(label, kwargs, attributes)
139 if not content:
140 return ''
141 return f' [{content}]'
142
143
144 def escape(s: str) -> 'NoHtml':
145 r"""Return ``s`` as literal disabling special meaning of backslashes and ``'<...>'``.
146
147 see also https://www.graphviz.org/doc/info/attrs.html#k:escString
148
149 Args:
150 s: String in which backslashes and ``'<...>'`` should be treated as literal.
151
152 Returns:
153 Escaped string subclass instance.
154
155 Raises:
156 TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2.
157
158 Example:
159 >>> import graphviz
160 >>> print(graphviz.escape(r'\l'))
161 \\l
162 """
163 return nohtml(s.replace('\\', '\\\\'))
164
165
166 class NoHtml(str):
167 """String subclass that does not treat ``'<...>'`` as DOT HTML string."""
168
169 __slots__ = ()
170
171
172 def nohtml(s: str) -> NoHtml:
173 """Return copy of ``s`` that will not treat ``'<...>'`` as DOT HTML string in quoting.
174
175 Args:
176 s: String in which leading ``'<'`` and trailing ``'>'`` should be treated as literal.
177
178 Returns:
179 String subclass instance.
180
181 Raises:
182 TypeError: If ``s`` is not a ``str`` on Python 3, or a ``str``/``unicode`` on Python 2.
183
184 Example:
185 >>> import graphviz
186 >>> g = graphviz.Graph()
187 >>> g.node(graphviz.nohtml('<>-*-<>'))
188 >>> print(g.source) # doctest: +NORMALIZE_WHITESPACE
189 graph {
190 "<>-*-<>"
191 }
192 """
193 return NoHtml(s)
0 # tools.py - generic helpers
1
2 import os
3
4 from . import _compat
5
6 __all__ = ['attach', 'mkdirs', 'mapping_items']
7
8
9 def attach(object, name):
10 """Return a decorator doing ``setattr(object, name)`` with its argument.
11
12 >>> spam = type('Spam', (object,), {})()
13 >>> @attach(spam, 'eggs')
14 ... def func():
15 ... pass
16 >>> spam.eggs # doctest: +ELLIPSIS
17 <function func at 0x...>
18 """
19 def decorator(func):
20 setattr(object, name, func)
21 return func
22 return decorator
23
24
25 def mkdirs(filename, mode=0o777):
26 """Recursively create directories up to the path of ``filename`` as needed."""
27 dirname = os.path.dirname(filename)
28 if not dirname:
29 return
30 _compat.makedirs(dirname, mode=mode, exist_ok=True)
31
32
33 def mapping_items(mapping):
34 """Return an iterator over the ``mapping`` items, sort if it's a plain dict.
35
36 >>> list(mapping_items({'spam': 0, 'ham': 1, 'eggs': 2}))
37 [('eggs', 2), ('ham', 1), ('spam', 0)]
38
39 >>> from collections import OrderedDict
40 >>> list(mapping_items(OrderedDict(enumerate(['spam', 'ham', 'eggs']))))
41 [(0, 'spam'), (1, 'ham'), (2, 'eggs')]
42 """
43 result = _compat.iteritems(mapping)
44 if type(mapping) is dict:
45 result = iter(sorted(result))
46 return result
0 """Generic re-useable self-contained helper functions."""
1
2 import os
3 import typing
4
5 __all__ = ['attach',
6 'mkdirs',
7 'mapping_items']
8
9
10 def attach(object: typing.Any, name: str) -> typing.Callable:
11 """Return a decorator doing ``setattr(object, name)`` with its argument.
12
13 >>> spam = type('Spam', (object,), {})()
14
15 >>> @attach(spam, 'eggs')
16 ... def func():
17 ... pass
18
19 >>> spam.eggs # doctest: +ELLIPSIS
20 <function func at 0x...>
21 """
22 def decorator(func):
23 setattr(object, name, func)
24 return func
25 return decorator
26
27
28 def mkdirs(filename, mode: int = 0o777) -> None:
29 """Recursively create directories up to the path of ``filename`` as needed."""
30 dirname = os.path.dirname(filename)
31 if not dirname:
32 return
33 os.makedirs(dirname, mode=mode, exist_ok=True)
34
35
36 def mapping_items(mapping):
37 """Return an iterator over the ``mapping`` items, sort if it's a plain dict.
38
39 >>> list(mapping_items({'spam': 0, 'ham': 1, 'eggs': 2}))
40 [('eggs', 2), ('ham', 1), ('spam', 0)]
41
42 >>> from collections import OrderedDict
43 >>> list(mapping_items(OrderedDict(enumerate(['spam', 'ham', 'eggs']))))
44 [(0, 'spam'), (1, 'ham'), (2, 'eggs')]
45 """
46 result = iter(mapping.items())
47 if type(mapping) is dict:
48 result = iter(sorted(result))
49 return result
0 Metadata-Version: 2.1
1 Name: graphviz
2 Version: 0.14.2
3 Summary: Simple Python interface for Graphviz
4 Home-page: https://github.com/xflr6/graphviz
5 Author: Sebastian Bank
6 Author-email: sebastian.bank@uni-leipzig.de
7 License: MIT
8 Project-URL: Documentation, https://graphviz.readthedocs.io
9 Project-URL: Changelog, https://graphviz.readthedocs.io/en/latest/changelog.html
10 Project-URL: Issue Tracker, https://github.com/xflr6/graphviz/issues
11 Description: Graphviz
12 ========
13
14 |PyPI version| |License| |Supported Python| |Format|
15
16 |Travis| |Codecov| |Readthedocs-stable| |Readthedocs-latest|
17
18 This package facilitates the creation and rendering of graph descriptions in
19 the DOT_ language of the Graphviz_ graph drawing software (`master repo`_) from
20 Python.
21
22 Create a graph object, assemble the graph by adding nodes and edges, and
23 retrieve its DOT source code string. Save the source code to a file and render
24 it with the Graphviz installation of your system.
25
26 Use the ``view`` option/method to directly inspect the resulting (PDF, PNG,
27 SVG, etc.) file with its default application. Graphs can also be rendered
28 and displayed within `Jupyter notebooks`_ (formerly known as
29 `IPython notebooks`_, example_) as well as the `Jupyter Qt Console`_.
30
31
32 Links
33 -----
34
35 - GitHub: https://github.com/xflr6/graphviz
36 - PyPI: https://pypi.org/project/graphviz/
37 - Documentation: https://graphviz.readthedocs.io
38 - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html
39 - Issue Tracker: https://github.com/xflr6/graphviz/issues
40 - Download: https://pypi.org/project/graphviz/#files
41
42
43 Installation
44 ------------
45
46 This package runs under Python 2.7, and 3.5+, use pip_ to install:
47
48 .. code:: bash
49
50 $ pip install graphviz
51
52 To render the generated DOT source code, you also need to install Graphviz
53 (`download page`_).
54
55 Make sure that the directory containing the ``dot`` executable is on your
56 systems' path.
57
58
59 Quickstart
60 ----------
61
62 Create a graph object:
63
64 .. code:: python
65
66 >>> from graphviz import Digraph
67
68 >>> dot = Digraph(comment='The Round Table')
69
70 >>> dot #doctest: +ELLIPSIS
71 <graphviz.dot.Digraph object at 0x...>
72
73 Add nodes and edges:
74
75 .. code:: python
76
77 >>> dot.node('A', 'King Arthur')
78 >>> dot.node('B', 'Sir Bedevere the Wise')
79 >>> dot.node('L', 'Sir Lancelot the Brave')
80
81 >>> dot.edges(['AB', 'AL'])
82 >>> dot.edge('B', 'L', constraint='false')
83
84 Check the generated source code:
85
86 .. code:: python
87
88 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
89 // The Round Table
90 digraph {
91 A [label="King Arthur"]
92 B [label="Sir Bedevere the Wise"]
93 L [label="Sir Lancelot the Brave"]
94 A -> B
95 A -> L
96 B -> L [constraint=false]
97 }
98
99 Save and render the source code, optionally view the result:
100
101 .. code:: python
102
103 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
104 'test-output/round-table.gv.pdf'
105
106 .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png
107 :align: center
108
109
110 See also
111 --------
112
113 - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG
114 - graphviz-python_ |--| official Python bindings (documentation_)
115 - pydot_ |--| stable pure-Python approach, requires pyparsing
116
117
118 License
119 -------
120
121 This package is distributed under the `MIT license`_.
122
123
124 .. _pip: https://pip.readthedocs.io
125 .. _Graphviz: https://www.graphviz.org
126 .. _master repo: https://gitlab.com/graphviz/graphviz/
127 .. _download page: https://www.graphviz.org/download/
128 .. _DOT: https://www.graphviz.org/doc/info/lang.html
129 .. _Jupyter notebooks: https://jupyter.org
130 .. _IPython notebooks: https://ipython.org/notebook.html
131 .. _example: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/notebook.ipynb
132 .. _Jupyter Qt Console: https://qtconsole.readthedocs.io
133
134 .. _pygraphviz: https://pypi.org/project/pygraphviz/
135 .. _graphviz-python: https://pypi.org/project/graphviz-python/
136 .. _documentation: https://www.graphviz.org/pdf/gv.3python.pdf
137 .. _pydot: https://pypi.org/project/pydot/
138
139 .. _MIT license: https://opensource.org/licenses/MIT
140
141
142 .. |--| unicode:: U+2013
143
144
145 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg
146 :target: https://pypi.org/project/graphviz/
147 :alt: Latest PyPI Version
148 .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg
149 :target: https://pypi.org/project/graphviz/
150 :alt: License
151 .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg
152 :target: https://pypi.org/project/graphviz/
153 :alt: Supported Python Versions
154 .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg
155 :target: https://pypi.org/project/graphviz/
156 :alt: Format
157
158 .. |Travis| image:: https://travis-ci.org/xflr6/graphviz.svg?branch=master
159 :target: https://travis-ci.org/xflr6/graphviz
160 :alt: Travis
161 .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg
162 :target: https://codecov.io/gh/xflr6/graphviz
163 :alt: Codecov
164 .. |Readthedocs-stable| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable
165 :target: https://graphviz.readthedocs.io/en/stable/?badge=stable
166 :alt: Readthedocs stable
167 .. |Readthedocs-latest| image:: https://readthedocs.org/projects/graphviz/badge/?version=latest
168 :target: https://graphviz.readthedocs.io/en/latest/?badge=latest
169 :alt: Readthedocs latest
170 Keywords: graph visualization dot render
171 Platform: any
172 Classifier: Development Status :: 4 - Beta
173 Classifier: Intended Audience :: Developers
174 Classifier: Intended Audience :: Science/Research
175 Classifier: License :: OSI Approved :: MIT License
176 Classifier: Operating System :: OS Independent
177 Classifier: Programming Language :: Python :: 2
178 Classifier: Programming Language :: Python :: 2.7
179 Classifier: Programming Language :: Python :: 3
180 Classifier: Programming Language :: Python :: 3.5
181 Classifier: Programming Language :: Python :: 3.6
182 Classifier: Programming Language :: Python :: 3.7
183 Classifier: Programming Language :: Python :: 3.8
184 Classifier: Topic :: Scientific/Engineering :: Visualization
185 Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*
186 Provides-Extra: dev
187 Provides-Extra: test
188 Provides-Extra: docs
0 Metadata-Version: 2.1
1 Name: graphviz
2 Version: 0.17.dev0
3 Summary: Simple Python interface for Graphviz
4 Home-page: https://github.com/xflr6/graphviz
5 Author: Sebastian Bank
6 Author-email: sebastian.bank@uni-leipzig.de
7 License: MIT
8 Project-URL: Documentation, https://graphviz.readthedocs.io
9 Project-URL: Changelog, https://graphviz.readthedocs.io/en/latest/changelog.html
10 Project-URL: Issue Tracker, https://github.com/xflr6/graphviz/issues
11 Project-URL: CI, https://travis-ci.org/xflr6/graphviz
12 Project-URL: Coverage, https://codecov.io/gh/xflr6/graphviz
13 Description: Graphviz
14 ========
15
16 |PyPI version| |License| |Supported Python| |Format|
17
18 |Travis| |Codecov| |Readthedocs-stable| |Readthedocs-latest|
19
20 This package facilitates the creation and rendering of graph descriptions in
21 the DOT_ language of the Graphviz_ graph drawing software (`upstream repo`_)
22 from Python.
23
24 Create a graph object, assemble the graph by adding nodes and edges, and
25 retrieve its DOT source code string. Save the source code to a file and render
26 it with the Graphviz installation of your system.
27
28 Use the ``view`` option/method to directly inspect the resulting (PDF, PNG,
29 SVG, etc.) file with its default application. Graphs can also be rendered
30 and displayed within `Jupyter notebooks`_ (formerly known as
31 `IPython notebooks`_,
32 `example <notebook_>`_, `nbviewer <notebook-nbviewer_>`_)
33 as well as the `Jupyter QtConsole`_.
34
35
36 Links
37 -----
38
39 - GitHub: https://github.com/xflr6/graphviz
40 - PyPI: https://pypi.org/project/graphviz/
41 - Documentation: https://graphviz.readthedocs.io
42 - Changelog: https://graphviz.readthedocs.io/en/latest/changelog.html
43 - Issue Tracker: https://github.com/xflr6/graphviz/issues
44 - Download: https://pypi.org/project/graphviz/#files
45
46
47 Installation
48 ------------
49
50 This package runs under Python 3.6+, use pip_ to install:
51
52 .. code:: bash
53
54 $ pip install graphviz
55
56 To render the generated DOT source code, you also need to install Graphviz_
57 (`download page <upstream-download_>`_,
58 `archived versions <upstream-archived_>`_,
59 `installation procedure for Windows <upstream-windows_>`_).
60
61 Make sure that the directory containing the ``dot`` executable is on your
62 systems' path.
63
64 Anaconda_: see the conda-forge_ package
65 `conda-forge/python-graphviz <conda-forge-python-graphviz_>`_
66 (`feedstock <conda-forge-python-graphviz-feedstock_>`_),
67 which should automatically ``conda install``
68 `conda-forge/graphviz <conda-forge-graphviz_>`_
69 (`feedstock <conda-forge-graphviz-feedstock_>`_) as dependency.
70
71
72 Quickstart
73 ----------
74
75 Create a graph object:
76
77 .. code:: python
78
79 >>> import graphviz
80 >>> dot = graphviz.Digraph(comment='The Round Table')
81 >>> dot #doctest: +ELLIPSIS
82 <graphviz.dot.Digraph object at 0x...>
83
84 Add nodes and edges:
85
86 .. code:: python
87
88 >>> dot.node('A', 'King Arthur')
89 >>> dot.node('B', 'Sir Bedevere the Wise')
90 >>> dot.node('L', 'Sir Lancelot the Brave')
91
92 >>> dot.edges(['AB', 'AL'])
93 >>> dot.edge('B', 'L', constraint='false')
94
95 Check the generated source code:
96
97 .. code:: python
98
99 >>> print(dot.source) # doctest: +NORMALIZE_WHITESPACE
100 // The Round Table
101 digraph {
102 A [label="King Arthur"]
103 B [label="Sir Bedevere the Wise"]
104 L [label="Sir Lancelot the Brave"]
105 A -> B
106 A -> L
107 B -> L [constraint=false]
108 }
109
110 Save and render the source code, optionally view the result:
111
112 .. code:: python
113
114 >>> dot.render('test-output/round-table.gv', view=True) # doctest: +SKIP
115 'test-output/round-table.gv.pdf'
116
117 .. image:: https://raw.github.com/xflr6/graphviz/master/docs/round-table.png
118 :align: center
119
120
121 See also
122 --------
123
124 - pygraphviz_ |--| full-blown interface wrapping the Graphviz C library with SWIG
125 - graphviz-python_ |--| official Python bindings
126 (`documentation <graphviz-python-docs_>`_)
127 - pydot_ |--| stable pure-Python approach, requires pyparsing
128
129
130 License
131 -------
132
133 This package is distributed under the `MIT license`_.
134
135
136 .. _Graphviz: https://www.graphviz.org
137 .. _DOT: https://www.graphviz.org/doc/info/lang.html
138 .. _upstream repo: https://gitlab.com/graphviz/graphviz/
139 .. _upstream-download: https://www.graphviz.org/download/
140 .. _upstream-archived: https://www2.graphviz.org/Archive/stable/
141 .. _upstream-windows: https://forum.graphviz.org/t/new-simplified-installation-procedure-on-windows/224
142
143 .. _pip: https://pip.readthedocs.io
144
145 .. _Jupyter notebooks: https://jupyter.org
146 .. _IPython notebooks: https://ipython.org/notebook.html
147 .. _Jupyter QtConsole: https://qtconsole.readthedocs.io
148
149 .. _notebook: https://github.com/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
150 .. _notebook-nbviewer: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-notebook.ipynb
151
152 .. _Anaconda: https://docs.anaconda.com/anaconda/install/
153 .. _conda-forge: https://conda-forge.org
154 .. _conda-forge-python-graphviz: https://anaconda.org/conda-forge/python-graphviz
155 .. _conda-forge-python-graphviz-feedstock: https://github.com/conda-forge/python-graphviz-feedstock
156 .. _conda-forge-graphviz: https://anaconda.org/conda-forge/graphviz
157 .. _conda-forge-graphviz-feedstock: https://github.com/conda-forge/graphviz-feedstock
158
159 .. _pygraphviz: https://pypi.org/project/pygraphviz/
160 .. _graphviz-python: https://pypi.org/project/graphviz-python/
161 .. _graphviz-python-docs: https://www.graphviz.org/pdf/gv.3python.pdf
162 .. _pydot: https://pypi.org/project/pydot/
163
164 .. _MIT license: https://opensource.org/licenses/MIT
165
166
167 .. |--| unicode:: U+2013
168
169
170 .. |PyPI version| image:: https://img.shields.io/pypi/v/graphviz.svg
171 :target: https://pypi.org/project/graphviz/
172 :alt: Latest PyPI Version
173 .. |License| image:: https://img.shields.io/pypi/l/graphviz.svg
174 :target: https://pypi.org/project/graphviz/
175 :alt: License
176 .. |Supported Python| image:: https://img.shields.io/pypi/pyversions/graphviz.svg
177 :target: https://pypi.org/project/graphviz/
178 :alt: Supported Python Versions
179 .. |Format| image:: https://img.shields.io/pypi/format/graphviz.svg
180 :target: https://pypi.org/project/graphviz/
181 :alt: Format
182
183 .. |Travis| image:: https://travis-ci.org/xflr6/graphviz.svg?branch=master
184 :target: https://travis-ci.org/xflr6/graphviz
185 :alt: Travis
186 .. |Codecov| image:: https://codecov.io/gh/xflr6/graphviz/branch/master/graph/badge.svg
187 :target: https://codecov.io/gh/xflr6/graphviz
188 :alt: Codecov
189 .. |Readthedocs-stable| image:: https://readthedocs.org/projects/graphviz/badge/?version=stable
190 :target: https://graphviz.readthedocs.io/en/stable/?badge=stable
191 :alt: Readthedocs stable
192 .. |Readthedocs-latest| image:: https://readthedocs.org/projects/graphviz/badge/?version=latest
193 :target: https://graphviz.readthedocs.io/en/latest/?badge=latest
194 :alt: Readthedocs latest
195 Keywords: graph visualization dot render
196 Platform: any
197 Classifier: Development Status :: 4 - Beta
198 Classifier: Intended Audience :: Developers
199 Classifier: Intended Audience :: Science/Research
200 Classifier: License :: OSI Approved :: MIT License
201 Classifier: Operating System :: OS Independent
202 Classifier: Programming Language :: Python :: 3
203 Classifier: Programming Language :: Python :: 3.6
204 Classifier: Programming Language :: Python :: 3.7
205 Classifier: Programming Language :: Python :: 3.8
206 Classifier: Programming Language :: Python :: 3.9
207 Classifier: Topic :: Scientific/Engineering :: Visualization
208 Requires-Python: >=3.6
209 Provides-Extra: dev
210 Provides-Extra: docs
211 Provides-Extra: test
1515 docs/license.rst
1616 docs/manual.rst
1717 docs/notebooks.rst
18 docs/pet-shop.png
1918 docs/round-table.png
2019 docs/_static/angles.svg
2120 docs/_static/btree.svg
4140 docs/_static/structs_revisited.svg
4241 docs/_static/traffic_lights.svg
4342 docs/_static/unix.svg
43 docs/_static/wide-unflatten-stagger-2.svg
44 docs/_static/wide-unflatten-stagger-3.svg
45 docs/_static/wide.svg
4446 examples/angles.py
4547 examples/btree.py
4648 examples/cluster.py
5153 examples/g_c_n.py
5254 examples/graphviz-engines.ipynb
5355 examples/graphviz-escapes.ipynb
56 examples/graphviz-notebook.ipynb
5457 examples/hello.py
5558 examples/notebook.ipynb
5659 examples/process.py
6063 examples/traffic_lights.py
6164 examples/unix.py
6265 graphviz/__init__.py
63 graphviz/_compat.py
6466 graphviz/backend.py
6567 graphviz/dot.py
6668 graphviz/files.py
7274 graphviz.egg-info/requires.txt
7375 graphviz.egg-info/top_level.txt
7476 tests/conftest.py
75 tests/dot_red.png
7677 tests/test_backend.py
7778 tests/test_dot.py
7879 tests/test_files.py
7980 tests/test_lang.py
80 tests/test_tools.py
81 tests/test_tools.py
82 tests/utils.py
83 tests/files/dot_red.png
00
11 [dev]
2 tox>=3
32 flake8
43 pep8-naming
4 tox>=3
5 twine
56 wheel
6 twine
77
88 [docs]
9 sphinx-autodoc-typehints
10 sphinx-rtd-theme
911 sphinx>=1.8
10 sphinx-rtd-theme
1112
1213 [test]
1314 mock>=3
14 pytest>=4
15 pytest-cov
1516 pytest-mock>=2
16 pytest-cov
17 pytest>=5.2
0 # development environment: install in development mode
1 -e .[dev,test,docs]
0 # development environment: install in development mode
1 -e .[dev,test,docs]
0 #!/usr/bin/env python
1
2 import platform
3 import sys
4
5 import pytest
6
7 ARGS = [
8 #'--pdb',
9 #'--exitfirst',
10 ]
11
12 if platform.system() == 'Windows':
13 if 'idlelib' in sys.modules:
14 ARGS.extend(['--capture=sys', '--color=no'])
15 elif sys.version_info.major == 2 and 'win_unicode_console' in sys.modules:
16 ARGS.append('--capture=sys')
17
18 sys.exit(pytest.main(ARGS + sys.argv[1:]))
0 #!/usr/bin/env python3
1
2 import platform
3 import sys
4
5 import pytest
6
7 ARGS = [#'--skip-exe',
8 #'--collect-only',
9 #'--verbose',
10 #'--pdb',
11 #'--exitfirst', # a.k.a. -x
12 #'-W', 'error',
13 ]
14
15 if platform.system() == 'Windows':
16 if 'idlelib' in sys.modules:
17 ARGS += ['--capture=sys', '--color=no']
18
19 args = sys.argv[1:] + ARGS
20
21 print(f'pytest.main({args!r})')
22 sys.exit(pytest.main(args))
0 [metadata]
1 license_file = LICENSE.txt
2
3 [sdist]
4 formats = zip
5
6 [bdist_wheel]
7 universal = 1
8
9 [tool:pytest]
10 minversion = 4
11 testpaths = README.rst docs graphviz tests
12 addopts =
13 --doctest-modules --doctest-glob='*.rst' --ignore=docs/conf.py
14 --cov --cov-report=term --cov-report=html
15 mock_use_standalone_module = true
16 log_cli = false
17 log_cli_level = DEBUG
18 log_file = test-log.txt
19 log_file_level = DEBUG
20
21 [coverage:run]
22 source = graphviz
23 branch = false
24
25 [flake8]
26 ignore = E126,E128
27 max-line-length = 100
28 exclude = docs, .tox
29
30 [egg_info]
31 tag_build =
32 tag_date = 0
33
0 [metadata]
1 license_file = LICENSE.txt
2
3 [sdist]
4 formats = zip
5
6 [tool:pytest]
7 minversion = 5.2
8 testpaths = README.rst docs graphviz tests
9 addopts =
10 --doctest-modules
11 --doctest-glob='*.rst' --ignore=docs/conf.py
12 --cov --cov-report=term --cov-report=html
13 --strict-markers
14 mock_use_standalone_module = true
15 log_cli = false
16 log_cli_level = DEBUG
17 log_file = test-log.txt
18 log_file_level = DEBUG
19
20 [coverage:run]
21 source = graphviz
22 branch = false
23
24 [flake8]
25 ignore = E126,E128
26 max-line-length = 100
27 exclude = docs, .tox
28
29 [egg_info]
30 tag_build =
31 tag_date = 0
32
0 # setup.py
1
2 import io
3 from setuptools import setup, find_packages
4
5 setup(
6 name='graphviz',
7 version='0.14.2',
8 author='Sebastian Bank',
9 author_email='sebastian.bank@uni-leipzig.de',
10 description='Simple Python interface for Graphviz',
11 keywords='graph visualization dot render',
12 license='MIT',
13 url='https://github.com/xflr6/graphviz',
14 project_urls={
15 'Documentation': 'https://graphviz.readthedocs.io',
16 'Changelog': 'https://graphviz.readthedocs.io/en/latest/changelog.html',
17 'Issue Tracker': 'https://github.com/xflr6/graphviz/issues',
18 },
19 packages=find_packages(),
20 platforms='any',
21 python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*',
22 extras_require={
23 'dev': ['tox>=3', 'flake8', 'pep8-naming', 'wheel', 'twine'],
24 'test': ['mock>=3', 'pytest>=4', 'pytest-mock>=2', 'pytest-cov'],
25 'docs': ['sphinx>=1.8', 'sphinx-rtd-theme'],
26 },
27 long_description=io.open('README.rst', encoding='utf-8').read(),
28 classifiers=[
29 'Development Status :: 4 - Beta',
30 'Intended Audience :: Developers',
31 'Intended Audience :: Science/Research',
32 'License :: OSI Approved :: MIT License',
33 'Operating System :: OS Independent',
34 'Programming Language :: Python :: 2',
35 'Programming Language :: Python :: 2.7',
36 'Programming Language :: Python :: 3',
37 'Programming Language :: Python :: 3.5',
38 'Programming Language :: Python :: 3.6',
39 'Programming Language :: Python :: 3.7',
40 'Programming Language :: Python :: 3.8',
41 'Topic :: Scientific/Engineering :: Visualization',
42 ],
43 )
0 # setup.py
1
2 import pathlib
3 from setuptools import setup, find_packages
4
5 setup(
6 name='graphviz',
7 version='0.17.dev0',
8 author='Sebastian Bank',
9 author_email='sebastian.bank@uni-leipzig.de',
10 description='Simple Python interface for Graphviz',
11 keywords='graph visualization dot render',
12 license='MIT',
13 url='https://github.com/xflr6/graphviz',
14 project_urls={
15 'Documentation': 'https://graphviz.readthedocs.io',
16 'Changelog': 'https://graphviz.readthedocs.io/en/latest/changelog.html',
17 'Issue Tracker': 'https://github.com/xflr6/graphviz/issues',
18 'CI': 'https://travis-ci.org/xflr6/graphviz',
19 'Coverage': 'https://codecov.io/gh/xflr6/graphviz',
20 },
21 packages=find_packages(),
22 platforms='any',
23 python_requires='>=3.6',
24 extras_require={
25 'dev': ['tox>=3', 'flake8', 'pep8-naming', 'wheel', 'twine'],
26 'test': ['mock>=3', 'pytest>=5.2', 'pytest-mock>=2', 'pytest-cov'],
27 'docs': ['sphinx>=1.8', 'sphinx-autodoc-typehints', 'sphinx-rtd-theme'],
28 },
29 long_description=pathlib.Path('README.rst').read_text(encoding='utf-8'),
30 classifiers=[
31 'Development Status :: 4 - Beta',
32 'Intended Audience :: Developers',
33 'Intended Audience :: Science/Research',
34 'License :: OSI Approved :: MIT License',
35 'Operating System :: OS Independent',
36 'Programming Language :: Python :: 3',
37 'Programming Language :: Python :: 3.6',
38 'Programming Language :: Python :: 3.7',
39 'Programming Language :: Python :: 3.8',
40 'Programming Language :: Python :: 3.9',
41 'Topic :: Scientific/Engineering :: Visualization',
42 ],
43 )
0 # conftest.py
1
2 import sys
3 import platform as platform_
4
5 import pytest
6
7
8 def pytest_addoption(parser):
9 parser.addoption('--skipexe', action='store_true',
10 help='skip tests that run Graphviz executables'
11 'or subprocesses')
12
13
14 def pytest_configure(config):
15 pytest.exe = pytest.mark.skipif(config.getoption('--skipexe'),
16 reason='skipped by --skipexe option')
17
18
19 @pytest.fixture(scope='session')
20 def py2():
21 return sys.version_info.major == 2
22
23
24 @pytest.fixture(scope='session')
25 def filesdir(tmpdir_factory):
26 LocalPath = tmpdir_factory.getbasetemp().__class__ # noqa: N806
27 return LocalPath(__file__).new(basename='')
28
29
30 @pytest.fixture(scope='session')
31 def test_platform():
32 return platform_.system().lower()
33
34
35 @pytest.fixture(params=['darwin', 'freebsd', 'linux', 'windows'],
36 ids=lambda p: 'platform=%r' % p)
37 def platform(monkeypatch, request):
38 monkeypatch.setattr('graphviz.backend.PLATFORM', request.param)
39 yield request.param
40
41
42 @pytest.fixture
43 def unknown_platform(monkeypatch, name='nonplatform'):
44 monkeypatch.setattr('graphviz.backend.PLATFORM', name)
45 yield name
46
47
48 @pytest.fixture
49 def Popen(mocker): # noqa: N802
50 yield mocker.patch('subprocess.Popen', autospec=True)
51
52
53 @pytest.fixture
54 def startfile(mocker, test_platform):
55 if test_platform == 'windows':
56 kwargs = {'autospec': True}
57 else:
58 kwargs = {'create': True, 'new_callable': mocker.Mock}
59 yield mocker.patch('os.startfile', **kwargs)
60
61
62 @pytest.fixture
63 def empty_path(monkeypatch):
64 monkeypatch.setenv('PATH', '')
65
66
67 @pytest.fixture(params=[False, True], ids=lambda q: 'quiet=%r' % q)
68 def quiet(request):
69 return request.param
70
71
72 @pytest.fixture
73 def pipe(mocker):
74 yield mocker.patch('graphviz.backend.pipe', autospec=True)
75
76
77 @pytest.fixture
78 def render(mocker):
79 yield mocker.patch('graphviz.backend.render', autospec=True)
0 """pytest command line options and fixtures."""
1
2 import pathlib
3 import platform as platform_
4
5 import pytest
6
7 DIRECTORY = pathlib.Path(__file__).parent
8
9 SKIP_EXE = '--skip-exe'
10
11
12 def pytest_addoption(parser):
13 parser.addoption(SKIP_EXE, action='store_true',
14 help='skip tests that run Graphviz executables'
15 ' or subprocesses')
16
17
18 def pytest_configure(config):
19 config.addinivalue_line('markers',
20 f'exe: skip if {SKIP_EXE} is given')
21
22
23 def pytest_collection_modifyitems(config, items):
24 if config.getoption(SKIP_EXE):
25 for item in items:
26 if 'exe' in item.keywords:
27 marker = pytest.mark.skip(reason=f'skipped by {SKIP_EXE} flag')
28 item.add_marker(marker)
29
30
31 @pytest.fixture(scope='session')
32 def files_path():
33 return DIRECTORY / 'files'
34
35
36 @pytest.fixture(scope='session')
37 def platform():
38 return platform_.system().lower()
39
40
41 @pytest.fixture(params=['darwin', 'freebsd', 'linux', 'windows'],
42 ids=lambda p: f'platform={p!r}')
43 def mock_platform(monkeypatch, request):
44 monkeypatch.setattr('graphviz.backend.PLATFORM', request.param)
45 yield request.param
46
47
48 @pytest.fixture
49 def unknown_platform(monkeypatch, name='nonplatform'):
50 monkeypatch.setattr('graphviz.backend.PLATFORM', name)
51 yield name
52
53
54 @pytest.fixture
55 def Popen(mocker): # noqa: N802
56 yield mocker.patch('subprocess.Popen', autospec=True)
57
58
59 @pytest.fixture
60 def startfile(mocker, platform):
61 if platform == 'windows':
62 kwargs = {'autospec': True}
63 else:
64 kwargs = {'create': True, 'new_callable': mocker.Mock}
65 yield mocker.patch('os.startfile', **kwargs)
66
67
68 @pytest.fixture
69 def empty_path(monkeypatch):
70 monkeypatch.setenv('PATH', '')
71
72
73 @pytest.fixture(params=[False, True], ids=lambda q: f'quiet={q!r}')
74 def quiet(request):
75 return request.param
76
77
78 @pytest.fixture
79 def pipe(mocker):
80 yield mocker.patch('graphviz.backend.pipe', autospec=True)
81
82
83 @pytest.fixture
84 def render(mocker):
85 yield mocker.patch('graphviz.backend.render', autospec=True)
tests/dot_red.png less more
Binary diff not shown
Binary diff not shown
0 # test_backend.py
1
2 import os
3 import re
4 import errno
5 import platform
6 import subprocess
7
8 import pytest
9
10 from graphviz.backend import (run, render, pipe, version, view,
11 ExecutableNotFound, RequiredArgumentError)
12
13
14 if platform.system().lower() == 'windows':
15 def check_startupinfo(startupinfo): # noqa: N803
16 assert isinstance(startupinfo, subprocess.STARTUPINFO)
17 assert startupinfo.dwFlags & subprocess.STARTF_USESHOWWINDOW
18 assert startupinfo.wShowWindow == subprocess.SW_HIDE
19 else:
20 def check_startupinfo(startupinfo): # noqa: N803
21 assert startupinfo is None
22
23
24 @pytest.exe
25 def test_run_oserror():
26 with pytest.raises(OSError) as e:
27 run([''])
28 assert e.value.errno in (errno.EACCES, errno.EINVAL)
29
30
31 def test_run_encoding_mocked(mocker, Popen, input=u'sp\xe4m', encoding='utf-8'):
32 proc = Popen.return_value
33 proc.returncode = 0
34 mocks = [mocker.create_autospec(bytes, instance=True, name=n) for n in ('out', 'err')]
35 proc.communicate.return_value = mocks
36
37 result = run(mocker.sentinel.cmd,
38 input=input, capture_output=True, encoding=encoding)
39
40 Popen.assert_called_once_with(mocker.sentinel.cmd,
41 stdin=subprocess.PIPE,
42 stdout=subprocess.PIPE,
43 stderr=subprocess.PIPE,
44 startupinfo=mocker.ANY)
45 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
46 proc.communicate.assert_called_once_with(input.encode(encoding))
47 assert result == tuple(m.decode.return_value for m in mocks)
48 for m in mocks:
49 m.decode.assert_called_once_with(encoding)
50
51
52 @pytest.exe
53 @pytest.mark.usefixtures('empty_path')
54 @pytest.mark.parametrize('func, args', [
55 (render, ['dot', 'pdf', 'nonfilepath']),
56 (pipe, ['dot', 'pdf', b'nongraph']),
57 (version, []),
58 ])
59 def test_missing_executable(func, args):
60 with pytest.raises(ExecutableNotFound, match=r'execute'):
61 func(*args)
62
63
64 def test_render_engine_unknown():
65 with pytest.raises(ValueError, match=r'unknown engine'):
66 render('', 'pdf', 'nonfilepath')
67
68
69 def test_render_format_unknown():
70 with pytest.raises(ValueError, match=r'unknown format'):
71 render('dot', '', 'nonfilepath')
72
73
74 def test_render_renderer_unknown():
75 with pytest.raises(ValueError, match=r'unknown renderer'):
76 render('dot', 'ps', 'nonfilepath', '', None)
77
78
79 def test_render_renderer_missing():
80 with pytest.raises(RequiredArgumentError, match=r'without renderer'):
81 render('dot', 'ps', 'nonfilepath', None, 'core')
82
83
84 def test_render_formatter_unknown():
85 with pytest.raises(ValueError, match=r'unknown formatter'):
86 render('dot', 'ps', 'nonfilepath', 'ps', '')
87
88
89 @pytest.exe
90 def test_render_missing_file(quiet, engine='dot', format_='pdf'):
91 with pytest.raises(subprocess.CalledProcessError) as e:
92 render(engine, format_, '', quiet=quiet)
93 assert e.value.returncode == 2
94
95
96 @pytest.exe
97 @pytest.mark.parametrize('format_, renderer, formatter, expected_suffix', [
98 ('pdf', None, None, 'pdf'),
99 ('plain', 'dot', 'core', 'core.dot.plain'),
100 ])
101 @pytest.mark.parametrize('engine', ['dot'])
102 def test_render(capsys, tmpdir, engine, format_, renderer, formatter,
103 expected_suffix, filename='hello.gv',
104 data=b'digraph { hello -> world }'):
105 lpath = tmpdir / filename
106 lpath.write_binary(data)
107 rendered = lpath.new(ext='%s.%s' % (lpath.ext, expected_suffix))
108
109 assert render(engine, format_, str(lpath), renderer, formatter) == str(rendered)
110
111 assert rendered.size()
112 assert capsys.readouterr() == ('', '')
113
114
115 @pytest.exe
116 def test_render_img(capsys, tmpdir, filesdir, engine='dot', format_='pdf'):
117 subdir = tmpdir / 'subdir'
118 subdir.ensure(dir=True)
119
120 img_path = subdir / 'dot_red.png'
121 (filesdir / img_path.basename).copy(img_path)
122 assert img_path.size()
123
124 gv_path = subdir / 'img.gv'
125 rendered = gv_path.new(ext='%s.%s' % (gv_path.ext, format_))
126 gv_rel, rendered_rel = map(tmpdir.bestrelpath, (gv_path, rendered))
127 assert all(s.startswith('subdir') for s in (gv_rel, rendered_rel))
128 gv_path.write_text(u'graph { red_dot [image="%s"] }' % img_path.basename,
129 encoding='ascii')
130
131 with tmpdir.as_cwd():
132 assert render(engine, format_, gv_rel) == rendered_rel
133
134 assert rendered.size()
135 assert capsys.readouterr() == ('', '')
136
137
138 def test_render_mocked(capsys, mocker, Popen, quiet): # noqa: N803
139 proc = Popen.return_value
140 proc.returncode = 0
141 proc.communicate.return_value = (b'stdout', b'stderr')
142
143 assert render('dot', 'pdf', 'nonfilepath', quiet=quiet) == 'nonfilepath.pdf'
144
145 Popen.assert_called_once_with(['dot', '-Tpdf', '-O', 'nonfilepath'],
146 stdout=subprocess.PIPE,
147 stderr=subprocess.PIPE,
148 cwd=None, startupinfo=mocker.ANY)
149 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
150 proc.communicate.assert_called_once_with(None)
151 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
152
153
154 @pytest.exe
155 @pytest.mark.xfail('version() == (2, 36, 0)',
156 reason='https://bugs.launchpad.net/ubuntu/+source/graphviz/+bug/1694108')
157 def test_pipe_invalid_data(capsys, quiet, engine='dot', format_='svg'):
158 with pytest.raises(subprocess.CalledProcessError) as e:
159 pipe(engine, format_, b'nongraph', quiet=quiet)
160
161 assert e.value.returncode == 1
162 assert 'syntax error in line' in str(e.value)
163 out, err = capsys.readouterr()
164 assert out == ''
165 if quiet:
166 assert err == ''
167 else:
168 assert 'syntax error in line' in err
169
170
171 @pytest.exe
172 @pytest.mark.parametrize('format_, renderer, formatter, pattern', [
173 ('svg', None, None, r'(?s)^<\?xml .+</svg>\s*$'),
174 ('ps', 'ps', 'core', r'%!PS-'),
175 ])
176 @pytest.mark.parametrize('engine', ['dot'])
177 def test_pipe(capsys, engine, format_, renderer, formatter, pattern,
178 data=b'graph { spam }'):
179 out = pipe(engine, format_, data, renderer, formatter).decode('ascii')
180
181 if pattern is not None:
182 assert re.match(pattern, out)
183 assert capsys.readouterr() == ('', '')
184
185
186 def test_pipe_pipe_invalid_data_mocked(mocker, py2, Popen, quiet): # noqa: N803
187 stderr = mocker.patch('sys.stderr', autospec=True,
188 **{'flush': mocker.Mock(), 'encoding': 'nonencoding'})
189 proc = Popen.return_value
190 proc.returncode = mocker.sentinel.returncode
191 err = mocker.create_autospec(bytes, instance=True, name='err',
192 **{'__len__.return_value': 23})
193 proc.communicate.return_value = (mocker.sentinel.out, err)
194
195 with pytest.raises(subprocess.CalledProcessError) as e:
196 pipe('dot', 'png', b'nongraph', quiet=quiet)
197
198 assert e.value.returncode is mocker.sentinel.returncode
199 assert e.value.stderr is err
200 assert e.value.stdout is mocker.sentinel.out
201 e.value.stdout = mocker.sentinel.new_stdout
202 assert e.value.stdout is mocker.sentinel.new_stdout
203 Popen.assert_called_once_with(['dot', '-Tpng'],
204 stdin=subprocess.PIPE,
205 stdout=subprocess.PIPE,
206 stderr=subprocess.PIPE,
207 startupinfo=mocker.ANY)
208 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
209 proc.communicate.assert_called_once_with(b'nongraph')
210 if not quiet:
211 if py2:
212 stderr.write.assert_called_once_with(err)
213 else:
214 err.decode.assert_called_once_with(stderr.encoding)
215 stderr.write.assert_called_once_with(err.decode.return_value)
216 stderr.flush.assert_called_once_with()
217
218
219 def test_pipe_mocked(capsys, mocker, Popen, quiet): # noqa: N803
220 proc = Popen.return_value
221 proc.returncode = 0
222 proc.communicate.return_value = (mocker.sentinel.out, b'stderr')
223
224 assert pipe('dot', 'png', b'nongraph', quiet=quiet) is mocker.sentinel.out
225
226 Popen.assert_called_once_with(['dot', '-Tpng'],
227 stdin=subprocess.PIPE,
228 stdout=subprocess.PIPE,
229 stderr=subprocess.PIPE,
230 startupinfo=mocker.ANY)
231 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
232 proc.communicate.assert_called_once_with(b'nongraph')
233 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
234
235
236 @pytest.exe
237 def test_version(capsys):
238 result = version()
239 assert isinstance(result, tuple) and result
240 assert all(isinstance(d, int) for d in result)
241 assert capsys.readouterr() == ('', '')
242
243
244 def test_version_parsefail_mocked(mocker, Popen): # noqa: N803
245 proc = Popen.return_value
246 proc.returncode = 0
247 proc.communicate.return_value = (b'nonversioninfo', None)
248
249 with pytest.raises(RuntimeError, match=r'nonversioninfo'):
250 version()
251
252 Popen.assert_called_once_with(['dot', '-V'],
253 stdout=subprocess.PIPE,
254 stderr=subprocess.STDOUT,
255 startupinfo=mocker.ANY)
256 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
257 proc.communicate.assert_called_once_with(None)
258
259
260 @pytest.mark.parametrize('stdout, expected', [
261 (b'dot - graphviz version 1.2.3 (mocked)', (1, 2, 3)),
262 (b'dot - graphviz version 2.43.20190912.0211 (20190912.0211)\n', (2, 43, 20190912, 211)),
263 (b'dot - graphviz version 2.44.2~dev.20200927.0217 (20200927.0217)\n', (2, 44, 2)),
264 (b'dot - graphviz version 2.44.1 (mocked)\n', (2, 44, 1)),
265 (b'dot - graphviz version 2.44.2~dev.20200704.1652 (mocked)\n', (2, 44, 2)),
266 ])
267 def test_version_mocked(mocker, Popen, stdout, expected): # noqa: N803
268 proc = Popen.return_value
269 proc.returncode = 0
270 proc.communicate.return_value = (stdout, None)
271
272 assert version() == expected
273
274 Popen.assert_called_once_with(['dot', '-V'],
275 stdout=subprocess.PIPE,
276 stderr=subprocess.STDOUT,
277 startupinfo=mocker.ANY)
278 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
279 proc.communicate.assert_called_once_with(None)
280
281
282 def test_view_unknown_platform(unknown_platform):
283 with pytest.raises(RuntimeError, match=r'platform'):
284 view('nonfilepath')
285
286
287 def test_view(mocker, py2, platform, Popen, startfile, quiet): # noqa: N803
288 if quiet and py2:
289 open_ = mocker.patch('__builtin__.open', mocker.mock_open())
290
291 assert view('nonfilepath', quiet=quiet) is None
292
293 if platform == 'windows':
294 startfile.assert_called_once_with('nonfilepath')
295 return
296
297 if quiet and py2:
298 open_.assert_called_once_with(os.devnull, 'w')
299 kwargs = {'stderr': open_.return_value}
300 elif quiet:
301 kwargs = {'stderr': subprocess.DEVNULL}
302 else:
303 kwargs = {}
304
305 if platform == 'darwin':
306 Popen.assert_called_once_with(['open', 'nonfilepath'], **kwargs)
307 elif platform in ('linux', 'freebsd'):
308 Popen.assert_called_once_with(['xdg-open', 'nonfilepath'], **kwargs)
309 else:
310 raise RuntimeError
0 # test_backend.py
1
2 import errno
3 import platform
4 import re
5 import shutil
6 import subprocess
7
8 import pytest
9
10 from graphviz.backend import (run, render, pipe, unflatten, version, view,
11 ExecutableNotFound, RequiredArgumentError)
12
13 import utils
14
15 SVG_PATTERN = r'(?s)^<\?xml .+</svg>\s*$'
16
17
18 if platform.system().lower() == 'windows':
19 def check_startupinfo(startupinfo): # noqa: N803
20 assert isinstance(startupinfo, subprocess.STARTUPINFO)
21 assert startupinfo.dwFlags & subprocess.STARTF_USESHOWWINDOW
22 assert startupinfo.wShowWindow == subprocess.SW_HIDE
23 else:
24 def check_startupinfo(startupinfo): # noqa: N803
25 assert startupinfo is None
26
27
28 @pytest.mark.exe
29 def test_run_oserror():
30 with pytest.raises(OSError) as e:
31 run([''])
32 assert e.value.errno in (errno.EACCES, errno.EINVAL)
33
34
35 def test_run_encoding_mocked(mocker, Popen, input='sp\xe4m', encoding='utf-8'):
36 proc = Popen.return_value
37 proc.returncode = 0
38 mocks = [mocker.create_autospec(bytes, instance=True, name=n) for n in ('out', 'err')]
39 proc.communicate.return_value = mocks
40
41 result = run(mocker.sentinel.cmd,
42 input=input, capture_output=True, encoding=encoding)
43
44 Popen.assert_called_once_with(mocker.sentinel.cmd,
45 stdin=subprocess.PIPE,
46 stdout=subprocess.PIPE,
47 stderr=subprocess.PIPE,
48 startupinfo=mocker.ANY)
49 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
50 proc.communicate.assert_called_once_with(input.encode(encoding))
51 assert result == tuple(m.decode.return_value for m in mocks)
52 for m in mocks:
53 m.decode.assert_called_once_with(encoding)
54
55
56 @pytest.mark.exe
57 @pytest.mark.usefixtures('empty_path')
58 @pytest.mark.parametrize('func, args', [
59 (render, ['dot', 'pdf', 'nonfilepath']),
60 (pipe, ['dot', 'pdf', b'nongraph']),
61 (unflatten, ['graph {}']),
62 (version, []),
63 ])
64 def test_missing_executable(func, args):
65 with pytest.raises(ExecutableNotFound, match=r'execute'):
66 func(*args)
67
68
69 def test_render_engine_unknown():
70 with pytest.raises(ValueError, match=r'unknown engine'):
71 render('', 'pdf', 'nonfilepath')
72
73
74 def test_render_format_unknown():
75 with pytest.raises(ValueError, match=r'unknown format'):
76 render('dot', '', 'nonfilepath')
77
78
79 def test_render_renderer_unknown():
80 with pytest.raises(ValueError, match=r'unknown renderer'):
81 render('dot', 'ps', 'nonfilepath', '', None)
82
83
84 def test_render_renderer_missing():
85 with pytest.raises(RequiredArgumentError, match=r'without renderer'):
86 render('dot', 'ps', 'nonfilepath', None, 'core')
87
88
89 def test_render_formatter_unknown():
90 with pytest.raises(ValueError, match=r'unknown formatter'):
91 render('dot', 'ps', 'nonfilepath', 'ps', '')
92
93
94 @pytest.mark.exe
95 def test_render_missing_file(quiet, engine='dot', format_='pdf'):
96 with pytest.raises(subprocess.CalledProcessError) as e:
97 render(engine, format_, '', quiet=quiet)
98 assert e.value.returncode == 2
99
100
101 @pytest.mark.exe
102 @pytest.mark.parametrize('format_, renderer, formatter, expected_suffix', [
103 ('pdf', None, None, 'pdf'),
104 ('plain', 'dot', 'core', 'core.dot.plain'),
105 ])
106 @pytest.mark.parametrize('engine', ['dot'])
107 def test_render(capsys, tmp_path, engine, format_, renderer, formatter,
108 expected_suffix, filename='hello.gv',
109 data=b'digraph { hello -> world }'):
110 lpath = tmp_path / filename
111 lpath.write_bytes(data)
112 rendered = lpath.with_suffix(f'{lpath.suffix}.{expected_suffix}')
113
114 assert render(engine, format_, str(lpath), renderer, formatter) == str(rendered)
115
116 assert rendered.stat().st_size
117 assert capsys.readouterr() == ('', '')
118
119
120 @pytest.mark.exe
121 def test_render_img(capsys, tmp_path, files_path, engine='dot', format_='pdf'):
122 subdir = tmp_path / 'subdir'
123 subdir.mkdir()
124
125 img_path = subdir / 'dot_red.png'
126 shutil.copy(files_path / img_path.name, img_path)
127 assert img_path.stat().st_size
128
129 gv_path = subdir / 'img.gv'
130 rendered = gv_path.with_suffix(f'{gv_path.suffix}.{format_}')
131 gv_rel, rendered_rel = (p.relative_to(tmp_path) for p in (gv_path, rendered))
132 assert all(str(s).startswith('subdir') for s in (gv_rel, rendered_rel))
133 gv_path.write_text(f'graph {{ red_dot [image="{img_path.name}"] }}',
134 encoding='ascii')
135
136 with utils.as_cwd(tmp_path):
137 assert render(engine, format_, gv_rel) == str(rendered_rel)
138
139 assert rendered.stat().st_size
140 assert capsys.readouterr() == ('', '')
141
142
143 def test_render_mocked(capsys, mocker, Popen, quiet): # noqa: N803
144 proc = Popen.return_value
145 proc.returncode = 0
146 proc.communicate.return_value = (b'stdout', b'stderr')
147
148 assert render('dot', 'pdf', 'nonfilepath', quiet=quiet) == 'nonfilepath.pdf'
149
150 Popen.assert_called_once_with(['dot', '-Kdot', '-Tpdf', '-O', 'nonfilepath'],
151 stdout=subprocess.PIPE,
152 stderr=subprocess.PIPE,
153 cwd=None, startupinfo=mocker.ANY)
154 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
155 proc.communicate.assert_called_once_with(None)
156 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
157
158
159 @pytest.mark.exe
160 @pytest.mark.xfail('version() == (2, 36, 0)',
161 reason='https://bugs.launchpad.net/ubuntu/+source/graphviz/+bug/1694108')
162 def test_pipe_invalid_data(capsys, quiet, engine='dot', format_='svg'):
163 with pytest.raises(subprocess.CalledProcessError) as e:
164 pipe(engine, format_, b'nongraph', quiet=quiet)
165
166 assert e.value.returncode == 1
167 assert 'syntax error in line' in str(e.value)
168 out, err = capsys.readouterr()
169 assert out == ''
170 if quiet:
171 assert err == ''
172 else:
173 assert 'syntax error in line' in err
174
175
176 @pytest.mark.exe
177 @pytest.mark.parametrize('engine, format_, renderer, formatter, pattern', [
178 ('dot', 'svg', None, None, SVG_PATTERN),
179 ('dot', 'ps', 'ps', 'core', r'%!PS-'),
180 # Error: remove_overlap: Graphviz not built with triangulation library
181 pytest.param('sfdp', 'svg', None, None, SVG_PATTERN,
182 marks=pytest.mark.xfail('version() > (2, 38, 0)'
183 " and platform.system().lower() == 'windows'",
184 reason='https://gitlab.com/graphviz/graphviz/-/issues/1269')),
185 ])
186 def test_pipe(capsys, engine, format_, renderer, formatter, pattern,
187 data=b'graph { spam }'):
188 out = pipe(engine, format_, data, renderer, formatter).decode('ascii')
189
190 if pattern is not None:
191 assert re.match(pattern, out)
192 assert capsys.readouterr() == ('', '')
193
194
195 def test_pipe_pipe_invalid_data_mocked(mocker, Popen, quiet): # noqa: N803
196 stderr = mocker.patch('sys.stderr', autospec=True,
197 **{'flush': mocker.Mock(), 'encoding': 'nonencoding'})
198 proc = Popen.return_value
199 proc.returncode = mocker.sentinel.returncode
200 err = mocker.create_autospec(bytes, instance=True, name='err',
201 **{'__len__.return_value': 23})
202 out = mocker.create_autospec(bytes, instance=True, name='out')
203 proc.communicate.return_value = (out, err)
204
205 with pytest.raises(subprocess.CalledProcessError) as e:
206 pipe('dot', 'png', b'nongraph', quiet=quiet)
207
208 assert e.value.returncode is mocker.sentinel.returncode
209 assert e.value.stderr is err
210 assert e.value.stdout is out
211 e.value.stdout = mocker.sentinel.new_stdout
212 assert e.value.stdout is mocker.sentinel.new_stdout
213 Popen.assert_called_once_with(['dot', '-Kdot', '-Tpng'],
214 stdin=subprocess.PIPE,
215 stdout=subprocess.PIPE,
216 stderr=subprocess.PIPE,
217 startupinfo=mocker.ANY)
218 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
219 proc.communicate.assert_called_once_with(b'nongraph')
220 if not quiet:
221 err.decode.assert_called_once_with(stderr.encoding)
222 stderr.write.assert_called_once_with(err.decode.return_value)
223 stderr.flush.assert_called_once_with()
224
225
226 def test_pipe_mocked(capsys, mocker, Popen, quiet): # noqa: N803
227 proc = Popen.return_value
228 proc.returncode = 0
229 proc.communicate.return_value = (b'stdout', b'stderr')
230
231 assert pipe('dot', 'png', b'nongraph', quiet=quiet) == b'stdout'
232
233 Popen.assert_called_once_with(['dot', '-Kdot', '-Tpng'],
234 stdin=subprocess.PIPE,
235 stdout=subprocess.PIPE,
236 stderr=subprocess.PIPE,
237 startupinfo=mocker.ANY)
238 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
239 proc.communicate.assert_called_once_with(b'nongraph')
240 assert capsys.readouterr() == ('', '' if quiet else 'stderr')
241
242
243 @pytest.mark.exe
244 @pytest.mark.parametrize('source, kwargs, expected', [
245 ('digraph {1 -> 2; 1 -> 3; 1 -> 4}',
246 {'stagger': 3, 'fanout': True, 'chain': 42},
247 'digraph { 1 -> 2 [minlen=1]; 1 -> 3 [minlen=2]; 1 -> 4 [minlen=3]; }'),
248 ])
249 def test_unflatten(source, kwargs, expected):
250 result = unflatten(source, **kwargs)
251 normalized = re.sub(r'\s+', ' ', result.strip())
252 assert normalized == expected
253
254
255 def test_unflatten_mocked(capsys, mocker, Popen):
256 proc = Popen.return_value
257 proc.returncode = 0
258 proc.communicate.return_value = (b'nonresult', b'')
259
260 assert unflatten('nonsource') == 'nonresult'
261 Popen.assert_called_once_with(['unflatten'],
262 stdin=subprocess.PIPE,
263 stdout=subprocess.PIPE,
264 stderr=subprocess.PIPE,
265 startupinfo=mocker.ANY)
266 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
267 proc.communicate.assert_called_once_with(b'nonsource')
268 assert capsys.readouterr() == ('', '')
269
270
271 def test_unflatten_stagger_missing():
272 with pytest.raises(RequiredArgumentError, match=r'without stagger'):
273 unflatten('graph {}', fanout=True)
274
275
276 @pytest.mark.exe
277 def test_version(capsys):
278 result = version()
279 assert isinstance(result, tuple) and result
280 assert all(isinstance(d, int) for d in result)
281 assert capsys.readouterr() == ('', '')
282
283
284 def test_version_parsefail_mocked(mocker, Popen): # noqa: N803
285 proc = Popen.return_value
286 proc.returncode = 0
287 proc.communicate.return_value = (b'nonversioninfo', None)
288
289 with pytest.raises(RuntimeError, match=r'nonversioninfo'):
290 version()
291
292 Popen.assert_called_once_with(['dot', '-V'],
293 stdout=subprocess.PIPE,
294 stderr=subprocess.STDOUT,
295 startupinfo=mocker.ANY)
296 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
297 proc.communicate.assert_called_once_with(None)
298
299
300 @pytest.mark.parametrize('stdout, expected', [
301 (b'dot - graphviz version 1.2.3 (mocked)', (1, 2, 3)),
302 (b'dot - graphviz version 2.43.20190912.0211 (20190912.0211)\n', (2, 43, 20190912, 211)),
303 (b'dot - graphviz version 2.44.2~dev.20200927.0217 (20200927.0217)\n', (2, 44, 2)),
304 (b'dot - graphviz version 2.44.1 (mocked)\n', (2, 44, 1)),
305 (b'dot - graphviz version 2.44.2~dev.20200704.1652 (mocked)\n', (2, 44, 2)),
306 ])
307 def test_version_mocked(mocker, Popen, stdout, expected): # noqa: N803
308 proc = Popen.return_value
309 proc.returncode = 0
310 proc.communicate.return_value = (stdout, None)
311
312 assert version() == expected
313
314 Popen.assert_called_once_with(['dot', '-V'],
315 stdout=subprocess.PIPE,
316 stderr=subprocess.STDOUT,
317 startupinfo=mocker.ANY)
318 check_startupinfo(Popen.call_args.kwargs['startupinfo'])
319 proc.communicate.assert_called_once_with(None)
320
321
322 def test_view_unknown_platform(unknown_platform):
323 with pytest.raises(RuntimeError, match=r'platform'):
324 view('nonfilepath')
325
326
327 def test_view(mocker, mock_platform, Popen, startfile, quiet): # noqa: N803
328 assert view('nonfilepath', quiet=quiet) is None
329
330 if mock_platform == 'windows':
331 startfile.assert_called_once_with('nonfilepath')
332 return
333
334 if quiet:
335 kwargs = {'stderr': subprocess.DEVNULL}
336 else:
337 kwargs = {}
338
339 if mock_platform == 'darwin':
340 Popen.assert_called_once_with(['open', 'nonfilepath'], **kwargs)
341 elif mock_platform in ('linux', 'freebsd'):
342 Popen.assert_called_once_with(['xdg-open', 'nonfilepath'], **kwargs)
343 else:
344 raise RuntimeError
0 # test_dot.py
1
2 import itertools
3
4 import pytest
5
6 from graphviz.dot import Graph, Digraph
7
8
9 @pytest.fixture(params=[Graph, Digraph])
10 def cls(request):
11 return request.param
12
13
14 @pytest.fixture(params=list(itertools.permutations([Graph, Digraph], 2)),
15 ids=lambda c: '%s, %s' % (c[0].__name__, c[1].__name__))
16 def classes(request):
17 return request.param
18
19
20 def test_copy(cls):
21 c = cls()
22 assert c.__class__ is cls
23 assert c.copy() is not c
24 assert c.copy() is not c.copy()
25 assert c.copy().__class__ is c.__class__
26 assert c.copy().__dict__ == c.__dict__ == c.copy().__dict__
27
28
29 def test__repr_svg_(mocker, cls):
30 c = cls()
31 kwargs = {'return_value.decode.return_value': mocker.sentinel.decoded}
32 pipe = mocker.patch.object(c, 'pipe', autospec=True, **kwargs)
33
34 assert c._repr_svg_() is mocker.sentinel.decoded
35
36 pipe.assert_called_once_with(format='svg')
37 pipe.return_value.decode.assert_called_once_with(c.encoding)
38
39
40 @pytest.mark.parametrize('keep_attrs', [False, True])
41 def test_clear(cls, keep_attrs):
42 kwargs = {'%s_attr' % a: {a: a} for a in ('graph', 'node', 'edge')}
43 c = cls(**kwargs)
44 assert all(getattr(c, k) == v for k, v in kwargs.items())
45 c.node('spam')
46 assert len(c.body) == 1
47 body = c.body
48
49 c.clear(keep_attrs)
50 assert c.body == []
51 assert c.body is body
52 if keep_attrs:
53 assert all(getattr(c, k) == v for k, v in kwargs.items())
54 else:
55 assert all(getattr(c, k) == {} for k in kwargs)
56
57
58 def test_iter_subgraph_strict(cls):
59 with pytest.raises(ValueError, match=r'strict'):
60 cls().subgraph(cls(strict=True))
61
62
63 @pytest.mark.parametrize('cls, expected', [
64 (Graph, 'strict graph {\n}'),
65 (Digraph, 'strict digraph {\n}'),
66 ], ids=lambda p: getattr(p, '__name__', '...'))
67 def test_iter_strict(cls, expected):
68 assert cls(strict=True).source == expected
69
70
71 def test_attr_invalid_kw(cls):
72 with pytest.raises(ValueError, match=r'attr'):
73 cls().attr('spam')
74
75
76 @pytest.mark.parametrize('cls, expected', [
77 (Graph, 'graph {\n\tspam=eggs\n}'),
78 (Digraph, 'digraph {\n\tspam=eggs\n}'),
79 ], ids=lambda p: getattr(p, '__name__', '...'))
80 def test_attr_kw_none(cls, expected):
81 dot = cls()
82 dot.attr(spam='eggs')
83 assert dot.source == expected
84
85
86 @pytest.mark.parametrize('cls, expected', [
87 (Graph, 'graph {\n\tA [label="%s"]\n\tB [label="%s"]\n}' % (r'\\', r'\"\\\"')),
88 (Digraph, 'digraph {\n\tA [label="%s"]\n\tB [label="%s"]\n}' % (r'\\', r'\"\\\"')),
89 ], ids=lambda p: getattr(p, '__name__', '...'))
90 def test_escaped_quotes_and_escapes(cls, expected):
91 dot = cls()
92 dot.node('A', label='\\\\')
93 dot.node('B', label=r'"\\"')
94 assert dot.source == expected
95
96
97 @pytest.mark.parametrize('cls, expected', [
98 (Graph, 'graph {\n\t// comment\n\tsubgraph name {\n\t}\n}'),
99 (Digraph, 'digraph {\n\t// comment\n\tsubgraph name {\n\t}\n}'),
100 ], ids=lambda p: getattr(p, '__name__', '...'))
101 def test_subgraph_graph_none(cls, expected):
102 dot = cls()
103 with dot.subgraph(name='name', comment='comment'):
104 pass
105 assert dot.source == expected
106
107
108 def test_subgraph_graph_notsole(cls):
109 with pytest.raises(ValueError, match=r'sole'):
110 cls().subgraph(cls(), name='spam')
111
112
113 def test_subgraph_mixed(classes):
114 cls1, cls2 = classes
115 with pytest.raises(ValueError, match=r'kind'):
116 cls1().subgraph(cls2())
117
118
119 @pytest.mark.parametrize('cls, expected', [
120 (Graph, 'graph {\n\t{\n\t}\n}'),
121 (Digraph, 'digraph {\n\t{\n\t}\n}'),
122 ], ids=lambda p: getattr(p, '__name__', '...'))
123 def test_subgraph_reflexive(cls, expected): # guard against potential infinite loop
124 dot = cls()
125 dot.subgraph(dot)
126 assert dot.source == expected
127
128
129 def test_subgraph():
130 s1 = Graph()
131 s1.node('A')
132 s1.node('B')
133 s1.node('C')
134 s1.edge('A', 'B', constraint='false')
135 s1.edges(['AC', 'BC'])
136
137 s2 = Graph()
138 s2.node('D')
139 s2.node('E')
140 s2.node('F')
141 s2.edge('D', 'E', constraint='false')
142 s2.edges(['DF', 'EF'])
143
144 dot = Graph()
145 dot.subgraph(s1)
146 dot.subgraph(s2)
147 dot.attr('edge', style='dashed')
148 dot.edges(['AD', 'BE', 'CF'])
149
150 assert dot.source == '''graph {
151 \t{
152 \t\tA
153 \t\tB
154 \t\tC
155 \t\tA -- B [constraint=false]
156 \t\tA -- C
157 \t\tB -- C
158 \t}
159 \t{
160 \t\tD
161 \t\tE
162 \t\tF
163 \t\tD -- E [constraint=false]
164 \t\tD -- F
165 \t\tE -- F
166 \t}
167 \tedge [style=dashed]
168 \tA -- D
169 \tB -- E
170 \tC -- F
171 }'''
172
173
174 def test_label_html():
175 """http://www.graphviz.org/doc/info/shapes.html#html"""
176 dot = Digraph('structs', node_attr={'shape': 'plaintext'})
177 dot.node('struct1', '''<
178 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
179 <TR>
180 <TD>left</TD>
181 <TD PORT="f1">middle</TD>
182 <TD PORT="f2">right</TD>
183 </TR>
184 </TABLE>>''')
185 dot.node('struct2', '''<
186 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
187 <TR>
188 <TD PORT="f0">one</TD>
189 <TD>two</TD>
190 </TR>
191 </TABLE>>''')
192 dot.node('struct3', '''<
193 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
194 <TR>
195 <TD ROWSPAN="3">hello<BR/>world</TD>
196 <TD COLSPAN="3">b</TD>
197 <TD ROWSPAN="3">g</TD>
198 <TD ROWSPAN="3">h</TD>
199 </TR>
200 <TR>
201 <TD>c</TD>
202 <TD PORT="here">d</TD>
203 <TD>e</TD>
204 </TR>
205 <TR>
206 <TD COLSPAN="3">f</TD>
207 </TR>
208 </TABLE>>''')
209 dot.edge('struct1:f1', 'struct2:f0')
210 dot.edge('struct1:f2', 'struct3:here')
211 assert dot.source == '''digraph structs {
212 \tnode [shape=plaintext]
213 \tstruct1 [label=<
214 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
215 <TR>
216 <TD>left</TD>
217 <TD PORT="f1">middle</TD>
218 <TD PORT="f2">right</TD>
219 </TR>
220 </TABLE>>]
221 \tstruct2 [label=<
222 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
223 <TR>
224 <TD PORT="f0">one</TD>
225 <TD>two</TD>
226 </TR>
227 </TABLE>>]
228 \tstruct3 [label=<
229 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
230 <TR>
231 <TD ROWSPAN="3">hello<BR/>world</TD>
232 <TD COLSPAN="3">b</TD>
233 <TD ROWSPAN="3">g</TD>
234 <TD ROWSPAN="3">h</TD>
235 </TR>
236 <TR>
237 <TD>c</TD>
238 <TD PORT="here">d</TD>
239 <TD>e</TD>
240 </TR>
241 <TR>
242 <TD COLSPAN="3">f</TD>
243 </TR>
244 </TABLE>>]
245 \tstruct1:f1 -> struct2:f0
246 \tstruct1:f2 -> struct3:here
247 }'''
0 # test_dot.py
1
2 import itertools
3 import re
4
5 import pytest
6
7 from graphviz.dot import Graph, Digraph
8 from graphviz.files import Source
9
10
11 @pytest.fixture(params=[Graph, Digraph])
12 def cls(request):
13 return request.param
14
15
16 @pytest.fixture(params=list(itertools.permutations([Graph, Digraph], 2)),
17 ids=lambda c: f'{c[0].__name__}, {c[1].__name__}')
18 def classes(request):
19 return request.param
20
21
22 def test_copy(cls):
23 c = cls()
24 assert c.__class__ is cls
25 assert c.copy() is not c
26 assert c.copy() is not c.copy()
27 assert c.copy().__class__ is c.__class__
28 assert c.copy().__dict__ == c.__dict__ == c.copy().__dict__
29
30
31 def test_str(cls):
32 c = cls()
33 assert str(c) == c.source
34
35
36 @pytest.mark.exe
37 def test_unflatten(cls):
38 c = cls()
39 result = c.unflatten()
40 assert isinstance(result, Source)
41
42 normalized = re.sub(r'\s+', ' ', result.source.strip())
43 assert normalized.startswith('digraph {' if c.directed else 'graph {')
44
45
46 def test__repr_svg_(mocker, cls):
47 c = cls()
48 kwargs = {'return_value.decode.return_value': mocker.sentinel.decoded}
49 pipe = mocker.patch.object(c, 'pipe', autospec=True, **kwargs)
50
51 assert c._repr_svg_() is mocker.sentinel.decoded
52
53 pipe.assert_called_once_with(format='svg')
54 pipe.return_value.decode.assert_called_once_with(c.encoding)
55
56
57 @pytest.mark.parametrize('keep_attrs', [False, True])
58 def test_clear(cls, keep_attrs):
59 kwargs = {f'{a}_attr': {a: a} for a in ('graph', 'node', 'edge')}
60 c = cls(**kwargs)
61 assert all(getattr(c, k) == v for k, v in kwargs.items())
62 c.node('spam')
63 assert len(c.body) == 1
64 body = c.body
65
66 c.clear(keep_attrs)
67 assert c.body == []
68 assert c.body is body
69 if keep_attrs:
70 assert all(getattr(c, k) == v for k, v in kwargs.items())
71 else:
72 assert all(getattr(c, k) == {} for k in kwargs)
73
74
75 def test_iter_subgraph_strict(cls):
76 with pytest.raises(ValueError, match=r'strict'):
77 cls().subgraph(cls(strict=True))
78
79
80 @pytest.mark.parametrize('cls, expected', [
81 (Graph, 'strict graph {\n}'),
82 (Digraph, 'strict digraph {\n}'),
83 ], ids=lambda p: getattr(p, '__name__', '...'))
84 def test_iter_strict(cls, expected):
85 assert cls(strict=True).source == expected
86
87
88 def test_attr_invalid_kw(cls):
89 with pytest.raises(ValueError, match=r'attr'):
90 cls().attr('spam')
91
92
93 @pytest.mark.parametrize('cls, expected', [
94 (Graph, 'graph {\n\tspam=eggs\n}'),
95 (Digraph, 'digraph {\n\tspam=eggs\n}'),
96 ], ids=lambda p: getattr(p, '__name__', '...'))
97 def test_attr_kw_none(cls, expected):
98 dot = cls()
99 dot.attr(spam='eggs')
100 assert dot.source == expected
101
102
103 @pytest.mark.parametrize('cls, expected', [
104 (Graph, 'graph {\n\tA [label="%s"]\n\tB [label="%s"]\n}' % (r'\\', r'\"\\\"')),
105 (Digraph, 'digraph {\n\tA [label="%s"]\n\tB [label="%s"]\n}' % (r'\\', r'\"\\\"')),
106 ], ids=lambda p: getattr(p, '__name__', '...'))
107 def test_escaped_quotes_and_escapes(cls, expected):
108 dot = cls()
109 dot.node('A', label='\\\\')
110 dot.node('B', label=r'"\\"')
111 assert dot.source == expected
112
113
114 @pytest.mark.parametrize('cls, expected', [
115 (Graph, 'graph {\n\t// comment\n\tsubgraph name {\n\t}\n}'),
116 (Digraph, 'digraph {\n\t// comment\n\tsubgraph name {\n\t}\n}'),
117 ], ids=lambda p: getattr(p, '__name__', '...'))
118 def test_subgraph_graph_none(cls, expected):
119 dot = cls(directory='nondirectory', format='png',
120 encoding='ascii', engine='neato')
121 assert dot.strict is False
122
123 with dot.subgraph(name='name', comment='comment') as child:
124 assert child.directory == dot.directory
125 assert child.format == dot.format
126 assert child.engine == dot.engine
127 assert child.encoding == dot.encoding
128 assert child.strict is None
129
130 assert dot.source == expected
131
132
133 def test_subgraph_graph_notsole(cls):
134 with pytest.raises(ValueError, match=r'sole'):
135 cls().subgraph(cls(), name='spam')
136
137
138 def test_subgraph_mixed(classes):
139 cls1, cls2 = classes
140 with pytest.raises(ValueError, match=r'kind'):
141 cls1().subgraph(cls2())
142
143
144 @pytest.mark.parametrize('cls, expected', [
145 (Graph, 'graph {\n\t{\n\t}\n}'),
146 (Digraph, 'digraph {\n\t{\n\t}\n}'),
147 ], ids=lambda p: getattr(p, '__name__', '...'))
148 def test_subgraph_reflexive(cls, expected): # guard against potential infinite loop
149 dot = cls()
150 dot.subgraph(dot)
151 assert dot.source == expected
152
153
154 def test_subgraph():
155 s1 = Graph()
156 s1.node('A')
157 s1.node('B')
158 s1.node('C')
159 s1.edge('A', 'B', constraint='false')
160 s1.edges(['AC', 'BC'])
161
162 s2 = Graph()
163 s2.node('D')
164 s2.node('E')
165 s2.node('F')
166 s2.edge('D', 'E', constraint='false')
167 s2.edges(['DF', 'EF'])
168
169 dot = Graph()
170 dot.subgraph(s1)
171 dot.subgraph(s2)
172 dot.attr('edge', style='dashed')
173 dot.edges(['AD', 'BE', 'CF'])
174
175 assert dot.source == '''graph {
176 \t{
177 \t\tA
178 \t\tB
179 \t\tC
180 \t\tA -- B [constraint=false]
181 \t\tA -- C
182 \t\tB -- C
183 \t}
184 \t{
185 \t\tD
186 \t\tE
187 \t\tF
188 \t\tD -- E [constraint=false]
189 \t\tD -- F
190 \t\tE -- F
191 \t}
192 \tedge [style=dashed]
193 \tA -- D
194 \tB -- E
195 \tC -- F
196 }'''
197
198
199 @pytest.mark.exe
200 @pytest.mark.parametrize('cls, expected', [
201 (Graph, 'graph {\n\tC\n}\n'),
202 (Digraph, 'digraph {\n\tC\n}\n'),
203 ], ids=lambda p: getattr(p, '__name__', '...'))
204 def test_subgraph_render(capsys, tmp_path, cls, expected):
205 lpath = tmp_path / 's1.gv'
206 rendered = lpath.with_suffix('.gv.pdf')
207
208 dot = cls()
209 dot.edge('A', 'B')
210
211 with dot.subgraph() as s1:
212 s1.node('C')
213 result = s1.render(str(lpath))
214
215 assert result == str(rendered)
216
217 assert lpath.read_text(encoding='ascii') == expected
218
219 assert rendered.stat().st_size
220 assert capsys.readouterr() == ('', '')
221
222
223 def test_label_html():
224 """http://www.graphviz.org/doc/info/shapes.html#html"""
225 dot = Digraph('structs', node_attr={'shape': 'plaintext'})
226 dot.node('struct1', '''<
227 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
228 <TR>
229 <TD>left</TD>
230 <TD PORT="f1">middle</TD>
231 <TD PORT="f2">right</TD>
232 </TR>
233 </TABLE>>''')
234 dot.node('struct2', '''<
235 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
236 <TR>
237 <TD PORT="f0">one</TD>
238 <TD>two</TD>
239 </TR>
240 </TABLE>>''')
241 dot.node('struct3', '''<
242 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
243 <TR>
244 <TD ROWSPAN="3">hello<BR/>world</TD>
245 <TD COLSPAN="3">b</TD>
246 <TD ROWSPAN="3">g</TD>
247 <TD ROWSPAN="3">h</TD>
248 </TR>
249 <TR>
250 <TD>c</TD>
251 <TD PORT="here">d</TD>
252 <TD>e</TD>
253 </TR>
254 <TR>
255 <TD COLSPAN="3">f</TD>
256 </TR>
257 </TABLE>>''')
258 dot.edge('struct1:f1', 'struct2:f0')
259 dot.edge('struct1:f2', 'struct3:here')
260 assert dot.source == '''digraph structs {
261 \tnode [shape=plaintext]
262 \tstruct1 [label=<
263 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
264 <TR>
265 <TD>left</TD>
266 <TD PORT="f1">middle</TD>
267 <TD PORT="f2">right</TD>
268 </TR>
269 </TABLE>>]
270 \tstruct2 [label=<
271 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
272 <TR>
273 <TD PORT="f0">one</TD>
274 <TD>two</TD>
275 </TR>
276 </TABLE>>]
277 \tstruct3 [label=<
278 <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4">
279 <TR>
280 <TD ROWSPAN="3">hello<BR/>world</TD>
281 <TD COLSPAN="3">b</TD>
282 <TD ROWSPAN="3">g</TD>
283 <TD ROWSPAN="3">h</TD>
284 </TR>
285 <TR>
286 <TD>c</TD>
287 <TD PORT="here">d</TD>
288 <TD>e</TD>
289 </TR>
290 <TR>
291 <TD COLSPAN="3">f</TD>
292 </TR>
293 </TABLE>>]
294 \tstruct1:f1 -> struct2:f0
295 \tstruct1:f2 -> struct3:here
296 }'''
0 # test_files.py
1
2 import locale
3
4 import pytest
5
6 from graphviz.files import Source
7
8 SOURCE = {
9 'source': 'digraph { hello -> world }',
10 'filename': 'hello.gv', 'directory': 'test-output',
11 'format': 'PNG', 'engine': 'NEATO', 'encoding': 'utf-8',
12 }
13
14
15 @pytest.fixture(scope='module')
16 def source():
17 return Source(**SOURCE)
18
19
20 def test_format(source):
21 assert not SOURCE['format'].islower()
22
23 assert source.format == SOURCE['format'].lower()
24 with pytest.raises(ValueError, match=r'format'):
25 source.format = ''
26
27
28 def test_engine(source):
29 assert not SOURCE['engine'].islower()
30
31 assert source.engine == SOURCE['engine'].lower()
32 with pytest.raises(ValueError, match=r'engine'):
33 source.engine = ''
34
35
36 def test_encoding(source):
37 assert source.encoding == SOURCE['encoding']
38
39 with pytest.raises(LookupError, match=r'encoding'):
40 source.encoding = ''
41
42
43 def test_encoding_none(source):
44 source_copy = source.copy()
45 source_copy.encoding = None
46 assert source_copy.encoding == locale.getpreferredencoding()
47
48
49 def test_init(source):
50 assert source.source == SOURCE['source']
51 assert source.filename == SOURCE['filename']
52 assert source.directory == SOURCE['directory']
53
54
55 def test_init_filename():
56 assert Source('').filename == 'Source.gv'
57 assert type('Named', (Source,), {'name': 'name'})('').filename == 'name.gv'
58
59
60 def test__repr_svg_(mocker, source):
61 pipe = mocker.patch.object(source, 'pipe', autospec=True,
62 **{'return_value.decode.return_value':
63 mocker.sentinel.decoded})
64
65 assert source._repr_svg_() is mocker.sentinel.decoded
66
67 pipe.assert_called_once_with(format='svg')
68 pipe.return_value.decode.assert_called_once_with(source.encoding)
69
70
71 def test_pipe_format(pipe, source, format_='svg'):
72 assert source.format != format_
73
74 assert source.pipe(format=format_) is pipe.return_value
75
76 data = source.source.encode(source.encoding)
77 pipe.assert_called_once_with(source.engine, format_, data,
78 renderer=None, formatter=None,
79 quiet=False)
80
81
82 def test_pipe(pipe, source):
83 assert source.pipe() is pipe.return_value
84
85 data = source.source.encode(source.encoding)
86 pipe.assert_called_once_with(source.engine, source.format, data,
87 renderer=None, formatter=None,
88 quiet=False)
89
90
91 def test_filepath(test_platform, source):
92 if test_platform == 'windows':
93 assert source.filepath == 'test-output\\hello.gv'
94 else:
95 assert source.filepath == 'test-output/hello.gv'
96
97
98 def test_save(mocker, py2, filename='nonfilename', directory='nondirectory'):
99 source = Source(**SOURCE)
100 makedirs = mocker.patch('os.makedirs', autospec=True)
101 open_ = mocker.patch('io.open', mocker.mock_open())
102
103 assert source.save(filename, directory) == source.filepath
104
105 assert source.filename == filename and source.directory == directory
106 if py2:
107 makedirs.assert_called_once_with(source.directory, 0o777)
108 else:
109 makedirs.assert_called_once_with(source.directory, 0o777, exist_ok=True)
110 open_.assert_called_once_with(source.filepath, 'w',
111 encoding=source.encoding)
112 assert open_.return_value.write.call_args_list == [mocker.call(source.source),
113 mocker.call(u'\n')]
114
115
116 def test_render(mocker, render, source):
117 save = mocker.patch.object(source, 'save', autospec=True,
118 **{'return_value': mocker.sentinel.nonfilepath})
119 _view = mocker.patch.object(source, '_view', autospec=True)
120 remove = mocker.patch('os.remove', autospec=True)
121
122 assert source.render(cleanup=True, view=True) is render.return_value
123
124 save.assert_called_once_with(None, None)
125 render.assert_called_once_with(source.engine, source.format,
126 save.return_value,
127 renderer=None, formatter=None,
128 quiet=False)
129 remove.assert_called_once_with(save.return_value)
130 _view.assert_called_once_with(render.return_value, source.format, False)
131
132
133 def test_view(mocker, source):
134 render = mocker.patch.object(source, 'render', autospec=True)
135 kwargs = {'filename': 'filename', 'directory': 'directory',
136 'cleanup': True, 'quiet': True, 'quiet_view': True}
137
138 assert source.view(**kwargs) is render.return_value
139
140 render.assert_called_once_with(view=True, **kwargs)
141
142
143 def test__view_unknown_platform(unknown_platform, source):
144 with pytest.raises(RuntimeError, match=r'support'):
145 source._view('name', 'png', False)
146
147
148 def test__view(mocker, platform, source):
149 _view_platform = mocker.patch.object(source, '_view_%s' % platform,
150 autospec=True)
151
152 assert source._view(mocker.sentinel.name, 'png', False) is None
153
154 _view_platform.assert_called_once_with(mocker.sentinel.name, False)
155
156
157 def test_copy(source):
158 assert source.copy() is not source
159 assert source.copy() is not source.copy()
160 assert source.copy().__class__ is source.__class__
161 assert source.copy().__dict__ == source.__dict__ == source.copy().__dict__
162
163
164 def test_from_file(tmpdir, filename='hello.gv', directory='source_hello',
165 data=u'digraph { hello -> world }', encoding='utf-8'):
166 lpath = tmpdir.mkdir(directory)
167 (lpath / filename).write_text(data, encoding=encoding)
168
169 source = Source.from_file(filename, str(lpath))
170 assert source.encoding == 'utf-8'
171
172 source = Source.from_file(filename, str(lpath), encoding=None)
173 assert source.encoding == locale.getpreferredencoding()
174
175 source = Source.from_file(filename, str(lpath), encoding=encoding)
176 assert source.source == data
177 assert source.filename == filename
178 assert source.directory == str(lpath)
179 assert source.encoding == encoding
0 # test_files.py
1
2 import locale
3 import re
4
5 import pytest
6
7 from graphviz.files import Source
8
9 SOURCE = {'source': 'digraph { hello -> world }',
10 'filename': 'hello.gv', 'directory': 'test-output',
11 'format': 'PNG', 'engine': 'NEATO', 'encoding': 'utf-8'}
12
13
14 @pytest.fixture(scope='module')
15 def source():
16 return Source(**SOURCE)
17
18
19 def test_engine(source):
20 assert not SOURCE['engine'].islower()
21
22 assert source.engine == SOURCE['engine'].lower()
23 with pytest.raises(ValueError, match=r'engine'):
24 source.engine = ''
25
26
27 def test_format(source):
28 assert not SOURCE['format'].islower()
29
30 assert source.format == SOURCE['format'].lower()
31 with pytest.raises(ValueError, match=r'format'):
32 source.format = ''
33
34
35 def test_encoding(source):
36 assert source.encoding == SOURCE['encoding']
37
38 with pytest.raises(LookupError, match=r'encoding'):
39 source.encoding = ''
40
41
42 def test_encoding_none(source):
43 source_copy = source.copy()
44 source_copy.encoding = None
45 assert source_copy.encoding == locale.getpreferredencoding()
46
47
48 def test_init(source):
49 assert source.source == SOURCE['source']
50 assert source.filename == SOURCE['filename']
51 assert source.directory == SOURCE['directory']
52
53
54 def test_init_filename():
55 assert Source('').filename == 'Source.gv'
56 assert type('Named', (Source,), {'name': 'name'})('').filename == 'name.gv'
57
58
59 def test_str(source):
60 assert str(source) == source.source
61
62
63 @pytest.mark.exe
64 def test_unflatten(source):
65 result = source.unflatten()
66 assert isinstance(result, Source)
67
68 normalized = re.sub(r'\s+', ' ', result.source.strip())
69 assert normalized == 'digraph { hello -> world; }'
70
71
72 def test__repr_svg_(mocker, source):
73 pipe = mocker.patch.object(source, 'pipe', autospec=True,
74 **{'return_value.decode.return_value':
75 mocker.sentinel.decoded})
76
77 assert source._repr_svg_() is mocker.sentinel.decoded
78
79 pipe.assert_called_once_with(format='svg')
80 pipe.return_value.decode.assert_called_once_with(source.encoding)
81
82
83 def test_pipe_format(pipe, source, format_='svg'):
84 assert source.format != format_
85
86 assert source.pipe(format=format_) is pipe.return_value
87
88 data = source.source.encode(source.encoding)
89 pipe.assert_called_once_with(source.engine, format_, data,
90 renderer=None, formatter=None,
91 quiet=False)
92
93
94 def test_pipe(pipe, source):
95 assert source.pipe() is pipe.return_value
96
97 data = source.source.encode(source.encoding)
98 pipe.assert_called_once_with(source.engine, source.format, data,
99 renderer=None, formatter=None,
100 quiet=False)
101
102
103 def test_filepath(platform, source):
104 if platform == 'windows':
105 assert source.filepath == 'test-output\\hello.gv'
106 else:
107 assert source.filepath == 'test-output/hello.gv'
108
109
110 def test_save(mocker, filename='nonfilename', directory='nondirectory'):
111 source = Source(**SOURCE)
112 makedirs = mocker.patch('os.makedirs', autospec=True)
113 open_ = mocker.patch('builtins.open', mocker.mock_open())
114
115 assert source.save(filename, directory) == source.filepath
116
117 assert source.filename == filename and source.directory == directory
118 makedirs.assert_called_once_with(source.directory, 0o777, exist_ok=True)
119 open_.assert_called_once_with(source.filepath, 'w',
120 encoding=source.encoding)
121 assert open_.return_value.write.call_args_list == [mocker.call(source.source),
122 mocker.call('\n')]
123
124
125 def test_render(mocker, render, source):
126 save = mocker.patch.object(source, 'save', autospec=True,
127 **{'return_value': mocker.sentinel.nonfilepath})
128 _view = mocker.patch.object(source, '_view', autospec=True)
129 remove = mocker.patch('os.remove', autospec=True)
130
131 assert source.render(cleanup=True, view=True) is render.return_value
132
133 save.assert_called_once_with(None, None)
134 render.assert_called_once_with(source.engine, source.format,
135 save.return_value,
136 renderer=None, formatter=None,
137 quiet=False)
138 remove.assert_called_once_with(save.return_value)
139 _view.assert_called_once_with(render.return_value, source.format, False)
140
141
142 def test_view(mocker, source):
143 render = mocker.patch.object(source, 'render', autospec=True)
144 kwargs = {'filename': 'filename', 'directory': 'directory',
145 'cleanup': True, 'quiet': True, 'quiet_view': True}
146
147 assert source.view(**kwargs) is render.return_value
148
149 render.assert_called_once_with(view=True, **kwargs)
150
151
152 def test__view_unknown_platform(unknown_platform, source):
153 with pytest.raises(RuntimeError, match=r'support'):
154 source._view('name', 'png', False)
155
156
157 def test__view(mocker, mock_platform, source):
158 _view_platform = mocker.patch.object(source, f'_view_{mock_platform}',
159 autospec=True)
160
161 kwargs = {'quiet': False}
162
163 assert source._view(mocker.sentinel.name, 'png', **kwargs) is None
164
165 _view_platform.assert_called_once_with(mocker.sentinel.name, **kwargs)
166
167
168 def test_copy(source):
169 assert source.copy() is not source
170 assert source.copy() is not source.copy()
171 assert source.copy().__class__ is source.__class__
172 assert source.copy().__dict__ == source.__dict__ == source.copy().__dict__
173
174
175 def test_from_file(tmp_path, filename='hello.gv', directory='source_hello',
176 data='digraph { hello -> world }', encoding='utf-8'):
177 lpath = tmp_path / directory
178 lpath.mkdir()
179 (lpath / filename).write_text(data, encoding=encoding)
180
181 source = Source.from_file(filename, str(lpath))
182 assert source.encoding == 'utf-8'
183
184 source = Source.from_file(filename, str(lpath), encoding=None)
185 assert source.encoding == locale.getpreferredencoding()
186
187 source = Source.from_file(filename, str(lpath), encoding=encoding)
188 assert source.source == data
189 assert source.filename == filename
190 assert source.directory == str(lpath)
191 assert source.encoding == encoding
0 # test_lang.py
1
2 import sys
3 import warnings
4
5 import pytest
6
7 from graphviz.lang import quote, attr_list, nohtml
8
9
10 @pytest.mark.parametrize('char', ['G', 'E', 'T', 'H', 'L', 'l'])
11 def test_deprecated_escape(recwarn, char):
12 warnings.simplefilter('always')
13
14 escape = eval(r'"\%s"' % char)
15
16 if sys.version_info < (3, 6):
17 assert not recwarn
18 else:
19 assert len(recwarn) == 1
20 w = recwarn.pop(DeprecationWarning)
21 assert str(w.message).startswith('invalid escape sequence')
22
23 assert escape == '\\%s' % char
24 assert quote(escape) == '"\\%s"' % char
25
26
27 @pytest.mark.parametrize('identifier, expected', [
28 ('"spam"', r'"\"spam\""'),
29 ('node', '"node"'),
30 ('EDGE', '"EDGE"'),
31 ('Graph', '"Graph"'),
32 ('\\G \\N \\E \\T \\H \\L', '"\\G \\N \\E \\T \\H \\L"'),
33 ('\\n \\l \\r', '"\\n \\l \\r"'),
34 ('\r\n', '"\r\n"'),
35 ('\\\\n', r'"\\n"'),
36 (u'\u0665.\u0660', u'"\u0665.\u0660"'),
37 ('\\"spam', r'"\"spam"'),
38 ('\\\\"spam', r'"\\\"spam"'),
39 ('\\\\\\"spam', r'"\\\"spam"'),
40 ('\\\\\\\\"spam', r'"\\\\\"spam"'),
41 ])
42 def test_quote(identifier, expected):
43 assert quote(identifier) == expected
44
45
46 @pytest.mark.parametrize('attributes, expected', [
47 ([('spam', 'eggs')], ' [spam=eggs]'),
48 ({'spam': 'eggs'}, ' [spam=eggs]'),
49 ])
50 def test_attr_list(attributes, expected):
51 assert attr_list(attributes=attributes) == expected
52
53
54 @pytest.mark.parametrize('string', ['spam', u'spam'])
55 def test_nohtml(string):
56 result = nohtml(string)
57 assert result == string
58 assert isinstance(result, type(string))
59
60
61 def test_nohtml_invalid(py2):
62 match = r"required types.+'str'"
63 if py2:
64 match += r".+'unicode'"
65 with pytest.raises(TypeError, match=match):
66 nohtml(True)
0 # test_lang.py
1
2 import warnings
3
4 import pytest
5
6 from graphviz import lang
7
8
9 @pytest.mark.parametrize('char', ['G', 'E', 'T', 'H', 'L', 'l'])
10 def test_deprecated_escape(recwarn, char):
11 warnings.simplefilter('always')
12
13 escape = eval(rf'"\{char}"')
14
15 assert len(recwarn) == 1
16 w = recwarn.pop(DeprecationWarning)
17 assert str(w.message).startswith('invalid escape sequence')
18
19 assert escape == f'\\{char}'
20 assert lang.quote(escape) == f'"\\{char}"'
21
22
23 @pytest.mark.parametrize('identifier, expected', [
24 ('"spam"', r'"\"spam\""'),
25 ('node', '"node"'),
26 ('EDGE', '"EDGE"'),
27 ('Graph', '"Graph"'),
28 ('\\G \\N \\E \\T \\H \\L', '"\\G \\N \\E \\T \\H \\L"'),
29 ('\\n \\l \\r', '"\\n \\l \\r"'),
30 ('\r\n', '"\r\n"'),
31 ('\\\\n', r'"\\n"'),
32 ('\u0665.\u0660', '"\u0665.\u0660"'),
33 ('\\"spam', r'"\"spam"'),
34 ('\\\\"spam', r'"\\\"spam"'),
35 ('\\\\\\"spam', r'"\\\"spam"'),
36 ('\\\\\\\\"spam', r'"\\\\\"spam"'),
37 ])
38 def test_quote(identifier, expected):
39 assert lang.quote(identifier) == expected
40
41
42 @pytest.mark.parametrize('attributes, expected', [
43 ([('spam', 'eggs')], ' [spam=eggs]'),
44 ({'spam': 'eggs'}, ' [spam=eggs]'),
45 ])
46 def test_attr_list(attributes, expected):
47 assert lang.attr_list(attributes=attributes) == expected
48
49
50 @pytest.mark.parametrize('string, expected, expected_quoted', [
51 ('spam', 'spam', 'spam'),
52 ('<>-*-<>', '<>-*-<>', '"<>-*-<>"'),
53 ])
54 def test_nohtml(string, expected, expected_quoted):
55 result = lang.nohtml(string)
56 assert isinstance(result, str)
57 assert isinstance(result, lang.NoHtml)
58 assert result == expected
59
60 quoted = lang.quote(result)
61 assert isinstance(quoted, str)
62 assert quoted == expected_quoted
0 # test_tools.py
1
2 import os
3 import functools
4
5 import pytest
6
7 from graphviz.tools import mkdirs
8
9
10 def itertree(root):
11 for path, dirs, files in os.walk(root):
12 base = os.path.relpath(path, root)
13 rel_path = functools.partial(os.path.join, base if base != '.' else '')
14 for is_file, names in enumerate((dirs, files)):
15 for n in names:
16 yield bool(is_file), rel_path(n).replace('\\', '/')
17
18
19 def test_mkdirs_invalid(tmpdir):
20 with tmpdir.as_cwd():
21 (tmpdir / 'spam.eggs').write_binary(b'')
22 with pytest.raises(OSError):
23 mkdirs('spam.eggs/spam')
24
25
26 def test_mkdirs(tmpdir):
27 with tmpdir.as_cwd():
28 mkdirs('spam.eggs')
29 assert list(itertree(str(tmpdir))) == []
30 for _ in range(2):
31 mkdirs('spam/eggs/spam.eggs')
32 assert list(itertree(str(tmpdir))) == [(False, 'spam'),
33 (False, 'spam/eggs')]
0 # test_tools.py
1
2 import functools
3 import os
4
5 import pytest
6
7 from graphviz.tools import mkdirs
8
9 import utils
10
11
12 def itertree(root):
13 for path, dirs, files in os.walk(root):
14 base = os.path.relpath(path, root)
15 rel_path = functools.partial(os.path.join, base if base != '.' else '')
16 for is_file, names in enumerate((dirs, files)):
17 for n in names:
18 yield bool(is_file), rel_path(n).replace('\\', '/')
19
20
21 def test_mkdirs_invalid(tmp_path):
22 with utils.as_cwd(tmp_path):
23 (tmp_path / 'spam.eggs').write_bytes(b'')
24 with pytest.raises(OSError):
25 mkdirs('spam.eggs/spam')
26
27
28 def test_mkdirs(tmp_path):
29 with utils.as_cwd(tmp_path):
30 mkdirs('spam.eggs')
31 assert list(itertree(str(tmp_path))) == []
32 for _ in range(2):
33 mkdirs('spam/eggs/spam.eggs')
34 assert list(itertree(str(tmp_path))) == [(False, 'spam'),
35 (False, 'spam/eggs')]
0 # utils.py
1
2 import contextlib
3 import os
4 import pathlib
5
6
7 @contextlib.contextmanager
8 def as_cwd(path):
9 """Return a context manager, which changes to the path’s dir during the managed “with” context."""
10 cwd = pathlib.Path().resolve()
11 os.chdir(path)
12 yield
13 os.chdir(cwd)
0 [tox]
1 envlist = py{27,35,36,37,38}
2 skip_missing_interpreters = true
3
4 [testenv]
5 extras = test
6 commands = ./run-tests.py {posargs}
0 [tox]
1 envlist = py{39,38,37,36}
2 skip_missing_interpreters = true
3
4 [testenv]
5 extras = test
6 commands = ./run-tests.py {posargs}
0 #!/usr/bin/env python
1 # try-examples.py - import graphviz here and run all scripts in the example dir
2
3 import os
4 import io
5 import glob
6
7 import graphviz # noqa: F401
8
9 os.chdir('examples')
10 for filename in glob.iglob('*.py'):
11 with io.open(filename, encoding='utf-8') as fd:
12 code = fd.read()
13 exec(code)
0 #!/usr/bin/env python3
1
2 """Import ``graphviz`` here and run all scripts in the ``examples/`` dir."""
3
4 import os
5 import pathlib
6 import warnings
7
8 import graphviz # noqa: F401
9
10 EXAMPLES = pathlib.Path('examples')
11
12 os.chdir(EXAMPLES)
13
14 for path in pathlib.Path().glob('*.py'):
15 code = path.read_text(encoding='utf-8')
16 try:
17 exec(code)
18 except Exception as e:
19 warnings.warn(e)