diff --git a/code/+phys/luttinger.m b/code/+phys/luttinger.m index f225f1a..92ce238 100644 --- a/code/+phys/luttinger.m +++ b/code/+phys/luttinger.m @@ -1,10 +1,11 @@ -function [I,Lfig] = luttinger(w,sloc,gloc) +function I = luttinger(w,sloc,gloc) %% Computes the Luttinger sum-rule, as defined in PRB 90 075150 % % Input: -% w : real valued array, \omega domain -% sloc : complex valued array, \Sigma(\omega) function +% w : real valued array, \omega domain +% sloc : complex valued array, \Sigma(\omega) function % gloc : complex valued array, G_{loc}(\omega) function +% % Output: % I = \frac{1}{\pi}\Im\int_{-\infty}^{\infty}dwG_loc(w)d\Sigma(w)/dw % @@ -12,49 +13,43 @@ % % Copyright (c) 2022, Gabriele Bellomia % All rights reserved. - global DEBUG -% The original definition, as given by Logan, Tucker and Galpin, prescribes -% to integrate over the negative semiaxis: -% -% I = \frac{2}{\pi} \Im\int_{-\infty}^{0} dw G_loc(w) d\Sigma(w) / dw -% -% Nevertheless we find most useful to exploit particle-hole symmetry and -% thus integrate over the whole real-axis. Care has to be taken whenever -% the frequency domain contains the origin, for therein resides a nasty -% pole, arising from the derivative of the self-energy. Thus we divide -% the integrand in (w < 0) and (w > 0) parts, and integrate the union. -% Failing to exclude the (w = 0) point, if exist, leads to a diverging -% uncontrolled result. - -wl = w(w<0); % Build w < 0 patch -gl = gloc(w<0); -sl = sloc(w<0); -wl = wl(1:end-1); -gl = gl(1:end-1); -dl = diff(sl); - -wr = w(w>0); % Build w > 0 patch -gr = gloc(w>0); -sr = sloc(w>0); -wr = wr(1:end-1); -gr = gr(1:end-1); -dr = diff(sr); - -w = [wl,wr]; % Join the patches -ds = [dl,dr]; -g = [gl,gr]; - -integrand = imag(g.*ds); -I = 1/pi*sum(integrand); -I = abs(I); - if DEBUG -Lfig = figure("Name",'Luttinger integrand','Visible','off'); -plot(w,integrand); -xlabel('\omega'); -ylabel('Im[G(\omega)\partial\Sigma/\partial\omega]'); -ylim([-0.1,0.2]); - end + % The original definition, as given by Logan, Tucker and Galpin, prescribes + % to integrate over the negative semiaxis: + % + % I = \frac{2}{\pi} \Im\int_{-\infty}^{0} dw G_loc(w) d\Sigma(w) / dw + % + % Nevertheless we find most useful to exploit particle-hole symmetry and + % thus integrate over the whole real-axis. Care has to be taken whenever + % the frequency domain contains the origin, for therein resides a nasty + % pole, arising from the derivative of the self-energy. Thus we divide + % the integrand in (w < 0) and (w > 0) parts, and integrate the union. + % Failing to exclude the (w = 0) point, if exist, leads to a diverging + % uncontrolled result. + + wl = w(w<0); % Build w < 0 patch + gl = gloc(w<0); + sl = sloc(w<0); + wl = wl(1:end-1); + gl = gl(1:end-1); + dl = diff(sl); + + wr = w(w>0); % Build w > 0 patch + gr = gloc(w>0); + sr = sloc(w>0); + wr = wr(1:end-1); + gr = gr(1:end-1); + dr = diff(sr); + + w = [wl,wr]; % Join the patches + ds = [dl,dr]; + g = [gl,gr]; + + integrand = imag(g.*ds); + I = 1/pi*sum(integrand); + I = abs(I); + end + diff --git a/code/+phys/sopt.m b/code/+phys/sopt.m index c4297da..dd0a575 100644 --- a/code/+phys/sopt.m +++ b/code/+phys/sopt.m @@ -1,4 +1,4 @@ -function im_sloc = sopt(A,F,U) +function iS = sopt(A,F,U) %% SOPT stands for Second Order Perturbation Theory: % it computes the imag of the 2nd order diagram for the self-energy % @@ -58,7 +58,7 @@ D = D + flip(D); % flip{v(1:end)}=v(end:1) %% Imaginary part of the Self-Energy according to SOPT - im_sloc = -pi * U^2 * D; + iS = -pi * U^2 * D; end diff --git a/code/dmft_loop.m b/code/dmft_loop.m index 691d1a7..12ce62b 100644 --- a/code/dmft_loop.m +++ b/code/dmft_loop.m @@ -35,7 +35,7 @@ % %% BSD 3-Clause License % -% Copyright (c) 2020, Gabriele Bellomia +% Copyright (c) 2020-2022, Gabriele Bellomia % All rights reserved. if(~exist('pmode','var')) @@ -55,7 +55,7 @@ while LOOP % Weiss field from local Green's function - g0 = 1 ./ (w + eta - 0.25 .* gloc); + g0 = 1 ./ (w + eta - 0.25*D^2 .* gloc); % Spectral-function of Weiss field A0 = -imag(g0) ./ pi; diff --git a/code/main.m b/code/main.m index 9082b72..9e33ec1 100644 --- a/code/main.m +++ b/code/main.m @@ -11,8 +11,8 @@ end %% INPUT: Physical Parameters -D = 1; % Bandwidth -U = 0.1; % On-site Repulsion +D = 4.0; % Bandwidth +U = 4.0; % On-site Repulsion beta = inf; % Inverse Temperature %% INPUT: Boolean Flags @@ -20,7 +20,7 @@ ULINE = 1; % Takes and fixes the given beta value and performs a U-driven line TLINE = 0; % Takes and fixes the given U value and performs a T-driven line UTSCAN = 0; % Ignores both given U and beta values and builds a full phase diagram -SPECTRAL = 0; % Controls plotting of spectral functions +SPECTRAL = 1; % Controls plotting of spectral functions PLOT = 1; % Controls plotting of *all static* figures GIF = 0; % Controls plotting of *animated* figures UARRAY = 0; % Activates SLURM scaling of interaction values @@ -32,11 +32,11 @@ mloop = 1000; % Max number of DMFT iterations err = 1e-5; % Convergence threshold for self-consistency mix = 0.10; % Mixing parameter for DMFT iterations (=1 means full update) -wres = 2^15+1; % Energy resolution in real-frequency axis -wcut = 6.00; % Energy cutoff in real-frequency axis -Umin = 0.00; % Hubbard U minimum value for phase diagrams -Ustep = 0.10; % Hubbard U incremental step for phase diagrams -Umax = 6.00; % Hubbard U maximum value for phase diagrams +wres = 2^13+1; % Energy resolution in real-frequency axis +wcut = 6.00 * D; % Energy cutoff in real-frequency axis +Umin = 0.00 * D; % Hubbard U minimum value for phase diagrams +Ustep = 0.10 * D; % Hubbard U incremental step for phase diagrams +Umax = 6.00 * D; % Hubbard U maximum value for phase diagrams Tmin = 1e-3; % Temperature U minimum value for phase diagrams Tstep = 1e-3; % Temperature incremental step for phase diagrams Tmax = 5e-2; % Temperature U maximum value for phase diagrams @@ -94,8 +94,7 @@ fprintf('< U = %f\n',U); [gloc{i},sloc{i}] = dmft_loop(gloc_0,w,D,U,beta,mloop,mix,err,'quiet'); Z(i) = phys.zetaweight(w,sloc{i}); - [I(i),infig] = phys.luttinger(w,sloc{i},gloc{i}); - plot.push_frame('luttok.gif',i,mloop,dt,infig); + I(i) = phys.luttinger(w,sloc{i},gloc{i}); S(i) = phys.strcorrel(w,sloc{i}); end if(PLOT) diff --git a/legacy/PYTHON/.ipynb_checkpoints/real_ipt-text_v3-checkpoint.ipynb b/legacy/PYTHON/.ipynb_checkpoints/real_ipt-text_v3-checkpoint.ipynb index 1ca35e4..647a778 100644 --- a/legacy/PYTHON/.ipynb_checkpoints/real_ipt-text_v3-checkpoint.ipynb +++ b/legacy/PYTHON/.ipynb_checkpoints/real_ipt-text_v3-checkpoint.ipynb @@ -3,12 +3,10 @@ { "cell_type": "code", "execution_count": 1, - "metadata": { - "collapsed": true - }, + "metadata": {}, "outputs": [], "source": [ - "%matplotlib inline" + "%matplotlib notebook" ] }, { @@ -43,7 +41,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -65,7 +63,7 @@ " return 1. / (np.exp(exponent) + 1)\n", "\n", "\n", - "def semi_circle_hiltrans(zeta, D=1):\n", + "def semi_circle_hiltrans(zeta, D):\n", " \"\"\"Calculate the Hilbert transform with a semicircular DOS \"\"\"\n", " sqr = np.sqrt(zeta**2 - D**2)\n", " sqr = np.sign(sqr.imag) * sqr\n", @@ -84,7 +82,7 @@ " return -np.pi * U**2 * (Appp + Appp[::-1])\n", "\n", "\n", - "def dmft_loop(gloc, w, U, beta, loops):\n", + "def dmft_loop(gloc, w, U, beta, D, loops):\n", " \"\"\"DMFT Loop for the single band Hubbard Model at Half-Filling\n", "\n", "\n", @@ -98,6 +96,8 @@ " On site interaction, Hubbard U\n", " beta : float\n", " Inverse temperature\n", + " D : float\n", + " Half-bandwidth of the noninteracting system\n", " loops : int\n", " Amount of DMFT loops to perform\n", "\n", @@ -130,7 +130,7 @@ " sigma = hsi + 1j * isi\n", "\n", " # Semi-circle Hilbert Transform\n", - " gloc = semi_circle_hiltrans(w - sigma)\n", + " gloc = semi_circle_hiltrans(w - sigma, D)\n", "\n", " return gloc, sigma" ] @@ -144,38 +144,1011 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "metadata": { - "scrolled": true + "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + " if (this.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: this.ratio });\n", + " }\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " evt.data.type = 'image/png';\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " evt.data\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.which === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.which;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.which !== 17) {\n", + " value += 'ctrl+';\n", + " }\n", + " if (event.altKey && event.which !== 18) {\n", + " value += 'alt+';\n", + " }\n", + " if (event.shiftKey && event.which !== 16) {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k';\n", + " value += event.which.toString();\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "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\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(msg['content']['data']);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ - "