diff --git a/.gitignore b/.gitignore
index e6133b777200ab3b5af5cebedc528094037d5869..bc7453473705cbaf6a772e13df5d45c1d3891700 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@ Breakpoints_v2.xcbkptlist
 *.c
 *.so
 *.pyc
+*.pyo
 *~
 /dstatInterface/dist/
-/dstatInterface/build/
\ No newline at end of file
+/dstatInterface/build/
+/dstat-interface/dstat-interface/dist/
+/dstat-interface/dstat-interface/build/
\ No newline at end of file
diff --git a/dstatInterface/interface/__init__.py b/dstat-interface/CHANGELOG
similarity index 100%
rename from dstatInterface/interface/__init__.py
rename to dstat-interface/CHANGELOG
diff --git a/dstat-interface/LICENSE b/dstat-interface/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dstat-interface/README b/dstat-interface/README
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dstat-interface/dstat-interface.psp b/dstat-interface/dstat-interface.psp
new file mode 100644
index 0000000000000000000000000000000000000000..b18557a8d05adb4378a09e8f25d7f2afd2856190
--- /dev/null
+++ b/dstat-interface/dstat-interface.psp
@@ -0,0 +1,6 @@
+<?xml version="1.0" ?>
+<project name="dstat-interface" version="1.0">
+   <optionset name="general"/>
+   <package name="dstat-interface"/>
+   <folder name="tests"/>
+</project>
diff --git a/dstat-interface/dstat-interface/__init__.py b/dstat-interface/dstat-interface/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dstatInterface/build_windows.py b/dstat-interface/dstat-interface/build_windows.py
similarity index 89%
rename from dstatInterface/build_windows.py
rename to dstat-interface/dstat-interface/build_windows.py
index b5377bea146eaebd2484b376dc8d5c9030973922..14d1fbda70190e8c7c19bacc30e58a5891b6897c 100644
--- a/dstatInterface/build_windows.py
+++ b/dstat-interface/dstat-interface/build_windows.py
@@ -5,7 +5,7 @@ __requires__ = 'PyInstaller==2.1'
 import os, sys
 os.chdir(os.path.dirname(sys.argv[0]))
 
-args = ['interface_test.spec']
+args = ['dstat.spec']
 args.extend(sys.argv[1:])
 
 import PyInstaller.main as pyi #For some reason, it gets the path here, so working dir must be set first
diff --git a/dstatInterface/drivers/VirtualSerial.inf b/dstat-interface/dstat-interface/drivers/VirtualSerial.inf
similarity index 100%
rename from dstatInterface/drivers/VirtualSerial.inf
rename to dstat-interface/dstat-interface/drivers/VirtualSerial.inf
diff --git a/dstat-interface/dstat-interface/dstat.spec b/dstat-interface/dstat-interface/dstat.spec
new file mode 100644
index 0000000000000000000000000000000000000000..c0f001d40d21cd853351472898e4aee887784fbb
--- /dev/null
+++ b/dstat-interface/dstat-interface/dstat.spec
@@ -0,0 +1,25 @@
+# -*- mode: python -*-
+a = Analysis(['./main.py'],
+             pathex=['/Users/mdryden/src/dstat-interface2/dstatInterface'],
+             hiddenimports=[],
+             hookspath=None,
+             runtime_hooks=None)
+pyz = PYZ(a.pure)
+exe = EXE(pyz,
+          a.scripts,
+          exclude_binaries=True,
+          name='DStat',
+          debug=False,
+          strip=None,
+          upx=True,
+          console=False )
+coll = COLLECT(exe,
+               a.binaries,
+               a.zipfiles,
+               a.datas,
+               strip=None,
+               upx=True,
+               name='DStat')
+app = BUNDLE(coll,
+             name='DStat.app',
+             icon=None)
diff --git a/dstatInterface/dstatInterface.xcodeproj/project.pbxproj b/dstat-interface/dstat-interface/dstatInterface.xcodeproj/project.pbxproj
similarity index 100%
rename from dstatInterface/dstatInterface.xcodeproj/project.pbxproj
rename to dstat-interface/dstat-interface/dstatInterface.xcodeproj/project.pbxproj
diff --git a/dstatInterface/dstatInterface.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/dstat-interface/dstat-interface/dstatInterface.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from dstatInterface/dstatInterface.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to dstat-interface/dstat-interface/dstatInterface.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/dstatInterface/dstatInterface.xcodeproj/project.xcworkspace/xcshareddata/dstatInterface.xccheckout b/dstat-interface/dstat-interface/dstatInterface.xcodeproj/project.xcworkspace/xcshareddata/dstatInterface.xccheckout
similarity index 100%
rename from dstatInterface/dstatInterface.xcodeproj/project.xcworkspace/xcshareddata/dstatInterface.xccheckout
rename to dstat-interface/dstat-interface/dstatInterface.xcodeproj/project.xcworkspace/xcshareddata/dstatInterface.xccheckout
diff --git a/dstatInterface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/dstatInterface.xcscheme b/dstat-interface/dstat-interface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/dstatInterface.xcscheme
similarity index 100%
rename from dstatInterface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/dstatInterface.xcscheme
rename to dstat-interface/dstat-interface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/dstatInterface.xcscheme
diff --git a/dstatInterface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/xcschememanagement.plist b/dstat-interface/dstat-interface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/xcschememanagement.plist
similarity index 100%
rename from dstatInterface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/xcschememanagement.plist
rename to dstat-interface/dstat-interface/dstatInterface.xcodeproj/xcuserdata/mdryden.xcuserdatad/xcschemes/xcschememanagement.plist
diff --git a/dstatInterface/dstat_comm.py b/dstat-interface/dstat-interface/dstat_comm.py
similarity index 62%
rename from dstatInterface/dstat_comm.py
rename to dstat-interface/dstat-interface/dstat_comm.py
index 69ceb4cd69296412536a60d8e5b9d96f15b08aca..ff4dab024f5949b782e6625d80b2dce11b388985 100644
--- a/dstatInterface/dstat_comm.py
+++ b/dstat-interface/dstat-interface/dstat_comm.py
@@ -1,26 +1,36 @@
 #!/usr/bin/env python
 
-import serial, io, time, struct, sys, os
-from types import *
+import serial
 from serial.tools import list_ports
-import numpy as np
+import time
+import struct
 import multiprocessing as mp
-from Queue import Empty
 
 def call_it(instance, name, args=(), kwargs=None):
-    "indirect caller for instance methods and multiprocessing"
+    """Indirect caller for instance methods and multiprocessing.
+    
+    Arguments:
+    instance -- instance to which the method belongs
+    name -- method to call
+    args -- passed to method
+    kwargs -- passed to method
+    """
     if kwargs is None:
         kwargs = {}
     return getattr(instance, name)(*args, **kwargs)
 
 
-class delayedSerial(serial.Serial): #overrides normal serial write so that characters are output individually with a slight delay
+class delayedSerial(serial.Serial): 
+    """Extends Serial.write so that characters are output individually
+    with a slight delay
+    """
     def write(self, data):
         for i in data:
             serial.Serial.write(self, i)
             time.sleep(.001)
 
-class SerialDevices:
+class SerialDevices(object):
+    """Retrieves and stores list of serial devices in self.ports"""
     def __init__(self):
         try:
             self.ports, _, _ = zip(*list_ports.comports())
@@ -29,22 +39,33 @@ class SerialDevices:
             print "No serial ports found"
     
     def refresh(self):
+        """Refreshes list of ports."""
         self.ports, _, _ = zip(*list_ports.comports())
 
-class Experiment:
+class Experiment(object):
+    """Store and acquire a potentiostat experiment. Meant to be subclassed
+    to by different experiment types and not used instanced directly.
+    """
     def run_wrapper(self, *argv):
-        self.p = mp.Process(target=call_it, args=(self, 'run', argv))
-        self.p.start()
+        """Execute experiment indirectly using call_it to bypass lack of fork()
+        on Windows for multiprocessing.
+        """
+        self.proc = mp.Process(target=call_it, args=(self, 'run', argv))
+        self.proc.start()
 
-    def __init__(self): #will always be overriden, but self.parameters, self.viewparameters, and self.databytes should be defined
-        pass
+    def __init__(self, parameters, main_pipe):
+        """Must be overridden to define self.parameters, and self.databytes."""
+        self.parameters = parameters
+        self.main_pipe = main_pipe
+        self.databytes = 8
     
     def init(self):
-        self.data_extra = [] #must be defined even when not needed
+        """Adds commands for gain and ADC."""
+        self.data_extra = []  # must be defined even when not needed
         self.__gaintable = [1e2, 3e2, 3e3, 3e4, 3e5, 3e6, 3e7, 5e8]
         self.gain = self.__gaintable[int(self.parameters['gain'])]
 
-        self.commands = ["A","G"]
+        self.commands = ["A", "G"]
     
         self.commands[0] += (self.parameters['adc_buffer'])
         self.commands[0] += " "
@@ -55,8 +76,15 @@ class Experiment:
         self.commands[1] += (self.parameters['gain'])
         self.commands[1] += " "
 
-    def run(self, strPort):
-        self.serial = delayedSerial(strPort, 1024000, timeout=1)
+    def run(self, ser_port):
+        """Execute experiment. Connects and sends handshake signal to DStat
+        then sendsself.commands. Don't call directly as a process in Windows,
+        use run_wrapper instead.
+        
+        Arguments:
+        ser_port -- address of serial port to use
+        """
+        self.serial = delayedSerial(ser_port, 1024000, timeout=1)
         self.serial.write("ck")
         
         self.serial.flushInput()
@@ -77,6 +105,10 @@ class Experiment:
         self.main_pipe.close()
     
     def serial_handler(self):
+        """Handles incoming serial transmissions from DStat. Returns False
+        if stop button pressed and sends abort signal to instrument. Sends
+        data to self.main_pipe as result of self.data_handler).
+        """
         scan = 0
         while True:
             if self.main_pipe.poll():
@@ -87,7 +119,8 @@ class Experiment:
                         
             for line in self.serial:
                 if line.startswith('B'):
-                    self.main_pipe.send(self.data_handler((scan, self.serial.read(size=self.databytes))))
+                    self.main_pipe.send(self.data_handler(
+                                 (scan, self.serial.read(size=self.databytes))))
                 elif line.startswith('S'):
                     scan += 1
                 elif line.startswith("#"):
@@ -98,22 +131,31 @@ class Experiment:
                     return True
     
     
-    def data_handler(self, input):
-        scan, data = input
+    def data_handler(self, data_input):
+        """Takes data_input as tuple -- (scan, data).
+        Returns:
+        (scan number, [voltage, current]) -- voltage in mV, current in A
+        """
+        scan, data = data_input
         voltage, current = struct.unpack('<Hl', data) #uint16 + int32
-        return (scan, [(voltage-32768)*3000./65536, current*(1.5/self.gain/8388607)])
+        return (scan,
+                [(voltage-32768)*3000./65536, current*(1.5/self.gain/8388607)])
     
     def data_postprocessing(self):
+        """No data postprocessing done by default, can be overridden
+        in subclass.
+        """
         pass
 
 class chronoamp(Experiment):
+    """Chronoamperometry experiment"""
     def __init__(self, parameters, main_pipe):
         self.main_pipe = main_pipe
         self.parameters = parameters
         self.datatype = "linearData"
         self.xlabel = "Time (s)"
         self.ylabel = "Current (A)"
-        self.data = [[],[]]
+        self.data = [[], []]
         self.datalength = 2
         self.databytes = 8
         self.xmin = 0
@@ -122,7 +164,7 @@ class chronoamp(Experiment):
         for i in self.parameters['time']:
             self.xmax += int(i)
         
-        self.init() #need to call after xmin and xmax are set
+        self.init()  # need to call after xmin and xmax are set
         
         self.commands += "R"
         self.commands[2] += str(len(self.parameters['potential']))
@@ -134,12 +176,16 @@ class chronoamp(Experiment):
             self.commands[2] += str(i)
             self.commands[2] += " "
             
-    def data_handler(self, input): #overrides inherited method to not convert x axis
-        scan, data = input
-        seconds, milliseconds, current = struct.unpack('<HHl', data) #2*uint16 + int32
-        return (scan, [seconds+milliseconds/1000., current*(1.5/self.gain/8388607)])
+    def data_handler(self, data_input):
+        """Overrides Experiment method to not convert x axis to mV."""
+        scan, data = data_input
+        # 2*uint16 + int32
+        seconds, milliseconds, current = struct.unpack('<HHl', data)
+        return (scan,
+                [seconds+milliseconds/1000., current*(1.5/self.gain/8388607)])
 
 class lsv_exp(Experiment):
+    """Linear Scan Voltammetry experiment"""
     def __init__(self, parameters, send_pipe):
         self.main_pipe = send_pipe
         self.parameters = parameters
@@ -147,22 +193,24 @@ class lsv_exp(Experiment):
         self.datatype = "linearData"
         self.xlabel = "Voltage (mV)"
         self.ylabel = "Current (A)"
-        self.data = [[],[]]
+        self.data = [[], []]
         self.datalength = 2
-        self.databytes = 6 #uint16 + int32
+        self.databytes = 6  # uint16 + int32
         self.xmin = self.parameters['start']
         self.xmax = self.parameters['stop']
         
-        self.init() #need to call after xmin and xmax are set
+        self.init()  # need to call after xmin and xmax are set
         
         self.commands += "L"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['clean_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['clean_mV']*
+                                (65536./3000)+32768))
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['dep_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['dep_mV']*
+                                (65536./3000)+32768))
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['start'])
         self.commands[2] += " "
@@ -172,6 +220,7 @@ class lsv_exp(Experiment):
         self.commands[2] += " "
 
 class cv_exp(Experiment):
+    """Cyclic Voltammetry experiment"""
     def __init__(self, parameters, main_pipe):
         self.main_pipe = main_pipe
         self.parameters = parameters
@@ -179,9 +228,9 @@ class cv_exp(Experiment):
         self.datatype = "CVData"
         self.xlabel = "Voltage (mV)"
         self.ylabel = "Current (A)"
-        self.data = [[],[]] #Will have to alter data_handler to add new lists as needed
-        self.datalength = 2 * self.parameters['scans'] #x and y for each scan
-        self.databytes = 6 #uint16 + int32
+        self.data = [[], []]
+        self.datalength = 2 * self.parameters['scans']  # x and y for each scan
+        self.databytes = 6  # uint16 + int32
         self.xmin = self.parameters['v1']
         self.xmax = self.parameters['v2']
         
@@ -192,9 +241,11 @@ class cv_exp(Experiment):
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['clean_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['clean_mV']*
+                                (65536./3000)+32768))
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['dep_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['dep_mV']*
+                                (65536./3000)+32768))
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['v1'])
         self.commands[2] += " "
@@ -206,13 +257,9 @@ class cv_exp(Experiment):
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['slope'])
         self.commands[2] += " "
-    
-    def data_handler(self, input):
-        scan, data = input
-        voltage, current = struct.unpack('<Hl', data) #uint16 + int32
-        return (scan, [(voltage-32768)*3000./65536, current*(1.5/self.gain/8388607)])
 
 class swv_exp(Experiment):
+    """Square Wave Voltammetry experiment"""
     def __init__(self, parameters, main_pipe):
         self.main_pipe = main_pipe
         self.parameters = parameters
@@ -220,7 +267,7 @@ class swv_exp(Experiment):
         self.datatype = "SWVData"
         self.xlabel = "Voltage (mV)"
         self.ylabel = "Current (A)"
-        self.data = [[],[]] #only difference stored here
+        self.data = [[], []]  # only difference stored here
         self.datalength = 2 * self.parameters['scans']
         self.databytes = 10
         
@@ -228,16 +275,20 @@ class swv_exp(Experiment):
         self.xmax = self.parameters['stop']
         
         self.init()
-        self.data_extra = [[],[]] #forward/reverse stored here - needs to be after self.init to keep from being redefined
+        # forward/reverse stored here - needs to be after 
+        # self.init to keep from being redefined
+        self.data_extra = [[], []]  
         
         self.commands += "S"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['clean_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['clean_mV']*
+                                    (65536./3000)+32768))
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['dep_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['dep_mV']*
+                                    (65536./3000)+32768))
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['start'])
         self.commands[2] += " "
@@ -252,21 +303,28 @@ class swv_exp(Experiment):
         self.commands[2] += str(self.parameters['scans'])
         self.commands[2] += " "
     
-    def data_handler(self, input):
-        scan, data = input
-        voltage, forward, reverse = struct.unpack('<Hll', data) #uint16 + int32
-        return (scan, [(voltage-32768)*3000./65536, (forward-reverse)*(1.5/self.gain/8388607), forward*(1.5/self.gain/8388607), reverse*(1.5/self.gain/8388607)])
+    def data_handler(self, input_data):
+        """Overrides Experiment method to calculate difference current"""
+        scan, data = input_data
+        # uint16 + int32
+        voltage, forward, reverse = struct.unpack('<Hll', data)
+        return (scan, [(voltage-32768)*3000./65536,
+                       (forward-reverse)*(1.5/self.gain/8388607),
+                       forward*(1.5/self.gain/8388607),
+                       reverse*(1.5/self.gain/8388607)])
 
 
 class dpv_exp(swv_exp):
+    """Diffential Pulse Voltammetry experiment."""
     def __init__(self, parameters, main_pipe):
+        """Overrides swv_exp method"""
         self.main_pipe = main_pipe
         self.parameters = parameters
         
         self.datatype = "SWVData"
         self.xlabel = "Voltage (mV)"
         self.ylabel = "Current (A)"
-        self.data = [[],[]] #only difference stored here
+        self.data = [[], []]  # only difference stored here
         self.datalength = 2
         self.databytes = 10
         
@@ -274,16 +332,20 @@ class dpv_exp(swv_exp):
         self.xmax = self.parameters['stop']
         
         self.init()
-        self.data_extra = [[],[]] #forward/reverse stored here - needs to be after self.init to keep from being redefined
+        # forward/reverse stored here - needs to be after self.init to
+        # keep from being redefined
+        self.data_extra = [[], []]
         
         self.commands += "D"
         self.commands[2] += str(self.parameters['clean_s'])
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['dep_s'])
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['clean_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['clean_mV']*
+                                    (65536./3000)+32768))
         self.commands[2] += " "
-        self.commands[2] += str(int(self.parameters['dep_mV']*(65536./3000)+32768))
+        self.commands[2] += str(int(self.parameters['dep_mV']*
+                                    (65536./3000)+32768))
         self.commands[2] += " "
         self.commands[2] += str(self.parameters['start'])
         self.commands[2] += " "
diff --git a/dstat-interface/dstat-interface/interface/__init__.py b/dstat-interface/dstat-interface/interface/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dstatInterface/interface/acv.glade b/dstat-interface/dstat-interface/interface/acv.glade
similarity index 100%
rename from dstatInterface/interface/acv.glade
rename to dstat-interface/dstat-interface/interface/acv.glade
diff --git a/dstatInterface/interface/adc_pot.glade b/dstat-interface/dstat-interface/interface/adc_pot.glade
similarity index 100%
rename from dstatInterface/interface/adc_pot.glade
rename to dstat-interface/dstat-interface/interface/adc_pot.glade
diff --git a/dstatInterface/interface/adc_pot.py b/dstat-interface/dstat-interface/interface/adc_pot.py
similarity index 100%
rename from dstatInterface/interface/adc_pot.py
rename to dstat-interface/dstat-interface/interface/adc_pot.py
diff --git a/dstatInterface/interface/chronoamp.glade b/dstat-interface/dstat-interface/interface/chronoamp.glade
similarity index 100%
rename from dstatInterface/interface/chronoamp.glade
rename to dstat-interface/dstat-interface/interface/chronoamp.glade
diff --git a/dstatInterface/interface/cv.glade b/dstat-interface/dstat-interface/interface/cv.glade
similarity index 100%
rename from dstatInterface/interface/cv.glade
rename to dstat-interface/dstat-interface/interface/cv.glade
diff --git a/dstatInterface/interface/dpv.glade b/dstat-interface/dstat-interface/interface/dpv.glade
similarity index 100%
rename from dstatInterface/interface/dpv.glade
rename to dstat-interface/dstat-interface/interface/dpv.glade
diff --git a/dstatInterface/interface/dstatinterface.glade b/dstat-interface/dstat-interface/interface/dstatinterface.glade
similarity index 96%
rename from dstatInterface/interface/dstatinterface.glade
rename to dstat-interface/dstat-interface/interface/dstatinterface.glade
index 6b1062a172816a5543303c918182dd7edbdf0d5a..511429af2f81c175fec9fc4d113e85235cd7cf5e 100644
--- a/dstatInterface/interface/dstatinterface.glade
+++ b/dstat-interface/dstat-interface/interface/dstatinterface.glade
@@ -6,37 +6,46 @@
     <columns>
       <!-- column-name index -->
       <column type="guint"/>
+      <!-- column-name id -->
+      <column type="gchararray"/>
       <!-- column-name name -->
       <column type="gchararray"/>
     </columns>
     <data>
       <row>
         <col id="0">0</col>
-        <col id="1" translatable="yes">Chronoamperometry</col>
+        <col id="1" translatable="yes">cae</col>
+        <col id="2" translatable="yes">Chronoamperometry</col>
       </row>
       <row>
         <col id="0">1</col>
-        <col id="1" translatable="yes">Linear Sweep Voltammetry</col>
+        <col id="1" translatable="yes">lsv</col>
+        <col id="2" translatable="yes">Linear Sweep Voltammetry</col>
       </row>
       <row>
         <col id="0">2</col>
-        <col id="1" translatable="yes">Cyclic Voltammetry</col>
+        <col id="1" translatable="yes">cve</col>
+        <col id="2" translatable="yes">Cyclic Voltammetry</col>
       </row>
       <row>
         <col id="0">3</col>
-        <col id="1" translatable="yes">Square Wave Voltammetry</col>
+        <col id="1" translatable="yes">swv</col>
+        <col id="2" translatable="yes">Square Wave Voltammetry</col>
       </row>
       <row>
         <col id="0">4</col>
-        <col id="1" translatable="yes">Differential Pulse Voltammetry</col>
+        <col id="1" translatable="yes">dpv</col>
+        <col id="2" translatable="yes">Differential Pulse Voltammetry</col>
       </row>
       <row>
         <col id="0">5</col>
-        <col id="1" translatable="yes">AC Voltammetry</col>
+        <col id="1" translatable="yes">acv</col>
+        <col id="2" translatable="yes">AC Voltammetry</col>
       </row>
       <row>
         <col id="0">6</col>
-        <col id="1" translatable="yes">Photodiode</col>
+        <col id="1" translatable="yes">pde</col>
+        <col id="2" translatable="yes">Photodiode</col>
       </row>
     </data>
   </object>
@@ -188,6 +197,7 @@
                         <property name="label">gtk-connect</property>
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
+                        <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <signal name="activate" handler="on_menu_dropbot_connect_activate" swapped="no"/>
                       </object>
@@ -198,6 +208,7 @@
                         <property name="visible">True</property>
                         <property name="sensitive">False</property>
                         <property name="can_focus">False</property>
+                        <property name="use_underline">True</property>
                         <property name="use_stock">True</property>
                         <signal name="activate" handler="on_menu_dropbot_disconnect_activate" swapped="no"/>
                       </object>
diff --git a/dstat-interface/dstat-interface/interface/exp_int.py b/dstat-interface/dstat-interface/interface/exp_int.py
new file mode 100644
index 0000000000000000000000000000000000000000..8208eeb7d7cba6127dc71e8daac54065aaf25c4a
--- /dev/null
+++ b/dstat-interface/dstat-interface/interface/exp_int.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+
+import gtk
+
+class ExpInterface(object):
+    """Generic experiment interface class. Should be subclassed to implement
+    experiment interfaces by populating self.entry.
+    
+    Public methods:
+    get_params(self)
+    """
+    def __init__(self, glade_path):
+        self.builder = gtk.Builder()
+        self.builder.add_from_file(glade_path)
+        self.builder.connect_signals(self)
+        self.entry = {}
+
+    def get_params(self):
+        """Returns a dict of parameters for experiment."""
+        parameters = {}    
+        for key, value in self.entry.iteritems():
+            parameters[key] = int(value.get_text())    
+        return parameters
+        
+class Chronoamp(ExpInterface):
+    """Experiment class for chronoamperometry. Extends ExpInterface class to
+    support treeview neeeded for CA.
+    
+    Public methods:
+    on_add_button_clicked(self, widget)
+    on_remove_button_clicked(self, widget)
+    get_params(self)
+    """
+    def __init__(self):
+        """Extends superclass method to support treeview."""
+        super(Chronoamp, self).__init__('interface/chronoamp.glade')
+        
+        self.statusbar = self.builder.get_object('statusbar')
+        self.model = self.builder.get_object('ca_list')
+        self.treeview = self.builder.get_object('treeview')
+        self.cell_renderer = gtk.CellRendererText()
+        
+        self.treeview.insert_column_with_attributes(-1, "Time",
+                                    self.cell_renderer, text=1).set_expand(True)
+        self.treeview.insert_column_with_attributes(-1, "Potential",
+                                    self.cell_renderer, text=0).set_expand(True)
+        
+        self.selection = self.treeview.get_selection()
+        self.selection.set_mode(gtk.SELECTION_MULTIPLE)
+
+    def on_add_button_clicked(self, widget):
+        """Add current values in potential_entry and time_entry to model."""
+        
+        self.statusbar.remove_all(0)
+        
+        try:
+            potential = int(
+                          self.builder.get_object('potential_entry').get_text())
+            time = int(self.builder.get_object('time_entry').get_text())
+            
+            if (potential > 1499 or potential < -1500):
+                raise ValueError("Potential out of range")
+            if (time < 1 or time > 65535):
+                raise ValueError("Time out of range")
+        
+            self.model.append([potential, time])
+        
+        except ValueError as err:
+            self.statusbar.push(0, str(err))
+        except TypeError as err:
+            self.statusbar.push(0, str(err))
+
+    def on_remove_button_clicked(self, widget):
+        """Remove currently selected items from model."""
+        # returns 2-tuple: treemodel, list of paths of selected rows
+        selected_rows = list(self.selection.get_selected_rows()[1])
+        referencelist = []
+        
+        for i in selected_rows:
+            referencelist.append(gtk.TreeRowReference(self.model, i))
+        
+        for i in referencelist:
+            self.model.remove(self.model.get_iter(i.get_path()))
+
+    def get_params(self):
+        """Returns a dict of parameters for experiment. Overrides superclass
+        method.
+        """
+        parameters = {}
+        parameters['potential'] = [int(r[0]) for r in self.model]
+        parameters['time'] = [int(r[1]) for r in self.model]
+        
+        return parameters
+              
+class LSV(ExpInterface):
+    """Experiment class for LSV."""
+    def __init__(self):
+        """Adds entry listings to superclass's self.entry dict"""
+        super(LSV, self).__init__('interface/lsv.glade')
+
+        self.entry['clean_mV'] = self.builder.get_object('clean_mV')
+        self.entry['clean_s'] = self.builder.get_object('clean_s')
+        self.entry['dep_mV'] = self.builder.get_object('dep_mV')
+        self.entry['dep_s'] = self.builder.get_object('dep_s')
+        self.entry['start'] = self.builder.get_object('start_entry')
+        self.entry['stop'] = self.builder.get_object('stop_entry')
+        self.entry['slope'] = self.builder.get_object('slope_entry')
+        
+class CV(ExpInterface):
+    """Experiment class for CV."""
+    def __init__(self):
+        """Adds entry listings to superclass's self.entry dict"""
+        super(CV, self).__init__('interface/cv.glade')
+
+        self.entry['clean_mV'] = self.builder.get_object('clean_mV')
+        self.entry['clean_s'] = self.builder.get_object('clean_s')
+        self.entry['dep_mV'] = self.builder.get_object('dep_mV')
+        self.entry['dep_s'] = self.builder.get_object('dep_s')
+        self.entry['start'] = self.builder.get_object('start_entry')
+        self.entry['v1'] = self.builder.get_object('v1_entry')
+        self.entry['v2'] = self.builder.get_object('v2_entry')
+        self.entry['slope'] = self.builder.get_object('slope_entry')
+        self.entry['scans'] = self.builder.get_object('scans_entry')
+
+class SWV(ExpInterface):
+    """Experiment class for SWV."""
+    def __init__(self):
+        """Adds entry listings to superclass's self.entry dict"""
+        super(SWV, self).__init__('interface/swv.glade')
+
+        self.entry['clean_mV'] = self.builder.get_object('clean_mV')
+        self.entry['clean_s'] = self.builder.get_object('clean_s')
+        self.entry['dep_mV'] = self.builder.get_object('dep_mV')
+        self.entry['dep_s'] = self.builder.get_object('dep_s')
+        self.entry['start'] = self.builder.get_object('start_entry')
+        self.entry['stop'] = self.builder.get_object('stop_entry')
+        self.entry['step'] = self.builder.get_object('step_entry')
+        self.entry['pulse'] = self.builder.get_object('pulse_entry')
+        self.entry['freq'] = self.builder.get_object('freq_entry')
+        self.entry['scans'] = self.builder.get_object('scans_entry')
+        
+    def get_params(self):
+        """Extends superclass method to pass status of cyclic_checkbutton"""
+        parameters = {}
+        parameters['cyclic_checkbutton'] = self.builder.get_object(
+                                              'cyclic_checkbutton').get_active()
+        parameters.update(super(SWV, self).get_params())
+        
+        return parameters
+        
+class DPV(ExpInterface):
+    """Experiment class for DPV."""
+    def __init__(self):
+        """Adds entry listings to superclass's self.entry dict"""
+        super(DPV, self).__init__('interface/dpv.glade')
+
+        self.entry['clean_mV'] = self.builder.get_object('clean_mV')
+        self.entry['clean_s'] = self.builder.get_object('clean_s')
+        self.entry['dep_mV'] = self.builder.get_object('dep_mV')
+        self.entry['dep_s'] = self.builder.get_object('dep_s')
+        self.entry['start'] = self.builder.get_object('start_entry')
+        self.entry['stop'] = self.builder.get_object('stop_entry')
+        self.entry['step'] = self.builder.get_object('step_entry')
+        self.entry['pulse'] = self.builder.get_object('pulse_entry')
+        self.entry['period'] = self.builder.get_object('period_entry')
+        self.entry['width'] = self.builder.get_object('width_entry')
+        
+class ACV(ExpInterface):
+    """Experiment class for ACV."""
+    def __init__(self):
+        """Adds entry listings to superclass's self.entry dict"""
+        super(ACV, self).__init__('interface/acv.glade')
+        
+        self.entry['start'] = self.builder.get_object('start_entry')
+        self.entry['stop'] = self.builder.get_object('stop_entry')
+        self.entry['slope'] = self.builder.get_object('slope_entry')
+        self.entry['amplitude'] = self.builder.get_object('amplitude_entry')
+        self.entry['freq'] = self.builder.get_object('freq_entry')
+
+class PD(ExpInterface):
+    """Experiment class for PD."""
+    def __init__(self):
+        """Adds entry listings to superclass's self.entry dict"""
+        super(PD, self).__init__('interface/pd.glade')
+        
+        self.entry['voltage'] = self.builder.get_object('voltage_entry')
+        self.entry['time'] = self.builder.get_object('time_entry')
\ No newline at end of file
diff --git a/dstat-interface/dstat-interface/interface/exp_window.py b/dstat-interface/dstat-interface/interface/exp_window.py
new file mode 100644
index 0000000000000000000000000000000000000000..6038229e29453b7e3352317ba3621d15c8ad21bd
--- /dev/null
+++ b/dstat-interface/dstat-interface/interface/exp_window.py
@@ -0,0 +1,43 @@
+import interface.exp_int as exp
+
+class Experiments:
+    def __init__(self, builder):
+        self.builder = builder
+        
+        self.classes = {}
+        self.classes['cae'] = exp.Chronoamp()
+        self.classes['lsv'] = exp.LSV()
+        self.classes['cve'] = exp.CV()
+        self.classes['swv'] = exp.SWV()
+        self.classes['dpv'] = exp.DPV()
+        self.classes['acv'] = exp.ACV()
+        self.classes['pde'] = exp.PD()
+ 
+        #fill exp_section
+        exp_section = self.builder.get_object('exp_section_box')
+        self.containers = {}
+        
+        for key, cls in self.classes.iteritems():
+            self.containers[key] = cls.builder.get_object('scrolledwindow1')
+
+        for key in self.containers:
+            self.containers[key].reparent(exp_section)
+            self.containers[key].hide()
+            
+        
+    def set_exp(self, selection):
+        """Changes parameter tab to selected experiment. Returns True if 
+        successful, False if invalid selection received.
+        
+        Arguments:
+        selection -- id string of experiment type
+        """
+        for key in self.containers:
+            self.containers[key].hide()
+
+        self.containers[selection].show()
+        
+        return True
+        
+    def get_params(self, experiment):
+        return self.classes[experiment].get_params()
\ No newline at end of file
diff --git a/dstatInterface/interface/lsv.glade b/dstat-interface/dstat-interface/interface/lsv.glade
similarity index 100%
rename from dstatInterface/interface/lsv.glade
rename to dstat-interface/dstat-interface/interface/lsv.glade
diff --git a/dstatInterface/interface/pd.glade b/dstat-interface/dstat-interface/interface/pd.glade
similarity index 100%
rename from dstatInterface/interface/pd.glade
rename to dstat-interface/dstat-interface/interface/pd.glade
diff --git a/dstatInterface/interface/save.py b/dstat-interface/dstat-interface/interface/save.py
similarity index 88%
rename from dstatInterface/interface/save.py
rename to dstat-interface/dstat-interface/interface/save.py
index 4456d08f27347a589ab654ea16eac6603d02f031..8cc67f240fa7a235751abcb7e421650749db2b66 100644
--- a/dstatInterface/interface/save.py
+++ b/dstat-interface/dstat-interface/interface/save.py
@@ -7,7 +7,9 @@ from datetime import datetime
 
 def manSave(current_exp):
     exp = current_exp
-    fcd = gtk.FileChooserDialog("Save...", None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK))
+    fcd = gtk.FileChooserDialog("Save...", None, gtk.FILE_CHOOSER_ACTION_SAVE,
+                                (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+                                 gtk.STOCK_SAVE, gtk.RESPONSE_OK))
     
     filters = [gtk.FileFilter()]
     filters[0].set_name("NumPy binary (.npy)")
@@ -37,7 +39,10 @@ def manSave(current_exp):
         fcd.destroy()
 
 def plotSave(plot):
-    fcd = gtk.FileChooserDialog("Save Plot…", None, gtk.FILE_CHOOSER_ACTION_SAVE, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK))
+    fcd = gtk.FileChooserDialog("Save Plot…", None,
+                                gtk.FILE_CHOOSER_ACTION_SAVE,
+                                (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+                                 gtk.STOCK_SAVE, gtk.RESPONSE_OK))
 
     filters = [gtk.FileFilter()]
     filters[0].set_name("Portable Document Format (.pdf)")
@@ -65,7 +70,7 @@ def plotSave(plot):
             if not path.endswith(".png"):
                 path += ".png"
 
-        plot.figure.savefig(path) #savefig determines format from file extension
+        plot.figure.savefig(path)  # determines format from file extension
         fcd.destroy()
     
     elif response == gtk.RESPONSE_CANCEL:
diff --git a/dstatInterface/interface/swv.glade b/dstat-interface/dstat-interface/interface/swv.glade
similarity index 100%
rename from dstatInterface/interface/swv.glade
rename to dstat-interface/dstat-interface/interface/swv.glade
diff --git a/dstatInterface/interface_test.spec b/dstat-interface/dstat-interface/interface_test.spec.bak
similarity index 100%
rename from dstatInterface/interface_test.spec
rename to dstat-interface/dstat-interface/interface_test.spec.bak
diff --git a/dstatInterface/interface_test.py b/dstat-interface/dstat-interface/main.py
similarity index 50%
rename from dstatInterface/interface_test.py
rename to dstat-interface/dstat-interface/main.py
index abca328e397154c6b03f2ba4c5b572e8f2e954ec..e2cb161c97aeefb50fbce670b4ad5441c01fd0ff 100644
--- a/dstatInterface/interface_test.py
+++ b/dstat-interface/dstat-interface/main.py
@@ -1,59 +1,54 @@
 #!/usr/bin/env python
 # -*- coding: utf-8 -*-
+""" GUI Interface for Wheeler Lab DStat """
 
 import sys
 try:
     import pygtk
     pygtk.require('2.0')
-except:
-    pass
+except ImportError:
+    print('PyGTK 2.0 not available')
+    sys.exit(1)
 try:
     import gtk
-    import gobject
-except:
+except ImportError:
     print('GTK not available')
     sys.exit(1)
-
 try:
     import gobject
-except:
+except ImportError:
     print('gobject not available')
     sys.exit(1)
 
-import interface.adc_pot as adc_pot
-import interface.chronoamp as chronoamp
-import interface.lsv as lsv
-import interface.cv as cv
-import interface.swv as swv
-import interface.dpv as dpv
-import interface.acv as acv
-import interface.pd as pd
 import interface.save as save
 import dstat_comm as comm
+import interface.exp_window as exp_window
+import interface.adc_pot as adc_pot
+import mpltest
+import microdrop
+
 from serial import SerialException
 import multiprocessing
 import time
 
-import mpltest
-import microdrop
-
 class Error(Exception):
+    """Copies Exception class"""
     pass
 
 class InputError(Error):
-    """Exception raised for errors in the input.
+    """Exception raised for errors in the input. Extends Error class.
         
-        Attributes:
+    Attributes:
         expr -- input expression in which the error occurred
         msg  -- error message
-        """
+    """
     
     def __init__(self, expr, msg):
         self.expr = expr
         self.msg = msg
 
-class main:
-    
+class Main(object):
+    """Main program """
     def __init__(self):
         self.builder = gtk.Builder()
         self.builder.add_from_file('interface/dstatinterface.glade')
@@ -69,19 +64,14 @@ class main:
         self.stopbutton = self.builder.get_object('pot_stop')
         self.startbutton = self.builder.get_object('pot_start')
         self.adc_pot = adc_pot.adc_pot()
-        self.chronoamp = chronoamp.chronoamp()
-        self.lsv = lsv.lsv()
-        self.cv = cv.cv()
-        self.swv = swv.swv()
-        self.dpv = dpv.dpv()
-        self.acv = acv.acv()
-        self.pd = pd.pd()
         
         self.error_context_id = self.statusbar.get_context_id("error")
         self.message_context_id = self.statusbar.get_context_id("message")
         
         self.plotwindow = self.builder.get_object('plotbox')
         
+        self.exp_window = exp_window.Experiments(self.builder)
+        
         #setup autosave
         self.autosave_checkbox = self.builder.get_object('autosave_checkbutton')
         self.autosavedir_button = self.builder.get_object('autosavedir_button')
@@ -89,23 +79,6 @@ class main:
         
         self.plot = mpltest.plotbox(self.plotwindow)
         
-        #fill exp_section
-        self.exp_section = self.builder.get_object('exp_section_box')
-        self.chronoamp_container = self.chronoamp.builder.get_object('scrolledwindow1')
-        self.chronoamp_container.reparent(self.exp_section)
-        self.lsv_container = self.lsv.builder.get_object('scrolledwindow1')
-        self.lsv_container.reparent(self.exp_section)
-        self.cv_container = self.cv.builder.get_object('scrolledwindow1')
-        self.cv_container.reparent(self.exp_section)
-        self.swv_container = self.swv.builder.get_object('scrolledwindow1')
-        self.swv_container.reparent(self.exp_section)
-        self.dpv_container = self.dpv.builder.get_object('scrolledwindow1')
-        self.dpv_container.reparent(self.exp_section)
-        self.acv_container = self.acv.builder.get_object('scrolledwindow1')
-        self.acv_container.reparent(self.exp_section)
-        self.pd_container = self.pd.builder.get_object('scrolledwindow1')
-        self.pd_container.reparent(self.exp_section)
-        
         #fill adc_pot_box
         self.adc_pot_box = self.builder.get_object('gain_adc_box')
         self.adc_pot_container = self.adc_pot.builder.get_object('vbox1')
@@ -127,7 +100,7 @@ class main:
         #initialize experiment selection combobox
         self.expcombobox = self.builder.get_object('expcombobox')
         self.expcombobox.pack_start(self.cell, True)
-        self.expcombobox.add_attribute(self.cell, 'text', 1)
+        self.expcombobox.add_attribute(self.cell, 'text', 2)
         self.expcombobox.set_active(0)
         
         self.spinner = self.builder.get_object('spinner')
@@ -136,67 +109,44 @@ class main:
         self.mainwindow.set_title("Dstat Interface 0.1")
         self.mainwindow.show_all()
         
-        ##hide unused experiment controls
-        #self.chronoamp_container.hide()
-        self.lsv_container.hide()
-        self.cv_container.hide()
-        self.swv_container.hide()
-        self.dpv_container.hide()
-        self.acv_container.hide()
-        self.pd_container.hide()
+        self.on_expcombobox_changed()
 
         self.expnumber = 0
         
-        self.menu_dropbot_connect = self.builder.get_object('menu_dropbot_connect')
-        self.menu_dropbot_disconnect = self.builder.get_object('menu_dropbot_disconnect')
+        self.menu_dropbot_connect = self.builder.get_object(
+                                                         'menu_dropbot_connect')
+        self.menu_dropbot_disconnect = self.builder.get_object(
+                                                      'menu_dropbot_disconnect')
         self.dropbot_enabled = False
         self.dropbot_triggered = False
 
-    def exp_param_show(self, selection):
-        self.chronoamp_container.hide()
-        self.lsv_container.hide()
-        self.cv_container.hide()
-        self.swv_container.hide()
-        self.dpv_container.hide()
-        self.acv_container.hide()
-        self.pd_container.hide()
-        
-        self.statusbar.remove_all(self.error_context_id)
-
-        if selection == 0:
-            self.chronoamp_container.show()
-        elif selection == 1:
-            self.lsv_container.show()
-        elif selection == 2:
-            self.cv_container.show()
-        elif selection == 3:
-            self.swv_container.show()
-        elif selection == 4:
-            self.dpv_container.show()
-        elif selection == 5:
-            self.acv_container.show()
-        elif selection == 6:
-            self.pd_container.show()
-        else:
-            self.statusbar.push(self.error_context_id, "Experiment not yet implemented")
-
     def on_window1_destroy(self, object, data=None):
+        """ Quit when main window closed."""
         print "quit with cancel"
         gtk.main_quit()
 
     def on_gtk_quit_activate(self, menuitem, data=None):
+        """Quit when Quit selected from menu."""
         print "quit from menu"
         gtk.main_quit()
 
     def on_gtk_about_activate(self, menuitem, data=None):
+        """Display the about window."""
         print "help about selected"
-        self.response = self.aboutdialog.run() #waits for user to click close
+        self.response = self.aboutdialog.run()  # waits for user to click close
         self.aboutdialog.hide()
 
     def on_expcombobox_changed(self, data=None):
-        self.exp_param_show(self.expcombobox.get_active())
+        """Change the experiment window when experiment box changed."""
+        model = self.expcombobox.get_model()
+        _, id, _ = model[self.expcombobox.get_active()]  # id is in 2nd col
+        self.statusbar.remove_all(self.error_context_id)
+        if not self.exp_window.set_exp(id):
+            self.statusbar.push(
+                self.error_context_id, "Experiment not yet implemented")
 
     def on_serial_refresh_clicked(self, data=None):
+        """Refresh list of serial devices."""
         self.serial_devices.refresh()
         self.serial_liststore.clear()
         
@@ -204,21 +154,22 @@ class main:
             self.serial_liststore.append([i])
 
     def on_pot_start_clicked(self, data=None):
-    
-        def exceptions(): #cleans up after errors
+        """Run currently visible experiment."""
+        def exceptions():
+            """ Cleans up after errors """
             if self.dropbot_enabled == True:
                 if self.dropbot_triggered == True:
                     self.dropbot_triggered = False
                     print "finallydone"
                     self.microdrop.reply(microdrop.EXPFINISHED)
-                    self.microdrop_proc = gobject.timeout_add(500, self.microdrop_listen)
+                    self.microdrop_proc = gobject.timeout_add(500,
+                                                          self.microdrop_listen)
             self.spinner.stop()
             self.startbutton.set_sensitive(True)
             self.stopbutton.set_sensitive(False)
             
         selection = self.expcombobox.get_active()
         parameters = {}
-        view_parameters = {}
         
         if self.adc_pot.buffer_toggle.get_active(): #True if box checked
             parameters['adc_buffer'] = "2"
@@ -229,9 +180,12 @@ class main:
         pga_model = self.adc_pot.pga_combobox.get_model()
         gain_model = self.adc_pot.gain_combobox.get_model()
         
-        parameters['adc_rate'] = srate_model.get_value(self.adc_pot.srate_combobox.get_active_iter(), 2) #third column
-        parameters['adc_pga'] = pga_model.get_value(self.adc_pot.pga_combobox.get_active_iter(), 2)
-        parameters['gain'] = gain_model.get_value(self.adc_pot.gain_combobox.get_active_iter(), 2)
+        parameters['adc_rate'] = srate_model.get_value(
+               self.adc_pot.srate_combobox.get_active_iter(), 2)  # third column
+        parameters['adc_pga'] = pga_model.get_value(
+                                 self.adc_pot.pga_combobox.get_active_iter(), 2)
+        parameters['gain'] = gain_model.get_value(
+                                self.adc_pot.gain_combobox.get_active_iter(), 2)
         
         self.line = 0
         self.lastline = 0
@@ -243,12 +197,12 @@ class main:
         self.statusbar.remove_all(self.error_context_id)
         
         try:
-            if selection == 0: #CA
-                parameters['potential'] = [int(r[0]) for r in self.chronoamp.model]
-                parameters['time'] = [int(r[1]) for r in self.chronoamp.model]
-            
+            if selection == 0:  # CA
+                # Add experiment parameters to existing
+                parameters.update(self.exp_window.get_params('cae'))
                 if not parameters['potential']:
-                    raise InputError(parameters['potential'],"Step table is empty")
+                    raise InputError(parameters['potential'],
+                                     "Step table is empty")
                 
                 self.recv_p, self.send_p = multiprocessing.Pipe(duplex=True)
                 self.current_exp = comm.chronoamp(parameters, self.send_p)
@@ -261,40 +215,46 @@ class main:
                 for i in self.current_exp.commands:
                     self.rawbuffer.insert_at_cursor(i)
                 
-                self.current_exp.run_wrapper(self.serial_liststore.get_value(self.serial_combobox.get_active_iter(), 0))
-
-                self.send_p.close() #need to close this copy of connection object for EOF signal to work
+                self.current_exp.run_wrapper(self.serial_liststore.get_value(
+                                     self.serial_combobox.get_active_iter(), 0))
+                                    
+                self.send_p.close()  # need for EOF signal to work
                 
-                self.plot_proc = gobject.timeout_add(200, self.experiment_running_plot)
+                self.plot_proc = gobject.timeout_add(200, 
+                                                   self.experiment_running_plot)
                 gobject.idle_add(self.experiment_running)
                 return
         
-            elif selection == 1: #LSV
-                parameters['clean_mV'] = int(self.lsv.clean_mV.get_text())
-                parameters['clean_s'] = int(self.lsv.clean_s.get_text())
-                parameters['dep_mV'] = int(self.lsv.dep_mV.get_text())
-                parameters['dep_s'] = int(self.lsv.dep_s.get_text())
-                parameters['start'] = int(self.lsv.start_entry.get_text())
-                parameters['stop'] = int(self.lsv.stop_entry.get_text())
-                parameters['slope'] = int(self.lsv.slope_entry.get_text())
+            elif selection == 1: # LSV
+                parameters.update(self.exp_window.get_params('lsv'))
                 
                 #check parameters are within hardware limits
-                if (parameters['clean_mV'] > 1499 or parameters['clean_mV'] < -1500):
-                    raise InputError(parameters['clean_mV'],"Clean potential exceeds hardware limits.")
-                if (parameters['dep_mV'] > 1499 or parameters['dep_mV'] < -1500):
-                    raise InputError(parameters['dep_mV'],"Deposition potential exceeds hardware limits.")
+                if (parameters['clean_mV'] > 1499 or 
+                        parameters['clean_mV'] < -1500):
+                    raise InputError(parameters['clean_mV'],
+                                     "Clean potential exceeds hardware limits.")
+                if (parameters['dep_mV'] > 1499 or
+                        parameters['dep_mV'] < -1500):
+                    raise InputError(parameters['dep_mV'],
+                                "Deposition potential exceeds hardware limits.")
                 if (parameters['clean_s'] < 0):
-                    raise InputError(parameters['clean_s'],"Clean time cannot be negative.")
+                    raise InputError(parameters['clean_s'],
+                                     "Clean time cannot be negative.")
                 if (parameters['dep_s'] < 0):
-                    raise InputError(parameters['dep_s'],"Deposition time cannot be negative.")
+                    raise InputError(parameters['dep_s'],
+                                     "Deposition time cannot be negative.")
                 if (parameters['start'] > 1499 or parameters['start'] < -1500):
-                    raise InputError(parameters['start'],"Start parameter exceeds hardware limits.")
+                    raise InputError(parameters['start'],
+                                     "Start parameter exceeds hardware limits.")
                 if (parameters['stop'] > 1499 or parameters['stop'] < -1500):
-                    raise InputError(parameters['stop'],"Stop parameter exceeds hardware limits.")
+                    raise InputError(parameters['stop'],
+                                     "Stop parameter exceeds hardware limits.")
                 if (parameters['slope'] > 2000 or parameters['slope'] < 1):
-                    raise InputError(parameters['slope'],"Slope parameter exceeds hardware limits.")
+                    raise InputError(parameters['slope'],
+                                     "Slope parameter exceeds hardware limits.")
                 if parameters['start'] == parameters['stop']:
-                    raise InputError(parameters['start'],"Start cannot equal Stop.")
+                    raise InputError(parameters['start'],
+                                     "Start cannot equal Stop.")
 
                 self.recv_p, self.send_p = multiprocessing.Pipe(duplex=True)
                 self.current_exp = comm.lsv_exp(parameters, self.send_p)
@@ -307,46 +267,53 @@ class main:
                 for i in self.current_exp.commands:
                     self.rawbuffer.insert_at_cursor(i)
                 
-                self.current_exp.run_wrapper(self.serial_liststore.get_value(self.serial_combobox.get_active_iter(), 0))
+                self.current_exp.run_wrapper(
+                    self.serial_liststore.get_value(
+                        self.serial_combobox.get_active_iter(), 0))
                 
                 self.send_p.close()
 
-                self.plot_proc = gobject.timeout_add(200, self.experiment_running_plot)
+                self.plot_proc = gobject.timeout_add(200, 
+                                                self.experiment_running_plot)
                 gobject.idle_add(self.experiment_running)
                 return
             
-            elif selection == 2: #CV
-                parameters['clean_mV'] = int(self.cv.clean_mV.get_text())
-                parameters['clean_s'] = int(self.cv.clean_s.get_text())
-                parameters['dep_mV'] = int(self.cv.dep_mV.get_text())
-                parameters['dep_s'] = int(self.cv.dep_s.get_text())
-                parameters['start'] = int(self.cv.start_entry.get_text())
-                parameters['slope'] = int(self.cv.slope_entry.get_text())
-                parameters['v1'] = int(self.cv.v1_entry.get_text())
-                parameters['v2'] = int(self.cv.v2_entry.get_text())
-                parameters['scans'] = int(self.cv.scans_entry.get_text())
+            elif selection == 2: # CV
+                parameters.update(self.exp_window.get_params('cve'))
                 
-                #check parameters are within hardware limits
-                if (parameters['clean_mV'] > 1499 or parameters['clean_mV'] < -1500):
-                    raise InputError(parameters['clean_mV'],"Clean potential exceeds hardware limits.")
-                if (parameters['dep_mV'] > 1499 or parameters['dep_mV'] < -1500):
-                    raise InputError(parameters['dep_mV'],"Deposition potential exceeds hardware limits.")
+                # check parameters are within hardware limits
+                if (parameters['clean_mV'] > 1499 or
+                        parameters['clean_mV'] < -1500):
+                    raise InputError(parameters['clean_mV'],
+                                     "Clean potential exceeds hardware limits.")
+                if (parameters['dep_mV'] > 1499 or
+                        parameters['dep_mV'] < -1500):
+                    raise InputError(parameters['dep_mV'],
+                                "Deposition potential exceeds hardware limits.")
                 if (parameters['clean_s'] < 0):
-                    raise InputError(parameters['clean_s'],"Clean time cannot be negative.")
+                    raise InputError(parameters['clean_s'],
+                                     "Clean time cannot be negative.")
                 if (parameters['dep_s'] < 0):
-                    raise InputError(parameters['dep_s'],"Deposition time cannot be negative.")
+                    raise InputError(parameters['dep_s'],
+                                     "Deposition time cannot be negative.")
                 if (parameters['start'] > 1499 or parameters['start'] < -1500):
-                    raise InputError(parameters['start'],"Start parameter exceeds hardware limits.")
+                    raise InputError(parameters['start'],
+                                     "Start parameter exceeds hardware limits.")
                 if (parameters['slope'] > 2000 or parameters['slope'] < 1):
-                    raise InputError(parameters['slope'],"Slope parameter exceeds hardware limits.")
+                    raise InputError(parameters['slope'],
+                                     "Slope parameter exceeds hardware limits.")
                 if (parameters['v1'] > 1499 or parameters['v1'] < -1500):
-                    raise InputError(parameters['v1'],"Vertex 1 parameter exceeds hardware limits.")
+                    raise InputError(parameters['v1'],
+                                  "Vertex 1 parameter exceeds hardware limits.")
                 if (parameters['v2'] > 1499 or parameters['v2'] < -1500):
-                    raise InputError(parameters['v2'],"Vertex 2 parameter exceeds hardware limits.")
+                    raise InputError(parameters['v2'],
+                                  "Vertex 2 parameter exceeds hardware limits.")
                 if (parameters['scans'] < 1 or parameters['scans'] > 255):
-                    raise InputError(parameters['scans'], "Scans parameter outside limits.")
+                    raise InputError(parameters['scans'], 
+                                     "Scans parameter outside limits.")
                 if parameters['v1'] == parameters['v2']:
-                    raise InputError(parameters['v1'],"Vertex 1 cannot equal Vertex 2.")
+                    raise InputError(parameters['v1'],
+                                     "Vertex 1 cannot equal Vertex 2.")
                 
                 self.recv_p, self.send_p = multiprocessing.Pipe(duplex=True)
                 self.current_exp = comm.cv_exp(parameters, self.send_p)
@@ -359,53 +326,62 @@ class main:
                 for i in self.current_exp.commands:
                     self.rawbuffer.insert_at_cursor(i)
                 
-                self.current_exp.run_wrapper(self.serial_liststore.get_value(self.serial_combobox.get_active_iter(), 0))
+                self.current_exp.run_wrapper(
+                    self.serial_liststore.get_value(
+                        self.serial_combobox.get_active_iter(), 0))
                 
                 self.send_p.close()
                 
-                self.plot_proc = gobject.timeout_add(200, self.experiment_running_plot)
+                self.plot_proc = gobject.timeout_add(200, 
+                                                self.experiment_running_plot)
                 gobject.idle_add(self.experiment_running)
                 return
                 
-            elif selection == 3: #SWV
-                parameters['clean_mV'] = int(self.swv.clean_mV.get_text())
-                parameters['clean_s'] = int(self.swv.clean_s.get_text())
-                parameters['dep_mV'] = int(self.swv.dep_mV.get_text())
-                parameters['dep_s'] = int(self.swv.dep_s.get_text())
-                parameters['start'] = int(self.swv.start_entry.get_text())
-                parameters['stop'] = int(self.swv.stop_entry.get_text())
-                parameters['step'] = int(self.swv.step_entry.get_text())
-                parameters['pulse'] = int(self.swv.pulse_entry.get_text())
-                parameters['freq'] = int(self.swv.freq_entry.get_text())
+            elif selection == 3:  # SWV
+                parameters.update(self.exp_window.get_params('swv'))
                 
-                if self.swv.cyclic_checkbutton.get_active():
-                    parameters['scans'] = int(self.swv.scans_entry.get_text())
+                if parameters['cyclic_checkbutton'] :
                     if parameters['scans'] < 1:
-                        raise InputError(parameters['scans'],"Must have at least one scan.")
+                        raise InputError(parameters['scans'],
+                                        "Must have at least one scan.")
                 else:
                     parameters['scans'] = 0
                 
-                #check parameters are within hardware limits (doesn't check if pulse will go out of bounds, but instrument checks this (I think))
-                if (parameters['clean_mV'] > 1499 or parameters['clean_mV'] < -1500):
-                    raise InputError(parameters['clean_mV'],"Clean potential exceeds hardware limits.")
-                if (parameters['dep_mV'] > 1499 or parameters['dep_mV'] < -1500):
-                    raise InputError(parameters['dep_mV'],"Deposition potential exceeds hardware limits.")
+                # check parameters are within hardware limits (doesn't
+                # check if pulse will go out of bounds, but instrument
+                # checks this (I think))
+                if (parameters['clean_mV'] > 1499 or
+                        parameters['clean_mV'] < -1500):
+                    raise InputError(parameters['clean_mV'],
+                                     "Clean potential exceeds hardware limits.")
+                if (parameters['dep_mV'] > 1499 or
+                        parameters['dep_mV'] < -1500):
+                    raise InputError(parameters['dep_mV'],
+                                "Deposition potential exceeds hardware limits.")
                 if (parameters['clean_s'] < 0):
-                    raise InputError(parameters['clean_s'],"Clean time cannot be negative.")
+                    raise InputError(parameters['clean_s'],
+                                     "Clean time cannot be negative.")
                 if (parameters['dep_s'] < 0):
-                    raise InputError(parameters['dep_s'],"Deposition time cannot be negative.")
+                    raise InputError(parameters['dep_s'],
+                                     "Deposition time cannot be negative.")
                 if (parameters['start'] > 1499 or parameters['start'] < -1500):
-                    raise InputError(parameters['start'],"Start parameter exceeds hardware limits.")
+                    raise InputError(parameters['start'],
+                                     "Start parameter exceeds hardware limits.")
                 if (parameters['step'] > 200 or parameters['step'] < 1):
-                    raise InputError(parameters['step'],"Step height parameter exceeds hardware limits.")
+                    raise InputError(parameters['step'],
+                               "Step height parameter exceeds hardware limits.")
                 if (parameters['stop'] > 1499 or parameters['stop'] < -1500):
-                    raise InputError(parameters['stop'],"Stop parameter exceeds hardware limits.")
+                    raise InputError(parameters['stop'],
+                                      "Stop parameter exceeds hardware limits.")
                 if (parameters['pulse'] > 150 or parameters['pulse'] < 1):
-                    raise InputError(parameters['pulse'],"Pulse height parameter exceeds hardware limits.")
+                    raise InputError(parameters['pulse'],
+                              "Pulse height parameter exceeds hardware limits.")
                 if (parameters['freq'] < 1 or parameters['freq'] > 1000):
-                    raise InputError(parameters['freq'], "Frequency parameter outside limits.")
+                    raise InputError(parameters['freq'],
+                                     "Frequency parameter outside limits.")
                 if parameters['start'] == parameters['stop']:
-                    raise InputError(parameters['start'],"Start cannot equal Stop.")
+                    raise InputError(parameters['start'],
+                                     "Start cannot equal Stop.")
                     
                 self.recv_p, self.send_p = multiprocessing.Pipe(duplex=True)
                 self.current_exp = comm.swv_exp(parameters, self.send_p)
@@ -418,51 +394,58 @@ class main:
                 for i in self.current_exp.commands:
                     self.rawbuffer.insert_at_cursor(i)
                 
-                self.current_exp.run_wrapper(self.serial_liststore.get_value(self.serial_combobox.get_active_iter(), 0))
+                self.current_exp.run_wrapper(
+                    self.serial_liststore.get_value(
+                        self.serial_combobox.get_active_iter(), 0))
                 
                 self.send_p.close()
                 
-                self.plot_proc = gobject.timeout_add(200, self.experiment_running_plot)
+                self.plot_proc = gobject.timeout_add(200, 
+                                                self.experiment_running_plot)
                 gobject.idle_add(self.experiment_running)
                 return
         
-            elif selection == 4: #DPV
-                parameters['clean_mV'] = int(self.dpv.clean_mV.get_text())
-                parameters['clean_s'] = int(self.dpv.clean_s.get_text())
-                parameters['dep_mV'] = int(self.dpv.dep_mV.get_text())
-                parameters['dep_s'] = int(self.dpv.dep_s.get_text())
-                parameters['start'] = int(self.dpv.start_entry.get_text())
-                parameters['stop'] = int(self.dpv.stop_entry.get_text())
-                parameters['step'] = int(self.dpv.step_entry.get_text())
-                parameters['pulse'] = int(self.dpv.pulse_entry.get_text())
-                parameters['period'] = int(self.dpv.period_entry.get_text())
-                parameters['width'] = int(self.dpv.width_entry.get_text())
+            elif selection == 4:  # DPV
+                parameters.update(self.exp_window.get_params('dpv'))
                 
-                #check parameters are within hardware limits (doesn't check if pulse will go out of bounds, but instrument checks this (I think))
-                if (parameters['clean_mV'] > 1499 or parameters['clean_mV'] < -1500):
-                    raise InputError(parameters['clean_mV'],"Clean potential exceeds hardware limits.")
-                if (parameters['dep_mV'] > 1499 or parameters['dep_mV'] < -1500):
-                    raise InputError(parameters['dep_mV'],"Deposition potential exceeds hardware limits.")
+                if (parameters['clean_mV'] > 1499 or
+                        parameters['clean_mV'] < -1500):
+                    raise InputError(parameters['clean_mV'],
+                                     "Clean potential exceeds hardware limits.")
+                if (parameters['dep_mV'] > 1499 or
+                        parameters['dep_mV'] < -1500):
+                    raise InputError(parameters['dep_mV'],
+                                "Deposition potential exceeds hardware limits.")
                 if (parameters['clean_s'] < 0):
-                    raise InputError(parameters['clean_s'],"Clean time cannot be negative.")
+                    raise InputError(parameters['clean_s'],
+                                     "Clean time cannot be negative.")
                 if (parameters['dep_s'] < 0):
-                    raise InputError(parameters['dep_s'],"Deposition time cannot be negative.")
+                    raise InputError(parameters['dep_s'],
+                                     "Deposition time cannot be negative.")
                 if (parameters['start'] > 1499 or parameters['start'] < -1500):
-                    raise InputError(parameters['start'],"Start parameter exceeds hardware limits.")
+                    raise InputError(parameters['start'],
+                                     "Start parameter exceeds hardware limits.")
                 if (parameters['step'] > 200 or parameters['step'] < 1):
-                    raise InputError(parameters['step'],"Step height parameter exceeds hardware limits.")
+                    raise InputError(parameters['step'],
+                               "Step height parameter exceeds hardware limits.")
                 if (parameters['stop'] > 1499 or parameters['stop'] < -1500):
-                    raise InputError(parameters['stop'],"Stop parameter exceeds hardware limits.")
+                    raise InputError(parameters['stop'],
+                                     "Stop parameter exceeds hardware limits.")
                 if (parameters['pulse'] > 150 or parameters['pulse'] < 1):
-                    raise InputError(parameters['pulse'],"Pulse height parameter exceeds hardware limits.")
+                    raise InputError(parameters['pulse'],
+                        "Pulse height parameter exceeds hardware limits.")
                 if (parameters['period'] < 1 or parameters['period'] > 1000):
-                    raise InputError(parameters['period'], "Period parameter outside limits.")
+                    raise InputError(parameters['period'], 
+                                    "Period parameter outside limits.")
                 if (parameters['width'] < 1 or parameters['width'] > 1000):
-                    raise InputError(parameters['width'], "Width parameter outside limits.")
+                    raise InputError(parameters['width'],
+                                     "Width parameter outside limits.")
                 if parameters['period'] <= parameters['width']:
-                    raise InputError(parameters['width'],"Width must be less than period.")
+                    raise InputError(parameters['width'],
+                                     "Width must be less than period.")
                 if parameters['start'] == parameters['stop']:
-                    raise InputError(parameters['start'],"Start cannot equal Stop.")
+                    raise InputError(parameters['start'],
+                                     "Start cannot equal Stop.")
                 
                 self.recv_p, self.send_p = multiprocessing.Pipe(duplex=True)
                 self.current_exp = comm.dpv_exp(parameters, self.send_p)
@@ -475,47 +458,62 @@ class main:
                 for i in self.current_exp.commands:
                     self.rawbuffer.insert_at_cursor(i)
 
-                self.current_exp.run_wrapper(self.serial_liststore.get_value(self.serial_combobox.get_active_iter(), 0))
+                self.current_exp.run_wrapper(
+                    self.serial_liststore.get_value(
+                        self.serial_combobox.get_active_iter(), 0))
 
                 self.send_p.close()
 
-                self.plot_proc = gobject.timeout_add(200, self.experiment_running_plot)
+                self.plot_proc = gobject.timeout_add(200,
+                                                   self.experiment_running_plot)
                 gobject.idle_add(self.experiment_running)
                 return
 
             else:
-                self.statusbar.push(self.error_context_id, "Experiment not yet implemented.")
+                self.statusbar.push(self.error_context_id, 
+                                    "Experiment not yet implemented.")
                 exceptions()
                 
         except ValueError:
-            self.statusbar.push(self.error_context_id, "Experiment parameters must be integers.")
+            self.statusbar.push(self.error_context_id, 
+                                "Experiment parameters must be integers.")
             exceptions()
         
-        except InputError as e:
-            self.statusbar.push(self.error_context_id, e.msg)
+        except InputError as err:
+            self.statusbar.push(self.error_context_id, err.msg)
             exceptions()
         
         except SerialException:
-            self.statusbar.push(self.error_context_id, "Could not establish serial connection.")
+            self.statusbar.push(self.error_context_id, 
+                                "Could not establish serial connection.")
             exceptions()
 
-        except AssertionError as e:
-            self.statusbar.push(self.error_context_id, str(e))
+        except AssertionError as err:
+            self.statusbar.push(self.error_context_id, str(err))
             exceptions()
 
     def experiment_running(self):
+        """Receive data from experiment process and add to current_exp.data.
+        Run in GTK main loop.
+        
+        Returns:
+        True -- when experiment is continuing to keep function in GTK's queue.
+        False -- when experiment process signals EOFError or IOError to remove
+            function from GTK's queue.
+        """
         try:
             if self.recv_p.poll():
                 self.line, data = self.recv_p.recv()
                 if self.line > self.lastdataline:
-                    self.current_exp.data += [[],[]]
+                    self.current_exp.data += [[], []]
                     if len(data) > 2:
-                        self.current_exp.data_extra += [[],[]]
+                        self.current_exp.data_extra += [[], []]
                     self.lastdataline = self.line
                 for i in range(2):
                     self.current_exp.data[2*self.line+i].append(data[i])
-                if len(data) > 2:
-                    self.current_exp.data_extra[2*self.line+i].append(data[i])
+                    if len(data) > 2:
+                        self.current_exp.data_extra[2*self.line+i].append(
+                                                                      data[i+2])
             else:
                 time.sleep(.001)
             return True
@@ -527,23 +525,31 @@ class main:
             return False
             
     def experiment_running_plot(self):
+        """Plot all data in current_exp.data.
+        Run in GTK main loop. Always returns True so must be manually
+        removed from GTK's queue.
+        """
         if self.line > self.lastline:
             self.plot.addline()
-            self.plot.updateline(self.current_exp, self.lastline) #make sure all of last line is added
+            # make sure all of last line is added
+            self.plot.updateline(self.current_exp, self.lastline) 
             self.lastline = self.line
         self.plot.updateline(self.current_exp, self.line)
         self.plot.redraw()
         return True
 
     def experiment_done(self):
-        gobject.source_remove(self.plot_proc) #stop automatic plot update
-        self.experiment_running_plot() #make sure all data updated on plot
+        """Clean up after data acquisition is complete. Update plot and
+        copy data to raw data tab. Saves data if autosave enabled.
+        """
+        gobject.source_remove(self.plot_proc)  # stop automatic plot update
+        self.experiment_running_plot()  # make sure all data updated on plot
 
         self.databuffer.set_text("")
         self.databuffer.place_cursor(self.databuffer.get_start_iter())
         self.rawbuffer.insert_at_cursor("\n")
-#        self.rawbuffer.set_text("")
-#        self.rawbuffer.place_cursor(self.rawbuffer.get_start_iter())
+        self.rawbuffer.set_text("")
+        self.rawbuffer.place_cursor(self.rawbuffer.get_start_iter())
 
         for col in zip(*self.current_exp.data):
             for row in col:
@@ -557,8 +563,10 @@ class main:
                 self.databuffer.insert_at_cursor("\n")
     
         if self.autosave_checkbox.get_active():
-            save.autoSave(self.current_exp, self.autosavedir_button, self.autosavename.get_text(), self.expnumber)
-            save.autoPlot(self.plot, self.autosavedir_button, self.autosavename.get_text(), self.expnumber)
+            save.autoSave(self.current_exp, self.autosavedir_button,
+                          self.autosavename.get_text(), self.expnumber)
+            save.autoPlot(self.plot, self.autosavedir_button,
+                          self.autosavename.get_text(), self.expnumber)
             self.expnumber += 1
         
         if self.dropbot_enabled == True:
@@ -566,33 +574,40 @@ class main:
                 self.dropbot_triggered = False
                 print "expdone"
                 self.microdrop.reply(microdrop.EXPFINISHED)
-            self.microdrop_proc = gobject.timeout_add(500, self.microdrop_listen)
+            self.microdrop_proc = gobject.timeout_add(500,
+                                                      self.microdrop_listen)
         
         self.spinner.stop()
         self.startbutton.set_sensitive(True)
         self.stopbutton.set_sensitive(False)
 
     def on_pot_stop_clicked(self, data=None):
+        """Stop current experiment. Signals experiment process to stop."""
         if self.recv_p:
             print "stop"
             self.recv_p.send('a')
     
     def on_file_save_exp_activate(self, menuitem, data=None):
+        """Activate dialogue to save current experiment data. """
         if self.current_exp:
             save_inst = save.manSave(self.current_exp)
     
     def on_file_save_plot_activate(self, menuitem, data=None):
+        """Activate dialogue to save current plot."""
         save_inst = save.plotSave(self.plot)
     
     def on_menu_dropbot_connect_activate(self, menuitem, data=None):
+        """Listen for remote control connection from µDrop."""
         self.microdrop = microdrop.microdropConnection()
         self.dropbot_enabled = True
         self.menu_dropbot_connect.set_sensitive(False)
         self.menu_dropbot_disconnect.set_sensitive(True)
-        self.statusbar.push(self.message_context_id, "Waiting for µDrop to connect…")
+        self.statusbar.push(self.message_context_id,
+                            "Waiting for µDrop to connect…")
         self.microdrop_proc = gobject.timeout_add(500, self.microdrop_listen)
     
     def on_menu_dropbot_disconnect_activate(self, menuitem, data= None):
+        """Disconnect µDrop connection and stop listening."""
         gobject.source_remove(self.microdrop_proc)
         self.microdrop.reset()
         del self.microdrop
@@ -601,32 +616,35 @@ class main:
         self.menu_dropbot_disconnect.set_sensitive(False)
 
     def microdrop_listen(self):
+        """Manage signals from µDrop. Must be added to GTK's main loop to
+        run periodically.
+        """
         drdy, data = self.microdrop.listen()
         if drdy == False:
             return True
-        if self.microdrop.connected == False:
-            if data == microdrop.CONREQ:
-                print "INFO: µDrop connected"
-                self.statusbar.push(self.message_context_id, "µDrop connected.")
-                self.microdrop.reply(microdrop.CONREP)
-                self.microdrop.connected = True
+
+        if data == microdrop.EXP_FINISH_REQ:
+            if self.dropbot_triggered:
+                self.on_pot_start_clicked()
+                return False  # Removes function from GTK's main loop
             else:
-                print "WAR: Invalid µDrop connection request."
-                self.microdrop.reply(microdrop.INVAL_CMD)
+                print "WAR: µDrop requested experiment finish confirmation \
+                        without starting experiment."
+                self.microdrop.reply(microdrop.EXPFINISHED)
+            
         elif data == microdrop.STARTEXP:
+            self.microdrop.connected = True
+            self.statusbar.push(self.message_context_id, "µDrop connected.")
             self.dropbot_triggered = True
-            self.on_pot_start_clicked()
-            return False
+            self.microdrop.reply(microdrop.START_REP)
         else:
             print "WAR: Received invalid command from µDrop"
             self.microdrop.reply(microdrop.INVAL_CMD)
         return True
 
 
-
-
 if __name__ == "__main__":
     multiprocessing.freeze_support()
     gobject.threads_init()
-    main = main()
+    MAIN = Main()
     gtk.main()
\ No newline at end of file
diff --git a/dstatInterface/microdrop.py b/dstat-interface/dstat-interface/microdrop.py
similarity index 52%
rename from dstatInterface/microdrop.py
rename to dstat-interface/dstat-interface/microdrop.py
index 95ea34cbe86d9998730c12a9eb91151e23782028..8546ad38a13fccc093f49b27f2ef290979e958f3 100644
--- a/dstatInterface/microdrop.py
+++ b/dstat-interface/dstat-interface/microdrop.py
@@ -4,26 +4,39 @@ import zmq.error
 #signals
 CONREQ = "0"
 CONREP = "1"
-STARTEXP = "10"
-EXPFINISHED = "11"
+STARTEXP = "start"
+START_REP = "started"
+EXP_FINISH_REQ = "notify_completion"
+EXPFINISHED = "completed"
 INVAL_CMD = "99"
 
 #States
 RECV = 0
 SEND = 1
 
-class microdropConnection:
-
+class microdropConnection(object):
+    """Manages microdrop connection over TCP with zmq"""
     def __init__(self, port=6789):
+        """Create zmq context and bind to port. Should be called manually
+        to reinitialize if reset is called.
+        
+        Keyword arguments:
+        port -- the TCP to bind to on localhost
+        """
         self.port = port
         self.connected = False
         self.state = RECV
     
         self.ctx = zmq.Context()
         self.soc = zmq.Socket(self.ctx, zmq.REP)
-        self.soc.bind("".join(['tcp://*:',str(self.port)]))
+        self.soc.bind("".join(['tcp://*:', str(self.port)]))
     
     def listen(self):
+        """Perform non-blocking recv on zmq port. self.state must be RECV.
+        Returns a tuple:
+        [0] -- True if a message was received, False otherwise.
+        [1] -- The recieved message or "" if no message received.
+        """
         if self.state == SEND:
             print "WAR: Microdrop Connection state invalid, resetting..."
             self.reset()
@@ -36,6 +49,11 @@ class microdropConnection:
             return (False, "")
 
     def reply(self, data):
+        """Sends a reply on zmq port. self.state must be SEND.
+        
+        Arguments:
+        data -- a str to be sent
+        """
         if self.state == RECV:
             print "WAR: Microdrop Connection state invalid, resetting..."
             self.reset()
@@ -46,6 +64,7 @@ class microdropConnection:
         return True
         
     def reset(self):
-        self.soc.unbind("".join(['tcp://*:',str(self.port)]))
+        """Reset zmq interface. Must call __init__ again to reinitialize."""
+        self.soc.unbind("".join(['tcp://*:', str(self.port)]))
         del self.soc
         del self.ctx
diff --git a/dstat-interface/dstat-interface/mpltest.py b/dstat-interface/dstat-interface/mpltest.py
new file mode 100644
index 0000000000000000000000000000000000000000..59e53922f4271278cf56079b117d205398cc53f9
--- /dev/null
+++ b/dstat-interface/dstat-interface/mpltest.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+"""
+Creates data plot.
+"""
+import gtk
+from matplotlib.figure import Figure
+
+#from matplotlib.backends.backend_gtkcairo\
+#   import FigureCanvasGTKCairo as FigureCanvas
+#from matplotlib.backends.backend_gtkcairo\
+#   import NavigationToolbar2Cairo as NavigationToolbar
+from matplotlib.backends.backend_gtkagg \
+    import FigureCanvasGTKAgg as FigureCanvas
+from matplotlib.backends.backend_gtkagg \
+    import NavigationToolbar2GTKAgg as NavigationToolbar
+
+class plotbox(object):
+    """Contains main data plot and associated methods."""
+    def __init__(self, plotwindow_instance):
+        """Creates plot and moves it to a gtk container.
+        
+        Arguments:
+        plotwindow_instance -- gtk container to hold plot.
+        """
+        
+        self.figure = Figure()
+        self.figure.subplots_adjust(left=0.07, bottom=0.07,
+                                    right=0.96, top=0.96)
+        self.axe1 = self.figure.add_subplot(111)
+        
+        self.lines = self.axe1.plot([0, 1], [0, 1])
+        
+        self.axe1.ticklabel_format(style='sci', scilimits=(0, 3),
+                                   useOffset=False, axis='y')
+
+        self.canvas = FigureCanvas(self.figure)
+        self.win = gtk.Window()
+        self.vbox = gtk.VBox()
+        self.win.add(self.vbox)
+        self.vbox.pack_start(self.canvas)
+        self.toolbar = NavigationToolbar(self.canvas, self.win)
+        self.vbox.pack_start(self.toolbar, False, False)
+        self.vbox.reparent(plotwindow_instance)
+    
+    def clearall(self):
+        """Remove all lines on plot. """
+        for i in self.lines:
+            i.remove()
+        self.lines = self.axe1.plot([0, 1], [0, 1])
+    
+    def clearline(self, line_number):
+        """Remove a line specified by line_number."""
+        self.lines[line_number].remove()
+        self.lines.pop(line_number)
+    
+    def addline(self):
+        """Add a new line to plot. (initialized with dummy data)))"""
+        self.lines.append(self.axe1.plot([0, 1], [0, 1])[0])
+    
+    def updateline(self, Experiment, line_number):
+        """Update a line specified by line_number with data stored in
+        the Experiment instance.
+        """
+        # limits display to 2000 data points per line
+        divisor = len(Experiment.data[1+line_number*2]) // 2000 + 1
+        
+        self.lines[line_number].set_ydata(
+                                   Experiment.data[1+line_number*2][1::divisor])
+        self.lines[line_number].set_xdata(
+                                   Experiment.data[line_number*2][1::divisor])
+
+    def changetype(self, Experiment):
+        """Change plot type. Set axis labels and x bounds to those stored
+        in the Experiment instance.
+        """
+        self.axe1.set_xlabel(Experiment.xlabel)
+        self.axe1.set_ylabel(Experiment.ylabel)
+        self.axe1.set_xlim(Experiment.xmin, Experiment.xmax)
+
+        self.figure.canvas.draw()
+
+    def redraw(self):
+        """Autoscale and refresh the plot."""
+        self.axe1.relim()
+        self.axe1.autoscale(True, axis = 'y')
+        self.figure.canvas.draw()
+
+        return True
+        
diff --git a/dstatInterface/setup.py b/dstat-interface/dstat-interface/setup.py
similarity index 100%
rename from dstatInterface/setup.py
rename to dstat-interface/dstat-interface/setup.py
diff --git a/dstat-interface/setup.py b/dstat-interface/setup.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dstatInterface/glade1.py b/dstatInterface/glade1.py
deleted file mode 100644
index 454320aa4e21bda38289abc438a88655457d1c99..0000000000000000000000000000000000000000
--- a/dstatInterface/glade1.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/env python
-
-import sys
-try:
-    import pygtk
-    pygtk.require('2.0')
-except:
-    pass
-try:
-    import gtk
-except:
-    print('GTK not available')
-    sys.exit(1)
-try:
-    import math
-except:
-    print('math lib missing')
-    sys.exit(1)
-
-# we can call it just about anything we want
-class Buglump:
-    
-    # This first define is for our on_window1_destroy signal we created in the
-    # Glade designer. The print message does just that and prints to the terminal
-    # which can be useful for debugging. The 'object' if you remember is the signal
-    # class we picked from GtkObject.
-    def on_window1_destroy(self, object, data=None):
-        print "quit with cancel"
-        gtk.main_quit()
-    
-    # This is the same as above but for our menu item.
-    def on_gtk_quit_activate(self, menuitem, data=None):
-        print "quit from menu"
-        gtk.main_quit()
-    
-    def on_gtk_about_activate(self, menuitem, data=None):
-        print "help about selected"
-        self.response = self.aboutdialog.run() #waits for user to click close - could test response with if
-        self.aboutdialog.hide()
-    
-    def on_push_status_activate(self, menuitem, data=None): #adds message to top of stack
-        self.status_count += 1 #increment status_count
-        self.statusbar.push(self.context_id, "Message number %s" % str(self.status_count))
-    
-    def on_pop_status_activate(self, menuitem, data=None): #removes top message from stack
-        self.status_count -= 1
-        self.statusbar.pop(self.context_id)
-
-    def on_clear_status_activate(self, menuitem, data=None): #clears status stack
-        self.statusbar.remove_all(self.context_id)
-        self.status_count = 0
-#        while (self.status_count > 0):
-#            self.statusbar.pop(self.context_id)
-#            self.status_count -= 1
-
-    def on_sfm_button_clicked(self, button, data=None):
-        # create an instance of the entry objects
-        # so we can get and set the text values
-        self.entry1 = self.builder.get_object("entry1")
-        self.entry2 = self.builder.get_object("entry2")
-        self.result1 = self.builder.get_object("result1")
-
-        # get the text from the GtkEntry widget and convert
-        # it to a float value so we can calculate the result
-        self.sfm = float(self.entry1.get_text())
-        self.diameter = float(self.entry2.get_text())
-
-        # calculate the result convert to an int to round the number
-        # then convert to a string to set the text in our label
-        # notice the math.pi constant is used in the calculation
-        self.rpm = str(int(self.sfm * ((12/math.pi)/self.diameter)))
-
-        # debugging print
-        print "calculate rpm clicked"
-
-        # set the result label with our results
-        self.result1.set_text(self.rpm)
-
-    def on_gtk_new_activate(self, menuitem, data=None):
-        # debugging message
-        print 'File New selected'
-        
-        # create a label for the tab and using get_n_pages() to find out how
-        # many pages there is so the next page has a sequential number.
-        self.label1 = gtk.Label('Page ' + str(self.notebook.get_n_pages() + 1))
-        
-        # create a label to put into the page
-        self.label2 = gtk.Label('Hello World')
-        # If you don't show the contents of the tab it won't show up
-        self.label2.show()
-        
-        # append a page with label5 as the contents and label5 as the tab
-        self.notebook.append_page(self.label2, self.label1)
-
-    def on_notebook1_switch_page(self,  notebook, page, page_num, data=None):
-        self.tab = notebook.get_nth_page(page_num)
-        self.label = notebook.get_tab_label(self.tab).get_label()
-        self.message_id = self.statusbar.push(0, self.label)
-
-
-
-    # This is our init part where we connect the signals
-    def __init__(self):
-        self.gladefile = "test1.glade" # store the file name
-        self.builder = gtk.Builder() # create an instance of the gtk.Builder
-        self.builder.add_from_file(self.gladefile) # add the xml file to the Builder
-        
-        # This line does the magic of connecting the signals created in the Glade3
-        # builder to our defines above. You must have one def for each signal if
-        # you use this line to connect the signals.
-        self.builder.connect_signals(self)
-        
-        #get widgets
-        self.window = self.builder.get_object("window1")
-        self.aboutdialog = self.builder.get_object("aboutdialog1")
-        self.statusbar = self.builder.get_object("statusbar")
-        self.notebook = self.builder.get_object("notebook1")
-        
-        self.window.show() # this shows the 'window1' object
-
-        self.context_id = self.statusbar.get_context_id("status") #register and get statusbar context_id for description "status"
-        self.status_count = 0 #count of messages pushed
-
-# If this is run stand alone execute the following after the 'if'
-# If this class is imported into another program the code after the 'if' will
-# not run. This makes the code more flexible.
-if __name__ == "__main__":
-    main = Buglump() # create an instance of our class
-    gtk.main() # run the darn thing
\ No newline at end of file
diff --git a/dstatInterface/interface/acv.py b/dstatInterface/interface/acv.py
deleted file mode 100644
index 214af8345b8acbc345fc3bd2eb67be0a4e946565..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/acv.py
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class acv:
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/acv.glade')
-        self.builder.connect_signals(self)
-
-        self.start_entry = self.builder.get_object('start_entry')
-        self.stop_entry = self.builder.get_object('stop_entry')
-        self.slope_entry = self.builder.get_object('slope_entry')
-        self.amplitude_entry = self.builder.get_object('amplitude_entry')
-        self.freq_entry = self.builder.get_object('freq_entry')
\ No newline at end of file
diff --git a/dstatInterface/interface/chronoamp.py b/dstatInterface/interface/chronoamp.py
deleted file mode 100644
index 0eb3b090969634dce88602626b2a415c92da88c6..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/chronoamp.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class chronoamp:
-    def label_set_func(self, tree_column, cell, model, iter):
-        info = model.get_value(iter, 1)
-        cell.set_property("text", info)
-    
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/chronoamp.glade')
-        self.builder.connect_signals(self)
-        
-        self.statusbar = self.builder.get_object('statusbar')
-        self.potential = self.builder.get_object('potential_entry')
-        self.time = self.builder.get_object('time_entry')
-        self.model = self.builder.get_object('ca_list')
-        self.treeview = self.builder.get_object('treeview')
-
-        self.cell_renderer = gtk.CellRendererText()
-        
-        self.treeview.insert_column_with_attributes(-1, "Time", self.cell_renderer, text=1).set_expand(True)
-        self.treeview.insert_column_with_attributes(-1, "Potential", self.cell_renderer, text=0).set_expand(True)
-        
-        self.treeviewselection = self.treeview.get_selection()
-        self.treeviewselection.set_mode(gtk.SELECTION_MULTIPLE)
-
-    def on_add_button_clicked(self, widget):
-        self.statusbar.remove_all(0)
-        
-        try:
-            potential = int(self.potential.get_text())
-            time = int(self.time.get_text())
-            
-            if (potential > 1499 or potential < -1500):
-                raise ValueError("Potential out of range")
-            if (time < 1 or time > 65535):
-                raise ValueError("Time out of range")
-        
-            self.model.append([potential, time])
-        
-        except ValueError as e:
-            self.statusbar.push(0, str(e))
-        except TypeError as e:
-            self.statusbar.push(0, str(e))
-
-    def on_remove_button_clicked(self, widget):
-        self.selected_rows = list(self.treeviewselection.get_selected_rows()[1]) #returns 2-tuple: treemodel, list of paths selected rows
-        
-        self.referencelist = []
-        
-        for i in self.selected_rows:
-            x=gtk.TreeRowReference(self.model, i)
-            self.referencelist.append(x)
-        
-        for i in self.referencelist:
-            self.model.remove(self.model.get_iter(i.get_path()))
diff --git a/dstatInterface/interface/cv.py b/dstatInterface/interface/cv.py
deleted file mode 100644
index 0aadf29d6e6f46e12793d5916514600dc9448da7..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/cv.py
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class cv:
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/cv.glade')
-        self.builder.connect_signals(self)
-
-        self.clean_mV = self.builder.get_object('clean_mV')
-        self.clean_s = self.builder.get_object('clean_s')
-        self.dep_mV = self.builder.get_object('dep_mV')
-        self.dep_s = self.builder.get_object('dep_s')
-        self.start_entry = self.builder.get_object('start_entry')
-        self.v1_entry = self.builder.get_object('v1_entry')
-        self.v2_entry = self.builder.get_object('v2_entry')
-        self.slope_entry = self.builder.get_object('slope_entry')
-        self.scans_entry = self.builder.get_object('scans_entry')
\ No newline at end of file
diff --git a/dstatInterface/interface/dpv.py b/dstatInterface/interface/dpv.py
deleted file mode 100644
index deb81bf8c73c2f45f02a9264c3088fbcec6c069a..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/dpv.py
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class dpv:
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/dpv.glade')
-        self.builder.connect_signals(self)
-
-        self.clean_mV = self.builder.get_object('clean_mV')
-        self.clean_s = self.builder.get_object('clean_s')
-        self.dep_mV = self.builder.get_object('dep_mV')
-        self.dep_s = self.builder.get_object('dep_s')
-        self.start_entry = self.builder.get_object('start_entry')
-        self.stop_entry = self.builder.get_object('stop_entry')
-        self.step_entry = self.builder.get_object('step_entry')
-        self.pulse_entry = self.builder.get_object('pulse_entry')
-        self.period_entry = self.builder.get_object('period_entry')
-        self.width_entry = self.builder.get_object('width_entry')
\ No newline at end of file
diff --git a/dstatInterface/interface/lsv.py b/dstatInterface/interface/lsv.py
deleted file mode 100644
index 990ca640c8c4471d4bae47205d79302bb72c7000..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/lsv.py
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class lsv:
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/lsv.glade')
-        self.builder.connect_signals(self)
-        
-        
-        self.clean_mV = self.builder.get_object('clean_mV')
-        self.clean_s = self.builder.get_object('clean_s')
-        self.dep_mV = self.builder.get_object('dep_mV')
-        self.dep_s = self.builder.get_object('dep_s')
-        self.start_entry = self.builder.get_object('start_entry')
-        self.stop_entry = self.builder.get_object('stop_entry')
-        self.slope_entry = self.builder.get_object('slope_entry')
\ No newline at end of file
diff --git a/dstatInterface/interface/pd.py b/dstatInterface/interface/pd.py
deleted file mode 100644
index bd6652d821b15e513ef6eafb9ddf6c1fabd91d2b..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/pd.py
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class pd:
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/pd.glade')
-        self.builder.connect_signals(self)
-
-        self.voltage_entry = self.builder.get_object('voltage_entry')
-        self.time_entry = self.builder.get_object('time_entry')
\ No newline at end of file
diff --git a/dstatInterface/interface/swv.py b/dstatInterface/interface/swv.py
deleted file mode 100644
index a78c44b9ec1cd518c23a5b9c14417a68d492daec..0000000000000000000000000000000000000000
--- a/dstatInterface/interface/swv.py
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/usr/bin/env python
-
-import gtk
-
-class swv:
-    def __init__(self):
-        self.builder = gtk.Builder()
-        self.builder.add_from_file('interface/swv.glade')
-        self.builder.connect_signals(self)
-
-        self.clean_mV = self.builder.get_object('clean_mV')
-        self.clean_s = self.builder.get_object('clean_s')
-        self.dep_mV = self.builder.get_object('dep_mV')
-        self.dep_s = self.builder.get_object('dep_s')
-        self.start_entry = self.builder.get_object('start_entry')
-        self.stop_entry = self.builder.get_object('stop_entry')
-        self.step_entry = self.builder.get_object('step_entry')
-        self.pulse_entry = self.builder.get_object('pulse_entry')
-        self.freq_entry = self.builder.get_object('freq_entry')
-        self.cyclic_checkbutton = self.builder.get_object('cyclic_checkbutton')
-        self.scans_entry = self.builder.get_object('scans_entry')
\ No newline at end of file
diff --git a/dstatInterface/mpl.py b/dstatInterface/mpl.py
deleted file mode 100644
index 0d57177bfb29cede8b4e2f9160643b568737cf8c..0000000000000000000000000000000000000000
--- a/dstatInterface/mpl.py
+++ /dev/null
@@ -1,123 +0,0 @@
-#!/usr/bin/env python
-
-import sys, serial, io
-import numpy as np
-import matplotlib
-import gtk
-from time import sleep
-from collections import deque
-from matplotlib import pyplot as plt
-
-
-# class that holds analog data for N samples
-class AnalogData:
-    # constr
-    def __init__(self):
-        self.ax = []
-        self.ay = []
-        self.first = 1
-    
-    # add data
-    def add(self, data):
-        if self.first == 1:
-            self.first = 0
-            return
-        assert(len(data) == 2)
-        self.ax.append(data[0])
-        self.ay.append(data[1])
-
-    # clear data
-    def clear(self):
-        self.first = 1
-        self.ax = []
-        self.ay = []
-
-
-# plot class
-class AnalogPlot:
-    
-    # constr
-    def __init__(self, analogData):
-        self.i = 0
-        # set plot to animated
-        plt.ion() #interactive mode on
-        plt.autoscale(True,True,True)
-        
-        self.line = plt.plot(analogData.ax,analogData.ay)
-    
-    # update plot
-    def update(self, analogData):
-        if self.i < 5:
-            self.i += 1
-            return
-        plt.setp(self.line,xdata=analogData.ax, ydata=analogData.ay)
-        ax = plt.gca()
-
-        # recompute the ax.dataLim
-        ax.relim()
-        # update ax.viewLim using the new dataLim
-        ax.autoscale_view()
-        plt.draw()
-        self.i=0
-
-# main() function
-def main():
-#    # expects 1 arg - serial port string
-#    if(len(sys.argv) != 2):
-#        print 'Example usage: python showdata.py "/dev/tty.usbmodem411"'
-#        exit(1)
-
-    #strPort = '/dev/tty.usbserial-A7006Yqh'
-    #strPort = sys.argv[1];
-    strPort = '/dev/cu.usbmodem12...E1'
-
-    # open serial port
-    ser = serial.Serial(strPort, 1024000,timeout=2)
-    sio = io.TextIOWrapper(io.BufferedRWPair(ser,ser,buffer_size=1),
-                            newline = '\n',
-                            line_buffering = True)
-    ser.write("ck")
-
-    # plot parameters
-    digiData = AnalogData()
-    digiPlot = AnalogPlot(digiData)
-
-    try:
-        while True:
-            output = raw_input('Commands:')
-            ser.flushInput() #clear input buffer
-            digiData.clear() #clear old data
-            ser.write(output)
-            print output
-            
-            while True:
-                for line in ser:
-                    print line
-                    if line.lstrip().startswith("no"):
-                        ser.flushInput()
-                        break
-                    if not (line.isspace() or line.lstrip().startswith('#')):
-                        #print line
-                        data = [float(val) for val in line.split()]
-                        if(len(data) == 2):
-                            digiData.add(data)
-                            digiPlot.update(digiData)
-
-                break
-#                if not line.lstrip().startswith('#'):
-#                    data = [float(val) for val in line.split()]
-##                    if(len(data) == 2):
-##                        analogData.add(data)
-##                        analogPlot.update(analogData)
-#                    block.append(line)
-#                    print line
-#            print block
-    except KeyboardInterrupt:
-        print 'exiting'
-    # close serial
-    ser.flush()
-    ser.close()
-
-# call main
-if __name__ == '__main__':
-    main()
\ No newline at end of file
diff --git a/dstatInterface/mpltest.py b/dstatInterface/mpltest.py
deleted file mode 100644
index ea8bc7585a474746f87782ce287df979f53d0beb..0000000000000000000000000000000000000000
--- a/dstatInterface/mpltest.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-"""
-    show how to add a matplotlib FigureCanvasGTK or FigureCanvasGTKAgg widget to a
-    gtk.Window
-    """
-import gtk
-from matplotlib.figure import Figure
-from matplotlib import pyplot as plt
-import numpy as np
-
-#from matplotlib.backends.backend_gtkcairo import FigureCanvasGTKCairo as FigureCanvas
-#from matplotlib.backends.backend_gtkcairo import NavigationToolbar2Cairo as NavigationToolbar
-from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas
-from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar
-
-class plotbox:
-    def __init__(self, plotwindow_instance):
-        self.figure = Figure()
-        self.figure.subplots_adjust(left=0.07, bottom=0.07, right=0.96, top=0.96)
-        self.axe1 = self.figure.add_subplot(111)
-        
-        self.lines = self.axe1.plot([0,1], [0,1])
-        
-        self.axe1.ticklabel_format(style='sci', scilimits=(0,3), useOffset=False, axis='y')
-
-        self.canvas = FigureCanvas(self.figure)
-        self.win = gtk.Window()
-        self.vbox = gtk.VBox()
-        self.win.add(self.vbox)
-        self.vbox.pack_start(self.canvas)
-        self.toolbar = NavigationToolbar(self.canvas, self.win)
-        self.vbox.pack_start(self.toolbar, False, False)
-        self.vbox.reparent(plotwindow_instance)
-    
-    def clearall(self):
-        for i in self.lines:
-            i.remove()
-        self.lines = self.axe1.plot([0,1], [0,1])
-    
-    def clearline(self, line_number):
-        self.lines[line_number].remove()
-        self.lines.pop(line_number)
-    
-    def addline(self):
-        self.lines.append(self.axe1.plot([0,1], [0,1])[0])
-    
-    def updateline(self, Experiment, line_number):
-        divisor = len(Experiment.data[1+line_number*2]) // 2000 + 1 #limits display to 2000 data points per line
-        
-        self.lines[line_number].set_ydata(Experiment.data[1+line_number*2][1::divisor])
-        self.lines[line_number].set_xdata(Experiment.data[line_number*2][1::divisor])
-
-    def changetype(self, Experiment):
-        self.axe1.set_xlabel(Experiment.xlabel)
-        self.axe1.set_ylabel(Experiment.ylabel)
-        self.axe1.set_xlim(Experiment.xmin, Experiment.xmax)
-
-        self.figure.canvas.draw()
-
-    def redraw(self):
-        self.axe1.relim()
-        self.axe1.autoscale(True, axis = 'y')
-        self.figure.canvas.draw()
-
-        return True
-