-
Notifications
You must be signed in to change notification settings - Fork 38
/
gvmagic.py
194 lines (154 loc) · 4.85 KB
/
gvmagic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
"""
Graphviz IPython magic extensions
Magic methods:
%dot <dot graph>
%%dot <dot ...
... graph>
%dotstr "<dot graph>"
%dotobj obj.to_dot()
%dotobjs obj[0].to_dot(), obj[1].to_dot(), ...
also: %twopi, %neato, %sdp, %fsdp, and %circo magic families.
Usage:
%load_ext gvmagic
"""
from logging import info, error
from subprocess import Popen, PIPE
from IPython.display import display, SVG
from IPython.core.magic import Magics
from IPython.core.magic import line_cell_magic
from IPython.core.magic import line_magic
from IPython.core.magic import magics_class
def show_svg(d):
display(SVG(data=d))
def run_graphviz(s, layout_engine='dot'):
"""Execute dot with a layout and return a raw SVG image, or None."""
cmd = ['dot', '-Tsvg', '-K', layout_engine]
dot = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdoutdata, stderrdata = dot.communicate(s.encode('utf-8'))
status = dot.wait()
if status == 0:
return stdoutdata
else:
fstr = "dot returned {}\n[==== stderr ====]\n{}"
error(fstr.format(status, stderrdata.decode('utf-8')))
return None
@magics_class
class GraphvizMagics(Magics):
@line_cell_magic
def dot(self, line, cell=None):
self._from_cell(line, cell, 'dot')
@line_magic
def dotstr(self, line):
self._from_str(line, 'dot')
@line_magic
def dotobj(self, line):
self._from_obj(line, 'dot')
@line_magic
def dotobjs(self, line):
self._from_objs(line, 'dot')
@line_cell_magic
def neato(self, line, cell=None):
self._from_cell(line, cell, 'neato')
@line_magic
def neatostr(self, line):
self._from_str(line, 'neato')
@line_magic
def neatoobj(self, line):
self._from_obj(line, 'neato')
@line_magic
def neatoobjs(self, line):
self._from_objs(line, 'neato')
@line_cell_magic
def sfdp(self, line, cell=None):
self._from_cell(line, cell, 'sfdp')
@line_magic
def sfdpstr(self, line):
self._from_str(line, 'sfdp')
@line_magic
def sfdpobj(self, line):
self._from_obj(line, 'sfdp')
@line_magic
def sfdpobjs(self, line):
self._from_objs(line, 'sfdp')
@line_cell_magic
def fdp(self, line, cell=None):
self._from_cell(line, cell, 'fdp')
@line_magic
def fdpstr(self, line):
self._from_str(line, 'fdp')
@line_magic
def fdpobj(self, line):
self._from_obj(line, 'fdp')
@line_magic
def fdpobjs(self, line):
self._from_objs(line, 'fdp')
@line_cell_magic
def twopi(self, line, cell=None):
self._from_cell(line, cell, 'twopi')
@line_magic
def twopistr(self, line):
self._from_str(line, 'twopi')
@line_magic
def twopiobj(self, line):
self._from_obj(line, 'twopi')
@line_magic
def twopiobjs(self, line):
self._from_objs(line, 'twopi')
@line_cell_magic
def circo(self, line, cell=None):
self._from_cell(line, cell, 'circo')
@line_magic
def circostr(self, line):
self._from_str(line, 'circo')
@line_magic
def circoobj(self, line):
self._from_obj(line, 'circo')
@line_magic
def circoobjs(self, line):
self._from_objs(line, 'circo')
def _from_cell(self, line, cell, layout_engine):
if cell is None:
s = line
else:
s = line + '\n' + cell
data = run_graphviz(s, layout_engine)
if data:
show_svg(data)
def _from_str(self, line, layout_engine):
s = self.shell.ev(line)
data = run_graphviz(s, layout_engine)
if data:
show_svg(data)
def _from_obj(self, line, layout_engine):
obj = self.shell.ev(line)
try:
s = obj.to_dot()
except AttributeError:
error("expected object to implement 'to_dot()' method")
except TypeError:
error("expected to_dot method to be callable w/o args")
else:
data = run_graphviz(s, layout_engine)
if data:
show_svg(data)
def _from_objs(self, line, layout_engine):
"""dot objects magic"""
objs = self.shell.ev(line)
for i, obj in enumerate(objs):
try:
s = obj.to_dot()
except AttributeError:
error("expected object to implement 'to_dot()' method")
except TypeError:
error("expected to_dot method to be callable w/o args")
else:
data = run_graphviz(s, layout_engine)
if data:
info("object {}:".format(i))
show_svg(data)
def load_ipython_extension(ipython):
"""Load the extension in IPython."""
ipython.register_magics(GraphvizMagics)
def unload_ipython_extension(ipython):
"""Unload the extension in IPython."""
pass