From 628fe73ae17735b189b72400817e4023b7f45412 Mon Sep 17 00:00:00 2001 From: "William H.P. Nielsen" Date: Tue, 21 Mar 2017 15:46:38 +0100 Subject: [PATCH] driver: ziuhfli (#466) * feat: Add a driver for ZI UHF-LI First commit providing a driver with a working sweeper. Needs refactorising the sweeper into a MultiParameter * fix: Change the sweep into a MultiParameter Change the sweep from a normal instrument method into a MultiParameter Breaking Changes: execute_sweep no longer exists. All sweep data goes through the Sweep parameter. * fix: Tidy code Tidy code and remove whitespace * feat: Add example notebook Add an example notebook explaining how to use the sweeper. * fix: Correct multiple dict keys Correct the multiply-defined dict keys of the demodulator trigger. * updating ZIUHFLI.py on dummy setup * intermediate commit * testing" " * feat: Add parameters Finish Sigout parameters and start adding scope parameters. * Intermediate commit To be cleaned later * feat: Add scope get function Add a get function to the scope multiparameter and document this in the notebook. * fix: Update setpoints with delay Update the scope setpoints with reference and delay values. * fix: Adjust setpoints Adjust the setpoints of the scope to match the expectations of the loop. * fix: pep8 Break lines and trim whitespace. * fix: Add scope instance to instrument Add a scope instance to the __init__ of the instrument. * docs: Fix requested changes Add requested docs --- .../Qcodes example with ZI UHF-LI.ipynb | 3144 +++++++++++++++++ qcodes/instrument_drivers/ZI/ZIUHFLI.py | 1930 ++++++++++ qcodes/instrument_drivers/ZI/__init__.py | 1 + 3 files changed, 5075 insertions(+) create mode 100644 docs/examples/Qcodes example with ZI UHF-LI.ipynb create mode 100644 qcodes/instrument_drivers/ZI/ZIUHFLI.py create mode 100644 qcodes/instrument_drivers/ZI/__init__.py diff --git a/docs/examples/Qcodes example with ZI UHF-LI.ipynb b/docs/examples/Qcodes example with ZI UHF-LI.ipynb new file mode 100644 index 00000000000..e90b3d1fb77 --- /dev/null +++ b/docs/examples/Qcodes example with ZI UHF-LI.ipynb @@ -0,0 +1,3144 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# QCoDeS Example with ZI UHF-LI\n", + "\n", + "\n", + "## Table of Contents\n", + "\n", + "* [Prerequisites](#prereq)\n", + "* [Basic Usage of the ZI UHF-LI](#basic)\n", + " * [Signal Inputs](#sigins)\n", + " * [Demodulators](#demods)\n", + " * [Signal Outputs](#sigouts)\n", + "* [Using the Sweeper](#sweeper)\n", + "* [Using the Scope](#scope)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true, + "scrolled": true + }, + "outputs": [], + "source": [ + "%matplotlib notebook\n", + "import time\n", + "import logging\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "plt.ion()\n", + "\n", + "import qcodes as qc\n", + "from qcodes.instrument_drivers.ZI.ZIUHFLI import ZIUHFLI\n", + "\n", + "log = logging.getLogger(__name__)\n", + "log.setLevel(logging.INFO)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "deletable": true, + "editable": true + }, + "source": [ + "# Prerequisites \n", + "\n", + "It is necessary to download and install the ZI Lab One software. Additionally, both the data server and the web server must run, and a connection to the instrument must be instantiated (this can be done via the web interface). This example notebook makes no assumptions on what is connected to the instrument (but if you want nice data plots, go ahead and connect something interesting)." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true, + "scrolled": false + }, + "outputs": [], + "source": [ + "# Instantiate the QCoDeS instrument\n", + "zi = ZIUHFLI('ZIUHFLI', 'dev2235')\n", + "\n", + "# Bind it to a QCoDeS station for later use (one should ALWAYS do this with instruments)\n", + "station = qc.Station(zi)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "deletable": true, + "editable": true + }, + "source": [ + "# Basic Usage of the ZI UHF-LI \n", + "\n", + "Most of the \"front panel\" (i.e. the Web UI) `Lock-In` and `signal input` settings are available as parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Oscillator 2 has frequency: 752100 Hz\n" + ] + } + ], + "source": [ + "zi.oscillator2_freq.set(752.1e3)\n", + "print('Oscillator 2 has frequency: {:.0f} Hz'.format(zi.oscillator2_freq.get()))\n", + "zi.signal_input1_range(1)\n", + "zi.signal_input1_scaling(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Signal Inputs " + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Available signal input settings:\n", + "\n", + " signal_input1_AC, AC coupling ()\n", + " signal_input1_impedance, Input impedance ()\n", + " signal_input1_scaling, Input scaling ()\n", + " signal_input1_diff, Input signal subtraction ()\n", + " signal_input1_range, Input range (V)\n" + ] + } + ], + "source": [ + "print('Available signal input settings:\\n')\n", + "for param in [p for p in zi.parameters if 'signal_input1' in p]:\n", + " print(' {}, {} ({})'.format(param, zi.parameters[param].label, zi.parameters[param].unit))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "deletable": true, + "editable": true + }, + "source": [ + "## Demodulators " + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Available demodulator settings:\n", + "\n", + " demod1_streaming, Data streaming ()\n", + " demod1_timeconstant, Filter time constant (s)\n", + " demod1_samplerate, Sample rate (Sa/s)\n", + " demod1_phaseshift, Phase shift (degrees)\n", + " demod1_sinc, Sinc filter ()\n", + " demod1_harmonic, Reference frequency multiplication factor ()\n", + " demod1_signalin, Signal input ()\n", + " demod1_order, Filter order ()\n", + " demod1_trigger, Trigger ()\n" + ] + } + ], + "source": [ + "print('Available demodulator settings:\\n')\n", + "for param in [p for p in zi.parameters if 'demod1' in p]:\n", + " print(' {}, {} ({})'.format(param, zi.parameters[param].label, zi.parameters[param].unit))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Signal Outputs " + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Available signal output settings:\n", + "\n", + " signal_output1_enable, Enable signal output's amplitude. ()\n", + " signal_output1_offset, Signal output offset (V)\n", + " signal_output1_imp50, Switch to turn on 50 Ohm impedance ()\n", + " signal_output1_on, Turn signal output on and off. ()\n", + " signal_output1_range, Signal output range ()\n", + " signal_output1_autorange, Enable signal output range. ()\n", + " signal_output1_ampdef, Signal output amplitude's definition (V)\n", + " signal_output1_amplitude, Signal output amplitude (V)\n" + ] + } + ], + "source": [ + "print('Available signal output settings:\\n')\n", + "for param in [p for p in zi.parameters if 'signal_output1' in p]:\n", + " print(' {}, {} ({})'.format(param, zi.parameters[param].label, zi.parameters[param].unit))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "deletable": true, + "editable": true + }, + "source": [ + "# Using the sweeper \n", + "\n", + "The QCoDeS sweep is fully indendent of the GUI Sweep, meaning that parameters set in QCoDeS will not affect the GUI sweep and vice versa.\n", + "\n", + "The sweeper settings are configured via a bunch of parameters, all named `sweeper_XXX`.\n", + "This configures the x-axis of the sweep as well as the sweep acquisition settings. To learn more about what a certain parameter does, it is sometimes helpful to print its `__doc__` attribute.\n", + "\n", + "Which signals are **returned** by the sweeper is controlled by adding (removing) signals to (from) the sweep.\n", + "\n", + "The sweep settings can be displayed with the `print_sweeper_settings` command.\n", + "\n", + "Before the sweep can be performed, it must be built. \n", + "This is done with the Sweep parameter, which is the parameter holding the sweep data.\n", + "Note that building the sweep may change some of the time constants, and in particular change the sweep time. In case of doubt, re-run `print_sweeper_settings`." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [], + "source": [ + "# Set up a sweep sweeping an internal oscillator frequency from 1 MHz to 5 MHz\n", + "# We want the sweeper to sweep linearly over 200 points\n", + "zi.sweeper_param('Osc 1 Frequency')\n", + "zi.sweeper_xmapping('lin')\n", + "zi.sweeper_start(1e6)\n", + "zi.sweeper_stop(10e6)\n", + "zi.sweeper_samplecount(100)\n", + "zi.sweeper_BWmode('fixed')\n", + "zi.sweeper_BW(250)\n", + "zi.sweeper_order(4)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " For each sweep point, the demodulator\n", + " filter bandwidth (time constant) may\n", + " be either set automatically, be the\n", + " current demodulator bandwidth or be\n", + " a fixed number; the sweeper_BW\n", + " parameter.\n", + " \r\n", + "\r\n", + "Parameter class:\r\n", + "\r\n", + "* `name` sweeper_BWmode\r\n", + "* `label` Sweeper bandwidth control mode\r\n", + "* `unit` \r\n", + "* `vals` \n" + ] + } + ], + "source": [ + "# I wonder what the sweeper BWmode does...\n", + "print(zi.sweeper_BWmode.__doc__)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true, + "deletable": true, + "editable": true + }, + "outputs": [], + "source": [ + "# Add three signals to the sweep, all measured on demodulator 1\n", + "zi.add_signal_to_sweeper(1, 'Xrms')\n", + "zi.add_signal_to_sweeper(1, 'Yrms')\n", + "zi.add_signal_to_sweeper(1, 'Rrms')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [], + "source": [ + "# Make sure that demodulator 1 is measuring what and as it should\n", + "zi.demod1_trigger('Continuous')\n", + "zi.demod1_signalin('Sig In 1')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ACQUISITION\n", + " Sweeper bandwidth control mode: fixed ()\n", + " Fixed bandwidth sweeper bandwidth (NEP): 50.0 ()\n", + " Sweeper filter order: 1 ()\n", + " Minimal no. of samples to average at each sweep point: 25 ()\n", + " Minimal averaging time: 0.1 (s)\n", + " Minimal settling time for the sweeper: 1e-06 (s)\n", + " Sweep filter settling time: 4.605170185988091 (dim. less.)\n", + "HORISONTAL\n", + " Start value of the sweep: 1000000.0\n", + " Stop value of the sweep: 10000000.0\n", + " Units of sweep x-axis: Hz\n", + " Length of the sweep (pts): 25\n", + " Parameter to sweep (sweep x-axis): Osc 1 Frequency\n", + " Sweep mode: Sequential\n", + " Sweep timeout: 600\n", + "VERTICAL\n", + " Signal 1: Demodulator 1: Xrms\n", + " Signal 2: Demodulator 1: Yrms\n", + " Signal 3: Demodulator 1: Rrms\n", + "DEMODULATORS\n", + " Demodulator 1: Filter time constant: 0.000311 (s)\n", + " Demodulator 1: Filter order: 4.000000 ()\n", + " Demodulator 1: Sample rate: 1716.613770 (Sa/s)\n", + "META\n", + " Expected sweep time: 0.9 (s)\n", + " Sweep timeout: 600 (s)\n", + " Sweep built and ready to execute: False\n" + ] + } + ], + "source": [ + "# I wonder what kind of sweep we have made now...\n", + "zi.print_sweeper_settings()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ACQUISITION\n", + " Sweeper bandwidth control mode: fixed ()\n", + " Fixed bandwidth sweeper bandwidth (NEP): 250.0 ()\n", + " Sweeper filter order: 4 ()\n", + " Minimal no. of samples to average at each sweep point: 25 ()\n", + " Minimal averaging time: 0.1 (s)\n", + " Minimal settling time for the sweeper: 1e-06 (s)\n", + " Sweep filter settling time: 9.998049677807453 (dim. less.)\n", + "HORISONTAL\n", + " Start value of the sweep: 1000000.0\n", + " Stop value of the sweep: 10000000.0\n", + " Units of sweep x-axis: Hz\n", + " Length of the sweep (pts): 100\n", + " Parameter to sweep (sweep x-axis): Osc 1 Frequency\n", + " Sweep mode: Sequential\n", + " Sweep timeout: 600\n", + "VERTICAL\n", + " Signal 1: Demodulator 1: Xrms\n", + " Signal 2: Demodulator 1: Yrms\n", + " Signal 3: Demodulator 1: Rrms\n", + "DEMODULATORS\n", + " Demodulator 1: Filter time constant: 0.000311 (s)\n", + " Demodulator 1: Filter order: 4.000000 ()\n", + " Demodulator 1: Sample rate: 1716.613770 (Sa/s)\n", + "META\n", + " Expected sweep time: 1.8 (s)\n", + " Sweep timeout: 600 (s)\n", + " Sweep built and ready to execute: True\n" + ] + } + ], + "source": [ + "# Gee, that looks good! Note the last line, the sweep is NOT ready to execute.\n", + "zi.Sweep.build_sweep()\n", + "# Now it is!\n", + "zi.print_sweeper_settings()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [], + "source": [ + "# We can now execute the sweeper by simply invoking Sweep.get\n", + "# This returns a tuple with the signals we asked for\n", + "(X, Y, R) = zi.Sweep.get()" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false, + "deletable": true, + "editable": true + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\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('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", + "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 = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(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 (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.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", + " this.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 = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\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", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('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", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\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", + " // 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", + "\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= 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('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\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('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", + "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 = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(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 (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.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", + " this.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 = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\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 nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\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", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('