{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Pulsebuilding tutorial\n", "\n", "## Table of Contents \n", "\n", " * [Lingo](#lingo)\n", " * [Blueprints](#blueprints)\n", " * [Basic blueprinting](#basicbp)\n", " * [Markers](#markers)\n", " * [Modifying blueprints](#bp-modify)\n", " * [Special segments](#specialsegments)\n", " * [Timesteps](#timesteps)\n", "\n", " * [Elements](#elements)\n", " * [Sequences](#sequences)\n", " * [Tektronix AWG 5014 output](#awg)\n", " * [Delays and filter compensation](#compensation)\n", " * [Sequences varying parameters](#seq-vary)\n", "\n", "## Lingo \n", "\n", "Let's settle on a vocabulary. At the highest level, we construct **sequences**. These sequences will eventually be uploaded to an AWG, e.g. the Tektronix AWG 5014. Each sequence consists of several **elements** than again consist of a number of **channels**. On each channel reside a **waveform** and two **markers**. The waveform and markers may either be added as numpy arrays or as **blueprint**. A blueprint is a set of instructions for making a waveform and two markers and consists of several **segments**\n", "\n", "That is to say, the food chain goes: segment -> blueprint -> element -> sequence.\n", "\n", "\n", "### Segments\n", "\n", "#### Normal segments\n", "\n", "A normal segment consists of a _unique_ name, a function object, a tuple of arguments to the function, and a **duration**. \n", "\n", " * The name: can be provided by the user or omitted. If omitted, the segment will get the name of its function. Since all names must be unique, the blueprint _appends numbers_ to names if they occur more than once. The numbers are appended chronologically throughout the blueprint. See example below. Note that valid input (base) names are strings NOT ending in a number. Thus, 'pi/2pulse' is valid, whereas 'pulsepi/2' is not.\n", " \n", " * The function: must be a python function taking at least two arguments; the sample rate and the segment duration. If the function takes other arguments (such as ramp slope, frequency, etc.) sample rate and duration arguments must be the last positional arguments. Keyword arguments are currently not allowed. See example at the very end.\n", " \n", " * The arguments: are in a tuple of $n-2$ arguments for a function taking $n$ arguments, i.e. specifying everything but the sample rate and duration.\n", " \n", "* The duration is a single number giving the desired duration of the segment in seconds. Some responsibility for making this number sensible with respect to the sample rate rests on the user.\n", "\n", "#### Special segments\n", "\n", "A special segment has a (protected) name and a number of arguments. So far, two special segments exist.\n", " \n", " * `waituntil`, args [time (int)]: When put in a blueprint, this function ensures that the _next_ segment starts at the absolute time `time` after the start of the element. It does so by filling any excess time with zeros. It fails if the previous segment will finish after time `time`.\n", " \n", " * `makemeanfit`. Not implemented yet. Will make the mean of the blueprint be a specified number. Will (eventually) exist in several versions, e.g. one achieving the goal by adding an offset, another by adding an appropriate DC segment at the end of the blueprint.\n", "\n", "### Blueprints\n", "\n", "Consist of a number of segments. Has an associated sample rate.\n", "\n", "### Elements\n", "\n", "Has a number of blueprints on each channel. Can have an arbitraty amount of integer-indexed channels, but the blueprint on each channel must have the same number of points and the same total duration as all the other blueprints.\n", "\n", "### Sequences\n", "\n", "Have an associated sample rate. \n", "\n" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "#\n", "# IMPORTS\n", "#\n", "%matplotlib inline\n", "import matplotlib as mpl\n", "import numpy as np\n", "\n", "import broadbean as bb\n", "from broadbean.plotting import plotter\n", "\n", "mpl.rcParams[\"figure.figsize\"] = (8, 3)\n", "mpl.rcParams[\"figure.subplot.bottom\"] = 0.15" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Blueprints \n", "\n", "## Basic blueprinting \n", "([back to ToC](#toc))\n", "\n", "In this section we show how to construct basic blueprints. The units of the vertical axis is **volts** and the units of the horizontal axis (the durations) is **seconds**." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Legend: Name, function, arguments, timesteps, durations\n", "Segment 1: \"ramp\", PulseAtoms.ramp, (0, 0.001), 3e-06\n", "----------\n", "Legend: Name, function, arguments, timesteps, durations\n", "Segment 1: \"ramp\", PulseAtoms.ramp, (0, 0.001), 3e-06\n", "Segment 2: \"mysine\", PulseAtoms.sine, (500000.0, 0.001, 0.001, 0), 2e-06\n", "Segment 3: \"ramp2\", PulseAtoms.ramp, (0.001, 0), 3e-06\n", "Segment 4: \"myfunc\", PulseAtoms.arb_func, ( at 0x000001B2945D0280>, {'ampl': 500000000.0}), 2e-06\n", "----------\n" ] } ], "source": [ "# The pulsebuilding module comes with a (small) collection of functions appropriate for being segments.\n", "ramp = bb.PulseAtoms.ramp # args: start, stop\n", "sine = bb.PulseAtoms.sine # args: freq, ampl, off, phase\n", "arb_func = bb.PulseAtoms.arb_func # args provided in a dict\n", "\n", "# make a blueprint\n", "\n", "# The blueprint takes no arguments\n", "bp1 = bb.BluePrint() # Do-nothing initialisation\n", "\n", "# the blueprint is filled via the insertSegment method\n", "# Call signature: position in the blueprint, function, args, name, duration\n", "bp1.insertSegment(0, ramp, (0, 1e-3), name=\"\", dur=3e-6)\n", "\n", "# A sample rate can be set (Sa/S). Without a sample rate, we can not plot the blueprint.\n", "bp1.setSR(1e9)\n", "\n", "# The blueprint can be inspected. Note that the segment was auto-named 'ramp'\n", "bp1.showPrint()\n", "\n", "# more segments can be added...\n", "bp1.insertSegment(1, sine, (5e5, 1e-3, 1e-3, 0), name=\"mysine\", dur=2e-6)\n", "bp1.insertSegment(2, ramp, (1e-3, 0), name=\"\", dur=3e-6)\n", "bp1.insertSegment(\n", " 3, arb_func, (lambda t, ampl: ampl * t * t, {\"ampl\": 5e8}), name=\"myfunc\", dur=2e-6\n", ")\n", "\n", "# ... and reinspected\n", "bp1.showPrint()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# For easy overview, we may plot the blueprint\n", "plotter(bp1)\n", "\n", "# The two bleak lines (red, blue) above the graph represent the channel markers.\n", "# They are described below." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/png": "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hkv5a/Too4/iwQcfxJEjR3DXXXfhE5/4BBKJBN71rnfZ3TQicqGFhQVcuXJl+etr167h1KlTaGxsRG9vL9773vfiIx/5CLZv344tW7bgT/7kT9DZ2bmcuU9EtJqHH34Yzz77LP793/8dNTU1y/tG6+rqEI1GUVdXh4ceegiPPvooGhsbUVtbi/e85z245557bMvIB1gual0+9alP4eMf/zhGR0dx55134sknn8Tdd99td7OIyIW+973v4Sd+4iek6w8++CCeeeYZ6LqOD3/4w/ibv/kbzM7O4sd+7Mfw6U9/Gjt27LChtUTkNj6fz/T63/7t3+I3fuM3AOQL7L/vfe/DF77wBaTTadx333349Kc/betSPgNTIiIiInIE7jElIiIiIkdgYEpEREREjsDAlIiIiIgcgYEpERERETkCA1MiIiIicgQGpkRERETkCAxMiYiIiMgRGJgSERERkSMwMCUiWsXU1BRaW1tx/fr1Db3OG9/4Rrz3ve8tSZtK5R3veAf+6q/+yu5mEBEt48lPRESrePTRRzE/P4+nn356Q68zPT2NYDCImpqaErVs4/r7+/H6178e165dQ11dnd3NISLijCkRUSGLi4v43Oc+h4ceemjDr9XY2Fh0UKrrOnK53IbbINq3bx+2bduGf/iHfyj5axMRFYOBKRFRAV/96lcRDofxmte8Zvna9773Pfh8PnzjG9/AwYMHEY1G8ZM/+ZMYHx/H1772NezevRu1tbX41V/9VSwuLi4/T1zKT6fT+MAHPoCenh6Ew2Hccccd+NznPmf4GV/72tdw+PBhhMNh/OAHP0A6ncbv/u7vorW1FZFIBD/2Yz+GY8eOrfoePv3pT2P79u2IRCJoa2vD/fffb/j+2972NvzTP/1TCT4tIqKNC9jdACIip3rhhRdw+PBh0+/96Z/+KT71qU+hqqoKDzzwAB544AGEw2E8++yzWFhYwM///M/jk5/8JD7wgQ+YPv/Xf/3X8eKLL+LJJ5/EgQMHcO3aNUxOThoe84d/+If4y7/8S2zduhUNDQ34gz/4A3z5y1/G3/3d32HTpk144okncN999+HKlStobGyUfsbx48fxu7/7u/j7v/97vPa1r8X09DReeOEFw2PuuusufPSjH0U6nUY4HC7ykyIiKg0GpkREBdy4cQOdnZ2m3/vIRz6C173udQCAhx56CI899hiuXr2KrVu3AgDuv/9+fPe73zUNTC9duoQvfelL+Na3voV7770XAJaft9L/+3//D29605sAAIlEAp/5zGfwzDPP4C1veQsA4Omnn8a3vvUtfO5zn8P73/9+6fkDAwOIxWL42Z/9WdTU1GDTpk04ePCg4TGdnZ3IZDIYHR3Fpk2b1vrREBFZgkv5REQFJJNJRCIR0+/t379/+f/b2tpQVVVlCC7b2towPj5u+txTp07B7/fjDW94w6o//8iRI8v/f/XqVWSz2eVgGACCwSDuuusunD9/3vT5b3rTm7Bp0yZs3boV73znO/GP//iPhu0FABCNRgFAuk5EZAcGpkREBTQ3N2NmZsb0e8FgcPn/fT6f4eula5qmmT53KRi8nVgstsaWmqupqcHJkyfxhS98AR0dHfjQhz6EAwcOYHZ2dvkx09PTAICWlpYN/SwiolJgYEpEVMDBgwdx7ty5kr9uX18fNE3D888/v+bnbNu2DaFQCP/zP/+zfC2bzeLYsWPYs2dPwecFAgHce++9eOKJJ3D69Glcv34d3/nOd5a/39/fj+7ubjQ3Nxf3ZoiISoh7TImICrjvvvvw2GOPYWZmBg0NDSV73c2bN+PBBx/Eb/7mby4nP924cQPj4+N44IEHTJ8Ti8Xw27/923j/+9+PxsZG9Pb24oknnsDi4mLBclZf+cpX8Morr+D1r389Ghoa8NWvfhWapmHnzp3Lj3nhhRfw5je/uWTvjYhoIxiYEhEV0NfXh0OHDuFLX/oS3v3ud5f0tT/zmc/ggx/8IH7nd34HU1NT6O3txQc/+MFVn/Oxj30Mmqbhne98J+bn53HkyBF84xvfKBg019fX41//9V/xp3/6p0ilUti+fTu+8IUvYO/evQCAVCqFf/u3f8PXv/71kr43IqJi8eQnIqJV/Nd//Rfe//73o7+/H4rird1Pn/nMZ/Dcc8/hm9/8pt1NISICwBlTIqJV/czP/AwuX76MoaEh9PT02N2ckgoGg/jkJz9pdzOIiJZxxpSIiIiIHMFb61JERERE5FoMTImIiIjIERiYEhEREZEjMDAlIiIiIkdgYEpEREREjsDAlIiIiIgcgYEpERERETkCA1MiIiIicgQGpkRERETkCP8fP0ogRU+GBtwAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Blueprints may be added together\n", "bp2 = bp1 + bp1\n", "plotter(bp2)\n", "\n", "# Segments may be removed from a blueprint. They are removed by name.\n", "bp2.removeSegment(\"ramp2\")\n", "plotter(bp2)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number of points in blueprint: 10000\n", "Length of blueprint in seconds: 9.999999999999999e-06\n", "Number of segments in blueprint: 4\n" ] } ], "source": [ "# A blueprint has a handful of different lengths one may check\n", "print(f\"Number of points in blueprint: {bp1.points}\")\n", "print(f\"Length of blueprint in seconds: {bp1.duration}\")\n", "print(f\"Number of segments in blueprint: {bp1.length_segments}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Markers \n", "([back to ToC](#toc))\n", "\n", "All markers are OFF by default. Markers can be added to a blueprint (switched ON) in two different ways. Either a marker is specified by its ON time in *absolute time* or by its ON time *relative* to a certain segment." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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 */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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 */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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" } ], "source": [ "# An essential feature of blueprints is that they can be modified\n", "\n", "bp_mod = bb.BluePrint()\n", "bp_mod.setSR(100)\n", "\n", "bp_mod.insertSegment(0, ramp, (0, 0), name=\"before\", dur=1)\n", "bp_mod.insertSegment(1, ramp, (1, 1), name=\"plateau\", dur=1)\n", "bp_mod.insertSegment(2, ramp, (0, 0), name=\"after\", dur=1)\n", "\n", "plotter(bp_mod)\n", "\n", "# Functional arguments can be changed\n", "\n", "# They are looked up by segment name\n", "bp_mod.changeArg(\n", " \"before\", \"stop\", 1\n", ") # the argument to change may either be the argument name or its position\n", "bp_mod.changeArg(\"after\", 0, 1)\n", "\n", "plotter(bp_mod)\n", "\n", "# Durations can also be changed\n", "bp_mod.changeDuration(\"plateau\", 2)\n", "\n", "plotter(bp_mod)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Special segments \n", "([back to ToC](#toc))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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" } ], "source": [ "# The 'waituntil' segment fills up a part of the blueprint with zeros\n", "\n", "# Example: a square pulse, then waiting until 5 s exactly and then a new sine\n", "\n", "bp_wait = bb.BluePrint()\n", "bp_wait.setSR(100)\n", "\n", "bp_wait.insertSegment(0, ramp, (0, 0), dur=1)\n", "bp_wait.insertSegment(1, ramp, (1, 1), name=\"plateau\", dur=1)\n", "# function must be sthe string 'waituntil', the argument is the ABSOLUTE time to wait until\n", "bp_wait.insertSegment(2, \"waituntil\", (5,))\n", "bp_wait.insertSegment(3, sine, (1, 0.1, 0, -np.pi / 2), dur=1)\n", "plotter(bp_wait)\n", "\n", "# If we make the square pulse longer, the sine still occurs at 5 s\n", "bp_wait.changeDuration(\"plateau\", 1.5)\n", "plotter(bp_wait)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Elements \n", "([back to ToC](#toc))\n", "\n", "Elements are containers containing blueprints. A valid element consists of blueprints that all have the same number of points and the same overall duration." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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" } ], "source": [ "# We can modify the blueprints of an element through the element object\n", "\n", "# Change the sine freq\n", "elem1.changeArg(\n", " 3, \"sine\", \"freq\", 6.67e6\n", ") # Call signature: channel, segment name, argument, new_value\n", "\n", "# make the second plateaus last longer\n", "elem1.changeDuration(\n", " 1, \"top2\", 0.2e-6\n", ") # In this blueprint, the second top is called top2\n", "elem1.changeDuration(3, \"top\", 0.2e-6)\n", "\n", "plotter(elem1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Sequences \n", "([back to ToC](#toc))\n", "\n", "Finally, we have reached the top level of the module: sequences. Unsurprisingly, sequences are containers containing elements. All elements in a sequence must specify the same channels." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "seq1 = bb.Sequence()\n", "\n", "# We fill up the sequence by adding elements at different sequence positions.\n", "# A valid sequence is filled from 1 to N with NO HOLES, i.e. if position 4 is filled, so must be position 1, 2, and 3\n", "\n", "#\n", "# Make blueprints, make elements\n", "\n", "# Create the blueprints\n", "bp_square = bb.BluePrint()\n", "bp_square.setSR(1e9)\n", "bp_square.insertSegment(0, ramp, (0, 0), dur=100e-9)\n", "bp_square.insertSegment(1, ramp, (1e-3, 1e-3), name=\"top\", dur=100e-9)\n", "bp_square.insertSegment(2, ramp, (0, 0), dur=100e-9)\n", "bp_boxes = bp_square + bp_square\n", "#\n", "bp_sine = bb.BluePrint()\n", "bp_sine.setSR(1e9)\n", "bp_sine.insertSegment(0, sine, (3.333e6, 1.5e-3, 0, 0), dur=300e-9)\n", "bp_sineandboxes = bp_sine + bp_square\n", "\n", "# create elements\n", "elem1 = bb.Element()\n", "elem1.addBluePrint(1, bp_boxes)\n", "elem1.addBluePrint(3, bp_sineandboxes)\n", "#\n", "elem2 = bb.Element()\n", "elem2.addBluePrint(3, bp_boxes)\n", "elem2.addBluePrint(1, bp_sineandboxes)\n", "\n", "# Fill up the sequence\n", "seq1.addElement(1, elem1) # Call signature: seq. pos., element\n", "seq1.addElement(2, elem2)\n", "seq1.addElement(3, elem1)\n", "\n", "# set its sample rate\n", "seq1.setSR(elem1.SR)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on method changeArg in module broadbean.broadbean:\n", "\n", "changeArg(channel:Union[str, int], name:str, arg:Union[str, int], value:Union[int, float], replaceeverywhere:bool=False) -> None method of broadbean.broadbean.Element instance\n", " Change the argument of a function of the blueprint on the specified\n", " channel.\n", " \n", " Args:\n", " channel: The channel where the blueprint sits.\n", " name: The name of the segment in which to change an argument\n", " arg: Either the position (int) or name (str) of\n", " the argument to change\n", " value: The new value of the argument\n", " replaceeverywhere: If True, the same argument is overwritten\n", " in ALL segments where the name matches. E.g. 'gaussian1' will\n", " match 'gaussian', 'gaussian2', etc. If False, only the segment\n", " with exact name match gets a replacement.\n", " \n", " Raises:\n", " ValueError: If the specified channel has no blueprint.\n", " ValueError: If the argument can not be matched (either the argument\n", " name does not match or the argument number is wrong).\n", "\n" ] } ], "source": [ "help(seq1.element(1).changeArg)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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" } ], "source": [ "seq1.setChannelAmplitude(1, 10e-3) # Call signature: channel, amplitude (peak-to-peak)\n", "seq1.setChannelOffset(1, 0)\n", "seq1.setChannelAmplitude(3, 10e-3)\n", "seq1.setChannelOffset(3, 0)\n", "\n", "# Here we repeat each element twice and then proceed to the next, wrapping over at the end\n", "seq1.setSequencingTriggerWait(1, 0)\n", "seq1.setSequencingNumberOfRepetitions(1, 2)\n", "seq1.setSequencingEventJumpTarget(1, 0)\n", "seq1.setSequencingGoto(1, 2)\n", "#\n", "seq1.setSequencingTriggerWait(2, 0)\n", "seq1.setSequencingNumberOfRepetitions(2, 2)\n", "seq1.setSequencingEventJumpTarget(2, 0)\n", "seq1.setSequencingGoto(1, 3)\n", "#\n", "seq1.setSequencingTriggerWait(3, 0)\n", "seq1.setSequencingNumberOfRepetitions(3, 2)\n", "seq1.setSequencingEventJumpTarget(3, 0)\n", "seq1.setSequencingGoto(3, 1)\n", "\n", "# then we may finally get the \"package\" to give the QCoDeS driver for upload\n", "package = seq1.outputForAWGFile()\n", "\n", "# Note that the sequencing information is included in the plot in a way mimicking the\n", "# way the display of the Tektronix AWG 5014\n", "plotter(seq1)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 3]" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# The package is a SLICEABLE object\n", "# By slicing and indexing it, one may retrieve different parts of the sequence\n", "\n", "chan1_awg_input = package[0] # returns a tuple yielding an awg file with channel 1\n", "chan3_awg_input = package[1] # returns a tuple yielding an awg file with channel 3\n", "\n", "both_chans_awg_input = package[\n", " :\n", "] # returns a tuple yielding an awg file with both channels\n", "\n", "# This may be useful to make one big sequence for one experiment and then uploading part of it to one awg\n", "# and part of it to another (since physical awg's usually don't have enough channels for a big experiment)\n", "\n", "# To see how the channels are counted, look up the channels\n", "package.channels" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "## Example of uploading the sequence (requires having qcodes installed, see https://github.com/QCoDeS/Qcodes)\n", "\n", "# from qcodes.instrument_drivers.tektronix.AWG5014 import Tektronix_AWG5014\n", "# awg = Tektronix_AWG5014('AWG1', 'TCPIP0::172.20.3.57::inst0::INSTR', timeout=40)\n", "# awg.make_send_and_load_awg_file(*package[:])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Delays and filter compensation\n", "([back to ToC](#toc))\n", "\n", "In a real experimental setting, the signal transmission line may distort and/or delay the pulse sequence. The Sequence object can perform some compensation for this when making the `.awg` file." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [], "source": [ "# To delay channel 1 with respect to the other channels, set its delay\n", "seq1.setChannelDelay(1, 0)\n", "seq1.setChannelDelay(3, 123e-9)\n", "\n", "# To apply for a high pass filter with a cut-off frequency of 1 MHz on channel 3, we can do\n", "seq1.setChannelFilterCompensation(3, \"HP\", order=1, f_cut=1e6)\n", "# or, equivalently,\n", "seq1.setChannelFilterCompensation(3, \"HP\", order=1, tau=1e-6)\n", "\n", "# Note that setting the filter compensation may invalidate the sequence in the sense that the specified voltage ranges\n", "# on the AWG may have become too small. The function outputForAWGFile will warn you if this is the case.\n", "\n", "newpackage = seq1.outputForAWGFile()" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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 */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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" } ], "source": [ "# Example 2: Vary the duration AND the high level\n", "\n", "# It is straighforward to vary several things throughout the sequence\n", "\n", "# We make the same base element as in Example 1\n", "basebp = bb.BluePrint()\n", "basebp.insertSegment(0, ramp, (0, 0), dur=0.5)\n", "basebp.insertSegment(1, ramp, (1, 1), dur=1, name=\"varyme\")\n", "basebp.insertSegment(2, \"waituntil\", 5)\n", "basebp.setSR(100)\n", "\n", "baseelem = bb.Element()\n", "baseelem.addBluePrint(1, basebp)\n", "\n", "# Now we make a 5-step sequence varying the duration AND the high level\n", "# We thus vary 3 things, a duration, a ramp start, and a ramp stop\n", "channels = [1, 1, 1]\n", "names = [\"varyme\", \"varyme\", \"varyme\"]\n", "args = [\"duration\", \"start\", \"stop\"]\n", "iters = [[1, 1.5, 2, 2.5, 3], [1, 0.8, 0.7, 0.6, 0.5], [1, 0.8, 0.7, 0.6, 0.5]]\n", "\n", "seq2 = bb.makeVaryingSequence(baseelem, channels, names, args, iters)\n", "plotter(seq2)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/william/sourcecodes/pulsebuilding/broadbean/broadbean.py:1425: UserWarning: Deprecation warning. This function is only compatible with AWG5014 output and will be removed. Please use the specific setSequencingXXX methods.\n", " warnings.warn('Deprecation warning. This function is only compatible '\n" ] }, { "data": { "application/javascript": "/* Put everything inside the global mpl namespace */\nwindow.mpl = {};\n\n\nmpl.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\nmpl.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\nmpl.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\nmpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n\n}\n\n\nmpl.figure.prototype._root_extra_style = function(canvas_div) {\n\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype._root_extra_style = function(el){\n var fig = this\n el.on(\"remove\", function(){\n\tfig.close_ws(fig, {});\n });\n}\n\nmpl.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\nmpl.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\nmpl.figure.prototype.handle_save = function(fig, msg) {\n fig.ondownload(fig, null);\n}\n\n\nmpl.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.\nif (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" } ], "source": [ "# Example 3: Modify the high level of a square pulse inside a sequence\n", "\n", "#\n", "\n", "pulsebp = bb.BluePrint()\n", "pulsebp.insertSegment(0, ramp, (0, 0), dur=5e-4)\n", "pulsebp.insertSegment(1, ramp, (1, 1), dur=1e-3, name=\"varyme\")\n", "pulsebp.insertSegment(2, \"waituntil\", 2e-3)\n", "pulsebp.setSR(1e6)\n", "\n", "sinebp = bb.BluePrint()\n", "sinebp.insertSegment(0, sine, (0.2e3, 0.5, 0.5, 0), dur=10e-3)\n", "sinebp.setSR(1e6)\n", "\n", "elem1 = bb.Element()\n", "elem1.addBluePrint(1, pulsebp)\n", "\n", "elem2 = bb.Element()\n", "elem2.addBluePrint(1, sinebp)\n", "\n", "baseseq = bb.Sequence()\n", "baseseq.setSR(1e6)\n", "baseseq.addElement(1, elem1)\n", "baseseq.addElement(2, elem2)\n", "\n", "baseseq.setSequenceSettings(1, 0, 20, 0, 0)\n", "baseseq.setSequenceSettings(2, 0, 1, 0, 1)\n", "\n", "plotter(baseseq)\n", "\n", "# now vary this sequence\n", "\n", "poss = [1, 1]\n", "channels = [1, 1]\n", "names = [\"varyme\", \"varyme\"]\n", "args = [\"start\", \"stop\"]\n", "iters = [[1, 0.75, 0.5], [1, 0.75, 0.5]]\n", "\n", "newseq = bb.repeatAndVarySequence(baseseq, poss, channels, names, args, iters)\n", "plotter(newseq)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.11" } }, "nbformat": 4, "nbformat_minor": 2 }