This diff has been collapsed as it changes many lines, (1991 lines changed) Show them Hide them | |||||
@@ -0,0 +1,1991 | |||||
|
1 | { | |||
|
2 | "cells": [ | |||
|
3 | { | |||
|
4 | "cell_type": "code", | |||
|
5 | "execution_count": 11, | |||
|
6 | "metadata": { | |||
|
7 | "ExecuteTime": { | |||
|
8 | "end_time": "2018-04-03T16:04:10.171721Z", | |||
|
9 | "start_time": "2018-04-03T16:04:10.156985Z" | |||
|
10 | } | |||
|
11 | }, | |||
|
12 | "outputs": [], | |||
|
13 | "source": [ | |||
|
14 | "import numpy as np\n", | |||
|
15 | "import matplotlib.pyplot as plt\n", | |||
|
16 | "import pandas as pds\n", | |||
|
17 | "%matplotlib notebook\n", | |||
|
18 | "\n", | |||
|
19 | "SAMPLING_FREQ = 218181.818\n", | |||
|
20 | "start = int(round(SAMPLING_FREQ*11))\n", | |||
|
21 | "snapshot_width = int(round(SAMPLING_FREQ*22))\n", | |||
|
22 | "second_width = int(round(SAMPLING_FREQ*1))" | |||
|
23 | ] | |||
|
24 | }, | |||
|
25 | { | |||
|
26 | "cell_type": "markdown", | |||
|
27 | "metadata": {}, | |||
|
28 | "source": [ | |||
|
29 | "# Calibration CSV file loading" | |||
|
30 | ] | |||
|
31 | }, | |||
|
32 | { | |||
|
33 | "cell_type": "code", | |||
|
34 | "execution_count": 39, | |||
|
35 | "metadata": { | |||
|
36 | "ExecuteTime": { | |||
|
37 | "end_time": "2018-04-03T16:35:08.062058Z", | |||
|
38 | "start_time": "2018-04-03T16:35:07.247444Z" | |||
|
39 | } | |||
|
40 | }, | |||
|
41 | "outputs": [ | |||
|
42 | { | |||
|
43 | "name": "stdout", | |||
|
44 | "output_type": "stream", | |||
|
45 | "text": [ | |||
|
46 | "93600003 ./multisin_paquet2.csv\r\n" | |||
|
47 | ] | |||
|
48 | } | |||
|
49 | ], | |||
|
50 | "source": [ | |||
|
51 | "!wc -l ./multisin_paquet2.csv" | |||
|
52 | ] | |||
|
53 | }, | |||
|
54 | { | |||
|
55 | "cell_type": "code", | |||
|
56 | "execution_count": 41, | |||
|
57 | "metadata": { | |||
|
58 | "ExecuteTime": { | |||
|
59 | "end_time": "2018-04-03T16:35:44.885853Z", | |||
|
60 | "start_time": "2018-04-03T16:35:44.679374Z" | |||
|
61 | } | |||
|
62 | }, | |||
|
63 | "outputs": [ | |||
|
64 | { | |||
|
65 | "name": "stdout", | |||
|
66 | "output_type": "stream", | |||
|
67 | "text": [ | |||
|
68 | "waveformName,Multisine_paquet2\r", | |||
|
69 | "\r\n", | |||
|
70 | "waveformPoints,93600000\r", | |||
|
71 | "\r\n", | |||
|
72 | "waveformType,WAVE_ANALOG_16\r", | |||
|
73 | "\r\n", | |||
|
74 | "0.100000\r", | |||
|
75 | "\r\n", | |||
|
76 | "0.100000\r", | |||
|
77 | "\r\n" | |||
|
78 | ] | |||
|
79 | } | |||
|
80 | ], | |||
|
81 | "source": [ | |||
|
82 | "!head -n 5 ./multisin_paquet2.csv" | |||
|
83 | ] | |||
|
84 | }, | |||
|
85 | { | |||
|
86 | "cell_type": "code", | |||
|
87 | "execution_count": 12, | |||
|
88 | "metadata": { | |||
|
89 | "ExecuteTime": { | |||
|
90 | "end_time": "2018-04-03T16:04:21.756250Z", | |||
|
91 | "start_time": "2018-04-03T16:04:13.394367Z" | |||
|
92 | } | |||
|
93 | }, | |||
|
94 | "outputs": [], | |||
|
95 | "source": [ | |||
|
96 | "df = pds.read_csv('./multisin_paquet2.csv', skiprows=3, header=None)" | |||
|
97 | ] | |||
|
98 | }, | |||
|
99 | { | |||
|
100 | "cell_type": "markdown", | |||
|
101 | "metadata": { | |||
|
102 | "ExecuteTime": { | |||
|
103 | "end_time": "2018-04-03T15:27:20.097031Z", | |||
|
104 | "start_time": "2018-04-03T15:27:20.088523Z" | |||
|
105 | } | |||
|
106 | }, | |||
|
107 | "source": [ | |||
|
108 | "## Few verifications\n", | |||
|
109 | "### Is start position asumption good?" | |||
|
110 | ] | |||
|
111 | }, | |||
|
112 | { | |||
|
113 | "cell_type": "code", | |||
|
114 | "execution_count": 13, | |||
|
115 | "metadata": { | |||
|
116 | "ExecuteTime": { | |||
|
117 | "end_time": "2018-04-03T16:04:22.794779Z", | |||
|
118 | "start_time": "2018-04-03T16:04:22.716928Z" | |||
|
119 | } | |||
|
120 | }, | |||
|
121 | "outputs": [ | |||
|
122 | { | |||
|
123 | "data": { | |||
|
124 | "application/javascript": [ | |||
|
125 | "/* Put everything inside the global mpl namespace */\n", | |||
|
126 | "window.mpl = {};\n", | |||
|
127 | "\n", | |||
|
128 | "\n", | |||
|
129 | "mpl.get_websocket_type = function() {\n", | |||
|
130 | " if (typeof(WebSocket) !== 'undefined') {\n", | |||
|
131 | " return WebSocket;\n", | |||
|
132 | " } else if (typeof(MozWebSocket) !== 'undefined') {\n", | |||
|
133 | " return MozWebSocket;\n", | |||
|
134 | " } else {\n", | |||
|
135 | " alert('Your browser does not have WebSocket support.' +\n", | |||
|
136 | " 'Please try Chrome, Safari or Firefox β₯ 6. ' +\n", | |||
|
137 | " 'Firefox 4 and 5 are also supported but you ' +\n", | |||
|
138 | " 'have to enable WebSockets in about:config.');\n", | |||
|
139 | " };\n", | |||
|
140 | "}\n", | |||
|
141 | "\n", | |||
|
142 | "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", | |||
|
143 | " this.id = figure_id;\n", | |||
|
144 | "\n", | |||
|
145 | " this.ws = websocket;\n", | |||
|
146 | "\n", | |||
|
147 | " this.supports_binary = (this.ws.binaryType != undefined);\n", | |||
|
148 | "\n", | |||
|
149 | " if (!this.supports_binary) {\n", | |||
|
150 | " var warnings = document.getElementById(\"mpl-warnings\");\n", | |||
|
151 | " if (warnings) {\n", | |||
|
152 | " warnings.style.display = 'block';\n", | |||
|
153 | " warnings.textContent = (\n", | |||
|
154 | " \"This browser does not support binary websocket messages. \" +\n", | |||
|
155 | " \"Performance may be slow.\");\n", | |||
|
156 | " }\n", | |||
|
157 | " }\n", | |||
|
158 | "\n", | |||
|
159 | " this.imageObj = new Image();\n", | |||
|
160 | "\n", | |||
|
161 | " this.context = undefined;\n", | |||
|
162 | " this.message = undefined;\n", | |||
|
163 | " this.canvas = undefined;\n", | |||
|
164 | " this.rubberband_canvas = undefined;\n", | |||
|
165 | " this.rubberband_context = undefined;\n", | |||
|
166 | " this.format_dropdown = undefined;\n", | |||
|
167 | "\n", | |||
|
168 | " this.image_mode = 'full';\n", | |||
|
169 | "\n", | |||
|
170 | " this.root = $('<div/>');\n", | |||
|
171 | " this._root_extra_style(this.root)\n", | |||
|
172 | " this.root.attr('style', 'display: inline-block');\n", | |||
|
173 | "\n", | |||
|
174 | " $(parent_element).append(this.root);\n", | |||
|
175 | "\n", | |||
|
176 | " this._init_header(this);\n", | |||
|
177 | " this._init_canvas(this);\n", | |||
|
178 | " this._init_toolbar(this);\n", | |||
|
179 | "\n", | |||
|
180 | " var fig = this;\n", | |||
|
181 | "\n", | |||
|
182 | " this.waiting = false;\n", | |||
|
183 | "\n", | |||
|
184 | " this.ws.onopen = function () {\n", | |||
|
185 | " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |||
|
186 | " fig.send_message(\"send_image_mode\", {});\n", | |||
|
187 | " if (mpl.ratio != 1) {\n", | |||
|
188 | " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |||
|
189 | " }\n", | |||
|
190 | " fig.send_message(\"refresh\", {});\n", | |||
|
191 | " }\n", | |||
|
192 | "\n", | |||
|
193 | " this.imageObj.onload = function() {\n", | |||
|
194 | " if (fig.image_mode == 'full') {\n", | |||
|
195 | " // Full images could contain transparency (where diff images\n", | |||
|
196 | " // almost always do), so we need to clear the canvas so that\n", | |||
|
197 | " // there is no ghosting.\n", | |||
|
198 | " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |||
|
199 | " }\n", | |||
|
200 | " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |||
|
201 | " };\n", | |||
|
202 | "\n", | |||
|
203 | " this.imageObj.onunload = function() {\n", | |||
|
204 | " fig.ws.close();\n", | |||
|
205 | " }\n", | |||
|
206 | "\n", | |||
|
207 | " this.ws.onmessage = this._make_on_message_function(this);\n", | |||
|
208 | "\n", | |||
|
209 | " this.ondownload = ondownload;\n", | |||
|
210 | "}\n", | |||
|
211 | "\n", | |||
|
212 | "mpl.figure.prototype._init_header = function() {\n", | |||
|
213 | " var titlebar = $(\n", | |||
|
214 | " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |||
|
215 | " 'ui-helper-clearfix\"/>');\n", | |||
|
216 | " var titletext = $(\n", | |||
|
217 | " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |||
|
218 | " 'text-align: center; padding: 3px;\"/>');\n", | |||
|
219 | " titlebar.append(titletext)\n", | |||
|
220 | " this.root.append(titlebar);\n", | |||
|
221 | " this.header = titletext[0];\n", | |||
|
222 | "}\n", | |||
|
223 | "\n", | |||
|
224 | "\n", | |||
|
225 | "\n", | |||
|
226 | "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |||
|
227 | "\n", | |||
|
228 | "}\n", | |||
|
229 | "\n", | |||
|
230 | "\n", | |||
|
231 | "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |||
|
232 | "\n", | |||
|
233 | "}\n", | |||
|
234 | "\n", | |||
|
235 | "mpl.figure.prototype._init_canvas = function() {\n", | |||
|
236 | " var fig = this;\n", | |||
|
237 | "\n", | |||
|
238 | " var canvas_div = $('<div/>');\n", | |||
|
239 | "\n", | |||
|
240 | " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |||
|
241 | "\n", | |||
|
242 | " function canvas_keyboard_event(event) {\n", | |||
|
243 | " return fig.key_event(event, event['data']);\n", | |||
|
244 | " }\n", | |||
|
245 | "\n", | |||
|
246 | " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |||
|
247 | " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |||
|
248 | " this.canvas_div = canvas_div\n", | |||
|
249 | " this._canvas_extra_style(canvas_div)\n", | |||
|
250 | " this.root.append(canvas_div);\n", | |||
|
251 | "\n", | |||
|
252 | " var canvas = $('<canvas/>');\n", | |||
|
253 | " canvas.addClass('mpl-canvas');\n", | |||
|
254 | " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |||
|
255 | "\n", | |||
|
256 | " this.canvas = canvas[0];\n", | |||
|
257 | " this.context = canvas[0].getContext(\"2d\");\n", | |||
|
258 | "\n", | |||
|
259 | " var backingStore = this.context.backingStorePixelRatio ||\n", | |||
|
260 | "\tthis.context.webkitBackingStorePixelRatio ||\n", | |||
|
261 | "\tthis.context.mozBackingStorePixelRatio ||\n", | |||
|
262 | "\tthis.context.msBackingStorePixelRatio ||\n", | |||
|
263 | "\tthis.context.oBackingStorePixelRatio ||\n", | |||
|
264 | "\tthis.context.backingStorePixelRatio || 1;\n", | |||
|
265 | "\n", | |||
|
266 | " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |||
|
267 | "\n", | |||
|
268 | " var rubberband = $('<canvas/>');\n", | |||
|
269 | " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |||
|
270 | "\n", | |||
|
271 | " var pass_mouse_events = true;\n", | |||
|
272 | "\n", | |||
|
273 | " canvas_div.resizable({\n", | |||
|
274 | " start: function(event, ui) {\n", | |||
|
275 | " pass_mouse_events = false;\n", | |||
|
276 | " },\n", | |||
|
277 | " resize: function(event, ui) {\n", | |||
|
278 | " fig.request_resize(ui.size.width, ui.size.height);\n", | |||
|
279 | " },\n", | |||
|
280 | " stop: function(event, ui) {\n", | |||
|
281 | " pass_mouse_events = true;\n", | |||
|
282 | " fig.request_resize(ui.size.width, ui.size.height);\n", | |||
|
283 | " },\n", | |||
|
284 | " });\n", | |||
|
285 | "\n", | |||
|
286 | " function mouse_event_fn(event) {\n", | |||
|
287 | " if (pass_mouse_events)\n", | |||
|
288 | " return fig.mouse_event(event, event['data']);\n", | |||
|
289 | " }\n", | |||
|
290 | "\n", | |||
|
291 | " rubberband.mousedown('button_press', mouse_event_fn);\n", | |||
|
292 | " rubberband.mouseup('button_release', mouse_event_fn);\n", | |||
|
293 | " // Throttle sequential mouse events to 1 every 20ms.\n", | |||
|
294 | " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |||
|
295 | "\n", | |||
|
296 | " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |||
|
297 | " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |||
|
298 | "\n", | |||
|
299 | " canvas_div.on(\"wheel\", function (event) {\n", | |||
|
300 | " event = event.originalEvent;\n", | |||
|
301 | " event['data'] = 'scroll'\n", | |||
|
302 | " if (event.deltaY < 0) {\n", | |||
|
303 | " event.step = 1;\n", | |||
|
304 | " } else {\n", | |||
|
305 | " event.step = -1;\n", | |||
|
306 | " }\n", | |||
|
307 | " mouse_event_fn(event);\n", | |||
|
308 | " });\n", | |||
|
309 | "\n", | |||
|
310 | " canvas_div.append(canvas);\n", | |||
|
311 | " canvas_div.append(rubberband);\n", | |||
|
312 | "\n", | |||
|
313 | " this.rubberband = rubberband;\n", | |||
|
314 | " this.rubberband_canvas = rubberband[0];\n", | |||
|
315 | " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |||
|
316 | " this.rubberband_context.strokeStyle = \"#000000\";\n", | |||
|
317 | "\n", | |||
|
318 | " this._resize_canvas = function(width, height) {\n", | |||
|
319 | " // Keep the size of the canvas, canvas container, and rubber band\n", | |||
|
320 | " // canvas in synch.\n", | |||
|
321 | " canvas_div.css('width', width)\n", | |||
|
322 | " canvas_div.css('height', height)\n", | |||
|
323 | "\n", | |||
|
324 | " canvas.attr('width', width * mpl.ratio);\n", | |||
|
325 | " canvas.attr('height', height * mpl.ratio);\n", | |||
|
326 | " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |||
|
327 | "\n", | |||
|
328 | " rubberband.attr('width', width);\n", | |||
|
329 | " rubberband.attr('height', height);\n", | |||
|
330 | " }\n", | |||
|
331 | "\n", | |||
|
332 | " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |||
|
333 | " // upon first draw.\n", | |||
|
334 | " this._resize_canvas(600, 600);\n", | |||
|
335 | "\n", | |||
|
336 | " // Disable right mouse context menu.\n", | |||
|
337 | " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |||
|
338 | " return false;\n", | |||
|
339 | " });\n", | |||
|
340 | "\n", | |||
|
341 | " function set_focus () {\n", | |||
|
342 | " canvas.focus();\n", | |||
|
343 | " canvas_div.focus();\n", | |||
|
344 | " }\n", | |||
|
345 | "\n", | |||
|
346 | " window.setTimeout(set_focus, 100);\n", | |||
|
347 | "}\n", | |||
|
348 | "\n", | |||
|
349 | "mpl.figure.prototype._init_toolbar = function() {\n", | |||
|
350 | " var fig = this;\n", | |||
|
351 | "\n", | |||
|
352 | " var nav_element = $('<div/>')\n", | |||
|
353 | " nav_element.attr('style', 'width: 100%');\n", | |||
|
354 | " this.root.append(nav_element);\n", | |||
|
355 | "\n", | |||
|
356 | " // Define a callback function for later on.\n", | |||
|
357 | " function toolbar_event(event) {\n", | |||
|
358 | " return fig.toolbar_button_onclick(event['data']);\n", | |||
|
359 | " }\n", | |||
|
360 | " function toolbar_mouse_event(event) {\n", | |||
|
361 | " return fig.toolbar_button_onmouseover(event['data']);\n", | |||
|
362 | " }\n", | |||
|
363 | "\n", | |||
|
364 | " for(var toolbar_ind in mpl.toolbar_items) {\n", | |||
|
365 | " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |||
|
366 | " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |||
|
367 | " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |||
|
368 | " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |||
|
369 | "\n", | |||
|
370 | " if (!name) {\n", | |||
|
371 | " // put a spacer in here.\n", | |||
|
372 | " continue;\n", | |||
|
373 | " }\n", | |||
|
374 | " var button = $('<button/>');\n", | |||
|
375 | " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |||
|
376 | " 'ui-button-icon-only');\n", | |||
|
377 | " button.attr('role', 'button');\n", | |||
|
378 | " button.attr('aria-disabled', 'false');\n", | |||
|
379 | " button.click(method_name, toolbar_event);\n", | |||
|
380 | " button.mouseover(tooltip, toolbar_mouse_event);\n", | |||
|
381 | "\n", | |||
|
382 | " var icon_img = $('<span/>');\n", | |||
|
383 | " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |||
|
384 | " icon_img.addClass(image);\n", | |||
|
385 | " icon_img.addClass('ui-corner-all');\n", | |||
|
386 | "\n", | |||
|
387 | " var tooltip_span = $('<span/>');\n", | |||
|
388 | " tooltip_span.addClass('ui-button-text');\n", | |||
|
389 | " tooltip_span.html(tooltip);\n", | |||
|
390 | "\n", | |||
|
391 | " button.append(icon_img);\n", | |||
|
392 | " button.append(tooltip_span);\n", | |||
|
393 | "\n", | |||
|
394 | " nav_element.append(button);\n", | |||
|
395 | " }\n", | |||
|
396 | "\n", | |||
|
397 | " var fmt_picker_span = $('<span/>');\n", | |||
|
398 | "\n", | |||
|
399 | " var fmt_picker = $('<select/>');\n", | |||
|
400 | " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |||
|
401 | " fmt_picker_span.append(fmt_picker);\n", | |||
|
402 | " nav_element.append(fmt_picker_span);\n", | |||
|
403 | " this.format_dropdown = fmt_picker[0];\n", | |||
|
404 | "\n", | |||
|
405 | " for (var ind in mpl.extensions) {\n", | |||
|
406 | " var fmt = mpl.extensions[ind];\n", | |||
|
407 | " var option = $(\n", | |||
|
408 | " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |||
|
409 | " fmt_picker.append(option)\n", | |||
|
410 | " }\n", | |||
|
411 | "\n", | |||
|
412 | " // Add hover states to the ui-buttons\n", | |||
|
413 | " $( \".ui-button\" ).hover(\n", | |||
|
414 | " function() { $(this).addClass(\"ui-state-hover\");},\n", | |||
|
415 | " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |||
|
416 | " );\n", | |||
|
417 | "\n", | |||
|
418 | " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |||
|
419 | " nav_element.append(status_bar);\n", | |||
|
420 | " this.message = status_bar[0];\n", | |||
|
421 | "}\n", | |||
|
422 | "\n", | |||
|
423 | "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |||
|
424 | " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |||
|
425 | " // which will in turn request a refresh of the image.\n", | |||
|
426 | " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |||
|
427 | "}\n", | |||
|
428 | "\n", | |||
|
429 | "mpl.figure.prototype.send_message = function(type, properties) {\n", | |||
|
430 | " properties['type'] = type;\n", | |||
|
431 | " properties['figure_id'] = this.id;\n", | |||
|
432 | " this.ws.send(JSON.stringify(properties));\n", | |||
|
433 | "}\n", | |||
|
434 | "\n", | |||
|
435 | "mpl.figure.prototype.send_draw_message = function() {\n", | |||
|
436 | " if (!this.waiting) {\n", | |||
|
437 | " this.waiting = true;\n", | |||
|
438 | " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |||
|
439 | " }\n", | |||
|
440 | "}\n", | |||
|
441 | "\n", | |||
|
442 | "\n", | |||
|
443 | "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |||
|
444 | " var format_dropdown = fig.format_dropdown;\n", | |||
|
445 | " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |||
|
446 | " fig.ondownload(fig, format);\n", | |||
|
447 | "}\n", | |||
|
448 | "\n", | |||
|
449 | "\n", | |||
|
450 | "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |||
|
451 | " var size = msg['size'];\n", | |||
|
452 | " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |||
|
453 | " fig._resize_canvas(size[0], size[1]);\n", | |||
|
454 | " fig.send_message(\"refresh\", {});\n", | |||
|
455 | " };\n", | |||
|
456 | "}\n", | |||
|
457 | "\n", | |||
|
458 | "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |||
|
459 | " var x0 = msg['x0'] / mpl.ratio;\n", | |||
|
460 | " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |||
|
461 | " var x1 = msg['x1'] / mpl.ratio;\n", | |||
|
462 | " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |||
|
463 | " x0 = Math.floor(x0) + 0.5;\n", | |||
|
464 | " y0 = Math.floor(y0) + 0.5;\n", | |||
|
465 | " x1 = Math.floor(x1) + 0.5;\n", | |||
|
466 | " y1 = Math.floor(y1) + 0.5;\n", | |||
|
467 | " var min_x = Math.min(x0, x1);\n", | |||
|
468 | " var min_y = Math.min(y0, y1);\n", | |||
|
469 | " var width = Math.abs(x1 - x0);\n", | |||
|
470 | " var height = Math.abs(y1 - y0);\n", | |||
|
471 | "\n", | |||
|
472 | " fig.rubberband_context.clearRect(\n", | |||
|
473 | " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |||
|
474 | "\n", | |||
|
475 | " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |||
|
476 | "}\n", | |||
|
477 | "\n", | |||
|
478 | "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |||
|
479 | " // Updates the figure title.\n", | |||
|
480 | " fig.header.textContent = msg['label'];\n", | |||
|
481 | "}\n", | |||
|
482 | "\n", | |||
|
483 | "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |||
|
484 | " var cursor = msg['cursor'];\n", | |||
|
485 | " switch(cursor)\n", | |||
|
486 | " {\n", | |||
|
487 | " case 0:\n", | |||
|
488 | " cursor = 'pointer';\n", | |||
|
489 | " break;\n", | |||
|
490 | " case 1:\n", | |||
|
491 | " cursor = 'default';\n", | |||
|
492 | " break;\n", | |||
|
493 | " case 2:\n", | |||
|
494 | " cursor = 'crosshair';\n", | |||
|
495 | " break;\n", | |||
|
496 | " case 3:\n", | |||
|
497 | " cursor = 'move';\n", | |||
|
498 | " break;\n", | |||
|
499 | " }\n", | |||
|
500 | " fig.rubberband_canvas.style.cursor = cursor;\n", | |||
|
501 | "}\n", | |||
|
502 | "\n", | |||
|
503 | "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |||
|
504 | " fig.message.textContent = msg['message'];\n", | |||
|
505 | "}\n", | |||
|
506 | "\n", | |||
|
507 | "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |||
|
508 | " // Request the server to send over a new figure.\n", | |||
|
509 | " fig.send_draw_message();\n", | |||
|
510 | "}\n", | |||
|
511 | "\n", | |||
|
512 | "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |||
|
513 | " fig.image_mode = msg['mode'];\n", | |||
|
514 | "}\n", | |||
|
515 | "\n", | |||
|
516 | "mpl.figure.prototype.updated_canvas_event = function() {\n", | |||
|
517 | " // Called whenever the canvas gets updated.\n", | |||
|
518 | " this.send_message(\"ack\", {});\n", | |||
|
519 | "}\n", | |||
|
520 | "\n", | |||
|
521 | "// A function to construct a web socket function for onmessage handling.\n", | |||
|
522 | "// Called in the figure constructor.\n", | |||
|
523 | "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |||
|
524 | " return function socket_on_message(evt) {\n", | |||
|
525 | " if (evt.data instanceof Blob) {\n", | |||
|
526 | " /* FIXME: We get \"Resource interpreted as Image but\n", | |||
|
527 | " * transferred with MIME type text/plain:\" errors on\n", | |||
|
528 | " * Chrome. But how to set the MIME type? It doesn't seem\n", | |||
|
529 | " * to be part of the websocket stream */\n", | |||
|
530 | " evt.data.type = \"image/png\";\n", | |||
|
531 | "\n", | |||
|
532 | " /* Free the memory for the previous frames */\n", | |||
|
533 | " if (fig.imageObj.src) {\n", | |||
|
534 | " (window.URL || window.webkitURL).revokeObjectURL(\n", | |||
|
535 | " fig.imageObj.src);\n", | |||
|
536 | " }\n", | |||
|
537 | "\n", | |||
|
538 | " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |||
|
539 | " evt.data);\n", | |||
|
540 | " fig.updated_canvas_event();\n", | |||
|
541 | " fig.waiting = false;\n", | |||
|
542 | " return;\n", | |||
|
543 | " }\n", | |||
|
544 | " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |||
|
545 | " fig.imageObj.src = evt.data;\n", | |||
|
546 | " fig.updated_canvas_event();\n", | |||
|
547 | " fig.waiting = false;\n", | |||
|
548 | " return;\n", | |||
|
549 | " }\n", | |||
|
550 | "\n", | |||
|
551 | " var msg = JSON.parse(evt.data);\n", | |||
|
552 | " var msg_type = msg['type'];\n", | |||
|
553 | "\n", | |||
|
554 | " // Call the \"handle_{type}\" callback, which takes\n", | |||
|
555 | " // the figure and JSON message as its only arguments.\n", | |||
|
556 | " try {\n", | |||
|
557 | " var callback = fig[\"handle_\" + msg_type];\n", | |||
|
558 | " } catch (e) {\n", | |||
|
559 | " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |||
|
560 | " return;\n", | |||
|
561 | " }\n", | |||
|
562 | "\n", | |||
|
563 | " if (callback) {\n", | |||
|
564 | " try {\n", | |||
|
565 | " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |||
|
566 | " callback(fig, msg);\n", | |||
|
567 | " } catch (e) {\n", | |||
|
568 | " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |||
|
569 | " }\n", | |||
|
570 | " }\n", | |||
|
571 | " };\n", | |||
|
572 | "}\n", | |||
|
573 | "\n", | |||
|
574 | "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |||
|
575 | "mpl.findpos = function(e) {\n", | |||
|
576 | " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |||
|
577 | " var targ;\n", | |||
|
578 | " if (!e)\n", | |||
|
579 | " e = window.event;\n", | |||
|
580 | " if (e.target)\n", | |||
|
581 | " targ = e.target;\n", | |||
|
582 | " else if (e.srcElement)\n", | |||
|
583 | " targ = e.srcElement;\n", | |||
|
584 | " if (targ.nodeType == 3) // defeat Safari bug\n", | |||
|
585 | " targ = targ.parentNode;\n", | |||
|
586 | "\n", | |||
|
587 | " // jQuery normalizes the pageX and pageY\n", | |||
|
588 | " // pageX,Y are the mouse positions relative to the document\n", | |||
|
589 | " // offset() returns the position of the element relative to the document\n", | |||
|
590 | " var x = e.pageX - $(targ).offset().left;\n", | |||
|
591 | " var y = e.pageY - $(targ).offset().top;\n", | |||
|
592 | "\n", | |||
|
593 | " return {\"x\": x, \"y\": y};\n", | |||
|
594 | "};\n", | |||
|
595 | "\n", | |||
|
596 | "/*\n", | |||
|
597 | " * return a copy of an object with only non-object keys\n", | |||
|
598 | " * we need this to avoid circular references\n", | |||
|
599 | " * http://stackoverflow.com/a/24161582/3208463\n", | |||
|
600 | " */\n", | |||
|
601 | "function simpleKeys (original) {\n", | |||
|
602 | " return Object.keys(original).reduce(function (obj, key) {\n", | |||
|
603 | " if (typeof original[key] !== 'object')\n", | |||
|
604 | " obj[key] = original[key]\n", | |||
|
605 | " return obj;\n", | |||
|
606 | " }, {});\n", | |||
|
607 | "}\n", | |||
|
608 | "\n", | |||
|
609 | "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |||
|
610 | " var canvas_pos = mpl.findpos(event)\n", | |||
|
611 | "\n", | |||
|
612 | " if (name === 'button_press')\n", | |||
|
613 | " {\n", | |||
|
614 | " this.canvas.focus();\n", | |||
|
615 | " this.canvas_div.focus();\n", | |||
|
616 | " }\n", | |||
|
617 | "\n", | |||
|
618 | " var x = canvas_pos.x * mpl.ratio;\n", | |||
|
619 | " var y = canvas_pos.y * mpl.ratio;\n", | |||
|
620 | "\n", | |||
|
621 | " this.send_message(name, {x: x, y: y, button: event.button,\n", | |||
|
622 | " step: event.step,\n", | |||
|
623 | " guiEvent: simpleKeys(event)});\n", | |||
|
624 | "\n", | |||
|
625 | " /* This prevents the web browser from automatically changing to\n", | |||
|
626 | " * the text insertion cursor when the button is pressed. We want\n", | |||
|
627 | " * to control all of the cursor setting manually through the\n", | |||
|
628 | " * 'cursor' event from matplotlib */\n", | |||
|
629 | " event.preventDefault();\n", | |||
|
630 | " return false;\n", | |||
|
631 | "}\n", | |||
|
632 | "\n", | |||
|
633 | "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |||
|
634 | " // Handle any extra behaviour associated with a key event\n", | |||
|
635 | "}\n", | |||
|
636 | "\n", | |||
|
637 | "mpl.figure.prototype.key_event = function(event, name) {\n", | |||
|
638 | "\n", | |||
|
639 | " // Prevent repeat events\n", | |||
|
640 | " if (name == 'key_press')\n", | |||
|
641 | " {\n", | |||
|
642 | " if (event.which === this._key)\n", | |||
|
643 | " return;\n", | |||
|
644 | " else\n", | |||
|
645 | " this._key = event.which;\n", | |||
|
646 | " }\n", | |||
|
647 | " if (name == 'key_release')\n", | |||
|
648 | " this._key = null;\n", | |||
|
649 | "\n", | |||
|
650 | " var value = '';\n", | |||
|
651 | " if (event.ctrlKey && event.which != 17)\n", | |||
|
652 | " value += \"ctrl+\";\n", | |||
|
653 | " if (event.altKey && event.which != 18)\n", | |||
|
654 | " value += \"alt+\";\n", | |||
|
655 | " if (event.shiftKey && event.which != 16)\n", | |||
|
656 | " value += \"shift+\";\n", | |||
|
657 | "\n", | |||
|
658 | " value += 'k';\n", | |||
|
659 | " value += event.which.toString();\n", | |||
|
660 | "\n", | |||
|
661 | " this._key_event_extra(event, name);\n", | |||
|
662 | "\n", | |||
|
663 | " this.send_message(name, {key: value,\n", | |||
|
664 | " guiEvent: simpleKeys(event)});\n", | |||
|
665 | " return false;\n", | |||
|
666 | "}\n", | |||
|
667 | "\n", | |||
|
668 | "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |||
|
669 | " if (name == 'download') {\n", | |||
|
670 | " this.handle_save(this, null);\n", | |||
|
671 | " } else {\n", | |||
|
672 | " this.send_message(\"toolbar_button\", {name: name});\n", | |||
|
673 | " }\n", | |||
|
674 | "};\n", | |||
|
675 | "\n", | |||
|
676 | "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |||
|
677 | " this.message.textContent = tooltip;\n", | |||
|
678 | "};\n", | |||
|
679 | "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |||
|
680 | "\n", | |||
|
681 | "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |||
|
682 | "\n", | |||
|
683 | "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |||
|
684 | " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |||
|
685 | " // object with the appropriate methods. Currently this is a non binary\n", | |||
|
686 | " // socket, so there is still some room for performance tuning.\n", | |||
|
687 | " var ws = {};\n", | |||
|
688 | "\n", | |||
|
689 | " ws.close = function() {\n", | |||
|
690 | " comm.close()\n", | |||
|
691 | " };\n", | |||
|
692 | " ws.send = function(m) {\n", | |||
|
693 | " //console.log('sending', m);\n", | |||
|
694 | " comm.send(m);\n", | |||
|
695 | " };\n", | |||
|
696 | " // Register the callback with on_msg.\n", | |||
|
697 | " comm.on_msg(function(msg) {\n", | |||
|
698 | " //console.log('receiving', msg['content']['data'], msg);\n", | |||
|
699 | " // Pass the mpl event to the overriden (by mpl) onmessage function.\n", | |||
|
700 | " ws.onmessage(msg['content']['data'])\n", | |||
|
701 | " });\n", | |||
|
702 | " return ws;\n", | |||
|
703 | "}\n", | |||
|
704 | "\n", | |||
|
705 | "mpl.mpl_figure_comm = function(comm, msg) {\n", | |||
|
706 | " // This is the function which gets called when the mpl process\n", | |||
|
707 | " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", | |||
|
708 | "\n", | |||
|
709 | " var id = msg.content.data.id;\n", | |||
|
710 | " // Get hold of the div created by the display call when the Comm\n", | |||
|
711 | " // socket was opened in Python.\n", | |||
|
712 | " var element = $(\"#\" + id);\n", | |||
|
713 | " var ws_proxy = comm_websocket_adapter(comm)\n", | |||
|
714 | "\n", | |||
|
715 | " function ondownload(figure, format) {\n", | |||
|
716 | " window.open(figure.imageObj.src);\n", | |||
|
717 | " }\n", | |||
|
718 | "\n", | |||
|
719 | " var fig = new mpl.figure(id, ws_proxy,\n", | |||
|
720 | " ondownload,\n", | |||
|
721 | " element.get(0));\n", | |||
|
722 | "\n", | |||
|
723 | " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", | |||
|
724 | " // web socket which is closed, not our websocket->open comm proxy.\n", | |||
|
725 | " ws_proxy.onopen();\n", | |||
|
726 | "\n", | |||
|
727 | " fig.parent_element = element.get(0);\n", | |||
|
728 | " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", | |||
|
729 | " if (!fig.cell_info) {\n", | |||
|
730 | " console.error(\"Failed to find cell for figure\", id, fig);\n", | |||
|
731 | " return;\n", | |||
|
732 | " }\n", | |||
|
733 | "\n", | |||
|
734 | " var output_index = fig.cell_info[2]\n", | |||
|
735 | " var cell = fig.cell_info[0];\n", | |||
|
736 | "\n", | |||
|
737 | "};\n", | |||
|
738 | "\n", | |||
|
739 | "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |||
|
740 | " var width = fig.canvas.width/mpl.ratio\n", | |||
|
741 | " fig.root.unbind('remove')\n", | |||
|
742 | "\n", | |||
|
743 | " // Update the output cell to use the data from the current canvas.\n", | |||
|
744 | " fig.push_to_output();\n", | |||
|
745 | " var dataURL = fig.canvas.toDataURL();\n", | |||
|
746 | " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |||
|
747 | " // the notebook keyboard shortcuts fail.\n", | |||
|
748 | " IPython.keyboard_manager.enable()\n", | |||
|
749 | " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |||
|
750 | " fig.close_ws(fig, msg);\n", | |||
|
751 | "}\n", | |||
|
752 | "\n", | |||
|
753 | "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |||
|
754 | " fig.send_message('closing', msg);\n", | |||
|
755 | " // fig.ws.close()\n", | |||
|
756 | "}\n", | |||
|
757 | "\n", | |||
|
758 | "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |||
|
759 | " // Turn the data on the canvas into data in the output cell.\n", | |||
|
760 | " var width = this.canvas.width/mpl.ratio\n", | |||
|
761 | " var dataURL = this.canvas.toDataURL();\n", | |||
|
762 | " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |||
|
763 | "}\n", | |||
|
764 | "\n", | |||
|
765 | "mpl.figure.prototype.updated_canvas_event = function() {\n", | |||
|
766 | " // Tell IPython that the notebook contents must change.\n", | |||
|
767 | " IPython.notebook.set_dirty(true);\n", | |||
|
768 | " this.send_message(\"ack\", {});\n", | |||
|
769 | " var fig = this;\n", | |||
|
770 | " // Wait a second, then push the new image to the DOM so\n", | |||
|
771 | " // that it is saved nicely (might be nice to debounce this).\n", | |||
|
772 | " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |||
|
773 | "}\n", | |||
|
774 | "\n", | |||
|
775 | "mpl.figure.prototype._init_toolbar = function() {\n", | |||
|
776 | " var fig = this;\n", | |||
|
777 | "\n", | |||
|
778 | " var nav_element = $('<div/>')\n", | |||
|
779 | " nav_element.attr('style', 'width: 100%');\n", | |||
|
780 | " this.root.append(nav_element);\n", | |||
|
781 | "\n", | |||
|
782 | " // Define a callback function for later on.\n", | |||
|
783 | " function toolbar_event(event) {\n", | |||
|
784 | " return fig.toolbar_button_onclick(event['data']);\n", | |||
|
785 | " }\n", | |||
|
786 | " function toolbar_mouse_event(event) {\n", | |||
|
787 | " return fig.toolbar_button_onmouseover(event['data']);\n", | |||
|
788 | " }\n", | |||
|
789 | "\n", | |||
|
790 | " for(var toolbar_ind in mpl.toolbar_items){\n", | |||
|
791 | " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |||
|
792 | " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |||
|
793 | " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |||
|
794 | " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |||
|
795 | "\n", | |||
|
796 | " if (!name) { continue; };\n", | |||
|
797 | "\n", | |||
|
798 | " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |||
|
799 | " button.click(method_name, toolbar_event);\n", | |||
|
800 | " button.mouseover(tooltip, toolbar_mouse_event);\n", | |||
|
801 | " nav_element.append(button);\n", | |||
|
802 | " }\n", | |||
|
803 | "\n", | |||
|
804 | " // Add the status bar.\n", | |||
|
805 | " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |||
|
806 | " nav_element.append(status_bar);\n", | |||
|
807 | " this.message = status_bar[0];\n", | |||
|
808 | "\n", | |||
|
809 | " // Add the close button to the window.\n", | |||
|
810 | " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |||
|
811 | " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |||
|
812 | " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |||
|
813 | " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |||
|
814 | " buttongrp.append(button);\n", | |||
|
815 | " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |||
|
816 | " titlebar.prepend(buttongrp);\n", | |||
|
817 | "}\n", | |||
|
818 | "\n", | |||
|
819 | "mpl.figure.prototype._root_extra_style = function(el){\n", | |||
|
820 | " var fig = this\n", | |||
|
821 | " el.on(\"remove\", function(){\n", | |||
|
822 | "\tfig.close_ws(fig, {});\n", | |||
|
823 | " });\n", | |||
|
824 | "}\n", | |||
|
825 | "\n", | |||
|
826 | "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |||
|
827 | " // this is important to make the div 'focusable\n", | |||
|
828 | " el.attr('tabindex', 0)\n", | |||
|
829 | " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |||
|
830 | " // off when our div gets focus\n", | |||
|
831 | "\n", | |||
|
832 | " // location in version 3\n", | |||
|
833 | " if (IPython.notebook.keyboard_manager) {\n", | |||
|
834 | " IPython.notebook.keyboard_manager.register_events(el);\n", | |||
|
835 | " }\n", | |||
|
836 | " else {\n", | |||
|
837 | " // location in version 2\n", | |||
|
838 | " IPython.keyboard_manager.register_events(el);\n", | |||
|
839 | " }\n", | |||
|
840 | "\n", | |||
|
841 | "}\n", | |||
|
842 | "\n", | |||
|
843 | "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |||
|
844 | " var manager = IPython.notebook.keyboard_manager;\n", | |||
|
845 | " if (!manager)\n", | |||
|
846 | " manager = IPython.keyboard_manager;\n", | |||
|
847 | "\n", | |||
|
848 | " // Check for shift+enter\n", | |||
|
849 | " if (event.shiftKey && event.which == 13) {\n", | |||
|
850 | " this.canvas_div.blur();\n", | |||
|
851 | " event.shiftKey = false;\n", | |||
|
852 | " // Send a \"J\" for go to next cell\n", | |||
|
853 | " event.which = 74;\n", | |||
|
854 | " event.keyCode = 74;\n", | |||
|
855 | " manager.command_mode();\n", | |||
|
856 | " manager.handle_keydown(event);\n", | |||
|
857 | " }\n", | |||
|
858 | "}\n", | |||
|
859 | "\n", | |||
|
860 | "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |||
|
861 | " fig.ondownload(fig, null);\n", | |||
|
862 | "}\n", | |||
|
863 | "\n", | |||
|
864 | "\n", | |||
|
865 | "mpl.find_output_cell = function(html_output) {\n", | |||
|
866 | " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |||
|
867 | " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |||
|
868 | " // IPython event is triggered only after the cells have been serialised, which for\n", | |||
|
869 | " // our purposes (turning an active figure into a static one), is too late.\n", | |||
|
870 | " var cells = IPython.notebook.get_cells();\n", | |||
|
871 | " var ncells = cells.length;\n", | |||
|
872 | " for (var i=0; i<ncells; i++) {\n", | |||
|
873 | " var cell = cells[i];\n", | |||
|
874 | " if (cell.cell_type === 'code'){\n", | |||
|
875 | " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |||
|
876 | " var data = cell.output_area.outputs[j];\n", | |||
|
877 | " if (data.data) {\n", | |||
|
878 | " // IPython >= 3 moved mimebundle to data attribute of output\n", | |||
|
879 | " data = data.data;\n", | |||
|
880 | " }\n", | |||
|
881 | " if (data['text/html'] == html_output) {\n", | |||
|
882 | " return [cell, data, j];\n", | |||
|
883 | " }\n", | |||
|
884 | " }\n", | |||
|
885 | " }\n", | |||
|
886 | " }\n", | |||
|
887 | "}\n", | |||
|
888 | "\n", | |||
|
889 | "// Register the function which deals with the matplotlib target/channel.\n", | |||
|
890 | "// The kernel may be null if the page has been refreshed.\n", | |||
|
891 | "if (IPython.notebook.kernel != null) {\n", | |||
|
892 | " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |||
|
893 | "}\n" | |||
|
894 | ], | |||
|
895 | "text/plain": [ | |||
|
896 | "<IPython.core.display.Javascript object>" | |||
|
897 | ] | |||
|
898 | }, | |||
|
899 | "metadata": {}, | |||
|
900 | "output_type": "display_data" | |||
|
901 | }, | |||
|
902 | { | |||
|
903 | "data": { | |||
|
904 | "text/html": [ | |||
|
905 | "<img src=\"data:image/png;base64,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\" width=\"1226\">" | |||
|
906 | ], | |||
|
907 | "text/plain": [ | |||
|
908 | "<IPython.core.display.HTML object>" | |||
|
909 | ] | |||
|
910 | }, | |||
|
911 | "metadata": {}, | |||
|
912 | "output_type": "display_data" | |||
|
913 | }, | |||
|
914 | { | |||
|
915 | "data": { | |||
|
916 | "text/plain": [ | |||
|
917 | "<matplotlib.axes._subplots.AxesSubplot at 0x7f7d7dc060b8>" | |||
|
918 | ] | |||
|
919 | }, | |||
|
920 | "execution_count": 13, | |||
|
921 | "metadata": {}, | |||
|
922 | "output_type": "execute_result" | |||
|
923 | } | |||
|
924 | ], | |||
|
925 | "source": [ | |||
|
926 | "df[start-100:start+100].plot()" | |||
|
927 | ] | |||
|
928 | }, | |||
|
929 | { | |||
|
930 | "cell_type": "markdown", | |||
|
931 | "metadata": {}, | |||
|
932 | "source": [ | |||
|
933 | "### If start position is good we should get exactly 0" | |||
|
934 | ] | |||
|
935 | }, | |||
|
936 | { | |||
|
937 | "cell_type": "code", | |||
|
938 | "execution_count": 14, | |||
|
939 | "metadata": { | |||
|
940 | "ExecuteTime": { | |||
|
941 | "end_time": "2018-04-03T16:04:30.382468Z", | |||
|
942 | "start_time": "2018-04-03T16:04:30.369427Z" | |||
|
943 | } | |||
|
944 | }, | |||
|
945 | "outputs": [ | |||
|
946 | { | |||
|
947 | "data": { | |||
|
948 | "text/plain": [ | |||
|
949 | "0 0.0\n", | |||
|
950 | "Name: 2400000, dtype: float64" | |||
|
951 | ] | |||
|
952 | }, | |||
|
953 | "execution_count": 14, | |||
|
954 | "metadata": {}, | |||
|
955 | "output_type": "execute_result" | |||
|
956 | } | |||
|
957 | ], | |||
|
958 | "source": [ | |||
|
959 | "df.iloc[start]" | |||
|
960 | ] | |||
|
961 | }, | |||
|
962 | { | |||
|
963 | "cell_type": "code", | |||
|
964 | "execution_count": 15, | |||
|
965 | "metadata": { | |||
|
966 | "ExecuteTime": { | |||
|
967 | "end_time": "2018-04-03T16:04:30.824264Z", | |||
|
968 | "start_time": "2018-04-03T16:04:30.820242Z" | |||
|
969 | } | |||
|
970 | }, | |||
|
971 | "outputs": [ | |||
|
972 | { | |||
|
973 | "data": { | |||
|
974 | "text/plain": [ | |||
|
975 | "(93600000, (93600000, 1))" | |||
|
976 | ] | |||
|
977 | }, | |||
|
978 | "execution_count": 15, | |||
|
979 | "metadata": {}, | |||
|
980 | "output_type": "execute_result" | |||
|
981 | } | |||
|
982 | ], | |||
|
983 | "source": [ | |||
|
984 | "start + 19*snapshot_width , df.shapez" | |||
|
985 | ] | |||
|
986 | }, | |||
|
987 | { | |||
|
988 | "cell_type": "markdown", | |||
|
989 | "metadata": {}, | |||
|
990 | "source": [ | |||
|
991 | "# Block Design\n", | |||
|
992 | "The idea is to be able to discriminate seconds inside a block (snapshot). The easy solution is to generate steps where the current position inside the block can be deduced by the DC level. \n", | |||
|
993 | "Then in order to cross validate with **TDS** which has high pass filters we also need a higher frequency marker." | |||
|
994 | ] | |||
|
995 | }, | |||
|
996 | { | |||
|
997 | "cell_type": "code", | |||
|
998 | "execution_count": 75, | |||
|
999 | "metadata": { | |||
|
1000 | "ExecuteTime": { | |||
|
1001 | "end_time": "2018-04-03T17:35:27.380942Z", | |||
|
1002 | "start_time": "2018-04-03T17:35:27.063793Z" | |||
|
1003 | }, | |||
|
1004 | "scrolled": false | |||
|
1005 | }, | |||
|
1006 | "outputs": [ | |||
|
1007 | { | |||
|
1008 | "data": { | |||
|
1009 | "application/javascript": [ | |||
|
1010 | "/* Put everything inside the global mpl namespace */\n", | |||
|
1011 | "window.mpl = {};\n", | |||
|
1012 | "\n", | |||
|
1013 | "\n", | |||
|
1014 | "mpl.get_websocket_type = function() {\n", | |||
|
1015 | " if (typeof(WebSocket) !== 'undefined') {\n", | |||
|
1016 | " return WebSocket;\n", | |||
|
1017 | " } else if (typeof(MozWebSocket) !== 'undefined') {\n", | |||
|
1018 | " return MozWebSocket;\n", | |||
|
1019 | " } else {\n", | |||
|
1020 | " alert('Your browser does not have WebSocket support.' +\n", | |||
|
1021 | " 'Please try Chrome, Safari or Firefox β₯ 6. ' +\n", | |||
|
1022 | " 'Firefox 4 and 5 are also supported but you ' +\n", | |||
|
1023 | " 'have to enable WebSockets in about:config.');\n", | |||
|
1024 | " };\n", | |||
|
1025 | "}\n", | |||
|
1026 | "\n", | |||
|
1027 | "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", | |||
|
1028 | " this.id = figure_id;\n", | |||
|
1029 | "\n", | |||
|
1030 | " this.ws = websocket;\n", | |||
|
1031 | "\n", | |||
|
1032 | " this.supports_binary = (this.ws.binaryType != undefined);\n", | |||
|
1033 | "\n", | |||
|
1034 | " if (!this.supports_binary) {\n", | |||
|
1035 | " var warnings = document.getElementById(\"mpl-warnings\");\n", | |||
|
1036 | " if (warnings) {\n", | |||
|
1037 | " warnings.style.display = 'block';\n", | |||
|
1038 | " warnings.textContent = (\n", | |||
|
1039 | " \"This browser does not support binary websocket messages. \" +\n", | |||
|
1040 | " \"Performance may be slow.\");\n", | |||
|
1041 | " }\n", | |||
|
1042 | " }\n", | |||
|
1043 | "\n", | |||
|
1044 | " this.imageObj = new Image();\n", | |||
|
1045 | "\n", | |||
|
1046 | " this.context = undefined;\n", | |||
|
1047 | " this.message = undefined;\n", | |||
|
1048 | " this.canvas = undefined;\n", | |||
|
1049 | " this.rubberband_canvas = undefined;\n", | |||
|
1050 | " this.rubberband_context = undefined;\n", | |||
|
1051 | " this.format_dropdown = undefined;\n", | |||
|
1052 | "\n", | |||
|
1053 | " this.image_mode = 'full';\n", | |||
|
1054 | "\n", | |||
|
1055 | " this.root = $('<div/>');\n", | |||
|
1056 | " this._root_extra_style(this.root)\n", | |||
|
1057 | " this.root.attr('style', 'display: inline-block');\n", | |||
|
1058 | "\n", | |||
|
1059 | " $(parent_element).append(this.root);\n", | |||
|
1060 | "\n", | |||
|
1061 | " this._init_header(this);\n", | |||
|
1062 | " this._init_canvas(this);\n", | |||
|
1063 | " this._init_toolbar(this);\n", | |||
|
1064 | "\n", | |||
|
1065 | " var fig = this;\n", | |||
|
1066 | "\n", | |||
|
1067 | " this.waiting = false;\n", | |||
|
1068 | "\n", | |||
|
1069 | " this.ws.onopen = function () {\n", | |||
|
1070 | " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", | |||
|
1071 | " fig.send_message(\"send_image_mode\", {});\n", | |||
|
1072 | " if (mpl.ratio != 1) {\n", | |||
|
1073 | " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", | |||
|
1074 | " }\n", | |||
|
1075 | " fig.send_message(\"refresh\", {});\n", | |||
|
1076 | " }\n", | |||
|
1077 | "\n", | |||
|
1078 | " this.imageObj.onload = function() {\n", | |||
|
1079 | " if (fig.image_mode == 'full') {\n", | |||
|
1080 | " // Full images could contain transparency (where diff images\n", | |||
|
1081 | " // almost always do), so we need to clear the canvas so that\n", | |||
|
1082 | " // there is no ghosting.\n", | |||
|
1083 | " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", | |||
|
1084 | " }\n", | |||
|
1085 | " fig.context.drawImage(fig.imageObj, 0, 0);\n", | |||
|
1086 | " };\n", | |||
|
1087 | "\n", | |||
|
1088 | " this.imageObj.onunload = function() {\n", | |||
|
1089 | " fig.ws.close();\n", | |||
|
1090 | " }\n", | |||
|
1091 | "\n", | |||
|
1092 | " this.ws.onmessage = this._make_on_message_function(this);\n", | |||
|
1093 | "\n", | |||
|
1094 | " this.ondownload = ondownload;\n", | |||
|
1095 | "}\n", | |||
|
1096 | "\n", | |||
|
1097 | "mpl.figure.prototype._init_header = function() {\n", | |||
|
1098 | " var titlebar = $(\n", | |||
|
1099 | " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", | |||
|
1100 | " 'ui-helper-clearfix\"/>');\n", | |||
|
1101 | " var titletext = $(\n", | |||
|
1102 | " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", | |||
|
1103 | " 'text-align: center; padding: 3px;\"/>');\n", | |||
|
1104 | " titlebar.append(titletext)\n", | |||
|
1105 | " this.root.append(titlebar);\n", | |||
|
1106 | " this.header = titletext[0];\n", | |||
|
1107 | "}\n", | |||
|
1108 | "\n", | |||
|
1109 | "\n", | |||
|
1110 | "\n", | |||
|
1111 | "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", | |||
|
1112 | "\n", | |||
|
1113 | "}\n", | |||
|
1114 | "\n", | |||
|
1115 | "\n", | |||
|
1116 | "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", | |||
|
1117 | "\n", | |||
|
1118 | "}\n", | |||
|
1119 | "\n", | |||
|
1120 | "mpl.figure.prototype._init_canvas = function() {\n", | |||
|
1121 | " var fig = this;\n", | |||
|
1122 | "\n", | |||
|
1123 | " var canvas_div = $('<div/>');\n", | |||
|
1124 | "\n", | |||
|
1125 | " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", | |||
|
1126 | "\n", | |||
|
1127 | " function canvas_keyboard_event(event) {\n", | |||
|
1128 | " return fig.key_event(event, event['data']);\n", | |||
|
1129 | " }\n", | |||
|
1130 | "\n", | |||
|
1131 | " canvas_div.keydown('key_press', canvas_keyboard_event);\n", | |||
|
1132 | " canvas_div.keyup('key_release', canvas_keyboard_event);\n", | |||
|
1133 | " this.canvas_div = canvas_div\n", | |||
|
1134 | " this._canvas_extra_style(canvas_div)\n", | |||
|
1135 | " this.root.append(canvas_div);\n", | |||
|
1136 | "\n", | |||
|
1137 | " var canvas = $('<canvas/>');\n", | |||
|
1138 | " canvas.addClass('mpl-canvas');\n", | |||
|
1139 | " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", | |||
|
1140 | "\n", | |||
|
1141 | " this.canvas = canvas[0];\n", | |||
|
1142 | " this.context = canvas[0].getContext(\"2d\");\n", | |||
|
1143 | "\n", | |||
|
1144 | " var backingStore = this.context.backingStorePixelRatio ||\n", | |||
|
1145 | "\tthis.context.webkitBackingStorePixelRatio ||\n", | |||
|
1146 | "\tthis.context.mozBackingStorePixelRatio ||\n", | |||
|
1147 | "\tthis.context.msBackingStorePixelRatio ||\n", | |||
|
1148 | "\tthis.context.oBackingStorePixelRatio ||\n", | |||
|
1149 | "\tthis.context.backingStorePixelRatio || 1;\n", | |||
|
1150 | "\n", | |||
|
1151 | " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", | |||
|
1152 | "\n", | |||
|
1153 | " var rubberband = $('<canvas/>');\n", | |||
|
1154 | " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", | |||
|
1155 | "\n", | |||
|
1156 | " var pass_mouse_events = true;\n", | |||
|
1157 | "\n", | |||
|
1158 | " canvas_div.resizable({\n", | |||
|
1159 | " start: function(event, ui) {\n", | |||
|
1160 | " pass_mouse_events = false;\n", | |||
|
1161 | " },\n", | |||
|
1162 | " resize: function(event, ui) {\n", | |||
|
1163 | " fig.request_resize(ui.size.width, ui.size.height);\n", | |||
|
1164 | " },\n", | |||
|
1165 | " stop: function(event, ui) {\n", | |||
|
1166 | " pass_mouse_events = true;\n", | |||
|
1167 | " fig.request_resize(ui.size.width, ui.size.height);\n", | |||
|
1168 | " },\n", | |||
|
1169 | " });\n", | |||
|
1170 | "\n", | |||
|
1171 | " function mouse_event_fn(event) {\n", | |||
|
1172 | " if (pass_mouse_events)\n", | |||
|
1173 | " return fig.mouse_event(event, event['data']);\n", | |||
|
1174 | " }\n", | |||
|
1175 | "\n", | |||
|
1176 | " rubberband.mousedown('button_press', mouse_event_fn);\n", | |||
|
1177 | " rubberband.mouseup('button_release', mouse_event_fn);\n", | |||
|
1178 | " // Throttle sequential mouse events to 1 every 20ms.\n", | |||
|
1179 | " rubberband.mousemove('motion_notify', mouse_event_fn);\n", | |||
|
1180 | "\n", | |||
|
1181 | " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", | |||
|
1182 | " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", | |||
|
1183 | "\n", | |||
|
1184 | " canvas_div.on(\"wheel\", function (event) {\n", | |||
|
1185 | " event = event.originalEvent;\n", | |||
|
1186 | " event['data'] = 'scroll'\n", | |||
|
1187 | " if (event.deltaY < 0) {\n", | |||
|
1188 | " event.step = 1;\n", | |||
|
1189 | " } else {\n", | |||
|
1190 | " event.step = -1;\n", | |||
|
1191 | " }\n", | |||
|
1192 | " mouse_event_fn(event);\n", | |||
|
1193 | " });\n", | |||
|
1194 | "\n", | |||
|
1195 | " canvas_div.append(canvas);\n", | |||
|
1196 | " canvas_div.append(rubberband);\n", | |||
|
1197 | "\n", | |||
|
1198 | " this.rubberband = rubberband;\n", | |||
|
1199 | " this.rubberband_canvas = rubberband[0];\n", | |||
|
1200 | " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", | |||
|
1201 | " this.rubberband_context.strokeStyle = \"#000000\";\n", | |||
|
1202 | "\n", | |||
|
1203 | " this._resize_canvas = function(width, height) {\n", | |||
|
1204 | " // Keep the size of the canvas, canvas container, and rubber band\n", | |||
|
1205 | " // canvas in synch.\n", | |||
|
1206 | " canvas_div.css('width', width)\n", | |||
|
1207 | " canvas_div.css('height', height)\n", | |||
|
1208 | "\n", | |||
|
1209 | " canvas.attr('width', width * mpl.ratio);\n", | |||
|
1210 | " canvas.attr('height', height * mpl.ratio);\n", | |||
|
1211 | " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", | |||
|
1212 | "\n", | |||
|
1213 | " rubberband.attr('width', width);\n", | |||
|
1214 | " rubberband.attr('height', height);\n", | |||
|
1215 | " }\n", | |||
|
1216 | "\n", | |||
|
1217 | " // Set the figure to an initial 600x600px, this will subsequently be updated\n", | |||
|
1218 | " // upon first draw.\n", | |||
|
1219 | " this._resize_canvas(600, 600);\n", | |||
|
1220 | "\n", | |||
|
1221 | " // Disable right mouse context menu.\n", | |||
|
1222 | " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", | |||
|
1223 | " return false;\n", | |||
|
1224 | " });\n", | |||
|
1225 | "\n", | |||
|
1226 | " function set_focus () {\n", | |||
|
1227 | " canvas.focus();\n", | |||
|
1228 | " canvas_div.focus();\n", | |||
|
1229 | " }\n", | |||
|
1230 | "\n", | |||
|
1231 | " window.setTimeout(set_focus, 100);\n", | |||
|
1232 | "}\n", | |||
|
1233 | "\n", | |||
|
1234 | "mpl.figure.prototype._init_toolbar = function() {\n", | |||
|
1235 | " var fig = this;\n", | |||
|
1236 | "\n", | |||
|
1237 | " var nav_element = $('<div/>')\n", | |||
|
1238 | " nav_element.attr('style', 'width: 100%');\n", | |||
|
1239 | " this.root.append(nav_element);\n", | |||
|
1240 | "\n", | |||
|
1241 | " // Define a callback function for later on.\n", | |||
|
1242 | " function toolbar_event(event) {\n", | |||
|
1243 | " return fig.toolbar_button_onclick(event['data']);\n", | |||
|
1244 | " }\n", | |||
|
1245 | " function toolbar_mouse_event(event) {\n", | |||
|
1246 | " return fig.toolbar_button_onmouseover(event['data']);\n", | |||
|
1247 | " }\n", | |||
|
1248 | "\n", | |||
|
1249 | " for(var toolbar_ind in mpl.toolbar_items) {\n", | |||
|
1250 | " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |||
|
1251 | " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |||
|
1252 | " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |||
|
1253 | " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |||
|
1254 | "\n", | |||
|
1255 | " if (!name) {\n", | |||
|
1256 | " // put a spacer in here.\n", | |||
|
1257 | " continue;\n", | |||
|
1258 | " }\n", | |||
|
1259 | " var button = $('<button/>');\n", | |||
|
1260 | " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", | |||
|
1261 | " 'ui-button-icon-only');\n", | |||
|
1262 | " button.attr('role', 'button');\n", | |||
|
1263 | " button.attr('aria-disabled', 'false');\n", | |||
|
1264 | " button.click(method_name, toolbar_event);\n", | |||
|
1265 | " button.mouseover(tooltip, toolbar_mouse_event);\n", | |||
|
1266 | "\n", | |||
|
1267 | " var icon_img = $('<span/>');\n", | |||
|
1268 | " icon_img.addClass('ui-button-icon-primary ui-icon');\n", | |||
|
1269 | " icon_img.addClass(image);\n", | |||
|
1270 | " icon_img.addClass('ui-corner-all');\n", | |||
|
1271 | "\n", | |||
|
1272 | " var tooltip_span = $('<span/>');\n", | |||
|
1273 | " tooltip_span.addClass('ui-button-text');\n", | |||
|
1274 | " tooltip_span.html(tooltip);\n", | |||
|
1275 | "\n", | |||
|
1276 | " button.append(icon_img);\n", | |||
|
1277 | " button.append(tooltip_span);\n", | |||
|
1278 | "\n", | |||
|
1279 | " nav_element.append(button);\n", | |||
|
1280 | " }\n", | |||
|
1281 | "\n", | |||
|
1282 | " var fmt_picker_span = $('<span/>');\n", | |||
|
1283 | "\n", | |||
|
1284 | " var fmt_picker = $('<select/>');\n", | |||
|
1285 | " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", | |||
|
1286 | " fmt_picker_span.append(fmt_picker);\n", | |||
|
1287 | " nav_element.append(fmt_picker_span);\n", | |||
|
1288 | " this.format_dropdown = fmt_picker[0];\n", | |||
|
1289 | "\n", | |||
|
1290 | " for (var ind in mpl.extensions) {\n", | |||
|
1291 | " var fmt = mpl.extensions[ind];\n", | |||
|
1292 | " var option = $(\n", | |||
|
1293 | " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", | |||
|
1294 | " fmt_picker.append(option)\n", | |||
|
1295 | " }\n", | |||
|
1296 | "\n", | |||
|
1297 | " // Add hover states to the ui-buttons\n", | |||
|
1298 | " $( \".ui-button\" ).hover(\n", | |||
|
1299 | " function() { $(this).addClass(\"ui-state-hover\");},\n", | |||
|
1300 | " function() { $(this).removeClass(\"ui-state-hover\");}\n", | |||
|
1301 | " );\n", | |||
|
1302 | "\n", | |||
|
1303 | " var status_bar = $('<span class=\"mpl-message\"/>');\n", | |||
|
1304 | " nav_element.append(status_bar);\n", | |||
|
1305 | " this.message = status_bar[0];\n", | |||
|
1306 | "}\n", | |||
|
1307 | "\n", | |||
|
1308 | "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", | |||
|
1309 | " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", | |||
|
1310 | " // which will in turn request a refresh of the image.\n", | |||
|
1311 | " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", | |||
|
1312 | "}\n", | |||
|
1313 | "\n", | |||
|
1314 | "mpl.figure.prototype.send_message = function(type, properties) {\n", | |||
|
1315 | " properties['type'] = type;\n", | |||
|
1316 | " properties['figure_id'] = this.id;\n", | |||
|
1317 | " this.ws.send(JSON.stringify(properties));\n", | |||
|
1318 | "}\n", | |||
|
1319 | "\n", | |||
|
1320 | "mpl.figure.prototype.send_draw_message = function() {\n", | |||
|
1321 | " if (!this.waiting) {\n", | |||
|
1322 | " this.waiting = true;\n", | |||
|
1323 | " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", | |||
|
1324 | " }\n", | |||
|
1325 | "}\n", | |||
|
1326 | "\n", | |||
|
1327 | "\n", | |||
|
1328 | "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |||
|
1329 | " var format_dropdown = fig.format_dropdown;\n", | |||
|
1330 | " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", | |||
|
1331 | " fig.ondownload(fig, format);\n", | |||
|
1332 | "}\n", | |||
|
1333 | "\n", | |||
|
1334 | "\n", | |||
|
1335 | "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", | |||
|
1336 | " var size = msg['size'];\n", | |||
|
1337 | " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", | |||
|
1338 | " fig._resize_canvas(size[0], size[1]);\n", | |||
|
1339 | " fig.send_message(\"refresh\", {});\n", | |||
|
1340 | " };\n", | |||
|
1341 | "}\n", | |||
|
1342 | "\n", | |||
|
1343 | "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", | |||
|
1344 | " var x0 = msg['x0'] / mpl.ratio;\n", | |||
|
1345 | " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", | |||
|
1346 | " var x1 = msg['x1'] / mpl.ratio;\n", | |||
|
1347 | " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", | |||
|
1348 | " x0 = Math.floor(x0) + 0.5;\n", | |||
|
1349 | " y0 = Math.floor(y0) + 0.5;\n", | |||
|
1350 | " x1 = Math.floor(x1) + 0.5;\n", | |||
|
1351 | " y1 = Math.floor(y1) + 0.5;\n", | |||
|
1352 | " var min_x = Math.min(x0, x1);\n", | |||
|
1353 | " var min_y = Math.min(y0, y1);\n", | |||
|
1354 | " var width = Math.abs(x1 - x0);\n", | |||
|
1355 | " var height = Math.abs(y1 - y0);\n", | |||
|
1356 | "\n", | |||
|
1357 | " fig.rubberband_context.clearRect(\n", | |||
|
1358 | " 0, 0, fig.canvas.width, fig.canvas.height);\n", | |||
|
1359 | "\n", | |||
|
1360 | " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", | |||
|
1361 | "}\n", | |||
|
1362 | "\n", | |||
|
1363 | "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", | |||
|
1364 | " // Updates the figure title.\n", | |||
|
1365 | " fig.header.textContent = msg['label'];\n", | |||
|
1366 | "}\n", | |||
|
1367 | "\n", | |||
|
1368 | "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", | |||
|
1369 | " var cursor = msg['cursor'];\n", | |||
|
1370 | " switch(cursor)\n", | |||
|
1371 | " {\n", | |||
|
1372 | " case 0:\n", | |||
|
1373 | " cursor = 'pointer';\n", | |||
|
1374 | " break;\n", | |||
|
1375 | " case 1:\n", | |||
|
1376 | " cursor = 'default';\n", | |||
|
1377 | " break;\n", | |||
|
1378 | " case 2:\n", | |||
|
1379 | " cursor = 'crosshair';\n", | |||
|
1380 | " break;\n", | |||
|
1381 | " case 3:\n", | |||
|
1382 | " cursor = 'move';\n", | |||
|
1383 | " break;\n", | |||
|
1384 | " }\n", | |||
|
1385 | " fig.rubberband_canvas.style.cursor = cursor;\n", | |||
|
1386 | "}\n", | |||
|
1387 | "\n", | |||
|
1388 | "mpl.figure.prototype.handle_message = function(fig, msg) {\n", | |||
|
1389 | " fig.message.textContent = msg['message'];\n", | |||
|
1390 | "}\n", | |||
|
1391 | "\n", | |||
|
1392 | "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", | |||
|
1393 | " // Request the server to send over a new figure.\n", | |||
|
1394 | " fig.send_draw_message();\n", | |||
|
1395 | "}\n", | |||
|
1396 | "\n", | |||
|
1397 | "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", | |||
|
1398 | " fig.image_mode = msg['mode'];\n", | |||
|
1399 | "}\n", | |||
|
1400 | "\n", | |||
|
1401 | "mpl.figure.prototype.updated_canvas_event = function() {\n", | |||
|
1402 | " // Called whenever the canvas gets updated.\n", | |||
|
1403 | " this.send_message(\"ack\", {});\n", | |||
|
1404 | "}\n", | |||
|
1405 | "\n", | |||
|
1406 | "// A function to construct a web socket function for onmessage handling.\n", | |||
|
1407 | "// Called in the figure constructor.\n", | |||
|
1408 | "mpl.figure.prototype._make_on_message_function = function(fig) {\n", | |||
|
1409 | " return function socket_on_message(evt) {\n", | |||
|
1410 | " if (evt.data instanceof Blob) {\n", | |||
|
1411 | " /* FIXME: We get \"Resource interpreted as Image but\n", | |||
|
1412 | " * transferred with MIME type text/plain:\" errors on\n", | |||
|
1413 | " * Chrome. But how to set the MIME type? It doesn't seem\n", | |||
|
1414 | " * to be part of the websocket stream */\n", | |||
|
1415 | " evt.data.type = \"image/png\";\n", | |||
|
1416 | "\n", | |||
|
1417 | " /* Free the memory for the previous frames */\n", | |||
|
1418 | " if (fig.imageObj.src) {\n", | |||
|
1419 | " (window.URL || window.webkitURL).revokeObjectURL(\n", | |||
|
1420 | " fig.imageObj.src);\n", | |||
|
1421 | " }\n", | |||
|
1422 | "\n", | |||
|
1423 | " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", | |||
|
1424 | " evt.data);\n", | |||
|
1425 | " fig.updated_canvas_event();\n", | |||
|
1426 | " fig.waiting = false;\n", | |||
|
1427 | " return;\n", | |||
|
1428 | " }\n", | |||
|
1429 | " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", | |||
|
1430 | " fig.imageObj.src = evt.data;\n", | |||
|
1431 | " fig.updated_canvas_event();\n", | |||
|
1432 | " fig.waiting = false;\n", | |||
|
1433 | " return;\n", | |||
|
1434 | " }\n", | |||
|
1435 | "\n", | |||
|
1436 | " var msg = JSON.parse(evt.data);\n", | |||
|
1437 | " var msg_type = msg['type'];\n", | |||
|
1438 | "\n", | |||
|
1439 | " // Call the \"handle_{type}\" callback, which takes\n", | |||
|
1440 | " // the figure and JSON message as its only arguments.\n", | |||
|
1441 | " try {\n", | |||
|
1442 | " var callback = fig[\"handle_\" + msg_type];\n", | |||
|
1443 | " } catch (e) {\n", | |||
|
1444 | " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", | |||
|
1445 | " return;\n", | |||
|
1446 | " }\n", | |||
|
1447 | "\n", | |||
|
1448 | " if (callback) {\n", | |||
|
1449 | " try {\n", | |||
|
1450 | " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", | |||
|
1451 | " callback(fig, msg);\n", | |||
|
1452 | " } catch (e) {\n", | |||
|
1453 | " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", | |||
|
1454 | " }\n", | |||
|
1455 | " }\n", | |||
|
1456 | " };\n", | |||
|
1457 | "}\n", | |||
|
1458 | "\n", | |||
|
1459 | "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", | |||
|
1460 | "mpl.findpos = function(e) {\n", | |||
|
1461 | " //this section is from http://www.quirksmode.org/js/events_properties.html\n", | |||
|
1462 | " var targ;\n", | |||
|
1463 | " if (!e)\n", | |||
|
1464 | " e = window.event;\n", | |||
|
1465 | " if (e.target)\n", | |||
|
1466 | " targ = e.target;\n", | |||
|
1467 | " else if (e.srcElement)\n", | |||
|
1468 | " targ = e.srcElement;\n", | |||
|
1469 | " if (targ.nodeType == 3) // defeat Safari bug\n", | |||
|
1470 | " targ = targ.parentNode;\n", | |||
|
1471 | "\n", | |||
|
1472 | " // jQuery normalizes the pageX and pageY\n", | |||
|
1473 | " // pageX,Y are the mouse positions relative to the document\n", | |||
|
1474 | " // offset() returns the position of the element relative to the document\n", | |||
|
1475 | " var x = e.pageX - $(targ).offset().left;\n", | |||
|
1476 | " var y = e.pageY - $(targ).offset().top;\n", | |||
|
1477 | "\n", | |||
|
1478 | " return {\"x\": x, \"y\": y};\n", | |||
|
1479 | "};\n", | |||
|
1480 | "\n", | |||
|
1481 | "/*\n", | |||
|
1482 | " * return a copy of an object with only non-object keys\n", | |||
|
1483 | " * we need this to avoid circular references\n", | |||
|
1484 | " * http://stackoverflow.com/a/24161582/3208463\n", | |||
|
1485 | " */\n", | |||
|
1486 | "function simpleKeys (original) {\n", | |||
|
1487 | " return Object.keys(original).reduce(function (obj, key) {\n", | |||
|
1488 | " if (typeof original[key] !== 'object')\n", | |||
|
1489 | " obj[key] = original[key]\n", | |||
|
1490 | " return obj;\n", | |||
|
1491 | " }, {});\n", | |||
|
1492 | "}\n", | |||
|
1493 | "\n", | |||
|
1494 | "mpl.figure.prototype.mouse_event = function(event, name) {\n", | |||
|
1495 | " var canvas_pos = mpl.findpos(event)\n", | |||
|
1496 | "\n", | |||
|
1497 | " if (name === 'button_press')\n", | |||
|
1498 | " {\n", | |||
|
1499 | " this.canvas.focus();\n", | |||
|
1500 | " this.canvas_div.focus();\n", | |||
|
1501 | " }\n", | |||
|
1502 | "\n", | |||
|
1503 | " var x = canvas_pos.x * mpl.ratio;\n", | |||
|
1504 | " var y = canvas_pos.y * mpl.ratio;\n", | |||
|
1505 | "\n", | |||
|
1506 | " this.send_message(name, {x: x, y: y, button: event.button,\n", | |||
|
1507 | " step: event.step,\n", | |||
|
1508 | " guiEvent: simpleKeys(event)});\n", | |||
|
1509 | "\n", | |||
|
1510 | " /* This prevents the web browser from automatically changing to\n", | |||
|
1511 | " * the text insertion cursor when the button is pressed. We want\n", | |||
|
1512 | " * to control all of the cursor setting manually through the\n", | |||
|
1513 | " * 'cursor' event from matplotlib */\n", | |||
|
1514 | " event.preventDefault();\n", | |||
|
1515 | " return false;\n", | |||
|
1516 | "}\n", | |||
|
1517 | "\n", | |||
|
1518 | "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |||
|
1519 | " // Handle any extra behaviour associated with a key event\n", | |||
|
1520 | "}\n", | |||
|
1521 | "\n", | |||
|
1522 | "mpl.figure.prototype.key_event = function(event, name) {\n", | |||
|
1523 | "\n", | |||
|
1524 | " // Prevent repeat events\n", | |||
|
1525 | " if (name == 'key_press')\n", | |||
|
1526 | " {\n", | |||
|
1527 | " if (event.which === this._key)\n", | |||
|
1528 | " return;\n", | |||
|
1529 | " else\n", | |||
|
1530 | " this._key = event.which;\n", | |||
|
1531 | " }\n", | |||
|
1532 | " if (name == 'key_release')\n", | |||
|
1533 | " this._key = null;\n", | |||
|
1534 | "\n", | |||
|
1535 | " var value = '';\n", | |||
|
1536 | " if (event.ctrlKey && event.which != 17)\n", | |||
|
1537 | " value += \"ctrl+\";\n", | |||
|
1538 | " if (event.altKey && event.which != 18)\n", | |||
|
1539 | " value += \"alt+\";\n", | |||
|
1540 | " if (event.shiftKey && event.which != 16)\n", | |||
|
1541 | " value += \"shift+\";\n", | |||
|
1542 | "\n", | |||
|
1543 | " value += 'k';\n", | |||
|
1544 | " value += event.which.toString();\n", | |||
|
1545 | "\n", | |||
|
1546 | " this._key_event_extra(event, name);\n", | |||
|
1547 | "\n", | |||
|
1548 | " this.send_message(name, {key: value,\n", | |||
|
1549 | " guiEvent: simpleKeys(event)});\n", | |||
|
1550 | " return false;\n", | |||
|
1551 | "}\n", | |||
|
1552 | "\n", | |||
|
1553 | "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", | |||
|
1554 | " if (name == 'download') {\n", | |||
|
1555 | " this.handle_save(this, null);\n", | |||
|
1556 | " } else {\n", | |||
|
1557 | " this.send_message(\"toolbar_button\", {name: name});\n", | |||
|
1558 | " }\n", | |||
|
1559 | "};\n", | |||
|
1560 | "\n", | |||
|
1561 | "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", | |||
|
1562 | " this.message.textContent = tooltip;\n", | |||
|
1563 | "};\n", | |||
|
1564 | "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", | |||
|
1565 | "\n", | |||
|
1566 | "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", | |||
|
1567 | "\n", | |||
|
1568 | "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", | |||
|
1569 | " // Create a \"websocket\"-like object which calls the given IPython comm\n", | |||
|
1570 | " // object with the appropriate methods. Currently this is a non binary\n", | |||
|
1571 | " // socket, so there is still some room for performance tuning.\n", | |||
|
1572 | " var ws = {};\n", | |||
|
1573 | "\n", | |||
|
1574 | " ws.close = function() {\n", | |||
|
1575 | " comm.close()\n", | |||
|
1576 | " };\n", | |||
|
1577 | " ws.send = function(m) {\n", | |||
|
1578 | " //console.log('sending', m);\n", | |||
|
1579 | " comm.send(m);\n", | |||
|
1580 | " };\n", | |||
|
1581 | " // Register the callback with on_msg.\n", | |||
|
1582 | " comm.on_msg(function(msg) {\n", | |||
|
1583 | " //console.log('receiving', msg['content']['data'], msg);\n", | |||
|
1584 | " // Pass the mpl event to the overriden (by mpl) onmessage function.\n", | |||
|
1585 | " ws.onmessage(msg['content']['data'])\n", | |||
|
1586 | " });\n", | |||
|
1587 | " return ws;\n", | |||
|
1588 | "}\n", | |||
|
1589 | "\n", | |||
|
1590 | "mpl.mpl_figure_comm = function(comm, msg) {\n", | |||
|
1591 | " // This is the function which gets called when the mpl process\n", | |||
|
1592 | " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", | |||
|
1593 | "\n", | |||
|
1594 | " var id = msg.content.data.id;\n", | |||
|
1595 | " // Get hold of the div created by the display call when the Comm\n", | |||
|
1596 | " // socket was opened in Python.\n", | |||
|
1597 | " var element = $(\"#\" + id);\n", | |||
|
1598 | " var ws_proxy = comm_websocket_adapter(comm)\n", | |||
|
1599 | "\n", | |||
|
1600 | " function ondownload(figure, format) {\n", | |||
|
1601 | " window.open(figure.imageObj.src);\n", | |||
|
1602 | " }\n", | |||
|
1603 | "\n", | |||
|
1604 | " var fig = new mpl.figure(id, ws_proxy,\n", | |||
|
1605 | " ondownload,\n", | |||
|
1606 | " element.get(0));\n", | |||
|
1607 | "\n", | |||
|
1608 | " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", | |||
|
1609 | " // web socket which is closed, not our websocket->open comm proxy.\n", | |||
|
1610 | " ws_proxy.onopen();\n", | |||
|
1611 | "\n", | |||
|
1612 | " fig.parent_element = element.get(0);\n", | |||
|
1613 | " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", | |||
|
1614 | " if (!fig.cell_info) {\n", | |||
|
1615 | " console.error(\"Failed to find cell for figure\", id, fig);\n", | |||
|
1616 | " return;\n", | |||
|
1617 | " }\n", | |||
|
1618 | "\n", | |||
|
1619 | " var output_index = fig.cell_info[2]\n", | |||
|
1620 | " var cell = fig.cell_info[0];\n", | |||
|
1621 | "\n", | |||
|
1622 | "};\n", | |||
|
1623 | "\n", | |||
|
1624 | "mpl.figure.prototype.handle_close = function(fig, msg) {\n", | |||
|
1625 | " var width = fig.canvas.width/mpl.ratio\n", | |||
|
1626 | " fig.root.unbind('remove')\n", | |||
|
1627 | "\n", | |||
|
1628 | " // Update the output cell to use the data from the current canvas.\n", | |||
|
1629 | " fig.push_to_output();\n", | |||
|
1630 | " var dataURL = fig.canvas.toDataURL();\n", | |||
|
1631 | " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", | |||
|
1632 | " // the notebook keyboard shortcuts fail.\n", | |||
|
1633 | " IPython.keyboard_manager.enable()\n", | |||
|
1634 | " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", | |||
|
1635 | " fig.close_ws(fig, msg);\n", | |||
|
1636 | "}\n", | |||
|
1637 | "\n", | |||
|
1638 | "mpl.figure.prototype.close_ws = function(fig, msg){\n", | |||
|
1639 | " fig.send_message('closing', msg);\n", | |||
|
1640 | " // fig.ws.close()\n", | |||
|
1641 | "}\n", | |||
|
1642 | "\n", | |||
|
1643 | "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", | |||
|
1644 | " // Turn the data on the canvas into data in the output cell.\n", | |||
|
1645 | " var width = this.canvas.width/mpl.ratio\n", | |||
|
1646 | " var dataURL = this.canvas.toDataURL();\n", | |||
|
1647 | " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", | |||
|
1648 | "}\n", | |||
|
1649 | "\n", | |||
|
1650 | "mpl.figure.prototype.updated_canvas_event = function() {\n", | |||
|
1651 | " // Tell IPython that the notebook contents must change.\n", | |||
|
1652 | " IPython.notebook.set_dirty(true);\n", | |||
|
1653 | " this.send_message(\"ack\", {});\n", | |||
|
1654 | " var fig = this;\n", | |||
|
1655 | " // Wait a second, then push the new image to the DOM so\n", | |||
|
1656 | " // that it is saved nicely (might be nice to debounce this).\n", | |||
|
1657 | " setTimeout(function () { fig.push_to_output() }, 1000);\n", | |||
|
1658 | "}\n", | |||
|
1659 | "\n", | |||
|
1660 | "mpl.figure.prototype._init_toolbar = function() {\n", | |||
|
1661 | " var fig = this;\n", | |||
|
1662 | "\n", | |||
|
1663 | " var nav_element = $('<div/>')\n", | |||
|
1664 | " nav_element.attr('style', 'width: 100%');\n", | |||
|
1665 | " this.root.append(nav_element);\n", | |||
|
1666 | "\n", | |||
|
1667 | " // Define a callback function for later on.\n", | |||
|
1668 | " function toolbar_event(event) {\n", | |||
|
1669 | " return fig.toolbar_button_onclick(event['data']);\n", | |||
|
1670 | " }\n", | |||
|
1671 | " function toolbar_mouse_event(event) {\n", | |||
|
1672 | " return fig.toolbar_button_onmouseover(event['data']);\n", | |||
|
1673 | " }\n", | |||
|
1674 | "\n", | |||
|
1675 | " for(var toolbar_ind in mpl.toolbar_items){\n", | |||
|
1676 | " var name = mpl.toolbar_items[toolbar_ind][0];\n", | |||
|
1677 | " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", | |||
|
1678 | " var image = mpl.toolbar_items[toolbar_ind][2];\n", | |||
|
1679 | " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", | |||
|
1680 | "\n", | |||
|
1681 | " if (!name) { continue; };\n", | |||
|
1682 | "\n", | |||
|
1683 | " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", | |||
|
1684 | " button.click(method_name, toolbar_event);\n", | |||
|
1685 | " button.mouseover(tooltip, toolbar_mouse_event);\n", | |||
|
1686 | " nav_element.append(button);\n", | |||
|
1687 | " }\n", | |||
|
1688 | "\n", | |||
|
1689 | " // Add the status bar.\n", | |||
|
1690 | " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", | |||
|
1691 | " nav_element.append(status_bar);\n", | |||
|
1692 | " this.message = status_bar[0];\n", | |||
|
1693 | "\n", | |||
|
1694 | " // Add the close button to the window.\n", | |||
|
1695 | " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", | |||
|
1696 | " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", | |||
|
1697 | " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", | |||
|
1698 | " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", | |||
|
1699 | " buttongrp.append(button);\n", | |||
|
1700 | " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", | |||
|
1701 | " titlebar.prepend(buttongrp);\n", | |||
|
1702 | "}\n", | |||
|
1703 | "\n", | |||
|
1704 | "mpl.figure.prototype._root_extra_style = function(el){\n", | |||
|
1705 | " var fig = this\n", | |||
|
1706 | " el.on(\"remove\", function(){\n", | |||
|
1707 | "\tfig.close_ws(fig, {});\n", | |||
|
1708 | " });\n", | |||
|
1709 | "}\n", | |||
|
1710 | "\n", | |||
|
1711 | "mpl.figure.prototype._canvas_extra_style = function(el){\n", | |||
|
1712 | " // this is important to make the div 'focusable\n", | |||
|
1713 | " el.attr('tabindex', 0)\n", | |||
|
1714 | " // reach out to IPython and tell the keyboard manager to turn it's self\n", | |||
|
1715 | " // off when our div gets focus\n", | |||
|
1716 | "\n", | |||
|
1717 | " // location in version 3\n", | |||
|
1718 | " if (IPython.notebook.keyboard_manager) {\n", | |||
|
1719 | " IPython.notebook.keyboard_manager.register_events(el);\n", | |||
|
1720 | " }\n", | |||
|
1721 | " else {\n", | |||
|
1722 | " // location in version 2\n", | |||
|
1723 | " IPython.keyboard_manager.register_events(el);\n", | |||
|
1724 | " }\n", | |||
|
1725 | "\n", | |||
|
1726 | "}\n", | |||
|
1727 | "\n", | |||
|
1728 | "mpl.figure.prototype._key_event_extra = function(event, name) {\n", | |||
|
1729 | " var manager = IPython.notebook.keyboard_manager;\n", | |||
|
1730 | " if (!manager)\n", | |||
|
1731 | " manager = IPython.keyboard_manager;\n", | |||
|
1732 | "\n", | |||
|
1733 | " // Check for shift+enter\n", | |||
|
1734 | " if (event.shiftKey && event.which == 13) {\n", | |||
|
1735 | " this.canvas_div.blur();\n", | |||
|
1736 | " event.shiftKey = false;\n", | |||
|
1737 | " // Send a \"J\" for go to next cell\n", | |||
|
1738 | " event.which = 74;\n", | |||
|
1739 | " event.keyCode = 74;\n", | |||
|
1740 | " manager.command_mode();\n", | |||
|
1741 | " manager.handle_keydown(event);\n", | |||
|
1742 | " }\n", | |||
|
1743 | "}\n", | |||
|
1744 | "\n", | |||
|
1745 | "mpl.figure.prototype.handle_save = function(fig, msg) {\n", | |||
|
1746 | " fig.ondownload(fig, null);\n", | |||
|
1747 | "}\n", | |||
|
1748 | "\n", | |||
|
1749 | "\n", | |||
|
1750 | "mpl.find_output_cell = function(html_output) {\n", | |||
|
1751 | " // Return the cell and output element which can be found *uniquely* in the notebook.\n", | |||
|
1752 | " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", | |||
|
1753 | " // IPython event is triggered only after the cells have been serialised, which for\n", | |||
|
1754 | " // our purposes (turning an active figure into a static one), is too late.\n", | |||
|
1755 | " var cells = IPython.notebook.get_cells();\n", | |||
|
1756 | " var ncells = cells.length;\n", | |||
|
1757 | " for (var i=0; i<ncells; i++) {\n", | |||
|
1758 | " var cell = cells[i];\n", | |||
|
1759 | " if (cell.cell_type === 'code'){\n", | |||
|
1760 | " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", | |||
|
1761 | " var data = cell.output_area.outputs[j];\n", | |||
|
1762 | " if (data.data) {\n", | |||
|
1763 | " // IPython >= 3 moved mimebundle to data attribute of output\n", | |||
|
1764 | " data = data.data;\n", | |||
|
1765 | " }\n", | |||
|
1766 | " if (data['text/html'] == html_output) {\n", | |||
|
1767 | " return [cell, data, j];\n", | |||
|
1768 | " }\n", | |||
|
1769 | " }\n", | |||
|
1770 | " }\n", | |||
|
1771 | " }\n", | |||
|
1772 | "}\n", | |||
|
1773 | "\n", | |||
|
1774 | "// Register the function which deals with the matplotlib target/channel.\n", | |||
|
1775 | "// The kernel may be null if the page has been refreshed.\n", | |||
|
1776 | "if (IPython.notebook.kernel != null) {\n", | |||
|
1777 | " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", | |||
|
1778 | "}\n" | |||
|
1779 | ], | |||
|
1780 | "text/plain": [ | |||
|
1781 | "<IPython.core.display.Javascript object>" | |||
|
1782 | ] | |||
|
1783 | }, | |||
|
1784 | "metadata": {}, | |||
|
1785 | "output_type": "display_data" | |||
|
1786 | }, | |||
|
1787 | { | |||
|
1788 | "data": { | |||
|
1789 | "text/html": [ | |||
|
1790 | "<img src=\"data:image/png;base64,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\" width=\"1400\">" | |||
|
1791 | ], | |||
|
1792 | "text/plain": [ | |||
|
1793 | "<IPython.core.display.HTML object>" | |||
|
1794 | ] | |||
|
1795 | }, | |||
|
1796 | "metadata": {}, | |||
|
1797 | "output_type": "display_data" | |||
|
1798 | } | |||
|
1799 | ], | |||
|
1800 | "source": [ | |||
|
1801 | "volatge_range = (-1., 1.) # normalized to -1.0 to 1.0 \n", | |||
|
1802 | "steps = 22\n", | |||
|
1803 | "voltage_step = (volatge_range[1]-volatge_range[0]-0.2)/(steps-1)\n", | |||
|
1804 | "frequency_range = (48.,48.+22*12)\n", | |||
|
1805 | "frequency_step = 12.\n", | |||
|
1806 | "\n", | |||
|
1807 | "block = 9999.*np.ones(snapshot_width) # set 9999 to see unset data normaly once updated, it should fit [-1.;1.] range\n", | |||
|
1808 | "for sec_idx in range(22):\n", | |||
|
1809 | " block_idx_slice = slice(sec_idx*second_width,(sec_idx+1)*second_width,1) \n", | |||
|
1810 | " block[block_idx_slice] = volatge_range[0] + (sec_idx * voltage_step) + 0.1\n", | |||
|
1811 | " N = len(block[block_idx_slice])\n", | |||
|
1812 | " F = (frequency_range[0] + ( 12. * sec_idx )) #/ SAMPLING_FREQ\n", | |||
|
1813 | " block[block_idx_slice] += 0.1*np.sin( 2 * np.pi / N * F * np.arange(N))\n", | |||
|
1814 | " \n", | |||
|
1815 | "plt.figure(figsize=(14,6))\n", | |||
|
1816 | "plt.plot(block)\n", | |||
|
1817 | "plt.show()" | |||
|
1818 | ] | |||
|
1819 | }, | |||
|
1820 | { | |||
|
1821 | "cell_type": "code", | |||
|
1822 | "execution_count": 94, | |||
|
1823 | "metadata": { | |||
|
1824 | "ExecuteTime": { | |||
|
1825 | "end_time": "2018-04-05T10:26:06.813157Z", | |||
|
1826 | "start_time": "2018-04-05T10:26:06.377816Z" | |||
|
1827 | } | |||
|
1828 | }, | |||
|
1829 | "outputs": [ | |||
|
1830 | { | |||
|
1831 | "data": { | |||
|
1832 | "text/plain": [ | |||
|
1833 | "(0.9999999999066982, -0.9999999999896335)" | |||
|
1834 | ] | |||
|
1835 | }, | |||
|
1836 | "execution_count": 94, | |||
|
1837 | "metadata": {}, | |||
|
1838 | "output_type": "execute_result" | |||
|
1839 | } | |||
|
1840 | ], | |||
|
1841 | "source": [ | |||
|
1842 | "max(block),min(block)" | |||
|
1843 | ] | |||
|
1844 | }, | |||
|
1845 | { | |||
|
1846 | "cell_type": "code", | |||
|
1847 | "execution_count": 90, | |||
|
1848 | "metadata": { | |||
|
1849 | "ExecuteTime": { | |||
|
1850 | "end_time": "2018-04-05T10:24:52.805851Z", | |||
|
1851 | "start_time": "2018-04-05T10:24:46.480886Z" | |||
|
1852 | } | |||
|
1853 | }, | |||
|
1854 | "outputs": [], | |||
|
1855 | "source": [ | |||
|
1856 | "block_ascii = \"\"\n", | |||
|
1857 | "for sample in block:\n", | |||
|
1858 | " block_ascii+=\"{:1.6f}\\n\".format(sample)\n", | |||
|
1859 | "\n", | |||
|
1860 | "with open('multisin_paquet2_synchro.csv','w') as multisin:\n", | |||
|
1861 | " multisin.write(\"\"\"waveformName,Multisine_paquet2\n", | |||
|
1862 | "waveformPoints,93600000\n", | |||
|
1863 | "waveformType,WAVE_ANALOG_16\n", | |||
|
1864 | "\"\"\")\n", | |||
|
1865 | " for i in range(start):\n", | |||
|
1866 | " multisin.write(\"0.100000\\n\")\n", | |||
|
1867 | " for blk in range(19):\n", | |||
|
1868 | " multisin.write(block_ascii)\n", | |||
|
1869 | " " | |||
|
1870 | ] | |||
|
1871 | }, | |||
|
1872 | { | |||
|
1873 | "cell_type": "code", | |||
|
1874 | "execution_count": 95, | |||
|
1875 | "metadata": { | |||
|
1876 | "ExecuteTime": { | |||
|
1877 | "end_time": "2018-04-05T10:27:57.867698Z", | |||
|
1878 | "start_time": "2018-04-05T10:27:50.128517Z" | |||
|
1879 | } | |||
|
1880 | }, | |||
|
1881 | "outputs": [ | |||
|
1882 | { | |||
|
1883 | "name": "stdout", | |||
|
1884 | "output_type": "stream", | |||
|
1885 | "text": [ | |||
|
1886 | "unix2dos: conversion du fichier multisin_paquet2_synchro.csv au format DOSβ¦\r\n" | |||
|
1887 | ] | |||
|
1888 | } | |||
|
1889 | ], | |||
|
1890 | "source": [ | |||
|
1891 | "!unix2dos multisin_paquet2_synchro.csv" | |||
|
1892 | ] | |||
|
1893 | }, | |||
|
1894 | { | |||
|
1895 | "cell_type": "code", | |||
|
1896 | "execution_count": 96, | |||
|
1897 | "metadata": { | |||
|
1898 | "ExecuteTime": { | |||
|
1899 | "end_time": "2018-04-05T10:29:22.060090Z", | |||
|
1900 | "start_time": "2018-04-05T10:28:36.658160Z" | |||
|
1901 | } | |||
|
1902 | }, | |||
|
1903 | "outputs": [ | |||
|
1904 | { | |||
|
1905 | "name": "stdout", | |||
|
1906 | "output_type": "stream", | |||
|
1907 | "text": [ | |||
|
1908 | " adding: multisin_paquet2_synchro.csv (deflated 70%)\n" | |||
|
1909 | ] | |||
|
1910 | } | |||
|
1911 | ], | |||
|
1912 | "source": [ | |||
|
1913 | "!zip multisin_paquet2_synchro.zip multisin_paquet2_synchro.csv" | |||
|
1914 | ] | |||
|
1915 | } | |||
|
1916 | ], | |||
|
1917 | "metadata": { | |||
|
1918 | "kernelspec": { | |||
|
1919 | "display_name": "Python 3", | |||
|
1920 | "language": "python", | |||
|
1921 | "name": "python3" | |||
|
1922 | }, | |||
|
1923 | "language_info": { | |||
|
1924 | "codemirror_mode": { | |||
|
1925 | "name": "ipython", | |||
|
1926 | "version": 3 | |||
|
1927 | }, | |||
|
1928 | "file_extension": ".py", | |||
|
1929 | "mimetype": "text/x-python", | |||
|
1930 | "name": "python", | |||
|
1931 | "nbconvert_exporter": "python", | |||
|
1932 | "pygments_lexer": "ipython3", | |||
|
1933 | "version": "3.6.4" | |||
|
1934 | }, | |||
|
1935 | "toc": { | |||
|
1936 | "colors": { | |||
|
1937 | "hover_highlight": "#DAA520", | |||
|
1938 | "navigate_num": "#000000", | |||
|
1939 | "navigate_text": "#333333", | |||
|
1940 | "running_highlight": "#FF0000", | |||
|
1941 | "selected_highlight": "#FFD700", | |||
|
1942 | "sidebar_border": "#EEEEEE", | |||
|
1943 | "wrapper_background": "#FFFFFF" | |||
|
1944 | }, | |||
|
1945 | "moveMenuLeft": true, | |||
|
1946 | "nav_menu": { | |||
|
1947 | "height": "118px", | |||
|
1948 | "width": "252px" | |||
|
1949 | }, | |||
|
1950 | "navigate_menu": true, | |||
|
1951 | "number_sections": true, | |||
|
1952 | "sideBar": true, | |||
|
1953 | "threshold": 4, | |||
|
1954 | "toc_cell": false, | |||
|
1955 | "toc_section_display": "block", | |||
|
1956 | "toc_window_display": false, | |||
|
1957 | "widenNotebook": false | |||
|
1958 | }, | |||
|
1959 | "varInspector": { | |||
|
1960 | "cols": { | |||
|
1961 | "lenName": 16, | |||
|
1962 | "lenType": 16, | |||
|
1963 | "lenVar": 40 | |||
|
1964 | }, | |||
|
1965 | "kernels_config": { | |||
|
1966 | "python": { | |||
|
1967 | "delete_cmd_postfix": "", | |||
|
1968 | "delete_cmd_prefix": "del ", | |||
|
1969 | "library": "var_list.py", | |||
|
1970 | "varRefreshCmd": "print(var_dic_list())" | |||
|
1971 | }, | |||
|
1972 | "r": { | |||
|
1973 | "delete_cmd_postfix": ") ", | |||
|
1974 | "delete_cmd_prefix": "rm(", | |||
|
1975 | "library": "var_list.r", | |||
|
1976 | "varRefreshCmd": "cat(var_dic_list()) " | |||
|
1977 | } | |||
|
1978 | }, | |||
|
1979 | "types_to_exclude": [ | |||
|
1980 | "module", | |||
|
1981 | "function", | |||
|
1982 | "builtin_function_or_method", | |||
|
1983 | "instance", | |||
|
1984 | "_Feature" | |||
|
1985 | ], | |||
|
1986 | "window_display": false | |||
|
1987 | } | |||
|
1988 | }, | |||
|
1989 | "nbformat": 4, | |||
|
1990 | "nbformat_minor": 2 | |||
|
1991 | } |
General Comments 0
You need to be logged in to leave comments.
Login now