Import upstream version 0.16+git20210515.1.bb1af2e
Debian Janitor
2 years ago
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 ``'−'`` 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 ``'−'`` 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 |
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 | |
158 | 181 | :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->n14 --> | |
86 | <g id="edge1" class="edge"><title>n5->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->n14 --> | |
94 | <g id="edge1" class="edge"> | |
95 | <title>n5->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->node1 --> | |
30 | <g id="edge2" class="edge"><title>node0:f0->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->node4 --> | |
44 | <g id="edge1" class="edge"><title>node0:f2->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->node2 --> | |
58 | <g id="edge3" class="edge"><title>node1:f0->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->node3 --> | |
72 | <g id="edge4" class="edge"><title>node1:f2->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->node7 --> | |
86 | <g id="edge6" class="edge"><title>node2:f0->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->node8 --> | |
100 | <g id="edge5" class="edge"><title>node2:f2->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->node5 --> | |
114 | <g id="edge8" class="edge"><title>node4:f0->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->node6 --> | |
128 | <g id="edge7" class="edge"><title>node4:f2->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->node1 --> | |
32 | <g id="edge2" class="edge"> | |
33 | <title>node0:f0->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->node4 --> | |
48 | <g id="edge1" class="edge"> | |
49 | <title>node0:f2->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->node2 --> | |
64 | <g id="edge3" class="edge"> | |
65 | <title>node1:f0->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->node3 --> | |
80 | <g id="edge4" class="edge"> | |
81 | <title>node1:f2->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->node7 --> | |
96 | <g id="edge6" class="edge"> | |
97 | <title>node2:f0->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->node8 --> | |
112 | <g id="edge5" class="edge"> | |
113 | <title>node2:f2->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->node5 --> | |
128 | <g id="edge8" class="edge"> | |
129 | <title>node4:f0->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->node6 --> | |
144 | <g id="edge7" class="edge"> | |
145 | <title>node4:f2->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->a1 --> | |
30 | <g id="edge1" class="edge"><title>a0->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->a2 --> | |
40 | <g id="edge2" class="edge"><title>a1->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->b3 --> | |
50 | <g id="edge9" class="edge"><title>a1->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->a3 --> | |
60 | <g id="edge3" class="edge"><title>a2->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->a0 --> | |
65 | <g id="edge11" class="edge"><title>a3->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->end --> | |
79 | <g id="edge12" class="edge"><title>a3->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->b1 --> | |
94 | <g id="edge4" class="edge"><title>b0->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->b2 --> | |
104 | <g id="edge5" class="edge"><title>b1->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->a3 --> | |
109 | <g id="edge10" class="edge"><title>b2->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->b3 --> | |
114 | <g id="edge6" class="edge"><title>b2->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->end --> | |
119 | <g id="edge13" class="edge"><title>b3->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->a0 --> | |
133 | <g id="edge7" class="edge"><title>start->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->b0 --> | |
138 | <g id="edge8" class="edge"><title>start->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->a1 --> | |
34 | <g id="edge1" class="edge"> | |
35 | <title>a0->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->a2 --> | |
46 | <g id="edge2" class="edge"> | |
47 | <title>a1->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->b3 --> | |
58 | <g id="edge9" class="edge"> | |
59 | <title>a1->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->a3 --> | |
70 | <g id="edge3" class="edge"> | |
71 | <title>a2->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->a0 --> | |
76 | <g id="edge11" class="edge"> | |
77 | <title>a3->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->end --> | |
92 | <g id="edge12" class="edge"> | |
93 | <title>a3->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->b1 --> | |
110 | <g id="edge4" class="edge"> | |
111 | <title>b0->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->b2 --> | |
122 | <g id="edge5" class="edge"> | |
123 | <title>b1->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->a3 --> | |
128 | <g id="edge10" class="edge"> | |
129 | <title>b2->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->b3 --> | |
134 | <g id="edge6" class="edge"> | |
135 | <title>b2->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->end --> | |
140 | <g id="edge13" class="edge"> | |
141 | <title>b3->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->a0 --> | |
156 | <g id="edge7" class="edge"> | |
157 | <title>start->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->b0 --> | |
162 | <g id="edge8" class="edge"> | |
163 | <title>start->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->b --> | |
28 | <g id="edge1" class="edge"><title>a->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->c --> | |
38 | <g id="edge2" class="edge"><title>a->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->d --> | |
48 | <g id="edge3" class="edge"><title>b->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->f --> | |
58 | <g id="edge7" class="edge"><title>b->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->d --> | |
63 | <g id="edge4" class="edge"><title>c->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->e --> | |
73 | <g id="edge10" class="edge"><title>c->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->g --> | |
83 | <g id="edge9" class="edge"><title>c->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->e --> | |
88 | <g id="edge8" class="edge"><title>d->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->h --> | |
98 | <g id="edge11" class="edge"><title>d->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->g --> | |
103 | <g id="edge5" class="edge"><title>e->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->f --> | |
108 | <g id="edge6" class="edge"><title>e->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->b --> | |
32 | <g id="edge1" class="edge"> | |
33 | <title>a->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->c --> | |
44 | <g id="edge2" class="edge"> | |
45 | <title>a->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->d --> | |
56 | <g id="edge3" class="edge"> | |
57 | <title>b->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->f --> | |
68 | <g id="edge7" class="edge"> | |
69 | <title>b->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->d --> | |
74 | <g id="edge4" class="edge"> | |
75 | <title>c->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->e --> | |
86 | <g id="edge10" class="edge"> | |
87 | <title>c->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->g --> | |
98 | <g id="edge9" class="edge"> | |
99 | <title>c->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->e --> | |
104 | <g id="edge8" class="edge"> | |
105 | <title>d->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->h --> | |
116 | <g id="edge11" class="edge"> | |
117 | <title>d->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->g --> | |
122 | <g id="edge5" class="edge"> | |
123 | <title>e->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->f --> | |
128 | <g id="edge6" class="edge"> | |
129 | <title>e->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"><></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"><></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-I --> | |
19 | <g id="node10" class="node"><title>C-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-I</text> | |
22 | </g> | |
23 | <!-- course--C-I --> | |
24 | <g id="edge3" class="edge"><title>course--C-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--name1 --> | |
39 | <g id="edge5" class="edge"><title>institute--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-I --> | |
43 | <g id="node12" class="node"><title>S-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-I</text> | |
46 | </g> | |
47 | <!-- institute--S-I --> | |
48 | <g id="edge6" class="edge"><title>institute--S-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--name2 --> | |
63 | <g id="edge9" class="edge"><title>student--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--grade --> | |
72 | <g id="edge8" class="edge"><title>student--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--number --> | |
81 | <g id="edge10" class="edge"><title>student--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-C --> | |
85 | <g id="node11" class="node"><title>S-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-C</text> | |
88 | </g> | |
89 | <!-- student--S-C --> | |
90 | <g id="edge11" class="edge"><title>student--S-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--course --> | |
100 | <g id="edge1" class="edge"><title>name0--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--course --> | |
109 | <g id="edge2" class="edge"><title>code--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-I--institute --> | |
113 | <g id="edge4" class="edge"><title>C-I--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-C--course --> | |
118 | <g id="edge12" class="edge"><title>S-C--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-I--student --> | |
123 | <g id="edge7" class="edge"><title>S-I--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-I --> | |
20 | <g id="node10" class="node"> | |
21 | <title>C-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-I</text> | |
24 | </g> | |
25 | <!-- course--C-I --> | |
26 | <g id="edge3" class="edge"> | |
27 | <title>course--C-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--name1 --> | |
44 | <g id="edge5" class="edge"> | |
45 | <title>institute--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-I --> | |
49 | <g id="node12" class="node"> | |
50 | <title>S-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-I</text> | |
53 | </g> | |
54 | <!-- institute--S-I --> | |
55 | <g id="edge6" class="edge"> | |
56 | <title>institute--S-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--name2 --> | |
73 | <g id="edge9" class="edge"> | |
74 | <title>student--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--grade --> | |
84 | <g id="edge8" class="edge"> | |
85 | <title>student--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--number --> | |
95 | <g id="edge10" class="edge"> | |
96 | <title>student--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-C --> | |
100 | <g id="node11" class="node"> | |
101 | <title>S-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-C</text> | |
104 | </g> | |
105 | <!-- student--S-C --> | |
106 | <g id="edge11" class="edge"> | |
107 | <title>student--S-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--course --> | |
118 | <g id="edge1" class="edge"> | |
119 | <title>name0--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--course --> | |
129 | <g id="edge2" class="edge"> | |
130 | <title>code--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-I--institute --> | |
134 | <g id="edge4" class="edge"> | |
135 | <title>C-I--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-C--course --> | |
140 | <g id="edge12" class="edge"> | |
141 | <title>S-C--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-I--student --> | |
146 | <g id="edge7" class="edge"> | |
147 | <title>S-I--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--__0:clusterB --> | |
27 | <g id="edge7" class="edge"><title>e--__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--b --> | |
41 | <g id="edge1" class="edge"><title>a--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--D --> | |
55 | <g id="edge2" class="edge"><title>C--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--D --> | |
64 | <g id="edge4" class="edge"><title>d--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--f --> | |
73 | <g id="edge3" class="edge"><title>d--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--__2:clusterB --> | |
79 | <g id="edge8" class="edge"><title>__1:clusterC--__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--__0:clusterB --> | |
31 | <g id="edge7" class="edge"> | |
32 | <title>e--__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--b --> | |
48 | <g id="edge1" class="edge"> | |
49 | <title>a--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--D --> | |
65 | <g id="edge2" class="edge"> | |
66 | <title>C--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--D --> | |
76 | <g id="edge4" class="edge"> | |
77 | <title>d--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--f --> | |
87 | <g id="edge3" class="edge"> | |
88 | <title>d--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--__2:clusterB --> | |
94 | <g id="edge8" class="edge"> | |
95 | <title>__1:clusterC--__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->LR_2 --> | |
23 | <g id="edge1" class="edge"><title>LR_0->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->LR_1 --> | |
34 | <g id="edge2" class="edge"><title>LR_0->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->LR_6 --> | |
63 | <g id="edge13" class="edge"><title>LR_8->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->LR_5 --> | |
74 | <g id="edge14" class="edge"><title>LR_8->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->LR_4 --> | |
80 | <g id="edge6" class="edge"><title>LR_2->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->LR_6 --> | |
86 | <g id="edge4" class="edge"><title>LR_2->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->LR_5 --> | |
92 | <g id="edge5" class="edge"><title>LR_2->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->LR_3 --> | |
98 | <g id="edge3" class="edge"><title>LR_1->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->LR_6 --> | |
104 | <g id="edge9" class="edge"><title>LR_6->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->LR_5 --> | |
110 | <g id="edge10" class="edge"><title>LR_6->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->LR_5 --> | |
116 | <g id="edge8" class="edge"><title>LR_5->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->LR_7 --> | |
127 | <g id="edge7" class="edge"><title>LR_5->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->LR_8 --> | |
133 | <g id="edge11" class="edge"><title>LR_7->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->LR_5 --> | |
139 | <g id="edge12" class="edge"><title>LR_7->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->LR_2 --> | |
25 | <g id="edge1" class="edge"> | |
26 | <title>LR_0->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->LR_1 --> | |
38 | <g id="edge2" class="edge"> | |
39 | <title>LR_0->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->LR_6 --> | |
72 | <g id="edge13" class="edge"> | |
73 | <title>LR_8->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->LR_5 --> | |
85 | <g id="edge14" class="edge"> | |
86 | <title>LR_8->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->LR_4 --> | |
92 | <g id="edge6" class="edge"> | |
93 | <title>LR_2->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->LR_6 --> | |
99 | <g id="edge4" class="edge"> | |
100 | <title>LR_2->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->LR_5 --> | |
106 | <g id="edge5" class="edge"> | |
107 | <title>LR_2->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->LR_3 --> | |
113 | <g id="edge3" class="edge"> | |
114 | <title>LR_1->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->LR_6 --> | |
120 | <g id="edge9" class="edge"> | |
121 | <title>LR_6->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->LR_5 --> | |
127 | <g id="edge10" class="edge"> | |
128 | <title>LR_6->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->LR_5 --> | |
134 | <g id="edge8" class="edge"> | |
135 | <title>LR_5->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->LR_7 --> | |
147 | <g id="edge7" class="edge"> | |
148 | <title>LR_5->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->LR_8 --> | |
154 | <g id="edge11" class="edge"> | |
155 | <title>LR_7->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->LR_5 --> | |
161 | <g id="edge12" class="edge"> | |
162 | <title>LR_7->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->World --> | |
22 | <g id="edge1" class="edge"><title>Hello->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->World --> | |
24 | <g id="edge1" class="edge"> | |
25 | <title>Hello->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->2 --> | |
22 | <g id="edge1" class="edge"><title>1->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->3 --> | |
32 | <g id="edge2" class="edge"><title>2->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->lob --> | |
42 | <g id="edge3" class="edge"><title>3->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->2 --> | |
24 | <g id="edge1" class="edge"> | |
25 | <title>1->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->3 --> | |
36 | <g id="edge2" class="edge"> | |
37 | <title>2->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->lob --> | |
48 | <g id="edge3" class="edge"> | |
49 | <title>3->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--2 --> | |
22 | <g id="edge1" class="edge"><title>1--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--3 --> | |
31 | <g id="edge2" class="edge"><title>2--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--4 --> | |
40 | <g id="edge3" class="edge"><title>3--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--5 --> | |
49 | <g id="edge4" class="edge"><title>4--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--2 --> | |
24 | <g id="edge1" class="edge"> | |
25 | <title>1--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--3 --> | |
35 | <g id="edge2" class="edge"> | |
36 | <title>2--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--4 --> | |
46 | <g id="edge3" class="edge"> | |
47 | <title>3--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--5 --> | |
57 | <g id="edge4" class="edge"> | |
58 | <title>4--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-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-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->dead --> | |
20 | <g id="edge1" class="edge"><title>parrot->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-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-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->dead --> | |
22 | <g id="edge1" class="edge"> | |
23 | <title>parrot->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--intr --> | |
22 | <g id="edge1" class="edge"><title>run--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--kernel --> | |
31 | <g id="edge4" class="edge"><title>run--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--runbl --> | |
40 | <g id="edge2" class="edge"><title>intr--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--run --> | |
44 | <g id="edge3" class="edge"><title>runbl--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--zombie --> | |
53 | <g id="edge5" class="edge"><title>kernel--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--sleep --> | |
62 | <g id="edge6" class="edge"><title>kernel--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--runmem --> | |
71 | <g id="edge7" class="edge"><title>kernel--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--runmem --> | |
75 | <g id="edge13" class="edge"><title>sleep--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--swap --> | |
84 | <g id="edge8" class="edge"><title>sleep--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--runswap --> | |
93 | <g id="edge9" class="edge"><title>swap--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--runmem --> | |
97 | <g id="edge11" class="edge"><title>runswap--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--new --> | |
106 | <g id="edge10" class="edge"><title>runswap--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--runmem --> | |
110 | <g id="edge12" class="edge"><title>new--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--intr --> | |
22 | <g id="edge1" class="edge"><title>run--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--kernel --> | |
31 | <g id="edge4" class="edge"><title>run--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--runbl --> | |
40 | <g id="edge2" class="edge"><title>intr--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--run --> | |
44 | <g id="edge3" class="edge"><title>runbl--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--zombie --> | |
53 | <g id="edge5" class="edge"><title>kernel--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--sleep --> | |
62 | <g id="edge6" class="edge"><title>kernel--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--runmem --> | |
71 | <g id="edge7" class="edge"><title>kernel--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--runmem --> | |
75 | <g id="edge13" class="edge"><title>sleep--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--swap --> | |
84 | <g id="edge8" class="edge"><title>sleep--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--runswap --> | |
93 | <g id="edge9" class="edge"><title>swap--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--runmem --> | |
97 | <g id="edge11" class="edge"><title>runswap--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--new --> | |
106 | <g id="edge10" class="edge"><title>runswap--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--runmem --> | |
110 | <g id="edge12" class="edge"><title>new--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->C --> | |
22 | <g id="edge2" class="edge"><title>A->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->B --> | |
32 | <g id="edge1" class="edge"><title>A->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->Y --> | |
47 | <g id="edge4" class="edge"><title>X->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->D --> | |
57 | <g id="edge3" class="edge"><title>C->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->C --> | |
23 | <g id="edge2" class="edge"> | |
24 | <title>A->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->B --> | |
35 | <g id="edge1" class="edge"> | |
36 | <title>A->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->Y --> | |
53 | <g id="edge4" class="edge"> | |
54 | <title>X->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->D --> | |
65 | <g id="edge3" class="edge"> | |
66 | <title>C->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->B --> | |
22 | <g id="edge1" class="edge"><title>A->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->L --> | |
32 | <g id="edge2" class="edge"><title>A->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->L --> | |
37 | <g id="edge3" class="edge"><title>B->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->B --> | |
23 | <g id="edge1" class="edge"> | |
24 | <title>A->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->L --> | |
35 | <g id="edge2" class="edge"> | |
36 | <title>A->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->L --> | |
41 | <g id="edge3" class="edge"> | |
42 | <title>B->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->struct2 --> | |
28 | <g id="edge1" class="edge"><title>struct1:f1->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->struct3 --> | |
53 | <g id="edge2" class="edge"><title>struct1:f2->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->struct2 --> | |
30 | <g id="edge1" class="edge"> | |
31 | <title>struct1:f1->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->struct3 --> | |
57 | <g id="edge2" class="edge"> | |
58 | <title>struct1:f2->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->struct2 --> | |
28 | <g id="edge1" class="edge"><title>struct1:f1->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->struct3 --> | |
53 | <g id="edge2" class="edge"><title>struct1:f2->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->struct2 --> | |
30 | <g id="edge1" class="edge"> | |
31 | <title>struct1:f1->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->struct3 --> | |
57 | <g id="edge2" class="edge"> | |
58 | <title>struct1:f2->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->yellow2 --> | |
24 | <g id="edge1" class="edge"><title>gy2->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->red2 --> | |
39 | <g id="edge4" class="edge"><title>yr2->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->safe1 --> | |
49 | <g id="edge3" class="edge"><title>yr2->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->green2 --> | |
64 | <g id="edge2" class="edge"><title>rg2->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->yellow1 --> | |
79 | <g id="edge9" class="edge"><title>gy1->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->safe2 --> | |
94 | <g id="edge11" class="edge"><title>yr1->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->red1 --> | |
104 | <g id="edge12" class="edge"><title>yr1->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->green1 --> | |
119 | <g id="edge10" class="edge"><title>rg1->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->gy2 --> | |
124 | <g id="edge6" class="edge"><title>green2->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->yr2 --> | |
129 | <g id="edge7" class="edge"><title>yellow2->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->rg2 --> | |
134 | <g id="edge8" class="edge"><title>red2->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->rg2 --> | |
139 | <g id="edge5" class="edge"><title>safe2->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->gy1 --> | |
144 | <g id="edge14" class="edge"><title>green1->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->yr1 --> | |
149 | <g id="edge15" class="edge"><title>yellow1->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->rg1 --> | |
154 | <g id="edge16" class="edge"><title>red1->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->rg1 --> | |
159 | <g id="edge13" class="edge"><title>safe1->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->yellow2 --> | |
26 | <g id="edge1" class="edge"> | |
27 | <title>gy2->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->red2 --> | |
44 | <g id="edge4" class="edge"> | |
45 | <title>yr2->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->safe1 --> | |
56 | <g id="edge3" class="edge"> | |
57 | <title>yr2->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->green2 --> | |
74 | <g id="edge2" class="edge"> | |
75 | <title>rg2->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->yellow1 --> | |
92 | <g id="edge9" class="edge"> | |
93 | <title>gy1->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->safe2 --> | |
110 | <g id="edge11" class="edge"> | |
111 | <title>yr1->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->red1 --> | |
122 | <g id="edge12" class="edge"> | |
123 | <title>yr1->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->green1 --> | |
140 | <g id="edge10" class="edge"> | |
141 | <title>rg1->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->gy2 --> | |
146 | <g id="edge6" class="edge"> | |
147 | <title>green2->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->yr2 --> | |
152 | <g id="edge7" class="edge"> | |
153 | <title>yellow2->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->rg2 --> | |
158 | <g id="edge8" class="edge"> | |
159 | <title>red2->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->rg2 --> | |
164 | <g id="edge5" class="edge"> | |
165 | <title>safe2->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->gy1 --> | |
170 | <g id="edge14" class="edge"> | |
171 | <title>green1->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->yr1 --> | |
176 | <g id="edge15" class="edge"> | |
177 | <title>yellow1->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->rg1 --> | |
182 | <g id="edge16" class="edge"> | |
183 | <title>red1->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->rg1 --> | |
188 | <g id="edge13" class="edge"> | |
189 | <title>safe1->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->6th Edition --> | |
22 | <g id="edge1" class="edge"><title>5th Edition->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->PWB 1.0 --> | |
32 | <g id="edge2" class="edge"><title>5th Edition->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->LSX --> | |
42 | <g id="edge3" class="edge"><title>6th Edition->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->1 BSD --> | |
52 | <g id="edge4" class="edge"><title>6th Edition->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->Mini Unix --> | |
62 | <g id="edge5" class="edge"><title>6th Edition->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->Wollongong --> | |
72 | <g id="edge6" class="edge"><title>6th Edition->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->Interdata --> | |
82 | <g id="edge7" class="edge"><title>6th Edition->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->PWB 1.2 --> | |
92 | <g id="edge31" class="edge"><title>PWB 1.0->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->USG 1.0 --> | |
102 | <g id="edge32" class="edge"><title>PWB 1.0->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->2 BSD --> | |
112 | <g id="edge19" class="edge"><title>1 BSD->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->Unix/TS 3.0 --> | |
122 | <g id="edge8" class="edge"><title>Interdata->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->PWB 2.0 --> | |
132 | <g id="edge9" class="edge"><title>Interdata->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->7th Edition --> | |
142 | <g id="edge10" class="edge"><title>Interdata->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->TS 4.0 --> | |
152 | <g id="edge44" class="edge"><title>Unix/TS 3.0->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->Unix/TS 3.0 --> | |
157 | <g id="edge42" class="edge"><title>PWB 2.0->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->8th Edition --> | |
167 | <g id="edge11" class="edge"><title>7th Edition->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->32V --> | |
177 | <g id="edge12" class="edge"><title>7th Edition->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->V7M --> | |
187 | <g id="edge13" class="edge"><title>7th Edition->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-11 --> | |
192 | <g id="node15" class="node"><title>Ultrix-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-11</text> | |
195 | </g> | |
196 | <!-- 7th Edition->Ultrix-11 --> | |
197 | <g id="edge14" class="edge"><title>7th Edition->Ultrix-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->Xenix --> | |
207 | <g id="edge15" class="edge"><title>7th Edition->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->UniPlus+ --> | |
217 | <g id="edge16" class="edge"><title>7th Edition->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->9th Edition --> | |
227 | <g id="edge18" class="edge"><title>8th Edition->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->3 BSD --> | |
237 | <g id="edge23" class="edge"><title>32V->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->Ultrix-11 --> | |
242 | <g id="edge17" class="edge"><title>V7M->Ultrix-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->2.8 BSD --> | |
252 | <g id="edge20" class="edge"><title>2 BSD->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->Ultrix-11 --> | |
257 | <g id="edge21" class="edge"><title>2.8 BSD->Ultrix-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->2.9 BSD --> | |
267 | <g id="edge22" class="edge"><title>2.8 BSD->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->4 BSD --> | |
277 | <g id="edge24" class="edge"><title>3 BSD->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->4.1 BSD --> | |
287 | <g id="edge25" class="edge"><title>4 BSD->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->8th Edition --> | |
292 | <g id="edge28" class="edge"><title>4.1 BSD->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->2.8 BSD --> | |
297 | <g id="edge27" class="edge"><title>4.1 BSD->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->4.2 BSD --> | |
307 | <g id="edge26" class="edge"><title>4.1 BSD->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->4.3 BSD --> | |
317 | <g id="edge29" class="edge"><title>4.2 BSD->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-32 --> | |
322 | <g id="node27" class="node"><title>Ultrix-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-32</text> | |
325 | </g> | |
326 | <!-- 4.2 BSD->Ultrix-32 --> | |
327 | <g id="edge30" class="edge"><title>4.2 BSD->Ultrix-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->PWB 2.0 --> | |
332 | <g id="edge33" class="edge"><title>PWB 1.2->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->CB Unix 1 --> | |
342 | <g id="edge34" class="edge"><title>USG 1.0->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->USG 2.0 --> | |
352 | <g id="edge35" class="edge"><title>USG 1.0->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->CB Unix 2 --> | |
362 | <g id="edge36" class="edge"><title>CB Unix 1->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->USG 3.0 --> | |
372 | <g id="edge40" class="edge"><title>USG 2.0->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->CB Unix 3 --> | |
382 | <g id="edge37" class="edge"><title>CB Unix 2->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->Unix/TS++ --> | |
392 | <g id="edge38" class="edge"><title>CB Unix 3->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-11 Sys V --> | |
397 | <g id="node35" class="node"><title>PDP-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-11 Sys V</text> | |
400 | </g> | |
401 | <!-- CB Unix 3->PDP-11 Sys V --> | |
402 | <g id="edge39" class="edge"><title>CB Unix 3->PDP-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->TS 4.0 --> | |
407 | <g id="edge46" class="edge"><title>CB Unix 3->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++->TS 4.0 --> | |
412 | <g id="edge45" class="edge"><title>Unix/TS++->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->Unix/TS 3.0 --> | |
417 | <g id="edge41" class="edge"><title>USG 3.0->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->Unix/TS 3.0 --> | |
427 | <g id="edge43" class="edge"><title>Unix/TS 1.0->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->System V.0 --> | |
437 | <g id="edge47" class="edge"><title>TS 4.0->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->System V.2 --> | |
447 | <g id="edge48" class="edge"><title>System V.0->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->System V.3 --> | |
457 | <g id="edge49" class="edge"><title>System V.2->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->6th Edition --> | |
24 | <g id="edge1" class="edge"> | |
25 | <title>5th Edition->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->PWB 1.0 --> | |
36 | <g id="edge2" class="edge"> | |
37 | <title>5th Edition->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->LSX --> | |
48 | <g id="edge3" class="edge"> | |
49 | <title>6th Edition->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->1 BSD --> | |
60 | <g id="edge4" class="edge"> | |
61 | <title>6th Edition->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->Mini Unix --> | |
72 | <g id="edge5" class="edge"> | |
73 | <title>6th Edition->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->Wollongong --> | |
84 | <g id="edge6" class="edge"> | |
85 | <title>6th Edition->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->Interdata --> | |
96 | <g id="edge7" class="edge"> | |
97 | <title>6th Edition->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->PWB 1.2 --> | |
108 | <g id="edge31" class="edge"> | |
109 | <title>PWB 1.0->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->USG 1.0 --> | |
120 | <g id="edge32" class="edge"> | |
121 | <title>PWB 1.0->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->2 BSD --> | |
132 | <g id="edge19" class="edge"> | |
133 | <title>1 BSD->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->Unix/TS 3.0 --> | |
144 | <g id="edge8" class="edge"> | |
145 | <title>Interdata->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->PWB 2.0 --> | |
156 | <g id="edge9" class="edge"> | |
157 | <title>Interdata->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->7th Edition --> | |
168 | <g id="edge10" class="edge"> | |
169 | <title>Interdata->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->TS 4.0 --> | |
180 | <g id="edge44" class="edge"> | |
181 | <title>Unix/TS 3.0->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->Unix/TS 3.0 --> | |
186 | <g id="edge42" class="edge"> | |
187 | <title>PWB 2.0->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->8th Edition --> | |
198 | <g id="edge11" class="edge"> | |
199 | <title>7th Edition->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->32V --> | |
210 | <g id="edge12" class="edge"> | |
211 | <title>7th Edition->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->V7M --> | |
222 | <g id="edge13" class="edge"> | |
223 | <title>7th Edition->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-11 --> | |
228 | <g id="node15" class="node"> | |
229 | <title>Ultrix-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-11</text> | |
232 | </g> | |
233 | <!-- 7th Edition->Ultrix-11 --> | |
234 | <g id="edge14" class="edge"> | |
235 | <title>7th Edition->Ultrix-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->Xenix --> | |
246 | <g id="edge15" class="edge"> | |
247 | <title>7th Edition->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->UniPlus+ --> | |
258 | <g id="edge16" class="edge"> | |
259 | <title>7th Edition->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->9th Edition --> | |
270 | <g id="edge18" class="edge"> | |
271 | <title>8th Edition->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->3 BSD --> | |
282 | <g id="edge23" class="edge"> | |
283 | <title>32V->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->Ultrix-11 --> | |
288 | <g id="edge17" class="edge"> | |
289 | <title>V7M->Ultrix-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->2.8 BSD --> | |
300 | <g id="edge20" class="edge"> | |
301 | <title>2 BSD->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->Ultrix-11 --> | |
306 | <g id="edge21" class="edge"> | |
307 | <title>2.8 BSD->Ultrix-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->2.9 BSD --> | |
318 | <g id="edge22" class="edge"> | |
319 | <title>2.8 BSD->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->4 BSD --> | |
330 | <g id="edge24" class="edge"> | |
331 | <title>3 BSD->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->4.1 BSD --> | |
342 | <g id="edge25" class="edge"> | |
343 | <title>4 BSD->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->8th Edition --> | |
348 | <g id="edge28" class="edge"> | |
349 | <title>4.1 BSD->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->2.8 BSD --> | |
354 | <g id="edge27" class="edge"> | |
355 | <title>4.1 BSD->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->4.2 BSD --> | |
366 | <g id="edge26" class="edge"> | |
367 | <title>4.1 BSD->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->4.3 BSD --> | |
378 | <g id="edge29" class="edge"> | |
379 | <title>4.2 BSD->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-32 --> | |
384 | <g id="node27" class="node"> | |
385 | <title>Ultrix-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-32</text> | |
388 | </g> | |
389 | <!-- 4.2 BSD->Ultrix-32 --> | |
390 | <g id="edge30" class="edge"> | |
391 | <title>4.2 BSD->Ultrix-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->PWB 2.0 --> | |
396 | <g id="edge33" class="edge"> | |
397 | <title>PWB 1.2->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->CB Unix 1 --> | |
408 | <g id="edge34" class="edge"> | |
409 | <title>USG 1.0->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->USG 2.0 --> | |
420 | <g id="edge35" class="edge"> | |
421 | <title>USG 1.0->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->CB Unix 2 --> | |
432 | <g id="edge36" class="edge"> | |
433 | <title>CB Unix 1->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->USG 3.0 --> | |
444 | <g id="edge40" class="edge"> | |
445 | <title>USG 2.0->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->CB Unix 3 --> | |
456 | <g id="edge37" class="edge"> | |
457 | <title>CB Unix 2->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->Unix/TS++ --> | |
468 | <g id="edge38" class="edge"> | |
469 | <title>CB Unix 3->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-11 Sys V --> | |
474 | <g id="node35" class="node"> | |
475 | <title>PDP-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-11 Sys V</text> | |
478 | </g> | |
479 | <!-- CB Unix 3->PDP-11 Sys V --> | |
480 | <g id="edge39" class="edge"> | |
481 | <title>CB Unix 3->PDP-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->TS 4.0 --> | |
486 | <g id="edge46" class="edge"> | |
487 | <title>CB Unix 3->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++->TS 4.0 --> | |
492 | <g id="edge45" class="edge"> | |
493 | <title>Unix/TS++->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->Unix/TS 3.0 --> | |
498 | <g id="edge41" class="edge"> | |
499 | <title>USG 3.0->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->Unix/TS 3.0 --> | |
510 | <g id="edge43" class="edge"> | |
511 | <title>Unix/TS 1.0->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->System V.0 --> | |
522 | <g id="edge47" class="edge"> | |
523 | <title>TS 4.0->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->System V.2 --> | |
534 | <g id="edge48" class="edge"> | |
535 | <title>System V.0->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->System V.3 --> | |
546 | <g id="edge49" class="edge"> | |
547 | <title>System V.2->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->1 --> | |
23 | <g id="edge1" class="edge"> | |
24 | <title>0->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->2 --> | |
35 | <g id="edge2" class="edge"> | |
36 | <title>0->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->3 --> | |
47 | <g id="edge3" class="edge"> | |
48 | <title>0->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->4 --> | |
59 | <g id="edge4" class="edge"> | |
60 | <title>0->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->5 --> | |
71 | <g id="edge5" class="edge"> | |
72 | <title>0->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->6 --> | |
83 | <g id="edge6" class="edge"> | |
84 | <title>0->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->7 --> | |
95 | <g id="edge7" class="edge"> | |
96 | <title>0->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->8 --> | |
107 | <g id="edge8" class="edge"> | |
108 | <title>0->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->9 --> | |
119 | <g id="edge9" class="edge"> | |
120 | <title>0->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->1 --> | |
23 | <g id="edge1" class="edge"> | |
24 | <title>0->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->2 --> | |
35 | <g id="edge2" class="edge"> | |
36 | <title>0->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->3 --> | |
47 | <g id="edge3" class="edge"> | |
48 | <title>0->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->4 --> | |
59 | <g id="edge4" class="edge"> | |
60 | <title>0->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->5 --> | |
71 | <g id="edge5" class="edge"> | |
72 | <title>0->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->6 --> | |
83 | <g id="edge6" class="edge"> | |
84 | <title>0->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->7 --> | |
95 | <g id="edge7" class="edge"> | |
96 | <title>0->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->8 --> | |
107 | <g id="edge8" class="edge"> | |
108 | <title>0->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->9 --> | |
119 | <g id="edge9" class="edge"> | |
120 | <title>0->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->1 --> | |
23 | <g id="edge1" class="edge"> | |
24 | <title>0->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->2 --> | |
35 | <g id="edge2" class="edge"> | |
36 | <title>0->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->3 --> | |
47 | <g id="edge3" class="edge"> | |
48 | <title>0->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->4 --> | |
59 | <g id="edge4" class="edge"> | |
60 | <title>0->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->5 --> | |
71 | <g id="edge5" class="edge"> | |
72 | <title>0->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->6 --> | |
83 | <g id="edge6" class="edge"> | |
84 | <title>0->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->7 --> | |
95 | <g id="edge7" class="edge"> | |
96 | <title>0->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->8 --> | |
107 | <g id="edge8" class="edge"> | |
108 | <title>0->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->9 --> | |
119 | <g id="edge9" class="edge"> | |
120 | <title>0->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 | # -*- 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 | |
12 | 12 | .. _graphviz-escapes.ipynb: https://nbviewer.jupyter.org/github/xflr6/graphviz/blob/master/examples/graphviz-escapes.ipynb⏎ |
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() |
61 | 61 | "</svg>\r\n" |
62 | 62 | ], |
63 | 63 | "text/plain": [ |
64 | "<graphviz.dot.Digraph at 0x525b188>" | |
64 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
65 | 65 | ] |
66 | 66 | }, |
67 | 67 | "metadata": {}, |
123 | 123 | "</svg>\r\n" |
124 | 124 | ], |
125 | 125 | "text/plain": [ |
126 | "<graphviz.dot.Digraph at 0x525b188>" | |
126 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
127 | 127 | ] |
128 | 128 | }, |
129 | 129 | "metadata": {}, |
185 | 185 | "</svg>\r\n" |
186 | 186 | ], |
187 | 187 | "text/plain": [ |
188 | "<graphviz.dot.Digraph at 0x525b188>" | |
188 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
189 | 189 | ] |
190 | 190 | }, |
191 | 191 | "metadata": {}, |
247 | 247 | "</svg>\r\n" |
248 | 248 | ], |
249 | 249 | "text/plain": [ |
250 | "<graphviz.dot.Digraph at 0x525b188>" | |
250 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
251 | 251 | ] |
252 | 252 | }, |
253 | 253 | "metadata": {}, |
309 | 309 | "</svg>\r\n" |
310 | 310 | ], |
311 | 311 | "text/plain": [ |
312 | "<graphviz.dot.Digraph at 0x525b188>" | |
312 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
313 | 313 | ] |
314 | 314 | }, |
315 | 315 | "metadata": {}, |
356 | 356 | "</svg>\r\n" |
357 | 357 | ], |
358 | 358 | "text/plain": [ |
359 | "<graphviz.dot.Digraph at 0x525b188>" | |
359 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
360 | 360 | ] |
361 | 361 | }, |
362 | 362 | "metadata": {}, |
418 | 418 | "</svg>\r\n" |
419 | 419 | ], |
420 | 420 | "text/plain": [ |
421 | "<graphviz.dot.Digraph at 0x525b188>" | |
421 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
422 | 422 | ] |
423 | 423 | }, |
424 | 424 | "metadata": {}, |
480 | 480 | "</svg>\r\n" |
481 | 481 | ], |
482 | 482 | "text/plain": [ |
483 | "<graphviz.dot.Digraph at 0x525b188>" | |
483 | "<graphviz.dot.Digraph at 0x4f7ebb0>" | |
484 | 484 | ] |
485 | 485 | }, |
486 | 486 | "metadata": {}, |
495 | 495 | } |
496 | 496 | ], |
497 | 497 | "source": [ |
498 | "%cd -q ..\n", | |
499 | "\n", | |
498 | 500 | "from IPython.display import display\n", |
499 | 501 | "\n", |
500 | 502 | "import graphviz\n", |
526 | 528 | "name": "python", |
527 | 529 | "nbconvert_exporter": "python", |
528 | 530 | "pygments_lexer": "ipython3", |
529 | "version": "3.7.4" | |
531 | "version": "3.8.7" | |
530 | 532 | } |
531 | 533 | }, |
532 | 534 | "nbformat": 4, |
36 | 36 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
37 | 37 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
38 | 38 | " \"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", | |
42 | 42 | "<svg width=\"62pt\" height=\"44pt\"\r\n", |
43 | 43 | " 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", |
44 | 44 | "<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", | |
49 | 49 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
50 | 50 | "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">"</text>\r\n", |
51 | 51 | "</g>\r\n", |
53 | 53 | "</svg>\r\n" |
54 | 54 | ], |
55 | 55 | "text/plain": [ |
56 | "<graphviz.dot.Digraph at 0x4f041f0>" | |
56 | "<graphviz.dot.Digraph at 0x50015b0>" | |
57 | 57 | ] |
58 | 58 | }, |
59 | 59 | "execution_count": 2, |
85 | 85 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
86 | 86 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
87 | 87 | " \"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", | |
91 | 91 | "<svg width=\"62pt\" height=\"44pt\"\r\n", |
92 | 92 | " 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", |
93 | 93 | "<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", | |
98 | 98 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
99 | 99 | "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">\\</text>\r\n", |
100 | 100 | "</g>\r\n", |
102 | 102 | "</svg>\r\n" |
103 | 103 | ], |
104 | 104 | "text/plain": [ |
105 | "<graphviz.dot.Digraph at 0x4efdac0>" | |
105 | "<graphviz.dot.Digraph at 0x4fdbbb0>" | |
106 | 106 | ] |
107 | 107 | }, |
108 | 108 | "execution_count": 3, |
134 | 134 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
135 | 135 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
136 | 136 | " \"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", | |
140 | 140 | "<svg width=\"62pt\" height=\"44pt\"\r\n", |
141 | 141 | " 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", |
142 | 142 | "<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", | |
147 | 147 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
148 | 148 | "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">\\"</text>\r\n", |
149 | 149 | "</g>\r\n", |
151 | 151 | "</svg>\r\n" |
152 | 152 | ], |
153 | 153 | "text/plain": [ |
154 | "<graphviz.dot.Digraph at 0x4ee4c70>" | |
154 | "<graphviz.dot.Digraph at 0x4fd8af0>" | |
155 | 155 | ] |
156 | 156 | }, |
157 | 157 | "execution_count": 4, |
190 | 190 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
191 | 191 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
192 | 192 | " \"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", | |
196 | 196 | "<svg width=\"87pt\" height=\"44pt\"\r\n", |
197 | 197 | " 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", |
198 | 198 | "<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>" | |
211 | 211 | ] |
212 | 212 | }, |
213 | 213 | "execution_count": 5, |
239 | 239 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
240 | 240 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
241 | 241 | " \"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", | |
243 | 243 | " -->\r\n", |
244 | 244 | "<!-- Title: spam Pages: 1 -->\r\n", |
245 | 245 | "<svg width=\"118pt\" height=\"44pt\"\r\n", |
246 | 246 | " 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", |
247 | 247 | "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n", |
248 | 248 | "<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>" | |
260 | 261 | ] |
261 | 262 | }, |
262 | 263 | "execution_count": 6, |
288 | 289 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
289 | 290 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
290 | 291 | " \"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", | |
294 | 295 | "<svg width=\"69pt\" height=\"44pt\"\r\n", |
295 | 296 | " 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", |
296 | 297 | "<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", | |
301 | 302 | "<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", | |
304 | 305 | "</a>\r\n", |
305 | 306 | "</g>\r\n", |
306 | 307 | "</g>\r\n", |
308 | 309 | "</svg>\r\n" |
309 | 310 | ], |
310 | 311 | "text/plain": [ |
311 | "<graphviz.dot.Digraph at 0x514fd30>" | |
312 | "<graphviz.dot.Digraph at 0x5001a00>" | |
312 | 313 | ] |
313 | 314 | }, |
314 | 315 | "execution_count": 7, |
340 | 341 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
341 | 342 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
342 | 343 | " \"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", | |
346 | 347 | "<svg width=\"99pt\" height=\"83pt\"\r\n", |
347 | 348 | " 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>" | |
363 | 364 | ] |
364 | 365 | }, |
365 | 366 | "execution_count": 8, |
388 | 389 | "name": "python", |
389 | 390 | "nbconvert_exporter": "python", |
390 | 391 | "pygments_lexer": "ipython3", |
391 | "version": "3.8.2" | |
392 | "version": "3.8.7" | |
392 | 393 | } |
393 | 394 | }, |
394 | 395 | "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->B -->\r\n", | |
66 | "<g id=\"edge1\" class=\"edge\">\r\n", | |
67 | "<title>A->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->L -->\r\n", | |
78 | "<g id=\"edge2\" class=\"edge\">\r\n", | |
79 | "<title>A->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->L -->\r\n", | |
84 | "<g id=\"edge3\" class=\"edge\">\r\n", | |
85 | "<title>B->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->2 -->\r\n", | |
153 | "<g id=\"edge1\" class=\"edge\">\r\n", | |
154 | "<title>1->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->3 -->\r\n", | |
165 | "<g id=\"edge2\" class=\"edge\">\r\n", | |
166 | "<title>2->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->lob -->\r\n", | |
177 | "<g id=\"edge3\" class=\"edge\">\r\n", | |
178 | "<title>3->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->LR_2 -->\r\n", | |
239 | "<g id=\"edge1\" class=\"edge\">\r\n", | |
240 | "<title>LR_0->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->LR_1 -->\r\n", | |
252 | "<g id=\"edge2\" class=\"edge\">\r\n", | |
253 | "<title>LR_0->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->LR_6 -->\r\n", | |
286 | "<g id=\"edge13\" class=\"edge\">\r\n", | |
287 | "<title>LR_8->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->LR_5 -->\r\n", | |
299 | "<g id=\"edge14\" class=\"edge\">\r\n", | |
300 | "<title>LR_8->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->LR_4 -->\r\n", | |
306 | "<g id=\"edge6\" class=\"edge\">\r\n", | |
307 | "<title>LR_2->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->LR_6 -->\r\n", | |
313 | "<g id=\"edge4\" class=\"edge\">\r\n", | |
314 | "<title>LR_2->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->LR_5 -->\r\n", | |
320 | "<g id=\"edge5\" class=\"edge\">\r\n", | |
321 | "<title>LR_2->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->LR_3 -->\r\n", | |
327 | "<g id=\"edge3\" class=\"edge\">\r\n", | |
328 | "<title>LR_1->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->LR_6 -->\r\n", | |
334 | "<g id=\"edge9\" class=\"edge\">\r\n", | |
335 | "<title>LR_6->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->LR_5 -->\r\n", | |
341 | "<g id=\"edge10\" class=\"edge\">\r\n", | |
342 | "<title>LR_6->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->LR_5 -->\r\n", | |
348 | "<g id=\"edge8\" class=\"edge\">\r\n", | |
349 | "<title>LR_5->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->LR_7 -->\r\n", | |
361 | "<g id=\"edge7\" class=\"edge\">\r\n", | |
362 | "<title>LR_5->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->LR_8 -->\r\n", | |
368 | "<g id=\"edge11\" class=\"edge\">\r\n", | |
369 | "<title>LR_7->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->LR_5 -->\r\n", | |
375 | "<g id=\"edge12\" class=\"edge\">\r\n", | |
376 | "<title>LR_7->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->b -->\r\n", | |
471 | "<g id=\"edge1\" class=\"edge\">\r\n", | |
472 | "<title>a->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->c -->\r\n", | |
483 | "<g id=\"edge2\" class=\"edge\">\r\n", | |
484 | "<title>a->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->d -->\r\n", | |
495 | "<g id=\"edge3\" class=\"edge\">\r\n", | |
496 | "<title>b->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->f -->\r\n", | |
507 | "<g id=\"edge7\" class=\"edge\">\r\n", | |
508 | "<title>b->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->d -->\r\n", | |
513 | "<g id=\"edge4\" class=\"edge\">\r\n", | |
514 | "<title>c->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->e -->\r\n", | |
525 | "<g id=\"edge10\" class=\"edge\">\r\n", | |
526 | "<title>c->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->g -->\r\n", | |
537 | "<g id=\"edge9\" class=\"edge\">\r\n", | |
538 | "<title>c->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->e -->\r\n", | |
543 | "<g id=\"edge8\" class=\"edge\">\r\n", | |
544 | "<title>d->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->h -->\r\n", | |
555 | "<g id=\"edge11\" class=\"edge\">\r\n", | |
556 | "<title>d->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->g -->\r\n", | |
561 | "<g id=\"edge5\" class=\"edge\">\r\n", | |
562 | "<title>e->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->f -->\r\n", | |
567 | "<g id=\"edge6\" class=\"edge\">\r\n", | |
568 | "<title>e->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() |
3 | 3 | "cell_type": "code", |
4 | 4 | "execution_count": 1, |
5 | 5 | "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 | ], | |
7 | 18 | "source": [ |
8 | 19 | "import logging\n", |
9 | 20 | "\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__" | |
11 | 26 | ] |
12 | 27 | }, |
13 | 28 | { |
19 | 34 | "name": "stderr", |
20 | 35 | "output_type": "stream", |
21 | 36 | "text": [ |
22 | "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n" | |
37 | "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n" | |
23 | 38 | ] |
24 | 39 | }, |
25 | 40 | { |
28 | 43 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
29 | 44 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
30 | 45 | " \"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", | |
32 | 47 | " -->\r\n", |
33 | "<!-- Title: %3 Pages: 1 -->\r\n", | |
48 | "<!-- Pages: 1 -->\r\n", | |
34 | 49 | "<svg width=\"390pt\" height=\"116pt\"\r\n", |
35 | 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", |
36 | 51 | "<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", | |
39 | 53 | "<!-- 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", | |
43 | 58 | "</g>\r\n", |
44 | 59 | "<!-- 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", | |
48 | 64 | "</g>\r\n", |
49 | 65 | "<!-- A->B -->\r\n", |
50 | "<g id=\"edge1\" class=\"edge\"><title>A->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->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", | |
53 | 70 | "</g>\r\n", |
54 | 71 | "<!-- 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", | |
58 | 76 | "</g>\r\n", |
59 | 77 | "<!-- A->L -->\r\n", |
60 | "<g id=\"edge2\" class=\"edge\"><title>A->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->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", | |
63 | 82 | "</g>\r\n", |
64 | 83 | "<!-- B->L -->\r\n", |
65 | "<g id=\"edge3\" class=\"edge\"><title>B->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->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", | |
68 | 88 | "</g>\r\n", |
69 | 89 | "</g>\r\n", |
70 | 90 | "</svg>\r\n" |
71 | 91 | ], |
72 | 92 | "text/plain": [ |
73 | "<graphviz.dot.Digraph at 0x505fcc8>" | |
93 | "<graphviz.dot.Digraph at 0x1c71cc84970>" | |
74 | 94 | ] |
75 | 95 | }, |
76 | 96 | "execution_count": 2, |
79 | 99 | } |
80 | 100 | ], |
81 | 101 | "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", | |
85 | 103 | "\n", |
86 | 104 | "dot.node('A', 'King Arthur')\n", |
87 | 105 | "dot.node('B', 'Sir Bedevere the Wise')\n", |
102 | 120 | "name": "stderr", |
103 | 121 | "output_type": "stream", |
104 | 122 | "text": [ |
105 | "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n" | |
123 | "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n" | |
106 | 124 | ] |
107 | 125 | }, |
108 | 126 | { |
111 | 129 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
112 | 130 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
113 | 131 | " \"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", | |
115 | 133 | " -->\r\n", |
116 | 134 | "<!-- Title: the holy hand grenade Pages: 1 -->\r\n", |
117 | 135 | "<svg width=\"332pt\" height=\"44pt\"\r\n", |
118 | 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", |
119 | 137 | "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 40)\">\r\n", |
120 | 138 | "<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", | |
122 | 140 | "<!-- 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", | |
124 | 143 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
125 | 144 | "<text text-anchor=\"middle\" x=\"27\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">1</text>\r\n", |
126 | 145 | "</g>\r\n", |
127 | 146 | "<!-- 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", | |
129 | 149 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"117\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
130 | 150 | "<text text-anchor=\"middle\" x=\"117\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">2</text>\r\n", |
131 | 151 | "</g>\r\n", |
132 | 152 | "<!-- 1->2 -->\r\n", |
133 | "<g id=\"edge1\" class=\"edge\"><title>1->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->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", | |
136 | 157 | "</g>\r\n", |
137 | 158 | "<!-- 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", | |
139 | 161 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"207\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
140 | 162 | "<text text-anchor=\"middle\" x=\"207\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">3</text>\r\n", |
141 | 163 | "</g>\r\n", |
142 | 164 | "<!-- 2->3 -->\r\n", |
143 | "<g id=\"edge2\" class=\"edge\"><title>2->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->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", | |
146 | 169 | "</g>\r\n", |
147 | 170 | "<!-- 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", | |
149 | 173 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"297\" cy=\"-18\" rx=\"27\" ry=\"18\"/>\r\n", |
150 | 174 | "<text text-anchor=\"middle\" x=\"297\" y=\"-14.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">lob</text>\r\n", |
151 | 175 | "</g>\r\n", |
152 | 176 | "<!-- 3->lob -->\r\n", |
153 | "<g id=\"edge3\" class=\"edge\"><title>3->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->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", | |
156 | 181 | "</g>\r\n", |
157 | 182 | "</g>\r\n", |
158 | 183 | "</svg>\r\n" |
159 | 184 | ], |
160 | 185 | "text/plain": [ |
161 | "<graphviz.files.Source at 0x505f808>" | |
186 | "<graphviz.files.Source at 0x1c71cde6d60>" | |
162 | 187 | ] |
163 | 188 | }, |
164 | 189 | "execution_count": 3, |
167 | 192 | } |
168 | 193 | ], |
169 | 194 | "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", | |
173 | 196 | "src" |
174 | 197 | ] |
175 | 198 | }, |
182 | 205 | "name": "stderr", |
183 | 206 | "output_type": "stream", |
184 | 207 | "text": [ |
185 | "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n" | |
208 | "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n" | |
186 | 209 | ] |
187 | 210 | }, |
188 | 211 | { |
191 | 214 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
192 | 215 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
193 | 216 | " \"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", | |
195 | 218 | " -->\r\n", |
196 | 219 | "<!-- Title: finite_state_machine Pages: 1 -->\r\n", |
197 | 220 | "<svg width=\"576pt\" height=\"258pt\"\r\n", |
198 | 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", |
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", | |
200 | 223 | "<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", | |
202 | 225 | "<!-- 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", | |
207 | 231 | "</g>\r\n", |
208 | 232 | "<!-- 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", | |
212 | 237 | "</g>\r\n", |
213 | 238 | "<!-- LR_0->LR_2 -->\r\n", |
214 | "<g id=\"edge1\" class=\"edge\"><title>LR_0->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->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", | |
218 | 244 | "</g>\r\n", |
219 | 245 | "<!-- 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", | |
223 | 250 | "</g>\r\n", |
224 | 251 | "<!-- LR_0->LR_1 -->\r\n", |
225 | "<g id=\"edge2\" class=\"edge\"><title>LR_0->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->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", | |
229 | 257 | "</g>\r\n", |
230 | 258 | "<!-- 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", | |
235 | 264 | "</g>\r\n", |
236 | 265 | "<!-- 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", | |
241 | 271 | "</g>\r\n", |
242 | 272 | "<!-- 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", | |
247 | 278 | "</g>\r\n", |
248 | 279 | "<!-- 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", | |
252 | 284 | "</g>\r\n", |
253 | 285 | "<!-- LR_8->LR_6 -->\r\n", |
254 | "<g id=\"edge13\" class=\"edge\"><title>LR_8->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->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", | |
258 | 291 | "</g>\r\n", |
259 | 292 | "<!-- 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", | |
263 | 297 | "</g>\r\n", |
264 | 298 | "<!-- LR_8->LR_5 -->\r\n", |
265 | "<g id=\"edge14\" class=\"edge\"><title>LR_8->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->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", | |
269 | 304 | "</g>\r\n", |
270 | 305 | "<!-- LR_2->LR_4 -->\r\n", |
271 | "<g id=\"edge6\" class=\"edge\"><title>LR_2->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->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", | |
275 | 311 | "</g>\r\n", |
276 | 312 | "<!-- LR_2->LR_6 -->\r\n", |
277 | "<g id=\"edge4\" class=\"edge\"><title>LR_2->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->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", | |
281 | 318 | "</g>\r\n", |
282 | 319 | "<!-- LR_2->LR_5 -->\r\n", |
283 | "<g id=\"edge5\" class=\"edge\"><title>LR_2->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->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", | |
287 | 325 | "</g>\r\n", |
288 | 326 | "<!-- LR_1->LR_3 -->\r\n", |
289 | "<g id=\"edge3\" class=\"edge\"><title>LR_1->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->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", | |
293 | 332 | "</g>\r\n", |
294 | 333 | "<!-- LR_6->LR_6 -->\r\n", |
295 | "<g id=\"edge9\" class=\"edge\"><title>LR_6->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->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", | |
299 | 339 | "</g>\r\n", |
300 | 340 | "<!-- LR_6->LR_5 -->\r\n", |
301 | "<g id=\"edge10\" class=\"edge\"><title>LR_6->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->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", | |
305 | 346 | "</g>\r\n", |
306 | 347 | "<!-- LR_5->LR_5 -->\r\n", |
307 | "<g id=\"edge8\" class=\"edge\"><title>LR_5->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->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", | |
311 | 353 | "</g>\r\n", |
312 | 354 | "<!-- 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", | |
316 | 359 | "</g>\r\n", |
317 | 360 | "<!-- LR_5->LR_7 -->\r\n", |
318 | "<g id=\"edge7\" class=\"edge\"><title>LR_5->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->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", | |
322 | 366 | "</g>\r\n", |
323 | 367 | "<!-- LR_7->LR_8 -->\r\n", |
324 | "<g id=\"edge11\" class=\"edge\"><title>LR_7->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->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", | |
328 | 373 | "</g>\r\n", |
329 | 374 | "<!-- LR_7->LR_5 -->\r\n", |
330 | "<g id=\"edge12\" class=\"edge\"><title>LR_7->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->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", | |
334 | 380 | "</g>\r\n", |
335 | 381 | "</g>\r\n", |
336 | 382 | "</svg>\r\n" |
337 | 383 | ], |
338 | 384 | "text/plain": [ |
339 | "<graphviz.dot.Digraph at 0x5090888>" | |
385 | "<graphviz.dot.Digraph at 0x1c71cdf0220>" | |
340 | 386 | ] |
341 | 387 | }, |
342 | 388 | "execution_count": 4, |
347 | 393 | "source": [ |
348 | 394 | "# http://www.graphviz.org/content/fsm\n", |
349 | 395 | "\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", | |
353 | 397 | "f.attr(rankdir='LR', size='8,5')\n", |
354 | 398 | "\n", |
355 | 399 | "f.attr('node', shape='doublecircle')\n", |
386 | 430 | "name": "stderr", |
387 | 431 | "output_type": "stream", |
388 | 432 | "text": [ |
389 | "[DEBUG@graphviz.backend] run ['dot', '-Tsvg']\n" | |
433 | "[DEBUG@graphviz.backend] run ['dot', '-Kdot', '-Tsvg']\n" | |
390 | 434 | ] |
391 | 435 | }, |
392 | 436 | { |
395 | 439 | "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n", |
396 | 440 | "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\r\n", |
397 | 441 | " \"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", | |
399 | 443 | " -->\r\n", |
400 | 444 | "<!-- Title: G Pages: 1 -->\r\n", |
401 | 445 | "<svg width=\"222pt\" height=\"364pt\"\r\n", |
402 | 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", |
403 | 447 | "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 360)\">\r\n", |
404 | 448 | "<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", | |
407 | 452 | "<polygon fill=\"none\" stroke=\"black\" points=\"64,-152 64,-348 206,-348 206,-152 64,-152\"/>\r\n", |
408 | 453 | "</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", | |
410 | 456 | "<polygon fill=\"none\" stroke=\"black\" points=\"64,-8 64,-132 206,-132 206,-8 64,-8\"/>\r\n", |
411 | 457 | "</g>\r\n", |
412 | 458 | "<!-- 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", | |
414 | 461 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"135\" cy=\"-322\" rx=\"27\" ry=\"18\"/>\r\n", |
415 | 462 | "<text text-anchor=\"middle\" x=\"135\" y=\"-318.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">a</text>\r\n", |
416 | 463 | "</g>\r\n", |
417 | 464 | "<!-- 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", | |
419 | 467 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\r\n", |
420 | 468 | "<text text-anchor=\"middle\" x=\"99\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">b</text>\r\n", |
421 | 469 | "</g>\r\n", |
422 | 470 | "<!-- a->b -->\r\n", |
423 | "<g id=\"edge1\" class=\"edge\"><title>a->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->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", | |
426 | 475 | "</g>\r\n", |
427 | 476 | "<!-- 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", | |
429 | 479 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-250\" rx=\"27\" ry=\"18\"/>\r\n", |
430 | 480 | "<text text-anchor=\"middle\" x=\"171\" y=\"-246.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">c</text>\r\n", |
431 | 481 | "</g>\r\n", |
432 | 482 | "<!-- a->c -->\r\n", |
433 | "<g id=\"edge2\" class=\"edge\"><title>a->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->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", | |
436 | 487 | "</g>\r\n", |
437 | 488 | "<!-- 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", | |
439 | 491 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-178\" rx=\"27\" ry=\"18\"/>\r\n", |
440 | 492 | "<text text-anchor=\"middle\" x=\"99\" y=\"-174.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">d</text>\r\n", |
441 | 493 | "</g>\r\n", |
442 | 494 | "<!-- b->d -->\r\n", |
443 | "<g id=\"edge3\" class=\"edge\"><title>b->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->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", | |
446 | 499 | "</g>\r\n", |
447 | 500 | "<!-- 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", | |
449 | 503 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\r\n", |
450 | 504 | "<text text-anchor=\"middle\" x=\"99\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">f</text>\r\n", |
451 | 505 | "</g>\r\n", |
452 | 506 | "<!-- b->f -->\r\n", |
453 | "<g id=\"edge7\" class=\"edge\"><title>b->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->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", | |
456 | 511 | "</g>\r\n", |
457 | 512 | "<!-- c->d -->\r\n", |
458 | "<g id=\"edge4\" class=\"edge\"><title>c->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->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", | |
461 | 517 | "</g>\r\n", |
462 | 518 | "<!-- 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", | |
464 | 521 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"99\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\r\n", |
465 | 522 | "<text text-anchor=\"middle\" x=\"99\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">e</text>\r\n", |
466 | 523 | "</g>\r\n", |
467 | 524 | "<!-- c->e -->\r\n", |
468 | "<g id=\"edge10\" class=\"edge\"><title>c->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->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", | |
471 | 529 | "</g>\r\n", |
472 | 530 | "<!-- 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", | |
474 | 533 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"171\" cy=\"-34\" rx=\"27\" ry=\"18\"/>\r\n", |
475 | 534 | "<text text-anchor=\"middle\" x=\"171\" y=\"-30.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">g</text>\r\n", |
476 | 535 | "</g>\r\n", |
477 | 536 | "<!-- c->g -->\r\n", |
478 | "<g id=\"edge9\" class=\"edge\"><title>c->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->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", | |
481 | 541 | "</g>\r\n", |
482 | 542 | "<!-- d->e -->\r\n", |
483 | "<g id=\"edge8\" class=\"edge\"><title>d->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->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", | |
486 | 547 | "</g>\r\n", |
487 | 548 | "<!-- 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", | |
489 | 551 | "<ellipse fill=\"none\" stroke=\"black\" cx=\"27\" cy=\"-106\" rx=\"27\" ry=\"18\"/>\r\n", |
490 | 552 | "<text text-anchor=\"middle\" x=\"27\" y=\"-102.3\" font-family=\"Times New Roman,serif\" font-size=\"14.00\">h</text>\r\n", |
491 | 553 | "</g>\r\n", |
492 | 554 | "<!-- d->h -->\r\n", |
493 | "<g id=\"edge11\" class=\"edge\"><title>d->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->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", | |
496 | 559 | "</g>\r\n", |
497 | 560 | "<!-- e->g -->\r\n", |
498 | "<g id=\"edge5\" class=\"edge\"><title>e->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->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", | |
501 | 565 | "</g>\r\n", |
502 | 566 | "<!-- e->f -->\r\n", |
503 | "<g id=\"edge6\" class=\"edge\"><title>e->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->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", | |
506 | 571 | "</g>\r\n", |
507 | 572 | "</g>\r\n", |
508 | 573 | "</svg>\r\n" |
509 | 574 | ], |
510 | 575 | "text/plain": [ |
511 | "<graphviz.dot.Digraph at 0x5094308>" | |
576 | "<graphviz.dot.Digraph at 0x1c71cdf19d0>" | |
512 | 577 | ] |
513 | 578 | }, |
514 | 579 | "execution_count": 5, |
517 | 582 | } |
518 | 583 | ], |
519 | 584 | "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", | |
525 | 588 | "g.attr(compound='true')\n", |
526 | 589 | "\n", |
527 | 590 | "with g.subgraph(name='cluster0') as c:\n", |
556 | 619 | "name": "python", |
557 | 620 | "nbconvert_exporter": "python", |
558 | 621 | "pygments_lexer": "ipython3", |
559 | "version": "3.7.4" | |
622 | "version": "3.9.4" | |
560 | 623 | } |
561 | 624 | }, |
562 | 625 | "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 | # _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 |
15 | 15 | docs/license.rst |
16 | 16 | docs/manual.rst |
17 | 17 | docs/notebooks.rst |
18 | docs/pet-shop.png | |
19 | 18 | docs/round-table.png |
20 | 19 | docs/_static/angles.svg |
21 | 20 | docs/_static/btree.svg |
41 | 40 | docs/_static/structs_revisited.svg |
42 | 41 | docs/_static/traffic_lights.svg |
43 | 42 | 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 | |
44 | 46 | examples/angles.py |
45 | 47 | examples/btree.py |
46 | 48 | examples/cluster.py |
51 | 53 | examples/g_c_n.py |
52 | 54 | examples/graphviz-engines.ipynb |
53 | 55 | examples/graphviz-escapes.ipynb |
56 | examples/graphviz-notebook.ipynb | |
54 | 57 | examples/hello.py |
55 | 58 | examples/notebook.ipynb |
56 | 59 | examples/process.py |
60 | 63 | examples/traffic_lights.py |
61 | 64 | examples/unix.py |
62 | 65 | graphviz/__init__.py |
63 | graphviz/_compat.py | |
64 | 66 | graphviz/backend.py |
65 | 67 | graphviz/dot.py |
66 | 68 | graphviz/files.py |
72 | 74 | graphviz.egg-info/requires.txt |
73 | 75 | graphviz.egg-info/top_level.txt |
74 | 76 | tests/conftest.py |
75 | tests/dot_red.png | |
76 | 77 | tests/test_backend.py |
77 | 78 | tests/test_dot.py |
78 | 79 | tests/test_files.py |
79 | 80 | tests/test_lang.py |
80 | tests/test_tools.py⏎ | |
81 | tests/test_tools.py | |
82 | tests/utils.py | |
83 | tests/files/dot_red.png⏎ |
0 | 0 | |
1 | 1 | [dev] |
2 | tox>=3 | |
3 | 2 | flake8 |
4 | 3 | pep8-naming |
4 | tox>=3 | |
5 | twine | |
5 | 6 | wheel |
6 | twine | |
7 | 7 | |
8 | 8 | [docs] |
9 | sphinx-autodoc-typehints | |
10 | sphinx-rtd-theme | |
9 | 11 | sphinx>=1.8 |
10 | sphinx-rtd-theme | |
11 | 12 | |
12 | 13 | [test] |
13 | 14 | mock>=3 |
14 | pytest>=4 | |
15 | pytest-cov | |
15 | 16 | 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) |
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) |