From 12d45106e8a4f8ef9c4d08f7caca72f6c6d97eb1 Mon Sep 17 00:00:00 2001 From: Merlin Date: Fri, 15 Apr 2016 18:51:27 +0200 Subject: [PATCH 001/169] Added drivers for agilent 34400 series, keithley 2600 series, keithley2400 (super-basic), triton fridge, patches for loop.py and ip.py loop.py and ip.py needed fixes for things to work --- .../Qcodes example with Agilent 34400A.ipynb | 497 ++++++++++++++ .../Qcodes example with Keithley 2600.ipynb | 632 ++++++++++++++++++ .../examples/Qcodes example with Triton.ipynb | 332 +++++++++ docs/examples/Triton1_thermometry.reg | 295 ++++++++ qcodes/instrument/ip.py | 11 +- .../agilent/Agilent_34400A.py | 136 ++++ qcodes/instrument_drivers/oxford/triton.py | 145 ++++ .../tektronix/Keithley_2400.py | 55 ++ .../tektronix/Keithley_2600.py | 124 ++++ qcodes/loops.py | 3 +- 10 files changed, 2224 insertions(+), 6 deletions(-) create mode 100644 docs/examples/Qcodes example with Agilent 34400A.ipynb create mode 100644 docs/examples/Qcodes example with Keithley 2600.ipynb create mode 100644 docs/examples/Qcodes example with Triton.ipynb create mode 100644 docs/examples/Triton1_thermometry.reg create mode 100644 qcodes/instrument_drivers/agilent/Agilent_34400A.py create mode 100644 qcodes/instrument_drivers/oxford/triton.py create mode 100644 qcodes/instrument_drivers/tektronix/Keithley_2400.py create mode 100644 qcodes/instrument_drivers/tektronix/Keithley_2600.py diff --git a/docs/examples/Qcodes example with Agilent 34400A.ipynb b/docs/examples/Qcodes example with Agilent 34400A.ipynb new file mode 100644 index 000000000000..4610d70ccce1 --- /dev/null +++ b/docs/examples/Qcodes example with Agilent 34400A.ipynb @@ -0,0 +1,497 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "/*\r\n", + " * Qcodes Jupyter/IPython widgets\r\n", + " */\r\n", + "require([\r\n", + " 'nbextensions/widgets/widgets/js/widget',\r\n", + " 'nbextensions/widgets/widgets/js/manager'\r\n", + "], function (widget, manager) {\r\n", + "\r\n", + " var UpdateView = widget.DOMWidgetView.extend({\r\n", + " render: function() {\r\n", + " window.MYWIDGET = this;\r\n", + " this._interval = 0;\r\n", + " this.update();\r\n", + " },\r\n", + " update: function() {\r\n", + " this.display(this.model.get('_message'));\r\n", + " this.setInterval();\r\n", + " },\r\n", + " display: function(message) {\r\n", + " /*\r\n", + " * display method: override this for custom display logic\r\n", + " */\r\n", + " this.el.innerHTML = message;\r\n", + " },\r\n", + " remove: function() {\r\n", + " clearInterval(this._updater);\r\n", + " },\r\n", + " setInterval: function(newInterval) {\r\n", + " var me = this;\r\n", + " if(newInterval===undefined) newInterval = me.model.get('interval');\r\n", + " if(newInterval===me._interval) return;\r\n", + "\r\n", + " me._interval = newInterval;\r\n", + "\r\n", + " if(me._updater) clearInterval(me._updater);\r\n", + "\r\n", + " if(me._interval) {\r\n", + " me._updater = setInterval(function() {\r\n", + " me.send({myupdate: true});\r\n", + " if(!me.model.comm_live) {\r\n", + " console.log('missing comm, canceling widget updates', me);\r\n", + " clearInterval(me._updater);\r\n", + " }\r\n", + " }, me._interval * 1000);\r\n", + " }\r\n", + " }\r\n", + " });\r\n", + " manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n", + "\r\n", + " var HiddenUpdateView = UpdateView.extend({\r\n", + " display: function(message) {\r\n", + " this.$el.hide();\r\n", + " }\r\n", + " });\r\n", + " manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n", + "\r\n", + " var SubprocessView = UpdateView.extend({\r\n", + " render: function() {\r\n", + " var me = window.SPVIEW = this;\r\n", + " me._interval = 0;\r\n", + " me._minimize = '';\r\n", + " me._restore = '';\r\n", + "\r\n", + " // in case there is already an outputView present,\r\n", + " // like from before restarting the kernel\r\n", + " $('.qcodes-output-view').not(me.$el).remove();\r\n", + "\r\n", + " me.$el\r\n", + " .addClass('qcodes-output-view')\r\n", + " .attr('qcodes-state', 'docked')\r\n", + " .html(\r\n", + " '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "from qcodes.utils.validators import Enum, Strings\n",
+    "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith\n",
+    "import qcodes.instrument_drivers.agilent.Agilent_34401A as agi\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "class Timer(object):\n",
+    "    def __init__(self, name=None):\n",
+    "        self.name = name\n",
+    "\n",
+    "    def __enter__(self):\n",
+    "        self.tstart = time.time()\n",
+    "\n",
+    "    def __exit__(self, type, value, traceback):\n",
+    "        if self.name:\n",
+    "            print('[%s]' % self.name,)\n",
+    "        print('Elapsed: %s' % (time.time() - self.tstart))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# create Instruments\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a')\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b')\n",
+    "\n",
+    "a1 = agi.Agilent_34400A('Agilent1', 'GPIB0::11::INSTR')\n",
+    "a2 = agi.Agilent_34400A('Agilent2', 'GPIB0::6::INSTR')\n",
+    "\n",
+    "# set integration time (number of line cycles)\n",
+    "a1.NPLC.set(10)\n",
+    "a2.NPLC.set(10)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "station1 = qc.Station(a1,a2)\n",
+    "station1.set_measurement(a1.volt)\n",
+    "station2 = qc.Station(a1,a2)\n",
+    "station2.set_measurement(a1.volt, a2.volt)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time s1]\n",
+      "Elapsed: 0.41602373123168945\n",
+      "[Time s2]\n",
+      "Elapsed: 0.8230471611022949\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time s1'):\n",
+    "    station1.measure()\n",
+    "with Timer('Time s2'):\n",
+    "    station2.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time a1]\n",
+      "Elapsed: 0.4150238037109375\n",
+      "[Time a2]\n",
+      "Elapsed: 0.4080233573913574\n"
+     ]
+    }
+   ],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time a1'):\n",
+    "    a1.volt.get()\n",
+    "with Timer('Time a2'):\n",
+    "    a2.volt.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
+      "   volt: volt\n",
+      "   volt_set: volt\n",
+      "started at 2016-04-15 16:35:52\n",
+      "[Time Loop 1]\n",
+      "Elapsed: 4.65026593208313\n",
+      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
+      "   volt_1: volt\n",
+      "   volt_0: volt\n",
+      "   volt_set: volt\n",
+      "started at 2016-04-15 16:36:00\n",
+      "[Time Loop 2]\n",
+      "Elapsed: 8.254472017288208\n"
+     ]
+    }
+   ],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True,background=False)\n",
+    "\n",
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True,background=False)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt: volt\n",
+      "   volt_set: volt\n",
+      "started at 2016-04-15 16:36:03\n",
+      "[Time Loop 1]\n",
+      "Elapsed: 4.743271112442017\n"
+     ]
+    }
+   ],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt_1: volt\n",
+      "   volt_0: volt\n",
+      "   volt_set: volt\n",
+      "started at 2016-04-15 16:36:16\n",
+      "[Time Loop 2]\n",
+      "Elapsed: 8.797503232955933\n"
+     ]
+    }
+   ],
+   "source": [
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "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.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Keithley 2600.ipynb b/docs/examples/Qcodes example with Keithley 2600.ipynb
new file mode 100644
index 000000000000..279fdcae3d9a
--- /dev/null
+++ b/docs/examples/Qcodes example with Keithley 2600.ipynb	
@@ -0,0 +1,632 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# spawn doesn't like function or class definitions in the interpreter\n",
+    "# session - had to move them to a file.\n",
+    "\n",
+    "# now create this \"experiment\"\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a',server_name=None)\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b',server_name=None)\n",
+    "\n",
+    "station = qc.Station(k1,k2)\n",
+    "\n",
+    "# could measure any number of things by adding arguments to this\n",
+    "# function call, but here we're just measuring one, the meter amplitude\n",
+    "station.set_measurement(k1.curr,k2.curr)\n",
+    "\n",
+    "# it's nice to have the key parameters be part of the global namespace\n",
+    "# that way they're objects that we can easily set, get, and slice\n",
+    "# this could be simplified to a station method that gathers all parameters\n",
+    "# and adds them all as (disambiguated) globals, printing what it did\n",
+    "# something like:\n",
+    "#   station.gather_parameters(globals())\n",
+    "\n",
+    "vsd1, vsd2, curr1, curr2 = k1.volt, k2.volt, k1.curr, k2.curr\n",
+    "\n",
+    "# once we have implemented a monitor, defining a station will start a\n",
+    "# DataServer process, and you would see it in the subprocess widget,\n",
+    "# or via active_children() as here:\n",
+    "# qc.active_children()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'model': '2614B',\n",
+       " 'serial_number': '4083825',\n",
+       " 'software_revision': '3.2.1',\n",
+       " 'vendor': 'Keithley Instruments Inc.'}"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "k2.info"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 26,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'Model 2614B,'"
+      ]
+     },
+     "execution_count": 26,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "import re\n",
+    "text = 'Keithley Instruments Inc., Model 2614B, 4083825, 3.2.1'\n",
+    "m = re.search('Model (.+?),', text)\n",
+    "# if m:\n",
+    "#     found = m.group(1)\n",
+    "m.group()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[-8.34465e-14, -1.0848e-12]"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# we can get the measured quantities right now\n",
+    "station.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   curr_0: curr\n",
+      "   curr_1: curr\n",
+      "   volt: volt\n",
+      "started at 2016-04-14 22:21:31\n"
+     ]
+    }
+   ],
+   "source": [
+    "# start a Loop (which by default runs in a seprarate process)\n",
+    "# the sweep values are defined by slicing the parameter object\n",
+    "# but more complicated sweeps (eg nonlinear, or adaptive) can\n",
+    "# easily be used instead\n",
+    "\n",
+    "# Notice that I'm using an explicit location and `overwrite=True` here so that\n",
+    "# running this notebook over and over won't result in extra files.\n",
+    "# But if you leave these out, you get a new timestamped DataSet each time.\n",
+    "data = qc.Loop(vsd1[-5:5:0.5], 0.03).run(location='testsweep', overwrite=True)\n",
+    "\n",
+    "# now there should be two extra processes running, DataServer and a sweep\n",
+    "# I'll omit the active_children call now because you can see them in the\n",
+    "# subprocess widget"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'curr_0': DataArray[20]: curr_0\n",
+       " array([ -3.40915000e-10,  -4.52161000e-11,   8.41618000e-12,\n",
+       "          4.14968000e-11,   6.37770000e-11,   7.77721000e-11,\n",
+       "          8.52823000e-11,   8.91566000e-11,   9.08732000e-11,\n",
+       "          9.14335000e-11,   9.11236000e-11,   9.22322000e-11,\n",
+       "          9.23514000e-11,   9.24468000e-11,   9.29832000e-11,\n",
+       "          9.34243000e-11,   9.27448000e-11,   9.26137000e-11,\n",
+       "          9.26971000e-11,   9.18150000e-11]), 'curr_1': DataArray[20]: curr_1\n",
+       " array([ -1.38283000e-12,  -9.05991000e-13,  -1.06096000e-12,\n",
+       "         -1.23978000e-12,  -1.02520000e-12,  -1.13249000e-12,\n",
+       "         -1.22786000e-12,  -1.09673000e-12,  -1.21593000e-12,\n",
+       "         -1.09673000e-12,  -1.02520000e-12,  -9.41753000e-13,\n",
+       "         -9.77516000e-13,  -1.19209000e-12,  -9.89437000e-13,\n",
+       "         -1.07288000e-12,  -1.09673000e-12,  -1.14441000e-12,\n",
+       "         -1.25170000e-12,  -1.00136000e-12]), 'volt': DataArray[20]: volt\n",
+       " array([-5. , -4.5, -4. , -3.5, -3. , -2.5, -2. , -1.5, -1. , -0.5,  0. ,\n",
+       "         0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5])}"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# manually bring the data into the main process and display it as numbers\n",
+    "data.sync()\n",
+    "data.arrays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "# live-updating plot, that syncs the data and stops updating when it's finished\n",
+    "# plot = qc.MatPlot(data.amplitude)\n",
+    "plotQ1 = qc.QtPlot(data.volt, data.curr_0)\n",
+    "plotQ2 = qc.QtPlot(data.volt, data.curr_1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
+      "   curr_0: curr\n",
+      "   volt_0: volt\n",
+      "   curr_1: curr\n",
+      "   volt: volt\n",
+      "started at 2016-04-14 22:22:54\n"
+     ]
+    }
+   ],
+   "source": [
+    "data2 = qc.Loop(vsd1[-5:5:0.1],0).each(\n",
+    "                qc.Loop(vsd2[-2:2:.2], 0)\n",
+    ").run(location='test2d', overwrite=True)\n",
+    "\n",
+    "# use the subplot and add features of qc.MatPlot\n",
+    "# plot2 = qc.MatPlot(data2.amplitude_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1, 2))\n",
+    "# plot2.add(data2.amplitude_3, cmap=plt.cm.hot, subplot=2)\n",
+    "\n",
+    "# the equivalent in QtPlot\n",
+    "plot2Q = qc.QtPlot(data2.curr_1, figsize=(1200, 500))\n",
+    "# plot2Q.add(data2.curr_1, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "plot2Q.add(data2.curr_0, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "   volt_0: volt\n",
+      "   curr_1_1: curr\n",
+      "   curr_1_0: curr\n",
+      "   curr_2: curr\n",
+      "   volt_1: volt\n",
+      "   curr_3: curr\n",
+      "   curr_0_0: curr\n",
+      "   curr_0_1: curr\n",
+      "   volt: volt\n",
+      "started at 2016-04-14 22:49:45\n"
+     ]
+    },
+    {
+     "ename": "AttributeError",
+     "evalue": "'DataSet' object and its delegates have no attribute 'curr_1'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# plot3b = qc.MatPlot(data3.curr_1_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;31m# plot3b.add(data3.curr_0_1, subplot=2)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mplot3Q\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[0mplot3bQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfigsize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1200\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m500\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[0mplot3bQ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msubplot\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\helpers.py\u001b[0m in \u001b[0;36m__getattr__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m    187\u001b[0m         raise AttributeError(\n\u001b[0;32m    188\u001b[0m             \"'{}' object and its delegates have no attribute '{}'\".format(\n\u001b[1;32m--> 189\u001b[1;33m                 self.__class__.__name__, key))\n\u001b[0m\u001b[0;32m    190\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    191\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__dir__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mAttributeError\u001b[0m: 'DataSet' object and its delegates have no attribute 'curr_1'"
+     ]
+    }
+   ],
+   "source": [
+    "data3 = qc.Loop(vsd1[-15:15:1], 0).each(\n",
+    "                qc.Loop(vsd2[-5:5:1], 0),\n",
+    "                qc.Loop(vsd2[5:-5:1], 0),\n",
+    "                curr1,curr2,\n",
+    ").run(location='test_multi_d', overwrite=True)\n",
+    "\n",
+    "# several plots updating simultaneously\n",
+    "# plot3 = qc.MatPlot(data3.curr_1_1, cmap=plt.cm.hot)\n",
+    "# plot3b = qc.MatPlot(data3.curr_1_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\n",
+    "# plot3b.add(data3.curr_0_1, subplot=2)\n",
+    "plot3Q = qc.QtPlot(data3.curr_1)\n",
+    "plot3bQ = qc.QtPlot(data3.curr_1, figsize=(1200, 500))\n",
+    "plot3bQ.add(data3.curr_0, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude: amplitude\n",
+      "started at 2016-02-02 12:18:09\n"
+     ]
+    }
+   ],
+   "source": [
+    "# An example of a parameter that returns several values of different dimension\n",
+    "# This produces the last two arrays from data3, but only takes the data once.\n",
+    "data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
+    "    AverageAndRaw(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
+    ").run(location='test_complex_param', overwrite=True)\n",
+    "\n",
+    "# plot4 = qc.MatPlot(data4.amplitude, cmap=plt.cm.hot, subplots=(1,2), figsize=(12, 4.5))\n",
+    "# plot4.add(data4.avg_amplitude, subplot=2)\n",
+    "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
+    "plot4Q.add(data4.avg_amplitude, subplot=2)"
+   ]
+  }
+ ],
+ "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.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Qcodes example with Triton.ipynb b/docs/examples/Qcodes example with Triton.ipynb
new file mode 100644
index 000000000000..0d905116eccd
--- /dev/null
+++ b/docs/examples/Qcodes example with Triton.ipynb	
@@ -0,0 +1,332 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "18:37:58\n",
+      "0.0185306\n",
+      "0.0185306\n",
+      "Circulating\n",
+      "OK\n"
+     ]
+    }
+   ],
+   "source": [
+    "import qcodes.instrument_drivers.oxford.triton as triton\n",
+    "\n",
+    "\n",
+    "triton = triton.Triton(name = 'Triton 1', address='127.0.0.1', port=33576, tmpfile='Triton1_thermometry.reg')\n",
+    "triton.set_address(address='172.20.3.27', port=33576)\n",
+    "# triton._get_temp_channels('thermometry.reg')\n",
+    "# print(triton.chan_alias)\n",
+    "\n",
+    "print(triton.time.get())\n",
+    "print(triton.T5.get())\n",
+    "print(triton.MC.get())\n",
+    "# for name,param in triton.parameters.items():\n",
+    "#     print(name,param.get())\n",
+    "print(triton.action.get())\n",
+    "print(triton.status.get())\n",
+    "triton.close()\n"
+   ]
+  },
+  {
+   "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.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/docs/examples/Triton1_thermometry.reg b/docs/examples/Triton1_thermometry.reg
new file mode 100644
index 000000000000..8230c8925020
--- /dev/null
+++ b/docs/examples/Triton1_thermometry.reg
@@ -0,0 +1,295 @@
+Windows Registry Editor Version 5.00
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry]
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[-1]]
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Magnet top/X55352.cof"
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[0]]
+"m_lpszName"="PT2 Head"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/4K head/X53075.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="2000"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="897.18"
+"m_dblResistance"="944.51"
+"m_dblOldTemperature"="21.8619581878346"
+"m_dblTemperature"="20.7073938117749"
+"m_dblOldTime"="1460555546"
+"m_dblTime"="1460555661"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[10]]
+"m_lpszName"="Still shield tail"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/CP/M_RuO2_Ext_4.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:0000000b
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="200"
+"m_dblExcitation"="0.000199999893084169"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="67.869"
+"m_dblResistance"="67.855"
+"m_dblOldTemperature"="287.095485095483"
+"m_dblTemperature"="287.167409962017"
+"m_dblOldTime"="1387444773"
+"m_dblTime"="1387444887"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[11]]
+"m_lpszName"="chan[11]"
+"m_lpszCalibFileName"="C:\\VeriCold\\Thermometry\\none.dll"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000011
+"m_dwExcitation"=dword:00000007
+"m_dblRange"="200000"
+"m_dblExcitation"="0.002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="149"
+"m_dblResistance"="192"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="1455629381"
+"m_dblTime"="1455629514"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:000003ea
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[12]]
+"m_lpszName"="Lead 1"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Lead 1/X53306.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="632000"
+"m_dblExcitation"="0.000199999776668847"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="7840"
+"m_dblResistance"="17319"
+"m_dblOldTemperature"="1.62496396307643"
+"m_dblTemperature"="1.41588562351072"
+"m_dblOldTime"="1386671337"
+"m_dblTime"="1386671488"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000001
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[13]]
+"m_lpszName"="Lead 2"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Lead 2/X55193.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000000
+"m_dblRange"="1000"
+"m_dblExcitation"="2.47032822920623e-323"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="0"
+"m_dblResistance"="0"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="0"
+"m_dblTime"="0"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[14]]
+"m_lpszName"="Sample rod"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/CP/M_RuO2_Ext_4.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000000
+"m_dblRange"="1000"
+"m_dblExcitation"="9.99998883344234e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="0"
+"m_dblResistance"="0"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="0"
+"m_dblTime"="0"
+"m_bAutorange"="false"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[15]]
+"m_lpszName"="Lower 4K shield"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/4K shield bottom/X55350.cof"
+"m_dwEnabled"=dword:00000000
+"m_dwRange"=dword:00000016
+"m_dwExcitation"=dword:00000000
+"m_dblRange"="1000"
+"m_dblExcitation"="9.99998883344234e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="0"
+"m_dblResistance"="0"
+"m_dblOldTemperature"="0"
+"m_dblTemperature"="0"
+"m_dblOldTime"="0"
+"m_dblTime"="0"
+"m_bAutorange"="false"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[1]]
+"m_lpszName"="PT2 Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/4K plate/X52922.340"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="2000"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="1162.17"
+"m_dblResistance"="1231.5"
+"m_dblOldTemperature"="21.2899987351121"
+"m_dblTemperature"="20.0278849440418"
+"m_dblOldTime"="1460555555"
+"m_dblTime"="1460555670"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[2]]
+"m_lpszName"="Still Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/still/Cgbh9.vcc"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000e
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="6320"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="4518.41"
+"m_dblResistance"="4520.25"
+"m_dblOldTemperature"="62.7156089361273"
+"m_dblTemperature"="62.3436033599238"
+"m_dblOldTime"="1460555569"
+"m_dblTime"="1460555684"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000001
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[3]]
+"m_lpszName"="MC Cernox"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/MC/X52921.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="2000"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="675.35"
+"m_dblResistance"="676.68"
+"m_dblOldTemperature"="34.8821016614691"
+"m_dblTemperature"="34.8088886990759"
+"m_dblOldTime"="1460555582"
+"m_dblTime"="1460555698"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[4]]
+"m_lpszName"="MC RuO2"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/MC/DDah8_DAH8.vcc"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000d
+"m_dwExcitation"=dword:00000004
+"m_dblRange"="2000"
+"m_dblExcitation"="6.32e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="531.8"
+"m_dblResistance"="531.79"
+"m_dblOldTemperature"="17.4380571653974"
+"m_dblTemperature"="17.4414440709406"
+"m_dblOldTime"="1460555476"
+"m_dblTime"="1460555591"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000001
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[5]]
+"m_lpszName"="100mK Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/CP/M_RuO2_Ext_4.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000e
+"m_dwExcitation"=dword:00000004
+"m_dblRange"="6320"
+"m_dblExcitation"="6.32e-05"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="2252.99"
+"m_dblResistance"="2255.98"
+"m_dblOldTemperature"="51.8305567689997"
+"m_dblTemperature"="49.9064763085877"
+"m_dblOldTime"="1460555489"
+"m_dblTime"="1460555604"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[6]]
+"m_lpszName"="Magnet  Bottom"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Magnet top/X55352.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000c
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="632"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="431.724"
+"m_dblResistance"="432.145"
+"m_dblOldTemperature"="21.8656699671321"
+"m_dblTemperature"="21.8374371966018"
+"m_dblOldTime"="1460555502"
+"m_dblTime"="1460555617"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[7]]
+"m_lpszName"="Magnet Almost Bottom"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/Magnet Bottom/X55342.cof"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:0000000b
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="200"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="250.825"
+"m_dblResistance"="251.859"
+"m_dblOldTemperature"="58.0663607489416"
+"m_dblTemperature"="57.7839958105985"
+"m_dblOldTime"="1459019529"
+"m_dblTime"="1459019646"
+"m_bAutorange"="false"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[8]]
+"m_lpszName"="PT1 Head"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/pt100std.dll"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:00000009
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="20"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="11.6661"
+"m_dblResistance"="11.571"
+"m_dblOldTemperature"="57.3984906949643"
+"m_dblTemperature"="57.1817076128138"
+"m_dblOldTime"="1460555522"
+"m_dblTime"="1460555638"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
+[HKEY_CURRENT_USER\Software\Oxford Instruments\Triton System Control\Thermometry\chan[9]]
+"m_lpszName"="PT1 Plate"
+"m_lpszCalibFileName"="C:/Oxford Instruments/Thermometry Calibration Files/pt100std.dll"
+"m_dwEnabled"=dword:00000001
+"m_dwRange"=dword:00000009
+"m_dwExcitation"=dword:00000005
+"m_dblRange"="20"
+"m_dblExcitation"="0.0002"
+"m_dwSettleDelay"=dword:00001f40
+"m_dblOldResistance"="18.382"
+"m_dblResistance"="18.3744"
+"m_dblOldTemperature"="72.8123204216882"
+"m_dblTemperature"="72.7947627066479"
+"m_dblOldTime"="1460555531"
+"m_dblTime"="1460555647"
+"m_bAutorange"="true"
+"m_dwInCalibRange"=dword:00000000
+
diff --git a/qcodes/instrument/ip.py b/qcodes/instrument/ip.py
index 7b2e0a9292a7..97b05eccfdd6 100644
--- a/qcodes/instrument/ip.py
+++ b/qcodes/instrument/ip.py
@@ -31,6 +31,7 @@ def __init__(self, name, address=None, port=None, timeout=5,
         self._confirmation = write_confirmation
 
         self._ensure_connection = EnsureConnection(self)
+        self._buffer = 1024
 
         self._socket = None
 
@@ -83,7 +84,7 @@ def set_timeout(self, timeout=None):
             self._timeout = timeout
 
         if self._socket is not None:
-            self.socket.settimeout(float(self.timeout))
+            self._socket.settimeout(float(self._timeout))
 
     def set_terminator(self, terminator):
         self._terminator = terminator
@@ -93,7 +94,7 @@ def _send(self, cmd):
         self._socket.send(data.encode())
 
     def _recv(self):
-        return self._socket.recv(512).decode()
+        return self._socket.recv(self._buffer).decode()
 
     def close(self):
         self._disconnect()
@@ -113,12 +114,12 @@ def ask(self, cmd):
 
 class EnsureConnection:
     def __init__(self, instrument):
-        self._instrument = instrument
+        self.instrument = instrument
 
     def __enter__(self):
         if not self.instrument._persistent or self.instrument._socket is None:
             self.instrument._connect()
 
-    def __exit__(self):
+    def __exit__(self, type, value, tb):
         if not self.instrument._persistent:
-            self.instrument._disconnect()
+            self.instrument._disconnect()
\ No newline at end of file
diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
new file mode 100644
index 000000000000..5e3d36779aff
--- /dev/null
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -0,0 +1,136 @@
+# Agilent_34401A.py driver for Agilent 34401A DMM
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+from qcodes.utils.validators import Enum, Strings
+from qcodes import VisaInstrument
+
+class Agilent_34400A(VisaInstrument):
+    '''
+    channel: use channel 'a' or 'b'
+
+    This is the qcodes driver for the Agilent_34400A DMM Series,
+    tested with Agilent_34401A
+
+    Status: beta-version.
+        TODO:
+        - Add all parameters that are in the manual
+        - Integration time does no value mapping
+        - Need a clear_cmd thing in the parameter
+
+    '''
+    def __init__(self, name, address, **kwargs):
+        super().__init__(name, address, terminator='\n', **kwargs)
+
+        self.IDN = self.visa_handle.ask('*IDN?')
+
+        vendor, model, serial, software = map(str.strip, self.IDN.split(','))
+        self.model = model
+        self.info = {'vendor':vendor, 'model':model,
+                     'serial_number':serial, 'software_revision':software}
+
+#         Async has tow send 'INIT' and later ask for 'FETCH?'
+
+        self.add_parameter('volt',
+                           get_cmd='READ?',
+                           get_parser=float)
+        self.add_parameter('NPLC',
+                           get_cmd='VOLT:NPLC?',
+                           get_parser=float,
+                           set_cmd='VOLT:NPLC {:f}',
+                           vals=Enum(0.02,0.2,1,10,100))
+        # For dc and resistance measurements, changing the number of digits
+        # does more than just change the resolution of the multimeter. It also
+        # changes the integration time!
+        # Resolution Choices          Integration Time
+        #   Fast 4 Digit                0.02 PLC
+        #   * Slow 4 Digit              1 PLC
+        #   Fast 5 Digit                0.2 PLC
+        #   * Slow 5 Digit (default)    10 PLC
+        #   * Fast 6 Digit              10 PLC
+        #   Slow 6 Digit                100 PLC
+        self.add_parameter('resolution',
+                           get_cmd='VOLT:DC:RES?',
+                           get_parser=float,
+                           set_cmd='VOLT:DC:RES {:.7f}',
+                           vals=Enum(3e-07, 1e-06, 3e-06, 1e-05, 1e-04))
+        # Integration Time    Resolutionc
+        self.add_parameter('integration_time',
+                           get_cmd='VOLT:DC:RES?',
+                           get_parser=float,
+                           set_cmd='VOLT:DC:RES {:f}',
+#                            vals=Enum(0.02,0.2,1,10,100),
+                           units='NPLC',
+                           val_mapping = {0.02: 0.0001,
+                                          0.2:  0.00001,
+                                          1:    0.000003,
+                                          10:   0.000001,
+                                          100:  0.0000003})
+        self.add_parameter('terminals',
+                           get_cmd='ROUT:TERM?')
+        self.add_parameter('range_auto',
+                           get_cmd='VOLT:RANG:AUTO?',
+                           get_parser=self._onoff_parser,
+                           set_cmd='VOLT:RANG:AUTO {:d}',
+                           val_mapping = {'ON': 1,
+                                          'OFF':0,
+                                          1:    1,
+                                          0:    0})
+        self.add_parameter('range',
+                           get_cmd='SENS:VOLT:DC:RANG?',
+                           get_parser=float,
+                           set_cmd='SENS:VOLT:DC:RANG {:f}',
+                           vals=Enum(0.1, 1.0, 10.0, 100.0, 1000.0))
+
+        if self.model in ['34401A']:
+            self.add_parameter('display_text',
+                               get_cmd='DISP:TEXT?',
+                               set_cmd='DISP:TEXT "{}"',
+                               vals=Strings())
+        elif self.model in ['34410A', '34411A']:
+            self.add_parameter('display_text',
+                               get_cmd='DISP:WIND1:TEXT?',
+                               set_cmd='DISP:WIND1:TEXT "{}"',
+                               vals=Strings())
+            self.add_parameter('display_text_2',
+                               get_cmd='DISP:WIND2:TEXT?',
+                               set_cmd='DISP:WIND2:TEXT "{}"',
+                               vals=Strings())
+    def display_clear(self):
+        if self.model in ['34401A']:
+            self.write('DISP:WIND:TEXT:CLE')
+            self.write('DISP:WIND:STAT 1')
+        elif self.model in ['34410A', '34411A']:
+            self.write('DISP:WIND1:TEXT:CLE')
+            self.write('DISP:WIND1:STAT 1')
+            self.write('DISP:WIND2:TEXT:CLE')
+            self.write('DISP:WIND2:STAT 1')
+
+    def reset(self):
+        self.write('*RST')
+    def _onoff_parser(self, msg):
+        if msg == '0':
+            return 'OFF'
+        elif msg == '1':
+            return 'ON'
+        return None
\ No newline at end of file
diff --git a/qcodes/instrument_drivers/oxford/triton.py b/qcodes/instrument_drivers/oxford/triton.py
new file mode 100644
index 000000000000..e16d90f65202
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/triton.py
@@ -0,0 +1,145 @@
+# triton.py driver for Oxford Triton fridges
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import configparser
+from qcodes import IPInstrument
+
+
+class Triton(IPInstrument):
+    '''
+    Triton Driver
+    TODO: fetch registry directly from fridge-computer
+
+    Comment from Merlin:
+        I had to change the IP instrument, somehow the port does not get transferred to the socket connection
+        And I had other problesm with the _connect method, check those changes :)
+        Further there was a problem with the EnsureConnection class
+    '''
+    def __init__(self, name, address=None, port=None, terminator='\r\n', tmpfile = None, **kwargs):
+        super().__init__(name, address=address, port=port, terminator=terminator, **kwargs)
+
+        self.add_parameter(name='time',
+                           label='System Time',
+                           units='',
+                           get_cmd='READ:SYS:TIME',
+                           get_parser=self._parse_time)
+
+        self.add_parameter(name='action',
+                           label='Current action',
+                           units='',
+                           get_cmd='READ:SYS:DR:ACTN',
+                           get_parser=self._parse_action )
+
+        self.add_parameter(name='status',
+                           label='Status',
+                           units='',
+                           get_cmd='READ:SYS:DR:STATUS',
+                           get_parser=self._parse_status)
+
+        self.chan_alias = {}
+        self.chan_temps = {}
+        if tmpfile != None:
+            self._get_temp_channels(tmpfile)
+        self.get_pressure_channels()
+        self._get_named_channels()
+
+
+    def _get_named_channels(self):
+        allchans = self.ask('READ:SYS:DR:CHAN')
+        allchans = allchans.replace('STAT:SYS:DR:CHAN:', '', 1).split(':')
+        for ch in allchans:
+            msg = 'READ:SYS:DR:CHAN:%s'%ch
+            rep = self.ask(msg)
+            if not 'INVALID' in rep:
+                alias, channel = rep.split(':')[-2:]
+                self.chan_alias[alias] = channel
+                self.add_parameter(name=alias,
+                                   units='K',
+                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP'%channel,
+                                   get_parser=self._parse_temp)
+
+
+
+    def get_pressure_channels(self):
+        for i in range(1,7):
+            chan = 'P%d'%i
+            self.add_parameter(name=chan,
+                               units='bar',
+                               get_cmd='READ:DEV:%s:PRES:SIG:PRES'%chan,
+                               get_parser=self._parse_pres)
+
+
+    def _get_temp_channels(self, file):
+        config = configparser.ConfigParser()
+        with open(file, 'r') as f:
+            next(f)
+            config.read_file(f)
+
+        for section in config.sections():
+            options = config.options(section)
+            namestr = '"m_lpszname"'
+            if namestr in options:
+                chan = 'T'+section.split('\\')[-1].split('[')[-1]
+                name = config.get(section, '"m_lpszname"').strip("\"")
+                self.chan_temps[chan] = {'name':name, 'value':None}
+                self.add_parameter(name=chan,
+                                   units='K',
+                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP'%chan,
+                                   get_parser=self._parse_temp)
+
+    def _parse_action(self, msg):
+        action = msg[17:]
+        if action == 'PCL':
+            action = 'Precooling'
+        elif action == 'EPCL':
+            action = 'Empty precool loop'
+        elif action == 'COND':
+            action = 'Condensing'
+        elif action == 'NONE':
+            if self.MC.get() < 2:
+                action = 'Circulating'
+            else:
+                action = 'Idle'
+        elif action == 'COLL':
+            action = 'Collecting mixture'
+        else:
+            action = 'Unknown'
+        return action
+
+    def _parse_status(self, msg):
+        return msg[19:]
+
+    def _parse_time(self, msg):
+        return msg[14:]
+
+    def _parse_temp(self, msg):
+        if 'NOT_FOUND' in msg:
+            return None
+        return float(msg.split('SIG:TEMP:')[-1].strip('K'))
+    def _parse_pres(self, msg):
+        if 'NOT_FOUND' in msg:
+            return None
+        return float(msg.split('SIG:PRES:')[-1].strip('mB'))*1e3
+
+    def _recv(self):
+        return super()._recv().rstrip()
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2400.py b/qcodes/instrument_drivers/tektronix/Keithley_2400.py
new file mode 100644
index 000000000000..97355143b5ef
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2400.py
@@ -0,0 +1,55 @@
+# Keithley_2400.py driver for Keithley 2400 DMM
+#
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+from qcodes.instrument.visa import VisaInstrument
+import time
+import logging
+
+#%% Helper functions
+
+
+
+#%% Driver for Keithley_2400
+
+class Keithley_2400(VisaInstrument):
+    '''
+    TODO
+    '''
+    def __init__(self, name, address, reset=False, **kwargs):
+        t0 = time.time()
+        super().__init__(name, address, terminator='\n', **kwargs)
+
+        self._modes = ['']
+        self.add_parameter('IDN', get_cmd='*IDN?')
+
+        # Add parameters to wrapper
+        self.add_parameter('volt', get_cmd=':READ?',
+                           get_parser=self.get_volt, set_cmd='sour:volt:lev {:.5f};',
+                           units='V' )
+        self.add_parameter('curr', get_cmd=':READ?',
+                           get_parser=self.get_curr, set_cmd='sour:curr:lev {:.5f};',
+                           units='A' )
+        # One might want to initialize like this:
+        # ':SOUR:VOLT:MODE FIX'
+        # ':SENS:FUNC:ON "CURR"'
+
+    def get_curr(self, msg):
+        return float(msg.split(',')[1])
+
+    def get_volt(self, msg):
+        return float(msg.split(',')[0])
+
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
new file mode 100644
index 000000000000..bc2a0d72b8a1
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -0,0 +1,124 @@
+# Keithley_2600.py driver for Keithley 2600 Source-Meter series
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import re
+from qcodes import VisaInstrument
+
+class Keithley_2600(VisaInstrument):
+    '''
+    channel: use channel 'a' or 'b'
+
+    This is the qcodes driver for the Keithley_2600 Source-Meter series,
+    tested with Keithley_2614B
+
+    Status: beta-version.
+        TODO:
+        - Add all parameters that are in the manual
+        - range and limit should be set according to mode
+        - add ramping and such stuff
+
+    '''
+    def __init__(self, name, address, channel, **kwargs):
+        super().__init__(name, address, terminator='\n', **kwargs)
+        self._channel = channel
+
+        self.IDN = self.visa_handle.ask('*IDN?')
+        vendor, model, serial, software = map(str.strip, self.IDN.split(','))
+        self.model = model[6:]
+
+        self.info = {'vendor':vendor, 'model':self.model,
+                     'serial_number':serial, 'software_revision':software}
+
+        self.add_parameter('volt', get_cmd='measure.v()',
+                           get_parser=float, set_cmd='source.levelv={:.8f}',
+                           units='V')
+        self.add_parameter('curr', get_cmd='measure.i()',
+                           get_parser=float, set_cmd='source.leveli={:.8f}',
+                           units='A')
+        self.add_parameter('mode',
+                           get_cmd='source.func',
+                           get_parser=self._mode_parser,
+                           set_cmd='source.func={:d}',
+                           val_mapping={'current':0, 'curr':0, 'AMPS':0,
+                                        'voltage':1, 'volt':1, 'VOLT':1})
+        self.add_parameter('output',
+                           get_cmd='source.output',
+                           get_parser=self._output_parser,
+                           set_cmd='source.output={:d}',
+                           val_mapping={'on': 1, 'ON': 1,
+                                        'off':0, 'OFF':0})
+        # Source range
+        self.add_parameter('rangev',
+                           get_cmd='source.rangev',
+                           get_parser=float,
+                           set_cmd='source.rangev={:.4f}',
+                           units='V')
+        # Measure range
+        self.add_parameter('rangei',
+                           get_cmd='source.rangei',
+                           get_parser=float,
+                           set_cmd='source.rangei={:.4f}',
+                           units='A')
+        # Compliance limit
+        self.add_parameter('limitv',
+                           get_cmd='source.limitv',
+                           get_parser=float,
+                           set_cmd='source.limitv={:.4f}',
+                           units='V')
+        # Compliance limit
+        self.add_parameter('limiti',
+                           get_cmd='source.limiti',
+                           get_parser=float,
+                           set_cmd='source.limiti={:.4f}',
+                           units='A')
+
+    def _mode_parser(self, msg):
+        if msg[0] == '0':
+            return 'current'
+        elif msg[0] == '1':
+            return 'voltage'
+        return None
+    def _output_parser(self, msg):
+        if msg[0] == '0':
+            return 'OFF'
+        elif msg[0] == '1':
+            return 'ON'
+        return None
+
+    def reset(self):
+        self.write('reset()')
+
+    def get_curr(self, msg):
+        return float(msg.rstrip().split(',')[1])
+
+    def get_volt(self, msg):
+        return float(msg.rstrip().split(',')[0])
+
+    def ask_direct(self, cmd):
+        return self.visa_handle.ask(cmd)
+
+    def ask(self, cmd):
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel,cmd))
+
+    def write(self, cmd):
+        super().write('smu{:s}.{:s}'.format(self._channel, cmd))
\ No newline at end of file
diff --git a/qcodes/loops.py b/qcodes/loops.py
index 3a1be4e12fd7..e104778031d4 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -466,7 +466,8 @@ def run(self, background=True, use_threads=True, enqueue=False,
             self.data_set.mode = DataMode.PULL_FROM_SERVER
         else:
             self._run_wrapper()
-            self.data_set.read()
+            # This line breaks loops run with background=False
+            # self.data_set.read()
 
         if not quiet:
             print(repr(self.data_set))

From a2ea6be0e575cd947871880c4220aaf590c18426 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sun, 17 Apr 2016 21:56:05 +0200
Subject: [PATCH 002/169] Adding MercuryiPS magnet driver

---
 ...es example with Mercury IPS (Magnet).ipynb | 432 ++++++++++++++++++
 .../instrument_drivers/oxford/mercuryiPS.py   | 184 ++++++++
 2 files changed, 616 insertions(+)
 create mode 100644 docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb
 create mode 100644 qcodes/instrument_drivers/oxford/mercuryiPS.py

diff --git a/docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb b/docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb
new file mode 100644
index 000000000000..58bd186f0453
--- /dev/null
+++ b/docs/examples/Qcodes example with Mercury IPS (Magnet).ipynb	
@@ -0,0 +1,432 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "import re\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "from qcodes.instrument_drivers.oxford.mercuryiPS import MercuryiPS"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "magnet = MercuryiPS(name = 'Magnet', address='ASRL10::INSTR')# , server_name=None"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "0.0\n",
+      "3.352161306002045e-06\n"
+     ]
+    }
+   ],
+   "source": [
+    "# this does not work with the remote server thing\n",
+    "# print(magnet.axes)\n",
+    "# print(magnet.info)\n",
+    "print(magnet.x_fld.get())\n",
+    "print(magnet.x_fldC.get())"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'HOLD'"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# magnet.hold()\n",
+    "magnet.x_ACTN.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.05"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "magnet.x_rate.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.0"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "magnet.x_setpoint.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "RTOZ\n",
+      "HOLD\n"
+     ]
+    }
+   ],
+   "source": [
+    "magnet.x_ACTN.set('RTOZ')\n",
+    "print(magnet.x_ACTN.get())\n",
+    "time.sleep(1)\n",
+    "print(magnet.x_ACTN.get())"
+   ]
+  },
+  {
+   "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.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS.py b/qcodes/instrument_drivers/oxford/mercuryiPS.py
new file mode 100644
index 000000000000..b25b5ed358b7
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS.py
@@ -0,0 +1,184 @@
+# mercuryiPS.py driver for Oxford MercuryiPS magnet power supply
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from functools import partial
+import re
+
+from qcodes import VisaInstrument
+from qcodes.utils.validators import Strings, Enum
+
+
+class MercuryiPS(VisaInstrument):
+    '''
+    MercuryiPS Driver
+
+    This is the qcodes driver for the Oxford MercuryiPS magnet power supply.
+
+    Status: beta-version.
+        TODO:
+        - SAFETY!! we need to make sure the magnet is only ramped at certain
+          conditions!
+        - Add parameters that get data for all channels:
+          magnet.fld.get() should return [fx, fy, fz] or whatever axes are
+          available
+        - Fix this call = ''
+                   eval(call)
+          stuff, I guess there is a smarter way of doing that?
+        - this findall stuff in _get_cmd, is that smart?
+    '''
+    def __init__(self, name, axes=None, **kwargs):
+        super().__init__(name, terminator='\n', **kwargs)
+        self.axes = axes
+        self._ATOB = {}
+        self._latest_response = ''
+        # for some reason the first call is always invalid?! need some kind of init?
+        self.ask('*IDN?')
+        self.IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, software = map(str.strip, self.IDN.split(':'))
+        self.model = model
+        self.info = {'vendor': vendor, 'model': self.model,
+                     'serial_number': serial, 'software_revision': software}
+
+        if axes is None:
+            self._determine_magnet_axes()
+        self._determine_current_to_field()
+
+        for ax in self.axes:
+            self.add_parameter(ax.lower()+'_fld',
+                               get_cmd=partial(self._get_fld, ax, 'FLD'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fldC',
+                               get_cmd=partial(self._get_fld_converted,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_ACTN',
+                               get_cmd=partial(self._get_cmd,
+                                               'READ:DEV:GRP{}:PSU:ACTN?'.format(ax)),
+                               set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+            self.add_parameter(ax.lower()+'_setpoint',
+                               get_cmd=partial(self._get_fld, ax, 'FSET'),
+                               set_cmd=partial(self._set_fld, ax, 'FSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_setpointC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'CSET'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'CSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_rate',
+                               get_cmd=partial(self._get_fld, ax, 'RFST'),
+                               set_cmd=partial(self._set_fld, ax, 'RFST'),
+                               units='T/m')
+            self.add_parameter(ax.lower()+'_rateC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'RCST'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'RCST'),
+                               units='T/m')
+    def hold(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("HOLD")'.format(ax.lower())
+            eval(call)
+
+    def to_zero(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOZ")'.format(ax.lower())
+            eval(call)
+
+    def _ramp_to_setpoint(self, ax, cmd, setpoint):
+        # There should be a blocking and non-blocking version of this
+        if cmd is 'CSET':
+            self._set_fld_converted(ax, cmd, setpoint)
+        elif cmd is 'FSET':
+            self._set_fld(ax, cmd, setpoint)
+        self.write('SET:DEV:GRP{}:PSU:ACTN:RTOS'.format(ax))
+
+    def _set_fld(self, ax, cmd, setpoint):
+        # Could be FSET for setpoint
+        #          RFST for rate
+        cmd = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'.format(ax, cmd, setpoint)
+        self.write(cmd)
+
+    def _get_fld(self, ax, cmd):
+        # Could be FSET for setpoint
+        #          FLD for field
+        #          RFLD for rate
+        #          PFLD persistent field reading
+        fld = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return fld
+
+    def _set_fld_converted(self, ax, cmd, setpoint):
+        # Could be CSET for setpoint
+        #          RCST for rate
+        #
+        # We set current, not field, this gives higher resolution due to
+        # limited number of digits
+        cur = setpoint * self._ATOB[ax]
+        cmd = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'.format(ax, cmd, cur)
+        self.write(cmd)
+
+    def _get_fld_converted(self, ax, cmd):
+        # Could be CSET for setpoint
+        #          CURR for field
+        #          RCUR for rate
+        #          PCUR persistent current reading
+        # We ask for current, not field, this gives higher resolution due to
+        # limited number of digits
+        # The conversion gives us a float with lots of digits, how to limit that?
+        curr = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return curr / self._ATOB[ax]
+
+    def _get_cmd(self, question, parser=None):
+        msg = self.ask(question)[len(question):]
+        # How would one macth this without specifying the units?
+        # m = re.match('STAT:DEV:GRPX:PSU:SIG:RFST:(.+?)T/m',
+        #              'STAT:DEV:GRPX:PSU:SIG:RFST:0.0200T/m')
+        # m.groups()[0]
+        if parser is float:
+            return(float(re.findall("[-+]?\d*\.\d+|\d+", msg)[0]))
+        return msg
+
+    def _float_parser(self, msg):
+        pass
+
+    def _determine_magnet_axes(self):
+        cat = self.ask('READ:SYS:CAT')
+        self.axes = re.findall('DEV:GRP(.+?):PSU', cat)
+
+    def _determine_current_to_field(self):
+        # This has a unit A/T
+        self._ATOB = {}
+        for ax in self.axes:
+            r = self._get_cmd('READ:DEV:GRP{}:PSU:ATOB?'.format(ax), float)
+            self._ATOB[ax] = r
+
+    def write(self, msg):
+        rep = self.ask(msg)
+        self._latest_response = rep
+        if 'INVALID' in rep:
+            raise Warning(rep)

From 0cb217c7c8274ab3e1b20a4747ba9d9247d29888 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sun, 17 Apr 2016 21:56:43 +0200
Subject: [PATCH 003/169] pep8'ing most of the stuff added a few labels

---
 .../agilent/Agilent_34400A.py                 | 44 ++++++++++--------
 qcodes/instrument_drivers/oxford/triton.py    | 46 ++++++++++---------
 .../tektronix/Keithley_2600.py                | 24 ++++++----
 3 files changed, 63 insertions(+), 51 deletions(-)

diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
index 5e3d36779aff..2b5f342665ba 100644
--- a/qcodes/instrument_drivers/agilent/Agilent_34400A.py
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -10,8 +10,8 @@
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
 #
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
 #
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -25,6 +25,7 @@
 from qcodes.utils.validators import Enum, Strings
 from qcodes import VisaInstrument
 
+
 class Agilent_34400A(VisaInstrument):
     '''
     channel: use channel 'a' or 'b'
@@ -37,6 +38,7 @@ class Agilent_34400A(VisaInstrument):
         - Add all parameters that are in the manual
         - Integration time does no value mapping
         - Need a clear_cmd thing in the parameter
+        - Add labels
 
     '''
     def __init__(self, name, address, **kwargs):
@@ -46,20 +48,21 @@ def __init__(self, name, address, **kwargs):
 
         vendor, model, serial, software = map(str.strip, self.IDN.split(','))
         self.model = model
-        self.info = {'vendor':vendor, 'model':model,
-                     'serial_number':serial, 'software_revision':software}
+        self.info = {'vendor': vendor, 'model': model,
+                     'serial_number': serial, 'software_revision': software}
 
-#         Async has tow send 'INIT' and later ask for 'FETCH?'
+        # Async has to send 'INIT' and later ask for 'FETCH?'
 
         self.add_parameter('volt',
                            get_cmd='READ?',
+                           label='Voltage',
                            get_parser=float)
         self.add_parameter('NPLC',
                            get_cmd='VOLT:NPLC?',
                            get_parser=float,
                            set_cmd='VOLT:NPLC {:f}',
-                           vals=Enum(0.02,0.2,1,10,100))
-        # For dc and resistance measurements, changing the number of digits
+                           vals=Enum(0.02, 0.2, 1, 10, 100))
+        # For DC and resistance measurements, changing the number of digits
         # does more than just change the resolution of the multimeter. It also
         # changes the integration time!
         # Resolution Choices          Integration Time
@@ -73,29 +76,30 @@ def __init__(self, name, address, **kwargs):
                            get_cmd='VOLT:DC:RES?',
                            get_parser=float,
                            set_cmd='VOLT:DC:RES {:.7f}',
-                           vals=Enum(3e-07, 1e-06, 3e-06, 1e-05, 1e-04))
+                           vals=Enum(3e-07, 1e-06, 3e-06, 1e-05, 1e-04),
+                           unit='V')
         # Integration Time    Resolutionc
         self.add_parameter('integration_time',
                            get_cmd='VOLT:DC:RES?',
                            get_parser=float,
                            set_cmd='VOLT:DC:RES {:f}',
-#                            vals=Enum(0.02,0.2,1,10,100),
+                           # vals=Enum(0.02,0.2,1,10,100),
                            units='NPLC',
-                           val_mapping = {0.02: 0.0001,
-                                          0.2:  0.00001,
-                                          1:    0.000003,
-                                          10:   0.000001,
-                                          100:  0.0000003})
+                           val_mapping={0.02: 0.0001,
+                                        0.2:  0.00001,
+                                        1:    0.000003,
+                                        10:   0.000001,
+                                        100:  0.0000003})
         self.add_parameter('terminals',
                            get_cmd='ROUT:TERM?')
         self.add_parameter('range_auto',
                            get_cmd='VOLT:RANG:AUTO?',
                            get_parser=self._onoff_parser,
                            set_cmd='VOLT:RANG:AUTO {:d}',
-                           val_mapping = {'ON': 1,
-                                          'OFF':0,
-                                          1:    1,
-                                          0:    0})
+                           val_mapping={'ON': 1,
+                                        'OFF': 0,
+                                        1: 1,
+                                        0: 0})
         self.add_parameter('range',
                            get_cmd='SENS:VOLT:DC:RANG?',
                            get_parser=float,
@@ -116,6 +120,7 @@ def __init__(self, name, address, **kwargs):
                                get_cmd='DISP:WIND2:TEXT?',
                                set_cmd='DISP:WIND2:TEXT "{}"',
                                vals=Strings())
+
     def display_clear(self):
         if self.model in ['34401A']:
             self.write('DISP:WIND:TEXT:CLE')
@@ -128,9 +133,10 @@ def display_clear(self):
 
     def reset(self):
         self.write('*RST')
+
     def _onoff_parser(self, msg):
         if msg == '0':
             return 'OFF'
         elif msg == '1':
             return 'ON'
-        return None
\ No newline at end of file
+        return None
diff --git a/qcodes/instrument_drivers/oxford/triton.py b/qcodes/instrument_drivers/oxford/triton.py
index e16d90f65202..0a683101dc5d 100644
--- a/qcodes/instrument_drivers/oxford/triton.py
+++ b/qcodes/instrument_drivers/oxford/triton.py
@@ -10,8 +10,8 @@
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
 #
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
 #
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -31,12 +31,17 @@ class Triton(IPInstrument):
     TODO: fetch registry directly from fridge-computer
 
     Comment from Merlin:
-        I had to change the IP instrument, somehow the port does not get transferred to the socket connection
-        And I had other problesm with the _connect method, check those changes :)
+        I had to change the IP instrument, somehow the port does not get
+        transferred to the socket connection
+        And I had other problems with the _connect method,
+          check those changes :)
         Further there was a problem with the EnsureConnection class
     '''
-    def __init__(self, name, address=None, port=None, terminator='\r\n', tmpfile = None, **kwargs):
-        super().__init__(name, address=address, port=port, terminator=terminator, **kwargs)
+
+    def __init__(self, name, address=None, port=None, terminator='\r\n',
+                 tmpfile=None, **kwargs):
+        super().__init__(name, address=address, port=port,
+                         terminator=terminator, **kwargs)
 
         self.add_parameter(name='time',
                            label='System Time',
@@ -48,7 +53,7 @@ def __init__(self, name, address=None, port=None, terminator='\r\n', tmpfile = N
                            label='Current action',
                            units='',
                            get_cmd='READ:SYS:DR:ACTN',
-                           get_parser=self._parse_action )
+                           get_parser=self._parse_action)
 
         self.add_parameter(name='status',
                            label='Status',
@@ -58,37 +63,33 @@ def __init__(self, name, address=None, port=None, terminator='\r\n', tmpfile = N
 
         self.chan_alias = {}
         self.chan_temps = {}
-        if tmpfile != None:
+        if tmpfile is not None:
             self._get_temp_channels(tmpfile)
         self.get_pressure_channels()
         self._get_named_channels()
 
-
     def _get_named_channels(self):
         allchans = self.ask('READ:SYS:DR:CHAN')
         allchans = allchans.replace('STAT:SYS:DR:CHAN:', '', 1).split(':')
         for ch in allchans:
-            msg = 'READ:SYS:DR:CHAN:%s'%ch
+            msg = 'READ:SYS:DR:CHAN:%s' % ch
             rep = self.ask(msg)
-            if not 'INVALID' in rep:
-                alias, channel = rep.split(':')[-2:]
-                self.chan_alias[alias] = channel
+            if 'INVALID' not in rep:
+                alias, chan = rep.split(':')[-2:]
+                self.chan_alias[alias] = chan
                 self.add_parameter(name=alias,
                                    units='K',
-                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP'%channel,
+                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP' % chan,
                                    get_parser=self._parse_temp)
 
-
-
     def get_pressure_channels(self):
-        for i in range(1,7):
-            chan = 'P%d'%i
+        for i in range(1, 7):
+            chan = 'P%d' % i
             self.add_parameter(name=chan,
                                units='bar',
-                               get_cmd='READ:DEV:%s:PRES:SIG:PRES'%chan,
+                               get_cmd='READ:DEV:%s:PRES:SIG:PRES' % chan,
                                get_parser=self._parse_pres)
 
-
     def _get_temp_channels(self, file):
         config = configparser.ConfigParser()
         with open(file, 'r') as f:
@@ -101,10 +102,10 @@ def _get_temp_channels(self, file):
             if namestr in options:
                 chan = 'T'+section.split('\\')[-1].split('[')[-1]
                 name = config.get(section, '"m_lpszname"').strip("\"")
-                self.chan_temps[chan] = {'name':name, 'value':None}
+                self.chan_temps[chan] = {'name': name, 'value': None}
                 self.add_parameter(name=chan,
                                    units='K',
-                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP'%chan,
+                                   get_cmd='READ:DEV:%s:TEMP:SIG:TEMP' % chan,
                                    get_parser=self._parse_temp)
 
     def _parse_action(self, msg):
@@ -136,6 +137,7 @@ def _parse_temp(self, msg):
         if 'NOT_FOUND' in msg:
             return None
         return float(msg.split('SIG:TEMP:')[-1].strip('K'))
+
     def _parse_pres(self, msg):
         if 'NOT_FOUND' in msg:
             return None
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index bc2a0d72b8a1..593037e10075 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -10,8 +10,8 @@
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
 #
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
 #
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
@@ -24,6 +24,7 @@
 import re
 from qcodes import VisaInstrument
 
+
 class Keithley_2600(VisaInstrument):
     '''
     channel: use channel 'a' or 'b'
@@ -46,27 +47,29 @@ def __init__(self, name, address, channel, **kwargs):
         vendor, model, serial, software = map(str.strip, self.IDN.split(','))
         self.model = model[6:]
 
-        self.info = {'vendor':vendor, 'model':self.model,
-                     'serial_number':serial, 'software_revision':software}
+        self.info = {'vendor': vendor, 'model': self.model,
+                     'serial_number': serial, 'software_revision': software}
 
         self.add_parameter('volt', get_cmd='measure.v()',
                            get_parser=float, set_cmd='source.levelv={:.8f}',
+                           label='Voltage',
                            units='V')
         self.add_parameter('curr', get_cmd='measure.i()',
                            get_parser=float, set_cmd='source.leveli={:.8f}',
+                           label='Current',
                            units='A')
         self.add_parameter('mode',
                            get_cmd='source.func',
                            get_parser=self._mode_parser,
                            set_cmd='source.func={:d}',
-                           val_mapping={'current':0, 'curr':0, 'AMPS':0,
-                                        'voltage':1, 'volt':1, 'VOLT':1})
+                           val_mapping={'current': 0, 'curr': 0, 'AMPS': 0,
+                                        'voltage': 1, 'volt': 1, 'VOLT': 1})
         self.add_parameter('output',
                            get_cmd='source.output',
                            get_parser=self._output_parser,
                            set_cmd='source.output={:d}',
-                           val_mapping={'on': 1, 'ON': 1,
-                                        'off':0, 'OFF':0})
+                           val_mapping={'on':  1, 'ON':  1,
+                                        'off': 0, 'OFF': 0})
         # Source range
         self.add_parameter('rangev',
                            get_cmd='source.rangev',
@@ -98,6 +101,7 @@ def _mode_parser(self, msg):
         elif msg[0] == '1':
             return 'voltage'
         return None
+
     def _output_parser(self, msg):
         if msg[0] == '0':
             return 'OFF'
@@ -118,7 +122,7 @@ def ask_direct(self, cmd):
         return self.visa_handle.ask(cmd)
 
     def ask(self, cmd):
-        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel,cmd))
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel, cmd))
 
     def write(self, cmd):
-        super().write('smu{:s}.{:s}'.format(self._channel, cmd))
\ No newline at end of file
+        super().write('smu{:s}.{:s}'.format(self._channel, cmd))

From 835801f957648eaf27c0f84c3e6c4b1f14f507eb Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sun, 17 Apr 2016 23:36:51 +0200
Subject: [PATCH 004/169] removed obsolete functions

---
 qcodes/instrument_drivers/tektronix/Keithley_2600.py | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index 593037e10075..fb3f4db6f911 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -112,12 +112,6 @@ def _output_parser(self, msg):
     def reset(self):
         self.write('reset()')
 
-    def get_curr(self, msg):
-        return float(msg.rstrip().split(',')[1])
-
-    def get_volt(self, msg):
-        return float(msg.rstrip().split(',')[0])
-
     def ask_direct(self, cmd):
         return self.visa_handle.ask(cmd)
 

From 48cf07649f75a4f4ca588cf54bd51c0561a0a5c4 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 12:03:39 +0200
Subject: [PATCH 005/169] removed channel comment, added volt_fetch

---
 qcodes/instrument_drivers/agilent/Agilent_34400A.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
index 2b5f342665ba..d458b4abd0cf 100644
--- a/qcodes/instrument_drivers/agilent/Agilent_34400A.py
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -28,8 +28,6 @@
 
 class Agilent_34400A(VisaInstrument):
     '''
-    channel: use channel 'a' or 'b'
-
     This is the qcodes driver for the Agilent_34400A DMM Series,
     tested with Agilent_34401A
 
@@ -57,6 +55,10 @@ def __init__(self, name, address, **kwargs):
                            get_cmd='READ?',
                            label='Voltage',
                            get_parser=float)
+        self.add_parameter('volt_fetch',
+                           get_cmd='FETCH?',
+                           label='Voltage',
+                           get_parser=float)
         self.add_parameter('NPLC',
                            get_cmd='VOLT:NPLC?',
                            get_parser=float,
@@ -121,6 +123,9 @@ def __init__(self, name, address, **kwargs):
                                set_cmd='DISP:WIND2:TEXT "{}"',
                                vals=Strings())
 
+    def init_measurement(self):
+        self.write('INIT')
+
     def display_clear(self):
         if self.model in ['34401A']:
             self.write('DISP:WIND:TEXT:CLE')

From 735473b6b17f9f60a6b5efc62f79d12eaac27629 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 12:26:45 +0200
Subject: [PATCH 006/169] fixed buffer-size name

---
 qcodes/instrument/ip.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/qcodes/instrument/ip.py b/qcodes/instrument/ip.py
index 97b05eccfdd6..3e6d6e2ff553 100644
--- a/qcodes/instrument/ip.py
+++ b/qcodes/instrument/ip.py
@@ -31,7 +31,7 @@ def __init__(self, name, address=None, port=None, timeout=5,
         self._confirmation = write_confirmation
 
         self._ensure_connection = EnsureConnection(self)
-        self._buffer = 1024
+        self._buffer_size = 1024
 
         self._socket = None
 
@@ -94,7 +94,7 @@ def _send(self, cmd):
         self._socket.send(data.encode())
 
     def _recv(self):
-        return self._socket.recv(self._buffer).decode()
+        return self._socket.recv(self._buffer_size).decode()
 
     def close(self):
         self._disconnect()
@@ -122,4 +122,4 @@ def __enter__(self):
 
     def __exit__(self, type, value, tb):
         if not self.instrument._persistent:
-            self.instrument._disconnect()
\ No newline at end of file
+            self.instrument._disconnect()

From 2ca3dd700d37f29c2e6b83654c89bdd1fae77ea9 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 14:16:13 +0200
Subject: [PATCH 007/169] Adding __call__ to parameters which direct to set and
 get

---
 qcodes/instrument/parameter.py | 21 +++++++++++++++++++--
 qcodes/instrument/remote.py    |  6 ++++++
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index bce50caed89b..292f4fd31bd2 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -137,6 +137,9 @@ def __init__(self,
                  vals=None, **kwargs):
         super().__init__(**kwargs)
 
+        self.has_get = False
+        self.has_set = False
+
         if names is not None:
             # check for names first - that way you can provide both name
             # AND names for instrument parameters - name is how you get the
@@ -169,6 +172,19 @@ def __init__(self,
 
         self.get_latest = GetLatest(self)
 
+    def __call__(self, *args):
+        if len(args) == 0:
+            if self.has_get:
+                return self.get()
+            else:
+                raise NoCommandError('no get cmd found in' +
+                                     ' Parameter {}'.format(self.name))
+        else:
+            if self.has_set:
+                self.set(*args)
+            else:
+                raise NoCommandError('no set cmd found in' +
+                                     ' Parameter {}'.format(self.name))
     def has_instrument_storage(self):
         return False
         # TODO - rip out completely, parameters for server instruments
@@ -344,8 +360,6 @@ def __init__(self, name, instrument=None,
         # having to call .get() for every .set()
         self._max_val_age = 0
 
-        self.has_get = False
-        self.has_set = False
 
         self._set_get(get_cmd, async_get_cmd, get_parser)
         self._set_set(set_cmd, async_set_cmd, set_parser)
@@ -550,6 +564,9 @@ def __init__(self, name, instrument=None, initial_value=None, **kwargs):
             self.validate(initial_value)
             self._save_val(initial_value)
 
+        self.has_get = True
+        self.has_set = True
+
     def set(self, value):
         self.validate(value)
         self._save_val(value)
diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index 43a2757d3fee..b9015e3fa21b 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -113,6 +113,12 @@ def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.get_latest = GetLatest(self)
 
+    def __call__(self, *args):
+        if len(args) == 0:
+            self.get()
+        else:
+            self.set(*args)
+
     def get(self):
         return self._instrument.connection.ask('get', self.name)
 

From 29be9134f990c070ab590be498dec7385ace1171 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 14:21:49 +0200
Subject: [PATCH 008/169] example notebook where it does not work with the mock
 instruments

---
 .../Qcodes example parameter call.ipynb       | 594 ++++++++++++++++++
 1 file changed, 594 insertions(+)
 create mode 100644 docs/examples/Qcodes example parameter call.ipynb

diff --git a/docs/examples/Qcodes example parameter call.ipynb b/docs/examples/Qcodes example parameter call.ipynb
new file mode 100644
index 000000000000..2ed3f6c5a789
--- /dev/null
+++ b/docs/examples/Qcodes example parameter call.ipynb	
@@ -0,0 +1,594 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# spawn doesn't like function or class definitions in the interpreter\n",
+    "# session - had to move them to a file.\n",
+    "from toymodel import AModel, MockGates, MockSource, MockMeter, AverageGetter, AverageAndRaw\n",
+    "\n",
+    "# now create this \"experiment\"\n",
+    "model = AModel()\n",
+    "gates = MockGates('gates', model=model,server_name=None)\n",
+    "source = MockSource('source', model=model,server_name=None)\n",
+    "meter = MockMeter('meter', model=model,server_name=None)\n",
+    "\n",
+    "station = qc.Station(gates, source, meter)\n",
+    "\n",
+    "# could measure any number of things by adding arguments to this\n",
+    "# function call, but here we're just measuring one, the meter amplitude\n",
+    "station.set_measurement(meter.amplitude)\n",
+    "\n",
+    "# it's nice to have the key parameters be part of the global namespace\n",
+    "# that way they're objects that we can easily set, get, and slice\n",
+    "# this could be simplified to a station method that gathers all parameters\n",
+    "# and adds them all as (disambiguated) globals, printing what it did\n",
+    "# something like:\n",
+    "#   station.gather_parameters(globals())\n",
+    "c0, c1, c2, vsd = gates.chan0, gates.chan1, gates.chan2, source.amplitude\n",
+    "\n",
+    "# once we have implemented a monitor, defining a station will start a\n",
+    "# DataServer process, and you would see it in the subprocess widget,\n",
+    "# or via active_children() as here:\n",
+    "# qc.active_children()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "0.117"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "meter.amplitude()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "ename": "AttributeError",
+     "evalue": "*** error on Model-fa91743 ***\n\nTraceback (most recent call last):\n  File \"C:\\Github\\Qcodes\\qcodes\\instrument\\mock.py\", line 152, in _run_server\n    self._response_queue.put(getter(param[:-1]))\n  File \"C:\\GitHub\\Qcodes\\docs\\examples\\toymodel.py\", line 43, in gates_get\n    return self.fmt(self.gates[int(parameter[1:])])\nAttributeError: (\"'AModel' object has no attribute 'gates'\", \"error processing query ['gates', 'c0?']\")\n",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mc0\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mc0\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\instrument\\parameter.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m    176\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    177\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhas_get\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 178\u001b[1;33m                 \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    179\u001b[0m             \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    180\u001b[0m                 raise NoCommandError('no get cmd found in' +\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\instrument\\parameter.py\u001b[0m in \u001b[0;36mget\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    373\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    374\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 375\u001b[1;33m         \u001b[0mvalue\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_get\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    376\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_save_val\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    377\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\sync_async.py\u001b[0m in \u001b[0;36mcall\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m    202\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mcall\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    203\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalidate_arg_count\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 204\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexec_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    205\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    206\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0masyncio\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\sync_async.py\u001b[0m in \u001b[0;36mcall_by_str_parsed_out\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m    148\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    149\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mcall_by_str_parsed_out\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 150\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0moutput_parser\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexec_str\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcmd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    151\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    152\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0masyncio\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\instrument\\mock.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, cmd)\u001b[0m\n\u001b[0;32m     93\u001b[0m                                  'ask', parameter))\n\u001b[0;32m     94\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 95\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_model\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m':'\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mcmd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     96\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     97\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, timeout, *query)\u001b[0m\n\u001b[0;32m    333\u001b[0m                     \u001b[1;31m# only raise if we're not about to find a deeper error\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    334\u001b[0m                     \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 335\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_for_errors\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_expect_error\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    336\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    337\u001b[0m             \u001b[1;32mreturn\u001b[0m \u001b[0mres\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36m_check_for_errors\u001b[1;34m(self, expect_error)\u001b[0m\n\u001b[0;32m    298\u001b[0m                 \u001b[0merr_type\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    299\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 300\u001b[1;33m             \u001b[1;32mraise\u001b[0m \u001b[0merr_type\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0merrhead\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m'\\n\\n'\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0merrstr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    301\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    302\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_check_response\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mAttributeError\u001b[0m: *** error on Model-fa91743 ***\n\nTraceback (most recent call last):\n  File \"C:\\Github\\Qcodes\\qcodes\\instrument\\mock.py\", line 152, in _run_server\n    self._response_queue.put(getter(param[:-1]))\n  File \"C:\\GitHub\\Qcodes\\docs\\examples\\toymodel.py\", line 43, in gates_get\n    return self.fmt(self.gates[int(parameter[1:])])\nAttributeError: (\"'AModel' object has no attribute 'gates'\", \"error processing query ['gates', 'c0?']\")\n"
+     ]
+    }
+   ],
+   "source": [
+    "c0(1)\n",
+    "c0()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[]"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# we can get the measured quantities right now\n",
+    "station.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "ename": "TypeError",
+     "evalue": "'RemoteMethod' object is not subscriptable",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mLoop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc0\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.03\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_temp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m#(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[1;31m# now there should be two extra processes running, DataServer and a sweep\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
+     ]
+    }
+   ],
+   "source": [
+    "# start a Loop (which by default runs in a seprarate process)\n",
+    "# the sweep values are defined by slicing the parameter object\n",
+    "# but more complicated sweeps (eg nonlinear, or adaptive) can\n",
+    "# easily be used instead\n",
+    "\n",
+    "# Notice that I'm using an explicit location and `overwrite=True` here so that\n",
+    "# running this notebook over and over won't result in extra files.\n",
+    "# But if you leave these out, you get a new timestamped DataSet each time.\n",
+    "# data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True, background=False)\n",
+    "\n",
+    "data = qc.Loop(c0[-20:20:0.1], 0.03).run_temp()#(location='testsweep', overwrite=True, background=False)\n",
+    "\n",
+    "# now there should be two extra processes running, DataServer and a sweep\n",
+    "# I'll omit the active_children call now because you can see them in the\n",
+    "# subprocess widget"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 11,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "ename": "NameError",
+     "evalue": "name 'data' is not defined",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# manually bring the data into the main process and display it as numbers\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msync\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marrays\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mNameError\u001b[0m: name 'data' is not defined"
+     ]
+    }
+   ],
+   "source": [
+    "# manually bring the data into the main process and display it as numbers\n",
+    "data.sync()\n",
+    "data.arrays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "# live-updating plot, that syncs the data and stops updating when it's finished\n",
+    "# plot = qc.MatPlot(data.amplitude)\n",
+    "plotQ = qc.QtPlot(data.amplitude)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 12,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "ename": "TypeError",
+     "evalue": "'RemoteMethod' object is not subscriptable",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m data2 = qc.Loop(c1[-15:15:1], 0.1).loop(c0[-15:12:.5], 0.01).each(\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# first measurement, at c2=0 -> amplitude_0 bcs it's action 0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# action 1 -> c2.set(1)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mWait\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0.001\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# second measurement, at c2=1 -> amplitude_4 bcs it's action 4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
+     ]
+    }
+   ],
+   "source": [
+    "data2 = qc.Loop(c1[-15:15:1], 0.1).loop(c0[-15:12:.5], 0.01).each(\n",
+    "    meter.amplitude, # first measurement, at c2=0 -> amplitude_0 bcs it's action 0\n",
+    "    qc.Task(c2.set, 1), # action 1 -> c2.set(1)\n",
+    "    qc.Wait(0.001),\n",
+    "    meter.amplitude, # second measurement, at c2=1 -> amplitude_4 bcs it's action 4\n",
+    "    qc.Task(c2.set, 0)\n",
+    "    ).run(location='test2d', overwrite=True)\n",
+    "\n",
+    "# use the subplot and add features of qc.MatPlot\n",
+    "# plot2 = qc.MatPlot(data2.amplitude_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1, 2))\n",
+    "# plot2.add(data2.amplitude_3, cmap=plt.cm.hot, subplot=2)\n",
+    "\n",
+    "# the equivalent in QtPlot\n",
+    "plot2Q = qc.QtPlot(data2.amplitude_0, figsize=(1200, 500))\n",
+    "plot2Q.add(data2.amplitude_3, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan0: chan0\n",
+      "   amplitude_2: amplitude\n",
+      "   chan1: chan1\n",
+      "   amplitude_3_0: amplitude\n",
+      "   amplitude_5_0: amplitude\n",
+      "started at 2016-04-13 15:24:20\n"
+     ]
+    }
+   ],
+   "source": [
+    "data3 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
+    "    qc.Task(c0.set, -10),\n",
+    "    qc.Task(c2.set, 0),\n",
+    "    # a 1D measurement\n",
+    "    meter.amplitude,\n",
+    "    # a 2D sweep, .each is actually unnecessary bcs this is the default measurement\n",
+    "    qc.Loop(c0[-15:15:1], 0.001).each(meter.amplitude),\n",
+    "    qc.Task(c0.set, -10),\n",
+    "    # a 2D sweep with the same outer but different inner loop\n",
+    "    qc.Loop(c2[-10:10:0.2], 0.001),\n",
+    "    AverageGetter(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
+    ").run(location='test_multi_d', overwrite=True)\n",
+    "\n",
+    "# several plots updating simultaneously\n",
+    "# plot3 = qc.MatPlot(data3.amplitude_3_0, cmap=plt.cm.hot)\n",
+    "# plot3b = qc.MatPlot(data3.amplitude_5_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\n",
+    "# plot3b.add(data3.avg_amplitude, subplot=2)\n",
+    "plot3Q = qc.QtPlot(data3.amplitude_3_0)\n",
+    "plot3bQ = qc.QtPlot(data3.amplitude_5_0, figsize=(1200, 500))\n",
+    "plot3bQ.add(data3.avg_amplitude, subplot=2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude: amplitude\n",
+      "started at 2016-02-02 12:18:09\n"
+     ]
+    }
+   ],
+   "source": [
+    "# An example of a parameter that returns several values of different dimension\n",
+    "# This produces the last two arrays from data3, but only takes the data once.\n",
+    "data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
+    "    AverageAndRaw(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
+    ").run(location='test_complex_param', overwrite=True)\n",
+    "\n",
+    "# plot4 = qc.MatPlot(data4.amplitude, cmap=plt.cm.hot, subplots=(1,2), figsize=(12, 4.5))\n",
+    "# plot4.add(data4.avg_amplitude, subplot=2)\n",
+    "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
+    "plot4Q.add(data4.avg_amplitude, subplot=2)"
+   ]
+  }
+ ],
+ "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.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}

From 924114853d02c430886feb02496f357937c4a96d Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 14:25:39 +0200
Subject: [PATCH 009/169] little notebook update

---
 .../Qcodes example parameter call.ipynb       | 124 ++++++++++--------
 1 file changed, 66 insertions(+), 58 deletions(-)

diff --git a/docs/examples/Qcodes example parameter call.ipynb b/docs/examples/Qcodes example parameter call.ipynb
index 2ed3f6c5a789..8bc5faf63df4 100644
--- a/docs/examples/Qcodes example parameter call.ipynb	
+++ b/docs/examples/Qcodes example parameter call.ipynb	
@@ -262,7 +262,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 13,
    "metadata": {
     "collapsed": false
    },
@@ -274,9 +274,9 @@
     "\n",
     "# now create this \"experiment\"\n",
     "model = AModel()\n",
-    "gates = MockGates('gates', model=model,server_name=None)\n",
-    "source = MockSource('source', model=model,server_name=None)\n",
-    "meter = MockMeter('meter', model=model,server_name=None)\n",
+    "gates = MockGates('gates', model=model)\n",
+    "source = MockSource('source', model=model)\n",
+    "meter = MockMeter('meter', model=model)\n",
     "\n",
     "station = qc.Station(gates, source, meter)\n",
     "\n",
@@ -300,7 +300,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 14,
    "metadata": {
     "collapsed": false
    },
@@ -311,7 +311,7 @@
        "0.117"
       ]
      },
-     "execution_count": 10,
+     "execution_count": 14,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -322,38 +322,30 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 17,
    "metadata": {
     "collapsed": false
    },
    "outputs": [
     {
-     "ename": "AttributeError",
-     "evalue": "*** error on Model-fa91743 ***\n\nTraceback (most recent call last):\n  File \"C:\\Github\\Qcodes\\qcodes\\instrument\\mock.py\", line 152, in _run_server\n    self._response_queue.put(getter(param[:-1]))\n  File \"C:\\GitHub\\Qcodes\\docs\\examples\\toymodel.py\", line 43, in gates_get\n    return self.fmt(self.gates[int(parameter[1:])])\nAttributeError: (\"'AModel' object has no attribute 'gates'\", \"error processing query ['gates', 'c0?']\")\n",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[0mc0\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mc0\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\instrument\\parameter.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m    176\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    177\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mhas_get\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 178\u001b[1;33m                 \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    179\u001b[0m             \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    180\u001b[0m                 raise NoCommandError('no get cmd found in' +\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\instrument\\parameter.py\u001b[0m in \u001b[0;36mget\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    373\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    374\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 375\u001b[1;33m         \u001b[0mvalue\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_get\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    376\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_save_val\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    377\u001b[0m         \u001b[1;32mreturn\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\sync_async.py\u001b[0m in \u001b[0;36mcall\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m    202\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mcall\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    203\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalidate_arg_count\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 204\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexec_function\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    205\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    206\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0masyncio\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\sync_async.py\u001b[0m in \u001b[0;36mcall_by_str_parsed_out\u001b[1;34m(self, *args)\u001b[0m\n\u001b[0;32m    148\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    149\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mcall_by_str_parsed_out\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 150\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0moutput_parser\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexec_str\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcmd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mformat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    151\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    152\u001b[0m     \u001b[1;33m@\u001b[0m\u001b[0masyncio\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcoroutine\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\instrument\\mock.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, cmd)\u001b[0m\n\u001b[0;32m     93\u001b[0m                                  'ask', parameter))\n\u001b[0;32m     94\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 95\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_model\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m':'\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0mcmd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     96\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     97\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mread\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, timeout, *query)\u001b[0m\n\u001b[0;32m    333\u001b[0m                     \u001b[1;31m# only raise if we're not about to find a deeper error\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    334\u001b[0m                     \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 335\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_for_errors\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_expect_error\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    336\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    337\u001b[0m             \u001b[1;32mreturn\u001b[0m \u001b[0mres\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36m_check_for_errors\u001b[1;34m(self, expect_error)\u001b[0m\n\u001b[0;32m    298\u001b[0m                 \u001b[0merr_type\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    299\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 300\u001b[1;33m             \u001b[1;32mraise\u001b[0m \u001b[0merr_type\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0merrhead\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;34m'\\n\\n'\u001b[0m \u001b[1;33m+\u001b[0m \u001b[0merrstr\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    301\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    302\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_check_response\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;31mAttributeError\u001b[0m: *** error on Model-fa91743 ***\n\nTraceback (most recent call last):\n  File \"C:\\Github\\Qcodes\\qcodes\\instrument\\mock.py\", line 152, in _run_server\n    self._response_queue.put(getter(param[:-1]))\n  File \"C:\\GitHub\\Qcodes\\docs\\examples\\toymodel.py\", line 43, in gates_get\n    return self.fmt(self.gates[int(parameter[1:])])\nAttributeError: (\"'AModel' object has no attribute 'gates'\", \"error processing query ['gates', 'c0?']\")\n"
-     ]
+     "data": {
+      "text/plain": [
+       "0.5"
+      ]
+     },
+     "execution_count": 17,
+     "metadata": {},
+     "output_type": "execute_result"
     }
    ],
    "source": [
-    "c0(1)\n",
-    "c0()"
+    "vsd(0.5)\n",
+    "vsd()"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 18,
    "metadata": {
     "collapsed": false
    },
@@ -364,7 +356,7 @@
        "[]"
       ]
      },
-     "execution_count": 4,
+     "execution_count": 18,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -376,7 +368,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 19,
    "metadata": {
     "collapsed": false
    },
@@ -388,7 +380,7 @@
      "traceback": [
       "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mLoop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc0\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.03\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_temp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m#(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[1;31m# now there should be two extra processes running, DataServer and a sweep\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mLoop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc0\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.03\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_temp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m#(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[1;31m# now there should be two extra processes running, DataServer and a sweep\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
      ]
     }
@@ -413,7 +405,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 20,
    "metadata": {
     "collapsed": false,
     "scrolled": true
@@ -426,7 +418,7 @@
      "traceback": [
       "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# manually bring the data into the main process and display it as numbers\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msync\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marrays\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# manually bring the data into the main process and display it as numbers\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msync\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marrays\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;31mNameError\u001b[0m: name 'data' is not defined"
      ]
     }
@@ -439,12 +431,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 21,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "ename": "NameError",
+     "evalue": "name 'data' is not defined",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# live-updating plot, that syncs the data and stops updating when it's finished\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# plot = qc.MatPlot(data.amplitude)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mplotQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[1;31mNameError\u001b[0m: name 'data' is not defined"
+     ]
+    }
+   ],
    "source": [
     "# live-updating plot, that syncs the data and stops updating when it's finished\n",
     "# plot = qc.MatPlot(data.amplitude)\n",
@@ -453,7 +457,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 22,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -466,7 +470,7 @@
      "traceback": [
       "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m data2 = qc.Loop(c1[-15:15:1], 0.1).loop(c0[-15:12:.5], 0.01).each(\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# first measurement, at c2=0 -> amplitude_0 bcs it's action 0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# action 1 -> c2.set(1)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mWait\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0.001\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# second measurement, at c2=1 -> amplitude_4 bcs it's action 4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m data2 = qc.Loop(c1[-15:15:1], 0.1).loop(c0[-15:12:.5], 0.01).each(\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# first measurement, at c2=0 -> amplitude_0 bcs it's action 0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# action 1 -> c2.set(1)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mWait\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0.001\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# second measurement, at c2=1 -> amplitude_4 bcs it's action 4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
      ]
     }
@@ -491,24 +495,20 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 23,
    "metadata": {
     "collapsed": false
    },
    "outputs": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
-      "   avg_amplitude: avg_amplitude\n",
-      "   chan2: chan2\n",
-      "   chan0: chan0\n",
-      "   amplitude_2: amplitude\n",
-      "   chan1: chan1\n",
-      "   amplitude_3_0: amplitude\n",
-      "   amplitude_5_0: amplitude\n",
-      "started at 2016-04-13 15:24:20\n"
+     "ename": "TypeError",
+     "evalue": "'RemoteMethod' object is not subscriptable",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m data3 = qc.Loop(c1[-15:15:1], 0.1).each(\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc0\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[1;31m# a 1D measurement\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
      ]
     }
    ],
@@ -537,22 +537,21 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 24,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
    "outputs": [
     {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
-      "   avg_amplitude: avg_amplitude\n",
-      "   chan2: chan2\n",
-      "   chan1: chan1\n",
-      "   amplitude: amplitude\n",
-      "started at 2016-02-02 12:18:09\n"
+     "ename": "TypeError",
+     "evalue": "'RemoteMethod' object is not subscriptable",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# An example of a parameter that returns several values of different dimension\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# This produces the last two arrays from data3, but only takes the data once.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n\u001b[0m\u001b[0;32m      4\u001b[0m     \u001b[0mAverageAndRaw\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mc2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m0.2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.001\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m ).run(location='test_complex_param', overwrite=True)\n",
+      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
      ]
     }
    ],
@@ -568,6 +567,15 @@
     "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
     "plot4Q.add(data4.avg_amplitude, subplot=2)"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {

From 50347580bddf80e829875bfec53467ea988adebd Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 14:32:24 +0200
Subject: [PATCH 010/169] also return self.get()

---
 qcodes/instrument/remote.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index b9015e3fa21b..8c6c0b39d36f 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -115,7 +115,7 @@ def __init__(self, *args, **kwargs):
 
     def __call__(self, *args):
         if len(args) == 0:
-            self.get()
+            return self.get()
         else:
             self.set(*args)
 

From d04403edb1db605962cbe162533effd8410cc6d5 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 14:37:41 +0200
Subject: [PATCH 011/169] updated notebook

---
 .../Qcodes example parameter call.ipynb       | 204 +++++++++++++-----
 1 file changed, 148 insertions(+), 56 deletions(-)

diff --git a/docs/examples/Qcodes example parameter call.ipynb b/docs/examples/Qcodes example parameter call.ipynb
index 8bc5faf63df4..1c89311b7bf2 100644
--- a/docs/examples/Qcodes example parameter call.ipynb	
+++ b/docs/examples/Qcodes example parameter call.ipynb	
@@ -262,7 +262,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 2,
    "metadata": {
     "collapsed": false
    },
@@ -300,7 +300,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": 3,
    "metadata": {
     "collapsed": false
    },
@@ -311,7 +311,7 @@
        "0.117"
       ]
      },
-     "execution_count": 14,
+     "execution_count": 3,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -322,7 +322,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 4,
    "metadata": {
     "collapsed": false
    },
@@ -333,7 +333,7 @@
        "0.5"
       ]
      },
-     "execution_count": 17,
+     "execution_count": 4,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -345,7 +345,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 5,
    "metadata": {
     "collapsed": false
    },
@@ -353,10 +353,10 @@
     {
      "data": {
       "text/plain": [
-       "[]"
+       "[0.627]"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -368,23 +368,11 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 6,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [
-    {
-     "ename": "TypeError",
-     "evalue": "'RemoteMethod' object is not subscriptable",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mdata\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mLoop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc0\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m20\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.03\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrun_temp\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;31m#(location='testsweep', overwrite=True, background=False)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[1;31m# now there should be two extra processes running, DataServer and a sweep\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# start a Loop (which by default runs in a seprarate process)\n",
     "# the sweep values are defined by slicing the parameter object\n",
@@ -405,22 +393,117 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false,
     "scrolled": true
    },
    "outputs": [
     {
-     "ename": "NameError",
-     "evalue": "name 'data' is not defined",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# manually bring the data into the main process and display it as numbers\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msync\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marrays\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;31mNameError\u001b[0m: name 'data' is not defined"
-     ]
+     "data": {
+      "text/plain": [
+       "{'amplitude': DataArray[400]: amplitude\n",
+       " array([ 0.627,  0.661,  0.69 ,  0.711,  0.723,  0.723,  0.711,  0.687,\n",
+       "         0.653,  0.613,  0.569,  0.524,  0.479,  0.437,  0.398,  0.362,\n",
+       "         0.329,  0.3  ,  0.273,  0.25 ,  0.229,  0.21 ,  0.194,  0.179,\n",
+       "         0.166,  0.154,  0.143,  0.134,  0.125,  0.117,  0.11 ,  0.103,\n",
+       "         0.098,  0.092,  0.087,  0.083,  0.078,  0.075,  0.071,  0.068,\n",
+       "         0.065,  0.062,  0.059,  0.057,  0.054,  0.052,  0.05 ,  0.048,\n",
+       "         0.046,  0.045,  0.043,  0.045,  0.046,  0.048,  0.05 ,  0.052,\n",
+       "         0.054,  0.057,  0.059,  0.062,  0.065,  0.068,  0.071,  0.075,\n",
+       "         0.078,  0.083,  0.087,  0.092,  0.098,  0.103,  0.11 ,  0.117,\n",
+       "         0.125,  0.134,  0.143,  0.154,  0.166,  0.179,  0.194,  0.21 ,\n",
+       "         0.229,  0.25 ,  0.273,  0.3  ,  0.329,  0.362,  0.398,  0.437,\n",
+       "         0.479,  0.524,  0.569,  0.613,  0.653,  0.687,  0.711,  0.723,\n",
+       "         0.723,  0.711,  0.69 ,  0.661,  0.627,  0.661,  0.69 ,  0.711,\n",
+       "         0.723,  0.723,  0.711,  0.687,  0.653,  0.613,  0.569,  0.524,\n",
+       "         0.479,  0.437,  0.398,  0.362,  0.329,  0.3  ,  0.273,  0.25 ,\n",
+       "         0.229,  0.21 ,  0.194,  0.179,  0.166,  0.154,  0.143,  0.134,\n",
+       "         0.125,  0.117,  0.11 ,  0.103,  0.098,  0.092,  0.087,  0.083,\n",
+       "         0.078,  0.075,  0.071,  0.068,  0.065,  0.062,  0.059,  0.057,\n",
+       "         0.054,  0.052,  0.05 ,  0.048,  0.046,  0.045,  0.043,  0.045,\n",
+       "         0.046,  0.048,  0.05 ,  0.052,  0.054,  0.057,  0.059,  0.062,\n",
+       "         0.065,  0.068,  0.071,  0.075,  0.078,  0.083,  0.087,  0.092,\n",
+       "         0.098,  0.103,  0.11 ,  0.117,  0.125,  0.134,  0.143,  0.154,\n",
+       "         0.166,  0.179,  0.194,  0.21 ,  0.229,  0.25 ,  0.273,  0.3  ,\n",
+       "         0.329,  0.362,  0.398,  0.437,  0.479,  0.524,  0.569,  0.613,\n",
+       "         0.653,  0.687,  0.711,  0.723,  0.723,  0.711,  0.69 ,  0.661,\n",
+       "         0.627,  0.661,  0.69 ,  0.711,  0.723,  0.723,  0.711,  0.687,\n",
+       "         0.653,  0.613,  0.569,  0.524,  0.479,  0.437,  0.398,  0.362,\n",
+       "         0.329,  0.3  ,  0.273,  0.25 ,  0.229,  0.21 ,  0.194,  0.179,\n",
+       "         0.166,  0.154,  0.143,  0.134,  0.125,  0.117,  0.11 ,  0.103,\n",
+       "         0.098,  0.092,  0.087,  0.083,  0.078,  0.075,  0.071,  0.068,\n",
+       "         0.065,  0.062,  0.059,  0.057,  0.054,  0.052,  0.05 ,  0.048,\n",
+       "         0.046,  0.045,  0.043,  0.045,  0.046,  0.048,  0.05 ,  0.052,\n",
+       "         0.054,  0.057,  0.059,  0.062,  0.065,  0.068,  0.071,  0.075,\n",
+       "         0.078,  0.083,  0.087,  0.092,  0.098,  0.103,  0.11 ,  0.117,\n",
+       "         0.125,  0.134,  0.143,  0.154,  0.166,  0.179,  0.194,  0.21 ,\n",
+       "         0.229,  0.25 ,  0.273,  0.3  ,  0.329,  0.362,  0.398,  0.437,\n",
+       "         0.479,  0.524,  0.569,  0.613,  0.653,  0.687,  0.711,  0.723,\n",
+       "         0.723,  0.711,  0.69 ,  0.661,  0.627,  0.661,  0.69 ,  0.711,\n",
+       "         0.723,  0.723,  0.711,  0.687,  0.653,  0.613,  0.569,  0.524,\n",
+       "         0.479,  0.437,  0.398,  0.362,  0.329,  0.3  ,  0.273,  0.25 ,\n",
+       "         0.229,  0.21 ,  0.194,  0.179,  0.166,  0.154,  0.143,  0.134,\n",
+       "         0.125,  0.117,  0.11 ,  0.103,  0.098,  0.092,  0.087,  0.083,\n",
+       "         0.078,  0.075,  0.071,  0.068,  0.065,  0.062,  0.059,  0.057,\n",
+       "         0.054,  0.052,  0.05 ,  0.048,  0.046,  0.045,  0.043,  0.045,\n",
+       "         0.046,  0.048,  0.05 ,  0.052,  0.054,  0.057,  0.059,  0.062,\n",
+       "         0.065,  0.068,  0.071,  0.075,  0.078,  0.083,  0.087,  0.092,\n",
+       "         0.098,  0.103,  0.11 ,  0.117,  0.125,  0.134,  0.143,  0.154,\n",
+       "         0.166,  0.179,  0.194,  0.21 ,  0.229,  0.25 ,  0.273,  0.3  ,\n",
+       "         0.329,  0.362,  0.398,  0.437,  0.479,  0.524,  0.569,  0.613,\n",
+       "         0.653,  0.687,  0.711,  0.723,  0.723,  0.711,  0.69 ,  0.661]),\n",
+       " 'chan0': DataArray[400]: chan0\n",
+       " array([-20. , -19.9, -19.8, -19.7, -19.6, -19.5, -19.4, -19.3, -19.2,\n",
+       "        -19.1, -19. , -18.9, -18.8, -18.7, -18.6, -18.5, -18.4, -18.3,\n",
+       "        -18.2, -18.1, -18. , -17.9, -17.8, -17.7, -17.6, -17.5, -17.4,\n",
+       "        -17.3, -17.2, -17.1, -17. , -16.9, -16.8, -16.7, -16.6, -16.5,\n",
+       "        -16.4, -16.3, -16.2, -16.1, -16. , -15.9, -15.8, -15.7, -15.6,\n",
+       "        -15.5, -15.4, -15.3, -15.2, -15.1, -15. , -14.9, -14.8, -14.7,\n",
+       "        -14.6, -14.5, -14.4, -14.3, -14.2, -14.1, -14. , -13.9, -13.8,\n",
+       "        -13.7, -13.6, -13.5, -13.4, -13.3, -13.2, -13.1, -13. , -12.9,\n",
+       "        -12.8, -12.7, -12.6, -12.5, -12.4, -12.3, -12.2, -12.1, -12. ,\n",
+       "        -11.9, -11.8, -11.7, -11.6, -11.5, -11.4, -11.3, -11.2, -11.1,\n",
+       "        -11. , -10.9, -10.8, -10.7, -10.6, -10.5, -10.4, -10.3, -10.2,\n",
+       "        -10.1, -10. ,  -9.9,  -9.8,  -9.7,  -9.6,  -9.5,  -9.4,  -9.3,\n",
+       "         -9.2,  -9.1,  -9. ,  -8.9,  -8.8,  -8.7,  -8.6,  -8.5,  -8.4,\n",
+       "         -8.3,  -8.2,  -8.1,  -8. ,  -7.9,  -7.8,  -7.7,  -7.6,  -7.5,\n",
+       "         -7.4,  -7.3,  -7.2,  -7.1,  -7. ,  -6.9,  -6.8,  -6.7,  -6.6,\n",
+       "         -6.5,  -6.4,  -6.3,  -6.2,  -6.1,  -6. ,  -5.9,  -5.8,  -5.7,\n",
+       "         -5.6,  -5.5,  -5.4,  -5.3,  -5.2,  -5.1,  -5. ,  -4.9,  -4.8,\n",
+       "         -4.7,  -4.6,  -4.5,  -4.4,  -4.3,  -4.2,  -4.1,  -4. ,  -3.9,\n",
+       "         -3.8,  -3.7,  -3.6,  -3.5,  -3.4,  -3.3,  -3.2,  -3.1,  -3. ,\n",
+       "         -2.9,  -2.8,  -2.7,  -2.6,  -2.5,  -2.4,  -2.3,  -2.2,  -2.1,\n",
+       "         -2. ,  -1.9,  -1.8,  -1.7,  -1.6,  -1.5,  -1.4,  -1.3,  -1.2,\n",
+       "         -1.1,  -1. ,  -0.9,  -0.8,  -0.7,  -0.6,  -0.5,  -0.4,  -0.3,\n",
+       "         -0.2,  -0.1,   0. ,   0.1,   0.2,   0.3,   0.4,   0.5,   0.6,\n",
+       "          0.7,   0.8,   0.9,   1. ,   1.1,   1.2,   1.3,   1.4,   1.5,\n",
+       "          1.6,   1.7,   1.8,   1.9,   2. ,   2.1,   2.2,   2.3,   2.4,\n",
+       "          2.5,   2.6,   2.7,   2.8,   2.9,   3. ,   3.1,   3.2,   3.3,\n",
+       "          3.4,   3.5,   3.6,   3.7,   3.8,   3.9,   4. ,   4.1,   4.2,\n",
+       "          4.3,   4.4,   4.5,   4.6,   4.7,   4.8,   4.9,   5. ,   5.1,\n",
+       "          5.2,   5.3,   5.4,   5.5,   5.6,   5.7,   5.8,   5.9,   6. ,\n",
+       "          6.1,   6.2,   6.3,   6.4,   6.5,   6.6,   6.7,   6.8,   6.9,\n",
+       "          7. ,   7.1,   7.2,   7.3,   7.4,   7.5,   7.6,   7.7,   7.8,\n",
+       "          7.9,   8. ,   8.1,   8.2,   8.3,   8.4,   8.5,   8.6,   8.7,\n",
+       "          8.8,   8.9,   9. ,   9.1,   9.2,   9.3,   9.4,   9.5,   9.6,\n",
+       "          9.7,   9.8,   9.9,  10. ,  10.1,  10.2,  10.3,  10.4,  10.5,\n",
+       "         10.6,  10.7,  10.8,  10.9,  11. ,  11.1,  11.2,  11.3,  11.4,\n",
+       "         11.5,  11.6,  11.7,  11.8,  11.9,  12. ,  12.1,  12.2,  12.3,\n",
+       "         12.4,  12.5,  12.6,  12.7,  12.8,  12.9,  13. ,  13.1,  13.2,\n",
+       "         13.3,  13.4,  13.5,  13.6,  13.7,  13.8,  13.9,  14. ,  14.1,\n",
+       "         14.2,  14.3,  14.4,  14.5,  14.6,  14.7,  14.8,  14.9,  15. ,\n",
+       "         15.1,  15.2,  15.3,  15.4,  15.5,  15.6,  15.7,  15.8,  15.9,\n",
+       "         16. ,  16.1,  16.2,  16.3,  16.4,  16.5,  16.6,  16.7,  16.8,\n",
+       "         16.9,  17. ,  17.1,  17.2,  17.3,  17.4,  17.5,  17.6,  17.7,\n",
+       "         17.8,  17.9,  18. ,  18.1,  18.2,  18.3,  18.4,  18.5,  18.6,\n",
+       "         18.7,  18.8,  18.9,  19. ,  19.1,  19.2,  19.3,  19.4,  19.5,\n",
+       "         19.6,  19.7,  19.8,  19.9])}"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
     }
    ],
    "source": [
@@ -431,21 +514,25 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 10,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
    "outputs": [
     {
-     "ename": "NameError",
-     "evalue": "name 'data' is not defined",
+     "ename": "TypeError",
+     "evalue": "sequence item 0: expected str instance, bool found",
      "output_type": "error",
      "traceback": [
       "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# live-updating plot, that syncs the data and stops updating when it's finished\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# plot = qc.MatPlot(data.amplitude)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mplotQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
-      "\u001b[1;31mNameError\u001b[0m: name 'data' is not defined"
+      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# live-updating plot, that syncs the data and stops updating when it's finished\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# plot = qc.MatPlot(data.amplitude)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mplotQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, figsize, interval, windowTitle, theme, *args, **kwargs)\u001b[0m\n\u001b[0;32m     53\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     54\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0margs\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 55\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     56\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     57\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_init_qt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\base.py\u001b[0m in \u001b[0;36madd\u001b[1;34m(self, updater, *args, **kwargs)\u001b[0m\n\u001b[0;32m     48\u001b[0m         '''\n\u001b[0;32m     49\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexpand_trace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 50\u001b[1;33m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_to_plot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     51\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_updater\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mupdater\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     52\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36madd_to_plot\u001b[1;34m(self, subplot, **kwargs)\u001b[0m\n\u001b[0;32m    102\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    103\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mprev_default_title\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwindowTitle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 104\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetWindowTitle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_default_title\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    106\u001b[0m     def _draw_plot(self, subplot_object, y, x=None, color=None, width=None,\n",
+      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\base.py\u001b[0m in \u001b[0;36mget_default_title\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m     91\u001b[0m                     \u001b[1;32mif\u001b[0m \u001b[0mlocation\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mtitle_parts\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     92\u001b[0m                         \u001b[0mtitle_parts\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlocation\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 93\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[1;34m', '\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtitle_parts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     94\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     95\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mget_label\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata_array\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mTypeError\u001b[0m: sequence item 0: expected str instance, bool found"
      ]
     }
    ],
@@ -457,21 +544,22 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 11,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
    "outputs": [
     {
-     "ename": "TypeError",
-     "evalue": "'RemoteMethod' object is not subscriptable",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m data2 = qc.Loop(c1[-15:15:1], 0.1).loop(c0[-15:12:.5], 0.01).each(\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# first measurement, at c2=0 -> amplitude_0 bcs it's action 0\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# action 1 -> c2.set(1)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mWait\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m0.001\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;31m# second measurement, at c2=1 -> amplitude_4 bcs it's action 4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
+      "   amplitude_3: amplitude\n",
+      "   chan0: chan0\n",
+      "   chan1: chan1\n",
+      "   amplitude_0: amplitude\n",
+      "started at 2016-04-18 14:36:09\n"
      ]
     }
    ],
@@ -495,20 +583,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 13,
    "metadata": {
     "collapsed": false
    },
    "outputs": [
     {
-     "ename": "TypeError",
-     "evalue": "'RemoteMethod' object is not subscriptable",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m data3 = qc.Loop(c1[-15:15:1], 0.1).each(\n\u001b[0m\u001b[0;32m      2\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc0\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m-\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mTask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mc2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[1;31m# a 1D measurement\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "   amplitude_5_0: amplitude\n",
+      "   chan0: chan0\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude_3_0: amplitude\n",
+      "   amplitude_2: amplitude\n",
+      "started at 2016-04-18 14:36:38\n"
      ]
     }
    ],

From 4b769b5b770e690408a0e4b14cf90bd247be5e74 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 14:50:14 +0200
Subject: [PATCH 012/169] Adding parameters to the _get_method_attrs thing

---
 qcodes/instrument/base.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index c34208a40926..38dbc3fc2bf5 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -5,7 +5,7 @@
 from qcodes.utils.helpers import DelegateAttributes, strip_attrs
 from .parameter import Parameter, StandardParameter
 from .function import Function
-from .remote import RemoteInstrument
+from .remote import RemoteInstrument, RemoteParameter
 
 
 class NoDefault:
@@ -421,7 +421,10 @@ def _get_method_attrs(self):
 
         for attr in dir(self):
             value = getattr(self, attr)
-            if (not callable(value)) or isinstance(value, Function):
+            if (not callable(value)) or isinstance(value, (Function,
+                                                           Parameter,
+                                                           StandardParameter,
+                                                           RemoteParameter)):
                 # Functions are callable, and they show up in dir(),
                 # but we don't want them included in methods, they have
                 # their own listing. But we don't want to just exclude

From 40b94f210621879f6bed64717aa6c3a7f07a0189 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 15:41:27 +0200
Subject: [PATCH 013/169] Notebook update

---
 .../Qcodes example parameter call.ipynb       | 50 +++++++++++--------
 1 file changed, 30 insertions(+), 20 deletions(-)

diff --git a/docs/examples/Qcodes example parameter call.ipynb b/docs/examples/Qcodes example parameter call.ipynb
index 1c89311b7bf2..0c1d9a7737c0 100644
--- a/docs/examples/Qcodes example parameter call.ipynb	
+++ b/docs/examples/Qcodes example parameter call.ipynb	
@@ -514,7 +514,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 9,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -527,7 +527,7 @@
      "traceback": [
       "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# live-updating plot, that syncs the data and stops updating when it's finished\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# plot = qc.MatPlot(data.amplitude)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mplotQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# live-updating plot, that syncs the data and stops updating when it's finished\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# plot = qc.MatPlot(data.amplitude)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mplotQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
       "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, figsize, interval, windowTitle, theme, *args, **kwargs)\u001b[0m\n\u001b[0;32m     53\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     54\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0margs\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 55\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     56\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     57\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_init_qt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\base.py\u001b[0m in \u001b[0;36madd\u001b[1;34m(self, updater, *args, **kwargs)\u001b[0m\n\u001b[0;32m     48\u001b[0m         '''\n\u001b[0;32m     49\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexpand_trace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 50\u001b[1;33m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_to_plot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     51\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_updater\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mupdater\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     52\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36madd_to_plot\u001b[1;34m(self, subplot, **kwargs)\u001b[0m\n\u001b[0;32m    102\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    103\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mprev_default_title\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwindowTitle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 104\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetWindowTitle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_default_title\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    106\u001b[0m     def _draw_plot(self, subplot_object, y, x=None, color=None, width=None,\n",
@@ -544,7 +544,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 10,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -556,10 +556,10 @@
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
       "   amplitude_3: amplitude\n",
-      "   chan0: chan0\n",
-      "   chan1: chan1\n",
       "   amplitude_0: amplitude\n",
-      "started at 2016-04-18 14:36:09\n"
+      "   chan1: chan1\n",
+      "   chan0: chan0\n",
+      "started at 2016-04-18 14:56:45\n"
      ]
     }
    ],
@@ -583,7 +583,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 12,
    "metadata": {
     "collapsed": false
    },
@@ -593,14 +593,14 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
-      "   amplitude_5_0: amplitude\n",
-      "   chan0: chan0\n",
+      "   amplitude_3_0: amplitude\n",
       "   avg_amplitude: avg_amplitude\n",
       "   chan2: chan2\n",
       "   chan1: chan1\n",
-      "   amplitude_3_0: amplitude\n",
+      "   amplitude_5_0: amplitude\n",
+      "   chan0: chan0\n",
       "   amplitude_2: amplitude\n",
-      "started at 2016-04-18 14:36:38\n"
+      "started at 2016-04-18 15:40:28\n"
      ]
     }
    ],
@@ -629,21 +629,22 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 24,
+   "execution_count": 14,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
    "outputs": [
     {
-     "ename": "TypeError",
-     "evalue": "'RemoteMethod' object is not subscriptable",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# An example of a parameter that returns several values of different dimension\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# This produces the last two arrays from data3, but only takes the data once.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n\u001b[0m\u001b[0;32m      4\u001b[0m     \u001b[0mAverageAndRaw\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmeter\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mc2\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m-\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;36m0.2\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m0.001\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m ).run(location='test_complex_param', overwrite=True)\n",
-      "\u001b[1;31mTypeError\u001b[0m: 'RemoteMethod' object is not subscriptable"
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan2: chan2\n",
+      "   chan1: chan1\n",
+      "   amplitude: amplitude\n",
+      "started at 2016-04-18 15:40:51\n"
      ]
     }
    ],
@@ -660,6 +661,15 @@
     "plot4Q.add(data4.avg_amplitude, subplot=2)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
+  },
   {
    "cell_type": "code",
    "execution_count": null,

From f6f8c37241ec998ac44fca2c097625d269d594c9 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 18 Apr 2016 16:09:22 +0200
Subject: [PATCH 014/169] More flexibility here

---
 qcodes/instrument/base.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index 38dbc3fc2bf5..064ce6884e02 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -421,10 +421,9 @@ def _get_method_attrs(self):
 
         for attr in dir(self):
             value = getattr(self, attr)
-            if (not callable(value)) or isinstance(value, (Function,
-                                                           Parameter,
-                                                           StandardParameter,
-                                                           RemoteParameter)):
+            if ((not callable(value)) or
+                    value is self.parameters.get(attr) or
+                    value is self.functions.get(attr)):
                 # Functions are callable, and they show up in dir(),
                 # but we don't want them included in methods, they have
                 # their own listing. But we don't want to just exclude

From adfb731b5cbd2f29ecc8a752185bcd41a9070900 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 18 Apr 2016 23:24:40 +0200
Subject: [PATCH 015/169] _normalize_slashes fix for abs paths

---
 qcodes/data/io.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/qcodes/data/io.py b/qcodes/data/io.py
index ea3cf9dc3fe2..3c8c67aa1321 100644
--- a/qcodes/data/io.py
+++ b/qcodes/data/io.py
@@ -84,7 +84,10 @@ def open(self, filename, mode):
             yield f
 
     def _normalize_slashes(self, location):
-        return os.path.join(*re.split('[\\\\/]', location))
+        # note that this is NOT os.path.join - the difference is os.path.join
+        # discards empty strings, so if you use it on a re.split absolute
+        # path you will get a relative path!
+        return os.sep.join(re.split('[\\\\/]', location))
 
     def _add_base(self, location):
         location = self._normalize_slashes(location)

From d5940c78969394041e6854879057804a2f38708b Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 19 Apr 2016 13:16:05 +0200
Subject: [PATCH 016/169] add __version__ tag to package

---
 qcodes/__init__.py             |  1 +
 qcodes/instrument/parameter.py |  2 +-
 setup.py                       | 22 ++++++++++++++++++++--
 3 files changed, 22 insertions(+), 3 deletions(-)

diff --git a/qcodes/__init__.py b/qcodes/__init__.py
index 71920e94d0f6..32ca3c455e3b 100644
--- a/qcodes/__init__.py
+++ b/qcodes/__init__.py
@@ -5,6 +5,7 @@
 # separately import multiprocessing
 from multiprocessing import active_children
 
+from qcodes.version import __version__
 from qcodes.utils.multiprocessing import set_mp_method
 from qcodes.utils.helpers import in_notebook
 
diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 9a94c6536bef..ecd069310e7f 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -337,7 +337,7 @@ def __init__(self, name, instrument=None,
                 set_parser = self._set_mapping.__getitem__
 
         if get_parser is not None and not isinstance(get_cmd, str):
-            logging.warning('get_parser is set, but will not be used')
+            logging.warning('get_parser is set, but will not be used (name %s)' % name)
         super().__init__(name=name, vals=vals, **kwargs)
 
         self._instrument = instrument
diff --git a/setup.py b/setup.py
index 0079a6e9e3c1..954abc05d78e 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,23 @@
 from setuptools import setup, find_packages
 from distutils.version import StrictVersion
 from importlib import import_module
+import re
+
+def get_version(verbose=0):
+    """ Extract version information from source code """
+
+    try:
+        with open('qcodes/version.py', 'r') as f:
+            ln = f.readline()
+            # print(ln)
+            m = re.search('.* ''(.*)''', ln)
+            version = (m.group(1))
+    except Exception as E:
+        print(E)
+        version = 'none'
+    if verbose:
+        print('get_version: %s' % version)
+    return version
 
 
 def readme():
@@ -15,7 +32,7 @@ def readme():
 extras_require = {k: '>='.join(v) for k, v in extras.items()}
 
 setup(name='qcodes',
-      version='0.1.0',
+      version=get_version(),
       use_2to3=False,
       author='Alex Johnson',
       author_email='johnson.alex.c@gmail.com',
@@ -91,4 +108,5 @@ def readme():
     except ImportError:
         print(missing_template.format(module_name, extra))
     except ValueError:
-        print(valueerror_template.format(module_name, module.__version__, min_version, extra))
+        print(valueerror_template.format(
+            module_name, module.__version__, min_version, extra))

From ec51408ec40a9be520599d09f5634849b134b834 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 19 Apr 2016 14:39:42 +0200
Subject: [PATCH 017/169] added missing file

---
 qcodes/version.py | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 qcodes/version.py

diff --git a/qcodes/version.py b/qcodes/version.py
new file mode 100644
index 000000000000..b794fd409a5e
--- /dev/null
+++ b/qcodes/version.py
@@ -0,0 +1 @@
+__version__ = '0.1.0'

From 4b3223f5ac3af1b3e600beee747d120d71b24f93 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 19 Apr 2016 17:04:38 +0200
Subject: [PATCH 018/169] instrument constructor docs

---
 qcodes/instrument/base.py | 18 ++++++++++++------
 qcodes/instrument/mock.py |  5 ++++-
 2 files changed, 16 insertions(+), 7 deletions(-)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index e5b591927bec..75aaf28a70e1 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -3,7 +3,7 @@
 
 from qcodes.utils.metadata import Metadatable
 from qcodes.utils.helpers import DelegateAttributes, strip_attrs
-from .parameter import Parameter, StandardParameter
+from .parameter import StandardParameter
 from .function import Function
 from .remote import RemoteInstrument
 
@@ -28,6 +28,8 @@ class Instrument(Metadatable, DelegateAttributes):
         `default_server_name`, passing in all the constructor kwargs, to
         determine the name. If not overridden, this is just 'Instruments'.
 
+        ** see notes below about `server_name` in SUBCLASS CONSTRUCTORS **
+
         Use None to operate without a server - but then this Instrument
         will not work with qcodes Loops or other multiprocess procedures.
 
@@ -46,12 +48,16 @@ class Instrument(Metadatable, DelegateAttributes):
     `shared_kwargs` class attribute to a list of kwarg names that should
     be treated this way.
 
-    shared_kwargs must be provided ONLY as kwargs when constructing
-    instruments that need them, you CANNOT provide them as positional args.
+    It is an error to initialize two instruments on the same server with
+    different keys or values for `shared_kwargs`, unless the later
+    instruments have NO shared_kwargs at all.
 
-    It is an error to initialize two instruments on
-    the same server with different keys or values for these kwargs, unless
-    the later instruments have NO shared_kwargs at all.
+    SUBCLASS CONSTRUCTORS: `server_name` and any `shared_kwargs` must be
+    available as kwargs and kwargs ONLY (not positional) in all subclasses,
+    and not modified in the inheritance chain. This is because we need to
+    create the server before instantiating the actual instrument. The easiest
+    way to manage this is to accept **kwargs in your subclass and pass them
+    on to super().__init()
     '''
     shared_kwargs = []
 
diff --git a/qcodes/instrument/mock.py b/qcodes/instrument/mock.py
index ec73231c0635..0d8699df8063 100644
--- a/qcodes/instrument/mock.py
+++ b/qcodes/instrument/mock.py
@@ -14,7 +14,10 @@ class MockInstrument(Instrument):
     delay: the time (in seconds) to wait after any operation
         to simulate communication delay
     model: a MockModel object to connect this MockInstrument to.
-        should have one or two methods related directly to this instrument:
+        Subclasses MUST accept `model` as a constructor kwarg ONLY, even
+        though it is required. See notes in `Instrument` docstring.
+        A model should have one or two methods related directly to this
+        instrument:
         _set(param, value) -> set a parameter on the model
         _get(param) -> returns the value
     keep_history: record (in self.history) every command sent to this

From 6359d540046845c8fd6518333215a7addcaec76d Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 19 Apr 2016 17:17:36 +0200
Subject: [PATCH 019/169] added initial FAQ

---
 README.md   |  2 ++
 docs/FAQ.md | 17 +++++++++++++++++
 2 files changed, 19 insertions(+)
 create mode 100644 docs/FAQ.md

diff --git a/README.md b/README.md
index 69bdcf1594d6..33d6c607c02b 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,8 @@ if qcpath not in sys.path:
     sys.path.append(qcpath)
 ```
 
+For frequently asked questions see the [Qcodes FAQ](docs/FAQ.md).
+
 ## Contributing
 
 See [Contributing](CONTRIBUTING.md) for information about bug/issue reports, contributing code, style, and testing
diff --git a/docs/FAQ.md b/docs/FAQ.md
new file mode 100644
index 000000000000..803e5957c0db
--- /dev/null
+++ b/docs/FAQ.md
@@ -0,0 +1,17 @@
+# QCodes FAQ
+
+This FAQ is intended for users for Qcodes. For development, see Github.
+
+## Installation
+
+### How to install Qcodes?
+
+...
+## Usage
+
+### How to abort a running measurement?
+
+Use `qc.halt_bg()`. To list the active measurements use `qc.active_children()`
+
+
+

From c3cbe2256d27ef34437318c392be5d619440beff Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 19 Apr 2016 22:13:33 +0200
Subject: [PATCH 020/169] fix toymodel typo

---
 docs/examples/toymodel.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/docs/examples/toymodel.py b/docs/examples/toymodel.py
index bccbeaae2dc2..2731171d07f8 100644
--- a/docs/examples/toymodel.py
+++ b/docs/examples/toymodel.py
@@ -40,7 +40,7 @@ def gates_set(self, parameter, value):
 
     def gates_get(self, parameter):
         if parameter[0] == 'c':
-            return self.fmt(self.gates[int(parameter[1:])])
+            return self.fmt(self._gates[int(parameter[1:])])
         else:
             raise ValueError
 

From 94bbdfdd026a32616047afa36695a350a889d174 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 19 Apr 2016 22:51:26 +0200
Subject: [PATCH 021/169] default datamode is local

---
 qcodes/data/data_set.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 21f3da8d4498..e07ae4278806 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -181,7 +181,7 @@ class DataSet(DelegateAttributes):
     default_formatter = GNUPlotFormat()
     location_provider = TimestampLocation()
 
-    def __init__(self, location=None, mode=None, arrays=None,
+    def __init__(self, location=None, mode=DataMode.LOCAL, arrays=None,
                  data_manager=None, formatter=None, io=None):
         if location is False or isinstance(location, str):
             self.location = location

From f78a7070ddc6b8911f3682853fdad4101327740e Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 19 Apr 2016 23:09:03 +0200
Subject: [PATCH 022/169] use load_data in old data example nb anyway

---
 docs/examples/Load-and-plot-old-data.ipynb | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/docs/examples/Load-and-plot-old-data.ipynb b/docs/examples/Load-and-plot-old-data.ipynb
index f125d5e0cce4..d41c484dd2de 100644
--- a/docs/examples/Load-and-plot-old-data.ipynb
+++ b/docs/examples/Load-and-plot-old-data.ipynb
@@ -234,7 +234,7 @@
        "    min-height: 50px;\n",
        "    max-height: 400px;\n",
        "    min-width: 400px;\n",
-       "    max-width: 700px;\n",
+       "    max-width: 1000px;\n",
        "}"
       ],
       "text/plain": [
@@ -248,8 +248,8 @@
      "data": {
       "text/plain": [
        "DataSet: DataMode.LOCAL, location='testsweep'\n",
-       "   amplitude: None\n",
-       "   chan0: None"
+       "   chan0: None\n",
+       "   amplitude: None"
       ]
      },
      "execution_count": 1,
@@ -260,7 +260,7 @@
    "source": [
     "%matplotlib nbagg\n",
     "import qcodes as qc\n",
-    "data = qc.DataSet('testsweep')\n",
+    "data = qc.load_data('testsweep')\n",
     "data"
    ]
   },
@@ -1050,7 +1050,7 @@
     {
      "data": {
       "text/plain": [
-       ""
+       ""
       ]
      },
      "execution_count": 2,

From 5ddfe8f8ce2a49d3c3cf2700ba2755a6704ea44d Mon Sep 17 00:00:00 2001
From: Merlin 
Date: Wed, 20 Apr 2016 00:16:59 +0200
Subject: [PATCH 023/169] Fixes passing of snapshot arguments

Fixes station.snapshot(update=True)
---
 qcodes/station.py        | 4 ++--
 qcodes/utils/metadata.py | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/qcodes/station.py b/qcodes/station.py
index 4621f19a98ea..ba5a5f500e24 100644
--- a/qcodes/station.py
+++ b/qcodes/station.py
@@ -31,8 +31,8 @@ def __init__(self, *instruments, monitor=None, default=True, **kwargs):
 
         self.monitor = monitor
 
-    def snapshot_base(self):
-        return {'instruments': {name: ins.snapshot()
+    def snapshot_base(self, *args, **kwargs):
+        return {'instruments': {name: ins.snapshot(*args, **kwargs)
                                 for name, ins in self.instruments.items()}}
 
     def add_instrument(self, instrument, name=None):
diff --git a/qcodes/utils/metadata.py b/qcodes/utils/metadata.py
index d2f3fcdd78f7..231d24c63417 100644
--- a/qcodes/utils/metadata.py
+++ b/qcodes/utils/metadata.py
@@ -20,7 +20,7 @@ def snapshot(self, *args, **kwargs):
 
         return snap
 
-    def snapshot_base(self):
+    def snapshot_base(self, *ignore_args, **ignore_kwargs):
         '''
         override this with the primary information for a subclass
         '''

From a60de92332fb93fecd82aa19b69923059722395f Mon Sep 17 00:00:00 2001
From: Merlin 
Date: Wed, 20 Apr 2016 00:22:43 +0200
Subject: [PATCH 024/169] added use of update into notebook for illustration

---
 docs/examples/Qcodes example.ipynb | 149 +++++++++++++++++++++--------
 1 file changed, 108 insertions(+), 41 deletions(-)

diff --git a/docs/examples/Qcodes example.ipynb b/docs/examples/Qcodes example.ipynb
index 72e32516e913..3de9650b4001 100644
--- a/docs/examples/Qcodes example.ipynb	
+++ b/docs/examples/Qcodes example.ipynb	
@@ -308,7 +308,14 @@
     {
      "data": {
       "text/plain": [
-       "[0.117]"
+       "{'instruments': {'gates': {'functions': {'reset': {}},\n",
+       "   'parameters': {'chan0': {'ts': None, 'value': None},\n",
+       "    'chan1': {'ts': None, 'value': None},\n",
+       "    'chan2': {'ts': None, 'value': None}}},\n",
+       "  'meter': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': None, 'value': None}}},\n",
+       "  'source': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': None, 'value': None}}}}}"
       ]
      },
      "execution_count": 3,
@@ -316,6 +323,57 @@
      "output_type": "execute_result"
     }
    ],
+   "source": [
+    "station.snapshot()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'instruments': {'gates': {'functions': {'reset': {}},\n",
+       "   'parameters': {'chan0': {'ts': '2016-04-20 00:19:23', 'value': 0.0},\n",
+       "    'chan1': {'ts': '2016-04-20 00:19:23', 'value': 0.0},\n",
+       "    'chan2': {'ts': '2016-04-20 00:19:23', 'value': 0.0}}},\n",
+       "  'meter': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': '2016-04-20 00:19:23', 'value': 0.117}}},\n",
+       "  'source': {'functions': {},\n",
+       "   'parameters': {'amplitude': {'ts': '2016-04-20 00:19:23', 'value': 0.1}}}}}"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "station.snapshot(update=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0.117]"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "# we can get the measured quantities right now\n",
     "station.measure()"
@@ -323,7 +381,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 6,
    "metadata": {
     "collapsed": false
    },
@@ -333,9 +391,9 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
-      "   amplitude: amplitude\n",
       "   chan0: chan0\n",
-      "started at 2016-04-13 15:23:05\n"
+      "   amplitude: amplitude\n",
+      "started at 2016-04-20 00:19:28\n"
      ]
     }
    ],
@@ -357,7 +415,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 8,
    "metadata": {
     "collapsed": false,
     "scrolled": true
@@ -377,16 +435,16 @@
        "         0.007,  0.008,  0.008,  0.008,  0.009,  0.009,  0.01 ,  0.01 ,\n",
        "         0.01 ,  0.011,  0.011,  0.012,  0.013,  0.013,  0.014,  0.015,\n",
        "         0.016,  0.017,  0.018,  0.019,  0.02 ,  0.022,  0.023,  0.025,\n",
-       "         0.027,  0.029,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
+       "         0.027,  0.029,  0.031,  0.034,  0.037,  0.04 ,  0.044,  0.048,\n",
+       "         0.053,  0.058,  0.064,  0.071,  0.077,  0.085,  0.092,  0.099,\n",
+       "         0.106,  0.111,  0.115,  0.117,  0.117,  0.117,  0.115,  0.111,\n",
+       "         0.106,  0.099,  0.092,  0.085,  0.077,  0.071,  0.064,  0.058,\n",
+       "         0.053,  0.048,  0.044,  0.04 ,  0.037,  0.034,  0.031,  0.029,\n",
+       "         0.027,  0.025,  0.023,  0.022,  0.02 ,  0.019,  0.018,  0.017,\n",
+       "         0.016,  0.015,  0.014,  0.013,  0.013,  0.012,  0.011,  0.011,\n",
+       "         0.01 ,  0.01 ,  0.01 ,  0.009,  0.009,  0.008,  0.008,  0.008,\n",
+       "         0.007,  0.007,  0.007,  0.007,  0.006,  0.006,  0.006,  0.006,\n",
+       "         0.006,  0.007,  0.007,    nan,    nan,    nan,    nan,    nan,\n",
        "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
        "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
        "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
@@ -427,15 +485,15 @@
        "        -14.6, -14.5, -14.4, -14.3, -14.2, -14.1, -14. , -13.9, -13.8,\n",
        "        -13.7, -13.6, -13.5, -13.4, -13.3, -13.2, -13.1, -13. , -12.9,\n",
        "        -12.8, -12.7, -12.6, -12.5, -12.4, -12.3, -12.2, -12.1, -12. ,\n",
-       "        -11.9, -11.8,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
+       "        -11.9, -11.8, -11.7, -11.6, -11.5, -11.4, -11.3, -11.2, -11.1,\n",
+       "        -11. , -10.9, -10.8, -10.7, -10.6, -10.5, -10.4, -10.3, -10.2,\n",
+       "        -10.1, -10. ,  -9.9,  -9.8,  -9.7,  -9.6,  -9.5,  -9.4,  -9.3,\n",
+       "         -9.2,  -9.1,  -9. ,  -8.9,  -8.8,  -8.7,  -8.6,  -8.5,  -8.4,\n",
+       "         -8.3,  -8.2,  -8.1,  -8. ,  -7.9,  -7.8,  -7.7,  -7.6,  -7.5,\n",
+       "         -7.4,  -7.3,  -7.2,  -7.1,  -7. ,  -6.9,  -6.8,  -6.7,  -6.6,\n",
+       "         -6.5,  -6.4,  -6.3,  -6.2,  -6.1,  -6. ,  -5.9,  -5.8,  -5.7,\n",
+       "         -5.6,  -5.5,  -5.4,  -5.3,  -5.2,  -5.1,  -5. ,  -4.9,  -4.8,\n",
+       "         -4.7,  -4.6,  -4.5,   nan,   nan,   nan,   nan,   nan,   nan,\n",
        "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
        "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
        "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
@@ -465,7 +523,7 @@
        "          nan,   nan,   nan,   nan])}"
       ]
      },
-     "execution_count": 5,
+     "execution_count": 8,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -478,7 +536,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 9,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -492,7 +550,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 10,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -503,11 +561,11 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
-      "   chan1: chan1\n",
       "   amplitude_3: amplitude\n",
-      "   chan0: chan0\n",
       "   amplitude_0: amplitude\n",
-      "started at 2016-04-13 15:23:28\n"
+      "   chan0: chan0\n",
+      "   chan1: chan1\n",
+      "started at 2016-04-20 00:19:58\n"
      ]
     }
    ],
@@ -531,7 +589,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 12,
    "metadata": {
     "collapsed": false
    },
@@ -541,14 +599,14 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
-      "   avg_amplitude: avg_amplitude\n",
-      "   chan2: chan2\n",
-      "   chan0: chan0\n",
       "   amplitude_2: amplitude\n",
+      "   chan0: chan0\n",
+      "   chan2: chan2\n",
       "   chan1: chan1\n",
-      "   amplitude_3_0: amplitude\n",
+      "   avg_amplitude: avg_amplitude\n",
       "   amplitude_5_0: amplitude\n",
-      "started at 2016-04-13 15:24:20\n"
+      "   amplitude_3_0: amplitude\n",
+      "started at 2016-04-20 00:20:54\n"
      ]
     }
    ],
@@ -577,7 +635,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": 13,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -589,10 +647,10 @@
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
       "   avg_amplitude: avg_amplitude\n",
-      "   chan2: chan2\n",
-      "   chan1: chan1\n",
       "   amplitude: amplitude\n",
-      "started at 2016-02-02 12:18:09\n"
+      "   chan1: chan1\n",
+      "   chan2: chan2\n",
+      "started at 2016-04-20 00:21:35\n"
      ]
     }
    ],
@@ -608,6 +666,15 @@
     "plot4Q = qc.QtPlot(data4.amplitude, figsize=(1200, 500))\n",
     "plot4Q.add(data4.avg_amplitude, subplot=2)"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": []
   }
  ],
  "metadata": {
@@ -626,7 +693,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.5.0"
+   "version": "3.5.1"
   }
  },
  "nbformat": 4,

From efdc69d8a9669b1a9780ea4f319b5a64379c307e Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 20 Apr 2016 10:22:32 +0200
Subject: [PATCH 025/169] more in load_data notebook, and prevent DataServer
 starting unnecessarily

---
 docs/examples/Load-and-plot-old-data.ipynb | 53 +++++++++++++++++++++-
 qcodes/data/data_set.py                    |  6 +--
 2 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/docs/examples/Load-and-plot-old-data.ipynb b/docs/examples/Load-and-plot-old-data.ipynb
index d41c484dd2de..4c8218d0efd2 100644
--- a/docs/examples/Load-and-plot-old-data.ipynb
+++ b/docs/examples/Load-and-plot-old-data.ipynb
@@ -1,5 +1,30 @@
 {
  "cells": [
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "# Loading data for analysis: the `load_data` function.\n",
+    "\n",
+    "`DataSet` objects are not intended to be instantiated directly, but\n",
+    "rather through the helper functions:\n",
+    "- `load_data` for existing data sets, including the data currently\n",
+    "  being acquired.\n",
+    "- `new_data` to make an empty data set to be populated with new\n",
+    "  measurements or simulation data. `new_data` is called internally by\n",
+    "  `Loop.run()` so is also generally not needed directly.\n",
+    "\n",
+    "If you omit `location`, or if `location` matches the data set currently\n",
+    "being acquired, `load_data` and subsequent calls to `data_set.sync()`\n",
+    "will pull from the `DataServer` (`DataMode.PULL_FROM_SERVER`).\n",
+    "Otherwise `load_data` and `data_set.sync()` will read from disk\n",
+    "(`DataMode.LOCAL`).\n",
+    "\n",
+    "Note that a `DataServer` is, at least for now, local to one parent\n",
+    "process / notebook, so if you open a separate notebook for analysis, even\n",
+    "your live data will be pulled from disk."
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": 1,
@@ -1050,7 +1075,7 @@
     {
      "data": {
       "text/plain": [
-       ""
+       ""
       ]
      },
      "execution_count": 2,
@@ -1062,6 +1087,32 @@
     "qc.MatPlot(data.amplitude)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "ename": "RuntimeError",
+     "evalue": "DataManager has no live data",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
+      "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mlive_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mload_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m  \u001b[0;31m# this will be an error because there is no live data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      2\u001b[0m \u001b[0mlive_data\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;32m/Users/alex/qdev/Qcodes/qcodes/data/data_set.py\u001b[0m in \u001b[0;36mload_data\u001b[0;34m(location, data_manager, formatter, io)\u001b[0m\n\u001b[1;32m     85\u001b[0m                                'not exist or was requested not to be used')\n\u001b[1;32m     86\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 87\u001b[0;31m         \u001b[0;32mreturn\u001b[0m \u001b[0m_get_live_data\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdata_manager\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m     88\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m     89\u001b[0m     elif (data_manager and\n",
+      "\u001b[0;32m/Users/alex/qdev/Qcodes/qcodes/data/data_set.py\u001b[0m in \u001b[0;36m_get_live_data\u001b[0;34m(data_manager)\u001b[0m\n\u001b[1;32m     99\u001b[0m     \u001b[0mlive_data\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mdata_manager\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mask\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'get_data'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    100\u001b[0m     \u001b[0;32mif\u001b[0m \u001b[0mlive_data\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlive_data\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mNoData\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 101\u001b[0;31m         \u001b[0;32mraise\u001b[0m \u001b[0mRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'DataManager has no live data'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    102\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    103\u001b[0m     \u001b[0mlive_data\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmode\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mDataMode\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mPULL_FROM_SERVER\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
+      "\u001b[0;31mRuntimeError\u001b[0m: DataManager has no live data"
+     ]
+    }
+   ],
+   "source": [
+    "live_data = qc.load_data()  # this will be an error because there is no live data\n",
+    "live_data"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": null,
diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index e07ae4278806..0ab37c9ff56e 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -1,7 +1,7 @@
 from enum import Enum
 from datetime import datetime
 
-from .manager import get_data_manager
+from .manager import get_data_manager, NoData
 from .format import GNUPlotFormat
 from .io import DiskIO
 from qcodes.utils.helpers import DelegateAttributes
@@ -97,7 +97,7 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
 def _get_live_data(data_manager):
     live_data = data_manager.ask('get_data')
-    if live_data is None:
+    if live_data is None or isinstance(live_data, NoData):
         raise RuntimeError('DataManager has no live data')
 
     live_data.mode = DataMode.PULL_FROM_SERVER
@@ -199,7 +199,7 @@ def __init__(self, location=None, mode=DataMode.LOCAL, arrays=None,
             for array in arrays:
                 self.add_array(array)
 
-        if data_manager is None:
+        if data_manager is None and mode in SERVER_MODES:
             data_manager = get_data_manager()
 
         if mode == DataMode.LOCAL:

From a7dbea232a743c7a316d3d57df636954cb40e217 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 20 Apr 2016 10:49:08 +0200
Subject: [PATCH 026/169] address some lingering test failures from previous
 changes

---
 qcodes/instrument/base.py        | 11 +++++++----
 qcodes/tests/instrument_mocks.py | 12 ++++++------
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index e5b591927bec..e731a8e4dc99 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -221,10 +221,13 @@ def delattr(self, attr, prune=True):
                     delattr(self, attr[0])
 
     def __del__(self):
-        wr = weakref.ref(self)
-        if wr in getattr(self, '_instances', {}):
-            self._instances.remove(wr)
-        self.close()
+        try:
+            wr = weakref.ref(self)
+            if wr in getattr(self, '_instances', {}):
+                self._instances.remove(wr)
+            self.close()
+        except:
+            pass
 
     def close(self):
         '''
diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py
index 214d9f3ffdca..48527ce29499 100644
--- a/qcodes/tests/instrument_mocks.py
+++ b/qcodes/tests/instrument_mocks.py
@@ -95,6 +95,8 @@ def add5(self, b):
 
 class MockGates(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('gates', model=model, delay=0.001, **kwargs)
+
         for i in range(3):
             cmdbase = 'c{}'.format(i)
             self.add_parameter('chan{}'.format(i), get_cmd=cmdbase + '?',
@@ -123,8 +125,6 @@ def __init__(self, model=None, **kwargs):
 
         self.add_function('reset', call_cmd='rst')
 
-        super().__init__('gates', model=model, delay=0.001, **kwargs)
-
     def slow_neg_set(self, val):
         if val < 0:
             time.sleep(0.05)
@@ -133,18 +133,18 @@ def slow_neg_set(self, val):
 
 class MockSource(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('source', model=model, delay=0.001, **kwargs)
+
         self.add_parameter('amplitude', get_cmd='ampl?',
                            set_cmd='ampl:{:.4f}', get_parser=float,
                            vals=Numbers(0, 1),
                            sweep_step=0.2, sweep_delay=0.005)
 
-        super().__init__('source', model=model, delay=0.001, **kwargs)
-
 
 class MockMeter(MockInstTester):
     def __init__(self, model=None, **kwargs):
+        super().__init__('meter', model=model, delay=0.001, **kwargs)
+
         self.add_parameter('amplitude', get_cmd='ampl?', get_parser=float)
         self.add_function('echo', call_cmd='echo {:.2f}?',
                           args=[Numbers(0, 1000)], return_parser=float)
-
-        super().__init__('meter', model=model, delay=0.001, **kwargs)

From 757603258d907a7017b535c59756a7d89358f38d Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 20 Apr 2016 11:41:57 +0200
Subject: [PATCH 027/169] one more load_data edge case and some tests

---
 qcodes/data/data_set.py   |  4 ++++
 qcodes/tests/test_data.py | 30 ++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 0ab37c9ff56e..41b57a531553 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -86,6 +86,10 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
         return _get_live_data(data_manager)
 
+    elif location is False:
+        raise ValueError('location=False means a temporary DataSet, '
+                         'which is incompatible with load_data')
+
     elif (data_manager and
             location == data_manager.ask('get_data', 'location')):
         return _get_live_data(data_manager)
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 64ac7596576b..672827450d39 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -2,6 +2,10 @@
 import numpy as np
 
 from qcodes.data.data_array import DataArray
+from qcodes.data.manager import get_data_manager
+from qcodes.data.data_set import load_data
+from qcodes.utils.helpers import killprocesses
+from qcodes import active_children
 
 
 class TestDataArray(TestCase):
@@ -198,3 +202,29 @@ def test_data_set_property(self):
         self.assertIsNone(data.data_set)
         data.data_set = mock_data_set2
         self.assertEqual(data.data_set, mock_data_set2)
+
+
+class TestLoadData(TestCase):
+    def setUp(self):
+        killprocesses()
+
+    def test_no_live_data(self):
+        # live data with no DataManager at all
+        with self.assertRaises(RuntimeError):
+            load_data()
+        self.assertEqual(len(active_children()), 0)
+
+        # now make a DataManager and try again
+        get_data_manager()
+        self.assertEqual(len(active_children()), 1)
+        # same result but different code path
+        with self.assertRaises(RuntimeError):
+            load_data()
+
+    def test_no_saved_data(self):
+        with self.assertRaises(IOError):
+            load_data('_no/such/file_')
+
+    def test_load_false(self):
+        with self.assertRaises(ValueError):
+            load_data(False)

From 74516ea30ed01f4fdb69cc14dadd14418c917070 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 20 Apr 2016 12:20:09 +0200
Subject: [PATCH 028/169] fix plotting with location=False, and update nb that
 uses it

---
 .../Qcodes example parameter call.ipynb       | 305 +++++++++++++++---
 qcodes/plots/base.py                          |   2 +-
 2 files changed, 261 insertions(+), 46 deletions(-)

diff --git a/docs/examples/Qcodes example parameter call.ipynb b/docs/examples/Qcodes example parameter call.ipynb
index 4d2b151673ed..74ae997c59e2 100644
--- a/docs/examples/Qcodes example parameter call.ipynb	
+++ b/docs/examples/Qcodes example parameter call.ipynb	
@@ -2,11 +2,249 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 1,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\n",
+       " * Qcodes Jupyter/IPython widgets\n",
+       " */\n",
+       "require([\n",
+       "    'nbextensions/widgets/widgets/js/widget',\n",
+       "    'nbextensions/widgets/widgets/js/manager'\n",
+       "], function (widget, manager) {\n",
+       "\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\n",
+       "        render: function() {\n",
+       "            window.MYWIDGET = this;\n",
+       "            this._interval = 0;\n",
+       "            this.update();\n",
+       "        },\n",
+       "        update: function() {\n",
+       "            this.display(this.model.get('_message'));\n",
+       "            this.setInterval();\n",
+       "        },\n",
+       "        display: function(message) {\n",
+       "            /*\n",
+       "             * display method: override this for custom display logic\n",
+       "             */\n",
+       "            this.el.innerHTML = message;\n",
+       "        },\n",
+       "        remove: function() {\n",
+       "            clearInterval(this._updater);\n",
+       "        },\n",
+       "        setInterval: function(newInterval) {\n",
+       "            var me = this;\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\n",
+       "            if(newInterval===me._interval) return;\n",
+       "\n",
+       "            me._interval = newInterval;\n",
+       "\n",
+       "            if(me._updater) clearInterval(me._updater);\n",
+       "\n",
+       "            if(me._interval) {\n",
+       "                me._updater = setInterval(function() {\n",
+       "                    me.send({myupdate: true});\n",
+       "                    if(!me.model.comm_live) {\n",
+       "                        console.log('missing comm, canceling widget updates', me);\n",
+       "                        clearInterval(me._updater);\n",
+       "                    }\n",
+       "                }, me._interval * 1000);\n",
+       "            }\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\n",
+       "\n",
+       "    var HiddenUpdateView = UpdateView.extend({\n",
+       "        display: function(message) {\n",
+       "            this.$el.hide();\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\n",
+       "\n",
+       "    var SubprocessView = UpdateView.extend({\n",
+       "        render: function() {\n",
+       "            var me = window.SPVIEW = this;\n",
+       "            me._interval = 0;\n",
+       "            me._minimize = '';\n",
+       "            me._restore = '';\n",
+       "\n",
+       "            // in case there is already an outputView present,\n",
+       "            // like from before restarting the kernel\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\n",
+       "\n",
+       "            me.$el\n",
+       "                .addClass('qcodes-output-view')\n",
+       "                .attr('qcodes-state', 'docked')\n",
+       "                .html(\n",
+       "                    '
' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '
' +\n", + " '
'\n",
+       "                );\n",
+       "\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\n",
+       "            me.outputArea = me.$el.find('pre');\n",
+       "            me.subprocessList = me.$el.find('span');\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\n",
+       "\n",
+       "            me.clearButton.click(function() {\n",
+       "                me.outputArea.html('');\n",
+       "                me.clearButton.addClass('disabled');\n",
+       "            });\n",
+       "\n",
+       "            me.abortButton.click(function() {\n",
+       "                me.send({abort: true});\n",
+       "            });\n",
+       "\n",
+       "            me.$el.find('.js-state').click(function() {\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\n",
+       "                        .split('-')[1].split(' ')[0];\n",
+       "\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\n",
+       "                // some other bit of code resets the parent after render if I do it there.\n",
+       "                // To be safe, just do it on every state click.\n",
+       "                me.$el.appendTo('body');\n",
+       "\n",
+       "                if(oldState === 'floated') {\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\n",
+       "                }\n",
+       "\n",
+       "                me.$el.attr('qcodes-state', state);\n",
+       "\n",
+       "                if(state === 'floated') {\n",
+       "                    me.$el.draggable().css({\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\n",
+       "                    });\n",
+       "                }\n",
+       "            });\n",
+       "\n",
+       "            $(window).resize(function() {\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\n",
+       "                    var position = me.$el.position(),\n",
+       "                        minVis = 20,\n",
+       "                        maxLeft = window.innerWidth - minVis,\n",
+       "                        maxTop = window.innerHeight - minVis;\n",
+       "\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\n",
+       "                }\n",
+       "            });\n",
+       "\n",
+       "            me.update();\n",
+       "        },\n",
+       "\n",
+       "        display: function(message) {\n",
+       "            if(message) {\n",
+       "                var initialScroll = this.outputArea.scrollTop();\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\n",
+       "\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\n",
+       "                    this.$el.find('.qcodes-docked').click();\n",
+       "                    // always scroll to the bottom if we're restoring\n",
+       "                    // because of a new message\n",
+       "                    initialScroll = scrollBottom;\n",
+       "                }\n",
+       "\n",
+       "                this.outputArea.append(message);\n",
+       "                this.clearButton.removeClass('disabled');\n",
+       "\n",
+       "                // if we were scrolled to the bottom initially, make sure\n",
+       "                // we stay that way.\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\n",
+       "            }\n",
+       "\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\n",
+       "            this.subprocessList.text(processes);\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\n",
+       "});\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
    "source": [
     "%matplotlib nbagg\n",
     "import matplotlib.pyplot as plt\n",
@@ -24,7 +262,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 16,
+   "execution_count": 2,
    "metadata": {
     "collapsed": false
    },
@@ -62,7 +300,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 17,
+   "execution_count": 3,
    "metadata": {
     "collapsed": false
    },
@@ -73,7 +311,7 @@
        "0.117"
       ]
      },
-     "execution_count": 17,
+     "execution_count": 3,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -84,7 +322,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 4,
    "metadata": {
     "collapsed": false
    },
@@ -95,7 +333,7 @@
        "0.5"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 4,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -107,7 +345,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 19,
+   "execution_count": 5,
    "metadata": {
     "collapsed": false
    },
@@ -118,7 +356,7 @@
        "[0.627]"
       ]
      },
-     "execution_count": 19,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -130,32 +368,25 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 6,
    "metadata": {
     "collapsed": false
    },
    "outputs": [],
    "source": [
-    "# start a Loop (which by default runs in a seprarate process)\n",
+    "# start a Loop\n",
     "# the sweep values are defined by slicing the parameter object\n",
     "# but more complicated sweeps (eg nonlinear, or adaptive) can\n",
     "# easily be used instead\n",
     "\n",
-    "# Notice that I'm using an explicit location and `overwrite=True` here so that\n",
-    "# running this notebook over and over won't result in extra files.\n",
-    "# But if you leave these out, you get a new timestamped DataSet each time.\n",
-    "# data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True, background=False)\n",
+    "# run_temp makes this a foreground (blocking) loop with no saving location.\n",
     "\n",
-    "data = qc.Loop(c0[-20:20:0.1], 0.03).run_temp()#(location='testsweep', overwrite=True, background=False)\n",
-    "\n",
-    "# now there should be two extra processes running, DataServer and a sweep\n",
-    "# I'll omit the active_children call now because you can see them in the\n",
-    "# subprocess widget"
+    "data = qc.Loop(c0[-20:20:0.1], 0.03).run_temp()"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 21,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false,
     "scrolled": true
@@ -263,7 +494,7 @@
        "         19.6,  19.7,  19.8,  19.9])}"
       ]
      },
-     "execution_count": 21,
+     "execution_count": 7,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -276,28 +507,12 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 22,
+   "execution_count": 8,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
-   "outputs": [
-    {
-     "ename": "TypeError",
-     "evalue": "sequence item 0: expected str instance, bool found",
-     "output_type": "error",
-     "traceback": [
-      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
-      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# live-updating plot, that syncs the data and stops updating when it's finished\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;31m# plot = qc.MatPlot(data.amplitude)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m \u001b[0mplotQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mamplitude\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36m__init__\u001b[1;34m(self, figsize, interval, windowTitle, theme, *args, **kwargs)\u001b[0m\n\u001b[0;32m     53\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     54\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0margs\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 55\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     56\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     57\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_init_qt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\base.py\u001b[0m in \u001b[0;36madd\u001b[1;34m(self, updater, *args, **kwargs)\u001b[0m\n\u001b[0;32m     48\u001b[0m         '''\n\u001b[0;32m     49\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mexpand_trace\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 50\u001b[1;33m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_to_plot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     51\u001b[0m         \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_updater\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mupdater\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     52\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\pyqtgraph.py\u001b[0m in \u001b[0;36madd_to_plot\u001b[1;34m(self, subplot, **kwargs)\u001b[0m\n\u001b[0;32m    102\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    103\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mprev_default_title\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwindowTitle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 104\u001b[1;33m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwin\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msetWindowTitle\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_default_title\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    106\u001b[0m     def _draw_plot(self, subplot_object, y, x=None, color=None, width=None,\n",
-      "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\plots\\base.py\u001b[0m in \u001b[0;36mget_default_title\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m     91\u001b[0m                     \u001b[1;32mif\u001b[0m \u001b[0mlocation\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mtitle_parts\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     92\u001b[0m                         \u001b[0mtitle_parts\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlocation\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 93\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[1;34m', '\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtitle_parts\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     94\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     95\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mget_label\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata_array\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
-      "\u001b[1;31mTypeError\u001b[0m: sequence item 0: expected str instance, bool found"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# live-updating plot, that syncs the data and stops updating when it's finished\n",
     "# plot = qc.MatPlot(data.amplitude)\n",
@@ -306,7 +521,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 23,
+   "execution_count": 9,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -317,11 +532,11 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
+      "   chan0: chan0\n",
       "   amplitude_3: amplitude\n",
-      "   amplitude_0: amplitude\n",
       "   chan1: chan1\n",
-      "   chan0: chan0\n",
-      "started at 2016-04-18 16:23:14\n"
+      "   amplitude_0: amplitude\n",
+      "started at 2016-04-20 12:16:14\n"
      ]
     }
    ],
@@ -458,7 +673,7 @@
    "name": "python",
    "nbconvert_exporter": "python",
    "pygments_lexer": "ipython3",
-   "version": "3.5.1"
+   "version": "3.5.0"
   }
  },
  "nbformat": 4,
diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 7a8999a23387..4080a3d29fa4 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -88,7 +88,7 @@ def get_default_title(self):
                 data_array = config.get(part, '')
                 if hasattr(data_array, 'data_set'):
                     location = data_array.data_set.location
-                    if location not in title_parts:
+                    if location and location not in title_parts:
                         title_parts.append(location)
         return ', '.join(title_parts)
 

From c478f5d8a75c8a4af9a8393d88454dd691b4c9f6 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 20 Apr 2016 17:27:02 +0200
Subject: [PATCH 029/169] minor keithley stuff

---
 .../Qcodes example with Keithley 2600.ipynb   | 250 ++++++++++++------
 .../tektronix/Keithley_2600.py                |   2 +
 2 files changed, 176 insertions(+), 76 deletions(-)

diff --git a/docs/examples/Qcodes example with Keithley 2600.ipynb b/docs/examples/Qcodes example with Keithley 2600.ipynb
index 279fdcae3d9a..2df8a5e6e2d4 100644
--- a/docs/examples/Qcodes example with Keithley 2600.ipynb	
+++ b/docs/examples/Qcodes example with Keithley 2600.ipynb	
@@ -243,6 +243,13 @@
      },
      "metadata": {},
      "output_type": "display_data"
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "No loop running\n"
+     ]
     }
    ],
    "source": [
@@ -253,6 +260,7 @@
     "\n",
     "import qcodes as qc\n",
     "\n",
+    "qc.halt_bg()\n",
     "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
     "\n",
     "# this makes a widget in the corner of the window to show and control\n",
@@ -260,6 +268,15 @@
     "qc.show_subprocess_widget()"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  },
   {
    "cell_type": "code",
    "execution_count": 2,
@@ -283,8 +300,8 @@
     "# session - had to move them to a file.\n",
     "\n",
     "# now create this \"experiment\"\n",
-    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a',server_name=None)\n",
-    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b',server_name=None)\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a')#,server_name=None)\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b')#,server_name=None)\n",
     "\n",
     "station = qc.Station(k1,k2)\n",
     "\n",
@@ -309,60 +326,55 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 4,
    "metadata": {
     "collapsed": false,
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "{'model': '2614B',\n",
-       " 'serial_number': '4083825',\n",
-       " 'software_revision': '3.2.1',\n",
-       " 'vendor': 'Keithley Instruments Inc.'}"
-      ]
-     },
-     "execution_count": 7,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "k2.info"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 26,
-   "metadata": {
-    "collapsed": false
+    "scrolled": false
    },
    "outputs": [
     {
      "data": {
       "text/plain": [
-       "'Model 2614B,'"
+       "{'instruments': {'Keithley1': {'functions': {},\n",
+       "   'metadata': {'info': {'model': '2614B',\n",
+       "     'serial_number': '4083825',\n",
+       "     'software_revision': '3.2.1',\n",
+       "     'vendor': 'Keithley Instruments Inc.'}},\n",
+       "   'parameters': {'curr': {'ts': None, 'value': None},\n",
+       "    'limiti': {'ts': None, 'value': None},\n",
+       "    'limitv': {'ts': None, 'value': None},\n",
+       "    'mode': {'ts': None, 'value': None},\n",
+       "    'output': {'ts': None, 'value': None},\n",
+       "    'rangei': {'ts': None, 'value': None},\n",
+       "    'rangev': {'ts': None, 'value': None},\n",
+       "    'volt': {'ts': None, 'value': None}}},\n",
+       "  'Keithley2': {'functions': {},\n",
+       "   'metadata': {'info': {'model': '2614B',\n",
+       "     'serial_number': '4083825',\n",
+       "     'software_revision': '3.2.1',\n",
+       "     'vendor': 'Keithley Instruments Inc.'}},\n",
+       "   'parameters': {'curr': {'ts': None, 'value': None},\n",
+       "    'limiti': {'ts': None, 'value': None},\n",
+       "    'limitv': {'ts': None, 'value': None},\n",
+       "    'mode': {'ts': None, 'value': None},\n",
+       "    'output': {'ts': None, 'value': None},\n",
+       "    'rangei': {'ts': None, 'value': None},\n",
+       "    'rangev': {'ts': None, 'value': None},\n",
+       "    'volt': {'ts': None, 'value': None}}}}}"
       ]
      },
-     "execution_count": 26,
+     "execution_count": 4,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
-    "import re\n",
-    "text = 'Keithley Instruments Inc., Model 2614B, 4083825, 3.2.1'\n",
-    "m = re.search('Model (.+?),', text)\n",
-    "# if m:\n",
-    "#     found = m.group(1)\n",
-    "m.group()"
+    "station.snapshot()"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 4,
+   "execution_count": 5,
    "metadata": {
     "collapsed": false
    },
@@ -370,10 +382,10 @@
     {
      "data": {
       "text/plain": [
-       "[-8.34465e-14, -1.0848e-12]"
+       "[2.98023e-13, -9.41753e-13]"
       ]
      },
-     "execution_count": 4,
+     "execution_count": 5,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -385,7 +397,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 5,
+   "execution_count": 6,
    "metadata": {
     "collapsed": false
    },
@@ -398,7 +410,7 @@
       "   curr_0: curr\n",
       "   curr_1: curr\n",
       "   volt: volt\n",
-      "started at 2016-04-14 22:21:31\n"
+      "started at 2016-04-20 15:37:23\n"
      ]
     }
    ],
@@ -420,7 +432,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false,
     "scrolled": true
@@ -430,25 +442,17 @@
      "data": {
       "text/plain": [
        "{'curr_0': DataArray[20]: curr_0\n",
-       " array([ -3.40915000e-10,  -4.52161000e-11,   8.41618000e-12,\n",
-       "          4.14968000e-11,   6.37770000e-11,   7.77721000e-11,\n",
-       "          8.52823000e-11,   8.91566000e-11,   9.08732000e-11,\n",
-       "          9.14335000e-11,   9.11236000e-11,   9.22322000e-11,\n",
-       "          9.23514000e-11,   9.24468000e-11,   9.29832000e-11,\n",
-       "          9.34243000e-11,   9.27448000e-11,   9.26137000e-11,\n",
-       "          9.26971000e-11,   9.18150000e-11]), 'curr_1': DataArray[20]: curr_1\n",
-       " array([ -1.38283000e-12,  -9.05991000e-13,  -1.06096000e-12,\n",
-       "         -1.23978000e-12,  -1.02520000e-12,  -1.13249000e-12,\n",
-       "         -1.22786000e-12,  -1.09673000e-12,  -1.21593000e-12,\n",
-       "         -1.09673000e-12,  -1.02520000e-12,  -9.41753000e-13,\n",
-       "         -9.77516000e-13,  -1.19209000e-12,  -9.89437000e-13,\n",
-       "         -1.07288000e-12,  -1.09673000e-12,  -1.14441000e-12,\n",
-       "         -1.25170000e-12,  -1.00136000e-12]), 'volt': DataArray[20]: volt\n",
-       " array([-5. , -4.5, -4. , -3.5, -3. , -2.5, -2. , -1.5, -1. , -0.5,  0. ,\n",
-       "         0.5,  1. ,  1.5,  2. ,  2.5,  3. ,  3.5,  4. ,  4.5])}"
+       " array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,\n",
+       "         nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan]),\n",
+       " 'curr_1': DataArray[20]: curr_1\n",
+       " array([ nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,\n",
+       "         nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan]),\n",
+       " 'volt': DataArray[20]: volt\n",
+       " array([ -5.,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,\n",
+       "         nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan,  nan])}"
       ]
      },
-     "execution_count": 6,
+     "execution_count": 7,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -461,7 +465,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": 8,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -476,7 +480,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 9,
    "metadata": {
     "collapsed": false,
     "scrolled": true
@@ -487,11 +491,11 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
-      "   curr_0: curr\n",
-      "   volt_0: volt\n",
       "   curr_1: curr\n",
       "   volt: volt\n",
-      "started at 2016-04-14 22:22:54\n"
+      "   curr_0: curr\n",
+      "   volt_0: volt\n",
+      "started at 2016-04-20 15:22:46\n"
      ]
     }
    ],
@@ -509,6 +513,103 @@
     "# plot2Q.add(data2.curr_1, subplot=2)"
    ]
   },
+  {
+   "cell_type": "code",
+   "execution_count": 19,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'model': '2614B',\n",
+       " 'serial_number': '4083825',\n",
+       " 'software_revision': '3.2.1',\n",
+       " 'vendor': 'Keithley Instruments Inc.'}"
+      ]
+     },
+     "execution_count": 19,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "k1.setattr(('metadata','test'), 11)\n",
+    "k1.getattr('info')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'Keithley Instruments Inc., Model 2614B, 4083825, 3.2.1'"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "k1.ask_direct('*IDN?')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'instruments': {'Keithley1': {'functions': {},\n",
+       "   'metadata': {'test': 11},\n",
+       "   'parameters': {'curr': {'ts': '2016-04-20 15:31:51', 'value': -2.14577e-13},\n",
+       "    'limiti': {'ts': '2016-04-20 15:31:51', 'value': 0.1},\n",
+       "    'limitv': {'ts': '2016-04-20 15:31:51', 'value': 20.0},\n",
+       "    'mode': {'ts': '2016-04-20 15:31:51', 'value': 'voltage'},\n",
+       "    'output': {'ts': '2016-04-20 15:31:51', 'value': 'ON'},\n",
+       "    'rangei': {'ts': '2016-04-20 15:31:51', 'value': 1e-07},\n",
+       "    'rangev': {'ts': '2016-04-20 15:31:51', 'value': 20.0},\n",
+       "    'volt': {'ts': '2016-04-20 15:31:51', 'value': 4.90016}}},\n",
+       "  'Keithley2': {'functions': {},\n",
+       "   'parameters': {'curr': {'ts': '2016-04-20 15:31:51', 'value': -1.07288e-12},\n",
+       "    'limiti': {'ts': '2016-04-20 15:31:51', 'value': 0.1},\n",
+       "    'limitv': {'ts': '2016-04-20 15:31:51', 'value': 20.0},\n",
+       "    'mode': {'ts': '2016-04-20 15:31:51', 'value': 'voltage'},\n",
+       "    'output': {'ts': '2016-04-20 15:31:51', 'value': 'ON'},\n",
+       "    'rangei': {'ts': '2016-04-20 15:31:51', 'value': 1e-07},\n",
+       "    'rangev': {'ts': '2016-04-20 15:31:51', 'value': 2.0},\n",
+       "    'volt': {'ts': '2016-04-20 15:31:51', 'value': 1.80006}}}}}"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "station.snapshot(update=True)"
+   ]
+  },
   {
    "cell_type": "code",
    "execution_count": 12,
@@ -517,12 +618,12 @@
    },
    "outputs": [],
    "source": [
-    "plot2Q.add(data2.curr_0, subplot=2)"
+    "plot2Q.add(data2.curr_0, subplot=2)\n"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": 20,
+   "execution_count": 18,
    "metadata": {
     "collapsed": false
    },
@@ -532,16 +633,14 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
+      "   curr_0_1: curr\n",
       "   volt_0: volt\n",
-      "   curr_1_1: curr\n",
-      "   curr_1_0: curr\n",
-      "   curr_2: curr\n",
-      "   volt_1: volt\n",
-      "   curr_3: curr\n",
       "   curr_0_0: curr\n",
-      "   curr_0_1: curr\n",
+      "   volt_1: volt\n",
+      "   curr_1_0: curr\n",
+      "   curr_1_1: curr\n",
       "   volt: volt\n",
-      "started at 2016-04-14 22:49:45\n"
+      "started at 2016-04-20 14:09:16\n"
      ]
     },
     {
@@ -551,7 +650,7 @@
      "traceback": [
       "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
       "\u001b[1;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
-      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# plot3b = qc.MatPlot(data3.curr_1_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;31m# plot3b.add(data3.curr_0_1, subplot=2)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mplot3Q\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[0mplot3bQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfigsize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1200\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m500\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     13\u001b[0m \u001b[0mplot3bQ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msubplot\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      8\u001b[0m \u001b[1;31m# plot3b = qc.MatPlot(data3.curr_1_0, cmap=plt.cm.hot, figsize=(12, 4.5), subplots=(1,2))\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m \u001b[1;31m# plot3b.add(data3.curr_0_1, subplot=2)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0mplot3Q\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     11\u001b[0m \u001b[0mplot3bQ\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mqc\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mQtPlot\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfigsize\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1200\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m500\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[0mplot3bQ\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdata3\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcurr_0\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0msubplot\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;32mC:\\Github\\Qcodes\\qcodes\\utils\\helpers.py\u001b[0m in \u001b[0;36m__getattr__\u001b[1;34m(self, key)\u001b[0m\n\u001b[0;32m    187\u001b[0m         raise AttributeError(\n\u001b[0;32m    188\u001b[0m             \"'{}' object and its delegates have no attribute '{}'\".format(\n\u001b[1;32m--> 189\u001b[1;33m                 self.__class__.__name__, key))\n\u001b[0m\u001b[0;32m    190\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    191\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__dir__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
       "\u001b[1;31mAttributeError\u001b[0m: 'DataSet' object and its delegates have no attribute 'curr_1'"
      ]
@@ -561,7 +660,6 @@
     "data3 = qc.Loop(vsd1[-15:15:1], 0).each(\n",
     "                qc.Loop(vsd2[-5:5:1], 0),\n",
     "                qc.Loop(vsd2[5:-5:1], 0),\n",
-    "                curr1,curr2,\n",
     ").run(location='test_multi_d', overwrite=True)\n",
     "\n",
     "# several plots updating simultaneously\n",
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index fb3f4db6f911..d741aa478467 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -50,6 +50,8 @@ def __init__(self, name, address, channel, **kwargs):
         self.info = {'vendor': vendor, 'model': self.model,
                      'serial_number': serial, 'software_revision': software}
 
+        self.metadata['info'] = self.info
+
         self.add_parameter('volt', get_cmd='measure.v()',
                            get_parser=float, set_cmd='source.levelv={:.8f}',
                            label='Voltage',

From 3557dd143c73afeb9ddedb0014ef8a5a4c8132e2 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 20 Apr 2016 17:27:44 +0200
Subject: [PATCH 030/169] Fixing some folder slashes

---
 qcodes/data/format.py | 2 +-
 qcodes/data/io.py     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 828285b41b0f..a88c9a184afc 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -382,7 +382,7 @@ def write(self, data_set):
 
         for group in groups:
             if len(groups) == 1:
-                fn = location + self.extension
+                fn = io_manager.join(location + self.extension)
             else:
                 fn = io_manager.join(location, group.name + self.extension)
 
diff --git a/qcodes/data/io.py b/qcodes/data/io.py
index 3c8c67aa1321..cfb0e2a6b70b 100644
--- a/qcodes/data/io.py
+++ b/qcodes/data/io.py
@@ -103,7 +103,7 @@ def join(self, *args):
         '''
         the context-dependent version of os.path.join for this io manager
         '''
-        return os.path.join(*args)
+        return os.path.join(*list(map(self._normalize_slashes, args)))
 
     def isfile(self, location):
         '''

From 31b32a8968bcbca1c6a2118c39f7dd8fe30dd264 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 20 Apr 2016 17:40:54 +0200
Subject: [PATCH 031/169] Removing and in future ignoring those data files

---
 docs/examples/Qcodes example.ipynb            |  598 ++--
 docs/examples/test2d.dat                      | 1652 ---------
 docs/examples/test_complex_param/chan1.dat    |   33 -
 .../test_complex_param/chan1_chan2.dat        | 3032 -----------------
 docs/examples/test_multi_d/chan1.dat          |   33 -
 docs/examples/test_multi_d/chan1_chan0.dat    |  932 -----
 docs/examples/test_multi_d/chan1_chan2.dat    | 3032 -----------------
 7 files changed, 299 insertions(+), 9013 deletions(-)
 delete mode 100644 docs/examples/test2d.dat
 delete mode 100644 docs/examples/test_complex_param/chan1.dat
 delete mode 100644 docs/examples/test_complex_param/chan1_chan2.dat
 delete mode 100644 docs/examples/test_multi_d/chan1.dat
 delete mode 100644 docs/examples/test_multi_d/chan1_chan0.dat
 delete mode 100644 docs/examples/test_multi_d/chan1_chan2.dat

diff --git a/docs/examples/Qcodes example.ipynb b/docs/examples/Qcodes example.ipynb
index 3de9650b4001..0eb4a6bf1347 100644
--- a/docs/examples/Qcodes example.ipynb	
+++ b/docs/examples/Qcodes example.ipynb	
@@ -10,171 +10,171 @@
     {
      "data": {
       "application/javascript": [
-       "/*\n",
-       " * Qcodes Jupyter/IPython widgets\n",
-       " */\n",
-       "require([\n",
-       "    'nbextensions/widgets/widgets/js/widget',\n",
-       "    'nbextensions/widgets/widgets/js/manager'\n",
-       "], function (widget, manager) {\n",
-       "\n",
-       "    var UpdateView = widget.DOMWidgetView.extend({\n",
-       "        render: function() {\n",
-       "            window.MYWIDGET = this;\n",
-       "            this._interval = 0;\n",
-       "            this.update();\n",
-       "        },\n",
-       "        update: function() {\n",
-       "            this.display(this.model.get('_message'));\n",
-       "            this.setInterval();\n",
-       "        },\n",
-       "        display: function(message) {\n",
-       "            /*\n",
-       "             * display method: override this for custom display logic\n",
-       "             */\n",
-       "            this.el.innerHTML = message;\n",
-       "        },\n",
-       "        remove: function() {\n",
-       "            clearInterval(this._updater);\n",
-       "        },\n",
-       "        setInterval: function(newInterval) {\n",
-       "            var me = this;\n",
-       "            if(newInterval===undefined) newInterval = me.model.get('interval');\n",
-       "            if(newInterval===me._interval) return;\n",
-       "\n",
-       "            me._interval = newInterval;\n",
-       "\n",
-       "            if(me._updater) clearInterval(me._updater);\n",
-       "\n",
-       "            if(me._interval) {\n",
-       "                me._updater = setInterval(function() {\n",
-       "                    me.send({myupdate: true});\n",
-       "                    if(!me.model.comm_live) {\n",
-       "                        console.log('missing comm, canceling widget updates', me);\n",
-       "                        clearInterval(me._updater);\n",
-       "                    }\n",
-       "                }, me._interval * 1000);\n",
-       "            }\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\n",
-       "\n",
-       "    var HiddenUpdateView = UpdateView.extend({\n",
-       "        display: function(message) {\n",
-       "            this.$el.hide();\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\n",
-       "\n",
-       "    var SubprocessView = UpdateView.extend({\n",
-       "        render: function() {\n",
-       "            var me = window.SPVIEW = this;\n",
-       "            me._interval = 0;\n",
-       "            me._minimize = '';\n",
-       "            me._restore = '';\n",
-       "\n",
-       "            // in case there is already an outputView present,\n",
-       "            // like from before restarting the kernel\n",
-       "            $('.qcodes-output-view').not(me.$el).remove();\n",
-       "\n",
-       "            me.$el\n",
-       "                .addClass('qcodes-output-view')\n",
-       "                .attr('qcodes-state', 'docked')\n",
-       "                .html(\n",
-       "                    '
' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '
' +\n", - " '
'\n",
-       "                );\n",
-       "\n",
-       "            me.clearButton = me.$el.find('.qcodes-clear-output');\n",
-       "            me.minButton = me.$el.find('.qcodes-minimize');\n",
-       "            me.outputArea = me.$el.find('pre');\n",
-       "            me.subprocessList = me.$el.find('span');\n",
-       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\n",
-       "\n",
-       "            me.clearButton.click(function() {\n",
-       "                me.outputArea.html('');\n",
-       "                me.clearButton.addClass('disabled');\n",
-       "            });\n",
-       "\n",
-       "            me.abortButton.click(function() {\n",
-       "                me.send({abort: true});\n",
-       "            });\n",
-       "\n",
-       "            me.$el.find('.js-state').click(function() {\n",
-       "                var oldState = me.$el.attr('qcodes-state'),\n",
-       "                    state = this.className.substr(this.className.indexOf('qcodes'))\n",
-       "                        .split('-')[1].split(' ')[0];\n",
-       "\n",
-       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\n",
-       "                // some other bit of code resets the parent after render if I do it there.\n",
-       "                // To be safe, just do it on every state click.\n",
-       "                me.$el.appendTo('body');\n",
-       "\n",
-       "                if(oldState === 'floated') {\n",
-       "                    me.$el.draggable('destroy').css({left:'', top: ''});\n",
-       "                }\n",
-       "\n",
-       "                me.$el.attr('qcodes-state', state);\n",
-       "\n",
-       "                if(state === 'floated') {\n",
-       "                    me.$el.draggable().css({\n",
-       "                        left: window.innerWidth - me.$el.width() - 15,\n",
-       "                        top: window.innerHeight - me.$el.height() - 10\n",
-       "                    });\n",
-       "                }\n",
-       "            });\n",
-       "\n",
-       "            $(window).resize(function() {\n",
-       "                if(me.$el.attr('qcodes-state') === 'floated') {\n",
-       "                    var position = me.$el.position(),\n",
-       "                        minVis = 20,\n",
-       "                        maxLeft = window.innerWidth - minVis,\n",
-       "                        maxTop = window.innerHeight - minVis;\n",
-       "\n",
-       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\n",
-       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\n",
-       "                }\n",
-       "            });\n",
-       "\n",
-       "            me.update();\n",
-       "        },\n",
-       "\n",
-       "        display: function(message) {\n",
-       "            if(message) {\n",
-       "                var initialScroll = this.outputArea.scrollTop();\n",
-       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\n",
-       "                var scrollBottom = this.outputArea.scrollTop();\n",
-       "\n",
-       "                if(this.$el.attr('qcodes-state') === 'minimized') {\n",
-       "                    this.$el.find('.qcodes-docked').click();\n",
-       "                    // always scroll to the bottom if we're restoring\n",
-       "                    // because of a new message\n",
-       "                    initialScroll = scrollBottom;\n",
-       "                }\n",
-       "\n",
-       "                this.outputArea.append(message);\n",
-       "                this.clearButton.removeClass('disabled');\n",
-       "\n",
-       "                // if we were scrolled to the bottom initially, make sure\n",
-       "                // we stay that way.\n",
-       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\n",
-       "                    this.outputArea.prop('scrollHeight') : initialScroll);\n",
-       "            }\n",
-       "\n",
-       "            var processes = this.model.get('_processes') || 'No subprocesses';\n",
-       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\n",
-       "            this.subprocessList.text(processes);\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\n",
-       "});\n"
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
       ],
       "text/plain": [
        ""
@@ -186,55 +186,55 @@
     {
      "data": {
       "text/html": [
-       ""
       ],
       "text/plain": [
@@ -338,13 +338,13 @@
      "data": {
       "text/plain": [
        "{'instruments': {'gates': {'functions': {'reset': {}},\n",
-       "   'parameters': {'chan0': {'ts': '2016-04-20 00:19:23', 'value': 0.0},\n",
-       "    'chan1': {'ts': '2016-04-20 00:19:23', 'value': 0.0},\n",
-       "    'chan2': {'ts': '2016-04-20 00:19:23', 'value': 0.0}}},\n",
+       "   'parameters': {'chan0': {'ts': '2016-04-20 17:31:50', 'value': 0.0},\n",
+       "    'chan1': {'ts': '2016-04-20 17:31:50', 'value': 0.0},\n",
+       "    'chan2': {'ts': '2016-04-20 17:31:50', 'value': 0.0}}},\n",
        "  'meter': {'functions': {},\n",
-       "   'parameters': {'amplitude': {'ts': '2016-04-20 00:19:23', 'value': 0.117}}},\n",
+       "   'parameters': {'amplitude': {'ts': '2016-04-20 17:31:50', 'value': 0.117}}},\n",
        "  'source': {'functions': {},\n",
-       "   'parameters': {'amplitude': {'ts': '2016-04-20 00:19:23', 'value': 0.1}}}}}"
+       "   'parameters': {'amplitude': {'ts': '2016-04-20 17:31:50', 'value': 0.1}}}}}"
       ]
      },
      "execution_count": 4,
@@ -381,7 +381,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false
    },
@@ -390,10 +390,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "DataSet: DataMode.PULL_FROM_SERVER, location='data/testsweep'\n",
       "   chan0: chan0\n",
       "   amplitude: amplitude\n",
-      "started at 2016-04-20 00:19:28\n"
+      "started at 2016-04-20 17:32:19\n"
      ]
     }
    ],
@@ -406,7 +406,7 @@
     "# Notice that I'm using an explicit location and `overwrite=True` here so that\n",
     "# running this notebook over and over won't result in extra files.\n",
     "# But if you leave these out, you get a new timestamped DataSet each time.\n",
-    "data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='testsweep', overwrite=True)\n",
+    "data = qc.Loop(c0[-20:20:0.1], 0.03).run(location='data/testsweep', overwrite=True)\n",
     "\n",
     "# now there should be two extra processes running, DataServer and a sweep\n",
     "# I'll omit the active_children call now because you can see them in the\n",
@@ -444,37 +444,37 @@
        "         0.016,  0.015,  0.014,  0.013,  0.013,  0.012,  0.011,  0.011,\n",
        "         0.01 ,  0.01 ,  0.01 ,  0.009,  0.009,  0.008,  0.008,  0.008,\n",
        "         0.007,  0.007,  0.007,  0.007,  0.006,  0.006,  0.006,  0.006,\n",
-       "         0.006,  0.007,  0.007,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan,\n",
-       "           nan,    nan,    nan,    nan,    nan,    nan,    nan,    nan]),\n",
+       "         0.006,  0.007,  0.007,  0.007,  0.007,  0.008,  0.008,  0.008,\n",
+       "         0.009,  0.009,  0.01 ,  0.01 ,  0.01 ,  0.011,  0.011,  0.012,\n",
+       "         0.013,  0.013,  0.014,  0.015,  0.016,  0.017,  0.018,  0.019,\n",
+       "         0.02 ,  0.022,  0.023,  0.025,  0.027,  0.029,  0.031,  0.034,\n",
+       "         0.037,  0.04 ,  0.044,  0.048,  0.053,  0.058,  0.064,  0.071,\n",
+       "         0.077,  0.085,  0.092,  0.099,  0.106,  0.111,  0.115,  0.117,\n",
+       "         0.117,  0.117,  0.115,  0.111,  0.106,  0.099,  0.092,  0.085,\n",
+       "         0.077,  0.071,  0.064,  0.058,  0.053,  0.048,  0.044,  0.04 ,\n",
+       "         0.037,  0.034,  0.031,  0.029,  0.027,  0.025,  0.023,  0.022,\n",
+       "         0.02 ,  0.019,  0.018,  0.017,  0.016,  0.015,  0.014,  0.013,\n",
+       "         0.013,  0.012,  0.011,  0.011,  0.01 ,  0.01 ,  0.01 ,  0.009,\n",
+       "         0.009,  0.008,  0.008,  0.008,  0.007,  0.007,  0.007,  0.007,\n",
+       "         0.006,  0.006,  0.006,  0.006,  0.006,  0.007,  0.007,  0.007,\n",
+       "         0.007,  0.008,  0.008,  0.008,  0.009,  0.009,  0.01 ,  0.01 ,\n",
+       "         0.01 ,  0.011,  0.011,  0.012,  0.013,  0.013,  0.014,  0.015,\n",
+       "         0.016,  0.017,  0.018,  0.019,  0.02 ,  0.022,  0.023,  0.025,\n",
+       "         0.027,  0.029,  0.031,  0.034,  0.037,  0.04 ,  0.044,  0.048,\n",
+       "         0.053,  0.058,  0.064,  0.071,  0.077,  0.085,  0.092,  0.099,\n",
+       "         0.106,  0.111,  0.115,  0.117,  0.117,  0.117,  0.115,  0.111,\n",
+       "         0.106,  0.099,  0.092,  0.085,  0.077,  0.071,  0.064,  0.058,\n",
+       "         0.053,  0.048,  0.044,  0.04 ,  0.037,  0.034,  0.031,  0.029,\n",
+       "         0.027,  0.025,  0.023,  0.022,  0.02 ,  0.019,  0.018,  0.017,\n",
+       "         0.016,  0.015,  0.014,  0.013,  0.013,  0.012,  0.011,  0.011,\n",
+       "         0.01 ,  0.01 ,  0.01 ,  0.009,  0.009,  0.008,  0.008,  0.008,\n",
+       "         0.007,  0.007,  0.007,  0.007,  0.006,  0.006,  0.006,  0.006,\n",
+       "         0.006,  0.007,  0.007,  0.007,  0.007,  0.008,  0.008,  0.008,\n",
+       "         0.009,  0.009,  0.01 ,  0.01 ,  0.01 ,  0.011,  0.011,  0.012,\n",
+       "         0.013,  0.013,  0.014,  0.015,  0.016,  0.017,  0.018,  0.019,\n",
+       "         0.02 ,  0.022,  0.023,  0.025,  0.027,  0.029,  0.031,  0.034,\n",
+       "         0.037,  0.04 ,  0.044,  0.048,  0.053,  0.058,  0.064,  0.071,\n",
+       "         0.077,  0.085,  0.092,  0.099,  0.106,  0.111,  0.115,  0.117]),\n",
        " 'chan0': DataArray[400]: chan0\n",
        " array([-20. , -19.9, -19.8, -19.7, -19.6, -19.5, -19.4, -19.3, -19.2,\n",
        "        -19.1, -19. , -18.9, -18.8, -18.7, -18.6, -18.5, -18.4, -18.3,\n",
@@ -493,34 +493,34 @@
        "         -7.4,  -7.3,  -7.2,  -7.1,  -7. ,  -6.9,  -6.8,  -6.7,  -6.6,\n",
        "         -6.5,  -6.4,  -6.3,  -6.2,  -6.1,  -6. ,  -5.9,  -5.8,  -5.7,\n",
        "         -5.6,  -5.5,  -5.4,  -5.3,  -5.2,  -5.1,  -5. ,  -4.9,  -4.8,\n",
-       "         -4.7,  -4.6,  -4.5,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,   nan,\n",
-       "          nan,   nan,   nan,   nan])}"
+       "         -4.7,  -4.6,  -4.5,  -4.4,  -4.3,  -4.2,  -4.1,  -4. ,  -3.9,\n",
+       "         -3.8,  -3.7,  -3.6,  -3.5,  -3.4,  -3.3,  -3.2,  -3.1,  -3. ,\n",
+       "         -2.9,  -2.8,  -2.7,  -2.6,  -2.5,  -2.4,  -2.3,  -2.2,  -2.1,\n",
+       "         -2. ,  -1.9,  -1.8,  -1.7,  -1.6,  -1.5,  -1.4,  -1.3,  -1.2,\n",
+       "         -1.1,  -1. ,  -0.9,  -0.8,  -0.7,  -0.6,  -0.5,  -0.4,  -0.3,\n",
+       "         -0.2,  -0.1,   0. ,   0.1,   0.2,   0.3,   0.4,   0.5,   0.6,\n",
+       "          0.7,   0.8,   0.9,   1. ,   1.1,   1.2,   1.3,   1.4,   1.5,\n",
+       "          1.6,   1.7,   1.8,   1.9,   2. ,   2.1,   2.2,   2.3,   2.4,\n",
+       "          2.5,   2.6,   2.7,   2.8,   2.9,   3. ,   3.1,   3.2,   3.3,\n",
+       "          3.4,   3.5,   3.6,   3.7,   3.8,   3.9,   4. ,   4.1,   4.2,\n",
+       "          4.3,   4.4,   4.5,   4.6,   4.7,   4.8,   4.9,   5. ,   5.1,\n",
+       "          5.2,   5.3,   5.4,   5.5,   5.6,   5.7,   5.8,   5.9,   6. ,\n",
+       "          6.1,   6.2,   6.3,   6.4,   6.5,   6.6,   6.7,   6.8,   6.9,\n",
+       "          7. ,   7.1,   7.2,   7.3,   7.4,   7.5,   7.6,   7.7,   7.8,\n",
+       "          7.9,   8. ,   8.1,   8.2,   8.3,   8.4,   8.5,   8.6,   8.7,\n",
+       "          8.8,   8.9,   9. ,   9.1,   9.2,   9.3,   9.4,   9.5,   9.6,\n",
+       "          9.7,   9.8,   9.9,  10. ,  10.1,  10.2,  10.3,  10.4,  10.5,\n",
+       "         10.6,  10.7,  10.8,  10.9,  11. ,  11.1,  11.2,  11.3,  11.4,\n",
+       "         11.5,  11.6,  11.7,  11.8,  11.9,  12. ,  12.1,  12.2,  12.3,\n",
+       "         12.4,  12.5,  12.6,  12.7,  12.8,  12.9,  13. ,  13.1,  13.2,\n",
+       "         13.3,  13.4,  13.5,  13.6,  13.7,  13.8,  13.9,  14. ,  14.1,\n",
+       "         14.2,  14.3,  14.4,  14.5,  14.6,  14.7,  14.8,  14.9,  15. ,\n",
+       "         15.1,  15.2,  15.3,  15.4,  15.5,  15.6,  15.7,  15.8,  15.9,\n",
+       "         16. ,  16.1,  16.2,  16.3,  16.4,  16.5,  16.6,  16.7,  16.8,\n",
+       "         16.9,  17. ,  17.1,  17.2,  17.3,  17.4,  17.5,  17.6,  17.7,\n",
+       "         17.8,  17.9,  18. ,  18.1,  18.2,  18.3,  18.4,  18.5,  18.6,\n",
+       "         18.7,  18.8,  18.9,  19. ,  19.1,  19.2,  19.3,  19.4,  19.5,\n",
+       "         19.6,  19.7,  19.8,  19.9])}"
       ]
      },
      "execution_count": 8,
@@ -561,11 +561,11 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='test2d'\n",
+      "   chan1: chan1\n",
+      "   chan0: chan0\n",
       "   amplitude_3: amplitude\n",
       "   amplitude_0: amplitude\n",
-      "   chan0: chan0\n",
-      "   chan1: chan1\n",
-      "started at 2016-04-20 00:19:58\n"
+      "started at 2016-04-20 17:35:13\n"
      ]
     }
    ],
@@ -589,7 +589,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 12,
+   "execution_count": 11,
    "metadata": {
     "collapsed": false
    },
@@ -598,15 +598,15 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='test_multi_d'\n",
-      "   amplitude_2: amplitude\n",
-      "   chan0: chan0\n",
-      "   chan2: chan2\n",
-      "   chan1: chan1\n",
-      "   avg_amplitude: avg_amplitude\n",
+      "DataSet: DataMode.PULL_FROM_SERVER, location='data/test_multi_d'\n",
       "   amplitude_5_0: amplitude\n",
       "   amplitude_3_0: amplitude\n",
-      "started at 2016-04-20 00:20:54\n"
+      "   avg_amplitude: avg_amplitude\n",
+      "   chan1: chan1\n",
+      "   chan0: chan0\n",
+      "   chan2: chan2\n",
+      "   amplitude_2: amplitude\n",
+      "started at 2016-04-20 17:35:21\n"
      ]
     }
    ],
@@ -622,7 +622,7 @@
     "    # a 2D sweep with the same outer but different inner loop\n",
     "    qc.Loop(c2[-10:10:0.2], 0.001),\n",
     "    AverageGetter(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
-    ").run(location='test_multi_d', overwrite=True)\n",
+    ").run(location='data/test_multi_d', overwrite=True)\n",
     "\n",
     "# several plots updating simultaneously\n",
     "# plot3 = qc.MatPlot(data3.amplitude_3_0, cmap=plt.cm.hot)\n",
@@ -635,7 +635,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": 12,
    "metadata": {
     "collapsed": false,
     "scrolled": false
@@ -645,12 +645,12 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='test_complex_param'\n",
+      "DataSet: DataMode.PULL_FROM_SERVER, location='data/test_complex_param'\n",
       "   avg_amplitude: avg_amplitude\n",
-      "   amplitude: amplitude\n",
       "   chan1: chan1\n",
       "   chan2: chan2\n",
-      "started at 2016-04-20 00:21:35\n"
+      "   amplitude: amplitude\n",
+      "started at 2016-04-20 17:35:49\n"
      ]
     }
    ],
@@ -659,7 +659,7 @@
     "# This produces the last two arrays from data3, but only takes the data once.\n",
     "data4 = qc.Loop(c1[-15:15:1], 0.1).each(\n",
     "    AverageAndRaw(meter.amplitude, c2[-10:10:0.2], 0.001)\n",
-    ").run(location='test_complex_param', overwrite=True)\n",
+    ").run(location='data/test_complex_param', overwrite=True)\n",
     "\n",
     "# plot4 = qc.MatPlot(data4.amplitude, cmap=plt.cm.hot, subplots=(1,2), figsize=(12, 4.5))\n",
     "# plot4.add(data4.avg_amplitude, subplot=2)\n",
diff --git a/docs/examples/test2d.dat b/docs/examples/test2d.dat
deleted file mode 100644
index feafadab27d1..000000000000
--- a/docs/examples/test2d.dat
+++ /dev/null
@@ -1,1652 +0,0 @@
-# chan1	chan0	amplitude_0	amplitude_3
-# "Gate Channel 1 (mV)"	"Gate Channel 0 (mV)"	"Current (nA)"	"Current (nA)"
-# 30	54
--15	-15	0.003	0.009
--15	-14.5	0.004	0.009
--15	-14	0.004	0.01
--15	-13.5	0.004	0.011
--15	-13	0.005	0.012
--15	-12.5	0.005	0.013
--15	-12	0.005	0.014
--15	-11.5	0.006	0.015
--15	-11	0.006	0.016
--15	-10.5	0.006	0.017
--15	-10	0.006	0.017
--15	-9.5	0.006	0.017
--15	-9	0.006	0.016
--15	-8.5	0.006	0.015
--15	-8	0.005	0.014
--15	-7.5	0.005	0.013
--15	-7	0.005	0.012
--15	-6.5	0.004	0.011
--15	-6	0.004	0.01
--15	-5.5	0.004	0.009
--15	-5	0.003	0.009
--15	-4.5	0.004	0.009
--15	-4	0.004	0.01
--15	-3.5	0.004	0.011
--15	-3	0.005	0.012
--15	-2.5	0.005	0.013
--15	-2	0.005	0.014
--15	-1.5	0.006	0.015
--15	-1	0.006	0.016
--15	-0.5	0.006	0.017
--15	0	0.006	0.017
--15	0.5	0.006	0.017
--15	1	0.006	0.016
--15	1.5	0.006	0.015
--15	2	0.005	0.014
--15	2.5	0.005	0.013
--15	3	0.005	0.012
--15	3.5	0.004	0.011
--15	4	0.004	0.01
--15	4.5	0.004	0.009
--15	5	0.003	0.009
--15	5.5	0.004	0.009
--15	6	0.004	0.01
--15	6.5	0.004	0.011
--15	7	0.005	0.012
--15	7.5	0.005	0.013
--15	8	0.005	0.014
--15	8.5	0.006	0.015
--15	9	0.006	0.016
--15	9.5	0.006	0.017
--15	10	0.006	0.017
--15	10.5	0.006	0.017
--15	11	0.006	0.016
--15	11.5	0.006	0.015
-
--14	-15	0.004	0.01
--14	-14.5	0.004	0.012
--14	-14	0.005	0.013
--14	-13.5	0.005	0.015
--14	-13	0.006	0.017
--14	-12.5	0.007	0.019
--14	-12	0.007	0.021
--14	-11.5	0.008	0.023
--14	-11	0.008	0.025
--14	-10.5	0.009	0.026
--14	-10	0.009	0.027
--14	-9.5	0.009	0.026
--14	-9	0.008	0.025
--14	-8.5	0.008	0.023
--14	-8	0.007	0.021
--14	-7.5	0.007	0.019
--14	-7	0.006	0.017
--14	-6.5	0.005	0.015
--14	-6	0.005	0.013
--14	-5.5	0.004	0.012
--14	-5	0.004	0.01
--14	-4.5	0.004	0.012
--14	-4	0.005	0.013
--14	-3.5	0.005	0.015
--14	-3	0.006	0.017
--14	-2.5	0.007	0.019
--14	-2	0.007	0.021
--14	-1.5	0.008	0.023
--14	-1	0.008	0.025
--14	-0.5	0.009	0.026
--14	0	0.009	0.027
--14	0.5	0.009	0.026
--14	1	0.008	0.025
--14	1.5	0.008	0.023
--14	2	0.007	0.021
--14	2.5	0.007	0.019
--14	3	0.006	0.017
--14	3.5	0.005	0.015
--14	4	0.005	0.013
--14	4.5	0.004	0.012
--14	5	0.004	0.01
--14	5.5	0.004	0.012
--14	6	0.005	0.013
--14	6.5	0.005	0.015
--14	7	0.006	0.017
--14	7.5	0.007	0.019
--14	8	0.007	0.021
--14	8.5	0.008	0.023
--14	9	0.008	0.025
--14	9.5	0.009	0.026
--14	10	0.009	0.027
--14	10.5	0.009	0.026
--14	11	0.008	0.025
--14	11.5	0.008	0.023
-
--13	-15	0.005	0.012
--13	-14.5	0.005	0.014
--13	-14	0.006	0.017
--13	-13.5	0.007	0.02
--13	-13	0.008	0.024
--13	-12.5	0.009	0.028
--13	-12	0.01	0.033
--13	-11.5	0.012	0.039
--13	-11	0.013	0.044
--13	-10.5	0.014	0.048
--13	-10	0.014	0.05
--13	-9.5	0.014	0.048
--13	-9	0.013	0.044
--13	-8.5	0.012	0.039
--13	-8	0.01	0.033
--13	-7.5	0.009	0.028
--13	-7	0.008	0.024
--13	-6.5	0.007	0.02
--13	-6	0.006	0.017
--13	-5.5	0.005	0.014
--13	-5	0.005	0.012
--13	-4.5	0.005	0.014
--13	-4	0.006	0.017
--13	-3.5	0.007	0.02
--13	-3	0.008	0.024
--13	-2.5	0.009	0.028
--13	-2	0.01	0.033
--13	-1.5	0.012	0.039
--13	-1	0.013	0.044
--13	-0.5	0.014	0.048
--13	0	0.014	0.05
--13	0.5	0.014	0.048
--13	1	0.013	0.044
--13	1.5	0.012	0.039
--13	2	0.01	0.033
--13	2.5	0.009	0.028
--13	3	0.008	0.024
--13	3.5	0.007	0.02
--13	4	0.006	0.017
--13	4.5	0.005	0.014
--13	5	0.005	0.012
--13	5.5	0.005	0.014
--13	6	0.006	0.017
--13	6.5	0.007	0.02
--13	7	0.008	0.024
--13	7.5	0.009	0.028
--13	8	0.01	0.033
--13	8.5	0.012	0.039
--13	9	0.013	0.044
--13	9.5	0.014	0.048
--13	10	0.014	0.05
--13	10.5	0.014	0.048
--13	11	0.013	0.044
--13	11.5	0.012	0.039
-
--12	-15	0.005	0.014
--12	-14.5	0.006	0.017
--12	-14	0.007	0.021
--12	-13.5	0.009	0.026
--12	-13	0.01	0.033
--12	-12.5	0.013	0.043
--12	-12	0.016	0.057
--12	-11.5	0.019	0.074
--12	-11	0.023	0.094
--12	-10.5	0.026	0.11
--12	-10	0.027	0.117
--12	-9.5	0.026	0.11
--12	-9	0.023	0.094
--12	-8.5	0.019	0.074
--12	-8	0.016	0.057
--12	-7.5	0.013	0.043
--12	-7	0.01	0.033
--12	-6.5	0.009	0.026
--12	-6	0.007	0.021
--12	-5.5	0.006	0.017
--12	-5	0.005	0.014
--12	-4.5	0.006	0.017
--12	-4	0.007	0.021
--12	-3.5	0.009	0.026
--12	-3	0.01	0.033
--12	-2.5	0.013	0.043
--12	-2	0.016	0.057
--12	-1.5	0.019	0.074
--12	-1	0.023	0.094
--12	-0.5	0.026	0.11
--12	0	0.027	0.117
--12	0.5	0.026	0.11
--12	1	0.023	0.094
--12	1.5	0.019	0.074
--12	2	0.016	0.057
--12	2.5	0.013	0.043
--12	3	0.01	0.033
--12	3.5	0.009	0.026
--12	4	0.007	0.021
--12	4.5	0.006	0.017
--12	5	0.005	0.014
--12	5.5	0.006	0.017
--12	6	0.007	0.021
--12	6.5	0.009	0.026
--12	7	0.01	0.033
--12	7.5	0.013	0.043
--12	8	0.016	0.057
--12	8.5	0.019	0.074
--12	9	0.023	0.094
--12	9.5	0.026	0.11
--12	10	0.027	0.117
--12	10.5	0.026	0.11
--12	11	0.023	0.094
--12	11.5	0.019	0.074
-
--11	-15	0.006	0.016
--11	-14.5	0.007	0.02
--11	-14	0.008	0.025
--11	-13.5	0.01	0.033
--11	-13	0.013	0.044
--11	-12.5	0.017	0.063
--11	-12	0.023	0.094
--11	-11.5	0.031	0.141
--11	-11	0.044	0.196
--11	-10.5	0.057	0.228
--11	-10	0.064	0.233
--11	-9.5	0.057	0.228
--11	-9	0.044	0.196
--11	-8.5	0.031	0.141
--11	-8	0.023	0.094
--11	-7.5	0.017	0.063
--11	-7	0.013	0.044
--11	-6.5	0.01	0.033
--11	-6	0.008	0.025
--11	-5.5	0.007	0.02
--11	-5	0.006	0.016
--11	-4.5	0.007	0.02
--11	-4	0.008	0.025
--11	-3.5	0.01	0.033
--11	-3	0.013	0.044
--11	-2.5	0.017	0.063
--11	-2	0.023	0.094
--11	-1.5	0.031	0.141
--11	-1	0.044	0.196
--11	-0.5	0.057	0.228
--11	0	0.064	0.233
--11	0.5	0.057	0.228
--11	1	0.044	0.196
--11	1.5	0.031	0.141
--11	2	0.023	0.094
--11	2.5	0.017	0.063
--11	3	0.013	0.044
--11	3.5	0.01	0.033
--11	4	0.008	0.025
--11	4.5	0.007	0.02
--11	5	0.006	0.016
--11	5.5	0.007	0.02
--11	6	0.008	0.025
--11	6.5	0.01	0.033
--11	7	0.013	0.044
--11	7.5	0.017	0.063
--11	8	0.023	0.094
--11	8.5	0.031	0.141
--11	9	0.044	0.196
--11	9.5	0.057	0.228
--11	10	0.064	0.233
--11	10.5	0.057	0.228
--11	11	0.044	0.196
--11	11.5	0.031	0.141
-
--10	-15	0.006	0.017
--10	-14.5	0.007	0.021
--10	-14	0.009	0.027
--10	-13.5	0.011	0.035
--10	-13	0.014	0.05
--10	-12.5	0.019	0.074
--10	-12	0.027	0.117
--10	-11.5	0.04	0.184
--10	-11	0.064	0.233
--10	-10.5	0.099	0.201
--10	-10	0.117	0.147
--10	-9.5	0.099	0.201
--10	-9	0.064	0.233
--10	-8.5	0.04	0.184
--10	-8	0.027	0.117
--10	-7.5	0.019	0.074
--10	-7	0.014	0.05
--10	-6.5	0.011	0.035
--10	-6	0.009	0.027
--10	-5.5	0.007	0.021
--10	-5	0.006	0.017
--10	-4.5	0.007	0.021
--10	-4	0.009	0.027
--10	-3.5	0.011	0.035
--10	-3	0.014	0.05
--10	-2.5	0.019	0.074
--10	-2	0.027	0.117
--10	-1.5	0.04	0.184
--10	-1	0.064	0.233
--10	-0.5	0.099	0.201
--10	0	0.117	0.147
--10	0.5	0.099	0.201
--10	1	0.064	0.233
--10	1.5	0.04	0.184
--10	2	0.027	0.117
--10	2.5	0.019	0.074
--10	3	0.014	0.05
--10	3.5	0.011	0.035
--10	4	0.009	0.027
--10	4.5	0.007	0.021
--10	5	0.006	0.017
--10	5.5	0.007	0.021
--10	6	0.009	0.027
--10	6.5	0.011	0.035
--10	7	0.014	0.05
--10	7.5	0.019	0.074
--10	8	0.027	0.117
--10	8.5	0.04	0.184
--10	9	0.064	0.233
--10	9.5	0.099	0.201
--10	10	0.117	0.147
--10	10.5	0.099	0.201
--10	11	0.064	0.233
--10	11.5	0.04	0.184
-
--9	-15	0.006	0.016
--9	-14.5	0.007	0.02
--9	-14	0.008	0.025
--9	-13.5	0.01	0.033
--9	-13	0.013	0.044
--9	-12.5	0.017	0.063
--9	-12	0.023	0.094
--9	-11.5	0.031	0.141
--9	-11	0.044	0.196
--9	-10.5	0.057	0.228
--9	-10	0.064	0.233
--9	-9.5	0.057	0.228
--9	-9	0.044	0.196
--9	-8.5	0.031	0.141
--9	-8	0.023	0.094
--9	-7.5	0.017	0.063
--9	-7	0.013	0.044
--9	-6.5	0.01	0.033
--9	-6	0.008	0.025
--9	-5.5	0.007	0.02
--9	-5	0.006	0.016
--9	-4.5	0.007	0.02
--9	-4	0.008	0.025
--9	-3.5	0.01	0.033
--9	-3	0.013	0.044
--9	-2.5	0.017	0.063
--9	-2	0.023	0.094
--9	-1.5	0.031	0.141
--9	-1	0.044	0.196
--9	-0.5	0.057	0.228
--9	0	0.064	0.233
--9	0.5	0.057	0.228
--9	1	0.044	0.196
--9	1.5	0.031	0.141
--9	2	0.023	0.094
--9	2.5	0.017	0.063
--9	3	0.013	0.044
--9	3.5	0.01	0.033
--9	4	0.008	0.025
--9	4.5	0.007	0.02
--9	5	0.006	0.016
--9	5.5	0.007	0.02
--9	6	0.008	0.025
--9	6.5	0.01	0.033
--9	7	0.013	0.044
--9	7.5	0.017	0.063
--9	8	0.023	0.094
--9	8.5	0.031	0.141
--9	9	0.044	0.196
--9	9.5	0.057	0.228
--9	10	0.064	0.233
--9	10.5	0.057	0.228
--9	11	0.044	0.196
--9	11.5	0.031	0.141
-
--8	-15	0.005	0.014
--8	-14.5	0.006	0.017
--8	-14	0.007	0.021
--8	-13.5	0.009	0.026
--8	-13	0.01	0.033
--8	-12.5	0.013	0.043
--8	-12	0.016	0.057
--8	-11.5	0.019	0.074
--8	-11	0.023	0.094
--8	-10.5	0.026	0.11
--8	-10	0.027	0.117
--8	-9.5	0.026	0.11
--8	-9	0.023	0.094
--8	-8.5	0.019	0.074
--8	-8	0.016	0.057
--8	-7.5	0.013	0.043
--8	-7	0.01	0.033
--8	-6.5	0.009	0.026
--8	-6	0.007	0.021
--8	-5.5	0.006	0.017
--8	-5	0.005	0.014
--8	-4.5	0.006	0.017
--8	-4	0.007	0.021
--8	-3.5	0.009	0.026
--8	-3	0.01	0.033
--8	-2.5	0.013	0.043
--8	-2	0.016	0.057
--8	-1.5	0.019	0.074
--8	-1	0.023	0.094
--8	-0.5	0.026	0.11
--8	0	0.027	0.117
--8	0.5	0.026	0.11
--8	1	0.023	0.094
--8	1.5	0.019	0.074
--8	2	0.016	0.057
--8	2.5	0.013	0.043
--8	3	0.01	0.033
--8	3.5	0.009	0.026
--8	4	0.007	0.021
--8	4.5	0.006	0.017
--8	5	0.005	0.014
--8	5.5	0.006	0.017
--8	6	0.007	0.021
--8	6.5	0.009	0.026
--8	7	0.01	0.033
--8	7.5	0.013	0.043
--8	8	0.016	0.057
--8	8.5	0.019	0.074
--8	9	0.023	0.094
--8	9.5	0.026	0.11
--8	10	0.027	0.117
--8	10.5	0.026	0.11
--8	11	0.023	0.094
--8	11.5	0.019	0.074
-
--7	-15	0.005	0.012
--7	-14.5	0.005	0.014
--7	-14	0.006	0.017
--7	-13.5	0.007	0.02
--7	-13	0.008	0.024
--7	-12.5	0.009	0.028
--7	-12	0.01	0.033
--7	-11.5	0.012	0.039
--7	-11	0.013	0.044
--7	-10.5	0.014	0.048
--7	-10	0.014	0.05
--7	-9.5	0.014	0.048
--7	-9	0.013	0.044
--7	-8.5	0.012	0.039
--7	-8	0.01	0.033
--7	-7.5	0.009	0.028
--7	-7	0.008	0.024
--7	-6.5	0.007	0.02
--7	-6	0.006	0.017
--7	-5.5	0.005	0.014
--7	-5	0.005	0.012
--7	-4.5	0.005	0.014
--7	-4	0.006	0.017
--7	-3.5	0.007	0.02
--7	-3	0.008	0.024
--7	-2.5	0.009	0.028
--7	-2	0.01	0.033
--7	-1.5	0.012	0.039
--7	-1	0.013	0.044
--7	-0.5	0.014	0.048
--7	0	0.014	0.05
--7	0.5	0.014	0.048
--7	1	0.013	0.044
--7	1.5	0.012	0.039
--7	2	0.01	0.033
--7	2.5	0.009	0.028
--7	3	0.008	0.024
--7	3.5	0.007	0.02
--7	4	0.006	0.017
--7	4.5	0.005	0.014
--7	5	0.005	0.012
--7	5.5	0.005	0.014
--7	6	0.006	0.017
--7	6.5	0.007	0.02
--7	7	0.008	0.024
--7	7.5	0.009	0.028
--7	8	0.01	0.033
--7	8.5	0.012	0.039
--7	9	0.013	0.044
--7	9.5	0.014	0.048
--7	10	0.014	0.05
--7	10.5	0.014	0.048
--7	11	0.013	0.044
--7	11.5	0.012	0.039
-
--6	-15	0.004	0.01
--6	-14.5	0.004	0.012
--6	-14	0.005	0.013
--6	-13.5	0.005	0.015
--6	-13	0.006	0.017
--6	-12.5	0.007	0.019
--6	-12	0.007	0.021
--6	-11.5	0.008	0.023
--6	-11	0.008	0.025
--6	-10.5	0.009	0.026
--6	-10	0.009	0.027
--6	-9.5	0.009	0.026
--6	-9	0.008	0.025
--6	-8.5	0.008	0.023
--6	-8	0.007	0.021
--6	-7.5	0.007	0.019
--6	-7	0.006	0.017
--6	-6.5	0.005	0.015
--6	-6	0.005	0.013
--6	-5.5	0.004	0.012
--6	-5	0.004	0.01
--6	-4.5	0.004	0.012
--6	-4	0.005	0.013
--6	-3.5	0.005	0.015
--6	-3	0.006	0.017
--6	-2.5	0.007	0.019
--6	-2	0.007	0.021
--6	-1.5	0.008	0.023
--6	-1	0.008	0.025
--6	-0.5	0.009	0.026
--6	0	0.009	0.027
--6	0.5	0.009	0.026
--6	1	0.008	0.025
--6	1.5	0.008	0.023
--6	2	0.007	0.021
--6	2.5	0.007	0.019
--6	3	0.006	0.017
--6	3.5	0.005	0.015
--6	4	0.005	0.013
--6	4.5	0.004	0.012
--6	5	0.004	0.01
--6	5.5	0.004	0.012
--6	6	0.005	0.013
--6	6.5	0.005	0.015
--6	7	0.006	0.017
--6	7.5	0.007	0.019
--6	8	0.007	0.021
--6	8.5	0.008	0.023
--6	9	0.008	0.025
--6	9.5	0.009	0.026
--6	10	0.009	0.027
--6	10.5	0.009	0.026
--6	11	0.008	0.025
--6	11.5	0.008	0.023
-
--5	-15	0.003	0.009
--5	-14.5	0.004	0.009
--5	-14	0.004	0.01
--5	-13.5	0.004	0.011
--5	-13	0.005	0.012
--5	-12.5	0.005	0.013
--5	-12	0.005	0.014
--5	-11.5	0.006	0.015
--5	-11	0.006	0.016
--5	-10.5	0.006	0.017
--5	-10	0.006	0.017
--5	-9.5	0.006	0.017
--5	-9	0.006	0.016
--5	-8.5	0.006	0.015
--5	-8	0.005	0.014
--5	-7.5	0.005	0.013
--5	-7	0.005	0.012
--5	-6.5	0.004	0.011
--5	-6	0.004	0.01
--5	-5.5	0.004	0.009
--5	-5	0.003	0.009
--5	-4.5	0.004	0.009
--5	-4	0.004	0.01
--5	-3.5	0.004	0.011
--5	-3	0.005	0.012
--5	-2.5	0.005	0.013
--5	-2	0.005	0.014
--5	-1.5	0.006	0.015
--5	-1	0.006	0.016
--5	-0.5	0.006	0.017
--5	0	0.006	0.017
--5	0.5	0.006	0.017
--5	1	0.006	0.016
--5	1.5	0.006	0.015
--5	2	0.005	0.014
--5	2.5	0.005	0.013
--5	3	0.005	0.012
--5	3.5	0.004	0.011
--5	4	0.004	0.01
--5	4.5	0.004	0.009
--5	5	0.003	0.009
--5	5.5	0.004	0.009
--5	6	0.004	0.01
--5	6.5	0.004	0.011
--5	7	0.005	0.012
--5	7.5	0.005	0.013
--5	8	0.005	0.014
--5	8.5	0.006	0.015
--5	9	0.006	0.016
--5	9.5	0.006	0.017
--5	10	0.006	0.017
--5	10.5	0.006	0.017
--5	11	0.006	0.016
--5	11.5	0.006	0.015
-
--4	-15	0.004	0.01
--4	-14.5	0.004	0.012
--4	-14	0.005	0.013
--4	-13.5	0.005	0.015
--4	-13	0.006	0.017
--4	-12.5	0.007	0.019
--4	-12	0.007	0.021
--4	-11.5	0.008	0.023
--4	-11	0.008	0.025
--4	-10.5	0.009	0.026
--4	-10	0.009	0.027
--4	-9.5	0.009	0.026
--4	-9	0.008	0.025
--4	-8.5	0.008	0.023
--4	-8	0.007	0.021
--4	-7.5	0.007	0.019
--4	-7	0.006	0.017
--4	-6.5	0.005	0.015
--4	-6	0.005	0.013
--4	-5.5	0.004	0.012
--4	-5	0.004	0.01
--4	-4.5	0.004	0.012
--4	-4	0.005	0.013
--4	-3.5	0.005	0.015
--4	-3	0.006	0.017
--4	-2.5	0.007	0.019
--4	-2	0.007	0.021
--4	-1.5	0.008	0.023
--4	-1	0.008	0.025
--4	-0.5	0.009	0.026
--4	0	0.009	0.027
--4	0.5	0.009	0.026
--4	1	0.008	0.025
--4	1.5	0.008	0.023
--4	2	0.007	0.021
--4	2.5	0.007	0.019
--4	3	0.006	0.017
--4	3.5	0.005	0.015
--4	4	0.005	0.013
--4	4.5	0.004	0.012
--4	5	0.004	0.01
--4	5.5	0.004	0.012
--4	6	0.005	0.013
--4	6.5	0.005	0.015
--4	7	0.006	0.017
--4	7.5	0.007	0.019
--4	8	0.007	0.021
--4	8.5	0.008	0.023
--4	9	0.008	0.025
--4	9.5	0.009	0.026
--4	10	0.009	0.027
--4	10.5	0.009	0.026
--4	11	0.008	0.025
--4	11.5	0.008	0.023
-
--3	-15	0.005	0.012
--3	-14.5	0.005	0.014
--3	-14	0.006	0.017
--3	-13.5	0.007	0.02
--3	-13	0.008	0.024
--3	-12.5	0.009	0.028
--3	-12	0.01	0.033
--3	-11.5	0.012	0.039
--3	-11	0.013	0.044
--3	-10.5	0.014	0.048
--3	-10	0.014	0.05
--3	-9.5	0.014	0.048
--3	-9	0.013	0.044
--3	-8.5	0.012	0.039
--3	-8	0.01	0.033
--3	-7.5	0.009	0.028
--3	-7	0.008	0.024
--3	-6.5	0.007	0.02
--3	-6	0.006	0.017
--3	-5.5	0.005	0.014
--3	-5	0.005	0.012
--3	-4.5	0.005	0.014
--3	-4	0.006	0.017
--3	-3.5	0.007	0.02
--3	-3	0.008	0.024
--3	-2.5	0.009	0.028
--3	-2	0.01	0.033
--3	-1.5	0.012	0.039
--3	-1	0.013	0.044
--3	-0.5	0.014	0.048
--3	0	0.014	0.05
--3	0.5	0.014	0.048
--3	1	0.013	0.044
--3	1.5	0.012	0.039
--3	2	0.01	0.033
--3	2.5	0.009	0.028
--3	3	0.008	0.024
--3	3.5	0.007	0.02
--3	4	0.006	0.017
--3	4.5	0.005	0.014
--3	5	0.005	0.012
--3	5.5	0.005	0.014
--3	6	0.006	0.017
--3	6.5	0.007	0.02
--3	7	0.008	0.024
--3	7.5	0.009	0.028
--3	8	0.01	0.033
--3	8.5	0.012	0.039
--3	9	0.013	0.044
--3	9.5	0.014	0.048
--3	10	0.014	0.05
--3	10.5	0.014	0.048
--3	11	0.013	0.044
--3	11.5	0.012	0.039
-
--2	-15	0.005	0.014
--2	-14.5	0.006	0.017
--2	-14	0.007	0.021
--2	-13.5	0.009	0.026
--2	-13	0.01	0.033
--2	-12.5	0.013	0.043
--2	-12	0.016	0.057
--2	-11.5	0.019	0.074
--2	-11	0.023	0.094
--2	-10.5	0.026	0.11
--2	-10	0.027	0.117
--2	-9.5	0.026	0.11
--2	-9	0.023	0.094
--2	-8.5	0.019	0.074
--2	-8	0.016	0.057
--2	-7.5	0.013	0.043
--2	-7	0.01	0.033
--2	-6.5	0.009	0.026
--2	-6	0.007	0.021
--2	-5.5	0.006	0.017
--2	-5	0.005	0.014
--2	-4.5	0.006	0.017
--2	-4	0.007	0.021
--2	-3.5	0.009	0.026
--2	-3	0.01	0.033
--2	-2.5	0.013	0.043
--2	-2	0.016	0.057
--2	-1.5	0.019	0.074
--2	-1	0.023	0.094
--2	-0.5	0.026	0.11
--2	0	0.027	0.117
--2	0.5	0.026	0.11
--2	1	0.023	0.094
--2	1.5	0.019	0.074
--2	2	0.016	0.057
--2	2.5	0.013	0.043
--2	3	0.01	0.033
--2	3.5	0.009	0.026
--2	4	0.007	0.021
--2	4.5	0.006	0.017
--2	5	0.005	0.014
--2	5.5	0.006	0.017
--2	6	0.007	0.021
--2	6.5	0.009	0.026
--2	7	0.01	0.033
--2	7.5	0.013	0.043
--2	8	0.016	0.057
--2	8.5	0.019	0.074
--2	9	0.023	0.094
--2	9.5	0.026	0.11
--2	10	0.027	0.117
--2	10.5	0.026	0.11
--2	11	0.023	0.094
--2	11.5	0.019	0.074
-
--1	-15	0.006	0.016
--1	-14.5	0.007	0.02
--1	-14	0.008	0.025
--1	-13.5	0.01	0.033
--1	-13	0.013	0.044
--1	-12.5	0.017	0.063
--1	-12	0.023	0.094
--1	-11.5	0.031	0.141
--1	-11	0.044	0.196
--1	-10.5	0.057	0.228
--1	-10	0.064	0.233
--1	-9.5	0.057	0.228
--1	-9	0.044	0.196
--1	-8.5	0.031	0.141
--1	-8	0.023	0.094
--1	-7.5	0.017	0.063
--1	-7	0.013	0.044
--1	-6.5	0.01	0.033
--1	-6	0.008	0.025
--1	-5.5	0.007	0.02
--1	-5	0.006	0.016
--1	-4.5	0.007	0.02
--1	-4	0.008	0.025
--1	-3.5	0.01	0.033
--1	-3	0.013	0.044
--1	-2.5	0.017	0.063
--1	-2	0.023	0.094
--1	-1.5	0.031	0.141
--1	-1	0.044	0.196
--1	-0.5	0.057	0.228
--1	0	0.064	0.233
--1	0.5	0.057	0.228
--1	1	0.044	0.196
--1	1.5	0.031	0.141
--1	2	0.023	0.094
--1	2.5	0.017	0.063
--1	3	0.013	0.044
--1	3.5	0.01	0.033
--1	4	0.008	0.025
--1	4.5	0.007	0.02
--1	5	0.006	0.016
--1	5.5	0.007	0.02
--1	6	0.008	0.025
--1	6.5	0.01	0.033
--1	7	0.013	0.044
--1	7.5	0.017	0.063
--1	8	0.023	0.094
--1	8.5	0.031	0.141
--1	9	0.044	0.196
--1	9.5	0.057	0.228
--1	10	0.064	0.233
--1	10.5	0.057	0.228
--1	11	0.044	0.196
--1	11.5	0.031	0.141
-
-0	-15	0.006	0.017
-0	-14.5	0.007	0.021
-0	-14	0.009	0.027
-0	-13.5	0.011	0.035
-0	-13	0.014	0.05
-0	-12.5	0.019	0.074
-0	-12	0.027	0.117
-0	-11.5	0.04	0.184
-0	-11	0.064	0.233
-0	-10.5	0.099	0.201
-0	-10	0.117	0.147
-0	-9.5	0.099	0.201
-0	-9	0.064	0.233
-0	-8.5	0.04	0.184
-0	-8	0.027	0.117
-0	-7.5	0.019	0.074
-0	-7	0.014	0.05
-0	-6.5	0.011	0.035
-0	-6	0.009	0.027
-0	-5.5	0.007	0.021
-0	-5	0.006	0.017
-0	-4.5	0.007	0.021
-0	-4	0.009	0.027
-0	-3.5	0.011	0.035
-0	-3	0.014	0.05
-0	-2.5	0.019	0.074
-0	-2	0.027	0.117
-0	-1.5	0.04	0.184
-0	-1	0.064	0.233
-0	-0.5	0.099	0.201
-0	0	0.117	0.147
-0	0.5	0.099	0.201
-0	1	0.064	0.233
-0	1.5	0.04	0.184
-0	2	0.027	0.117
-0	2.5	0.019	0.074
-0	3	0.014	0.05
-0	3.5	0.011	0.035
-0	4	0.009	0.027
-0	4.5	0.007	0.021
-0	5	0.006	0.017
-0	5.5	0.007	0.021
-0	6	0.009	0.027
-0	6.5	0.011	0.035
-0	7	0.014	0.05
-0	7.5	0.019	0.074
-0	8	0.027	0.117
-0	8.5	0.04	0.184
-0	9	0.064	0.233
-0	9.5	0.099	0.201
-0	10	0.117	0.147
-0	10.5	0.099	0.201
-0	11	0.064	0.233
-0	11.5	0.04	0.184
-
-1	-15	0.006	0.016
-1	-14.5	0.007	0.02
-1	-14	0.008	0.025
-1	-13.5	0.01	0.033
-1	-13	0.013	0.044
-1	-12.5	0.017	0.063
-1	-12	0.023	0.094
-1	-11.5	0.031	0.141
-1	-11	0.044	0.196
-1	-10.5	0.057	0.228
-1	-10	0.064	0.233
-1	-9.5	0.057	0.228
-1	-9	0.044	0.196
-1	-8.5	0.031	0.141
-1	-8	0.023	0.094
-1	-7.5	0.017	0.063
-1	-7	0.013	0.044
-1	-6.5	0.01	0.033
-1	-6	0.008	0.025
-1	-5.5	0.007	0.02
-1	-5	0.006	0.016
-1	-4.5	0.007	0.02
-1	-4	0.008	0.025
-1	-3.5	0.01	0.033
-1	-3	0.013	0.044
-1	-2.5	0.017	0.063
-1	-2	0.023	0.094
-1	-1.5	0.031	0.141
-1	-1	0.044	0.196
-1	-0.5	0.057	0.228
-1	0	0.064	0.233
-1	0.5	0.057	0.228
-1	1	0.044	0.196
-1	1.5	0.031	0.141
-1	2	0.023	0.094
-1	2.5	0.017	0.063
-1	3	0.013	0.044
-1	3.5	0.01	0.033
-1	4	0.008	0.025
-1	4.5	0.007	0.02
-1	5	0.006	0.016
-1	5.5	0.007	0.02
-1	6	0.008	0.025
-1	6.5	0.01	0.033
-1	7	0.013	0.044
-1	7.5	0.017	0.063
-1	8	0.023	0.094
-1	8.5	0.031	0.141
-1	9	0.044	0.196
-1	9.5	0.057	0.228
-1	10	0.064	0.233
-1	10.5	0.057	0.228
-1	11	0.044	0.196
-1	11.5	0.031	0.141
-
-2	-15	0.005	0.014
-2	-14.5	0.006	0.017
-2	-14	0.007	0.021
-2	-13.5	0.009	0.026
-2	-13	0.01	0.033
-2	-12.5	0.013	0.043
-2	-12	0.016	0.057
-2	-11.5	0.019	0.074
-2	-11	0.023	0.094
-2	-10.5	0.026	0.11
-2	-10	0.027	0.117
-2	-9.5	0.026	0.11
-2	-9	0.023	0.094
-2	-8.5	0.019	0.074
-2	-8	0.016	0.057
-2	-7.5	0.013	0.043
-2	-7	0.01	0.033
-2	-6.5	0.009	0.026
-2	-6	0.007	0.021
-2	-5.5	0.006	0.017
-2	-5	0.005	0.014
-2	-4.5	0.006	0.017
-2	-4	0.007	0.021
-2	-3.5	0.009	0.026
-2	-3	0.01	0.033
-2	-2.5	0.013	0.043
-2	-2	0.016	0.057
-2	-1.5	0.019	0.074
-2	-1	0.023	0.094
-2	-0.5	0.026	0.11
-2	0	0.027	0.117
-2	0.5	0.026	0.11
-2	1	0.023	0.094
-2	1.5	0.019	0.074
-2	2	0.016	0.057
-2	2.5	0.013	0.043
-2	3	0.01	0.033
-2	3.5	0.009	0.026
-2	4	0.007	0.021
-2	4.5	0.006	0.017
-2	5	0.005	0.014
-2	5.5	0.006	0.017
-2	6	0.007	0.021
-2	6.5	0.009	0.026
-2	7	0.01	0.033
-2	7.5	0.013	0.043
-2	8	0.016	0.057
-2	8.5	0.019	0.074
-2	9	0.023	0.094
-2	9.5	0.026	0.11
-2	10	0.027	0.117
-2	10.5	0.026	0.11
-2	11	0.023	0.094
-2	11.5	0.019	0.074
-
-3	-15	0.005	0.012
-3	-14.5	0.005	0.014
-3	-14	0.006	0.017
-3	-13.5	0.007	0.02
-3	-13	0.008	0.024
-3	-12.5	0.009	0.028
-3	-12	0.01	0.033
-3	-11.5	0.012	0.039
-3	-11	0.013	0.044
-3	-10.5	0.014	0.048
-3	-10	0.014	0.05
-3	-9.5	0.014	0.048
-3	-9	0.013	0.044
-3	-8.5	0.012	0.039
-3	-8	0.01	0.033
-3	-7.5	0.009	0.028
-3	-7	0.008	0.024
-3	-6.5	0.007	0.02
-3	-6	0.006	0.017
-3	-5.5	0.005	0.014
-3	-5	0.005	0.012
-3	-4.5	0.005	0.014
-3	-4	0.006	0.017
-3	-3.5	0.007	0.02
-3	-3	0.008	0.024
-3	-2.5	0.009	0.028
-3	-2	0.01	0.033
-3	-1.5	0.012	0.039
-3	-1	0.013	0.044
-3	-0.5	0.014	0.048
-3	0	0.014	0.05
-3	0.5	0.014	0.048
-3	1	0.013	0.044
-3	1.5	0.012	0.039
-3	2	0.01	0.033
-3	2.5	0.009	0.028
-3	3	0.008	0.024
-3	3.5	0.007	0.02
-3	4	0.006	0.017
-3	4.5	0.005	0.014
-3	5	0.005	0.012
-3	5.5	0.005	0.014
-3	6	0.006	0.017
-3	6.5	0.007	0.02
-3	7	0.008	0.024
-3	7.5	0.009	0.028
-3	8	0.01	0.033
-3	8.5	0.012	0.039
-3	9	0.013	0.044
-3	9.5	0.014	0.048
-3	10	0.014	0.05
-3	10.5	0.014	0.048
-3	11	0.013	0.044
-3	11.5	0.012	0.039
-
-4	-15	0.004	0.01
-4	-14.5	0.004	0.012
-4	-14	0.005	0.013
-4	-13.5	0.005	0.015
-4	-13	0.006	0.017
-4	-12.5	0.007	0.019
-4	-12	0.007	0.021
-4	-11.5	0.008	0.023
-4	-11	0.008	0.025
-4	-10.5	0.009	0.026
-4	-10	0.009	0.027
-4	-9.5	0.009	0.026
-4	-9	0.008	0.025
-4	-8.5	0.008	0.023
-4	-8	0.007	0.021
-4	-7.5	0.007	0.019
-4	-7	0.006	0.017
-4	-6.5	0.005	0.015
-4	-6	0.005	0.013
-4	-5.5	0.004	0.012
-4	-5	0.004	0.01
-4	-4.5	0.004	0.012
-4	-4	0.005	0.013
-4	-3.5	0.005	0.015
-4	-3	0.006	0.017
-4	-2.5	0.007	0.019
-4	-2	0.007	0.021
-4	-1.5	0.008	0.023
-4	-1	0.008	0.025
-4	-0.5	0.009	0.026
-4	0	0.009	0.027
-4	0.5	0.009	0.026
-4	1	0.008	0.025
-4	1.5	0.008	0.023
-4	2	0.007	0.021
-4	2.5	0.007	0.019
-4	3	0.006	0.017
-4	3.5	0.005	0.015
-4	4	0.005	0.013
-4	4.5	0.004	0.012
-4	5	0.004	0.01
-4	5.5	0.004	0.012
-4	6	0.005	0.013
-4	6.5	0.005	0.015
-4	7	0.006	0.017
-4	7.5	0.007	0.019
-4	8	0.007	0.021
-4	8.5	0.008	0.023
-4	9	0.008	0.025
-4	9.5	0.009	0.026
-4	10	0.009	0.027
-4	10.5	0.009	0.026
-4	11	0.008	0.025
-4	11.5	0.008	0.023
-
-5	-15	0.003	0.009
-5	-14.5	0.004	0.009
-5	-14	0.004	0.01
-5	-13.5	0.004	0.011
-5	-13	0.005	0.012
-5	-12.5	0.005	0.013
-5	-12	0.005	0.014
-5	-11.5	0.006	0.015
-5	-11	0.006	0.016
-5	-10.5	0.006	0.017
-5	-10	0.006	0.017
-5	-9.5	0.006	0.017
-5	-9	0.006	0.016
-5	-8.5	0.006	0.015
-5	-8	0.005	0.014
-5	-7.5	0.005	0.013
-5	-7	0.005	0.012
-5	-6.5	0.004	0.011
-5	-6	0.004	0.01
-5	-5.5	0.004	0.009
-5	-5	0.003	0.009
-5	-4.5	0.004	0.009
-5	-4	0.004	0.01
-5	-3.5	0.004	0.011
-5	-3	0.005	0.012
-5	-2.5	0.005	0.013
-5	-2	0.005	0.014
-5	-1.5	0.006	0.015
-5	-1	0.006	0.016
-5	-0.5	0.006	0.017
-5	0	0.006	0.017
-5	0.5	0.006	0.017
-5	1	0.006	0.016
-5	1.5	0.006	0.015
-5	2	0.005	0.014
-5	2.5	0.005	0.013
-5	3	0.005	0.012
-5	3.5	0.004	0.011
-5	4	0.004	0.01
-5	4.5	0.004	0.009
-5	5	0.003	0.009
-5	5.5	0.004	0.009
-5	6	0.004	0.01
-5	6.5	0.004	0.011
-5	7	0.005	0.012
-5	7.5	0.005	0.013
-5	8	0.005	0.014
-5	8.5	0.006	0.015
-5	9	0.006	0.016
-5	9.5	0.006	0.017
-5	10	0.006	0.017
-5	10.5	0.006	0.017
-5	11	0.006	0.016
-5	11.5	0.006	0.015
-
-6	-15	0.004	0.01
-6	-14.5	0.004	0.012
-6	-14	0.005	0.013
-6	-13.5	0.005	0.015
-6	-13	0.006	0.017
-6	-12.5	0.007	0.019
-6	-12	0.007	0.021
-6	-11.5	0.008	0.023
-6	-11	0.008	0.025
-6	-10.5	0.009	0.026
-6	-10	0.009	0.027
-6	-9.5	0.009	0.026
-6	-9	0.008	0.025
-6	-8.5	0.008	0.023
-6	-8	0.007	0.021
-6	-7.5	0.007	0.019
-6	-7	0.006	0.017
-6	-6.5	0.005	0.015
-6	-6	0.005	0.013
-6	-5.5	0.004	0.012
-6	-5	0.004	0.01
-6	-4.5	0.004	0.012
-6	-4	0.005	0.013
-6	-3.5	0.005	0.015
-6	-3	0.006	0.017
-6	-2.5	0.007	0.019
-6	-2	0.007	0.021
-6	-1.5	0.008	0.023
-6	-1	0.008	0.025
-6	-0.5	0.009	0.026
-6	0	0.009	0.027
-6	0.5	0.009	0.026
-6	1	0.008	0.025
-6	1.5	0.008	0.023
-6	2	0.007	0.021
-6	2.5	0.007	0.019
-6	3	0.006	0.017
-6	3.5	0.005	0.015
-6	4	0.005	0.013
-6	4.5	0.004	0.012
-6	5	0.004	0.01
-6	5.5	0.004	0.012
-6	6	0.005	0.013
-6	6.5	0.005	0.015
-6	7	0.006	0.017
-6	7.5	0.007	0.019
-6	8	0.007	0.021
-6	8.5	0.008	0.023
-6	9	0.008	0.025
-6	9.5	0.009	0.026
-6	10	0.009	0.027
-6	10.5	0.009	0.026
-6	11	0.008	0.025
-6	11.5	0.008	0.023
-
-7	-15	0.005	0.012
-7	-14.5	0.005	0.014
-7	-14	0.006	0.017
-7	-13.5	0.007	0.02
-7	-13	0.008	0.024
-7	-12.5	0.009	0.028
-7	-12	0.01	0.033
-7	-11.5	0.012	0.039
-7	-11	0.013	0.044
-7	-10.5	0.014	0.048
-7	-10	0.014	0.05
-7	-9.5	0.014	0.048
-7	-9	0.013	0.044
-7	-8.5	0.012	0.039
-7	-8	0.01	0.033
-7	-7.5	0.009	0.028
-7	-7	0.008	0.024
-7	-6.5	0.007	0.02
-7	-6	0.006	0.017
-7	-5.5	0.005	0.014
-7	-5	0.005	0.012
-7	-4.5	0.005	0.014
-7	-4	0.006	0.017
-7	-3.5	0.007	0.02
-7	-3	0.008	0.024
-7	-2.5	0.009	0.028
-7	-2	0.01	0.033
-7	-1.5	0.012	0.039
-7	-1	0.013	0.044
-7	-0.5	0.014	0.048
-7	0	0.014	0.05
-7	0.5	0.014	0.048
-7	1	0.013	0.044
-7	1.5	0.012	0.039
-7	2	0.01	0.033
-7	2.5	0.009	0.028
-7	3	0.008	0.024
-7	3.5	0.007	0.02
-7	4	0.006	0.017
-7	4.5	0.005	0.014
-7	5	0.005	0.012
-7	5.5	0.005	0.014
-7	6	0.006	0.017
-7	6.5	0.007	0.02
-7	7	0.008	0.024
-7	7.5	0.009	0.028
-7	8	0.01	0.033
-7	8.5	0.012	0.039
-7	9	0.013	0.044
-7	9.5	0.014	0.048
-7	10	0.014	0.05
-7	10.5	0.014	0.048
-7	11	0.013	0.044
-7	11.5	0.012	0.039
-
-8	-15	0.005	0.014
-8	-14.5	0.006	0.017
-8	-14	0.007	0.021
-8	-13.5	0.009	0.026
-8	-13	0.01	0.033
-8	-12.5	0.013	0.043
-8	-12	0.016	0.057
-8	-11.5	0.019	0.074
-8	-11	0.023	0.094
-8	-10.5	0.026	0.11
-8	-10	0.027	0.117
-8	-9.5	0.026	0.11
-8	-9	0.023	0.094
-8	-8.5	0.019	0.074
-8	-8	0.016	0.057
-8	-7.5	0.013	0.043
-8	-7	0.01	0.033
-8	-6.5	0.009	0.026
-8	-6	0.007	0.021
-8	-5.5	0.006	0.017
-8	-5	0.005	0.014
-8	-4.5	0.006	0.017
-8	-4	0.007	0.021
-8	-3.5	0.009	0.026
-8	-3	0.01	0.033
-8	-2.5	0.013	0.043
-8	-2	0.016	0.057
-8	-1.5	0.019	0.074
-8	-1	0.023	0.094
-8	-0.5	0.026	0.11
-8	0	0.027	0.117
-8	0.5	0.026	0.11
-8	1	0.023	0.094
-8	1.5	0.019	0.074
-8	2	0.016	0.057
-8	2.5	0.013	0.043
-8	3	0.01	0.033
-8	3.5	0.009	0.026
-8	4	0.007	0.021
-8	4.5	0.006	0.017
-8	5	0.005	0.014
-8	5.5	0.006	0.017
-8	6	0.007	0.021
-8	6.5	0.009	0.026
-8	7	0.01	0.033
-8	7.5	0.013	0.043
-8	8	0.016	0.057
-8	8.5	0.019	0.074
-8	9	0.023	0.094
-8	9.5	0.026	0.11
-8	10	0.027	0.117
-8	10.5	0.026	0.11
-8	11	0.023	0.094
-8	11.5	0.019	0.074
-
-9	-15	0.006	0.016
-9	-14.5	0.007	0.02
-9	-14	0.008	0.025
-9	-13.5	0.01	0.033
-9	-13	0.013	0.044
-9	-12.5	0.017	0.063
-9	-12	0.023	0.094
-9	-11.5	0.031	0.141
-9	-11	0.044	0.196
-9	-10.5	0.057	0.228
-9	-10	0.064	0.233
-9	-9.5	0.057	0.228
-9	-9	0.044	0.196
-9	-8.5	0.031	0.141
-9	-8	0.023	0.094
-9	-7.5	0.017	0.063
-9	-7	0.013	0.044
-9	-6.5	0.01	0.033
-9	-6	0.008	0.025
-9	-5.5	0.007	0.02
-9	-5	0.006	0.016
-9	-4.5	0.007	0.02
-9	-4	0.008	0.025
-9	-3.5	0.01	0.033
-9	-3	0.013	0.044
-9	-2.5	0.017	0.063
-9	-2	0.023	0.094
-9	-1.5	0.031	0.141
-9	-1	0.044	0.196
-9	-0.5	0.057	0.228
-9	0	0.064	0.233
-9	0.5	0.057	0.228
-9	1	0.044	0.196
-9	1.5	0.031	0.141
-9	2	0.023	0.094
-9	2.5	0.017	0.063
-9	3	0.013	0.044
-9	3.5	0.01	0.033
-9	4	0.008	0.025
-9	4.5	0.007	0.02
-9	5	0.006	0.016
-9	5.5	0.007	0.02
-9	6	0.008	0.025
-9	6.5	0.01	0.033
-9	7	0.013	0.044
-9	7.5	0.017	0.063
-9	8	0.023	0.094
-9	8.5	0.031	0.141
-9	9	0.044	0.196
-9	9.5	0.057	0.228
-9	10	0.064	0.233
-9	10.5	0.057	0.228
-9	11	0.044	0.196
-9	11.5	0.031	0.141
-
-10	-15	0.006	0.017
-10	-14.5	0.007	0.021
-10	-14	0.009	0.027
-10	-13.5	0.011	0.035
-10	-13	0.014	0.05
-10	-12.5	0.019	0.074
-10	-12	0.027	0.117
-10	-11.5	0.04	0.184
-10	-11	0.064	0.233
-10	-10.5	0.099	0.201
-10	-10	0.117	0.147
-10	-9.5	0.099	0.201
-10	-9	0.064	0.233
-10	-8.5	0.04	0.184
-10	-8	0.027	0.117
-10	-7.5	0.019	0.074
-10	-7	0.014	0.05
-10	-6.5	0.011	0.035
-10	-6	0.009	0.027
-10	-5.5	0.007	0.021
-10	-5	0.006	0.017
-10	-4.5	0.007	0.021
-10	-4	0.009	0.027
-10	-3.5	0.011	0.035
-10	-3	0.014	0.05
-10	-2.5	0.019	0.074
-10	-2	0.027	0.117
-10	-1.5	0.04	0.184
-10	-1	0.064	0.233
-10	-0.5	0.099	0.201
-10	0	0.117	0.147
-10	0.5	0.099	0.201
-10	1	0.064	0.233
-10	1.5	0.04	0.184
-10	2	0.027	0.117
-10	2.5	0.019	0.074
-10	3	0.014	0.05
-10	3.5	0.011	0.035
-10	4	0.009	0.027
-10	4.5	0.007	0.021
-10	5	0.006	0.017
-10	5.5	0.007	0.021
-10	6	0.009	0.027
-10	6.5	0.011	0.035
-10	7	0.014	0.05
-10	7.5	0.019	0.074
-10	8	0.027	0.117
-10	8.5	0.04	0.184
-10	9	0.064	0.233
-10	9.5	0.099	0.201
-10	10	0.117	0.147
-10	10.5	0.099	0.201
-10	11	0.064	0.233
-10	11.5	0.04	0.184
-
-11	-15	0.006	0.016
-11	-14.5	0.007	0.02
-11	-14	0.008	0.025
-11	-13.5	0.01	0.033
-11	-13	0.013	0.044
-11	-12.5	0.017	0.063
-11	-12	0.023	0.094
-11	-11.5	0.031	0.141
-11	-11	0.044	0.196
-11	-10.5	0.057	0.228
-11	-10	0.064	0.233
-11	-9.5	0.057	0.228
-11	-9	0.044	0.196
-11	-8.5	0.031	0.141
-11	-8	0.023	0.094
-11	-7.5	0.017	0.063
-11	-7	0.013	0.044
-11	-6.5	0.01	0.033
-11	-6	0.008	0.025
-11	-5.5	0.007	0.02
-11	-5	0.006	0.016
-11	-4.5	0.007	0.02
-11	-4	0.008	0.025
-11	-3.5	0.01	0.033
-11	-3	0.013	0.044
-11	-2.5	0.017	0.063
-11	-2	0.023	0.094
-11	-1.5	0.031	0.141
-11	-1	0.044	0.196
-11	-0.5	0.057	0.228
-11	0	0.064	0.233
-11	0.5	0.057	0.228
-11	1	0.044	0.196
-11	1.5	0.031	0.141
-11	2	0.023	0.094
-11	2.5	0.017	0.063
-11	3	0.013	0.044
-11	3.5	0.01	0.033
-11	4	0.008	0.025
-11	4.5	0.007	0.02
-11	5	0.006	0.016
-11	5.5	0.007	0.02
-11	6	0.008	0.025
-11	6.5	0.01	0.033
-11	7	0.013	0.044
-11	7.5	0.017	0.063
-11	8	0.023	0.094
-11	8.5	0.031	0.141
-11	9	0.044	0.196
-11	9.5	0.057	0.228
-11	10	0.064	0.233
-11	10.5	0.057	0.228
-11	11	0.044	0.196
-11	11.5	0.031	0.141
-
-12	-15	0.005	0.014
-12	-14.5	0.006	0.017
-12	-14	0.007	0.021
-12	-13.5	0.009	0.026
-12	-13	0.01	0.033
-12	-12.5	0.013	0.043
-12	-12	0.016	0.057
-12	-11.5	0.019	0.074
-12	-11	0.023	0.094
-12	-10.5	0.026	0.11
-12	-10	0.027	0.117
-12	-9.5	0.026	0.11
-12	-9	0.023	0.094
-12	-8.5	0.019	0.074
-12	-8	0.016	0.057
-12	-7.5	0.013	0.043
-12	-7	0.01	0.033
-12	-6.5	0.009	0.026
-12	-6	0.007	0.021
-12	-5.5	0.006	0.017
-12	-5	0.005	0.014
-12	-4.5	0.006	0.017
-12	-4	0.007	0.021
-12	-3.5	0.009	0.026
-12	-3	0.01	0.033
-12	-2.5	0.013	0.043
-12	-2	0.016	0.057
-12	-1.5	0.019	0.074
-12	-1	0.023	0.094
-12	-0.5	0.026	0.11
-12	0	0.027	0.117
-12	0.5	0.026	0.11
-12	1	0.023	0.094
-12	1.5	0.019	0.074
-12	2	0.016	0.057
-12	2.5	0.013	0.043
-12	3	0.01	0.033
-12	3.5	0.009	0.026
-12	4	0.007	0.021
-12	4.5	0.006	0.017
-12	5	0.005	0.014
-12	5.5	0.006	0.017
-12	6	0.007	0.021
-12	6.5	0.009	0.026
-12	7	0.01	0.033
-12	7.5	0.013	0.043
-12	8	0.016	0.057
-12	8.5	0.019	0.074
-12	9	0.023	0.094
-12	9.5	0.026	0.11
-12	10	0.027	0.117
-12	10.5	0.026	0.11
-12	11	0.023	0.094
-12	11.5	0.019	0.074
-
-13	-15	0.005	0.012
-13	-14.5	0.005	0.014
-13	-14	0.006	0.017
-13	-13.5	0.007	0.02
-13	-13	0.008	0.024
-13	-12.5	0.009	0.028
-13	-12	0.01	0.033
-13	-11.5	0.012	0.039
-13	-11	0.013	0.044
-13	-10.5	0.014	0.048
-13	-10	0.014	0.05
-13	-9.5	0.014	0.048
-13	-9	0.013	0.044
-13	-8.5	0.012	0.039
-13	-8	0.01	0.033
-13	-7.5	0.009	0.028
-13	-7	0.008	0.024
-13	-6.5	0.007	0.02
-13	-6	0.006	0.017
-13	-5.5	0.005	0.014
-13	-5	0.005	0.012
-13	-4.5	0.005	0.014
-13	-4	0.006	0.017
-13	-3.5	0.007	0.02
-13	-3	0.008	0.024
-13	-2.5	0.009	0.028
-13	-2	0.01	0.033
-13	-1.5	0.012	0.039
-13	-1	0.013	0.044
-13	-0.5	0.014	0.048
-13	0	0.014	0.05
-13	0.5	0.014	0.048
-13	1	0.013	0.044
-13	1.5	0.012	0.039
-13	2	0.01	0.033
-13	2.5	0.009	0.028
-13	3	0.008	0.024
-13	3.5	0.007	0.02
-13	4	0.006	0.017
-13	4.5	0.005	0.014
-13	5	0.005	0.012
-13	5.5	0.005	0.014
-13	6	0.006	0.017
-13	6.5	0.007	0.02
-13	7	0.008	0.024
-13	7.5	0.009	0.028
-13	8	0.01	0.033
-13	8.5	0.012	0.039
-13	9	0.013	0.044
-13	9.5	0.014	0.048
-13	10	0.014	0.05
-13	10.5	0.014	0.048
-13	11	0.013	0.044
-13	11.5	0.012	0.039
-
-14	-15	0.004	0.01
-14	-14.5	0.004	0.012
-14	-14	0.005	0.013
-14	-13.5	0.005	0.015
-14	-13	0.006	0.017
-14	-12.5	0.007	0.019
-14	-12	0.007	0.021
-14	-11.5	0.008	0.023
-14	-11	0.008	0.025
-14	-10.5	0.009	0.026
-14	-10	0.009	0.027
-14	-9.5	0.009	0.026
-14	-9	0.008	0.025
-14	-8.5	0.008	0.023
-14	-8	0.007	0.021
-14	-7.5	0.007	0.019
-14	-7	0.006	0.017
-14	-6.5	0.005	0.015
-14	-6	0.005	0.013
-14	-5.5	0.004	0.012
-14	-5	0.004	0.01
-14	-4.5	0.004	0.012
-14	-4	0.005	0.013
-14	-3.5	0.005	0.015
-14	-3	0.006	0.017
-14	-2.5	0.007	0.019
-14	-2	0.007	0.021
-14	-1.5	0.008	0.023
-14	-1	0.008	0.025
-14	-0.5	0.009	0.026
-14	0	0.009	0.027
-14	0.5	0.009	0.026
-14	1	0.008	0.025
-14	1.5	0.008	0.023
-14	2	0.007	0.021
-14	2.5	0.007	0.019
-14	3	0.006	0.017
-14	3.5	0.005	0.015
-14	4	0.005	0.013
-14	4.5	0.004	0.012
-14	5	0.004	0.01
-14	5.5	0.004	0.012
-14	6	0.005	0.013
-14	6.5	0.005	0.015
-14	7	0.006	0.017
-14	7.5	0.007	0.019
-14	8	0.007	0.021
-14	8.5	0.008	0.023
-14	9	0.008	0.025
-14	9.5	0.009	0.026
-14	10	0.009	0.027
-14	10.5	0.009	0.026
-14	11	0.008	0.025
-14	11.5	0.008	0.023
diff --git a/docs/examples/test_complex_param/chan1.dat b/docs/examples/test_complex_param/chan1.dat
deleted file mode 100644
index 7d416d204ea6..000000000000
--- a/docs/examples/test_complex_param/chan1.dat
+++ /dev/null
@@ -1,33 +0,0 @@
-# chan1	avg_amplitude
-# "Gate Channel 1 (mV)"	"Average: Current (nA)"
-# 30
--15	1.63366
--14	1.48254
--13	1.3513
--12	1.24736
--11	1.17375
--10	1.12666
--9	1.17375
--8	1.24736
--7	1.3513
--6	1.48254
--5	1.63366
--4	1.48254
--3	1.3513
--2	1.24736
--1	1.17375
-0	1.12666
-1	1.17375
-2	1.24736
-3	1.3513
-4	1.48254
-5	1.63366
-6	1.48254
-7	1.3513
-8	1.24736
-9	1.17375
-10	1.12666
-11	1.17375
-12	1.24736
-13	1.3513
-14	1.48254
diff --git a/docs/examples/test_complex_param/chan1_chan2.dat b/docs/examples/test_complex_param/chan1_chan2.dat
deleted file mode 100644
index 27a88c0745ae..000000000000
--- a/docs/examples/test_complex_param/chan1_chan2.dat
+++ /dev/null
@@ -1,3032 +0,0 @@
-# chan1	chan2	amplitude
-# "Gate Channel 1 (mV)"	"Gate Channel 2 (mV)"	"Current (nA)"
-# 30	100
--15	-10	3.362
--15	-9.8	3.253
--15	-9.6	3.148
--15	-9.4	3.047
--15	-9.2	2.95
--15	-9	2.858
--15	-8.8	2.771
--15	-8.6	2.689
--15	-8.4	2.613
--15	-8.2	2.544
--15	-8	2.483
--15	-7.8	2.43
--15	-7.6	2.388
--15	-7.4	2.357
--15	-7.2	2.339
--15	-7	2.339
--15	-6.8	2.359
--15	-6.6	2.402
--15	-6.4	2.475
--15	-6.2	2.581
--15	-6	2.721
--15	-5.8	2.889
--15	-5.6	3.062
--15	-5.4	3.188
--15	-5.2	3.192
--15	-5	3.01
--15	-4.8	2.644
--15	-4.6	2.177
--15	-4.4	1.709
--15	-4.2	1.306
--15	-4	0.985
--15	-3.8	0.741
--15	-3.6	0.559
--15	-3.4	0.424
--15	-3.2	0.323
--15	-3	0.247
--15	-2.8	0.19
--15	-2.6	0.146
--15	-2.4	0.112
--15	-2.2	0.086
--15	-2	0.066
--15	-1.8	0.051
--15	-1.6	0.039
--15	-1.4	0.029
--15	-1.2	0.022
--15	-1	0.017
--15	-0.8	0.013
--15	-0.6	0.01
--15	-0.4	0.008
--15	-0.2	0.007
--15	0	0.006
--15	0.2	0.007
--15	0.4	0.008
--15	0.6	0.01
--15	0.8	0.013
--15	1	0.017
--15	1.2	0.022
--15	1.4	0.029
--15	1.6	0.039
--15	1.8	0.051
--15	2	0.066
--15	2.2	0.086
--15	2.4	0.112
--15	2.6	0.146
--15	2.8	0.19
--15	3	0.247
--15	3.2	0.323
--15	3.4	0.424
--15	3.6	0.559
--15	3.8	0.741
--15	4	0.985
--15	4.2	1.306
--15	4.4	1.709
--15	4.6	2.177
--15	4.8	2.644
--15	5	3.01
--15	5.2	3.192
--15	5.4	3.188
--15	5.6	3.062
--15	5.8	2.889
--15	6	2.721
--15	6.2	2.581
--15	6.4	2.475
--15	6.6	2.402
--15	6.8	2.359
--15	7	2.339
--15	7.2	2.339
--15	7.4	2.357
--15	7.6	2.388
--15	7.8	2.43
--15	8	2.483
--15	8.2	2.544
--15	8.4	2.613
--15	8.6	2.689
--15	8.8	2.771
--15	9	2.858
--15	9.2	2.95
--15	9.4	3.047
--15	9.6	3.148
--15	9.8	3.253
-
--14	-10	3.279
--14	-9.8	3.163
--14	-9.6	3.05
--14	-9.4	2.94
--14	-9.2	2.833
--14	-9	2.73
--14	-8.8	2.63
--14	-8.6	2.533
--14	-8.4	2.44
--14	-8.2	2.351
--14	-8	2.265
--14	-7.8	2.184
--14	-7.6	2.108
--14	-7.4	2.036
--14	-7.2	1.97
--14	-7	1.91
--14	-6.8	1.857
--14	-6.6	1.811
--14	-6.4	1.773
--14	-6.2	1.746
--14	-6	1.731
--14	-5.8	1.73
--14	-5.6	1.745
--14	-5.4	1.779
--14	-5.2	1.835
--14	-5	1.912
--14	-4.8	2.005
--14	-4.6	2.097
--14	-4.4	2.152
--14	-4.2	2.122
--14	-4	1.968
--14	-3.8	1.699
--14	-3.6	1.372
--14	-3.4	1.055
--14	-3.2	0.788
--14	-3	0.58
--14	-2.8	0.425
--14	-2.6	0.311
--14	-2.4	0.228
--14	-2.2	0.168
--14	-2	0.124
--14	-1.8	0.091
--14	-1.6	0.067
--14	-1.4	0.049
--14	-1.2	0.036
--14	-1	0.027
--14	-0.8	0.02
--14	-0.6	0.015
--14	-0.4	0.012
--14	-0.2	0.01
--14	0	0.009
--14	0.2	0.01
--14	0.4	0.012
--14	0.6	0.015
--14	0.8	0.02
--14	1	0.027
--14	1.2	0.036
--14	1.4	0.049
--14	1.6	0.067
--14	1.8	0.091
--14	2	0.124
--14	2.2	0.168
--14	2.4	0.228
--14	2.6	0.311
--14	2.8	0.425
--14	3	0.58
--14	3.2	0.788
--14	3.4	1.055
--14	3.6	1.372
--14	3.8	1.699
--14	4	1.968
--14	4.2	2.122
--14	4.4	2.152
--14	4.6	2.097
--14	4.8	2.005
--14	5	1.912
--14	5.2	1.835
--14	5.4	1.779
--14	5.6	1.745
--14	5.8	1.73
--14	6	1.731
--14	6.2	1.746
--14	6.4	1.773
--14	6.6	1.811
--14	6.8	1.857
--14	7	1.91
--14	7.2	1.97
--14	7.4	2.036
--14	7.6	2.108
--14	7.8	2.184
--14	8	2.265
--14	8.2	2.351
--14	8.4	2.44
--14	8.6	2.533
--14	8.8	2.63
--14	9	2.73
--14	9.2	2.833
--14	9.4	2.94
--14	9.6	3.05
--14	9.8	3.163
-
--13	-10	3.232
--13	-9.8	3.113
--13	-9.6	2.996
--13	-9.4	2.882
--13	-9.2	2.771
--13	-9	2.663
--13	-8.8	2.557
--13	-8.6	2.454
--13	-8.4	2.355
--13	-8.2	2.258
--13	-8	2.164
--13	-7.8	2.073
--13	-7.6	1.986
--13	-7.4	1.901
--13	-7.2	1.82
--13	-7	1.743
--13	-6.8	1.669
--13	-6.6	1.599
--13	-6.4	1.533
--13	-6.2	1.471
--13	-6	1.414
--13	-5.8	1.361
--13	-5.6	1.315
--13	-5.4	1.275
--13	-5.2	1.242
--13	-5	1.216
--13	-4.8	1.2
--13	-4.6	1.195
--13	-4.4	1.201
--13	-4.2	1.22
--13	-4	1.25
--13	-3.8	1.288
--13	-3.6	1.321
--13	-3.4	1.328
--13	-3.2	1.28
--13	-3	1.158
--13	-2.8	0.973
--13	-2.6	0.763
--13	-2.4	0.569
--13	-2.2	0.41
--13	-2	0.291
--13	-1.8	0.204
--13	-1.6	0.143
--13	-1.4	0.1
--13	-1.2	0.07
--13	-1	0.05
--13	-0.8	0.035
--13	-0.6	0.026
--13	-0.4	0.02
--13	-0.2	0.016
--13	0	0.014
--13	0.2	0.016
--13	0.4	0.02
--13	0.6	0.026
--13	0.8	0.035
--13	1	0.05
--13	1.2	0.07
--13	1.4	0.1
--13	1.6	0.143
--13	1.8	0.204
--13	2	0.291
--13	2.2	0.41
--13	2.4	0.569
--13	2.6	0.763
--13	2.8	0.973
--13	3	1.158
--13	3.2	1.28
--13	3.4	1.328
--13	3.6	1.321
--13	3.8	1.288
--13	4	1.25
--13	4.2	1.22
--13	4.4	1.201
--13	4.6	1.195
--13	4.8	1.2
--13	5	1.216
--13	5.2	1.242
--13	5.4	1.275
--13	5.6	1.315
--13	5.8	1.361
--13	6	1.414
--13	6.2	1.471
--13	6.4	1.533
--13	6.6	1.599
--13	6.8	1.669
--13	7	1.743
--13	7.2	1.82
--13	7.4	1.901
--13	7.6	1.986
--13	7.8	2.073
--13	8	2.164
--13	8.2	2.258
--13	8.4	2.355
--13	8.6	2.454
--13	8.8	2.557
--13	9	2.663
--13	9.2	2.771
--13	9.4	2.882
--13	9.6	2.996
--13	9.8	3.113
-
--12	-10	3.203
--12	-9.8	3.082
--12	-9.6	2.964
--12	-9.4	2.848
--12	-9.2	2.735
--12	-9	2.624
--12	-8.8	2.516
--12	-8.6	2.411
--12	-8.4	2.308
--12	-8.2	2.208
--12	-8	2.111
--12	-7.8	2.016
--12	-7.6	1.924
--12	-7.4	1.835
--12	-7.2	1.748
--12	-7	1.665
--12	-6.8	1.584
--12	-6.6	1.506
--12	-6.4	1.431
--12	-6.2	1.359
--12	-6	1.29
--12	-5.8	1.224
--12	-5.6	1.161
--12	-5.4	1.102
--12	-5.2	1.046
--12	-5	0.993
--12	-4.8	0.945
--12	-4.6	0.901
--12	-4.4	0.861
--12	-4.2	0.825
--12	-4	0.795
--12	-3.8	0.771
--12	-3.6	0.753
--12	-3.4	0.741
--12	-3.2	0.736
--12	-3	0.736
--12	-2.8	0.738
--12	-2.6	0.735
--12	-2.4	0.715
--12	-2.2	0.666
--12	-2	0.58
--12	-1.8	0.468
--12	-1.6	0.351
--12	-1.4	0.25
--12	-1.2	0.172
--12	-1	0.117
--12	-0.8	0.08
--12	-0.6	0.055
--12	-0.4	0.04
--12	-0.2	0.031
--12	0	0.027
--12	0.2	0.031
--12	0.4	0.04
--12	0.6	0.055
--12	0.8	0.08
--12	1	0.117
--12	1.2	0.172
--12	1.4	0.25
--12	1.6	0.351
--12	1.8	0.468
--12	2	0.58
--12	2.2	0.666
--12	2.4	0.715
--12	2.6	0.735
--12	2.8	0.738
--12	3	0.736
--12	3.2	0.736
--12	3.4	0.741
--12	3.6	0.753
--12	3.8	0.771
--12	4	0.795
--12	4.2	0.825
--12	4.4	0.861
--12	4.6	0.901
--12	4.8	0.945
--12	5	0.993
--12	5.2	1.046
--12	5.4	1.102
--12	5.6	1.161
--12	5.8	1.224
--12	6	1.29
--12	6.2	1.359
--12	6.4	1.431
--12	6.6	1.506
--12	6.8	1.584
--12	7	1.665
--12	7.2	1.748
--12	7.4	1.835
--12	7.6	1.924
--12	7.8	2.016
--12	8	2.111
--12	8.2	2.208
--12	8.4	2.308
--12	8.6	2.411
--12	8.8	2.516
--12	9	2.624
--12	9.2	2.735
--12	9.4	2.848
--12	9.6	2.964
--12	9.8	3.082
-
--11	-10	3.185
--11	-9.8	3.063
--11	-9.6	2.943
--11	-9.4	2.827
--11	-9.2	2.712
--11	-9	2.601
--11	-8.8	2.491
--11	-8.6	2.385
--11	-8.4	2.281
--11	-8.2	2.179
--11	-8	2.08
--11	-7.8	1.984
--11	-7.6	1.89
--11	-7.4	1.799
--11	-7.2	1.71
--11	-7	1.624
--11	-6.8	1.54
--11	-6.6	1.459
--11	-6.4	1.381
--11	-6.2	1.305
--11	-6	1.232
--11	-5.8	1.161
--11	-5.6	1.094
--11	-5.4	1.029
--11	-5.2	0.966
--11	-5	0.906
--11	-4.8	0.849
--11	-4.6	0.795
--11	-4.4	0.744
--11	-4.2	0.695
--11	-4	0.65
--11	-3.8	0.607
--11	-3.6	0.567
--11	-3.4	0.531
--11	-3.2	0.498
--11	-3	0.468
--11	-2.8	0.442
--11	-2.6	0.419
--11	-2.4	0.399
--11	-2.2	0.382
--11	-2	0.368
--11	-1.8	0.354
--11	-1.6	0.337
--11	-1.4	0.313
--11	-1.2	0.279
--11	-1	0.233
--11	-0.8	0.182
--11	-0.6	0.135
--11	-0.4	0.099
--11	-0.2	0.075
--11	0	0.064
--11	0.2	0.075
--11	0.4	0.099
--11	0.6	0.135
--11	0.8	0.182
--11	1	0.233
--11	1.2	0.279
--11	1.4	0.313
--11	1.6	0.337
--11	1.8	0.354
--11	2	0.368
--11	2.2	0.382
--11	2.4	0.399
--11	2.6	0.419
--11	2.8	0.442
--11	3	0.468
--11	3.2	0.498
--11	3.4	0.531
--11	3.6	0.567
--11	3.8	0.607
--11	4	0.65
--11	4.2	0.695
--11	4.4	0.744
--11	4.6	0.795
--11	4.8	0.849
--11	5	0.906
--11	5.2	0.966
--11	5.4	1.029
--11	5.6	1.094
--11	5.8	1.161
--11	6	1.232
--11	6.2	1.305
--11	6.4	1.381
--11	6.6	1.459
--11	6.8	1.54
--11	7	1.624
--11	7.2	1.71
--11	7.4	1.799
--11	7.6	1.89
--11	7.8	1.984
--11	8	2.08
--11	8.2	2.179
--11	8.4	2.281
--11	8.6	2.385
--11	8.8	2.491
--11	9	2.601
--11	9.2	2.712
--11	9.4	2.827
--11	9.6	2.943
--11	9.8	3.063
-
--10	-10	3.173
--10	-9.8	3.05
--10	-9.6	2.93
--10	-9.4	2.813
--10	-9.2	2.698
--10	-9	2.586
--10	-8.8	2.476
--10	-8.6	2.368
--10	-8.4	2.264
--10	-8.2	2.161
--10	-8	2.062
--10	-7.8	1.964
--10	-7.6	1.869
--10	-7.4	1.777
--10	-7.2	1.687
--10	-7	1.6
--10	-6.8	1.515
--10	-6.6	1.433
--10	-6.4	1.353
--10	-6.2	1.276
--10	-6	1.202
--10	-5.8	1.129
--10	-5.6	1.06
--10	-5.4	0.993
--10	-5.2	0.928
--10	-5	0.866
--10	-4.8	0.806
--10	-4.6	0.749
--10	-4.4	0.694
--10	-4.2	0.642
--10	-4	0.593
--10	-3.8	0.546
--10	-3.6	0.501
--10	-3.4	0.459
--10	-3.2	0.419
--10	-3	0.382
--10	-2.8	0.348
--10	-2.6	0.316
--10	-2.4	0.286
--10	-2.2	0.259
--10	-2	0.234
--10	-1.8	0.212
--10	-1.6	0.192
--10	-1.4	0.175
--10	-1.2	0.16
--10	-1	0.147
--10	-0.8	0.137
--10	-0.6	0.129
--10	-0.4	0.123
--10	-0.2	0.119
--10	0	0.117
--10	0.2	0.119
--10	0.4	0.123
--10	0.6	0.129
--10	0.8	0.137
--10	1	0.147
--10	1.2	0.16
--10	1.4	0.175
--10	1.6	0.192
--10	1.8	0.212
--10	2	0.234
--10	2.2	0.259
--10	2.4	0.286
--10	2.6	0.316
--10	2.8	0.348
--10	3	0.382
--10	3.2	0.419
--10	3.4	0.459
--10	3.6	0.501
--10	3.8	0.546
--10	4	0.593
--10	4.2	0.642
--10	4.4	0.694
--10	4.6	0.749
--10	4.8	0.806
--10	5	0.866
--10	5.2	0.928
--10	5.4	0.993
--10	5.6	1.06
--10	5.8	1.129
--10	6	1.202
--10	6.2	1.276
--10	6.4	1.353
--10	6.6	1.433
--10	6.8	1.515
--10	7	1.6
--10	7.2	1.687
--10	7.4	1.777
--10	7.6	1.869
--10	7.8	1.964
--10	8	2.062
--10	8.2	2.161
--10	8.4	2.264
--10	8.6	2.368
--10	8.8	2.476
--10	9	2.586
--10	9.2	2.698
--10	9.4	2.813
--10	9.6	2.93
--10	9.8	3.05
-
--9	-10	3.185
--9	-9.8	3.063
--9	-9.6	2.943
--9	-9.4	2.827
--9	-9.2	2.712
--9	-9	2.601
--9	-8.8	2.491
--9	-8.6	2.385
--9	-8.4	2.281
--9	-8.2	2.179
--9	-8	2.08
--9	-7.8	1.984
--9	-7.6	1.89
--9	-7.4	1.799
--9	-7.2	1.71
--9	-7	1.624
--9	-6.8	1.54
--9	-6.6	1.459
--9	-6.4	1.381
--9	-6.2	1.305
--9	-6	1.232
--9	-5.8	1.161
--9	-5.6	1.094
--9	-5.4	1.029
--9	-5.2	0.966
--9	-5	0.906
--9	-4.8	0.849
--9	-4.6	0.795
--9	-4.4	0.744
--9	-4.2	0.695
--9	-4	0.65
--9	-3.8	0.607
--9	-3.6	0.567
--9	-3.4	0.531
--9	-3.2	0.498
--9	-3	0.468
--9	-2.8	0.442
--9	-2.6	0.419
--9	-2.4	0.399
--9	-2.2	0.382
--9	-2	0.368
--9	-1.8	0.354
--9	-1.6	0.337
--9	-1.4	0.313
--9	-1.2	0.279
--9	-1	0.233
--9	-0.8	0.182
--9	-0.6	0.135
--9	-0.4	0.099
--9	-0.2	0.075
--9	0	0.064
--9	0.2	0.075
--9	0.4	0.099
--9	0.6	0.135
--9	0.8	0.182
--9	1	0.233
--9	1.2	0.279
--9	1.4	0.313
--9	1.6	0.337
--9	1.8	0.354
--9	2	0.368
--9	2.2	0.382
--9	2.4	0.399
--9	2.6	0.419
--9	2.8	0.442
--9	3	0.468
--9	3.2	0.498
--9	3.4	0.531
--9	3.6	0.567
--9	3.8	0.607
--9	4	0.65
--9	4.2	0.695
--9	4.4	0.744
--9	4.6	0.795
--9	4.8	0.849
--9	5	0.906
--9	5.2	0.966
--9	5.4	1.029
--9	5.6	1.094
--9	5.8	1.161
--9	6	1.232
--9	6.2	1.305
--9	6.4	1.381
--9	6.6	1.459
--9	6.8	1.54
--9	7	1.624
--9	7.2	1.71
--9	7.4	1.799
--9	7.6	1.89
--9	7.8	1.984
--9	8	2.08
--9	8.2	2.179
--9	8.4	2.281
--9	8.6	2.385
--9	8.8	2.491
--9	9	2.601
--9	9.2	2.712
--9	9.4	2.827
--9	9.6	2.943
--9	9.8	3.063
-
--8	-10	3.203
--8	-9.8	3.082
--8	-9.6	2.964
--8	-9.4	2.848
--8	-9.2	2.735
--8	-9	2.624
--8	-8.8	2.516
--8	-8.6	2.411
--8	-8.4	2.308
--8	-8.2	2.208
--8	-8	2.111
--8	-7.8	2.016
--8	-7.6	1.924
--8	-7.4	1.835
--8	-7.2	1.748
--8	-7	1.665
--8	-6.8	1.584
--8	-6.6	1.506
--8	-6.4	1.431
--8	-6.2	1.359
--8	-6	1.29
--8	-5.8	1.224
--8	-5.6	1.161
--8	-5.4	1.102
--8	-5.2	1.046
--8	-5	0.993
--8	-4.8	0.945
--8	-4.6	0.901
--8	-4.4	0.861
--8	-4.2	0.825
--8	-4	0.795
--8	-3.8	0.771
--8	-3.6	0.753
--8	-3.4	0.741
--8	-3.2	0.736
--8	-3	0.736
--8	-2.8	0.738
--8	-2.6	0.735
--8	-2.4	0.715
--8	-2.2	0.666
--8	-2	0.58
--8	-1.8	0.468
--8	-1.6	0.351
--8	-1.4	0.25
--8	-1.2	0.172
--8	-1	0.117
--8	-0.8	0.08
--8	-0.6	0.055
--8	-0.4	0.04
--8	-0.2	0.031
--8	0	0.027
--8	0.2	0.031
--8	0.4	0.04
--8	0.6	0.055
--8	0.8	0.08
--8	1	0.117
--8	1.2	0.172
--8	1.4	0.25
--8	1.6	0.351
--8	1.8	0.468
--8	2	0.58
--8	2.2	0.666
--8	2.4	0.715
--8	2.6	0.735
--8	2.8	0.738
--8	3	0.736
--8	3.2	0.736
--8	3.4	0.741
--8	3.6	0.753
--8	3.8	0.771
--8	4	0.795
--8	4.2	0.825
--8	4.4	0.861
--8	4.6	0.901
--8	4.8	0.945
--8	5	0.993
--8	5.2	1.046
--8	5.4	1.102
--8	5.6	1.161
--8	5.8	1.224
--8	6	1.29
--8	6.2	1.359
--8	6.4	1.431
--8	6.6	1.506
--8	6.8	1.584
--8	7	1.665
--8	7.2	1.748
--8	7.4	1.835
--8	7.6	1.924
--8	7.8	2.016
--8	8	2.111
--8	8.2	2.208
--8	8.4	2.308
--8	8.6	2.411
--8	8.8	2.516
--8	9	2.624
--8	9.2	2.735
--8	9.4	2.848
--8	9.6	2.964
--8	9.8	3.082
-
--7	-10	3.232
--7	-9.8	3.113
--7	-9.6	2.996
--7	-9.4	2.882
--7	-9.2	2.771
--7	-9	2.663
--7	-8.8	2.557
--7	-8.6	2.454
--7	-8.4	2.355
--7	-8.2	2.258
--7	-8	2.164
--7	-7.8	2.073
--7	-7.6	1.986
--7	-7.4	1.901
--7	-7.2	1.82
--7	-7	1.743
--7	-6.8	1.669
--7	-6.6	1.599
--7	-6.4	1.533
--7	-6.2	1.471
--7	-6	1.414
--7	-5.8	1.361
--7	-5.6	1.315
--7	-5.4	1.275
--7	-5.2	1.242
--7	-5	1.216
--7	-4.8	1.2
--7	-4.6	1.195
--7	-4.4	1.201
--7	-4.2	1.22
--7	-4	1.25
--7	-3.8	1.288
--7	-3.6	1.321
--7	-3.4	1.328
--7	-3.2	1.28
--7	-3	1.158
--7	-2.8	0.973
--7	-2.6	0.763
--7	-2.4	0.569
--7	-2.2	0.41
--7	-2	0.291
--7	-1.8	0.204
--7	-1.6	0.143
--7	-1.4	0.1
--7	-1.2	0.07
--7	-1	0.05
--7	-0.8	0.035
--7	-0.6	0.026
--7	-0.4	0.02
--7	-0.2	0.016
--7	0	0.014
--7	0.2	0.016
--7	0.4	0.02
--7	0.6	0.026
--7	0.8	0.035
--7	1	0.05
--7	1.2	0.07
--7	1.4	0.1
--7	1.6	0.143
--7	1.8	0.204
--7	2	0.291
--7	2.2	0.41
--7	2.4	0.569
--7	2.6	0.763
--7	2.8	0.973
--7	3	1.158
--7	3.2	1.28
--7	3.4	1.328
--7	3.6	1.321
--7	3.8	1.288
--7	4	1.25
--7	4.2	1.22
--7	4.4	1.201
--7	4.6	1.195
--7	4.8	1.2
--7	5	1.216
--7	5.2	1.242
--7	5.4	1.275
--7	5.6	1.315
--7	5.8	1.361
--7	6	1.414
--7	6.2	1.471
--7	6.4	1.533
--7	6.6	1.599
--7	6.8	1.669
--7	7	1.743
--7	7.2	1.82
--7	7.4	1.901
--7	7.6	1.986
--7	7.8	2.073
--7	8	2.164
--7	8.2	2.258
--7	8.4	2.355
--7	8.6	2.454
--7	8.8	2.557
--7	9	2.663
--7	9.2	2.771
--7	9.4	2.882
--7	9.6	2.996
--7	9.8	3.113
-
--6	-10	3.279
--6	-9.8	3.163
--6	-9.6	3.05
--6	-9.4	2.94
--6	-9.2	2.833
--6	-9	2.73
--6	-8.8	2.63
--6	-8.6	2.533
--6	-8.4	2.44
--6	-8.2	2.351
--6	-8	2.265
--6	-7.8	2.184
--6	-7.6	2.108
--6	-7.4	2.036
--6	-7.2	1.97
--6	-7	1.91
--6	-6.8	1.857
--6	-6.6	1.811
--6	-6.4	1.773
--6	-6.2	1.746
--6	-6	1.731
--6	-5.8	1.73
--6	-5.6	1.745
--6	-5.4	1.779
--6	-5.2	1.835
--6	-5	1.912
--6	-4.8	2.005
--6	-4.6	2.097
--6	-4.4	2.152
--6	-4.2	2.122
--6	-4	1.968
--6	-3.8	1.699
--6	-3.6	1.372
--6	-3.4	1.055
--6	-3.2	0.788
--6	-3	0.58
--6	-2.8	0.425
--6	-2.6	0.311
--6	-2.4	0.228
--6	-2.2	0.168
--6	-2	0.124
--6	-1.8	0.091
--6	-1.6	0.067
--6	-1.4	0.049
--6	-1.2	0.036
--6	-1	0.027
--6	-0.8	0.02
--6	-0.6	0.015
--6	-0.4	0.012
--6	-0.2	0.01
--6	0	0.009
--6	0.2	0.01
--6	0.4	0.012
--6	0.6	0.015
--6	0.8	0.02
--6	1	0.027
--6	1.2	0.036
--6	1.4	0.049
--6	1.6	0.067
--6	1.8	0.091
--6	2	0.124
--6	2.2	0.168
--6	2.4	0.228
--6	2.6	0.311
--6	2.8	0.425
--6	3	0.58
--6	3.2	0.788
--6	3.4	1.055
--6	3.6	1.372
--6	3.8	1.699
--6	4	1.968
--6	4.2	2.122
--6	4.4	2.152
--6	4.6	2.097
--6	4.8	2.005
--6	5	1.912
--6	5.2	1.835
--6	5.4	1.779
--6	5.6	1.745
--6	5.8	1.73
--6	6	1.731
--6	6.2	1.746
--6	6.4	1.773
--6	6.6	1.811
--6	6.8	1.857
--6	7	1.91
--6	7.2	1.97
--6	7.4	2.036
--6	7.6	2.108
--6	7.8	2.184
--6	8	2.265
--6	8.2	2.351
--6	8.4	2.44
--6	8.6	2.533
--6	8.8	2.63
--6	9	2.73
--6	9.2	2.833
--6	9.4	2.94
--6	9.6	3.05
--6	9.8	3.163
-
--5	-10	3.362
--5	-9.8	3.253
--5	-9.6	3.148
--5	-9.4	3.047
--5	-9.2	2.95
--5	-9	2.858
--5	-8.8	2.771
--5	-8.6	2.689
--5	-8.4	2.613
--5	-8.2	2.544
--5	-8	2.483
--5	-7.8	2.43
--5	-7.6	2.388
--5	-7.4	2.357
--5	-7.2	2.339
--5	-7	2.339
--5	-6.8	2.359
--5	-6.6	2.402
--5	-6.4	2.475
--5	-6.2	2.581
--5	-6	2.721
--5	-5.8	2.889
--5	-5.6	3.062
--5	-5.4	3.188
--5	-5.2	3.192
--5	-5	3.01
--5	-4.8	2.644
--5	-4.6	2.177
--5	-4.4	1.709
--5	-4.2	1.306
--5	-4	0.985
--5	-3.8	0.741
--5	-3.6	0.559
--5	-3.4	0.424
--5	-3.2	0.323
--5	-3	0.247
--5	-2.8	0.19
--5	-2.6	0.146
--5	-2.4	0.112
--5	-2.2	0.086
--5	-2	0.066
--5	-1.8	0.051
--5	-1.6	0.039
--5	-1.4	0.029
--5	-1.2	0.022
--5	-1	0.017
--5	-0.8	0.013
--5	-0.6	0.01
--5	-0.4	0.008
--5	-0.2	0.007
--5	0	0.006
--5	0.2	0.007
--5	0.4	0.008
--5	0.6	0.01
--5	0.8	0.013
--5	1	0.017
--5	1.2	0.022
--5	1.4	0.029
--5	1.6	0.039
--5	1.8	0.051
--5	2	0.066
--5	2.2	0.086
--5	2.4	0.112
--5	2.6	0.146
--5	2.8	0.19
--5	3	0.247
--5	3.2	0.323
--5	3.4	0.424
--5	3.6	0.559
--5	3.8	0.741
--5	4	0.985
--5	4.2	1.306
--5	4.4	1.709
--5	4.6	2.177
--5	4.8	2.644
--5	5	3.01
--5	5.2	3.192
--5	5.4	3.188
--5	5.6	3.062
--5	5.8	2.889
--5	6	2.721
--5	6.2	2.581
--5	6.4	2.475
--5	6.6	2.402
--5	6.8	2.359
--5	7	2.339
--5	7.2	2.339
--5	7.4	2.357
--5	7.6	2.388
--5	7.8	2.43
--5	8	2.483
--5	8.2	2.544
--5	8.4	2.613
--5	8.6	2.689
--5	8.8	2.771
--5	9	2.858
--5	9.2	2.95
--5	9.4	3.047
--5	9.6	3.148
--5	9.8	3.253
-
--4	-10	3.279
--4	-9.8	3.163
--4	-9.6	3.05
--4	-9.4	2.94
--4	-9.2	2.833
--4	-9	2.73
--4	-8.8	2.63
--4	-8.6	2.533
--4	-8.4	2.44
--4	-8.2	2.351
--4	-8	2.265
--4	-7.8	2.184
--4	-7.6	2.108
--4	-7.4	2.036
--4	-7.2	1.97
--4	-7	1.91
--4	-6.8	1.857
--4	-6.6	1.811
--4	-6.4	1.773
--4	-6.2	1.746
--4	-6	1.731
--4	-5.8	1.73
--4	-5.6	1.745
--4	-5.4	1.779
--4	-5.2	1.835
--4	-5	1.912
--4	-4.8	2.005
--4	-4.6	2.097
--4	-4.4	2.152
--4	-4.2	2.122
--4	-4	1.968
--4	-3.8	1.699
--4	-3.6	1.372
--4	-3.4	1.055
--4	-3.2	0.788
--4	-3	0.58
--4	-2.8	0.425
--4	-2.6	0.311
--4	-2.4	0.228
--4	-2.2	0.168
--4	-2	0.124
--4	-1.8	0.091
--4	-1.6	0.067
--4	-1.4	0.049
--4	-1.2	0.036
--4	-1	0.027
--4	-0.8	0.02
--4	-0.6	0.015
--4	-0.4	0.012
--4	-0.2	0.01
--4	0	0.009
--4	0.2	0.01
--4	0.4	0.012
--4	0.6	0.015
--4	0.8	0.02
--4	1	0.027
--4	1.2	0.036
--4	1.4	0.049
--4	1.6	0.067
--4	1.8	0.091
--4	2	0.124
--4	2.2	0.168
--4	2.4	0.228
--4	2.6	0.311
--4	2.8	0.425
--4	3	0.58
--4	3.2	0.788
--4	3.4	1.055
--4	3.6	1.372
--4	3.8	1.699
--4	4	1.968
--4	4.2	2.122
--4	4.4	2.152
--4	4.6	2.097
--4	4.8	2.005
--4	5	1.912
--4	5.2	1.835
--4	5.4	1.779
--4	5.6	1.745
--4	5.8	1.73
--4	6	1.731
--4	6.2	1.746
--4	6.4	1.773
--4	6.6	1.811
--4	6.8	1.857
--4	7	1.91
--4	7.2	1.97
--4	7.4	2.036
--4	7.6	2.108
--4	7.8	2.184
--4	8	2.265
--4	8.2	2.351
--4	8.4	2.44
--4	8.6	2.533
--4	8.8	2.63
--4	9	2.73
--4	9.2	2.833
--4	9.4	2.94
--4	9.6	3.05
--4	9.8	3.163
-
--3	-10	3.232
--3	-9.8	3.113
--3	-9.6	2.996
--3	-9.4	2.882
--3	-9.2	2.771
--3	-9	2.663
--3	-8.8	2.557
--3	-8.6	2.454
--3	-8.4	2.355
--3	-8.2	2.258
--3	-8	2.164
--3	-7.8	2.073
--3	-7.6	1.986
--3	-7.4	1.901
--3	-7.2	1.82
--3	-7	1.743
--3	-6.8	1.669
--3	-6.6	1.599
--3	-6.4	1.533
--3	-6.2	1.471
--3	-6	1.414
--3	-5.8	1.361
--3	-5.6	1.315
--3	-5.4	1.275
--3	-5.2	1.242
--3	-5	1.216
--3	-4.8	1.2
--3	-4.6	1.195
--3	-4.4	1.201
--3	-4.2	1.22
--3	-4	1.25
--3	-3.8	1.288
--3	-3.6	1.321
--3	-3.4	1.328
--3	-3.2	1.28
--3	-3	1.158
--3	-2.8	0.973
--3	-2.6	0.763
--3	-2.4	0.569
--3	-2.2	0.41
--3	-2	0.291
--3	-1.8	0.204
--3	-1.6	0.143
--3	-1.4	0.1
--3	-1.2	0.07
--3	-1	0.05
--3	-0.8	0.035
--3	-0.6	0.026
--3	-0.4	0.02
--3	-0.2	0.016
--3	0	0.014
--3	0.2	0.016
--3	0.4	0.02
--3	0.6	0.026
--3	0.8	0.035
--3	1	0.05
--3	1.2	0.07
--3	1.4	0.1
--3	1.6	0.143
--3	1.8	0.204
--3	2	0.291
--3	2.2	0.41
--3	2.4	0.569
--3	2.6	0.763
--3	2.8	0.973
--3	3	1.158
--3	3.2	1.28
--3	3.4	1.328
--3	3.6	1.321
--3	3.8	1.288
--3	4	1.25
--3	4.2	1.22
--3	4.4	1.201
--3	4.6	1.195
--3	4.8	1.2
--3	5	1.216
--3	5.2	1.242
--3	5.4	1.275
--3	5.6	1.315
--3	5.8	1.361
--3	6	1.414
--3	6.2	1.471
--3	6.4	1.533
--3	6.6	1.599
--3	6.8	1.669
--3	7	1.743
--3	7.2	1.82
--3	7.4	1.901
--3	7.6	1.986
--3	7.8	2.073
--3	8	2.164
--3	8.2	2.258
--3	8.4	2.355
--3	8.6	2.454
--3	8.8	2.557
--3	9	2.663
--3	9.2	2.771
--3	9.4	2.882
--3	9.6	2.996
--3	9.8	3.113
-
--2	-10	3.203
--2	-9.8	3.082
--2	-9.6	2.964
--2	-9.4	2.848
--2	-9.2	2.735
--2	-9	2.624
--2	-8.8	2.516
--2	-8.6	2.411
--2	-8.4	2.308
--2	-8.2	2.208
--2	-8	2.111
--2	-7.8	2.016
--2	-7.6	1.924
--2	-7.4	1.835
--2	-7.2	1.748
--2	-7	1.665
--2	-6.8	1.584
--2	-6.6	1.506
--2	-6.4	1.431
--2	-6.2	1.359
--2	-6	1.29
--2	-5.8	1.224
--2	-5.6	1.161
--2	-5.4	1.102
--2	-5.2	1.046
--2	-5	0.993
--2	-4.8	0.945
--2	-4.6	0.901
--2	-4.4	0.861
--2	-4.2	0.825
--2	-4	0.795
--2	-3.8	0.771
--2	-3.6	0.753
--2	-3.4	0.741
--2	-3.2	0.736
--2	-3	0.736
--2	-2.8	0.738
--2	-2.6	0.735
--2	-2.4	0.715
--2	-2.2	0.666
--2	-2	0.58
--2	-1.8	0.468
--2	-1.6	0.351
--2	-1.4	0.25
--2	-1.2	0.172
--2	-1	0.117
--2	-0.8	0.08
--2	-0.6	0.055
--2	-0.4	0.04
--2	-0.2	0.031
--2	0	0.027
--2	0.2	0.031
--2	0.4	0.04
--2	0.6	0.055
--2	0.8	0.08
--2	1	0.117
--2	1.2	0.172
--2	1.4	0.25
--2	1.6	0.351
--2	1.8	0.468
--2	2	0.58
--2	2.2	0.666
--2	2.4	0.715
--2	2.6	0.735
--2	2.8	0.738
--2	3	0.736
--2	3.2	0.736
--2	3.4	0.741
--2	3.6	0.753
--2	3.8	0.771
--2	4	0.795
--2	4.2	0.825
--2	4.4	0.861
--2	4.6	0.901
--2	4.8	0.945
--2	5	0.993
--2	5.2	1.046
--2	5.4	1.102
--2	5.6	1.161
--2	5.8	1.224
--2	6	1.29
--2	6.2	1.359
--2	6.4	1.431
--2	6.6	1.506
--2	6.8	1.584
--2	7	1.665
--2	7.2	1.748
--2	7.4	1.835
--2	7.6	1.924
--2	7.8	2.016
--2	8	2.111
--2	8.2	2.208
--2	8.4	2.308
--2	8.6	2.411
--2	8.8	2.516
--2	9	2.624
--2	9.2	2.735
--2	9.4	2.848
--2	9.6	2.964
--2	9.8	3.082
-
--1	-10	3.185
--1	-9.8	3.063
--1	-9.6	2.943
--1	-9.4	2.827
--1	-9.2	2.712
--1	-9	2.601
--1	-8.8	2.491
--1	-8.6	2.385
--1	-8.4	2.281
--1	-8.2	2.179
--1	-8	2.08
--1	-7.8	1.984
--1	-7.6	1.89
--1	-7.4	1.799
--1	-7.2	1.71
--1	-7	1.624
--1	-6.8	1.54
--1	-6.6	1.459
--1	-6.4	1.381
--1	-6.2	1.305
--1	-6	1.232
--1	-5.8	1.161
--1	-5.6	1.094
--1	-5.4	1.029
--1	-5.2	0.966
--1	-5	0.906
--1	-4.8	0.849
--1	-4.6	0.795
--1	-4.4	0.744
--1	-4.2	0.695
--1	-4	0.65
--1	-3.8	0.607
--1	-3.6	0.567
--1	-3.4	0.531
--1	-3.2	0.498
--1	-3	0.468
--1	-2.8	0.442
--1	-2.6	0.419
--1	-2.4	0.399
--1	-2.2	0.382
--1	-2	0.368
--1	-1.8	0.354
--1	-1.6	0.337
--1	-1.4	0.313
--1	-1.2	0.279
--1	-1	0.233
--1	-0.8	0.182
--1	-0.6	0.135
--1	-0.4	0.099
--1	-0.2	0.075
--1	0	0.064
--1	0.2	0.075
--1	0.4	0.099
--1	0.6	0.135
--1	0.8	0.182
--1	1	0.233
--1	1.2	0.279
--1	1.4	0.313
--1	1.6	0.337
--1	1.8	0.354
--1	2	0.368
--1	2.2	0.382
--1	2.4	0.399
--1	2.6	0.419
--1	2.8	0.442
--1	3	0.468
--1	3.2	0.498
--1	3.4	0.531
--1	3.6	0.567
--1	3.8	0.607
--1	4	0.65
--1	4.2	0.695
--1	4.4	0.744
--1	4.6	0.795
--1	4.8	0.849
--1	5	0.906
--1	5.2	0.966
--1	5.4	1.029
--1	5.6	1.094
--1	5.8	1.161
--1	6	1.232
--1	6.2	1.305
--1	6.4	1.381
--1	6.6	1.459
--1	6.8	1.54
--1	7	1.624
--1	7.2	1.71
--1	7.4	1.799
--1	7.6	1.89
--1	7.8	1.984
--1	8	2.08
--1	8.2	2.179
--1	8.4	2.281
--1	8.6	2.385
--1	8.8	2.491
--1	9	2.601
--1	9.2	2.712
--1	9.4	2.827
--1	9.6	2.943
--1	9.8	3.063
-
-0	-10	3.173
-0	-9.8	3.05
-0	-9.6	2.93
-0	-9.4	2.813
-0	-9.2	2.698
-0	-9	2.586
-0	-8.8	2.476
-0	-8.6	2.368
-0	-8.4	2.264
-0	-8.2	2.161
-0	-8	2.062
-0	-7.8	1.964
-0	-7.6	1.869
-0	-7.4	1.777
-0	-7.2	1.687
-0	-7	1.6
-0	-6.8	1.515
-0	-6.6	1.433
-0	-6.4	1.353
-0	-6.2	1.276
-0	-6	1.202
-0	-5.8	1.129
-0	-5.6	1.06
-0	-5.4	0.993
-0	-5.2	0.928
-0	-5	0.866
-0	-4.8	0.806
-0	-4.6	0.749
-0	-4.4	0.694
-0	-4.2	0.642
-0	-4	0.593
-0	-3.8	0.546
-0	-3.6	0.501
-0	-3.4	0.459
-0	-3.2	0.419
-0	-3	0.382
-0	-2.8	0.348
-0	-2.6	0.316
-0	-2.4	0.286
-0	-2.2	0.259
-0	-2	0.234
-0	-1.8	0.212
-0	-1.6	0.192
-0	-1.4	0.175
-0	-1.2	0.16
-0	-1	0.147
-0	-0.8	0.137
-0	-0.6	0.129
-0	-0.4	0.123
-0	-0.2	0.119
-0	0	0.117
-0	0.2	0.119
-0	0.4	0.123
-0	0.6	0.129
-0	0.8	0.137
-0	1	0.147
-0	1.2	0.16
-0	1.4	0.175
-0	1.6	0.192
-0	1.8	0.212
-0	2	0.234
-0	2.2	0.259
-0	2.4	0.286
-0	2.6	0.316
-0	2.8	0.348
-0	3	0.382
-0	3.2	0.419
-0	3.4	0.459
-0	3.6	0.501
-0	3.8	0.546
-0	4	0.593
-0	4.2	0.642
-0	4.4	0.694
-0	4.6	0.749
-0	4.8	0.806
-0	5	0.866
-0	5.2	0.928
-0	5.4	0.993
-0	5.6	1.06
-0	5.8	1.129
-0	6	1.202
-0	6.2	1.276
-0	6.4	1.353
-0	6.6	1.433
-0	6.8	1.515
-0	7	1.6
-0	7.2	1.687
-0	7.4	1.777
-0	7.6	1.869
-0	7.8	1.964
-0	8	2.062
-0	8.2	2.161
-0	8.4	2.264
-0	8.6	2.368
-0	8.8	2.476
-0	9	2.586
-0	9.2	2.698
-0	9.4	2.813
-0	9.6	2.93
-0	9.8	3.05
-
-1	-10	3.185
-1	-9.8	3.063
-1	-9.6	2.943
-1	-9.4	2.827
-1	-9.2	2.712
-1	-9	2.601
-1	-8.8	2.491
-1	-8.6	2.385
-1	-8.4	2.281
-1	-8.2	2.179
-1	-8	2.08
-1	-7.8	1.984
-1	-7.6	1.89
-1	-7.4	1.799
-1	-7.2	1.71
-1	-7	1.624
-1	-6.8	1.54
-1	-6.6	1.459
-1	-6.4	1.381
-1	-6.2	1.305
-1	-6	1.232
-1	-5.8	1.161
-1	-5.6	1.094
-1	-5.4	1.029
-1	-5.2	0.966
-1	-5	0.906
-1	-4.8	0.849
-1	-4.6	0.795
-1	-4.4	0.744
-1	-4.2	0.695
-1	-4	0.65
-1	-3.8	0.607
-1	-3.6	0.567
-1	-3.4	0.531
-1	-3.2	0.498
-1	-3	0.468
-1	-2.8	0.442
-1	-2.6	0.419
-1	-2.4	0.399
-1	-2.2	0.382
-1	-2	0.368
-1	-1.8	0.354
-1	-1.6	0.337
-1	-1.4	0.313
-1	-1.2	0.279
-1	-1	0.233
-1	-0.8	0.182
-1	-0.6	0.135
-1	-0.4	0.099
-1	-0.2	0.075
-1	0	0.064
-1	0.2	0.075
-1	0.4	0.099
-1	0.6	0.135
-1	0.8	0.182
-1	1	0.233
-1	1.2	0.279
-1	1.4	0.313
-1	1.6	0.337
-1	1.8	0.354
-1	2	0.368
-1	2.2	0.382
-1	2.4	0.399
-1	2.6	0.419
-1	2.8	0.442
-1	3	0.468
-1	3.2	0.498
-1	3.4	0.531
-1	3.6	0.567
-1	3.8	0.607
-1	4	0.65
-1	4.2	0.695
-1	4.4	0.744
-1	4.6	0.795
-1	4.8	0.849
-1	5	0.906
-1	5.2	0.966
-1	5.4	1.029
-1	5.6	1.094
-1	5.8	1.161
-1	6	1.232
-1	6.2	1.305
-1	6.4	1.381
-1	6.6	1.459
-1	6.8	1.54
-1	7	1.624
-1	7.2	1.71
-1	7.4	1.799
-1	7.6	1.89
-1	7.8	1.984
-1	8	2.08
-1	8.2	2.179
-1	8.4	2.281
-1	8.6	2.385
-1	8.8	2.491
-1	9	2.601
-1	9.2	2.712
-1	9.4	2.827
-1	9.6	2.943
-1	9.8	3.063
-
-2	-10	3.203
-2	-9.8	3.082
-2	-9.6	2.964
-2	-9.4	2.848
-2	-9.2	2.735
-2	-9	2.624
-2	-8.8	2.516
-2	-8.6	2.411
-2	-8.4	2.308
-2	-8.2	2.208
-2	-8	2.111
-2	-7.8	2.016
-2	-7.6	1.924
-2	-7.4	1.835
-2	-7.2	1.748
-2	-7	1.665
-2	-6.8	1.584
-2	-6.6	1.506
-2	-6.4	1.431
-2	-6.2	1.359
-2	-6	1.29
-2	-5.8	1.224
-2	-5.6	1.161
-2	-5.4	1.102
-2	-5.2	1.046
-2	-5	0.993
-2	-4.8	0.945
-2	-4.6	0.901
-2	-4.4	0.861
-2	-4.2	0.825
-2	-4	0.795
-2	-3.8	0.771
-2	-3.6	0.753
-2	-3.4	0.741
-2	-3.2	0.736
-2	-3	0.736
-2	-2.8	0.738
-2	-2.6	0.735
-2	-2.4	0.715
-2	-2.2	0.666
-2	-2	0.58
-2	-1.8	0.468
-2	-1.6	0.351
-2	-1.4	0.25
-2	-1.2	0.172
-2	-1	0.117
-2	-0.8	0.08
-2	-0.6	0.055
-2	-0.4	0.04
-2	-0.2	0.031
-2	0	0.027
-2	0.2	0.031
-2	0.4	0.04
-2	0.6	0.055
-2	0.8	0.08
-2	1	0.117
-2	1.2	0.172
-2	1.4	0.25
-2	1.6	0.351
-2	1.8	0.468
-2	2	0.58
-2	2.2	0.666
-2	2.4	0.715
-2	2.6	0.735
-2	2.8	0.738
-2	3	0.736
-2	3.2	0.736
-2	3.4	0.741
-2	3.6	0.753
-2	3.8	0.771
-2	4	0.795
-2	4.2	0.825
-2	4.4	0.861
-2	4.6	0.901
-2	4.8	0.945
-2	5	0.993
-2	5.2	1.046
-2	5.4	1.102
-2	5.6	1.161
-2	5.8	1.224
-2	6	1.29
-2	6.2	1.359
-2	6.4	1.431
-2	6.6	1.506
-2	6.8	1.584
-2	7	1.665
-2	7.2	1.748
-2	7.4	1.835
-2	7.6	1.924
-2	7.8	2.016
-2	8	2.111
-2	8.2	2.208
-2	8.4	2.308
-2	8.6	2.411
-2	8.8	2.516
-2	9	2.624
-2	9.2	2.735
-2	9.4	2.848
-2	9.6	2.964
-2	9.8	3.082
-
-3	-10	3.232
-3	-9.8	3.113
-3	-9.6	2.996
-3	-9.4	2.882
-3	-9.2	2.771
-3	-9	2.663
-3	-8.8	2.557
-3	-8.6	2.454
-3	-8.4	2.355
-3	-8.2	2.258
-3	-8	2.164
-3	-7.8	2.073
-3	-7.6	1.986
-3	-7.4	1.901
-3	-7.2	1.82
-3	-7	1.743
-3	-6.8	1.669
-3	-6.6	1.599
-3	-6.4	1.533
-3	-6.2	1.471
-3	-6	1.414
-3	-5.8	1.361
-3	-5.6	1.315
-3	-5.4	1.275
-3	-5.2	1.242
-3	-5	1.216
-3	-4.8	1.2
-3	-4.6	1.195
-3	-4.4	1.201
-3	-4.2	1.22
-3	-4	1.25
-3	-3.8	1.288
-3	-3.6	1.321
-3	-3.4	1.328
-3	-3.2	1.28
-3	-3	1.158
-3	-2.8	0.973
-3	-2.6	0.763
-3	-2.4	0.569
-3	-2.2	0.41
-3	-2	0.291
-3	-1.8	0.204
-3	-1.6	0.143
-3	-1.4	0.1
-3	-1.2	0.07
-3	-1	0.05
-3	-0.8	0.035
-3	-0.6	0.026
-3	-0.4	0.02
-3	-0.2	0.016
-3	0	0.014
-3	0.2	0.016
-3	0.4	0.02
-3	0.6	0.026
-3	0.8	0.035
-3	1	0.05
-3	1.2	0.07
-3	1.4	0.1
-3	1.6	0.143
-3	1.8	0.204
-3	2	0.291
-3	2.2	0.41
-3	2.4	0.569
-3	2.6	0.763
-3	2.8	0.973
-3	3	1.158
-3	3.2	1.28
-3	3.4	1.328
-3	3.6	1.321
-3	3.8	1.288
-3	4	1.25
-3	4.2	1.22
-3	4.4	1.201
-3	4.6	1.195
-3	4.8	1.2
-3	5	1.216
-3	5.2	1.242
-3	5.4	1.275
-3	5.6	1.315
-3	5.8	1.361
-3	6	1.414
-3	6.2	1.471
-3	6.4	1.533
-3	6.6	1.599
-3	6.8	1.669
-3	7	1.743
-3	7.2	1.82
-3	7.4	1.901
-3	7.6	1.986
-3	7.8	2.073
-3	8	2.164
-3	8.2	2.258
-3	8.4	2.355
-3	8.6	2.454
-3	8.8	2.557
-3	9	2.663
-3	9.2	2.771
-3	9.4	2.882
-3	9.6	2.996
-3	9.8	3.113
-
-4	-10	3.279
-4	-9.8	3.163
-4	-9.6	3.05
-4	-9.4	2.94
-4	-9.2	2.833
-4	-9	2.73
-4	-8.8	2.63
-4	-8.6	2.533
-4	-8.4	2.44
-4	-8.2	2.351
-4	-8	2.265
-4	-7.8	2.184
-4	-7.6	2.108
-4	-7.4	2.036
-4	-7.2	1.97
-4	-7	1.91
-4	-6.8	1.857
-4	-6.6	1.811
-4	-6.4	1.773
-4	-6.2	1.746
-4	-6	1.731
-4	-5.8	1.73
-4	-5.6	1.745
-4	-5.4	1.779
-4	-5.2	1.835
-4	-5	1.912
-4	-4.8	2.005
-4	-4.6	2.097
-4	-4.4	2.152
-4	-4.2	2.122
-4	-4	1.968
-4	-3.8	1.699
-4	-3.6	1.372
-4	-3.4	1.055
-4	-3.2	0.788
-4	-3	0.58
-4	-2.8	0.425
-4	-2.6	0.311
-4	-2.4	0.228
-4	-2.2	0.168
-4	-2	0.124
-4	-1.8	0.091
-4	-1.6	0.067
-4	-1.4	0.049
-4	-1.2	0.036
-4	-1	0.027
-4	-0.8	0.02
-4	-0.6	0.015
-4	-0.4	0.012
-4	-0.2	0.01
-4	0	0.009
-4	0.2	0.01
-4	0.4	0.012
-4	0.6	0.015
-4	0.8	0.02
-4	1	0.027
-4	1.2	0.036
-4	1.4	0.049
-4	1.6	0.067
-4	1.8	0.091
-4	2	0.124
-4	2.2	0.168
-4	2.4	0.228
-4	2.6	0.311
-4	2.8	0.425
-4	3	0.58
-4	3.2	0.788
-4	3.4	1.055
-4	3.6	1.372
-4	3.8	1.699
-4	4	1.968
-4	4.2	2.122
-4	4.4	2.152
-4	4.6	2.097
-4	4.8	2.005
-4	5	1.912
-4	5.2	1.835
-4	5.4	1.779
-4	5.6	1.745
-4	5.8	1.73
-4	6	1.731
-4	6.2	1.746
-4	6.4	1.773
-4	6.6	1.811
-4	6.8	1.857
-4	7	1.91
-4	7.2	1.97
-4	7.4	2.036
-4	7.6	2.108
-4	7.8	2.184
-4	8	2.265
-4	8.2	2.351
-4	8.4	2.44
-4	8.6	2.533
-4	8.8	2.63
-4	9	2.73
-4	9.2	2.833
-4	9.4	2.94
-4	9.6	3.05
-4	9.8	3.163
-
-5	-10	3.362
-5	-9.8	3.253
-5	-9.6	3.148
-5	-9.4	3.047
-5	-9.2	2.95
-5	-9	2.858
-5	-8.8	2.771
-5	-8.6	2.689
-5	-8.4	2.613
-5	-8.2	2.544
-5	-8	2.483
-5	-7.8	2.43
-5	-7.6	2.388
-5	-7.4	2.357
-5	-7.2	2.339
-5	-7	2.339
-5	-6.8	2.359
-5	-6.6	2.402
-5	-6.4	2.475
-5	-6.2	2.581
-5	-6	2.721
-5	-5.8	2.889
-5	-5.6	3.062
-5	-5.4	3.188
-5	-5.2	3.192
-5	-5	3.01
-5	-4.8	2.644
-5	-4.6	2.177
-5	-4.4	1.709
-5	-4.2	1.306
-5	-4	0.985
-5	-3.8	0.741
-5	-3.6	0.559
-5	-3.4	0.424
-5	-3.2	0.323
-5	-3	0.247
-5	-2.8	0.19
-5	-2.6	0.146
-5	-2.4	0.112
-5	-2.2	0.086
-5	-2	0.066
-5	-1.8	0.051
-5	-1.6	0.039
-5	-1.4	0.029
-5	-1.2	0.022
-5	-1	0.017
-5	-0.8	0.013
-5	-0.6	0.01
-5	-0.4	0.008
-5	-0.2	0.007
-5	0	0.006
-5	0.2	0.007
-5	0.4	0.008
-5	0.6	0.01
-5	0.8	0.013
-5	1	0.017
-5	1.2	0.022
-5	1.4	0.029
-5	1.6	0.039
-5	1.8	0.051
-5	2	0.066
-5	2.2	0.086
-5	2.4	0.112
-5	2.6	0.146
-5	2.8	0.19
-5	3	0.247
-5	3.2	0.323
-5	3.4	0.424
-5	3.6	0.559
-5	3.8	0.741
-5	4	0.985
-5	4.2	1.306
-5	4.4	1.709
-5	4.6	2.177
-5	4.8	2.644
-5	5	3.01
-5	5.2	3.192
-5	5.4	3.188
-5	5.6	3.062
-5	5.8	2.889
-5	6	2.721
-5	6.2	2.581
-5	6.4	2.475
-5	6.6	2.402
-5	6.8	2.359
-5	7	2.339
-5	7.2	2.339
-5	7.4	2.357
-5	7.6	2.388
-5	7.8	2.43
-5	8	2.483
-5	8.2	2.544
-5	8.4	2.613
-5	8.6	2.689
-5	8.8	2.771
-5	9	2.858
-5	9.2	2.95
-5	9.4	3.047
-5	9.6	3.148
-5	9.8	3.253
-
-6	-10	3.279
-6	-9.8	3.163
-6	-9.6	3.05
-6	-9.4	2.94
-6	-9.2	2.833
-6	-9	2.73
-6	-8.8	2.63
-6	-8.6	2.533
-6	-8.4	2.44
-6	-8.2	2.351
-6	-8	2.265
-6	-7.8	2.184
-6	-7.6	2.108
-6	-7.4	2.036
-6	-7.2	1.97
-6	-7	1.91
-6	-6.8	1.857
-6	-6.6	1.811
-6	-6.4	1.773
-6	-6.2	1.746
-6	-6	1.731
-6	-5.8	1.73
-6	-5.6	1.745
-6	-5.4	1.779
-6	-5.2	1.835
-6	-5	1.912
-6	-4.8	2.005
-6	-4.6	2.097
-6	-4.4	2.152
-6	-4.2	2.122
-6	-4	1.968
-6	-3.8	1.699
-6	-3.6	1.372
-6	-3.4	1.055
-6	-3.2	0.788
-6	-3	0.58
-6	-2.8	0.425
-6	-2.6	0.311
-6	-2.4	0.228
-6	-2.2	0.168
-6	-2	0.124
-6	-1.8	0.091
-6	-1.6	0.067
-6	-1.4	0.049
-6	-1.2	0.036
-6	-1	0.027
-6	-0.8	0.02
-6	-0.6	0.015
-6	-0.4	0.012
-6	-0.2	0.01
-6	0	0.009
-6	0.2	0.01
-6	0.4	0.012
-6	0.6	0.015
-6	0.8	0.02
-6	1	0.027
-6	1.2	0.036
-6	1.4	0.049
-6	1.6	0.067
-6	1.8	0.091
-6	2	0.124
-6	2.2	0.168
-6	2.4	0.228
-6	2.6	0.311
-6	2.8	0.425
-6	3	0.58
-6	3.2	0.788
-6	3.4	1.055
-6	3.6	1.372
-6	3.8	1.699
-6	4	1.968
-6	4.2	2.122
-6	4.4	2.152
-6	4.6	2.097
-6	4.8	2.005
-6	5	1.912
-6	5.2	1.835
-6	5.4	1.779
-6	5.6	1.745
-6	5.8	1.73
-6	6	1.731
-6	6.2	1.746
-6	6.4	1.773
-6	6.6	1.811
-6	6.8	1.857
-6	7	1.91
-6	7.2	1.97
-6	7.4	2.036
-6	7.6	2.108
-6	7.8	2.184
-6	8	2.265
-6	8.2	2.351
-6	8.4	2.44
-6	8.6	2.533
-6	8.8	2.63
-6	9	2.73
-6	9.2	2.833
-6	9.4	2.94
-6	9.6	3.05
-6	9.8	3.163
-
-7	-10	3.232
-7	-9.8	3.113
-7	-9.6	2.996
-7	-9.4	2.882
-7	-9.2	2.771
-7	-9	2.663
-7	-8.8	2.557
-7	-8.6	2.454
-7	-8.4	2.355
-7	-8.2	2.258
-7	-8	2.164
-7	-7.8	2.073
-7	-7.6	1.986
-7	-7.4	1.901
-7	-7.2	1.82
-7	-7	1.743
-7	-6.8	1.669
-7	-6.6	1.599
-7	-6.4	1.533
-7	-6.2	1.471
-7	-6	1.414
-7	-5.8	1.361
-7	-5.6	1.315
-7	-5.4	1.275
-7	-5.2	1.242
-7	-5	1.216
-7	-4.8	1.2
-7	-4.6	1.195
-7	-4.4	1.201
-7	-4.2	1.22
-7	-4	1.25
-7	-3.8	1.288
-7	-3.6	1.321
-7	-3.4	1.328
-7	-3.2	1.28
-7	-3	1.158
-7	-2.8	0.973
-7	-2.6	0.763
-7	-2.4	0.569
-7	-2.2	0.41
-7	-2	0.291
-7	-1.8	0.204
-7	-1.6	0.143
-7	-1.4	0.1
-7	-1.2	0.07
-7	-1	0.05
-7	-0.8	0.035
-7	-0.6	0.026
-7	-0.4	0.02
-7	-0.2	0.016
-7	0	0.014
-7	0.2	0.016
-7	0.4	0.02
-7	0.6	0.026
-7	0.8	0.035
-7	1	0.05
-7	1.2	0.07
-7	1.4	0.1
-7	1.6	0.143
-7	1.8	0.204
-7	2	0.291
-7	2.2	0.41
-7	2.4	0.569
-7	2.6	0.763
-7	2.8	0.973
-7	3	1.158
-7	3.2	1.28
-7	3.4	1.328
-7	3.6	1.321
-7	3.8	1.288
-7	4	1.25
-7	4.2	1.22
-7	4.4	1.201
-7	4.6	1.195
-7	4.8	1.2
-7	5	1.216
-7	5.2	1.242
-7	5.4	1.275
-7	5.6	1.315
-7	5.8	1.361
-7	6	1.414
-7	6.2	1.471
-7	6.4	1.533
-7	6.6	1.599
-7	6.8	1.669
-7	7	1.743
-7	7.2	1.82
-7	7.4	1.901
-7	7.6	1.986
-7	7.8	2.073
-7	8	2.164
-7	8.2	2.258
-7	8.4	2.355
-7	8.6	2.454
-7	8.8	2.557
-7	9	2.663
-7	9.2	2.771
-7	9.4	2.882
-7	9.6	2.996
-7	9.8	3.113
-
-8	-10	3.203
-8	-9.8	3.082
-8	-9.6	2.964
-8	-9.4	2.848
-8	-9.2	2.735
-8	-9	2.624
-8	-8.8	2.516
-8	-8.6	2.411
-8	-8.4	2.308
-8	-8.2	2.208
-8	-8	2.111
-8	-7.8	2.016
-8	-7.6	1.924
-8	-7.4	1.835
-8	-7.2	1.748
-8	-7	1.665
-8	-6.8	1.584
-8	-6.6	1.506
-8	-6.4	1.431
-8	-6.2	1.359
-8	-6	1.29
-8	-5.8	1.224
-8	-5.6	1.161
-8	-5.4	1.102
-8	-5.2	1.046
-8	-5	0.993
-8	-4.8	0.945
-8	-4.6	0.901
-8	-4.4	0.861
-8	-4.2	0.825
-8	-4	0.795
-8	-3.8	0.771
-8	-3.6	0.753
-8	-3.4	0.741
-8	-3.2	0.736
-8	-3	0.736
-8	-2.8	0.738
-8	-2.6	0.735
-8	-2.4	0.715
-8	-2.2	0.666
-8	-2	0.58
-8	-1.8	0.468
-8	-1.6	0.351
-8	-1.4	0.25
-8	-1.2	0.172
-8	-1	0.117
-8	-0.8	0.08
-8	-0.6	0.055
-8	-0.4	0.04
-8	-0.2	0.031
-8	0	0.027
-8	0.2	0.031
-8	0.4	0.04
-8	0.6	0.055
-8	0.8	0.08
-8	1	0.117
-8	1.2	0.172
-8	1.4	0.25
-8	1.6	0.351
-8	1.8	0.468
-8	2	0.58
-8	2.2	0.666
-8	2.4	0.715
-8	2.6	0.735
-8	2.8	0.738
-8	3	0.736
-8	3.2	0.736
-8	3.4	0.741
-8	3.6	0.753
-8	3.8	0.771
-8	4	0.795
-8	4.2	0.825
-8	4.4	0.861
-8	4.6	0.901
-8	4.8	0.945
-8	5	0.993
-8	5.2	1.046
-8	5.4	1.102
-8	5.6	1.161
-8	5.8	1.224
-8	6	1.29
-8	6.2	1.359
-8	6.4	1.431
-8	6.6	1.506
-8	6.8	1.584
-8	7	1.665
-8	7.2	1.748
-8	7.4	1.835
-8	7.6	1.924
-8	7.8	2.016
-8	8	2.111
-8	8.2	2.208
-8	8.4	2.308
-8	8.6	2.411
-8	8.8	2.516
-8	9	2.624
-8	9.2	2.735
-8	9.4	2.848
-8	9.6	2.964
-8	9.8	3.082
-
-9	-10	3.185
-9	-9.8	3.063
-9	-9.6	2.943
-9	-9.4	2.827
-9	-9.2	2.712
-9	-9	2.601
-9	-8.8	2.491
-9	-8.6	2.385
-9	-8.4	2.281
-9	-8.2	2.179
-9	-8	2.08
-9	-7.8	1.984
-9	-7.6	1.89
-9	-7.4	1.799
-9	-7.2	1.71
-9	-7	1.624
-9	-6.8	1.54
-9	-6.6	1.459
-9	-6.4	1.381
-9	-6.2	1.305
-9	-6	1.232
-9	-5.8	1.161
-9	-5.6	1.094
-9	-5.4	1.029
-9	-5.2	0.966
-9	-5	0.906
-9	-4.8	0.849
-9	-4.6	0.795
-9	-4.4	0.744
-9	-4.2	0.695
-9	-4	0.65
-9	-3.8	0.607
-9	-3.6	0.567
-9	-3.4	0.531
-9	-3.2	0.498
-9	-3	0.468
-9	-2.8	0.442
-9	-2.6	0.419
-9	-2.4	0.399
-9	-2.2	0.382
-9	-2	0.368
-9	-1.8	0.354
-9	-1.6	0.337
-9	-1.4	0.313
-9	-1.2	0.279
-9	-1	0.233
-9	-0.8	0.182
-9	-0.6	0.135
-9	-0.4	0.099
-9	-0.2	0.075
-9	0	0.064
-9	0.2	0.075
-9	0.4	0.099
-9	0.6	0.135
-9	0.8	0.182
-9	1	0.233
-9	1.2	0.279
-9	1.4	0.313
-9	1.6	0.337
-9	1.8	0.354
-9	2	0.368
-9	2.2	0.382
-9	2.4	0.399
-9	2.6	0.419
-9	2.8	0.442
-9	3	0.468
-9	3.2	0.498
-9	3.4	0.531
-9	3.6	0.567
-9	3.8	0.607
-9	4	0.65
-9	4.2	0.695
-9	4.4	0.744
-9	4.6	0.795
-9	4.8	0.849
-9	5	0.906
-9	5.2	0.966
-9	5.4	1.029
-9	5.6	1.094
-9	5.8	1.161
-9	6	1.232
-9	6.2	1.305
-9	6.4	1.381
-9	6.6	1.459
-9	6.8	1.54
-9	7	1.624
-9	7.2	1.71
-9	7.4	1.799
-9	7.6	1.89
-9	7.8	1.984
-9	8	2.08
-9	8.2	2.179
-9	8.4	2.281
-9	8.6	2.385
-9	8.8	2.491
-9	9	2.601
-9	9.2	2.712
-9	9.4	2.827
-9	9.6	2.943
-9	9.8	3.063
-
-10	-10	3.173
-10	-9.8	3.05
-10	-9.6	2.93
-10	-9.4	2.813
-10	-9.2	2.698
-10	-9	2.586
-10	-8.8	2.476
-10	-8.6	2.368
-10	-8.4	2.264
-10	-8.2	2.161
-10	-8	2.062
-10	-7.8	1.964
-10	-7.6	1.869
-10	-7.4	1.777
-10	-7.2	1.687
-10	-7	1.6
-10	-6.8	1.515
-10	-6.6	1.433
-10	-6.4	1.353
-10	-6.2	1.276
-10	-6	1.202
-10	-5.8	1.129
-10	-5.6	1.06
-10	-5.4	0.993
-10	-5.2	0.928
-10	-5	0.866
-10	-4.8	0.806
-10	-4.6	0.749
-10	-4.4	0.694
-10	-4.2	0.642
-10	-4	0.593
-10	-3.8	0.546
-10	-3.6	0.501
-10	-3.4	0.459
-10	-3.2	0.419
-10	-3	0.382
-10	-2.8	0.348
-10	-2.6	0.316
-10	-2.4	0.286
-10	-2.2	0.259
-10	-2	0.234
-10	-1.8	0.212
-10	-1.6	0.192
-10	-1.4	0.175
-10	-1.2	0.16
-10	-1	0.147
-10	-0.8	0.137
-10	-0.6	0.129
-10	-0.4	0.123
-10	-0.2	0.119
-10	0	0.117
-10	0.2	0.119
-10	0.4	0.123
-10	0.6	0.129
-10	0.8	0.137
-10	1	0.147
-10	1.2	0.16
-10	1.4	0.175
-10	1.6	0.192
-10	1.8	0.212
-10	2	0.234
-10	2.2	0.259
-10	2.4	0.286
-10	2.6	0.316
-10	2.8	0.348
-10	3	0.382
-10	3.2	0.419
-10	3.4	0.459
-10	3.6	0.501
-10	3.8	0.546
-10	4	0.593
-10	4.2	0.642
-10	4.4	0.694
-10	4.6	0.749
-10	4.8	0.806
-10	5	0.866
-10	5.2	0.928
-10	5.4	0.993
-10	5.6	1.06
-10	5.8	1.129
-10	6	1.202
-10	6.2	1.276
-10	6.4	1.353
-10	6.6	1.433
-10	6.8	1.515
-10	7	1.6
-10	7.2	1.687
-10	7.4	1.777
-10	7.6	1.869
-10	7.8	1.964
-10	8	2.062
-10	8.2	2.161
-10	8.4	2.264
-10	8.6	2.368
-10	8.8	2.476
-10	9	2.586
-10	9.2	2.698
-10	9.4	2.813
-10	9.6	2.93
-10	9.8	3.05
-
-11	-10	3.185
-11	-9.8	3.063
-11	-9.6	2.943
-11	-9.4	2.827
-11	-9.2	2.712
-11	-9	2.601
-11	-8.8	2.491
-11	-8.6	2.385
-11	-8.4	2.281
-11	-8.2	2.179
-11	-8	2.08
-11	-7.8	1.984
-11	-7.6	1.89
-11	-7.4	1.799
-11	-7.2	1.71
-11	-7	1.624
-11	-6.8	1.54
-11	-6.6	1.459
-11	-6.4	1.381
-11	-6.2	1.305
-11	-6	1.232
-11	-5.8	1.161
-11	-5.6	1.094
-11	-5.4	1.029
-11	-5.2	0.966
-11	-5	0.906
-11	-4.8	0.849
-11	-4.6	0.795
-11	-4.4	0.744
-11	-4.2	0.695
-11	-4	0.65
-11	-3.8	0.607
-11	-3.6	0.567
-11	-3.4	0.531
-11	-3.2	0.498
-11	-3	0.468
-11	-2.8	0.442
-11	-2.6	0.419
-11	-2.4	0.399
-11	-2.2	0.382
-11	-2	0.368
-11	-1.8	0.354
-11	-1.6	0.337
-11	-1.4	0.313
-11	-1.2	0.279
-11	-1	0.233
-11	-0.8	0.182
-11	-0.6	0.135
-11	-0.4	0.099
-11	-0.2	0.075
-11	0	0.064
-11	0.2	0.075
-11	0.4	0.099
-11	0.6	0.135
-11	0.8	0.182
-11	1	0.233
-11	1.2	0.279
-11	1.4	0.313
-11	1.6	0.337
-11	1.8	0.354
-11	2	0.368
-11	2.2	0.382
-11	2.4	0.399
-11	2.6	0.419
-11	2.8	0.442
-11	3	0.468
-11	3.2	0.498
-11	3.4	0.531
-11	3.6	0.567
-11	3.8	0.607
-11	4	0.65
-11	4.2	0.695
-11	4.4	0.744
-11	4.6	0.795
-11	4.8	0.849
-11	5	0.906
-11	5.2	0.966
-11	5.4	1.029
-11	5.6	1.094
-11	5.8	1.161
-11	6	1.232
-11	6.2	1.305
-11	6.4	1.381
-11	6.6	1.459
-11	6.8	1.54
-11	7	1.624
-11	7.2	1.71
-11	7.4	1.799
-11	7.6	1.89
-11	7.8	1.984
-11	8	2.08
-11	8.2	2.179
-11	8.4	2.281
-11	8.6	2.385
-11	8.8	2.491
-11	9	2.601
-11	9.2	2.712
-11	9.4	2.827
-11	9.6	2.943
-11	9.8	3.063
-
-12	-10	3.203
-12	-9.8	3.082
-12	-9.6	2.964
-12	-9.4	2.848
-12	-9.2	2.735
-12	-9	2.624
-12	-8.8	2.516
-12	-8.6	2.411
-12	-8.4	2.308
-12	-8.2	2.208
-12	-8	2.111
-12	-7.8	2.016
-12	-7.6	1.924
-12	-7.4	1.835
-12	-7.2	1.748
-12	-7	1.665
-12	-6.8	1.584
-12	-6.6	1.506
-12	-6.4	1.431
-12	-6.2	1.359
-12	-6	1.29
-12	-5.8	1.224
-12	-5.6	1.161
-12	-5.4	1.102
-12	-5.2	1.046
-12	-5	0.993
-12	-4.8	0.945
-12	-4.6	0.901
-12	-4.4	0.861
-12	-4.2	0.825
-12	-4	0.795
-12	-3.8	0.771
-12	-3.6	0.753
-12	-3.4	0.741
-12	-3.2	0.736
-12	-3	0.736
-12	-2.8	0.738
-12	-2.6	0.735
-12	-2.4	0.715
-12	-2.2	0.666
-12	-2	0.58
-12	-1.8	0.468
-12	-1.6	0.351
-12	-1.4	0.25
-12	-1.2	0.172
-12	-1	0.117
-12	-0.8	0.08
-12	-0.6	0.055
-12	-0.4	0.04
-12	-0.2	0.031
-12	0	0.027
-12	0.2	0.031
-12	0.4	0.04
-12	0.6	0.055
-12	0.8	0.08
-12	1	0.117
-12	1.2	0.172
-12	1.4	0.25
-12	1.6	0.351
-12	1.8	0.468
-12	2	0.58
-12	2.2	0.666
-12	2.4	0.715
-12	2.6	0.735
-12	2.8	0.738
-12	3	0.736
-12	3.2	0.736
-12	3.4	0.741
-12	3.6	0.753
-12	3.8	0.771
-12	4	0.795
-12	4.2	0.825
-12	4.4	0.861
-12	4.6	0.901
-12	4.8	0.945
-12	5	0.993
-12	5.2	1.046
-12	5.4	1.102
-12	5.6	1.161
-12	5.8	1.224
-12	6	1.29
-12	6.2	1.359
-12	6.4	1.431
-12	6.6	1.506
-12	6.8	1.584
-12	7	1.665
-12	7.2	1.748
-12	7.4	1.835
-12	7.6	1.924
-12	7.8	2.016
-12	8	2.111
-12	8.2	2.208
-12	8.4	2.308
-12	8.6	2.411
-12	8.8	2.516
-12	9	2.624
-12	9.2	2.735
-12	9.4	2.848
-12	9.6	2.964
-12	9.8	3.082
-
-13	-10	3.232
-13	-9.8	3.113
-13	-9.6	2.996
-13	-9.4	2.882
-13	-9.2	2.771
-13	-9	2.663
-13	-8.8	2.557
-13	-8.6	2.454
-13	-8.4	2.355
-13	-8.2	2.258
-13	-8	2.164
-13	-7.8	2.073
-13	-7.6	1.986
-13	-7.4	1.901
-13	-7.2	1.82
-13	-7	1.743
-13	-6.8	1.669
-13	-6.6	1.599
-13	-6.4	1.533
-13	-6.2	1.471
-13	-6	1.414
-13	-5.8	1.361
-13	-5.6	1.315
-13	-5.4	1.275
-13	-5.2	1.242
-13	-5	1.216
-13	-4.8	1.2
-13	-4.6	1.195
-13	-4.4	1.201
-13	-4.2	1.22
-13	-4	1.25
-13	-3.8	1.288
-13	-3.6	1.321
-13	-3.4	1.328
-13	-3.2	1.28
-13	-3	1.158
-13	-2.8	0.973
-13	-2.6	0.763
-13	-2.4	0.569
-13	-2.2	0.41
-13	-2	0.291
-13	-1.8	0.204
-13	-1.6	0.143
-13	-1.4	0.1
-13	-1.2	0.07
-13	-1	0.05
-13	-0.8	0.035
-13	-0.6	0.026
-13	-0.4	0.02
-13	-0.2	0.016
-13	0	0.014
-13	0.2	0.016
-13	0.4	0.02
-13	0.6	0.026
-13	0.8	0.035
-13	1	0.05
-13	1.2	0.07
-13	1.4	0.1
-13	1.6	0.143
-13	1.8	0.204
-13	2	0.291
-13	2.2	0.41
-13	2.4	0.569
-13	2.6	0.763
-13	2.8	0.973
-13	3	1.158
-13	3.2	1.28
-13	3.4	1.328
-13	3.6	1.321
-13	3.8	1.288
-13	4	1.25
-13	4.2	1.22
-13	4.4	1.201
-13	4.6	1.195
-13	4.8	1.2
-13	5	1.216
-13	5.2	1.242
-13	5.4	1.275
-13	5.6	1.315
-13	5.8	1.361
-13	6	1.414
-13	6.2	1.471
-13	6.4	1.533
-13	6.6	1.599
-13	6.8	1.669
-13	7	1.743
-13	7.2	1.82
-13	7.4	1.901
-13	7.6	1.986
-13	7.8	2.073
-13	8	2.164
-13	8.2	2.258
-13	8.4	2.355
-13	8.6	2.454
-13	8.8	2.557
-13	9	2.663
-13	9.2	2.771
-13	9.4	2.882
-13	9.6	2.996
-13	9.8	3.113
-
-14	-10	3.279
-14	-9.8	3.163
-14	-9.6	3.05
-14	-9.4	2.94
-14	-9.2	2.833
-14	-9	2.73
-14	-8.8	2.63
-14	-8.6	2.533
-14	-8.4	2.44
-14	-8.2	2.351
-14	-8	2.265
-14	-7.8	2.184
-14	-7.6	2.108
-14	-7.4	2.036
-14	-7.2	1.97
-14	-7	1.91
-14	-6.8	1.857
-14	-6.6	1.811
-14	-6.4	1.773
-14	-6.2	1.746
-14	-6	1.731
-14	-5.8	1.73
-14	-5.6	1.745
-14	-5.4	1.779
-14	-5.2	1.835
-14	-5	1.912
-14	-4.8	2.005
-14	-4.6	2.097
-14	-4.4	2.152
-14	-4.2	2.122
-14	-4	1.968
-14	-3.8	1.699
-14	-3.6	1.372
-14	-3.4	1.055
-14	-3.2	0.788
-14	-3	0.58
-14	-2.8	0.425
-14	-2.6	0.311
-14	-2.4	0.228
-14	-2.2	0.168
-14	-2	0.124
-14	-1.8	0.091
-14	-1.6	0.067
-14	-1.4	0.049
-14	-1.2	0.036
-14	-1	0.027
-14	-0.8	0.02
-14	-0.6	0.015
-14	-0.4	0.012
-14	-0.2	0.01
-14	0	0.009
-14	0.2	0.01
-14	0.4	0.012
-14	0.6	0.015
-14	0.8	0.02
-14	1	0.027
-14	1.2	0.036
-14	1.4	0.049
-14	1.6	0.067
-14	1.8	0.091
-14	2	0.124
-14	2.2	0.168
-14	2.4	0.228
-14	2.6	0.311
-14	2.8	0.425
-14	3	0.58
-14	3.2	0.788
-14	3.4	1.055
-14	3.6	1.372
-14	3.8	1.699
-14	4	1.968
-14	4.2	2.122
-14	4.4	2.152
-14	4.6	2.097
-14	4.8	2.005
-14	5	1.912
-14	5.2	1.835
-14	5.4	1.779
-14	5.6	1.745
-14	5.8	1.73
-14	6	1.731
-14	6.2	1.746
-14	6.4	1.773
-14	6.6	1.811
-14	6.8	1.857
-14	7	1.91
-14	7.2	1.97
-14	7.4	2.036
-14	7.6	2.108
-14	7.8	2.184
-14	8	2.265
-14	8.2	2.351
-14	8.4	2.44
-14	8.6	2.533
-14	8.8	2.63
-14	9	2.73
-14	9.2	2.833
-14	9.4	2.94
-14	9.6	3.05
-14	9.8	3.163
diff --git a/docs/examples/test_multi_d/chan1.dat b/docs/examples/test_multi_d/chan1.dat
deleted file mode 100644
index 91ead1d6f75d..000000000000
--- a/docs/examples/test_multi_d/chan1.dat
+++ /dev/null
@@ -1,33 +0,0 @@
-# chan1	avg_amplitude	amplitude_2
-# "Gate Channel 1 (mV)"	"Average: Current (nA)"	"Current (nA)"
-# 30
--15	1.63366	0.006
--14	1.48254	0.009
--13	1.3513	0.014
--12	1.24736	0.027
--11	1.17375	0.064
--10	1.12666	0.117
--9	1.17375	0.064
--8	1.24736	0.027
--7	1.3513	0.014
--6	1.48254	0.009
--5	1.63366	0.006
--4	1.48254	0.009
--3	1.3513	0.014
--2	1.24736	0.027
--1	1.17375	0.064
-0	1.12666	0.117
-1	1.17375	0.064
-2	1.24736	0.027
-3	1.3513	0.014
-4	1.48254	0.009
-5	1.63366	0.006
-6	1.48254	0.009
-7	1.3513	0.014
-8	1.24736	0.027
-9	1.17375	0.064
-10	1.12666	0.117
-11	1.17375	0.064
-12	1.24736	0.027
-13	1.3513	0.014
-14	1.48254	0.009
diff --git a/docs/examples/test_multi_d/chan1_chan0.dat b/docs/examples/test_multi_d/chan1_chan0.dat
deleted file mode 100644
index 25d0d053de83..000000000000
--- a/docs/examples/test_multi_d/chan1_chan0.dat
+++ /dev/null
@@ -1,932 +0,0 @@
-# chan1	chan0	amplitude_3_0
-# "Gate Channel 1 (mV)"	"Gate Channel 0 (mV)"	"Current (nA)"
-# 30	30
--15	-15	0.003
--15	-14	0.004
--15	-13	0.005
--15	-12	0.005
--15	-11	0.006
--15	-10	0.006
--15	-9	0.006
--15	-8	0.005
--15	-7	0.005
--15	-6	0.004
--15	-5	0.003
--15	-4	0.004
--15	-3	0.005
--15	-2	0.005
--15	-1	0.006
--15	0	0.006
--15	1	0.006
--15	2	0.005
--15	3	0.005
--15	4	0.004
--15	5	0.003
--15	6	0.004
--15	7	0.005
--15	8	0.005
--15	9	0.006
--15	10	0.006
--15	11	0.006
--15	12	0.005
--15	13	0.005
--15	14	0.004
-
--14	-15	0.004
--14	-14	0.005
--14	-13	0.006
--14	-12	0.007
--14	-11	0.008
--14	-10	0.009
--14	-9	0.008
--14	-8	0.007
--14	-7	0.006
--14	-6	0.005
--14	-5	0.004
--14	-4	0.005
--14	-3	0.006
--14	-2	0.007
--14	-1	0.008
--14	0	0.009
--14	1	0.008
--14	2	0.007
--14	3	0.006
--14	4	0.005
--14	5	0.004
--14	6	0.005
--14	7	0.006
--14	8	0.007
--14	9	0.008
--14	10	0.009
--14	11	0.008
--14	12	0.007
--14	13	0.006
--14	14	0.005
-
--13	-15	0.005
--13	-14	0.006
--13	-13	0.008
--13	-12	0.01
--13	-11	0.013
--13	-10	0.014
--13	-9	0.013
--13	-8	0.01
--13	-7	0.008
--13	-6	0.006
--13	-5	0.005
--13	-4	0.006
--13	-3	0.008
--13	-2	0.01
--13	-1	0.013
--13	0	0.014
--13	1	0.013
--13	2	0.01
--13	3	0.008
--13	4	0.006
--13	5	0.005
--13	6	0.006
--13	7	0.008
--13	8	0.01
--13	9	0.013
--13	10	0.014
--13	11	0.013
--13	12	0.01
--13	13	0.008
--13	14	0.006
-
--12	-15	0.005
--12	-14	0.007
--12	-13	0.01
--12	-12	0.016
--12	-11	0.023
--12	-10	0.027
--12	-9	0.023
--12	-8	0.016
--12	-7	0.01
--12	-6	0.007
--12	-5	0.005
--12	-4	0.007
--12	-3	0.01
--12	-2	0.016
--12	-1	0.023
--12	0	0.027
--12	1	0.023
--12	2	0.016
--12	3	0.01
--12	4	0.007
--12	5	0.005
--12	6	0.007
--12	7	0.01
--12	8	0.016
--12	9	0.023
--12	10	0.027
--12	11	0.023
--12	12	0.016
--12	13	0.01
--12	14	0.007
-
--11	-15	0.006
--11	-14	0.008
--11	-13	0.013
--11	-12	0.023
--11	-11	0.044
--11	-10	0.064
--11	-9	0.044
--11	-8	0.023
--11	-7	0.013
--11	-6	0.008
--11	-5	0.006
--11	-4	0.008
--11	-3	0.013
--11	-2	0.023
--11	-1	0.044
--11	0	0.064
--11	1	0.044
--11	2	0.023
--11	3	0.013
--11	4	0.008
--11	5	0.006
--11	6	0.008
--11	7	0.013
--11	8	0.023
--11	9	0.044
--11	10	0.064
--11	11	0.044
--11	12	0.023
--11	13	0.013
--11	14	0.008
-
--10	-15	0.006
--10	-14	0.009
--10	-13	0.014
--10	-12	0.027
--10	-11	0.064
--10	-10	0.117
--10	-9	0.064
--10	-8	0.027
--10	-7	0.014
--10	-6	0.009
--10	-5	0.006
--10	-4	0.009
--10	-3	0.014
--10	-2	0.027
--10	-1	0.064
--10	0	0.117
--10	1	0.064
--10	2	0.027
--10	3	0.014
--10	4	0.009
--10	5	0.006
--10	6	0.009
--10	7	0.014
--10	8	0.027
--10	9	0.064
--10	10	0.117
--10	11	0.064
--10	12	0.027
--10	13	0.014
--10	14	0.009
-
--9	-15	0.006
--9	-14	0.008
--9	-13	0.013
--9	-12	0.023
--9	-11	0.044
--9	-10	0.064
--9	-9	0.044
--9	-8	0.023
--9	-7	0.013
--9	-6	0.008
--9	-5	0.006
--9	-4	0.008
--9	-3	0.013
--9	-2	0.023
--9	-1	0.044
--9	0	0.064
--9	1	0.044
--9	2	0.023
--9	3	0.013
--9	4	0.008
--9	5	0.006
--9	6	0.008
--9	7	0.013
--9	8	0.023
--9	9	0.044
--9	10	0.064
--9	11	0.044
--9	12	0.023
--9	13	0.013
--9	14	0.008
-
--8	-15	0.005
--8	-14	0.007
--8	-13	0.01
--8	-12	0.016
--8	-11	0.023
--8	-10	0.027
--8	-9	0.023
--8	-8	0.016
--8	-7	0.01
--8	-6	0.007
--8	-5	0.005
--8	-4	0.007
--8	-3	0.01
--8	-2	0.016
--8	-1	0.023
--8	0	0.027
--8	1	0.023
--8	2	0.016
--8	3	0.01
--8	4	0.007
--8	5	0.005
--8	6	0.007
--8	7	0.01
--8	8	0.016
--8	9	0.023
--8	10	0.027
--8	11	0.023
--8	12	0.016
--8	13	0.01
--8	14	0.007
-
--7	-15	0.005
--7	-14	0.006
--7	-13	0.008
--7	-12	0.01
--7	-11	0.013
--7	-10	0.014
--7	-9	0.013
--7	-8	0.01
--7	-7	0.008
--7	-6	0.006
--7	-5	0.005
--7	-4	0.006
--7	-3	0.008
--7	-2	0.01
--7	-1	0.013
--7	0	0.014
--7	1	0.013
--7	2	0.01
--7	3	0.008
--7	4	0.006
--7	5	0.005
--7	6	0.006
--7	7	0.008
--7	8	0.01
--7	9	0.013
--7	10	0.014
--7	11	0.013
--7	12	0.01
--7	13	0.008
--7	14	0.006
-
--6	-15	0.004
--6	-14	0.005
--6	-13	0.006
--6	-12	0.007
--6	-11	0.008
--6	-10	0.009
--6	-9	0.008
--6	-8	0.007
--6	-7	0.006
--6	-6	0.005
--6	-5	0.004
--6	-4	0.005
--6	-3	0.006
--6	-2	0.007
--6	-1	0.008
--6	0	0.009
--6	1	0.008
--6	2	0.007
--6	3	0.006
--6	4	0.005
--6	5	0.004
--6	6	0.005
--6	7	0.006
--6	8	0.007
--6	9	0.008
--6	10	0.009
--6	11	0.008
--6	12	0.007
--6	13	0.006
--6	14	0.005
-
--5	-15	0.003
--5	-14	0.004
--5	-13	0.005
--5	-12	0.005
--5	-11	0.006
--5	-10	0.006
--5	-9	0.006
--5	-8	0.005
--5	-7	0.005
--5	-6	0.004
--5	-5	0.003
--5	-4	0.004
--5	-3	0.005
--5	-2	0.005
--5	-1	0.006
--5	0	0.006
--5	1	0.006
--5	2	0.005
--5	3	0.005
--5	4	0.004
--5	5	0.003
--5	6	0.004
--5	7	0.005
--5	8	0.005
--5	9	0.006
--5	10	0.006
--5	11	0.006
--5	12	0.005
--5	13	0.005
--5	14	0.004
-
--4	-15	0.004
--4	-14	0.005
--4	-13	0.006
--4	-12	0.007
--4	-11	0.008
--4	-10	0.009
--4	-9	0.008
--4	-8	0.007
--4	-7	0.006
--4	-6	0.005
--4	-5	0.004
--4	-4	0.005
--4	-3	0.006
--4	-2	0.007
--4	-1	0.008
--4	0	0.009
--4	1	0.008
--4	2	0.007
--4	3	0.006
--4	4	0.005
--4	5	0.004
--4	6	0.005
--4	7	0.006
--4	8	0.007
--4	9	0.008
--4	10	0.009
--4	11	0.008
--4	12	0.007
--4	13	0.006
--4	14	0.005
-
--3	-15	0.005
--3	-14	0.006
--3	-13	0.008
--3	-12	0.01
--3	-11	0.013
--3	-10	0.014
--3	-9	0.013
--3	-8	0.01
--3	-7	0.008
--3	-6	0.006
--3	-5	0.005
--3	-4	0.006
--3	-3	0.008
--3	-2	0.01
--3	-1	0.013
--3	0	0.014
--3	1	0.013
--3	2	0.01
--3	3	0.008
--3	4	0.006
--3	5	0.005
--3	6	0.006
--3	7	0.008
--3	8	0.01
--3	9	0.013
--3	10	0.014
--3	11	0.013
--3	12	0.01
--3	13	0.008
--3	14	0.006
-
--2	-15	0.005
--2	-14	0.007
--2	-13	0.01
--2	-12	0.016
--2	-11	0.023
--2	-10	0.027
--2	-9	0.023
--2	-8	0.016
--2	-7	0.01
--2	-6	0.007
--2	-5	0.005
--2	-4	0.007
--2	-3	0.01
--2	-2	0.016
--2	-1	0.023
--2	0	0.027
--2	1	0.023
--2	2	0.016
--2	3	0.01
--2	4	0.007
--2	5	0.005
--2	6	0.007
--2	7	0.01
--2	8	0.016
--2	9	0.023
--2	10	0.027
--2	11	0.023
--2	12	0.016
--2	13	0.01
--2	14	0.007
-
--1	-15	0.006
--1	-14	0.008
--1	-13	0.013
--1	-12	0.023
--1	-11	0.044
--1	-10	0.064
--1	-9	0.044
--1	-8	0.023
--1	-7	0.013
--1	-6	0.008
--1	-5	0.006
--1	-4	0.008
--1	-3	0.013
--1	-2	0.023
--1	-1	0.044
--1	0	0.064
--1	1	0.044
--1	2	0.023
--1	3	0.013
--1	4	0.008
--1	5	0.006
--1	6	0.008
--1	7	0.013
--1	8	0.023
--1	9	0.044
--1	10	0.064
--1	11	0.044
--1	12	0.023
--1	13	0.013
--1	14	0.008
-
-0	-15	0.006
-0	-14	0.009
-0	-13	0.014
-0	-12	0.027
-0	-11	0.064
-0	-10	0.117
-0	-9	0.064
-0	-8	0.027
-0	-7	0.014
-0	-6	0.009
-0	-5	0.006
-0	-4	0.009
-0	-3	0.014
-0	-2	0.027
-0	-1	0.064
-0	0	0.117
-0	1	0.064
-0	2	0.027
-0	3	0.014
-0	4	0.009
-0	5	0.006
-0	6	0.009
-0	7	0.014
-0	8	0.027
-0	9	0.064
-0	10	0.117
-0	11	0.064
-0	12	0.027
-0	13	0.014
-0	14	0.009
-
-1	-15	0.006
-1	-14	0.008
-1	-13	0.013
-1	-12	0.023
-1	-11	0.044
-1	-10	0.064
-1	-9	0.044
-1	-8	0.023
-1	-7	0.013
-1	-6	0.008
-1	-5	0.006
-1	-4	0.008
-1	-3	0.013
-1	-2	0.023
-1	-1	0.044
-1	0	0.064
-1	1	0.044
-1	2	0.023
-1	3	0.013
-1	4	0.008
-1	5	0.006
-1	6	0.008
-1	7	0.013
-1	8	0.023
-1	9	0.044
-1	10	0.064
-1	11	0.044
-1	12	0.023
-1	13	0.013
-1	14	0.008
-
-2	-15	0.005
-2	-14	0.007
-2	-13	0.01
-2	-12	0.016
-2	-11	0.023
-2	-10	0.027
-2	-9	0.023
-2	-8	0.016
-2	-7	0.01
-2	-6	0.007
-2	-5	0.005
-2	-4	0.007
-2	-3	0.01
-2	-2	0.016
-2	-1	0.023
-2	0	0.027
-2	1	0.023
-2	2	0.016
-2	3	0.01
-2	4	0.007
-2	5	0.005
-2	6	0.007
-2	7	0.01
-2	8	0.016
-2	9	0.023
-2	10	0.027
-2	11	0.023
-2	12	0.016
-2	13	0.01
-2	14	0.007
-
-3	-15	0.005
-3	-14	0.006
-3	-13	0.008
-3	-12	0.01
-3	-11	0.013
-3	-10	0.014
-3	-9	0.013
-3	-8	0.01
-3	-7	0.008
-3	-6	0.006
-3	-5	0.005
-3	-4	0.006
-3	-3	0.008
-3	-2	0.01
-3	-1	0.013
-3	0	0.014
-3	1	0.013
-3	2	0.01
-3	3	0.008
-3	4	0.006
-3	5	0.005
-3	6	0.006
-3	7	0.008
-3	8	0.01
-3	9	0.013
-3	10	0.014
-3	11	0.013
-3	12	0.01
-3	13	0.008
-3	14	0.006
-
-4	-15	0.004
-4	-14	0.005
-4	-13	0.006
-4	-12	0.007
-4	-11	0.008
-4	-10	0.009
-4	-9	0.008
-4	-8	0.007
-4	-7	0.006
-4	-6	0.005
-4	-5	0.004
-4	-4	0.005
-4	-3	0.006
-4	-2	0.007
-4	-1	0.008
-4	0	0.009
-4	1	0.008
-4	2	0.007
-4	3	0.006
-4	4	0.005
-4	5	0.004
-4	6	0.005
-4	7	0.006
-4	8	0.007
-4	9	0.008
-4	10	0.009
-4	11	0.008
-4	12	0.007
-4	13	0.006
-4	14	0.005
-
-5	-15	0.003
-5	-14	0.004
-5	-13	0.005
-5	-12	0.005
-5	-11	0.006
-5	-10	0.006
-5	-9	0.006
-5	-8	0.005
-5	-7	0.005
-5	-6	0.004
-5	-5	0.003
-5	-4	0.004
-5	-3	0.005
-5	-2	0.005
-5	-1	0.006
-5	0	0.006
-5	1	0.006
-5	2	0.005
-5	3	0.005
-5	4	0.004
-5	5	0.003
-5	6	0.004
-5	7	0.005
-5	8	0.005
-5	9	0.006
-5	10	0.006
-5	11	0.006
-5	12	0.005
-5	13	0.005
-5	14	0.004
-
-6	-15	0.004
-6	-14	0.005
-6	-13	0.006
-6	-12	0.007
-6	-11	0.008
-6	-10	0.009
-6	-9	0.008
-6	-8	0.007
-6	-7	0.006
-6	-6	0.005
-6	-5	0.004
-6	-4	0.005
-6	-3	0.006
-6	-2	0.007
-6	-1	0.008
-6	0	0.009
-6	1	0.008
-6	2	0.007
-6	3	0.006
-6	4	0.005
-6	5	0.004
-6	6	0.005
-6	7	0.006
-6	8	0.007
-6	9	0.008
-6	10	0.009
-6	11	0.008
-6	12	0.007
-6	13	0.006
-6	14	0.005
-
-7	-15	0.005
-7	-14	0.006
-7	-13	0.008
-7	-12	0.01
-7	-11	0.013
-7	-10	0.014
-7	-9	0.013
-7	-8	0.01
-7	-7	0.008
-7	-6	0.006
-7	-5	0.005
-7	-4	0.006
-7	-3	0.008
-7	-2	0.01
-7	-1	0.013
-7	0	0.014
-7	1	0.013
-7	2	0.01
-7	3	0.008
-7	4	0.006
-7	5	0.005
-7	6	0.006
-7	7	0.008
-7	8	0.01
-7	9	0.013
-7	10	0.014
-7	11	0.013
-7	12	0.01
-7	13	0.008
-7	14	0.006
-
-8	-15	0.005
-8	-14	0.007
-8	-13	0.01
-8	-12	0.016
-8	-11	0.023
-8	-10	0.027
-8	-9	0.023
-8	-8	0.016
-8	-7	0.01
-8	-6	0.007
-8	-5	0.005
-8	-4	0.007
-8	-3	0.01
-8	-2	0.016
-8	-1	0.023
-8	0	0.027
-8	1	0.023
-8	2	0.016
-8	3	0.01
-8	4	0.007
-8	5	0.005
-8	6	0.007
-8	7	0.01
-8	8	0.016
-8	9	0.023
-8	10	0.027
-8	11	0.023
-8	12	0.016
-8	13	0.01
-8	14	0.007
-
-9	-15	0.006
-9	-14	0.008
-9	-13	0.013
-9	-12	0.023
-9	-11	0.044
-9	-10	0.064
-9	-9	0.044
-9	-8	0.023
-9	-7	0.013
-9	-6	0.008
-9	-5	0.006
-9	-4	0.008
-9	-3	0.013
-9	-2	0.023
-9	-1	0.044
-9	0	0.064
-9	1	0.044
-9	2	0.023
-9	3	0.013
-9	4	0.008
-9	5	0.006
-9	6	0.008
-9	7	0.013
-9	8	0.023
-9	9	0.044
-9	10	0.064
-9	11	0.044
-9	12	0.023
-9	13	0.013
-9	14	0.008
-
-10	-15	0.006
-10	-14	0.009
-10	-13	0.014
-10	-12	0.027
-10	-11	0.064
-10	-10	0.117
-10	-9	0.064
-10	-8	0.027
-10	-7	0.014
-10	-6	0.009
-10	-5	0.006
-10	-4	0.009
-10	-3	0.014
-10	-2	0.027
-10	-1	0.064
-10	0	0.117
-10	1	0.064
-10	2	0.027
-10	3	0.014
-10	4	0.009
-10	5	0.006
-10	6	0.009
-10	7	0.014
-10	8	0.027
-10	9	0.064
-10	10	0.117
-10	11	0.064
-10	12	0.027
-10	13	0.014
-10	14	0.009
-
-11	-15	0.006
-11	-14	0.008
-11	-13	0.013
-11	-12	0.023
-11	-11	0.044
-11	-10	0.064
-11	-9	0.044
-11	-8	0.023
-11	-7	0.013
-11	-6	0.008
-11	-5	0.006
-11	-4	0.008
-11	-3	0.013
-11	-2	0.023
-11	-1	0.044
-11	0	0.064
-11	1	0.044
-11	2	0.023
-11	3	0.013
-11	4	0.008
-11	5	0.006
-11	6	0.008
-11	7	0.013
-11	8	0.023
-11	9	0.044
-11	10	0.064
-11	11	0.044
-11	12	0.023
-11	13	0.013
-11	14	0.008
-
-12	-15	0.005
-12	-14	0.007
-12	-13	0.01
-12	-12	0.016
-12	-11	0.023
-12	-10	0.027
-12	-9	0.023
-12	-8	0.016
-12	-7	0.01
-12	-6	0.007
-12	-5	0.005
-12	-4	0.007
-12	-3	0.01
-12	-2	0.016
-12	-1	0.023
-12	0	0.027
-12	1	0.023
-12	2	0.016
-12	3	0.01
-12	4	0.007
-12	5	0.005
-12	6	0.007
-12	7	0.01
-12	8	0.016
-12	9	0.023
-12	10	0.027
-12	11	0.023
-12	12	0.016
-12	13	0.01
-12	14	0.007
-
-13	-15	0.005
-13	-14	0.006
-13	-13	0.008
-13	-12	0.01
-13	-11	0.013
-13	-10	0.014
-13	-9	0.013
-13	-8	0.01
-13	-7	0.008
-13	-6	0.006
-13	-5	0.005
-13	-4	0.006
-13	-3	0.008
-13	-2	0.01
-13	-1	0.013
-13	0	0.014
-13	1	0.013
-13	2	0.01
-13	3	0.008
-13	4	0.006
-13	5	0.005
-13	6	0.006
-13	7	0.008
-13	8	0.01
-13	9	0.013
-13	10	0.014
-13	11	0.013
-13	12	0.01
-13	13	0.008
-13	14	0.006
-
-14	-15	0.004
-14	-14	0.005
-14	-13	0.006
-14	-12	0.007
-14	-11	0.008
-14	-10	0.009
-14	-9	0.008
-14	-8	0.007
-14	-7	0.006
-14	-6	0.005
-14	-5	0.004
-14	-4	0.005
-14	-3	0.006
-14	-2	0.007
-14	-1	0.008
-14	0	0.009
-14	1	0.008
-14	2	0.007
-14	3	0.006
-14	4	0.005
-14	5	0.004
-14	6	0.005
-14	7	0.006
-14	8	0.007
-14	9	0.008
-14	10	0.009
-14	11	0.008
-14	12	0.007
-14	13	0.006
-14	14	0.005
diff --git a/docs/examples/test_multi_d/chan1_chan2.dat b/docs/examples/test_multi_d/chan1_chan2.dat
deleted file mode 100644
index 1b2e51fe76e1..000000000000
--- a/docs/examples/test_multi_d/chan1_chan2.dat
+++ /dev/null
@@ -1,3032 +0,0 @@
-# chan1	chan2	amplitude_5_0
-# "Gate Channel 1 (mV)"	"Gate Channel 2 (mV)"	"Current (nA)"
-# 30	100
--15	-10	3.362
--15	-9.8	3.253
--15	-9.6	3.148
--15	-9.4	3.047
--15	-9.2	2.95
--15	-9	2.858
--15	-8.8	2.771
--15	-8.6	2.689
--15	-8.4	2.613
--15	-8.2	2.544
--15	-8	2.483
--15	-7.8	2.43
--15	-7.6	2.388
--15	-7.4	2.357
--15	-7.2	2.339
--15	-7	2.339
--15	-6.8	2.359
--15	-6.6	2.402
--15	-6.4	2.475
--15	-6.2	2.581
--15	-6	2.721
--15	-5.8	2.889
--15	-5.6	3.062
--15	-5.4	3.188
--15	-5.2	3.192
--15	-5	3.01
--15	-4.8	2.644
--15	-4.6	2.177
--15	-4.4	1.709
--15	-4.2	1.306
--15	-4	0.985
--15	-3.8	0.741
--15	-3.6	0.559
--15	-3.4	0.424
--15	-3.2	0.323
--15	-3	0.247
--15	-2.8	0.19
--15	-2.6	0.146
--15	-2.4	0.112
--15	-2.2	0.086
--15	-2	0.066
--15	-1.8	0.051
--15	-1.6	0.039
--15	-1.4	0.029
--15	-1.2	0.022
--15	-1	0.017
--15	-0.8	0.013
--15	-0.6	0.01
--15	-0.4	0.008
--15	-0.2	0.007
--15	0	0.006
--15	0.2	0.007
--15	0.4	0.008
--15	0.6	0.01
--15	0.8	0.013
--15	1	0.017
--15	1.2	0.022
--15	1.4	0.029
--15	1.6	0.039
--15	1.8	0.051
--15	2	0.066
--15	2.2	0.086
--15	2.4	0.112
--15	2.6	0.146
--15	2.8	0.19
--15	3	0.247
--15	3.2	0.323
--15	3.4	0.424
--15	3.6	0.559
--15	3.8	0.741
--15	4	0.985
--15	4.2	1.306
--15	4.4	1.709
--15	4.6	2.177
--15	4.8	2.644
--15	5	3.01
--15	5.2	3.192
--15	5.4	3.188
--15	5.6	3.062
--15	5.8	2.889
--15	6	2.721
--15	6.2	2.581
--15	6.4	2.475
--15	6.6	2.402
--15	6.8	2.359
--15	7	2.339
--15	7.2	2.339
--15	7.4	2.357
--15	7.6	2.388
--15	7.8	2.43
--15	8	2.483
--15	8.2	2.544
--15	8.4	2.613
--15	8.6	2.689
--15	8.8	2.771
--15	9	2.858
--15	9.2	2.95
--15	9.4	3.047
--15	9.6	3.148
--15	9.8	3.253
-
--14	-10	3.279
--14	-9.8	3.163
--14	-9.6	3.05
--14	-9.4	2.94
--14	-9.2	2.833
--14	-9	2.73
--14	-8.8	2.63
--14	-8.6	2.533
--14	-8.4	2.44
--14	-8.2	2.351
--14	-8	2.265
--14	-7.8	2.184
--14	-7.6	2.108
--14	-7.4	2.036
--14	-7.2	1.97
--14	-7	1.91
--14	-6.8	1.857
--14	-6.6	1.811
--14	-6.4	1.773
--14	-6.2	1.746
--14	-6	1.731
--14	-5.8	1.73
--14	-5.6	1.745
--14	-5.4	1.779
--14	-5.2	1.835
--14	-5	1.912
--14	-4.8	2.005
--14	-4.6	2.097
--14	-4.4	2.152
--14	-4.2	2.122
--14	-4	1.968
--14	-3.8	1.699
--14	-3.6	1.372
--14	-3.4	1.055
--14	-3.2	0.788
--14	-3	0.58
--14	-2.8	0.425
--14	-2.6	0.311
--14	-2.4	0.228
--14	-2.2	0.168
--14	-2	0.124
--14	-1.8	0.091
--14	-1.6	0.067
--14	-1.4	0.049
--14	-1.2	0.036
--14	-1	0.027
--14	-0.8	0.02
--14	-0.6	0.015
--14	-0.4	0.012
--14	-0.2	0.01
--14	0	0.009
--14	0.2	0.01
--14	0.4	0.012
--14	0.6	0.015
--14	0.8	0.02
--14	1	0.027
--14	1.2	0.036
--14	1.4	0.049
--14	1.6	0.067
--14	1.8	0.091
--14	2	0.124
--14	2.2	0.168
--14	2.4	0.228
--14	2.6	0.311
--14	2.8	0.425
--14	3	0.58
--14	3.2	0.788
--14	3.4	1.055
--14	3.6	1.372
--14	3.8	1.699
--14	4	1.968
--14	4.2	2.122
--14	4.4	2.152
--14	4.6	2.097
--14	4.8	2.005
--14	5	1.912
--14	5.2	1.835
--14	5.4	1.779
--14	5.6	1.745
--14	5.8	1.73
--14	6	1.731
--14	6.2	1.746
--14	6.4	1.773
--14	6.6	1.811
--14	6.8	1.857
--14	7	1.91
--14	7.2	1.97
--14	7.4	2.036
--14	7.6	2.108
--14	7.8	2.184
--14	8	2.265
--14	8.2	2.351
--14	8.4	2.44
--14	8.6	2.533
--14	8.8	2.63
--14	9	2.73
--14	9.2	2.833
--14	9.4	2.94
--14	9.6	3.05
--14	9.8	3.163
-
--13	-10	3.232
--13	-9.8	3.113
--13	-9.6	2.996
--13	-9.4	2.882
--13	-9.2	2.771
--13	-9	2.663
--13	-8.8	2.557
--13	-8.6	2.454
--13	-8.4	2.355
--13	-8.2	2.258
--13	-8	2.164
--13	-7.8	2.073
--13	-7.6	1.986
--13	-7.4	1.901
--13	-7.2	1.82
--13	-7	1.743
--13	-6.8	1.669
--13	-6.6	1.599
--13	-6.4	1.533
--13	-6.2	1.471
--13	-6	1.414
--13	-5.8	1.361
--13	-5.6	1.315
--13	-5.4	1.275
--13	-5.2	1.242
--13	-5	1.216
--13	-4.8	1.2
--13	-4.6	1.195
--13	-4.4	1.201
--13	-4.2	1.22
--13	-4	1.25
--13	-3.8	1.288
--13	-3.6	1.321
--13	-3.4	1.328
--13	-3.2	1.28
--13	-3	1.158
--13	-2.8	0.973
--13	-2.6	0.763
--13	-2.4	0.569
--13	-2.2	0.41
--13	-2	0.291
--13	-1.8	0.204
--13	-1.6	0.143
--13	-1.4	0.1
--13	-1.2	0.07
--13	-1	0.05
--13	-0.8	0.035
--13	-0.6	0.026
--13	-0.4	0.02
--13	-0.2	0.016
--13	0	0.014
--13	0.2	0.016
--13	0.4	0.02
--13	0.6	0.026
--13	0.8	0.035
--13	1	0.05
--13	1.2	0.07
--13	1.4	0.1
--13	1.6	0.143
--13	1.8	0.204
--13	2	0.291
--13	2.2	0.41
--13	2.4	0.569
--13	2.6	0.763
--13	2.8	0.973
--13	3	1.158
--13	3.2	1.28
--13	3.4	1.328
--13	3.6	1.321
--13	3.8	1.288
--13	4	1.25
--13	4.2	1.22
--13	4.4	1.201
--13	4.6	1.195
--13	4.8	1.2
--13	5	1.216
--13	5.2	1.242
--13	5.4	1.275
--13	5.6	1.315
--13	5.8	1.361
--13	6	1.414
--13	6.2	1.471
--13	6.4	1.533
--13	6.6	1.599
--13	6.8	1.669
--13	7	1.743
--13	7.2	1.82
--13	7.4	1.901
--13	7.6	1.986
--13	7.8	2.073
--13	8	2.164
--13	8.2	2.258
--13	8.4	2.355
--13	8.6	2.454
--13	8.8	2.557
--13	9	2.663
--13	9.2	2.771
--13	9.4	2.882
--13	9.6	2.996
--13	9.8	3.113
-
--12	-10	3.203
--12	-9.8	3.082
--12	-9.6	2.964
--12	-9.4	2.848
--12	-9.2	2.735
--12	-9	2.624
--12	-8.8	2.516
--12	-8.6	2.411
--12	-8.4	2.308
--12	-8.2	2.208
--12	-8	2.111
--12	-7.8	2.016
--12	-7.6	1.924
--12	-7.4	1.835
--12	-7.2	1.748
--12	-7	1.665
--12	-6.8	1.584
--12	-6.6	1.506
--12	-6.4	1.431
--12	-6.2	1.359
--12	-6	1.29
--12	-5.8	1.224
--12	-5.6	1.161
--12	-5.4	1.102
--12	-5.2	1.046
--12	-5	0.993
--12	-4.8	0.945
--12	-4.6	0.901
--12	-4.4	0.861
--12	-4.2	0.825
--12	-4	0.795
--12	-3.8	0.771
--12	-3.6	0.753
--12	-3.4	0.741
--12	-3.2	0.736
--12	-3	0.736
--12	-2.8	0.738
--12	-2.6	0.735
--12	-2.4	0.715
--12	-2.2	0.666
--12	-2	0.58
--12	-1.8	0.468
--12	-1.6	0.351
--12	-1.4	0.25
--12	-1.2	0.172
--12	-1	0.117
--12	-0.8	0.08
--12	-0.6	0.055
--12	-0.4	0.04
--12	-0.2	0.031
--12	0	0.027
--12	0.2	0.031
--12	0.4	0.04
--12	0.6	0.055
--12	0.8	0.08
--12	1	0.117
--12	1.2	0.172
--12	1.4	0.25
--12	1.6	0.351
--12	1.8	0.468
--12	2	0.58
--12	2.2	0.666
--12	2.4	0.715
--12	2.6	0.735
--12	2.8	0.738
--12	3	0.736
--12	3.2	0.736
--12	3.4	0.741
--12	3.6	0.753
--12	3.8	0.771
--12	4	0.795
--12	4.2	0.825
--12	4.4	0.861
--12	4.6	0.901
--12	4.8	0.945
--12	5	0.993
--12	5.2	1.046
--12	5.4	1.102
--12	5.6	1.161
--12	5.8	1.224
--12	6	1.29
--12	6.2	1.359
--12	6.4	1.431
--12	6.6	1.506
--12	6.8	1.584
--12	7	1.665
--12	7.2	1.748
--12	7.4	1.835
--12	7.6	1.924
--12	7.8	2.016
--12	8	2.111
--12	8.2	2.208
--12	8.4	2.308
--12	8.6	2.411
--12	8.8	2.516
--12	9	2.624
--12	9.2	2.735
--12	9.4	2.848
--12	9.6	2.964
--12	9.8	3.082
-
--11	-10	3.185
--11	-9.8	3.063
--11	-9.6	2.943
--11	-9.4	2.827
--11	-9.2	2.712
--11	-9	2.601
--11	-8.8	2.491
--11	-8.6	2.385
--11	-8.4	2.281
--11	-8.2	2.179
--11	-8	2.08
--11	-7.8	1.984
--11	-7.6	1.89
--11	-7.4	1.799
--11	-7.2	1.71
--11	-7	1.624
--11	-6.8	1.54
--11	-6.6	1.459
--11	-6.4	1.381
--11	-6.2	1.305
--11	-6	1.232
--11	-5.8	1.161
--11	-5.6	1.094
--11	-5.4	1.029
--11	-5.2	0.966
--11	-5	0.906
--11	-4.8	0.849
--11	-4.6	0.795
--11	-4.4	0.744
--11	-4.2	0.695
--11	-4	0.65
--11	-3.8	0.607
--11	-3.6	0.567
--11	-3.4	0.531
--11	-3.2	0.498
--11	-3	0.468
--11	-2.8	0.442
--11	-2.6	0.419
--11	-2.4	0.399
--11	-2.2	0.382
--11	-2	0.368
--11	-1.8	0.354
--11	-1.6	0.337
--11	-1.4	0.313
--11	-1.2	0.279
--11	-1	0.233
--11	-0.8	0.182
--11	-0.6	0.135
--11	-0.4	0.099
--11	-0.2	0.075
--11	0	0.064
--11	0.2	0.075
--11	0.4	0.099
--11	0.6	0.135
--11	0.8	0.182
--11	1	0.233
--11	1.2	0.279
--11	1.4	0.313
--11	1.6	0.337
--11	1.8	0.354
--11	2	0.368
--11	2.2	0.382
--11	2.4	0.399
--11	2.6	0.419
--11	2.8	0.442
--11	3	0.468
--11	3.2	0.498
--11	3.4	0.531
--11	3.6	0.567
--11	3.8	0.607
--11	4	0.65
--11	4.2	0.695
--11	4.4	0.744
--11	4.6	0.795
--11	4.8	0.849
--11	5	0.906
--11	5.2	0.966
--11	5.4	1.029
--11	5.6	1.094
--11	5.8	1.161
--11	6	1.232
--11	6.2	1.305
--11	6.4	1.381
--11	6.6	1.459
--11	6.8	1.54
--11	7	1.624
--11	7.2	1.71
--11	7.4	1.799
--11	7.6	1.89
--11	7.8	1.984
--11	8	2.08
--11	8.2	2.179
--11	8.4	2.281
--11	8.6	2.385
--11	8.8	2.491
--11	9	2.601
--11	9.2	2.712
--11	9.4	2.827
--11	9.6	2.943
--11	9.8	3.063
-
--10	-10	3.173
--10	-9.8	3.05
--10	-9.6	2.93
--10	-9.4	2.813
--10	-9.2	2.698
--10	-9	2.586
--10	-8.8	2.476
--10	-8.6	2.368
--10	-8.4	2.264
--10	-8.2	2.161
--10	-8	2.062
--10	-7.8	1.964
--10	-7.6	1.869
--10	-7.4	1.777
--10	-7.2	1.687
--10	-7	1.6
--10	-6.8	1.515
--10	-6.6	1.433
--10	-6.4	1.353
--10	-6.2	1.276
--10	-6	1.202
--10	-5.8	1.129
--10	-5.6	1.06
--10	-5.4	0.993
--10	-5.2	0.928
--10	-5	0.866
--10	-4.8	0.806
--10	-4.6	0.749
--10	-4.4	0.694
--10	-4.2	0.642
--10	-4	0.593
--10	-3.8	0.546
--10	-3.6	0.501
--10	-3.4	0.459
--10	-3.2	0.419
--10	-3	0.382
--10	-2.8	0.348
--10	-2.6	0.316
--10	-2.4	0.286
--10	-2.2	0.259
--10	-2	0.234
--10	-1.8	0.212
--10	-1.6	0.192
--10	-1.4	0.175
--10	-1.2	0.16
--10	-1	0.147
--10	-0.8	0.137
--10	-0.6	0.129
--10	-0.4	0.123
--10	-0.2	0.119
--10	0	0.117
--10	0.2	0.119
--10	0.4	0.123
--10	0.6	0.129
--10	0.8	0.137
--10	1	0.147
--10	1.2	0.16
--10	1.4	0.175
--10	1.6	0.192
--10	1.8	0.212
--10	2	0.234
--10	2.2	0.259
--10	2.4	0.286
--10	2.6	0.316
--10	2.8	0.348
--10	3	0.382
--10	3.2	0.419
--10	3.4	0.459
--10	3.6	0.501
--10	3.8	0.546
--10	4	0.593
--10	4.2	0.642
--10	4.4	0.694
--10	4.6	0.749
--10	4.8	0.806
--10	5	0.866
--10	5.2	0.928
--10	5.4	0.993
--10	5.6	1.06
--10	5.8	1.129
--10	6	1.202
--10	6.2	1.276
--10	6.4	1.353
--10	6.6	1.433
--10	6.8	1.515
--10	7	1.6
--10	7.2	1.687
--10	7.4	1.777
--10	7.6	1.869
--10	7.8	1.964
--10	8	2.062
--10	8.2	2.161
--10	8.4	2.264
--10	8.6	2.368
--10	8.8	2.476
--10	9	2.586
--10	9.2	2.698
--10	9.4	2.813
--10	9.6	2.93
--10	9.8	3.05
-
--9	-10	3.185
--9	-9.8	3.063
--9	-9.6	2.943
--9	-9.4	2.827
--9	-9.2	2.712
--9	-9	2.601
--9	-8.8	2.491
--9	-8.6	2.385
--9	-8.4	2.281
--9	-8.2	2.179
--9	-8	2.08
--9	-7.8	1.984
--9	-7.6	1.89
--9	-7.4	1.799
--9	-7.2	1.71
--9	-7	1.624
--9	-6.8	1.54
--9	-6.6	1.459
--9	-6.4	1.381
--9	-6.2	1.305
--9	-6	1.232
--9	-5.8	1.161
--9	-5.6	1.094
--9	-5.4	1.029
--9	-5.2	0.966
--9	-5	0.906
--9	-4.8	0.849
--9	-4.6	0.795
--9	-4.4	0.744
--9	-4.2	0.695
--9	-4	0.65
--9	-3.8	0.607
--9	-3.6	0.567
--9	-3.4	0.531
--9	-3.2	0.498
--9	-3	0.468
--9	-2.8	0.442
--9	-2.6	0.419
--9	-2.4	0.399
--9	-2.2	0.382
--9	-2	0.368
--9	-1.8	0.354
--9	-1.6	0.337
--9	-1.4	0.313
--9	-1.2	0.279
--9	-1	0.233
--9	-0.8	0.182
--9	-0.6	0.135
--9	-0.4	0.099
--9	-0.2	0.075
--9	0	0.064
--9	0.2	0.075
--9	0.4	0.099
--9	0.6	0.135
--9	0.8	0.182
--9	1	0.233
--9	1.2	0.279
--9	1.4	0.313
--9	1.6	0.337
--9	1.8	0.354
--9	2	0.368
--9	2.2	0.382
--9	2.4	0.399
--9	2.6	0.419
--9	2.8	0.442
--9	3	0.468
--9	3.2	0.498
--9	3.4	0.531
--9	3.6	0.567
--9	3.8	0.607
--9	4	0.65
--9	4.2	0.695
--9	4.4	0.744
--9	4.6	0.795
--9	4.8	0.849
--9	5	0.906
--9	5.2	0.966
--9	5.4	1.029
--9	5.6	1.094
--9	5.8	1.161
--9	6	1.232
--9	6.2	1.305
--9	6.4	1.381
--9	6.6	1.459
--9	6.8	1.54
--9	7	1.624
--9	7.2	1.71
--9	7.4	1.799
--9	7.6	1.89
--9	7.8	1.984
--9	8	2.08
--9	8.2	2.179
--9	8.4	2.281
--9	8.6	2.385
--9	8.8	2.491
--9	9	2.601
--9	9.2	2.712
--9	9.4	2.827
--9	9.6	2.943
--9	9.8	3.063
-
--8	-10	3.203
--8	-9.8	3.082
--8	-9.6	2.964
--8	-9.4	2.848
--8	-9.2	2.735
--8	-9	2.624
--8	-8.8	2.516
--8	-8.6	2.411
--8	-8.4	2.308
--8	-8.2	2.208
--8	-8	2.111
--8	-7.8	2.016
--8	-7.6	1.924
--8	-7.4	1.835
--8	-7.2	1.748
--8	-7	1.665
--8	-6.8	1.584
--8	-6.6	1.506
--8	-6.4	1.431
--8	-6.2	1.359
--8	-6	1.29
--8	-5.8	1.224
--8	-5.6	1.161
--8	-5.4	1.102
--8	-5.2	1.046
--8	-5	0.993
--8	-4.8	0.945
--8	-4.6	0.901
--8	-4.4	0.861
--8	-4.2	0.825
--8	-4	0.795
--8	-3.8	0.771
--8	-3.6	0.753
--8	-3.4	0.741
--8	-3.2	0.736
--8	-3	0.736
--8	-2.8	0.738
--8	-2.6	0.735
--8	-2.4	0.715
--8	-2.2	0.666
--8	-2	0.58
--8	-1.8	0.468
--8	-1.6	0.351
--8	-1.4	0.25
--8	-1.2	0.172
--8	-1	0.117
--8	-0.8	0.08
--8	-0.6	0.055
--8	-0.4	0.04
--8	-0.2	0.031
--8	0	0.027
--8	0.2	0.031
--8	0.4	0.04
--8	0.6	0.055
--8	0.8	0.08
--8	1	0.117
--8	1.2	0.172
--8	1.4	0.25
--8	1.6	0.351
--8	1.8	0.468
--8	2	0.58
--8	2.2	0.666
--8	2.4	0.715
--8	2.6	0.735
--8	2.8	0.738
--8	3	0.736
--8	3.2	0.736
--8	3.4	0.741
--8	3.6	0.753
--8	3.8	0.771
--8	4	0.795
--8	4.2	0.825
--8	4.4	0.861
--8	4.6	0.901
--8	4.8	0.945
--8	5	0.993
--8	5.2	1.046
--8	5.4	1.102
--8	5.6	1.161
--8	5.8	1.224
--8	6	1.29
--8	6.2	1.359
--8	6.4	1.431
--8	6.6	1.506
--8	6.8	1.584
--8	7	1.665
--8	7.2	1.748
--8	7.4	1.835
--8	7.6	1.924
--8	7.8	2.016
--8	8	2.111
--8	8.2	2.208
--8	8.4	2.308
--8	8.6	2.411
--8	8.8	2.516
--8	9	2.624
--8	9.2	2.735
--8	9.4	2.848
--8	9.6	2.964
--8	9.8	3.082
-
--7	-10	3.232
--7	-9.8	3.113
--7	-9.6	2.996
--7	-9.4	2.882
--7	-9.2	2.771
--7	-9	2.663
--7	-8.8	2.557
--7	-8.6	2.454
--7	-8.4	2.355
--7	-8.2	2.258
--7	-8	2.164
--7	-7.8	2.073
--7	-7.6	1.986
--7	-7.4	1.901
--7	-7.2	1.82
--7	-7	1.743
--7	-6.8	1.669
--7	-6.6	1.599
--7	-6.4	1.533
--7	-6.2	1.471
--7	-6	1.414
--7	-5.8	1.361
--7	-5.6	1.315
--7	-5.4	1.275
--7	-5.2	1.242
--7	-5	1.216
--7	-4.8	1.2
--7	-4.6	1.195
--7	-4.4	1.201
--7	-4.2	1.22
--7	-4	1.25
--7	-3.8	1.288
--7	-3.6	1.321
--7	-3.4	1.328
--7	-3.2	1.28
--7	-3	1.158
--7	-2.8	0.973
--7	-2.6	0.763
--7	-2.4	0.569
--7	-2.2	0.41
--7	-2	0.291
--7	-1.8	0.204
--7	-1.6	0.143
--7	-1.4	0.1
--7	-1.2	0.07
--7	-1	0.05
--7	-0.8	0.035
--7	-0.6	0.026
--7	-0.4	0.02
--7	-0.2	0.016
--7	0	0.014
--7	0.2	0.016
--7	0.4	0.02
--7	0.6	0.026
--7	0.8	0.035
--7	1	0.05
--7	1.2	0.07
--7	1.4	0.1
--7	1.6	0.143
--7	1.8	0.204
--7	2	0.291
--7	2.2	0.41
--7	2.4	0.569
--7	2.6	0.763
--7	2.8	0.973
--7	3	1.158
--7	3.2	1.28
--7	3.4	1.328
--7	3.6	1.321
--7	3.8	1.288
--7	4	1.25
--7	4.2	1.22
--7	4.4	1.201
--7	4.6	1.195
--7	4.8	1.2
--7	5	1.216
--7	5.2	1.242
--7	5.4	1.275
--7	5.6	1.315
--7	5.8	1.361
--7	6	1.414
--7	6.2	1.471
--7	6.4	1.533
--7	6.6	1.599
--7	6.8	1.669
--7	7	1.743
--7	7.2	1.82
--7	7.4	1.901
--7	7.6	1.986
--7	7.8	2.073
--7	8	2.164
--7	8.2	2.258
--7	8.4	2.355
--7	8.6	2.454
--7	8.8	2.557
--7	9	2.663
--7	9.2	2.771
--7	9.4	2.882
--7	9.6	2.996
--7	9.8	3.113
-
--6	-10	3.279
--6	-9.8	3.163
--6	-9.6	3.05
--6	-9.4	2.94
--6	-9.2	2.833
--6	-9	2.73
--6	-8.8	2.63
--6	-8.6	2.533
--6	-8.4	2.44
--6	-8.2	2.351
--6	-8	2.265
--6	-7.8	2.184
--6	-7.6	2.108
--6	-7.4	2.036
--6	-7.2	1.97
--6	-7	1.91
--6	-6.8	1.857
--6	-6.6	1.811
--6	-6.4	1.773
--6	-6.2	1.746
--6	-6	1.731
--6	-5.8	1.73
--6	-5.6	1.745
--6	-5.4	1.779
--6	-5.2	1.835
--6	-5	1.912
--6	-4.8	2.005
--6	-4.6	2.097
--6	-4.4	2.152
--6	-4.2	2.122
--6	-4	1.968
--6	-3.8	1.699
--6	-3.6	1.372
--6	-3.4	1.055
--6	-3.2	0.788
--6	-3	0.58
--6	-2.8	0.425
--6	-2.6	0.311
--6	-2.4	0.228
--6	-2.2	0.168
--6	-2	0.124
--6	-1.8	0.091
--6	-1.6	0.067
--6	-1.4	0.049
--6	-1.2	0.036
--6	-1	0.027
--6	-0.8	0.02
--6	-0.6	0.015
--6	-0.4	0.012
--6	-0.2	0.01
--6	0	0.009
--6	0.2	0.01
--6	0.4	0.012
--6	0.6	0.015
--6	0.8	0.02
--6	1	0.027
--6	1.2	0.036
--6	1.4	0.049
--6	1.6	0.067
--6	1.8	0.091
--6	2	0.124
--6	2.2	0.168
--6	2.4	0.228
--6	2.6	0.311
--6	2.8	0.425
--6	3	0.58
--6	3.2	0.788
--6	3.4	1.055
--6	3.6	1.372
--6	3.8	1.699
--6	4	1.968
--6	4.2	2.122
--6	4.4	2.152
--6	4.6	2.097
--6	4.8	2.005
--6	5	1.912
--6	5.2	1.835
--6	5.4	1.779
--6	5.6	1.745
--6	5.8	1.73
--6	6	1.731
--6	6.2	1.746
--6	6.4	1.773
--6	6.6	1.811
--6	6.8	1.857
--6	7	1.91
--6	7.2	1.97
--6	7.4	2.036
--6	7.6	2.108
--6	7.8	2.184
--6	8	2.265
--6	8.2	2.351
--6	8.4	2.44
--6	8.6	2.533
--6	8.8	2.63
--6	9	2.73
--6	9.2	2.833
--6	9.4	2.94
--6	9.6	3.05
--6	9.8	3.163
-
--5	-10	3.362
--5	-9.8	3.253
--5	-9.6	3.148
--5	-9.4	3.047
--5	-9.2	2.95
--5	-9	2.858
--5	-8.8	2.771
--5	-8.6	2.689
--5	-8.4	2.613
--5	-8.2	2.544
--5	-8	2.483
--5	-7.8	2.43
--5	-7.6	2.388
--5	-7.4	2.357
--5	-7.2	2.339
--5	-7	2.339
--5	-6.8	2.359
--5	-6.6	2.402
--5	-6.4	2.475
--5	-6.2	2.581
--5	-6	2.721
--5	-5.8	2.889
--5	-5.6	3.062
--5	-5.4	3.188
--5	-5.2	3.192
--5	-5	3.01
--5	-4.8	2.644
--5	-4.6	2.177
--5	-4.4	1.709
--5	-4.2	1.306
--5	-4	0.985
--5	-3.8	0.741
--5	-3.6	0.559
--5	-3.4	0.424
--5	-3.2	0.323
--5	-3	0.247
--5	-2.8	0.19
--5	-2.6	0.146
--5	-2.4	0.112
--5	-2.2	0.086
--5	-2	0.066
--5	-1.8	0.051
--5	-1.6	0.039
--5	-1.4	0.029
--5	-1.2	0.022
--5	-1	0.017
--5	-0.8	0.013
--5	-0.6	0.01
--5	-0.4	0.008
--5	-0.2	0.007
--5	0	0.006
--5	0.2	0.007
--5	0.4	0.008
--5	0.6	0.01
--5	0.8	0.013
--5	1	0.017
--5	1.2	0.022
--5	1.4	0.029
--5	1.6	0.039
--5	1.8	0.051
--5	2	0.066
--5	2.2	0.086
--5	2.4	0.112
--5	2.6	0.146
--5	2.8	0.19
--5	3	0.247
--5	3.2	0.323
--5	3.4	0.424
--5	3.6	0.559
--5	3.8	0.741
--5	4	0.985
--5	4.2	1.306
--5	4.4	1.709
--5	4.6	2.177
--5	4.8	2.644
--5	5	3.01
--5	5.2	3.192
--5	5.4	3.188
--5	5.6	3.062
--5	5.8	2.889
--5	6	2.721
--5	6.2	2.581
--5	6.4	2.475
--5	6.6	2.402
--5	6.8	2.359
--5	7	2.339
--5	7.2	2.339
--5	7.4	2.357
--5	7.6	2.388
--5	7.8	2.43
--5	8	2.483
--5	8.2	2.544
--5	8.4	2.613
--5	8.6	2.689
--5	8.8	2.771
--5	9	2.858
--5	9.2	2.95
--5	9.4	3.047
--5	9.6	3.148
--5	9.8	3.253
-
--4	-10	3.279
--4	-9.8	3.163
--4	-9.6	3.05
--4	-9.4	2.94
--4	-9.2	2.833
--4	-9	2.73
--4	-8.8	2.63
--4	-8.6	2.533
--4	-8.4	2.44
--4	-8.2	2.351
--4	-8	2.265
--4	-7.8	2.184
--4	-7.6	2.108
--4	-7.4	2.036
--4	-7.2	1.97
--4	-7	1.91
--4	-6.8	1.857
--4	-6.6	1.811
--4	-6.4	1.773
--4	-6.2	1.746
--4	-6	1.731
--4	-5.8	1.73
--4	-5.6	1.745
--4	-5.4	1.779
--4	-5.2	1.835
--4	-5	1.912
--4	-4.8	2.005
--4	-4.6	2.097
--4	-4.4	2.152
--4	-4.2	2.122
--4	-4	1.968
--4	-3.8	1.699
--4	-3.6	1.372
--4	-3.4	1.055
--4	-3.2	0.788
--4	-3	0.58
--4	-2.8	0.425
--4	-2.6	0.311
--4	-2.4	0.228
--4	-2.2	0.168
--4	-2	0.124
--4	-1.8	0.091
--4	-1.6	0.067
--4	-1.4	0.049
--4	-1.2	0.036
--4	-1	0.027
--4	-0.8	0.02
--4	-0.6	0.015
--4	-0.4	0.012
--4	-0.2	0.01
--4	0	0.009
--4	0.2	0.01
--4	0.4	0.012
--4	0.6	0.015
--4	0.8	0.02
--4	1	0.027
--4	1.2	0.036
--4	1.4	0.049
--4	1.6	0.067
--4	1.8	0.091
--4	2	0.124
--4	2.2	0.168
--4	2.4	0.228
--4	2.6	0.311
--4	2.8	0.425
--4	3	0.58
--4	3.2	0.788
--4	3.4	1.055
--4	3.6	1.372
--4	3.8	1.699
--4	4	1.968
--4	4.2	2.122
--4	4.4	2.152
--4	4.6	2.097
--4	4.8	2.005
--4	5	1.912
--4	5.2	1.835
--4	5.4	1.779
--4	5.6	1.745
--4	5.8	1.73
--4	6	1.731
--4	6.2	1.746
--4	6.4	1.773
--4	6.6	1.811
--4	6.8	1.857
--4	7	1.91
--4	7.2	1.97
--4	7.4	2.036
--4	7.6	2.108
--4	7.8	2.184
--4	8	2.265
--4	8.2	2.351
--4	8.4	2.44
--4	8.6	2.533
--4	8.8	2.63
--4	9	2.73
--4	9.2	2.833
--4	9.4	2.94
--4	9.6	3.05
--4	9.8	3.163
-
--3	-10	3.232
--3	-9.8	3.113
--3	-9.6	2.996
--3	-9.4	2.882
--3	-9.2	2.771
--3	-9	2.663
--3	-8.8	2.557
--3	-8.6	2.454
--3	-8.4	2.355
--3	-8.2	2.258
--3	-8	2.164
--3	-7.8	2.073
--3	-7.6	1.986
--3	-7.4	1.901
--3	-7.2	1.82
--3	-7	1.743
--3	-6.8	1.669
--3	-6.6	1.599
--3	-6.4	1.533
--3	-6.2	1.471
--3	-6	1.414
--3	-5.8	1.361
--3	-5.6	1.315
--3	-5.4	1.275
--3	-5.2	1.242
--3	-5	1.216
--3	-4.8	1.2
--3	-4.6	1.195
--3	-4.4	1.201
--3	-4.2	1.22
--3	-4	1.25
--3	-3.8	1.288
--3	-3.6	1.321
--3	-3.4	1.328
--3	-3.2	1.28
--3	-3	1.158
--3	-2.8	0.973
--3	-2.6	0.763
--3	-2.4	0.569
--3	-2.2	0.41
--3	-2	0.291
--3	-1.8	0.204
--3	-1.6	0.143
--3	-1.4	0.1
--3	-1.2	0.07
--3	-1	0.05
--3	-0.8	0.035
--3	-0.6	0.026
--3	-0.4	0.02
--3	-0.2	0.016
--3	0	0.014
--3	0.2	0.016
--3	0.4	0.02
--3	0.6	0.026
--3	0.8	0.035
--3	1	0.05
--3	1.2	0.07
--3	1.4	0.1
--3	1.6	0.143
--3	1.8	0.204
--3	2	0.291
--3	2.2	0.41
--3	2.4	0.569
--3	2.6	0.763
--3	2.8	0.973
--3	3	1.158
--3	3.2	1.28
--3	3.4	1.328
--3	3.6	1.321
--3	3.8	1.288
--3	4	1.25
--3	4.2	1.22
--3	4.4	1.201
--3	4.6	1.195
--3	4.8	1.2
--3	5	1.216
--3	5.2	1.242
--3	5.4	1.275
--3	5.6	1.315
--3	5.8	1.361
--3	6	1.414
--3	6.2	1.471
--3	6.4	1.533
--3	6.6	1.599
--3	6.8	1.669
--3	7	1.743
--3	7.2	1.82
--3	7.4	1.901
--3	7.6	1.986
--3	7.8	2.073
--3	8	2.164
--3	8.2	2.258
--3	8.4	2.355
--3	8.6	2.454
--3	8.8	2.557
--3	9	2.663
--3	9.2	2.771
--3	9.4	2.882
--3	9.6	2.996
--3	9.8	3.113
-
--2	-10	3.203
--2	-9.8	3.082
--2	-9.6	2.964
--2	-9.4	2.848
--2	-9.2	2.735
--2	-9	2.624
--2	-8.8	2.516
--2	-8.6	2.411
--2	-8.4	2.308
--2	-8.2	2.208
--2	-8	2.111
--2	-7.8	2.016
--2	-7.6	1.924
--2	-7.4	1.835
--2	-7.2	1.748
--2	-7	1.665
--2	-6.8	1.584
--2	-6.6	1.506
--2	-6.4	1.431
--2	-6.2	1.359
--2	-6	1.29
--2	-5.8	1.224
--2	-5.6	1.161
--2	-5.4	1.102
--2	-5.2	1.046
--2	-5	0.993
--2	-4.8	0.945
--2	-4.6	0.901
--2	-4.4	0.861
--2	-4.2	0.825
--2	-4	0.795
--2	-3.8	0.771
--2	-3.6	0.753
--2	-3.4	0.741
--2	-3.2	0.736
--2	-3	0.736
--2	-2.8	0.738
--2	-2.6	0.735
--2	-2.4	0.715
--2	-2.2	0.666
--2	-2	0.58
--2	-1.8	0.468
--2	-1.6	0.351
--2	-1.4	0.25
--2	-1.2	0.172
--2	-1	0.117
--2	-0.8	0.08
--2	-0.6	0.055
--2	-0.4	0.04
--2	-0.2	0.031
--2	0	0.027
--2	0.2	0.031
--2	0.4	0.04
--2	0.6	0.055
--2	0.8	0.08
--2	1	0.117
--2	1.2	0.172
--2	1.4	0.25
--2	1.6	0.351
--2	1.8	0.468
--2	2	0.58
--2	2.2	0.666
--2	2.4	0.715
--2	2.6	0.735
--2	2.8	0.738
--2	3	0.736
--2	3.2	0.736
--2	3.4	0.741
--2	3.6	0.753
--2	3.8	0.771
--2	4	0.795
--2	4.2	0.825
--2	4.4	0.861
--2	4.6	0.901
--2	4.8	0.945
--2	5	0.993
--2	5.2	1.046
--2	5.4	1.102
--2	5.6	1.161
--2	5.8	1.224
--2	6	1.29
--2	6.2	1.359
--2	6.4	1.431
--2	6.6	1.506
--2	6.8	1.584
--2	7	1.665
--2	7.2	1.748
--2	7.4	1.835
--2	7.6	1.924
--2	7.8	2.016
--2	8	2.111
--2	8.2	2.208
--2	8.4	2.308
--2	8.6	2.411
--2	8.8	2.516
--2	9	2.624
--2	9.2	2.735
--2	9.4	2.848
--2	9.6	2.964
--2	9.8	3.082
-
--1	-10	3.185
--1	-9.8	3.063
--1	-9.6	2.943
--1	-9.4	2.827
--1	-9.2	2.712
--1	-9	2.601
--1	-8.8	2.491
--1	-8.6	2.385
--1	-8.4	2.281
--1	-8.2	2.179
--1	-8	2.08
--1	-7.8	1.984
--1	-7.6	1.89
--1	-7.4	1.799
--1	-7.2	1.71
--1	-7	1.624
--1	-6.8	1.54
--1	-6.6	1.459
--1	-6.4	1.381
--1	-6.2	1.305
--1	-6	1.232
--1	-5.8	1.161
--1	-5.6	1.094
--1	-5.4	1.029
--1	-5.2	0.966
--1	-5	0.906
--1	-4.8	0.849
--1	-4.6	0.795
--1	-4.4	0.744
--1	-4.2	0.695
--1	-4	0.65
--1	-3.8	0.607
--1	-3.6	0.567
--1	-3.4	0.531
--1	-3.2	0.498
--1	-3	0.468
--1	-2.8	0.442
--1	-2.6	0.419
--1	-2.4	0.399
--1	-2.2	0.382
--1	-2	0.368
--1	-1.8	0.354
--1	-1.6	0.337
--1	-1.4	0.313
--1	-1.2	0.279
--1	-1	0.233
--1	-0.8	0.182
--1	-0.6	0.135
--1	-0.4	0.099
--1	-0.2	0.075
--1	0	0.064
--1	0.2	0.075
--1	0.4	0.099
--1	0.6	0.135
--1	0.8	0.182
--1	1	0.233
--1	1.2	0.279
--1	1.4	0.313
--1	1.6	0.337
--1	1.8	0.354
--1	2	0.368
--1	2.2	0.382
--1	2.4	0.399
--1	2.6	0.419
--1	2.8	0.442
--1	3	0.468
--1	3.2	0.498
--1	3.4	0.531
--1	3.6	0.567
--1	3.8	0.607
--1	4	0.65
--1	4.2	0.695
--1	4.4	0.744
--1	4.6	0.795
--1	4.8	0.849
--1	5	0.906
--1	5.2	0.966
--1	5.4	1.029
--1	5.6	1.094
--1	5.8	1.161
--1	6	1.232
--1	6.2	1.305
--1	6.4	1.381
--1	6.6	1.459
--1	6.8	1.54
--1	7	1.624
--1	7.2	1.71
--1	7.4	1.799
--1	7.6	1.89
--1	7.8	1.984
--1	8	2.08
--1	8.2	2.179
--1	8.4	2.281
--1	8.6	2.385
--1	8.8	2.491
--1	9	2.601
--1	9.2	2.712
--1	9.4	2.827
--1	9.6	2.943
--1	9.8	3.063
-
-0	-10	3.173
-0	-9.8	3.05
-0	-9.6	2.93
-0	-9.4	2.813
-0	-9.2	2.698
-0	-9	2.586
-0	-8.8	2.476
-0	-8.6	2.368
-0	-8.4	2.264
-0	-8.2	2.161
-0	-8	2.062
-0	-7.8	1.964
-0	-7.6	1.869
-0	-7.4	1.777
-0	-7.2	1.687
-0	-7	1.6
-0	-6.8	1.515
-0	-6.6	1.433
-0	-6.4	1.353
-0	-6.2	1.276
-0	-6	1.202
-0	-5.8	1.129
-0	-5.6	1.06
-0	-5.4	0.993
-0	-5.2	0.928
-0	-5	0.866
-0	-4.8	0.806
-0	-4.6	0.749
-0	-4.4	0.694
-0	-4.2	0.642
-0	-4	0.593
-0	-3.8	0.546
-0	-3.6	0.501
-0	-3.4	0.459
-0	-3.2	0.419
-0	-3	0.382
-0	-2.8	0.348
-0	-2.6	0.316
-0	-2.4	0.286
-0	-2.2	0.259
-0	-2	0.234
-0	-1.8	0.212
-0	-1.6	0.192
-0	-1.4	0.175
-0	-1.2	0.16
-0	-1	0.147
-0	-0.8	0.137
-0	-0.6	0.129
-0	-0.4	0.123
-0	-0.2	0.119
-0	0	0.117
-0	0.2	0.119
-0	0.4	0.123
-0	0.6	0.129
-0	0.8	0.137
-0	1	0.147
-0	1.2	0.16
-0	1.4	0.175
-0	1.6	0.192
-0	1.8	0.212
-0	2	0.234
-0	2.2	0.259
-0	2.4	0.286
-0	2.6	0.316
-0	2.8	0.348
-0	3	0.382
-0	3.2	0.419
-0	3.4	0.459
-0	3.6	0.501
-0	3.8	0.546
-0	4	0.593
-0	4.2	0.642
-0	4.4	0.694
-0	4.6	0.749
-0	4.8	0.806
-0	5	0.866
-0	5.2	0.928
-0	5.4	0.993
-0	5.6	1.06
-0	5.8	1.129
-0	6	1.202
-0	6.2	1.276
-0	6.4	1.353
-0	6.6	1.433
-0	6.8	1.515
-0	7	1.6
-0	7.2	1.687
-0	7.4	1.777
-0	7.6	1.869
-0	7.8	1.964
-0	8	2.062
-0	8.2	2.161
-0	8.4	2.264
-0	8.6	2.368
-0	8.8	2.476
-0	9	2.586
-0	9.2	2.698
-0	9.4	2.813
-0	9.6	2.93
-0	9.8	3.05
-
-1	-10	3.185
-1	-9.8	3.063
-1	-9.6	2.943
-1	-9.4	2.827
-1	-9.2	2.712
-1	-9	2.601
-1	-8.8	2.491
-1	-8.6	2.385
-1	-8.4	2.281
-1	-8.2	2.179
-1	-8	2.08
-1	-7.8	1.984
-1	-7.6	1.89
-1	-7.4	1.799
-1	-7.2	1.71
-1	-7	1.624
-1	-6.8	1.54
-1	-6.6	1.459
-1	-6.4	1.381
-1	-6.2	1.305
-1	-6	1.232
-1	-5.8	1.161
-1	-5.6	1.094
-1	-5.4	1.029
-1	-5.2	0.966
-1	-5	0.906
-1	-4.8	0.849
-1	-4.6	0.795
-1	-4.4	0.744
-1	-4.2	0.695
-1	-4	0.65
-1	-3.8	0.607
-1	-3.6	0.567
-1	-3.4	0.531
-1	-3.2	0.498
-1	-3	0.468
-1	-2.8	0.442
-1	-2.6	0.419
-1	-2.4	0.399
-1	-2.2	0.382
-1	-2	0.368
-1	-1.8	0.354
-1	-1.6	0.337
-1	-1.4	0.313
-1	-1.2	0.279
-1	-1	0.233
-1	-0.8	0.182
-1	-0.6	0.135
-1	-0.4	0.099
-1	-0.2	0.075
-1	0	0.064
-1	0.2	0.075
-1	0.4	0.099
-1	0.6	0.135
-1	0.8	0.182
-1	1	0.233
-1	1.2	0.279
-1	1.4	0.313
-1	1.6	0.337
-1	1.8	0.354
-1	2	0.368
-1	2.2	0.382
-1	2.4	0.399
-1	2.6	0.419
-1	2.8	0.442
-1	3	0.468
-1	3.2	0.498
-1	3.4	0.531
-1	3.6	0.567
-1	3.8	0.607
-1	4	0.65
-1	4.2	0.695
-1	4.4	0.744
-1	4.6	0.795
-1	4.8	0.849
-1	5	0.906
-1	5.2	0.966
-1	5.4	1.029
-1	5.6	1.094
-1	5.8	1.161
-1	6	1.232
-1	6.2	1.305
-1	6.4	1.381
-1	6.6	1.459
-1	6.8	1.54
-1	7	1.624
-1	7.2	1.71
-1	7.4	1.799
-1	7.6	1.89
-1	7.8	1.984
-1	8	2.08
-1	8.2	2.179
-1	8.4	2.281
-1	8.6	2.385
-1	8.8	2.491
-1	9	2.601
-1	9.2	2.712
-1	9.4	2.827
-1	9.6	2.943
-1	9.8	3.063
-
-2	-10	3.203
-2	-9.8	3.082
-2	-9.6	2.964
-2	-9.4	2.848
-2	-9.2	2.735
-2	-9	2.624
-2	-8.8	2.516
-2	-8.6	2.411
-2	-8.4	2.308
-2	-8.2	2.208
-2	-8	2.111
-2	-7.8	2.016
-2	-7.6	1.924
-2	-7.4	1.835
-2	-7.2	1.748
-2	-7	1.665
-2	-6.8	1.584
-2	-6.6	1.506
-2	-6.4	1.431
-2	-6.2	1.359
-2	-6	1.29
-2	-5.8	1.224
-2	-5.6	1.161
-2	-5.4	1.102
-2	-5.2	1.046
-2	-5	0.993
-2	-4.8	0.945
-2	-4.6	0.901
-2	-4.4	0.861
-2	-4.2	0.825
-2	-4	0.795
-2	-3.8	0.771
-2	-3.6	0.753
-2	-3.4	0.741
-2	-3.2	0.736
-2	-3	0.736
-2	-2.8	0.738
-2	-2.6	0.735
-2	-2.4	0.715
-2	-2.2	0.666
-2	-2	0.58
-2	-1.8	0.468
-2	-1.6	0.351
-2	-1.4	0.25
-2	-1.2	0.172
-2	-1	0.117
-2	-0.8	0.08
-2	-0.6	0.055
-2	-0.4	0.04
-2	-0.2	0.031
-2	0	0.027
-2	0.2	0.031
-2	0.4	0.04
-2	0.6	0.055
-2	0.8	0.08
-2	1	0.117
-2	1.2	0.172
-2	1.4	0.25
-2	1.6	0.351
-2	1.8	0.468
-2	2	0.58
-2	2.2	0.666
-2	2.4	0.715
-2	2.6	0.735
-2	2.8	0.738
-2	3	0.736
-2	3.2	0.736
-2	3.4	0.741
-2	3.6	0.753
-2	3.8	0.771
-2	4	0.795
-2	4.2	0.825
-2	4.4	0.861
-2	4.6	0.901
-2	4.8	0.945
-2	5	0.993
-2	5.2	1.046
-2	5.4	1.102
-2	5.6	1.161
-2	5.8	1.224
-2	6	1.29
-2	6.2	1.359
-2	6.4	1.431
-2	6.6	1.506
-2	6.8	1.584
-2	7	1.665
-2	7.2	1.748
-2	7.4	1.835
-2	7.6	1.924
-2	7.8	2.016
-2	8	2.111
-2	8.2	2.208
-2	8.4	2.308
-2	8.6	2.411
-2	8.8	2.516
-2	9	2.624
-2	9.2	2.735
-2	9.4	2.848
-2	9.6	2.964
-2	9.8	3.082
-
-3	-10	3.232
-3	-9.8	3.113
-3	-9.6	2.996
-3	-9.4	2.882
-3	-9.2	2.771
-3	-9	2.663
-3	-8.8	2.557
-3	-8.6	2.454
-3	-8.4	2.355
-3	-8.2	2.258
-3	-8	2.164
-3	-7.8	2.073
-3	-7.6	1.986
-3	-7.4	1.901
-3	-7.2	1.82
-3	-7	1.743
-3	-6.8	1.669
-3	-6.6	1.599
-3	-6.4	1.533
-3	-6.2	1.471
-3	-6	1.414
-3	-5.8	1.361
-3	-5.6	1.315
-3	-5.4	1.275
-3	-5.2	1.242
-3	-5	1.216
-3	-4.8	1.2
-3	-4.6	1.195
-3	-4.4	1.201
-3	-4.2	1.22
-3	-4	1.25
-3	-3.8	1.288
-3	-3.6	1.321
-3	-3.4	1.328
-3	-3.2	1.28
-3	-3	1.158
-3	-2.8	0.973
-3	-2.6	0.763
-3	-2.4	0.569
-3	-2.2	0.41
-3	-2	0.291
-3	-1.8	0.204
-3	-1.6	0.143
-3	-1.4	0.1
-3	-1.2	0.07
-3	-1	0.05
-3	-0.8	0.035
-3	-0.6	0.026
-3	-0.4	0.02
-3	-0.2	0.016
-3	0	0.014
-3	0.2	0.016
-3	0.4	0.02
-3	0.6	0.026
-3	0.8	0.035
-3	1	0.05
-3	1.2	0.07
-3	1.4	0.1
-3	1.6	0.143
-3	1.8	0.204
-3	2	0.291
-3	2.2	0.41
-3	2.4	0.569
-3	2.6	0.763
-3	2.8	0.973
-3	3	1.158
-3	3.2	1.28
-3	3.4	1.328
-3	3.6	1.321
-3	3.8	1.288
-3	4	1.25
-3	4.2	1.22
-3	4.4	1.201
-3	4.6	1.195
-3	4.8	1.2
-3	5	1.216
-3	5.2	1.242
-3	5.4	1.275
-3	5.6	1.315
-3	5.8	1.361
-3	6	1.414
-3	6.2	1.471
-3	6.4	1.533
-3	6.6	1.599
-3	6.8	1.669
-3	7	1.743
-3	7.2	1.82
-3	7.4	1.901
-3	7.6	1.986
-3	7.8	2.073
-3	8	2.164
-3	8.2	2.258
-3	8.4	2.355
-3	8.6	2.454
-3	8.8	2.557
-3	9	2.663
-3	9.2	2.771
-3	9.4	2.882
-3	9.6	2.996
-3	9.8	3.113
-
-4	-10	3.279
-4	-9.8	3.163
-4	-9.6	3.05
-4	-9.4	2.94
-4	-9.2	2.833
-4	-9	2.73
-4	-8.8	2.63
-4	-8.6	2.533
-4	-8.4	2.44
-4	-8.2	2.351
-4	-8	2.265
-4	-7.8	2.184
-4	-7.6	2.108
-4	-7.4	2.036
-4	-7.2	1.97
-4	-7	1.91
-4	-6.8	1.857
-4	-6.6	1.811
-4	-6.4	1.773
-4	-6.2	1.746
-4	-6	1.731
-4	-5.8	1.73
-4	-5.6	1.745
-4	-5.4	1.779
-4	-5.2	1.835
-4	-5	1.912
-4	-4.8	2.005
-4	-4.6	2.097
-4	-4.4	2.152
-4	-4.2	2.122
-4	-4	1.968
-4	-3.8	1.699
-4	-3.6	1.372
-4	-3.4	1.055
-4	-3.2	0.788
-4	-3	0.58
-4	-2.8	0.425
-4	-2.6	0.311
-4	-2.4	0.228
-4	-2.2	0.168
-4	-2	0.124
-4	-1.8	0.091
-4	-1.6	0.067
-4	-1.4	0.049
-4	-1.2	0.036
-4	-1	0.027
-4	-0.8	0.02
-4	-0.6	0.015
-4	-0.4	0.012
-4	-0.2	0.01
-4	0	0.009
-4	0.2	0.01
-4	0.4	0.012
-4	0.6	0.015
-4	0.8	0.02
-4	1	0.027
-4	1.2	0.036
-4	1.4	0.049
-4	1.6	0.067
-4	1.8	0.091
-4	2	0.124
-4	2.2	0.168
-4	2.4	0.228
-4	2.6	0.311
-4	2.8	0.425
-4	3	0.58
-4	3.2	0.788
-4	3.4	1.055
-4	3.6	1.372
-4	3.8	1.699
-4	4	1.968
-4	4.2	2.122
-4	4.4	2.152
-4	4.6	2.097
-4	4.8	2.005
-4	5	1.912
-4	5.2	1.835
-4	5.4	1.779
-4	5.6	1.745
-4	5.8	1.73
-4	6	1.731
-4	6.2	1.746
-4	6.4	1.773
-4	6.6	1.811
-4	6.8	1.857
-4	7	1.91
-4	7.2	1.97
-4	7.4	2.036
-4	7.6	2.108
-4	7.8	2.184
-4	8	2.265
-4	8.2	2.351
-4	8.4	2.44
-4	8.6	2.533
-4	8.8	2.63
-4	9	2.73
-4	9.2	2.833
-4	9.4	2.94
-4	9.6	3.05
-4	9.8	3.163
-
-5	-10	3.362
-5	-9.8	3.253
-5	-9.6	3.148
-5	-9.4	3.047
-5	-9.2	2.95
-5	-9	2.858
-5	-8.8	2.771
-5	-8.6	2.689
-5	-8.4	2.613
-5	-8.2	2.544
-5	-8	2.483
-5	-7.8	2.43
-5	-7.6	2.388
-5	-7.4	2.357
-5	-7.2	2.339
-5	-7	2.339
-5	-6.8	2.359
-5	-6.6	2.402
-5	-6.4	2.475
-5	-6.2	2.581
-5	-6	2.721
-5	-5.8	2.889
-5	-5.6	3.062
-5	-5.4	3.188
-5	-5.2	3.192
-5	-5	3.01
-5	-4.8	2.644
-5	-4.6	2.177
-5	-4.4	1.709
-5	-4.2	1.306
-5	-4	0.985
-5	-3.8	0.741
-5	-3.6	0.559
-5	-3.4	0.424
-5	-3.2	0.323
-5	-3	0.247
-5	-2.8	0.19
-5	-2.6	0.146
-5	-2.4	0.112
-5	-2.2	0.086
-5	-2	0.066
-5	-1.8	0.051
-5	-1.6	0.039
-5	-1.4	0.029
-5	-1.2	0.022
-5	-1	0.017
-5	-0.8	0.013
-5	-0.6	0.01
-5	-0.4	0.008
-5	-0.2	0.007
-5	0	0.006
-5	0.2	0.007
-5	0.4	0.008
-5	0.6	0.01
-5	0.8	0.013
-5	1	0.017
-5	1.2	0.022
-5	1.4	0.029
-5	1.6	0.039
-5	1.8	0.051
-5	2	0.066
-5	2.2	0.086
-5	2.4	0.112
-5	2.6	0.146
-5	2.8	0.19
-5	3	0.247
-5	3.2	0.323
-5	3.4	0.424
-5	3.6	0.559
-5	3.8	0.741
-5	4	0.985
-5	4.2	1.306
-5	4.4	1.709
-5	4.6	2.177
-5	4.8	2.644
-5	5	3.01
-5	5.2	3.192
-5	5.4	3.188
-5	5.6	3.062
-5	5.8	2.889
-5	6	2.721
-5	6.2	2.581
-5	6.4	2.475
-5	6.6	2.402
-5	6.8	2.359
-5	7	2.339
-5	7.2	2.339
-5	7.4	2.357
-5	7.6	2.388
-5	7.8	2.43
-5	8	2.483
-5	8.2	2.544
-5	8.4	2.613
-5	8.6	2.689
-5	8.8	2.771
-5	9	2.858
-5	9.2	2.95
-5	9.4	3.047
-5	9.6	3.148
-5	9.8	3.253
-
-6	-10	3.279
-6	-9.8	3.163
-6	-9.6	3.05
-6	-9.4	2.94
-6	-9.2	2.833
-6	-9	2.73
-6	-8.8	2.63
-6	-8.6	2.533
-6	-8.4	2.44
-6	-8.2	2.351
-6	-8	2.265
-6	-7.8	2.184
-6	-7.6	2.108
-6	-7.4	2.036
-6	-7.2	1.97
-6	-7	1.91
-6	-6.8	1.857
-6	-6.6	1.811
-6	-6.4	1.773
-6	-6.2	1.746
-6	-6	1.731
-6	-5.8	1.73
-6	-5.6	1.745
-6	-5.4	1.779
-6	-5.2	1.835
-6	-5	1.912
-6	-4.8	2.005
-6	-4.6	2.097
-6	-4.4	2.152
-6	-4.2	2.122
-6	-4	1.968
-6	-3.8	1.699
-6	-3.6	1.372
-6	-3.4	1.055
-6	-3.2	0.788
-6	-3	0.58
-6	-2.8	0.425
-6	-2.6	0.311
-6	-2.4	0.228
-6	-2.2	0.168
-6	-2	0.124
-6	-1.8	0.091
-6	-1.6	0.067
-6	-1.4	0.049
-6	-1.2	0.036
-6	-1	0.027
-6	-0.8	0.02
-6	-0.6	0.015
-6	-0.4	0.012
-6	-0.2	0.01
-6	0	0.009
-6	0.2	0.01
-6	0.4	0.012
-6	0.6	0.015
-6	0.8	0.02
-6	1	0.027
-6	1.2	0.036
-6	1.4	0.049
-6	1.6	0.067
-6	1.8	0.091
-6	2	0.124
-6	2.2	0.168
-6	2.4	0.228
-6	2.6	0.311
-6	2.8	0.425
-6	3	0.58
-6	3.2	0.788
-6	3.4	1.055
-6	3.6	1.372
-6	3.8	1.699
-6	4	1.968
-6	4.2	2.122
-6	4.4	2.152
-6	4.6	2.097
-6	4.8	2.005
-6	5	1.912
-6	5.2	1.835
-6	5.4	1.779
-6	5.6	1.745
-6	5.8	1.73
-6	6	1.731
-6	6.2	1.746
-6	6.4	1.773
-6	6.6	1.811
-6	6.8	1.857
-6	7	1.91
-6	7.2	1.97
-6	7.4	2.036
-6	7.6	2.108
-6	7.8	2.184
-6	8	2.265
-6	8.2	2.351
-6	8.4	2.44
-6	8.6	2.533
-6	8.8	2.63
-6	9	2.73
-6	9.2	2.833
-6	9.4	2.94
-6	9.6	3.05
-6	9.8	3.163
-
-7	-10	3.232
-7	-9.8	3.113
-7	-9.6	2.996
-7	-9.4	2.882
-7	-9.2	2.771
-7	-9	2.663
-7	-8.8	2.557
-7	-8.6	2.454
-7	-8.4	2.355
-7	-8.2	2.258
-7	-8	2.164
-7	-7.8	2.073
-7	-7.6	1.986
-7	-7.4	1.901
-7	-7.2	1.82
-7	-7	1.743
-7	-6.8	1.669
-7	-6.6	1.599
-7	-6.4	1.533
-7	-6.2	1.471
-7	-6	1.414
-7	-5.8	1.361
-7	-5.6	1.315
-7	-5.4	1.275
-7	-5.2	1.242
-7	-5	1.216
-7	-4.8	1.2
-7	-4.6	1.195
-7	-4.4	1.201
-7	-4.2	1.22
-7	-4	1.25
-7	-3.8	1.288
-7	-3.6	1.321
-7	-3.4	1.328
-7	-3.2	1.28
-7	-3	1.158
-7	-2.8	0.973
-7	-2.6	0.763
-7	-2.4	0.569
-7	-2.2	0.41
-7	-2	0.291
-7	-1.8	0.204
-7	-1.6	0.143
-7	-1.4	0.1
-7	-1.2	0.07
-7	-1	0.05
-7	-0.8	0.035
-7	-0.6	0.026
-7	-0.4	0.02
-7	-0.2	0.016
-7	0	0.014
-7	0.2	0.016
-7	0.4	0.02
-7	0.6	0.026
-7	0.8	0.035
-7	1	0.05
-7	1.2	0.07
-7	1.4	0.1
-7	1.6	0.143
-7	1.8	0.204
-7	2	0.291
-7	2.2	0.41
-7	2.4	0.569
-7	2.6	0.763
-7	2.8	0.973
-7	3	1.158
-7	3.2	1.28
-7	3.4	1.328
-7	3.6	1.321
-7	3.8	1.288
-7	4	1.25
-7	4.2	1.22
-7	4.4	1.201
-7	4.6	1.195
-7	4.8	1.2
-7	5	1.216
-7	5.2	1.242
-7	5.4	1.275
-7	5.6	1.315
-7	5.8	1.361
-7	6	1.414
-7	6.2	1.471
-7	6.4	1.533
-7	6.6	1.599
-7	6.8	1.669
-7	7	1.743
-7	7.2	1.82
-7	7.4	1.901
-7	7.6	1.986
-7	7.8	2.073
-7	8	2.164
-7	8.2	2.258
-7	8.4	2.355
-7	8.6	2.454
-7	8.8	2.557
-7	9	2.663
-7	9.2	2.771
-7	9.4	2.882
-7	9.6	2.996
-7	9.8	3.113
-
-8	-10	3.203
-8	-9.8	3.082
-8	-9.6	2.964
-8	-9.4	2.848
-8	-9.2	2.735
-8	-9	2.624
-8	-8.8	2.516
-8	-8.6	2.411
-8	-8.4	2.308
-8	-8.2	2.208
-8	-8	2.111
-8	-7.8	2.016
-8	-7.6	1.924
-8	-7.4	1.835
-8	-7.2	1.748
-8	-7	1.665
-8	-6.8	1.584
-8	-6.6	1.506
-8	-6.4	1.431
-8	-6.2	1.359
-8	-6	1.29
-8	-5.8	1.224
-8	-5.6	1.161
-8	-5.4	1.102
-8	-5.2	1.046
-8	-5	0.993
-8	-4.8	0.945
-8	-4.6	0.901
-8	-4.4	0.861
-8	-4.2	0.825
-8	-4	0.795
-8	-3.8	0.771
-8	-3.6	0.753
-8	-3.4	0.741
-8	-3.2	0.736
-8	-3	0.736
-8	-2.8	0.738
-8	-2.6	0.735
-8	-2.4	0.715
-8	-2.2	0.666
-8	-2	0.58
-8	-1.8	0.468
-8	-1.6	0.351
-8	-1.4	0.25
-8	-1.2	0.172
-8	-1	0.117
-8	-0.8	0.08
-8	-0.6	0.055
-8	-0.4	0.04
-8	-0.2	0.031
-8	0	0.027
-8	0.2	0.031
-8	0.4	0.04
-8	0.6	0.055
-8	0.8	0.08
-8	1	0.117
-8	1.2	0.172
-8	1.4	0.25
-8	1.6	0.351
-8	1.8	0.468
-8	2	0.58
-8	2.2	0.666
-8	2.4	0.715
-8	2.6	0.735
-8	2.8	0.738
-8	3	0.736
-8	3.2	0.736
-8	3.4	0.741
-8	3.6	0.753
-8	3.8	0.771
-8	4	0.795
-8	4.2	0.825
-8	4.4	0.861
-8	4.6	0.901
-8	4.8	0.945
-8	5	0.993
-8	5.2	1.046
-8	5.4	1.102
-8	5.6	1.161
-8	5.8	1.224
-8	6	1.29
-8	6.2	1.359
-8	6.4	1.431
-8	6.6	1.506
-8	6.8	1.584
-8	7	1.665
-8	7.2	1.748
-8	7.4	1.835
-8	7.6	1.924
-8	7.8	2.016
-8	8	2.111
-8	8.2	2.208
-8	8.4	2.308
-8	8.6	2.411
-8	8.8	2.516
-8	9	2.624
-8	9.2	2.735
-8	9.4	2.848
-8	9.6	2.964
-8	9.8	3.082
-
-9	-10	3.185
-9	-9.8	3.063
-9	-9.6	2.943
-9	-9.4	2.827
-9	-9.2	2.712
-9	-9	2.601
-9	-8.8	2.491
-9	-8.6	2.385
-9	-8.4	2.281
-9	-8.2	2.179
-9	-8	2.08
-9	-7.8	1.984
-9	-7.6	1.89
-9	-7.4	1.799
-9	-7.2	1.71
-9	-7	1.624
-9	-6.8	1.54
-9	-6.6	1.459
-9	-6.4	1.381
-9	-6.2	1.305
-9	-6	1.232
-9	-5.8	1.161
-9	-5.6	1.094
-9	-5.4	1.029
-9	-5.2	0.966
-9	-5	0.906
-9	-4.8	0.849
-9	-4.6	0.795
-9	-4.4	0.744
-9	-4.2	0.695
-9	-4	0.65
-9	-3.8	0.607
-9	-3.6	0.567
-9	-3.4	0.531
-9	-3.2	0.498
-9	-3	0.468
-9	-2.8	0.442
-9	-2.6	0.419
-9	-2.4	0.399
-9	-2.2	0.382
-9	-2	0.368
-9	-1.8	0.354
-9	-1.6	0.337
-9	-1.4	0.313
-9	-1.2	0.279
-9	-1	0.233
-9	-0.8	0.182
-9	-0.6	0.135
-9	-0.4	0.099
-9	-0.2	0.075
-9	0	0.064
-9	0.2	0.075
-9	0.4	0.099
-9	0.6	0.135
-9	0.8	0.182
-9	1	0.233
-9	1.2	0.279
-9	1.4	0.313
-9	1.6	0.337
-9	1.8	0.354
-9	2	0.368
-9	2.2	0.382
-9	2.4	0.399
-9	2.6	0.419
-9	2.8	0.442
-9	3	0.468
-9	3.2	0.498
-9	3.4	0.531
-9	3.6	0.567
-9	3.8	0.607
-9	4	0.65
-9	4.2	0.695
-9	4.4	0.744
-9	4.6	0.795
-9	4.8	0.849
-9	5	0.906
-9	5.2	0.966
-9	5.4	1.029
-9	5.6	1.094
-9	5.8	1.161
-9	6	1.232
-9	6.2	1.305
-9	6.4	1.381
-9	6.6	1.459
-9	6.8	1.54
-9	7	1.624
-9	7.2	1.71
-9	7.4	1.799
-9	7.6	1.89
-9	7.8	1.984
-9	8	2.08
-9	8.2	2.179
-9	8.4	2.281
-9	8.6	2.385
-9	8.8	2.491
-9	9	2.601
-9	9.2	2.712
-9	9.4	2.827
-9	9.6	2.943
-9	9.8	3.063
-
-10	-10	3.173
-10	-9.8	3.05
-10	-9.6	2.93
-10	-9.4	2.813
-10	-9.2	2.698
-10	-9	2.586
-10	-8.8	2.476
-10	-8.6	2.368
-10	-8.4	2.264
-10	-8.2	2.161
-10	-8	2.062
-10	-7.8	1.964
-10	-7.6	1.869
-10	-7.4	1.777
-10	-7.2	1.687
-10	-7	1.6
-10	-6.8	1.515
-10	-6.6	1.433
-10	-6.4	1.353
-10	-6.2	1.276
-10	-6	1.202
-10	-5.8	1.129
-10	-5.6	1.06
-10	-5.4	0.993
-10	-5.2	0.928
-10	-5	0.866
-10	-4.8	0.806
-10	-4.6	0.749
-10	-4.4	0.694
-10	-4.2	0.642
-10	-4	0.593
-10	-3.8	0.546
-10	-3.6	0.501
-10	-3.4	0.459
-10	-3.2	0.419
-10	-3	0.382
-10	-2.8	0.348
-10	-2.6	0.316
-10	-2.4	0.286
-10	-2.2	0.259
-10	-2	0.234
-10	-1.8	0.212
-10	-1.6	0.192
-10	-1.4	0.175
-10	-1.2	0.16
-10	-1	0.147
-10	-0.8	0.137
-10	-0.6	0.129
-10	-0.4	0.123
-10	-0.2	0.119
-10	0	0.117
-10	0.2	0.119
-10	0.4	0.123
-10	0.6	0.129
-10	0.8	0.137
-10	1	0.147
-10	1.2	0.16
-10	1.4	0.175
-10	1.6	0.192
-10	1.8	0.212
-10	2	0.234
-10	2.2	0.259
-10	2.4	0.286
-10	2.6	0.316
-10	2.8	0.348
-10	3	0.382
-10	3.2	0.419
-10	3.4	0.459
-10	3.6	0.501
-10	3.8	0.546
-10	4	0.593
-10	4.2	0.642
-10	4.4	0.694
-10	4.6	0.749
-10	4.8	0.806
-10	5	0.866
-10	5.2	0.928
-10	5.4	0.993
-10	5.6	1.06
-10	5.8	1.129
-10	6	1.202
-10	6.2	1.276
-10	6.4	1.353
-10	6.6	1.433
-10	6.8	1.515
-10	7	1.6
-10	7.2	1.687
-10	7.4	1.777
-10	7.6	1.869
-10	7.8	1.964
-10	8	2.062
-10	8.2	2.161
-10	8.4	2.264
-10	8.6	2.368
-10	8.8	2.476
-10	9	2.586
-10	9.2	2.698
-10	9.4	2.813
-10	9.6	2.93
-10	9.8	3.05
-
-11	-10	3.185
-11	-9.8	3.063
-11	-9.6	2.943
-11	-9.4	2.827
-11	-9.2	2.712
-11	-9	2.601
-11	-8.8	2.491
-11	-8.6	2.385
-11	-8.4	2.281
-11	-8.2	2.179
-11	-8	2.08
-11	-7.8	1.984
-11	-7.6	1.89
-11	-7.4	1.799
-11	-7.2	1.71
-11	-7	1.624
-11	-6.8	1.54
-11	-6.6	1.459
-11	-6.4	1.381
-11	-6.2	1.305
-11	-6	1.232
-11	-5.8	1.161
-11	-5.6	1.094
-11	-5.4	1.029
-11	-5.2	0.966
-11	-5	0.906
-11	-4.8	0.849
-11	-4.6	0.795
-11	-4.4	0.744
-11	-4.2	0.695
-11	-4	0.65
-11	-3.8	0.607
-11	-3.6	0.567
-11	-3.4	0.531
-11	-3.2	0.498
-11	-3	0.468
-11	-2.8	0.442
-11	-2.6	0.419
-11	-2.4	0.399
-11	-2.2	0.382
-11	-2	0.368
-11	-1.8	0.354
-11	-1.6	0.337
-11	-1.4	0.313
-11	-1.2	0.279
-11	-1	0.233
-11	-0.8	0.182
-11	-0.6	0.135
-11	-0.4	0.099
-11	-0.2	0.075
-11	0	0.064
-11	0.2	0.075
-11	0.4	0.099
-11	0.6	0.135
-11	0.8	0.182
-11	1	0.233
-11	1.2	0.279
-11	1.4	0.313
-11	1.6	0.337
-11	1.8	0.354
-11	2	0.368
-11	2.2	0.382
-11	2.4	0.399
-11	2.6	0.419
-11	2.8	0.442
-11	3	0.468
-11	3.2	0.498
-11	3.4	0.531
-11	3.6	0.567
-11	3.8	0.607
-11	4	0.65
-11	4.2	0.695
-11	4.4	0.744
-11	4.6	0.795
-11	4.8	0.849
-11	5	0.906
-11	5.2	0.966
-11	5.4	1.029
-11	5.6	1.094
-11	5.8	1.161
-11	6	1.232
-11	6.2	1.305
-11	6.4	1.381
-11	6.6	1.459
-11	6.8	1.54
-11	7	1.624
-11	7.2	1.71
-11	7.4	1.799
-11	7.6	1.89
-11	7.8	1.984
-11	8	2.08
-11	8.2	2.179
-11	8.4	2.281
-11	8.6	2.385
-11	8.8	2.491
-11	9	2.601
-11	9.2	2.712
-11	9.4	2.827
-11	9.6	2.943
-11	9.8	3.063
-
-12	-10	3.203
-12	-9.8	3.082
-12	-9.6	2.964
-12	-9.4	2.848
-12	-9.2	2.735
-12	-9	2.624
-12	-8.8	2.516
-12	-8.6	2.411
-12	-8.4	2.308
-12	-8.2	2.208
-12	-8	2.111
-12	-7.8	2.016
-12	-7.6	1.924
-12	-7.4	1.835
-12	-7.2	1.748
-12	-7	1.665
-12	-6.8	1.584
-12	-6.6	1.506
-12	-6.4	1.431
-12	-6.2	1.359
-12	-6	1.29
-12	-5.8	1.224
-12	-5.6	1.161
-12	-5.4	1.102
-12	-5.2	1.046
-12	-5	0.993
-12	-4.8	0.945
-12	-4.6	0.901
-12	-4.4	0.861
-12	-4.2	0.825
-12	-4	0.795
-12	-3.8	0.771
-12	-3.6	0.753
-12	-3.4	0.741
-12	-3.2	0.736
-12	-3	0.736
-12	-2.8	0.738
-12	-2.6	0.735
-12	-2.4	0.715
-12	-2.2	0.666
-12	-2	0.58
-12	-1.8	0.468
-12	-1.6	0.351
-12	-1.4	0.25
-12	-1.2	0.172
-12	-1	0.117
-12	-0.8	0.08
-12	-0.6	0.055
-12	-0.4	0.04
-12	-0.2	0.031
-12	0	0.027
-12	0.2	0.031
-12	0.4	0.04
-12	0.6	0.055
-12	0.8	0.08
-12	1	0.117
-12	1.2	0.172
-12	1.4	0.25
-12	1.6	0.351
-12	1.8	0.468
-12	2	0.58
-12	2.2	0.666
-12	2.4	0.715
-12	2.6	0.735
-12	2.8	0.738
-12	3	0.736
-12	3.2	0.736
-12	3.4	0.741
-12	3.6	0.753
-12	3.8	0.771
-12	4	0.795
-12	4.2	0.825
-12	4.4	0.861
-12	4.6	0.901
-12	4.8	0.945
-12	5	0.993
-12	5.2	1.046
-12	5.4	1.102
-12	5.6	1.161
-12	5.8	1.224
-12	6	1.29
-12	6.2	1.359
-12	6.4	1.431
-12	6.6	1.506
-12	6.8	1.584
-12	7	1.665
-12	7.2	1.748
-12	7.4	1.835
-12	7.6	1.924
-12	7.8	2.016
-12	8	2.111
-12	8.2	2.208
-12	8.4	2.308
-12	8.6	2.411
-12	8.8	2.516
-12	9	2.624
-12	9.2	2.735
-12	9.4	2.848
-12	9.6	2.964
-12	9.8	3.082
-
-13	-10	3.232
-13	-9.8	3.113
-13	-9.6	2.996
-13	-9.4	2.882
-13	-9.2	2.771
-13	-9	2.663
-13	-8.8	2.557
-13	-8.6	2.454
-13	-8.4	2.355
-13	-8.2	2.258
-13	-8	2.164
-13	-7.8	2.073
-13	-7.6	1.986
-13	-7.4	1.901
-13	-7.2	1.82
-13	-7	1.743
-13	-6.8	1.669
-13	-6.6	1.599
-13	-6.4	1.533
-13	-6.2	1.471
-13	-6	1.414
-13	-5.8	1.361
-13	-5.6	1.315
-13	-5.4	1.275
-13	-5.2	1.242
-13	-5	1.216
-13	-4.8	1.2
-13	-4.6	1.195
-13	-4.4	1.201
-13	-4.2	1.22
-13	-4	1.25
-13	-3.8	1.288
-13	-3.6	1.321
-13	-3.4	1.328
-13	-3.2	1.28
-13	-3	1.158
-13	-2.8	0.973
-13	-2.6	0.763
-13	-2.4	0.569
-13	-2.2	0.41
-13	-2	0.291
-13	-1.8	0.204
-13	-1.6	0.143
-13	-1.4	0.1
-13	-1.2	0.07
-13	-1	0.05
-13	-0.8	0.035
-13	-0.6	0.026
-13	-0.4	0.02
-13	-0.2	0.016
-13	0	0.014
-13	0.2	0.016
-13	0.4	0.02
-13	0.6	0.026
-13	0.8	0.035
-13	1	0.05
-13	1.2	0.07
-13	1.4	0.1
-13	1.6	0.143
-13	1.8	0.204
-13	2	0.291
-13	2.2	0.41
-13	2.4	0.569
-13	2.6	0.763
-13	2.8	0.973
-13	3	1.158
-13	3.2	1.28
-13	3.4	1.328
-13	3.6	1.321
-13	3.8	1.288
-13	4	1.25
-13	4.2	1.22
-13	4.4	1.201
-13	4.6	1.195
-13	4.8	1.2
-13	5	1.216
-13	5.2	1.242
-13	5.4	1.275
-13	5.6	1.315
-13	5.8	1.361
-13	6	1.414
-13	6.2	1.471
-13	6.4	1.533
-13	6.6	1.599
-13	6.8	1.669
-13	7	1.743
-13	7.2	1.82
-13	7.4	1.901
-13	7.6	1.986
-13	7.8	2.073
-13	8	2.164
-13	8.2	2.258
-13	8.4	2.355
-13	8.6	2.454
-13	8.8	2.557
-13	9	2.663
-13	9.2	2.771
-13	9.4	2.882
-13	9.6	2.996
-13	9.8	3.113
-
-14	-10	3.279
-14	-9.8	3.163
-14	-9.6	3.05
-14	-9.4	2.94
-14	-9.2	2.833
-14	-9	2.73
-14	-8.8	2.63
-14	-8.6	2.533
-14	-8.4	2.44
-14	-8.2	2.351
-14	-8	2.265
-14	-7.8	2.184
-14	-7.6	2.108
-14	-7.4	2.036
-14	-7.2	1.97
-14	-7	1.91
-14	-6.8	1.857
-14	-6.6	1.811
-14	-6.4	1.773
-14	-6.2	1.746
-14	-6	1.731
-14	-5.8	1.73
-14	-5.6	1.745
-14	-5.4	1.779
-14	-5.2	1.835
-14	-5	1.912
-14	-4.8	2.005
-14	-4.6	2.097
-14	-4.4	2.152
-14	-4.2	2.122
-14	-4	1.968
-14	-3.8	1.699
-14	-3.6	1.372
-14	-3.4	1.055
-14	-3.2	0.788
-14	-3	0.58
-14	-2.8	0.425
-14	-2.6	0.311
-14	-2.4	0.228
-14	-2.2	0.168
-14	-2	0.124
-14	-1.8	0.091
-14	-1.6	0.067
-14	-1.4	0.049
-14	-1.2	0.036
-14	-1	0.027
-14	-0.8	0.02
-14	-0.6	0.015
-14	-0.4	0.012
-14	-0.2	0.01
-14	0	0.009
-14	0.2	0.01
-14	0.4	0.012
-14	0.6	0.015
-14	0.8	0.02
-14	1	0.027
-14	1.2	0.036
-14	1.4	0.049
-14	1.6	0.067
-14	1.8	0.091
-14	2	0.124
-14	2.2	0.168
-14	2.4	0.228
-14	2.6	0.311
-14	2.8	0.425
-14	3	0.58
-14	3.2	0.788
-14	3.4	1.055
-14	3.6	1.372
-14	3.8	1.699
-14	4	1.968
-14	4.2	2.122
-14	4.4	2.152
-14	4.6	2.097
-14	4.8	2.005
-14	5	1.912
-14	5.2	1.835
-14	5.4	1.779
-14	5.6	1.745
-14	5.8	1.73
-14	6	1.731
-14	6.2	1.746
-14	6.4	1.773
-14	6.6	1.811
-14	6.8	1.857
-14	7	1.91
-14	7.2	1.97
-14	7.4	2.036
-14	7.6	2.108
-14	7.8	2.184
-14	8	2.265
-14	8.2	2.351
-14	8.4	2.44
-14	8.6	2.533
-14	8.8	2.63
-14	9	2.73
-14	9.2	2.833
-14	9.4	2.94
-14	9.6	3.05
-14	9.8	3.163

From 91bfe0f094f6634fb20eaf5d5a909ff810b18316 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 20 Apr 2016 17:42:22 +0200
Subject: [PATCH 032/169] add the data directory to the .gitignore

---
 .gitignore | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/.gitignore b/.gitignore
index a78571ac301a..58582eb41cd6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,4 +62,5 @@ target/
 # Generated data
 *.csv
 *.data
-*.hdf5
\ No newline at end of file
+*.hdf5
+docs/examples/data/*

From a40c25191f36e2254628faf88bf9ec6382bc277b Mon Sep 17 00:00:00 2001
From: Alan Geller 
Date: Wed, 20 Apr 2016 13:59:28 -0700
Subject: [PATCH 033/169] Updated license file

Standard MIT license
---
 LICENSE.md  | 9 +++++++++
 LICENSE.txt | 8 --------
 2 files changed, 9 insertions(+), 8 deletions(-)
 create mode 100644 LICENSE.md
 delete mode 100644 LICENSE.txt

diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 000000000000..97a517759723
--- /dev/null
+++ b/LICENSE.md
@@ -0,0 +1,9 @@
+QCoDeS is available under the [MIT open-source license](https://opensource.org/licenses/MIT):
+
+Copyright (c) 2015, 2016 by Microsoft Corporation and Københavns Universitet.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/LICENSE.txt b/LICENSE.txt
deleted file mode 100644
index ad51df55917f..000000000000
--- a/LICENSE.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-Copyright (c) 2015-16 Alex Johnson
-
-Qcodes is currently a private development of Microsoft's Station Q
-collaboration, and IS NOT licensed for distribution outside the collaboration.
-We intend to release it as open source software once it is robust and reasonably
-stable under the [MIT license](https://en.wikipedia.org/wiki/MIT_License) or similar,
-so that Qcodes may be used freely and incorporated into other packages, even if they
-are closed source.

From 077efbb7446f53e7bd8b9e31a13ecd370279ec02 Mon Sep 17 00:00:00 2001
From: Alan Geller 
Date: Wed, 20 Apr 2016 14:01:13 -0700
Subject: [PATCH 034/169] Updated README to reflect new license terms

---
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 33d6c607c02b..e1d9650bf076 100644
--- a/README.md
+++ b/README.md
@@ -63,4 +63,4 @@ See the [Roadmap](ROADMAP.md) an overview of where the project intends to go.
 
 ## License
 
-Qcodes is currently a private development of Microsoft's Station Q collaboration, and IS NOT licensed for distribution outside the collaboration. We intend to release it as open source software once it is robust and reasonably stable, under the MIT license or similar. See [License](LICENSE.txt)
+Qcodes is currently a private development of Microsoft's Station Q collaboration, and IS NOT licensed for distribution outside the collaboration except by arrangement. We intend to release it as open source software once it is robust and reasonably stable, under the MIT license. See [License](LICENSE.md).

From b5f993778e38b381347aa3cfeec5ffafd4dd6209 Mon Sep 17 00:00:00 2001
From: Alan Geller 
Date: Wed, 20 Apr 2016 14:11:11 -0700
Subject: [PATCH 035/169] Clarified license terms

---
 LICENSE.md | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/LICENSE.md b/LICENSE.md
index 97a517759723..cf93541ce807 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,9 +1,21 @@
-QCoDeS is available under the [MIT open-source license](https://opensource.org/licenses/MIT):
-
 Copyright (c) 2015, 2016 by Microsoft Corporation and Københavns Universitet.
 
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+QCoDeS is currently available only within the Microsoft Station Q collaboration or by specific arrangement.
+We intend to release it as open source software once it is robust and reasonably stable, under the following license terms:
 
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+> QCoDeS is available under the [MIT open-source license](https://opensource.org/licenses/MIT):
+> 
+> Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+> and associated documentation files (the "Software"), to deal in the Software without restriction, 
+> including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, 
+> and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, 
+> subject to the following conditions:
+   
+> The above copyright notice and this permission notice shall be included in all copies or 
+> substantial portions of the Software.
+   
+> SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
+> LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+> IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
+> WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 
+> SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

From 41589f1f1d07d5487088b3c0928e81bfc11ff448 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Thu, 21 Apr 2016 13:07:55 +0200
Subject: [PATCH 036/169] add **kwargs to Keithley driver constructor

---
 qcodes/instrument_drivers/tektronix/Keithley_2700.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
index 39e11a2b8a04..ea48c509fe51 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2700.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -77,9 +77,9 @@ class Keithley_2700(VisaInstrument):
     This driver does not contain all commands available, but only the ones
     most commonly used.
     '''
-    def __init__(self, name, address, reset=False):
+    def __init__(self, name, address, reset=False, **kwargs):
         t0 = time.time()
-        super().__init__(name, address)
+        super().__init__(name, address, **kwargs)
 
         self.add_parameter('IDN', get_cmd='*IDN?')
 

From 93f26a0f5d1f6b17148882e9bd9c7a8d7dc59441 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Thu, 21 Apr 2016 15:43:32 +0200
Subject: [PATCH 037/169] Added Ithaco driver

---
 .../examples/Qcodes example with Ithaco.ipynb | 598 ++++++++++++++++++
 .../agilent/Agilent_34400A.py                 |   6 +-
 .../instrument_drivers/ithaco/Ithaco_1211.py  | 115 ++++
 3 files changed, 717 insertions(+), 2 deletions(-)
 create mode 100644 docs/examples/Qcodes example with Ithaco.ipynb
 create mode 100644 qcodes/instrument_drivers/ithaco/Ithaco_1211.py

diff --git a/docs/examples/Qcodes example with Ithaco.ipynb b/docs/examples/Qcodes example with Ithaco.ipynb
new file mode 100644
index 000000000000..36302f46a45e
--- /dev/null
+++ b/docs/examples/Qcodes example with Ithaco.ipynb	
@@ -0,0 +1,598 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\r\n",
+       " * Qcodes Jupyter/IPython widgets\r\n",
+       " */\r\n",
+       "require([\r\n",
+       "    'nbextensions/widgets/widgets/js/widget',\r\n",
+       "    'nbextensions/widgets/widgets/js/manager'\r\n",
+       "], function (widget, manager) {\r\n",
+       "\r\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            window.MYWIDGET = this;\r\n",
+       "            this._interval = 0;\r\n",
+       "            this.update();\r\n",
+       "        },\r\n",
+       "        update: function() {\r\n",
+       "            this.display(this.model.get('_message'));\r\n",
+       "            this.setInterval();\r\n",
+       "        },\r\n",
+       "        display: function(message) {\r\n",
+       "            /*\r\n",
+       "             * display method: override this for custom display logic\r\n",
+       "             */\r\n",
+       "            this.el.innerHTML = message;\r\n",
+       "        },\r\n",
+       "        remove: function() {\r\n",
+       "            clearInterval(this._updater);\r\n",
+       "        },\r\n",
+       "        setInterval: function(newInterval) {\r\n",
+       "            var me = this;\r\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\r\n",
+       "            if(newInterval===me._interval) return;\r\n",
+       "\r\n",
+       "            me._interval = newInterval;\r\n",
+       "\r\n",
+       "            if(me._updater) clearInterval(me._updater);\r\n",
+       "\r\n",
+       "            if(me._interval) {\r\n",
+       "                me._updater = setInterval(function() {\r\n",
+       "                    me.send({myupdate: true});\r\n",
+       "                    if(!me.model.comm_live) {\r\n",
+       "                        console.log('missing comm, canceling widget updates', me);\r\n",
+       "                        clearInterval(me._updater);\r\n",
+       "                    }\r\n",
+       "                }, me._interval * 1000);\r\n",
+       "            }\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\r\n",
+       "\r\n",
+       "    var HiddenUpdateView = UpdateView.extend({\r\n",
+       "        display: function(message) {\r\n",
+       "            this.$el.hide();\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\r\n",
+       "\r\n",
+       "    var SubprocessView = UpdateView.extend({\r\n",
+       "        render: function() {\r\n",
+       "            var me = window.SPVIEW = this;\r\n",
+       "            me._interval = 0;\r\n",
+       "            me._minimize = '';\r\n",
+       "            me._restore = '';\r\n",
+       "\r\n",
+       "            // in case there is already an outputView present,\r\n",
+       "            // like from before restarting the kernel\r\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\r\n",
+       "\r\n",
+       "            me.$el\r\n",
+       "                .addClass('qcodes-output-view')\r\n",
+       "                .attr('qcodes-state', 'docked')\r\n",
+       "                .html(\r\n",
+       "                    '
' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '' +\r\n", + " '
' +\r\n", + " '
'\r\n",
+       "                );\r\n",
+       "\r\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\r\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\r\n",
+       "            me.outputArea = me.$el.find('pre');\r\n",
+       "            me.subprocessList = me.$el.find('span');\r\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\r\n",
+       "\r\n",
+       "            me.clearButton.click(function() {\r\n",
+       "                me.outputArea.html('');\r\n",
+       "                me.clearButton.addClass('disabled');\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.abortButton.click(function() {\r\n",
+       "                me.send({abort: true});\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.$el.find('.js-state').click(function() {\r\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\r\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\r\n",
+       "                        .split('-')[1].split(' ')[0];\r\n",
+       "\r\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\r\n",
+       "                // some other bit of code resets the parent after render if I do it there.\r\n",
+       "                // To be safe, just do it on every state click.\r\n",
+       "                me.$el.appendTo('body');\r\n",
+       "\r\n",
+       "                if(oldState === 'floated') {\r\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                me.$el.attr('qcodes-state', state);\r\n",
+       "\r\n",
+       "                if(state === 'floated') {\r\n",
+       "                    me.$el.draggable().css({\r\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\r\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\r\n",
+       "                    });\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            $(window).resize(function() {\r\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\r\n",
+       "                    var position = me.$el.position(),\r\n",
+       "                        minVis = 20,\r\n",
+       "                        maxLeft = window.innerWidth - minVis,\r\n",
+       "                        maxTop = window.innerHeight - minVis;\r\n",
+       "\r\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\r\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\r\n",
+       "                }\r\n",
+       "            });\r\n",
+       "\r\n",
+       "            me.update();\r\n",
+       "        },\r\n",
+       "\r\n",
+       "        display: function(message) {\r\n",
+       "            if(message) {\r\n",
+       "                var initialScroll = this.outputArea.scrollTop();\r\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\r\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\r\n",
+       "\r\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\r\n",
+       "                    this.$el.find('.qcodes-docked').click();\r\n",
+       "                    // always scroll to the bottom if we're restoring\r\n",
+       "                    // because of a new message\r\n",
+       "                    initialScroll = scrollBottom;\r\n",
+       "                }\r\n",
+       "\r\n",
+       "                this.outputArea.append(message);\r\n",
+       "                this.clearButton.removeClass('disabled');\r\n",
+       "\r\n",
+       "                // if we were scrolled to the bottom initially, make sure\r\n",
+       "                // we stay that way.\r\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\r\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\r\n",
+       "            }\r\n",
+       "\r\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\r\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\r\n",
+       "            this.subprocessList.text(processes);\r\n",
+       "        }\r\n",
+       "    });\r\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\r\n",
+       "});\r\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "%matplotlib nbagg\n",
+    "import matplotlib.pyplot as plt\n",
+    "import time\n",
+    "import numpy as np\n",
+    "\n",
+    "import qcodes as qc\n",
+    "from qcodes.utils.validators import Enum, Strings\n",
+    "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith\n",
+    "import qcodes.instrument_drivers.agilent.Agilent_34400A as agi\n",
+    "import qcodes.instrument_drivers.ithaco.Ithaco_1211 as ithaco\n",
+    "\n",
+    "from qcodes.instrument.parameter import Parameter, StandardParameter\n",
+    "\n",
+    "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
+    "\n",
+    "# this makes a widget in the corner of the window to show and control\n",
+    "# subprocesses and any output they would print to the terminal\n",
+    "qc.show_subprocess_widget()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "import time\n",
+    "class Timer(object):\n",
+    "    def __init__(self, name=None):\n",
+    "        self.name = name\n",
+    "\n",
+    "    def __enter__(self):\n",
+    "        self.tstart = time.time()\n",
+    "\n",
+    "    def __exit__(self, type, value, traceback):\n",
+    "        if self.name:\n",
+    "            print('[%s]' % self.name,)\n",
+    "        print('Elapsed: %s' % (time.time() - self.tstart))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# create Instruments\n",
+    "k1 = keith.Keithley_2600('Keithley1', 'GPIB0::15::INSTR',channel='a')\n",
+    "k2 = keith.Keithley_2600('Keithley2', 'GPIB0::15::INSTR',channel='b')\n",
+    "\n",
+    "a1 = agi.Agilent_34400A('Agilent1', 'GPIB0::11::INSTR')\n",
+    "a2 = agi.Agilent_34400A('Agilent2', 'GPIB0::6::INSTR')\n",
+    "\n",
+    "camp = ithaco.Ithaco_1211('camp1')\n",
+    "camp.sens.set(1e-4)\n",
+    "\n",
+    "curr = ithaco.CurrentParameter(a2.volt, camp)\n",
+    "\n",
+    "# set integration time (number of line cycles)\n",
+    "a1.NPLC.set(1)\n",
+    "a2.NPLC.set(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'functions': {},\n",
+       " 'metadata': {'info': {'model': '1211',\n",
+       "   'serial_number': None,\n",
+       "   'software_revision': None,\n",
+       "   'vendor': 'Ithaco (DL Instruments)'}},\n",
+       " 'parameters': {'invert': {'ts': '2016-04-21 12:48:41', 'value': True},\n",
+       "  'risetime': {'ts': '2016-04-21 12:48:41', 'value': 0.3},\n",
+       "  'sens': {'ts': '2016-04-21 12:48:41', 'value': 0.0001},\n",
+       "  'sens_x': {'ts': '2016-04-21 12:48:41', 'value': 1},\n",
+       "  'suppression': {'ts': '2016-04-21 12:48:41', 'value': 1e-07}}}"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "camp.snapshot()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "''"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a2.volt.units"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "('', 'A')"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "curr.units"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 15,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt: volt\n",
+      "   volt_set: volt\n",
+      "   current: current\n",
+      "started at 2016-04-21 12:59:30\n"
+     ]
+    }
+   ],
+   "source": [
+    "data = qc.Loop(k1.volt[-5:5:1], 0).each(curr).run(location='testsweep', overwrite=True)\n",
+    "plotQ = qc.QtPlot(data.current,windowTitle='YEAH')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 16,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       ""
+      ]
+     },
+     "execution_count": 16,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "plotQ"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 18,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'CamP': DataArray[10]: CamP\n",
+       " array([ -5.00525151e-04,  -4.00422238e-04,  -3.00307785e-04,\n",
+       "         -2.00213046e-04,  -1.00101573e-04,   2.36665412e-08,\n",
+       "          1.00138489e-04,   2.00251222e-04,   3.00358976e-04,\n",
+       "          4.00463605e-04]), 'volt': DataArray[10]: volt\n",
+       " array([  5.00525151e+00,   4.00422238e+00,   3.00307785e+00,\n",
+       "          2.00213046e+00,   1.00101573e+00,  -2.36665412e-04,\n",
+       "         -1.00138489e+00,  -2.00251222e+00,  -3.00358976e+00,\n",
+       "         -4.00463605e+00]), 'volt_set': DataArray[10]: volt_set\n",
+       " array([-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.])}"
+      ]
+     },
+     "execution_count": 18,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "data.sync()\n",
+    "data.arrays"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "station1 = qc.Station(a1,a2)\n",
+    "station1.set_measurement(a1.volt)\n",
+    "station2 = qc.Station(a1,a2)\n",
+    "station2.set_measurement(a1.volt, a2.volt)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time s1'):\n",
+    "    station1.measure()\n",
+    "with Timer('Time s2'):\n",
+    "    station2.measure()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "# Time single readings\n",
+    "with Timer('Time a1'):\n",
+    "    a1.volt.get()\n",
+    "with Timer('Time a2'):\n",
+    "    a2.volt.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True,background=False)\n",
+    "\n",
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True,background=False)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [],
+   "source": [
+    "with Timer('Time Loop 1'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "with Timer('Time Loop 2'):\n",
+    "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True)\n",
+    "    while data.sync():\n",
+    "        time.sleep(0.1)"
+   ]
+  },
+  {
+   "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.5.1"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
index d458b4abd0cf..2bfa2d6850ea 100644
--- a/qcodes/instrument_drivers/agilent/Agilent_34400A.py
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -54,11 +54,13 @@ def __init__(self, name, address, **kwargs):
         self.add_parameter('volt',
                            get_cmd='READ?',
                            label='Voltage',
-                           get_parser=float)
+                           get_parser=float,
+                           units='V')
         self.add_parameter('volt_fetch',
                            get_cmd='FETCH?',
                            label='Voltage',
-                           get_parser=float)
+                           get_parser=float
+                           units='V')
         self.add_parameter('NPLC',
                            get_cmd='VOLT:NPLC?',
                            get_parser=float,
diff --git a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
new file mode 100644
index 000000000000..317621761b5a
--- /dev/null
+++ b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
@@ -0,0 +1,115 @@
+# Ithaco_1211.py driver for Ithaco 1211 Current-preamplifier
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from qcodes import Instrument
+from qcodes.instrument.parameter import ManualParameter
+from qcodes.utils.validators import Enum, Bool
+
+from qcodes.instrument.parameter import Parameter
+
+
+class CurrentParameter(Parameter):
+    def __init__(self, measured_param, camp_ins):
+        p_name = measured_param.name
+        super().__init__(names=(p_name, 'current'))
+        _p_label = None
+        _p_unit = None
+
+        self.measured_param = measured_param
+        self.camp = camp_ins
+
+        if hasattr(measured_param, 'label'):
+            _p_label = measured_param.label
+        if hasattr(measured_param, 'units'):
+            _p_unit = measured_param.units
+
+        self.labels = (_p_label, 'Current')
+        self.units = (_p_unit, 'A')
+
+    def get(self):
+        volt = self.measured_param.get()
+        current = (self.camp.sens.get() *
+                   self.camp.sens_x.get()) * volt
+
+        if self.camp.invert.get():
+            current *= -1
+        return (volt, current)
+
+
+class Ithaco_1211(Instrument):
+    '''
+    dmm_parameter: The parameter used to measure the voltage output
+
+    This is the qcodes driver for the Ithaco 1211 Current-preamplifier,
+    This is a virtual driver only and will not talk to your instrument.
+    '''
+    def __init__(self, name, dmm_parameter=None, **kwargs):
+        super().__init__(name, **kwargs)
+        self.dmm_parameter = dmm_parameter
+
+        vendor = 'Ithaco (DL Instruments)'
+        model = '1211'
+        serial = None
+        software = None
+
+        self.info = {'vendor': vendor, 'model': model,
+                     'serial_number': serial, 'software_revision': software}
+
+        self.metadata['info'] = self.info
+
+        self.add_parameter('sens',
+                           parameter_class=ManualParameter,
+                           initial_value=1e-8,
+                           label='Sensitivity',
+                           units='A/V',
+                           vals=Enum(1e-11, 1e-10, 1e-09, 1e-08, 1e-07,
+                                     1e-06, 1e-05, 1e-4, 1e-3))
+
+        self.add_parameter('invert',
+                           parameter_class=ManualParameter,
+                           initial_value=True,
+                           label='Iverted output',
+                           vals=Bool())
+
+        self.add_parameter('sens_x',
+                           parameter_class=ManualParameter,
+                           initial_value=1,
+                           label='sensitivity x',
+                           units=None,
+                           vals=Enum(0.1, 1, 10))
+
+        self.add_parameter('suppression',
+                           parameter_class=ManualParameter,
+                           initial_value=1e-7,
+                           label='Suppression',
+                           units='A',
+                           vals=Enum(1e-10, 1e-09, 1e-08, 1e-07, 1e-06,
+                                     1e-05, 1e-4, 1e-3))
+
+        self.add_parameter('risetime',
+                           parameter_class=ManualParameter,
+                           initial_value=0.3,
+                           label='Rise Time',
+                           units='msec',
+                           vals=Enum(0.01, 0.03, 0.1, 0.3, 1, 3, 10, 30,
+                                     100, 300, 1000))

From 18b04d09f113606818c37d2bc9db51c8be7b46ef Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Thu, 21 Apr 2016 15:47:36 +0200
Subject: [PATCH 038/169] fixed typos

---
 qcodes/instrument_drivers/agilent/Agilent_34400A.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
index 2bfa2d6850ea..2ac5de0a9e2c 100644
--- a/qcodes/instrument_drivers/agilent/Agilent_34400A.py
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -59,7 +59,7 @@ def __init__(self, name, address, **kwargs):
         self.add_parameter('volt_fetch',
                            get_cmd='FETCH?',
                            label='Voltage',
-                           get_parser=float
+                           get_parser=float,
                            units='V')
         self.add_parameter('NPLC',
                            get_cmd='VOLT:NPLC?',
@@ -81,7 +81,7 @@ def __init__(self, name, address, **kwargs):
                            get_parser=float,
                            set_cmd='VOLT:DC:RES {:.7f}',
                            vals=Enum(3e-07, 1e-06, 3e-06, 1e-05, 1e-04),
-                           unit='V')
+                           units='V')
         # Integration Time    Resolutionc
         self.add_parameter('integration_time',
                            get_cmd='VOLT:DC:RES?',

From 86ce5f2b5aeee7e4da102ced11017514fd2cb70a Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Fri, 22 Apr 2016 10:52:44 +0200
Subject: [PATCH 039/169] update

---
 .../examples/Qcodes example with Ithaco.ipynb | 134 +++++++++++++-----
 1 file changed, 101 insertions(+), 33 deletions(-)

diff --git a/docs/examples/Qcodes example with Ithaco.ipynb b/docs/examples/Qcodes example with Ithaco.ipynb
index 36302f46a45e..59c370425723 100644
--- a/docs/examples/Qcodes example with Ithaco.ipynb	
+++ b/docs/examples/Qcodes example with Ithaco.ipynb	
@@ -246,7 +246,8 @@
     }
    ],
    "source": [
-    "%matplotlib nbagg\n",
+    "# %matplotlib nbagg\n",
+    "%gui qt \n",
     "import matplotlib.pyplot as plt\n",
     "import time\n",
     "import numpy as np\n",
@@ -328,11 +329,11 @@
        "   'serial_number': None,\n",
        "   'software_revision': None,\n",
        "   'vendor': 'Ithaco (DL Instruments)'}},\n",
-       " 'parameters': {'invert': {'ts': '2016-04-21 12:48:41', 'value': True},\n",
-       "  'risetime': {'ts': '2016-04-21 12:48:41', 'value': 0.3},\n",
-       "  'sens': {'ts': '2016-04-21 12:48:41', 'value': 0.0001},\n",
-       "  'sens_x': {'ts': '2016-04-21 12:48:41', 'value': 1},\n",
-       "  'suppression': {'ts': '2016-04-21 12:48:41', 'value': 1e-07}}}"
+       " 'parameters': {'invert': {'ts': '2016-04-21 15:56:06', 'value': True},\n",
+       "  'risetime': {'ts': '2016-04-21 15:56:06', 'value': 0.3},\n",
+       "  'sens': {'ts': '2016-04-21 15:56:06', 'value': 0.0001},\n",
+       "  'sens_x': {'ts': '2016-04-21 15:56:06', 'value': 1},\n",
+       "  'suppression': {'ts': '2016-04-21 15:56:06', 'value': 1e-07}}}"
       ]
      },
      "execution_count": 4,
@@ -354,7 +355,7 @@
     {
      "data": {
       "text/plain": [
-       "''"
+       "'V'"
       ]
      },
      "execution_count": 5,
@@ -376,7 +377,7 @@
     {
      "data": {
       "text/plain": [
-       "('', 'A')"
+       "('V', 'A')"
       ]
      },
      "execution_count": 6,
@@ -399,7 +400,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 15,
+   "execution_count": 7,
    "metadata": {
     "collapsed": false
    },
@@ -409,10 +410,10 @@
      "output_type": "stream",
      "text": [
       "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   current: current\n",
       "   volt: volt\n",
       "   volt_set: volt\n",
-      "   current: current\n",
-      "started at 2016-04-21 12:59:30\n"
+      "started at 2016-04-21 15:56:10\n"
      ]
     }
    ],
@@ -445,7 +446,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 18,
+   "execution_count": 9,
    "metadata": {
     "collapsed": false
    },
@@ -453,19 +454,17 @@
     {
      "data": {
       "text/plain": [
-       "{'CamP': DataArray[10]: CamP\n",
-       " array([ -5.00525151e-04,  -4.00422238e-04,  -3.00307785e-04,\n",
-       "         -2.00213046e-04,  -1.00101573e-04,   2.36665412e-08,\n",
-       "          1.00138489e-04,   2.00251222e-04,   3.00358976e-04,\n",
-       "          4.00463605e-04]), 'volt': DataArray[10]: volt\n",
-       " array([  5.00525151e+00,   4.00422238e+00,   3.00307785e+00,\n",
-       "          2.00213046e+00,   1.00101573e+00,  -2.36665412e-04,\n",
-       "         -1.00138489e+00,  -2.00251222e+00,  -3.00358976e+00,\n",
-       "         -4.00463605e+00]), 'volt_set': DataArray[10]: volt_set\n",
+       "{'current': DataArray[10]: current\n",
+       " array([ -4.98941000e-04,  -3.99618000e-04,  -3.00370000e-04,\n",
+       "         -2.01084000e-04,  -1.01763000e-04,  -2.42637000e-06,\n",
+       "          9.69014000e-05,   1.96216000e-04,   2.95535000e-04,\n",
+       "          3.94851000e-04]), 'volt': DataArray[10]: volt\n",
+       " array([ 4.98941  ,  3.99618  ,  3.0037   ,  2.01084  ,  1.01763  ,\n",
+       "         0.0242637, -0.969014 , -1.96216  , -2.95535  , -3.94851  ]), 'volt_set': DataArray[10]: volt_set\n",
        " array([-5., -4., -3., -2., -1.,  0.,  1.,  2.,  3.,  4.])}"
       ]
      },
-     "execution_count": 18,
+     "execution_count": 9,
      "metadata": {},
      "output_type": "execute_result"
     }
@@ -477,7 +476,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 10,
    "metadata": {
     "collapsed": true
    },
@@ -491,11 +490,22 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 11,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time s1]\n",
+      "Elapsed: 0.05600309371948242\n",
+      "[Time s2]\n",
+      "Elapsed: 0.10500597953796387\n"
+     ]
+    }
+   ],
    "source": [
     "# Time single readings\n",
     "with Timer('Time s1'):\n",
@@ -506,11 +516,22 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 12,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "[Time a1]\n",
+      "Elapsed: 0.05600309371948242\n",
+      "[Time a2]\n",
+      "Elapsed: 0.049002885818481445\n"
+     ]
+    }
+   ],
    "source": [
     "# Time single readings\n",
     "with Timer('Time a1'):\n",
@@ -521,12 +542,32 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 13,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt: volt\n",
+      "started at 2016-04-21 15:51:15\n",
+      "[Time Loop 1]\n",
+      "Elapsed: 0.5770328044891357\n",
+      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt_0: volt\n",
+      "   volt_1: volt\n",
+      "started at 2016-04-21 15:51:16\n",
+      "[Time Loop 2]\n",
+      "Elapsed: 1.0900623798370361\n"
+     ]
+    }
+   ],
    "source": [
     "with Timer('Time Loop 1'):\n",
     "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True,background=False)\n",
@@ -537,12 +578,25 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 14,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt: volt\n",
+      "started at 2016-04-21 15:51:16\n",
+      "[Time Loop 1]\n",
+      "Elapsed: 1.075061559677124\n"
+     ]
+    }
+   ],
    "source": [
     "with Timer('Time Loop 1'):\n",
     "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True)\n",
@@ -552,11 +606,25 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 15,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [],
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
+      "   volt_set: volt\n",
+      "   volt_0: volt\n",
+      "   volt_1: volt\n",
+      "started at 2016-04-21 15:51:17\n",
+      "[Time Loop 2]\n",
+      "Elapsed: 1.569089651107788\n"
+     ]
+    }
+   ],
    "source": [
     "with Timer('Time Loop 2'):\n",
     "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True)\n",

From 6367474c1251fbc0c3bdfb93e29393290796f393 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 22 Apr 2016 13:35:18 +0200
Subject: [PATCH 040/169] added waveform setting to AWG driver

---
 .../instrument_drivers/tektronix/AWG5014.py   | 82 +++++++++++++++++--
 1 file changed, 74 insertions(+), 8 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index c34798932290..7fb0dcd3c813 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -23,9 +23,13 @@
 from io import BytesIO
 import os
 import logging
+import array as arr
 
 from qcodes import VisaInstrument, validators as vals
 
+def parsestr(v):
+    return v.strip().strip('"')
+
 
 class Tektronix_AWG5014(VisaInstrument):
     '''
@@ -228,6 +232,7 @@ def __init__(self, name, setup_folder, address, reset=False,
             amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(i)
             offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(i)
             state_cmd = 'OUTPUT{}:STATE'.format(i)
+            waveform_cmd = 'SOUR{}:WAV'.format(i)
             # Set channel first to ensure sensible sorting of pars
             self.add_parameter('ch{}_state'.format(i),
                                label='Status channel {}'.format(i),
@@ -246,6 +251,12 @@ def __init__(self, name, setup_folder, address, reset=False,
                                set_cmd=offset_cmd + ' {:.3f}',
                                vals=vals.Numbers(-.1, .1),
                                get_parser=float)
+            self.add_parameter('ch{}_waveform'.format(i),
+                               label='Waveform channel {}'.format(i),
+                               get_cmd=waveform_cmd+'?',
+                               set_cmd=waveform_cmd+' "{}"',
+                               vals=vals.Strings(),
+                               get_parser=parsestr)
             # Marker channels
             for j in range(1, 3):
                 m_del_cmd = 'SOUR{}:MARK{}:DEL'.format(i, j)
@@ -862,26 +873,27 @@ def send_waveform(self, w, m1, m2, filename, clock=None):
         self._values['files'][filename] = self._file_dict(w, m1, m2, clock)
 
         m = m1 + np.multiply(m2, 2)
-        ws = ''
+        ws = b''
         # this is probalbly verry slow and memmory consuming!
         for i in range(0, len(w)):
             ws = ws + struct.pack('
Date: Fri, 22 Apr 2016 13:46:28 +0200
Subject: [PATCH 041/169] autopep8 AWG driver

---
 .../instrument_drivers/tektronix/AWG5014.py   | 270 ++++++++++--------
 1 file changed, 148 insertions(+), 122 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index 7fb0dcd3c813..1bf922842a83 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -27,6 +27,7 @@
 
 from qcodes import VisaInstrument, validators as vals
 
+
 def parsestr(v):
     return v.strip().strip('"')
 
@@ -89,37 +90,56 @@ class Tektronix_AWG5014(VisaInstrument):
         'INTERLEAVE_ADJ_AMPLITUDE': 'd',
     }
     AWG_FILE_FORMAT_CHANNEL = {
-        'OUTPUT_WAVEFORM_NAME_N': 's',  # Include NULL.(Output Waveform Name for Non-Sequence mode)
+        # Include NULL.(Output Waveform Name for Non-Sequence mode)
+        'OUTPUT_WAVEFORM_NAME_N': 's',
         'CHANNEL_STATE_N': 'h',  # On | Off
         'ANALOG_DIRECT_OUTPUT_N': 'h',  # On | Off
         'ANALOG_FILTER_N': 'h',  # Enum type.
         'ANALOG_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'ANALOG_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'ANALOG_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'ANALOG_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'ANALOG_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'ANALOG_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'ANALOG_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'ANALOG_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'ANALOG_LOW_N': 'd',
         'MARKER1_SKEW_N': 'd',
         'MARKER1_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'MARKER1_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER1_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER1_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'MARKER1_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER1_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER1_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER1_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER1_LOW_N': 'd',
         'MARKER2_SKEW_N': 'd',
         'MARKER2_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'MARKER2_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER2_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'MARKER2_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'MARKER2_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER2_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'MARKER2_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER2_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'MARKER2_LOW_N': 'd',
         'DIGITAL_METHOD_N': 'h',  # Amplitude/Offset, High/Low
-        'DIGITAL_AMPLITUDE_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'DIGITAL_OFFSET_N': 'd',  # When the Input Method is High/Low, it is skipped.
-        'DIGITAL_HIGH_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
-        'DIGITAL_LOW_N': 'd',  # When the Input Method is Amplitude/Offset, it is skipped.
+        # When the Input Method is High/Low, it is skipped.
+        'DIGITAL_AMPLITUDE_N': 'd',
+        # When the Input Method is High/Low, it is skipped.
+        'DIGITAL_OFFSET_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'DIGITAL_HIGH_N': 'd',
+        # When the Input Method is Amplitude/Offset, it is skipped.
+        'DIGITAL_LOW_N': 'd',
         'EXTERNAL_ADD_N': 'h',  # AWG5000 only
         'PHASE_DELAY_INPUT_METHOD_N':   'h',  # Phase/DelayInme/DelayInints
         'PHASE_N': 'd',  # When the Input Method is not Phase, it is skipped.
-        'DELAY_IN_TIME_N': 'd',  # When the Input Method is not DelayInTime, it is skipped.
-        'DELAY_IN_POINTS_N': 'd',  # When the Input Method is not DelayInPoint, it is skipped.
+        # When the Input Method is not DelayInTime, it is skipped.
+        'DELAY_IN_TIME_N': 'd',
+        # When the Input Method is not DelayInPoint, it is skipped.
+        'DELAY_IN_POINTS_N': 'd',
         'CHANNEL_SKEW_N': 'd',
         'DC_OUTPUT_LEVEL_N': 'd',  # V
     }
@@ -168,39 +188,39 @@ def __init__(self, name, setup_folder, address, reset=False,
         self.add_parameter('trigger_impedance',
                            label='Trigger impedance (Ohm)',
                            get_cmd='TRIG:IMP?',
-                           set_cmd='TRIG:IMP '+'{}',
+                           set_cmd='TRIG:IMP ' + '{}',
                            vals=vals.Enum(50, 1000),
                            get_parser=float)
         self.add_parameter('trigger_level',
                            label='Trigger level (V)',
                            get_cmd='TRIG:LEV?',
-                           set_cmd='TRIG:LEV '+'{:.3f}',
+                           set_cmd='TRIG:LEV ' + '{:.3f}',
                            vals=vals.Numbers(-5, 5),
                            get_parser=float)
         self.add_parameter('trigger_slope',
                            get_cmd='TRIG:SLOP?',
-                           set_cmd='TRIG:SLOP '+'{}',
-                           vals=vals.Enum('POS', 'NEG'))#,
-                           # get_parser=self.parse_int_pos_neg)
+                           set_cmd='TRIG:SLOP ' + '{}',
+                           vals=vals.Enum('POS', 'NEG'))  # ,
+        # get_parser=self.parse_int_pos_neg)
         self.add_parameter('trigger_source',
                            get_cmd='TRIG:source?',
-                           set_cmd='TRIG:source '+'{}',
+                           set_cmd='TRIG:source ' + '{}',
                            vals=vals.Enum('INT', 'EXT'))
         # Event parameters #
         self.add_parameter('event_polarity',
                            get_cmd='EVEN:POL?',
-                           set_cmd='EVEN:POL '+'{}',
+                           set_cmd='EVEN:POL ' + '{}',
                            vals=vals.Enum('POS', 'NEG'))
         self.add_parameter('event_impedance',
                            label='Event impedance (Ohm)',
                            get_cmd='EVEN:IMP?',
-                           set_cmd='EVEN:IMP '+'{}',
+                           set_cmd='EVEN:IMP ' + '{}',
                            vals=vals.Enum(50, 1000),
                            get_parser=float)
         self.add_parameter('event_level',
                            label='Event level (V)',
                            get_cmd='EVEN:LEV?',
-                           set_cmd='EVEN:LEV '+'{:.3f}',
+                           set_cmd='EVEN:LEV ' + '{:.3f}',
                            vals=vals.Numbers(-5, 5),
                            get_parser=float)
         self.add_parameter('event_jump_timing',
@@ -211,7 +231,7 @@ def __init__(self, name, setup_folder, address, reset=False,
         self.add_parameter('clock_freq',
                            label='Clock frequency (Hz)',
                            get_cmd='SOUR:FREQ?',
-                           set_cmd='SOUR:FREQ '+'{}',
+                           set_cmd='SOUR:FREQ ' + '{}',
                            vals=vals.Numbers(1e6, 1.2e9),
                            get_parser=float)
 
@@ -222,10 +242,10 @@ def __init__(self, name, setup_folder, address, reset=False,
                            vals=vals.Ints(100, int(1e9)))
         self.add_parameter('setup_filename',
                            get_cmd='AWGC:SNAM?')
-                           # set_cmd=self.do_set_setup_filename,
-                           # vals=vals.Strings())
-                           # set function has optional args and therefore
-                           # does not work with QCodes
+        # set_cmd=self.do_set_setup_filename,
+        # vals=vals.Strings())
+        # set function has optional args and therefore
+        # does not work with QCodes
 
         # Channel parameters #
         for i in range(1, 5):
@@ -236,8 +256,8 @@ def __init__(self, name, setup_folder, address, reset=False,
             # Set channel first to ensure sensible sorting of pars
             self.add_parameter('ch{}_state'.format(i),
                                label='Status channel {}'.format(i),
-                               get_cmd=state_cmd+'?',
-                               set_cmd=state_cmd+' {}',
+                               get_cmd=state_cmd + '?',
+                               set_cmd=state_cmd + ' {}',
                                vals=vals.Ints(0, 1))
             self.add_parameter('ch{}_amp'.format(i),
                                label='Amplitude channel {} (V)'.format(i),
@@ -253,8 +273,8 @@ def __init__(self, name, setup_folder, address, reset=False,
                                get_parser=float)
             self.add_parameter('ch{}_waveform'.format(i),
                                label='Waveform channel {}'.format(i),
-                               get_cmd=waveform_cmd+'?',
-                               set_cmd=waveform_cmd+' "{}"',
+                               get_cmd=waveform_cmd + '?',
+                               set_cmd=waveform_cmd + ' "{}"',
                                vals=vals.Strings(),
                                get_parser=parsestr)
             # Marker channels
@@ -526,8 +546,9 @@ def set_sq_length(self, seq_length):
     def set_sqel_event_jump_target_index(self, element_no, jtar_index_no):
         self.write('SEQ:ELEM%s:JTAR:INDex %s' % (element_no, jtar_index_no))
 
-    def set_sqel_event_jump_type(self, element_no,jtar_state):
-        self.write('SEQuence:ELEMent%s:JTAR:TYPE %s' % (element_no, jtar_state))
+    def set_sqel_event_jump_type(self, element_no, jtar_state):
+        self.write('SEQuence:ELEMent%s:JTAR:TYPE %s' %
+                   (element_no, jtar_state))
 
     def get_sq_mode(self):
         return self.ask('AWGC:SEQ:TYPE?')
@@ -561,33 +582,33 @@ def _load_new_style(self, wfname_l, nrep_l, wait_l, goto_l, logic_jump_l):
         '''
         load sequence not using sequence file
         '''
-        self.set_sq_length(0) # delete prev seq
-        #print wfname_l
+        self.set_sq_length(0)  # delete prev seq
+        # print wfname_l
         len_sq = len(nrep_l)
         self.set_sq_length(len_sq)
         n_ch = len(wfname_l)
         for k in range(len_sq):
-            #wfname_l[k]
-            #print k
+            # wfname_l[k]
+            # print k
             for n in range(n_ch):
-                #print n
-                #print wfname_l[n][k]
+                # print n
+                # print wfname_l[n][k]
                 if wfname_l[n][k] is not None:
 
-                    self.set_sqel_waveform(wfname_l[n][k], n+1, k+1)
-            self.set_sqel_trigger_wait(k+1, int(wait_l[k]!=0))
-            self.set_sqel_loopcnt_to_inf(k+1, False)
-            self.set_sqel_loopcnt(nrep_l[k],k+1)
+                    self.set_sqel_waveform(wfname_l[n][k], n + 1, k + 1)
+            self.set_sqel_trigger_wait(k + 1, int(wait_l[k] != 0))
+            self.set_sqel_loopcnt_to_inf(k + 1, False)
+            self.set_sqel_loopcnt(nrep_l[k], k + 1)
             qt.msleep()
-            if  goto_l[k] == 0:
-                self.set_sqel_goto_state(k+1, False)
+            if goto_l[k] == 0:
+                self.set_sqel_goto_state(k + 1, False)
             else:
-                self.set_sqel_goto_state(k+1, True)
-                self.set_sqel_goto_target_index(k+1, goto_l[k])
+                self.set_sqel_goto_state(k + 1, True)
+                self.set_sqel_goto_target_index(k + 1, goto_l[k])
             if logic_jump_l[k] == -1:
-                self.set_sqel_event_target_index_next(k+1)
+                self.set_sqel_event_target_index_next(k + 1)
             else:
-                self.set_sqel_event_target_index(k+1, logic_jump_l[k])
+                self.set_sqel_event_target_index(k + 1, logic_jump_l[k])
 
     def _load_old_style(self, wfs, rep, wait, goto, logic_jump, filename):
         '''
@@ -629,7 +650,7 @@ def _import_and_load_waveform_file_to_channel(self, channel_no,
         while not (self.visa_handle.ask("sour%s:wav?" % channel_no)
                    == '"%s"' % waveform_listname):
             sleep(0.01)
-            i = i+1
+            i = i + 1
         return
     ######################
     # AWG file functions #
@@ -652,15 +673,15 @@ def _pack_record(self, name, value, dtype):
            characters denoted in the documentation of the struct package
         '''
         if len(dtype) == 1:
-            record_data = struct.pack('<'+dtype, value)
+            record_data = struct.pack('<' + dtype, value)
         else:
             if dtype[-1] == 's':
                 record_data = value.encode('ASCII')
             else:
-                record_data = struct.pack('<'+dtype, *value)
+                record_data = struct.pack('<' + dtype, *value)
 
         # the zero byte at the end the record name is the "(Include NULL.)"
-        record_name = name.encode('ASCII')+b'\x00'
+        record_name = name.encode('ASCII') + b'\x00'
         record_name_size = len(record_name)
         record_data_size = len(record_data)
         size_struct = struct.pack(' 0:
             print(np.where(packed_wf == -1))
         return packed_wf
@@ -892,7 +914,7 @@ def send_waveform(self, w, m1, m2, filename, clock=None):
         s2 = '#' + lenlen + str(len(s6) + len(s5) + len(s4) + len(s3))
         s2 = s2.encode('UTF-8')
         mes = s1 + s2 + s3 + s4 + s5 + s6
-        
+
         self.visa_handle.write_raw(mes)
 
     def _file_dict(self, w, m1, m2, clock):
@@ -960,7 +982,7 @@ def set_filename(self, name, channel):
         # logging.debug(__name__  + ' : Try to set %s on channel %s' %(name, channel))
         exists = False
         if name in self._values['files']:
-            exists= True
+            exists = True
             # logging.debug(__name__  + ' : File exists in local memory')
             self._values['recent_channel_%s' % channel] = \
                 self._values['files'][name]
@@ -970,44 +992,46 @@ def set_filename(self, name, channel):
             # reading from instrument')
             lijst = self.visa_handle.ask('MMEM:CAT? "MAIN"')
             bool = False
-            bestand=""
+            bestand = ""
             for i in range(len(lijst)):
-                if (lijst[i]=='"'):
-                    bool=True
-                elif (lijst[i]==','):
-                    bool=False
-                    if (bestand==name): exists=True
-                    bestand=""
+                if (lijst[i] == '"'):
+                    bool = True
+                elif (lijst[i] == ','):
+                    bool = False
+                    if (bestand == name):
+                        exists = True
+                    bestand = ""
                 elif bool:
                     bestand = bestand + lijst[i]
         if exists:
-            data = self.visa_handle.ask('MMEM:DATA? "%s"' %name)
+            data = self.visa_handle.ask('MMEM:DATA? "%s"' % name)
 
             # logging.debug(__name__  + ' : File exists on instrument, loading \
             #         into local memory')
             self._import_waveform_file(name, name)
-            # string alsvolgt opgebouwd: '#'   'MAGIC 1000\r\n' '#'  'CLOCK ' 
+            # string alsvolgt opgebouwd: '#'   'MAGIC 1000\r\n'
+            # '#'  'CLOCK ' 
             len1 = int(data[1])
-            len2 = int(data[2:2+len1])
+            len2 = int(data[2:2 + len1])
             i = len1
             tekst = ""
             while (tekst != '#'):
                 tekst = data[i]
-                i = i+1
+                i = i + 1
             len3 = int(data[i])
-            len4 = int(data[i+1:i+1+len3])
+            len4 = int(data[i + 1:i + 1 + len3])
             w = []
             m1 = []
             m2 = []
 
-            for q in range(i+1+len3, i+1+len3+len4,5):
-                j=int(q)
-                c,d = struct.unpack('
Date: Fri, 22 Apr 2016 15:46:36 +0200
Subject: [PATCH 042/169] more robust import failure catching on importing
 plotting packages

---
 qcodes/__init__.py | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/qcodes/__init__.py b/qcodes/__init__.py
index 32ca3c455e3b..cc13fcf5f152 100644
--- a/qcodes/__init__.py
+++ b/qcodes/__init__.py
@@ -15,13 +15,17 @@
 if in_notebook():  # pragma: no cover
     try:
         from qcodes.plots.matplotlib import MatPlot
-    except ImportError:
-        print('matplotlib plotting not supported')
+    except Exception:
+        print('matplotlib plotting not supported, '
+              'try "from qcodes.plots.matplotlib import MatPlot" '
+              'to see the full error')
 
     try:
         from qcodes.plots.pyqtgraph import QtPlot
-    except ImportError:
-        print('pyqtgraph plotting not supported')
+    except Exception:
+        print('pyqtgraph plotting not supported, '
+              'try "from qcodes.plots.pyqtgraph import QtPlot" '
+              'to see the full error')
 
     from qcodes.widgets.widgets import show_subprocess_widget
 

From 5e3488a8b3f7aa1c860c1e203be3b33706280b7d Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Fri, 22 Apr 2016 16:35:00 +0200
Subject: [PATCH 043/169] test to fix metadata update, still fails on remote

---
 qcodes/instrument/parameter.py | 5 ++++-
 qcodes/instrument/remote.py    | 4 ++--
 qcodes/utils/metadata.py       | 2 +-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 549c20a1bb84..15e1838d30c1 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -236,13 +236,16 @@ def get_attrs(self):
 
         return out
 
-    def snapshot_base(self):
+    def snapshot_base(self, update=False, *args, **kwargs):
         '''
         json state of the Parameter
 
         optionally pass in the state, so if this is an instrument parameter
         we can collect all calls to the server into one
         '''
+        if update:
+            self.get()
+
         state = self._latest()
 
         if state['ts'] is not None:
diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index 8c6c0b39d36f..b3ea2b7c6ef7 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -141,9 +141,9 @@ def _latest(self):
         return self._instrument.connection.ask('param_call', self.name,
                                                '_latest')
 
-    def snapshot(self):
+    def snapshot(self, *args, **kwargs):
         return self._instrument.connection.ask('param_call', self.name,
-                                               'snapshot')
+                                               'snapshot',*args, **kwargs)
 
     def setattr(self, attr, value):
         self._instrument.connection.ask('param_setattr', self.name,
diff --git a/qcodes/utils/metadata.py b/qcodes/utils/metadata.py
index 231d24c63417..9ae4a861fe9b 100644
--- a/qcodes/utils/metadata.py
+++ b/qcodes/utils/metadata.py
@@ -20,7 +20,7 @@ def snapshot(self, *args, **kwargs):
 
         return snap
 
-    def snapshot_base(self, *ignore_args, **ignore_kwargs):
+    def snapshot_base(self, *args, **kwargs):
         '''
         override this with the primary information for a subclass
         '''

From 77a599f514fd7f591ae2ee42eb015c52c1e0b476 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Fri, 22 Apr 2016 22:54:03 +0200
Subject: [PATCH 044/169] ignore (new) .dat files

---
 .gitignore | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.gitignore b/.gitignore
index 58582eb41cd6..c1ce888e2fb1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -62,5 +62,6 @@ target/
 # Generated data
 *.csv
 *.data
+*.dat
 *.hdf5
 docs/examples/data/*

From 6aca37d63e4362d13097a6d302849c6691d4d403 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sat, 23 Apr 2016 15:00:40 +0200
Subject: [PATCH 045/169] Updating instruments for consistent IDN, and
 metadata-use

---
 .../Qcodes example with Agilent 34400A.ipynb  | 98 ++++++-------------
 .../examples/Qcodes example with Triton.ipynb | 46 +++++++--
 .../agilent/Agilent_34400A.py                 | 26 +++--
 .../instrument_drivers/ithaco/Ithaco_1211.py  | 16 +--
 .../instrument_drivers/oxford/mercuryiPS.py   | 10 +-
 qcodes/instrument_drivers/oxford/triton.py    |  5 +
 .../tektronix/Keithley_2400.py                |  8 +-
 .../tektronix/Keithley_2600.py                | 12 +--
 8 files changed, 116 insertions(+), 105 deletions(-)

diff --git a/docs/examples/Qcodes example with Agilent 34400A.ipynb b/docs/examples/Qcodes example with Agilent 34400A.ipynb
index 4610d70ccce1..b4c778442893 100644
--- a/docs/examples/Qcodes example with Agilent 34400A.ipynb	
+++ b/docs/examples/Qcodes example with Agilent 34400A.ipynb	
@@ -254,7 +254,7 @@
     "import qcodes as qc\n",
     "from qcodes.utils.validators import Enum, Strings\n",
     "import qcodes.instrument_drivers.tektronix.Keithley_2600 as keith\n",
-    "import qcodes.instrument_drivers.agilent.Agilent_34401A as agi\n",
+    "import qcodes.instrument_drivers.agilent.Agilent_34400A as agi\n",
     "\n",
     "qc.set_mp_method('spawn')  # force Windows behavior on mac\n",
     "\n",
@@ -331,9 +331,25 @@
      "output_type": "stream",
      "text": [
       "[Time s1]\n",
-      "Elapsed: 0.41602373123168945\n",
-      "[Time s2]\n",
-      "Elapsed: 0.8230471611022949\n"
+      "Elapsed: 2.0011143684387207\n"
+     ]
+    },
+    {
+     "ename": "Empty",
+     "evalue": "",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[1;31mEmpty\u001b[0m                                     Traceback (most recent call last)",
+      "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# Time single readings\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      2\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mTimer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Time s1'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 3\u001b[1;33m     \u001b[0mstation1\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmeasure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      4\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mTimer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'Time s2'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mstation2\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmeasure\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\station.py\u001b[0m in \u001b[0;36mmeasure\u001b[1;34m(self, *actions)\u001b[0m\n\u001b[0;32m    105\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0maction\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mactions\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    106\u001b[0m             \u001b[1;32mif\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'get'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 107\u001b[1;33m                 \u001b[0mout\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    108\u001b[0m             \u001b[1;32melif\u001b[0m \u001b[0mcallable\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0maction\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    109\u001b[0m                 \u001b[0maction\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\instrument\\remote.py\u001b[0m in \u001b[0;36mget\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m    121\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    122\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 123\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_instrument\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mconnection\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'get'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    124\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    125\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\instrument\\server.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, func_name, *args, **kwargs)\u001b[0m\n\u001b[0;32m    134\u001b[0m         \u001b[0mQuery\u001b[0m \u001b[0mthe\u001b[0m \u001b[0mserver\u001b[0m \u001b[0mcopy\u001b[0m \u001b[0mof\u001b[0m \u001b[0mthis\u001b[0m \u001b[0minstrument\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mexpecting\u001b[0m \u001b[0ma\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    135\u001b[0m         '''\n\u001b[1;32m--> 136\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmanager\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mask\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'ask'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mid\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfunc_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    137\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    138\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0mwrite\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfunc_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, timeout, *query)\u001b[0m\n\u001b[0;32m    332\u001b[0m                 \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_error_queue\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mempty\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    333\u001b[0m                     \u001b[1;31m# only raise if we're not about to find a deeper error\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 334\u001b[1;33m                     \u001b[1;32mraise\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    335\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_for_errors\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_expect_error\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    336\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36mask\u001b[1;34m(self, timeout, *query)\u001b[0m\n\u001b[0;32m    324\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    325\u001b[0m             \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 326\u001b[1;33m                 \u001b[0mres\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_check_response\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    327\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    328\u001b[0m                 \u001b[1;32mwhile\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_response_queue\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mempty\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mE:\\Git\\Qcodes\\qcodes\\utils\\multiprocessing.py\u001b[0m in \u001b[0;36m_check_response\u001b[1;34m(self, timeout)\u001b[0m\n\u001b[0;32m    301\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    302\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m_check_response\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 303\u001b[1;33m         \u001b[0mres\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_response_queue\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    304\u001b[0m         \u001b[1;32mif\u001b[0m \u001b[0mres\u001b[0m \u001b[1;33m==\u001b[0m \u001b[0mSERVER_ERR\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    305\u001b[0m             \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_expect_error\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;32mc:\\users\\qdev\\anaconda3\\lib\\multiprocessing\\queues.py\u001b[0m in \u001b[0;36mget\u001b[1;34m(self, block, timeout)\u001b[0m\n\u001b[0;32m    103\u001b[0m                     \u001b[0mtimeout\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdeadline\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mtime\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    104\u001b[0m                     \u001b[1;32mif\u001b[0m \u001b[0mtimeout\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m0\u001b[0m \u001b[1;32mor\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtimeout\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 105\u001b[1;33m                         \u001b[1;32mraise\u001b[0m \u001b[0mEmpty\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    106\u001b[0m                 \u001b[1;32melif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_poll\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    107\u001b[0m                     \u001b[1;32mraise\u001b[0m \u001b[0mEmpty\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
+      "\u001b[1;31mEmpty\u001b[0m: "
      ]
     }
    ],
@@ -347,22 +363,11 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": null,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "[Time a1]\n",
-      "Elapsed: 0.4150238037109375\n",
-      "[Time a2]\n",
-      "Elapsed: 0.4080233573913574\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# Time single readings\n",
     "with Timer('Time a1'):\n",
@@ -373,32 +378,12 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 7,
+   "execution_count": null,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
-      "   volt: volt\n",
-      "   volt_set: volt\n",
-      "started at 2016-04-15 16:35:52\n",
-      "[Time Loop 1]\n",
-      "Elapsed: 4.65026593208313\n",
-      "DataSet: DataMode.PUSH_TO_SERVER, location='testsweep'\n",
-      "   volt_1: volt\n",
-      "   volt_0: volt\n",
-      "   volt_set: volt\n",
-      "started at 2016-04-15 16:36:00\n",
-      "[Time Loop 2]\n",
-      "Elapsed: 8.254472017288208\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "with Timer('Time Loop 1'):\n",
     "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True,background=False)\n",
@@ -409,25 +394,12 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": null,
    "metadata": {
     "collapsed": false,
     "scrolled": false
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
-      "   volt: volt\n",
-      "   volt_set: volt\n",
-      "started at 2016-04-15 16:36:03\n",
-      "[Time Loop 1]\n",
-      "Elapsed: 4.743271112442017\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "with Timer('Time Loop 1'):\n",
     "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt).run(location='testsweep', overwrite=True)\n",
@@ -437,25 +409,11 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 9,
+   "execution_count": null,
    "metadata": {
     "collapsed": false
    },
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "DataSet: DataMode.PULL_FROM_SERVER, location='testsweep'\n",
-      "   volt_1: volt\n",
-      "   volt_0: volt\n",
-      "   volt_set: volt\n",
-      "started at 2016-04-15 16:36:16\n",
-      "[Time Loop 2]\n",
-      "Elapsed: 8.797503232955933\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "with Timer('Time Loop 2'):\n",
     "    data = qc.Loop(k1.volt[-5:5:1], 0).each(a1.volt, a2.volt).run(location='testsweep', overwrite=True)\n",
diff --git a/docs/examples/Qcodes example with Triton.ipynb b/docs/examples/Qcodes example with Triton.ipynb
index 0d905116eccd..dd3d40e41485 100644
--- a/docs/examples/Qcodes example with Triton.ipynb	
+++ b/docs/examples/Qcodes example with Triton.ipynb	
@@ -262,7 +262,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 2,
+   "execution_count": 5,
    "metadata": {
     "collapsed": false
    },
@@ -271,10 +271,10 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "18:37:58\n",
-      "0.0185306\n",
-      "0.0185306\n",
-      "Circulating\n",
+      "13:21:17\n",
+      "23.3481\n",
+      "23.3481\n",
+      "Idle\n",
       "OK\n"
      ]
     }
@@ -284,7 +284,6 @@
     "\n",
     "\n",
     "triton = triton.Triton(name = 'Triton 1', address='127.0.0.1', port=33576, tmpfile='Triton1_thermometry.reg')\n",
-    "triton.set_address(address='172.20.3.27', port=33576)\n",
     "# triton._get_temp_channels('thermometry.reg')\n",
     "# print(triton.chan_alias)\n",
     "\n",
@@ -295,7 +294,40 @@
     "#     print(name,param.get())\n",
     "print(triton.action.get())\n",
     "print(triton.status.get())\n",
-    "triton.close()\n"
+    "# triton.close()\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "t = triton.ask('*IDN?')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 10,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['OXFORD INSTRUMENTS', 'Triton', 'N/A', '2.445']"
+      ]
+     },
+     "execution_count": 10,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "t.split(':')[1:]"
    ]
   },
   {
diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
index 2ac5de0a9e2c..6f1faf9f57f6 100644
--- a/qcodes/instrument_drivers/agilent/Agilent_34400A.py
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -42,12 +42,11 @@ class Agilent_34400A(VisaInstrument):
     def __init__(self, name, address, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
 
-        self.IDN = self.visa_handle.ask('*IDN?')
-
-        vendor, model, serial, software = map(str.strip, self.IDN.split(','))
+        IDN = self.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
         self.model = model
-        self.info = {'vendor': vendor, 'model': model,
-                     'serial_number': serial, 'software_revision': software}
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
 
         # Async has to send 'INIT' and later ask for 'FETCH?'
 
@@ -56,11 +55,17 @@ def __init__(self, name, address, **kwargs):
                            label='Voltage',
                            get_parser=float,
                            units='V')
-        self.add_parameter('volt_fetch',
+        self.add_parameter('fetch',
                            get_cmd='FETCH?',
                            label='Voltage',
                            get_parser=float,
-                           units='V')
+                           units='V',
+                           snapshot_get=False,
+                           docstring=('Reads the data you asked for, i.e.'
+                                      'after an `init_measurement()` you can '
+                                      'read the data with fetch.\n'
+                                      'Do not call this when you didn\'t ask '
+                                      'for data in the first place!'))
         self.add_parameter('NPLC',
                            get_cmd='VOLT:NPLC?',
                            get_parser=float,
@@ -125,6 +130,13 @@ def __init__(self, name, address, **kwargs):
                                set_cmd='DISP:WIND2:TEXT "{}"',
                                vals=Strings())
 
+    def clear_errors(self):
+        while True:
+            err = self.ask('SYST:ERR?')
+            if 'No error' in err:
+                return
+            print(err)
+
     def init_measurement(self):
         self.write('INIT')
 
diff --git a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
index 317621761b5a..81bc88efd8b1 100644
--- a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
+++ b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
@@ -29,9 +29,11 @@
 
 
 class CurrentParameter(Parameter):
-    def __init__(self, measured_param, camp_ins):
+    def __init__(self, measured_param, camp_ins, name='curr'):
         p_name = measured_param.name
+        self.name = name
         super().__init__(names=(p_name, 'current'))
+
         _p_label = None
         _p_unit = None
 
@@ -70,12 +72,10 @@ def __init__(self, name, dmm_parameter=None, **kwargs):
         vendor = 'Ithaco (DL Instruments)'
         model = '1211'
         serial = None
-        software = None
-
-        self.info = {'vendor': vendor, 'model': model,
-                     'serial_number': serial, 'software_revision': software}
+        firmware = None
 
-        self.metadata['info'] = self.info
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
 
         self.add_parameter('sens',
                            parameter_class=ManualParameter,
@@ -91,10 +91,10 @@ def __init__(self, name, dmm_parameter=None, **kwargs):
                            label='Iverted output',
                            vals=Bool())
 
-        self.add_parameter('sens_x',
+        self.add_parameter('sens_factor',
                            parameter_class=ManualParameter,
                            initial_value=1,
-                           label='sensitivity x',
+                           label='sensitivity factor',
                            units=None,
                            vals=Enum(0.1, 1, 10))
 
diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS.py b/qcodes/instrument_drivers/oxford/mercuryiPS.py
index b25b5ed358b7..89419f3a0286 100644
--- a/qcodes/instrument_drivers/oxford/mercuryiPS.py
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS.py
@@ -53,11 +53,11 @@ def __init__(self, name, axes=None, **kwargs):
         self._latest_response = ''
         # for some reason the first call is always invalid?! need some kind of init?
         self.ask('*IDN?')
-        self.IDN = self.ask('*IDN?')[4:]
-        vendor, model, serial, software = map(str.strip, self.IDN.split(':'))
-        self.model = model
-        self.info = {'vendor': vendor, 'model': self.model,
-                     'serial_number': serial, 'software_revision': software}
+        IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':'))
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
 
         if axes is None:
             self._determine_magnet_axes()
diff --git a/qcodes/instrument_drivers/oxford/triton.py b/qcodes/instrument_drivers/oxford/triton.py
index 0a683101dc5d..9ba16699048d 100644
--- a/qcodes/instrument_drivers/oxford/triton.py
+++ b/qcodes/instrument_drivers/oxford/triton.py
@@ -43,6 +43,11 @@ def __init__(self, name, address=None, port=None, terminator='\r\n',
         super().__init__(name, address=address, port=port,
                          terminator=terminator, **kwargs)
 
+        IDN = self.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':')[1:])
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+
         self.add_parameter(name='time',
                            label='System Time',
                            units='',
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2400.py b/qcodes/instrument_drivers/tektronix/Keithley_2400.py
index 97355143b5ef..a116a530c5c9 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2400.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2400.py
@@ -34,7 +34,13 @@ def __init__(self, name, address, reset=False, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
 
         self._modes = ['']
-        self.add_parameter('IDN', get_cmd='*IDN?')
+
+        IDN = self.ask('*IDN?')
+        # Dont have a 2400 here right now
+        # vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        # self.model = model
+        # self.IDN = {'vendor': vendor, 'model': model,
+        #             'serial': serial, 'firmware': firmware}
 
         # Add parameters to wrapper
         self.add_parameter('volt', get_cmd=':READ?',
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index d741aa478467..d3d608b279e3 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -43,14 +43,12 @@ def __init__(self, name, address, channel, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
         self._channel = channel
 
-        self.IDN = self.visa_handle.ask('*IDN?')
-        vendor, model, serial, software = map(str.strip, self.IDN.split(','))
-        self.model = model[6:]
+        IDN = self.visa_handle.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        model = model[6:]
 
-        self.info = {'vendor': vendor, 'model': self.model,
-                     'serial_number': serial, 'software_revision': software}
-
-        self.metadata['info'] = self.info
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
 
         self.add_parameter('volt', get_cmd='measure.v()',
                            get_parser=float, set_cmd='source.levelv={:.8f}',

From f1a03cfa53a6a68774f8c5de79c70c58d46e7cad Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sat, 23 Apr 2016 16:05:24 +0200
Subject: [PATCH 046/169] attribute compatibility with StandardParameter

---
 qcodes/instrument_drivers/ithaco/Ithaco_1211.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
index 81bc88efd8b1..5ade2786f0fe 100644
--- a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
+++ b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
@@ -38,7 +38,7 @@ def __init__(self, measured_param, camp_ins, name='curr'):
         _p_unit = None
 
         self.measured_param = measured_param
-        self.camp = camp_ins
+        self._instrument = camp_ins
 
         if hasattr(measured_param, 'label'):
             _p_label = measured_param.label
@@ -50,10 +50,10 @@ def __init__(self, measured_param, camp_ins, name='curr'):
 
     def get(self):
         volt = self.measured_param.get()
-        current = (self.camp.sens.get() *
-                   self.camp.sens_x.get()) * volt
+        current = (self._instrument.sens.get() *
+                   self._instrument.sens_sens_factor.get()) * volt
 
-        if self.camp.invert.get():
+        if self._instrument.invert.get():
             current *= -1
         return (volt, current)
 

From 5e3f3227fad07460f830e521d4b8b32fb581a241 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sun, 24 Apr 2016 14:43:20 +0200
Subject: [PATCH 047/169] fixed typo

---
 qcodes/instrument_drivers/ithaco/Ithaco_1211.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
index 5ade2786f0fe..deeeebf95020 100644
--- a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
+++ b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
@@ -51,7 +51,7 @@ def __init__(self, measured_param, camp_ins, name='curr'):
     def get(self):
         volt = self.measured_param.get()
         current = (self._instrument.sens.get() *
-                   self._instrument.sens_sens_factor.get()) * volt
+                   self._instrument.sens_factor.get()) * volt
 
         if self._instrument.invert.get():
             current *= -1

From a2026d39dd4266e76cdd7085b7d380a3f28f8038 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 25 Apr 2016 14:42:21 +0200
Subject: [PATCH 048/169] repr for Instrument

---
 qcodes/instrument/base.py | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index daa105736cd4..e4d37bc3fc3b 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -3,9 +3,9 @@
 
 from qcodes.utils.metadata import Metadatable
 from qcodes.utils.helpers import DelegateAttributes, strip_attrs
-from .parameter import Parameter, StandardParameter
+from .parameter import StandardParameter
 from .function import Function
-from .remote import RemoteInstrument, RemoteParameter
+from .remote import RemoteInstrument
 
 
 class NoDefault:
@@ -90,6 +90,9 @@ def connect_message(self, param_name, begin_time=None):
         return 'Connected to: {} in {:.2f}s'.format(
             idn.strip(), time.time() - (begin_time or self._t0))
 
+    def __repr__(self):
+        return '<{}: {}>'.format(type(self).__name__, self.name)
+
     def getattr(self, attr, default=NoDefault):
         '''
         Get an attribute of this Instrument.

From e1b8f7e81081c67c07a1cbffe4dd7791fa7289bd Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 25 Apr 2016 14:42:46 +0200
Subject: [PATCH 049/169] detail on errors in write/ask to visa and ip
 instruments

---
 qcodes/instrument/ip.py   | 22 +++++++++++++++-------
 qcodes/instrument/visa.py | 14 +++++++++++---
 2 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/qcodes/instrument/ip.py b/qcodes/instrument/ip.py
index 7b2e0a9292a7..ff6c25cd5629 100644
--- a/qcodes/instrument/ip.py
+++ b/qcodes/instrument/ip.py
@@ -100,15 +100,23 @@ def close(self):
         super().close()
 
     def write(self, cmd):
-        with self._ensure_connection:
-            self._send(cmd)
-            if self._confirmation:
-                self._recv()
+        try:
+            with self._ensure_connection:
+                self._send(cmd)
+                if self._confirmation:
+                    self._recv()
+        except Exception as e:
+            e.args = e.args + ('writing ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
 
     def ask(self, cmd):
-        with self._ensure_connection:
-            self._send(cmd)
-            return self._recv()
+        try:
+            with self._ensure_connection:
+                self._send(cmd)
+                return self._recv()
+        except Exception as e:
+            e.args = e.args + ('asking ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
 
 
 class EnsureConnection:
diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py
index 5d4e16f34ee6..0ac72e71c999 100644
--- a/qcodes/instrument/visa.py
+++ b/qcodes/instrument/visa.py
@@ -91,8 +91,16 @@ def check_error(self, ret_code):
             raise visa.VisaIOError(ret_code)
 
     def write(self, cmd):
-        nr_bytes_written, ret_code = self.visa_handle.write(cmd)
-        self.check_error(ret_code)
+        try:
+            nr_bytes_written, ret_code = self.visa_handle.write(cmd)
+            self.check_error(ret_code)
+        except Exception as e:
+            e.args = e.args + ('writing ' + repr(cmd) + ' to ' + repr(self),)
+            raise e
 
     def ask(self, cmd):
-        return self.visa_handle.ask(cmd)
+        try:
+            return self.visa_handle.ask(cmd)
+        except Exception as e:
+            e.args = e.args + ('asking ' + repr(cmd) + ' to ' + repr(self),)
+            raise e

From 25410b08e186c545b41cb5c2f99f4965051b47ee Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 25 Apr 2016 14:59:38 +0200
Subject: [PATCH 050/169] more information in StandardParameter set and get
 errors

---
 qcodes/instrument/parameter.py | 49 +++++++++++++++++++++++-----------
 1 file changed, 33 insertions(+), 16 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 549c20a1bb84..04680c01935f 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -375,9 +375,14 @@ def __init__(self, name, instrument=None,
                                  ' Parameter {}'.format(self.name))
 
     def get(self):
-        value = self._get()
-        self._save_val(value)
-        return value
+        try:
+            value = self._get()
+            self._save_val(value)
+            return value
+        except Exception as e:
+            e.args = e.args + (
+                'getting {}:{}'.format(self._instrument.name, self.name),)
+            raise e
 
     @asyncio.coroutine
     def get_async(self):
@@ -406,9 +411,15 @@ def _set_set(self, set_cmd, async_set_cmd, set_parser):
             self.has_set = True
 
     def _validate_and_set(self, value):
-        self.validate(value)
-        self._set(value)
-        self._save_val(value)
+        try:
+            self.validate(value)
+            self._set(value)
+            self._save_val(value)
+        except Exception as e:
+            e.args = e.args + (
+                'setting {}:{} to {}'.format(self._instrument.name,
+                                             self.name, repr(value)),)
+            raise e
 
     @asyncio.coroutine
     def _validate_and_set_async(self, value):
@@ -454,17 +465,23 @@ def _update_sweep_ts(self, step_clock):
         return step_clock, remainder
 
     def _validate_and_sweep(self, value):
-        self.validate(value)
-        step_clock = time.perf_counter()
-
-        for step_val in self._sweep_steps(value):
-            self._set(step_val)
-            self._save_val(step_val)
-            step_clock, remainder = self._update_sweep_ts(step_clock)
-            time.sleep(remainder)
+        try:
+            self.validate(value)
+            step_clock = time.perf_counter()
 
-        self._set(value)
-        self._save_val(value)
+            for step_val in self._sweep_steps(value):
+                self._set(step_val)
+                self._save_val(step_val)
+                step_clock, remainder = self._update_sweep_ts(step_clock)
+                time.sleep(remainder)
+
+            self._set(value)
+            self._save_val(value)
+        except Exception as e:
+            e.args = e.args + (
+                'setting {}:{} to {}'.format(self._instrument.name,
+                                             self.name, repr(value)),)
+            raise e
 
     @asyncio.coroutine
     def _validate_and_sweep_async(self, value):

From 607277ecc822e2181c67a6bd9afa3a1b0672607f Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 25 Apr 2016 16:54:59 +0200
Subject: [PATCH 051/169] no wait/warn on zero delay, and error on bad delay

---
 qcodes/loops.py           | 28 +++++++++++++++++++---------
 qcodes/tests/test_loop.py | 24 ++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 3a1be4e12fd7..68cd3e244cf5 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -106,7 +106,9 @@ class Loop:
     sweep_values - a SweepValues or compatible object describing what
         parameter to set in the loop and over what values
     delay - a number of seconds to wait after setting a value before
-        continuing.
+        continuing. 0 (default) means no waiting and no warnings. > 0
+        means to wait, potentially filling the delay time with monitoring,
+        and give an error if you wait longer than expected.
 
     After creating a Loop, you attach `action`s to it, making an `ActiveLoop`
     that you can `.run()`, or you can `.run()` a `Loop` directly, in which
@@ -117,12 +119,14 @@ class Loop:
     data), `Wait` times, or other `ActiveLoop`s or `Loop`s to nest inside
     this one.
     '''
-    def __init__(self, sweep_values, delay):
+    def __init__(self, sweep_values, delay=0):
+        if not delay >= 0:
+            raise ValueError('delay must be > 0, not {}'.format(repr(delay)))
         self.sweep_values = sweep_values
         self.delay = delay
         self.nested_loop = None
 
-    def loop(self, sweep_values, delay):
+    def loop(self, sweep_values, delay=0):
         '''
         Nest another loop inside this one
 
@@ -556,13 +560,16 @@ def _run_loop(self, first_delay=0, action_indices=(),
             delay = self.delay
 
     def _wait(self, delay):
-        finish_clock = time.perf_counter() + delay
+        if delay:
+            finish_clock = time.perf_counter() + delay
 
-        if self._monitor:
-            self._monitor.call(finish_by=finish_clock)
+            if self._monitor:
+                self._monitor.call(finish_by=finish_clock)
 
-        self._check_signal()
-        time.sleep(wait_secs(finish_clock))
+            self._check_signal()
+            time.sleep(wait_secs(finish_clock))
+        else:
+            self._check_signal()
 
 
 class Task:
@@ -596,10 +603,13 @@ class Wait:
     But for use outside of a Loop, it is also callable (then it just sleeps)
     '''
     def __init__(self, delay):
+        if not delay >= 0:
+            raise ValueError('delay must be > 0, not {}'.format(repr(delay)))
         self.delay = delay
 
     def __call__(self):
-        time.sleep(self.delay)
+        if self.delay:
+            time.sleep(self.delay)
 
 
 class _Measure:
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index e08711b9ca17..752a3cb0bade 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -1,4 +1,5 @@
 from unittest import TestCase
+from unittest.mock import patch
 import time
 import multiprocessing as mp
 import numpy as np
@@ -211,6 +212,29 @@ def test_tasks_waits(self):
             self.assertLessEqual(delay, target)
             self.assertGreater(delay, target - 0.001)
 
+    @patch('time.sleep')
+    def test_delay0(self, sleep_mock):
+        self.p2.set(3)
+
+        loop = Loop(self.p1[1:3:1]).each(self.p2)
+
+        self.assertEqual(loop.delay, 0)
+
+        data = loop.run_temp()
+        self.assertEqual(data.p1.tolist(), [1, 2])
+        self.assertEqual(data.p2.tolist(), [3, 3])
+
+        self.assertEqual(sleep_mock.call_count, 0)
+
+    def test_bad_delay(self):
+        for val, err in [(-1, ValueError), (-0.1, ValueError),
+                         (None, TypeError), ('forever', TypeError)]:
+            with self.assertRaises(err):
+                Loop(self.p1[1:3:1], val)
+
+            with self.assertRaises(err):
+                Wait(val)
+
     def test_bare_wait(self):
         # Wait gets transformed to a Task, but is also callable on its own
         t0 = time.perf_counter()

From c81ce8f4bdb11837619f51e67890cdbb2d8b4320 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 25 Apr 2016 16:59:43 +0200
Subject: [PATCH 052/169] no threads_map if it would only be one thread

---
 qcodes/loops.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 68cd3e244cf5..90d06e9cacbf 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -618,7 +618,7 @@ class _Measure:
     This should not be constructed manually, only by an ActiveLoop.
     '''
     def __init__(self, params_indices, data_set, use_threads):
-        self.use_threads = use_threads
+        self.use_threads = use_threads and len(params_indices) > 1
         # the applicable DataSet.store function
         self.store = data_set.store
 

From 28eb9f561c72131b5248507a745d4c77f3eace74 Mon Sep 17 00:00:00 2001
From: Guen P 
Date: Mon, 25 Apr 2016 23:03:36 +0200
Subject: [PATCH 053/169] idn parser

---
 qcodes/instrument/visa.py | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py
index 5d4e16f34ee6..74824cd036dd 100644
--- a/qcodes/instrument/visa.py
+++ b/qcodes/instrument/visa.py
@@ -30,6 +30,8 @@ def __init__(self, name, address=None, timeout=5, terminator='', **kwargs):
         self.set_address(address)
         self.set_timeout(timeout)
         self.set_terminator(terminator)
+        self.add_parameter('IDN', get_cmd='*IDN?',
+                           get_parser=self.get_idn_dict)
 
     @classmethod
     def default_server_name(cls, **kwargs):
@@ -96,3 +98,7 @@ def write(self, cmd):
 
     def ask(self, cmd):
         return self.visa_handle.ask(cmd)
+
+    def get_idn_dict(self, IDN):
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        return {'vendor': vendor, 'model': model, 'serial': serial, 'firmware': firmware}
\ No newline at end of file

From 0a29c55d853b988c077b0c2e9ce607b2a3aafb49 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 25 Apr 2016 23:06:13 +0200
Subject: [PATCH 054/169] parameter step/delay refactor

---
 qcodes/instrument/parameter.py | 155 +++++++++++++++++++--------------
 1 file changed, 88 insertions(+), 67 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 549c20a1bb84..a7297ba7f18c 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -326,19 +326,26 @@ class StandardParameter(Parameter):
 
     vals: a Validator object for this parameter
 
-    sweep_step: max increment of parameter value - larger changes
+    delay: time (in seconds) to wait after the *start* of each set,
+        whether part of a sweep or not. Can be set 0 to go maximum speed with
+        no errors.
+    max_delay: If > delay, we don't emit a warning unless the time
+        taken during a single set is greater than this, even though we aim for
+        delay. If delay
+    step: max increment of parameter value - larger changes
         are broken into steps this size
-    sweep_delay: time (in seconds) to wait after each sweep step
     max_val_age: max time (in seconds) to trust a saved value from
         this parameter as the starting point of a sweep
+
     docstring: documentation string for the __doc__ field of the object
-        The __doc__ field of the instance is used by some help systems, but not all
+        The __doc__ field of the instance is used by some help systems,
+        but not all
     '''
     def __init__(self, name, instrument=None,
                  get_cmd=None, async_get_cmd=None, get_parser=None,
                  set_cmd=None, async_set_cmd=None, set_parser=None,
-                 sweep_step=None, sweep_delay=None, max_sweep_delay=None,
-                 max_val_age=3600, vals=None, val_mapping=None, **kwargs):
+                 delay=None, max_delay=None, step=0, max_val_age=3600,
+                 vals=None, val_mapping=None, **kwargs):
         # handle val_mapping before super init because it impacts
         # vals / validation in the base class
         if val_mapping:
@@ -354,7 +361,8 @@ def __init__(self, name, instrument=None,
                 set_parser = self._set_mapping.__getitem__
 
         if get_parser is not None and not isinstance(get_cmd, str):
-            logging.warning('get_parser is set, but will not be used (name %s)' % name)
+            logging.warning('get_parser is set, but will not be used ' +
+                            '(name %s)' % name)
         super().__init__(name=name, vals=vals, **kwargs)
 
         self._instrument = instrument
@@ -366,9 +374,8 @@ def __init__(self, name, instrument=None,
 
         self._set_get(get_cmd, async_get_cmd, get_parser)
         self._set_set(set_cmd, async_set_cmd, set_parser)
-        self.set_sweep(sweep_step, sweep_delay,
-                       max_sweep_delay=max_sweep_delay,
-                       max_val_age=max_val_age)
+        self.set_delay(delay, max_delay)
+        self.set_step(step, max_val_age)
 
         if not (self.has_get or self.has_set):
             raise NoCommandError('neither set nor get cmd found in' +
@@ -437,13 +444,13 @@ def _sweep_steps(self, value):
             return []
 
         # drop the initial value, we're already there
-        return permissive_range(start_value, value, self._sweep_step)[1:]
+        return permissive_range(start_value, value, self._step)[1:]
 
     def _update_sweep_ts(self, step_clock):
         # calculate the delay time to the *max* delay,
         # then take off up to the tolerance
-        tolerance = self._sweep_delay_tolerance
-        step_clock += self._sweep_delay
+        tolerance = self._delay_tolerance
+        step_clock += self._delay
         remainder = wait_secs(step_clock + tolerance)
         if remainder <= tolerance:
             # don't allow extra delays to compound
@@ -480,72 +487,86 @@ def _validate_and_sweep_async(self, value):
         yield from self._set_async(value)
         self._save_val(value)
 
-    def set_sweep(self, sweep_step, sweep_delay, max_sweep_delay=None,
-                  max_val_age=None):
+    def set_step(self, step, max_val_age=None):
+        '''
+        Configure whether this Parameter uses steps during set operations.
+        If step is a positive number, this is the maximum value change
+        allowed in one hardware call, so a single set can result in many
+        calls to the hardware if the starting value is far from the target.
+
+        step: a positive number, the largest change allowed in one call
+            all but the final change will attempt to change by +/- step
+            exactly
+
+        max_val_age: Only used with stepping, the max time (in seconds) to
+            trust a saved value. If this parameter has not been set or measured
+            more recently than this, it will be measured before starting to
+            step, so we're confident in the value we're starting from.
         '''
-        configure this Parameter to set using a stair-step sweep
+        if not step:
+            # single-command setting
+            self.set = self._validate_and_set
+            self.set_async = self._validate_and_set_async
+
+        elif not self._vals.is_numeric:
+            raise TypeError('you can only step numeric parameters')
+        elif step <= 0:
+            raise ValueError('step must be positive')
+        elif (isinstance(self._vals, Ints) and
+                not isinstance(step, int)):
+            raise TypeError(
+                'step must be a positive int for an Ints parameter')
+        elif not isinstance(step, (int, float)):
+            raise TypeError('step must be a positive number')
 
-        This means a single .set call will generate many instrument writes
-        so that the value only changes at most sweep_step in a time sweep_delay
+        else:
+            # stepped setting
+            if max_val_age is not None:
+                if not isinstance(max_val_age, (int, float)):
+                    raise TypeError(
+                        'max_val_age must be a non-negative number')
+                if max_val_age < 0:
+                    raise ValueError('max_val_age must be non-negative')
+                self._max_val_age = max_val_age
 
-        sweep_step: the biggest change in value allowed at once
+            self._step = step
+            self.set = self._validate_and_sweep
+            self.set_async = self._validate_and_sweep_async
 
-        sweep_delay: the target time between steps. The actual time will not be
+    def set_delay(self, delay, max_delay=None):
+        '''
+        Configure this parameter with a delay between set operations.
+        Typically used in conjunction with set_step to create an effective
+        ramp rate, but can also be used without a step to enforce a delay
+        after every set.
+
+        delay: the target time between set calls. The actual time will not be
             shorter than this, but may be longer if the underlying set call
-            takes longer than this time.
+            takes longer.
 
-        max_sweep_delay: if given, the longest time allowed between steps (due
-            to a slow set call, presumably) before we emit a warning
+        max_delay: if given, the longest time allowed for the underlying set
+            call before we emit a warning.
 
-        max_val_age: max time (in seconds) to trust a saved value. Important
-        since we need to know what value we're starting from in this sweep.
+        If delay is 0 and max_delay is None or 0, we never emit warnings
+        no matter how long the set takes.
         '''
-        if sweep_step is not None or sweep_delay is not None:
-            if not self._vals.is_numeric:
-                raise TypeError('you can only sweep numeric parameters')
-
-            if (isinstance(self._vals, Ints) and
-                    not isinstance(sweep_step, int)):
+        if not isinstance(delay, (int, float)):
+            raise TypeError('delay must be a non-negative number')
+        if delay < 0:
+            raise ValueError('delay must not be negative')
+        self._delay = delay
+
+        if max_delay is not None:
+            if not isinstance(max_delay, (int, float)) or max_delay < delay:
                 raise TypeError(
-                    'sweep_step must be a positive int for an Ints parameter')
-            elif not isinstance(sweep_step, (int, float)):
-                raise TypeError('sweep_step must be a positive number')
-            if sweep_step <= 0:
-                raise ValueError('sweep_step must be positive')
-
-            if not isinstance(sweep_delay, (int, float)):
-                raise TypeError('sweep_delay must be a positive number')
-            if sweep_delay <= 0:
-                raise ValueError('sweep_delay must be positive')
-
-            self._sweep_step = sweep_step
-            self._sweep_delay = sweep_delay
-
-            if max_sweep_delay is not None:
-                if not isinstance(max_sweep_delay, (int, float)):
-                    raise TypeError(
-                        'max_sweep_delay must be a positive number')
-                if max_sweep_delay < sweep_delay:
-                    raise ValueError(
-                        'max_sweep_delay must not be shorter than sweep_delay')
-                self._sweep_delay_tolerance = max_sweep_delay - sweep_delay
-            else:
-                self._sweep_delay_tolerance = 0
-
-            # assign the setters with a sweep
-            self.set = self._validate_and_sweep
-            self.set_async = self._validate_and_sweep_async
+                    'max_delay must be a number no shorter than delay')
+            self._delay_tolerance = max_delay - delay
         else:
-            # assign the setters as immediate jumps
-            self.set = self._validate_and_set
-            self.set_async = self._validate_and_set_async
+            self._delay_tolerance = 0
 
-        if max_val_age is not None:
-            if not isinstance(max_val_age, (int, float)):
-                raise TypeError('max_val_age must be a non-negative number')
-            if max_val_age < 0:
-                raise ValueError('max_val_age must be non-negative')
-            self._max_val_age = max_val_age
+        if not (self._delay or self._delay_tolerance):
+            # denotes that we shouldn't emit any warnings
+            self._delay = None
 
 
 class ManualParameter(Parameter):

From 2248d2939b0bede6aeb56dd5f6d1b667e1539b63 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 01:07:36 +0200
Subject: [PATCH 055/169] new dict for dataset.store every time we measure in a
 loop

---
 qcodes/loops.py | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 3a1be4e12fd7..cbeb53e58ef4 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -613,9 +613,7 @@ def __init__(self, params_indices, data_set, use_threads):
         self.store = data_set.store
 
         # for performance, pre-calculate which params return data for
-        # multiple arrays, pre-create the dict to pass these to store fn
-        # and pre-calculate the name mappings
-        self.dict = {}
+        # multiple arrays, and the name mappings
         self.getters = []
         self.param_ids = []
         self.composite = []
@@ -627,16 +625,15 @@ def __init__(self, params_indices, data_set, use_threads):
                 for i in range(len(param.names)):
                     param_id = data_set.action_id_map[action_indices + (i,)]
                     part_ids.append(param_id)
-                    self.dict[param_id] = None
                 self.param_ids.append(None)
                 self.composite.append(part_ids)
             else:
                 param_id = data_set.action_id_map[action_indices]
-                self.dict[param_id] = None
                 self.param_ids.append(param_id)
                 self.composite.append(False)
 
     def __call__(self, loop_indices, **ignore_kwargs):
+        out_dict = {}
         if self.use_threads:
             out = thread_map(self.getters)
         else:
@@ -646,11 +643,11 @@ def __call__(self, loop_indices, **ignore_kwargs):
                                                   self.composite):
             if composite:
                 for val, part_id in zip(param_out, composite):
-                    self.dict[part_id] = val
+                    out_dict[part_id] = val
             else:
-                self.dict[param_id] = param_out
+                out_dict[param_id] = param_out
 
-        self.store(loop_indices, self.dict)
+        self.store(loop_indices, out_dict)
 
 
 class _Nest:

From 6952c75c38ae617e9f7bfb35cced79f3fd29c44d Mon Sep 17 00:00:00 2001
From: Guen P 
Date: Tue, 26 Apr 2016 03:31:08 +0200
Subject: [PATCH 056/169] Instrument channel

for keithley_2600 and mercuryIPS magnet power supply
works without InstrumentServer - problem with daemonic processes not
allowed to create children
---
 docs/examples/Channel example.ipynb           | 421 ++++++++++++++++++
 qcodes/instrument/base.py                     |  34 +-
 qcodes/instrument/mock.py                     |  13 +-
 qcodes/instrument/visa.py                     |  14 +-
 .../tektronix/Keithley_2600.py                |  27 +-
 5 files changed, 483 insertions(+), 26 deletions(-)
 create mode 100644 docs/examples/Channel example.ipynb

diff --git a/docs/examples/Channel example.ipynb b/docs/examples/Channel example.ipynb
new file mode 100644
index 000000000000..a40f5aeab4da
--- /dev/null
+++ b/docs/examples/Channel example.ipynb	
@@ -0,0 +1,421 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": [
+       "/*\n",
+       " * Qcodes Jupyter/IPython widgets\n",
+       " */\n",
+       "require([\n",
+       "    'nbextensions/widgets/widgets/js/widget',\n",
+       "    'nbextensions/widgets/widgets/js/manager'\n",
+       "], function (widget, manager) {\n",
+       "\n",
+       "    var UpdateView = widget.DOMWidgetView.extend({\n",
+       "        render: function() {\n",
+       "            window.MYWIDGET = this;\n",
+       "            this._interval = 0;\n",
+       "            this.update();\n",
+       "        },\n",
+       "        update: function() {\n",
+       "            this.display(this.model.get('_message'));\n",
+       "            this.setInterval();\n",
+       "        },\n",
+       "        display: function(message) {\n",
+       "            /*\n",
+       "             * display method: override this for custom display logic\n",
+       "             */\n",
+       "            this.el.innerHTML = message;\n",
+       "        },\n",
+       "        remove: function() {\n",
+       "            clearInterval(this._updater);\n",
+       "        },\n",
+       "        setInterval: function(newInterval) {\n",
+       "            var me = this;\n",
+       "            if(newInterval===undefined) newInterval = me.model.get('interval');\n",
+       "            if(newInterval===me._interval) return;\n",
+       "\n",
+       "            me._interval = newInterval;\n",
+       "\n",
+       "            if(me._updater) clearInterval(me._updater);\n",
+       "\n",
+       "            if(me._interval) {\n",
+       "                me._updater = setInterval(function() {\n",
+       "                    me.send({myupdate: true});\n",
+       "                    if(!me.model.comm_live) {\n",
+       "                        console.log('missing comm, canceling widget updates', me);\n",
+       "                        clearInterval(me._updater);\n",
+       "                    }\n",
+       "                }, me._interval * 1000);\n",
+       "            }\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\n",
+       "\n",
+       "    var HiddenUpdateView = UpdateView.extend({\n",
+       "        display: function(message) {\n",
+       "            this.$el.hide();\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\n",
+       "\n",
+       "    var SubprocessView = UpdateView.extend({\n",
+       "        render: function() {\n",
+       "            var me = window.SPVIEW = this;\n",
+       "            me._interval = 0;\n",
+       "            me._minimize = '';\n",
+       "            me._restore = '';\n",
+       "\n",
+       "            // in case there is already an outputView present,\n",
+       "            // like from before restarting the kernel\n",
+       "            $('.qcodes-output-view').not(me.$el).remove();\n",
+       "\n",
+       "            me.$el\n",
+       "                .addClass('qcodes-output-view')\n",
+       "                .attr('qcodes-state', 'docked')\n",
+       "                .html(\n",
+       "                    '
' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '' +\n", + " '
' +\n", + " '
'\n",
+       "                );\n",
+       "\n",
+       "            me.clearButton = me.$el.find('.qcodes-clear-output');\n",
+       "            me.minButton = me.$el.find('.qcodes-minimize');\n",
+       "            me.outputArea = me.$el.find('pre');\n",
+       "            me.subprocessList = me.$el.find('span');\n",
+       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\n",
+       "\n",
+       "            me.clearButton.click(function() {\n",
+       "                me.outputArea.html('');\n",
+       "                me.clearButton.addClass('disabled');\n",
+       "            });\n",
+       "\n",
+       "            me.abortButton.click(function() {\n",
+       "                me.send({abort: true});\n",
+       "            });\n",
+       "\n",
+       "            me.$el.find('.js-state').click(function() {\n",
+       "                var oldState = me.$el.attr('qcodes-state'),\n",
+       "                    state = this.className.substr(this.className.indexOf('qcodes'))\n",
+       "                        .split('-')[1].split(' ')[0];\n",
+       "\n",
+       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\n",
+       "                // some other bit of code resets the parent after render if I do it there.\n",
+       "                // To be safe, just do it on every state click.\n",
+       "                me.$el.appendTo('body');\n",
+       "\n",
+       "                if(oldState === 'floated') {\n",
+       "                    me.$el.draggable('destroy').css({left:'', top: ''});\n",
+       "                }\n",
+       "\n",
+       "                me.$el.attr('qcodes-state', state);\n",
+       "\n",
+       "                if(state === 'floated') {\n",
+       "                    me.$el.draggable().css({\n",
+       "                        left: window.innerWidth - me.$el.width() - 15,\n",
+       "                        top: window.innerHeight - me.$el.height() - 10\n",
+       "                    });\n",
+       "                }\n",
+       "            });\n",
+       "\n",
+       "            $(window).resize(function() {\n",
+       "                if(me.$el.attr('qcodes-state') === 'floated') {\n",
+       "                    var position = me.$el.position(),\n",
+       "                        minVis = 20,\n",
+       "                        maxLeft = window.innerWidth - minVis,\n",
+       "                        maxTop = window.innerHeight - minVis;\n",
+       "\n",
+       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\n",
+       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\n",
+       "                }\n",
+       "            });\n",
+       "\n",
+       "            me.update();\n",
+       "        },\n",
+       "\n",
+       "        display: function(message) {\n",
+       "            if(message) {\n",
+       "                var initialScroll = this.outputArea.scrollTop();\n",
+       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\n",
+       "                var scrollBottom = this.outputArea.scrollTop();\n",
+       "\n",
+       "                if(this.$el.attr('qcodes-state') === 'minimized') {\n",
+       "                    this.$el.find('.qcodes-docked').click();\n",
+       "                    // always scroll to the bottom if we're restoring\n",
+       "                    // because of a new message\n",
+       "                    initialScroll = scrollBottom;\n",
+       "                }\n",
+       "\n",
+       "                this.outputArea.append(message);\n",
+       "                this.clearButton.removeClass('disabled');\n",
+       "\n",
+       "                // if we were scrolled to the bottom initially, make sure\n",
+       "                // we stay that way.\n",
+       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\n",
+       "                    this.outputArea.prop('scrollHeight') : initialScroll);\n",
+       "            }\n",
+       "\n",
+       "            var processes = this.model.get('_processes') || 'No subprocesses';\n",
+       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\n",
+       "            this.subprocessList.text(processes);\n",
+       "        }\n",
+       "    });\n",
+       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\n",
+       "});\n"
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       ""
+      ],
+      "text/plain": [
+       ""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "import qcodes"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {
+    "collapsed": true
+   },
+   "outputs": [],
+   "source": [
+    "import random"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "class Mock(qcodes.MockInstrument):\n",
+    "    def __init__(self, name, *args, **kwargs):\n",
+    "        super().__init__(name, delay=.001, model=qcodes.MockModel())\n",
+    "    def ask(self, cmd, channel='0'):\n",
+    "        return float(channel) + eval(cmd)\n",
+    "    def write(self, cmd, channel='0'):\n",
+    "        return None\n",
+    "ins = Mock('mock')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [],
+   "source": [
+    "ins.add_channels({'chan1' : '1', 'chan2' : '5'})"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": true
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'__doc__': 'Parameter class:\\n* `name` volt\\n* `label` volt\\n* `units` V\\n* `vals` ',\n",
+       " '_vals': ,\n",
+       " 'has_get': True,\n",
+       " 'has_set': False,\n",
+       " 'label': 'volt',\n",
+       " 'metadata': {},\n",
+       " 'name': 'volt',\n",
+       " 'units': 'V'}"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ins.add_parameter('volt', get_cmd='random.random()', get_parser=float, units='V')"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'chan1': ,\n",
+       " 'chan2': }"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ins.channels"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {
+    "collapsed": false,
+    "scrolled": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1.9201047725554221"
+      ]
+     },
+     "execution_count": 8,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ins.chan1.volt.get()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {
+    "collapsed": false
+   },
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "5.427205579617249"
+      ]
+     },
+     "execution_count": 9,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "ins.chan2.volt.get()"
+   ]
+  },
+  {
+   "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.5.0"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 0
+}
diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index daa105736cd4..c99f4243be7d 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -14,7 +14,6 @@ class NoDefault:
     '''
     pass
 
-
 class Instrument(Metadatable, DelegateAttributes):
     '''
     Base class for all QCodes instruments
@@ -67,6 +66,7 @@ def __init__(self, name, server_name=None, **kwargs):
         super().__init__(**kwargs)
         self.parameters = {}
         self.functions = {}
+        self.channels = {}
 
         self.name = str(name)
 
@@ -295,10 +295,13 @@ def add_parameter(self, name, parameter_class=StandardParameter,
 
         kwargs: see StandardParameter (or `parameter_class`)
         '''
-        if name in self.parameters:
-            raise KeyError('Duplicate parameter name {}'.format(name))
-        param = parameter_class(name=name, instrument=self, **kwargs)
-        self.parameters[name] = param
+        if not self.channels:
+            self.channels = {None: self}
+        for instrument in self.channels.values():
+            if name in instrument.parameters:
+                raise KeyError('Duplicate parameter name {}'.format(name))
+            param = parameter_class(name=name, instrument=instrument, **kwargs)
+            instrument.parameters[name] = param
 
         # for use in RemoteInstruments to add parameters to the server
         # we return the info they need to construct their proxy
@@ -369,13 +372,16 @@ def ask(self, cmd):
     #  etc...                                                                #
     ##########################################################################
 
-    delegate_attr_dicts = ['parameters', 'functions']
+    delegate_attr_dicts = ['parameters', 'functions', 'channels']
 
     def __getitem__(self, key):
         try:
             return self.parameters[key]
         except KeyError:
-            return self.functions[key]
+            try:
+                return self.functions[key]
+            except KeyError:
+                return self.channels[key]
 
     def set(self, param_name, value):
         self.parameters[param_name].set(value)
@@ -430,3 +436,17 @@ def _get_method_attrs(self):
                 attrs['__doc__'] = value.__doc__
 
         return out
+
+class InstrumentChannel(Instrument):
+    def __init__(self, name, channel_id, instrument):
+        self._t0 = time.time()
+        self.name = str(name)
+        self._channel_id = channel_id
+        self._instrument = instrument
+        self.parameters = {}
+
+    def ask(self, cmd, *args, **kwargs):
+        return self._instrument.ask(cmd, self._channel_id, *args, **kwargs)
+
+    def write(self, cmd, *args, **kwargs):
+        return self._instrument.write(cmd, self._channel_id, *args, **kwargs)
\ No newline at end of file
diff --git a/qcodes/instrument/mock.py b/qcodes/instrument/mock.py
index ec73231c0635..228158298d21 100644
--- a/qcodes/instrument/mock.py
+++ b/qcodes/instrument/mock.py
@@ -2,7 +2,7 @@
 from datetime import datetime
 from traceback import format_exc
 
-from .base import Instrument
+from .base import Instrument, InstrumentChannel
 from qcodes.utils.multiprocessing import ServerManager, SERVER_ERR
 
 
@@ -100,6 +100,17 @@ def read(self):
 
         return self._read_response
 
+    def add_channels(self, channels, channel_class=InstrumentChannel, **kwargs):
+        '''
+        creates a Channel for this instrument
+        each Channel has its own set of parameters as defined by add_parameter
+        '''
+        for name in channels:
+            if name in self.channels:
+                raise KeyError('Duplicate channel name {}'.format(name))
+            channel = channel_class(name, channels[name], instrument=self, **kwargs)
+            self.channels[name] = channel
+
 
 class MockModel(ServerManager):  # pragma: no cover
     # this is purely in service of mock instruments which *are* tested
diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py
index 74824cd036dd..03098b51c0bf 100644
--- a/qcodes/instrument/visa.py
+++ b/qcodes/instrument/visa.py
@@ -101,4 +101,16 @@ def ask(self, cmd):
 
     def get_idn_dict(self, IDN):
         vendor, model, serial, firmware = map(str.strip, IDN.split(','))
-        return {'vendor': vendor, 'model': model, 'serial': serial, 'firmware': firmware}
\ No newline at end of file
+        model = model[6:]
+        return {'vendor': vendor, 'model': model, 'serial': serial, 'firmware': firmware}
+
+    def add_channels(self, channels, channel_class=InstrumentChannel, **kwargs):
+        '''
+        creates a Channel for this instrument
+        each Channel has its own set of parameters as defined by add_parameter
+        '''
+        for name in channels:
+            if name in self.channels:
+                raise KeyError('Duplicate channel name {}'.format(name))
+            channel = channel_class(name, channels[name], instrument=self, **kwargs)
+            self.channels[name] = channel
\ No newline at end of file
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index d3d608b279e3..edc4440164b4 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -22,8 +22,14 @@
 # THE SOFTWARE.
 
 import re
-from qcodes import VisaInstrument
+from qcodes import VisaInstrument, InstrumentChannel
 
+class KeithleyChannel(InstrumentChannel):
+    def ask(self, cmd, channel):
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(channel, cmd))
+
+    def write(self, cmd, channel):
+        super().write('smu{:s}.{:s}'.format(channel, cmd))
 
 class Keithley_2600(VisaInstrument):
     '''
@@ -39,17 +45,10 @@ class Keithley_2600(VisaInstrument):
         - add ramping and such stuff
 
     '''
-    def __init__(self, name, address, channel, **kwargs):
+    def __init__(self, name, address, channels, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
-        self._channel = channel
-
-        IDN = self.visa_handle.ask('*IDN?')
-        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
-        model = model[6:]
-
-        self.IDN = {'vendor': vendor, 'model': model,
-                    'serial': serial, 'firmware': firmware}
-
+        
+        self.add_channels(channels, channel_class = KeithleyChannel)
         self.add_parameter('volt', get_cmd='measure.v()',
                            get_parser=float, set_cmd='source.levelv={:.8f}',
                            label='Voltage',
@@ -114,9 +113,3 @@ def reset(self):
 
     def ask_direct(self, cmd):
         return self.visa_handle.ask(cmd)
-
-    def ask(self, cmd):
-        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel, cmd))
-
-    def write(self, cmd):
-        super().write('smu{:s}.{:s}'.format(self._channel, cmd))

From c0200a518313a6cd25ea8634e3c4d9170d9c819b Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Mon, 25 Apr 2016 21:11:51 +0200
Subject: [PATCH 057/169] Use larges buffer possible while staying save

from discussion at
https://github.com/qdev-dk/Qcodes/pull/74#discussion_r60216559
---
 qcodes/instrument/ip.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/instrument/ip.py b/qcodes/instrument/ip.py
index 3e6d6e2ff553..302648e3c35f 100644
--- a/qcodes/instrument/ip.py
+++ b/qcodes/instrument/ip.py
@@ -31,7 +31,7 @@ def __init__(self, name, address=None, port=None, timeout=5,
         self._confirmation = write_confirmation
 
         self._ensure_connection = EnsureConnection(self)
-        self._buffer_size = 1024
+        self._buffer_size = 1400
 
         self._socket = None
 

From cdfa77f896e6a4136e56574c0f977269a8c00e85 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 10:20:11 +0200
Subject: [PATCH 058/169] test VisaInstrument, including new error reporting

---
 qcodes/tests/test_visa.py | 114 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 qcodes/tests/test_visa.py

diff --git a/qcodes/tests/test_visa.py b/qcodes/tests/test_visa.py
new file mode 100644
index 000000000000..a8eb6f937c50
--- /dev/null
+++ b/qcodes/tests/test_visa.py
@@ -0,0 +1,114 @@
+from unittest import TestCase
+import visa
+from qcodes.instrument.visa import VisaInstrument
+from qcodes.utils.validators import Numbers
+
+
+class MockVisa(VisaInstrument):
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.add_parameter('state',
+                           get_cmd='STAT?', get_parser=float,
+                           set_cmd='STAT:{:.3f}',
+                           vals=Numbers(-20, 20))
+
+    def set_address(self, address):
+        self.visa_handle = MockVisaHandle()
+
+
+class MockVisaHandle:
+    '''
+    mock the API needed for a visa handle that throws lots of errors:
+    - any write command sets a single "state" variable to a float
+      after the last : in the command
+      - a negative number results in an error raised here
+      - 0 results in a return code for visa timeout
+
+    - any ask command returns the state
+      - a state > 10 throws an error
+    '''
+    def __init__(self):
+        self.state = 0
+
+    def clear(self):
+        self.state = 0
+
+    def close(self):
+        # make it an error to ask or write after close
+        self.write = None
+        self.ask = None
+
+    def write(self, cmd):
+        num = float(cmd.split(':')[-1])
+        self.state = num
+
+        if num < 0:
+            raise ValueError('be more positive!')
+
+        if num == 0:
+            ret_code = visa.constants.VI_ERROR_TMO
+        else:
+            ret_code = 0
+
+        return len(cmd), ret_code
+
+    def ask(self, cmd):
+        if self.state > 10:
+            raise ValueError("I'm out of fingers")
+        return self.state
+
+
+class TestVisaInstrument(TestCase):
+    def test_default_server_name(self):
+        dsn = VisaInstrument.default_server_name
+        self.assertEqual(dsn(), 'VisaServer')
+        self.assertEqual(dsn(address='Gpib::10'), 'GPIBServer')
+        self.assertEqual(dsn(address='aSRL4'), 'SerialServer')
+
+    def test_ask_write_local(self):
+        mv = MockVisa('Joe', server_name=None)
+
+        # test normal ask and write behavior
+        mv.state.set(2)
+        self.assertEqual(mv.state.get(), 2)
+        mv.state.set(3.4567)
+        self.assertEqual(mv.state.get(), 3.457)  # driver rounds to 3 digits
+
+        # test ask and write errors
+        with self.assertRaises(ValueError):
+            mv.state.set(-10)
+        self.assertEqual(mv.state.get(), -10)  # set still happened
+
+        with self.assertRaises(visa.VisaIOError):
+            mv.state.set(0)
+        self.assertEqual(mv.state.get(), 0)
+
+        mv.state.set(15)
+        with self.assertRaises(ValueError):
+            mv.state.get()
+
+    def test_ask_write_server(self):
+        # same thing as above but Joe is on a server now...
+        mv = MockVisa('Joe')
+
+        # test normal ask and write behavior
+        mv.state.set(2)
+        self.assertEqual(mv.state.get(), 2)
+        mv.state.set(3.4567)
+        self.assertEqual(mv.state.get(), 3.457)  # driver rounds to 3 digits
+
+        # test ask and write errors
+        with self.assertRaises(ValueError):
+            mv.state.set(-10)
+        self.assertEqual(mv.state.get(), -10)  # set still happened
+
+        # only built-in errors get propagated to the main process as the
+        # same type. Perhaps we could include some more common ones like
+        # this (visa.VisaIOError) in the future...
+        with self.assertRaises(RuntimeError):
+            mv.state.set(0)
+        self.assertEqual(mv.state.get(), 0)
+
+        mv.state.set(15)
+        with self.assertRaises(ValueError):
+            mv.state.get()

From f8cd67eaf3f78778b9d7fae609ae93df13f64329 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Tue, 26 Apr 2016 10:46:49 +0200
Subject: [PATCH 059/169] Revert "Instrument channel"

This reverts commit 6952c75c38ae617e9f7bfb35cced79f3fd29c44d.
---
 docs/examples/Channel example.ipynb           | 421 ------------------
 qcodes/instrument/base.py                     |  34 +-
 qcodes/instrument/mock.py                     |  13 +-
 qcodes/instrument/visa.py                     |  14 +-
 .../tektronix/Keithley_2600.py                |  27 +-
 5 files changed, 26 insertions(+), 483 deletions(-)
 delete mode 100644 docs/examples/Channel example.ipynb

diff --git a/docs/examples/Channel example.ipynb b/docs/examples/Channel example.ipynb
deleted file mode 100644
index a40f5aeab4da..000000000000
--- a/docs/examples/Channel example.ipynb	
+++ /dev/null
@@ -1,421 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "metadata": {
-    "collapsed": false
-   },
-   "outputs": [
-    {
-     "data": {
-      "application/javascript": [
-       "/*\n",
-       " * Qcodes Jupyter/IPython widgets\n",
-       " */\n",
-       "require([\n",
-       "    'nbextensions/widgets/widgets/js/widget',\n",
-       "    'nbextensions/widgets/widgets/js/manager'\n",
-       "], function (widget, manager) {\n",
-       "\n",
-       "    var UpdateView = widget.DOMWidgetView.extend({\n",
-       "        render: function() {\n",
-       "            window.MYWIDGET = this;\n",
-       "            this._interval = 0;\n",
-       "            this.update();\n",
-       "        },\n",
-       "        update: function() {\n",
-       "            this.display(this.model.get('_message'));\n",
-       "            this.setInterval();\n",
-       "        },\n",
-       "        display: function(message) {\n",
-       "            /*\n",
-       "             * display method: override this for custom display logic\n",
-       "             */\n",
-       "            this.el.innerHTML = message;\n",
-       "        },\n",
-       "        remove: function() {\n",
-       "            clearInterval(this._updater);\n",
-       "        },\n",
-       "        setInterval: function(newInterval) {\n",
-       "            var me = this;\n",
-       "            if(newInterval===undefined) newInterval = me.model.get('interval');\n",
-       "            if(newInterval===me._interval) return;\n",
-       "\n",
-       "            me._interval = newInterval;\n",
-       "\n",
-       "            if(me._updater) clearInterval(me._updater);\n",
-       "\n",
-       "            if(me._interval) {\n",
-       "                me._updater = setInterval(function() {\n",
-       "                    me.send({myupdate: true});\n",
-       "                    if(!me.model.comm_live) {\n",
-       "                        console.log('missing comm, canceling widget updates', me);\n",
-       "                        clearInterval(me._updater);\n",
-       "                    }\n",
-       "                }, me._interval * 1000);\n",
-       "            }\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('UpdateView', UpdateView);\n",
-       "\n",
-       "    var HiddenUpdateView = UpdateView.extend({\n",
-       "        display: function(message) {\n",
-       "            this.$el.hide();\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('HiddenUpdateView', HiddenUpdateView);\n",
-       "\n",
-       "    var SubprocessView = UpdateView.extend({\n",
-       "        render: function() {\n",
-       "            var me = window.SPVIEW = this;\n",
-       "            me._interval = 0;\n",
-       "            me._minimize = '';\n",
-       "            me._restore = '';\n",
-       "\n",
-       "            // in case there is already an outputView present,\n",
-       "            // like from before restarting the kernel\n",
-       "            $('.qcodes-output-view').not(me.$el).remove();\n",
-       "\n",
-       "            me.$el\n",
-       "                .addClass('qcodes-output-view')\n",
-       "                .attr('qcodes-state', 'docked')\n",
-       "                .html(\n",
-       "                    '
' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '' +\n", - " '
' +\n", - " '
'\n",
-       "                );\n",
-       "\n",
-       "            me.clearButton = me.$el.find('.qcodes-clear-output');\n",
-       "            me.minButton = me.$el.find('.qcodes-minimize');\n",
-       "            me.outputArea = me.$el.find('pre');\n",
-       "            me.subprocessList = me.$el.find('span');\n",
-       "            me.abortButton = me.$el.find('.qcodes-abort-loop');\n",
-       "\n",
-       "            me.clearButton.click(function() {\n",
-       "                me.outputArea.html('');\n",
-       "                me.clearButton.addClass('disabled');\n",
-       "            });\n",
-       "\n",
-       "            me.abortButton.click(function() {\n",
-       "                me.send({abort: true});\n",
-       "            });\n",
-       "\n",
-       "            me.$el.find('.js-state').click(function() {\n",
-       "                var oldState = me.$el.attr('qcodes-state'),\n",
-       "                    state = this.className.substr(this.className.indexOf('qcodes'))\n",
-       "                        .split('-')[1].split(' ')[0];\n",
-       "\n",
-       "                // not sure why I can't pop it out of the widgetarea in render, but it seems that\n",
-       "                // some other bit of code resets the parent after render if I do it there.\n",
-       "                // To be safe, just do it on every state click.\n",
-       "                me.$el.appendTo('body');\n",
-       "\n",
-       "                if(oldState === 'floated') {\n",
-       "                    me.$el.draggable('destroy').css({left:'', top: ''});\n",
-       "                }\n",
-       "\n",
-       "                me.$el.attr('qcodes-state', state);\n",
-       "\n",
-       "                if(state === 'floated') {\n",
-       "                    me.$el.draggable().css({\n",
-       "                        left: window.innerWidth - me.$el.width() - 15,\n",
-       "                        top: window.innerHeight - me.$el.height() - 10\n",
-       "                    });\n",
-       "                }\n",
-       "            });\n",
-       "\n",
-       "            $(window).resize(function() {\n",
-       "                if(me.$el.attr('qcodes-state') === 'floated') {\n",
-       "                    var position = me.$el.position(),\n",
-       "                        minVis = 20,\n",
-       "                        maxLeft = window.innerWidth - minVis,\n",
-       "                        maxTop = window.innerHeight - minVis;\n",
-       "\n",
-       "                    if(position.left > maxLeft) me.$el.css('left', maxLeft);\n",
-       "                    if(position.top > maxTop) me.$el.css('top', maxTop);\n",
-       "                }\n",
-       "            });\n",
-       "\n",
-       "            me.update();\n",
-       "        },\n",
-       "\n",
-       "        display: function(message) {\n",
-       "            if(message) {\n",
-       "                var initialScroll = this.outputArea.scrollTop();\n",
-       "                this.outputArea.scrollTop(this.outputArea.prop('scrollHeight'));\n",
-       "                var scrollBottom = this.outputArea.scrollTop();\n",
-       "\n",
-       "                if(this.$el.attr('qcodes-state') === 'minimized') {\n",
-       "                    this.$el.find('.qcodes-docked').click();\n",
-       "                    // always scroll to the bottom if we're restoring\n",
-       "                    // because of a new message\n",
-       "                    initialScroll = scrollBottom;\n",
-       "                }\n",
-       "\n",
-       "                this.outputArea.append(message);\n",
-       "                this.clearButton.removeClass('disabled');\n",
-       "\n",
-       "                // if we were scrolled to the bottom initially, make sure\n",
-       "                // we stay that way.\n",
-       "                this.outputArea.scrollTop(initialScroll === scrollBottom ?\n",
-       "                    this.outputArea.prop('scrollHeight') : initialScroll);\n",
-       "            }\n",
-       "\n",
-       "            var processes = this.model.get('_processes') || 'No subprocesses';\n",
-       "            this.abortButton.toggleClass('disabled', processes.indexOf('Measurement')===-1);\n",
-       "            this.subprocessList.text(processes);\n",
-       "        }\n",
-       "    });\n",
-       "    manager.WidgetManager.register_widget_view('SubprocessView', SubprocessView);\n",
-       "});\n"
-      ],
-      "text/plain": [
-       ""
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       ""
-      ],
-      "text/plain": [
-       ""
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "import qcodes"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "metadata": {
-    "collapsed": true
-   },
-   "outputs": [],
-   "source": [
-    "import random"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "metadata": {
-    "collapsed": false
-   },
-   "outputs": [],
-   "source": [
-    "class Mock(qcodes.MockInstrument):\n",
-    "    def __init__(self, name, *args, **kwargs):\n",
-    "        super().__init__(name, delay=.001, model=qcodes.MockModel())\n",
-    "    def ask(self, cmd, channel='0'):\n",
-    "        return float(channel) + eval(cmd)\n",
-    "    def write(self, cmd, channel='0'):\n",
-    "        return None\n",
-    "ins = Mock('mock')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "metadata": {
-    "collapsed": false
-   },
-   "outputs": [],
-   "source": [
-    "ins.add_channels({'chan1' : '1', 'chan2' : '5'})"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "metadata": {
-    "collapsed": false,
-    "scrolled": true
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "{'__doc__': 'Parameter class:\\n* `name` volt\\n* `label` volt\\n* `units` V\\n* `vals` ',\n",
-       " '_vals': ,\n",
-       " 'has_get': True,\n",
-       " 'has_set': False,\n",
-       " 'label': 'volt',\n",
-       " 'metadata': {},\n",
-       " 'name': 'volt',\n",
-       " 'units': 'V'}"
-      ]
-     },
-     "execution_count": 6,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "ins.add_parameter('volt', get_cmd='random.random()', get_parser=float, units='V')"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "metadata": {
-    "collapsed": false
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "{'chan1': ,\n",
-       " 'chan2': }"
-      ]
-     },
-     "execution_count": 7,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "ins.channels"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "metadata": {
-    "collapsed": false,
-    "scrolled": false
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1.9201047725554221"
-      ]
-     },
-     "execution_count": 8,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "ins.chan1.volt.get()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "metadata": {
-    "collapsed": false
-   },
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "5.427205579617249"
-      ]
-     },
-     "execution_count": 9,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "ins.chan2.volt.get()"
-   ]
-  },
-  {
-   "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.5.0"
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 0
-}
diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index c99f4243be7d..daa105736cd4 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -14,6 +14,7 @@ class NoDefault:
     '''
     pass
 
+
 class Instrument(Metadatable, DelegateAttributes):
     '''
     Base class for all QCodes instruments
@@ -66,7 +67,6 @@ def __init__(self, name, server_name=None, **kwargs):
         super().__init__(**kwargs)
         self.parameters = {}
         self.functions = {}
-        self.channels = {}
 
         self.name = str(name)
 
@@ -295,13 +295,10 @@ def add_parameter(self, name, parameter_class=StandardParameter,
 
         kwargs: see StandardParameter (or `parameter_class`)
         '''
-        if not self.channels:
-            self.channels = {None: self}
-        for instrument in self.channels.values():
-            if name in instrument.parameters:
-                raise KeyError('Duplicate parameter name {}'.format(name))
-            param = parameter_class(name=name, instrument=instrument, **kwargs)
-            instrument.parameters[name] = param
+        if name in self.parameters:
+            raise KeyError('Duplicate parameter name {}'.format(name))
+        param = parameter_class(name=name, instrument=self, **kwargs)
+        self.parameters[name] = param
 
         # for use in RemoteInstruments to add parameters to the server
         # we return the info they need to construct their proxy
@@ -372,16 +369,13 @@ def ask(self, cmd):
     #  etc...                                                                #
     ##########################################################################
 
-    delegate_attr_dicts = ['parameters', 'functions', 'channels']
+    delegate_attr_dicts = ['parameters', 'functions']
 
     def __getitem__(self, key):
         try:
             return self.parameters[key]
         except KeyError:
-            try:
-                return self.functions[key]
-            except KeyError:
-                return self.channels[key]
+            return self.functions[key]
 
     def set(self, param_name, value):
         self.parameters[param_name].set(value)
@@ -436,17 +430,3 @@ def _get_method_attrs(self):
                 attrs['__doc__'] = value.__doc__
 
         return out
-
-class InstrumentChannel(Instrument):
-    def __init__(self, name, channel_id, instrument):
-        self._t0 = time.time()
-        self.name = str(name)
-        self._channel_id = channel_id
-        self._instrument = instrument
-        self.parameters = {}
-
-    def ask(self, cmd, *args, **kwargs):
-        return self._instrument.ask(cmd, self._channel_id, *args, **kwargs)
-
-    def write(self, cmd, *args, **kwargs):
-        return self._instrument.write(cmd, self._channel_id, *args, **kwargs)
\ No newline at end of file
diff --git a/qcodes/instrument/mock.py b/qcodes/instrument/mock.py
index 228158298d21..ec73231c0635 100644
--- a/qcodes/instrument/mock.py
+++ b/qcodes/instrument/mock.py
@@ -2,7 +2,7 @@
 from datetime import datetime
 from traceback import format_exc
 
-from .base import Instrument, InstrumentChannel
+from .base import Instrument
 from qcodes.utils.multiprocessing import ServerManager, SERVER_ERR
 
 
@@ -100,17 +100,6 @@ def read(self):
 
         return self._read_response
 
-    def add_channels(self, channels, channel_class=InstrumentChannel, **kwargs):
-        '''
-        creates a Channel for this instrument
-        each Channel has its own set of parameters as defined by add_parameter
-        '''
-        for name in channels:
-            if name in self.channels:
-                raise KeyError('Duplicate channel name {}'.format(name))
-            channel = channel_class(name, channels[name], instrument=self, **kwargs)
-            self.channels[name] = channel
-
 
 class MockModel(ServerManager):  # pragma: no cover
     # this is purely in service of mock instruments which *are* tested
diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py
index 03098b51c0bf..74824cd036dd 100644
--- a/qcodes/instrument/visa.py
+++ b/qcodes/instrument/visa.py
@@ -101,16 +101,4 @@ def ask(self, cmd):
 
     def get_idn_dict(self, IDN):
         vendor, model, serial, firmware = map(str.strip, IDN.split(','))
-        model = model[6:]
-        return {'vendor': vendor, 'model': model, 'serial': serial, 'firmware': firmware}
-
-    def add_channels(self, channels, channel_class=InstrumentChannel, **kwargs):
-        '''
-        creates a Channel for this instrument
-        each Channel has its own set of parameters as defined by add_parameter
-        '''
-        for name in channels:
-            if name in self.channels:
-                raise KeyError('Duplicate channel name {}'.format(name))
-            channel = channel_class(name, channels[name], instrument=self, **kwargs)
-            self.channels[name] = channel
\ No newline at end of file
+        return {'vendor': vendor, 'model': model, 'serial': serial, 'firmware': firmware}
\ No newline at end of file
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index edc4440164b4..d3d608b279e3 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -22,14 +22,8 @@
 # THE SOFTWARE.
 
 import re
-from qcodes import VisaInstrument, InstrumentChannel
+from qcodes import VisaInstrument
 
-class KeithleyChannel(InstrumentChannel):
-    def ask(self, cmd, channel):
-        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(channel, cmd))
-
-    def write(self, cmd, channel):
-        super().write('smu{:s}.{:s}'.format(channel, cmd))
 
 class Keithley_2600(VisaInstrument):
     '''
@@ -45,10 +39,17 @@ class Keithley_2600(VisaInstrument):
         - add ramping and such stuff
 
     '''
-    def __init__(self, name, address, channels, **kwargs):
+    def __init__(self, name, address, channel, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
-        
-        self.add_channels(channels, channel_class = KeithleyChannel)
+        self._channel = channel
+
+        IDN = self.visa_handle.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        model = model[6:]
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+
         self.add_parameter('volt', get_cmd='measure.v()',
                            get_parser=float, set_cmd='source.levelv={:.8f}',
                            label='Voltage',
@@ -113,3 +114,9 @@ def reset(self):
 
     def ask_direct(self, cmd):
         return self.visa_handle.ask(cmd)
+
+    def ask(self, cmd):
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel, cmd))
+
+    def write(self, cmd):
+        super().write('smu{:s}.{:s}'.format(self._channel, cmd))

From f4ada37ee0ea95327ffa6bbce800d48aff6d3b22 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 10:53:06 +0200
Subject: [PATCH 060/169] more precise testing of visa errors

---
 qcodes/tests/test_visa.py | 47 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 41 insertions(+), 6 deletions(-)

diff --git a/qcodes/tests/test_visa.py b/qcodes/tests/test_visa.py
index a8eb6f937c50..e07ee6363434 100644
--- a/qcodes/tests/test_visa.py
+++ b/qcodes/tests/test_visa.py
@@ -65,6 +65,26 @@ def test_default_server_name(self):
         self.assertEqual(dsn(address='Gpib::10'), 'GPIBServer')
         self.assertEqual(dsn(address='aSRL4'), 'SerialServer')
 
+    # error args for set(-10)
+    args1 = [
+        'be more positive!',
+        "writing 'STAT:-10.000' to ",
+        'setting Joe:state to -10'
+    ]
+
+    # error args for set(0)
+    args2 = [
+        "writing 'STAT:0.000' to ",
+        'setting Joe:state to 0'
+    ]
+
+    # error args for get -> 15
+    args3 = [
+        "I'm out of fingers",
+        "asking 'STAT?' to ",
+        'getting Joe:state'
+    ]
+
     def test_ask_write_local(self):
         mv = MockVisa('Joe', server_name=None)
 
@@ -75,17 +95,23 @@ def test_ask_write_local(self):
         self.assertEqual(mv.state.get(), 3.457)  # driver rounds to 3 digits
 
         # test ask and write errors
-        with self.assertRaises(ValueError):
+        with self.assertRaises(ValueError) as e:
             mv.state.set(-10)
+        for arg in self.args1:
+            self.assertIn(arg, e.exception.args)
         self.assertEqual(mv.state.get(), -10)  # set still happened
 
-        with self.assertRaises(visa.VisaIOError):
+        with self.assertRaises(visa.VisaIOError) as e:
             mv.state.set(0)
+        for arg in self.args2:
+            self.assertIn(arg, e.exception.args)
         self.assertEqual(mv.state.get(), 0)
 
         mv.state.set(15)
-        with self.assertRaises(ValueError):
+        with self.assertRaises(ValueError) as e:
             mv.state.get()
+        for arg in self.args3:
+            self.assertIn(arg, e.exception.args)
 
     def test_ask_write_server(self):
         # same thing as above but Joe is on a server now...
@@ -98,17 +124,26 @@ def test_ask_write_server(self):
         self.assertEqual(mv.state.get(), 3.457)  # driver rounds to 3 digits
 
         # test ask and write errors
-        with self.assertRaises(ValueError):
+        with self.assertRaises(ValueError) as e:
             mv.state.set(-10)
+        for arg in self.args1:
+            self.assertIn(repr(arg), e.exception.args[0])
         self.assertEqual(mv.state.get(), -10)  # set still happened
 
         # only built-in errors get propagated to the main process as the
         # same type. Perhaps we could include some more common ones like
         # this (visa.VisaIOError) in the future...
-        with self.assertRaises(RuntimeError):
+        with self.assertRaises(RuntimeError) as e:
             mv.state.set(0)
+        for arg in self.args2:
+            self.assertIn(repr(arg), e.exception.args[0])
+        # the error type isn't VisaIOError, but it should be in the message
+        self.assertIn('VisaIOError', e.exception.args[0])
+        self.assertIn('VI_ERROR_TMO', e.exception.args[0])
         self.assertEqual(mv.state.get(), 0)
 
         mv.state.set(15)
-        with self.assertRaises(ValueError):
+        with self.assertRaises(ValueError) as e:
             mv.state.get()
+        for arg in self.args3:
+            self.assertIn(repr(arg), e.exception.args[0])

From d638f527af6636c7d3180aa25dfb5e31d33eb4f8 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 26 Apr 2016 13:25:45 +0200
Subject: [PATCH 061/169] enable local version of pyqtgraph

---
 qcodes/plots/pyqtgraph.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index 8d6a3df41988..dce0a9afaf97 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -38,7 +38,7 @@ class QtPlot(BasePlot):
     rpg = None
 
     def __init__(self, *args, figsize=(1000, 600), interval=0.25,
-                 windowTitle='', theme=((60, 60, 60), 'w'), **kwargs):
+                 windowTitle='', theme=((60, 60, 60), 'w'), remote=True, **kwargs):
         super().__init__(interval)
 
         if not self.__class__.proc:
@@ -46,7 +46,12 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
 
         self.theme = theme
 
-        self.win = self.rpg.GraphicsWindow(title=windowTitle)
+        if remote:
+            self.win = self.rpg.GraphicsWindow(title=windowTitle)
+        else:            
+            self.win = pg.GraphicsWindow(title=windowTitle)
+            # overrule the remote pyqtgraph class
+            self.rpg = pg 
         self.win.setBackground(theme[1])
         self.win.resize(*figsize)
         self.subplots = [self.add_subplot()]

From 9e88d50cb2810984e545bd30e1dfbe82cca946f7 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 26 Apr 2016 15:11:58 +0200
Subject: [PATCH 062/169] improve code with suggestions from PR

---
 qcodes/plots/pyqtgraph.py | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index dce0a9afaf97..a0d040d84fcd 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -41,17 +41,15 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
                  windowTitle='', theme=((60, 60, 60), 'w'), remote=True, **kwargs):
         super().__init__(interval)
 
-        if not self.__class__.proc:
-            self._init_qt()
-
         self.theme = theme
 
         if remote:
-            self.win = self.rpg.GraphicsWindow(title=windowTitle)
+            if not self.__class__.proc:
+                self._init_qt()
         else:            
-            self.win = pg.GraphicsWindow(title=windowTitle)
             # overrule the remote pyqtgraph class
             self.rpg = pg 
+        self.win = pg.GraphicsWindow(title=windowTitle)
         self.win.setBackground(theme[1])
         self.win.resize(*figsize)
         self.subplots = [self.add_subplot()]

From d1790cf1b98667c4c69157807379f68c7c8c622e Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 26 Apr 2016 15:52:40 +0200
Subject: [PATCH 063/169] fix for remote plotting bug

---
 qcodes/plots/pyqtgraph.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index a0d040d84fcd..9be633a2b223 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -49,7 +49,7 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
         else:            
             # overrule the remote pyqtgraph class
             self.rpg = pg 
-        self.win = pg.GraphicsWindow(title=windowTitle)
+        self.win = self.rpg.GraphicsWindow(title=windowTitle)
         self.win.setBackground(theme[1])
         self.win.resize(*figsize)
         self.subplots = [self.add_subplot()]

From a766185941962a1da03a479165ba80bad418f85d Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 26 Apr 2016 16:16:15 +0200
Subject: [PATCH 064/169] added tests for plotting

---
 qcodes/tests/test_plots.py | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
 create mode 100644 qcodes/tests/test_plots.py

diff --git a/qcodes/tests/test_plots.py b/qcodes/tests/test_plots.py
new file mode 100644
index 000000000000..e74c3afbd2fe
--- /dev/null
+++ b/qcodes/tests/test_plots.py
@@ -0,0 +1,19 @@
+from unittest import TestCase
+import time
+import multiprocessing as mp
+import numpy as np
+
+import qcodes as qc
+
+class TestQtPlot(TestCase):
+    def setUp(self):
+	pass
+
+    def tearDown(self):
+	pass
+
+
+    def test_creation(self):
+        ''' Simple test function which created a QtPlot window '''
+        plotQ = qc.QtPlot(remote=False, show=False)
+

From 16b642677306994cab4530f13a9c393acddfffc0 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 26 Apr 2016 16:17:44 +0200
Subject: [PATCH 065/169] update

---
 qcodes/tests/test_plots.py | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/qcodes/tests/test_plots.py b/qcodes/tests/test_plots.py
index e74c3afbd2fe..76725b667c72 100644
--- a/qcodes/tests/test_plots.py
+++ b/qcodes/tests/test_plots.py
@@ -1,19 +1,32 @@
 from unittest import TestCase
-import time
-import multiprocessing as mp
 import numpy as np
 
-import qcodes as qc
+import qcodes 
+import matplotlib
+import matplotlib.pyplot as plt
 
 class TestQtPlot(TestCase):
+
     def setUp(self):
-	pass
+        pass
 
     def tearDown(self):
-	pass
-
+        pass
 
     def test_creation(self):
         ''' Simple test function which created a QtPlot window '''
-        plotQ = qc.QtPlot(remote=False, show=False)
+        plotQ = qcodes.QtPlot(remote=False, show=False)
+
+
+class TestMatPlot(TestCase):
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        pass
 
+    def test_creation(self):
+        ''' Simple test function which created a QtPlot window '''
+        plotM = qcodes.MatPlot()
+        plt.close(plotM.fig)

From 6d471224a3852a76c4942ad5f988083d906997e8 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 16:18:27 +0200
Subject: [PATCH 066/169] fix intermittent multiprocessing test error

---
 qcodes/tests/test_multiprocessing.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/qcodes/tests/test_multiprocessing.py b/qcodes/tests/test_multiprocessing.py
index 866cf7454059..c6606e98c0dd 100644
--- a/qcodes/tests/test_multiprocessing.py
+++ b/qcodes/tests/test_multiprocessing.py
@@ -194,11 +194,13 @@ def test_qcodes_process(self, in_nb_patch):
                 sender('row row ')
                 sender('row your boat\n')
                 sender('gently down ')
+                time.sleep(0.01)
                 data = [line for line in self.sq.get().split('\n') if line]
                 expected = [
                     label + 'row row row your boat',
                     label + 'gently down '
                 ]
+                self.assertEqual(len(data), len(expected), data)
                 for line, expected_line in zip(data, expected):
                     self.assertIsNotNone(queue_format.match(line), data)
                     self.assertEqual(line[14:], expected_line, data)
@@ -211,6 +213,7 @@ def test_qcodes_process(self, in_nb_patch):
             p2.send_out('polo\n')  # we don't see these single terminators
             p1.send_out('marco\n')  # when we change streams
             p2.send_out('polo')
+            time.sleep(0.01)
 
             data = self.sq.get().split('\n')
             for line in data:

From 7942b27a69880179cd317769374ce6685d04c66d Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 16:19:07 +0200
Subject: [PATCH 067/169] small changes to parameter and tests, tests still use
 the old syntax

---
 qcodes/instrument/parameter.py  | 25 ++++++++++++++++++++++---
 qcodes/tests/test_instrument.py | 12 ++----------
 2 files changed, 24 insertions(+), 13 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index a7297ba7f18c..93db76b64a8c 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -337,6 +337,10 @@ class StandardParameter(Parameter):
     max_val_age: max time (in seconds) to trust a saved value from
         this parameter as the starting point of a sweep
 
+    sweep_step: DEPRECATED - use step instead
+    sweep_delay: DEPRECATED - use delay instead
+    max_sweep_delay: DEPRECATED - use max_delay instead
+
     docstring: documentation string for the __doc__ field of the object
         The __doc__ field of the instance is used by some help systems,
         but not all
@@ -344,8 +348,19 @@ class StandardParameter(Parameter):
     def __init__(self, name, instrument=None,
                  get_cmd=None, async_get_cmd=None, get_parser=None,
                  set_cmd=None, async_set_cmd=None, set_parser=None,
-                 delay=None, max_delay=None, step=0, max_val_age=3600,
+                 delay=None, max_delay=None, step=None, max_val_age=3600,
+                 sweep_step=None, sweep_delay=None, max_sweep_delay=None,
                  vals=None, val_mapping=None, **kwargs):
+        # deprecated args - this block to be removed by june 1 2016 or before,
+        # as soon as people have had a chance to convert their WIP branches
+        # to the new arguments.
+        if step is None:
+            step = sweep_step
+        if delay is None:
+            delay = sweep_delay
+        if max_delay is None:
+            max_delay = max_sweep_delay
+
         # handle val_mapping before super init because it impacts
         # vals / validation in the base class
         if val_mapping:
@@ -547,9 +562,11 @@ def set_delay(self, delay, max_delay=None):
         max_delay: if given, the longest time allowed for the underlying set
             call before we emit a warning.
 
-        If delay is 0 and max_delay is None or 0, we never emit warnings
+        If delay and max_delay are both None or 0, we never emit warnings
         no matter how long the set takes.
         '''
+        if delay is None:
+            delay = 0
         if not isinstance(delay, (int, float)):
             raise TypeError('delay must be a non-negative number')
         if delay < 0:
@@ -557,9 +574,11 @@ def set_delay(self, delay, max_delay=None):
         self._delay = delay
 
         if max_delay is not None:
-            if not isinstance(max_delay, (int, float)) or max_delay < delay:
+            if not isinstance(max_delay, (int, float)):
                 raise TypeError(
                     'max_delay must be a number no shorter than delay')
+            if max_delay < delay:
+                raise ValueError('max_delay must be no shorter than delay')
             self._delay_tolerance = max_delay - delay
         else:
             self._delay_tolerance = 0
diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index 15727f6f2ac4..0571dd9abdd1 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -379,11 +379,7 @@ def test_set_sweep_errors(self):
             gates.add_parameter('t1', set_cmd='{}', vals=Ints(),
                                 sweep_step=0.1, sweep_delay=0.01)
         with self.assertRaises(ValueError):
-            # need a positive step
-            gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0, sweep_delay=0.01)
-        with self.assertRaises(ValueError):
-            # need a positive step
+            # need a non-negative step
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
                                 sweep_step=-0.1, sweep_delay=0.01)
         with self.assertRaises(TypeError):
@@ -391,13 +387,9 @@ def test_set_sweep_errors(self):
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
                                 sweep_step=0.1, sweep_delay='a tad')
         with self.assertRaises(ValueError):
-            # need a positive delay
+            # need a non-negative delay
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
                                 sweep_step=0.1, sweep_delay=-0.01)
-        with self.assertRaises(ValueError):
-            # need a positive delay
-            gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=0)
         with self.assertRaises(TypeError):
             # need a numeric max_val_age
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),

From e41fa8ec1547954e5dbc70ee2d9683b7ef2575db Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 16:35:29 +0200
Subject: [PATCH 068/169] test that delay messages disappear when delay is
 really zero

---
 qcodes/tests/test_loop.py | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 752a3cb0bade..f4e27818db26 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -12,7 +12,7 @@
 from qcodes.instrument.parameter import Parameter, ManualParameter
 from qcodes.utils.multiprocessing import QcodesProcess
 from qcodes.utils.validators import Numbers
-from qcodes.utils.helpers import killprocesses
+from qcodes.utils.helpers import killprocesses, LogCapture
 from .instrument_mocks import AMockModel, MockGates, MockSource, MockMeter
 
 
@@ -344,6 +344,22 @@ def test_bad_actors(self):
         with self.assertRaises(ValueError):
             Loop(self.p1[-20:20:1], 0.001).each(self.p1)
 
+    def test_very_short_delay(self):
+        with LogCapture() as s:
+            Loop(self.p1[1:3:1], 1e-9).each(self.p1).run_temp()
+
+        logstr = s.getvalue()
+        s.close()
+        self.assertEqual(logstr.count('negative delay'), 2, logstr)
+
+    def test_zero_delay(self):
+        with LogCapture() as s:
+            Loop(self.p1[1:3:1]).each(self.p1).run_temp()
+
+        logstr = s.getvalue()
+        s.close()
+        self.assertEqual(logstr.count('negative delay'), 0, logstr)
+
 
 class AbortingGetter(ManualParameter):
     '''

From 5be57f3597115bc93ebe7338520ab6627565d6a3 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 18:26:03 +0200
Subject: [PATCH 069/169] add and test delay without steps

---
 qcodes/instrument/parameter.py   | 23 +++++++++++++++++------
 qcodes/tests/instrument_mocks.py |  8 ++++++++
 qcodes/tests/test_instrument.py  | 12 ++++++++++--
 3 files changed, 35 insertions(+), 8 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 93db76b64a8c..4a1b15e6f468 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -428,15 +428,23 @@ def _set_set(self, set_cmd, async_set_cmd, set_parser):
             self.has_set = True
 
     def _validate_and_set(self, value):
+        clock = time.perf_counter()
         self.validate(value)
         self._set(value)
         self._save_val(value)
+        if self._delay is not None:
+            clock, remainder = self._update_set_ts(clock)
+            time.sleep(remainder)
 
     @asyncio.coroutine
     def _validate_and_set_async(self, value):
+        clock = time.perf_counter()
         self.validate(value)
         yield from self._set_async(value)
         self._save_val(value)
+        if self._delay is not None:
+            clock, remainder = self._update_set_ts(clock)
+            yield from asyncio.sleep(remainder)
 
     def _sweep_steps(self, value):
         oldest_ok_val = datetime.now() - timedelta(seconds=self._max_val_age)
@@ -461,7 +469,7 @@ def _sweep_steps(self, value):
         # drop the initial value, we're already there
         return permissive_range(start_value, value, self._step)[1:]
 
-    def _update_sweep_ts(self, step_clock):
+    def _update_set_ts(self, step_clock):
         # calculate the delay time to the *max* delay,
         # then take off up to the tolerance
         tolerance = self._delay_tolerance
@@ -482,8 +490,9 @@ def _validate_and_sweep(self, value):
         for step_val in self._sweep_steps(value):
             self._set(step_val)
             self._save_val(step_val)
-            step_clock, remainder = self._update_sweep_ts(step_clock)
-            time.sleep(remainder)
+            if self._delay is not None:
+                step_clock, remainder = self._update_set_ts(step_clock)
+                time.sleep(remainder)
 
         self._set(value)
         self._save_val(value)
@@ -496,8 +505,9 @@ def _validate_and_sweep_async(self, value):
         for step_val in self._sweep_steps(value):
             yield from self._set_async(step_val)
             self._save_val(step_val)
-            step_clock, remainder = self._update_sweep_ts(step_clock)
-            yield from asyncio.sleep(remainder)
+            if self._delay is not None:
+                step_clock, remainder = self._update_set_ts(step_clock)
+                yield from asyncio.sleep(remainder)
 
         yield from self._set_async(value)
         self._save_val(value)
@@ -584,7 +594,8 @@ def set_delay(self, delay, max_delay=None):
             self._delay_tolerance = 0
 
         if not (self._delay or self._delay_tolerance):
-            # denotes that we shouldn't emit any warnings
+            # denotes that we shouldn't follow the wait code or
+            # emit any warnings
             self._delay = None
 
 
diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py
index 48527ce29499..ff456d686190 100644
--- a/qcodes/tests/instrument_mocks.py
+++ b/qcodes/tests/instrument_mocks.py
@@ -122,6 +122,14 @@ def __init__(self, model=None, **kwargs):
                            set_cmd=self.slow_neg_set, get_parser=float,
                            vals=Numbers(-10, 10), sweep_step=0.2,
                            sweep_delay=0.01, max_sweep_delay=0.08)
+        self.add_parameter('chan0slow4', get_cmd='c0?',
+                           set_cmd=self.slow_neg_set, get_parser=float,
+                           vals=Numbers(-10, 10),
+                           sweep_delay=0.01, max_sweep_delay=0.02)
+        self.add_parameter('chan0slow5', get_cmd='c0?',
+                           set_cmd=self.slow_neg_set, get_parser=float,
+                           vals=Numbers(-10, 10),
+                           sweep_delay=0.01, max_sweep_delay=0.08)
 
         self.add_function('reset', call_cmd='rst')
 
diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index 0571dd9abdd1..c66818e200e4 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -122,11 +122,19 @@ def test_slow_set(self):
         # at least for now, need a local instrument to test logging
         gatesLocal = MockGates(model=self.model, server_name=None)
         for param, logcount in (('chan0slow', 2), ('chan0slow2', 2),
-                                ('chan0slow3', 0)):
+                                ('chan0slow3', 0), ('chan0slow4', 1),
+                                ('chan0slow5', 0)):
             gatesLocal.chan0.set(-0.5)
 
             with LogCapture() as s:
-                gatesLocal.set(param, 0.5)
+                if param in ('chan0slow', 'chan0slow2', 'chan0slow3'):
+                    # these are the stepped parameters
+                    gatesLocal.set(param, 0.5)
+                else:
+                    # these are the non-stepped parameters that
+                    # still have delays
+                    gatesLocal.set(param, -1)
+                    gatesLocal.set(param, 1)
 
             logs = s.getvalue().split('\n')[:-1]
             s.close()

From adc02a91601b4ed15ccd4137e49baad45eff60af Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 18:39:18 +0200
Subject: [PATCH 070/169] remove old sys.path comments in readme

---
 README.md | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/README.md b/README.md
index e1d9650bf076..889fffe45e9f 100644
--- a/README.md
+++ b/README.md
@@ -45,14 +45,6 @@ If you registered Qcodes with Python via `setup.py develop`, all you need to do
 
 See the [docs](docs) directory, particularly the notebooks in [docs/examples](docs/examples)
 
-Until we have this prepared as an installable package, you need to make sure Python can find qcodes by adding the repository root directory to `sys.path`:
-```
-import sys
-qcpath = 'your/Qcodes/repository/path'
-if qcpath not in sys.path:
-    sys.path.append(qcpath)
-```
-
 For frequently asked questions see the [Qcodes FAQ](docs/FAQ.md).
 
 ## Contributing

From 94eed8514e485d7e54d0afc0d2d6df207f4859ca Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 21:56:58 +0200
Subject: [PATCH 071/169] convert existing drivers and parameter tests to new
 step/delay names

---
 docs/examples/toymodel.py                |  4 +--
 qcodes/instrument_drivers/QuTech/IVVI.py |  6 ++--
 qcodes/tests/instrument_mocks.py         | 20 ++++++-------
 qcodes/tests/test_instrument.py          | 36 ++++++++++++------------
 4 files changed, 33 insertions(+), 33 deletions(-)

diff --git a/docs/examples/toymodel.py b/docs/examples/toymodel.py
index 2731171d07f8..3472f416191b 100644
--- a/docs/examples/toymodel.py
+++ b/docs/examples/toymodel.py
@@ -94,8 +94,8 @@ def __init__(self, name, model=None, **kwargs):
                            set_cmd='ampl:{:.4f}',
                            get_parser=float,
                            vals=Numbers(0, 10),
-                           sweep_step=0.1,
-                           sweep_delay=0.05)
+                           step=0.1,
+                           delay=0.05)
 
 
 class MockMeter(MockInstrument):
diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
index 63fb5eefdcea..2c89b74b23f0 100644
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -70,9 +70,9 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
                 get_cmd=self._gen_ch_get_func(self._get_dac, i),
                 set_cmd=self._gen_ch_set_func(self._set_dac, i),
                 vals=vals.Numbers(-2000, 2000),
-                sweep_step=10,
-                sweep_delay=.1,
-                max_sweep_delay=.2,
+                step=10,
+                delay=.1,
+                max_delay=.2,
                 max_val_age=10)
 
         self._update_time = 5  # seconds
diff --git a/qcodes/tests/instrument_mocks.py b/qcodes/tests/instrument_mocks.py
index ff456d686190..528090cbf1aa 100644
--- a/qcodes/tests/instrument_mocks.py
+++ b/qcodes/tests/instrument_mocks.py
@@ -108,28 +108,28 @@ def __init__(self, model=None, **kwargs):
                                set_cmd=cmdbase + ':{:.4f}',
                                get_parser=float,
                                vals=Numbers(-10, 10),
-                               sweep_step=0.1, sweep_delay=0.005)
+                               step=0.1, delay=0.005)
 
         self.add_parameter('chan0slow', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.02)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.02)
         self.add_parameter('chan0slow2', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.01, max_sweep_delay=0.02)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.01, max_delay=0.02)
         self.add_parameter('chan0slow3', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.01, max_sweep_delay=0.08)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.01, max_delay=0.08)
         self.add_parameter('chan0slow4', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
                            vals=Numbers(-10, 10),
-                           sweep_delay=0.01, max_sweep_delay=0.02)
+                           delay=0.01, max_delay=0.02)
         self.add_parameter('chan0slow5', get_cmd='c0?',
                            set_cmd=self.slow_neg_set, get_parser=float,
                            vals=Numbers(-10, 10),
-                           sweep_delay=0.01, max_sweep_delay=0.08)
+                           delay=0.01, max_delay=0.08)
 
         self.add_function('reset', call_cmd='rst')
 
@@ -146,7 +146,7 @@ def __init__(self, model=None, **kwargs):
         self.add_parameter('amplitude', get_cmd='ampl?',
                            set_cmd='ampl:{:.4f}', get_parser=float,
                            vals=Numbers(0, 1),
-                           sweep_step=0.2, sweep_delay=0.005)
+                           step=0.2, delay=0.005)
 
 
 class MockMeter(MockInstTester):
diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index c66818e200e4..2ab5eb7ba281 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -72,9 +72,9 @@ def __init__(self, *args, **kwargs):
         self.add_parameter('chan0bad', get_cmd='c0?',
                            set_cmd=self.slow_neg_set,
                            get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.01,
-                           max_sweep_delay='forever')
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.01,
+                           max_delay='forever')
 
 
 class GatesBadDelayValue(MockGates):
@@ -83,9 +83,9 @@ def __init__(self, *args, **kwargs):
         self.add_parameter('chan0bad', get_cmd='c0?',
                            set_cmd=self.slow_neg_set,
                            get_parser=float,
-                           vals=Numbers(-10, 10), sweep_step=0.2,
-                           sweep_delay=0.05,
-                           max_sweep_delay=0.03)
+                           vals=Numbers(-10, 10), step=0.2,
+                           delay=0.05,
+                           max_delay=0.03)
 
 
 class TestParameters(TestCase):
@@ -144,7 +144,7 @@ def test_slow_set(self):
             for line in logs:
                 self.assertTrue(line.startswith('negative delay'), line)
 
-    def test_max_sweep_delay_errors(self):
+    def test_max_delay_errors(self):
         with self.assertRaises(TypeError):
             # add_parameter works remotely with string commands, but
             # function commands are not going to be picklable, since they
@@ -347,7 +347,7 @@ def test_sweep_steps_edge_case(self):
         source.add_parameter('amplitude2', get_cmd='ampl?',
                              set_cmd='ampl:{}', get_parser=float,
                              vals=MultiType(Numbers(0, 1), Strings()),
-                             sweep_step=0.2, sweep_delay=0.02)
+                             step=0.2, delay=0.02)
         self.assertEqual(len(source.getattr('history')), 0)
 
         # 2 history items - get then set, and one warning (cannot sweep
@@ -369,44 +369,44 @@ def test_set_sweep_errors(self):
 
         # for reference, some add_parameter's that should work
         gates.add_parameter('t0', set_cmd='{}', vals=Numbers(),
-                            sweep_step=0.1, sweep_delay=0.01)
+                            step=0.1, delay=0.01)
         gates.add_parameter('t2', set_cmd='{}', vals=Ints(),
-                            sweep_step=1, sweep_delay=0.01,
+                            step=1, delay=0.01,
                             max_val_age=0)
 
         with self.assertRaises(TypeError):
             # can't sweep non-numerics
             gates.add_parameter('t1', set_cmd='{}', vals=Strings(),
-                                sweep_step=1, sweep_delay=0.01)
+                                step=1, delay=0.01)
         with self.assertRaises(TypeError):
             # need a numeric step too
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step='a skosh', sweep_delay=0.01)
+                                step='a skosh', delay=0.01)
         with self.assertRaises(TypeError):
             # Ints requires and int step
             gates.add_parameter('t1', set_cmd='{}', vals=Ints(),
-                                sweep_step=0.1, sweep_delay=0.01)
+                                step=0.1, delay=0.01)
         with self.assertRaises(ValueError):
             # need a non-negative step
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=-0.1, sweep_delay=0.01)
+                                step=-0.1, delay=0.01)
         with self.assertRaises(TypeError):
             # need a numeric delay
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay='a tad')
+                                step=0.1, delay='a tad')
         with self.assertRaises(ValueError):
             # need a non-negative delay
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=-0.01)
+                                step=0.1, delay=-0.01)
         with self.assertRaises(TypeError):
             # need a numeric max_val_age
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=0.01,
+                                step=0.1, delay=0.01,
                                 max_val_age='an hour')
         with self.assertRaises(ValueError):
             # need a non-negative max_val_age
             gates.add_parameter('t1', set_cmd='{}', vals=Numbers(),
-                                sweep_step=0.1, sweep_delay=0.01,
+                                step=0.1, delay=0.01,
                                 max_val_age=-1)
 
     def getmem(self, key):

From f46a383c9ff1f899ec17bbd0a16e3f37c46fc58f Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 22:45:05 +0200
Subject: [PATCH 072/169] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index e095e535f825..3cd6a3187068 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -22,15 +22,15 @@ Figured out a new way to use qcodes? Found a package that makes your life better
 
 ### Setup
 
-- Clone and register the package for development as described in [README.md#installation]
+- Clone and register the package for development as described in the [README](README.md#installation)
 
 ### Running Tests
 
-The core test runner is in `qcodes/test.py:
+The core test runner is in `qcodes/test.py`:
 ```
 python qcodes/test.py
-# optional extra verbosity
-python qcodes/test.py -v
+# optional extra verbosity and fail fast
+python qcodes/test.py -v -f
 ```
 You should see output that looks something like this:
 ```

From 9d437215c8ecf86da5f9317fc3df0cd6ab237246 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 22:46:26 +0200
Subject: [PATCH 073/169] Update CONTRIBUTING.md

---
 CONTRIBUTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3cd6a3187068..62062dcae1c2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -122,7 +122,7 @@ Coverage testing is generally meaningless for instrument drivers, as calls to `a
 
 - Write your new feature or fix. Be sure it doesn't break any existing tests, and please write tests that cover your feature as well, or if you are fixing a bug, write a test that would have failed before your fix. Our goal is 100% test coverage, and although we are not there, we should always strive to increase our coverage with each new feature. Please be aware also that 100% test coverage does NOT necessarily mean 100% logic coverage. If (as is often the case in Python) a single line of code can behave differently for different inputs, coverage in itself will not ensure that this is tested.
 
-- The standard test commands are listed above under [Running Tests](#running_tests). More notes on different test runners can be found in [TESTING.md].
+- The standard test commands are listed above under [Running Tests](#running_tests). More notes on different test runners can be found in [TESTING](TESTING.md).
 
 - Core tests live in [qcodes/tests](https://github.com/qdev-dk/Qcodes/tree/master/qcodes/tests) and instrument tests live in the same directories as the instrument drivers.
 

From 4cd5e6b5220c508f4a452f9aca5c09e0030d2d8e Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 22:49:03 +0200
Subject: [PATCH 074/169] Update TESTING.md

---
 TESTING.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/TESTING.md b/TESTING.md
index ef722a208118..83ad966ba7e9 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -1,6 +1,6 @@
 # Notes on test runners compatible with Qcodes
 
-There is now a test script [test.py] in the root directory that uses the standard `unittest` machinery to run all the core tests (does not include instrument drivers). It has been tested on Mac (terminal), and Windows (cmd, git bash, and PowerShell). It includes coverage testing, but will only print a coverage report if tests pass.
+There is now a test script [test.py](qcodes/test.py) in the qcodes directory that uses the standard `unittest` machinery to run all the core tests (does not include instrument drivers). It has been tested on Mac (terminal), and Windows (cmd, git bash, and PowerShell). It includes coverage testing, but will only print a coverage report if tests pass.
 
 The biggest difficulty with testing Qcodes is windows multiprocessing. The spawn method restricts execution in ways that are annoying for regular users (no class/function definitions in the notebook, no closures) but seem to be completely incompatible with some test runners (and/or coverage tracking)
 

From d7095622feb7cb02c4491f3b3dc6b3d1a4b35dbe Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 26 Apr 2016 22:56:33 +0200
Subject: [PATCH 075/169] remove deprecated parameter kwargs

---
 qcodes/instrument/parameter.py | 15 ---------------
 1 file changed, 15 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index ec6619ffa831..340d3cc9002d 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -337,10 +337,6 @@ class StandardParameter(Parameter):
     max_val_age: max time (in seconds) to trust a saved value from
         this parameter as the starting point of a sweep
 
-    sweep_step: DEPRECATED - use step instead
-    sweep_delay: DEPRECATED - use delay instead
-    max_sweep_delay: DEPRECATED - use max_delay instead
-
     docstring: documentation string for the __doc__ field of the object
         The __doc__ field of the instance is used by some help systems,
         but not all
@@ -349,18 +345,7 @@ def __init__(self, name, instrument=None,
                  get_cmd=None, async_get_cmd=None, get_parser=None,
                  set_cmd=None, async_set_cmd=None, set_parser=None,
                  delay=None, max_delay=None, step=None, max_val_age=3600,
-                 sweep_step=None, sweep_delay=None, max_sweep_delay=None,
                  vals=None, val_mapping=None, **kwargs):
-        # deprecated args - this block to be removed by june 1 2016 or before,
-        # as soon as people have had a chance to convert their WIP branches
-        # to the new arguments.
-        if step is None:
-            step = sweep_step
-        if delay is None:
-            delay = sweep_delay
-        if max_delay is None:
-            max_delay = max_sweep_delay
-
         # handle val_mapping before super init because it impacts
         # vals / validation in the base class
         if val_mapping:

From 9f76f6307701ee5e159c3abccb3fb54e390a580e Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 27 Apr 2016 11:05:04 +0200
Subject: [PATCH 076/169] fix loop running fg/bg and data_manager or not

---
 qcodes/data/data_set.py | 32 +++++++++++++++++++++++++++-----
 qcodes/loops.py         | 16 ++++++++++++----
 2 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 41b57a531553..8a605aa1601e 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -1,5 +1,6 @@
 from enum import Enum
 from datetime import datetime
+import time
 
 from .manager import get_data_manager, NoData
 from .format import GNUPlotFormat
@@ -44,7 +45,7 @@ def new_data(location=None, name=None, overwrite=False, io=None,
         location = location(io)
 
     if location and (not overwrite) and io.list(location):
-        raise FileExistsError
+        raise FileExistsError('"' + location + '" already has data')
 
     if data_manager is False:
         if mode != DataMode.LOCAL:
@@ -176,6 +177,11 @@ class DataSet(DelegateAttributes):
         The default (stored in class attribute DataSet.default_io) is
         DiskIO('.') which says the root data storage directory is the
         current working directory, ie where you started the notebook or python.
+
+    write_period: seconds (default 5) between saves to disk. This only applies
+        if mode=LOCAL, otherwise the DataManager handles this (and generally
+        writes more often because it's not tying up the main process to do so).
+        use None to disable writing from calls to self.store
     '''
 
     # ie data_array.arrays['vsd'] === data_array.vsd
@@ -186,7 +192,7 @@ class DataSet(DelegateAttributes):
     location_provider = TimestampLocation()
 
     def __init__(self, location=None, mode=DataMode.LOCAL, arrays=None,
-                 data_manager=None, formatter=None, io=None):
+                 data_manager=None, formatter=None, io=None, write_period=5):
         if location is False or isinstance(location, str):
             self.location = location
         else:
@@ -197,6 +203,9 @@ def __init__(self, location=None, mode=DataMode.LOCAL, arrays=None,
         self.formatter = formatter or self.default_formatter
         self.io = io or self.default_io
 
+        self.write_period = write_period
+        self.last_write = 0
+
         self.arrays = {}
         if arrays:
             self.action_id_map = self._clean_array_ids(arrays)
@@ -304,7 +313,11 @@ def sync(self):
         if not self.is_live_mode:
             # LOCAL DataSet - just read it in
             # TODO: compare timestamps to know if we need to read?
-            self.read()
+            try:
+                self.read()
+            except IOError:
+                # if no files exist, they probably haven't been created yet.
+                pass
             return False
             # TODO - for remote live plotting, maybe set some timestamp
             # threshold and call it static after it's been dormant a long time?
@@ -416,6 +429,10 @@ def store(self, loop_indices, ids_values):
         else:
             for array_id, value in ids_values.items():
                 self.arrays[array_id][loop_indices] = value
+            if (self.write_period is not None and
+                    time.time() > self.last_write + self.write_period):
+                self.write()
+                self.last_write = time.time()
 
     def read(self):
         '''
@@ -438,12 +455,17 @@ def write(self):
             return
         self.formatter.write(self)
 
-    def close(self):
+    def finalize(self):
         '''
-        Tell the DataServer that the measurement is done
+        Mark the DataSet as complete
         '''
         if self.mode == DataMode.PUSH_TO_SERVER:
             self.data_manager.ask('end_data')
+        elif self.mode == DataMode.LOCAL:
+            self.write()
+        else:
+            raise RuntimeError('This mode does not allow finalizing',
+                               self.mode)
 
     def plot(self, cut=None):
         pass  # TODO
diff --git a/qcodes/loops.py b/qcodes/loops.py
index 012f6b5b3212..f820125c3689 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -436,6 +436,8 @@ def run(self, background=True, use_threads=True, enqueue=False,
         formatter: knows how to read and write the file format
             default can be set in DataSet.default_formatter
         io: knows how to connect to the storage (disk vs cloud etc)
+        write_period: how often to save to storage during the loop.
+            default 5 sec, use None to write only at the end
 
 
         returns:
@@ -466,11 +468,17 @@ def run(self, background=True, use_threads=True, enqueue=False,
             p.start()
             self.process = p
 
+            # now that the data_set we created has been put in the loop
+            # process, this copy turns into a reader
+            # if you're not using a DataManager, it just stays local
+            # and sync() reads from disk
+            if self.data_set.mode == DataMode.PUSH_TO_SERVER:
+                self.data_set.mode = DataMode.PULL_FROM_SERVER
             self.data_set.sync()
-            self.data_set.mode = DataMode.PULL_FROM_SERVER
         else:
             self._run_wrapper()
-            self.data_set.read()
+            if self.data_set.mode != DataMode.LOCAL:
+                self.data_set.sync()
 
         if not quiet:
             print(repr(self.data_set))
@@ -513,8 +521,8 @@ def _run_wrapper(self, *args, **kwargs):
         try:
             self._run_loop(*args, **kwargs)
         finally:
-            if(hasattr(self, 'data_set') and hasattr(self.data_set, 'close')):
-                self.data_set.close()
+            if hasattr(self, 'data_set'):
+                self.data_set.finalize()
 
     def _run_loop(self, first_delay=0, action_indices=(),
                   loop_indices=(), current_values=(),

From 27c31e116fe93fc0e229a7ea405e3b4a4046f9b8 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 27 Apr 2016 11:43:30 +0200
Subject: [PATCH 077/169] test loops with fg/bg and data_manager or not

---
 qcodes/loops.py           |  4 ++++
 qcodes/tests/test_loop.py | 48 +++++++++++++++++++++++++++++++--------
 2 files changed, 43 insertions(+), 9 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index f820125c3689..b0668ffce4cf 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -476,6 +476,10 @@ def run(self, background=True, use_threads=True, enqueue=False,
                 self.data_set.mode = DataMode.PULL_FROM_SERVER
             self.data_set.sync()
         else:
+            if hasattr(self, 'process'):
+                # in case this ActiveLoop was run before in the background
+                del self.process
+
             self._run_wrapper()
             if self.data_set.mode != DataMode.LOCAL:
                 self.data_set.sync()
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index f4e27818db26..4e4b614a785e 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -34,36 +34,66 @@ def setUp(self):
         self.location2 = '_loop_test2_'
         self.io = DiskIO('.')
 
+        c1 = self.gates.chan1
+        self.loop = Loop(c1[1:5:1], 0.001).each(c1)
+
+        self.assertFalse(self.io.list(self.location))
+        self.assertFalse(self.io.list(self.location2))
+
     def tearDown(self):
         for instrument in [self.gates, self.source, self.meter]:
             instrument.close()
 
+        get_data_manager().close()
+        self.model.close()
+
         self.io.remove_all(self.location)
         self.io.remove_all(self.location2)
 
-    def test_instruments_in_loop(self):
+    def check_loop_data(self, data):
+        self.assertEqual(data.chan1.tolist(), [1, 2, 3, 4])
+        self.assertEqual(data.chan1_set.tolist(), [1, 2, 3, 4])
+
+        self.assertTrue(self.io.list(self.location))
+
+    def test_background_and_datamanager(self):
         # make sure that an unpicklable instrument can indeed run in a loop
-        self.assertFalse(self.io.list(self.location))
-        c1 = self.gates.chan1
-        loop = Loop(c1[1:5:1], 0.001).each(c1)
 
         # TODO: if we don't save the dataset (location=False) then we can't
         # sync it when we're done. Should fix that - for now that just means
         # you can only do in-memory loops if you set data_manager=False
         # TODO: this is the one place we don't do quiet=True - test that we
         # really print stuff?
-        data = loop.run(location=self.location)
+        data = self.loop.run(location=self.location)
 
         # wait for process to finish (ensures that this was run in the bg,
         # because otherwise there *is* no loop.process)
-        loop.process.join()
+        self.loop.process.join()
 
         data.sync()
+        self.check_loop_data(data)
 
-        self.assertEqual(data.chan1.tolist(), [1, 2, 3, 4])
-        self.assertEqual(data.chan1_set.tolist(), [1, 2, 3, 4])
+    def test_background_no_datamanager(self):
+        data = self.loop.run(location=self.location, data_manager=False,
+                             quiet=True)
+        self.loop.process.join()
 
-        self.assertTrue(self.io.list(self.location))
+        data.sync()
+        self.check_loop_data(data)
+
+    def test_foreground_and_datamanager(self):
+        data = self.loop.run(location=self.location, background=False,
+                             quiet=True)
+        self.assertFalse(hasattr(self.loop, 'process'))
+
+        self.check_loop_data(data)
+
+    def test_foreground_no_datamanager(self):
+        data = self.loop.run(location=self.location, background=False,
+                             data_manager=False, quiet=True)
+        self.assertFalse(hasattr(self.loop, 'process'))
+
+        self.check_loop_data(data)
 
     def test_enqueue(self):
         c1 = self.gates.chan1

From 1dcafecc944c3b079fb89669bb7da78415e55e00 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 27 Apr 2016 12:15:11 +0200
Subject: [PATCH 078/169] test that data arrays are present but empty on return
 from bg loop

---
 qcodes/tests/test_loop.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 4e4b614a785e..2af44ecd0134 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -50,6 +50,11 @@ def tearDown(self):
         self.io.remove_all(self.location)
         self.io.remove_all(self.location2)
 
+    def check_empty_data(self, data):
+        expected = repr([float('nan')] * 4)
+        self.assertEqual(repr(data.chan1.tolist()), expected)
+        self.assertEqual(repr(data.chan1_set.tolist()), expected)
+
     def check_loop_data(self, data):
         self.assertEqual(data.chan1.tolist(), [1, 2, 3, 4])
         self.assertEqual(data.chan1_set.tolist(), [1, 2, 3, 4])
@@ -65,6 +70,7 @@ def test_background_and_datamanager(self):
         # TODO: this is the one place we don't do quiet=True - test that we
         # really print stuff?
         data = self.loop.run(location=self.location)
+        self.check_empty_data(data)
 
         # wait for process to finish (ensures that this was run in the bg,
         # because otherwise there *is* no loop.process)
@@ -76,6 +82,8 @@ def test_background_and_datamanager(self):
     def test_background_no_datamanager(self):
         data = self.loop.run(location=self.location, data_manager=False,
                              quiet=True)
+        self.check_empty_data(data)
+
         self.loop.process.join()
 
         data.sync()

From 94c1a820b684f307ec589a78709f5ff27d7b9553 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 27 Apr 2016 15:02:13 +0200
Subject: [PATCH 079/169] Update FAQ.md

---
 docs/FAQ.md | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/docs/FAQ.md b/docs/FAQ.md
index 803e5957c0db..62090016b6b0 100644
--- a/docs/FAQ.md
+++ b/docs/FAQ.md
@@ -9,6 +9,22 @@ This FAQ is intended for users for Qcodes. For development, see Github.
 ...
 ## Usage
 
+### What are the different ways to run Loops, and when would you use them?
+
+`Loop.run()` (or `ActiveLoop.run()`) has a two arguments that control where the loop runs and how the data is handled: `background` (`True` (default) or `False`) and `data_manager` (`None` (gets the default `DataManager`) or `False`).
+
+- Default usage: `Loop.run()`:
+  Involves two extra processes, one `` process that sequences the loop actions and a `` process that the `` feeds data to, then stores it to disk and provides it to other processes that want it. This is the normal way to run loops, because it minimizes the work done in the measurement process, so it runs as fast as possible, and also keeps the main process free for other tasks like live plotting and analysis.
+
+- Foreground with a DataManager: `Loop.run(background=False)`:
+  The measurement loop runs in the process that started it, rather than making a new process, so the starting process blocks until the loop is finished. You might do this to make debugging easier.
+
+- Background with no DataManager: `Loop.run(data_manager=False)`:
+  The measurement loop runs in the background, but does not start (or connect to, if one is started already) a `` process; instead, it holds and stores the data itself. If the main process wants to sync this data during acquisition, it will need to read it from disk. Not sure why you would use this mode, but it's possible.
+
+- Foreground with no DataManager: `Loop.run(background=False, data_manager=False)`:
+  No extra processes are involved; the measurement loop runs in the process that started it, and holds and saves the data itself. If you want to start another measurement loop while one is already running (for example if you have a complex parameter that runs its own measurement loop to determine some derived value), you need to use this mode. That's because only one background measurement is allowed at a time, and only one `DataSet` may be on the `` at a time. But this mode will still save the `DataSet` it makes; in most such complex parameter cases you want an even more stripped-down loop: `Loop.run_temp()` which just calls: `Loop.run(background=False, quiet=True, data_manager=False, location=False)` so it does not save anything, nor does it print the normal messages that `run` prints describing the `DataSet` it makes.
+
 ### How to abort a running measurement?
 
 Use `qc.halt_bg()`. To list the active measurements use `qc.active_children()`

From 03ddda8a7641e3a11d6129cb017fefcc77d785bd Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 27 Apr 2016 15:03:57 +0200
Subject: [PATCH 080/169] update run() comment on data_manager - it DOES store
 now.

---
 qcodes/loops.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index b0668ffce4cf..e4dabc831226 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -423,7 +423,7 @@ def run(self, background=True, use_threads=True, enqueue=False,
             finish? If false, will raise an error if another sweep is running
         quiet: (default False): set True to not print anything except errors
         data_manager: a DataManager instance (omit to use default,
-            False to store locally and not write to disk)
+            False to store locally)
 
         kwargs are passed along to data_set.new_data. The key ones are:
         location: the location of the DataSet, a string whose meaning

From bb59b0b81134892e7f3209d16c1dc85b1fb6393d Mon Sep 17 00:00:00 2001
From: Adriaan Rol 
Date: Wed, 27 Apr 2016 16:41:39 +0200
Subject: [PATCH 081/169] Make sure connection message is actually displayed

---
 qcodes/instrument/base.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index ba520873c8a0..c48228076f24 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -6,6 +6,7 @@
 from .parameter import StandardParameter
 from .function import Function
 from .remote import RemoteInstrument
+import logging
 
 
 class NoDefault:
@@ -93,8 +94,9 @@ def connect_message(self, param_name, begin_time=None):
         '''
         idn = self.get(param_name).replace(',', ', ').replace('\n', ' ')
 
-        return 'Connected to: {} in {:.2f}s'.format(
+        con_msg = 'Connected to: {} in {:.2f}s'.format(
             idn.strip(), time.time() - (begin_time or self._t0))
+        return con_msg
 
     def __repr__(self):
         return '<{}: {}>'.format(type(self).__name__, self.name)

From 73fbc82792422f92d5f8614e65a5846a28f749ff Mon Sep 17 00:00:00 2001
From: Adriaan Rol 
Date: Wed, 27 Apr 2016 16:41:56 +0200
Subject: [PATCH 082/169] Don't know why it split these commits

---
 qcodes/instrument/base.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/qcodes/instrument/base.py b/qcodes/instrument/base.py
index c48228076f24..e625e01e13ad 100644
--- a/qcodes/instrument/base.py
+++ b/qcodes/instrument/base.py
@@ -96,6 +96,7 @@ def connect_message(self, param_name, begin_time=None):
 
         con_msg = 'Connected to: {} in {:.2f}s'.format(
             idn.strip(), time.time() - (begin_time or self._t0))
+        print(con_msg)
         return con_msg
 
     def __repr__(self):

From bb7ce87266f0bf2c11132b7ceefa58a4e987574f Mon Sep 17 00:00:00 2001
From: Adriaan Rol 
Date: Wed, 27 Apr 2016 16:43:55 +0200
Subject: [PATCH 083/169] Add a warning when the not ready exception is caugth

---
 qcodes/instrument_drivers/tektronix/AWG5014.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index c34798932290..1093e57ad67a 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -1112,6 +1112,7 @@ def is_awg_ready(self):
         try:
             self.ask('*OPC?')
         except:  # makes the awg read again if there is a timeout
+            logging.warning('AWG is not ready')
             self.visa_handle.read()
         return True
 

From a1f760a68944ed734374d4cc01bb297a8adb78c6 Mon Sep 17 00:00:00 2001
From: CJvanDiepen 
Date: Thu, 28 Apr 2016 09:55:24 +0200
Subject: [PATCH 084/169] Adjust Pep8 in AWG driver

Indented commented out code in AWG driver such that it is still clear what the code is originally meant to do.
---
 qcodes/instrument_drivers/tektronix/AWG5014.py | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index 1bf922842a83..969192eae2b6 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -201,7 +201,7 @@ def __init__(self, name, setup_folder, address, reset=False,
                            get_cmd='TRIG:SLOP?',
                            set_cmd='TRIG:SLOP ' + '{}',
                            vals=vals.Enum('POS', 'NEG'))  # ,
-        # get_parser=self.parse_int_pos_neg)
+                           # get_parser=self.parse_int_pos_neg)
         self.add_parameter('trigger_source',
                            get_cmd='TRIG:source?',
                            set_cmd='TRIG:source ' + '{}',
@@ -242,10 +242,10 @@ def __init__(self, name, setup_folder, address, reset=False,
                            vals=vals.Ints(100, int(1e9)))
         self.add_parameter('setup_filename',
                            get_cmd='AWGC:SNAM?')
-        # set_cmd=self.do_set_setup_filename,
-        # vals=vals.Strings())
-        # set function has optional args and therefore
-        # does not work with QCodes
+                           # set_cmd=self.do_set_setup_filename,
+                           # vals=vals.Strings())
+                           # set function has optional args and therefore
+                           # does not work with QCodes
 
         # Channel parameters #
         for i in range(1, 5):

From 5984acf847a5cb83ebc10eecfba7e2d52ef8ed96 Mon Sep 17 00:00:00 2001
From: CJvanDiepen 
Date: Thu, 28 Apr 2016 10:48:50 +0200
Subject: [PATCH 085/169] Changes in `send_waveform_to_list`

---
 qcodes/instrument_drivers/tektronix/AWG5014.py | 10 +++-------
 1 file changed, 3 insertions(+), 7 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index 969192eae2b6..a6080c1f7404 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -1189,13 +1189,9 @@ def send_waveform_to_list(self, w, m1, m2, wfmname):
         dim = len(w)
 
         if (not((len(w) == len(m1)) and ((len(m1) == len(m2))))):
-            return 'error: sizes of the waveforms do not match'
-
-        self._values['files'][wfmname] = {}
-        self._values['files'][wfmname]['w'] = w
-        self._values['files'][wfmname]['m1'] = m1
-        self._values['files'][wfmname]['m2'] = m2
-        self._values['files'][wfmname]['numpoints'] = len(w)
+            raise 'error: sizes of the waveforms do not match'
+            
+        self._values['files'][wfmname] = self._file_dict(w, m1, m2, None)
 
         # if we create a waveform with the same name but different size, it will not get over written
         # Delete the possibly existing file (will do nothing if the file

From da399f1d8838511fe40388ae81c4a5a4581b94ee Mon Sep 17 00:00:00 2001
From: CJvanDiepen 
Date: Thu, 28 Apr 2016 10:53:05 +0200
Subject: [PATCH 086/169] Minor correction

Minor correction in `send_waveform_to_list`
---
 qcodes/instrument_drivers/tektronix/AWG5014.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index a6080c1f7404..3c1f1d8a31b2 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -1189,7 +1189,7 @@ def send_waveform_to_list(self, w, m1, m2, wfmname):
         dim = len(w)
 
         if (not((len(w) == len(m1)) and ((len(m1) == len(m2))))):
-            raise 'error: sizes of the waveforms do not match'
+            raise Exception('error: sizes of the waveforms do not match')
             
         self._values['files'][wfmname] = self._file_dict(w, m1, m2, None)
 

From 621b92e9ef1d984cdf4ab2a1990cf0c5b2bab71f Mon Sep 17 00:00:00 2001
From: Adriaan 
Date: Thu, 28 Apr 2016 11:57:10 +0200
Subject: [PATCH 087/169] Port of 520 ready for testing

---
 .../instrument_drivers/tektronix/AWG5014.py   |   6 +-
 qcodes/instrument_drivers/tektronix/AWG520.py | 668 ++++++++++++++++++
 2 files changed, 673 insertions(+), 1 deletion(-)
 create mode 100644 qcodes/instrument_drivers/tektronix/AWG520.py

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index c34798932290..781be5117591 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -47,7 +47,7 @@ class Tektronix_AWG5014(VisaInstrument):
 
     CHANGES:
     26-11-2008 by Gijs: Copied this plugin from the 520 and added support for
-        2 more channels, added setget marker delay functions and increased max
+        2 more channels, added set get marker delay functions and increased max
         sampling freq to 1.2 	GS/s
     28-11-2008 ''  '' : Added some functionality to manipulate and manoeuvre
         through the folders on the AWG
@@ -163,11 +163,13 @@ def __init__(self, name, setup_folder, address, reset=False,
                            vals=vals.Enum('CONT', 'TRIG', 'SEQ', 'GAT'))
         self.add_parameter('trigger_impedance',
                            label='Trigger impedance (Ohm)',
+                           units='Ohm',
                            get_cmd='TRIG:IMP?',
                            set_cmd='TRIG:IMP '+'{}',
                            vals=vals.Enum(50, 1000),
                            get_parser=float)
         self.add_parameter('trigger_level',
+                           units='V',
                            label='Trigger level (V)',
                            get_cmd='TRIG:LEV?',
                            set_cmd='TRIG:LEV '+'{:.3f}',
@@ -236,12 +238,14 @@ def __init__(self, name, setup_folder, address, reset=False,
                                vals=vals.Ints(0, 1))
             self.add_parameter('ch{}_amp'.format(i),
                                label='Amplitude channel {} (V)'.format(i),
+                               units='V',
                                get_cmd=amp_cmd + '?',
                                set_cmd=amp_cmd + ' {:.6f}',
                                vals=vals.Numbers(0.02, 1.5),
                                get_parser=float)
             self.add_parameter('ch{}_offset'.format(i),
                                label='Offset channel {} (V)'.format(i),
+                               units='V',
                                get_cmd=offset_cmd + '?',
                                set_cmd=offset_cmd + ' {:.3f}',
                                vals=vals.Numbers(-.1, .1),
diff --git a/qcodes/instrument_drivers/tektronix/AWG520.py b/qcodes/instrument_drivers/tektronix/AWG520.py
new file mode 100644
index 000000000000..9707d108f3de
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/AWG520.py
@@ -0,0 +1,668 @@
+# Tektronix_AWG520.py class, to perform the communication between the Wrapper and the device
+# Pieter de Groot , 2008
+# Martijn Schaafsma , 2008
+# Vishal Ranjan, 2012
+# Ron schutjens, 2012
+# Adriaan Rol, 2016 Ported to QCodes
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+import time
+import logging
+import numpy as np
+import struct
+from qcodes import VisaInstrument, validators as vals
+
+
+class Tektronix_AWG520(VisaInstrument):
+    '''
+    This is the python driver for the Tektronix AWG520
+    Arbitrary Waveform Generator
+
+    TODO:
+    1) Get All
+    2) Remove test_send??
+    3) Add docstrings
+
+    TODO: use inheritance for common use with 520, currently contains
+          a lot of repetition
+    '''
+
+    def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
+                 **kw):
+        '''
+        Initializes the AWG520.
+
+        Input:
+            name (string)    : name of the instrument
+            address (string) : GPIB address
+            reset (bool)     : resets to default values, default=false
+            numpoints (int)  : sets the number of datapoints
+
+        Output:
+            None
+        '''
+        super().__init__(name, address, **kw)
+
+        self._address = address
+        # self.visa_handle = visa.instrument(self._address)
+        self._values = {}
+        self._values['files'] = {}
+        self._clock = clock
+        self._numpoints = numpoints
+        self._fname = ''
+
+        self.add_parameter('IDN', get_cmd='*IDN?')
+        self.add_function('reset', call_cmd='*RST')
+
+        # Add parameters
+        self.add_parameter('trigger_mode',
+                           get_cmd='AWGC:RMOD?',
+                           set_cmd='AWGC:RMOD ' + '{}',
+                           vals=vals.Enum('CONT', 'TRIG', 'ENH', 'GAT'))
+                           # TODO: check if 520 supports SEQ
+        self.add_parameter('trigger_impedance',
+                           units='Ohm',
+                           label='Trigger impedance (Ohm)',
+                           get_cmd='TRIG:IMP?',
+                           set_cmd='TRIG:IMP '+'{}',
+                           vals=vals.Enum(50, 1000),
+                           get_parser=float)
+        self.add_parameter('trigger_level',
+                           units='V',
+                           label='Trigger level (V)',
+                           get_cmd='TRIG:LEV?',
+                           set_cmd='TRIG:LEV '+'{:.3f}',
+                           vals=vals.Numbers(-5, 5),
+                           get_parser=float)
+
+        self.add_parameter('clock_freq',
+                           label='Clock frequency (Hz)',
+                           get_cmd='SOUR:FREQ?',
+                           set_cmd='SOUR:FREQ '+'{}',
+                           vals=vals.Numbers(1e6, 1e9),
+                           get_parser=float)
+        # Todo check if max freq is 1.2 GHz for the AWG 520 aswell
+        self.add_parameter('numpoints',
+                           label='Number of datapoints per wave',
+                           get_cmd=self._do_get_numpoints,
+                           set_cmd=self._do_set_numpoints,
+                           vals=vals.Ints(100, int(1e9)))
+
+        for ch in [1, 2]:
+            amp_cmd = 'SOUR{}:VOLT:LEV:IMM:AMPL'.format(ch)
+            offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(ch)
+
+            self.add_parameter(
+                'ch{}_filename', set_cmd=self._gen_ch_set_func(
+                    self._do_set_filename, ch), vals=vals.Anything())
+            self.add_parameter('ch{}_amp'.format(ch),
+                               label='Amplitude channel {} (V)'.format(ch),
+                               units='V',
+                               get_cmd=amp_cmd + '?',
+                               set_cmd=amp_cmd + ' {:.6f}',
+                               vals=vals.Numbers(0.02, 1.5),
+                               get_parser=float)
+
+            self.add_parameter('ch{}_offset'.format(ch),
+                               label='Offset channel {} (V)'.format(ch),
+                               units='V',
+                               get_cmd=offset_cmd + '?',
+                               set_cmd=offset_cmd + ' {:.3f}',
+                               vals=vals.Numbers(-.1, .1),
+                               get_parser=float)
+            self.add_parameter('ch{}_status'.format(ch),
+                               get_cmd='OUTP{}?'.format(ch),
+                               set_cmd='OUTP{}'.format(ch) + ' {}',
+                               vals=vals.Enum('ON', 'OFF'),
+                               get_parser=float)
+
+            for j in [1, 2]:
+                # TODO: check that 520 does not have marker delay feature
+                # m_del_cmd = 'SOUR{}:MARK{}:DEL'.format(ch, j)
+                m_high_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:HIGH'.format(ch, j)
+                m_low_cmd = 'SOUR{}:MARK{}:VOLT:LEV:IMM:LOW'.format(ch, j)
+
+                self.add_parameter(
+                    'ch{}_m{}_high'.format(ch, j),
+                    label='Channel {} Marker {} high level (V)'.format(ch, j),
+                    get_cmd=m_high_cmd + '?',
+                    set_cmd=m_high_cmd + '{:.3f}',
+                    vals=vals.Numbers(-2., 2.),
+                    get_parser=float)
+                self.add_parameter(
+                    'ch{}_m{}_low'.format(ch, j),
+                    label='Channel {} Marker {} low level (V)'.format(ch, j),
+                    get_cmd=m_low_cmd + '?',
+                    set_cmd=m_low_cmd + '{:.3f}',
+                    vals=vals.Numbers(-2., 2.),
+                    get_parser=float)
+
+        # Add functions
+        self.add_function('reset')
+        self.add_function('get_all')
+        self.add_function('clear_waveforms')
+
+        if reset:
+            self.reset()
+        else:
+            self.get_all()
+
+    # Functions
+    def _gen_ch_set_func(self, fun, ch):
+        def set_func(val):
+            return fun(ch, val)
+        return set_func
+
+    def _gen_ch_get_func(self, fun, ch):
+        def get_func():
+            return fun(ch)
+        return get_func
+
+
+    # get state AWG
+    def get_state(self):
+        state = self.visa_handle.ask('AWGC:RSTATE?')
+        if state == '0':
+            return 'Idle'
+        elif state == '1':
+            return 'Waiting for trigger'
+        elif state == '2':
+            return 'Running'
+        else:
+            logging.error(__name__  + ' : AWG in undefined state')
+            return 'error'
+
+    def start(self):
+        self.visa_handle.write('AWGC:RUN')
+        return self.get_state()
+
+    def stop(self):
+        self.visa_handle.write('AWGC:STOP')
+
+
+
+    def get_folder_contents(self):
+        return self.visa_handle.ask('mmem:cat?')
+
+    def get_current_folder_name(self):
+        return self.visa_handle.ask('mmem:cdir?')
+
+    def set_current_folder_name(self,file_path):
+        self.visa_handle.write('mmem:cdir "%s"'%file_path)
+
+    def change_folder(self,dir):
+        self.visa_handle.write('mmem:cdir "%s"' %dir)
+
+    def goto_root(self):
+        self.visa_handle.write('mmem:cdir')
+
+    def make_directory(self, dir, root):
+        '''
+        makes a directory
+        if root = True, new dir in main folder
+        '''
+        if root:
+            self.goto_root()
+            self.visa_handle.write('MMEMory:MDIRectory "{}"'.format(dir))
+        else:
+            self.visa_handle.write('MMEMory:MDIRectory "{}"'.format(dir))
+
+    def get_all(self, update=True):
+        return self.snapshot(update=update)
+
+    def clear_waveforms(self):
+        '''
+        Clears the waveform on both channels.
+
+        Input:
+            None
+
+        Output:
+            None
+        '''
+        logging.debug(__name__ + ' : Clear waveforms from channels')
+        self.visa_handle.write('SOUR1:FUNC:USER ""')
+        self.visa_handle.write('SOUR2:FUNC:USER ""')
+
+
+    # Parameters
+
+    def force_trigger(self):
+        '''
+        forces a trigger event (used for wait_trigger option in sequences)
+
+        Ron
+        '''
+        return self.visa_handle.write('TRIG:SEQ:IMM')
+
+    def force_logicjump(self):
+        '''
+        forces a jumplogic event (used as a conditional event during waveform
+        executions)
+
+        note: jump_logic events&mode have to be set properly!
+
+        Ron
+        '''
+        return self.visa_handle.write('AWGC:EVEN:SEQ:IMM')
+
+
+    def set_jumpmode(self,mode):
+        '''
+        sets the jump mode for jump logic events, possibilities:
+        LOGic,TABle,SOFTware
+        give mode as string
+
+        note: jump_logic events&mode have to be set properly!
+
+        Ron
+        '''
+        return self.visa_handle.write('AWGC:ENH:SEQ:JMOD %s' %mode)
+
+    def get_jumpmode(self,mode):
+        '''
+        get the jump mode for jump logic events
+
+        Ron
+        '''
+        return self.visa_handle.ask('AWGC:ENH:SEQ:JMOD?')
+
+
+    def _do_get_numpoints(self):
+        '''
+        Returns the number of datapoints in each wave
+
+        Input:
+            None
+
+        Output:
+            numpoints (int) : Number of datapoints in each wave
+        '''
+        return self._numpoints
+
+    def _do_set_numpoints(self, numpts):
+        '''
+        Sets the number of datapoints in each wave.
+        This acts on both channels.
+
+        Input:
+            numpts (int) : The number of datapoints in each wave
+
+        Output:
+            None
+        '''
+        logging.debug(__name__ + ' : Trying to set numpoints to %s' %numpts)
+        if numpts != self._numpoints:
+            logging.warning(__name__ + ' : changing numpoints. This will clear all waveforms!')
+
+        response = 'yes'  # raw_input('type "yes" to continue')
+        if response is 'yes':
+            logging.debug(__name__ + ' : Setting numpoints to %s' %numpts)
+            self._numpoints = numpts
+            self.clear_waveforms()
+        else:
+            print('aborted')
+
+
+
+    def set_setup_filename(self, fname, force_reload=False):
+        if self._fname == fname and not force_reload:
+            print('File %s already loaded in AWG520' %fname)
+            return
+        else:
+            self._fname = fname
+            filename = "\%s/%s.seq" % (fname, fname)
+            self.set_sequence(filename=filename)
+            print('Waiting for AWG to load file "%s"' % fname)
+            sleeptime = 0.5
+            # while state idle is not possible due to timeout error while loading
+            t0 = time.time()
+            while(time.time()-t0 < 360):
+                try:
+                    if self.get_state() == 'Idle':
+                        break
+                except:
+                    time.sleep(sleeptime)
+                    print('.')
+            self.get_state()
+            print('Loading file took %.2fs' % (time.time()-t0))
+            return
+
+
+    def _do_set_filename(self, name, channel):
+        '''
+        Specifies which file has to be set on which channel
+        Make sure the file exists, and the numpoints and clock of the file
+        matches the instrument settings.
+
+        If file doesn't exist an error is raised, if the numpoints doesn't match
+        the command is neglected
+
+        Input:
+            name (string) : filename of uploaded file
+            channel (int) : 1 or 2, the number of the designated channel
+
+        Output:
+            None
+        '''
+        logging.debug(__name__ + ' : Try to set {} on channel {}'.format(
+                      name, channel))
+        exists = False
+        if name in self._values['files']:
+            exists = True
+            logging.debug(__name__ + ' : File exists in loacal memory')
+            self._values['recent_channel_%s' % channel] = self._values[
+                'files'][name]
+            self._values['recent_channel_%s' % channel]['filename'] = name
+        else:
+            logging.debug(__name__ + ' : File does not exist in memory, \
+            reading from instrument')
+            lijst = self.visa_handle.ask('MMEM:CAT? "MAIN"')
+            bool = False
+            bestand = ""
+            for i in range(len(lijst)):
+                if (lijst[i] =='"'):
+                    bool = True
+                elif (lijst[i] == ','):
+                    bool = False
+                    if (bestand == name):
+                        exists = True
+                    bestand = ""
+                elif bool:
+                    bestand = bestand + lijst[i]
+        if exists:
+            data = self.visa_handle.ask('MMEM:DATA? "%s"' %name)
+            logging.debug(__name__  + ' : File exists on instrument, loading \
+            into local memory')
+            # string alsvolgt opgebouwd: '#'   'MAGIC 1000\r\n' '#'  'CLOCK ' 
+            len1 = int(data[1])
+            len2 = int(data[2:2+len1])
+            i = len1
+            tekst = ""
+            while (tekst !='#'):
+                tekst = data[i]
+                i = i+1
+            len3 = int(data[i])
+            len4 = int(data[i+1:i+1+len3])
+
+            w = []
+            m1 = []
+            m2 = []
+
+            for q in range(i+1+len3, i+1+len3+len4, 5):
+                j = int(q)
+                c, d = struct.unpack('
Date: Thu, 28 Apr 2016 15:01:59 +0200
Subject: [PATCH 088/169] Tested driver and fixed bug in 5014

---
 .../instrument_drivers/tektronix/AWG5014.py   |  8 +--
 qcodes/instrument_drivers/tektronix/AWG520.py | 63 +++++++++----------
 2 files changed, 32 insertions(+), 39 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index 781be5117591..1d355fdc2d9c 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -129,7 +129,7 @@ def __init__(self, name, setup_folder, address, reset=False,
             name (string)           : name of the instrument
             setup_folder (string)   : folder where externally generate seqs
                                         are stored
-            address (string)        : GPIB address
+            address (string)        : GPIB or ethernet address
             reset (bool)            : resets to default values, default=false
             numpoints (int)         : sets the number of datapoints
 
@@ -260,21 +260,21 @@ def __init__(self, name, setup_folder, address, reset=False,
                     'ch{}_m{}_del'.format(i, j),
                     label='Channel {} Marker {} delay (ns)'.format(i, j),
                     get_cmd=m_del_cmd + '?',
-                    set_cmd=m_del_cmd + '{:.3f}e-9',
+                    set_cmd=m_del_cmd + ' {:.3f}e-9',
                     vals=vals.Numbers(0, 1),
                     get_parser=float)
                 self.add_parameter(
                     'ch{}_m{}_high'.format(i, j),
                     label='Channel {} Marker {} high level (V)'.format(i, j),
                     get_cmd=m_high_cmd + '?',
-                    set_cmd=m_high_cmd + '{:.3f}',
+                    set_cmd=m_high_cmd + ' {:.3f}',
                     vals=vals.Numbers(-2.7, 2.7),
                     get_parser=float)
                 self.add_parameter(
                     'ch{}_m{}_low'.format(i, j),
                     label='Channel {} Marker {} low level (V)'.format(i, j),
                     get_cmd=m_low_cmd + '?',
-                    set_cmd=m_low_cmd + '{:.3f}',
+                    set_cmd=m_low_cmd + ' {:.3f}',
                     vals=vals.Numbers(-2.7, 2.7),
                     get_parser=float)
 
diff --git a/qcodes/instrument_drivers/tektronix/AWG520.py b/qcodes/instrument_drivers/tektronix/AWG520.py
index 9707d108f3de..83d182c5fd6f 100644
--- a/qcodes/instrument_drivers/tektronix/AWG520.py
+++ b/qcodes/instrument_drivers/tektronix/AWG520.py
@@ -47,7 +47,8 @@ def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
 
         Input:
             name (string)    : name of the instrument
-            address (string) : GPIB address
+            address (string) : GPIB address (Note: 520 cannot be controlled
+                               via ethernet)
             reset (bool)     : resets to default values, default=false
             numpoints (int)  : sets the number of datapoints
 
@@ -57,7 +58,6 @@ def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
         super().__init__(name, address, **kw)
 
         self._address = address
-        # self.visa_handle = visa.instrument(self._address)
         self._values = {}
         self._values['files'] = {}
         self._clock = clock
@@ -66,13 +66,14 @@ def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
 
         self.add_parameter('IDN', get_cmd='*IDN?')
         self.add_function('reset', call_cmd='*RST')
+        self.add_parameter('state',
+                           get_cmd=self.get_state)
 
         # Add parameters
         self.add_parameter('trigger_mode',
                            get_cmd='AWGC:RMOD?',
                            set_cmd='AWGC:RMOD ' + '{}',
                            vals=vals.Enum('CONT', 'TRIG', 'ENH', 'GAT'))
-                           # TODO: check if 520 supports SEQ
         self.add_parameter('trigger_impedance',
                            units='Ohm',
                            label='Trigger impedance (Ohm)',
@@ -106,7 +107,7 @@ def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
             offset_cmd = 'SOUR{}:VOLT:LEV:IMM:OFFS'.format(ch)
 
             self.add_parameter(
-                'ch{}_filename', set_cmd=self._gen_ch_set_func(
+                'ch{}_filename'.format(ch), set_cmd=self._gen_ch_set_func(
                     self._do_set_filename, ch), vals=vals.Anything())
             self.add_parameter('ch{}_amp'.format(ch),
                                label='Amplitude channel {} (V)'.format(ch),
@@ -139,26 +140,24 @@ def __init__(self, name, address, reset=False, clock=1e9, numpoints=1000,
                     'ch{}_m{}_high'.format(ch, j),
                     label='Channel {} Marker {} high level (V)'.format(ch, j),
                     get_cmd=m_high_cmd + '?',
-                    set_cmd=m_high_cmd + '{:.3f}',
+                    set_cmd=m_high_cmd + ' {:.3f}',
                     vals=vals.Numbers(-2., 2.),
                     get_parser=float)
                 self.add_parameter(
                     'ch{}_m{}_low'.format(ch, j),
                     label='Channel {} Marker {} low level (V)'.format(ch, j),
                     get_cmd=m_low_cmd + '?',
-                    set_cmd=m_low_cmd + '{:.3f}',
+                    set_cmd=m_low_cmd + ' {:.3f}',
                     vals=vals.Numbers(-2., 2.),
                     get_parser=float)
 
         # Add functions
-        self.add_function('reset')
-        self.add_function('get_all')
-        self.add_function('clear_waveforms')
-
         if reset:
             self.reset()
         else:
             self.get_all()
+        self.connect_message('IDN')
+
 
     # Functions
     def _gen_ch_set_func(self, fun, ch):
@@ -171,40 +170,37 @@ def get_func():
             return fun(ch)
         return get_func
 
-
     # get state AWG
     def get_state(self):
         state = self.visa_handle.ask('AWGC:RSTATE?')
-        if state == '0':
+        if state.startswith('0'):
             return 'Idle'
-        elif state == '1':
+        elif state.startswith('1'):
             return 'Waiting for trigger'
-        elif state == '2':
+        elif state.startswith('2'):
             return 'Running'
         else:
-            logging.error(__name__  + ' : AWG in undefined state')
+            logging.error(__name__ + ' : AWG in undefined state')
             return 'error'
 
     def start(self):
         self.visa_handle.write('AWGC:RUN')
-        return self.get_state()
+        return
 
     def stop(self):
         self.visa_handle.write('AWGC:STOP')
 
-
-
     def get_folder_contents(self):
         return self.visa_handle.ask('mmem:cat?')
 
     def get_current_folder_name(self):
         return self.visa_handle.ask('mmem:cdir?')
 
-    def set_current_folder_name(self,file_path):
-        self.visa_handle.write('mmem:cdir "%s"'%file_path)
+    def set_current_folder_name(self, file_path):
+        self.visa_handle.write('mmem:cdir "%s"' % file_path)
 
-    def change_folder(self,dir):
-        self.visa_handle.write('mmem:cdir "%s"' %dir)
+    def change_folder(self, dir):
+        self.visa_handle.write('mmem:cdir "%s"' % dir)
 
     def goto_root(self):
         self.visa_handle.write('mmem:cdir')
@@ -221,7 +217,10 @@ def make_directory(self, dir, root):
             self.visa_handle.write('MMEMory:MDIRectory "{}"'.format(dir))
 
     def get_all(self, update=True):
-        return self.snapshot(update=update)
+        # TODO: fix bug in snapshot where it tries to get setable only param
+        # return self.snapshot(update=update)
+
+        return self.snapshot(update=False)
 
     def clear_waveforms(self):
         '''
@@ -237,9 +236,6 @@ def clear_waveforms(self):
         self.visa_handle.write('SOUR1:FUNC:USER ""')
         self.visa_handle.write('SOUR2:FUNC:USER ""')
 
-
-    # Parameters
-
     def force_trigger(self):
         '''
         forces a trigger event (used for wait_trigger option in sequences)
@@ -259,8 +255,7 @@ def force_logicjump(self):
         '''
         return self.visa_handle.write('AWGC:EVEN:SEQ:IMM')
 
-
-    def set_jumpmode(self,mode):
+    def set_jumpmode(self, mode):
         '''
         sets the jump mode for jump logic events, possibilities:
         LOGic,TABle,SOFTware
@@ -270,9 +265,9 @@ def set_jumpmode(self,mode):
 
         Ron
         '''
-        return self.visa_handle.write('AWGC:ENH:SEQ:JMOD %s' %mode)
+        return self.visa_handle.write('AWGC:ENH:SEQ:JMOD %s' % mode)
 
-    def get_jumpmode(self,mode):
+    def get_jumpmode(self, mode):
         '''
         get the jump mode for jump logic events
 
@@ -280,7 +275,6 @@ def get_jumpmode(self,mode):
         '''
         return self.visa_handle.ask('AWGC:ENH:SEQ:JMOD?')
 
-
     def _do_get_numpoints(self):
         '''
         Returns the number of datapoints in each wave
@@ -304,13 +298,13 @@ def _do_set_numpoints(self, numpts):
         Output:
             None
         '''
-        logging.debug(__name__ + ' : Trying to set numpoints to %s' %numpts)
+        logging.debug(__name__ + ' : Trying to set numpoints to %s' % numpts)
         if numpts != self._numpoints:
             logging.warning(__name__ + ' : changing numpoints. This will clear all waveforms!')
 
         response = 'yes'  # raw_input('type "yes" to continue')
         if response is 'yes':
-            logging.debug(__name__ + ' : Setting numpoints to %s' %numpts)
+            logging.debug(__name__ + ' : Setting numpoints to %s' % numpts)
             self._numpoints = numpts
             self.clear_waveforms()
         else:
@@ -320,7 +314,7 @@ def _do_set_numpoints(self, numpts):
 
     def set_setup_filename(self, fname, force_reload=False):
         if self._fname == fname and not force_reload:
-            print('File %s already loaded in AWG520' %fname)
+            print('File %s already loaded in AWG520' % fname)
             return
         else:
             self._fname = fname
@@ -341,7 +335,6 @@ def set_setup_filename(self, fname, force_reload=False):
             print('Loading file took %.2fs' % (time.time()-t0))
             return
 
-
     def _do_set_filename(self, name, channel):
         '''
         Specifies which file has to be set on which channel

From 03ad96c1d8046b6d5754022ebaede8576b0d3c5b Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Thu, 28 Apr 2016 17:01:14 +0200
Subject: [PATCH 089/169] added basic check to IVVI driver

---
 qcodes/instrument_drivers/QuTech/IVVI.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
index 2c89b74b23f0..4238c7638be9 100644
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -78,6 +78,13 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
         self._update_time = 5  # seconds
         self._time_last_update = 0  # ensures first call will always update
         t1 = time.time()
+        
+        # basic test to confirm we are properly connected
+        try:
+            self.get_all()
+        except Exception as ex:
+            print('IVVI: get_all() failed, maybe connected to wrong port?')
+            
         print('Initialized IVVI-rack in %.2fs' % (t1-t0))
 
     def _get_version(self):
@@ -187,7 +194,7 @@ def _get_dacs(self):
                     self._mvoltages = self._bytes_to_mvoltages(reply)
                     self._time_last_update = time.time()
                     break
-                except:
+                except Exception as ex:
                     logging.warning('IVVI communication error trying again')
             if i+1 == max_tries:  # +1 because range goes stops before end
                 raise('IVVI Communication error')

From 294b13d0862c63c5c0e1311fe72ae34ddb8f561b Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Thu, 28 Apr 2016 22:38:17 +0200
Subject: [PATCH 090/169] Update LICENSE.md

---
 LICENSE.md | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/LICENSE.md b/LICENSE.md
index cf93541ce807..e38678b0de3a 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,6 +1,11 @@
 Copyright (c) 2015, 2016 by Microsoft Corporation and Københavns Universitet.
 
-QCoDeS is currently available only within the Microsoft Station Q collaboration or by specific arrangement.
+QCoDeS is currently available only within the Microsoft Station Q collaboration and by specific private arrangement with a beta test group. Please do not share it with anyone who is not part of the beta test program. If you have a coworker who would like access, please contact Alex Johnson (alex.johnson@nbi.ku.dk) to see if they can be added to the program.
+
+Please report all bugs, limitations, or missing functionality as issues on the Qcodes GitHub.
+
+We encourage you to contribute any bug fixes or new functionality you develop, especially device drivers, by creating a GitHub branch and submitting a pull request. Note that any code you contribute may be included in the public open source release of QCoDeS.
+
 We intend to release it as open source software once it is robust and reasonably stable, under the following license terms:
 
 > QCoDeS is available under the [MIT open-source license](https://opensource.org/licenses/MIT):

From 8988c67139fd6de8f38f33a0b27b9bb5dec05ab0 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 29 Apr 2016 10:51:45 +0200
Subject: [PATCH 091/169] added optional parameters to IVVI; added get_delay
 method to Instrument; print exception in constructor

---
 qcodes/instrument/parameter.py           |  4 ++++
 qcodes/instrument_drivers/QuTech/IVVI.py | 12 ++++++++----
 2 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 340d3cc9002d..d46f1fe70891 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -564,6 +564,10 @@ def set_step(self, step, max_val_age=None):
             self.set = self._validate_and_sweep
             self.set_async = self._validate_and_sweep_async
 
+    def get_delay(self):
+        ''' Return the delay time of this parameter. Also see `set_delay` '''
+        return self._delay
+
     def set_delay(self, delay, max_delay=None):
         '''
         Configure this parameter with a delay between set operations.
diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
index 4238c7638be9..a11d0024a57e 100644
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -26,7 +26,7 @@ class IVVI(VisaInstrument):
     Fullrange = 4000
     Halfrange = Fullrange / 2
 
-    def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
+    def __init__(self, name, address, reset=False, numdacs=16, dac_step=10, dac_delay = .1, dac_max_delay = 0.2, **kwargs):
                  # polarity=['BIP', 'BIP', 'BIP', 'BIP']):
                  # commented because still on the todo list
         '''
@@ -39,6 +39,9 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
             polarity (string[4]) : list of polarities of each set of 4 dacs
                                    choose from 'BIP', 'POS', 'NEG',
                                    default=['BIP', 'BIP', 'BIP', 'BIP']
+            dac_step (float)         : max step size for dac parameter
+            dac_delay (float)        : delay (in seconds) for dac
+            dac_max_delay (float)    : maximum delay before emitting a warning
         '''
         t0 = time.time()
         super().__init__(name, address, **kwargs)
@@ -70,9 +73,9 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
                 get_cmd=self._gen_ch_get_func(self._get_dac, i),
                 set_cmd=self._gen_ch_set_func(self._set_dac, i),
                 vals=vals.Numbers(-2000, 2000),
-                step=10,
-                delay=.1,
-                max_delay=.2,
+                step=dac_step,
+                delay=dac_delay,
+                max_delay=dac_max_delay,
                 max_val_age=10)
 
         self._update_time = 5  # seconds
@@ -84,6 +87,7 @@ def __init__(self, name, address, reset=False, numdacs=16, **kwargs):
             self.get_all()
         except Exception as ex:
             print('IVVI: get_all() failed, maybe connected to wrong port?')
+            print(ex)
             
         print('Initialized IVVI-rack in %.2fs' % (t1-t0))
 

From 7b3b7e18f8ffd067e7e1930845de92bdfe1956d0 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Fri, 29 Apr 2016 11:07:00 +0200
Subject: [PATCH 092/169] pep8 IVVI

---
 qcodes/instrument_drivers/QuTech/IVVI.py | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
index a11d0024a57e..a187a66fc6ea 100644
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -13,7 +13,8 @@ class IVVI(VisaInstrument):
             - Add individual parameters for channel polarities
             - Test polarities different from BIP
             - Add adjustable range and rate protection per channel
-            - Add error handling for the specific error messages in the protocol
+            - Add error handling for the specific error messages in the
+              protocol
             - Remove/fine-tune manual sleep statements
 
     This is the python driver for the D5 module of the IVVI-rack
@@ -26,7 +27,8 @@ class IVVI(VisaInstrument):
     Fullrange = 4000
     Halfrange = Fullrange / 2
 
-    def __init__(self, name, address, reset=False, numdacs=16, dac_step=10, dac_delay = .1, dac_max_delay = 0.2, **kwargs):
+    def __init__(self, name, address, reset=False, numdacs=16, dac_step=10,
+                 dac_delay=.1, dac_max_delay=0.2, **kwargs):
                  # polarity=['BIP', 'BIP', 'BIP', 'BIP']):
                  # commented because still on the todo list
         '''
@@ -81,14 +83,14 @@ def __init__(self, name, address, reset=False, numdacs=16, dac_step=10, dac_dela
         self._update_time = 5  # seconds
         self._time_last_update = 0  # ensures first call will always update
         t1 = time.time()
-        
+
         # basic test to confirm we are properly connected
         try:
             self.get_all()
         except Exception as ex:
             print('IVVI: get_all() failed, maybe connected to wrong port?')
             print(ex)
-            
+
         print('Initialized IVVI-rack in %.2fs' % (t1-t0))
 
     def _get_version(self):
@@ -106,7 +108,9 @@ def set_dacs_zero(self):
     # Conversion of data
     def _mvoltage_to_bytes(self, mvoltage):
         '''
-        Converts a mvoltage on a 0mV-4000mV scale to a 16-bit integer equivalent
+        Converts a mvoltage on a 0mV-4000mV scale to a 16-bit integer
+        equivalent
+
         output is a list of two bytes
 
         Input:

From cc725ef3c1134a41d0a6f7e0dcce2e64d86c46af Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 29 Apr 2016 11:15:15 +0200
Subject: [PATCH 093/169] use traceback for printing

---
 qcodes/instrument_drivers/QuTech/IVVI.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/qcodes/instrument_drivers/QuTech/IVVI.py b/qcodes/instrument_drivers/QuTech/IVVI.py
index a187a66fc6ea..03c435c68415 100644
--- a/qcodes/instrument_drivers/QuTech/IVVI.py
+++ b/qcodes/instrument_drivers/QuTech/IVVI.py
@@ -2,6 +2,7 @@
 import logging
 import numpy as np
 import visa  # used for the parity constant
+import traceback
 
 from qcodes import VisaInstrument, validators as vals
 
@@ -89,7 +90,7 @@ def __init__(self, name, address, reset=False, numdacs=16, dac_step=10,
             self.get_all()
         except Exception as ex:
             print('IVVI: get_all() failed, maybe connected to wrong port?')
-            print(ex)
+            print(traceback.format_exc())
 
         print('Initialized IVVI-rack in %.2fs' % (t1-t0))
 

From 6ddf4fab4ed93df4541bfb16c35d09f489cb5d95 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Fri, 29 Apr 2016 12:32:31 +0200
Subject: [PATCH 094/169] ''' -> """ in data/format.py

---
 qcodes/data/format.py | 40 ++++++++++++++++++++--------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index a88c9a184afc..226caf222e0d 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -8,7 +8,7 @@
 
 
 class Formatter:
-    '''
+    """
     Data file formatters
 
     Formatters translate between DataSets and data files.
@@ -32,15 +32,15 @@ class Formatter:
             - write will write ALL DataArrays in the DataSet, using
               last_saved_index and modified_range, as well as whether or not
               it found the specified file, to determine how much to write.
-    '''
+    """
     ArrayGroup = namedtuple('ArrayGroup', 'size set_arrays data name')
 
     def find_changes(self, arrays):
-        '''
+        """
         Collect changes made to any of these arrays and determine whether
         the WHOLE group is elligible for appending or not.
         Subclasses may choose to use or ignore this information.
-        '''
+        """
         new_data = {}
         can_append = True
 
@@ -55,26 +55,26 @@ def find_changes(self, arrays):
         return new_data, can_append
 
     def mark_saved(self, arrays):
-        '''
+        """
         Mark all DataArrays in this group as saved
-        '''
+        """
         for array in arrays.values():
             array.mark_saved()
 
     def write(self, data_set):
-        '''
+        """
         Write the DataSet to storage. It is up to the Formatter to decide
         when to overwrite completely, and when to just append or otherwise
         update the file(s).
-        '''
+        """
         raise NotImplementedError
 
     def read(self, data_set):
-        '''
+        """
         Read the entire DataSet by finding all files matching its location
         (using io_manager.list) and calling read_one_file from the Formatter
         subclass. Subclasses may alternatively override this entire method.
-        '''
+        """
         io_manager = data_set.io
         location = data_set.location
 
@@ -100,7 +100,7 @@ def read_one_file(self, data_set, f, ids_read):
         raise NotImplementedError
 
     def match_save_range(self, group, file_exists):
-        '''
+        """
         Find the save range that will capture all changes in an array group.
         matches all full-sized arrays: the data arrays plus the inner loop
         setpoint array
@@ -110,7 +110,7 @@ def match_save_range(self, group, file_exists):
 
         use the inner setpoint as a base and look for differences
         in last_saved_index and modified_range in the data arrays
-        '''
+        """
         inner_setpoint = group.set_arrays[-1]
         last_saved_index = (inner_setpoint.last_saved_index if file_exists
                             else None)
@@ -148,11 +148,11 @@ def match_save_range(self, group, file_exists):
         return last_saved_index, modified_range
 
     def group_arrays(self, arrays):
-        '''
+        """
         find the sets of arrays which share all the same setpoint arrays
         so each set can be grouped together into one file
         returns ArrayGroup namedtuples
-        '''
+        """
 
         set_array_sets = tuple(set(array.set_arrays
                                    for array in arrays.values()))
@@ -189,7 +189,7 @@ def group_arrays(self, arrays):
 
 
 class GNUPlotFormat(Formatter):
-    '''
+    """
     Saves data in one or more gnuplot-format files. We make one file for
     each set of matching dependent variables in the loop.
 
@@ -221,7 +221,7 @@ class GNUPlotFormat(Formatter):
     one blank line for each loop level that resets. (gnuplot *does* seem to
     use 2 blank lines sometimes, to denote a whole new dataset, which sort
     of corresponds to our situation.)
-    '''
+    """
     def __init__(self, extension='dat', terminator='\n', separator='\t',
                  comment='# ', number_format='g'):
         # file extension: accept either with or without leading dot
@@ -250,11 +250,11 @@ def __init__(self, extension='dat', terminator='\n', separator='\t',
         self.number_format = '{:' + number_format + '}'
 
     def read_one_file(self, data_set, f, ids_read):
-        '''
+        """
         Called by Formatter.read to bring one data file into
         a DataSet. Setpoint data may be duplicated across multiple files,
         but each measured DataArray must only map to one file.
-        '''
+        """
         arrays = data_set.arrays
         ids = self._read_comment_line(f).split()
         labels = self._get_labels(self._read_comment_line(f))
@@ -368,10 +368,10 @@ def _get_labels(self, labelstr):
             return [l.replace('\\"', '"').replace('\\\\', '\\') for l in parts]
 
     def write(self, data_set):
-        '''
+        """
         Write updates in this DataSet to storage. Will choose append if
         possible, overwrite if not.
-        '''
+        """
         io_manager = data_set.io
         location = data_set.location
         arrays = data_set.arrays

From 8c7d694adc9570fff34177786ea1274a0fcd5772 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Fri, 29 Apr 2016 12:48:30 +0200
Subject: [PATCH 095/169] GNUPlotFormat always_nest (default True) added

---
 qcodes/data/format.py | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 226caf222e0d..fdda772b8d26 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -193,6 +193,26 @@ class GNUPlotFormat(Formatter):
     Saves data in one or more gnuplot-format files. We make one file for
     each set of matching dependent variables in the loop.
 
+    options:
+
+    extension (default 'dat'): file extension for data files
+
+    terminator (default '\\n'): newline character(s) to use on write
+        not used for reading, we will read any combination of \\r and \\n
+
+    separator (default '\\t'): field (column) separator, must be whitespace.
+        Only used for writing, we will read with any whitespace separation.
+
+    comment (default '# '): lines starting with this are not data
+        Comments are written with this full string, and identified on read
+        by just the string after stripping whitespace.
+
+    number_format (default 'g'): from the format mini-language, how to
+        format numeric data into a string
+
+    always_nest (default True): whether to always make a folder for files
+        or just make a single data file if all data has the same setpoints
+
     These files are basically tab-separated values, but any quantity of
     any whitespace characters is accepted.
 
@@ -223,7 +243,7 @@ class GNUPlotFormat(Formatter):
     of corresponds to our situation.)
     """
     def __init__(self, extension='dat', terminator='\n', separator='\t',
-                 comment='# ', number_format='g'):
+                 comment='# ', number_format='g', always_nest=True):
         # file extension: accept either with or without leading dot
         self.extension = '.' + extension.lstrip('.')
 
@@ -249,6 +269,8 @@ def __init__(self, extension='dat', terminator='\n', separator='\t',
         # number format (only used for writing; will read any number)
         self.number_format = '{:' + number_format + '}'
 
+        self.always_nest = always_nest
+
     def read_one_file(self, data_set, f, ids_read):
         """
         Called by Formatter.read to bring one data file into
@@ -381,7 +403,7 @@ def write(self, data_set):
         written_files = set()
 
         for group in groups:
-            if len(groups) == 1:
+            if len(groups) == 1 and not self.always_nest:
                 fn = io_manager.join(location + self.extension)
             else:
                 fn = io_manager.join(location, group.name + self.extension)

From 12f55259b618ff62ec5aba93861d60f6066f8036 Mon Sep 17 00:00:00 2001
From: Adriaan Rol 
Date: Fri, 29 Apr 2016 16:23:18 +0200
Subject: [PATCH 096/169] Small bugfix for strings ending in \n

Bug caused some sequences not to have the correct AWG settings.
---
 qcodes/instrument_drivers/tektronix/AWG5014.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/AWG5014.py b/qcodes/instrument_drivers/tektronix/AWG5014.py
index 1d355fdc2d9c..63663671ebda 100644
--- a/qcodes/instrument_drivers/tektronix/AWG5014.py
+++ b/qcodes/instrument_drivers/tektronix/AWG5014.py
@@ -682,16 +682,16 @@ def generate_sequence_cfg(self):
             # External | Internal
             'TRIGGER_INPUT_IMPEDANCE': (1 if self.get('trigger_impedance') ==
                                         50. else 2),  # 50 ohm | 1 kohm
-            'TRIGGER_INPUT_SLOPE': (1 if self.get('trigger_slope') ==
-                                    'POS' else 2),  # Positive | Negative
-            'TRIGGER_INPUT_POLARITY': (1 if self.ask('TRIG:POL?') ==
-                                       'POS' else 2),  # Positive | Negative
+            'TRIGGER_INPUT_SLOPE': (1 if self.get('trigger_slope').startswith(
+                                    'POS') else 2),  # Positive | Negative
+            'TRIGGER_INPUT_POLARITY': (1 if self.ask('TRIG:POL?').startswith(
+                                       'POS') else 2),  # Positive | Negative
             'TRIGGER_INPUT_THRESHOLD':  self.get('trigger_level'),  # V
             'EVENT_INPUT_IMPEDANCE':   (1 if self.get('event_impedance') ==
                                         50. else 2),  # 50 ohm | 1 kohm
             'EVENT_INPUT_POLARITY':  (1 if
-                                      self.get('event_polarity').startswith('POS')
-                                      else 2),  # Positive | Negative
+                                      self.get('event_polarity').startswith(
+                                      'POS') else 2),  # Positive | Negative
             'EVENT_INPUT_THRESHOLD':   self.get('event_level'),  # V
             'JUMP_TIMING':   (1 if
                               self.get('event_jump_timing').startswith('SYNC')

From a9ffd0b749904080c148dc21e7f9bd2a6e4e9dfb Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sat, 30 Apr 2016 22:54:36 +0200
Subject: [PATCH 097/169] Stop Removing obsolete files

---
 qcodes/data/format.py | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index a88c9a184afc..673b1b37cf42 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -417,11 +417,7 @@ def write(self, data_set):
                     one_point = self._data_point(group, indices)
                     f.write(self.separator.join(one_point) + self.terminator)
 
-        extra_files = existing_files - written_files
-        if extra_files:
-            print('removing obsolete files: ' + ','.join(extra_files))
-            for fn in extra_files:
-                io_manager.remove(fn)
+        # tell gnuplot-loader only to use written_files
 
     def _make_header(self, group):
         ids, labels = [], []

From 4ecf38ada157eae210b52aa627ddc2c63c4bebef Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Sat, 30 Apr 2016 23:35:36 +0200
Subject: [PATCH 098/169] Fix the automatic reset of the colormap during
 _update_image

---
 qcodes/plots/pyqtgraph.py | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index 9be633a2b223..11d4f3cf3cb2 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -46,9 +46,9 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
         if remote:
             if not self.__class__.proc:
                 self._init_qt()
-        else:            
+        else:
             # overrule the remote pyqtgraph class
-            self.rpg = pg 
+            self.rpg = pg
         self.win = self.rpg.GraphicsWindow(title=windowTitle)
         self.win.setBackground(theme[1])
         self.win.resize(*figsize)
@@ -163,6 +163,7 @@ def _draw_image(self, subplot_object, z, x=None, y=None, cmap='hot',
         }
 
         self._update_image(plot_object, {'x': x, 'y': y, 'z': z})
+        self._update_cmap(plot_object)
 
         return plot_object
 
@@ -188,8 +189,6 @@ def _update_image(self, plot_object, config):
                 return
         z[np.where(np.isnan(z))] = z_range[0]
 
-        self._update_cmap(plot_object)
-
         hist_range = hist.getLevels()
         if hist_range == plot_object['histlevels']:
             plot_object['histlevels'] = z_range

From afbfe24447788ceb2caa07d7caee52da22af9e67 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sun, 1 May 2016 00:12:35 +0200
Subject: [PATCH 099/169] don't try to load files with wrong extension

---
 qcodes/data/format.py | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 673b1b37cf42..755613da7b11 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -255,6 +255,9 @@ def read_one_file(self, data_set, f, ids_read):
         a DataSet. Setpoint data may be duplicated across multiple files,
         but each measured DataArray must only map to one file.
         '''
+        if not f.name.endswith(self.extension):
+            return
+
         arrays = data_set.arrays
         ids = self._read_comment_line(f).split()
         labels = self._get_labels(self._read_comment_line(f))

From 4a75c1a36c596b4b83da5c98167aed16cea8fc15 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 09:42:09 +0200
Subject: [PATCH 100/169] GNUPlotFormat only writes full lines

---
 qcodes/data/data_array.py | 16 ++++++-----
 qcodes/data/format.py     | 57 +++++++++++++++++++++++++++++++--------
 qcodes/tests/test_data.py |  2 +-
 3 files changed, 57 insertions(+), 18 deletions(-)

diff --git a/qcodes/data/data_array.py b/qcodes/data/data_array.py
index 1cbfb32e6255..e825a9f1b39d 100644
--- a/qcodes/data/data_array.py
+++ b/qcodes/data/data_array.py
@@ -193,15 +193,19 @@ def _update_modified_range(self, low, high):
         else:
             self.modified_range = (low, high)
 
-    def mark_saved(self):
+    def mark_saved(self, last_saved_index):
         '''
-        after saving data, mark any outstanding modifications as saved
+        after saving data, mark outstanding modifications up to
+        last_saved_index as saved
         '''
         if self.modified_range:
-            self.last_saved_index = max(self.last_saved_index or 0,
-                                        self.modified_range[1])
-
-        self.modified_range = None
+            if last_saved_index >= self.modified_range[1]:
+                self.modified_range = None
+            else:
+                self.modified_range = (max(self.modified_range[0],
+                                           last_saved_index + 1),
+                                       self.modified_range[1])
+        self.last_saved_index = last_saved_index
 
     def clear_save(self):
         '''
diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index fdda772b8d26..42be758ce223 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -54,13 +54,6 @@ def find_changes(self, arrays):
 
         return new_data, can_append
 
-    def mark_saved(self, arrays):
-        """
-        Mark all DataArrays in this group as saved
-        """
-        for array in arrays.values():
-            array.mark_saved()
-
     def write(self, data_set):
         """
         Write the DataSet to storage. It is up to the Formatter to decide
@@ -99,7 +92,7 @@ def read(self, data_set):
     def read_one_file(self, data_set, f, ids_read):
         raise NotImplementedError
 
-    def match_save_range(self, group, file_exists):
+    def match_save_range(self, group, file_exists, only_complete=True):
         """
         Find the save range that will capture all changes in an array group.
         matches all full-sized arrays: the data arrays plus the inner loop
@@ -110,6 +103,9 @@ def match_save_range(self, group, file_exists):
 
         use the inner setpoint as a base and look for differences
         in last_saved_index and modified_range in the data arrays
+
+        if `only_complete` is True (default), will not mark any range to be
+        saved unless it contains no NaN values
         """
         inner_setpoint = group.set_arrays[-1]
         last_saved_index = (inner_setpoint.last_saved_index if file_exists
@@ -129,10 +125,17 @@ def match_save_range(self, group, file_exists):
                 else:
                     modified_range = amr
 
+        if only_complete and modified_range:
+            modified_range = self._get_completed_range(modified_range,
+                                                       inner_setpoint.shape,
+                                                       group.data)
+            if not modified_range:
+                return None
+
         # update all sources with the new matching values
-        for array in group.data + (inner_setpoint, ):
-            array.modified_range = modified_range
-            array.last_saved_index = last_saved_index
+        # for array in group.data + (inner_setpoint, ):
+        #     array.modified_range = modified_range
+        #     array.last_saved_index = last_saved_index
 
         # calculate the range to save
         if not modified_range:
@@ -147,6 +150,27 @@ def match_save_range(self, group, file_exists):
 
         return last_saved_index, modified_range
 
+    def _get_completed_range(self, modified_range, shape, arrays):
+        """
+        check the last data point to see if it's complete.
+
+        If it's not complete, back up one point so that we don't need
+        to rewrite this point later on when it *is* complete
+
+        This should work for regular `Loop` data that comes in sequentially.
+        But if you have non-sequential data, such as a parallel simulation,
+        then you would want to look farther back.
+        """
+        last_pt = modified_range[1]
+        indices = np.unravel_index(last_pt, shape)
+        for array in arrays:
+            if np.isnan(array[indices]):
+                if last_pt == modified_range[0]:
+                    return None
+                else:
+                    return (modified_range[0], last_pt - 1)
+        return modified_range
+
     def group_arrays(self, arrays):
         """
         find the sets of arrays which share all the same setpoint arrays
@@ -439,6 +463,17 @@ def write(self, data_set):
                     one_point = self._data_point(group, indices)
                     f.write(self.separator.join(one_point) + self.terminator)
 
+            # now that we've saved the data, mark it as such in the data.
+            # we mark the data arrays and the inner setpoint array. Outer
+            # setpoint arrays have different dimension (so would need a
+            # different unraveled index) but more importantly could have
+            # a different saved range anyway depending on whether there
+            # is outer data taken before or after the inner loop. Anyway we
+            # never look at the outer setpoint last_saved_index or
+            # modified_range, we just assume it's got the values we need.
+            for array in group.data + (group.set_arrays[-1],):
+                array.mark_saved(save_range[1])
+
         extra_files = existing_files - written_files
         if extra_files:
             print('removing obsolete files: ' + ','.join(extra_files))
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 672827450d39..1843696827d0 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -127,7 +127,7 @@ def test_edit_and_mark(self):
 
         self.assertEqual(data.modified_range, (0, 2))
 
-        data.mark_saved()
+        data.mark_saved(2)
         self.assertEqual(data.last_saved_index, 2)
         self.assertEqual(data.modified_range, None)
 

From 2c8dda2866a2489e25eb46b612f2287038d3f0fb Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 10:20:12 +0200
Subject: [PATCH 101/169] move GNUPlotFormat to its own file

---
 qcodes/__init__.py            |   3 +-
 qcodes/data/data_set.py       |   2 +-
 qcodes/data/format.py         | 300 ---------------------------------
 qcodes/data/gnuplot_format.py | 302 ++++++++++++++++++++++++++++++++++
 4 files changed, 305 insertions(+), 302 deletions(-)
 create mode 100644 qcodes/data/gnuplot_format.py

diff --git a/qcodes/__init__.py b/qcodes/__init__.py
index cc13fcf5f152..48129eb7c341 100644
--- a/qcodes/__init__.py
+++ b/qcodes/__init__.py
@@ -35,7 +35,8 @@
 from qcodes.data.manager import get_data_manager
 from qcodes.data.data_set import DataMode, DataSet, new_data, load_data
 from qcodes.data.data_array import DataArray
-from qcodes.data.format import Formatter, GNUPlotFormat
+from qcodes.data.format import Formatter
+from qcodes.data.gnuplot_format import GNUPlotFormat
 from qcodes.data.io import DiskIO
 
 from qcodes.instrument.base import Instrument
diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 8a605aa1601e..95899c79d3fd 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -3,7 +3,7 @@
 import time
 
 from .manager import get_data_manager, NoData
-from .format import GNUPlotFormat
+from .gnuplot_format import GNUPlotFormat
 from .io import DiskIO
 from qcodes.utils.helpers import DelegateAttributes
 
diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 42be758ce223..ffe278cdfd83 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -1,11 +1,7 @@
 from collections import namedtuple
 import numpy as np
-import re
-import math
 from traceback import format_exc
 
-from .data_array import DataArray
-
 
 class Formatter:
     """
@@ -210,299 +206,3 @@ def group_arrays(self, arrays):
                                        data=tuple(data),
                                        name=group_name))
         return out
-
-
-class GNUPlotFormat(Formatter):
-    """
-    Saves data in one or more gnuplot-format files. We make one file for
-    each set of matching dependent variables in the loop.
-
-    options:
-
-    extension (default 'dat'): file extension for data files
-
-    terminator (default '\\n'): newline character(s) to use on write
-        not used for reading, we will read any combination of \\r and \\n
-
-    separator (default '\\t'): field (column) separator, must be whitespace.
-        Only used for writing, we will read with any whitespace separation.
-
-    comment (default '# '): lines starting with this are not data
-        Comments are written with this full string, and identified on read
-        by just the string after stripping whitespace.
-
-    number_format (default 'g'): from the format mini-language, how to
-        format numeric data into a string
-
-    always_nest (default True): whether to always make a folder for files
-        or just make a single data file if all data has the same setpoints
-
-    These files are basically tab-separated values, but any quantity of
-    any whitespace characters is accepted.
-
-    Each row represents one setting of the setpoint variable(s)
-    the setpoint variable(s) are in the first column(s)
-    measured variable(s) come after.
-
-    The data is preceded by comment lines (starting with #).
-    We use three:
-    - one for the variable name
-    - the (longer) axis label, in quotes so a label can contain whitespace.
-    - for each dependent var, the (max) number of points in that dimension
-        (this also tells us how many dependent vars we have in this file)
-
-    # id1\tid2\t\id3...
-    # "label1"\t"label2"\t"label3"...
-    # 100\t250
-    1\t2\t3...
-    2\t3\t4...
-
-    For data of 2 dependent variables, gnuplot puts each inner loop into one
-    block, then increments the outer loop in the next block, separated by a
-    blank line.
-
-    We extend this to an arbitrary quantity of dependent variables by using
-    one blank line for each loop level that resets. (gnuplot *does* seem to
-    use 2 blank lines sometimes, to denote a whole new dataset, which sort
-    of corresponds to our situation.)
-    """
-    def __init__(self, extension='dat', terminator='\n', separator='\t',
-                 comment='# ', number_format='g', always_nest=True):
-        # file extension: accept either with or without leading dot
-        self.extension = '.' + extension.lstrip('.')
-
-        # line terminator (only used for writing; will read any \r\n combo)
-        if terminator not in ('\r', '\n', '\r\n'):
-            raise ValueError(
-                r'GNUPlotFormat terminator must be \r, \n, or \r\n')
-        self.terminator = terminator
-
-        # field separator (only used for writing; will read any whitespace)
-        if not re.fullmatch(r'\s+', separator):
-            raise ValueError('GNUPlotFormat separator must be whitespace')
-        self.separator = separator
-
-        # beginning of a comment line. (when reading, just checks the
-        # non-whitespace character(s) of comment
-        self.comment = comment
-        self.comment_chars = comment.rstrip()
-        if not self.comment_chars:
-            raise ValueError('comment must have some non-whitespace')
-        self.comment_len = len(self.comment_chars)
-
-        # number format (only used for writing; will read any number)
-        self.number_format = '{:' + number_format + '}'
-
-        self.always_nest = always_nest
-
-    def read_one_file(self, data_set, f, ids_read):
-        """
-        Called by Formatter.read to bring one data file into
-        a DataSet. Setpoint data may be duplicated across multiple files,
-        but each measured DataArray must only map to one file.
-        """
-        arrays = data_set.arrays
-        ids = self._read_comment_line(f).split()
-        labels = self._get_labels(self._read_comment_line(f))
-        size = tuple(map(int, self._read_comment_line(f).split()))
-        ndim = len(size)
-
-        set_arrays = ()
-        data_arrays = []
-        indexed_ids = list(enumerate(ids))
-
-        for i, array_id in indexed_ids[:ndim]:
-            # setpoint arrays
-            set_size = size[: i + 1]
-            if array_id in arrays:
-                set_array = arrays[array_id]
-                if set_array.size != set_size:
-                    raise ValueError(
-                        'sizes do not match for set array: ' + array_id)
-                if array_id not in ids_read:
-                    # it's OK for setpoints to be duplicated across
-                    # multiple files, but we should only empty the
-                    # array out the first time we see it, so subsequent
-                    # reads can check for consistency
-                    set_array.clear()
-            else:
-                set_array = DataArray(label=labels[i], array_id=array_id,
-                                      set_arrays=set_arrays, size=set_size)
-                set_array.init_data()
-                data_set.add_array(set_array)
-
-            set_arrays = set_arrays + (set_array, )
-            ids_read.add(array_id)
-
-        for i, array_id in indexed_ids[ndim:]:
-            # data arrays
-            if array_id in ids_read:
-                raise ValueError('duplicate data id found: ' + array_id)
-
-            if array_id in arrays:
-                data_array = arrays[array_id]
-                data_array.clear()
-            else:
-                data_array = DataArray(label=labels[i], array_id=array_id,
-                                       set_arrays=set_arrays, size=size)
-                data_array.init_data()
-                data_set.add_array(data_array)
-            data_arrays.append(data_array)
-            ids_read.add(array_id)
-
-        indices = [0] * ndim
-        first_point = True
-        resetting = 0
-        for line in f:
-            if self._is_comment(line):
-                continue
-
-            # ignore leading or trailing whitespace (including in blank lines)
-            line = line.strip()
-
-            if not line:
-                # each consecutive blank line implies one more loop to reset
-                # when we read the next data point. Don't depend on the number
-                # of setpoints that change, as there could be weird cases, like
-                # bidirectional sweeps, or highly diagonal sweeps, where this
-                # is incorrect. Anyway this really only matters for >2D sweeps.
-                if not first_point:
-                    resetting += 1
-                continue
-
-            values = tuple(map(float, line.split()))
-
-            if resetting:
-                indices[-resetting - 1] += 1
-                indices[-resetting:] = [0] * resetting
-                resetting = 0
-
-            for value, set_array in zip(values[:ndim], set_arrays):
-                nparray = set_array.ndarray
-                myindices = tuple(indices[:nparray.ndim])
-                stored_value = nparray[myindices]
-                if math.isnan(stored_value):
-                    nparray[myindices] = value
-                elif stored_value != value:
-                    raise ValueError('inconsistent setpoint values',
-                                     stored_value, value, set_array.name,
-                                     myindices, indices)
-
-            for value, data_array in zip(values[ndim:], data_arrays):
-                data_array.ndarray[tuple(indices)] = value
-
-            indices[-1] += 1
-            first_point = False
-
-    def _is_comment(self, line):
-        return line[:self.comment_len] == self.comment_chars
-
-    def _read_comment_line(self, f):
-        s = f.readline()
-        if not self._is_comment(s):
-            raise ValueError('expected a comment line, found:\n' + s)
-        return s[self.comment_len:]
-
-    def _get_labels(self, labelstr):
-        labelstr = labelstr.strip()
-        if labelstr[0] != '"' or labelstr[-1] != '"':
-            # fields are *not* quoted
-            return labelstr.split()
-        else:
-            # fields *are* quoted (and escaped)
-            parts = re.split('"\s+"', labelstr[1:-1])
-            return [l.replace('\\"', '"').replace('\\\\', '\\') for l in parts]
-
-    def write(self, data_set):
-        """
-        Write updates in this DataSet to storage. Will choose append if
-        possible, overwrite if not.
-        """
-        io_manager = data_set.io
-        location = data_set.location
-        arrays = data_set.arrays
-
-        groups = self.group_arrays(arrays)
-        existing_files = set(io_manager.list(location))
-        written_files = set()
-
-        for group in groups:
-            if len(groups) == 1 and not self.always_nest:
-                fn = io_manager.join(location + self.extension)
-            else:
-                fn = io_manager.join(location, group.name + self.extension)
-
-            written_files.add(fn)
-
-            file_exists = fn in existing_files
-            save_range = self.match_save_range(group, file_exists)
-
-            if save_range is None:
-                continue
-
-            overwrite = save_range[0] == 0
-            open_mode = 'w' if overwrite else 'a'
-            shape = group.set_arrays[-1].shape
-
-            with io_manager.open(fn, open_mode) as f:
-                if overwrite:
-                    f.write(self._make_header(group))
-
-                for i in range(save_range[0], save_range[1] + 1):
-                    indices = np.unravel_index(i, shape)
-
-                    # insert a blank line for each loop that reset (to index 0)
-                    # note that if *all* indices are zero (the first point)
-                    # we won't put any blanks
-                    for j, index in enumerate(reversed(indices)):
-                        if index != 0:
-                            if j:
-                                f.write(self.terminator * j)
-                            break
-
-                    one_point = self._data_point(group, indices)
-                    f.write(self.separator.join(one_point) + self.terminator)
-
-            # now that we've saved the data, mark it as such in the data.
-            # we mark the data arrays and the inner setpoint array. Outer
-            # setpoint arrays have different dimension (so would need a
-            # different unraveled index) but more importantly could have
-            # a different saved range anyway depending on whether there
-            # is outer data taken before or after the inner loop. Anyway we
-            # never look at the outer setpoint last_saved_index or
-            # modified_range, we just assume it's got the values we need.
-            for array in group.data + (group.set_arrays[-1],):
-                array.mark_saved(save_range[1])
-
-        extra_files = existing_files - written_files
-        if extra_files:
-            print('removing obsolete files: ' + ','.join(extra_files))
-            for fn in extra_files:
-                io_manager.remove(fn)
-
-    def _make_header(self, group):
-        ids, labels = [], []
-        for array in group.set_arrays + group.data:
-            ids.append(array.array_id)
-            label = getattr(array, 'label', array.array_id)
-            label = label.replace('\\', '\\\\').replace('"', '\\"')
-            labels.append('"' + label + '"')
-
-        sizes = [str(size) for size in group.set_arrays[-1].shape]
-        if len(sizes) != len(group.set_arrays):
-            raise ValueError('array dimensionality does not match setpoints')
-
-        out = (self._comment_line(ids) + self._comment_line(labels) +
-               self._comment_line(sizes))
-
-        return out
-
-    def _comment_line(self, items):
-        return self.comment + self.separator.join(items) + self.terminator
-
-    def _data_point(self, group, indices):
-        for array in group.set_arrays:
-            yield self.number_format.format(array[indices[:array.ndim]])
-
-        for array in group.data:
-            yield self.number_format.format(array[indices])
diff --git a/qcodes/data/gnuplot_format.py b/qcodes/data/gnuplot_format.py
new file mode 100644
index 000000000000..89e9e2e4e15f
--- /dev/null
+++ b/qcodes/data/gnuplot_format.py
@@ -0,0 +1,302 @@
+import numpy as np
+import re
+import math
+
+from .data_array import DataArray
+from .format import Formatter
+
+
+class GNUPlotFormat(Formatter):
+    """
+    Saves data in one or more gnuplot-format files. We make one file for
+    each set of matching dependent variables in the loop.
+
+    options:
+
+    extension (default 'dat'): file extension for data files
+
+    terminator (default '\\n'): newline character(s) to use on write
+        not used for reading, we will read any combination of \\r and \\n
+
+    separator (default '\\t'): field (column) separator, must be whitespace.
+        Only used for writing, we will read with any whitespace separation.
+
+    comment (default '# '): lines starting with this are not data
+        Comments are written with this full string, and identified on read
+        by just the string after stripping whitespace.
+
+    number_format (default 'g'): from the format mini-language, how to
+        format numeric data into a string
+
+    always_nest (default True): whether to always make a folder for files
+        or just make a single data file if all data has the same setpoints
+
+    These files are basically tab-separated values, but any quantity of
+    any whitespace characters is accepted.
+
+    Each row represents one setting of the setpoint variable(s)
+    the setpoint variable(s) are in the first column(s)
+    measured variable(s) come after.
+
+    The data is preceded by comment lines (starting with #).
+    We use three:
+    - one for the variable name
+    - the (longer) axis label, in quotes so a label can contain whitespace.
+    - for each dependent var, the (max) number of points in that dimension
+        (this also tells us how many dependent vars we have in this file)
+
+    # id1\tid2\t\id3...
+    # "label1"\t"label2"\t"label3"...
+    # 100\t250
+    1\t2\t3...
+    2\t3\t4...
+
+    For data of 2 dependent variables, gnuplot puts each inner loop into one
+    block, then increments the outer loop in the next block, separated by a
+    blank line.
+
+    We extend this to an arbitrary quantity of dependent variables by using
+    one blank line for each loop level that resets. (gnuplot *does* seem to
+    use 2 blank lines sometimes, to denote a whole new dataset, which sort
+    of corresponds to our situation.)
+    """
+    def __init__(self, extension='dat', terminator='\n', separator='\t',
+                 comment='# ', number_format='g', always_nest=True):
+        # file extension: accept either with or without leading dot
+        self.extension = '.' + extension.lstrip('.')
+
+        # line terminator (only used for writing; will read any \r\n combo)
+        if terminator not in ('\r', '\n', '\r\n'):
+            raise ValueError(
+                r'GNUPlotFormat terminator must be \r, \n, or \r\n')
+        self.terminator = terminator
+
+        # field separator (only used for writing; will read any whitespace)
+        if not re.fullmatch(r'\s+', separator):
+            raise ValueError('GNUPlotFormat separator must be whitespace')
+        self.separator = separator
+
+        # beginning of a comment line. (when reading, just checks the
+        # non-whitespace character(s) of comment
+        self.comment = comment
+        self.comment_chars = comment.rstrip()
+        if not self.comment_chars:
+            raise ValueError('comment must have some non-whitespace')
+        self.comment_len = len(self.comment_chars)
+
+        # number format (only used for writing; will read any number)
+        self.number_format = '{:' + number_format + '}'
+
+        self.always_nest = always_nest
+
+    def read_one_file(self, data_set, f, ids_read):
+        """
+        Called by Formatter.read to bring one data file into
+        a DataSet. Setpoint data may be duplicated across multiple files,
+        but each measured DataArray must only map to one file.
+        """
+        arrays = data_set.arrays
+        ids = self._read_comment_line(f).split()
+        labels = self._get_labels(self._read_comment_line(f))
+        size = tuple(map(int, self._read_comment_line(f).split()))
+        ndim = len(size)
+
+        set_arrays = ()
+        data_arrays = []
+        indexed_ids = list(enumerate(ids))
+
+        for i, array_id in indexed_ids[:ndim]:
+            # setpoint arrays
+            set_size = size[: i + 1]
+            if array_id in arrays:
+                set_array = arrays[array_id]
+                if set_array.size != set_size:
+                    raise ValueError(
+                        'sizes do not match for set array: ' + array_id)
+                if array_id not in ids_read:
+                    # it's OK for setpoints to be duplicated across
+                    # multiple files, but we should only empty the
+                    # array out the first time we see it, so subsequent
+                    # reads can check for consistency
+                    set_array.clear()
+            else:
+                set_array = DataArray(label=labels[i], array_id=array_id,
+                                      set_arrays=set_arrays, size=set_size)
+                set_array.init_data()
+                data_set.add_array(set_array)
+
+            set_arrays = set_arrays + (set_array, )
+            ids_read.add(array_id)
+
+        for i, array_id in indexed_ids[ndim:]:
+            # data arrays
+            if array_id in ids_read:
+                raise ValueError('duplicate data id found: ' + array_id)
+
+            if array_id in arrays:
+                data_array = arrays[array_id]
+                data_array.clear()
+            else:
+                data_array = DataArray(label=labels[i], array_id=array_id,
+                                       set_arrays=set_arrays, size=size)
+                data_array.init_data()
+                data_set.add_array(data_array)
+            data_arrays.append(data_array)
+            ids_read.add(array_id)
+
+        indices = [0] * ndim
+        first_point = True
+        resetting = 0
+        for line in f:
+            if self._is_comment(line):
+                continue
+
+            # ignore leading or trailing whitespace (including in blank lines)
+            line = line.strip()
+
+            if not line:
+                # each consecutive blank line implies one more loop to reset
+                # when we read the next data point. Don't depend on the number
+                # of setpoints that change, as there could be weird cases, like
+                # bidirectional sweeps, or highly diagonal sweeps, where this
+                # is incorrect. Anyway this really only matters for >2D sweeps.
+                if not first_point:
+                    resetting += 1
+                continue
+
+            values = tuple(map(float, line.split()))
+
+            if resetting:
+                indices[-resetting - 1] += 1
+                indices[-resetting:] = [0] * resetting
+                resetting = 0
+
+            for value, set_array in zip(values[:ndim], set_arrays):
+                nparray = set_array.ndarray
+                myindices = tuple(indices[:nparray.ndim])
+                stored_value = nparray[myindices]
+                if math.isnan(stored_value):
+                    nparray[myindices] = value
+                elif stored_value != value:
+                    raise ValueError('inconsistent setpoint values',
+                                     stored_value, value, set_array.name,
+                                     myindices, indices)
+
+            for value, data_array in zip(values[ndim:], data_arrays):
+                data_array.ndarray[tuple(indices)] = value
+
+            indices[-1] += 1
+            first_point = False
+
+    def _is_comment(self, line):
+        return line[:self.comment_len] == self.comment_chars
+
+    def _read_comment_line(self, f):
+        s = f.readline()
+        if not self._is_comment(s):
+            raise ValueError('expected a comment line, found:\n' + s)
+        return s[self.comment_len:]
+
+    def _get_labels(self, labelstr):
+        labelstr = labelstr.strip()
+        if labelstr[0] != '"' or labelstr[-1] != '"':
+            # fields are *not* quoted
+            return labelstr.split()
+        else:
+            # fields *are* quoted (and escaped)
+            parts = re.split('"\s+"', labelstr[1:-1])
+            return [l.replace('\\"', '"').replace('\\\\', '\\') for l in parts]
+
+    def write(self, data_set):
+        """
+        Write updates in this DataSet to storage. Will choose append if
+        possible, overwrite if not.
+        """
+        io_manager = data_set.io
+        location = data_set.location
+        arrays = data_set.arrays
+
+        groups = self.group_arrays(arrays)
+        existing_files = set(io_manager.list(location))
+        written_files = set()
+
+        for group in groups:
+            if len(groups) == 1 and not self.always_nest:
+                fn = io_manager.join(location + self.extension)
+            else:
+                fn = io_manager.join(location, group.name + self.extension)
+
+            written_files.add(fn)
+
+            file_exists = fn in existing_files
+            save_range = self.match_save_range(group, file_exists)
+
+            if save_range is None:
+                continue
+
+            overwrite = save_range[0] == 0
+            open_mode = 'w' if overwrite else 'a'
+            shape = group.set_arrays[-1].shape
+
+            with io_manager.open(fn, open_mode) as f:
+                if overwrite:
+                    f.write(self._make_header(group))
+
+                for i in range(save_range[0], save_range[1] + 1):
+                    indices = np.unravel_index(i, shape)
+
+                    # insert a blank line for each loop that reset (to index 0)
+                    # note that if *all* indices are zero (the first point)
+                    # we won't put any blanks
+                    for j, index in enumerate(reversed(indices)):
+                        if index != 0:
+                            if j:
+                                f.write(self.terminator * j)
+                            break
+
+                    one_point = self._data_point(group, indices)
+                    f.write(self.separator.join(one_point) + self.terminator)
+
+            # now that we've saved the data, mark it as such in the data.
+            # we mark the data arrays and the inner setpoint array. Outer
+            # setpoint arrays have different dimension (so would need a
+            # different unraveled index) but more importantly could have
+            # a different saved range anyway depending on whether there
+            # is outer data taken before or after the inner loop. Anyway we
+            # never look at the outer setpoint last_saved_index or
+            # modified_range, we just assume it's got the values we need.
+            for array in group.data + (group.set_arrays[-1],):
+                array.mark_saved(save_range[1])
+
+        extra_files = existing_files - written_files
+        if extra_files:
+            print('removing obsolete files: ' + ','.join(extra_files))
+            for fn in extra_files:
+                io_manager.remove(fn)
+
+    def _make_header(self, group):
+        ids, labels = [], []
+        for array in group.set_arrays + group.data:
+            ids.append(array.array_id)
+            label = getattr(array, 'label', array.array_id)
+            label = label.replace('\\', '\\\\').replace('"', '\\"')
+            labels.append('"' + label + '"')
+
+        sizes = [str(size) for size in group.set_arrays[-1].shape]
+        if len(sizes) != len(group.set_arrays):
+            raise ValueError('array dimensionality does not match setpoints')
+
+        out = (self._comment_line(ids) + self._comment_line(labels) +
+               self._comment_line(sizes))
+
+        return out
+
+    def _comment_line(self, items):
+        return self.comment + self.separator.join(items) + self.terminator
+
+    def _data_point(self, group, indices):
+        for array in group.set_arrays:
+            yield self.number_format.format(array[indices[:array.ndim]])
+
+        for array in group.data:
+            yield self.number_format.format(array[indices])

From 24f6ff092bafa04fe6e914197c579dcafb8f3b2c Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 10:27:59 +0200
Subject: [PATCH 102/169] sort arrays within group, so GNUPlotFormat is
 repeatable

---
 qcodes/data/format.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index ffe278cdfd83..155f9c1a0448 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -203,6 +203,6 @@ def group_arrays(self, arrays):
             group_name = '_'.join(sai.array_id for sai in set_arrays)
             out.append(self.ArrayGroup(size=set_arrays[-1].size,
                                        set_arrays=set_arrays,
-                                       data=tuple(data),
+                                       data=tuple(sorted(data)),
                                        name=group_name))
         return out

From 4f0c5d4f399912badeb3447ffc1771b5228d31be Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 10:32:42 +0200
Subject: [PATCH 103/169] remove DataSet.plot - we're not going to do it that
 way.

---
 qcodes/data/data_set.py | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 95899c79d3fd..7300155b342f 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -467,9 +467,6 @@ def finalize(self):
             raise RuntimeError('This mode does not allow finalizing',
                                self.mode)
 
-    def plot(self, cut=None):
-        pass  # TODO
-
     def __repr__(self):
         out = '{}: {}, location={}'.format(
             self.__class__.__name__, self.mode, repr(self.location))

From 4e9387a44a752d7dd359bd8c006101a6c719157d Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 10:45:42 +0200
Subject: [PATCH 104/169] test a new edge case of DataArray.mark_saved

---
 qcodes/tests/test_data.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 1843696827d0..6a99218f73df 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -127,6 +127,13 @@ def test_edit_and_mark(self):
 
         self.assertEqual(data.modified_range, (0, 2))
 
+        # as if we saved the first two points... the third should still
+        # show as modified
+        data.mark_saved(1)
+        self.assertEqual(data.last_saved_index, 1)
+        self.assertEqual(data.modified_range, (2, 2))
+
+        # now we save the third point... no modifications left.
         data.mark_saved(2)
         self.assertEqual(data.last_saved_index, 2)
         self.assertEqual(data.modified_range, None)

From 2931d5cd71da2d9b4e848f87c0afbe5cf014c05b Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 14:03:11 +0200
Subject: [PATCH 105/169] fix form and comments for non-default
 location_providers

---
 qcodes/data/data_set.py | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 7300155b342f..940729b90c16 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -42,7 +42,7 @@ def new_data(location=None, name=None, overwrite=False, io=None,
     if location is None:
         location = DataSet.location_provider(io, name)
     elif callable(location):
-        location = location(io)
+        location = location(io, name)
 
     if location and (not overwrite) and io.list(location):
         raise FileExistsError('"' + location + '" already has data')
@@ -111,14 +111,18 @@ def _get_live_data(data_manager):
 
 class TimestampLocation:
     '''
-    This is the default DataSet Location provider.
-    It provides a callable of one parameter (the io manager) that
-    returns a new location string, which is currently unused.
-    Uses `io.list(location)` to search for existing data at this location
-
-    Constructed with one parameter, a datetime.strftime format string,
-    which can include slashes (forward and backward are equivalent)
-    to create folder structure.
+    This is the default `DataSet.location_provider`.
+    A `location_provider` object should be a callable taking two parameters:
+    - an io manager `io` used to search for existing data using
+      `io.list(location)` so that the location returned is confirmed
+      to be unoccupied
+    - `name` - a string that should be incorporated somewhere into the
+      returned location.
+    returns a new, unoccupied location string
+
+    TimestampLocation is constructed with one parameter, a datetime.strftime
+    format string, which can include slashes (forward and backward are
+    equivalent) to create folder structure.
     Default format string is '%Y-%m-%d/%H-%M-%S'
     '''
     def __init__(self, fmt='%Y-%m-%d/%H-%M-%S'):

From 1ceefb57b9158ca204d27694d6f49867de35780d Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 14:40:08 +0200
Subject: [PATCH 106/169] correct sort key for arrays in GNUPlotFormat

---
 qcodes/data/format.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 155f9c1a0448..390d54f23c1f 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -1,6 +1,7 @@
 from collections import namedtuple
 import numpy as np
 from traceback import format_exc
+from operator import attrgetter
 
 
 class Formatter:
@@ -189,6 +190,7 @@ def group_arrays(self, arrays):
                 grouped_data[i].append(array)
 
         out = []
+        id_getter = attrgetter('array_id')
         for set_arrays, data in zip(set_array_sets, grouped_data):
             leni = len(set_arrays)
             if not data and any(1 for other_set_arrays in set_array_sets if
@@ -203,6 +205,9 @@ def group_arrays(self, arrays):
             group_name = '_'.join(sai.array_id for sai in set_arrays)
             out.append(self.ArrayGroup(size=set_arrays[-1].size,
                                        set_arrays=set_arrays,
-                                       data=tuple(sorted(data)),
+                                       data=tuple(sorted(data, key=id_getter)),
                                        name=group_name))
         return out
+
+    def array_sort_key(array):
+        array.array_id

From 43e033b7296b958d295c143c109e9f666c8f9792 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 17:15:51 +0200
Subject: [PATCH 107/169] test load_data (more), new_data, TimestampLocation

---
 qcodes/data/data_set.py   |   9 +--
 qcodes/tests/test_data.py | 138 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 141 insertions(+), 6 deletions(-)

diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 940729b90c16..b86720aeba92 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -96,8 +96,10 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
         return _get_live_data(data_manager)
 
     else:
-        return DataSet(location=location, formatter=formatter, io=io,
+        data = DataSet(location=location, formatter=formatter, io=io,
                        mode=DataMode.LOCAL)
+        data.read()
+        return data
 
 
 def _get_live_data(data_manager):
@@ -129,11 +131,12 @@ def __init__(self, fmt='%Y-%m-%d/%H-%M-%S'):
         self.fmt = fmt
 
     def __call__(self, io, name=None):
-        location = base_location = datetime.now().strftime(self.fmt)
+        location = datetime.now().strftime(self.fmt)
 
         if name:
             location += '_' + name
 
+        base_location = location
         for char in map(chr, range(ord('a'), ord('z') + 2)):
             if not io.list(location):
                 break
@@ -234,8 +237,6 @@ def _init_local(self):
         if self.arrays:
             for array in self.arrays.values():
                 array.init_data()
-        else:
-            self.read()
 
     def _init_push_to_server(self, data_manager):
         self.mode = DataMode.PUSH_TO_SERVER
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 6a99218f73df..13fd145d40f9 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -1,9 +1,12 @@
 from unittest import TestCase
+from unittest.mock import patch
 import numpy as np
+from datetime import datetime
 
 from qcodes.data.data_array import DataArray
-from qcodes.data.manager import get_data_manager
-from qcodes.data.data_set import load_data
+from qcodes.data.manager import get_data_manager, NoData
+from qcodes.data.data_set import (load_data, new_data, DataMode, DataSet,
+                                  TimestampLocation)
 from qcodes.utils.helpers import killprocesses
 from qcodes import active_children
 
@@ -211,6 +214,16 @@ def test_data_set_property(self):
         self.assertEqual(data.data_set, mock_data_set2)
 
 
+class MockDataManager:
+    def ask(self, *args, timeout=None):
+        if args == ('get_data', 'location'):
+            return self.location
+        elif args == ('get_data',):
+            return self.live_data
+        else:
+            raise Exception('unexpected query to MockDataManager')
+
+
 class TestLoadData(TestCase):
     def setUp(self):
         killprocesses()
@@ -235,3 +248,124 @@ def test_no_saved_data(self):
     def test_load_false(self):
         with self.assertRaises(ValueError):
             load_data(False)
+
+    def test_get_live(self):
+        loc = 'live from New York!'
+
+        class MockLive:
+            pass
+
+        live_data = MockLive()
+
+        dm = MockDataManager()
+        dm.location = loc
+        dm.live_data = live_data
+
+        data = load_data(data_manager=dm, location=loc)
+        self.assertEqual(data, live_data)
+
+        for nd in (None, NoData()):
+            dm.live_data = nd
+            with self.assertRaises(RuntimeError):
+                load_data(data_manager=dm, location=loc)
+            with self.assertRaises(RuntimeError):
+                load_data(data_manager=dm)
+
+    def test_get_read(self):
+        dm = MockDataManager()
+        dm.location = 'somewhere else'
+
+        class MyFormatter:
+            def read(self, data_set):
+                data_set.has_read_data = True
+
+        data = load_data(formatter=MyFormatter(), data_manager=dm,
+                         location='here!')
+        self.assertEqual(data.has_read_data, True)
+
+
+class FullIO:
+    def list(self, location):
+        return [location + '.whatever']
+
+
+class EmptyIO:
+    def list(self, location):
+        return []
+
+
+class MissingM:
+    def list(self, location):
+        if 'm' not in location:
+            return [location + '.whatever']
+        else:
+            return []
+
+
+class TestNewData(TestCase):
+    def setUp(self):
+        killprocesses()
+        self.original_lp = DataSet.location_provider
+
+    def tearDown(self):
+        DataSet.location_provider = self.original_lp
+
+    def test_overwrite(self):
+        io = FullIO()
+
+        with self.assertRaises(FileExistsError):
+            new_data(location='somewhere', io=io, data_manager=False)
+
+        data = new_data(location='somewhere', io=io, overwrite=True,
+                        data_manager=False)
+        self.assertEqual(data.location, 'somewhere')
+
+    def test_mode_error(self):
+        with self.assertRaises(ValueError):
+            new_data(mode=DataMode.PUSH_TO_SERVER, data_manager=False)
+
+    def test_location_functions(self):
+        def my_location(io, name):
+            return 'data/{}'.format(name or 'LOOP!')
+
+        def my_location2(io, name):
+            return 'data/{}/folder'.format(name or 'loop?')
+
+        DataSet.location_provider = my_location
+
+        self.assertEqual(new_data(data_manager=False).location, 'data/LOOP!')
+        self.assertEqual(new_data(data_manager=False, name='cheese').location,
+                         'data/cheese')
+
+        data = new_data(data_manager=False, location=my_location2)
+        self.assertEqual(data.location, 'data/loop?/folder')
+        data = new_data(data_manager=False, location=my_location2,
+                        name='iceCream')
+        self.assertEqual(data.location, 'data/iceCream/folder')
+
+
+class TestTimestampLocation(TestCase):
+    default_fmt = TimestampLocation().fmt
+    custom_fmt = 'DATA%Y/%B/%d/%I%p'
+
+    def check_cases(self, tsl, fmt):
+        self.assertEqual(tsl(EmptyIO()),
+                         datetime.now().strftime(fmt))
+        self.assertEqual(tsl(EmptyIO(), 'who?'),
+                         datetime.now().strftime(fmt) + '_who?')
+
+        self.assertEqual(tsl(MissingM()),
+                         datetime.now().strftime(fmt) + '_m')
+        self.assertEqual(tsl(MissingM(), 'you!'),
+                         datetime.now().strftime(fmt) + '_you!_m')
+
+        with self.assertRaises(FileExistsError):
+            tsl(FullIO())
+        with self.assertRaises(FileExistsError):
+            tsl(FullIO(), 'some_name')
+
+    def test_default(self):
+        self.check_cases(TimestampLocation(), self.default_fmt)
+
+    def test_fmt(self):
+        self.check_cases(TimestampLocation(self.custom_fmt), self.custom_fmt)

From 3671356cadecc04f0ca0905a8d6497285cc7eb92 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 22:16:02 +0200
Subject: [PATCH 108/169] finish testing DataSet

---
 qcodes/tests/test_data.py            | 132 ++++++++++++++++++++++++++-
 qcodes/tests/test_multiprocessing.py |   1 +
 2 files changed, 128 insertions(+), 5 deletions(-)

diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 13fd145d40f9..1ab08cb78543 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -2,6 +2,7 @@
 from unittest.mock import patch
 import numpy as np
 from datetime import datetime
+import multiprocessing as mp
 
 from qcodes.data.data_array import DataArray
 from qcodes.data.manager import get_data_manager, NoData
@@ -215,14 +216,35 @@ def test_data_set_property(self):
 
 
 class MockDataManager:
+    query_lock = mp.RLock()
+
+    def __init__(self):
+        self.needs_restart = False
+
     def ask(self, *args, timeout=None):
         if args == ('get_data', 'location'):
             return self.location
         elif args == ('get_data',):
             return self.live_data
+        elif args[0] == 'new_data' and len(args) == 2:
+            if self.needs_restart:
+                raise AttributeError('data_manager needs a restart')
+            else:
+                self.data_set = args[1]
         else:
             raise Exception('unexpected query to MockDataManager')
 
+    def restart(self):
+        self.needs_restart = False
+
+
+class MockFormatter:
+    def read(self, data_set):
+        data_set.has_read_data = True
+
+    def write(self, data_set):
+        data_set.has_written_data = True
+
 
 class TestLoadData(TestCase):
     def setUp(self):
@@ -275,11 +297,7 @@ def test_get_read(self):
         dm = MockDataManager()
         dm.location = 'somewhere else'
 
-        class MyFormatter:
-            def read(self, data_set):
-                data_set.has_read_data = True
-
-        data = load_data(formatter=MyFormatter(), data_manager=dm,
+        data = load_data(formatter=MockFormatter(), data_manager=dm,
                          location='here!')
         self.assertEqual(data.has_read_data, True)
 
@@ -369,3 +387,107 @@ def test_default(self):
 
     def test_fmt(self):
         self.check_cases(TimestampLocation(self.custom_fmt), self.custom_fmt)
+
+
+class MockLive:
+    arrays = 'whole lotta data'
+
+
+class TestDataSet(TestCase):
+    def tearDown(self):
+        killprocesses()
+
+    def test_constructor_errors(self):
+        # no location - only allowed with load_data
+        with self.assertRaises(ValueError):
+            DataSet()
+        # wrong type
+        with self.assertRaises(ValueError):
+            DataSet(location=42)
+
+        # OK to have location=False, but wrong mode
+        with self.assertRaises(ValueError):
+            DataSet(location=False, mode='happy')
+
+    @patch('qcodes.data.data_set.get_data_manager')
+    def test_from_server(self, gdm_mock):
+        mock_dm = MockDataManager()
+        gdm_mock.return_value = mock_dm
+        mock_dm.location = 'Mars'
+        mock_dm.live_data = MockLive()
+
+        # wrong location or False location - converts to local
+        data = DataSet(location='Jupiter', mode=DataMode.PULL_FROM_SERVER)
+        self.assertEqual(data.mode, DataMode.LOCAL)
+
+        data = DataSet(location=False, mode=DataMode.PULL_FROM_SERVER)
+        self.assertEqual(data.mode, DataMode.LOCAL)
+
+        # location matching server - stays in server mode
+        data = DataSet(location='Mars', mode=DataMode.PULL_FROM_SERVER,
+                       formatter=MockFormatter())
+        self.assertEqual(data.mode, DataMode.PULL_FROM_SERVER)
+        self.assertEqual(data.arrays, MockLive.arrays)
+
+        # cannot write except in LOCAL mode
+        with self.assertRaises(RuntimeError):
+            data.write()
+
+        # cannot finalize in PULL_FROM_SERVER mode
+        with self.assertRaises(RuntimeError):
+            data.finalize()
+
+        # now test when the server says it's not there anymore
+        mock_dm.location = 'Saturn'
+        data.sync()
+        self.assertEqual(data.mode, DataMode.LOCAL)
+        self.assertEqual(data.has_read_data, True)
+
+        # now it's LOCAL so we *can* write.
+        data.write()
+        self.assertEqual(data.has_written_data, True)
+
+        # location=False: write, read and sync are noops.
+        data.has_read_data = False
+        data.has_written_data = False
+        data.location = False
+        data.write()
+        data.read()
+        data.sync()
+        self.assertEqual(data.has_read_data, False)
+        self.assertEqual(data.has_written_data, False)
+
+    @patch('qcodes.data.data_set.get_data_manager')
+    def test_to_server(self, gdm_mock):
+        mock_dm = MockDataManager()
+        mock_dm.needs_restart = True
+        gdm_mock.return_value = mock_dm
+
+        data = DataSet(location='Venus', mode=DataMode.PUSH_TO_SERVER)
+        self.assertEqual(mock_dm.needs_restart, False, data)
+        self.assertEqual(mock_dm.data_set, data)
+        self.assertEqual(data.data_manager, mock_dm)
+        self.assertEqual(data.mode, DataMode.PUSH_TO_SERVER)
+
+        # cannot write except in LOCAL mode
+        with self.assertRaises(RuntimeError):
+            data.write()
+
+        # now do what the DataServer does with this DataSet: init_on_server
+        # fails until there is an array
+        with self.assertRaises(RuntimeError):
+            data.init_on_server()
+
+        class MockArray:
+            array_id = 'noise'
+
+            def init_data(self):
+                self.ready = True
+
+        data.add_array(MockArray())
+        data.init_on_server()
+        self.assertEqual(data.noise.ready, True)
+
+        # we can only add a given array_id once
+        with self.assertRaises(ValueError):
+            data.add_array(MockArray())
diff --git a/qcodes/tests/test_multiprocessing.py b/qcodes/tests/test_multiprocessing.py
index c6606e98c0dd..00cdff0ad177 100644
--- a/qcodes/tests/test_multiprocessing.py
+++ b/qcodes/tests/test_multiprocessing.py
@@ -200,6 +200,7 @@ def test_qcodes_process(self, in_nb_patch):
                     label + 'row row row your boat',
                     label + 'gently down '
                 ]
+                # TODO - intermittent error here
                 self.assertEqual(len(data), len(expected), data)
                 for line, expected_line in zip(data, expected):
                     self.assertIsNotNone(queue_format.match(line), data)

From 9ed2f7c7a1c29a681ec00ce1db727003f9fd62e0 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 22:54:18 +0200
Subject: [PATCH 109/169] get plot test skeleton working with test.py (on mac)

---
 qcodes/plots/base.py       |  7 ++++---
 qcodes/tests/test_plots.py | 25 ++++++++++++++++++-------
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 4080a3d29fa4..0b7830579346 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -23,9 +23,10 @@ def __init__(self, interval=1, data_keys='xyz'):
         self.traces = []
         self.data_updaters = set()
 
-        self.interval = interval
-        self.update_widget = HiddenUpdateWidget(self.update, interval)
-        display(self.update_widget)
+        if interval:
+            self.interval = interval
+            self.update_widget = HiddenUpdateWidget(self.update, interval)
+            display(self.update_widget)
 
     def add(self, *args, updater=None, **kwargs):
         '''
diff --git a/qcodes/tests/test_plots.py b/qcodes/tests/test_plots.py
index 76725b667c72..db66265d20fc 100644
--- a/qcodes/tests/test_plots.py
+++ b/qcodes/tests/test_plots.py
@@ -1,10 +1,20 @@
-from unittest import TestCase
-import numpy as np
-
-import qcodes 
-import matplotlib
+from unittest import TestCase, skipIf
 import matplotlib.pyplot as plt
 
+try:
+    from qcodes.plots.pyqtgraph import QtPlot
+    noQtPlot = False
+except Exception:
+    noQtPlot = True
+
+try:
+    from qcodes.plots.matplotlib import MatPlot
+    noMatPlot = False
+except Exception:
+    noMatPlot = True
+
+
+@skipIf(noQtPlot, '***pyqtgraph plotting cannot be tested***')
 class TestQtPlot(TestCase):
 
     def setUp(self):
@@ -15,9 +25,10 @@ def tearDown(self):
 
     def test_creation(self):
         ''' Simple test function which created a QtPlot window '''
-        plotQ = qcodes.QtPlot(remote=False, show=False)
+        plotQ = QtPlot(remote=False, interval=0)
 
 
+@skipIf(noQtPlot, '***matplotlib plotting cannot be tested***')
 class TestMatPlot(TestCase):
 
     def setUp(self):
@@ -28,5 +39,5 @@ def tearDown(self):
 
     def test_creation(self):
         ''' Simple test function which created a QtPlot window '''
-        plotM = qcodes.MatPlot()
+        plotM = MatPlot(interval=0)
         plt.close(plotM.fig)

From 56fba4269b1c6f4737b6f4908586b47fe9876c37 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 2 May 2016 22:57:11 +0200
Subject: [PATCH 110/169] move matplotlib import into MatPlot try block

---
 qcodes/tests/test_plots.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/qcodes/tests/test_plots.py b/qcodes/tests/test_plots.py
index db66265d20fc..a5c7864218f8 100644
--- a/qcodes/tests/test_plots.py
+++ b/qcodes/tests/test_plots.py
@@ -1,5 +1,4 @@
 from unittest import TestCase, skipIf
-import matplotlib.pyplot as plt
 
 try:
     from qcodes.plots.pyqtgraph import QtPlot
@@ -9,6 +8,7 @@
 
 try:
     from qcodes.plots.matplotlib import MatPlot
+    import matplotlib.pyplot as plt
     noMatPlot = False
 except Exception:
     noMatPlot = True

From 07e893bda344feb3552da45d04d842f4fb64bd58 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 3 May 2016 09:19:55 +0200
Subject: [PATCH 111/169] delete some unused methods in format.py

---
 qcodes/data/format.py       | 22 ----------------------
 qcodes/tests/test_format.py |  0
 2 files changed, 22 deletions(-)
 create mode 100644 qcodes/tests/test_format.py

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index 390d54f23c1f..b3dd03e672c5 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -32,25 +32,6 @@ class Formatter:
     """
     ArrayGroup = namedtuple('ArrayGroup', 'size set_arrays data name')
 
-    def find_changes(self, arrays):
-        """
-        Collect changes made to any of these arrays and determine whether
-        the WHOLE group is elligible for appending or not.
-        Subclasses may choose to use or ignore this information.
-        """
-        new_data = {}
-        can_append = True
-
-        for array in arrays.values():
-            if array.modified_range:
-                if array.modified_range[0] <= array.last_saved_index:
-                    can_append = False
-                    new_data[array.array_id] = 'overwrite'
-                else:
-                    new_data[array.array_id] = 'append'
-
-        return new_data, can_append
-
     def write(self, data_set):
         """
         Write the DataSet to storage. It is up to the Formatter to decide
@@ -208,6 +189,3 @@ def group_arrays(self, arrays):
                                        data=tuple(sorted(data, key=id_getter)),
                                        name=group_name))
         return out
-
-    def array_sort_key(array):
-        array.array_id
diff --git a/qcodes/tests/test_format.py b/qcodes/tests/test_format.py
new file mode 100644
index 000000000000..e69de29bb2d1

From 03ff6840cf9ea614061f710206757654f3d3938e Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 3 May 2016 11:37:17 +0200
Subject: [PATCH 112/169] add option to test.py

---
 qcodes/test.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/qcodes/test.py b/qcodes/test.py
index 18c8d9258f20..062ca5368212 100644
--- a/qcodes/test.py
+++ b/qcodes/test.py
@@ -41,6 +41,11 @@ def _test_core(**kwargs):
                         help=('increase verbosity. default 1, '
                               '-v is the same as -v 2'))
 
+    parser.add_argument('-c', '--coverage', nargs='?', dest='show_coverage',
+                        const=1, default=1, type=int,
+                        help=('show coverage. default is True '
+                              '-c is the same as -c 1'))
+
     parser.add_argument('-f', '--failfast', nargs='?', dest='failfast',
                         const=1, default=0, type=int,
                         help=('halt on first error/failure? default 0 '
@@ -56,5 +61,5 @@ def _test_core(**kwargs):
 
     cov.stop()
 
-    if success:
+    if success and args.show_coverage:
         cov.report()

From 664b5b5e4fae53e872b9ba534f403eddb1e4e736 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 3 May 2016 11:37:30 +0200
Subject: [PATCH 113/169] add option to hide window during creation

---
 qcodes/plots/pyqtgraph.py | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index 11d4f3cf3cb2..e35177d47f8a 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -38,7 +38,7 @@ class QtPlot(BasePlot):
     rpg = None
 
     def __init__(self, *args, figsize=(1000, 600), interval=0.25,
-                 windowTitle='', theme=((60, 60, 60), 'w'), remote=True, **kwargs):
+                 windowTitle='', theme=((60, 60, 60), 'w'), show_window=True, remote=True, **kwargs):
         super().__init__(interval)
 
         self.theme = theme
@@ -57,6 +57,9 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
         if args or kwargs:
             self.add(*args, **kwargs)
 
+        if not show_window:
+            self.win.hide()
+            
     def _init_qt(self):
         # starting the process for the pyqtgraph plotting
         # You do not want a new process to be created every time you start a

From ae0a389200b9dff96288407a1c2d291747f7f071 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 3 May 2016 11:38:19 +0200
Subject: [PATCH 114/169] fix bug in test_plots.py (noQtPlot->noMatPlot)

---
 qcodes/tests/test_plots.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/qcodes/tests/test_plots.py b/qcodes/tests/test_plots.py
index a5c7864218f8..ff4408dc26f9 100644
--- a/qcodes/tests/test_plots.py
+++ b/qcodes/tests/test_plots.py
@@ -25,10 +25,11 @@ def tearDown(self):
 
     def test_creation(self):
         ''' Simple test function which created a QtPlot window '''
-        plotQ = QtPlot(remote=False, interval=0)
+        plotQ = QtPlot(remote=False, show_window=False, interval=0)
+        _ = plotQ.add_subplot()
 
 
-@skipIf(noQtPlot, '***matplotlib plotting cannot be tested***')
+@skipIf(noMatPlot, '***matplotlib plotting cannot be tested***')
 class TestMatPlot(TestCase):
 
     def setUp(self):

From 98227aacbf22b58d65e0b2c276578b4adbd08a3b Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 3 May 2016 11:40:15 +0200
Subject: [PATCH 115/169] ignore temporary files in git

---
 .gitignore | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/.gitignore b/.gitignore
index c1ce888e2fb1..71abb8278ea5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,4 +64,9 @@ target/
 *.data
 *.dat
 *.hdf5
+
+# Temporary files
+*.md~
+tmp/
+
 docs/examples/data/*

From d5568a6fe75b20ccc616cc98e13186e23d92b886 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 3 May 2016 13:01:08 +0200
Subject: [PATCH 116/169] fix version string

---
 setup.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/setup.py b/setup.py
index 954abc05d78e..233a7c1bbfb1 100644
--- a/setup.py
+++ b/setup.py
@@ -3,7 +3,7 @@
 from importlib import import_module
 import re
 
-def get_version(verbose=0):
+def get_version(verbose=1):
     """ Extract version information from source code """
 
     try:
@@ -11,7 +11,7 @@ def get_version(verbose=0):
             ln = f.readline()
             # print(ln)
             m = re.search('.* ''(.*)''', ln)
-            version = (m.group(1))
+            version = (m.group(1)).strip('\'')
     except Exception as E:
         print(E)
         version = 'none'

From cc2e387ed2ab54af9d72af9147341c8ea9b49451 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 3 May 2016 16:40:27 +0200
Subject: [PATCH 117/169] test Formatter, start on GNUPlotFormat, and a little
 code cleanup

---
 qcodes/data/format.py         |  25 ++--
 qcodes/data/gnuplot_format.py |   7 ++
 qcodes/tests/data_mocks.py    | 102 +++++++++++++++++
 qcodes/tests/test_data.py     |  67 +----------
 qcodes/tests/test_format.py   | 210 ++++++++++++++++++++++++++++++++++
 5 files changed, 339 insertions(+), 72 deletions(-)
 create mode 100644 qcodes/tests/data_mocks.py

diff --git a/qcodes/data/format.py b/qcodes/data/format.py
index b3dd03e672c5..c8c6bcd53ff2 100644
--- a/qcodes/data/format.py
+++ b/qcodes/data/format.py
@@ -2,6 +2,7 @@
 import numpy as np
 from traceback import format_exc
 from operator import attrgetter
+import logging
 
 
 class Formatter:
@@ -55,7 +56,7 @@ def read(self, data_set):
 
         # in case the DataArrays exist but haven't been initialized
         for array in data_set.arrays.values():
-            if array.data is None:
+            if array.ndarray is None:
                 array.init_data()
 
         ids_read = set()
@@ -64,10 +65,21 @@ def read(self, data_set):
                 try:
                     self.read_one_file(data_set, f, ids_read)
                 except ValueError:
-                    print(format_exc())
-                    print('error reading file ' + fn)
+                    logging.warning('error reading file ' + fn)
+                    logging.warning(format_exc())
 
     def read_one_file(self, data_set, f, ids_read):
+        """
+        Formatter subclasses that handle multiple data files may choose to
+        override this method, which handles one file at a time.
+
+        data_set: the DataSet we are reading into
+        f: a file-like object to read from
+        ids_read: a `set` of array_ids that we have already read.
+            when you read an array, check that it's not in this set (except
+            setpoints, which can be in several files with different inner loop)
+            then add it to the set so other files know not to read it again
+        """
         raise NotImplementedError
 
     def match_save_range(self, group, file_exists, only_complete=True):
@@ -110,11 +122,6 @@ def match_save_range(self, group, file_exists, only_complete=True):
             if not modified_range:
                 return None
 
-        # update all sources with the new matching values
-        # for array in group.data + (inner_setpoint, ):
-        #     array.modified_range = modified_range
-        #     array.last_saved_index = last_saved_index
-
         # calculate the range to save
         if not modified_range:
             # nothing to save
@@ -126,8 +133,6 @@ def match_save_range(self, group, file_exists, only_complete=True):
             # we can append! save only from last save to end of mods
             return (last_saved_index + 1, modified_range[1])
 
-        return last_saved_index, modified_range
-
     def _get_completed_range(self, modified_range, shape, arrays):
         """
         check the last data point to see if it's complete.
diff --git a/qcodes/data/gnuplot_format.py b/qcodes/data/gnuplot_format.py
index 89e9e2e4e15f..23569831bf94 100644
--- a/qcodes/data/gnuplot_format.py
+++ b/qcodes/data/gnuplot_format.py
@@ -94,6 +94,13 @@ def read_one_file(self, data_set, f, ids_read):
         Called by Formatter.read to bring one data file into
         a DataSet. Setpoint data may be duplicated across multiple files,
         but each measured DataArray must only map to one file.
+
+        data_set: the DataSet we are reading into
+        f: a file-like object to read from
+        ids_read: a `set` of array_ids that we have already read.
+            when you read an array, check that it's not in this set (except
+            setpoints, which can be in several files with different inner loop)
+            then add it to the set so other files know not to read it again
         """
         arrays = data_set.arrays
         ids = self._read_comment_line(f).split()
diff --git a/qcodes/tests/data_mocks.py b/qcodes/tests/data_mocks.py
new file mode 100644
index 000000000000..d8328db3e625
--- /dev/null
+++ b/qcodes/tests/data_mocks.py
@@ -0,0 +1,102 @@
+import multiprocessing as mp
+
+from qcodes.data.data_array import DataArray
+from qcodes.data.data_set import new_data
+
+
+class MockDataManager:
+    query_lock = mp.RLock()
+
+    def __init__(self):
+        self.needs_restart = False
+
+    def ask(self, *args, timeout=None):
+        if args == ('get_data', 'location'):
+            return self.location
+        elif args == ('get_data',):
+            return self.live_data
+        elif args[0] == 'new_data' and len(args) == 2:
+            if self.needs_restart:
+                raise AttributeError('data_manager needs a restart')
+            else:
+                self.data_set = args[1]
+        else:
+            raise Exception('unexpected query to MockDataManager')
+
+    def restart(self):
+        self.needs_restart = False
+
+
+class MockFormatter:
+    def read(self, data_set):
+        data_set.has_read_data = True
+
+    def write(self, data_set):
+        data_set.has_written_data = True
+
+
+class FullIO:
+    def list(self, location):
+        return [location + '.whatever']
+
+
+class EmptyIO:
+    def list(self, location):
+        return []
+
+
+class MissingMIO:
+    def list(self, location):
+        if 'm' not in location:
+            return [location + '.whatever']
+        else:
+            return []
+
+
+class MockLive:
+    arrays = 'whole lotta data'
+
+
+class MockArray:
+    array_id = 'noise'
+
+    def init_data(self):
+        self.ready = True
+
+
+def DataSet1D(location=None):
+    # DataSet with one 1D array with 5 points
+    x = DataArray(name='x', label='X value', preset_data=(1., 2., 3., 4., 5.))
+    y = DataArray(name='y', label='Y value', preset_data=(3., 4., 5., 6., 7.),
+                  set_arrays=(x,))
+    return new_data(arrays=(x, y), location=location)
+
+
+def DataSet2D(location=None):
+    # DataSet with one 2D array, 2x3 points
+    x = DataArray(name='x', label='X', preset_data=(5., 6.))
+    y = DataArray(name='y', label='Y', preset_data=(7., 8., 9.))
+    y.nest(2, 0, x)
+    z = DataArray(name='z', label='Z',
+                  preset_data=((10., 11., 12.), (13., 14., 15.)),
+                  set_arrays=(x, y))
+    return new_data(arrays=(x, y, z), location=location)
+
+
+def DataSetCombined(location=None):
+    # Complex DataSet with two 1D and two 2D arrays
+    x = DataArray(name='x', label='X!', preset_data=(16., 17.))
+    y1 = DataArray(name='y1', label='Y1', preset_data=(18., 19.),
+                   set_arrays=(x,))
+    y2 = DataArray(name='y2', label='Y2', preset_data=(20., 21.),
+                   set_arrays=(x,))
+
+    yset = DataArray(name='yset', label='Y', preset_data=(22., 23., 24.))
+    yset.nest(2, 0, x)
+    z1 = DataArray(name='z1', label='Z1',
+                   preset_data=((25., 26., 27.), (28., 29., 30.)),
+                   set_arrays=(x, yset))
+    z2 = DataArray(name='z2', label='Z2',
+                   preset_data=((31., 32., 33.), (34., 35., 36.)),
+                   set_arrays=(x, yset))
+    return new_data(arrays=(x, y1, y2, yset, z1, z2), location=location)
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index 1ab08cb78543..f566572647dd 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -2,7 +2,6 @@
 from unittest.mock import patch
 import numpy as np
 from datetime import datetime
-import multiprocessing as mp
 
 from qcodes.data.data_array import DataArray
 from qcodes.data.manager import get_data_manager, NoData
@@ -11,6 +10,9 @@
 from qcodes.utils.helpers import killprocesses
 from qcodes import active_children
 
+from .data_mocks import (MockDataManager, MockFormatter, FullIO, EmptyIO,
+                         MissingMIO, MockLive, MockArray)
+
 
 class TestDataArray(TestCase):
     def test_attributes(self):
@@ -215,37 +217,6 @@ def test_data_set_property(self):
         self.assertEqual(data.data_set, mock_data_set2)
 
 
-class MockDataManager:
-    query_lock = mp.RLock()
-
-    def __init__(self):
-        self.needs_restart = False
-
-    def ask(self, *args, timeout=None):
-        if args == ('get_data', 'location'):
-            return self.location
-        elif args == ('get_data',):
-            return self.live_data
-        elif args[0] == 'new_data' and len(args) == 2:
-            if self.needs_restart:
-                raise AttributeError('data_manager needs a restart')
-            else:
-                self.data_set = args[1]
-        else:
-            raise Exception('unexpected query to MockDataManager')
-
-    def restart(self):
-        self.needs_restart = False
-
-
-class MockFormatter:
-    def read(self, data_set):
-        data_set.has_read_data = True
-
-    def write(self, data_set):
-        data_set.has_written_data = True
-
-
 class TestLoadData(TestCase):
     def setUp(self):
         killprocesses()
@@ -302,24 +273,6 @@ def test_get_read(self):
         self.assertEqual(data.has_read_data, True)
 
 
-class FullIO:
-    def list(self, location):
-        return [location + '.whatever']
-
-
-class EmptyIO:
-    def list(self, location):
-        return []
-
-
-class MissingM:
-    def list(self, location):
-        if 'm' not in location:
-            return [location + '.whatever']
-        else:
-            return []
-
-
 class TestNewData(TestCase):
     def setUp(self):
         killprocesses()
@@ -372,9 +325,9 @@ def check_cases(self, tsl, fmt):
         self.assertEqual(tsl(EmptyIO(), 'who?'),
                          datetime.now().strftime(fmt) + '_who?')
 
-        self.assertEqual(tsl(MissingM()),
+        self.assertEqual(tsl(MissingMIO()),
                          datetime.now().strftime(fmt) + '_m')
-        self.assertEqual(tsl(MissingM(), 'you!'),
+        self.assertEqual(tsl(MissingMIO(), 'you!'),
                          datetime.now().strftime(fmt) + '_you!_m')
 
         with self.assertRaises(FileExistsError):
@@ -389,10 +342,6 @@ def test_fmt(self):
         self.check_cases(TimestampLocation(self.custom_fmt), self.custom_fmt)
 
 
-class MockLive:
-    arrays = 'whole lotta data'
-
-
 class TestDataSet(TestCase):
     def tearDown(self):
         killprocesses()
@@ -478,12 +427,6 @@ def test_to_server(self, gdm_mock):
         with self.assertRaises(RuntimeError):
             data.init_on_server()
 
-        class MockArray:
-            array_id = 'noise'
-
-            def init_data(self):
-                self.ready = True
-
         data.add_array(MockArray())
         data.init_on_server()
         self.assertEqual(data.noise.ready, True)
diff --git a/qcodes/tests/test_format.py b/qcodes/tests/test_format.py
index e69de29bb2d1..cd7793cdb05d 100644
--- a/qcodes/tests/test_format.py
+++ b/qcodes/tests/test_format.py
@@ -0,0 +1,210 @@
+from unittest import TestCase
+import os
+
+from qcodes.data.format import Formatter
+from qcodes.data.gnuplot_format import GNUPlotFormat
+from qcodes.data.data_set import DataMode, DataSet
+from qcodes.utils.helpers import LogCapture
+
+from .data_mocks import DataSet1D, DataSet2D, DataSetCombined
+
+
+class TestBaseFormatter(TestCase):
+    def setUp(self):
+        self.io = DataSet.default_io
+        self.locations = ('_simple1d_', '_simple2d_', '_combined_')
+
+        for location in self.locations:
+            self.assertFalse(self.io.list(location))
+
+    def tearDown(self):
+        for location in self.locations:
+            self.io.remove_all(location)
+
+    def test_overridable_methods(self):
+        formatter = Formatter()
+        data = DataSet1D()
+
+        with self.assertRaises(NotImplementedError):
+            formatter.write(data)
+        with self.assertRaises(NotImplementedError):
+            formatter.read_one_file(data, 'a file!', set())
+
+    def test_no_files(self):
+        formatter = Formatter()
+        data = DataSet1D(self.locations[0])
+        with self.assertRaises(IOError):
+            formatter.read(data)
+
+    def test_init_and_bad_read(self):
+        location = self.locations[0]
+        path = './{}/bad.dat'.format(location)
+
+        class MyFormatter(Formatter):
+            def read_one_file(self, data_set, f, ids_read):
+                s = f.read()
+                if 'garbage' not in s:
+                    raise Exception('reading the wrong file?')
+
+                # mark this file as read, before generating an error
+                if not hasattr(data_set, 'files_read'):
+                    data_set.files_read = []
+                data_set.files_read.append(f.name)
+                raise ValueError('garbage in, garbage out')
+
+        formatter = MyFormatter()
+        data = DataSet1D(location)
+        data.x.ndarray = None
+        data.y.ndarray = None
+
+        os.makedirs(os.path.dirname(path), exist_ok=True)
+        with open(path, 'w') as f:
+            f.write('garbage')
+
+        with LogCapture() as s:
+            formatter.read(data)
+        logstr = s.getvalue()
+        s.close()
+        # we tried to read this file but it generated an error
+        self.assertEqual(logstr.count('error reading file'), 1, logstr)
+        self.assertEqual(data.files_read, [os.path.abspath(path)])
+
+        expected_array_repr = repr([float('nan')] * 5)
+        self.assertEqual(repr(data.x.tolist()), expected_array_repr)
+        self.assertEqual(repr(data.y.tolist()), expected_array_repr)
+
+    def test_group_arrays(self):
+        formatter = Formatter()
+        data = DataSetCombined()
+
+        groups = formatter.group_arrays(data.arrays)
+
+        self.assertEqual(len(groups), 2, groups)
+        groups.sort(key=lambda grp: len(grp.set_arrays))
+
+        g1d, g2d = groups
+
+        self.assertEqual(g1d.size, (2,))
+        self.assertEqual(g1d.set_arrays, (data.x,))
+        self.assertEqual(g1d.data, (data.y1, data.y2))
+        self.assertEqual(g1d.name, 'x')
+
+        self.assertEqual(g2d.size, (2, 3))
+        self.assertEqual(g2d.set_arrays, (data.x, data.yset))
+        self.assertEqual(g2d.data, (data.z1, data.z2))
+        self.assertEqual(g2d.name, 'x_yset')
+
+    def test_match_save_range(self):
+        formatter = Formatter()
+        data = DataSet1D()
+
+        group = formatter.group_arrays(data.arrays)[0]
+
+        # no matter what else, if nothing is listed as modified
+        # then save_range is None
+        for lsi_x in [None, 0, 3]:
+            data.x.last_saved_index = lsi_x
+            for lsi_y in [None, 1, 4]:
+                data.y.last_saved_index = lsi_y
+                for fe in [True, False]:
+                    save_range = formatter.match_save_range(
+                        group, file_exists=fe)
+                    self.assertEqual(save_range, None)
+
+        # consistent last_saved_index: if it's None or within the
+        # modified range, or if file does not exist, we need to overwrite
+        # otherwise start just after last_saved_index
+        for lsi, start in [(None, 0), (0, 1), (1, 2), (2, 3), (3, 0), (4, 0)]:
+            data.x.last_saved_index = data.y.last_saved_index = lsi
+
+            # inconsistent modified_range: expands to greatest extent
+            # so these situations are identical
+            for xmr, ymr in ([(4, 4), (3, 3)], [(3, 4), None], [None, (3, 4)]):
+                data.x.modified_range = xmr
+                data.y.modified_range = ymr
+
+                save_range = formatter.match_save_range(group,
+                                                        file_exists=False)
+                self.assertEqual(save_range, (0, 4))
+
+                save_range = formatter.match_save_range(group,
+                                                        file_exists=True)
+                self.assertEqual(save_range, (start, 4))
+
+        # inconsistent last_saved_index: need to overwrite no matter what
+        data.x.last_saved_index = 1
+        data.y.last_saved_index = 2
+        save_range = formatter.match_save_range(group, file_exists=True)
+        self.assertEqual(save_range, (0, 4))
+
+        # missing data point: don't write it unless only_complete is False
+        # but this will only back up one point!
+        data.y[4] = float('nan')
+        data.y[3] = float('nan')
+        data.x.last_saved_index = data.y.last_saved_index = 2
+
+        save_range = formatter.match_save_range(group, file_exists=True)
+        self.assertEqual(save_range, (3, 3))
+
+        save_range = formatter.match_save_range(group, file_exists=True,
+                                                only_complete=False)
+        self.assertEqual(save_range, (3, 4))
+
+
+class TestGNUPlotFormat(TestCase):
+    simplefile = '\n'.join([
+        '# x\ty',
+        '# "X value"\t"Y value"',
+        '# 5',
+        '1\t3',
+        '2\t4',
+        '3\t5',
+        '4\t6',
+        '5\t7', ''])
+
+    def setUp(self):
+        self.io = DataSet.default_io
+        self.locations = ('_simple1d_', '_simple2d_', '_combined_')
+
+        for location in self.locations:
+            self.assertFalse(self.io.list(location))
+
+    def tearDown(self):
+        for location in self.locations:
+            self.io.remove_all(location)
+
+    def checkArraysEqual(self, a, b):
+        self.checkArrayAttrs(a, b)
+
+        self.assertEqual(len(a.set_arrays), len(b.set_arrays))
+        for sa, sb in zip(a.set_arrays, b.set_arrays):
+            self.checkArrayAttrs(sa, sb)
+
+    def checkArrayAttrs(self, a, b):
+        self.assertEqual(a.tolist(), b.tolist())
+        self.assertEqual(a.label, b.label)
+        self.assertEqual(a.array_id, b.array_id)
+
+    def test_simple(self):
+        formatter = GNUPlotFormat()
+        location = self.locations[0]
+        data = DataSet1D(location)
+
+        # mark the data set as modified by... modifying it!
+        # without actually changing it :)
+        # TODO - are there cases we should automatically mark the data as
+        # modified on construction?
+        data.y[4] = data.y[4]
+
+        formatter.write(data)
+
+        with open(location + '/x.dat') as f:
+            self.assertEqual(f.read(), self.simplefile)
+
+        # normally this would be just done by data2 = load_data(location)
+        # but we want to work directly with the Formatter interface here
+        data2 = DataSet(location=location)
+        formatter.read(data2)
+
+        self.checkArraysEqual(data2.x, data.x)
+        self.checkArraysEqual(data2.y, data.y)

From 13072abc6b032a98f055182ed6a48cca463fd2f9 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 4 May 2016 10:17:59 +0200
Subject: [PATCH 118/169] take out query timeout for all our servers by default

---
 qcodes/data/manager.py          | 8 +++++---
 qcodes/instrument/server.py     | 9 ++++-----
 qcodes/utils/multiprocessing.py | 5 +++--
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/qcodes/data/manager.py b/qcodes/data/manager.py
index b7e0ee6985f3..ed160d300513 100644
--- a/qcodes/data/manager.py
+++ b/qcodes/data/manager.py
@@ -2,7 +2,7 @@
 from queue import Empty
 from traceback import format_exc
 
-from qcodes.utils.multiprocessing import ServerManager
+from qcodes.utils.multiprocessing import ServerManager, SERVER_ERR
 
 
 def get_data_manager(only_existing=False):
@@ -42,7 +42,7 @@ class DataManager(ServerManager):
     Written using multiprocessing Queue's, but should be easily
     extensible to other messaging systems
     '''
-    def __init__(self, query_timeout=2):
+    def __init__(self):
         type(self).default = self
         super().__init__(name='DataServer', server_class=DataServer)
 
@@ -122,7 +122,9 @@ def _reply(self, response):
 
     def _post_error(self, e):
         self._error_queue.put(format_exc())
-        self._response_queue.put('ERR')  # to short-circuit the timeout
+        # the caller is waiting on _response_queue, so put a signal there
+        # to say there's an error coming
+        self._response_queue.put(SERVER_ERR)
 
     ######################################################################
     # query handlers                                                     #
diff --git a/qcodes/instrument/server.py b/qcodes/instrument/server.py
index d586556c014b..61b4a932f269 100644
--- a/qcodes/instrument/server.py
+++ b/qcodes/instrument/server.py
@@ -122,10 +122,7 @@ class InstrumentConnection:
     def __init__(self, manager, instrument_class, new_id, args, kwargs):
         self.manager = manager
 
-        # long timeout on the initial call, to allow slow errors
-        # (like visa timeout) to get back to us
-        info = manager.ask('new', instrument_class, new_id, args, kwargs,
-                           timeout=20)
+        info = manager.ask('new', instrument_class, new_id, args, kwargs)
         for k, v in info.items():
             setattr(self, k, v)
 
@@ -190,7 +187,9 @@ def post_error(self, e, query=None):
         if query:
             e.args = e.args + ('error processing query ' + repr(query),)
         self._error_queue.put(format_exc())
-        self._response_queue.put(SERVER_ERR)  # to short-circuit timeout
+        # the caller is waiting on _response_queue, so put a signal there
+        # to say there's an error coming
+        self._response_queue.put(SERVER_ERR)
 
     def handle_halt(self, *args, **kwargs):
         '''
diff --git a/qcodes/utils/multiprocessing.py b/qcodes/utils/multiprocessing.py
index 091108424943..807452d10d28 100644
--- a/qcodes/utils/multiprocessing.py
+++ b/qcodes/utils/multiprocessing.py
@@ -225,10 +225,11 @@ class ServerManager:
 
     name: the name of the server. Can include .format specs to insert
         all or part of the uuid
-    query_timeout: the default time to wait for responses
+    query_timeout: (default None) the default time to wait for responses
     kwargs: passed along to the server constructor
     '''
-    def __init__(self, name, server_class, shared_attrs=None, query_timeout=2):
+    def __init__(self, name, server_class, shared_attrs=None,
+                 query_timeout=None):
         self._query_queue = mp.Queue()
         self._response_queue = mp.Queue()
         self._error_queue = mp.Queue()

From 6792bfc38d931fc39cb11492d38cd66752675aed Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 4 May 2016 10:33:48 +0200
Subject: [PATCH 119/169] slight simplification to how we handle server errors

---
 qcodes/tests/test_multiprocessing.py |  3 ++-
 qcodes/utils/multiprocessing.py      | 18 ++++++++++++------
 2 files changed, 14 insertions(+), 7 deletions(-)

diff --git a/qcodes/tests/test_multiprocessing.py b/qcodes/tests/test_multiprocessing.py
index c6606e98c0dd..269272afefd4 100644
--- a/qcodes/tests/test_multiprocessing.py
+++ b/qcodes/tests/test_multiprocessing.py
@@ -396,7 +396,8 @@ def test_mechanics(self):
                              '  OSError: your hard disk went floppy.')
         sm._error_queue.put(builtin_error_str)
         sm._response_queue.put(SERVER_ERR)
-        time.sleep(0.005)
+        while sm._error_queue.empty() or sm._response_queue.empty():
+            time.sleep(0.005)
         with self.assertRaises(OSError):
             sm.ask('which way does the wind blow?')
 
diff --git a/qcodes/utils/multiprocessing.py b/qcodes/utils/multiprocessing.py
index 807452d10d28..1c2fbcadd899 100644
--- a/qcodes/utils/multiprocessing.py
+++ b/qcodes/utils/multiprocessing.py
@@ -277,7 +277,7 @@ def write(self, *query):
         self._query_queue.put(query)
         self._check_for_errors()
 
-    def _check_for_errors(self, expect_error=False):
+    def _check_for_errors(self, expect_error=False, query=None):
         if expect_error or not self._error_queue.empty():
             # clear the response queue whenever there's an error
             # and give it a little time to flush first
@@ -298,12 +298,18 @@ def _check_for_errors(self, expect_error=False):
             if err_type is None or not issubclass(err_type, Exception):
                 err_type = RuntimeError
 
+            if query:
+                errhead += '\nwhile executing query: ' + repr(query)
+
             raise err_type(errhead + '\n\n' + errstr)
 
-    def _check_response(self, timeout):
+    def _check_response(self, timeout, query=None):
         res = self._response_queue.get(timeout=timeout)
         if res == SERVER_ERR:
-            self._expect_error = True
+            # TODO: I think the way we're doing this now, I could get rid of
+            # _error_queue completely and just have errors and regular
+            # responses labeled differently in _response_queue
+            self._check_for_errors(expect_error=True, query=query)
         return res
 
     def ask(self, *query, timeout=None):
@@ -324,16 +330,16 @@ def ask(self, *query, timeout=None):
             self._query_queue.put(query)
 
             try:
-                res = self._check_response(timeout)
+                res = self._check_response(timeout, query)
 
                 while not self._response_queue.empty():
-                    res = self._check_response(timeout)
+                    res = self._check_response(timeout, query)
 
             except Empty as e:
                 if self._error_queue.empty():
                     # only raise if we're not about to find a deeper error
                     raise e
-            self._check_for_errors(self._expect_error)
+            self._check_for_errors(query=query)
 
             return res
 

From 184967c98d11a8a9eb364bbda85be3f8d23cf0ef Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 4 May 2016 12:49:39 +0200
Subject: [PATCH 120/169] support slices in DataArray.__setitem__

---
 qcodes/data/data_array.py | 24 +++++++++++++++++-------
 qcodes/tests/test_data.py | 17 +++++++++++++++++
 2 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/qcodes/data/data_array.py b/qcodes/data/data_array.py
index e825a9f1b39d..dc368f41590f 100644
--- a/qcodes/data/data_array.py
+++ b/qcodes/data/data_array.py
@@ -138,8 +138,8 @@ def init_data(self, data=None):
         self._set_index_bounds()
 
     def _set_index_bounds(self):
-        self._min_indices = tuple(0 for d in self.size)
-        self._max_indices = tuple(d - 1 for d in self.size)
+        self._min_indices = [0 for d in self.size]
+        self._max_indices = [d - 1 for d in self.size]
 
     def clear(self):
         '''
@@ -161,14 +161,24 @@ def __setitem__(self, loop_indices, value):
         want this overhead, you can access self.ndarray directly.
         '''
         if isinstance(loop_indices, collections.Iterable):
-            loop_indices_tuple = loop_indices
+            min_indices = list(loop_indices)
+            max_indices = list(loop_indices)
         else:
-            loop_indices_tuple = (loop_indices, )
-        min_li = self._flat_index(loop_indices_tuple, self._min_indices)
-        max_li = self._flat_index(loop_indices_tuple, self._max_indices)
+            min_indices = [loop_indices]
+            max_indices = [loop_indices]
+
+        for i, index in enumerate(min_indices):
+            if isinstance(index, slice):
+                start, stop, step = index.indices(self.size[i])
+                min_indices[i] = start
+                max_indices[i] = start + (
+                    ((stop - start - 1)//step) * step)
+
+        min_li = self._flat_index(min_indices, self._min_indices)
+        max_li = self._flat_index(max_indices, self._max_indices)
         self._update_modified_range(min_li, max_li)
 
-        self.ndarray[loop_indices] = value
+        self.ndarray.__setitem__(loop_indices, value)
 
     def __getitem__(self, loop_indices):
         return self.ndarray[loop_indices]
diff --git a/qcodes/tests/test_data.py b/qcodes/tests/test_data.py
index f566572647dd..c33ad6b85311 100644
--- a/qcodes/tests/test_data.py
+++ b/qcodes/tests/test_data.py
@@ -148,6 +148,23 @@ def test_edit_and_mark(self):
         self.assertEqual(data.last_saved_index, None)
         self.assertEqual(data.modified_range, (0, 2))
 
+    def test_edit_and_mark_slice(self):
+        data = DataArray(preset_data=[[1] * 5] * 6)
+
+        self.assertEqual(data.size, (6, 5))
+        self.assertEqual(data.modified_range, None)
+
+        data[:4:2, 2:] = 2
+        self.assertEqual(data.tolist(), [
+            [1, 1, 2, 2, 2],
+            [1, 1, 1, 1, 1],
+            [1, 1, 2, 2, 2],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1],
+            [1, 1, 1, 1, 1]
+        ])
+        self.assertEqual(data.modified_range, (2, 14))
+
     def test_repr(self):
         array2d = [[1, 2], [3, 4]]
         arrayrepr = repr(np.array(array2d))

From 0356afe3289d36cb8ed5936fc921da73b6e483d8 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 4 May 2016 15:46:17 +0200
Subject: [PATCH 121/169] test almost all of GNUPlotFormat

---
 qcodes/tests/data_mocks.py  |  50 ++++++--
 qcodes/tests/test_format.py | 231 +++++++++++++++++++++++++++++++++---
 2 files changed, 251 insertions(+), 30 deletions(-)

diff --git a/qcodes/tests/data_mocks.py b/qcodes/tests/data_mocks.py
index d8328db3e625..aee15f451140 100644
--- a/qcodes/tests/data_mocks.py
+++ b/qcodes/tests/data_mocks.py
@@ -66,29 +66,30 @@ def init_data(self):
 
 def DataSet1D(location=None):
     # DataSet with one 1D array with 5 points
-    x = DataArray(name='x', label='X value', preset_data=(1., 2., 3., 4., 5.))
-    y = DataArray(name='y', label='Y value', preset_data=(3., 4., 5., 6., 7.),
+    x = DataArray(name='x', label='X', preset_data=(1., 2., 3., 4., 5.))
+    y = DataArray(name='y', label='Y', preset_data=(3., 4., 5., 6., 7.),
                   set_arrays=(x,))
     return new_data(arrays=(x, y), location=location)
 
 
-def DataSet2D(location=None):
-    # DataSet with one 2D array, 2x3 points
-    x = DataArray(name='x', label='X', preset_data=(5., 6.))
-    y = DataArray(name='y', label='Y', preset_data=(7., 8., 9.))
-    y.nest(2, 0, x)
-    z = DataArray(name='z', label='Z',
-                  preset_data=((10., 11., 12.), (13., 14., 15.)),
-                  set_arrays=(x, y))
-    return new_data(arrays=(x, y, z), location=location)
+def file_1d():
+    return '\n'.join([
+        '# x\ty',
+        '# "X"\t"Y"',
+        '# 5',
+        '1\t3',
+        '2\t4',
+        '3\t5',
+        '4\t6',
+        '5\t7', ''])
 
 
 def DataSetCombined(location=None):
     # Complex DataSet with two 1D and two 2D arrays
     x = DataArray(name='x', label='X!', preset_data=(16., 17.))
-    y1 = DataArray(name='y1', label='Y1', preset_data=(18., 19.),
+    y1 = DataArray(name='y1', label='Y1 value', preset_data=(18., 19.),
                    set_arrays=(x,))
-    y2 = DataArray(name='y2', label='Y2', preset_data=(20., 21.),
+    y2 = DataArray(name='y2', label='Y2 value', preset_data=(20., 21.),
                    set_arrays=(x,))
 
     yset = DataArray(name='yset', label='Y', preset_data=(22., 23., 24.))
@@ -100,3 +101,26 @@ def DataSetCombined(location=None):
                    preset_data=((31., 32., 33.), (34., 35., 36.)),
                    set_arrays=(x, yset))
     return new_data(arrays=(x, y1, y2, yset, z1, z2), location=location)
+
+
+def files_combined():
+    return [
+        '\n'.join([
+            '# x\ty1\ty2',
+            '# "X!"\t"Y1 value"\t"Y2 value"',
+            '# 2',
+            '16\t18\t20',
+            '17\t19\t21', '']),
+
+        '\n'.join([
+            '# x\tyset\tz1\tz2',
+            '# "X!"\t"Y"\t"Z1"\t"Z2"',
+            '# 2\t3',
+            '16\t22\t25\t31',
+            '16\t23\t26\t32',
+            '16\t24\t27\t33',
+            '',
+            '17\t22\t28\t34',
+            '17\t23\t29\t35',
+            '17\t24\t30\t36', ''])
+    ]
diff --git a/qcodes/tests/test_format.py b/qcodes/tests/test_format.py
index cd7793cdb05d..8b58c4c7527e 100644
--- a/qcodes/tests/test_format.py
+++ b/qcodes/tests/test_format.py
@@ -3,16 +3,17 @@
 
 from qcodes.data.format import Formatter
 from qcodes.data.gnuplot_format import GNUPlotFormat
-from qcodes.data.data_set import DataMode, DataSet
+from qcodes.data.data_array import DataArray
+from qcodes.data.data_set import DataSet, new_data
 from qcodes.utils.helpers import LogCapture
 
-from .data_mocks import DataSet1D, DataSet2D, DataSetCombined
+from .data_mocks import DataSet1D, file_1d, DataSetCombined, files_combined
 
 
 class TestBaseFormatter(TestCase):
     def setUp(self):
         self.io = DataSet.default_io
-        self.locations = ('_simple1d_', '_simple2d_', '_combined_')
+        self.locations = ('_simple1d_', '_combined_')
 
         for location in self.locations:
             self.assertFalse(self.io.list(location))
@@ -152,19 +153,9 @@ def test_match_save_range(self):
 
 
 class TestGNUPlotFormat(TestCase):
-    simplefile = '\n'.join([
-        '# x\ty',
-        '# "X value"\t"Y value"',
-        '# 5',
-        '1\t3',
-        '2\t4',
-        '3\t5',
-        '4\t6',
-        '5\t7', ''])
-
     def setUp(self):
         self.io = DataSet.default_io
-        self.locations = ('_simple1d_', '_simple2d_', '_combined_')
+        self.locations = ('_simple1d_', '_combined_')
 
         for location in self.locations:
             self.assertFalse(self.io.list(location))
@@ -185,7 +176,7 @@ def checkArrayAttrs(self, a, b):
         self.assertEqual(a.label, b.label)
         self.assertEqual(a.array_id, b.array_id)
 
-    def test_simple(self):
+    def test_full_write(self):
         formatter = GNUPlotFormat()
         location = self.locations[0]
         data = DataSet1D(location)
@@ -198,8 +189,19 @@ def test_simple(self):
 
         formatter.write(data)
 
-        with open(location + '/x.dat') as f:
-            self.assertEqual(f.read(), self.simplefile)
+        with open(location + '/x.dat', 'r') as f:
+            self.assertEqual(f.read(), file_1d())
+
+        # check that we can add comment lines randomly into the file
+        # as long as it's after the first three lines, which are comments
+        # with well-defined meaning,
+        # and that we can un-quote the labels
+        lines = file_1d().split('\n')
+        lines[1] = lines[1].replace('"', '')
+        lines[3:3] = ['# this data is awesome!']
+        lines[6:6] = ['# the next point is my favorite.']
+        with open(location + '/x.dat', 'w') as f:
+            f.write('\n'.join(lines))
 
         # normally this would be just done by data2 = load_data(location)
         # but we want to work directly with the Formatter interface here
@@ -208,3 +210,198 @@ def test_simple(self):
 
         self.checkArraysEqual(data2.x, data.x)
         self.checkArraysEqual(data2.y, data.y)
+
+        # while we're here, check some errors on bad reads
+
+        # first: trying to read into a dataset that already has the
+        # wrong size
+        x = DataArray(name='x', label='X', preset_data=(1., 2.))
+        y = DataArray(name='y', label='Y', preset_data=(3., 4.),
+                      set_arrays=(x,))
+        data3 = new_data(arrays=(x, y), location=location + 'XX')
+        # initially give it a different location so we can make it without
+        # error, then change back to the location we want.
+        data3.location = location
+        with LogCapture() as s:
+            formatter.read(data3)
+        logstr = s.getvalue()
+        s.close()
+        self.assertTrue('ValueError' in logstr, logstr)
+
+        # no problem reading again if only data has changed, it gets
+        # overwritten with the disk copy
+        data2.x[2] = 42
+        data2.y[2] = 99
+        formatter.read(data2)
+        self.assertEqual(data2.x[2], 3)
+        self.assertEqual(data2.y[2], 5)
+
+    def test_no_nest(self):
+        formatter = GNUPlotFormat(always_nest=False)
+        location = self.locations[0]
+        data = DataSet1D(location)
+
+        # mark the data set as modified by... modifying it!
+        # without actually changing it :)
+        # TODO - are there cases we should automatically mark the data as
+        # modified on construction?
+        data.y[4] = data.y[4]
+
+        formatter.write(data)
+
+        with open(location + '.dat', 'r') as f:
+            self.assertEqual(f.read(), file_1d())
+
+    def test_format_options(self):
+        formatter = GNUPlotFormat(extension='.splat', terminator='\r',
+                                  separator='  ', comment='?:',
+                                  number_format='5.2f')
+        location = self.locations[0]
+        data = DataSet1D(location)
+
+        # mark the data set as modified by... modifying it!
+        # without actually changing it :)
+        # TODO - are there cases we should automatically mark the data as
+        # modified on construction?
+        data.y[4] = data.y[4]
+
+        formatter.write(data)
+
+        # TODO - Python3 uses universal newlines for read and write...
+        # which means '\n' gets converted on write to the OS standard
+        # (os.linesep) and all of the options we support get converted
+        # back to '\n' on read. So I'm tempted to just take out terminator
+        # as an option rather than turn this feature off.
+        odd_format = '\n'.join([
+            '?:x  y',
+            '?:"X"  "Y"',
+            '?:5',
+            ' 1.00   3.00',
+            ' 2.00   4.00',
+            ' 3.00   5.00',
+            ' 4.00   6.00',
+            ' 5.00   7.00', ''])
+
+        with open(location + '/x.splat', 'r') as f:
+            self.assertEqual(f.read(), odd_format)
+
+    def add_star(self, path):
+        try:
+            with open(path, 'a') as f:
+                f.write('*')
+        except FileNotFoundError:
+            self.stars_before_write += 1
+
+    def test_incremental_write(self):
+        formatter = GNUPlotFormat()
+        location = self.locations[0]
+        data = DataSet1D(location)
+        path = location + '/x.dat'
+
+        data_copy = DataSet1D(False)
+
+        # empty the data and mark it as unmodified
+        data.x[:] = float('nan')
+        data.y[:] = float('nan')
+        data.x.modified_range = None
+        data.y.modified_range = None
+
+        # simulate writing after every value comes in, even within
+        # one row (x comes first, it's the setpoint)
+        # we'll add a '*' after each write and check that they're
+        # in the right places afterward, ie we don't write any given
+        # row until it's done and we never totally rewrite the file
+        self.stars_before_write = 0
+        for i, (x, y) in enumerate(zip(data_copy.x, data_copy.y)):
+            data.x[i] = x
+            formatter.write(data)
+            self.add_star(path)
+
+            data.y[i] = y
+            formatter.write(data)
+            self.add_star(path)
+
+        starred_file = '\n'.join([
+            '# x\ty',
+            '# "X"\t"Y"',
+            '# 5',
+            '1\t3',
+            '**2\t4',
+            '**3\t5',
+            '**4\t6',
+            '**5\t7', '*'])
+
+        with open(path, 'r') as f:
+            self.assertEqual(f.read(), starred_file)
+        self.assertEqual(self.stars_before_write, 1)
+
+    def test_constructor_errors(self):
+        with self.assertRaises(AttributeError):
+            # extension must be a string
+            GNUPlotFormat(extension=5)
+
+        with self.assertRaises(ValueError):
+            # terminator must be \r, \n, or \r\n
+            GNUPlotFormat(terminator='\n\r')
+
+        with self.assertRaises(ValueError):
+            # this is not CSV - separator must be whitespace
+            GNUPlotFormat(separator=',')
+
+        with self.assertRaises(ValueError):
+            GNUPlotFormat(comment='  \r\n\t  ')
+
+    def test_read_errors(self):
+        formatter = GNUPlotFormat()
+
+        # non-comment line at the beginning
+        location = self.locations[0]
+        data = DataSet(location=location)
+        os.makedirs(location, exist_ok=True)
+        with open(location + '/x.dat', 'w') as f:
+            f.write('1\t2\n' + file_1d())
+        with LogCapture() as s:
+            formatter.read(data)
+        logstr = s.getvalue()
+        s.close()
+        self.assertTrue('ValueError' in logstr, logstr)
+
+        # same data array in 2 files
+        location = self.locations[1]
+        data = DataSet(location=location)
+        os.makedirs(location, exist_ok=True)
+        with open(location + '/x.dat', 'w') as f:
+            f.write('\n'.join(['# x\ty', '# "X"\t"Y"', '# 2', '1\t2', '3\t4']))
+        with open(location + '/q.dat', 'w') as f:
+            f.write('\n'.join(['# q\ty', '# "Q"\t"Y"', '# 2', '1\t2', '3\t4']))
+        with LogCapture() as s:
+            formatter.read(data)
+        logstr = s.getvalue()
+        s.close()
+        self.assertTrue('ValueError' in logstr, logstr)
+
+    def test_multifile(self):
+        formatter = GNUPlotFormat(always_nest=False)  # will nest anyway
+        location = self.locations[1]
+        data = DataSetCombined(location)
+
+        # mark one array in each file as completely modified
+        # that should cause the whole files to be written, even though
+        # the other data and setpoint arrays are not marked as modified
+        data.y1[:] += 0
+        data.z1[:, :] += 0
+        formatter.write(data)
+
+        filex, filexy = files_combined()
+
+        with open(location + '/x.dat', 'r') as f:
+            self.assertEqual(f.read(), filex)
+        with open(location + '/x_yset.dat', 'r') as f:
+            self.assertEqual(f.read(), filexy)
+
+        data2 = DataSet(location=location)
+        formatter.read(data2)
+
+        for array_id in ('x', 'y1', 'y2', 'yset', 'z1', 'z2'):
+            self.checkArraysEqual(data2.arrays[array_id],
+                                  data.arrays[array_id])

From 64e82d83cfdd95f837a70f1a3469fec93f3346fe Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Wed, 4 May 2016 17:05:44 +0200
Subject: [PATCH 122/169] BreakIf basic functionality

---
 qcodes/__init__.py        |  2 +-
 qcodes/loops.py           | 33 ++++++++++++++++++++++++++-------
 qcodes/tests/test_loop.py | 28 +++++++++++++++++++++++++++-
 3 files changed, 54 insertions(+), 9 deletions(-)

diff --git a/qcodes/__init__.py b/qcodes/__init__.py
index cc13fcf5f152..4def1c359410 100644
--- a/qcodes/__init__.py
+++ b/qcodes/__init__.py
@@ -30,7 +30,7 @@
     from qcodes.widgets.widgets import show_subprocess_widget
 
 from qcodes.station import Station
-from qcodes.loops import get_bg, halt_bg, Loop, Task, Wait
+from qcodes.loops import get_bg, halt_bg, Loop, Task, Wait, BreakIf
 
 from qcodes.data.manager import get_data_manager
 from qcodes.data.data_set import DataMode, DataSet, new_data, load_data
diff --git a/qcodes/loops.py b/qcodes/loops.py
index e4dabc831226..5d94a475a596 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -45,7 +45,7 @@
 from qcodes.station import Station
 from qcodes.data.data_set import new_data, DataMode
 from qcodes.data.data_array import DataArray
-from qcodes.utils.helpers import wait_secs
+from qcodes.utils.helpers import wait_secs, is_function
 from qcodes.utils.multiprocessing import QcodesProcess
 from qcodes.utils.threading import thread_map
 
@@ -560,13 +560,16 @@ def _run_loop(self, first_delay=0, action_indices=(),
                 # only wait the delay time if an inner loop will not inherit it
                 self._wait(delay)
 
-            for f in callables:
-                f(first_delay=delay,
-                  loop_indices=new_indices,
-                  current_values=new_values)
+            try:
+                for f in callables:
+                    f(first_delay=delay,
+                      loop_indices=new_indices,
+                      current_values=new_values)
 
-                # after the first action, no delay is inherited
-                delay = 0
+                    # after the first action, no delay is inherited
+                    delay = 0
+            except _QcodesBreak:
+                break
 
             # after the first setpoint, delay reverts to the loop delay
             delay = self.delay
@@ -683,3 +686,19 @@ def __init__(self, inner_loop, action_indices):
 
     def __call__(self, **kwargs):
         self.inner_loop._run_loop(action_indices=self.action_indices, **kwargs)
+
+
+class BreakIf:
+    def __init__(self, condition):
+        if not is_function(condition, 0):
+            raise TypeError('BreakIf condition must be a callable with '
+                            'no arguments')
+        self.condition = condition
+
+    def __call__(self, **ignore_kwargs):
+        if self.condition():
+            raise _QcodesBreak
+
+
+class _QcodesBreak(Exception):
+    pass
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 2af44ecd0134..1504dffa2394 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -4,7 +4,8 @@
 import multiprocessing as mp
 import numpy as np
 
-from qcodes.loops import Loop, MP_NAME, get_bg, halt_bg, Task, Wait, ActiveLoop
+from qcodes.loops import (Loop, MP_NAME, get_bg, halt_bg, Task, Wait,
+                          ActiveLoop, BreakIf)
 from qcodes.station import Station
 from qcodes.data.io import DiskIO
 from qcodes.data.data_array import DataArray
@@ -238,8 +239,14 @@ def test_tasks_waits(self):
         delay_array = []
         loop._monitor = FakeMonitor(delay_array)
 
+        # give it a "process" as if it was run in the bg before,
+        # check that this gets cleared
+        loop.process = 'TDD'
+
         data = loop.run_temp()
 
+        self.assertFalse(hasattr(loop, 'process'))
+
         self.assertEqual(data.p1.tolist(), [1, 2])
         self.assertEqual(data.p2_2.tolist(), [-1, -1])
         self.assertEqual(data.p2_4.tolist(), [1, 1])
@@ -398,6 +405,25 @@ def test_zero_delay(self):
         s.close()
         self.assertEqual(logstr.count('negative delay'), 0, logstr)
 
+    def test_breakif(self):
+        def p1_ge_3():
+            return self.p1.get_latest() >= 3
+
+        nan = float('nan')
+        loop = Loop(self.p1[1:6:1])
+        data = loop.each(self.p1, BreakIf(p1_ge_3)).run_temp()
+        self.assertEqual(repr(data.p1.tolist()),
+                         repr([1., 2., 3., nan, nan]))
+
+        data = loop.each(BreakIf(p1_ge_3), self.p1).run_temp()
+        self.assertEqual(repr(data.p1.tolist()),
+                         repr([1., 2., nan, nan, nan]))
+
+        with self.assertRaises(TypeError):
+            BreakIf(True)
+        with self.assertRaises(TypeError):
+            BreakIf(self.p1.set)
+
 
 class AbortingGetter(ManualParameter):
     '''

From 7c1e5be84384bd0dff798ff0a8943474963d7a43 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Thu, 5 May 2016 00:26:41 +0200
Subject: [PATCH 123/169] deferred operations

---
 qcodes/utils/deferred_operations.py | 209 ++++++++++++++++++++++++++++
 1 file changed, 209 insertions(+)
 create mode 100644 qcodes/utils/deferred_operations.py

diff --git a/qcodes/utils/deferred_operations.py b/qcodes/utils/deferred_operations.py
new file mode 100644
index 000000000000..3a7a65e8358d
--- /dev/null
+++ b/qcodes/utils/deferred_operations.py
@@ -0,0 +1,209 @@
+import operator
+
+from .helpers import is_function
+
+
+class DeferredOperations:
+    """
+    make math and logic operations return callables to defer execution
+    of arbitrary formulae
+
+    Can be used as a mixin class - in which case you should NOT call __init__
+    and you SHOULD override __call__ and get with identical results
+
+    call_func: a callable taking no arguments
+    call_parts: the original callables, in case we want to
+        record them all (ie raw data)
+
+    You can evaluate a DeferredOperations by calling it or
+    by calling its .get() method
+
+    examples:
+        d = DeferredOperations(lambda:42)
+        d() -> 42
+        (d*5)() -> 210
+        (d>10)() -> True
+        ((84/d) + (d*d))() -> 1766
+
+    NOTE: and & or are special: there are no magic methods for
+    the regular and & or, so we need to use the bitwise operators &,| as
+    boolean operators. We DO NOT short-circuit them; the right side is
+    always evaluated.
+    """
+    def __init__(self, call_func, args=(), call_parts=()):
+        self._validate_callable(call_func, len(args))
+        self.call_func = call_func
+        self.args = args
+        self.call_parts = call_parts
+
+    def __call__(self):
+        return self.call_func(*self.args)
+
+    def get(self):
+        return self.call_func(*self.args)
+
+    def _validate_callable(self, func, arg_count=0):
+        # shouldn't need to do this, but is_function fails for a
+        # DeferredOperations object, as signature implicitly does ==
+        # with it.
+        if not (isinstance(func, DeferredOperations) or
+                is_function(func, arg_count)):
+            raise TypeError('function must be a callable taking no arguments')
+
+    def _call_unary(self, op):
+        return op(self())
+
+    def _unary(self, op):
+        if not getattr(self, 'call_parts'):
+            self.call_parts = (self,)
+
+        return DeferredOperations(self._call_unary, (op,), self.call_parts)
+
+    def _call_binary_callable(self, op, other):
+        return op(self(), other())
+
+    def _call_binary_constant(self, op, other):
+        return op(self(), other)
+
+    def _binary(self, op, other):
+        if not getattr(self, 'call_parts'):
+            self.call_parts = (self,)
+
+        if callable(other):
+            self._validate_callable(other)
+            other_parts = getattr(other, 'call_parts', (other,))
+            return DeferredOperations(self._call_binary_callable, (op, other),
+                                      self.call_parts + other_parts)
+        else:
+            return DeferredOperations(self._call_binary_constant, (op, other),
+                                      self.call_parts)
+
+    def __eq__(self, other):
+        return self._binary(operator.eq, other)
+
+    def __ne__(self, other):
+        return self._binary(operator.ne, other)
+
+    def __ge__(self, other):
+        return self._binary(operator.ge, other)
+
+    def __gt__(self, other):
+        return self._binary(operator.gt, other)
+
+    def __le__(self, other):
+        return self._binary(operator.le, other)
+
+    def __lt__(self, other):
+        return self._binary(operator.lt, other)
+
+    def __abs__(self):
+        return self._unary(operator.abs)
+
+    def __add__(self, other):
+        return self._binary(operator.add, other)
+
+    def __and__(self, other):
+        """
+        uses the bitwise and operator & to do boolean and
+        """
+        return self._binary(_and, other)
+
+    def __floordiv__(self, other):
+        return self._binary(operator.floordiv, other)
+
+    def __mod___(self, other):
+        return self._binary(operator.mod, other)
+
+    def __mul__(self, other):
+        return self._binary(operator.mul, other)
+
+    def __neg__(self, other):
+        return self._unary(operator.neg)
+
+    def __or__(self, other):
+        """
+        uses the bitwise or operator | to do boolean or
+        """
+        return self._binary(_or, other)
+
+    def __pos__(self):
+        return self._unary(operator.pos)
+
+    def __pow__(self, other):
+        return self._binary(operator.pow, other)
+
+    def __sub__(self, other):
+        return self._binary(operator.sub, other)
+
+    def __truediv__(self, other):
+        return self._binary(operator.truediv, other)
+
+    def __radd__(self, other):
+        return self._binary(operator.add, other)
+
+    def __rsub__(self, other):
+        return self._binary(_rsub, other)
+
+    def __rmul__(self, other):
+        return self._binary(operator.mul, other)
+
+    def __rtruediv__(self, other):
+        return self._binary(_rtruediv, other)
+
+    def __rfloordiv__(self, other):
+        return self._binary(_rfloordiv, other)
+
+    def __rmod__(self, other):
+        return self._binary(_rmod, other)
+
+    def __rpow__(self, other):
+        return self._binary(_rpow, other)
+
+    def __rand__(self, other):
+        return self._binary(_and, other)
+
+    def __ror__(self, other):
+        return self._binary(_or, other)
+
+    def __int__(self):
+        return self._unary(int)
+
+    def __float__(self):
+        return self._unary(float)
+
+    def __round__(self, other=None):
+        if other is None:
+            return self._unary(round)
+        else:
+            return self._binary(round, other)
+
+
+# functional forms not in the operator module, so we get
+# the order of arguments correct
+
+def _and(a, b):
+    return a and b
+
+
+def _or(a, b):
+    return a or b
+
+
+def _rsub(a, b):
+    return b - a
+
+
+def _rtruediv(a, b):
+    return b / a
+
+
+def _rfloordiv(a, b):
+    return b // a
+
+
+def _rmod(a, b):
+    return b % a
+
+
+def _rpow(a, b):
+    return b ** a

From fdce8a5a775abcd037a88a85dbf1cf77baa0d2e7 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Thu, 5 May 2016 01:17:11 +0200
Subject: [PATCH 124/169] test & fix DeferredOperations

---
 qcodes/tests/test_deferred_operations.py | 98 ++++++++++++++++++++++++
 qcodes/utils/deferred_operations.py      | 25 +++---
 2 files changed, 112 insertions(+), 11 deletions(-)
 create mode 100644 qcodes/tests/test_deferred_operations.py

diff --git a/qcodes/tests/test_deferred_operations.py b/qcodes/tests/test_deferred_operations.py
new file mode 100644
index 000000000000..d787ca3e7df5
--- /dev/null
+++ b/qcodes/tests/test_deferred_operations.py
@@ -0,0 +1,98 @@
+from unittest import TestCase
+
+from qcodes.utils.deferred_operations import DeferredOperations
+
+
+class TestDeferredOperations(TestCase):
+    def test_basic(self):
+        d = DeferredOperations(lambda: 5)
+        self.assertEqual(d(), 5)
+        self.assertEqual(d.get(), 5)
+
+    def test_errors(self):
+        with self.assertRaises(TypeError):
+            DeferredOperations(lambda: 5, args=(1,))
+
+        with self.assertRaises(TypeError):
+            DeferredOperations(10)
+
+        # this one doesn't cause errors on definition, only on calling
+        d = DeferredOperations(lambda: 1 / 0)
+        with self.assertRaises(ZeroDivisionError):
+            d()
+
+    def test_unary(self):
+        d = DeferredOperations(lambda: -3)
+        f = DeferredOperations(lambda: 4.221)
+
+        self.assertEqual((abs(d))(), 3)
+        self.assertEqual((-d)(), 3)
+        self.assertEqual((+d)(), -3)
+        self.assertEqual((round(f))(), 4)
+
+    def test_binary_constants(self):
+        d = DeferredOperations(lambda: -3)
+        f = DeferredOperations(lambda: 4.221)
+
+        self.assertEqual((d == -3)(), True)
+        self.assertEqual((d == -4)(), False)
+        self.assertEqual((d != -3)(), False)
+        self.assertEqual((d != -4)(), True)
+        self.assertEqual((d > -4)(), True)
+        self.assertEqual((d > -3)(), False)
+        self.assertEqual((d >= -3)(), True)
+        self.assertEqual((d >= -2)(), False)
+        self.assertEqual((d < -3)(), False)
+        self.assertEqual((d < -2)(), True)
+        self.assertEqual((d <= -3)(), True)
+        self.assertEqual((d <= -4)(), False)
+        self.assertEqual((d + 5)(), 2)
+        self.assertEqual((d & 10)(), 10)
+        self.assertEqual((d | 10)(), -3)
+        self.assertEqual((d // 2)(), -2)
+        self.assertEqual((d % 5)(), 2)
+        self.assertEqual((d * 4)(), -12)
+        self.assertEqual((d ** 3)(), -27)
+        self.assertEqual((d - 10)(), -13)
+        self.assertEqual((d / 2)(), -1.5)
+        self.assertEqual((7 + d)(), 4)
+        self.assertEqual((7 - d)(), 10)
+        self.assertEqual((7 * d)(), -21)
+        self.assertEqual((1.5 / d)(), -0.5)
+        self.assertEqual((7 // d)(), -3)
+        self.assertEqual((7 % d)(), -2)
+        self.assertEqual((10 ** d)(), 0.001)
+        self.assertEqual((8 & d)(), -3)
+        self.assertEqual((8 | d)(), 8)
+        self.assertEqual((round(f, 1))(), 4.2)
+
+    def test_binary_both(self):
+        d4 = DeferredOperations(lambda: 4)
+        d5 = DeferredOperations(lambda: 5)
+
+        self.assertEqual((d4 == d5)(), False)
+        self.assertEqual((d4 != d5)(), True)
+        self.assertEqual((d4 > d5)(), False)
+        self.assertEqual((d4 >= d5)(), False)
+        self.assertEqual((d4 < d5)(), True)
+        self.assertEqual((d4 <= d5)(), True)
+        self.assertEqual((d4 + d5)(), 9)
+        self.assertEqual((d4 & d5)(), 5)
+        self.assertEqual((d4 | d5)(), 4)
+        self.assertEqual((d4 // d5)(), 0)
+        self.assertEqual((d4 % d5)(), 4)
+        self.assertEqual((d4 * d5)(), 20)
+        self.assertEqual((d4 ** d5)(), 1024)
+        self.assertEqual((d4 - d5)(), -1)
+        self.assertEqual((d4 / d5)(), 0.8)
+        self.assertEqual((round(d4, d5))(), 4)
+
+    def test_complicated(self):
+        d2 = DeferredOperations(lambda: 2)
+        d3 = DeferredOperations(lambda: 3)
+
+        self.assertEqual((d2 + (d2 + d2))(), 6)
+        self.assertEqual(((d2 < 5) & (d3 > 1))(), True)
+        self.assertEqual(((d2 + 5) ** (d3 - d2 + 1))(), 49)
+        self.assertEqual((2 * d2 * d3 * d3 * d2 * 5)(), 360)
+        self.assertEqual(((1 / d3) < (1 / d2))(), True)
diff --git a/qcodes/utils/deferred_operations.py b/qcodes/utils/deferred_operations.py
index 3a7a65e8358d..b8860e213296 100644
--- a/qcodes/utils/deferred_operations.py
+++ b/qcodes/utils/deferred_operations.py
@@ -48,7 +48,8 @@ def _validate_callable(self, func, arg_count=0):
         # with it.
         if not (isinstance(func, DeferredOperations) or
                 is_function(func, arg_count)):
-            raise TypeError('function must be a callable taking no arguments')
+            raise TypeError('function must be a callable taking '
+                            '{} arguments'.format(arg_count))
 
     def _call_unary(self, op):
         return op(self())
@@ -111,13 +112,13 @@ def __and__(self, other):
     def __floordiv__(self, other):
         return self._binary(operator.floordiv, other)
 
-    def __mod___(self, other):
+    def __mod__(self, other):
         return self._binary(operator.mod, other)
 
     def __mul__(self, other):
         return self._binary(operator.mul, other)
 
-    def __neg__(self, other):
+    def __neg__(self):
         return self._unary(operator.neg)
 
     def __or__(self, other):
@@ -160,16 +161,10 @@ def __rpow__(self, other):
         return self._binary(_rpow, other)
 
     def __rand__(self, other):
-        return self._binary(_and, other)
+        return self._binary(_rand, other)
 
     def __ror__(self, other):
-        return self._binary(_or, other)
-
-    def __int__(self):
-        return self._unary(int)
-
-    def __float__(self):
-        return self._unary(float)
+        return self._binary(_ror, other)
 
     def __round__(self, other=None):
         if other is None:
@@ -185,10 +180,18 @@ def _and(a, b):
     return a and b
 
 
+def _rand(a, b):
+    return b and a
+
+
 def _or(a, b):
     return a or b
 
 
+def _ror(a, b):
+    return b or a
+
+
 def _rsub(a, b):
     return b - a
 

From cb0bd14668ac7e0b5365a44df449d6337d25f821 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Thu, 5 May 2016 02:08:16 +0200
Subject: [PATCH 125/169] parameters & related classes inherit
 DeferredOperations!

---
 qcodes/instrument/parameter.py | 5 +++--
 qcodes/instrument/remote.py    | 3 ++-
 2 files changed, 5 insertions(+), 3 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index d46f1fe70891..aa4ce7b03ac2 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -39,6 +39,7 @@
 import logging
 import os
 
+from qcodes.utils.deferred_operations import DeferredOperations
 from qcodes.utils.helpers import (permissive_range, wait_secs,
                                   DelegateAttributes)
 from qcodes.utils.metadata import Metadatable
@@ -57,7 +58,7 @@ def no_getter(*args, **kwargs):
         'set value.')
 
 
-class Parameter(Metadatable):
+class Parameter(Metadatable, DeferredOperations):
     '''
     defines one generic parameter, not necessarily part of
     an instrument. can be settable and/or gettable.
@@ -647,7 +648,7 @@ def get_async(self):
         return self.get()
 
 
-class GetLatest(DelegateAttributes):
+class GetLatest(DelegateAttributes, DeferredOperations):
     '''
     wrapper for a Parameter that just returns the last set or measured value
     stored in the Parameter itself.
diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index 8c6c0b39d36f..af626d439cb8 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -1,3 +1,4 @@
+from qcodes.utils.deferred_operations import DeferredOperations
 from qcodes.utils.helpers import DelegateAttributes
 from .parameter import Parameter, GetLatest
 from .function import Function
@@ -108,7 +109,7 @@ def __call__(self, *args, **kwargs):
         return self._instrument.connection.ask(self.name, *args, **kwargs)
 
 
-class RemoteParameter(RemoteComponent):
+class RemoteParameter(RemoteComponent, DeferredOperations):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.get_latest = GetLatest(self)

From 387dc3e4bd3d809ee6eccab902c2dd8e73431734 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Thu, 5 May 2016 02:09:28 +0200
Subject: [PATCH 126/169] move is_function into deferred_operations to test
 without circ. dep.

---
 qcodes/loops.py                     |  3 +-
 qcodes/tests/test_helpers.py        |  5 ++-
 qcodes/tests/test_instrument.py     | 15 +++++++
 qcodes/tests/test_loop.py           |  7 +--
 qcodes/utils/deferred_operations.py | 66 +++++++++++++++++++++++------
 qcodes/utils/helpers.py             | 35 ---------------
 qcodes/utils/sync_async.py          |  2 +-
 7 files changed, 77 insertions(+), 56 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 5d94a475a596..3813670b2c9c 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -45,7 +45,8 @@
 from qcodes.station import Station
 from qcodes.data.data_set import new_data, DataMode
 from qcodes.data.data_array import DataArray
-from qcodes.utils.helpers import wait_secs, is_function
+from qcodes.utils.deferred_operations import is_function
+from qcodes.utils.helpers import wait_secs
 from qcodes.utils.multiprocessing import QcodesProcess
 from qcodes.utils.threading import thread_map
 
diff --git a/qcodes/tests/test_helpers.py b/qcodes/tests/test_helpers.py
index 788b811d757a..17b3b3f56a81 100644
--- a/qcodes/tests/test_helpers.py
+++ b/qcodes/tests/test_helpers.py
@@ -3,9 +3,10 @@
 from datetime import datetime
 import asyncio
 
-from qcodes.utils.helpers import (is_function, is_sequence, permissive_range,
-                                  wait_secs, make_unique, DelegateAttributes,
+from qcodes.utils.helpers import (is_sequence, permissive_range, wait_secs,
+                                  make_unique, DelegateAttributes,
                                   LogCapture, strip_attrs)
+from qcodes.utils.deferred_operations import is_function
 
 
 class TestIsFunction(TestCase):
diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index 2ab5eb7ba281..e93deec004d5 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -661,6 +661,21 @@ def test_manual_parameter(self):
                                       parameter_class=ManualParameter,
                                       initial_value='nearsighted')
 
+    def test_deferred_ops(self):
+        gates = self.gates
+        c0, c1, c2 = gates.chan0, gates.chan1, gates.chan2
+
+        c0.set(0)
+        c1.set(1)
+        c2.set(2)
+
+        self.assertEqual((c0 + c1 + c2)(), 3)
+        self.assertEqual((10 + (c0**2) + (c1**2) + (c2**2)), 15)
+
+        d = c1.get_latest / c0.get_latest
+        with self.assertRaises(ZeroDivisionError):
+            d()
+
 
 class TestAttrAccess(TestCase):
     def tearDown(self):
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 1504dffa2394..a07b74fa6839 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -406,16 +406,13 @@ def test_zero_delay(self):
         self.assertEqual(logstr.count('negative delay'), 0, logstr)
 
     def test_breakif(self):
-        def p1_ge_3():
-            return self.p1.get_latest() >= 3
-
         nan = float('nan')
         loop = Loop(self.p1[1:6:1])
-        data = loop.each(self.p1, BreakIf(p1_ge_3)).run_temp()
+        data = loop.each(self.p1, BreakIf(self.p1 >= 3)).run_temp()
         self.assertEqual(repr(data.p1.tolist()),
                          repr([1., 2., 3., nan, nan]))
 
-        data = loop.each(BreakIf(p1_ge_3), self.p1).run_temp()
+        data = loop.each(BreakIf(self.p1.get_latest >= 3), self.p1).run_temp()
         self.assertEqual(repr(data.p1.tolist()),
                          repr([1., 2., nan, nan, nan]))
 
diff --git a/qcodes/utils/deferred_operations.py b/qcodes/utils/deferred_operations.py
index b8860e213296..1885b36626f6 100644
--- a/qcodes/utils/deferred_operations.py
+++ b/qcodes/utils/deferred_operations.py
@@ -1,6 +1,45 @@
 import operator
-
-from .helpers import is_function
+from asyncio import iscoroutinefunction
+from inspect import signature
+
+
+def is_function(f, arg_count, coroutine=False):
+    '''
+    require a function that can accept the specified number of positional
+    arguments, which either is or is not a coroutine
+    type casting "functions" are allowed, but only in the 1-argument form
+    '''
+    if not isinstance(arg_count, int) or arg_count < 0:
+        raise TypeError('arg_count must be a non-negative integer')
+
+    if not (callable(f) and bool(coroutine) is iscoroutinefunction(f)):
+        return False
+
+    # shouldn't need to do this, but is_function fails for a
+    # DeferredOperations object, as signature implicitly does ==
+    # with it.
+    if isinstance(f, DeferredOperations):
+        return arg_count == 0
+
+    if isinstance(f, type):
+        # for type casting functions, eg int, str, float
+        # only support the one-parameter form of these,
+        # otherwise the user should make an explicit function.
+        return arg_count == 1
+
+    try:
+        sig = signature(f)
+    except ValueError:
+        # some built-in functions/methods don't describe themselves to inspect
+        # we already know it's a callable and coroutine is correct.
+        return True
+
+    try:
+        inputs = [0] * arg_count
+        sig.bind(*inputs)
+        return True
+    except TypeError:
+        return False
 
 
 class DeferredOperations:
@@ -43,19 +82,16 @@ def get(self):
         return self.call_func(*self.args)
 
     def _validate_callable(self, func, arg_count=0):
-        # shouldn't need to do this, but is_function fails for a
-        # DeferredOperations object, as signature implicitly does ==
-        # with it.
-        if not (isinstance(func, DeferredOperations) or
-                is_function(func, arg_count)):
-            raise TypeError('function must be a callable taking '
-                            '{} arguments'.format(arg_count))
+        if not is_function(func, arg_count):
+            raise TypeError(
+                'function must be a callable taking '
+                '{} arguments, not {}'.format(arg_count, repr(func)))
 
     def _call_unary(self, op):
         return op(self())
 
     def _unary(self, op):
-        if not getattr(self, 'call_parts'):
+        if not getattr(self, 'call_parts', None):
             self.call_parts = (self,)
 
         return DeferredOperations(self._call_unary, (op,), self.call_parts)
@@ -67,7 +103,7 @@ def _call_binary_constant(self, op, other):
         return op(self(), other)
 
     def _binary(self, op, other):
-        if not getattr(self, 'call_parts'):
+        if not getattr(self, 'call_parts', None):
             self.call_parts = (self,)
 
         if callable(other):
@@ -75,9 +111,15 @@ def _binary(self, op, other):
             other_parts = getattr(other, 'call_parts', (other,))
             return DeferredOperations(self._call_binary_callable, (op, other),
                                       self.call_parts + other_parts)
-        else:
+
+        # TODO: any other types we should support?
+        elif isinstance(other, (int, float, str, type(None))):
             return DeferredOperations(self._call_binary_constant, (op, other),
                                       self.call_parts)
+        else:
+            raise TypeError(
+                'DeferredOperations are not compatible with '
+                '{}, type {}'.format(repr(other), repr(type(other))))
 
     def __eq__(self, other):
         return self._binary(operator.eq, other)
diff --git a/qcodes/utils/helpers.py b/qcodes/utils/helpers.py
index bcad2bbae92f..49a222001e7a 100644
--- a/qcodes/utils/helpers.py
+++ b/qcodes/utils/helpers.py
@@ -1,7 +1,5 @@
-from asyncio import iscoroutinefunction
 from collections import Iterable
 import time
-from inspect import signature
 import logging
 import math
 import sys
@@ -26,39 +24,6 @@ def is_sequence(obj):
     return isinstance(obj, Iterable) and not isinstance(obj, (str, bytes))
 
 
-def is_function(f, arg_count, coroutine=False):
-    '''
-    require a function that can accept the specified number of positional
-    arguments, which either is or is not a coroutine
-    type casting "functions" are allowed, but only in the 1-argument form
-    '''
-    if not isinstance(arg_count, int) or arg_count < 0:
-        raise TypeError('arg_count must be a non-negative integer')
-
-    if not (callable(f) and bool(coroutine) is iscoroutinefunction(f)):
-        return False
-
-    if isinstance(f, type):
-        # for type casting functions, eg int, str, float
-        # only support the one-parameter form of these,
-        # otherwise the user should make an explicit function.
-        return arg_count == 1
-
-    try:
-        sig = signature(f)
-    except ValueError:
-        # some built-in functions/methods don't describe themselves to inspect
-        # we already know it's a callable and coroutine is correct.
-        return True
-
-    try:
-        inputs = [0] * arg_count
-        sig.bind(*inputs)
-        return True
-    except TypeError:
-        return False
-
-
 # could use numpy.arange here, but
 # a) we don't want to require that as a dep so low level
 # b) I'd like to be more flexible with the sign of step
diff --git a/qcodes/utils/sync_async.py b/qcodes/utils/sync_async.py
index 1ab8fbb68b05..ad1e1ed22f80 100644
--- a/qcodes/utils/sync_async.py
+++ b/qcodes/utils/sync_async.py
@@ -1,6 +1,6 @@
 import asyncio
 
-from .helpers import is_function
+from .deferred_operations import is_function
 
 
 def wait_for_async(f, *args, **kwargs):

From 8b1f5c737f730710fdb7cfa3210977b7a1034ce1 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Fri, 6 May 2016 19:05:31 +0200
Subject: [PATCH 127/169] make sure data_manager agrees when a loop has been
 aborted

---
 qcodes/loops.py | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index e4dabc831226..f5b6634f5759 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -45,6 +45,7 @@
 from qcodes.station import Station
 from qcodes.data.data_set import new_data, DataMode
 from qcodes.data.data_array import DataArray
+from qcodes.data.manager import get_data_manager
 from qcodes.utils.helpers import wait_secs
 from qcodes.utils.multiprocessing import QcodesProcess
 from qcodes.utils.threading import thread_map
@@ -71,6 +72,9 @@ def get_bg(return_first=False):
     if loops:
         return loops[0]
 
+    # if we got here, there shouldn't be a loop running. Make sure the
+    # data manager, if there is one, agrees!
+    _clear_data_manager()
     return None
 
 
@@ -91,6 +95,14 @@ def halt_bg(timeout=5):
         loop.join(timeout/2)
         print('Background loop did not respond to halt signal, terminated')
 
+    _clear_data_manager()
+
+
+def _clear_data_manager():
+    dm = get_data_manager(only_existing=True)
+    if dm and dm.ask('get_measuring'):
+        dm.ask('end_data')
+
 
 # def measure(*actions):
 #     # measure has been moved into Station

From 15fa419142804a9946ed0d737921e3b277cc2b66 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 00:04:36 +0200
Subject: [PATCH 128/169] partial sync!

---
 qcodes/data/data_array.py | 67 +++++++++++++++++++++++--------
 qcodes/data/data_set.py   | 83 ++++++++++++++++++++++-----------------
 qcodes/data/manager.py    | 50 ++++++++++++-----------
 3 files changed, 126 insertions(+), 74 deletions(-)

diff --git a/qcodes/data/data_array.py b/qcodes/data/data_array.py
index 1cbfb32e6255..04c4269659d0 100644
--- a/qcodes/data/data_array.py
+++ b/qcodes/data/data_array.py
@@ -5,7 +5,7 @@
 
 
 class DataArray(DelegateAttributes):
-    '''
+    """
     A container for one parameter in a measurement loop
 
     If this is a measured parameter, This object doesn't contain
@@ -24,7 +24,7 @@ class DataArray(DelegateAttributes):
 
     Once the array is initialized, a DataArray acts a lot like a numpy array,
     because we delegate attributes through to the numpy array
-    '''
+    """
     def __init__(self, parameter=None, name=None, label=None, array_id=None,
                  set_arrays=(), size=None, action_indices=(),
                  preset_data=None):
@@ -67,7 +67,7 @@ def data_set(self, new_data_set):
         self._data_set = new_data_set
 
     def nest(self, size, action_index=None, set_array=None):
-        '''
+        """
         nest this array inside a new outer loop
 
         size: length of the new loop
@@ -76,7 +76,7 @@ def nest(self, size, action_index=None, set_array=None):
             if this DataArray *is* a setpoint array, you should omit both
             action_index and set_array, and it will reference itself as the
             set_array
-        '''
+        """
         if self.ndarray is not None and not self._preset:
             raise RuntimeError('Only preset arrays can be nested after data '
                                'is initialized! {}'.format(self))
@@ -105,11 +105,11 @@ def nest(self, size, action_index=None, set_array=None):
         return self
 
     def init_data(self, data=None):
-        '''
+        """
         create a data array (if one doesn't exist)
         if data is provided, this array is marked as a preset
         meaning it can still be nested around this data.
-        '''
+        """
         if data is not None:
             if not isinstance(data, np.ndarray):
                 if isinstance(data, collections.Iterator):
@@ -142,9 +142,9 @@ def _set_index_bounds(self):
         self._max_indices = tuple(d - 1 for d in self.size)
 
     def clear(self):
-        '''
+        """
         Fill the (already existing) data array with nan
-        '''
+        """
         # only floats can hold nan values. I guess we could
         # also raise an error in this case? But generally float is
         # what people want anyway.
@@ -153,13 +153,13 @@ def clear(self):
         self.ndarray.fill(float('nan'))
 
     def __setitem__(self, loop_indices, value):
-        '''
+        """
         set data values. Follows numpy syntax, allowing indices of lower
         dimensionality than the array, if value makes up the extra dimension(s)
 
         Also updates the record of modifications to the array. If you don't
         want this overhead, you can access self.ndarray directly.
-        '''
+        """
         if isinstance(loop_indices, collections.Iterable):
             loop_indices_tuple = loop_indices
         else:
@@ -176,10 +176,10 @@ def __getitem__(self, loop_indices):
     delegate_attr_objects = ['ndarray']
 
     def __len__(self):
-        '''
+        """
         must be explicitly delegated, because len() will look for this
         attribute to already exist
-        '''
+        """
         return len(self.ndarray)
 
     def _flat_index(self, indices, index_fill):
@@ -194,9 +194,9 @@ def _update_modified_range(self, low, high):
             self.modified_range = (low, high)
 
     def mark_saved(self):
-        '''
+        """
         after saving data, mark any outstanding modifications as saved
-        '''
+        """
         if self.modified_range:
             self.last_saved_index = max(self.last_saved_index or 0,
                                         self.modified_range[1])
@@ -204,15 +204,50 @@ def mark_saved(self):
         self.modified_range = None
 
     def clear_save(self):
-        '''
+        """
         make this array look unsaved, so we can force overwrite
         or rewrite, like if we're moving or copying the DataSet
-        '''
+        """
         if self.last_saved_index is not None:
             self._update_modified_range(0, self.last_saved_index)
 
         self.last_saved_index = None
 
+    def get_synced_index(self):
+        if not hasattr(self, 'synced_index'):
+            self.init_data()
+            self.synced_index = -1
+
+        return self.synced_index
+
+    def get_changes(self, synced_index):
+        latest_index = self.last_saved_index
+        if latest_index is None:
+            latest_index = -1
+        if self.modified_range:
+            latest_index = max(latest_index, self.modified_range[1])
+
+        vals = [
+            self.ndarray[np.unravel_index(i, self.ndarray.shape)]
+            for i in range(synced_index + 1, latest_index + 1)
+        ]
+
+        if self.array_id == 'avg_amplitude':
+            print(self.last_saved_index, self.modified_range, vals, self)
+
+        if vals:
+            return {
+                'start': synced_index + 1,
+                'stop': latest_index,
+                'vals': vals
+            }
+
+    def apply_changes(self, start, stop, vals):
+        for i, val in enumerate(vals):
+            index = np.unravel_index(i + start, self.ndarray.shape)
+            self.ndarray[index] = val
+        self.synced_index = stop
+
     def __repr__(self):
         array_id_or_none = ' {}'.format(self.array_id) if self.array_id else ''
         return '{}[{}]:{}\n{}'.format(self.__class__.__name__,
diff --git a/qcodes/data/data_set.py b/qcodes/data/data_set.py
index 8a605aa1601e..5a586e622659 100644
--- a/qcodes/data/data_set.py
+++ b/qcodes/data/data_set.py
@@ -19,7 +19,7 @@ class DataMode(Enum):
 
 def new_data(location=None, name=None, overwrite=False, io=None,
              data_manager=None, mode=DataMode.LOCAL, **kwargs):
-    '''
+    """
     Create a new DataSet. Arguments are the same as DataSet constructor, plus:
 
     overwrite: Are we allowed to overwrite an existing location? default False
@@ -35,7 +35,7 @@ def new_data(location=None, name=None, overwrite=False, io=None,
 
     name: an optional string to be passed to location_provider to augment
         the automatic location with something meaningful
-    '''
+    """
     if io is None:
         io = DataSet.default_io
 
@@ -58,7 +58,7 @@ def new_data(location=None, name=None, overwrite=False, io=None,
 
 
 def load_data(location=None, data_manager=None, formatter=None, io=None):
-    '''
+    """
     Load an existing DataSet. Arguments are a subset of the DataSet
     constructor:
 
@@ -76,7 +76,7 @@ def load_data(location=None, data_manager=None, formatter=None, io=None):
 
     formatter: as in DataSet
     io: as in DataSet
-    '''
+    """
     if data_manager is None:
         data_manager = get_data_manager(only_existing=True)
 
@@ -110,7 +110,7 @@ def _get_live_data(data_manager):
 
 
 class TimestampLocation:
-    '''
+    """
     This is the default DataSet Location provider.
     It provides a callable of one parameter (the io manager) that
     returns a new location string, which is currently unused.
@@ -120,7 +120,7 @@ class TimestampLocation:
     which can include slashes (forward and backward are equivalent)
     to create folder structure.
     Default format string is '%Y-%m-%d/%H-%M-%S'
-    '''
+    """
     def __init__(self, fmt='%Y-%m-%d/%H-%M-%S'):
         self.fmt = fmt
 
@@ -141,7 +141,7 @@ def __call__(self, io, name=None):
 
 
 class DataSet(DelegateAttributes):
-    '''
+    """
     A container for one complete measurement loop
     May contain many individual arrays with potentially different
     sizes and dimensionalities.
@@ -182,7 +182,7 @@ class DataSet(DelegateAttributes):
         if mode=LOCAL, otherwise the DataManager handles this (and generally
         writes more often because it's not tying up the main process to do so).
         use None to disable writing from calls to self.store
-    '''
+    """
 
     # ie data_array.arrays['vsd'] === data_array.vsd
     delegate_attr_dicts = ['arrays']
@@ -257,10 +257,10 @@ def _init_push_to_server(self, data_manager):
         self.data_manager = data_manager
 
     def init_on_server(self):
-        '''
+        """
         Configure this DataSet as the DataServer copy
         Should be run only by the DataServer itself.
-        '''
+        """
         if not self.arrays:
             raise RuntimeError('A server-side DataSet needs DataArrays.')
 
@@ -278,18 +278,18 @@ def _init_live(self, data_manager):
 
     @property
     def is_live_mode(self):
-        '''
+        """
         indicate whether this DataSet thinks it is live in the DataServer
         without actually talking to the DataServer or syncing with it
-        '''
+        """
         return self.mode in SERVER_MODES and self.data_manager and True
 
     @property
     def is_on_server(self):
-        '''
+        """
         Check whether this DataSet is being mirrored in the DataServer
         If it thought it was but isn't, convert it to mode=LOCAL
-        '''
+        """
         if not self.is_live_mode or self.location is False:
             return False
 
@@ -298,12 +298,12 @@ def is_on_server(self):
             return self.location == live_location
 
     def sync(self):
-        '''
+        """
         synchronize this data set with a possibly newer version either
         in storage or on the DataServer, depending on its mode
 
         returns: boolean, is this DataSet live on the server
-        '''
+        """
         # TODO: sync implies bidirectional... and it could be!
         # we should keep track of last sync timestamp and last modification
         # so we can tell whether this one, the other one, or both copies have
@@ -325,14 +325,15 @@ def sync(self):
 
         with self.data_manager.query_lock:
             if self.is_on_server:
-                # TODO: can we reduce the amount of data to send?
-                # seems like in the most general case this would need to
-                # remember each client DataSet on the server, and what has
-                # changed since that particular client last synced
-                # (at least first and last pt)
-                live_data = self.data_manager.ask('get_data').arrays
-                for array_id in self.arrays:
-                    self.arrays[array_id].ndarray = live_data[array_id].ndarray
+                synced_indices = {
+                    array_id: array.get_synced_index()
+                    for array_id, array in self.arrays.items()
+                }
+
+                changes = self.data_manager.ask('get_changes', synced_indices)
+
+                for array_id, array_changes in changes.items():
+                    self.arrays[array_id].apply_changes(**array_changes)
 
                 measuring = self.data_manager.ask('get_measuring')
                 if not measuring:
@@ -349,8 +350,18 @@ def sync(self):
                 self.read()
                 return False
 
+    def get_changes(self, synced_index):
+        changes = {}
+
+        for array_id, synced_index in synced_index.items():
+            array_changes = self.arrays[array_id].get_changes(synced_index)
+            if array_changes:
+                changes[array_id] = array_changes
+
+        return changes
+
     def add_array(self, data_array):
-        '''
+        """
         add one DataArray to this DataSet
 
         note: DO NOT just set data_set.arrays[id] = data_array
@@ -358,7 +369,7 @@ def add_array(self, data_array):
         reference back to this DataSet. It would also allow you to
         load the array in with different id than it holds itself.
 
-        '''
+        """
         # TODO: mask self.arrays so you *can't* set it directly
 
         if data_array.array_id in self.arrays:
@@ -370,10 +381,10 @@ def add_array(self, data_array):
         data_array.data_set = self
 
     def _clean_array_ids(self, arrays):
-        '''
+        """
         replace action_indices tuple with compact string array_ids
         stripping off as much extraneous info as possible
-        '''
+        """
         action_indices = [array.action_indices for array in arrays]
         array_names = set(array.name for array in arrays)
         for name in array_names:
@@ -416,14 +427,14 @@ def _clean_param_ids(self, arrays, name):
             array.array_id = name + ''.join('_' + str(i) for i in ai)
 
     def store(self, loop_indices, ids_values):
-        '''
+        """
         Set some collection of data points
 
         loop_indices: the indices within whatever loops we are inside
         values: a dict of action_index:value or array_id:value
             where value may be an arbitrarily nested list, to record
             many values at once into one array
-        '''
+        """
         if self.mode == DataMode.PUSH_TO_SERVER:
             self.data_manager.write('store_data', loop_indices, ids_values)
         else:
@@ -435,18 +446,18 @@ def store(self, loop_indices, ids_values):
                 self.last_write = time.time()
 
     def read(self):
-        '''
+        """
         Read the whole DataSet from storage, overwriting the local data
-        '''
+        """
         if self.location is False:
             return
         self.formatter.read(self)
 
     def write(self):
-        '''
+        """
         Write the whole (or only changed parts) DataSet to storage,
         overwriting the existing storage if any.
-        '''
+        """
         if self.mode != DataMode.LOCAL:
             raise RuntimeError('This object is connected to a DataServer, '
                                'which handles writing automatically.')
@@ -456,9 +467,9 @@ def write(self):
         self.formatter.write(self)
 
     def finalize(self):
-        '''
+        """
         Mark the DataSet as complete
-        '''
+        """
         if self.mode == DataMode.PUSH_TO_SERVER:
             self.data_manager.ask('end_data')
         elif self.mode == DataMode.LOCAL:
diff --git a/qcodes/data/manager.py b/qcodes/data/manager.py
index b7e0ee6985f3..5936fe1daa0a 100644
--- a/qcodes/data/manager.py
+++ b/qcodes/data/manager.py
@@ -6,10 +6,10 @@
 
 
 def get_data_manager(only_existing=False):
-    '''
+    """
     create or retrieve the storage manager
     makes sure we don't accidentally create multiple DataManager processes
-    '''
+    """
     dm = DataManager.default
     if dm and dm._server.is_alive():
         return dm
@@ -19,10 +19,10 @@ def get_data_manager(only_existing=False):
 
 
 class NoData:
-    '''
+    """
     A placeholder object for DataServer to hold
     when there is no loop running.
-    '''
+    """
     location = None
 
     def store(self, *args, **kwargs):
@@ -34,23 +34,23 @@ def write(self, *args, **kwargs):
 
 class DataManager(ServerManager):
     default = None
-    '''
+    """
     creates a separate process (DataServer) that holds running measurement
     and monitor data, and manages writing these to disk or other storage
 
     DataServer communicates with other processes through messages
     Written using multiprocessing Queue's, but should be easily
     extensible to other messaging systems
-    '''
+    """
     def __init__(self, query_timeout=2):
         type(self).default = self
         super().__init__(name='DataServer', server_class=DataServer)
 
     def restart(self, force=False):
-        '''
+        """
         Restart the DataServer
         Use force=True to abort a running measurement.
-        '''
+        """
         if (not force) and self.ask('get_data', 'location'):
             raise RuntimeError('A measurement is running. Use '
                                'restart(force=True) to override.')
@@ -58,7 +58,7 @@ def restart(self, force=False):
 
 
 class DataServer:
-    '''
+    """
     Running in its own process, receives, holds, and returns current `Loop` and
     monitor data, and writes it to disk (or other storage)
 
@@ -69,7 +69,7 @@ class DataServer:
     they are nearly identical objects, but are configured differently so that
     the loop `DataSet` doesn't hold any data itself, it only passes that data
     on to the `DataServer`
-    '''
+    """
     default_storage_period = 1  # seconds between data storage calls
     queries_per_store = 5
     default_monitor_period = 60  # seconds between monitoring storage calls
@@ -138,17 +138,17 @@ def _post_error(self, e):
     ######################################################################
 
     def handle_halt(self):
-        '''
+        """
         Quit this DataServer
-        '''
+        """
         self._running = False
         self._reply(True)
 
     def handle_new_data(self, data_set):
-        '''
+        """
         Load a new (normally empty) DataSet into the DataServer, and
         prepare it to start receiving and storing data
-        '''
+        """
         if self._measuring:
             raise RuntimeError('Already executing a measurement')
 
@@ -158,29 +158,35 @@ def handle_new_data(self, data_set):
         self._reply(True)
 
     def handle_end_data(self):
-        '''
+        """
         Mark this DataSet as complete and write its final changes to storage
-        '''
+        """
         self._data.write()
         self._measuring = False
         self._reply(True)
 
     def handle_store_data(self, *args):
-        '''
+        """
         Put some data into the DataSet
         This is the only query that does not return a value, so the measurement
         loop does not need to wait for a reply.
-        '''
+        """
         self._data.store(*args)
 
     def handle_get_measuring(self):
-        '''
+        """
         Is a measurement loop presently running?
-        '''
+        """
         self._reply(self._measuring)
 
     def handle_get_data(self, attr=None):
-        '''
+        """
         Return the active DataSet or some attribute of it
-        '''
+        """
         self._reply(getattr(self._data, attr) if attr else self._data)
+
+    def handle_get_changes(self, synced_indices):
+        """
+        Return all new data after the last sync
+        """
+        self._reply(self._data.get_changes(synced_indices))

From ac190b4729686f2f4996a265f8a3a99e33d97251 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 00:17:04 +0200
Subject: [PATCH 129/169] drop debug code - the problem with avg_amplitude was
 fixed by #148

---
 qcodes/data/data_array.py | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/qcodes/data/data_array.py b/qcodes/data/data_array.py
index aee14db7f344..43993fbf79cb 100644
--- a/qcodes/data/data_array.py
+++ b/qcodes/data/data_array.py
@@ -246,9 +246,6 @@ def get_changes(self, synced_index):
             for i in range(synced_index + 1, latest_index + 1)
         ]
 
-        if self.array_id == 'avg_amplitude':
-            print(self.last_saved_index, self.modified_range, vals, self)
-
         if vals:
             return {
                 'start': synced_index + 1,

From 658d7b5a8f5e143f62b13190933f6661c9f6c616 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 22:39:44 +0200
Subject: [PATCH 130/169] more helpful errors on bad Loop actions

---
 qcodes/loops.py           | 23 ++++++++++++++++++++---
 qcodes/station.py         |  7 +++++++
 qcodes/tests/test_loop.py | 15 +++++++++------
 3 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index e4dabc831226..7624fd6c653d 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -163,12 +163,31 @@ def each(self, *actions):
                 default = Station.default.default_measurement
                 actions[i] = action.each(*default)
 
+        self.validate_actions(*actions)
+
         if self.nested_loop:
             # recurse into the innermost loop and apply these actions there
             actions = [self.nested_loop.each(*actions)]
 
         return ActiveLoop(self.sweep_values, self.delay, *actions)
 
+    @staticmethod
+    def validate_actions(*actions):
+        """
+        Whitelist acceptable actions, so we can give nice error messages
+        if an action is not recognized
+        """
+        for action in actions:
+            if isinstance(action, (Task, Wait, ActiveLoop)):
+                continue
+            if hasattr(action, 'get'):
+                continue
+            raise TypeError('Unrecognized action:', action,
+                            'Allowed actions are: objects (parameters) with '
+                            'a `get` method, and `Task`, `Wait`, and '
+                            '`ActiveLoop` objects. `Loop` objects are OK too, '
+                            'except in Station default measurements.')
+
     def run(self, *args, **kwargs):
         '''
         shortcut to run a loop with the default measurement set
@@ -516,10 +535,8 @@ def _compile_one(self, action, new_action_indices):
             return Task(self._wait, action.delay)
         elif isinstance(action, ActiveLoop):
             return _Nest(action, new_action_indices)
-        elif callable(action):
-            return action
         else:
-            raise TypeError('unrecognized action', action)
+            return action
 
     def _run_wrapper(self, *args, **kwargs):
         try:
diff --git a/qcodes/station.py b/qcodes/station.py
index ba5a5f500e24..efc14620dbf4 100644
--- a/qcodes/station.py
+++ b/qcodes/station.py
@@ -57,6 +57,13 @@ def set_measurement(self, *actions):
         default Station, and any measurements among them can be done once
         by .measure
         '''
+        # Validate now so the user gets an error message ASAP
+        # and so we don't accept `Loop` as an action here, where
+        # it would cause infinite recursion.
+        # We need to import Loop inside here to avoid circular import
+        from .loops import Loop
+        Loop.validate_actions(*actions)
+
         self.default_measurement = actions
 
     def measure(self, *actions):
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 2af44ecd0134..0d0e492b4d24 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -372,14 +372,17 @@ def test_composite_params(self):
         self.assertEqual(data.index1.tolist(), [[[0, 1]] * 2] * 2)
 
     def test_bad_actors(self):
-        # would be nice to find errors at .each, but for now we find them
-        # at .run
-        loop = Loop(self.p1[1:3:1], 0.001).each(self.p1, 42)
-        with self.assertRaises(TypeError):
-            loop.run_temp()
+        def f():
+            return 42
+
+        for bad_action in (f, 42):
+            with self.assertRaises(TypeError):
+                # include a good action too, just to make sure we look
+                # at the whole list
+                Loop(self.p1[1:3:1], 0.001).each(self.p1, bad_action)
 
-        # at least invalid sweep values we find at .each
         with self.assertRaises(ValueError):
+            # invalid sweep values
             Loop(self.p1[-20:20:1], 0.001).each(self.p1)
 
     def test_very_short_delay(self):

From 036ff870579c4c24dd81c2d3d71755b2a4cef88a Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 23:21:53 +0200
Subject: [PATCH 131/169] remove enqueue kwarg in Loop.run

---
 qcodes/loops.py           | 15 +++++++--------
 qcodes/tests/test_loop.py | 24 ++++++++++++++++++++----
 2 files changed, 27 insertions(+), 12 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index e4dabc831226..fb8666c0beac 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -409,7 +409,7 @@ def run_temp(self, **kwargs):
         return self.run(background=False, quiet=True,
                         data_manager=False, location=False, **kwargs)
 
-    def run(self, background=True, use_threads=True, enqueue=False,
+    def run(self, background=True, use_threads=True,
             quiet=False, data_manager=None, **kwargs):
         '''
         execute this loop
@@ -419,8 +419,6 @@ def run(self, background=True, use_threads=True, enqueue=False,
         use_threads: (default True): whenever there are multiple `get` calls
             back-to-back, execute them in separate threads so they run in
             parallel (as long as they don't block each other)
-        enqueue: (default False): wait for a previous background sweep to
-            finish? If false, will raise an error if another sweep is running
         quiet: (default False): set True to not print anything except errors
         data_manager: a DataManager instance (omit to use default,
             False to store locally)
@@ -446,11 +444,9 @@ def run(self, background=True, use_threads=True, enqueue=False,
 
         prev_loop = get_bg()
         if prev_loop:
-            if enqueue:
-                prev_loop.join()  # wait until previous loop finishes
-            else:
-                raise RuntimeError(
-                    'a loop is already running in the background')
+            print('Waiting for the previous background Loop to finish...')
+            prev_loop.join()
+
         if data_manager is False:
             data_mode = DataMode.LOCAL
         else:
@@ -461,6 +457,9 @@ def run(self, background=True, use_threads=True, enqueue=False,
         self.set_common_attrs(data_set=data_set, use_threads=use_threads,
                               signal_queue=self.signal_queue)
 
+        if prev_loop:
+            print('...done. Starting ' + (data_set.location or 'new loop'))
+
         if background:
             p = QcodesProcess(target=self._run_wrapper, name=MP_NAME)
             p.is_sweep = True
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 2af44ecd0134..2adb936dd945 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -106,12 +106,28 @@ def test_foreground_no_datamanager(self):
     def test_enqueue(self):
         c1 = self.gates.chan1
         loop = Loop(c1[1:5:1], 0.01).each(c1)
-        loop.run(location=self.location, quiet=True)
+        data1 = loop.run(location=self.location, quiet=True)
+
+        # second running of the loop should be enqueued, blocks until
+        # the first one finishes.
+        # TODO: check what it prints?
+        data2 = loop.run(location=self.location2, quiet=True)
+
+        data1.sync()
+        data2.sync()
+        self.assertEqual(data1.chan1.tolist(), [1, 2, 3, 4])
+        for v in data2.chan1:
+            self.assertTrue(np.isnan(v))
 
-        with self.assertRaises(RuntimeError):
-            loop.run(location=self.location2, quiet=True)
-        loop.run(location=self.location2, quiet=True, enqueue=True)
         loop.process.join()
+        data2.sync()
+        self.assertEqual(data2.chan1.tolist(), [1, 2, 3, 4])
+
+        # and while we're here, check that running a loop in the
+        # foreground *after* the background clears its .process
+        self.assertTrue(hasattr(loop, 'process'))
+        loop.run_temp()
+        self.assertFalse(hasattr(loop, 'process'))
 
 
 def sleeper(t):

From 21dc62e6e1bec77861638ce234fb7f032e73aae7 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 23:29:58 +0200
Subject: [PATCH 132/169] flush so we see the "waiting" message immediately

---
 qcodes/loops.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index fb8666c0beac..1afffe707ac5 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -444,7 +444,8 @@ def run(self, background=True, use_threads=True,
 
         prev_loop = get_bg()
         if prev_loop:
-            print('Waiting for the previous background Loop to finish...')
+            print('Waiting for the previous background Loop to finish...',
+                  flush=True)
             prev_loop.join()
 
         if data_manager is False:
@@ -458,7 +459,8 @@ def run(self, background=True, use_threads=True,
                               signal_queue=self.signal_queue)
 
         if prev_loop:
-            print('...done. Starting ' + (data_set.location or 'new loop'))
+            print('...done. Starting ' + (data_set.location or 'new loop'),
+                  flush=True)
 
         if background:
             p = QcodesProcess(target=self._run_wrapper, name=MP_NAME)

From 23480d2fdc4c2fed553aa2c0d95c696ba66226eb Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 23:40:39 +0200
Subject: [PATCH 133/169] queue messages should respect quiet

---
 qcodes/loops.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 1afffe707ac5..9917eb58d9d6 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -444,8 +444,9 @@ def run(self, background=True, use_threads=True,
 
         prev_loop = get_bg()
         if prev_loop:
-            print('Waiting for the previous background Loop to finish...',
-                  flush=True)
+            if not quiet:
+                print('Waiting for the previous background Loop to finish...',
+                      flush=True)
             prev_loop.join()
 
         if data_manager is False:
@@ -458,7 +459,7 @@ def run(self, background=True, use_threads=True,
         self.set_common_attrs(data_set=data_set, use_threads=use_threads,
                               signal_queue=self.signal_queue)
 
-        if prev_loop:
+        if prev_loop and not quiet:
             print('...done. Starting ' + (data_set.location or 'new loop'),
                   flush=True)
 

From b7d39e0818da58c6b168a910a51723bf38ff4b17 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 23:55:21 +0200
Subject: [PATCH 134/169] add name/names to the validate_actions error message

---
 qcodes/loops.py | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 7624fd6c653d..ce0c0aff8293 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -184,9 +184,10 @@ def validate_actions(*actions):
                 continue
             raise TypeError('Unrecognized action:', action,
                             'Allowed actions are: objects (parameters) with '
-                            'a `get` method, and `Task`, `Wait`, and '
-                            '`ActiveLoop` objects. `Loop` objects are OK too, '
-                            'except in Station default measurements.')
+                            'a `get` method and `name` or `names` attribute, '
+                            'and `Task`, `Wait`, and `ActiveLoop` objects. '
+                            '`Loop` objects are OK too, except in Station '
+                            'default measurements.')
 
     def run(self, *args, **kwargs):
         '''

From 0122528f97c181838a8aa29b74cfeef245f49e9b Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sat, 7 May 2016 23:57:28 +0200
Subject: [PATCH 135/169] better test for name/names if we're going to tell
 people they need this!

---
 qcodes/loops.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index ce0c0aff8293..14e65c63c08d 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -180,7 +180,8 @@ def validate_actions(*actions):
         for action in actions:
             if isinstance(action, (Task, Wait, ActiveLoop)):
                 continue
-            if hasattr(action, 'get'):
+            if hasattr(action, 'get') and (hasattr(action, 'name') or
+                                           hasattr(action, 'names')):
                 continue
             raise TypeError('Unrecognized action:', action,
                             'Allowed actions are: objects (parameters) with '

From cd614d5a7138a6277bf04ab253fb5246271429a7 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sun, 8 May 2016 00:03:35 +0200
Subject: [PATCH 136/169] test minimal parameters in validate_actions

---
 qcodes/tests/test_loop.py | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 0d0e492b4d24..9d93a97dc1cb 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -375,15 +375,35 @@ def test_bad_actors(self):
         def f():
             return 42
 
-        for bad_action in (f, 42):
+        class NoName:
+            def get(self):
+                return 42
+
+        class HasName:
+            def get(self):
+                return 42
+
+            name = 'IHazName!'
+
+        class HasNames:
+            def get(self):
+                return 42
+
+            names = 'Namezz'
+
+        # first two minimal working gettables
+        Loop(self.p1[1:3:1]).each(HasName())
+        Loop(self.p1[1:3:1]).each(HasNames())
+
+        for bad_action in (f, 42, NoName()):
             with self.assertRaises(TypeError):
                 # include a good action too, just to make sure we look
                 # at the whole list
-                Loop(self.p1[1:3:1], 0.001).each(self.p1, bad_action)
+                Loop(self.p1[1:3:1]).each(self.p1, bad_action)
 
         with self.assertRaises(ValueError):
             # invalid sweep values
-            Loop(self.p1[-20:20:1], 0.001).each(self.p1)
+            Loop(self.p1[-20:20:1]).each(self.p1)
 
     def test_very_short_delay(self):
         with LogCapture() as s:

From ee545d8f05921587e8f2dbc4ea06eff1ac067a76 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Sun, 8 May 2016 23:00:45 +0200
Subject: [PATCH 137/169] add BreakIf to validate_actions

---
 qcodes/loops.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index ce78f6b900f5..28a1ef3c8c3e 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -179,7 +179,7 @@ def validate_actions(*actions):
         if an action is not recognized
         """
         for action in actions:
-            if isinstance(action, (Task, Wait, ActiveLoop)):
+            if isinstance(action, (Task, Wait, BreakIf, ActiveLoop)):
                 continue
             if hasattr(action, 'get') and (hasattr(action, 'name') or
                                            hasattr(action, 'names')):
@@ -187,9 +187,9 @@ def validate_actions(*actions):
             raise TypeError('Unrecognized action:', action,
                             'Allowed actions are: objects (parameters) with '
                             'a `get` method and `name` or `names` attribute, '
-                            'and `Task`, `Wait`, and `ActiveLoop` objects. '
-                            '`Loop` objects are OK too, except in Station '
-                            'default measurements.')
+                            'and `Task`, `Wait`, `BreakIf`, and `ActiveLoop` '
+                            'objects. `Loop` objects are OK too, except in '
+                            'Station default measurements.')
 
     def run(self, *args, **kwargs):
         '''

From 27e653315b7c5544da36d8b8f46cd02550b81e41 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Mon, 9 May 2016 13:46:37 +0200
Subject: [PATCH 138/169] improve documentation of notebook detection function

---
 qcodes/utils/helpers.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/qcodes/utils/helpers.py b/qcodes/utils/helpers.py
index bcad2bbae92f..29fc1c819fa0 100644
--- a/qcodes/utils/helpers.py
+++ b/qcodes/utils/helpers.py
@@ -9,9 +9,14 @@
 import multiprocessing as mp
 
 
+def is_interactive():
+    import __main__ as main
+    return not hasattr(main, '__file__')
+
 def in_notebook():
     '''
-    is this code in a process directly connected to a jupyter notebook?
+    Returns True if the code is running with a ipython or jypyter
+    This could mean we are connected to a notebook, but this is not guaranteed.
     see: http://stackoverflow.com/questions/15411967
     '''
     return 'ipy' in repr(sys.stdout)

From a78790b596579c0fd15439c2be346ec29175e9bd Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Mon, 9 May 2016 14:32:24 +0200
Subject: [PATCH 139/169] fix plot.update() for plain data_array

---
 qcodes/plots/base.py | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 0b7830579346..2d49857ac8f1 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -70,7 +70,8 @@ def add_updater(self, updater, plot_config):
             for key in self.data_keys:
                 data_array = plot_config.get(key, '')
                 if hasattr(data_array, 'data_set'):
-                    self.data_updaters.add(data_array.data_set.sync)
+                    if data_array.data_set is not None:
+                        self.data_updaters.add(data_array.data_set.sync)
 
         if self.data_updaters:
             self.update_widget.interval = self.interval
@@ -88,9 +89,10 @@ def get_default_title(self):
             for part in self.data_keys:
                 data_array = config.get(part, '')
                 if hasattr(data_array, 'data_set'):
-                    location = data_array.data_set.location
-                    if location and location not in title_parts:
-                        title_parts.append(location)
+                    if data_array.data_set is not None:
+                        location = data_array.data_set.location
+                        if location and location not in title_parts:
+                            title_parts.append(location)
         return ', '.join(title_parts)
 
     def get_label(self, data_array):

From 97567823a0665bff7abadfab1e596a4c81b51885 Mon Sep 17 00:00:00 2001
From: Pieter Eendebak 
Date: Tue, 10 May 2016 10:42:44 +0200
Subject: [PATCH 140/169] fix warnings in plotting

---
 qcodes/plots/pyqtgraph.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index e35177d47f8a..c12d2315f028 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -133,9 +133,14 @@ def _draw_plot(self, subplot_object, y, x=None, color=None, width=None,
             if 'symbolBrush' not in kwargs:
                 kwargs['symbolBrush'] = color
 
-        return subplot_object.plot(*self._line_data(x, y), antialias=antialias,
+        # suppress warnings when there are only NaN to plot
+        with warnings.catch_warnings():
+            warnings.filterwarnings("ignore", 'All-NaN axis encountered')
+            warnings.filterwarnings("ignore", 'All-NaN slice encountered')
+            pl = subplot_object.plot(*self._line_data(x, y), antialias=antialias,
                                    **kwargs)
-
+        return pl
+       
     def _line_data(self, x, y):
         return [self._clean_array(arg) for arg in [x, y] if arg is not None]
 

From 4c9f61d05d6dc331cf6c1fa951f90fdcc8dd6408 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 10 May 2016 12:03:02 +0200
Subject: [PATCH 141/169] lint

---
 qcodes/plots/pyqtgraph.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/qcodes/plots/pyqtgraph.py b/qcodes/plots/pyqtgraph.py
index c12d2315f028..2075434631ed 100644
--- a/qcodes/plots/pyqtgraph.py
+++ b/qcodes/plots/pyqtgraph.py
@@ -59,7 +59,7 @@ def __init__(self, *args, figsize=(1000, 600), interval=0.25,
 
         if not show_window:
             self.win.hide()
-            
+
     def _init_qt(self):
         # starting the process for the pyqtgraph plotting
         # You do not want a new process to be created every time you start a
@@ -135,12 +135,12 @@ def _draw_plot(self, subplot_object, y, x=None, color=None, width=None,
 
         # suppress warnings when there are only NaN to plot
         with warnings.catch_warnings():
-            warnings.filterwarnings("ignore", 'All-NaN axis encountered')
-            warnings.filterwarnings("ignore", 'All-NaN slice encountered')
-            pl = subplot_object.plot(*self._line_data(x, y), antialias=antialias,
-                                   **kwargs)
+            warnings.filterwarnings('ignore', 'All-NaN axis encountered')
+            warnings.filterwarnings('ignore', 'All-NaN slice encountered')
+            pl = subplot_object.plot(*self._line_data(x, y),
+                                     antialias=antialias, **kwargs)
         return pl
-       
+
     def _line_data(self, x, y):
         return [self._clean_array(arg) for arg in [x, y] if arg is not None]
 

From 5bbdceb8fcab8e7d4072f4528eabd68ad865c21a Mon Sep 17 00:00:00 2001
From: Pieter Eendebak 
Date: Tue, 10 May 2016 12:04:20 +0200
Subject: [PATCH 142/169] remove function (will be moved to other PR)

---
 qcodes/utils/helpers.py | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/qcodes/utils/helpers.py b/qcodes/utils/helpers.py
index 29fc1c819fa0..699fd12a3932 100644
--- a/qcodes/utils/helpers.py
+++ b/qcodes/utils/helpers.py
@@ -9,10 +9,6 @@
 import multiprocessing as mp
 
 
-def is_interactive():
-    import __main__ as main
-    return not hasattr(main, '__file__')
-
 def in_notebook():
     '''
     Returns True if the code is running with a ipython or jypyter

From 6405e1b7c58bfc5177b579e3bbae20dceaf5631d Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 10 May 2016 15:16:50 +0200
Subject: [PATCH 143/169] Loop.then

---
 qcodes/loops.py           | 79 ++++++++++++++++++++++++++++++++++++---
 qcodes/tests/test_loop.py | 55 +++++++++++++++++++++++++++
 2 files changed, 129 insertions(+), 5 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 28a1ef3c8c3e..18b28db24ae8 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -126,6 +126,7 @@ def __init__(self, sweep_values, delay=0):
         self.sweep_values = sweep_values
         self.delay = delay
         self.nested_loop = None
+        self.then_actions = ()
 
     def loop(self, sweep_values, delay=0):
         '''
@@ -136,16 +137,22 @@ def loop(self, sweep_values, delay=0):
 
         returns a new Loop object - the original is untouched
         '''
-        out = Loop(self.sweep_values, self.delay)
+        out = self._copy()
 
-        if self.nested_loop:
+        if out.nested_loop:
             # nest this new loop inside the deepest level
-            out.nested_loop = self.nested_loop.loop(sweep_values, delay)
+            out.nested_loop = out.nested_loop.loop(sweep_values, delay)
         else:
             out.nested_loop = Loop(sweep_values, delay)
 
         return out
 
+    def _copy(self):
+        out = Loop(self.sweep_values, self.delay)
+        out.nested_loop = self.nested_loop
+        out.then_actions = self.then_actions
+        return out
+
     def each(self, *actions):
         '''
         Perform a set of actions at each setting of this loop
@@ -170,7 +177,8 @@ def each(self, *actions):
             # recurse into the innermost loop and apply these actions there
             actions = [self.nested_loop.each(*actions)]
 
-        return ActiveLoop(self.sweep_values, self.delay, *actions)
+        return ActiveLoop(self.sweep_values, self.delay, *actions,
+                          then_actions=self.then_actions)
 
     @staticmethod
     def validate_actions(*actions):
@@ -207,6 +215,45 @@ def run_temp(self, *args, **kwargs):
         return self.run(*args, background=False, quiet=True,
                         data_manager=False, location=False, **kwargs)
 
+    def then(self, *actions, overwrite=False):
+        """
+        Attach actions to be performed after the loop completes.
+        These can only be `Task` and `Wait` actions, as they may not generate
+        any data.
+
+        returns a new Loop object - the original is untouched
+
+        This is more naturally done to an ActiveLoop (ie after .each())
+        and can also be done there, but it's allowed at this stage too so that
+        you can define final actions and share them among several `Loop`s that
+        have different loop actions.
+
+        *actions: `Task` and `Wait` objects to execute in order
+
+        overwrite: (default False) whether subsequent .then() calls (including
+            calls in an ActiveLoop after .then() has already been called on
+            the Loop) will add to each other or overwrite the earlier ones.
+        """
+        return _attach_then_actions(self._copy(), actions, overwrite)
+
+
+def _attach_then_actions(loop, actions, overwrite):
+    """
+    inner code for both Loop.then and ActiveLoop.then
+    """
+    for action in actions:
+        if not isinstance(action, (Task, Wait)):
+            raise TypeError('Unrecognized action:', action,
+                            '.then() allows only `Task` and `Wait` '
+                            'actions.')
+
+    if overwrite:
+        loop.then_actions = actions
+    else:
+        loop.then_actions = loop.then_actions + actions
+
+    return loop
+
 
 class ActiveLoop:
     '''
@@ -219,10 +266,11 @@ class ActiveLoop:
     '''
     HALT = 'HALT LOOP'
 
-    def __init__(self, sweep_values, delay, *actions):
+    def __init__(self, sweep_values, delay, *actions, then_actions=()):
         self.sweep_values = sweep_values
         self.delay = delay
         self.actions = actions
+        self.then_actions = then_actions
 
         # compile now, but don't save the results
         # just used for preemptive error checking
@@ -244,6 +292,24 @@ def __init__(self, sweep_values, delay, *actions):
 
         self._monitor = None  # TODO: how to specify this?
 
+    def then(self, *actions, overwrite=False):
+        """
+        Attach actions to be performed after the loop completes.
+        These can only be `Task` and `Wait` actions, as they may not generate
+        any data.
+
+        returns a new ActiveLoop object - the original is untouched
+
+        *actions: `Task` and `Wait` objects to execute in order
+
+        overwrite: (default False) whether subsequent .then() calls (including
+            calls in an ActiveLoop after .then() has already been called on
+            the Loop) will add to each other or overwrite the earlier ones.
+        """
+        loop = ActiveLoop(self.sweep_values, self.delay, *self.actions,
+                          then_actions=self.then_actions)
+        return _attach_then_actions(loop, actions, overwrite)
+
     def containers(self):
         '''
         Finds the data arrays that will be created by the actions in this
@@ -544,6 +610,9 @@ def _compile_one(self, action, new_action_indices):
     def _run_wrapper(self, *args, **kwargs):
         try:
             self._run_loop(*args, **kwargs)
+
+            for f in self._compile_actions(self.then_actions, ()):
+                f()
         finally:
             if hasattr(self, 'data_set'):
                 self.data_set.finalize()
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 9a447469d7ae..860b677acf60 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -444,6 +444,61 @@ def test_breakif(self):
         with self.assertRaises(TypeError):
             BreakIf(self.p1.set)
 
+    def test_then_construction(self):
+        loop = Loop(self.p1[1:6:1])
+        task1 = Task(self.p1.set, 2)
+        task2 = Wait(0.02)
+        loop2 = loop.then(task1)
+        loop3 = loop2.then(task2, task1)
+        loop4 = loop3.then(task2, overwrite=True)
+        loop5 = loop4.each(self.p1, BreakIf(self.p1 >= 3))
+        loop6 = loop5.then(task1)
+        loop7 = loop6.then(task1, overwrite=True)
+
+        # original loop is untouched, same as .each and .loop
+        self.assertEqual(loop.then_actions, ())
+
+        # but loop2 has the task we asked for
+        self.assertEqual(loop2.then_actions, (task1,))
+
+        # loop3 gets the other tasks appended
+        self.assertEqual(loop3.then_actions, (task1, task2, task1))
+
+        # loop4 gets only the new one
+        self.assertEqual(loop4.then_actions, (task2,))
+
+        # tasks survive .each
+        self.assertEqual(loop5.then_actions, (task2,))
+
+        # and ActiveLoop.then works the same way as Loop.then
+        self.assertEqual(loop6.then_actions, (task2, task1))
+        self.assertEqual(loop7.then_actions, (task1,))
+
+        # .then rejects Loops and others that are valid loop actions
+        for action in (loop2, loop7, BreakIf(self.p1 >= 3), self.p1,
+                       True, 42):
+            with self.assertRaises(TypeError):
+                loop.then(action)
+
+    def test_then_action(self):
+        nan = float('nan')
+        self.p1.set(5)
+        f_calls = []
+
+        def f():
+            f_calls.append(1)
+
+        data = Loop(self.p1[1:6:1]).each(
+            self.p1, BreakIf(self.p1 >= 3)
+        ).then(
+            Task(self.p1.set, 2), Wait(0.01), Task(f)
+        ).run_temp()
+
+        self.assertEqual(repr(data.p1.tolist()),
+                         repr([1., 2., 3., nan, nan]))
+        self.assertEqual(self.p1.get(), 2)
+        self.assertEqual(len(f_calls), 1)
+
 
 class AbortingGetter(ManualParameter):
     '''

From 42ea2e4df4ff169a8e465bc8d18d3884864e48ff Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 10 May 2016 15:21:37 +0200
Subject: [PATCH 144/169] ''' -> """ loops.py

---
 qcodes/loops.py | 72 ++++++++++++++++++++++++-------------------------
 1 file changed, 36 insertions(+), 36 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index d734b54f1dcc..bfc62735e7d0 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -1,4 +1,4 @@
-'''
+"""
 Data acquisition loops
 
 The general scheme is:
@@ -36,7 +36,7 @@
     ActiveLoop (or Loop, will be activated with default measurement)
     Task: any callable that does not generate data
     Wait: a delay
-'''
+"""
 from datetime import datetime
 import multiprocessing as mp
 import time
@@ -56,14 +56,14 @@
 
 
 def get_bg(return_first=False):
-    '''
+    """
     find the active background measurement process, if any
     returns None otherwise
 
     return_first: if there are multiple loops running return the first anyway.
         If false, multiple loops is a RuntimeError.
         default False
-    '''
+    """
     processes = mp.active_children()
     loops = [p for p in processes if getattr(p, 'name', '') == MP_NAME]
 
@@ -80,9 +80,9 @@ def get_bg(return_first=False):
 
 
 def halt_bg(timeout=5):
-    '''
+    """
     Stop the active background measurement process, if any
-    '''
+    """
     loop = get_bg(return_first=True)
     if not loop:
         print('No loop running')
@@ -113,7 +113,7 @@ def _clear_data_manager():
 
 
 class Loop:
-    '''
+    """
     The entry point for creating measurement loops
 
     sweep_values - a SweepValues or compatible object describing what
@@ -131,7 +131,7 @@ class Loop:
     `Parameter`s to measure, `Task`s to do (any callable that does not yield
     data), `Wait` times, or other `ActiveLoop`s or `Loop`s to nest inside
     this one.
-    '''
+    """
     def __init__(self, sweep_values, delay=0):
         if not delay >= 0:
             raise ValueError('delay must be > 0, not {}'.format(repr(delay)))
@@ -141,14 +141,14 @@ def __init__(self, sweep_values, delay=0):
         self.then_actions = ()
 
     def loop(self, sweep_values, delay=0):
-        '''
+        """
         Nest another loop inside this one
 
         Loop(sv1, d1).loop(sv2, d2).each(*a) is equivalent to:
         Loop(sv1, d1).each(Loop(sv2, d2).each(*a))
 
         returns a new Loop object - the original is untouched
-        '''
+        """
         out = self._copy()
 
         if out.nested_loop:
@@ -166,7 +166,7 @@ def _copy(self):
         return out
 
     def each(self, *actions):
-        '''
+        """
         Perform a set of actions at each setting of this loop
 
         Each action can be:
@@ -174,7 +174,7 @@ def each(self, *actions):
         - a Task to execute
         - a Wait
         - another Loop or ActiveLoop
-        '''
+        """
         actions = list(actions)
 
         # check for nested Loops, and activate them with default measurement
@@ -212,18 +212,18 @@ def validate_actions(*actions):
                             'Station default measurements.')
 
     def run(self, *args, **kwargs):
-        '''
+        """
         shortcut to run a loop with the default measurement set
         stored by Station.set_measurement
-        '''
+        """
         default = Station.default.default_measurement
         return self.each(*default).run(*args, **kwargs)
 
     def run_temp(self, *args, **kwargs):
-        '''
+        """
         shortcut to run a loop in the foreground as a temporary dataset
         using the default measurement set
-        '''
+        """
         return self.run(*args, background=False, quiet=True,
                         data_manager=False, location=False, **kwargs)
 
@@ -268,14 +268,14 @@ def _attach_then_actions(loop, actions, overwrite):
 
 
 class ActiveLoop:
-    '''
+    """
     Created by attaching actions to a `Loop`, this is the object that actually
     runs a measurement loop. An `ActiveLoop` can no longer be nested, only run,
     or used as an action inside another `Loop` which will run the whole thing.
 
     The `ActiveLoop` determines what `DataArray`s it will need to hold the data
     it collects, and it creates a `DataSet` holding these `DataArray`s
-    '''
+    """
     HALT = 'HALT LOOP'
 
     def __init__(self, sweep_values, delay, *actions, then_actions=()):
@@ -323,12 +323,12 @@ def then(self, *actions, overwrite=False):
         return _attach_then_actions(loop, actions, overwrite)
 
     def containers(self):
-        '''
+        """
         Finds the data arrays that will be created by the actions in this
         loop, and nests them inside this level of the loop.
 
         Recursively calls `.containers` on any enclosed actions.
-        '''
+        """
         loop_size = len(self.sweep_values)
         loop_array = DataArray(parameter=self.sweep_values.parameter)
         loop_array.nest(size=loop_size)
@@ -481,12 +481,12 @@ def _default_setpoints(self, size):
         return sp
 
     def set_common_attrs(self, data_set, use_threads, signal_queue):
-        '''
+        """
         set a couple of common attributes that the main and nested loops
         all need to have:
         - the DataSet collecting all our measurements
         - a queue for communicating with the main process
-        '''
+        """
         self.data_set = data_set
         self.signal_queue = signal_queue
         self.use_threads = use_threads
@@ -501,17 +501,17 @@ def _check_signal(self):
                 raise KeyboardInterrupt('sweep was halted')
 
     def run_temp(self, **kwargs):
-        '''
+        """
         wrapper to run this loop in the foreground as a temporary data set,
         especially for use in composite parameters that need to run a Loop
         as part of their get method
-        '''
+        """
         return self.run(background=False, quiet=True,
                         data_manager=False, location=False, **kwargs)
 
     def run(self, background=True, use_threads=True, enqueue=False,
             quiet=False, data_manager=None, **kwargs):
-        '''
+        """
         execute this loop
 
         background: (default True) run this sweep in a separate process
@@ -542,7 +542,7 @@ def run(self, background=True, use_threads=True, enqueue=False,
 
         returns:
             a DataSet object that we can use to plot
-        '''
+        """
 
         prev_loop = get_bg()
         if prev_loop:
@@ -632,7 +632,7 @@ def _run_wrapper(self, *args, **kwargs):
     def _run_loop(self, first_delay=0, action_indices=(),
                   loop_indices=(), current_values=(),
                   **ignore_kwargs):
-        '''
+        """
         the routine that actually executes the loop, and can be called
         from one loop to execute a nested loop
 
@@ -642,7 +642,7 @@ def _run_loop(self, first_delay=0, action_indices=(),
         current_values: setpoint values in any outer loops
         signal_queue: queue to communicate with main process directly
         ignore_kwargs: for compatibility with other loop tasks
-        '''
+        """
 
         # at the beginning of the loop, the time to wait after setting
         # the loop parameter may be increased if an outer loop requested longer
@@ -689,7 +689,7 @@ def _wait(self, delay):
 
 
 class Task:
-    '''
+    """
     A predefined task to be executed within a measurement Loop
     This form is for a simple task that does not measure any data,
     and does not depend on the state of the loop when it is called.
@@ -699,7 +699,7 @@ class Task:
 
     kwargs passed when the Task is called are ignored,
     but are accepted for compatibility with other things happening in a Loop.
-    '''
+    """
     def __init__(self, func, *args, **kwargs):
         self.func = func
         self.args = args
@@ -710,14 +710,14 @@ def __call__(self, **ignore_kwargs):
 
 
 class Wait:
-    '''
+    """
     A simple class to tell a Loop to wait  seconds
 
     This is transformed into a Task within the Loop, such that
     it can do other things (monitor, check for halt) during the delay.
 
     But for use outside of a Loop, it is also callable (then it just sleeps)
-    '''
+    """
     def __init__(self, delay):
         if not delay >= 0:
             raise ValueError('delay must be > 0, not {}'.format(repr(delay)))
@@ -729,10 +729,10 @@ def __call__(self):
 
 
 class _Measure:
-    '''
+    """
     A callable collection of parameters to measure.
     This should not be constructed manually, only by an ActiveLoop.
-    '''
+    """
     def __init__(self, params_indices, data_set, use_threads):
         self.use_threads = use_threads and len(params_indices) > 1
         # the applicable DataSet.store function
@@ -777,10 +777,10 @@ def __call__(self, loop_indices, **ignore_kwargs):
 
 
 class _Nest:
-    '''
+    """
     wrapper to make a callable nested ActiveLoop
     This should not be constructed manually, only by an ActiveLoop.
-    '''
+    """
     def __init__(self, inner_loop, action_indices):
         self.inner_loop = inner_loop
         self.action_indices = action_indices

From e7d8b28f335651509972c6746d6e8431292b01f4 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 10 May 2016 15:32:48 +0200
Subject: [PATCH 145/169] BreakIf docstring

---
 qcodes/loops.py | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index bfc62735e7d0..9793b52c19b2 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -790,6 +790,15 @@ def __call__(self, **kwargs):
 
 
 class BreakIf:
+    """
+    Loop action that breaks out of the loop if a condition is truthy
+
+    condition: a callable taking no arguments.
+        Can be a simple function that returns truthy when it's time to quit
+        May also be constructed by deferred operations on `Parameter`s, eg:
+            BreakIf(gates.chan1 >= 3)
+            BreakIf(abs(source.I * source.V) >= source.power_limit.get_latest)
+    """
     def __init__(self, condition):
         if not is_function(condition, 0):
             raise TypeError('BreakIf condition must be a callable with '

From a50fa8cd2ca8b3588f79ce07ab88085138b99834 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 10 May 2016 15:59:53 +0200
Subject: [PATCH 146/169] fix and test .then with nesting

---
 qcodes/loops.py                 |  7 ++++---
 qcodes/tests/test_instrument.py |  2 +-
 qcodes/tests/test_loop.py       | 35 ++++++++++++++++++++++++++++++++-
 3 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/qcodes/loops.py b/qcodes/loops.py
index 9793b52c19b2..244e2b210fed 100644
--- a/qcodes/loops.py
+++ b/qcodes/loops.py
@@ -622,9 +622,6 @@ def _compile_one(self, action, new_action_indices):
     def _run_wrapper(self, *args, **kwargs):
         try:
             self._run_loop(*args, **kwargs)
-
-            for f in self._compile_actions(self.then_actions, ()):
-                f()
         finally:
             if hasattr(self, 'data_set'):
                 self.data_set.finalize()
@@ -675,6 +672,10 @@ def _run_loop(self, first_delay=0, action_indices=(),
             # after the first setpoint, delay reverts to the loop delay
             delay = self.delay
 
+        # the loop is finished - run the .then actions
+        for f in self._compile_actions(self.then_actions, ()):
+            f()
+
     def _wait(self, delay):
         if delay:
             finish_clock = time.perf_counter() + delay
diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index e93deec004d5..130875828f77 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -670,7 +670,7 @@ def test_deferred_ops(self):
         c2.set(2)
 
         self.assertEqual((c0 + c1 + c2)(), 3)
-        self.assertEqual((10 + (c0**2) + (c1**2) + (c2**2)), 15)
+        self.assertEqual((10 + (c0**2) + (c1**2) + (c2**2))(), 15)
 
         d = c1.get_latest / c0.get_latest
         with self.assertRaises(ZeroDivisionError):
diff --git a/qcodes/tests/test_loop.py b/qcodes/tests/test_loop.py
index 860b677acf60..44a4b4aa2275 100644
--- a/qcodes/tests/test_loop.py
+++ b/qcodes/tests/test_loop.py
@@ -483,11 +483,14 @@ def test_then_construction(self):
     def test_then_action(self):
         nan = float('nan')
         self.p1.set(5)
-        f_calls = []
+        f_calls, g_calls = [], []
 
         def f():
             f_calls.append(1)
 
+        def g():
+            g_calls.append(1)
+
         data = Loop(self.p1[1:6:1]).each(
             self.p1, BreakIf(self.p1 >= 3)
         ).then(
@@ -499,6 +502,36 @@ def f():
         self.assertEqual(self.p1.get(), 2)
         self.assertEqual(len(f_calls), 1)
 
+        # now test a nested loop with .then inside and outside
+        f_calls[:] = []
+
+        Loop(self.p1[1:3:1]).each(
+            Loop(self.p2[1:3:1]).each(self.p2).then(Task(g))
+        ).then(Task(f)).run_temp()
+
+        self.assertEqual(len(f_calls), 1)
+        self.assertEqual(len(g_calls), 2)
+
+        # Loop.loop nesting always just makes the .then actions run after
+        # the outer loop
+        f_calls[:] = []
+        Loop(self.p1[1:3:1]).then(Task(f)).loop(self.p2[1:3:1]).each(
+            self.p1
+        ).run_temp()
+        self.assertEqual(len(f_calls), 1)
+
+        f_calls[:] = []
+        Loop(self.p1[1:3:1]).loop(self.p2[1:3:1]).then(Task(f)).each(
+            self.p1
+        ).run_temp()
+        self.assertEqual(len(f_calls), 1)
+
+        f_calls[:] = []
+        Loop(self.p1[1:3:1]).loop(self.p2[1:3:1]).each(
+            self.p1
+        ).then(Task(f)).run_temp()
+        self.assertEqual(len(f_calls), 1)
+
 
 class AbortingGetter(ManualParameter):
     '''

From 630556dfc0ed2185af92b8de657cca27f8c1d7cb Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Tue, 10 May 2016 16:04:42 +0200
Subject: [PATCH 147/169] prohibit __bool__ on DeferredOperations to prevent
 confusing errors

---
 qcodes/tests/test_deferred_operations.py | 7 +++++++
 qcodes/utils/deferred_operations.py      | 5 +++++
 2 files changed, 12 insertions(+)

diff --git a/qcodes/tests/test_deferred_operations.py b/qcodes/tests/test_deferred_operations.py
index d787ca3e7df5..9521d43cd20e 100644
--- a/qcodes/tests/test_deferred_operations.py
+++ b/qcodes/tests/test_deferred_operations.py
@@ -21,6 +21,13 @@ def test_errors(self):
         with self.assertRaises(ZeroDivisionError):
             d()
 
+        # you shouldn't evaluate the truthiness of the DeferredOperations
+        # object itself, only after it's called
+        d = DeferredOperations(lambda: 5)
+        with self.assertRaises(TypeError):
+            if d:
+                pass
+
     def test_unary(self):
         d = DeferredOperations(lambda: -3)
         f = DeferredOperations(lambda: 4.221)
diff --git a/qcodes/utils/deferred_operations.py b/qcodes/utils/deferred_operations.py
index 1885b36626f6..9948de135fe5 100644
--- a/qcodes/utils/deferred_operations.py
+++ b/qcodes/utils/deferred_operations.py
@@ -81,6 +81,11 @@ def __call__(self):
     def get(self):
         return self.call_func(*self.args)
 
+    def __bool__(self):
+        raise TypeError('This is a DeferredOperations object, you must '
+                        'call or .get() it before testing its truthiness',
+                        self)
+
     def _validate_callable(self, func, arg_count=0):
         if not is_function(func, arg_count):
             raise TypeError(

From bb51b874400c046675bffee7794d14da7e8adb92 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Wed, 11 May 2016 11:42:20 +0200
Subject: [PATCH 148/169] make number validator more generic

---
 qcodes/utils/validators.py | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py
index 990868305703..5d9bc9e475d1 100644
--- a/qcodes/utils/validators.py
+++ b/qcodes/utils/validators.py
@@ -1,4 +1,5 @@
 import math
+import numpy
 
 BIGSTRING = 1000000000
 BIGINT = int(1e18)
@@ -132,19 +133,21 @@ class Numbers(Validator):
     min_value <= value <= max_value
     '''
 
+    validtypes = (float, int, numpy.int64, numpy.float32)
+
     def __init__(self, min_value=-float("inf"), max_value=float("inf")):
-        if isinstance(min_value, (float, int)):
+        if isinstance(min_value, self.validtypes):
             self._min_value = min_value
         else:
             raise TypeError('min_value must be a number')
 
-        if isinstance(max_value, (float, int)) and max_value > min_value:
+        if isinstance(max_value, self.validtypes) and max_value > min_value:
             self._max_value = max_value
         else:
             raise TypeError('max_value must be a number bigger than min_value')
 
     def validate(self, value, context=''):
-        if not isinstance(value, (float, int)):
+        if not isinstance(value, self.validtypes):
             raise TypeError(
                 '{} is not an int or float; {}'.format(repr(value), context))
 

From ec11dc8abdc5bd82c118c1067fd5685c1f3fc792 Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Wed, 11 May 2016 13:58:13 +0200
Subject: [PATCH 149/169] better label for Keithley driver

---
 qcodes/instrument_drivers/tektronix/Keithley_2700.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
index ea48c509fe51..2079e44ceaa6 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2700.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -205,6 +205,7 @@ def __init__(self, name, address, reset=False, **kwargs):
         # add functions
         self.add_function('readnext',
                           units='arb.unit',
+                          label=name,
                           call_cmd=':DATA:FRESH?',
                           return_parser=float)
 

From 4b88e48c9d8489e3e9af06aac8c566ccae80d04c Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Wed, 11 May 2016 15:38:42 +0200
Subject: [PATCH 150/169] added tests for numpy scalars; made Int validator
 more generic

---
 qcodes/tests/test_validators.py | 10 ++++++++--
 qcodes/utils/validators.py      | 14 ++++++++------
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/qcodes/tests/test_validators.py b/qcodes/tests/test_validators.py
index 18ddd276353f..ac3ccd440efb 100644
--- a/qcodes/tests/test_validators.py
+++ b/qcodes/tests/test_validators.py
@@ -1,5 +1,6 @@
 from unittest import TestCase
 import math
+import numpy 
 
 from qcodes.utils.validators import (Validator, Anything, Bool, Strings,
                                      Numbers, Ints, Enum, MultiType)
@@ -174,7 +175,10 @@ class TestNumbers(TestCase):
                # warning: True==1 and False==0
                True, False,
                # warning: +/- inf are allowed if max & min are not specified!
-               -float("inf"), float("inf")]
+               -float("inf"), float("inf"),
+                # numpy scalars
+               numpy.int64(36), numpy.float32(-1.123)
+                ]
     not_numbers = ['', None, '1', [], {}, [1, 2], {1: 1},
                    b'good', AClass, AClass(), a_func]
 
@@ -264,7 +268,9 @@ class TestInts(TestCase):
     ints = [0, 1, 10, -1, 100, 1000000, int(-1e15), int(1e15),
             # warning: True==1 and False==0 - we *could* prohibit these, using
             # isinstance(v, bool)
-            True, False]
+            True, False,
+            # numpy scalars
+            numpy.int64(3)]
     not_ints = [0.1, -0.1, 1.0, 3.5, -2.3e6, 5.5e15, 1.34e-10, -2.5e-5,
                 math.pi, math.e, '', None, float("nan"), float("inf"),
                 -float("inf"), '1', [], {}, [1, 2], {1: 1}, b'good',
diff --git a/qcodes/utils/validators.py b/qcodes/utils/validators.py
index 5d9bc9e475d1..4d9aca3e427f 100644
--- a/qcodes/utils/validators.py
+++ b/qcodes/utils/validators.py
@@ -133,7 +133,7 @@ class Numbers(Validator):
     min_value <= value <= max_value
     '''
 
-    validtypes = (float, int, numpy.int64, numpy.float32)
+    validtypes = (float, int, numpy.integer, numpy.floating)
 
     def __init__(self, min_value=-float("inf"), max_value=float("inf")):
         if isinstance(min_value, self.validtypes):
@@ -172,22 +172,24 @@ class Ints(Validator):
     min_value <= value <= max_value
     '''
 
+    validtypes = (int, numpy.integer)
+
     def __init__(self, min_value=-BIGINT, max_value=BIGINT):
-        if isinstance(min_value, int):
-            self._min_value = min_value
+        if isinstance(min_value, self.validtypes):
+            self._min_value = int(min_value)
         else:
             raise TypeError('min_value must be an integer')
 
-        if not isinstance(max_value, int):
+        if not isinstance(max_value, self.validtypes):
             raise TypeError('max_value must be an integer')
         if max_value > min_value:
-            self._max_value = max_value
+            self._max_value = int(max_value)
         else:
             raise TypeError(
                 'max_value must be an integer bigger than min_value')
 
     def validate(self, value, context=''):
-        if not isinstance(value, int):
+        if not isinstance(value, self.validtypes):
             raise TypeError(
                 '{} is not an int; {}'.format(repr(value), context))
 

From 3c771c1c74e1b634f946119b50d8f2842e6f7326 Mon Sep 17 00:00:00 2001
From: Pieter Eendebak 
Date: Thu, 12 May 2016 17:04:22 +0200
Subject: [PATCH 151/169] better representation for parameter

---
 qcodes/instrument/parameter.py | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index aa4ce7b03ac2..66b35d89dd03 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -197,6 +197,10 @@ def __init__(self,
 
         self.get_latest = GetLatest(self)
 
+    def __repr__(self):
+        s='<' + '.'.join([self.__module__ , self.__class__.__name__]) +': ' + self.name + ' at ' + str(id(self)) +'>'
+        return s
+
     def __call__(self, *args):
         if len(args) == 0:
             if self.has_get:

From 9f9ddaef42ad01feb73b9280dc95400ebcf665fb Mon Sep 17 00:00:00 2001
From: Pieter Eendebak 
Date: Thu, 12 May 2016 23:50:14 +0200
Subject: [PATCH 152/169] use .format to generate string

---
 qcodes/instrument/parameter.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 66b35d89dd03..6e4c26485c6a 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -198,7 +198,11 @@ def __init__(self,
         self.get_latest = GetLatest(self)
 
     def __repr__(self):
-        s='<' + '.'.join([self.__module__ , self.__class__.__name__]) +': ' + self.name + ' at ' + str(id(self)) +'>'
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            self.name,
+            id(self))
         return s
 
     def __call__(self, *args):

From 24d063fd8ce5b3d67869112c1ed7bc9f0e7f57f3 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 13 May 2016 09:18:28 +0200
Subject: [PATCH 153/169] convert keithley function into parameter

---
 qcodes/instrument_drivers/tektronix/Keithley_2700.py | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2700.py b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
index 2079e44ceaa6..e85d636db446 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2700.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2700.py
@@ -203,11 +203,16 @@ def __init__(self, name, address, reset=False, **kwargs):
         '''
 
         # add functions
-        self.add_function('readnext',
+        self.add_parameter('amplitude',
                           units='arb.unit',
                           label=name,
-                          call_cmd=':DATA:FRESH?',
-                          return_parser=float)
+                          get_cmd=':DATA:FRESH?',
+                          get_parser=float)
+        self.add_parameter('readnext',
+                          units='arb.unit',
+                          label=name,
+                          get_cmd=':DATA:FRESH?',
+                          get_parser=float)
 
         if reset:
             self.reset()

From 6ce926a0ea95f5a55c5e840cf88e60e22f408517 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 13 May 2016 09:23:39 +0200
Subject: [PATCH 154/169] add __repr__ to remote param and function

---
 qcodes/instrument/remote.py | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index af626d439cb8..6a3f28f592f7 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -154,6 +154,14 @@ def getattr(self, attr):
         return self._instrument.connection.ask('param_getattr', self.name,
                                                attr)
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            self.name,
+            id(self))
+        return s
+
     # TODO: need set_sweep if it exists, and any methods a subclass defines.
 
 
@@ -166,3 +174,11 @@ def call(self, *args):
 
     def validate(self, *args):
         return Function.validate(self, *args)
+
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            self.name,
+            id(self))
+        return s

From 27e0f122e037bd85e7dabb8a183471f6b44072e2 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 13 May 2016 09:25:07 +0200
Subject: [PATCH 155/169] add __repr__ to remote instrument

---
 qcodes/instrument/remote.py | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index 6a3f28f592f7..88dc2f76d384 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -82,6 +82,13 @@ def __getitem__(self, key):
         except KeyError:
             return self.functions[key]
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            self.name,
+            id(self))
+        return s
 
 class RemoteComponent:
     '''

From 4beeffa0210731209a55b111561b1f0ab9af56b7 Mon Sep 17 00:00:00 2001
From: Pieter 
Date: Fri, 13 May 2016 11:14:00 +0200
Subject: [PATCH 156/169] add conversion of name to str

---
 qcodes/instrument/parameter.py    | 2 +-
 qcodes/instrument/remote.py       | 6 +++---
 qcodes/instrument/sweep_values.py | 8 ++++++++
 3 files changed, 12 insertions(+), 4 deletions(-)

diff --git a/qcodes/instrument/parameter.py b/qcodes/instrument/parameter.py
index 6e4c26485c6a..8e242eef0cf5 100644
--- a/qcodes/instrument/parameter.py
+++ b/qcodes/instrument/parameter.py
@@ -201,7 +201,7 @@ def __repr__(self):
         s = '<{}.{}: {} at {}>'.format(
             self.__module__,
             self.__class__.__name__,
-            self.name,
+            str(self.name),
             id(self))
         return s
 
diff --git a/qcodes/instrument/remote.py b/qcodes/instrument/remote.py
index 88dc2f76d384..49cc1a591227 100644
--- a/qcodes/instrument/remote.py
+++ b/qcodes/instrument/remote.py
@@ -86,7 +86,7 @@ def __repr__(self):
         s = '<{}.{}: {} at {}>'.format(
             self.__module__,
             self.__class__.__name__,
-            self.name,
+            str(self.name),
             id(self))
         return s
 
@@ -165,7 +165,7 @@ def __repr__(self):
         s = '<{}.{}: {} at {}>'.format(
             self.__module__,
             self.__class__.__name__,
-            self.name,
+            str(self.name),
             id(self))
         return s
 
@@ -186,6 +186,6 @@ def __repr__(self):
         s = '<{}.{}: {} at {}>'.format(
             self.__module__,
             self.__class__.__name__,
-            self.name,
+            str(self.name),
             id(self))
         return s
diff --git a/qcodes/instrument/sweep_values.py b/qcodes/instrument/sweep_values.py
index 768092179247..d22cfc051fd0 100644
--- a/qcodes/instrument/sweep_values.py
+++ b/qcodes/instrument/sweep_values.py
@@ -66,6 +66,14 @@ def __iter__(self):
         '''
         raise NotImplementedError
 
+    def __repr__(self):
+        s = '<{}.{}: {} at {}>'.format(
+            self.__module__,
+            self.__class__.__name__,
+            str(self.name),
+            id(self))
+        return s
+
 
 class SweepFixedValues(SweepValues):
     '''

From ff59cad45d778dcb59a53216faa27944a2dc0ac3 Mon Sep 17 00:00:00 2001
From: Pieter Eendebak 
Date: Fri, 13 May 2016 13:48:52 +0200
Subject: [PATCH 157/169] added test for repr

---
 qcodes/tests/test_instrument.py | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index 130875828f77..5e7a1c769bc0 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -65,6 +65,14 @@ def test_name_s(self):
         self.assertEqual(p.setpoint_names, setpoint_names)
         self.assertEqual(p.setpoint_labels, setpoint_labels)
 
+    def test_repr(self):
+      for i in [0, "foo", "", "fåil"]:
+          with self.subTest(i=i):
+             param = Parameter(name=i)
+             s = param.__repr__()
+             st='<{}.{}: {} at {}>'.format(param.__module__,
+                   param.__class__.__name__, param.name, id(param))
+             self.assertEqual(s , st )
 
 class GatesBadDelayType(MockGates):
     def __init__(self, *args, **kwargs):

From b5ed139e9647d2570f54d9844f486a31b12de05a Mon Sep 17 00:00:00 2001
From: Pieter Eendebak 
Date: Fri, 13 May 2016 19:56:58 +0200
Subject: [PATCH 158/169] add clear() function to MatPlot; add replace()
 function to BasePlot

---
 qcodes/plots/base.py       | 14 ++++++++++++++
 qcodes/plots/matplotlib.py | 20 ++++++++++++++++----
 2 files changed, 30 insertions(+), 4 deletions(-)

diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 2d49857ac8f1..9bedb7ce6b64 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -28,6 +28,20 @@ def __init__(self, interval=1, data_keys='xyz'):
             self.update_widget = HiddenUpdateWidget(self.update, interval)
             display(self.update_widget)
 
+    def clear(self):
+        '''
+        Clears the plot window and removes all subplots and traces
+        so that the window can be reused.
+        '''
+        self.traces = []
+        self.subplots = []
+        # any derived class should implement this
+        raise NotImplementedError
+
+    def replace(self, *args, updater=None, **kwargs):
+        self.clear()
+        self.add(*args, updater=updater, **kwargs)
+
     def add(self, *args, updater=None, **kwargs):
         '''
         add one trace to this plot
diff --git a/qcodes/plots/matplotlib.py b/qcodes/plots/matplotlib.py
index e159c618d336..1dabb61375ab 100644
--- a/qcodes/plots/matplotlib.py
+++ b/qcodes/plots/matplotlib.py
@@ -33,17 +33,29 @@ def __init__(self, *args, figsize=(8, 5), interval=1, subplots=(1, 1),
 
         super().__init__(interval)
 
+        self._init_plot(subplots, figsize)
+
+        if args or kwargs:
+            self.add(*args, **kwargs)
+
+    def _init_plot(self, subplots=(1, 1), figsize=(8, 5), num=None, **kwargs):
         if isinstance(subplots, Mapping):
-            self.fig, self.subplots = plt.subplots(figsize=figsize, **subplots)
+            self.fig, self.subplots = plt.subplots(figsize=figsize, num=num, **subplots)
         else:
-            self.fig, self.subplots = plt.subplots(*subplots, figsize=figsize)
+            self.fig, self.subplots = plt.subplots(*subplots, num=num, figsize=figsize)
         if not hasattr(self.subplots, '__len__'):
             self.subplots = (self.subplots,)
 
         self.title = self.fig.suptitle('')
 
-        if args or kwargs:
-            self.add(*args, **kwargs)
+    def clear(self, subplots=(1, 1), figsize=(8, 5)):
+        '''
+        Clears the plot window and removes all subplots and traces
+        so that the window can be reused.
+        '''
+        self.traces = []
+        self.fig.clf()
+        self._init_plot( subplots, figsize, num=self.fig.number)
 
     def add_to_plot(self, **kwargs):
         '''

From 701e68be4be8dbc28b9ee44a05649dbbda63519c Mon Sep 17 00:00:00 2001
From: Merlin 
Date: Mon, 16 May 2016 15:23:20 +0200
Subject: [PATCH 159/169] Add info on how to run a single test-file

---
 CONTRIBUTING.md | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 62062dcae1c2..067cec18f835 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -32,7 +32,14 @@ python qcodes/test.py
 # optional extra verbosity and fail fast
 python qcodes/test.py -v -f
 ```
-You should see output that looks something like this:
+
+You can also run single tests with:
+```
+# python -m unittest module.class.function
+python -m unittest qcodes.tests.test_metadata
+```
+
+If you run the core test runner, you should see output that looks something like this:
 ```
 .........***** found one MockMock, testing *****
 ............................................Timing resolution:

From 2f7ffa225aca861f24905c6b2a7b64ef8c152a29 Mon Sep 17 00:00:00 2001
From: Merlin 
Date: Mon, 16 May 2016 18:25:14 +0200
Subject: [PATCH 160/169] enhance: Add more info

---
 CONTRIBUTING.md | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 067cec18f835..9a96c5bb5202 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -35,8 +35,12 @@ python qcodes/test.py -v -f
 
 You can also run single tests with:
 ```
+# python -m unittest module
+# python -m unittest module.class
 # python -m unittest module.class.function
 python -m unittest qcodes.tests.test_metadata
+# or
+python -m unittest qcodes.tests.test_metadata.TestMetadatable.test_snapshot
 ```
 
 If you run the core test runner, you should see output that looks something like this:

From f567de45c4b9731c3ea8773e4256bbd6ebb90787 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 16 May 2016 23:17:07 +0200
Subject: [PATCH 161/169] indentation fix

---
 qcodes/tests/test_instrument.py | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/qcodes/tests/test_instrument.py b/qcodes/tests/test_instrument.py
index 5e7a1c769bc0..24da5e220352 100644
--- a/qcodes/tests/test_instrument.py
+++ b/qcodes/tests/test_instrument.py
@@ -66,13 +66,15 @@ def test_name_s(self):
         self.assertEqual(p.setpoint_labels, setpoint_labels)
 
     def test_repr(self):
-      for i in [0, "foo", "", "fåil"]:
-          with self.subTest(i=i):
-             param = Parameter(name=i)
-             s = param.__repr__()
-             st='<{}.{}: {} at {}>'.format(param.__module__,
-                   param.__class__.__name__, param.name, id(param))
-             self.assertEqual(s , st )
+        for i in [0, "foo", "", "fåil"]:
+            with self.subTest(i=i):
+                param = Parameter(name=i)
+                s = param.__repr__()
+                st = '<{}.{}: {} at {}>'.format(
+                    param.__module__, param.__class__.__name__,
+                    param.name, id(param))
+                self.assertEqual(s, st)
+
 
 class GatesBadDelayType(MockGates):
     def __init__(self, *args, **kwargs):

From ec8f1264828b8636b438f3c3e15d4284895fb73a Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 16 May 2016 23:42:24 +0200
Subject: [PATCH 162/169] pep8

---
 qcodes/plots/matplotlib.py | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/qcodes/plots/matplotlib.py b/qcodes/plots/matplotlib.py
index 1dabb61375ab..af633cd807e6 100644
--- a/qcodes/plots/matplotlib.py
+++ b/qcodes/plots/matplotlib.py
@@ -40,9 +40,11 @@ def __init__(self, *args, figsize=(8, 5), interval=1, subplots=(1, 1),
 
     def _init_plot(self, subplots=(1, 1), figsize=(8, 5), num=None, **kwargs):
         if isinstance(subplots, Mapping):
-            self.fig, self.subplots = plt.subplots(figsize=figsize, num=num, **subplots)
+            self.fig, self.subplots = plt.subplots(figsize=figsize, num=num,
+                                                   **subplots)
         else:
-            self.fig, self.subplots = plt.subplots(*subplots, num=num, figsize=figsize)
+            self.fig, self.subplots = plt.subplots(*subplots, num=num,
+                                                   figsize=figsize)
         if not hasattr(self.subplots, '__len__'):
             self.subplots = (self.subplots,)
 
@@ -55,7 +57,7 @@ def clear(self, subplots=(1, 1), figsize=(8, 5)):
         '''
         self.traces = []
         self.fig.clf()
-        self._init_plot( subplots, figsize, num=self.fig.number)
+        self._init_plot(subplots, figsize, num=self.fig.number)
 
     def add_to_plot(self, **kwargs):
         '''

From cbf36270d11102e3d409c34d647fbe3ceaa2e1f4 Mon Sep 17 00:00:00 2001
From: alexcjohnson 
Date: Mon, 16 May 2016 23:47:40 +0200
Subject: [PATCH 163/169] DRYer MatPlot defaults

---
 qcodes/plots/matplotlib.py | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/qcodes/plots/matplotlib.py b/qcodes/plots/matplotlib.py
index af633cd807e6..1ea59edbda39 100644
--- a/qcodes/plots/matplotlib.py
+++ b/qcodes/plots/matplotlib.py
@@ -28,7 +28,7 @@ class MatPlot(BasePlot):
 
     kwargs: passed along to MatPlot.add() to add the first data trace
     '''
-    def __init__(self, *args, figsize=(8, 5), interval=1, subplots=(1, 1),
+    def __init__(self, *args, figsize=None, interval=1, subplots=None,
                  **kwargs):
 
         super().__init__(interval)
@@ -38,7 +38,13 @@ def __init__(self, *args, figsize=(8, 5), interval=1, subplots=(1, 1),
         if args or kwargs:
             self.add(*args, **kwargs)
 
-    def _init_plot(self, subplots=(1, 1), figsize=(8, 5), num=None, **kwargs):
+    def _init_plot(self, subplots=None, figsize=None, num=None):
+        if figsize is None:
+            figsize = (8, 5)
+
+        if subplots is None:
+            subplots = (1, 1)
+
         if isinstance(subplots, Mapping):
             self.fig, self.subplots = plt.subplots(figsize=figsize, num=num,
                                                    **subplots)
@@ -50,7 +56,7 @@ def _init_plot(self, subplots=(1, 1), figsize=(8, 5), num=None, **kwargs):
 
         self.title = self.fig.suptitle('')
 
-    def clear(self, subplots=(1, 1), figsize=(8, 5)):
+    def clear(self, subplots=None, figsize=None):
         '''
         Clears the plot window and removes all subplots and traces
         so that the window can be reused.

From 55cf6f2692083259d5b3ac4c02715eb8a569aa1e Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 17 May 2016 09:48:58 +0200
Subject: [PATCH 164/169] add explanation of clear() function

---
 qcodes/plots/base.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 9bedb7ce6b64..72bcb18049b8 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -33,10 +33,12 @@ def clear(self):
         Clears the plot window and removes all subplots and traces
         so that the window can be reused.
         '''
-        self.traces = []
-        self.subplots = []
         # any derived class should implement this
         raise NotImplementedError
+        # typically traces and subplots should be cleared as well as the 
+        # figure window for the particular backend
+        self.traces = []
+        self.subplots = []
 
     def replace(self, *args, updater=None, **kwargs):
         self.clear()

From b532582e886a9dbcbb72feea82600a6cd12212bc Mon Sep 17 00:00:00 2001
From: eendebakpt 
Date: Tue, 17 May 2016 09:49:32 +0200
Subject: [PATCH 165/169] pep8

---
 qcodes/plots/base.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/qcodes/plots/base.py b/qcodes/plots/base.py
index 72bcb18049b8..22e4d5c449b0 100644
--- a/qcodes/plots/base.py
+++ b/qcodes/plots/base.py
@@ -7,6 +7,7 @@
 
 
 class BasePlot:
+
     '''
     create an auto-updating plot connected to a Jupyter notebook
 
@@ -18,6 +19,7 @@ class BasePlot:
         default 'xyz' (treated as a sequence) but add more if
         for example marker size or color can contain data
     '''
+
     def __init__(self, interval=1, data_keys='xyz'):
         self.data_keys = data_keys
         self.traces = []
@@ -35,7 +37,7 @@ def clear(self):
         '''
         # any derived class should implement this
         raise NotImplementedError
-        # typically traces and subplots should be cleared as well as the 
+        # typically traces and subplots should be cleared as well as the
         # figure window for the particular backend
         self.traces = []
         self.subplots = []

From 48b625200b2e9ca944f0460fabc9360924b71da1 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 11 May 2016 20:16:39 +0200
Subject: [PATCH 166/169] magnet visa

---
 .../instrument_drivers/oxford/mercuryiPS2.py  | 461 ++++++++++++++++++
 1 file changed, 461 insertions(+)
 create mode 100644 qcodes/instrument_drivers/oxford/mercuryiPS2.py

diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS2.py b/qcodes/instrument_drivers/oxford/mercuryiPS2.py
new file mode 100644
index 000000000000..9f779807fe48
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS2.py
@@ -0,0 +1,461 @@
+# mercuryiPS.py driver for Oxford MercuryiPS magnet power supply
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from functools import partial
+import re
+import time
+import numpy as np
+
+from qcodes import VisaInstrument
+from qcodes.utils.validators import Strings, Enum, Anything
+
+
+class MercuryiPS(VisaInstrument):
+    '''
+    MercuryiPS Driver
+
+    This is the qcodes driver for the Oxford MercuryiPS magnet power supply.
+
+    Status: beta-version.
+        TODO:
+        - SAFETY!! we need to make sure the magnet is only ramped at certain
+          conditions!
+        - Add parameters that get data for all channels:
+          magnet.fld.get() should return [fx, fy, fz] or whatever axes are
+          available
+        - Fix this call = ''
+                   eval(call)
+          stuff, I guess there is a smarter way of doing that?
+        - this findall stuff in _get_cmd, is that smart?
+    '''
+    def __init__(self, name, axes=None, **kwargs):
+        super().__init__(name, terminator='\n', **kwargs)
+    # def __init__(self, name, address=None, port=None, axes=None, **kwargs):
+    #     super().__init__(name, address=address, port=port, terminator='\n',
+    #                      **kwargs)
+        self.axes = axes
+        self._ATOB = {}
+        self._latest_response = ''
+        # for some reason the first call is always invalid?! need some kind of init?
+        self.ask('*IDN?')
+        IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':'))
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+        return
+
+        if axes is None:
+            self._determine_magnet_axes()
+        self._determine_current_to_field()
+
+        self.add_parameter('setpoint',
+                           get_cmd=partial(self._get_fld, self.axes, 'FSET'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+        self.add_parameter('fld',
+                           get_cmd=partial(self._get_fld, self.axes, 'FLD'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('fldC',
+                           get_cmd=partial(self._get_fld_converted,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('rtp',
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'FLD'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
+                           labels=['radius', 'theta', 'phi'],
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        self.add_parameter('rtpC',
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
+                           labels=['radius', 'theta', 'phi'],
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        # so we have radius, theta and phi in buffer
+        self.rtp.get()
+
+        self.add_parameter('radius',
+                           get_cmd=self._get_r,
+                           set_cmd=self._set_r,
+                           label='radius',
+                           unit='|B|')
+        self.add_parameter('theta',
+                           get_cmd=self._get_theta,
+                           set_cmd=self._set_theta,
+                           label='theta',
+                           unit='rad')
+        self.add_parameter('phi',
+                           get_cmd=self._get_phi,
+                           set_cmd=self._set_phi,
+                           label='phi',
+                           unit='rad')
+
+        # self.add_parameter('ACTN',
+        #                    get_cmd=self._ACTN,
+        #                    set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+        #                    vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+        for ax in self.axes:
+            self.add_parameter(ax.lower()+'_fld',
+                               get_cmd=partial(self._get_fld, ax, 'FLD'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fldC',
+                               get_cmd=partial(self._get_fld_converted,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fld_wait',
+                               get_cmd=partial(self._get_fld_converted,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint_and_wait, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_ACTN',
+                               get_cmd=partial(self._get_cmd,
+                                               'READ:DEV:GRP{}:PSU:ACTN?'.format(ax)),
+                               set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+            self.add_parameter(ax.lower()+'_setpoint',
+                               get_cmd=partial(self._get_fld, ax, 'FSET'),
+                               set_cmd=partial(self._set_fld, ax, 'FSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_setpointC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'CSET'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'CSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_rate',
+                               get_cmd=partial(self._get_fld, ax, 'RFST'),
+                               set_cmd=partial(self._set_fld, ax, 'RFST'),
+                               units='T/m')
+            self.add_parameter(ax.lower()+'_rateC',
+                               get_cmd=partial(self._get_fld_converted, ax, 'RCST'),
+                               set_cmd=partial(self._set_fld_converted, ax, 'RCST'),
+                               units='T/m')
+
+    def hold(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("HOLD")'.format(ax.lower())
+            eval(call)
+
+    def rtos(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOS")'.format(ax.lower())
+            eval(call)
+
+    def to_zero(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOZ")'.format(ax.lower())
+            eval(call)
+
+    def _ACTN(self):
+        actn = self._read_cmd('ACTN', self.axes,
+                              fmt='READ:DEV:GRP{}:PSU:ACTN?')
+        return actn
+
+    def _ramp_to_setpoint(self, ax, cmd, setpoint):
+        if cmd is 'CSET':
+            self._set_fld_converted(ax, cmd, setpoint)
+        elif cmd is 'FSET':
+            self._set_fld(ax, cmd, setpoint)
+        msg = ''
+        # print(ax, cmd, setpoint)
+        # time.sleep(1)
+        # self.rtos()
+        for axis in ax:
+            msg = 'SET:DEV:GRP{}:PSU:ACTN:RTOS'.format(axis)
+            self.write(msg)
+        self.ask('')
+
+    def _ramp_to_setpoint_and_wait(self, ax, cmd, setpoint):
+        error = 0.2e-3
+        fldc = getattr(self, ax.lower()+'_fldC')
+        fldc.set(setpoint)
+        # self._ramp_to_setpoint(ax, cmd, setpoint)
+
+        while abs(fldc.get() - setpoint) > error:
+            time.sleep(0.5)
+        if setpoint == 0.0:
+            # This ensures that the magnet wont try to go hold
+            # some funny xe-5 value.
+            fld = getattr(self, ax.lower()+'_fld')
+            fld.set(setpoint)
+
+    def _set_fld(self, ax, cmd, setpoint):
+        # Could be FSET for setpoint
+        #          RFST for rate
+        msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        if isinstance(ax, list):
+            msg2 = ''
+            for i, axis in enumerate(ax):
+                msg2 += msg.format(axis, cmd, setpoint[i])
+                msg2 += self._terminator
+                # self._set_fld_converted(axis, cmd, setpoint[i])
+            self.write(msg2)
+            return
+        msg2 = msg.format(ax, cmd, setpoint)
+        self.write(msg2)
+
+    def _get_fld(self, ax, cmd):
+        # Could be FSET for setpoint
+        #          FLD for field
+        #          RFLD for rate
+        #          PFLD persistent field reading
+        if isinstance(ax, list):
+            return [self._get_fld(axis, cmd) for axis in ax]
+        fld = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return fld
+
+    def _set_fld_converted(self, ax, cmd, setpoint):
+        # Could be CSET for setpoint
+        #          RCST for rate
+        #
+        # We set current, not field, this gives higher resolution due to
+        # limited number of digits
+        msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        if isinstance(ax, list):
+            msg2 = ''
+            for i, axis in enumerate(ax):
+                msg2 += msg.format(axis, cmd, setpoint[i] * self._ATOB[axis])
+                msg2 += self._terminator
+                # self._set_fld_converted(axis, cmd, setpoint[i])
+            self.write(msg2)
+            return
+        cur = setpoint * self._ATOB[ax]
+        msg2 = msg.format(ax, cmd, cur)
+        self.write(msg2)
+
+    def _get_fld_converted(self, ax, cmd):
+        # Could be CSET for setpoint
+        #          CURR for field
+        #          RCUR for rate
+        #          PCUR persistent current reading
+        # We ask for current, not field, this gives higher resolution due to
+        # limited number of digits
+        # The conversion gives us a float with lots of digits, how to limit that?
+        if isinstance(ax, list):
+            fld = []
+            for axis in ax:
+                fld.append(self._get_fld_converted(axis, cmd))
+                # print(axis, cmd, fld[-1])
+            return fld
+        curr = self._get_cmd('READ:DEV:GRP{}:PSU:SIG:{}?'.format(ax, cmd), float)
+        return curr / self._ATOB[ax]
+
+    def _get_rtp(self, ax, cmd):
+        if cmd == 'CURR':
+            fld = self._get_fld_converted(ax, cmd)
+        elif cmd == 'FLD':
+            fld = self._get_fld(ax, cmd)
+
+        sphere = self._carttosphere(fld)
+        self._radius, self._theta, self._phi = sphere
+        return sphere
+
+    def _set_rtp(self, ax, cmd, setpoint):
+        fld = self._spheretocart(setpoint)
+        self._ramp_to_setpoint(ax, cmd, fld)
+
+    def _get_r(self):
+        self.rtp.get()
+        return self._radius
+
+    def _set_r(self, val):
+        self.rtp.set([val, self._theta, self._phi])
+
+    def _get_theta(self):
+        self.rtp.get()
+        return self._theta
+
+    def _set_theta(self, val):
+        self.rtp.set([self._radius, val, self._phi])
+
+    def _get_phi(self):
+        self.rtp.get()
+        return self._phi
+
+    def _set_phi(self, val):
+        self.rtpC.set([self._radius, self._theta, val])
+
+    def _float_parser(self, msg):
+        pass
+
+    def _determine_magnet_axes(self):
+        cat = self.ask('READ:SYS:CAT')
+        self.axes = re.findall('DEV:GRP(.+?):PSU', cat)
+
+    def _determine_current_to_field(self):
+        # This has a unit A/T
+        self._ATOB = {}
+        for ax in self.axes:
+            r = self._get_cmd('READ:DEV:GRP{}:PSU:ATOB?'.format(ax), float)
+            self._ATOB[ax] = r
+
+    def _read_cmd(self, cmd, axes, parser=None, fmt='READ:DEV:GRP{}:PSU:SIG:{}?'):
+        msg = ''
+        msglist = []
+        for axis in axes:
+            msglist.append(fmt.format(axis, cmd))
+        msg = '\n'.join(msglist)
+
+        rep = self.ask(msg)
+        data = [None] * len(axes)
+        for i in range(20):
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[5:-1] in rep:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                # print(msg)
+                                return None
+                        data[ix] = val
+                    if all(data):
+                        break
+                if all(data):
+                    break
+            if all(data):
+                break
+            rep = self.ask('')
+
+        return data
+
+    def _write_cmd(self, cmd, axes, setpoint, fmt='SET:DEV:GRP{}:PSU:SIG:{}:{:6f}', parser=None):
+        msg = ''
+        msglist = []
+        for ix, axis in enumerate(axes):
+            msglist.append(fmt.format(axis, cmd, setpoint[ix]))
+        msg = '\n'.join(msglist)
+        rep = self.ask(msg)
+        data = [None] * len(axes)
+        for i in range(20):
+            print(rep)
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[-1] in rep:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                # print(msg)
+                                return None
+                        data[ix] = val
+                    if all(data):
+                        break
+                if all(data):
+                    break
+            if all(data):
+                break
+            rep = self.ask('')
+        print(data)
+        # return data
+
+
+
+    def _get_cmd(self, question, parser=None):
+        # print(question)
+        rep = self.ask(question)
+        # print(rep)
+        # print()
+        self._latest_response = rep
+        msg = rep[len(question):]
+        # How would one macth this without specifying the units?
+        # m = re.match('STAT:DEV:GRPX:PSU:SIG:RFST:(.+?)T/m',
+        #              'STAT:DEV:GRPX:PSU:SIG:RFST:0.0200T/m')
+        # m.groups()[0]
+        if parser is float:
+            try:
+                return(float(re.findall("[-+]?\d*\.\d+|\d+", msg)[0]))
+            except:
+                # print(msg)
+                return None
+        return msg.strip()
+
+    def write(self, msg):
+        rep = self.ask(msg)
+        self._latest_response = rep
+        if 'INVALID' in rep:
+            print('warning', msg, rep)
+
+    def ask(self, msg):
+        mc = msg.count(self._terminator)
+        rep = super().ask(msg)
+        for i in range(20):
+            # print(rep)
+            if not rep.startswith(':INVALID'):
+                for n in range(mc):
+                    rep2 = super().ask('')
+                    if 'INVALID' in rep2:
+                        break
+                    rep += self._terminator
+                    rep += rep2
+                break
+            rep = super().ask('')
+
+        return rep
+
+    def _spheretocart(self, sphere):
+        """
+        r,  theta,  phi = sphere
+        """
+        r,  theta,  phi = sphere
+        x = (r * np.sin(theta) * np.cos(phi))
+        y = (r * np.sin(theta) * np.sin(phi))
+        z = (r * np.cos(theta))
+        return [x,  y,  z]
+
+    def _carttosphere(self, field):
+        field = np.array(field)
+        r = np.sqrt(np.sum(field**2))
+        if r == 0:
+            theta = 0
+            phi = 0
+        else:
+            theta = np.arccos(field[2] / r);
+            phi = np.arctan2(field[1],  field[0])
+        return [r, theta, phi]

From 57ff5392bcf6c5e7ec42b9c3146d6114256c5b58 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 11 May 2016 20:16:19 +0200
Subject: [PATCH 167/169] Ugly Magnet update

---
 .../instrument_drivers/oxford/mercuryiPS3.py  | 415 ++++++++++++++++++
 1 file changed, 415 insertions(+)
 create mode 100644 qcodes/instrument_drivers/oxford/mercuryiPS3.py

diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS3.py b/qcodes/instrument_drivers/oxford/mercuryiPS3.py
new file mode 100644
index 000000000000..70fe59ca16f8
--- /dev/null
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS3.py
@@ -0,0 +1,415 @@
+# mercuryiPS.py driver for Oxford MercuryiPS magnet power supply
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from functools import partial
+import re
+import time
+import numpy as np
+
+from qcodes import IPInstrument
+from qcodes.utils.validators import Strings, Enum, Anything
+
+
+class MercuryiPS(IPInstrument):
+    '''
+    MercuryiPS Driver
+
+    This is the qcodes driver for the Oxford MercuryiPS magnet power supply.
+
+    Status: beta-version.
+        TODO:
+        - SAFETY!! we need to make sure the magnet is only ramped at certain
+          conditions!
+        - make ATOB a parameter, and move all possible to use _read_cmd, _write_cmd
+        - Fix this call = ''
+                   eval(call)
+          stuff, I guess there is a smarter way of doing that?
+        - this findall stuff in _get_cmd, is that smart?
+    '''
+    # def __init__(self, name, axes=None, **kwargs):
+    #     super().__init__(name, terminator='\n', **kwargs)
+    def __init__(self, name, address=None, port=None, axes=None, **kwargs):
+        super().__init__(name, address=address, port=port, terminator='\n',
+                         **kwargs)
+        self.axes = axes
+        self._ATOB = []
+        self._latest_response = ''
+        # for some reason the first call is always invalid?! need some kind of init?
+        self.ask('*IDN?')
+        IDN = self.ask('*IDN?')[4:]
+        vendor, model, serial, firmware = map(str.strip, IDN.split(':'))
+
+        self.IDN = {'vendor': vendor, 'model': model,
+                    'serial': serial, 'firmware': firmware}
+
+        if axes is None:
+            self._determine_magnet_axes()
+        self._determine_current_to_field()
+
+        self.add_parameter('setpoint',
+                           names=['setpoint_B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld, self.axes, 'FSET'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+        self.add_parameter('rate',
+                           names=['rate_B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld, self.axes, 'RFST'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'RFST'),
+                           labels=['rate_'+ax.lower() for ax in self.axes],
+                           units=['T/m'for ax in self.axes],
+                           vals=Anything())
+        self.add_parameter('fld',
+                           names=['B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld, self.axes, 'FLD'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('fldC',
+                           names=['B'+ax.lower() for ax in self.axes],
+                           get_cmd=partial(self._get_fld,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'),
+                           labels=['B'+ax.lower() for ax in self.axes],
+                           units=['T'for ax in self.axes],
+                           vals=Anything())
+
+        self.add_parameter('rtp',
+                           names=['radius', 'theta', 'phi'],
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'FLD'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
+                           labels=['radius', 'theta', 'phi'],
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        self.add_parameter('rtpC',
+                           names=['radius', 'theta', 'phi'],
+                           get_cmd=partial(self._get_rtp,
+                                           self.axes, 'CURR'),
+                           set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
+                           labels=['radius', 'theta', 'phi'],
+                           units=['|B|', 'rad', 'rad'],
+                           vals=Anything())
+
+        # so we have radius, theta and phi in buffer
+        self.rtp.get()
+
+        self.add_parameter('radius',
+                           get_cmd=self._get_r,
+                           set_cmd=self._set_r,
+                           label='radius',
+                           unit='|B|')
+        self.add_parameter('theta',
+                           get_cmd=self._get_theta,
+                           set_cmd=self._set_theta,
+                           label='theta',
+                           unit='rad')
+        self.add_parameter('phi',
+                           get_cmd=self._get_phi,
+                           set_cmd=self._set_phi,
+                           label='phi',
+                           unit='rad')
+
+        # self.add_parameter('ACTN',
+        #                    get_cmd=self._ACTN,
+        #                    set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+        #                    vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+        for ax in self.axes:
+            self.add_parameter(ax.lower()+'_fld',
+                               get_cmd=partial(self._get_fld, ax, 'FLD'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'FSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fldC',
+                               get_cmd=partial(self._get_fld,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_fld_wait',
+                               get_cmd=partial(self._get_fld,
+                                               ax, 'CURR'),
+                               set_cmd=partial(self._ramp_to_setpoint_and_wait, ax, 'CSET'),
+                               label='B'+ax.lower(),
+                               units='T')
+            self.add_parameter(ax.lower()+'_ACTN',
+                               get_cmd=partial(self._get_cmd,
+                                               'READ:DEV:GRP{}:PSU:ACTN?'.format(ax)),
+                               set_cmd='SET:DEV:GRP{}:PSU:ACTN:'.format(ax)+'{}',
+                               vals=Enum('HOLD', 'RTOS', 'RTOZ', 'CLMP'))
+            self.add_parameter(ax.lower()+'_setpoint',
+                               get_cmd=partial(self._get_fld, ax, 'FSET'),
+                               set_cmd=partial(self._set_fld, ax, 'FSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_setpointC',
+                               get_cmd=partial(self._get_fld, ax, 'CSET'),
+                               set_cmd=partial(self._set_fld, ax, 'CSET'),
+                               units='T')
+            self.add_parameter(ax.lower()+'_rate',
+                               get_cmd=partial(self._get_fld, ax, 'RFST'),
+                               set_cmd=partial(self._set_fld, ax, 'RFST'),
+                               units='T/m')
+            self.add_parameter(ax.lower()+'_rateC',
+                               get_cmd=partial(self._get_fld, ax, 'RCST'),
+                               set_cmd=partial(self._set_fld, ax, 'RCST'),
+                               units='T/m')
+
+    def hold(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("HOLD")'.format(ax.lower())
+            eval(call)
+
+    def rtos(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOS")'.format(ax.lower())
+            eval(call)
+
+    def to_zero(self):
+        for ax in self.axes:
+            # How do I properly call those parameters from here?
+            # self.{ax}_ACTN.set('HOLD')
+            call = 'self.{}_ACTN.set("RTOZ")'.format(ax.lower())
+            eval(call)
+
+    def _ACTN(self):
+        actn = self._read_cmd('ACTN', self.axes,
+                              fmt='READ:DEV:GRP{}:PSU:ACTN?')
+        return actn
+
+    def _ramp_to_setpoint(self, ax, cmd, setpoint):
+        # if cmd is 'CSET':
+        #     self._set_fld(ax, cmd, setpoint)
+        # elif cmd is 'FSET':
+        #     self._set_fld(ax, cmd, setpoint)
+        self._set_fld(ax, cmd, setpoint)
+        msg = ''
+        # print(ax, cmd, setpoint)
+        # time.sleep(1)
+        # self.rtos()
+        for axis in ax:
+            msg = 'SET:DEV:GRP{}:PSU:ACTN:RTOS'.format(axis)
+            self.write(msg)
+        # self.ask('')
+
+    def _ramp_to_setpoint_and_wait(self, ax, cmd, setpoint):
+        error = 0.2e-3
+        fldc = getattr(self, ax.lower()+'_fldC')
+        fldc.set(setpoint)
+        # self._ramp_to_setpoint(ax, cmd, setpoint)
+
+        while abs(fldc.get() - setpoint) > error:
+            time.sleep(0.5)
+        if setpoint == 0.0:
+            # This ensures that the magnet wont try to go hold
+            # some funny xe-5 value.
+            fld = getattr(self, ax.lower()+'_fld')
+            fld.set(setpoint)
+
+    def _set_fld(self, ax, cmd, setpoint):
+        # Could be FSET for setpoint
+        #          RFST for rate
+        if not isinstance(setpoint, list):
+            setpoint = [setpoint]
+        if cmd in ['CSET', 'RCST', 'CURR', 'PCUR', 'RCUR']:
+            setpoint = np.array(self._ATOB) * np.array(setpoint)
+
+        msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        self._write_cmd(cmd, ax, setpoint, msg)
+
+    def _get_fld(self, ax, cmd):
+        # Could be FSET for setpoint
+        #          FLD for field
+        #          RFLD for rate
+        #          PFLD persistent field reading
+        fld = self._read_cmd(cmd, ax, float)
+        if len(fld) == 1:
+            return fld[0]
+
+        if cmd in ['CSET', 'RCST', 'CURR', 'PCUR', 'RCUR']:
+            fld = np.array(fld) / np.array(self._ATOB)
+        return list(fld)
+
+    def _get_rtp(self, ax, cmd):
+        fld = self._get_fld(ax, cmd)
+        sphere = self._carttosphere(fld)
+        self._radius, self._theta, self._phi = sphere
+        return sphere
+
+    def _set_rtp(self, ax, cmd, setpoint):
+        fld = self._spheretocart(setpoint)
+        self._ramp_to_setpoint(ax, cmd, fld)
+
+    def _get_r(self):
+        self.rtp.get()
+        return self._radius
+
+    def _set_r(self, val):
+        self.rtp.set([val, self._theta, self._phi])
+
+    def _get_theta(self):
+        self.rtp.get()
+        return self._theta
+
+    def _set_theta(self, val):
+        self.rtp.set([self._radius, val, self._phi])
+
+    def _get_phi(self):
+        self.rtp.get()
+        return self._phi
+
+    def _set_phi(self, val):
+        self.rtpC.set([self._radius, self._theta, val])
+
+    def _determine_magnet_axes(self):
+        cat = self.ask('READ:SYS:CAT')
+        self.axes = re.findall('DEV:GRP(.+?):PSU', cat)
+
+    def _determine_current_to_field(self):
+        # This has a unit A/T
+        self._ATOB = []
+        for ax in self.axes:
+            r = self._get_cmd('READ:DEV:GRP{}:PSU:ATOB?'.format(ax), float)
+            self._ATOB.append(r)
+
+    def _read_cmd(self, cmd, axes, parser=None, fmt=None):
+        fmt = fmt or 'READ:DEV:GRP{}:PSU:SIG:{}?'
+        msg = ''
+        msglist = []
+        for axis in axes:
+            msglist.append(fmt.format(axis, cmd))
+        msg = '\n'.join(msglist)
+        self._send(msg)
+        rep = self._recv()
+        data = [None] * len(axes)
+        for i in range(20):
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[5:-1] in ln:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                continue
+                        data[ix] = val
+                    if not (None in data):
+                        return data
+            rep = self._recv()
+        return data
+
+    def _write_cmd(self, cmd, axes, setpoint, fmt=None, parser=None):
+        fmt = fmt or 'SET:DEV:GRP{}:PSU:SIG:{}:{:4f}'
+        msg = ''
+        msglist = []
+        for ix, axis in enumerate(axes):
+            msglist.append(fmt.format(axis, cmd, setpoint[ix]))
+        msg = '\n'.join(msglist)
+        self._send(msg)
+        rep = self._recv()
+        data = [None] * len(axes)
+        for i in range(20):
+            for ln in rep.split('\n'):
+                for ix, msg in enumerate(msglist):
+                    if msg[5:-1] in ln:
+                        val = ln.split(':')[-1]
+                        if parser is float:
+                            try:
+                                val = float(re.findall("[-+]?\d*\.\d+|\d+", val)[0])
+                            except:
+                                continue
+                        data[ix] = val
+                    if not (None in data):
+                        return data
+            rep = self._recv()
+        print(data)
+
+    def _get_cmd(self, question, parser=None):
+        # print(question)
+        rep = self.ask(question)
+        # print(rep)
+        # print()
+        self._latest_response = rep
+        msg = rep[len(question):]
+        # How would one macth this without specifying the units?
+        # m = re.match('STAT:DEV:GRPX:PSU:SIG:RFST:(.+?)T/m',
+        #              'STAT:DEV:GRPX:PSU:SIG:RFST:0.0200T/m')
+        # m.groups()[0]
+        if parser is float:
+            try:
+                return(float(re.findall("[-+]?\d*\.\d+|\d+", msg)[0]))
+            except:
+                # print(msg)
+                return None
+        return msg.strip()
+
+    def write(self, msg):
+        rep = self.ask(msg)
+        self._latest_response = rep
+        if 'INVALID' in rep:
+            print('warning', msg, rep)
+
+    # def ask(self, msg):
+    #     mc = msg.count(self._terminator)
+    #     rep = super().ask(msg)
+    #     for i in range(20):
+    #         # print(rep)
+    #         if not rep.startswith(':INVALID'):
+    #             for n in range(mc):
+    #                 rep2 = super().ask('')
+    #                 if 'INVALID' in rep2:
+    #                     break
+    #                 rep += self._terminator
+    #                 rep += rep2
+    #             break
+    #         rep = super().ask('')
+
+    #     return rep
+
+    def _spheretocart(self, sphere):
+        """
+        r,  theta,  phi = sphere
+        """
+        r,  theta,  phi = sphere
+        x = (r * np.sin(theta) * np.cos(phi))
+        y = (r * np.sin(theta) * np.sin(phi))
+        z = (r * np.cos(theta))
+        return [x,  y,  z]
+
+    def _carttosphere(self, field):
+        field = np.array(field)
+        r = np.sqrt(np.sum(field**2))
+        if r == 0:
+            theta = 0
+            phi = 0
+        else:
+            theta = np.arccos(field[2] / r);
+            phi = np.arctan2(field[1],  field[0])
+        return [r, theta, phi]

From a812e347eeff44d11024fd0af22ae5f83eee0122 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Wed, 18 May 2016 20:44:20 +0200
Subject: [PATCH 168/169] Merge remote-tracking branch
 'refs/remotes/origin/metadata' into JUNK-MAY-18

# Conflicts:
#	qcodes/data/data_set.py
#	qcodes/data/format.py
#	qcodes/data/io.py
#	qcodes/loops.py

remove snapshot from ip

Merge branch 'merlins-testing-branch-junk-thing' into
Merlins-instrument-drivers
---
 qcodes/instrument/ip.py                       |   3 +
 .../agilent/Agilent_34400A.py                 |  19 ++-
 .../instrument_drivers/ithaco/Ithaco_1211.py  |  13 +-
 .../instrument_drivers/oxford/mercuryiPS3.py  |  39 +++---
 .../stanford_research/SR_560.py               | 107 +++++++++++++++
 .../tektronix/Keithley_2600.py                |  20 ++-
 .../tektronix/Keithley_2600_bak.py            | 127 ++++++++++++++++++
 7 files changed, 294 insertions(+), 34 deletions(-)
 create mode 100644 qcodes/instrument_drivers/stanford_research/SR_560.py
 create mode 100644 qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py

diff --git a/qcodes/instrument/ip.py b/qcodes/instrument/ip.py
index 452f9d08c2f2..e0433ce11a05 100644
--- a/qcodes/instrument/ip.py
+++ b/qcodes/instrument/ip.py
@@ -119,6 +119,9 @@ def ask(self, cmd):
             e.args = e.args + ('asking ' + repr(cmd) + ' to ' + repr(self),)
             raise e
 
+    def __del__(self):
+        self.close()
+
 
 class EnsureConnection:
     def __init__(self, instrument):
diff --git a/qcodes/instrument_drivers/agilent/Agilent_34400A.py b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
index 6f1faf9f57f6..490b5cec7cda 100644
--- a/qcodes/instrument_drivers/agilent/Agilent_34400A.py
+++ b/qcodes/instrument_drivers/agilent/Agilent_34400A.py
@@ -22,7 +22,7 @@
 # THE SOFTWARE.
 
 
-from qcodes.utils.validators import Enum, Strings
+from qcodes.utils.validators import Enum, Strings, Anything
 from qcodes import VisaInstrument
 
 
@@ -42,11 +42,10 @@ class Agilent_34400A(VisaInstrument):
     def __init__(self, name, address, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
 
-        IDN = self.ask('*IDN?')
-        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
-        self.model = model
-        self.IDN = {'vendor': vendor, 'model': model,
-                    'serial': serial, 'firmware': firmware}
+        self.add_parameter('IDN', get_cmd='*IDN?',
+                           get_parser=self._parse_idn,
+                           vals=Anything())
+        self.IDN.get()
 
         # Async has to send 'INIT' and later ask for 'FETCH?'
 
@@ -130,6 +129,14 @@ def __init__(self, name, address, **kwargs):
                                set_cmd='DISP:WIND2:TEXT "{}"',
                                vals=Strings())
 
+    def _parse_idn(self, msg):
+        vendor, model, serial, firmware = map(str.strip, msg.split(','))
+        self.model = model
+
+        IDN = {'vendor': vendor, 'model': model,
+               'serial': serial, 'firmware': firmware}
+        return IDN
+
     def clear_errors(self):
         while True:
             err = self.ask('SYST:ERR?')
diff --git a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
index deeeebf95020..be75766dd5d0 100644
--- a/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
+++ b/qcodes/instrument_drivers/ithaco/Ithaco_1211.py
@@ -22,17 +22,17 @@
 # THE SOFTWARE.
 
 from qcodes import Instrument
+from qcodes.instrument.parameter import Parameter
 from qcodes.instrument.parameter import ManualParameter
-from qcodes.utils.validators import Enum, Bool
+from qcodes.utils.validators import Enum, Bool, Anything
 
-from qcodes.instrument.parameter import Parameter
 
 
 class CurrentParameter(Parameter):
     def __init__(self, measured_param, camp_ins, name='curr'):
         p_name = measured_param.name
         self.name = name
-        super().__init__(names=(p_name, 'current'))
+        super().__init__(names=('camp_raw_'+p_name, name))
 
         _p_label = None
         _p_unit = None
@@ -74,8 +74,11 @@ def __init__(self, name, dmm_parameter=None, **kwargs):
         serial = None
         firmware = None
 
-        self.IDN = {'vendor': vendor, 'model': model,
-                    'serial': serial, 'firmware': firmware}
+        self.add_parameter('IDN',
+                           parameter_class=ManualParameter,
+                           initial_value={'vendor': vendor, 'model': model,
+                                          'serial': serial, 'firmware': firmware},
+                           vals=Anything())
 
         self.add_parameter('sens',
                            parameter_class=ManualParameter,
diff --git a/qcodes/instrument_drivers/oxford/mercuryiPS3.py b/qcodes/instrument_drivers/oxford/mercuryiPS3.py
index 70fe59ca16f8..0e67914836ed 100644
--- a/qcodes/instrument_drivers/oxford/mercuryiPS3.py
+++ b/qcodes/instrument_drivers/oxford/mercuryiPS3.py
@@ -67,24 +67,23 @@ def __init__(self, name, address=None, port=None, axes=None, **kwargs):
         self._determine_current_to_field()
 
         self.add_parameter('setpoint',
-                           names=['setpoint_B'+ax.lower() for ax in self.axes],
+                           names=['B'+ax.lower()+'_setpoint' for ax in self.axes],
                            get_cmd=partial(self._get_fld, self.axes, 'FSET'),
                            set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
-                           labels=['B'+ax.lower() for ax in self.axes],
                            units=['T'for ax in self.axes],
                            vals=Anything())
+
         self.add_parameter('rate',
                            names=['rate_B'+ax.lower() for ax in self.axes],
                            get_cmd=partial(self._get_fld, self.axes, 'RFST'),
                            set_cmd=partial(self._ramp_to_setpoint, self.axes, 'RFST'),
-                           labels=['rate_'+ax.lower() for ax in self.axes],
                            units=['T/m'for ax in self.axes],
                            vals=Anything())
+
         self.add_parameter('fld',
                            names=['B'+ax.lower() for ax in self.axes],
                            get_cmd=partial(self._get_fld, self.axes, 'FLD'),
                            set_cmd=partial(self._ramp_to_setpoint, self.axes, 'FSET'),
-                           labels=['B'+ax.lower() for ax in self.axes],
                            units=['T'for ax in self.axes],
                            vals=Anything())
 
@@ -93,7 +92,6 @@ def __init__(self, name, address=None, port=None, axes=None, **kwargs):
                            get_cmd=partial(self._get_fld,
                                            self.axes, 'CURR'),
                            set_cmd=partial(self._ramp_to_setpoint, self.axes, 'CSET'),
-                           labels=['B'+ax.lower() for ax in self.axes],
                            units=['T'for ax in self.axes],
                            vals=Anything())
 
@@ -102,7 +100,6 @@ def __init__(self, name, address=None, port=None, axes=None, **kwargs):
                            get_cmd=partial(self._get_rtp,
                                            self.axes, 'FLD'),
                            set_cmd=partial(self._set_rtp, self.axes, 'FSET'),
-                           labels=['radius', 'theta', 'phi'],
                            units=['|B|', 'rad', 'rad'],
                            vals=Anything())
 
@@ -111,7 +108,6 @@ def __init__(self, name, address=None, port=None, axes=None, **kwargs):
                            get_cmd=partial(self._get_rtp,
                                            self.axes, 'CURR'),
                            set_cmd=partial(self._set_rtp, self.axes, 'CSET'),
-                           labels=['radius', 'theta', 'phi'],
                            units=['|B|', 'rad', 'rad'],
                            vals=Anything())
 
@@ -121,18 +117,15 @@ def __init__(self, name, address=None, port=None, axes=None, **kwargs):
         self.add_parameter('radius',
                            get_cmd=self._get_r,
                            set_cmd=self._set_r,
-                           label='radius',
-                           unit='|B|')
+                           units='|B|')
         self.add_parameter('theta',
                            get_cmd=self._get_theta,
                            set_cmd=self._set_theta,
-                           label='theta',
-                           unit='rad')
+                           units='rad')
         self.add_parameter('phi',
                            get_cmd=self._get_phi,
                            set_cmd=self._set_phi,
-                           label='phi',
-                           unit='rad')
+                           units='rad')
 
         # self.add_parameter('ACTN',
         #                    get_cmd=self._ACTN,
@@ -240,8 +233,16 @@ def _set_fld(self, ax, cmd, setpoint):
             setpoint = [setpoint]
         if cmd in ['CSET', 'RCST', 'CURR', 'PCUR', 'RCUR']:
             setpoint = np.array(self._ATOB) * np.array(setpoint)
+            # print('a', setpoint)
+
+        if len(ax) == 1:
+            # print('b', self.axes.index(ax))
+            setpoint = setpoint[self.axes.index(ax)]
+            # print('c', setpoint)
 
+        # print('d', ax, cmd, setpoint)
         msg = 'SET:DEV:GRP{}:PSU:SIG:{}:{:6f}'
+        # print('e', msg)
         self._write_cmd(cmd, ax, setpoint, msg)
 
     def _get_fld(self, ax, cmd):
@@ -249,12 +250,14 @@ def _get_fld(self, ax, cmd):
         #          FLD for field
         #          RFLD for rate
         #          PFLD persistent field reading
-        fld = self._read_cmd(cmd, ax, float)
-        if len(fld) == 1:
-            return fld[0]
+        fld = list(self._read_cmd(cmd, ax, float))
 
         if cmd in ['CSET', 'RCST', 'CURR', 'PCUR', 'RCUR']:
             fld = np.array(fld) / np.array(self._ATOB)
+
+        # print(ax, cmd, fld)
+        if len(ax) == 1:
+            return fld[self.axes.index(ax)]
         return list(fld)
 
     def _get_rtp(self, ax, cmd):
@@ -329,6 +332,8 @@ def _write_cmd(self, cmd, axes, setpoint, fmt=None, parser=None):
         fmt = fmt or 'SET:DEV:GRP{}:PSU:SIG:{}:{:4f}'
         msg = ''
         msglist = []
+        if len(axes) == 1:
+            setpoint = [setpoint]
         for ix, axis in enumerate(axes):
             msglist.append(fmt.format(axis, cmd, setpoint[ix]))
         msg = '\n'.join(msglist)
@@ -349,7 +354,7 @@ def _write_cmd(self, cmd, axes, setpoint, fmt=None, parser=None):
                     if not (None in data):
                         return data
             rep = self._recv()
-        print(data)
+        # print(data)
 
     def _get_cmd(self, question, parser=None):
         # print(question)
diff --git a/qcodes/instrument_drivers/stanford_research/SR_560.py b/qcodes/instrument_drivers/stanford_research/SR_560.py
new file mode 100644
index 000000000000..98713f86c21a
--- /dev/null
+++ b/qcodes/instrument_drivers/stanford_research/SR_560.py
@@ -0,0 +1,107 @@
+# sr_560.py driver for SR 560 Voltage-preamplifier
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+from qcodes import Instrument
+from qcodes.instrument.parameter import ManualParameter
+from qcodes.utils.validators import Enum, Bool, Anything, Numbers
+
+from qcodes.instrument.parameter import Parameter
+
+
+class VoltageParameter(Parameter):
+    def __init__(self, measured_param, vamp_ins, name='volt'):
+        p_name = measured_param.name
+        self.name = name
+        super().__init__(names=('vamp_raw_'+p_name, name))
+
+        _p_label = None
+        _p_unit = None
+
+        self.measured_param = measured_param
+        self._instrument = vamp_ins
+
+        if hasattr(measured_param, 'label'):
+            _p_label = measured_param.label
+        if hasattr(measured_param, 'units'):
+            _p_unit = measured_param.units
+
+        self.labels = (_p_label, 'Voltage')
+        self.units = (_p_unit, 'V')
+
+    def get(self):
+        volt = self.measured_param.get()
+        volt_amp = (volt / self._instrument.gain.get())
+
+        if self._instrument.invert.get():
+            volt_amp *= -1
+        return (volt, volt_amp)
+
+
+class SR_560(Instrument):
+    '''
+    dmm_parameter: The parameter used to measure the voltage output
+
+    This is the qcodes driver for the SR 560 Voltage-preamplifier,
+    This is a virtual driver only and will not talk to your instrument.
+    '''
+    def __init__(self, name, dmm_parameter=None, **kwargs):
+        super().__init__(name, **kwargs)
+        self.dmm_parameter = dmm_parameter
+
+        vendor = 'Stanford Research Systems'
+        model = 'SR560'
+        serial = None
+        firmware = None
+
+        self.add_parameter('IDN',
+                           parameter_class=ManualParameter,
+                           initial_value={'vendor': vendor, 'model': model,
+                                          'serial': serial, 'firmware': firmware},
+                           vals=Anything())
+
+        self.add_parameter('cutoff_lo',
+                           parameter_class=ManualParameter,
+                           initial_value='DC',
+                           label='High pass',
+                           units='Hz',
+                           vals=Anything())
+
+        self.add_parameter('cutoff_hi',
+                           parameter_class=ManualParameter,
+                           initial_value='1e6',
+                           label='Low pass',
+                           units='Hz',
+                           vals=Anything())
+
+        self.add_parameter('invert',
+                           parameter_class=ManualParameter,
+                           initial_value=True,
+                           label='Iverted output',
+                           vals=Bool())
+
+        self.add_parameter('gain',
+                           parameter_class=ManualParameter,
+                           initial_value=10,
+                           label='gain',
+                           units=None,
+                           vals=Numbers())
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600.py b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
index d3d608b279e3..5f3c91d40b43 100644
--- a/qcodes/instrument_drivers/tektronix/Keithley_2600.py
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600.py
@@ -23,6 +23,7 @@
 
 import re
 from qcodes import VisaInstrument
+from qcodes.utils.validators import Anything
 
 
 class Keithley_2600(VisaInstrument):
@@ -43,12 +44,8 @@ def __init__(self, name, address, channel, **kwargs):
         super().__init__(name, address, terminator='\n', **kwargs)
         self._channel = channel
 
-        IDN = self.visa_handle.ask('*IDN?')
-        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
-        model = model[6:]
-
-        self.IDN = {'vendor': vendor, 'model': model,
-                    'serial': serial, 'firmware': firmware}
+        self.add_parameter('IDN', get_cmd=self._get_IDN,
+                           vals=Anything())
 
         self.add_parameter('volt', get_cmd='measure.v()',
                            get_parser=float, set_cmd='source.levelv={:.8f}',
@@ -71,12 +68,14 @@ def __init__(self, name, address, channel, **kwargs):
                            val_mapping={'on':  1, 'ON':  1,
                                         'off': 0, 'OFF': 0})
         # Source range
+        # needs get after set
         self.add_parameter('rangev',
                            get_cmd='source.rangev',
                            get_parser=float,
                            set_cmd='source.rangev={:.4f}',
                            units='V')
         # Measure range
+        # needs get after set
         self.add_parameter('rangei',
                            get_cmd='source.rangei',
                            get_parser=float,
@@ -95,6 +94,15 @@ def __init__(self, name, address, channel, **kwargs):
                            set_cmd='source.limiti={:.4f}',
                            units='A')
 
+    def _get_IDN(self):
+        IDN = self.visa_handle.ask('*IDN?')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        model = model[6:]
+
+        self._IDN = {'vendor': vendor, 'model': model,
+                     'serial': serial, 'firmware': firmware}
+        return self._IDN
+
     def _mode_parser(self, msg):
         if msg[0] == '0':
             return 'current'
diff --git a/qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py b/qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py
new file mode 100644
index 000000000000..afd697880858
--- /dev/null
+++ b/qcodes/instrument_drivers/tektronix/Keithley_2600_bak.py
@@ -0,0 +1,127 @@
+# Keithley_2600.py driver for Keithley 2600 Source-Meter series
+#
+# The MIT License (MIT)
+# Copyright (c) 2016 Merlin von Soosten 
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in theSoftware without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+import re
+from qcodes import VisaInstrument
+
+
+class Keithley_2600(VisaInstrument):
+    '''
+    channel: use channel 'a' or 'b'
+
+    This is the qcodes driver for the Keithley_2600 Source-Meter series,
+    tested with Keithley_2614B
+
+    Status: beta-version.
+        TODO:
+        - Add all parameters that are in the manual
+        - range and limit should be set according to mode
+        - add ramping and such stuff
+
+    '''
+    def __init__(self, name, address, channel, **kwargs):
+        super().__init__(name, address, terminator='\n', **kwargs)
+        self._channel = channel
+
+        self.add_parameter('IDN', get_cmd='*IDN?',
+                           get_parser=self._get_idn_dict)
+
+        self.add_parameter('volt', get_cmd='measure.v()',
+                           get_parser=float, set_cmd='source.levelv={:.8f}',
+                           label='Voltage',
+                           units='V')
+        self.add_parameter('curr', get_cmd='measure.i()',
+                           get_parser=float, set_cmd='source.leveli={:.8f}',
+                           label='Current',
+                           units='A')
+        self.add_parameter('mode',
+                           get_cmd='source.func',
+                           get_parser=self._mode_parser,
+                           set_cmd='source.func={:d}',
+                           val_mapping={'current': 0, 'curr': 0, 'AMPS': 0,
+                                        'voltage': 1, 'volt': 1, 'VOLT': 1})
+        self.add_parameter('output',
+                           get_cmd='source.output',
+                           get_parser=self._output_parser,
+                           set_cmd='source.output={:d}',
+                           val_mapping={'on':  1, 'ON':  1,
+                                        'off': 0, 'OFF': 0})
+        # Source range
+        self.add_parameter('rangev',
+                           get_cmd='source.rangev',
+                           get_parser=float,
+                           set_cmd='source.rangev={:.4f}',
+                           units='V')
+        # Measure range
+        self.add_parameter('rangei',
+                           get_cmd='source.rangei',
+                           get_parser=float,
+                           set_cmd='source.rangei={:.4f}',
+                           units='A')
+        # Compliance limit
+        self.add_parameter('limitv',
+                           get_cmd='source.limitv',
+                           get_parser=float,
+                           set_cmd='source.limitv={:.4f}',
+                           units='V')
+        # Compliance limit
+        self.add_parameter('limiti',
+                           get_cmd='source.limiti',
+                           get_parser=float,
+                           set_cmd='source.limiti={:.4f}',
+                           units='A')
+
+    def _get_idn_dict(self, msg):
+
+        IDN = self.ask_direct('print(*IDN?)')
+        vendor, model, serial, firmware = map(str.strip, IDN.split(','))
+        model = model[6:]
+
+        return {'vendor': vendor, 'model': model,
+                'serial': serial, 'firmware': firmware}
+
+    def _mode_parser(self, msg):
+        if msg[0] == '0':
+            return 'current'
+        elif msg[0] == '1':
+            return 'voltage'
+        return None
+
+    def _output_parser(self, msg):
+        if msg[0] == '0':
+            return 'OFF'
+        elif msg[0] == '1':
+            return 'ON'
+        return None
+
+    def reset(self):
+        self.write('reset()')
+
+    def ask_direct(self, cmd):
+        return self.visa_handle.ask(cmd)
+
+    def ask(self, cmd):
+        return self.visa_handle.ask('print(smu{:s}.{:s})'.format(self._channel, cmd))
+
+    def write(self, cmd):
+        super().write('smu{:s}.{:s}'.format(self._channel, cmd))

From 99d4fa117a6f2d33da98b6d1bf015e245b1762b6 Mon Sep 17 00:00:00 2001
From: Triton1 
Date: Thu, 19 May 2016 10:49:49 +0200
Subject: [PATCH 169/169] remove idn

---
 qcodes/instrument/visa.py | 2 --
 1 file changed, 2 deletions(-)

diff --git a/qcodes/instrument/visa.py b/qcodes/instrument/visa.py
index 0b780e41f7bd..0ac72e71c999 100644
--- a/qcodes/instrument/visa.py
+++ b/qcodes/instrument/visa.py
@@ -30,8 +30,6 @@ def __init__(self, name, address=None, timeout=5, terminator='', **kwargs):
         self.set_address(address)
         self.set_timeout(timeout)
         self.set_terminator(terminator)
-        self.add_parameter('IDN', get_cmd='*IDN?',
-                           get_parser=self.get_idn_dict)
 
     @classmethod
     def default_server_name(cls, **kwargs):