Пример #1
0
class Librarian(traits.HasTraits):
    """Librarian provides a way of writing useful information into the 
    log folder for eagle logs. It is designed to make the information inside
    an eagle log easier to come back to. It mainly writes default strings into
    the comments file in the log folder"""
    
    logType = traits.Enum("important","debug","calibration")
    typeCommitButton = traits.Button("save")
    axisList = AxisSelector()
    purposeBlock = EntryBlock(fieldName="What is the purpose of this log?")
    explanationBlock = EntryBlock(fieldName = "Explain what the data shows (important parameters that change, does it make sense etc.)?")
    additionalComments = EntryBlock(fieldName = "Anything Else?")

    traits_view = traitsui.View(
        traitsui.VGroup(
            traitsui.Item("logFolder",show_label=False, style="readonly"),
            traitsui.HGroup(traitsui.Item("logType",show_label=False),traitsui.Item("typeCommitButton",show_label=False)),
            traitsui.Item("axisList",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("purposeBlock",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("explanationBlock",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("additionalComments",show_label=False, editor=traitsui.InstanceEditor(),style='custom')
        )  , resizable=True  , kind ="live"
    )    
    
    def __init__(self, **traitsDict):
        """Librarian object requires the log folder it is referring to. If a .csv
        file is given as logFolder argument it will use parent folder as the 
        logFolder"""
        super(Librarian, self).__init__(**traitsDict)
        if os.path.isfile(self.logFolder):
            self.logFolder = os.path.split(self.logFolder)[0]
        else:
            logger.debug("found these in %s: %s" %(self.logFolder, os.listdir(self.logFolder) ))
        
        self.logFile = os.path.join(self.logFolder, os.path.split(self.logFolder)[1]+".csv")
        self.commentFile = os.path.join(self.logFolder, "comments.txt")
        self.axisList.commentFile = self.commentFile
        self.axisList.logFile = self.logFile
        self.purposeBlock.commentFile = self.commentFile
        self.explanationBlock.commentFile = self.commentFile
        self.additionalComments.commentFile  = self.commentFile
        
    def _typeCommitButton_fired(self):
        logger.info("saving axes info starting")
        timeStamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        blockDelimiterStart = "__Log Type__<start>"
        blockDelimiterEnd = "__Log Type__<end>"
        fullString = "\n"+blockDelimiterStart+"\n"+timeStamp+"\n"+self.logType+"\n"+blockDelimiterEnd+"\n"
        with open(self.commentFile, "a+") as writeFile:
            writeFile.write(fullString)
        logger.info("saving axes info finished")
Пример #2
0
def make_plugin_view(model_name, model_nodes, selection_view, model_view):
    node_label = '=' + model_name
    container_nodes = [
        _traitsui.TreeNode(
            node_for=[CalcContainer],
            label=node_label,
            children='',
            auto_open=True,
            menu=[],
        ),
        _traitsui.TreeNode(
            node_for=[CalcContainer],
            label=node_label,
            children='calculations',
            auto_open=True,
            menu=[],
        ),
    ]

    plugin_tree = _traitsui.TreeEditor(
        nodes=container_nodes + model_nodes,
        # refresh='controller.update_tree',
        selected='controller.selected_object',
        editable=False,
        hide_root=True,
    )

    plugin_view = _traitsui.View(
        _traitsui.Group(
            # Left side tree
            _traitsui.Item('controller.model',
                           editor=plugin_tree,
                           show_label=False),
            # Right side
            _traitsui.Group(
                # Upper right side data set selection panel
                selection_view,
                # Lower right side calc settings panel
                _traitsui.Group(
                    _traitsui.Item(
                        'controller.edit_node',
                        editor=_traitsui.InstanceEditor(view=model_view),
                        style='custom',
                        show_label=False),
                    show_border=True,
                ),
                orientation='vertical',
            ),
            _traitsui.Spring(width=10),
            orientation='horizontal',
        ),
        resizable=True,
        buttons=['OK'],
    )

    return plugin_view
Пример #3
0
def navigation_sliders(data_axes, title=None):
    """Raises a windows with sliders to control the index of DataAxis
    
    Parameters
    ----------
    data_axes : list of DataAxis instances
    
    """

    class NavigationSliders(t.HasTraits):
        pass

    nav = NavigationSliders()
    view_tuple = ()
    for axis in data_axes:
        name = str(axis).replace(" ", "_")
        nav.add_class_trait(name, axis)
        nav.trait_set([name, axis])
        view_tuple += (
                        tui.Item(name,
                             style = "custom",
                             editor = tui.InstanceEditor(
                                 view=tui.View(
                                     tui.Item(
                                         "index",
                                         show_label=False,
                                         # The following is commented out
                                         # due to a traits ui bug
                                         #editor=tui.RangeEditor(mode="slider"),
                                          ),
                                     ),
                                 ),
                             ),
                         )
                               
                                  



    view = tui.View(tui.VSplit(view_tuple), title="Navigation sliders"
                                            if title is None
                                            else title)

    nav.edit_traits(view=view)
Пример #4
0
class ADC(traits.HasTraits):

    refreshTime = traits.Float(
        0.1, desc="how often to update the frequencies in seconds")
    logFile = traits.File
    rpiADCLogFolder = traits.String
    averageN = traits.Int(100)
    VMax = traits.Enum(3.3, 5.0)
    channelList = traits.List(
        [1, 3, 5, 6],
        desc="list of channels to show frequencies for and query")
    channelValues = [(0, 'Ch 0'), (1, 'Ch 1'), (2, 'Ch 2'), (3, 'Ch 3'),
                     (4, 'Ch 4'), (5, 'Ch 5'), (6, 'Ch 6'), (7, 'Ch 7')]
    #THIS ONLY WORKS IF PyHWI can be found! it is in the python path manager for lab-Monitoring-0
    connection = rpiADCClient.Connection()
    #if there are problems check the server is running on 192.168.0.111
    icon_trait = pyface.image_resource.ImageResource('icons/wavemeter.png')
    #oscilloscope = None

    currentLocalTime = time.localtime()
    currentYear = currentLocalTime.tm_year
    currentMonth = currentLocalTime.tm_mon
    currentDay = currentLocalTime.tm_mday

    channel0 = ADCChannel(channelNumber=0,
                          connection=connection,
                          channelName="Na Cavity Lock",
                          channelMessageHigh="Na Cavity Locked",
                          channelMessageLow="Na Cavity Out of Lock",
                          criticalValue=1.5,
                          highIsGood=True,
                          highSoundFile="NaLocked.wav",
                          lowSoundFile="NaOutOfLock.wav")

    channel1 = ADCChannel(channelNumber=1,
                          connection=connection,
                          channelName="Li MOT Fluorescence",
                          channelMessageHigh="MOT Loading",
                          channelMessageLow="No MOT",
                          criticalValue=0.1)
    channel2 = ADCChannel(
        channelNumber=2,
        connection=connection,
        channelName="Li MOT Power (stable)")  #changed by Martin
    channel3 = ADCChannel(channelNumber=3,
                          connection=connection,
                          channelName="Li MOT (unstable)")
    channel4 = ADCChannel(channelNumber=4,
                          connection=connection,
                          channelName="Na MOT Power (stable)")
    channel5 = ADCChannel(channelNumber=5,
                          connection=connection,
                          channelName="Na MOT Flourescence")
    channel6 = ADCChannel(channelNumber=6,
                          connection=connection,
                          channelName="ZS light Power")
    channel7 = ADCChannel(channelNumber=7,
                          connection=connection,
                          channelName="disconnected")

    channels = {
        0: channel0,
        1: channel1,
        2: channel2,
        3: channel3,
        4: channel4,
        5: channel5,
        6: channel6,
        7: channel7
    }

    def __init__(self, **traitsDict):
        """Called when object initialises. Starts timer etc. """
        print "Instantiating GUI.."
        super(ADC, self).__init__(**traitsDict)
        self.connection.connect()
        self.oscilloscope = Oscilloscope(connection=self.connection,
                                         resolution=self.refreshTime,
                                         visibleChannels=self.channelList)
        self.start_timer()

    def start_timer(self):
        """Called in init if user selected live update mode, otherwise called from menu action.
        Every self.wizard.updateRateSeconds, self._refresh_data_action will be called"""
        print "Timer Object Started. Will update ADC Information every %s seconds" % self.refreshTime
        self.timer = Timer(
            float(self.refreshTime) * 1000, self._refresh_Visible_channels)

    def _refreshTime_changed(self):
        self.timer.setInterval(float(self.refreshTime) * 1000)
        print "will update ADC every %s seconds" % (float(self.refreshTime))
        self.oscilloscope.resolution = self.refreshTime  #use refresh time to set resolution of oscilloscope

    def _logFile_changed(self):
        self._create_log_file()

    def _channelList_changed(self):
        """push changes to visible channels in oscilloscope """
        self.oscilloscope.visibleChannels = self.channelList

    def _logFile_default(self):
        """default log file has date stamp. log file is changed once a day """
        print "choosing default log file"
        return os.path.join(
            self.rpiADCLogFolder,
            time.strftime("rpiADC-%Y-%m-%d.csv", self.currentLocalTime))

    def getGroupFolder(self):
        """returns the location of the group folder. supports both
         linux and windows. assumes it is mounted to /media/ursa/AQOGroupFolder
         for linux"""
        if platform.system() == "Windows":
            groupFolder = os.path.join("\\\\ursa", "AQOGroupFolder")
        if platform.system() == "Linux":
            groupFolder = os.path.join("/media", "ursa", "AQOGroupFolder")
        return groupFolder

    def _rpiADCLogFolder_default(self):
        return os.path.join(self.getGroupFolder(), "Experiment Humphry",
                            "Experiment Control And Software", "rpiADC",
                            "data")

    def _create_log_file(self):
        if not os.path.exists(os.path.join(self.rpiADCLogFolder,
                                           self.logFile)):
            with open(self.logFile, 'a+') as csvFile:
                csvWriter = csv.writer(csvFile)
                csvWriter.writerow([
                    "epochSeconds", "Channel 0", "Channel 1", "Channel 2",
                    "Channel 3", "Channel 4", "Channel 5", "Channel 6",
                    "Channel 7"
                ])

    def checkDateForFileName(self):
        """gets current date and time and checks if we should change file name
        if we should it creates the new file and the name"""
        #self.currentLocalTime was already changed in log Temperatures
        if self.currentLocalTime.tm_mday != self.currentDay:
            #the day has changed we should start a new log file!
            self.logFile = self._logFile_default()
            self._create_log_file()

    def _log_channels(self):
        self.currentLocalTime = time.localtime()
        self.checkDateForFileName()
        self.currentMonth = self.currentLocalTime.tm_mon
        self.currentDay = self.currentLocalTime.tm_mday

        if not os.path.exists(os.path.join(self.rpiADCLogFolder,
                                           self.logFile)):
            self._create_log_file()

        voltages = [self.channels[i]._voltage_get() for i in range(0, 8)]
        with open(self.logFile, 'a+') as csvFile:
            csvWriter = csv.writer(csvFile)
            csvWriter.writerow([time.time()] + voltages)

    def _refresh_Visible_channels(self):
        self.connection.getResults()  #updates dictionary in connection object
        for channelNumber in self.channelList:
            channel = self.channels[channelNumber]
            channel._voltage_update()
        self.oscilloscope.updateArrays()
        self.oscilloscope.updateArrayPlotData()
        self._log_channels()

    settingsGroup = traitsui.VGroup(
        traitsui.Item("logFile", label="Log File"),
        traitsui.HGroup(
            traitsui.Item('refreshTime', label='refreshTime'),
            traitsui.Item(
                'averageN',
                label='averaging Number',
                tooltip=
                "Number of measurements taken and averaged for value shown"),
            traitsui.Item('VMax',
                          label='Maximum Voltage Setting',
                          tooltip="Whether the box is set to 3.3V or 5V max")),
    )

    selectionGroup = traitsui.Group(
        traitsui.Item('channelList',
                      editor=traitsui.CheckListEditor(values=channelValues,
                                                      cols=4),
                      style='custom',
                      label='Show'))

    groupLeft = traitsui.VGroup(
        traitsui.Item('channel0',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(0 in channelList)"),
        traitsui.Item('channel1',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(1 in channelList)"),
        traitsui.Item('channel2',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(2 in channelList)"),
        traitsui.Item('channel3',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(3 in channelList)"))

    groupRight = traitsui.VGroup(
        traitsui.Item('channel4',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(4 in channelList)"),
        traitsui.Item('channel5',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(5 in channelList)"),
        traitsui.Item('channel6',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(6 in channelList)"),
        traitsui.Item('channel7',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      visible_when="(7 in channelList)"))

    groupOscilloscope = traitsui.Group(
        traitsui.Item('oscilloscope',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False))

    groupAll = traitsui.VGroup(
        settingsGroup, selectionGroup,
        traitsui.VSplit(traitsui.HGroup(groupLeft, groupRight),
                        groupOscilloscope))

    traits_view = traitsui.View(groupAll,
                                resizable=True,
                                title="ADC Monitor",
                                handler=ADCHandler(),
                                icon=icon_trait)
Пример #5
0
class Librarian(traits.HasTraits):
    """Librarian provides a way of writing useful information into the 
    log folder for eagle logs. It is designed to make the information inside
    an eagle log easier to come back to. It mainly writes default strings into
    the comments file in the log folder"""

    logType = traits.Enum("important", "debug", "calibration")
    writeToOneNoteButton = traits.Button("save")
    refreshInformation = traits.Button("refresh")
    saveImage = traits.Button("save plot")
    axisList = AxisSelector()
    purposeBlock = EntryBlock(fieldName="What is the purpose of this log?")
    resultsBlock = EntryBlock(
        fieldName=
        "Explain what the data shows (important parameters that change, does it make sense etc.)?"
    )
    commentsBlock = EntryBlock(fieldName="Anything Else?")
    saveButton = traits.Button("Save")
    #    notebooks = traits.Enum(values = "notebookNames") # we could let user select from a range of notebooks
    #    notebookNames = traits.List
    notebookName = traits.String("Humphry's Notebook")
    sectionName = traits.String("Eagle Logs")
    logName = traits.String("")
    xAxis = traits.String("")
    yAxis = traits.String("")

    traits_view = traitsui.View(traitsui.VGroup(
        traitsui.Item("logName", show_label=False, style="readonly"),
        traitsui.Item("axisList",
                      show_label=False,
                      editor=traitsui.InstanceEditor(),
                      style='custom'),
        traitsui.Item("purposeBlock",
                      show_label=False,
                      editor=traitsui.InstanceEditor(),
                      style='custom'),
        traitsui.Item("resultsBlock",
                      show_label=False,
                      editor=traitsui.InstanceEditor(),
                      style='custom'),
        traitsui.Item("commentsBlock",
                      show_label=False,
                      editor=traitsui.InstanceEditor(),
                      style='custom'),
        traitsui.HGroup(
            traitsui.Item("writeToOneNoteButton", show_label=False),
            traitsui.Item("refreshInformation", show_label=False)),
    ),
                                resizable=True,
                                kind="live",
                                title="Eagle OneNote")

    def __init__(self, **traitsDict):
        """Librarian object requires the log folder it is referring to. If a .csv
        file is given as logFolder argument it will use parent folder as the 
        logFolder"""
        super(Librarian, self).__init__(**traitsDict)
        if os.path.isfile(self.logFolder):
            self.logFolder = os.path.split(self.logFolder)[0]
        else:
            logger.debug("found these in %s: %s" %
                         (self.logFolder, os.listdir(self.logFolder)))

        self.logName = os.path.split(self.logFolder)[1]
        self.logFile = os.path.join(self.logFolder,
                                    os.path.split(self.logFolder)[1] + ".csv")
        self.axisList.logFile = self.logFile  #needs a copy so it can calculate valid values
        self.axisList.masterList = self.axisList._masterList_default()
        self.axisList.masterListWithNone = self.axisList._masterListWithNone_default(
        )
        if self.xAxis != "":
            self.axisList.xAxis = self.xAxis
        if self.yAxis != "":
            self.axisList.yAxis = self.yAxis

        self.eagleOneNote = oneNotePython.eagleLogsOneNote.EagleLogOneNote(
            notebookName=self.notebookName, sectionName=self.sectionName)
        logPage = self.eagleOneNote.setPage(self.logName)
        #
        #        except Exception as e:
        #            logger.error("failed to created an EagleOneNote Instance. This could happen for many reasons. E.g. OneNote not installed or most likely, the registry is not correct. See known bug and fix in source code of onenotepython module:%s" % e.message)
        if logPage is not None:  #page exists
            self.purposeBlock.textBlock = self.eagleOneNote.getOutlineText(
                "purpose")
            self.resultsBlock.textBlock = self.eagleOneNote.getOutlineText(
                "results")
            self.commentsBlock.textBlock = self.eagleOneNote.getOutlineText(
                "comments")
            xAxis, yAxis, series = self.eagleOneNote.getParametersOutlineValues(
            )
            try:
                self.axisList.xAxis, self.axisList.yAxis, self.axisList.series = xAxis, yAxis, series
            except Exception as e:
                logger.error(
                    "error when trying to read analysis parameters: %s" %
                    e.message)
            self.pageExists = True
        else:
            self.pageExists = False
            self.purposeBlock.textBlock = ""
            self.resultsBlock.textBlock = ""
            self.commentsBlock.textBlock = ""
            #could also reset axis list but it isn't really necessary

    def _writeToOneNoteButton_fired(self):
        """writes content of librarian to one note page """
        if not self.pageExists:
            self.eagleOneNote.createNewEagleLogPage(self.logName,
                                                    refresh=True,
                                                    setCurrent=True)
            self.pageExists = True
        self.eagleOneNote.setOutline("purpose",
                                     self.purposeBlock.textBlock,
                                     rewrite=False)
        self.eagleOneNote.setOutline("results",
                                     self.resultsBlock.textBlock,
                                     rewrite=False)
        self.eagleOneNote.setOutline("comments",
                                     self.commentsBlock.textBlock,
                                     rewrite=False)
        self.eagleOneNote.setDataOutline(self.logName, rewrite=False)
        self.eagleOneNote.setParametersOutline(self.axisList.xAxis,
                                               self.axisList.yAxis,
                                               self.axisList.series,
                                               rewrite=False)
        self.eagleOneNote.currentPage.rewritePage()
        #now to get resizing done well we want to completely repull the XML and data
        #brute force method:
        self.eagleOneNote = oneNotePython.eagleLogsOneNote.EagleLogOneNote(
            notebookName=self.notebookName, sectionName=self.sectionName)
        logPage = self.eagleOneNote.setPage(
            self.logName)  #this sets current page of eagleOneNote
        self.eagleOneNote.organiseOutlineSizes()
Пример #6
0
                       "  2. Remove the column with the missing values and re-import the data\n"
                       "  3. Remove the row with the missing values and re-import the data")
        dlg.edit_traits(parent=self.win_handle, kind='modal')


    def _show_alignment_warning(self, ds_c, ds_s):
        dlg = ErrorMessage()
        dlg.err_msg = 'Consumer liking and sensory profiling data does not align'
        dlg.err_val = 'The Consumer liking data and descriptive analysis/sensory profiling data do not align. There are {0} rows in {1} and {2} rows in the {3}. Please select other data.'.format(ds_c.n_objs, ds_c.display_name, ds_s.n_objs, ds_s.display_name)
        dlg.edit_traits(parent=self.win_handle, kind='modal')



selection_view = _traitsui.Group(
    _traitsui.Item('controller.comb',
                   editor=_traitsui.InstanceEditor(),
                   style='custom',
                   show_label=False,
                   width=250,
                   height=150,
                   ),
    label='Select data set',
    show_border=True,
    )


prefmap_plugin_view =  make_plugin_view(
    'Prefmap', prefmap_nodes, selection_view, prefmap_view)


if __name__ == '__main__':
Пример #7
0
class PhysicsProperties(traits.HasTraits):
    
    selectedElement = traits.Instance(element.Element)#default of Li6 set in init
    species = traits.Enum(*element.names)

    massATU = traits.Float(22.9897692807,label="mass (u)", desc="mass in atomic mass units")
    decayRateMHz = traits.Float(9.7946,label = u"Decay Rate \u0393 (MHz)", desc= "decay rate/ natural line width of 2S1/2 -> 2P3/2")
    crossSectionSigmaPlus = traits.Float(1.6573163925E-13, label=u"cross section \u03C3 + (m^2)",
                                         desc = "resonant cross section 2S1/2 -> 2P3/2. Warning not accurate for 6Li yet")
    scatteringLength = traits.Float(62.0, label="scattering length (a0)")
    IsatSigmaPlus = traits.Float(6.260021, width=10, label=u"Isat (mW/cm^2)",desc = "I sat sigma + 2S1/2 -> 2P3/2")
    
    TOFFromVariableBool = traits.Bool(True, label = "Use TOF variable?", desc = "Attempt to read TOF variable from latestSequence.xml. If found update the TOF variable automatically")
    TOFVariableName = traits.String("ImagingTimeTOFLi",label="variable name:", desc = "The name of the TOF variable in Experiment Control")
    timeOfFlightTimems = traits.Float(4.0, label = "TOF Time (ms)", desc = "Time of Flight time in ms. Should match experiment control")

    
    trapGradientXFromVariableBool = traits.Bool(True, label = "Use MTGradientX variable?", desc = "Attempt to read MTGradientX variable from latestSequence.xml. If found update the TOF variable automatically")
    trapGradientXVariableName = traits.String("MagneticTrapEvaporation2GradientX",label="variable name:", desc = "The name of the trapGradientX variable in Experiment Control")
    trapGradientX = traits.Float(20.0, label="Trap Gradient (small) (G/cm)", desc = "gradient of trap before time of flight. Smaller of the anti helmholtz gradients" )
    trapFrequencyXHz = traits.Float(100.0, label="Trap frequency X (Hz)", desc = "trap frequency in X direction in Hz")
    trapFrequencyYHz = traits.Float(100.0, label="Trap frequency Y (Hz)", desc = "trap frequency in Y direction in Hz") 
    trapFrequencyZHz = traits.Float(100.0, label="Trap frequency Z (Hz)", desc = "trap frequency in Z direction in Hz")
    imagingDetuningLinewidths = traits.Float(0.0, label= u"imaging detuning (\u0393)", desc = "imaging light detuning from resonance in units of linewidths")    
    
    inTrapSizeX = traits.Float(0.0, label="In trap Size X (pixels)", desc = "size of cloud in trap in x direciton in pixels. Use very short TOF to estimate" )    
    inTrapSizeY = traits.Float(0.0, label="In trap Size Y (pixels)", desc = "size of cloud in trap in y direciton in pixels. Use very short TOF to estimate" )    
    autoInTrapSizeBool = traits.Bool(False, label="Change TOFTime InTrap Calibration?", desc= "Allows user to change the TOF time for which the fit will automatically update the in trap size if the autoSetSize box is checked for Gaussian fit")
    inTrapSizeTOFTimems = traits.Float(0.2, label="In Trap Size TOFTime", desc= "If the TOF time is this value and the autoSetSize box is checked, then we will automatically update the size whenever the TOFTime equals this value" )
    
    pixelSize = traits.Float(9.0, label=u"Pixel Size (\u03BCm)", desc = "Actual pixel size of the camera (excluding magnification)")    
    magnification = traits.Float(0.5, label="Magnification", desc = "Magnification of the imaging system")
    binningSize = traits.Int(1, label=u"Binning Size (px)", desc = "Binning size; influences effective pixel size")
    
    latestSequenceFile = os.path.join("\\\\ursa","AQOGroupFolder","Experiment Humphry","Experiment Control And Software","currentSequence", "latestSequence.xml")    
    secondLatestSequenceFile = os.path.join("\\\\ursa","AQOGroupFolder","Experiment Humphry","Experiment Control And Software","currentSequence", "secondLatestSequence.xml")    
    
    traits_view = traitsui.View(
                    traitsui.HGroup(

                        traitsui.VGroup(
                            traitsui.Item("species"),
                            traitsui.Item("selectedElement",editor = traitsui.InstanceEditor(), style="custom", show_label=False),                
                            show_border=True, label = "Element Properties"
                        ),
                        traitsui.VGroup(
                            traitsui.HGroup(traitsui.Item("TOFFromVariableBool"),traitsui.Item("TOFVariableName", visible_when="TOFFromVariableBool"),traitsui.Item("timeOfFlightTimems",style="readonly",visible_when="(TOFFromVariableBool)"),traitsui.Item("timeOfFlightTimems",visible_when="(not TOFFromVariableBool)")),
                            traitsui.HGroup(traitsui.Item("trapGradientXFromVariableBool"),traitsui.Item("trapGradientXVariableName", visible_when="trapGradientXFromVariableBool"),traitsui.Item("trapGradientX",style="readonly",visible_when="(trapGradientXFromVariableBool)"),traitsui.Item("trapGradientX",visible_when="(not trapGradientXFromVariableBool)")),
                            traitsui.Item("trapFrequencyXHz"),
                            traitsui.Item("trapFrequencyYHz"),
                            traitsui.Item("trapFrequencyZHz"),
                            traitsui.Item("inTrapSizeX"),
                            traitsui.Item("inTrapSizeY"),
                            traitsui.HGroup(traitsui.Item("autoInTrapSizeBool"),traitsui.Item("inTrapSizeTOFTimems", visible_when="(autoInTrapSizeBool)")),
                             label="Experiment Parameters", show_border=True
                        ),
                        traitsui.VGroup(
                            traitsui.Item("imagingDetuningLinewidths"), 
                            traitsui.Item("pixelSize"),
                            traitsui.Item("binningSize"),
                            traitsui.Item("magnification"), label="Camera and Imaging", show_border=True
                        )
                    )                    
                    )
    
    
    def __init__(self, **traitsDict):
        super(PhysicsProperties, self).__init__(**traitsDict)
        # self.selectedElement = element.Li6#set default element
        self.species = element.Li6.nameID
        #pull some uselful variables from the physics constants dictionary for reference
        
        self.constants = scipy.constants.physical_constants
        self.u = self.constants["atomic mass constant"][0]
        self.bohrMagneton = self.constants["Bohr magneton"][0]
        self.bohrRadius = self.constants["Bohr radius"][0]
        self.kb = self.constants["Boltzmann constant"][0]
        self.joulesToKelvin = self.constants["joule-kelvin relationship"][0]
        self.hbar = self.constants["Planck constant over 2 pi"][0]
        self.h = self.constants["Planck constant"][0]
        self.joulesToHertz = self.constants["joule-hertz relationship"][0]
        self.hertzToKelvin =self.constants["hertz-kelvin relationship"][0]
        self.a0 = self.constants["Bohr radius"][0]
        
    def _species_changed(self):
        """update constants according to the changed species """
        logger.debug("species changed to %s" % self.species)
        self.selectedElement = element.elements[self.species]
    
    def updatePhysics(self):
        try:
            logger.debug("attempting to update physics from xml")
            if os.path.exists(self.latestSequenceFile):
                modifiedTime = os.path.getmtime(self.latestSequenceFile)
                imageTime = self.selectedFileModifiedTime
                now = time.time()
                timeDiff = imageTime-modifiedTime
                timeDiff += 31 # ToDo: debug this strange time offset!!
                if timeDiff>300.0: #>5min
                    logger.warning("Found a time difference of >5min between modification time of XML and of image. Are you sure the latest XML file is being updated? Check snake is running?")
                if timeDiff<0:
                    logger.error("Found very fresh sequence file. Probably read already variables of next sequence?")
                    logger.warning("Use second last sequence file instead..")
                    self.tree = ET.parse(self.secondLatestSequenceFile)
                else:
                    self.tree = ET.parse(self.latestSequenceFile)
                logger.warning("Age of sequence file: {}".format(timeDiff)) # for debugging, remove or reduce log level later ;P
                # logger.warning("Age of image file: {}".format(imageTime))
                # logger.warning("Now = {}".format(now)) # for debugging, remove or reduce log level later ;P
                # logger.warning("ModifiedTime of xml = {}".format(modifiedTime)) # for debugging, remove or reduce log level later ;P
                self.root = self.tree.getroot()
                variables = self.root.find("variables")
                self.variables = {child[0].text:float(child[1].text) for child in variables}
                logger.debug("Read a TOF time of %s from variables in XML " % self.variables[self.TOFVariableName])
            else:
                logger.error("Could not find latest xml File. cannot update physics.")
                return
        except Exception as e:
            logger.error("Error when trying to load XML %s" % e.message)
            return
            
        #update TOF Time
        if self.TOFFromVariableBool:
            logger.debug("attempting to update TOF time from xml")
            try:
                self.timeOfFlightTimems = self.variables[self.TOFVariableName]*1.0E3
            except KeyError as e:
                logger.error("incorrect variable name. No variable %s found. Using default 1ms" % self.TOFVariableName )
                self.timeOfFlightTimems = 1.0
            
        if self.trapGradientXFromVariableBool:
            logger.debug("attempting to update trapGradientX from xml")
            try:
                self.trapGradientX = self.variables[self.trapGradientXVariableName]
            except KeyError:
                logger.error("incorrect variable name. No variable %s found. Using default 50G/cm" % self.trapGradientXVariableName )
                self.trapGradientX = 50.0
Пример #8
0
class ImagePlotInspector(traits.HasTraits):
    #Traits view definitions:

    settingsGroup = traitsui.VGroup(
        traitsui.VGroup(
            traitsui.Item("watchFolderBool", label="Watch Folder?"),
            traitsui.HGroup(traitsui.Item("selectedFile",
                                          label="Select a File"),
                            visible_when="not watchFolderBool"),
            traitsui.HGroup(traitsui.Item("watchFolder",
                                          label="Select a Directory"),
                            visible_when="watchFolderBool"),
            traitsui.HGroup(traitsui.Item("searchString",
                                          label="Filename sub-string"),
                            visible_when="watchFolderBool"),
            label="File Settings",
            show_border=True),
        traitsui.VGroup(traitsui.HGroup('autoRangeColor', 'colorMapRangeLow',
                                        'colorMapRangeHigh'),
                        traitsui.HGroup('horizontalAutoRange',
                                        'horizontalLowerLimit',
                                        'horizontalUpperLimit'),
                        traitsui.HGroup('verticalAutoRange',
                                        'verticalLowerLimit',
                                        'verticalUpperLimit'),
                        label="axis limits",
                        show_border=True),
        traitsui.VGroup(traitsui.HGroup('object.model.scale',
                                        'object.model.offset'),
                        traitsui.HGroup(
                            traitsui.Item('object.model.pixelsX',
                                          label="Pixels X"),
                            traitsui.Item('object.model.pixelsY',
                                          label="Pixels Y")),
                        traitsui.HGroup(
                            traitsui.Item('object.model.ODCorrectionBool',
                                          label="Correct OD?"),
                            traitsui.Item('object.model.ODSaturationValue',
                                          label="OD saturation value")),
                        traitsui.HGroup(
                            traitsui.Item('contourLevels',
                                          label="Contour Levels"),
                            traitsui.Item('colormap', label="Colour Map")),
                        traitsui.HGroup(
                            traitsui.Item('fixAspectRatioBool',
                                          label="Fix Plot Aspect Ratio?")),
                        traitsui.HGroup(
                            traitsui.Item('updatePhysicsBool',
                                          label="Update Physics with XML?")),
                        traitsui.HGroup(
                            traitsui.Item("cameraModel",
                                          label="Update Camera Settings to:")),
                        label="advanced",
                        show_border=True),
        label="settings")

    plotGroup = traitsui.Group(
        traitsui.Item('container',
                      editor=ComponentEditor(size=(800, 600)),
                      show_label=False))
    fitsGroup = traitsui.Group(traitsui.Item('fitList',
                                             style="custom",
                                             editor=traitsui.ListEditor(
                                                 use_notebook=True,
                                                 selected="selectedFit",
                                                 deletable=False,
                                                 export='DockWindowShell',
                                                 page_name=".name"),
                                             label="Fits",
                                             show_label=False),
                               springy=True)

    mainPlotGroup = traitsui.HSplit(plotGroup, fitsGroup, label="Image")

    fftGroup = traitsui.Group(label="Fourier Transform")

    physicsGroup = traitsui.Group(traitsui.Item(
        "physics",
        editor=traitsui.InstanceEditor(),
        style="custom",
        show_label=False),
                                  label="Physics")

    logFilePlotGroup = traitsui.Group(traitsui.Item(
        "logFilePlotObject",
        editor=traitsui.InstanceEditor(),
        style="custom",
        show_label=False),
                                      label="Log File Plotter")

    eagleMenubar = traitsmenu.MenuBar(
        traitsmenu.Menu(
            traitsui.Action(name='Save Image Copy As...',
                            action='_save_image_as'),
            traitsui.Action(name='Save Image Copy',
                            action='_save_image_default'),
            name="File",
        ))

    traits_view = traitsui.View(settingsGroup,
                                mainPlotGroup,
                                physicsGroup,
                                logFilePlotGroup,
                                buttons=traitsmenu.NoButtons,
                                menubar=eagleMenubar,
                                handler=EagleHandler,
                                title="Experiment Eagle",
                                statusbar="selectedFile",
                                icon=pyface.image_resource.ImageResource(
                                    os.path.join('icons', 'eagles.ico')),
                                resizable=True)

    model = CameraImage()
    physics = physicsProperties.physicsProperties.PhysicsProperties(
    )  #create a physics properties object
    logFilePlotObject = logFilePlot.LogFilePlot()
    fitList = model.fitList
    selectedFit = traits.Instance(fits.Fit)
    drawFitRequest = traits.Event
    drawFitBool = traits.Bool(False)  # true when drawing a fit as well
    selectedFile = traits.File()
    watchFolderBool = traits.Bool(False)
    watchFolder = traits.Directory()
    searchString = traits.String(
        desc=
        "sub string that must be contained in file name for it to be shown in Eagle. Can be used to allow different instances of Eagle to detect different saved images."
    )
    oldFiles = set()
    contourLevels = traits.Int(15)
    colormap = traits.Enum(colormaps.color_map_name_dict.keys())

    autoRangeColor = traits.Bool(True)
    colorMapRangeLow = traits.Float
    colorMapRangeHigh = traits.Float

    horizontalAutoRange = traits.Bool(True)
    horizontalLowerLimit = traits.Float
    horizontalUpperLimit = traits.Float

    verticalAutoRange = traits.Bool(True)
    verticalLowerLimit = traits.Float
    verticalUpperLimit = traits.Float

    fixAspectRatioBool = traits.Bool(False)
    updatePhysicsBool = traits.Bool(True)

    cameraModel = traits.Enum("Custom", "ALTA0", "ANDOR0", "ALTA1", "ANDOR1")

    #---------------------------------------------------------------------------
    # Private Traits
    #---------------------------------------------------------------------------
    _image_index = traits.Instance(chaco.GridDataSource)
    _image_value = traits.Instance(chaco.ImageData)
    _cmap = traits.Trait(colormaps.jet, traits.Callable)

    #---------------------------------------------------------------------------
    # Public View interface
    #---------------------------------------------------------------------------

    def __init__(self, *args, **kwargs):
        super(ImagePlotInspector, self).__init__(*args, **kwargs)
        #self.update(self.model)
        self.create_plot()
        for fit in self.fitList:
            fit.imageInspectorReference = self
            fit.physics = self.physics
        self.selectedFit = self.fitList[0]
        self.logFilePlotObject.physicsReference = self.physics
        #self._selectedFile_changed()
        logger.info("initialisation of experiment Eagle complete")

    def create_plot(self):

        # Create the mapper, etc
        self._image_index = chaco.GridDataSource(scipy.array([]),
                                                 scipy.array([]),
                                                 sort_order=("ascending",
                                                             "ascending"))
        image_index_range = chaco.DataRange2D(self._image_index)
        self._image_index.on_trait_change(self._metadata_changed,
                                          "metadata_changed")

        self._image_value = chaco.ImageData(data=scipy.array([]),
                                            value_depth=1)

        image_value_range = chaco.DataRange1D(self._image_value)

        # Create the contour plots
        #self.polyplot = ContourPolyPlot(index=self._image_index,
        self.polyplot = chaco.CMapImagePlot(
            index=self._image_index,
            value=self._image_value,
            index_mapper=chaco.GridMapper(range=image_index_range),
            color_mapper=self._cmap(image_value_range))

        # Add a left axis to the plot
        left = chaco.PlotAxis(orientation='left',
                              title="y",
                              mapper=self.polyplot.index_mapper._ymapper,
                              component=self.polyplot)
        self.polyplot.overlays.append(left)

        # Add a bottom axis to the plot
        bottom = chaco.PlotAxis(orientation='bottom',
                                title="x",
                                mapper=self.polyplot.index_mapper._xmapper,
                                component=self.polyplot)
        self.polyplot.overlays.append(bottom)

        # Add some tools to the plot
        self.polyplot.tools.append(
            tools.PanTool(self.polyplot,
                          constrain_key="shift",
                          drag_button="middle"))

        self.polyplot.overlays.append(
            tools.ZoomTool(component=self.polyplot,
                           tool_mode="box",
                           always_on=False))

        self.lineInspectorX = clickableLineInspector.ClickableLineInspector(
            component=self.polyplot,
            axis='index_x',
            inspect_mode="indexed",
            write_metadata=True,
            is_listener=False,
            color="white")

        self.lineInspectorY = clickableLineInspector.ClickableLineInspector(
            component=self.polyplot,
            axis='index_y',
            inspect_mode="indexed",
            write_metadata=True,
            color="white",
            is_listener=False)

        self.polyplot.overlays.append(self.lineInspectorX)
        self.polyplot.overlays.append(self.lineInspectorY)

        self.boxSelection2D = boxSelection2D.BoxSelection2D(
            component=self.polyplot)
        self.polyplot.overlays.append(self.boxSelection2D)

        # Add these two plots to one container
        self.centralContainer = chaco.OverlayPlotContainer(padding=0,
                                                           use_backbuffer=True,
                                                           unified_draw=True)
        self.centralContainer.add(self.polyplot)

        # Create a colorbar
        cbar_index_mapper = chaco.LinearMapper(range=image_value_range)
        self.colorbar = chaco.ColorBar(
            index_mapper=cbar_index_mapper,
            plot=self.polyplot,
            padding_top=self.polyplot.padding_top,
            padding_bottom=self.polyplot.padding_bottom,
            padding_right=40,
            resizable='v',
            width=30)

        self.plotData = chaco.ArrayPlotData(
            line_indexHorizontal=scipy.array([]),
            line_valueHorizontal=scipy.array([]),
            scatter_indexHorizontal=scipy.array([]),
            scatter_valueHorizontal=scipy.array([]),
            scatter_colorHorizontal=scipy.array([]),
            fitLine_indexHorizontal=scipy.array([]),
            fitLine_valueHorizontal=scipy.array([]))

        self.crossPlotHorizontal = chaco.Plot(self.plotData, resizable="h")
        self.crossPlotHorizontal.height = 100
        self.crossPlotHorizontal.padding = 20
        self.crossPlotHorizontal.plot(
            ("line_indexHorizontal", "line_valueHorizontal"), line_style="dot")
        self.crossPlotHorizontal.plot(
            ("scatter_indexHorizontal", "scatter_valueHorizontal",
             "scatter_colorHorizontal"),
            type="cmap_scatter",
            name="dot",
            color_mapper=self._cmap(image_value_range),
            marker="circle",
            marker_size=4)

        self.crossPlotHorizontal.index_range = self.polyplot.index_range.x_range

        self.plotData.set_data("line_indexVertical", scipy.array([]))
        self.plotData.set_data("line_valueVertical", scipy.array([]))
        self.plotData.set_data("scatter_indexVertical", scipy.array([]))
        self.plotData.set_data("scatter_valueVertical", scipy.array([]))
        self.plotData.set_data("scatter_colorVertical", scipy.array([]))
        self.plotData.set_data("fitLine_indexVertical", scipy.array([]))
        self.plotData.set_data("fitLine_valueVertical", scipy.array([]))

        self.crossPlotVertical = chaco.Plot(self.plotData,
                                            width=140,
                                            orientation="v",
                                            resizable="v",
                                            padding=20,
                                            padding_bottom=160)
        self.crossPlotVertical.plot(
            ("line_indexVertical", "line_valueVertical"), line_style="dot")

        self.crossPlotVertical.plot(
            ("scatter_indexVertical", "scatter_valueVertical",
             "scatter_colorVertical"),
            type="cmap_scatter",
            name="dot",
            color_mapper=self._cmap(image_value_range),
            marker="circle",
            marker_size=4)

        self.crossPlotVertical.index_range = self.polyplot.index_range.y_range

        # Create a container and add components
        self.container = chaco.HPlotContainer(padding=40,
                                              fill_padding=True,
                                              bgcolor="white",
                                              use_backbuffer=False)

        inner_cont = chaco.VPlotContainer(padding=40, use_backbuffer=True)
        inner_cont.add(self.crossPlotHorizontal)
        inner_cont.add(self.centralContainer)
        self.container.add(self.colorbar)
        self.container.add(inner_cont)
        self.container.add(self.crossPlotVertical)

    def initialiseFitPlot(self):
        """called if this is the first Fit Plot to be drawn """
        xstep = 1.0
        ystep = 1.0
        self.contourXS = scipy.linspace(xstep / 2.,
                                        self.model.pixelsX - xstep / 2.,
                                        self.model.pixelsX - 1)
        self.contourYS = scipy.linspace(ystep / 2.,
                                        self.model.pixelsY - ystep / 2.,
                                        self.model.pixelsY - 1)
        logger.debug("contour initialise fit debug. xs shape %s" %
                     self.contourXS.shape)
        logger.debug("contour initialise xs= %s" % self.contourXS)
        self._fit_value = chaco.ImageData(data=scipy.array([]), value_depth=1)

        self.lineplot = chaco.ContourLinePlot(
            index=self._image_index,
            value=self._fit_value,
            index_mapper=chaco.GridMapper(
                range=self.polyplot.index_mapper.range),
            levels=self.contourLevels)

        self.centralContainer.add(self.lineplot)
        self.plotData.set_data("fitLine_indexHorizontal", self.model.xs)
        self.plotData.set_data("fitLine_indexVertical", self.model.ys)
        self.crossPlotVertical.plot(
            ("fitLine_indexVertical", "fitLine_valueVertical"),
            type="line",
            name="fitVertical")
        self.crossPlotHorizontal.plot(
            ("fitLine_indexHorizontal", "fitLine_valueHorizontal"),
            type="line",
            name="fitHorizontal")
        logger.debug("initialise fit plot %s " % self.crossPlotVertical.plots)

    def addFitPlot(self, fit):
        """add a contour plot on top using fitted data and add additional plots to sidebars (TODO) """
        logger.debug("adding fit plot with fit %s " % fit)
        if not fit.fitted:
            logger.error(
                "cannot add a fitted plot for unfitted data. Run fit first")
            return
        if not self.drawFitBool:
            logger.info("first fit plot so initialising contour plot")
            self.initialiseFitPlot()
        logger.info("attempting to set fit data")
        self.contourPositions = [
            scipy.tile(self.contourXS, len(self.contourYS)),
            scipy.repeat(self.contourYS, len(self.contourXS))
        ]  #for creating data necessary for gauss2D function
        zsravelled = fit.fitFunc(self.contourPositions,
                                 *fit._getCalculatedValues())
        #        logger.debug("zs ravelled shape %s " % zsravelled.shape)
        self.contourZS = zsravelled.reshape(
            (len(self.contourYS), len(self.contourXS)))
        #        logger.debug("zs contour shape %s " % self.contourZS.shape)
        #        logger.info("shape contour = %s " % self.contourZS)
        self._fit_value.data = self.contourZS
        self.container.invalidate_draw()
        self.container.request_redraw()
        self.drawFitBool = True

    def update(self, model):
        logger.info("updating plot")
        #        if self.selectedFile=="":
        #            logger.warning("selected file was empty. Will not attempt to update plot.")
        #            return
        if self.autoRangeColor:
            self.colorbar.index_mapper.range.low = model.minZ
            self.colorbar.index_mapper.range.high = model.maxZ
        self._image_index.set_data(model.xs, model.ys)
        self._image_value.data = model.zs
        self.plotData.set_data("line_indexHorizontal", model.xs)
        self.plotData.set_data("line_indexVertical", model.ys)
        if self.drawFitBool:
            self.plotData.set_data("fitLine_indexHorizontal", self.contourXS)
            self.plotData.set_data("fitLine_indexVertical", self.contourYS)
        self.updatePlotLimits()
        self._image_index.metadata_changed = True
        self.container.invalidate_draw()
        self.container.request_redraw()

    #---------------------------------------------------------------------------
    # Event handlers
    #---------------------------------------------------------------------------

    def _metadata_changed(self, old, new):
        """ This function takes out a cross section from the image data, based
        on the line inspector selections, and updates the line and scatter
        plots."""
        if self.horizontalAutoRange:
            self.crossPlotHorizontal.value_range.low = self.model.minZ
            self.crossPlotHorizontal.value_range.high = self.model.maxZ
        if self.verticalAutoRange:
            self.crossPlotVertical.value_range.low = self.model.minZ
            self.crossPlotVertical.value_range.high = self.model.maxZ
        if self._image_index.metadata.has_key("selections"):
            selections = self._image_index.metadata["selections"]
            if not selections:  #selections is empty list
                return  #don't need to do update lines as no mouse over screen. This happens at beginning of script
            x_ndx, y_ndx = selections
            if y_ndx and x_ndx:
                self.plotData.set_data("line_valueHorizontal",
                                       self._image_value.data[y_ndx, :])
                self.plotData.set_data("line_valueVertical",
                                       self._image_value.data[:, x_ndx])
                xdata, ydata = self._image_index.get_data()
                xdata, ydata = xdata.get_data(), ydata.get_data()
                self.plotData.set_data("scatter_indexHorizontal",
                                       scipy.array([xdata[x_ndx]]))
                self.plotData.set_data("scatter_indexVertical",
                                       scipy.array([ydata[y_ndx]]))
                self.plotData.set_data(
                    "scatter_valueHorizontal",
                    scipy.array([self._image_value.data[y_ndx, x_ndx]]))
                self.plotData.set_data(
                    "scatter_valueVertical",
                    scipy.array([self._image_value.data[y_ndx, x_ndx]]))
                self.plotData.set_data(
                    "scatter_colorHorizontal",
                    scipy.array([self._image_value.data[y_ndx, x_ndx]]))
                self.plotData.set_data(
                    "scatter_colorVertical",
                    scipy.array([self._image_value.data[y_ndx, x_ndx]]))
                if self.drawFitBool:
                    self.plotData.set_data("fitLine_valueHorizontal",
                                           self._fit_value.data[y_ndx, :])
                    self.plotData.set_data("fitLine_valueVertical",
                                           self._fit_value.data[:, x_ndx])
        else:
            self.plotData.set_data("scatter_valueHorizontal", scipy.array([]))
            self.plotData.set_data("scatter_valueVertical", scipy.array([]))
            self.plotData.set_data("line_valueHorizontal", scipy.array([]))
            self.plotData.set_data("line_valueVertical", scipy.array([]))
            self.plotData.set_data("fitLine_valueHorizontal", scipy.array([]))
            self.plotData.set_data("fitLine_valueVertical", scipy.array([]))

    def _colormap_changed(self):
        self._cmap = colormaps.color_map_name_dict[self.colormap]
        if hasattr(self, "polyplot"):
            value_range = self.polyplot.color_mapper.range
            self.polyplot.color_mapper = self._cmap(value_range)
            value_range = self.crossPlotHorizontal.color_mapper.range
            self.crossPlotHorizontal.color_mapper = self._cmap(value_range)
            # FIXME: change when we decide how best to update plots using
            # the shared colormap in plot object
            self.crossPlotHorizontal.plots["dot"][0].color_mapper = self._cmap(
                value_range)
            self.crossPlotVertical.plots["dot"][0].color_mapper = self._cmap(
                value_range)
            self.container.request_redraw()

    def _colorMapRangeLow_changed(self):
        self.colorbar.index_mapper.range.low = self.colorMapRangeLow

    def _colorMapRangeHigh_changed(self):
        self.colorbar.index_mapper.range.high = self.colorMapRangeHigh

    def _horizontalLowerLimit_changed(self):
        self.crossPlotHorizontal.value_range.low = self.horizontalLowerLimit

    def _horizontalUpperLimit_changed(self):
        self.crossPlotHorizontal.value_range.high = self.horizontalUpperLimit

    def _verticalLowerLimit_changed(self):
        self.crossPlotVertical.value_range.low = self.verticalLowerLimit

    def _verticalUpperLimit_changed(self):
        self.crossPlotVertical.value_range.high = self.verticalUpperLimit

    def _autoRange_changed(self):
        if self.autoRange:
            self.colorbar.index_mapper.range.low = self.minz
            self.colorbar.index_mapper.range.high = self.maxz

    def _num_levels_changed(self):
        if self.num_levels > 3:
            self.polyplot.levels = self.num_levels
            self.lineplot.levels = self.num_levels

    def _colorMapRangeLow_default(self):
        logger.debug("setting color map rangle low default")
        return self.model.minZ

    def _colorMapRangeHigh_default(self):
        return self.model.maxZ

    def _horizontalLowerLimit_default(self):
        return self.model.minZ

    def _horizontalUpperLimit_default(self):
        return self.model.maxZ

    def _verticalLowerLimit_default(self):
        return self.model.minZ

    def _verticalUpperLimit_default(self):
        return self.model.maxZ

    def _selectedFit_changed(self, selected):
        logger.debug("selected fit was changed")

    def _fixAspectRatioBool_changed(self):
        if self.fixAspectRatioBool:
            #using zoom range works but then when you reset zoom this function isn't called...
            #            rangeObject = self.polyplot.index_mapper.range
            #            xrangeValue = rangeObject.high[0]-rangeObject.low[0]
            #            yrangeValue = rangeObject.high[1]-rangeObject.low[1]
            #            logger.info("xrange = %s, yrange = %s " % (xrangeValue, yrangeValue))
            #            aspectRatioSquare = (xrangeValue)/(yrangeValue)
            #            self.polyplot.aspect_ratio=aspectRatioSquare
            self.centralContainer.aspect_ratio = float(
                self.model.pixelsX) / float(self.model.pixelsY)
            #self.polyplot.aspect_ratio = self.model.pixelsX/self.model.pixelsY

        else:
            self.centralContainer.aspect_ratio = None
            #self.polyplot.aspect_ratio = None
        self.container.request_redraw()
        self.centralContainer.request_redraw()

    def updatePlotLimits(self):
        """just updates the values in the GUI  """
        if self.autoRangeColor:
            self.colorMapRangeLow = self.model.minZ
            self.colorMapRangeHigh = self.model.maxZ
        if self.horizontalAutoRange:
            self.horizontalLowerLimit = self.model.minZ
            self.horizontalUpperLimit = self.model.maxZ
        if self.verticalAutoRange:
            self.verticalLowerLimit = self.model.minZ
            self.verticalUpperLimit = self.model.maxZ

    def _selectedFile_changed(self):
        self.model.getImageData(self.selectedFile)
        if self.updatePhysicsBool:
            self.physics.updatePhysics()
        for fit in self.fitList:
            fit.fitted = False
            fit.fittingStatus = fit.notFittedForCurrentStatus
            if fit.autoFitBool:  #we should automatically start fitting for this Fit
                fit._fit_routine(
                )  #starts a thread to perform the fit. auto guess and auto draw will be handled automatically
        self.update_view()
        #update log file plot if autorefresh is selected
        if self.logFilePlotObject.autoRefresh:
            try:
                self.logFilePlotObject.refreshPlot()
            except Exception as e:
                logger.error("failed to update log plot -  %s...." % e.message)

    def _cameraModel_changed(self):
        """camera model enum can be used as a helper. It just sets all the relevant
        editable parameters to the correct values. e.g. pixels size, etc.

        cameras:  "Andor Ixon 3838", "Apogee ALTA"
        """
        logger.info("camera model changed")
        if self.cameraModel == "ANDOR0":
            self.model.pixelsX = 512
            self.model.pixelsY = 512
            self.physics.pixelSize = 16.0
            self.physics.magnification = 2.0
            self.searchString = "ANDOR0"
        elif self.cameraModel == "ALTA0":
            self.model.pixelsX = 768
            self.model.pixelsY = 512
            self.physics.pixelSize = 9.0
            self.physics.magnification = 0.5
            self.searchString = "ALTA0"
        elif self.cameraModel == "ALTA1":
            self.model.pixelsX = 768
            self.model.pixelsY = 512
            self.physics.pixelSize = 9.0
            self.physics.magnification = 4.25
            self.searchString = "ALTA1"
        elif self.cameraModel == "ANDOR1":
            self.model.pixelsX = 512
            self.model.pixelsY = 512
            self.physics.pixelSize = 16.0
            self.physics.magnification = 2.0
            self.searchString = "ANDOR1"
        else:
            logger.error("unrecognised camera model")
        self.refreshFitReferences()
        self.model.getImageData(self.selectedFile)

    def refreshFitReferences(self):
        """When aspects of the image change so that the fits need to have
        properties updated, it should be done by this function"""
        for fit in self.fitList:
            fit.endX = self.model.pixelsX
            fit.endY = self.model.pixelsY

    def _pixelsX_changed(self):
        """If pixelsX or pixelsY change, we must send the new arrays to the fit functions """
        logger.info("pixels X Change detected")
        self.refreshFitReferences()
        self.update(self.model)
        self.model.getImageData(self.selectedFile)

    def _pixelsY_changed(self):
        """If pixelsX or pixelsY change, we must send the new arrays to the fit functions """
        logger.info("pixels Y Change detected")
        self.refreshFitReferences()
        self.update(self.model)
        self.model.getImageData(self.selectedFile)

    @traits.on_trait_change('model')
    def update_view(self):
        if self.model is not None:
            self.update(self.model)

    def _save_image(self, originalFilePath, newFilePath):
        """given the original file path this saves a new copy to new File path """
        shutil.copy2(originalFilePath, newFilePath)

    def _save_image_as(self):
        """ opens a save as dialog and allows user to save a copy of current image to
        a custom location with a custom name"""
        originalFilePath = str(
            self.selectedFile
        )  #so that this can't be affected by auto update after the dialog is open
        file_wildcard = str("PNG (*.png)|All files|*")
        default_directory = os.path.join("\\\\ursa", "AQOGroupFolder",
                                         "Experiment Humphry", "Data",
                                         "savedEagleImages")
        dialog = FileDialog(action="save as",
                            default_directory=default_directory,
                            wildcard=file_wildcard)
        dialog.open()
        if dialog.return_code == OK:
            self._save_image(originalFilePath, dialog.path)
        logger.debug("custom image copy made")

    def _save_image_default(self):
        head, tail = os.path.split(self.selectedFile)
        default_file = os.path.join("\\\\ursa", "AQOGroupFolder",
                                    "Experiment Humphry", "Data",
                                    "savedEagleImages", tail)
        self._save_image(self.selectedFile, default_file)
        logger.debug("default image copy made")
Пример #9
0
class Librarian(traits.HasTraits):
    """Librarian provides a way of writing useful information into the 
    log folder for eagle logs. It is designed to make the information inside
    an eagle log easier to come back to. It mainly writes default strings into
    the comments file in the log folder"""
    
    sectionNames =  traits.List(traits.Str)
    sectionName = traits.Enum(values="sectionNames",desc="Investigation this eagle Log is for. Corresponds to tab in OneNote")
    
    importance = traits.Range(1,3,1)
    availableUsers = traits.List(traits.Str) # loaded from json file
    user = traits.Enum(values='availableUsers')
    keywords = traits.String('')
    writeToOneNoteButton = traits.Button("save")
    refreshInformation = traits.Button("refresh")
    # saveImage = traits.Button("save plot") # removed, because there is the same functionality as the button of the Matplotlibify dialog
    axisList = AxisSelector()
    purposeBlock = EntryBlock(fieldName="What is the purpose of this log?")
    resultsBlock = EntryBlock(fieldName = "Explain what the data shows (important parameters that change, does it make sense etc.)?")
    commentsBlock = EntryBlock(fieldName = "Anything Else?")
    matplotlibifyReference = traits.Any()#
    logFilePlotReference = traits.Any()#traits.Instance(plotObjects.logFilePlot.LogFilePlot)#gives access to most of the required attributes
    logFilePlotsReference = traits.Any()#traits.Instance(logFilePlots.LogFilePlots)#refernce to logFilePlots object
#    notebooks = traits.Enum(values = "notebookNames") # we could let user select from a range of notebooks
#    notebookNames = traits.List
    notebookName = traits.String("Investigations")
    
    logName = traits.String("")
    xAxis = traits.String("")
    yAxis = traits.String("")

    traits_view = traitsui.View(
        traitsui.VGroup(
            traitsui.HGroup(traitsui.Item("sectionName",label="investigation"),traitsui.Item("user",label="user")),
            traitsui.Item("importance",label="importance",style='custom'),
            traitsui.Item("logName",show_label=False, style="readonly"),            
            traitsui.Item("keywords",label='keywords'),            
            traitsui.Item("axisList",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("purposeBlock",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("resultsBlock",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("commentsBlock",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.Item("matplotlibifyReference",show_label=False, editor=traitsui.InstanceEditor(),style='custom'),
            traitsui.HGroup(
                # traitsui.Item("saveImage",show_label=False), # see above why commented
                traitsui.Item("writeToOneNoteButton",show_label=False),
                traitsui.Item("refreshInformation",show_label=False)
            ),
        )  , resizable=True  , kind ="live", title="Eagle OneNote", width=300, height=500
    )    
    
    def __init__(self, **traitsDict):
        """Librarian object requires the log folder it is referring to. If a .csv
        file is given as logFolder argument it will use parent folder as the 
        logFolder"""
        super(Librarian, self).__init__(**traitsDict)
        if os.path.isfile(self.logFolder):
            self.logFolder = os.path.split(self.logFolder)[0]
        else:
            logger.debug("found these in %s: %s" %(self.logFolder, os.listdir(self.logFolder) ))
        # load global settings
        filename = os.path.join("config","librarian.json")
        with open(filename, 'r') as f:
            settings = json.load( f )
            self.availableUsers = settings["users"]
        import matplotlibify.matplotlibify
        self.matplotlibifyReference = matplotlibify.matplotlibify.Matplotlibify(logFilePlotReference=self.logFilePlotReference,logFilePlotsReference=self.logFilePlotsReference, logLibrarianReference=self)
        self.matplotlibifyReference.templatesFolder = os.path.join("\\\\ursa","AQOGroupFolder","Experiment Humphry","Experiment Control And Software","LogFilePlots","matplotlibify","templates")
        self.matplotlibifyReference.templateFile = os.path.join(self.matplotlibifyReference.templatesFolder,"matplotlibifyDefaultTemplate.py")
        self.matplotlibifyReference.generatedScriptLocation = os.path.join(self.matplotlibifyReference.templatesFolder)
        self.logName = os.path.split(self.logFolder)[1]
        self.logFile = os.path.join(self.logFolder, os.path.split(self.logFolder)[1]+".csv")
        self.axisList.logFile = self.logFile#needs a copy so it can calculate valid values
        self.axisList.masterList = self.axisList._masterList_default()
        self.axisList.masterListWithNone = self.axisList._masterListWithNone_default() 
        if self.xAxis != "":
            self.axisList.xAxis = self.xAxis
        if self.yAxis != "":
            self.axisList.yAxis = self.yAxis
        
        self.eagleOneNote = eagleLogsOneNote.EagleLogOneNote(notebookName = self.notebookName, sectionName = self.sectionName)
        self.sectionNames = self._sectionNames_default()
        self.setupLogPage()

        # load local settings
        filename = os.path.join(self.logFolder,"logFilePlotSettings","librarian.json")
        if os.path.exists(filename):
            with open(filename, 'r') as f:
                settings = json.load( f )
                self.sectionName = settings["section"]

    def setupLogPage(self):
        """setup logPage object and change text boxes in GUI accordingly """
        logPage = self.eagleOneNote.setPage(self.logName)
#        
#        except Exception as e:
#            logger.error("failed to created an EagleOneNote Instance. This could happen for many reasons. E.g. OneNote not installed or most likely, the registry is not correct. See known bug and fix in source code of onenotepython module:%s" % e.message)
        if logPage is not None:#page exists
            self.purposeBlock.textBlock = self.eagleOneNote.getOutlineText("purpose")
            self.resultsBlock.textBlock = self.eagleOneNote.getOutlineText("results")
            self.commentsBlock.textBlock = self.eagleOneNote.getOutlineText("comments")
            xAxis,yAxis,series = self.eagleOneNote.getParametersOutlineValues()
            try:
                self.axisList.xAxis,self.axisList.yAxis,self.axisList.series = xAxis,yAxis,series
            except Exception as e:
                logger.error("error when trying to read analysis parameters: %s" % e.message)
            self.pageExists = True
        else:
            self.pageExists = False
            self.purposeBlock.textBlock = ""
            self.resultsBlock.textBlock = ""
            self.commentsBlock.textBlock = ""
            #could also reset axis list but it isn't really necessary
        
    def isUserInputGood(self):
        """runs a bunch of checks and provides a warning if user has written a bad eagle log.
        Returns True if the user has written a good eagle log and false if they havent"""
        issueStrings = []
        if self.axisList.series == "None":
            issueStrings.append("You have no Series selected, are there really no series for this log? If there are multiple series note this down in the Comments box.")
        if len(self.purposeBlock.textBlock)<200:
            issueStrings.append("The purpose text of your librarian is less than 200 characters. This is too short! Describe the measurement so that you could remember what you are doing in 2 years time.")
        if len(self.resultsBlock.textBlock)<200:
            issueStrings.append("The results text of your librarian is less than 200 characters. This is too short! Describe the results so that you can understand what was learnt in 2 years time. If this doesn't need to be long why do you need to save the log?")
        numberOfIssues = len(issueStrings)
        if numberOfIssues == 0:
            return True
        else:
            finalString = "There are issues with your Eagle Log\nPlease check the below points. If you are happy to continue press OK, otherwise press cancel and correct these issues.\n"
            finalString+= "u\n\u2022".join(issueStrings)
            return traitsui.error(message=finalString)

    def _sectionNames_default(self):
        """returns the the list of section (tab) names in the oneNote """
        if hasattr(self, "eagleOneNote"):
            return self.eagleOneNote.getSectionNames()
        else:
            return ['General']
            
    def _sectionName_changed(self):
        purposeBlockTemp = self.purposeBlock
        resultsBlockTemp = self.resultsBlock
        commentsBlocktemp = self.commentsBlock
        if hasattr(self, "eagleOneNote"):
            self.eagleOneNote.sectionName=self.sectionName
            self.eagleOneNote.eagleLogPages = self.eagleOneNote.notebook.getPagesfromSectionName(self.sectionName)
            self.setupLogPage()
        self.purposeBlock = purposeBlockTemp 
        self.resultsBlock = resultsBlockTemp
        self.commentsBlock = commentsBlocktemp
    
    def _writeToOneNoteButton_fired(self):
        """writes content of librarian to one note page """
        isGoodLibrarian = self.isUserInputGood()#False and they clicked cancel so just return
        if not isGoodLibrarian:
            return
        if not self.pageExists:
            self.eagleOneNote.createNewEagleLogPage(self.logName, refresh=True, setCurrent=True)
            self.pageExists = True
        self.eagleOneNote.setOutline("purpose", self.purposeBlock.textBlock,rewrite=False)
        self.eagleOneNote.setOutline("results", self.resultsBlock.textBlock,rewrite=False)
        automatic_comments = self._generate_automatic_additional_comments()
        self.eagleOneNote.setOutline("comments", automatic_comments+self.commentsBlock.textBlock,rewrite=False)
        self.eagleOneNote.setDataOutline(self.logName, rewrite=False)
        self.eagleOneNote.setParametersOutline(self.axisList.xAxis, self.axisList.yAxis, self.axisList.series, rewrite=False)
        self.eagleOneNote.currentPage.rewritePage()
        #now to get resizing done well we want to completely repull the XML and data
        #brute force method:
        self.eagleOneNote = eagleLogsOneNote.EagleLogOneNote(notebookName = self.notebookName, sectionName = self.sectionName)
        logPage = self.eagleOneNote.setPage(self.logName)#this sets current page of eagleOneNote
        self.eagleOneNote.organiseOutlineSizes()
        self.saveLocalSettings()


    def saveImageToFile(self,name=None,oneNote=True):
        if name is None:#use automatic location
            logFolder,tail = os.path.split(self.logFile)
            #logName = tail.strip(".csv")+" - "+str(self.xAxis)+" vs "+str(self.yAxis)
            logName =str(self.xAxis)+" vs "+str(self.yAxis)
            filename = datetime.datetime.today().strftime("%Y-%m-%dT%H%M%S")+"-"+logName+".png"
            imageFileName =os.path.join(logFolder, filename)
        else:
            imageFileName = name
    
        logger.info("saving image: %s" % imageFileName)
        self.matplotlibifyReference.autoSavePlotWithMatplotlib(imageFileName)
        
        if oneNote:
            try:
                logger.info("attempting to save image to oneNote page")
                logName =  tail.replace(".csv","")#this is what the name of the page should be in oneNote
                eagleOneNote = eagleLogsOneNote.EagleLogOneNote(notebookName =self.notebookName, sectionName =self.sectionName)
                logPage = eagleOneNote.setPage(logName)
                if logPage is None:
                    logger.info("saving image to one note . page doesn't exist. creating page")
                    eagleOneNote.createNewEagleLogPage(logName, refresh=True, setCurrent=True)
                logger.debug("attempting to save image")
                eagleOneNote.addImageToPlotOutline(imageFileName, (6.3*300,3.87*300),rewrite=True)
                if self.fitLogFileBool and self.fitPlot is not None and self.logFilePlotFitterReference.isFitted:
                    #these conditions mean that we have the fit data we can write to one note with the image!
                    logger.info("also writing fit data to one note")
                    eagleOneNote.setOutline("plots", eagleOneNote.getOutlineText("plots")+self.logFilePlotFitterReference.modelFitResult.fit_report())
                eagleOneNote.currentPage.rewritePage()
                #now to get resizing done well we want to completely repull the XML and data
                #brute force method:
                eagleOneNote = eagleLogsOneNote.EagleLogOneNote(notebookName = self.notebookName, sectionName = self.sectionName)
                logPage = eagleOneNote.setPage(logName)
                eagleOneNote.organiseOutlineSizes()
            
            except Exception as e:
                logger.error("failed to save the image to OneNote. error: %s " % e.message)
    
    def _saveImage_fired(self):
        self.logFilePlotReference.savePlotAsImage(self.matplotlibifyReference,self)
        

    def _generate_automatic_additional_comments(self):
        """generates some text that is always added to the beginning of additional comments """
        return "This log was written by %s. Importance ranking is **%s**.\nKeywords: %s" % (self.user, self.importance, self.keywords)
    
    def saveLocalSettings(self):
        filename = os.path.join(self.logFolder,"logFilePlotSettings","librarian.json")
        settings = {
            "section": self.sectionName
        }
        with open(filename, 'w') as f:
            json.dump( settings, f )
Пример #10
0
class DACHandler(traits.HasTraits):
    connection = ADEval_client.Connection()
    rpiADC = rpiADCClient.Connection()

    def __init__(self):
        self.x = ad.ADEvalBC()
        self.connection.connect()  #connect to ADEval
        #self.rpiADC.connect() # connect to rpiADC
        #self.start_timer()

    DACC1 = DACChannel("DAC A", 'A', connection, rpiADC)
    DACC2 = DACChannel("DAC B", 'B', connection, rpiADC)
    DACC3 = DACChannel("DAC C", 'C', connection, rpiADC)
    DACC4 = DACChannel("DAC D", 'D', connection, rpiADC)

    power_A = traits.Bool(desc="Power A")
    power_B = traits.Bool(desc="Power B")
    power_C = traits.Bool(desc="Power C")
    power_D = traits.Bool(desc="Power D")
    Power_switch = traits.Button()

    #    def start_timer(self):
    #        print "Timer started"
    #        self.timer = Timer(1000.0, self.update_channels)
    #
    #    def update_channels(self):
    #        self.DACC1._adcVoltage_update()
    #        self.DACC2._adcVoltage_update()
    #        self.DACC3._adcVoltage_update()
    #        self.DACC4._adcVoltage_update()

    groupLeft = traitsui.VGroup(
        traitsui.Item('DACC1',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False,
                      resizable=True),
        traitsui.Item('power_A'),
        traitsui.Item('DACC3',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False),
        traitsui.Item('power_C'),
    )

    groupRight = traitsui.VGroup(
        traitsui.Item('DACC2',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False),
        traitsui.Item('power_B'),
        traitsui.Item('DACC4',
                      editor=traitsui.InstanceEditor(),
                      style='custom',
                      show_label=False),
        traitsui.Item('power_D'),
    )

    groupH = traitsui.HGroup(
        groupLeft,
        groupRight,
    )

    groupall = traitsui.VGroup(
        groupH,
        traitsui.Item('Power_switch', show_label=False),
    )

    def _Power_switch_fired(self):
        #print self.x.setPowerMode( [self.power_A, self.power_B, self.power_C, self.power_D] )
        cmd = "cmd=" + self.x.setPowerMode(
            [self.power_A, self.power_B, self.power_C, self.power_D])
        self.connection.send(cmd)

    traits_view = traitsui.View(groupall, resizable=True)
Пример #11
0
class ExperimentSnake(traits.HasTraits):
    """Main Experiment Snake GUI that sends arbitrary actions based on the 
    experiment runner sequence and actions that have been set up."""

    #mainLog = utilities.TextDisplay()
    mainLog = outputStream.OutputStream()
    statusString = traits.String("Press Start Snake to begin...")
    isRunning = traits.Bool(False)  # true when the snake is running
    sequenceStarted = traits.Bool(
        False)  # flashes true for ~1ms when sequence starts
    queue = traits.Int(0)

    variables = traits.Dict(
        key_trait=traits.Str, value_trait=traits.Float
    )  #dictionary mapping variable names in Exp control to their values in this sequence
    timingEdges = traits.Dict(
        key_trait=traits.Str, value_trait=traits.Float
    )  #dictionary mapping timing Edge names in Exp control to their values in this sequence
    statusList = [
    ]  #eventually will contain the information gathered from experiment Runner each time we poll

    startAction = traitsui.Action(name='start',
                                  action='_startSnake',
                                  image=pyface.image_resource.ImageResource(
                                      os.path.join('icons', 'start.png')))
    stopAction = traitsui.Action(name='stop',
                                 action='_stopSnakeToolbar',
                                 image=pyface.image_resource.ImageResource(
                                     os.path.join('icons', 'stop.png')))
    reloadHWAsAction = traitsui.Action(
        name='reload',
        action='_reloadHWAsToolbar',
        image=pyface.image_resource.ImageResource(
            os.path.join('icons', 'reload.png')))

    connectionTimer = traits.Instance(
        Timer
    )  # polls the experiment runner and starts off callbacks at appropriate times
    statusStringTimer = traits.Instance(
        Timer)  #updates status bar at regular times (less freque)
    getCurrentTimer = traits.Instance(
        Timer
    )  #waits for get current to return which marks the beginning of a sequence

    getCurrentThread = traits.Instance(SocketThread)

    connectionPollFrequency = traits.Float(
        1000.0)  #milliseconds defines accuracy you will perform callbacks at
    statusStringFrequency = traits.Float(2000.0)  #milliseconds
    getCurrentFrequency = traits.Float(
        1000.0)  #milliseconds should be shorter than the sequence

    timeRunning = traits.Float(0.0)  #how long the sequence has been running
    totalTime = traits.Float(0.0)  # total length of sequence
    runnerHalted = traits.Bool(True)  # true if runner is halted
    haltedCount = 0
    progress = traits.Float(0.0)  # % of cycle complete
    #progressBar = ProgressDialog()
    hardwareActions = traits.List(hardwareAction.hardwareAction.HardwareAction)

    examineVariablesDictionary = traits.Instance(
        variableDictionary.ExamineVariablesDictionary)
    xmlString = ""  # STRING that will contain entire XML File

    menubar = traitsui.MenuBar(
        traitsui.Menu(
            traitsui.Action(name='Start Snake', action='_startSnake'),
            traitsui.Action(name='Stop Snake', action='_stopSnake'),
            traitsui.Action(name='Reload', action='_reloadHWAs'),
            traitsui.Menu(traitsui.Action(name='DEBUG',
                                          action='_changeLoggingLevelDebug'),
                          traitsui.Action(name='INFO',
                                          action='_changeLoggingLevelInfo'),
                          traitsui.Action(name='WARNING',
                                          action='_changeLoggingLevelWarning'),
                          traitsui.Action(name='ERROR',
                                          action='_changeLoggingLevelError'),
                          name="Log Level"),
            name='Menu'))

    toolbar = traitsui.ToolBar(startAction, stopAction, reloadHWAsAction)

    mainSnakeGroup = traitsui.VGroup(
        traitsui.Item('statusString', show_label=False, style='readonly'),
        traitsui.Item('mainLog',
                      show_label=False,
                      springy=True,
                      style='custom',
                      editor=traitsui.InstanceEditor()))

    hardwareActionsGroup = traitsui.Group(traitsui.Item(
        'hardwareActions',
        show_label=False,
        style='custom',
        editor=traitsui.ListEditor(style="custom")),
                                          label="Hardware Actions",
                                          show_border=True)

    variableExaminerGroup = traitsui.Group(traitsui.Item(
        "examineVariablesDictionary",
        editor=traitsui.InstanceEditor(),
        style="custom",
        show_label=False),
                                           label="Variable Examiner")

    sidePanelGroup = traitsui.VSplit(hardwareActionsGroup,
                                     variableExaminerGroup)

    traits_view = traitsui.View(traitsui.HSplit(sidePanelGroup,
                                                mainSnakeGroup,
                                                show_labels=True),
                                resizable=True,
                                menubar=menubar,
                                toolbar=toolbar,
                                width=0.5,
                                height=0.75,
                                title="Experiment Snake",
                                icon=pyface.image_resource.ImageResource(
                                    os.path.join('icons', 'snakeIcon.ico')))

    def __init__(self, **traits):
        """ takes no  arguments to construct the snake. Everything is done through GUI.
        Snake construction makes a ExperimentSnakeConnection object and writes to the 
        main log window"""

        super(ExperimentSnake, self).__init__(**traits)
        self.connection = experimentRunnerConnection.Connection(
        )  #can override default ports and IP
        self.hardwareActions = [
            hardwareAction.sequenceLoggerHWA.SequenceLogger(
                0.0, snakeReference=self),
            hardwareAction.experimentTablesHWA.ExperimentTables(
                0.0, snakeReference=self, enabled=False),
            hardwareAction.dlicEvapHWA.EvaporationRamp(1.0,
                                                       snakeReference=self),
            #hardwareAction.dlicRFSweepHWA.DLICRFSweep(1.0, snakeReference = self,enabled=False),
            hardwareAction.dlicRFSweepLZHWA.DLICRFSweep(1.0,
                                                        snakeReference=self,
                                                        enabled=False),
            hardwareAction.dlicRFSweepLZWithPowerCtrlHWA.DLICRFSweep(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.dlicRFSweepLZWithPowerCtrl13PreparationHWA.
            DLICRFSweep(1.0, snakeReference=self, enabled=True),
            hardwareAction.dlicPiPulseHWA.DLICPiPulse(1.0,
                                                      snakeReference=self,
                                                      enabled=False),
            hardwareAction.evapAttenuationHWA.EvapAttenuation(
                1.0, snakeReference=self),
            hardwareAction.greyMollassesOffsetFreqHWA.GreyMollassesOffset(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.evapAttenuation2HWA.EvapAttenuation(
                "EvapSnakeAttenuationTimeFinal",
                snakeReference=self,
                enabled=False),
            hardwareAction.picomotorPlugHWA.PicomotorPlug(1.0,
                                                          snakeReference=self,
                                                          enabled=False),
            hardwareAction.windFreakOffsetLockHWA.WindFreak(
                0.0, snakeReference=self, enabled=False),
            hardwareAction.windFreakOffsetLockHighFieldImagingHWA.WindFreak(
                0.0, snakeReference=self, enabled=True),
            hardwareAction.windFreakOffsetLock6ImagingHWA.WindFreak(
                2.0, snakeReference=self, enabled=False),
            hardwareAction.windFreak6To1HWA.WindFreak(2.0,
                                                      snakeReference=self,
                                                      enabled=False),
            hardwareAction.windFreakOffsetLockLaser3.WindFreak(
                3.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaZSFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaZSAtten(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaZSEOMFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaZSEOMAtten(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaSpecFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiImaging(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiImagingDetuning(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiPushPulseAttenuation(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiPushPulseDetuning(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaDarkSpotAOMFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaDarkSpotAOMAtten(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaMOTFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaMOTAtten(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaMOTEOMAtten(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaImagingDP(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiMOTRep(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiMOTCool(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelLiOpticalPump(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNa2to2OpticalPumpingFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNa2to2OpticalPumpingAtt(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaHighFieldImagingFreq(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.AOMChannelHWAs.AOMChannelNaHighFieldImagingAtt(
                1.0, snakeReference=self, enabled=False),
            hardwareAction.digitalMultimeterCurrentMeasureHWA.
            DigitalMultimeterMeasurement(1.0,
                                         snakeReference=self,
                                         enabled=True),
            hardwareAction.MXGPiPulseHWA.PiPulse(1.0,
                                                 snakeReference=self,
                                                 enabled=False),
            hardwareAction.variableExplorerHWA.VariableExplorer(
                2.0, snakeReference=self, enabled=False),
            hardwareAction.jds6600HWA.JDS6600HWA(1.0,
                                                 snakeReference=self,
                                                 enabled=False),
            hardwareAction.watchdogHWA.WatchdogHWA(18.0,
                                                   snakeReference=self,
                                                   enabled=True)
        ]
        introString = """Welcome to experiment snake."""

        self.mainLog.addLine(introString, 1)

    def initialiseHardwareActions(self):
        for hdwAct in self.hardwareActions:
            if hdwAct.enabled:
                returnString = hdwAct.init()
                hdwAct.variablesReference = self.variables
                self.mainLog.addLine(returnString)

    def closeHardwareActions(self):
        """ this function is called when the user presses stop key. it should cleanly close or 
        shutdown all hardware. user must appropriately implement the hardware action close function"""
        for hdwAct in self.hardwareActions:
            if hdwAct.initialised:
                returnString = hdwAct.close()
                self.mainLog.addLine(returnString)

    def _startSnake(self):
        """action call back from menu or toolbar. Simply starts the timer that
        polls the runner and makes the isRunning bool true  """
        self.mainLog.addLine("Experiment Snake Started", 1)
        self.isRunning = True
        self.getCurrentBlocking()
        self.initialiseHardwareActions()
        self.startTimers()

    def newSequenceStarted(self):
        """called by GetCurrent Thread at the beginning of every sequence """
        if self.isRunning:  #otherwise we have already stopped before new sequence began again
            self.getStatusUpdate()
            self.mainLog.addLine("New cycle started: %s" % self.statusList[0],
                                 1)
            self.refreshExamineVariablesDictionary(
            )  # update the examine variables dictionary to reflect the latest values
            self.refreshVariableDependentCallbackTimes(
            )  # if a callback time is a timing edge name or variable name we must pull the value here
        else:
            self.mainLog.addLine("final connection closed")
        for hdwAct in self.hardwareActions:
            hdwAct.awaitingCallback = True

    def _stopSnakeToolbar(self):
        """if snake is stopped, addLine to main log and then run stopSnake """
        self.mainLog.addLine(
            "Experiment Snake Stopped (you should still wait till the end of this sequence before continuing)",
            1)
        self._stopSnake()

    def _reloadHWAsToolbar(self):
        """if snake is stopped, addLine to main log and then run stopSnake """
        self.mainLog.addLine(
            "Experiment Snake Stopped (you should still wait till the end of this sequence before continuing)",
            1)
        self._reloadHWAs()

    def _reloadHWAs(self):
        """if snake is stopped, addLine to main log and then run stopSnake """
        self.mainLog.addLine("Reloading hardware actions (advanced feature)",
                             3)
        reload(hardwareAction.hardwareAction)
        reload(hardwareAction.sequenceLoggerHWA)
        reload(hardwareAction.dlicEvapHWA)
        reload(hardwareAction.dlicRFSweepHWA)
        reload(hardwareAction.dlicRFSweepHWA)
        reload(hardwareAction.evapAttenuationHWA)
        reload(hardwareAction.evapAttenuation2HWA)
        reload(hardwareAction.picomotorPlugHWA)
        reload(hardwareAction.windFreakOffsetLockHWA)
        #reload( hardwareAction.AOMChannelHWAs)#CAUSES REFERENCING PROBLEMS!
        reload(hardwareAction.experimentTablesHWA)
        reload(hardwareAction.windFreakOffsetLockHighFieldImagingHWA)
        reload(hardwareAction.greyMollassesOffsetFreqHWA)
        reload(hardwareAction.dlicRFSweepLZHWA)
        reload(hardwareAction.digitalMultimeterCurrentMeasureHWA)
        self.__init__()

    def stopTimers(self):
        """stops all timers with error catching """
        try:
            #stop any previous timer, should only have 1 timer at a time
            if self.connectionTimer is not None:
                self.connectionTimer.stop()
        except Exception as e:
            logger.error(
                "couldn't stop current timer before starting new one: %s" %
                e.message)
        try:
            #stop any previous timer, should only have 1 timer at a time
            if self.statusStringTimer is not None:
                self.statusStringTimer.stop()
        except Exception as e:
            logger.error(
                "couldn't stop current timer before starting new one: %s" %
                e.message)
        try:
            #stop any previous timer, should only have 1 timer at a time
            if self.getCurrentTimer is not None:
                self.getCurrentTimer.stop()
        except Exception as e:
            logger.error(
                "couldn't stop current timer before starting new one: %s" %
                e.message)

    def _stopSnake(self):
        """Simply stops the timers, shuts down hardware and sets isRunning bool false  """
        self.stopTimers()
        self.closeHardwareActions()
        self.isRunning = False

    def startTimers(self):
        """This timer object polls the experiment runner regularly polling at any time"""
        #stop any previous timers
        self.stopTimers()
        #start timer
        self.connectionTimer = Timer(self.connectionPollFrequency,
                                     self.getStatus)
        time.sleep(0.1)
        self.statusStringTimer = Timer(self.statusStringFrequency,
                                       self.updateStatusString)
        time.sleep(0.1)
        self.getCurrentTimer = Timer(self.getCurrentFrequency, self.getCurrent)
        """Menu action function to change logger level """
        logger.info("timers started")

    def getStatus(self):
        """calls the connection objects get status function and updates the statusList """
        logger.debug("starting getStatus")
        try:
            self.getStatusUpdate()
            self.checkForCallback()
        except Exception as e:
            logger.error("error in getStatus Function")
            logger.error("error: %s " % e.message)
            self.mainLog.addLine(
                "error in getStatus Function. Error: %s" % e.message, 4)

    def getStatusUpdate(self):
        """Calls get status and updates times """
        try:
            statusString = self.connection.getStatus()
        except socket.error as e:
            logger.error(
                "failed to get status . message=%s . errno=%s . errstring=%s "
                % (e.message, e.errno, e.strerror))
            self.mainLog.addLine(
                "Failed to get status from Experiment Runner. message=%s . errno=%s . errstring=%s"
                % (e.message, e.errno, e.strerror), 3)
            self.mainLog.addLine(
                "Cannot update timeRunning - callbacks could be wrong this sequence!",
                4)
            return
        self.statusList = statusString.split("\n")
        timeFormat = '%d/%m/%Y %H:%M:%S'
        timeBegin = datetime.datetime.strptime(self.statusList[2], timeFormat)
        timeCurrent = datetime.datetime.strptime(self.statusList[3],
                                                 timeFormat)
        self.timeRunning = (timeCurrent - timeBegin).total_seconds()
        logger.debug("time Running = %s " % self.timeRunning)

    def checkForCallback(self):
        """if we've received a sequence, we check through all callback times and
        send off a callback on a hardware action if appropriate"""
        try:
            for hdwAct in [
                    hdwA for hdwA in self.hardwareActions if hdwA.enabled
            ]:  #only iterate through enable hardware actions
                if hdwAct.awaitingCallback and self.timeRunning >= hdwAct.callbackTime:  #callback should be started!
                    try:
                        logger.debug("attempting to callback %s " %
                                     hdwAct.hardwareActionName)
                        hdwAct.setVariablesDictionary(self.variables)
                        logger.debug("vars dictionary set to %s " %
                                     self.variables)
                        callbackReturnString = hdwAct.callback()
                        self.mainLog.addLine(
                            "%s @ %s secs : %s" %
                            (hdwAct.hardwareActionName, self.timeRunning,
                             callbackReturnString), 2)
                        hdwAct.awaitingCallback = False
                        hdwAct.callbackCounter += 1
                    except Exception as e:
                        logger.error(
                            "error while performing callback on %s. see error message below"
                            % (hdwAct.hardwareActionName))
                        logger.error("error: %s " % e.message)
                        self.mainLog.addLine(
                            "error while performing callback on %s. Error: %s"
                            % (hdwAct.hardwareActionName, e.message), 4)
        except Exception as e:
            logger.error("error in checkForCallbackFunction")
            logger.error("error: %s " % e.message)
            self.mainLog.addLine(
                "error in checkForCallbackFunction. Error: %s" % e.message, 4)

    def getCurrent(self):
        """calls the connection objects get status function and updates the variables dictionary """
        if self.getCurrentThread and self.getCurrentThread.isAlive():
            #logger.debug( "getCurrent - already waiting - will not start new thread")
            #removed the above as it fills the log without any useful information
            self.sequenceStarted = False
            return
        else:
            logger.info("starting getCurrent Thread")
            self.getCurrentThread = SocketThread()
            self.getCurrentThread.snakeReference = self  # for calling functions of the snake
            self.getCurrentThread.start()

    def getCurrentBlocking(self):
        """calls getCurrent and won't return until XML parsed. unlike above threaded function
        This is useful when starting up the snake so that we don't start looking for hardware events
        until a sequence has started and we have received XML"""
        self.mainLog.addLine("Waiting for next sequence to start")
        self.xmlString = self.connection.getCurrent(
        )  # only returns at the beginning of a sequence! Experiment runner then returns the entire XML file
        logger.debug("length of xml string = %s " % len(self.xmlString))
        logger.debug("end of xml file is like [-30:]= %s" %
                     self.xmlString[-30:])
        try:
            root = ET.fromstring(self.xmlString)
            variables = root.find("variables")
            self.variables = {
                child[0].text: float(child[1].text)
                for child in variables
            }
            #timing edges dictionary : name--> value
            self.timingEdges = {
                timingEdge.find("name").text:
                float(timingEdge.find("value").text)
                for timingEdge in root.find("timing")
            }
            self.newSequenceStarted()
        except ET.ParseError as e:
            self.mainLog.addLine("Error. Could not parse XML: %s" % e.message,
                                 3)
            self.mainLog.addLine(
                "Possible cause is that buffer is full. is XML length %s>= limit %s ????"
                % (len(self.xmlString), self.connection.BUFFER_SIZE_XML), 3)
            logger.error("could not parse XML: %s " % self.xmlString)
            logger.error(e.message)

    def updateStatusString(self):
        """update the status string with first element of return of GETSTATUS. 
        similiar to experiment control and camera control. It also does the analysis
        of progress that doesn't need to be as accurate (e.g. progress bar)"""
        logger.info("starting update status string")
        self.statusString = self.statusList[
            0] + "- Time Running = %s " % self.timeRunning
        self.queue = int(self.statusList[1])
        timeFormat = '%d/%m/%Y %H:%M:%S'
        timeBegin = datetime.datetime.strptime(self.statusList[2], timeFormat)
        timeEnd = datetime.datetime.strptime(self.statusList[4], timeFormat)
        self.timeTotal = (timeEnd - timeBegin).total_seconds()
        if self.timeRunning > self.timeTotal:
            self.haltedCount += 1
            self.runnerHalted = True
            if self.haltedCount == 0:
                logger.critical("runner was stopped.")
                self.mainLog.addLine("Runner stopped!", 3)
                self.closeHardwareActions()
        else:
            if self.haltedCount > 0:
                self.initialiseHardwareActions()
            self.haltedCount = 0
            self.runnerHalted = False
        self.progress = 100.0 * self.timeRunning / self.timeTotal

    def _examineVariablesDictionary_default(self):
        if len(self.hardwareActions) > 0:
            logger.debug(
                "returning first hardware action %s for examineVariablesDictionary default"
                % self.hardwareActions[0].hardwareActionName)
            return variableDictionary.ExamineVariablesDictionary(
                hdwA=self.hardwareActions[0]
            )  #default is the first in the list
        else:
            logger.warning(
                "hardwareActions list was empty. how should I populate variable examiner...?!."
            )
            return None

    def updateExamineVariablesDictionary(self, hdwA):
        """Populates the examineVariablesDictionary Pane appropriately. It is passed the 
        hdwA so that it can find the necessary variables"""
        self.examineVariablesDictionary.hdwA = hdwA
        self.examineVariablesDictionary.hardwareActionName = hdwA.hardwareActionName
        self.examineVariablesDictionary.updateDisplayList()
        logger.critical("examineVariablesDictionary changed")

    def refreshExamineVariablesDictionary(self):
        """calls the updateDisplayList function of examineVariables Dictionary 
        this updates the values in the display list to the latest values in variables
        dictionary. useful for refereshing at the beginning of a sequence"""
        self.examineVariablesDictionary.updateDisplayList()
        logger.info("refreshed examine variables dictionary")

    def refreshVariableDependentCallbackTimes(self):
        """if a HWA is variable dependent call back time, we refresh the value 
        using this function. THis should be called in each sequence"""
        [
            hdwA.parseCallbackTime() for hdwA in self.hardwareActions
            if hdwA.callbackTimeVariableDependent
        ]

    def _changeLoggingLevelDebug(self):
        """Menu action function to change logger level """
        logger.setLevel(logging.DEBUG)

    def _changeLoggingLevelInfo(self):
        """Menu action function to change logger level """
        logger.setLevel(logging.INFO)

    def _changeLoggingLevelWarning(self):
        """Menu action function to change logger level """
        logger.setLevel(logging.WARNING)

    def _changeLoggingLevelError(self):
        """Menu action function to change logger level """
        logger.setLevel(logging.ERROR)