Belle II Software development
viewer.py
1
8from hep_ipython_tools import viewer
9import random
10import string
11
12
14 """The css string for styling the notebook."""
15
16
17 css_string = """
18 #notebook {
19 background-color: rgba(20, 166, 255, 0.3);
20 background-image: url("http://www-ekp.physik.uni-karlsruhe.de/~nbraun/belle.svg");
21 background-repeat: no-repeat;
22 background-position: right bottom;
23 }
24
25 #notebook-container {
26 width: 90%;
27 }
28
29 #menubar-container {
30 width: 90%;
31 }
32
33 #header-container {
34 width: 90%;
35 }
36 """
37
38
39class PathViewer(viewer.IPythonWidget):
40
41 """
42 Viewer object for the ipython_handler_basf2 path.
43 Do not use it on your own.
44 """
45
46 def __init__(self, path, standalone=False):
47 """
48 Create a new path viewer object with the path from the process
49 """
50
51 try:
52 self.path = path.modules()
53 except BaseException:
54 self.path = path
55
56
57 self.standalone = standalone
58
59 def create(self):
60 """
61 Create the widget
62 """
63
64 import ipywidgets as widgets
65
66 if self.path is None:
67 return widgets.HTML("No modules in path.")
68
69 a = widgets.Accordion()
70 children = []
71
72 for i, element in enumerate(self.path):
73 html = ModuleViewer(element, standalone=self.standalone)
74 children.append(html.create())
75 if isinstance(html.module.name, str):
76 a.set_title(i, html.module.name)
77 else:
78 a.set_title(i, html.module.name())
79
80 a.children = children
81
82 return a
83
84
86 """
87 A widget for showing module parameter with their content (not standalone)
88 or with their description (standalone).
89 """
90
91 def __init__(self, module, standalone=True):
92 """ Init with a module as a string or a registered one. """
93
94
95 if isinstance(module, str):
96 import basf2.core as _basf2
97 self.module = _basf2.register_module(module)
98 else:
99 self.module = module
100
101
102 self.standalone = standalone
103
104
105 self.table_beginning_html = """<table style="margin-left: auto; margin-right: auto;
106 border-collapse: separate; border-spacing: 0px;">"""
107
108
109 self.td_html = "style=\"padding: 10px;\""
110
111
112 self.table_row_parameters = """<tr><td {td_style}>{param.name}</td>
113 <td{color_text} {td_style}>{param.values}</td>
114 <td style="color: gray; {td_style}>{param.default}</td></tr>"""
115
116
117 self.table_row_help = """<tr><td {td_style}>{param.name}</td>
118 <td {td_style}>{param.type}</td>
119 <td {td_style}>{param.values}</td>
120 <td style="color: gray; {td_style}>{param.description}</td></tr>"""
121
122
123 self.table_row_html_single = """<tr><td colspan="4" {td_style}>{text}</td></tr>"""
124
125
126 self.table_title_html = """<thead><td colspan="4" style="text-align: center;
127 font-size: 18pt;" {td_style}>{module_name} ({package})</td></thead>"""
128
129 def get_color_code(self, param):
130 """
131 Handy function for getting a color based on a parameter:
132 if it has the default value, no color,
133 if not, red color.
134 """
135 if str(param.values) != str(param.default) and str(param.default) != "":
136 color_text = " style='color: red;'"
137 else:
138 color_text = ""
139 return color_text
140
141 def create(self):
142 """
143 Show the widget.
144 """
145 import ipywidgets as widgets
146
147 html = widgets.HTML()
148 html.value = self.table_beginning_html
149
150 if self.standalone:
151 if isinstance(self.module.name, str):
152 module_name = self.module.name
153 else:
154 module_name = self.module.name()
155
156 html.value += self.table_title_html.format(module_name=module_name, package=self.module.package(),
157 td_style=self.td_html)
158
159 html.value += self.table_row_html_single.format(text=self.module.description(), td_style=self.td_html)
160
161 if len(self.module.available_params()) == 0:
162 html.value += self.table_row_html_single.format(text="No parameters available.", td_style=self.td_html)
163 else:
164 for param in self.module.available_params():
165 color_text = self.get_color_code(param)
166
167 if self.standalone:
168 table_row_html = self.table_row_help
169 else:
170 table_row_html = self.table_row_parameters
171
172 html.value += table_row_html.format(param=param, color_text=color_text, td_style=self.td_html)
173 html.value += "</table>"
174
175 return html
176
177
179 """Show the dependencies in a nice and fancy way :-)"""
180
181 def __init__(self, store_arrays_with_dependencies_JSON):
182 """Create a new dependency viewer."""
183
184 self.store_arrays_with_dependencies_JSON = store_arrays_with_dependencies_JSON
185
186
187 self.random_name = ''.join(random.choice(string.ascii_letters) for _ in range(10))
188
189 self.element_name = "dependencies_" + self.random_name
190
191
192 self.d3_include_string = """<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>"""
193
194
195 self.d3_element_string = f"""<div id="{self.element_name}"></div>"""
196
197
198 self.style_template = """<style>
199 /* d3 related settings */
200 .node {
201 font: 300 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
202 fill: #bbb;
203 cursor: pointer;
204 }
205
206 .node:hover {
207 fill: #000;
208 }
209
210 .link {
211 stroke: rgba(20, 166, 255, 0.3);
212 stroke-width: 2px;
213 fill: none;
214 pointer-events: none;
215 }
216
217 .node:hover,
218 .node--source,
219 .node--target {
220 font-weight: 700;
221 }
222
223 .node--source {
224 fill: #2ca02c;
225 }
226
227 .node--target {
228 fill: #d62728;
229 }
230
231 .link--source,
232 .link--target {
233 stroke-opacity: 1;
234 stroke-width: 4px;
235 }
236
237 .link--source {
238 stroke: #d62728;
239 }
240
241 .link--target {
242 stroke: #2ca02c;
243 }
244 </style>"""
245
246
247 self.nodes_template = f"""<script>var test_nodes = JSON.parse('{self.store_arrays_with_dependencies_JSON}');</script>"""
248
249
251 <script>
252 var diameter = 960;
253 var radius = diameter / 2;
254 var innerRadius = radius - 120;
255
256 var cluster = d3.layout.cluster()
257 .size([360, innerRadius])
258 .sort(null)
259 .value(function(d) { return d.size; });
260
261 var bundle = d3.layout.bundle();
262
263 var line = d3.svg.line.radial()
264 .interpolate("bundle")
265 .tension(.85)
266 .radius(function(d) { return d.y; })
267 .angle(function(d) { return d.x / 180 * Math.PI; });
268
269 var svg = d3.select("#""" + self.element_name + """").append("svg")
270 .attr("width", diameter)
271 .attr("height", diameter)
272 .append("g")
273 .attr("transform", "translate(" + radius + "," + radius + ")");
274
275 var link = svg.append("g").selectAll(".link");
276 var node = svg.append("g").selectAll(".node");
277
278 var nodes = cluster.nodes(test_nodes);
279 var links = relations(nodes);
280
281 link = link
282 .data(bundle(links))
283 .enter()
284 .append("path")
285 .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; })
286 .attr("class", "link")
287 .attr("d", line);
288
289 node = node
290 .data(nodes.filter(function(n) { return !n.children; }))
291 .enter()
292 .append("text")
293 .attr("class", "node")
294 .attr("dy", ".31em")
295 .attr("transform", function(d) {
296 return "rotate(" + (d.x - 90) +
297 ")translate(" + (d.y + 8) + ",0)"
298 + (d.x < 180 ? "" : "rotate(180)");})
299 .style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
300 .text(function(d) { return d.key; })
301 .on("mouseover", mouseovered)
302 .on("mouseout", mouseouted);
303
304 function mouseovered(d) {
305 node.each(function(n) { n.target = n.source = false; });
306
307 link.classed("link--target", function(l) { if (l.target === d) return l.source.source = true; })
308 .classed("link--source", function(l) { if (l.source === d) return l.target.target = true; })
309 .filter(function(l) { return l.target === d || l.source === d; })
310 .each(function() { this.parentNode.appendChild(this); });
311
312 node.classed("node--target", function(n) { return n.target; })
313 .classed("node--source", function(n) { return n.source; });
314 }
315
316 function mouseouted(d) {
317 link.classed("link--target", false)
318 .classed("link--source", false);
319
320 node.classed("node--target", false)
321 .classed("node--source", false);
322 }
323
324 d3.select(self.frameElement).style("height", diameter + "px");
325
326 // Return a list of imports for the given array of nodes.
327 function relations(nodes) {
328 var map = {},
329 relation = [];
330
331 // Compute a map from name to node.
332 nodes.forEach(function(d) {
333 map[d.name] = d;
334 });
335
336 // For each import, construct a link from the source to target node.
337 nodes.forEach(function(d) {
338 if (d.relation) d.relation.forEach(function(i) {
339 relation.push({source: map[d.name], target: map[i]});
340 });
341 });
342
343 return relation;
344 }
345 </script>
346 """
347
348 def create(self):
349 """
350 Create the widget.
351 """
352 import ipywidgets as widgets
353 html = widgets.HTML(self.viewer_template)
354
355 return html
random_name
Part of the name representing the object for javascript.
Definition: viewer.py:187
def __init__(self, store_arrays_with_dependencies_JSON)
Definition: viewer.py:181
store_arrays_with_dependencies_JSON
A JSON from the processing of dependencies.
Definition: viewer.py:184
nodes_template
Template for inserting the node JSON.
Definition: viewer.py:247
element_name
The name representing the object for javascript.
Definition: viewer.py:189
table_beginning_html
Template for the table beginning.
Definition: viewer.py:105
standalone
In the standalone mode, the basic parameters of the modules are shown.
Definition: viewer.py:102
table_row_parameters
Template for the row of parameters.
Definition: viewer.py:112
def __init__(self, module, standalone=True)
Definition: viewer.py:91
standalone
In the standalone mode, the basic parameters of the modules are shown.
Definition: viewer.py:57
def __init__(self, path, standalone=False)
Definition: viewer.py:46