Example #1
0
def Plotting(queue):

    while queue.get() != "Start Plotting Process":
        wait = "Waiting"

    timeNow = datetime.time(datetime.now())
    time = timeNow.minute + (timeNow.second +
                             timeNow.microsecond / 1000000.0) / 60.0
    lastX = time
    lastY = 90250
    connect = True
    step = 0
    x = []
    y = []

    mode = "24-Hour-Plot"

    root = tk.Tk()
    root.wm_title("PyAmaseis v1.0")
    root.iconbitmap(r'icons/icon.ico')
    root.wm_state('zoomed')

    graphHeightConst = 2500

    fig = plt.figure(figsize=(15, 10))
    fig.set_tight_layout(0.4)

    ax = fig.add_subplot(1, 1, 1)
    ax.set_xlim(0, 60)
    ax.set_ylim(30250, 92750)
    ax.set_xlabel('Time(minutes)')

    xAxis = [0, 60]
    yAxis = [30250, 92750]

    y1 = (np.arange(min(yAxis), max(yAxis) + 1, graphHeightConst))
    y2 = calculateYAxisLabels()

    ax.set_xticks(np.arange(min(xAxis), max(xAxis) + 1, 1))
    plt.yticks(y1, y2)
    ax.yaxis.grid(color='#0000FF')
    ax.set_axisbelow(True)
    line, = ax.plot(x, y, color='k')
    canvas = FigureCanvasTkAgg(fig, master=root)

    canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    label = tk.Label(text="")
    label.pack()
    background = canvas.copy_from_bbox(ax.bbox)
    canvas.draw()

    root.after(0, plotData, queue, fig, ax, canvas, label, root, lastY, lastX,
               connect, background, line, mode)

    root.mainloop()
Example #2
0
def Plotting(queue):
    
    while queue.get() != "Start Plotting Process":
        wait = "Waiting"
    
    timeNow = datetime.time(datetime.now())
    time = timeNow.minute + (timeNow.second + timeNow.microsecond/1000000.0)/60.0
    lastX = time
    lastY = 90250
    connect = True
    step = 0
    x=[]
    y=[]
    
    mode = "24-Hour-Plot"
    
    root = tk.Tk()
    root.wm_title("PyAmaseis v1.0")
    root.iconbitmap(r'icons/icon.ico')
    root.wm_state('zoomed')
    
    graphHeightConst = 2500
    
    fig = plt.figure(figsize=(15,10))
    fig.set_tight_layout(0.4)
    
    ax = fig.add_subplot(1,1,1)
    ax.set_xlim(0,60)
    ax.set_ylim(30250,92750)
    ax.set_xlabel('Time(minutes)')
    
    xAxis = [0,60]
    yAxis = [30250,92750]
    
    y1 = (np.arange(min(yAxis), max(yAxis)+1,graphHeightConst))
    y2 = calculateYAxisLabels()
    
    ax.set_xticks(np.arange(min(xAxis), max(xAxis)+1,1))
    plt.yticks(y1, y2)
    ax.yaxis.grid(color = '#0000FF' )
    ax.set_axisbelow(True)
    line, = ax.plot(x, y, color='k')
    canvas = FigureCanvasTkAgg(fig, master=root)

    canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    label = tk.Label(text="")
    label.pack()
    background = canvas.copy_from_bbox(ax.bbox)
    canvas.draw()

    root.after(0, plotData,queue, fig, ax, canvas, label, root, lastY, lastX, connect, background, line, mode)
    
    root.mainloop()
Example #3
0
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        #bring up vertical scroll frame and place it
        scframe = VerticalScrolledFrame(self)
        scframe.place(x=130, y=40)
        #bring up canvas with plot in the frame with vertical scroll bar
        canvas = FigureCanvasTkAgg(f, scframe.interior)
        background = canvas.copy_from_bbox(f.bbox)
        canvas.draw()
        #create title label
        label = tk.Label(self, text="Dashboard", bg='white', font=TITLE_FONT)
        label.place(x=460, y=10)
        #embed graph into canvas
        canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        #add navigation bar
        toolbar = NavigationToolbar2Tk(canvas, self)
        toolbar.update()
        #color variables
        #data table labels
        table_title = tk.Label(self,
                               text="Data Summary",
                               bg="white",
                               font=LARGE_FONT)
        table_title.place(x=28, y=40)
        for i, param in enumerate(
                param_list):  #tk.Label self refers to Homepage
            param_label = tk.Label(self,
                                   text=param,
                                   fg="black",
                                   bg="white",
                                   font=MEDIUM_FONT,
                                   borderwidth=2,
                                   relief="ridge",
                                   width=18,
                                   height=1,
                                   anchor=W,
                                   justify=LEFT)
            param_label.place(x=5, y=65 + 22 * i)

        for i, param in enumerate(param_list):
            loading_text = tk.Label(self,
                                    text="Loading",
                                    fg="black",
                                    bg="white",
                                    font=MEDIUM_FONT,
                                    borderwidth=2,
                                    relief="ridge",
                                    width=5,
                                    height=1)
            loading_text.place(x=156, y=65 + 22 * i)
            current_text = Live_Text(loading_text)
            live_dict[param] = current_text
class StripChartWdg(tkinter.Frame):
    """A widget to changing values in real time as a strip chart
    
    Usage Hints:
    - For each variable quantity to display:
      - Call addLine once to specify the quantity
      - Call addPoint for each new data point you wish to display

    - For each constant line (e.g. limit) to display call addConstantLine
    
    - To make sure a plot includes one or two y values (e.g. 0 or a range of values) call showY

    - To manually scale a Y axis call setYLimits (by default all y axes are autoscaled).
    
    - All supplied times are POSIX timestamps (e.g. as supplied by time.time()).
        You may choose the kind of time displayed on the time axis (e.g. UTC or local time) using cnvTimeFunc
        and the format of that time using dateFormat.
    
    Known Issues:
    matplotlib's defaults present a number of challenges for making a nice strip chart display.
    Some issues and manual solutions are discussed in the main file's document string.
        
    Potentially Useful Attributes:
    - canvas: the matplotlib FigureCanvas
    - figure: the matplotlib Figure
    - subplotArr: list of subplots, from top to bottom; each is a matplotlib Subplot object,
        which is basically an Axes object but specialized to live in a rectangular grid
    - xaxis: the x axis shared by all subplots
    """
    def __init__(
        self,
        master,
        timeRange=3600,
        numSubplots=1,
        width=8,
        height=2,
        showGrid=True,
        dateFormat="%H:%M:%S",
        updateInterval=None,
        cnvTimeFunc=None,
    ):
        """Construct a StripChartWdg with the specified time range
        
        Inputs:
        - master: Tk parent widget
        - timeRange: range of time displayed (seconds)
        - width: width of graph in inches
        - height: height of graph in inches
        - numSubplots: the number of subplots
        - showGrid: if True a grid is shown
        - dateFormat: format for major axis labels, using time.strftime format
        - updateInterval: now often the time axis is updated (seconds); if None a value is calculated
        - cnvTimeFunc: a function that takes a POSIX timestamp (e.g. time.time()) and returns matplotlib days;
            typically an instance of TimeConverter; defaults to TimeConverter(useUTC=False)
        """
        tkinter.Frame.__init__(self, master)

        self._timeRange = timeRange
        self._isVisible = self.winfo_ismapped()
        self._isFirst = True
        if updateInterval is None:
            updateInterval = max(0.1, min(5.0, timeRange / 2000.0))
        self.updateInterval = float(updateInterval)
        #         print "updateInterval=", self.updateInterval

        if cnvTimeFunc is None:
            cnvTimeFunc = TimeConverter(useUTC=False)
        self._cnvTimeFunc = cnvTimeFunc

        # how many time axis updates occur before purging old data
        self._maxPurgeCounter = max(1, int(0.5 + (5.0 / self.updateInterval)))
        self._purgeCounter = 0

        self.figure = matplotlib.figure.Figure(figsize=(width, height),
                                               frameon=True)
        self.canvas = FigureCanvasTkAgg(self.figure, self)
        self.canvas.get_tk_widget().grid(row=0, column=0, sticky="news")
        self.canvas.mpl_connect('draw_event', self._handleDrawEvent)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        bottomSubplot = self.figure.add_subplot(numSubplots, 1, numSubplots)
        self.subplotArr = [self.figure.add_subplot(numSubplots, 1, n+1, sharex=bottomSubplot) \
            for n in range(numSubplots-1)] + [bottomSubplot]
        if showGrid:
            for subplot in self.subplotArr:
                subplot.grid(True)

        self.xaxis = bottomSubplot.xaxis
        bottomSubplot.xaxis_date()
        self.xaxis.set_major_formatter(
            matplotlib.dates.DateFormatter(dateFormat))

        # dictionary of constant line name: (matplotlib Line2D, matplotlib Subplot)
        self._constLineDict = dict()

        for subplot in self.subplotArr:
            subplot._scwLines = []  # a list of contained _Line objects;
            # different than the standard lines property in that:
            # - lines contains Line2D objects
            # - lines contains constant lines as well as data lines
            subplot._scwBackground = None  # background for animation
            subplot.label_outer(
            )  # disable axis labels on all but the bottom subplot
            subplot.set_ylim(auto=True)  # set auto scaling for the y axis

        self.bind("<Map>", self._handleMap)
        self.bind("<Unmap>", self._handleUnmap)
        self._timeAxisTimer = Timer()
        self._updateTimeAxis()

    def addConstantLine(self, y, subplotInd=0, **kargs):
        """Add a new constant to plot
        
        Inputs:
        - y: value of constant line
        - subplotInd: index of subplot
        - All other keyword arguments are sent to the matplotlib Line2D constructor
          to control the appearance of the data. See addLine for more information.
        """
        subplot = self.subplotArr[subplotInd]
        line2d = subplot.axhline(y, **kargs)
        yMin, yMax = subplot.get_ylim()
        if subplot.get_autoscaley_on() and numpy.isfinite(y) and not (yMin <= y
                                                                      <= yMax):
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)
        return line2d

    def addLine(self, subplotInd=0, **kargs):
        """Add a new quantity to plot
        
        Inputs:
        - subplotInd: index of subplot
        - All other keyword arguments are sent to the matplotlib Line2D constructor
          to control the appearance of the data. Useful arguments include:
          - label: name of line (displayed in a Legend)
          - color: color of line
          - linestyle: style of line (defaults to a solid line); "" for no line, "- -" for dashed, etc.
          - marker: marker shape, e.g. "+"
          Please do not attempt to control other sorts of line properties, such as its data.
          Arguments to avoid include: animated, data, xdata, ydata, zdata, figure.
        """
        subplot = self.subplotArr[subplotInd]
        return _Line(subplot=subplot,
                     cnvTimeFunc=self._cnvTimeFunc,
                     wdg=self,
                     **kargs)

    def clear(self):
        """Clear data in all non-constant lines
        """
        for subplot in self.subplotArr:
            for line in subplot._scwLines:
                line.clear()

    def getDoAutoscale(self, subplotInd=0):
        return self.subplotArr[subplotInd].get_autoscaley_on()

    def removeLine(self, line):
        """Remove an existing line added by addLine or addConstantLine
        
        Raise an exception if the line is not found
        """
        if isinstance(line, _Line):
            # a _Line object needs to be removed from _scwLines as well as the subplot
            line2d = line.line2d
            subplot = line.subplot
            subplot._scwLines.remove(line)
        else:
            # a constant line is just a matplotlib Line2D instance
            line2d = line
            subplot = line.axes

        subplot.lines.remove(line2d)
        if subplot.get_autoscaley_on():
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)
        self.canvas.draw()

    def setDoAutoscale(self, doAutoscale, subplotInd=0):
        """Turn autoscaling on or off for the specified subplot
        
        You can also turn off autoscaling by calling setYLimits.
        """
        doAutoscale = bool(doAutoscale)
        subplot = self.subplotArr[subplotInd]
        subplot.set_ylim(auto=doAutoscale)
        if doAutoscale:
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)

    def setYLimits(self, minY, maxY, subplotInd=0):
        """Set y limits for the specified subplot and disable autoscaling.
        
        Note: if you want to autoscale with a minimum range, use showY.
        """
        self.subplotArr[subplotInd].set_ylim(minY, maxY, auto=False)

    def showY(self, y0, y1=None, subplotInd=0):
        """Specify one or two values to always show in the y range.
        
        Inputs:
        - subplotInd: index of subplot
        - y0: first y value to show
        - y1: second y value to show; None to omit

        Warning: setYLimits overrides this method (but the values are remembered in case you turn
        autoscaling back on).
        """
        subplot = self.subplotArr[subplotInd]
        yMin, yMax = subplot.get_ylim()

        if y1 is not None:
            yList = [y0, y1]
        else:
            yList = [y0]
        doRescale = False
        for y in yList:
            subplot.axhline(y, linestyle=" ")
            if subplot.get_autoscaley_on() and numpy.isfinite(y) and not (
                    yMin <= y <= yMax):
                doRescale = True
        if doRescale:
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)

    def _handleDrawEvent(self, event=None):
        """Handle draw event
        """
        #         print "handleDrawEvent"
        for subplot in self.subplotArr:
            subplot._scwBackground = self.canvas.copy_from_bbox(subplot.bbox)
            for line in subplot._scwLines:
                subplot.draw_artist(line.line2d)
            self.canvas.blit(subplot.bbox)

    def _handleMap(self, evt):
        """Handle map event (widget made visible)
        """
        self._isVisible = True
        self._handleDrawEvent()
        self._updateTimeAxis()

    def _handleUnmap(self, evt):
        """Handle unmap event (widget made not visible)
        """
        self._isVisible = False

    def _updateTimeAxis(self):
        """Update the time axis; calls itself
        """
        tMax = time.time() + self.updateInterval
        tMin = tMax - self._timeRange
        minMplDays = self._cnvTimeFunc(tMin)
        maxMplDays = self._cnvTimeFunc(tMax)

        self._purgeCounter = (self._purgeCounter + 1) % self._maxPurgeCounter
        doPurge = self._purgeCounter == 0

        if doPurge:
            for subplot in self.subplotArr:
                for line in subplot._scwLines:
                    line._purgeOldData(minMplDays)

        if self._isVisible or self._isFirst:
            for subplot in self.subplotArr:
                subplot.set_xlim(minMplDays, maxMplDays)
                if doPurge:
                    if subplot.get_autoscaley_on():
                        # since data is being purged the y limits may have changed
                        subplot.relim()
                        subplot.autoscale_view(scalex=False, scaley=True)
            self._isFirst = False
            self.canvas.draw()
        self._timeAxisTimer.start(self.updateInterval, self._updateTimeAxis)
Example #5
0
class Annotator:
    def __init__(self, parent):
        self.parent = parent
        parent.title("Sound Annotation/Analyzation Tool")
        self.initUI()

    def initUI(self):

        self.labeldict = {}
        self.show = []
        self.timeValues = []
        self.stamp = -1
        self.stampHistory = []

        self.funclist = {
            "rms", "hfc", "complex", "complex_phase", "flux", "superflux",
            "noveltycurve", "CNNOnsetDetector", "RNNOnsetDetector",
            "modifiedKL", "weightedPhaseDev", "PhaseDev",
            "rectifiedComplexDomain", "ninos"
        }

        self.featurelist = [
            "Audio", "rms", "spectralCentroid", "spectralRolloff", "zcr",
            "spectralEntropy", "spectralFlux", "StrongDecay", "stft"
        ]
        self.hopsizes = []
        self.calculated_features_dict = {}
        self.calculated_features = []
        self.calculated_featuresParams = []

        self.defaultParams = {
            'rms': (512, 1024, 'hann'),
            'Audio': (),
            'spectralCentroid': (512, 1024, 'hann'),
            'spectralRolloff': (512, 1024, 'hann'),
            'spectralFlux': (512, 1024, 'hann'),
            'zcr': (512, 1024),
            'spectralEntropy': (512, 1024, 'hann'),
            'StrongDecay': (512, 1024),
            'stft': (512, 1024)
        }

        self.chunk_size = 2048
        self.mag = []
        self.phase = []
        self.sem = asyncio.Semaphore()

        # Info text
        self.info = StringVar()
        self.info.set("welcome")
        self.info_widget = Message(self.parent,
                                   textvariable=self.info,
                                   width=300)
        self.info_widget.grid(row=0, column=3, sticky=W + N + E + S, rowspan=2)

        # define options for opening file
        self.file_opt = options = {}
        options['defaultextension'] = '.wav'
        options['filetypes'] = [('All files', '.*'), ('Wav files', '.wav')]
        options['initialdir'] = os.getcwd() + "/sounds"
        if (options['initialdir'][-1] != '/'):
            options['initialdir'] += '/'

        # BUTTON TO SET DIRECTORY
        self.directory_button = Button(self.parent,
                                       text="Directory",
                                       command=self.set_directory)
        self.directory_button.grid(row=1, column=0, sticky=W)

        #TEXTBOX TO PRINT PATH OF THE SOUND FILE
        self.filelocation = Entry(self.parent)
        self.filelocation["width"] = 25
        self.filelocation.grid(row=0, column=0, sticky=W, padx=10)
        self.filelocation.delete(0, END)
        self.filename = ''  # initial file
        self.filelocation.insert(0,
                                 self.file_opt['initialdir'] + self.filename)

        #BUTTON TO BROWSE SOUND FILE
        self.open_file = Button(self.parent,
                                text="Browse...",
                                command=self.browse_file)
        self.open_file.grid(row=0, column=0, sticky=W, padx=(220, 6))

        #BUTTON TO PLOT SOUND FILE
        self.preview = Button(self.parent,
                              text="Plot",
                              command=self.plot,
                              bg="gray30",
                              fg="white")
        self.preview.grid(row=0, column=0, sticky=W, padx=(300, 6))

        #BUTTON TO draw  stamps
        self.draw = Button(self.parent,
                           text="Draw",
                           command=self.drawAllStamps,
                           bg="gray30",
                           fg="white")
        self.draw.grid(row=1, column=0, sticky=W, padx=(420, 6))

        # Dropdown Function Select
        self.funcname = StringVar()
        self.funcname.set("Select a function")
        self.fselect = OptionMenu(self.parent, self.funcname, *self.funclist)
        self.fselect.grid(row=1, column=2, sticky=W)

        # Button to Apply function
        self.afuncbtn = Button(self.parent,
                               text="Apply",
                               command=self.applyfunction,
                               bg="gray30",
                               fg="white")
        self.afuncbtn.grid(row=1, column=2, sticky=W, padx=(300, 6))

        # Dropdown SHOW FEATURE
        self.featurename = StringVar()
        self.featurename.set("Audio")
        self.featurename.trace("w", self.changeparams)
        self.ftselect = OptionMenu(self.parent, self.featurename,
                                   *self.featurelist)
        self.ftselect.grid(row=0, column=2, sticky=W)
        # Entry for feature params
        self.featureParamsEntry = Entry(self.parent)
        self.featureParamsEntry.grid(row=0, column=2, sticky=W, padx=(150, 6))
        self.featureParamsEntry.bind("<Enter>", self.updateinfo)
        # Button to show  feature
        self.afuncbtn = Button(self.parent,
                               text="Show",
                               command=self.showfeature,
                               bg="gray30",
                               fg="white")
        self.afuncbtn.grid(row=0, column=2, sticky=W, padx=(300, 6))

        # Button to send top feature to below plot
        self.sendbelowbtn = Button(self.parent,
                                   text="v",
                                   command=self.sendbelow)
        self.sendbelowbtn.grid(row=0, column=2, sticky=W, padx=(360, 6))
        #BUTTON TO PLAY/STOP , shortcut: spacebar
        self.play_mode = tk.BooleanVar(self.parent, False)
        self.new_sound = tk.BooleanVar(self.parent, False)
        self.playbutton = Button(self.parent,
                                 text="Play",
                                 command=self.playsound)
        self.playbutton.grid(row=0, column=0, sticky=W, padx=(350, 6))
        self.parent.bind("<space>", self.playsound)

        #BUTTON TO SAVE AND LOAD NEXT SOUND FILE
        self.saveload = Button(self.parent,
                               text="Save& Load Next",
                               command=self.saveAndNext)
        self.saveload.grid(row=0, column=1, sticky=W)

        #BUTTON TO ADD LABELS
        self.addlabel_button = Button(self.parent,
                                      text="Add/Manage Labels",
                                      command=self.addlabel_gui)
        self.addlabel_button.grid(row=0, column=0, sticky=W, padx=(420, 6))

        # BUTTON TO DISCARD CURRENT ANNOTATIONS
        self.discardbutton = Button(self.parent,
                                    text="Discard",
                                    command=self.discard)
        self.discardbutton.grid(row=0, column=4, sticky=W)

        #BUTTON TO get next
        self.load_next = Button(self.parent,
                                text="Next Sound",
                                command=self.getNext)
        self.load_next.grid(row=1, column=0, sticky=W, padx=(220, 6))

        # BUTTON TO QUIT
        self.quitbutton = Button(self.parent, text="Quit", command=self.quit)
        self.quitbutton.grid(row=3, column=4, sticky=W)

        # tickbox to autoload existing annotations
        self.ALoad = IntVar()
        self.autoload_annotations = Checkbutton(master=self.parent,
                                                text="Autoload Annotations?",
                                                variable=self.ALoad,
                                                onvalue=1,
                                                offvalue=0)
        self.autoload_annotations.grid(row=1, column=1, sticky=W)

        # tickbox to convert time to samples
        self.isTime = IntVar()
        self.timeorsamples = Checkbutton(master=self.parent,
                                         text="time?",
                                         variable=self.isTime,
                                         onvalue=1,
                                         offvalue=0)
        self.timeorsamples.grid(row=1, column=0, sticky=W, padx=(500, 6))

        # tickbox to enable discarding labels
        self.DLabels = IntVar()
        self.discardlabels_check = Checkbutton(master=self.parent,
                                               text="Discard Labels?",
                                               variable=self.DLabels,
                                               onvalue=1,
                                               offvalue=0)
        self.discardlabels_check.grid(row=1, column=4, sticky=W)

        # init figure for plotting
        self.currentplot = 0

        fig = plt.figure(figsize=(18, 7), dpi=100)
        self.mainplot = fig.add_subplot(211)
        self.secplot = fig.add_subplot(212)

        self.canvas = FigureCanvasTkAgg(fig, self.parent)
        self.canvaswidget = self.canvas.get_tk_widget()
        self.canvaswidget.grid(row=2, column=0, columnspan=5, sticky=W)

        toolbarFrame = Frame(master=self.parent)
        toolbarFrame.grid(row=3, column=0, columnspan=7)
        self.toolbar = NavigationToolbar2Tk(self.canvas, toolbarFrame)
        self.toolbar.update()

        self.canvas._tkcanvas.grid(row=2, column=0, columnspan=7, sticky=W)
        self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)
        self.cursor = self.mainplot.axvline(color="k", animated=True)
        self.cursor.set_xdata(0)

        self.colors = [
            'r', 'g', 'c', 'm', 'y', '#FFBD33', '#924A03', '#D00000',
            '#D000D0', '#6800D0', '#095549', 'b', 'r', 'r'
        ]

        # modification to original handler of 'release_zoom', "release_pan" and "_update_view" from NavigationToolbar2
        # latest one is for forward, backward and home buttons
        self.release_zoom_orig = self.toolbar.release_zoom
        self.toolbar.release_zoom = self.new_release_zoom
        self.release_pan_orig = self.toolbar.release_pan
        self.toolbar.release_pan = self.new_release_pan
        self._update_view_orig = self.toolbar._update_view
        self.toolbar._update_view = self.new_update_view

        self.canvas.mpl_connect('toolbar_event', self.handle_toolbar)
        cid1 = self.canvas.mpl_connect("button_press_event", self.onclick)
        self.parent.bind("<Escape>", self.release_stamp)
        self.parent.bind("x", self.discard_last)

        self.p = pyaudio.PyAudio()

        self.parent.bind("<<playbackmove>>", self.playbackMove)

        def callbackstream(in_data, frame_count, time_info, status):
            self.sem.acquire()
            data = self.wf.readframes(frame_count)
            self.parent.event_generate("<<playbackmove>>", when="now")
            self.sem.release()
            return (data, pyaudio.paContinue)

        self._callbackstream = callbackstream

    def updateinfo(self, event, *args):
        caller = event.widget
        if str(caller) == '.!entry2':
            self.info.set(getattr(features, self.featurename.get()).__doc__)

    def applyfunction(self):
        values = getattr(libod, self.funcname.get())(self.filelocation.get())
        if len(values) == 0:
            self.info.set("No detections")
        else:
            self.labeldict[len(self.labeldict)] = self.funcname.get()
            var = IntVar()
            var.set(1)
            self.show.append(var)
            self.timeValues.append([i * 44100 for i in values])
            self.drawAllStamps()

    def set_directory(self):
        directory = tkFileDialog.askdirectory() + '/'
        self.file_opt['initialdir'] = directory

    def release_stamp(self, event=None):
        self.stamp = -1
        self.info.set("Cursor")

    def discard_last(self,
                     event=None
                     ):  # discard last annotation for current sound. button: X
        self.mainplot.lines.pop()
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)
        self.timeValues[self.stampHistory[-1]].pop()
        self.stampHistory.pop()

    def discard(self):  # discard all annotations
        self.timeValues = []
        if (self.DLabels.get() == True or self.ALoad.get() == True):
            self.labeldict = {}
            self.show = []
        else:
            for i in range(len(self.labeldict)):
                self.timeValues.append([])
        self.stamp = -1
        self.stampHistory = []
        self.mag = []
        self.phase = []
        self.hopsizes = []
        self.calculated_features_dict = {}
        self.calculated_features = []
        self.calculated_featuresParams = {}

        self.currentplot = 0

    def label(self, event):
        self.info.set(self.labeldict[int(event.char) - 1] + " is selected")
        self.stamp = int(event.char) - 1

    def addlabel(self):
        self.labeldict[len(self.labeldict)] = self.newlabel_entry.get()
        var = IntVar()
        var.set(1)
        self.show.append(var)
        self.parent.bind("%d" % len(self.labeldict), self.label)
        self.timeValues.append([])

    def deselect(self):
        for cb in self.checkbuttons:
            cb.deselect()

    def addlabel_gui(self):
        frame_addlabel = Toplevel(master=self.parent)
        frame_addlabel.geometry(
            "%dx%d%+d%+d" % (400, 100 + 33 * len(self.labeldict), 200, 200))
        frame_addlabel.title("Add Labels")
        self.newlabel_entry = Entry(frame_addlabel)
        self.newlabel_entry.grid(row=0, column=0)
        labels_text = "Current Labels:"
        w = Message(frame_addlabel, text=labels_text, width=150)
        w.grid(row=1, column=0)

        labels_text = "Display?"
        w = Message(frame_addlabel, text=labels_text, width=150)
        w.grid(row=1, column=1)

        self.checkbuttons = []
        for i in range(len(self.labeldict)):
            labels_text = '%d' % (i + 1) + '. ' + self.labeldict[i]
            w = Message(frame_addlabel, text=labels_text, width=150)
            w.grid(row=i + 2, column=0)
            check = Checkbutton(master=frame_addlabel,
                                text="",
                                variable=self.show[i],
                                onvalue=1,
                                offvalue=0)
            check.grid(row=i + 2, column=1, sticky=W)
            self.checkbuttons.append(check)

        addbutton = Button(frame_addlabel, text="Add", command=self.addlabel)
        addbutton.grid(row=0, column=1, sticky=W)

        togglebutton = Button(frame_addlabel,
                              text="Deselect",
                              command=self.deselect)
        togglebutton.grid(row=1, column=2, sticky=W)

    def quit(self):
        try:
            self.stream.close()
            self.wf.close()
            self.p.terminate()
        except:
            print("no audio init")
        finally:
            self.parent.destroy()

    def initStream(self):
        self.stream = self.p.open(format=8,
                                  channels=1,
                                  rate=44100,
                                  output=True,
                                  stream_callback=self._callbackstream,
                                  start=True,
                                  frames_per_buffer=self.chunk_size)

    def playsound(self, event=None):
        if self.sem.locked():
            return
        if self.play_mode.get() == True:
            try:
                self.playbutton.config(text="Play")
                self.stream.close()
                self.stream.close()
                self.play_mode.set(False)
            except:
                print("stop failed")
        else:
            try:
                self.initStream()
                self.play_mode.set(True)
                self.playbutton.config(text="Stop")
            except:
                print("stop failed")

    def playbackMove(self, event=None):  # move cursor by audio chunk size
        incr = (self.chunk_size) // self.hopsizes[self.currentplot]
        self.cursor.set_xdata(self.cursor.get_xdata() + incr)
        self.updateCursor()

    def new_release_zoom(self, *args, **kwargs):
        self.release_zoom_orig(*args, **kwargs)
        s = 'toolbar_event'
        event = Event(s, self)
        self.canvas.callbacks.process(s, Event('toolbar_event', self))

    def new_release_pan(self, *args, **kwargs):
        self.release_pan_orig(*args, **kwargs)
        s = 'toolbar_event'
        event = Event(s, self)
        self.canvas.callbacks.process(s, Event('toolbar_event', self))

    def new_update_view(self, *args, **kwargs):
        self._update_view_orig(*args, **kwargs)
        s = 'toolbar_event'
        event = Event(s, self)
        self.canvas.callbacks.process(s, Event('toolbar_event', self))

    def handle_toolbar(self, event):
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)

    def onclick(self, event):
        if (self.toolbar._active == 'ZOOM' or self.toolbar._active == 'PAN'):
            pass

        elif (self.stamp > -1):
            self.stampHistory.append(self.stamp)
            self.timeValues[self.stamp].append(event.xdata *
                                               self.hopsizes[self.currentplot])
            self.mainplot.draw_artist(
                self.mainplot.axvline(x=event.xdata,
                                      color=self.colors[self.stamp]))
            self.canvas.draw()
            self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)
            self.info.set("Cursor")
            self.stamp = -1
        else:
            self.cursor.set_xdata(event.xdata)
            self.wf.setpos(int(event.xdata * self.hopsizes[self.currentplot]))
            self.updateCursor()

    def updateCursor(self):
        self.canvas.restore_region(self.background)
        self.mainplot.draw_artist(self.cursor)
        self.canvas.blit(self.mainplot.bbox)

    def browse_file(self):
        self.filename = os.path.basename(
            tkFileDialog.askopenfilename(**self.file_opt))
        self.filelocation.delete(0, END)
        self.filelocation.insert(0,
                                 self.file_opt['initialdir'] + self.filename)

    def changeparams(self, *args):
        self.featureParamsEntry.delete(0, END)
        try:
            self.featureParamsEntry.insert(
                0, str(self.defaultParams[self.featurename.get()]))
        except:
            self.featureParamsEntry.insert(0, "()")
            print("No default params for selected feature")

    def showfeature(self):
        self.mainplot.clear()
        featureName = self.featurename.get()
        featureParams = eval(self.featureParamsEntry.get())
        if featureName in self.calculated_features_dict and self.calculated_featuresParams[
                featureName] != featureParams:
            # if a feature is calculated before and params are the same; plot the saved result
            self.currentplot = self.calculated_features_dict[featureName]
            if len(self.calculated_features[self.currentplot].shape) == 2:
                ylim = 5000
                binToFreq = np.arange(0, ylim, 43.066)  # Fs/N
                self.mainplot.pcolormesh(
                    np.arange(
                        self.calculated_features[self.currentplot].shape[0]),
                    binToFreq, self.calculated_features[
                        self.currentplot].T[:binToFreq.size, :])
            else:
                self.mainplot.plot(self.calculated_features[self.currentplot])
            self.canvas.draw()
            self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)
            hopSize = self.hopsizes[self.calculated_features_dict[featureName]]
        else:
            self.currentplot = len(self.calculated_features)
            self.calculated_features_dict[featureName] = self.currentplot
            result, hopSize = getattr(features, featureName)(self.audio,
                                                             featureParams)
            if len(result.shape) == 2:
                ylim = 5000
                binToFreq = np.arange(0, ylim, 43.066)  # Fs/N
                self.mainplot.pcolormesh(np.arange(result.shape[0]), binToFreq,
                                         result.T[:binToFreq.size, :])
            else:
                self.mainplot.plot(result)
            self.canvas.draw()
            self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)
            self.calculated_features.append(result)
            self.hopsizes.append(hopSize)
            self.calculated_featuresParams[featureName] = featureParams
        self.drawAllStamps()

    def sendbelow(self):
        self.secplot.clear()
        if len(self.calculated_features[self.currentplot].shape) == 2:
            ylim = 5000
            binToFreq = np.arange(0, ylim, 43.066)  # Fs/N
            self.secplot.pcolormesh(
                np.arange(self.calculated_features[self.currentplot].shape[0]),
                binToFreq, self.calculated_features[
                    self.currentplot].T[:binToFreq.size, :])
        else:
            self.secplot.plot(self.calculated_features[self.currentplot])
            self.canvas.draw()

    def plot(self):
        self.discard()
        inputFile = self.filelocation.get()
        self.wf = wave.open(inputFile, 'rb')
        self.featurename.set("Audio")
        self.audio = MonoLoader(filename=inputFile, sampleRate=44100)()
        self.showfeature()
        self.cursor.set_xdata(0)
        self.canvaswidget.focus_set()
        if (self.ALoad.get() == 1):
            self.loadAnnotations()

    def saveAnnotations(self):
        directory = self.file_opt[
            'initialdir'] + "Annotations/" + self.filename.split('.')[
                0]  # deleting .wav
        if not os.path.exists(directory):
            os.makedirs(directory)
        for i in self.labeldict:
            with open(directory + '/%s.txt' % self.labeldict[i],
                      'w') as filehandle:
                json.dump(self.timeValues[i], filehandle)

    def loadAnnotations(self):
        directory = self.file_opt[
            'initialdir'] + "Annotations/" + self.filename.split('.')[0] + "/"
        if not os.path.exists(directory):
            print("No annotations")
        else:
            for x in sorted(os.listdir(directory)):
                with open(directory + x, 'r') as filehandle:
                    values = json.load(filehandle)
                    if self.isTime.get() == 1:
                        values = [v * 44100 for v in values]
                    self.labeldict[len(self.labeldict)] = x.split('.')[0]
                    var = IntVar()
                    var.set(1)
                    self.show.append(var)
                    self.timeValues.append(values)

    def getNext(self):
        self.discard()
        fileList = sorted(os.listdir(self.file_opt['initialdir']))
        nextIndex = fileList.index(self.filename) + 1
        if nextIndex == 0 or nextIndex == len(fileList):
            print("No more files")
        else:
            self.filename = fileList[nextIndex]
            self.filelocation.delete(0, END)
            self.filelocation.insert(
                0, self.file_opt['initialdir'] + fileList[nextIndex])
        self.plot()

    def drawAllStamps(self):
        hs = self.hopsizes[self.currentplot]
        try:
            del self.mainplot.lines[1:]
        except:
            pass
        for i in self.labeldict:
            if self.show[i].get() == 1:
                for j in self.timeValues[i]:
                    self.mainplot.draw_artist(
                        self.mainplot.axvline(x=j // hs, color=self.colors[i]))
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.mainplot.bbox)

    def saveAndNext(self):
        self.saveAnnotations()
        self.getNext()
        self.plot()
class App(Tk):
    def __init__(self):
        Tk.__init__(self)
        self.title("Baja GUI")
        
        self.grid()
        cw = 1   # cell width
        ch = 2
        
        cr = self.winfo_screenwidth() / 32
        
        print(self.winfo_screenheight())
        print(self.winfo_screenwidth())
        
        # Root level frames
        self.controlFrame = Frame(self, bg='grey', borderwidth=0, width=self.winfo_screenwidth(), height=(self.winfo_screenheight()/4))
        self.displayFrame = Frame(self, bg='grey', borderwidth=0)
        # Serial Control Frame
        self.serialFrame = Frame(self.controlFrame, borderwidth=0)  
        
        self.COMPort = StringVar()
        self.COMPortTextBox = Entry(self.serialFrame, textvariable = self.COMPort)
        self.COMPort.set('/dev/ttyUSB0')
        self.COMBaud = StringVar()
        self.COMBaudTextBox = Entry(self.serialFrame, textvariable = self.COMBaud)
        self.COMBaud.set('9600')
        self.COMButton = Button(self.serialFrame, text = "Start Serial", command = self.StartSerial)
        
        self.SerialSendButton = Button(self.serialFrame, text = "Send to Board", command = self.SendToSerial)
        self.SerialSendToDriverButton = Button(self.serialFrame, text = "Send to Driver", command = self.SendToDriver)
        self.SerialSendTextBox = Entry(self.serialFrame)

        

        # Extra Buttons
        self.SerialStopButton = Button(self.serialFrame, text = "Stop Serial", command = self.StopSerial)
        self.comeBackToPitNowButton = Button(self.controlFrame, text = "Pit Now", command = self.PitNow)
        self.comeBackToPitNextLapButton = Button(self.controlFrame, text = "Pit Next Lap", command = self.PitNextLap)

        # Informative Things
        self.dataBarFrame = Frame(self.controlFrame)
        
        self.numActiveThreads = StringVar()
        self.numThreadsLabel = Label(self.dataBarFrame, textvariable = self.numActiveThreads)
        self.numActiveThreads.set('Threads\n' + str(threading.enumerate().__len__()))
        self.numThreadsLabel.grid(column = 0, row = 0)
        
        
        self.counter = StringVar()
        self.counterLabel = Label(self.dataBarFrame, textvariable = self.counter)
        self.counter.set('Counter\n' + 'N/A')
        self.counterLabel.grid(column = 1, row = 0)
        
        self.gpsDate = StringVar()
        self.gpsDateLabel = Label(self.dataBarFrame, textvariable = self.gpsDate)
        self.gpsDate.set('Date\n' + '010100')
        self.gpsDateLabel.grid(column = 2, row = 0)
        
        self.gpsTime = StringVar()
        self.gpsTimeLabel = Label(self.dataBarFrame, textvariable = self.gpsTime)
        self.gpsTime.set('Time\n' + '00000000')
        self.gpsTimeLabel.grid(column = 3, row = 0)
        
        self.numSats = StringVar()
        self.numSatsLabel = Label(self.dataBarFrame, textvariable = self.numSats)
        self.numSats.set('Sats\n' + 'NSA')
        self.numSatsLabel.grid(column = 4, row = 0)

        self.currentLatitude = StringVar()
        self.latitudeLabel = Label(self.dataBarFrame, textvariable = self.currentLatitude)
        self.currentLatitude.set("Latitude\n" + 'Unknown')
        self.latitudeLabel.grid(column = 5, row = 0)
        
        
        self.currentLongitude = StringVar()
        self.longitudeLabel = Label(self.dataBarFrame, textvariable = self.currentLongitude)
        self.currentLongitude.set("Longitude\n" + 'Unknown')
        self.longitudeLabel.grid(column = 6, row = 0)
        
        
        self.currentSpeed = StringVar()
        self.speedLabel = Label(self.dataBarFrame, textvariable=self.currentSpeed)
        self.currentSpeed.set("Speed\n" + "86")
        self.speedLabel.grid(column = 7, row = 0)
        
        self.currentDashTemp = StringVar()
        self.dashTempLabel = Label(self.dataBarFrame, textvariable=self.currentDashTemp)
        self.currentDashTemp.set("Dash Temp\n" + "N/A")
        self.dashTempLabel.grid(column = 8, row = 0)
        
        self.batteryVoltage = StringVar()
        self.batteryVoltageLabel = Label(self.dataBarFrame, textvariable = self.batteryVoltage)
        self.batteryVoltage.set("BATT\n" + "N/A")
        self.batteryVoltageLabel.grid(column = 9, row = 0)
        
        
        self.xbeeSignalStrength = StringVar()
        self.xbeeSignalStrengthLabel = Label(self.dataBarFrame, textvariable = self.xbeeSignalStrength)
        self.xbeeSignalStrength.set("XBee\n" + "N/A")
        self.xbeeSignalStrengthLabel.grid(column = 10, row = 0)
        
        self.currentFrontBrakeAvg = StringVar()
        self.frontBrakeAvgLabel = Label(self.dataBarFrame, textvariable = self.currentFrontBrakeAvg)
        self.currentFrontBrakeAvg.set("Front Brake Avg\n" + "N/A")
        self.frontBrakeAvgLabel.grid(column = 11, row = 0)
        
        self.currentFrontBrakeMax = StringVar()
        self.frontBrakeMaxLabel = Label(self.dataBarFrame, textvariable = self.currentFrontBrakeMax)
        self.currentFrontBrakeMax.set("Front Brake Max\n" + "N/A")
        self.frontBrakeMaxLabel.grid(column = 12, row = 0)
        
        self.currentRearBrakeAvg = StringVar()
        self.rearBrakeAvgLabel = Label(self.dataBarFrame, textvariable = self.currentRearBrakeAvg)
        self.currentRearBrakeAvg.set("Rear Brake Avg\n" + "N/A")
        self.rearBrakeAvgLabel.grid(column = 13, row = 0)
        
        self.currentRearBrakeMax = StringVar()
        self.rearBrakeMaxLabel = Label(self.dataBarFrame, textvariable = self.currentRearBrakeMax)
        self.currentRearBrakeMax.set("Rear Brake Max\n" + "N/A")
        self.rearBrakeMaxLabel.grid(column = 14, row = 0)
        

        self.currentSteeringAvg = StringVar()
        self.steeringAvgLabel = Label(self.dataBarFrame, textvariable = self.currentSteeringAvg)
        self.currentSteeringAvg.set("Steering\n" + "Yes")
        self.steeringAvgLabel.grid(column = 15, row = 0)
        
        self.buttonPressed = StringVar()
        self.buttonPressedLabel = Label(self.dataBarFrame, textvariable = self.buttonPressed, borderwidth = 1)
        self.buttonPressed.set("Button\n" + "No")
        self.buttonPressedLabel.grid(column = 16, row = 0)
        
        
        self.currentPrimaryRPM = StringVar()
        self.currentSecondaryRPM = StringVar()
        
        # Accelerometer
        self.accX = [0]
        self.maxX = [0]
        self.accY = [0]
        self.maxY = [0]
        self.accZ = [0]
        self.maxZ = [0]
        
        # 
        self.rearTemp = [0]

        
        

        self.listbox = Listbox(self.controlFrame)
        
        # Set to full screen
        self.attributes('-fullscreen', True)
        
        # Bind <Return> Keypress to text boxes
        self.SerialSendTextBox.bind("<Return>", self.SendOnReturn)
        self.COMBaudTextBox.bind("<Return>", self.StartSerialOnReturn)
        
        # Pack Serial Controls into Serial Frame
        self.SerialSendTextBox.grid(column = 0, row=0, sticky=EW)
        self.SerialSendButton.grid(column = 2, row=0)
        self.SerialSendToDriverButton.grid(column = 3, row = 0)
        self.COMPortTextBox.grid(column = 4, row=0, sticky = E)
        self.COMBaudTextBox.grid(column=6, row=0, sticky = E)
        self.COMButton.grid(column = 8, row=0, sticky = NE)
        self.SerialStopButton.grid(row = 0, column = 9, sticky=NE)
        
        # Pack Control Widgets into Control Frame
        self.serialFrame.grid(row = 0, column=0, columnspan=12, sticky=EW)
        
        
        self.comeBackToPitNowButton.grid(row=0, column=10, sticky=NSEW)
        self.comeBackToPitNextLapButton.grid(row=1, column=10, sticky=NSEW)

        self.dataBarFrame.grid(row = 1, column = 0, columnspan = 10, sticky = EW)
        
        self.listbox.grid(row = 2, column = 0, columnspan=10, sticky = EW)
        
        # Pack Control Frame into root
        self.controlFrame.grid(row = 0, sticky=EW)
        
        
        # Top Level Display Frames
        self.leftDisplayFrame = Frame(self.displayFrame, bg='grey', borderwidth=0, width=(self.winfo_screenwidth()/2))
        self.rightDisplayFrame = Frame(self.displayFrame, bg='grey', borderwidth=0, width=(self.winfo_screenwidth()/2))
        
        # Inside Left Display Frames
        self.topLeftDisplayFrame = Frame(self.leftDisplayFrame, bg='grey', borderwidth=0, height=(self.winfo_screenheight()/4))
        self.middleLeftDisplayFrame = Frame(self.leftDisplayFrame, bg='grey', borderwidth=0, height=(self.winfo_screenheight()/4))
        self.bottomLeftDisplayFrame = Frame(self.leftDisplayFrame, bg='grey', borderwidth=0, height=(self.winfo_screenheight()/4))
        
        # Inside Top Left Display Frames
        
        # Inside Middle Left Display Frames
        self.brakeFrame = Frame(self.middleLeftDisplayFrame, borderwidth=0)
        
        # Inside Bottom Left Display Frames
        self.driveTrainTempFrame = Frame(self.bottomLeftDisplayFrame, borderwidth=0)
        self.driveTrainRPMFrame = Frame(self.bottomLeftDisplayFrame, borderwidth=0)
        
        # Inside Rigt Display Frames
        self.shieldTempFrame = Frame(self.rightDisplayFrame, borderwidth=0, bg='grey', height=(self.winfo_screenheight()/8))
        self.shieldHealthFrame = Frame(self.rightDisplayFrame, borderwidth=0, bg='grey')
        
        # Construct Items for Display Frame
        self.gpsFigure, self.gpsAxes = plt.subplots(figsize=(2*ch,2*ch), dpi=cr*2)
        self.speedFigure, self.speedAxes = plt.subplots(figsize=(2*ch,2*ch), dpi=cr)

        
        self.rpmFigure, self.rpmAxes = plt.subplots(figsize=(ch,ch), dpi=cr)
        self.dashTempFigure, self.dashTempAxes = plt.subplots(figsize=(2*ch,ch), dpi=cr)
        self.rearTempFigure, self.rearTempAxes = plt.subplots(figsize=(2*ch,ch), dpi=cr)
        self.gearTempFigure, self.gearTempAxes = plt.subplots(figsize=(2*ch,ch), dpi=cr)
        self.cvtTempFigure, self.cvtTempAxes = plt.subplots(figsize=(2*ch,ch), dpi=cr)
        self.battFigure, self.battAxes = plt.subplots(figsize=(ch,ch), dpi=cr)
        self.frontBrakeFigure, self.frontBrakeAxes = plt.subplots(figsize=(2*ch,ch), dpi=cr)
        self.rearBrakeFigure, self.rearBrakeAxes = plt.subplots(figsize=(2*ch,ch), dpi=cr)
        self.steeringFigure, self.steeringAxes = plt.subplots(figsize=(ch,2*ch), dpi=cr)
        self.buttonFigure, self.buttonGraph = plt.subplots(figsize=(ch,ch), dpi=cr)
        self.accFigure, self.accAxes = plt.subplots(figsize=(2*ch,2*ch), dpi=cr)
        self.zFigure, self.zAxes = plt.subplots(figsize=(ch, 2*ch), dpi=cr)
        
        
        # GPS Axes Setup
        self.gpsFigure.patch.set_visible(False)
        self.gpsAxes.set_title('GPS')
        #self.gpsAxes.set_xlim(-110.953,-110.952)
        self.gpsAxes.set_xlim(-118823207 - 3000,-118823207 + 3000)
        self.gpsAxes.set_ylim(34749085 - 3000,34749085 + 3000)
        self.gpsAxes.hold(True)
        
        self.gpsCanvas = FigureCanvasTkAgg(self.gpsFigure, master=self.rightDisplayFrame)
        self.gpsCanvas.show()
        
        
        
        
        
        # speed Axes Setup
        self.speedFigure.patch.set_visible(False)
        self.speedAxes.set_title('Speed')
        self.speedAxes.set_xlim(0,100)
        self.speedAxes.set_ylim(0,50)
        self.speedAxes.hold(True)
        
        self.speedCanvas = FigureCanvasTkAgg(self.speedFigure, master=self.topLeftDisplayFrame)
        self.speedCanvas.show()

        # Speed Textbox Setup

        
        # Dash Temperature Axes Setup
        self.dashTempFigure.patch.set_visible(False)
        self.dashTempAxes.set_title('Dash Temperature')
#        self.ten_wide = [0,1,2,3,4,5,6,7,8,9]
        self.dashTempAxes.set_xlim(0,100)
#        self.dashTempAxes.autoscale(enable=True, axis='x')
        self.dashTempAxes.set_ylim(0,100)
        self.dashTempAxes.hold(True)
        
        self.dashTempCanvas = FigureCanvasTkAgg(self.dashTempFigure, master=self.shieldTempFrame)
        self.dashTempCanvas.show()
#        self.dashTempCanvas.draw()

        
        
        # Rear Temperature Axes Setup
        self.rearTempFigure.patch.set_visible(False)
        self.rearTempAxes.set_title('Rear Temperature')
        self.rearTempAxes.set_xlim(0,500)
        self.rearTempAxes.set_ylim(0,100)
        self.rearTempAxes.hold(True)
        
        self.rearTempCanvas = FigureCanvasTkAgg(self.rearTempFigure, master=self.shieldTempFrame)
        self.rearTempCanvas.show()
#        
        
        
        # Gearbox Temperature Axes Setup
        self.gearTempFigure.patch.set_visible(False)
        self.gearTempAxes.set_title('Gearbox Temperature')
        self.gearTempAxes.set_xlim(0,500)
        self.gearTempAxes.set_ylim(0,100)
        self.gearTempAxes.hold(True)
        
        self.gearTempCanvas = FigureCanvasTkAgg(self.gearTempFigure, master=self.driveTrainTempFrame)
        self.gearTempCanvas.show()
#        
        
        
        # CVT Temperature Axes Setup
        self.cvtTempAxes.set_title('CVT Temperature')
        self.cvtTempAxes.set_xlim(0,500)
        self.cvtTempAxes.set_ylim(0,100)
        self.cvtTempAxes.hold(True)
        
        self.cvtTempCanvas = FigureCanvasTkAgg(self.cvtTempFigure, master=self.driveTrainTempFrame)
        self.cvtTempCanvas.show()
#        
        
        
        # Acceleration Axes Setup
        self.accFigure.patch.set_visible(False)
        self.accAxes.set_title('Acceleration 2-D')
        self.accAxes.set_xlim(-2, 2)
        self.accAxes.set_ylim(-2, 2)
        self.accAxes.hold(True)
        
        self.accCanvas = FigureCanvasTkAgg(self.accFigure, master=self.middleLeftDisplayFrame)
        self.accCanvas.show()
        
        self.zFigure.patch.set_visible(False)
        self.zAxes.set_title('Z-Acc')
        self.zAxes.set_xlim(-2, 2)
        self.zAxes.set_ylim(-2, 2)
        self.zAxes.hold(True)
        
        self.zCanvas = FigureCanvasTkAgg(self.zFigure, master=self.topLeftDisplayFrame)
        self.zCanvas.show()
        
        
        self.steeringFigure.patch.set_visible(False)
        self.steeringAxes.set_title('Steering')
        self.steeringAxes.set_xlim(-2, 2)
        self.steeringAxes.set_ylim(-2, 2)
        self.steeringAxes.hold(True)
        
        self.steeringCanvas = FigureCanvasTkAgg(self.steeringFigure, master=self.topLeftDisplayFrame)
        self.steeringCanvas.show()
        
        # Front Brake Axes Setup
        self.frontBrakeFigure.patch.set_visible(False)
        self.frontBrakeAxes.set_title('Front Brake Pressure')
        self.frontBrakeAxes.set_xlim(0,500)
        self.frontBrakeAxes.set_ylim(0,100)
        self.frontBrakeAxes.hold(True)
        
        self.frontBrakeCanvas = FigureCanvasTkAgg(self.frontBrakeFigure, master=self.brakeFrame)
        self.frontBrakeCanvas.show()
        
        # Rear Brake Axes Setup
        self.rearBrakeFigure.patch.set_visible(False)
        self.rearBrakeAxes.set_title('Rear Brake Pressure')
        self.rearBrakeAxes.set_xlim(0,500)
        self.rearBrakeAxes.set_ylim(0,100)
        self.rearBrakeAxes.hold(True)
        
        self.rearBrakeCanvas = FigureCanvasTkAgg(self.rearBrakeFigure, master=self.brakeFrame)
        self.rearBrakeCanvas.show()
        
        # Layout
        # Pack Brake Pressure
        self.frontBrakeCanvas.get_tk_widget().grid(column = 0, row=0, sticky=N)
#        self.frontBrakeCanvas._tkcanvas.grid(column=0, row=0, sticky=N)
        self.rearBrakeCanvas.get_tk_widget().grid(column=0, row=1, sticky=S)
#        self.rearBrakeCanvas._tkcanvas.grid(column=0, row=1, sticky=S)
        
        # Pack Drive Train RPM
        
        # Pack Drive Train Temp
        self.gearTempCanvas.get_tk_widget().grid(column = 0, row=0, sticky=W)
#        self.gearTempCanvas._tkcanvas.grid(column=0, row=0, sticky=W)
        self.cvtTempCanvas.get_tk_widget().grid(column=1, row=0, sticky=E)
#        self.cvtTempCanvas._tkcanvas.grid(column=1, row=0, sticky=E)
        
        # Pack stuff into top left
#        self.speedTextBox.grid(column=1, row=0, sticky=NSEW)
        self.zCanvas.get_tk_widget().grid(column=0, row=0, sticky=NSEW)
        self.steeringCanvas.get_tk_widget().grid(column=1, row=0, sticky=NSEW)
        self.speedCanvas.get_tk_widget().grid(column=2, row=0 , sticky=NSEW)
#        self.speedCanvas._tkcanvas.grid(column=2 , row=0 , sticky=NSEW)
        
        # Pack stuff into middle left
        self.accCanvas.get_tk_widget().grid(column=0 , row=1 , sticky=W  )
#        self.accCanvas._tkcanvas.grid(column=0 , row=1 , sticky=W  )
        self.brakeFrame.grid(column=1 , row=1 , sticky=E)
        
        # Pack stuff into bottom left
        self.driveTrainTempFrame.grid(column=0 , row=5 , sticky=N  )
        self.driveTrainRPMFrame.grid(column=0 , row=6 , sticky=S  )
        
        
        # Pack Left Display
        self.topLeftDisplayFrame.grid(column=0 , row=2 , sticky=NSEW  )
        self.middleLeftDisplayFrame.grid(column=0 , row=4 , sticky=NSEW  )
        self.bottomLeftDisplayFrame.grid(column=0 , row=6 , sticky=NSEW  )
        
        
        # Pack Shield Temp
        self.dashTempCanvas.get_tk_widget().grid(column=0 , row=5   )
#        self.dashTempCanvas._tkcanvas.grid(column=0 , row=5 , sticky=W  )
        self.rearTempCanvas.get_tk_widget().grid(column=1 , row=5   )
#        self.rearTempCanvas._tkcanvas.grid(column=1 , row=5 , sticky=E  )
        
        # Pack Shield Health
        
        # Pack stuff inside right display
        self.gpsCanvas.get_tk_widget().grid(column=4 , row=2 , sticky=NSEW  )
#        self.gpsCanvas._tkcanvas.grid(column=4 , row=2 , sticky=NSEW  )
        self.shieldTempFrame.grid(column=4 , row=5 , sticky=N  )
        self.shieldHealthFrame.grid(column=4 , row=6 , sticky=N  )
            # TODO: Button Press notification goes here...
        
        
        # Pack Display Frame
        self.leftDisplayFrame.grid(column=0 , row=3 , sticky=NS  )
        self.rightDisplayFrame.grid(column=5 , row=3 , sticky=NS  )
        
        # Pack Display Into Root
        self.displayFrame.grid(column=0 , row=2 , sticky=NSEW  )
        
        
    # Initialize Data Variables
        
        # Dash Data
#        self.counter.set(0) # Commented to preserve initial text value, left here to preserve variable order/index
#        self.gpsDate = 0
#        self.gpsTime = 0
#        self.numSats = 0
        self.latitude = [32236562]
        self.longitude = [-110952322]
        self.speed = [0]*102
        self.dashTemp = [0]*102
#        self.batteryVoltage = 0
#        self.xbeeSignalStrength = 0
        self.frontBrakeAvg = [0]
        self.frontBrakeMax = [0]
        self.rearBrakeAvg = [0]
        self.rearBrakeMax = [0]
        self.steeringAvg = [0]
#        self.buttonPressed = 0
        
        # Rear Board Data
        self.primaryRPM = 0
        self.secondaryRPM = 0
        
        
        # Accelerometer
        self.accX = [0]
        self.maxX = [0]
        self.accY = [0]
        self.maxY = [0]
        self.accZ = [0]
        self.maxZ = [0]
        
        # 
        self.rearTemp = [0]

        


        
        self.hundred_array = list(range(0,102))
        
        self.gpsBackground = self.gpsCanvas.copy_from_bbox(self.gpsAxes.bbox)
        self.speedBackground = self.speedCanvas.copy_from_bbox(self.speedAxes.bbox)
        self.dashTempBackground = self.dashTempCanvas.copy_from_bbox(self.dashTempAxes.bbox)
        
        self.gpsPlot = self.gpsAxes.plot(self.longitude, self.latitude, '-')[0]
        self.speedPlot = self.speedAxes.plot(self.hundred_array,self.speed)[0]
        self.dashTempPlot = self.dashTempAxes.plot(self.hundred_array, self.dashTemp)[0]
        
        
        # Create Queues for talking to serial line asyncronously
        self.rx = queue.Queue()
        self.tx = queue.Queue()
        
        


    def StartSerial(self):
        self.listbox.insert(0, "Baud Rate: " + self.COMBaud.get())
        self.listbox.insert(0, "COM Port: " + self.COMPort.get())
        self.numActiveThreads.set('Threads\n' + str(threading.enumerate().__len__()))
        if (threading.enumerate().__len__()!=1):
            self.serialThread.join()
        #print(threading.enumerate().__len__())
        self.numActiveThreads.set('Threads\n' + str(threading.enumerate().__len__()))
        self.serialThread = SerialThread(self.COMPort, self.COMBaud, self.rx, self.tx)
        
        self.serialThread.start()
        self.numActiveThreads.set('Threads\n' + str(threading.enumerate().__len__()))
        self.process_serial()


    def StopSerial(self):
        self.listbox.insert(0, "Serial Stopped")
        if (threading.enumerate().__len__()!=1):
            self.serialThread.join()
        self.numActiveThreads.set('Threads\n' + str(threading.enumerate().__len__()))
        
    def PitNow(self):
        self.listbox.insert(0, "Pit Now")
        self.tx.put("<PIT NOW>\n")

    def PitNextLap(self):
        self.listbox.insert(0, "Pit Next Lap")
        self.tx.put("<PIT NEXT LAP>\n")


    def SendOnReturn(self, event):
        self.SendToSerial()

    def StartSerialOnReturn(self, event):
        self.StartSerial()

    def SendToSerial(self):
        text_contents = self.SerialSendTextBox.get()
        self.listbox.insert(0, text_contents)
        self.tx.put(text_contents)
        self.SerialSendTextBox.delete(0,END)

    def SendToDriver(self):
        text_contents = self.SerialSendTextBox.get()
        self.listbox.insert(0, text_contents)
        self.tx.put('<')
        self.tx.put(text_contents)
        self.tx.put('>')
        self.SerialSendTextBox.delete(0,END)


    def process_serial(self):
        text = StringVar()
        if self.rx.qsize():
#            self.listbox.delete(0,END)
            try:
                dataString = self.rx.get()
                
            except Queue.Empty:
                pass
                
            self.listbox.insert(0, dataString)
            data = dataString.split(bytes(', ','UTF-8'))
            print(data.__len__())
            if(data.__len__()==18 or data.__len__()==28):
                try:
                    i = 0
                    # Dash Data
                    self.counter.set('Counter\n' + str(int(data[0])))
                    i = 1
                    self.gpsDate.set('Date\n' + str(int(data[1])))
                    i = 2
                    self.gpsTime.set('Time\n' + str(int(data[2])))
                    i = 3
                    self.numSats.set('Sats\n' + str(int(data[3])))
                    if (float(data[4])/1000000 < 100 and float(data[5])/1000000 < 200):
                        i = 4
                        self.latitude.append(int(data[4]))
                        self.currentLatitude.set('Latitude\n' + str(int(data[4])))
                        i = 5
                        self.longitude.append(int(data[5]))
                        self.currentLongitude.set('Longitude\n' + str(int(data[5])))
                    i = 6
                    self.speed.append(float(data[6]))
                    self.currentSpeed.set('Speed\n' + str(float(data[6])))
                    self.currentSpeed.set('Speed\n' + str(float(data[6])))
                    i = 7
                    self.dashTemp.append(float(data[7]))
                    self.currentDashTemp.set('Dash Temp\n' + str(float(data[7])) + 'C')
                    i = 8
                    self.batteryVoltage.set('Batt\n' + str(int(data[8])))
                    i = 9
                    self.xbeeSignalStrength.set('XBee\n' + str(int(data[9])))
                    i = 10
                    self.frontBrakeAvg.append(float(data[10]))
                    i = 11
                    self.frontBrakeMax.append(int(data[11]))
                    i = 12
                    self.rearBrakeAvg.append(float(data[12]))
                    i = 13
                    self.rearBrakeMax.append(int(data[13]))
                    i = 14
                    self.steeringAvg.append(float(data[14]))
                    i = 15
    #                    self.buttonPressed = int(data[15])
                    i = 16
    #                    
    #                    # Rear Board Data
    #                    self.primaryRPM = 0
    #                    self.secondaryRPM = 0
    #                    
    #                    
    #                    # Accelerometer
    #                    self.accX = [0]
    #                    self.maxX = [0]
    #                    self.accY = [0]
    #                    self.maxY = [0]
    #                    self.accZ = [0]
    #                    self.maxZ = [0]
    #                    
    #                    # 
    #                    self.rearTemp = [0]
                except:
                    print('Exception Raised!' + str(i))
                    pass
                    
 

                
                self.gpsCanvas.restore_region(self.gpsBackground)
                self.gpsPlot.set_data(self.longitude[1:], self.latitude[1:])
                self.gpsAxes.draw_artist(self.gpsPlot)
                self.gpsCanvas.blit(self.gpsAxes.bbox)
                
                self.speedCanvas.restore_region(self.speedBackground)
                self.speedPlot.set_data(self.hundred_array[-101:], self.speed[-101:])
                self.speedAxes.draw_artist(self.speedPlot)
                self.speedCanvas.blit(self.speedAxes.bbox)
                
                self.dashTempCanvas.restore_region(self.dashTempBackground)
                self.dashTempPlot.set_data(self.hundred_array[-101:], self.dashTemp[-101:])
                self.dashTempAxes.draw_artist(self.dashTempPlot)
                self.dashTempCanvas.blit(self.dashTempAxes.bbox)
                

                
        self.after(100, self.process_serial)
        
    # Graceful Exit
    def destroy(e):
        sys.exit()
Example #7
0
class Root(Widget, Generic[_T]):
    tk_widget: Optional[tk.Frame]
    canvas: Optional[FigureCanvasTkAgg]
    background_img: Optional[FigureImage]

    def __init__(self,
                 params,
                 w: int = 1429,
                 h: int = 799,
                 dpi: int = 141,
                 color: str = '#000000',
                 **kwargs) -> None:
        Widget.__init__(self)

        self.params = params
        self.w = w
        self.h = h
        self.dpi = dpi
        self.face_color = color

        matplotlib_config()

        self.fig: plt.Figure = plt.figure(
            figsize=(self.w / self.dpi, self.h / self.dpi),
            dpi=self.dpi,
            facecolor=self.face_color,
        )

        self.gs = self.fig.add_gridspec(nrows=90,
                                        ncols=160,
                                        left=0,
                                        right=1,
                                        top=1,
                                        bottom=0,
                                        hspace=0,
                                        wspace=0)

        self.properties = kwargs
        self.artists = {}
        self.tk_widget = None
        self.canvas = None
        self.background_img = None
        self._bg = None
        self._initialized = None

        self.__post_init__()

    def for_tk(self, parent: Union[tk.Tk, tk.Frame, tk.Canvas]) -> tk.Canvas:
        self.tk_widget = parent
        self.canvas = FigureCanvasTkAgg(self.fig, master=parent)
        widget = self.canvas.get_tk_widget()
        widget.pack(fill=tk.BOTH, expand=1)
        return widget

    @staticmethod
    def load_img(fp: PATH_LIKE) -> np.array:
        return plt.imread(cbook.get_sample_data(fp))

    @timer
    def save_img(self, fp: PATH_LIKE) -> None:
        self.fig.savefig(fp, transparent=True)

    @timer
    def set_background_from_img(self, img_array: np.array) -> None:
        self.background_img = plt.figimage(img_array)
        self.background_img.set_zorder(-999)

    def update(self, iteration_data: ITERATION_DATA) -> None:
        raise NotImplementedError

    def init(self) -> None:
        self._initialized = self._initialized or self.init_results() or True
        self.reset_results()
        self._bg = self._bg or self.canvas.copy_from_bbox(
            self.canvas.figure.bbox)
        self.draw_artists()

    def draw_artists(self) -> None:
        self.canvas.restore_region(self._bg)
        list(map(self.canvas.figure.draw_artist, self.animated))
        self.canvas.blit(self.canvas.figure.bbox)

    def __call__(self, iteration_data: List[ITERATION_DATA]):
        if hasattr(iteration_data, '__iter__'):
            list(map(self.update, iteration_data))
        else:
            self.update(iteration_data)
        self.draw_artists()

    def _set_background(self) -> None:
        pass

    def populate_from_iteration(self, iteration) -> None:
        raise NotImplementedError

    def _init_results(self) -> None:
        pass

    def set_result(self, *args) -> None:
        pass

    def _reset_results(self) -> None:
        pass
Example #8
0
def add_elements():
    global sa, playing, segment_playing, txt, my_thread, listbox, selection_A, ax1, ax2, bg
    global selection_B, left_select, right_select, max_wpm, x_scale, words_inwin
    global words_inwin, left_sel, audiopos, zoom_in, constructed
    global time_axis, fig, fig2, canvas, canvas2, step_width, stream

    constructed = True

    #audioname = 'semi_files//data//grav1.wav'
    #textname = 'semi_files//data//grav1.txt'
    tmpfolder = 'semi_files//data//tempalign'
    sa = SegmentAligner(audioname, textname, tmpfolder)
    #%% read all the data
    n_frames = sa.audio.getnframes()
    sr = sa.audio.getframerate()
    time_axis = np.arange(0, n_frames / sr, 1 / sr)

    sa.audio.setpos(sa.audio_sel[0])
    #struct.unpack(str(2*n_frames) + 'B', sa.audio.readframes(n_frames))
    data_all = np.frombuffer(sa.audio.readframes(n_frames), dtype=np.int16)
    sa.audio.setpos(sa.audio_sel[0])

    playing = False
    segment_playing = False
    txt = None
    my_thread = None
    listbox = None
    selection_A = 0
    selection_B = time_axis[-1]
    left_select = False
    right_select = False
    max_wpm = 400  # 200 is realistic
    x_scale = 20
    words_inwin = round(x_scale * (max_wpm / 60))
    step_width = 5
    left_sel = 0
    audiopos = 0
    zoom_in = 1

    #% --- create the figure for the audioplot
    fig = Figure(figsize=(8.5, 1.5), dpi=100,
                 frameon=False)  #means 1 inch = 100 pixels

    gs = fig.add_gridspec(5, 1)
    fig.add_subplot(gs[0:3, 0])

    ax1 = fig.gca()
    ax1.plot(time_axis[0:-1:200],
             data_all[0:-1:200],
             '-',
             color='dimgray',
             lw=0.5)
    ax1.get_yaxis().set_ticks([])
    ax1.set_xlim([0, x_scale])  # this works in audio, if pos> half of time a

    # ax1.text(1, 0,"test",  fontsize = 6, bbox=dict(pad = 0, facecolor='red', lw = 0 ), animated=False)

    # fig.set_tight_layout(True)
    # fig.tight_layout()

    fig.tight_layout(pad=0.01, w_pad=0.01, h_pad=0.01)
    fig.add_subplot(212).plot(time_axis,
                              np.empty((len(time_axis), 1)),
                              color='dimgray',
                              lw=0.2)

    ax2 = fig.gca()
    ax2.get_yaxis().set_ticks([])
    ax2.get_xaxis().set_ticks([])
    ax2.set_ylim([0, 1])
    ax2.set_xlim([0, x_scale])
    canvas = FigureCanvasTkAgg(fig, master=root)

    canvas.draw()
    # canvas.flush_events()
    # lines = ax1.get_lines()
    # for line in lines:
    #     line.set_animated(True)
    #     fig.draw_artist(line)

    canvas.get_tk_widget().place(x=0, y=30, width=850, height=220)

    #% --- create the figure for the labelplot

    # fig2 = Figure(figsize = (8.5,0.5), dpi=100,frameon=False) #means 1 inch = 100 pixels
    # fig2.add_subplot(111).plot(time_axis, np.empty((len(time_axis),1))
    #                            , color = 'dimgray', lw = 0.2)
    # fig2.gca().get_yaxis().set_ticks([])
    # fig2.gca().get_xaxis().set_ticks([])
    # fig2.tight_layout(pad=0.1)
    # fig2.gca().set_ylim([0,1])
    # fig2.gca().set_xlim([0,x_scale]) # this works in audio, if pos> half of time a

    # canvas2 = FigureCanvasTkAgg(fig2, master = root)
    # canvas2.draw()
    # canvas2.get_tk_widget().place(x = 0, y = 180, width=850, height=150)

    # define the audio stream which also updates the xposition
    #frame_count = 1024

    p = pyaudio.PyAudio()

    stream = p.open(format=p.get_format_from_width(sa.audio.getsampwidth()),
                    channels=sa.audio.getnchannels(),
                    rate=sa.audio.getframerate(),
                    output=True,
                    stream_callback=callback,
                    start=False)

    canvas.mpl_connect('button_press_event', onclick)

    align_button = tk.Button(root, text="align", command=align)
    align_button.place(x=850, y=505, width=150, height=25)

    txt_update_button = tk.Button(root, text='update', command=txt_update)
    txt_update_button.place(x=0, y=505, width=50, height=25)

    txt = tk.Text(root,
                  wrap=tk.WORD,
                  bg='grey12',
                  fg='gold',
                  inactiveselectbackground="red",
                  selectbackground='red',
                  insertbackground='red')

    # replace this with a canvas!
    scroll = tk.Scrollbar(txt)
    scroll.pack(side=tk.RIGHT, fill=tk.Y)
    # Configure the scrollbars
    # scroll.config(command=txt.yview)

    txt['yscrollcommand'] = scroll.set

    txt.place(x=0, y=270, width=850, height=240)

    add_text()

    #text['yscrollcommand'] = scrollbar1.set

    #word_axis = np.arange(1/sr, len(time_axis)-1/sr, len(sa.all_aligned_words))

    #txt.tag_config(word[0], background="yellow", foreground="red")
    #for word in sa.all_aligned_words:
    #print(txt.index('testtag'))
    #print(txt.get("1.0","end" ))
    #print(txt.get("%d.%d" % (1, 3),"%d.%d" % (1, 8)))

    # Creating a Listbox and
    # attaching it to root window
    listbox = tk.Listbox(root, selectmode="extended")

    # Adding Listbox
    listbox.place(x=850, y=30, width=150, height=480)

    # Creating a Scrollbar and
    # attaching it to listbox
    scrollbar = tk.Scrollbar(listbox)

    # Adding Scrollbar to the right
    # side of root window
    scrollbar.pack(side=tk.RIGHT, fill=tk.BOTH)

    fill_listbox()

    # Attaching Listbox to Scrollbar
    # Since we need to have a vertical
    # scroll we use yscrollcommand
    listbox.config(yscrollcommand=scrollbar.set)

    # setting scrollbar command parameter
    # to listbox.yview method its yview because
    # we need to have a vertical view
    scrollbar.config(command=listbox.yview)

    if words_read:
        for ii in range(len(words_read)):
            if (words_read[ii][0] == sa.all_aligned_words[ii][0]) and (
                    words_read[ii][1] == sa.all_aligned_words[ii][1]):
                sa.all_aligned_words[ii] = words_read[ii]
        fill_listbox()
        draw_words()

    bg = canvas.copy_from_bbox(ax1.bbox)
Example #9
0
class basemap(tk.Frame):
    def __init__(self, parent, datPath, navcrs, body, to_gui):
        self.parent = parent
        self.datPath = datPath
        self.navcrs = navcrs
        self.body = body
        self.to_gui = to_gui
        # create tkinter toplevel window to display basemap
        self.basemap_window = tk.Toplevel(self.parent)
        img = tk.PhotoImage(file="../recs/basemap_icon.png")
        self.basemap_window.tk.call("wm", "iconphoto", self.basemap_window._w,
                                    img)
        self.basemap_window.config(bg="#d9d9d9")
        self.basemap_window.title("RAGU - Map Window")
        self.map_display = tk.Frame(self.basemap_window)
        self.map_display.pack(side="bottom", fill="both", expand=1)
        # bind ctrl-q key to basemap_close()
        self.basemap_window.bind("<Control-q>", self.basemap_close)
        # bind x-out to basemap_close()
        self.basemap_window.protocol("WM_DELETE_WINDOW", self.basemap_close)
        self.cmap = tk.StringVar(value="Greys_r")
        self.setup()

    # setup the tkinter window
    def setup(self):
        # show basemap figure in basemap window
        # generate menubar
        menubar = tk.Menu(self.basemap_window)
        fileMenu = tk.Menu(menubar, tearoff=0)

        # settings submenu
        loadMenu = tk.Menu(fileMenu, tearoff=0)
        loadMenu.add_command(label="select files", command=self.load_tracks)
        loadMenu.add_command(label="select folder",
                             command=lambda: self.load_tracks(dir=True))
        fileMenu.add_cascade(label="load tracks", menu=loadMenu)

        fileMenu.add_command(label="clear tracks", command=self.clear_nav)
        fileMenu.add_command(label="preferences", command=self.settings)
        fileMenu.add_command(label="exit       [ctrl+q]",
                             command=self.basemap_close)
        # add items to menubar
        menubar.add_cascade(label="file", menu=fileMenu)
        # add the menubar to the window
        self.basemap_window.config(menu=menubar)

        # set up info frame
        infoFrame = tk.Frame(self.basemap_window)
        infoFrame.pack(side="top", fill="both")
        # button to toggle track visibility
        self.track_viz = tk.BooleanVar(value=True)
        tk.Label(infoFrame, text="track display: ").pack(side="left")
        tk.Radiobutton(infoFrame,
                       text="all",
                       variable=self.track_viz,
                       value=True,
                       command=self.plot_tracks).pack(side="left")
        tk.Radiobutton(infoFrame,
                       text="current",
                       variable=self.track_viz,
                       value=False,
                       command=self.plot_tracks).pack(side="left")

        # initialize the basemap figure
        self.map_fig = mpl.figure.Figure()
        self.map_fig.patch.set_facecolor(self.parent.cget("bg"))
        self.map_fig_ax = self.map_fig.add_subplot(111)
        self.bm_im = self.map_fig_ax.imshow(np.ones((100, 100)),
                                            cmap=self.cmap.get(),
                                            aspect="auto")
        self.map_fig_ax.set_visible(False)
        self.map_fig_ax.set(xlabel="x [km]", ylabel="y [km]")
        # initialize artists
        self.track_ln, = self.map_fig_ax.plot([], [], "k.", ms=.1, picker=True)
        self.track_start_ln, = self.map_fig_ax.plot([], [],
                                                    "go",
                                                    ms=3,
                                                    label="start")
        self.track_end_ln, = self.map_fig_ax.plot([], [],
                                                  "ro",
                                                  ms=3,
                                                  label="end")
        # pack mpl figure in canvas window
        self.map_dataCanvas = FigureCanvasTkAgg(self.map_fig,
                                                self.basemap_window)
        self.map_dataCanvas.get_tk_widget().pack(in_=self.map_display,
                                                 side="bottom",
                                                 fill="both",
                                                 expand=1)
        self.map_toolbar = NavigationToolbar2Tk(self.map_dataCanvas,
                                                self.basemap_window)
        self.map_dataCanvas._tkcanvas.pack()
        self.basemap_state = 1
        self.draw_cid = self.map_fig.canvas.mpl_connect(
            "draw_event", self.update_bg)
        self.pick_cid = self.map_fig.canvas.mpl_connect(
            "pick_event", self.on_pick)

    def set_vars(self):
        # initialize arrays to hold track nav info
        self.x = np.array(())
        self.y = np.array(())
        self.track_name = np.array(()).astype(dtype=np.str)
        self.loaded_tracks = np.array(()).astype(dtype=np.str)
        self.start_x = np.array(())
        self.start_y = np.array(())
        self.end_x = np.array(())
        self.end_y = np.array(())
        self.legend = None
        self.pick_loc = None
        self.profile_track = None

    # map is a method to plot the basemap in the basemap window
    def map(self, map_path):
        # pull track up on dem basemap
        if map_path:
            print("Loading Basemap: ", map_path.split("/")[-1])
            try:
                # read in basemap
                with rio.open(map_path, mode="r") as dataset:
                    # downsample if raster is too large
                    fac = 1
                    # if dataset.height >= 3e3 or dataset.width >= 3e3:
                    #     fac = 4
                    # elif dataset.height >= 2e3 or dataset.width >= 2e3:
                    #     fac = 3
                    if dataset.height >= 1e3 or dataset.width >= 1e3:
                        fac = 2
                    data = dataset.read(
                        out_shape=(dataset.count, int(dataset.height // fac),
                                   int(dataset.width // fac)),
                        resampling=rio.enums.Resampling.nearest)
                    self.bmcrs = dataset.crs
                # stack bands into numpy array
                im = np.dstack((data))
                if im.shape[-1] == 1:
                    im = im.reshape(im.shape[0], -1)
                cmin = np.nanmin(im)
                cmax = np.nanmax(im)
                self.bm_im.set_clim([cmin, cmax])
                self.bm_im.set_data(im)
                # set bm image extent based on raster bounds - convert from m to km
                self.bm_im.set_extent([
                    _i * 1e-3 for _i in [
                        dataset.bounds.left, dataset.bounds.right,
                        dataset.bounds.bottom, dataset.bounds.top
                    ]
                ])
                # save un-zoomed view to toolbar
                self.map_toolbar.push_current()
                self.map_fig_ax.set_visible(True)
                self.map_dataCanvas.draw()

            except Exception as err:
                print("basemap load error: " + str(err))
                pass

    # set_track is a method to pass the track name loaded in profile view to the basemap class
    def set_track(self, fn):
        self.profile_track = fn

    # set_nav is a method to update the navigation data plotted on the basemap
    def set_nav(self, fn, navdf):
        # skip if track already loaded to basemap
        if fn in self.track_name:
            return

        # transform navcrs to basemap crs
        x, y = pyproj.transform(
            self.navcrs,
            self.bmcrs,
            navdf["lon"].to_numpy(),
            navdf["lat"].to_numpy(),
        )
        # convert from m to km
        x = x * 1e-3
        y = y * 1e-3
        # add x and y coords to x and y coord arrays
        self.x = np.append(self.x, x)
        self.y = np.append(self.y, y)
        # add name to array to match with x,y
        self.track_name = np.append(self.track_name, np.repeat(fn, len(x)))
        self.start_x = np.append(self.start_x, x[0])
        self.start_y = np.append(self.start_y, y[0])
        self.end_x = np.append(self.end_x, x[-1])
        self.end_y = np.append(self.end_y, y[-1])
        # add name to list to match with endpoints
        self.loaded_tracks = np.append(self.loaded_tracks, fn)

    # plot_tracks is a method to plot track geom
    def plot_tracks(self):
        # if track_viz variable is true, add all track points to appropriate lines
        if self.track_viz.get():
            # set track line data
            self.track_ln.set_data(self.x, self.y)
            # set track ending line data
            self.track_start_ln.set_data(self.start_x, self.start_y)
            self.track_end_ln.set_data(self.end_x, self.end_y)

            x_range = [np.amin(self.x) - 5, np.amax(self.x) + 5]
            y_range = [np.amin(self.y) - 5, np.amax(self.y) + 5]
            r = max(x_range[1] - x_range[0], y_range[1] - y_range[0])
            x = np.median(x_range)
            y = np.median(y_range)
            self.map_fig_ax.axis([x - r, x + r, y - r, y + r])
        # otherwise just set track points from last line to appropriate lines
        else:
            # set track ending line data
            idx = np.where(self.loaded_tracks == self.profile_track)[0]
            self.track_start_ln.set_data(self.start_x[idx], self.start_y[idx])
            self.track_end_ln.set_data(self.end_x[idx], self.end_y[idx])
            # set track line data
            idx = np.where(self.track_name == self.profile_track)[0]
            self.track_ln.set_data(self.x[idx], self.y[idx])

            x_range = [np.amin(self.x[idx]) - 5, np.amax(self.x[idx]) + 5]
            y_range = [np.amin(self.y[idx]) - 5, np.amax(self.y[idx]) + 5]
            r = max(x_range[1] - x_range[0], y_range[1] - y_range[0])
            x = np.median(x_range)
            y = np.median(y_range)
            self.map_fig_ax.axis([x - r, x + r, y - r, y + r])

        if not self.legend:
            self.legend = self.map_fig_ax.legend()
        self.map_dataCanvas.draw()
        self.blit()

    # plot_idx is a method to plot the location of a click event on the datacanvas to the basemap
    def plot_idx(self, fn, idx):
        # basemap open, plot picked location regardless of picking state
        if self.basemap_state == 1 and len(self.x) > 0:
            # plot pick location on basemap
            if self.pick_loc:
                self.pick_loc.remove()
            self.pick_loc = self.map_fig_ax.scatter(
                self.x[self.track_name == fn][idx],
                self.y[self.track_name == fn][idx],
                c="b",
                marker="X",
                zorder=3)
            self.blit()

    # basemap_close is a method to close the basemap window
    def basemap_close(self, event=None):
        self.basemap_window.destroy()
        self.basemap_state = 0

    # get_state is a mathod to get the basemap state
    def get_state(self):
        return self.basemap_state

    # clear_basemap is a method to clear the basemap
    def clear_nav(self):
        # clear arrays
        self.track_name = np.array(()).astype(dtype=np.str)
        self.loaded_tracks = np.array(()).astype(dtype=np.str)
        self.x = np.array(())
        self.y = np.array(())
        self.start_x = np.array(())
        self.start_y = np.array(())
        self.end_x = np.array(())
        self.end_y = np.array(())
        # set lines
        self.track_ln.set_data(self.x, self.y)
        self.track_start_ln.set_data(self.start_x, self.start_y)
        self.track_end_ln.set_data(self.end_x, self.end_y)

        if self.legend:
            self.legend.remove()
            self.legend = None

        if self.pick_loc:
            self.pick_loc.remove()
            self.pick_loc = None

        self.map_fig.canvas.draw()

    def safe_draw(self):
        """temporarily disconnect the draw_event callback to avoid recursion"""
        canvas = self.map_fig.canvas
        canvas.mpl_disconnect(self.draw_cid)
        canvas.draw()
        self.draw_cid = canvas.mpl_connect("draw_event", self.update_bg)

    def update_bg(self, event=None):
        """
        when the figure is resized, hide picks, draw everything,
        and update the background.
        """
        if self.pick_loc:
            self.pick_loc.set_visible(False)
            self.safe_draw()
            self.axbg = self.map_dataCanvas.copy_from_bbox(
                self.map_fig_ax.bbox)
            self.pick_loc.set_visible(True)
            self.blit()
        else:
            self.safe_draw()
            self.axbg = self.map_dataCanvas.copy_from_bbox(
                self.map_fig_ax.bbox)
            self.blit()

    def blit(self):
        """
        update the figure, without needing to redraw the
        "axbg" artists.
        """
        self.map_fig.canvas.restore_region(self.axbg)
        if self.pick_loc:
            self.map_fig_ax.draw_artist(self.pick_loc)
        self.map_fig.canvas.blit(self.map_fig_ax.bbox)

    # load all tracks within a directory to basemap
    def load_tracks(self, dir=False):
        if dir:
            tmp_datPath = ""
            # select input file
            tmp_datPath = tk.filedialog.askdirectory(title="select folder",
                                                     initialdir=self.datPath,
                                                     mustexist=True)
            # if input selected, clear impick canvas, ingest data and pass to impick
            if tmp_datPath:
                # get list of data files in dir
                flist = glob.glob(tmp_datPath + "/*")
                print(tmp_datPath)

        else:
            flist = ""
            # select input files
            flist = tk.filedialog.askopenfilenames(title="select files",
                                                   initialdir=self.datPath,
                                                   multiple=True)
            if flist:
                flist = list(flist)

            # iterate through file list and retrieve navdat from proper getnav function
        for f in flist:

            if f.endswith("h5"):
                navdf = navparse.getnav_oibAK_h5(f, self.navcrs, self.body)
                fn = f.split("/")[-1].rstrip(".h5")
            elif f.endswith("mat"):
                try:
                    navdf = navparse.getnav_cresis_mat(f, self.navcrs,
                                                       self.body)
                    fn = f.split("/")[-1].rstrip(".mat")
                except:
                    navdf = navparse.getnav_oibAK_h5(f, self.navcrs, self.body)
                    fn = f.split("/")[-1].rstrip(".mat")
            elif f.lower().endswith("dzg"):
                navdf = navparse.getnav_gssi(f, self.navcrs, self.body)
                fn = f.split("/")[-1].rstrip(".DZG")
            elif f.endswith("tab"):
                navdf = navparse.getnav_sharad(f, self.navcrs, self.body)
                fn = f.split("/")[-1].rstrip("_geom.tab")
            else:
                continue
            self.set_nav(fn, navdf)

        # update datPath
        self.datPath = os.path.dirname(os.path.abspath(f)) + "/"
        # update extent
        self.plot_tracks()

    # settings menu
    def settings(self):
        settingsWindow = tk.Toplevel(self.basemap_window)

        row = tk.Frame(settingsWindow)
        row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)
        lab = tk.Label(row, width=10, text="cmap", anchor="w")
        lab.pack(side=tk.LEFT)
        tk.Radiobutton(row,
                       text="greys_r",
                       variable=self.cmap,
                       value="Greys_r").pack(side="top", anchor="w")
        tk.Radiobutton(row, text="gray", variable=self.cmap,
                       value="gray").pack(side="top", anchor="w")
        tk.Radiobutton(row,
                       text="terrain",
                       variable=self.cmap,
                       value="terrain").pack(side="top", anchor="w")

        row = tk.Frame(settingsWindow)
        row.pack(side=tk.TOP, anchor="c")
        b1 = tk.Button(row, text="save", command=self.updateSettings)
        b1.pack(side="left")
        b2 = tk.Button(row, text="close", command=settingsWindow.destroy)
        b2.pack(side="left")

    # update settings
    def updateSettings(self):
        # pass cmap
        self.bm_im.set_cmap(self.cmap.get())
        # redraw
        self.map_dataCanvas.draw()

    # on_pick gets the picked track from user click
    def on_pick(self, event):
        # determine which track was selected
        xdata = event.mouseevent.xdata
        idx = utils.find_nearest(self.x, xdata)
        track = self.track_name[idx]
        # pass track to impick
        if (track != self.profile_track) and (tk.messagebox.askyesno(
                "Load", "Load track: " + str(track) + "?") == True):
            self.to_gui(self.datPath, track)
Example #10
0
class TensileTestView(tk.Frame):
    def __init__(self, parent):
        tk.Frame.__init__(self, parent)  # Initialize this class as a frame
        self.animationBgCol = "black"  # Animation canvas background colour

        # Create and configure main frame
        mainArea = tk.Frame(self, bg=st.MAIN_AREA_BG)
        mainArea.grid(row=0, column=0, sticky="nsew")
        mainArea.grid_propagate(0)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)

        # Create and configure main grids
        grid = tuple([i for i in range(20)])
        mainArea.grid_columnconfigure(grid, weight=1, minsize=50)
        mainArea.grid_rowconfigure(grid, weight=1, minsize=35)

        # Create title
        label = tk.Label(mainArea,
                         text="Mechanical Workshop",
                         font=st.LARGE_FONT,
                         bg=st.MAIN_AREA_BG,
                         fg=st.TITLE_COLOUR)
        label.grid(row=0, column=14, columnspan=6, sticky='nse')

        # Create description
        label = tk.Label(
            mainArea,
            text="We are now going to perform a tensile test on the " +
            "sheet of aluminum that we cold rolled! We can see our sample of aluminum on the left side of "
            +
            "the screen as well as a stress-strain graph on the right side of the screen. "
            + "Press the start button to begin the tensile test!",
            bg=st.INPUT_BG,
            wraplength=650,
            fg='black',
            justify='left',
            relief='ridge')
        label.grid(row=1, column=6, rowspan=2, columnspan=14, sticky='nesw')

        # Canvas for graphic simulation
        self.height = 595
        self.width = 250
        self.animationWindow = tk.Canvas(mainArea,
                                         bg=self.animationBgCol,
                                         height=self.height,
                                         width=self.width,
                                         bd=0,
                                         highlightthickness=0,
                                         relief='ridge')
        self.animationWindow.grid(row=2,
                                  column=1,
                                  columnspan=5,
                                  rowspan=17,
                                  sticky='ne')

        # Create Plot
        self.f = Figure(figsize=(6, 6), dpi=100)
        self.a = self.f.add_subplot(111)
        self.a.grid(color='grey', linestyle='-', linewidth=0.3)
        self.a.set_ylabel('Stress (MPa)')
        self.a.set_xlabel('Strain (-)')
        self.line = self.a.plot([], [], "-")
        self.a.format_coord = lambda x, y: "Strain (-)={:6.4f}, Stress (MPa)={:6.3f}".format(
            x, y)

        # Create canvas for plot
        self.graphWindow = FigureCanvasTkAgg(self.f, mainArea)
        self.graphWindow.get_tk_widget().grid(row=5,
                                              column=6,
                                              rowspan=12,
                                              columnspan=12)
        self.BG = self.graphWindow.copy_from_bbox(self.a.bbox)
        self.OG = self.BG

        # Load arrow images
        self.arrow = ImageTk.PhotoImage(file=st.IMG_PATH + "left_arrow.png")
        self.arrowClicked = ImageTk.PhotoImage(file=st.IMG_PATH +
                                               "left_arrow_clicked.png")
        self.arrowDisabled = ImageTk.PhotoImage(file=st.IMG_PATH +
                                                "left_arrow_disabled.png")

        # Arrow for previous page
        self.nextPage = tk.Button(mainArea, image=self.arrow, borderwidth=0)
        self.nextPage.image = self.arrow
        self.nextPage.grid(row=9, rowspan=2, column=0, sticky='nesw')

        # Button to start simulation
        self.animationButton = ttk.Button(mainArea, text="Start")
        self.animationButton.grid(row=3,
                                  rowspan=2,
                                  column=6,
                                  columnspan=3,
                                  sticky='nesw')

        # Text for displaying cold work
        self.CW_text = tk.Label(mainArea,
                                text='',
                                borderwidth=2,
                                bg=st.INPUT_BG,
                                font=st.MEDIUM_FONT)
        self.CW_text.grid(row=0,
                          rowspan=2,
                          column=2,
                          columnspan=3,
                          sticky='nsew')

        # Draw the rod
        self.rod = Rod(self.animationWindow, self.width, self.height,
                       self.animationBgCol)
        self.rod.drawRod()

        # Create toolbar for plot
        self.toolbar = NavigationToolbar2Tk(self.graphWindow, mainArea)
        self.toolbar.update()
        self.toolbar.grid(row=17,
                          column=6,
                          rowspan=2,
                          columnspan=10,
                          sticky='nsew')

        # Draw mac logo
        logoImg = ImageTk.PhotoImage(Image.open(st.IMG_PATH + "macLogo.png"))
        canvas = tk.Canvas(mainArea,
                           bg=st.MAIN_AREA_BG,
                           width=130,
                           height=71,
                           bd=0,
                           highlightthickness=0,
                           relief='ridge')
        canvas.create_image(130 / 2, 71 / 2, image=logoImg, anchor="center")
        canvas.image = logoImg
        canvas.grid(row=17, column=17, rowspan=3, columnspan=3)

    def setGraphSize(self, x, y):
        """
		Set the graph size. Assume it is called before any other function
		"""
        self.a.set_xlim([-0.01, x + 0.3])
        self.a.set_ylim([0, y + 50])
        self.graphWindow.draw()
        self.BG = self.graphWindow.copy_from_bbox(self.a.bbox)

    def pressArrow(self):
        """
		Change arrow picture to "pressed arrow"
		"""
        self.nextPage.config(image=self.arrowClicked)
        self.nextPage.image = self.arrowClicked

    def normalArrow(self):
        """
		Change arrow picture to "normal arrow"
		"""
        self.nextPage.config(image=self.arrow)
        self.nextPage.image = self.arrow

    def disableArrow(self):
        """
		Change arrow picture to "disabled arrow"
		"""
        self.nextPage.config(image=self.arrowDisabled)
        self.nextPage.image = self.arrowDisabled

    def resetCanvas(self):
        """
		Reset the rod on canvas
		"""
        self.rod.resetRod()

    def setCW(self, val):
        """
		Set the coldwork text
		"""
        self.CW_text.config(text="%CW = " + str(val))

    def updateGraph(self, xvals, yvals):
        """
		Update the graph with xvals and yvals. This function is called at a given framerate
		"""
        self.line[0].set_data(xvals, yvals)
        self.graphWindow.restore_region(self.BG)
        self.a.draw_artist(self.line[0])
        self.graphWindow.blit(self.a.bbox)
        self.graphWindow.flush_events()

    def updateAnimation(self, elongation, widthFact, neckWidthFact,
                        neckHeightFact):
        """
		Update the canvas based on given values. This function is called at a given framerate
		"""
        self.rod.updateRod(elongation, widthFact, neckWidthFact,
                           neckHeightFact)

    def generateFracture(self, EL):
        """
		Generate a fracture in the Rod. Function is called at the end of the animation
		"""
        self.rod.drawFracture(EL)
Example #11
0
class MultichannelPlot(matplotlib.figure.Figure):
    def __init__(self, master, row=0, column=0, rowspan=5, columnspan=5, width=5, height=3, update_prot="blit"):
        matplotlib.figure.Figure.__init__(self, figsize=(width, height))
        self.update_prot = update_prot
        self.frame = Frame(master=master)
        self.frame.config(bd=5)

        self.frame.grid(row=row, column=column, padx=5, pady=5)
        self.channel_list = []
        self.array_list = []
        self.color_list = ["r", "b", "g", "c", "m", "y", "k"]

        self.a = self.add_subplot(MultichannelAxis(self, 111))

        self.canvas = FigureCanvasTkAgg(self, master=self.frame)
        self.canvas.show()

        self.canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=True)

        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.frame)
        self.toolbar.update()
        self.toolbar.pack(side=BOTTOM, fill=BOTH, expand=True)  # ,expand = True)#fill=BOTH)#, expand=1)
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.a.bbox)

        return None

    def AddChannel(self, spec_array, channel_type, color=None):

        if color == None or color == "":
            self.a.add_line(Channel([], [], self, spec_array, channel_type, color=self.color_list[0]))
            self.color_list.append(self.color_list[0])
            del (self.color_list[0])

        else:
            self.a.add_line(Channel([], [], self, spec_array, channel_type, color=color))
        # self.Update()
        self.Redraw()
        return self.a.lines[-1]

    def RemoveChannel(self, channel):
        self.a.lines.remove(channel)
        self.Redraw()

        return 0

    def SetChannelColor(self, channel, clr):
        if clr != "":
            channel.color = clr

        else:
            channel.color = self.color_list[0]
            self.color_list.append(self.color_list[0])
            del (self.color_list[0])

        return 0

    def ShowChannel(self, channel):
        channel.set_visible(True)

        self.Update()
        return 0

    def HideChannel(self, channel):
        channel.set_visible(False)
        self.Update()
        return 0

    def Redraw(self):

        self.a.relim()
        self.a.autoscale_view(tight=False)

        self.canvas.draw()
        self.canvas.restore_region(self.background)
        for line in self.a.lines:
            self.a.draw_artist(line)

        self.canvas.blit(self.a.bbox)

        return 0

    def SaveFigure(self, filename):

        self.f_copy = self.a
        self.f_copy.savefig("a.png")

        return 0

    def Update(self):
        if self.update_prot == "draw":
            self.canvas.draw()
            return 0

        (lower_y_lim, upper_y_lim) = self.a.get_ylim()
        (lower_x_lim, upper_x_lim) = self.a.get_xlim()
        scaley_bool = False
        scalex_bool = False
        scaley_down_bool = True

        for channel in self.a.lines:
            if channel.get_visible() == True:
                channel.ChannelUpdate()
                scaley_bool = (
                    scaley_bool or max(channel.get_ydata()) > upper_y_lim or min(channel.get_ydata()) < lower_y_lim
                )
                scaley_down_bool = scaley_down_bool and max(channel.get_ydata()) < upper_y_lim * 0.6
                scalex_bool = (
                    scalex_bool or max(channel.get_xdata()) != upper_x_lim or min(channel.get_xdata()) != lower_x_lim
                )

        if scaley_bool or scalex_bool or scaley_down_bool:

            self.Redraw()

        else:

            self.canvas.restore_region(self.background)
            for line in self.a.lines:
                self.a.draw_artist(line)

            self.canvas.blit(self.a.bbox)

        return 0
def quickPlayer(soundfile,
                data,
                stamps,
                names,
                h=128,
                onlyValues=False,
                regions=None):
    """
    USAGE:
    press spacebar to start/stop playing. 
    Navigate by clicking on plot, and with 'zoom' and 'pan' features of the toolbar.
    Zoom: Click and drag. Right click to zoom out.
   
    Plot and player will automatically follow if zoomed. But if zoomed too much, it may cause stuttering.
    Panning while audio is being played will cause stuttering.
    
    ARGS:
    onlyValues: If  provided time stamps does not have IDs or names (so just lines to be drawn), this should be True. Manually annotated files will have IDs and names for the stamps  . 
    
    soundfile: sound file to be played
    data: data that shown on the player plot
    stamps: lines will be drawed on these points on the data
    h: hopsize
    
    size(data) * h = size(sound)      If you pass audio samples as data, h (hop size) should be 1.
    """

    wf = wave.open(soundfile, 'rb')
    parent = Tk()

    chunk_size = 2048
    sem = asyncio.Semaphore()
    play_mode = tk.BooleanVar(parent, False)

    fig = plt.figure(figsize=(18, 7), dpi=100)
    mainplot = fig.add_subplot(111)

    canvas = FigureCanvasTkAgg(fig, parent)
    canvaswidget = canvas.get_tk_widget()
    canvaswidget.grid(row=2, column=0, columnspan=5, sticky=W)

    toolbarFrame = Frame(master=parent)
    toolbarFrame.grid(row=3, column=0, columnspan=7)
    toolbar = NavigationToolbar2Tk(canvas, toolbarFrame)
    toolbar.update()

    canvas._tkcanvas.grid(row=2, column=0, columnspan=7, sticky=W)
    global background
    background = canvas.copy_from_bbox(mainplot.bbox)
    cursor = mainplot.axvline(color="k", animated=True)
    cursor.set_xdata(0)

    for d in data:
        if d.ndim == 2:
            ymax = d.shape[1]
            ymin = 0
            mainplot.pcolormesh(np.arange(d.shape[0]), np.arange(d.shape[1]),
                                np.transpose(d))
        if d.ndim == 1:
            ymax = np.max(data[0])
            ymin = np.min(data[0])
            mainplot.plot(d)
    global x0, x1
    x0, x1 = mainplot.get_xlim()

    p = pyaudio.PyAudio()

    def callbackstream(in_data, frame_count, time_info, status):
        sem.acquire()
        data = wf.readframes(frame_count)
        parent.event_generate("<<playbackmove>>", when="now")
        sem.release()
        return (data, pyaudio.paContinue)

    _callbackstream = callbackstream

    def initStream():
        global stream
        stream = p.open(format=8,
                        channels=1,
                        rate=44100,
                        output=True,
                        stream_callback=_callbackstream,
                        start=True,
                        frames_per_buffer=chunk_size)

    def playsound(event=None):
        if sem.locked():
            return
        if play_mode.get() == True:
            # this is broken
            global stream
            stream.close()
            play_mode.set(False)
        else:
            try:
                initStream()
                play_mode.set(True)
            except:
                print("play failed")

    def playbackMove(event=None):  # move cursor by audio chunk size
        global x0, x1
        global background
        incr = (chunk_size) // h
        nextpos = cursor.get_xdata() + incr
        cursor.set_xdata(nextpos)
        updateCursor()
        if (x1 - nextpos) < 0:
            mainplot.set_xlim(x1, x1 + x1 - x0)
            canvas.draw()

            toolbar.push_current()
            background = canvas.copy_from_bbox(mainplot.bbox)
            x0, x1 = mainplot.get_xlim()

    def new_release_zoom(*args, **kwargs):
        global x0, x1
        release_zoom_orig(*args, **kwargs)
        s = 'toolbar_event'
        event = Event(s, canvas)
        canvas.callbacks.process(s, Event('toolbar_event', canvas))
        x0, x1 = mainplot.get_xlim()

    def new_release_pan(*args, **kwargs):
        global x0, x1
        release_pan_orig(*args, **kwargs)
        s = 'toolbar_event'
        event = Event(s, canvas)
        canvas.callbacks.process(s, Event('toolbar_event', canvas))
        x0, x1 = mainplot.get_xlim()

    def new_update_view(*args, **kwargs):
        global x0, x1
        _update_view_orig(*args, **kwargs)
        s = 'toolbar_event'
        event = Event(s, canvas)
        canvas.callbacks.process(s, Event('toolbar_event', canvas))
        x0, x1 = mainplot.get_xlim()

    def handle_toolbar(event):
        global x0, x1
        canvas.draw()
        global background
        background = canvas.copy_from_bbox(mainplot.bbox)

    def onclick(event):
        if (toolbar._active == 'ZOOM' or toolbar._active == 'PAN'):
            pass
        else:
            cursor.set_xdata(event.xdata)
            wf.setpos(int(event.xdata * h))
            updateCursor()

    def updateCursor():
        canvas.restore_region(background)
        mainplot.draw_artist(cursor)
        canvas.blit(mainplot.bbox)

    parent.bind("<space>", playsound)
    parent.bind("<<playbackmove>>", playbackMove)

    release_zoom_orig = toolbar.release_zoom
    toolbar.release_zoom = new_release_zoom
    release_pan_orig = toolbar.release_pan
    toolbar.release_pan = new_release_pan
    _update_view_orig = toolbar._update_view
    toolbar._update_view = new_update_view

    canvas.mpl_connect('toolbar_event', handle_toolbar)
    cid1 = canvas.mpl_connect("button_press_event", onclick)

    canvas.draw()

    colors = [
        'c', 'm', 'y', 'r', '#FFBD33', '#924A03', '#D00000', '#D000D0',
        '#6800D0', '#095549', 'b', 'r', 'r'
    ]
    if onlyValues:
        for i in range(len(stamps)):
            mainplot.draw_artist(
                mainplot.vlines(x=np.array(stamps[i]) / h,
                                color=colors[i],
                                ymin=ymin,
                                ymax=ymax,
                                label=names[i]))
            mainplot.legend(loc="upper left")
    else:
        for i in range(len(stamps)):
            for j in stamps[i]:
                mainplot.draw_artist(
                    mainplot.axvline(x=j[1] / h,
                                     ymin=ymin,
                                     ymax=ymax,
                                     color=colors[i]))
                mainplot.text(j[1] / h + 2, (0.8 * ymax) + (i * 0.04),
                              names[i] + str(j[0]),
                              bbox=dict(fill=False,
                                        edgecolor=colors[i],
                                        linewidth=1))

    if regions != None:
        for r in regions:
            mainplot.fill_betweenx([ymin, ymax],
                                   r[0],
                                   r[1],
                                   facecolor='blue',
                                   alpha=0.5)

    canvas.draw()
    background = canvas.copy_from_bbox(mainplot.bbox)

    parent.mainloop()

    for func in [stream.close, wf.close, p.terminate, parent.destroy]:
        try:
            func()
        except:
            pass

    return
Example #13
0
class Gui :
    """
    A tkinter GUI to quickly visualize ARPES data, i.e. cuts and maps. Should 
    be built in a modular fashion such that any data reader can be 'plugged in'.

    data      : 3D array; the raw data from the selected file. This is 
                expected to be in the shape (z, x, y) (z may be equal to 1)
    pp_data   : 3D array; the postprocessed data to be displayed.
    cmaps     : list of str; a list of available matplotlib colormap names.
    xscale, yscale, zscale
              : 1D arrays; the x, y and z-axis data.
    cursor_xy : tuple; current location of the cursor in the bottom left plot.
    dpi       : int; resolution at which to save .png`s.
    """
    data = STARTUP_DATA
    pp_data = STARTUP_DATA.copy()
    cmaps = CMAPS
    xscale = None
    yscale = None
    zscale = None
    cursor_xy = None
    dpi = DPI
    main_mesh = None
    vmain_mesh = None
    cut1 = None
    cut2 = None

    def __init__(self, master, filename=None) :
        """ This init function mostly just calls all 'real' initialization 
        functions where the actual work is outsourced to. """
        # Create the main container/window
        frame = tk.Frame(master)

        # Define some elements
        self._set_up_load_button(master)
        self._set_up_pp_selectors(master)
        self._set_up_plots(master)
        self._set_up_colormap_sliders(master)
        self._set_up_z_slider(master)
        self._set_up_integration_range_selector(master)
        self._set_up_status_label(master)

        # Align all elements
        self._align()

        # Load the given file
        if filename :
            self.filepath.set(filename)
            self.load_data()

        # The setup of event handling requires there to be some data already
        self._set_up_event_handling()

    def _align(self) :
        """ Use the grid() layout manager to align the elements of the GUI. 
        At this stage of development the grid has 12 columns of unequal size.
        """
        # The plot takes up the space of PLOT_COLUMNSPAN widgets
        PLOT_COLUMNSPAN = 8
        PLOT_ROWSPAN = 3
        N_PATH_FIELD = PLOT_COLUMNSPAN

        # 'Load file' elements
        LOADROW = 0
        c = 0
        self.browse_button.grid(row=LOADROW, column=c, sticky='ew')
        c += 1
        self.load_button.grid(row=LOADROW, column=c, sticky='ew')
        c += 1
        self.decrement_button.grid(row=LOADROW, column=c, sticky='ew')
        c += 1
        self.increment_button.grid(row=LOADROW, column=c, sticky='ew')
        c += 1
        self.path_field.grid(row=LOADROW, column=c, columnspan=N_PATH_FIELD, 
                             sticky='ew') 

        # Postprocessing selectors
        PPROW = LOADROW + 1
        c = 0
        for lst in self.radiobuttons :
            r = 0
            for btn in lst :
                btn.grid(row=PPROW+r, column=c, sticky='ew')
                r += 1
            c += 1

        # Plot & colormap sliders & selector
        PLOTROW = PPROW + max([len(lst) for lst in self.radiobuttons])
        PLOTCOLUMN = 1
        self.canvas.get_tk_widget().grid(row=PLOTROW, column=PLOTCOLUMN, 
                                         rowspan=PLOT_ROWSPAN, columnspan=PLOT_COLUMNSPAN)
        right_of_plot = PLOT_COLUMNSPAN + PLOTCOLUMN
        self.cm_min_slider.grid(row=PLOTROW, column=right_of_plot + 1)
        self.cm_max_slider.grid(row=PLOTROW, column=right_of_plot + 2)
        self.cmap_dropdown.grid(row=PLOTROW + 1, column=right_of_plot + 1)
        self.invert_cmap_checkbutton.grid(row=PLOTROW + 1, column=right_of_plot + 2)

        # Save png button
        self.save_button.grid(row=PLOTROW + 2, column=right_of_plot + 1)

        # z slider, integration range selector
        self.z_slider.grid(row=PLOTROW, column=0)
        self.integration_range_entry.grid(row=PLOTROW+1, column=0)

        # Put the status label at the very bottom left
        STATUSROW = PLOTROW + PLOT_ROWSPAN + 1
        self.status_label.grid(row=STATUSROW, column=0, columnspan=10,
                               sticky='ew')

    def _set_up_load_button(self, master) :
        """ Add a button which opens a filebrowser to choose the file to load
        and a textbox (Entry widget) where the filepath can be changed.
        """
        # Define the Browse button
        self.browse_button = tk.Button(master, text='Browse',
                                     command=self.browse)

        # and the Load button
        self.load_button = tk.Button(master, text='Load',
                                     command=self.load_data)
        
        # and the entry field which holds the path to the current file
        self.filepath = tk.StringVar()
        self.path_field = tk.Entry(master, textvariable=self.filepath)

        # Also add inc and decrement buttons
        self.increment_button = tk.Button(master, text='>',
                                          command=lambda : self.increment(1)) 
        self.decrement_button = tk.Button(master, text='<',
                                          command=lambda : self.increment(-1)) 

        # Add a 'save' button for creating png s
        self.save_button = tk.Button(master, text='Save png', 
                                     command=self.save_plot)

    def _set_up_pp_selectors(self, master) :
        """ Create radiobuttons for the selction of postprocessing methods. 
        The order of the pp methods in all lists is:
            0) Make map
            1) BG subtraction
            2) Normalization
            3) derivative
        """
        # Create control variables to hold the selections and store them in a 
        # list for programmatic access later on
        self.map = tk.StringVar()
        self.subtractor = tk.StringVar()
        self.normalizer = tk.StringVar()
        self.derivative = tk.StringVar()
        self.selection = [self.map,
                          self.subtractor,
                          self.normalizer,
                          self.derivative]
        # Create sets of radiobuttons and set all to default value 'Off'
        self.radiobuttons = []
        for i, D  in enumerate(PP_DICTS) :
            variable = self.selection[i]
            variable.set('Off')
            self.radiobuttons.append([])
            for key in D :
                rb = tk.Radiobutton(master, text=key, variable=variable,
                                   value=key, command=self.process_data,
                                   indicatoron=0)
                self.radiobuttons[i].append(rb)

    def _set_up_plots(self, master) :
        """ Take care of all the matplotlib stuff for the plot. """
        fig = Figure(figsize=FIGSIZE)
        fig.patch.set_alpha(0)
        ax_cut1 = fig.add_subplot(221)
        ax_cut2 = fig.add_subplot(224)
        ax_map = fig.add_subplot(223)#, sharex=ax_cut1, sharey=ax_cut2)
        ax_energy = fig.add_subplot(222)

        # Virtual figure and ax for creation of png's
        self.vfig = Figure(figsize=VFIGSIZE)
        vax = self.vfig.add_subplot(111)
        self.vcanvas = FigureCanvasTkAgg(self.vfig, master=master)
        
        # Remove padding between min and max of data and plot border
        ax_cut2.set_ymargin(0)

        # Move ticks to the other side
        ax_energy.xaxis.tick_top()
        ax_energy.yaxis.tick_right()

        ax_cut1.xaxis.tick_top()
        ax_cut2.yaxis.tick_right()

        # Get a handle on all axes through the dictionary self.axes
        self.axes = {'cut1': ax_cut1,
                     'cut2': ax_cut2,
                     'map': ax_map,
                     'energy': ax_energy,
                     'vax': vax}

        # Set bg color
        for ax in self.axes.values() :
            ax.set_facecolor(BGCOLOR)

        # Remove spacing between plots
        fig.subplots_adjust(wspace=PLOT_SPACING, hspace=PLOT_SPACING)

        self.canvas = FigureCanvasTkAgg(fig, master=master)
        self.canvas.show()

    def _set_up_colormap_sliders(self, master) :
        """ Add the colormap adjust sliders, set their starting position and add 
        its binding such that it only triggers upon release. Also, couple 
        them to the variables vmin/max_index.
        Then, also create a dropdown with all available cmaps and a checkbox 
        to invert the cmap.
        """
        self.vmin_index = tk.IntVar()
        self.vmax_index = tk.IntVar()
        cm_slider_kwargs = { 'showvalue' : 0,
                             'to' : CM_SLIDER_RESOLUTION, 
                             'length':SLIDER_LENGTH }
        self.cm_min_slider = tk.Scale(master, variable=self.vmin_index,
                                      label='Min', **cm_slider_kwargs)
        self.cm_min_slider.set(CM_SLIDER_RESOLUTION)

        self.cm_max_slider = tk.Scale(master, variable=self.vmax_index,
                                      label='Max', **cm_slider_kwargs)
        self.cm_max_slider.set(0)

        # StringVar to keep track of the cmap and whether it's inverted
        self.cmap = tk.StringVar()
        self.invert_cmap = tk.StringVar()
        # Default to the first cmap
        self.cmap.set(self.cmaps[0])
        self.invert_cmap.set('')

        # Register callbacks for colormap-range change
        for var in [self.vmin_index, self.vmax_index, self.cmap, 
                    self.invert_cmap] :
            var.trace('w', self.redraw_mesh)

        # Create the dropdown menu, populated with all strings in self.cmaps
        self.cmap_dropdown = tk.OptionMenu(master, self.cmap, *self.cmaps)

        # And a button to invert
        self.invert_cmap_checkbutton = tk.Checkbutton(master, text='Invert',
                                                      variable=self.invert_cmap,
                                                      onvalue='_r',
                                                      offvalue='')

    def _set_up_z_slider(self, master) :
        """ Create a Slider which allows to select the z value of the data.
        This value is stored in the DoubleVar self.z """
        self.z = tk.IntVar()
        self.z.set(0)
        self.zmax = tk.IntVar()
        self.zmax.set(1)
        self.z_slider = tk.Scale(master, variable=self.z, label='z', 
                                 to=self.zmax.get(), showvalue=1, 
                                 length=SLIDER_LENGTH) 
        self.z_slider.bind('<ButtonRelease-1>', self.process_data)

    def _set_up_integration_range_selector(self, master) :
        """ Create widgets that will allow setting the integration range when 
        creating a map. """
        self.integrate = tk.IntVar()
        self.integration_range_entry = tk.Entry(master, width=3,
                                           textvariable=self.integrate)

    def _set_up_status_label(self, master) :
        """ Create a label which can hold informative text about the current
        state of the GUI or success/failure of certain operations. This text 
        is held in the StringVar self.status.
        """
        self.status = tk.StringVar()
        # Initialize the variable with the default status
        self.update_status()
        self.status_label = tk.Label(textvariable=self.status, justify=tk.LEFT,
                                    anchor='w')

    def redraw_mesh(self, *args, **kwargs) :
        """ Efficiently redraw the pcolormesh without having to redraw the 
        axes, ticks, labels, etc. """
        # Get the new colormap parameters and apply them to the pcolormesh
        cmap = self.get_cmap()
        vmin, vmax = self.vminmax(self.pp_data)
        mesh = self.main_mesh
        mesh.set_clim(vmin=vmin, vmax=vmax)
        mesh.set_cmap(cmap)

        # Redraw the mesh
        ax = self.axes['map']
        ax.draw_artist(mesh)

        # Cursors need to be redrawn - the blitting happens there
        self.redraw_cursors()

        # Also redraw the cuts if they are pcolormeshes
        if self.map.get() != 'Off' :
            self.redraw_cuts()

    def redraw_cuts(self, *args, **kwargs) :
        """ Efficiently redraw the cuts (meshes or lines, depending on state 
        of `self.map`) without having to redraw the axes, ticks, labels, etc. 
        """
        axes = [self.axes['cut1'], self.axes['cut2']]
        data = [self.cut1, self.cut2]
        artists = [self.cut1_plot, self.cut2_plot] 
        cmap = self.get_cmap()
        for i,ax in enumerate(axes) :
            artist = artists[i]
            if self.map.get() != 'Off' :
                vmin, vmax = self.vminmax(data[i])
                artist.set_clim(vmin=vmin, vmax=vmax)
                artist.set_cmap(cmap)
            ax.draw_artist(artist)
            self.canvas.blit(ax.bbox)

    def redraw_cursors(self, *args, **kwargs) :
        """ Efficiently redraw the cursors in the bottom left plot without 
        having to redraw the axes, ticks, labels, etc. """
        ax = self.axes['map']
        #self.canvas.restore_region(self.bg_mesh)
        ax.draw_artist(self.xcursor)
        ax.draw_artist(self.ycursor)
        self.canvas.blit(ax.bbox)

    def update_z_slider(self, state) :
        """ Change the relief of the z slider to indicate that it is 
        inactive/active. Also update the z slider range"""
        if state == 'active' :
            config = dict(sliderrelief='raised', showvalue=1)
        else :
            config = dict(sliderrelief='flat', showvalue=0)
        self.zmax.set( len(self.data) - 1) 
        config.update(dict(to=self.zmax.get()))
        self.z_slider.config(**config)

    def get_filename(self) :
        """ Return the filename (without path) of the currently selected 
        file. """
        return self.filepath.get().split('/')[-1]

    def increment(self, plusminus) :
        # Get the path and the name of the current file
        filepath = self.filepath.get()
        split = filepath.split('/')
        # If just a filename is given, assume the current directory
        if filepath[0] is not '/' :
            path = './'
        else :
            #path = '/' + '/'.join(split[:-1]) + '/'
            path = '/'.join(split[:-1]) + '/'

        old_filename = split[-1]
        
        # Get a list of the files in the current directory
        dir_content = sorted( os.listdir(path) )
        dir_size = len(dir_content)

        # Get the index of the current file in the directory 
        index = dir_content.index(old_filename)

        # Raise/lower the index until a not-obiously skippable entry is found
        while True :
            index += plusminus
            # Cycle through the list
            index %= dir_size
            new_filename = dir_content[index]
            suffix = new_filename.split('.')[-1]
            if suffix not in SKIPPABLE :
                self.filepath.set(path+new_filename)
                break

    def update_status(self, status=DEFAULT_STATUS) :
        """ Update the status StringVar with the current time and the given
        status argument. 
        """
        now = datetime.now().strftime('%H:%M:%S')
        new_status = '[{}] {}'.format(now, status)
        self.status.set(new_status)

    def browse(self) :
        """ Open a filebrowser dialog and put the selected file into  
        self.path_field. 
        """
        # If the file entry field already contains a path to a file use it
        # as the default file for the browser
        old_filepath = self.filepath.get() 
        if old_filepath :
            default_file = old_filepath
            initialdir = None
        else :
            default_file = None
            initialdir = '/'

        # Open a browser dialog
        new_filepath = askopenfilename(initialfile=default_file,
                                       initialdir=initialdir)

        # Update the path only if a selection was made
        if new_filepath != "" :
            self.filepath.set(new_filepath)

    def load_data(self) :
        """ Load data from the file currently selected by self.filepath. And 
        reset and prepare several things such that the GUI is able to handle 
        the new data properly. 
        """
        # Show the user that something is happening
        self.update_status('Loading data...')

        # Try to load the data with the given dataloader
        try :
            ns = dl.load_data(self.filepath.get())
        except Exception as e :
            print(e)
            self.update_status('Failed to load data.')
            # Leave the function
            return 1

        # Extract the fields from the namespace
        self.data = ns.data
        self.xscale = ns.xscale
        self.yscale = ns.yscale
        try :
            self.zscale = ns.zscale
        except KeyError :
            # Set zscale to None
            self.zscale = None
            pass

        # Notify user of success
        self.update_status('Loaded data: {}.'.format(self.get_filename())) 

        # Update the max z value/toggle z slider (should better be handled in 
        # background by tkinter)
        if self.data.shape[0] == 1 :
            self.update_z_slider('disabled')
        else :
            self.update_z_slider('active')

        # Initiate new cursors
        self.cursor_xy = None

        # The postprocessing also creates copy of the raw data and replots
        self.process_data()

    def process_data(self, event=None) :
        """ Apply all the selected postprocessing routines in the following 
        order:
            0) Make map
            1) bg subtraction
            2) normalization
            3) derivative
        """
        # Retain a copy of the raw data
        self.pp_data = self.data.copy()
        z = self.z.get()

        # Make a map if necessary
        if self.map.get() != 'Off' :
            integrate = self.integrate.get()
            self.pp_data = pp.make_slice(self.pp_data, d=0, i=z, integrate=integrate)
            #self.pp_data = pp.make_map(self.pp_data, z, integrate=integrate)
            
            # Need to reshape
            shape = self.pp_data.shape
            self.pp_data = self.pp_data.reshape(1, shape[0], shape[1])


        # Apply all pp, unless they are set to 'Off' (None)
        for i, D in enumerate(PP_DICTS) :
            pp_operation = D[self.selection[i].get()]
            if pp_operation :
                self.pp_data = pp_operation(self.pp_data)
                #self.pp_data[z,:,:] = pp_operation(self.pp_data[z,:,:])

        # Replot
        self.plot_data()

    def plot_intensity(self) :
        """ Plot the binding energy distribution in the top right if we have 
        a map. """
        # Clear the current distribution
        ax = self.axes['energy']
        ax.clear()

        # Write the value of the energy in the upper right plot
        z = self.z.get()
        if self.zscale is not None :
            z_val = self.zscale[z]
        else :
            z_val = z
        ax.text(0.1, 0.05, z_val, color='red', transform=ax.transAxes)

        # Nothing else to do if we don't have a map
        if self.map.get() == 'Off' : 
            return

        # Get the energies and number of energies
        if self.zscale is not None :
            energies = self.zscale
        else :
            energies = np.arange(len(self.data))
        N_e = len(energies)
        
        # Get the intensities
        intensities = []
        for i in range(N_e) :
            this_slice = self.data[i,:,:]
            intensity = sum( sum(this_slice) )
            intensities.append(intensity)

        # Plot energy distribution
        ax.plot(energies, intensities, **intensity_kwargs)

        # Plot a cursor indicating the current value of z
        y0 = min(intensities)
        y1 = max(intensities)
        ylim = [y0, y1]
        ax.plot(2*[z_val], ylim, **intensity_cursor_kwargs)
        ax.set_ylim(ylim)

    def calculate_cuts(self) :
        """ """
        if self.map.get() != 'Off' :
            # Create a copy of the original map (3D) data
            data = self.data.copy()
            # Slice and dice it
            self.cut1 = pp.make_slice(data, d=1, i=self.yind, integrate=1)
            self.cut2 = pp.make_slice(data, d=2, i=self.xind, integrate=1)
        else :
            z = self.z.get()
            self.cut1 = self.pp_data[z, self.yind, :]
            self.cut2 = self.pp_data[z, :, self.xind]

    def plot_cuts(self) :
        """ Plot cuts of whatever is in the bottom left ('map') axis along 
        the current positions of the cursors. 
        """
        self.calculate_cuts()

        # Clear the current cuts
        for ax in ['cut1', 'cut2'] :
            self.axes[ax].clear()

        # Get the right xscale/yscale information
        xscale, yscale = self.get_xy_scales()

        if self.map.get() != 'Off' :
            kwargs = dict(cmap=self.get_cmap())

            # Ensure zscale is defined
            if self.zscale is None :
                zscale = np.arange(self.cut1.shape[0])
            else :
                zscale = self.zscale

            # Plot x cut in upper left
            vmin, vmax = self.vminmax(self.cut1)
            kwargs.update(dict(vmin=vmin, vmax=vmax))
            self.cut1_plot = self.axes['cut1'].pcolormesh(xscale, zscale, 
                                                      self.cut1, **kwargs)
            # Plot y cut in lower right (rotated by 90 degrees)
            vmin, vmax = self.vminmax(self.cut2)
            kwargs.update(dict(vmin=vmin, vmax=vmax))
            self.cut2_plot = self.axes['cut2'].pcolormesh(zscale, yscale, 
                                                      self.cut2.T, **kwargs)
        else :
            # Plot the x cut in the upper left
            self.cut1_plot = self.axes['cut1'].plot(xscale, self.cut1, 
                                                    **cut_kwargs)[0]
            # Plot the y cut in the lower right
            self.cut2_plot = self.axes['cut2'].plot(self.cut2, yscale, 
                                                    **cut_kwargs)[0]

            # Make sure the cut goes over the full range of the plot
            #self.axes['cut2'].set_ymargin(0) # For some reason this doesn't work
            ymin = min(yscale)
            ymax = max(yscale)
            self.axes['cut2'].set_ylim([ymin, ymax])

    def get_plot_args_and_kwargs(self) :
        """ Prepare args and kwargs for plotting, depending on the 
        circumstances. """
        # Add x and y scales to args if available
        args = []
        if self.xscale is not None and self.yscale is not None :
            args.append(self.xscale)
            args.append(self.yscale)

        # Use z=0 in case of a map (as pp_data is of length 1 along this 
        # dimension as a result of pp_make_cut())
        if self.map.get() != 'Off' :
            z = 0
        else :
            z = self.z.get()

        args.append(self.pp_data[z,:,:])

        vmin, vmax = self.vminmax(self.pp_data)
        kwargs = dict(cmap=self.get_cmap(), vmin=vmin, 
                      vmax=vmax)
        return args, kwargs

    def plot_data(self, event=None, *args, **kwargs) :
        """ Update the colormap range and (re)plot the data. """
        # Remove old plots
        for ax in self.axes.values() :
            ax.clear()

        args, kwargs = self.get_plot_args_and_kwargs()
        # Do the actual plotting with just defined args and kwargs
        ax = self.axes['map']
        self.main_mesh = ax.pcolormesh(*args, **kwargs)

        self.bg_mesh = self.canvas.copy_from_bbox(ax.bbox)

        # Update the cursors (such that they are above the pcolormesh) and cuts
        self.plot_cursors()
        self.plot_cuts()
        self.plot_intensity()
        self.canvas.draw()

    def get_cmap(self) :
        """ Build the name of the colormap by combining the value stored in 
        `self.cmap` (the basename of the colormap) and `self.invert_cmap` 
        (either empty string or '_r', which is the suffix for inverted cmaps 
        in matplotlib) """
        # Build the name of the cmap
        cmap_name = self.cmap.get() + self.invert_cmap.get()
        # Make sure this name exists in the list of cmaps. Otherwise reset to 
        # default cmap
        try :
            cmap = get_cmap(cmap_name)
        except ValueError :
            # Notify user
            message = \
            'Colormap {} not found. Using default instead.'.format(cmap_name)
            self.update_status(message)
            # Set default
            cmap = get_cmap(self.cmaps[0])

        return cmap

    def vminmax(self, data) :
        """ Helper function that returns appropriate values for vmin and vmax
        for a given set of data. """
        # Note: vmin_index goes from 100 to 0 and vice versa for vmax_index.
        # This is to turn the sliders upside down.
        # Crude method to avoid unreasonable colormap settings
        if self.vmin_index.get() < self.vmax_index.get() :
            self.vmin_index.set(CM_SLIDER_RESOLUTION)

        # Split the data value range into equal parts
        #drange = np.linspace(self.pp_data.min(), data.max(), 
        #                     CM_SLIDER_RESOLUTION + 1)
        drange = np.linspace(data.min(), data.max(), 
                             CM_SLIDER_RESOLUTION + 1)

        # Get the appropriate vmin and vmax values from the data
        vmin = drange[CM_SLIDER_RESOLUTION - self.vmin_index.get()]
        vmax = drange[CM_SLIDER_RESOLUTION - self.vmax_index.get()]

        return vmin, vmax

    def get_xy_minmax(self) :
        """ Return the min and max for the x and y axes, depending on whether 
        xscale and yscale are defined. 
        """
        xscale, yscale =  self.get_xy_scales()

        xmin = min(xscale)
        xmax = max(xscale)
        ymin = min(yscale)
        ymax = max(yscale)

        return xmin, xmax, ymin, ymax

    def get_xy_scales(self) :
        """ Depending on whether we have actual data scales (self.xscale and 
        self.yscale are defined) or not, return arrays which represent data 
        coordinates. 
        """
        if self.xscale is None or self.yscale is None :
            shape = self.data.shape
            yscale = np.arange(0, shape[1], 1)
            xscale = np.arange(0, shape[2], 1)
        else :
            xscale = self.xscale
            yscale = self.yscale

        return xscale, yscale

    def snap_to(self, x, y) :
        """ Return the closest data value to the given values of x and y. """
        xscale, yscale = self.get_xy_scales()

        # Find the index where element x/y would have to be inserted in the 
        # sorted array.
        self.xind = np.searchsorted(xscale, x)
        self.yind = np.searchsorted(yscale, y)

        # Find out whether the lower or upper 'neighbour' is closest
        x_lower = xscale[self.xind-1]
        y_lower = yscale[self.yind-1]
        # NOTE In principle, these IndexErrors shouldn't occur. Try-except 
        # only helps when debugging.
        try :
            x_upper = xscale[self.xind]
        except IndexError :
            x_upper = max(xscale)
        try :
            y_upper = yscale[self.yind]
        except IndexError :
            y_upper = max(yscale)

        dx_upper = x_upper - x
        dx_lower = x - x_lower
        dy_upper = y_upper - y
        dy_lower = y - y_lower

        # Assign the exact data value and update self.xind/yind if necessary
        if dx_upper < dx_lower :
            x_snap = x_upper
        else :
            x_snap = x_lower
            self.xind -= 1
            
        if dy_upper < dy_lower :
            y_snap = y_upper
        else :
            y_snap = y_lower
            self.yind -= 1

        return x_snap, y_snap

    def plot_cursors(self) :
        """ Plot the cursors in the bottom left axis. """
        # Delete current cursors (NOTE: this is dangerous if there are any 
        # other lines in the plot)
        ax = self.axes['map']
        ax.lines = []

        # Retrieve information about current data range
        xmin, xmax, ymin, ymax = self.get_xy_minmax()
       
        xlimits = [xmin, xmax]
        ylimits = [ymin, ymax]

        # Initiate cursors in the center of graph if necessary
        if self.cursor_xy is None :
            x = 0.5 * (xmax + xmin)
            y = 0.5 * (ymax + ymin)

            # Keep a handle on cursor positions
            self.cursor_xy = (x, y)
        else : 
            x, y = self.cursor_xy

        # Make the cursor snap to actual data points
        x, y = self.snap_to(x, y)

        # Plot cursors and keep handles on them (need the [0] because plot() 
        # returns a list of Line objects)
        self.xcursor = ax.plot([x, x], ylimits, zorder=3, **cursor_kwargs)[0]
        self.ycursor = ax.plot(xlimits, [y, y], zorder=3, **cursor_kwargs)[0]

    def _set_up_event_handling(self) :
        """ Define what happens when user clicks in the plot (move cursors to 
        clicked position) or presses an arrow key (move cursors in specified 
        direction). 
        """
        def on_click(event):
            event_ax = event.inaxes
            if event_ax == self.axes['map'] :
                self.cursor_xy = (event.xdata, event.ydata)
                self.plot_cursors()
                # Also update the cuts
                self.plot_cuts()
                self.canvas.draw()
            elif event_ax == self.axes['energy'] and \
                 self.map.get() != 'Off' :
                if self.zscale is not None :
                    z = np.where(self.zscale > event.xdata)[0][0]
                else :
                    z = int(event.xdata)
                self.z.set(z)
                # Since z changed we need to apply the whole data processing
                # and replot
                self.process_data()
                
        def on_press(event):
            # Get the name of the pressed key and info on the current cursors
            key = event.key
            x, y = self.cursor_xy
            xmin, xmax, ymin, ymax = self.get_xy_minmax()

            # Stop if no arrow key was pressed
            if key not in ['up', 'down', 'left', 'right'] : return

            # Move the cursor by one unit in data points
            xscale, yscale = self.get_xy_scales()
            dx = xscale[1] - xscale[0]
            dy = yscale[1] - yscale[0]

            # In-/decrement cursor positions depending on what button was 
            # pressed and only if we don't leave the axis
            if key == 'up' and y+dy <= ymax :
                y += dy
            elif key == 'down' and y-dy >= ymin :
                y -= dy
            elif key == 'right' and x+dx <= xmax :
                x += dx
            elif key == 'left' and x-dx >= xmin:
                x -= dx

            # Update the cursor position and redraw it
            self.cursor_xy = (x, y)
            #self.plot_cursors()
            self.redraw_cursors()
            # Now the cuts have to be redrawn as well
            self.calculate_cuts()
            #self.plot_cuts()
            self.redraw_cuts()

        cid = self.canvas.mpl_connect('button_press_event', on_click)
        pid = self.canvas.mpl_connect('key_press_event', on_press)

        # Inititate the cursors
        self.plot_cursors()

    def save_plot(self) :
        """ Save a png image of the currently plotted data (only what is in 
        bottom left) """
        # Plot the same thing into a virtual figure such that a png can be 
        # created
        args, kwargs = self.get_plot_args_and_kwargs()
        self.vmain_mesh = self.axes['vax'].pcolormesh(*args, **kwargs)

        # Open a filebrowser where user can select a place to store the result
        filename = asksaveasfilename(filetypes=[('PNG', '*.png')])
        if filename :
            self.vfig.savefig(filename, transparent=True, dpi=self.dpi)
            self.update_status('Saved file {}.'.format(filename))
        else :
            self.update_status('Saving file aborted.')
Example #14
0
class wvpick(tk.Frame):
    # wvpick is a class to optimize the picking of horizons from radar data
    def __init__(self, parent, button_tip, reset_picks, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent
        self.button_tip = button_tip
        self.reset_picks = reset_picks
        self.winSize = tk.IntVar(value=100)
        self.stepSize = tk.IntVar(value=10)
        self.horVar = tk.StringVar()
        self.segVar = tk.IntVar()
        self.color = tk.StringVar()
        self.interp_type = tk.StringVar()
        self.interp_type.set("cubic")
        self.setup()

    def setup(self):
        # set up frames
        infoFrame0 = tk.Frame(self.parent)
        infoFrame0.pack(side="top", fill="both")
        infoFrame = tk.Frame(infoFrame0)
        infoFrame.pack(side="left", fill="both")
        interpFrame = tk.Frame(infoFrame0, width=450)
        interpFrame.pack(side="right", fill="both")
        interpFrame.pack_propagate(0)
        toolbarFrame = tk.Frame(infoFrame)
        toolbarFrame.pack(side="bottom", fill="both")
        self.dataFrame = tk.Frame(self.parent)
        self.dataFrame.pack(side="bottom", fill="both", expand=1)

        # infoFrame exists for options to be added based on optimization needs
        tk.Label(infoFrame,
                 text="Amplitude Window [#Samples]: ").pack(side="left")
        entry = tk.Entry(infoFrame, textvariable=self.winSize, width=5)
        entry.pack(side="left")
        self.button_tip(self.parent, entry, \
            "Pick amplitude window size. Window size (number of samples) centered on \
            manual picks from which to select maximum amplitude using auto-pick optimization."                                                                                              )
        tk.ttk.Separator(infoFrame, orient="vertical").pack(side="left",
                                                            fill="both",
                                                            padx=10,
                                                            pady=4)

        tk.Label(infoFrame, text="Step Size [#Traces]: ").pack(side="left")
        entry = tk.Entry(infoFrame, textvariable=self.stepSize, width=5)
        entry.pack(side="left")
        self.button_tip(self.parent, entry, \
            "Number of traces to move forward and backwards in radargram upon ←/→ button or key press.")
        tk.ttk.Separator(infoFrame, orient="vertical").pack(side="left",
                                                            fill="both",
                                                            padx=10,
                                                            pady=4)

        button = tk.Button(infoFrame,
                           text="←",
                           command=self.stepBackward,
                           pady=0)
        button.pack(side="left")
        self.button_tip(self.parent, button, "Step backwards")
        button = tk.Button(infoFrame,
                           text="→",
                           command=self.stepForward,
                           pady=0)
        button.pack(side="left")
        self.button_tip(self.parent, button, "Step forwards")
        tk.ttk.Separator(infoFrame, orient="vertical").pack(side="left",
                                                            fill="both",
                                                            padx=10,
                                                            pady=4)

        # set up frame to hold pick information
        interpFrameT = tk.Frame(interpFrame)
        interpFrameT.pack(fill="both", expand=True)
        interpFrameT.pack_propagate(0)
        interpFrameB = tk.Frame(interpFrame)
        interpFrameB.pack(fill="both", expand=True)
        interpFrameB.pack_propagate(0)

        interpFrameTl = tk.Frame(interpFrameT,
                                 width=250,
                                 relief="ridge",
                                 borderwidth=1)
        interpFrameTl.pack(side="left", fill="both", expand=True)
        interpFrameTl.pack_propagate(0)
        interpFrameTr = tk.Frame(interpFrameT, width=200)
        interpFrameTr.pack(side="left", fill="both", expand=True)
        interpFrameTr.pack_propagate(0)

        interpFrameBl = tk.Frame(interpFrameB,
                                 width=250,
                                 relief="ridge",
                                 borderwidth=1)
        interpFrameBl.pack(side="left", fill="both", expand=True)
        interpFrameBl.pack_propagate(0)
        interpFrameBr = tk.Frame(interpFrameB, width=200)
        interpFrameBr.pack(side="left", fill="both", expand=True)
        interpFrameBr.pack_propagate(0)

        tk.Label(interpFrameTl,
                 text="{0:<8}".format("Horizon:")).pack(side="left")
        button = tk.Button(interpFrameTl,
                           text="Reset",
                           width=6,
                           command=self.reset)
        button.pack(side="right")
        self.button_tip(self.parent, button,
                        "Reset pick data from profile interpretations")
        self.horMenu = tk.OptionMenu(interpFrameTl, self.horVar, *[None])
        self.horMenu.pack(side="right")
        self.horMenu.config(width=10)
        self.horVar.trace("w", self.update_seg_opt_menu)
        self.horVar.trace("w", self.seg_select)
        self.horVar.trace(
            "w", lambda *args, menu=self.horMenu: self.set_menu_color(menu))

        tk.Label(interpFrameBl,
                 text="{0:<8}".format("Segment:")).pack(side="left")
        button = tk.Button(interpFrameBl, text=None, width=6, command=None)
        button.config(relief="sunken", state="disabled")
        button.pack(side="right")
        self.segMenu = tk.OptionMenu(interpFrameBl, self.segVar, *[None])
        self.segMenu.pack(side="right")
        self.segMenu.config(width=10)
        self.segVar.trace("w", self.first_trace)

        button = tk.Radiobutton(interpFrameTr,
                                text="Linear",
                                variable=self.interp_type,
                                value="linear")
        button.pack(side="left", fill="both", expand=True)
        self.button_tip(
            self.parent, button,
            "Linear interpolation between manual pick modifications")

        button = tk.Radiobutton(interpFrameTr,
                                text="Cubic Spline",
                                variable=self.interp_type,
                                value="cubic")
        button.pack(side="left", fill="both", expand=True)
        self.button_tip(
            self.parent, button,
            "Cubic spline interpolation between manual pick modifications")

        button = tk.Button(interpFrameBr,
                           text="Auto-Optimize",
                           command=self.auto_repick)
        button.pack(side="left", fill="both", expand=True)
        self.button_tip(
            self.parent, button,
            "Automatically optimize profile view interpretation picks for current horizon segment\
                                            by selecting maximum aplitude sample for each radargram trace within a window of the\
                                            specified size centered on existing profile picks."
        )

        button = tk.Button(interpFrameBr,
                           text="Interpolate",
                           command=self.interp_repick)
        button.pack(side="left", fill="both", expand=True)
        self.button_tip(
            self.parent, button,
            "Interpolate between manually updated waveform picks using the spefied interpolation method\
                                            for  current horizon segment.")

        # create figure object and datacanvas from it
        plt.rcParams.update({'font.size': 12})
        self.fig = mpl.figure.Figure()
        self.fig.patch.set_facecolor("#d9d9d9")
        self.dataCanvas = FigureCanvasTkAgg(self.fig, self.parent)
        self.dataCanvas.get_tk_widget().pack(in_=self.dataFrame,
                                             side="bottom",
                                             fill="both",
                                             expand=1)
        self.click = self.fig.canvas.mpl_connect("button_press_event",
                                                 self.onpress)
        self.unclick = self.fig.canvas.mpl_connect('button_release_event',
                                                   self.onrelease)
        self.draw_cid = self.fig.canvas.mpl_connect("draw_event",
                                                    self.update_bg)
        self.mousemotion = self.fig.canvas.mpl_connect('motion_notify_event',
                                                       self.on_mouse_move)

        # add toolbar to plot
        self.toolbar = NavigationToolbar2Tk(self.dataCanvas, toolbarFrame)
        self.toolbar.pack(side="left")
        # self.toolbar.update()

        # create the figure axes
        self.ax = self.fig.add_subplot(111)
        self.fig.tight_layout(rect=[.02, .05, .97, 1])
        self.ax.set_visible(False)

        # update the canvas
        self.dataCanvas._tkcanvas.pack()
        self.dataCanvas.draw()

    # set up variables
    def set_vars(self):
        self.rdata = None
        self.horizon_paths_opt = None
        self.ln_colors = {}
        self.horizons = []
        self.repick_idx = {
        }  # dictionary of indeces of repicked traces for each seg
        self.t = None  # hold current trace number

    # set_data is a method to receive the radar data
    def set_data(self, rdata):
        # get data in dB
        self.rdata = rdata

    # receive horizon paths from impick
    def set_horizon_paths(self, horizon_paths):
        self.horizon_paths = copy.deepcopy(horizon_paths)
        self.horizon_paths_opt = copy.deepcopy(horizon_paths)
        self.horizons = list(self.horizon_paths_opt)
        self.nhorizons = len(self.horizons)
        self.update_hor_opt_menu()
        self.update_seg_opt_menu()

    # return optimized horizon paths
    def get_horizon_paths(self):
        return self.horizon_paths_opt

    # receive horizon line colors
    def set_horizon_colors(self, ln_colors):
        self.ln_colors = ln_colors

    # reset returns updated picks from gui
    def reset(self):
        if tk.messagebox.askyesno("Reset",
                                  "Reset optimized horizon interpretations?"):
            self.reset_picks(force=True)

    # set_picks is a method which receives horizon interpretations for optimization
    def set_picks(self):
        self.ax.set_visible(True)
        # create lists of first and last picked trace number for each seg in each horizon
        self.segment_traces = {}
        # create dict to hold current trace number for each horizon
        self.trace = {}
        if self.nhorizons > 0:
            # iterate through horizon_paths
            for horizon, hdict in self.horizon_paths_opt.items():
                self.segment_traces[horizon] = bounds([], [])
                self.repick_idx[horizon] = []
                self.trace[horizon] = None
                # iterate through segments for each horizon
                for seg, path in hdict.items():
                    picked_traces = np.where(~np.isnan(path.x))[0]
                    if picked_traces.shape[0] > 0:
                        self.segment_traces[horizon].first.append(
                            picked_traces[0])
                        self.segment_traces[horizon].last.append(
                            picked_traces[-1])
                        if seg == 0:
                            self.trace[horizon] = picked_traces[0]
            # set horVar
            self.horVar.set(self.horizons[-1])
        else:
            self.trace[""] = 0

    # plot_wv is a method to draw the waveform on the datacanvas
    def plot_wv(self, *args):
        horizon = self.horVar.get()
        seg = self.segVar.get()
        winSize = self.winSize.get()
        # get previous x_lim
        xlim = self.ax.get_xlim()
        self.ax.clear()

        # plot trace power
        self.t = self.trace[horizon]
        self.ax.plot(self.rdata.proc.curr_dB[:, self.t], c="0.5")
        self.ax.set(xlabel="Sample",
                    ylabel="Power [dB]",
                    title="Trace: " + str(int(self.trace[horizon] + 1)) + "/" +
                    str(int(self.rdata.tnum)))

        # get pick value range
        val = np.array(())

        # if self.nhorizons > 0:
        for horizon in self.horizons:
            # get sample index of pick for given trace
            for seg in self.horizon_paths_opt[horizon].keys():
                pick_idx0 = self.horizon_paths[horizon][seg].y[self.t]
                pick_idx1 = self.horizon_paths_opt[horizon][seg].y[self.t]
                val = np.append(val, (pick_idx0 + pick_idx1) // 2)
                if not np.isnan(pick_idx0):
                    self.ax.axvline(x=pick_idx0,
                                    c=self.ln_colors[horizon],
                                    label=horizon + "_" + str(seg))
                    if not np.isnan(pick_idx1) and (pick_idx0 != pick_idx1):
                        self.ax.axvline(x=pick_idx1,
                                        c=self.ln_colors[horizon],
                                        ls="--",
                                        label=horizon + "_" + str(seg) + "_v2")

        self.ax.set(xlim=(0, self.rdata.snum))
        # save un-zoomed view to toolbar
        self.toolbar.push_current()

        # zoom in to window around horizons
        if not np.isnan(val).all():
            if xlim == (0, 1) or xlim == (0, self.rdata.snum):
                min_ = np.nanmin(val) - (2 * winSize)
                max_ = np.nanmax(val) + (2 * winSize)
                self.ax.set(xlim=(min_, max_))
            else:
                self.ax.set(xlim=xlim)

        if len(self.ax.lines) > 1:
            self.ax.legend(loc="lower right")

        # initialize cursor crosshair lines
        self.horizontal_line = self.ax.axhline(color="r", lw=1, ls=":")
        self.vertical_line = self.ax.axvline(color="r", lw=1, ls=":")

        self.dataCanvas.draw()

    # full extent for trace
    def fullExtent(self):
        horizon = self.horVar.get()
        self.ax.set_xlim(0, self.rdata.snum)
        self.ax.set_ylim(self.rdata.proc.curr_dB[:, self.trace[horizon]].min(),
                         self.rdata.proc.curr_dB[:, self.trace[horizon]].max())
        self.dataCanvas.draw()

    # stepBackward is a method to move backwards by the number of traces entered to stepSize
    def stepBackward(self):
        horizon = self.horVar.get()
        seg = self.segVar.get()
        step = self.stepSize.get()
        newTrace = self.trace[horizon] - step
        if self.nhorizons > 0:
            firstTrace_seg = self.segment_traces[horizon].first[seg]
            if newTrace >= firstTrace_seg:
                self.trace[horizon] -= step
            elif newTrace < firstTrace_seg:
                if self.trace[horizon] == firstTrace_seg:
                    return
                else:
                    self.trace[horizon] = firstTrace_seg

        else:
            if newTrace >= 0:
                self.trace[0] -= step
            elif newTrace < 0:
                if self.trace[0] == 0:
                    return
                else:
                    self.trace[0] = 0

        self.plot_wv()

    # stepForward is a method to move forward by the number of traces entered to stepSize
    def stepForward(self):
        horizon = self.horVar.get()
        seg = self.segVar.get()
        step = self.stepSize.get()
        newTrace = self.trace[horizon] + step
        if self.nhorizons > 0:
            lastTrace_seg = self.segment_traces[horizon].last[seg]
            if newTrace <= lastTrace_seg:
                self.trace[horizon] += step
            # if there are less traces left in the pick seg than the step size, move to the last trace in the seg
            elif newTrace > lastTrace_seg:
                if self.trace[horizon] == lastTrace_seg:
                    return
                    # if seg + 2 <= self.nhorizons and tk.messagebox.askokcancel("Next Sement","Finished optimization of current pick seg\n\tProceed to next seg?") == True:
                    # self.segVar.set(seg + 1)
                else:
                    self.trace[horizon] = self.segment_traces[horizon].last[
                        seg]

        else:
            if newTrace <= self.rdata.tnum:
                self.trace[0] += step
            elif newTrace > self.rdata.tnum:
                if self.trace[0] == self.rdata.tnum - 1:
                    return
                else:
                    self.trace[0] = self.rdata.tnum - 1

        self.plot_wv()

    # seg_select
    def seg_select(self, *args):
        if self.t is None:
            return
        horizon = self.horVar.get()
        seg = self.segVar.get()
        self.trace[horizon] = self.t
        t0_list = self.segment_traces[horizon].first
        t1_list = self.segment_traces[horizon].last
        # if switched horizon, select segment which has current trace, if any
        for _i in range(len(t0_list)):
            if (t0_list[_i] < self.t) and (t1_list[_i] > self.t):
                self.segVar.set(_i)
                self.t = None
                break
            else:
                continue

    # first_trace updates the segment selection sets self.trace[horizon] to the first trace for the selected segment and replots
    def first_trace(self, *args):
        if self.t is not None:
            horizon = self.horVar.get()
            seg = self.segVar.get()
            t0_list = self.segment_traces[horizon].first
            if seg > len(t0_list):
                return
            self.trace[horizon] = t0_list[seg]
        # reset xlim
        self.ax.set(xlim=(0, self.rdata.snum))
        self.plot_wv()

    # auto_repick is a method to automatically optimize subsurface picks by selecting the maximul amplitude sample within the specified window around existing picks
    def auto_repick(self):
        if self.nhorizons > 0:
            horizon = self.horVar.get()
            seg = self.segVar.get()
            winSize = self.winSize.get()
            x = np.arange(self.segment_traces[horizon].first[seg],
                          self.segment_traces[horizon].last[seg] + 1)
            y = self.horizon_paths[horizon][seg].y[x]
            for _i in range(len(x)):
                if not np.isnan(y[_i]):
                    # find argmax for window for given data trace in pick
                    max_idx = np.nanargmax(self.rdata.proc.curr_dB[
                        int(y[_i] - (winSize / 2)):int(y[_i] + (winSize / 2)),
                        x[_i]])
                    # add argmax index to pick_dict1 - account for window index shift
                    self.horizon_paths_opt[horizon][seg].y[
                        x[_i]] = max_idx + int(y[_i] - (winSize / 2))
            self.plot_wv()

    # manual_repick is a method to manually adjust existing picks by clicking along the displayed waveform
    def manual_repick(self, event):
        if (not self.nhorizons > 0) or (event.inaxes != self.ax):
            return
        horizon = self.horVar.get()
        seg = self.segVar.get()
        # append trace number to repick_idx list to keep track of indeces for interpolation
        if (len(self.repick_idx[horizon])
                == 0) or (self.repick_idx[horizon][-1] != self.trace[horizon]):
            self.repick_idx[horizon].append(self.trace[horizon])

        self.horizon_paths_opt[horizon][seg].y[self.trace[horizon]] = int(
            event.xdata)
        self.plot_wv()

    # interp_repick is a method to interpolate between manually refined subsurface picks
    def interp_repick(self):
        horizon = self.horVar.get()
        seg = self.segVar.get()
        interp = self.interp_type.get()
        if len(self.repick_idx[horizon]) < 2:
            return
        # get indeces of repicked traces
        xp = self.repick_idx[horizon]
        # generate array of indices between first and last optimized pick
        interp_idx = np.arange(xp[0], xp[-1] + 1)

        if interp == "linear":
            # get twtt values at repicked indicesself.pick_dict1
            fp = self.horizon_paths_opt[horizon][seg].y[xp]
            # interpolate repicked values for seg
            self.horizon_paths_opt[horizon][seg].y[interp_idx] = np.interp(
                interp_idx, xp, fp)

        elif interp == "cubic":
            # cubic spline between picks
            cs = CubicSpline(xp, self.horizon_paths_opt[horizon][seg].y[xp])
            # add cubic spline output interpolation to pick dictionary
            self.horizon_paths_opt[horizon][seg].y[interp_idx] = cs(
                [interp_idx]).astype(int)

    # set tkinter menu font colors to match color name
    def set_menu_color(self, menu=None, *args):
        horizon = self.horVar.get()
        if not horizon:
            return
        c = self.ln_colors[horizon]
        menu.config(foreground=c, activeforeground=c, highlightcolor=c)

    # update the horizon menu
    def update_hor_opt_menu(self):
        self.horizons = list(self.horizon_paths_opt.keys())
        self.horMenu["menu"].delete(0, "end")
        for i, horizon in enumerate(self.horizons):
            c = self.ln_colors[horizon]
            self.horMenu["menu"].add_command(label=horizon,
                                             foreground=c,
                                             activeforeground=c,
                                             command=tk._setit(
                                                 self.horVar, horizon))

    # update the horizon seg menu based on how many segments exist for given seg
    def update_seg_opt_menu(self, *args):
        horizon = self.horVar.get()
        self.segMenu["menu"].delete(0, "end")
        if horizon:
            for seg in sorted(self.horizon_paths_opt[horizon].keys()):
                self.segMenu["menu"].add_command(label=seg,
                                                 command=tk._setit(
                                                     self.segVar, seg))

    # show_artists
    def show_artists(self, val=True):
        for _i in self.ax.lines:
            _i.set_visible(val)

    # temporarily disconnect the draw_event callback to avoid recursion
    def safe_draw(self):
        canvas = self.fig.canvas
        canvas.mpl_disconnect(self.draw_cid)
        canvas.draw()
        self.draw_cid = canvas.mpl_connect("draw_event", self.update_bg)

    # when the figure is resized, hide picks, draw everything, and update the background image
    def update_bg(self, event=None):
        # temporarily hide artists
        self.show_artists(False)
        self.safe_draw()
        self.axbg = self.dataCanvas.copy_from_bbox(self.ax.bbox)
        # return artists visiblity to former state
        self.show_artists(True)
        self.blit()

    # update the figure, without needing to redraw the "axbg" artists
    def blit(self):
        self.fig.canvas.restore_region(self.axbg)
        for _i in self.ax.lines:
            self.ax.draw_artist(_i)
        self.fig.canvas.blit(self.ax.bbox)

    # onpress gets the time of the button_press_event
    def onpress(self, event):
        self.time_onclick = time.time()

    # onrelease calls manual_repick if the time between the button press and release events
    # is below a threshold so that segments aren't drawn while trying to zoom or pan
    def onrelease(self, event):
        if event.inaxes == self.ax:
            if event.button == 1 and (
                (time.time() - self.time_onclick) < 0.25):
                self.manual_repick(event)

    # on_mouse_move blit crosshairs
    def on_mouse_move(self, event):
        if self.rdata is None:
            return
        x = event.xdata
        y = event.ydata
        if event.inaxes == self.ax:
            y = self.rdata.proc.curr_dB[int(x), self.trace[self.horVar.get()]]
        self.horizontal_line.set_ydata(y)
        self.vertical_line.set_xdata(x)
        self.ax.figure.canvas.restore_region(self.axbg)
        self.ax.draw_artist(self.horizontal_line)
        self.ax.draw_artist(self.vertical_line)
        self.blit()

    # update_figsettings
    def update_figsettings(self, figsettings):
        self.figsettings = figsettings

        plt.rcParams.update({'font.size': self.figsettings["fontsize"].get()})

        for item in (
            [self.ax.title, self.ax.xaxis.label, self.ax.yaxis.label] +
                self.ax.get_xticklabels() + self.ax.get_yticklabels()):
            item.set_fontsize(self.figsettings["fontsize"].get())

        self.ax.title.set_visible(self.figsettings["figtitle"].get())

        self.fig.canvas.draw()

    # clear is a method to clear the wavePick tab and stored data when a new track is loaded
    def clear(self):
        self.ax.clear()
        self.dataCanvas.draw()
        self.set_vars()
Example #15
0
class CellCounter(tk.Tk):
    def __init__(self, *args, **kwargs):

        # Set up overall GUI
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, "Cell Counter")
        tk.Grid.columnconfigure(self, 0, weight=1)
        tk.Grid.rowconfigure(self, 0, weight=1)

        # Set up container frame
        container = tk.Frame(self)
        tk.Grid.columnconfigure(container, 0, weight=100)
        tk.Grid.columnconfigure(container, 1, weight=1)
        tk.Grid.columnconfigure(container, 2, weight=1)
        tk.Grid.rowconfigure(container, 0, weight=1)
        tk.Grid.rowconfigure(container, 1, weight=100)
        tk.Grid.rowconfigure(container, 2, weight=1)
        container.grid(row=0, column=0, sticky=tk.N + tk.S + tk.E + tk.W)

        # Set up matplotlib stuff
        self.fig = Figure(figsize=(5, 5), dpi=100)
        self.ax = self.fig.add_subplot(111)

        self.canvas = FigureCanvasTkAgg(self.fig, container)
        self.canvas.draw()
        self.canvas.get_tk_widget().grid(row=1,
                                         column=0,
                                         columnspan=3,
                                         padx=10,
                                         pady=5,
                                         sticky=tk.N + tk.S + tk.E + tk.W)
        self.axbg = self.canvas.copy_from_bbox(self.ax.bbox)

        toolbar_frame = tk.Frame(container)
        toolbar_frame.grid(row=2,
                           column=0,
                           columnspan=3,
                           padx=10,
                           pady=5,
                           sticky=tk.N + tk.S + tk.E + tk.W)
        self.toolbar = CustomToolbar(self.canvas, toolbar_frame, self)
        self.toolbar.pack(side=tk.LEFT)
        self.toolbar.update()

        # Set up buttons / entries
        self.fname = tk.StringVar()
        self.fname.set("Image filename")
        self.fname_entry = tk.Entry(container,
                                    width=10,
                                    textvariable=self.fname,
                                    justify='left')
        self.fname_entry.grid(row=0,
                              column=0,
                              padx=10,
                              pady=5,
                              sticky=tk.N + tk.S + tk.E + tk.W)

        self.browse_button = tk.Button(container,
                                       text="Browse",
                                       command=self.selectFile)
        self.browse_button.grid(row=0,
                                column=1,
                                padx=10,
                                pady=5,
                                sticky=tk.N + tk.S + tk.E + tk.W)

        self.run_button = tk.Button(container, text="Run", command=self.run)
        self.run_button.grid(row=0,
                             column=2,
                             padx=10,
                             pady=5,
                             sticky=tk.N + tk.S + tk.E + tk.W)

        self.paint_button = tk.Button(toolbar_frame,
                                      text="Paint",
                                      command=self.paint)
        self.paint_button.pack(side=tk.RIGHT)

        self.erase_button = tk.Button(toolbar_frame,
                                      text="Erase",
                                      command=self.erase)
        self.erase_button.pack(side=tk.RIGHT)

    def run(self):

        imageFile = self.fname.get()

        if not path.isfile(imageFile):
            return

        self.greenImg, self.redImg, self.greenCells, self.redCells = cc.findCells(
            imageFile)
        self.greenImShow = self.ax.imshow(self.greenImg,
                                          interpolation='None',
                                          animated=True)
        self.cellImShow = self.ax.imshow(self.greenCells,
                                         alpha=.1,
                                         interpolation='None',
                                         animated=True)

        self.ax.set_position([.05, .05, .9, .9])
        self.canvas.draw()

    def selectFile(self):
        imageFile = filedialog.askopenfilename(
            title="Select Image File",
            filetypes=(("tif files", "*.tif"), ("all files", "*.*")))
        self.fname.set(imageFile)

    def paint(self):
        return

    def erase(self):
        return
Example #16
0
class Application(Frame):
	def __init__(self, master=None):
		Frame.__init__(self, master)
		self.parent = master
		self.top = Frame()
		self.top.grid()
		self.top.update_idletasks()
		self.vertical_limit = 0.0
		self.horizontal_limit_1 = 0.0
		self.horizontal_limit_0 = 0.0
		
		master.columnconfigure(0, weight=1)
		master.rowconfigure(0, weight=1)

		self.top.columnconfigure(0, weight=1)
		self.top.rowconfigure(0, weight=1)
		
		self.x = 0
		self.i = 0
		self.delta_i = 1
		self.update = 2
		# maximum number of points to acquire
		self.n_data = 10000     
		self.xy_data = []

		width = root.winfo_screenwidth() / dpi

		# figsize (w,h tuple in inches) dpi (dots per inch)
		self.figure = pyplot.figure(figsize=(width,12), dpi=dpi, facecolor='#DCDCDC')
		
		self.subplot = self.figure.add_subplot(211, axisbg='#DCDCDC')
		self.subplot.grid(True)

		# define amplitude dos eixos
		#self.subplot.axis([0, horizontal_scale, -vertical_scale, vertical_scale])
		self.ax = self.subplot.axis([0, horizontal_scale, 0, vertical_scale])
		self.subplot.set_xbound(lower=0, upper=None)

		pyplot.xlabel('s')
		pyplot.ylabel('mV')

		self.tupla = self.subplot.transData.transform([(0,1),(1,0)])-self.subplot.transData.transform((0,0))
		#print self.tupla
	 
		self.line, = self.subplot.plot([],[], animated=True) # initialize line to be drawn
		# Note: The comma after line is because the right hand size returns
		#   a one element list, and we want to unpack that single element
		#   into line, not assign the list to line.
		self.text = pyplot.figtext(0.05,0.25,"") # initialize text section

		self.canvas = FigureCanvasTkAgg(self.figure, master=root)
		self.canvas.get_tk_widget().configure(highlightcolor='#DCDCDC')
		self.canvas.get_tk_widget().grid(row=2,column=0,columnspan=3)
		self.background = self.canvas.copy_from_bbox(self.subplot.bbox)


		#Cria a barra de ferramentas
		toolbar_frame = Frame(self.parent)
		toolbar_frame.grid(row=1, pady= 31, sticky=W+N) 
		#toolbar_frame.grid(row=1, sticky=W+S) 
		toolbar = CustomToolbar(self.canvas,toolbar_frame)

		#toolbar.grid(row=0, column=1)

		toolbar_frame.columnconfigure(0, weight=1)
		toolbar_frame.rowconfigure(0, weight=1)

		self.button_text = ['Iniciar','Pausar', 'Parar']
		self.buttons = [None] * len(self.button_text)
		self.buttonframe = Frame(root)
		#self.buttonframe.columnconfigure(0, weight=10)  
		#self.buttonframe.rowconfigure(0, weight=30)  
		self.buttonframe.grid(row=1, sticky=N+W) 

		for button_index in range(len(self.button_text)):
			button_id = Button(self.buttonframe, text = self.button_text[button_index])
			#button_id.columnconfigure(button_index)
			button_id.grid(row=0, column=button_index)
			self.buttons[button_index] = button_id

			def button_handler(event, self=self, button=button_index):
				return self.service_buttons(button)

			button_id.bind("<Button-1>", button_handler)

		#variáveis de configuração do módulo
		self.constant = 1
		self.offset = 0
		self.gain = 1
		self.baud_rate = 115200
		self.sampling_rate = 240
		self.connect = 2

		self.GDFile = open("gdf_data_" + time.strftime("%H:%M") +".dat", "wb")
		self.flag_file = 0
   		#self.writer = csv.writer(GDFile)
		
		self.module_frame()

	def module_frame(self):
		 #criação do painel que mostra as configurações do módulo na tela principal da interface
		self.ModuleBox = Text(self.parent, bg=mygreen, height= 6, width=45, relief="flat")
		self.ModuleBox.grid(row = 1,sticky="n")

		self.ModuleBox.tag_configure('title', justify='center', font=('Kreativ', 10), foreground='white')
		self.ModuleBox.tag_configure('preferences', font=('Kreativ', 9), foreground='white')

		self.ModuleBox.insert(INSERT, "Módulo" + "\n", 'title')

		fields = 'Constante de Conversão para Volts: ' + str(self.constant), 'Deslocamento (Offset): ' + str(self.offset) + ' V', 'Ganho: ' + str(self.gain),'Taxa de Transmissão: ' + str(self.baud_rate) + ' Bps', 'Taxa de Amostragem: ' + str(self.sampling_rate)
		
		for field in fields:
			self.ModuleBox.insert(INSERT, field + "\n", 'preferences')
		self.ModuleBox.configure(state='disable')    


	# buttons can be used to start and pause plotting
	def service_buttons(self, toolbar_index):
		if toolbar_index == 0:
			self.stop = False
			if self.connect == 0:
				self.serial_data()
				#plotter.plot(self, vertical_scale, horizontal_scale)  
			elif self.connect == 1:
				self.bluetooth_data()
			else:
				tkMessageBox.showerror("Erro", "Nenhum módulo de aquisição conectado")
				return    
			plotter.plot(self, vertical_scale, horizontal_scale)        
		else:
			self.stop = True
			if toolbar_index == 2: 
				if self.connect == 0:
					self.proc.terminate()
					self.ser.close()
					self.serial_queue.close()
					print("Porta serial fechada")       

				elif self.connect == 1:
					self.procb.terminate()		
				print("Parar")    
			else:
				print("Pausar") 

	def connect_serial(self, cb_port, cb_parity, cb_RTS, cb_DTR, win):
		self.connect = 0
		
		self.port = cb_port.get()
		self.parity = cb_parity.get()       

		self.RTS = cb_RTS.get()
		self.DTR = cb_DTR.get()

		print("Conectando à porta serial %s" % self.port)
		#print self.parity
		win.destroy()

	def serial_data(self):
		self.serial_queue = Queue()
	   
		#abre a porta serial
		try:
			self.ser = serial.Serial(self.port, self.baud_rate)   #conecta à porta correta

		except:
			print("Falhou ao conectar com a porta serial")
			return    

		print("Conexão à porta serial com sucesso")
		self.ser.close()
		self.ser.open()

		if self.parity == 'Par':
			self.parity = serial.PARITY_EVEN
			print("par")
		elif self.parity == 'Ímpar':
			self.parity = serial.PARITY_ODD
		else:
			self.parity = serial.PARITY_NONE

		if self.RTS == 'Ativado':
			self.ser.setRTS(True)
			print("RTS Ativado")

		if self.DTR == 'Ativado':
			self.ser.setDTR(True)
			print("DTR Ativado")

		self.proc = Process(target=serialRead.leitura_serial_driver, args=(self.serial_queue, self.ser))
		self.proc.start()

	def connect_bluetooth(self, addr):
		self.addr = addr
		self.connect = 1	    

	def bluetooth_data(self):
		self.bluetooth_queue = Queue()

		print("Procurando por um servidor em %s" % self.addr)

		service_matches = find_service(address = self.addr)
		flag = 0

		if len(service_matches) == 0:
			print("não foi possível encontrar um serviço")
			port = 1
			flag = 1

		else:
			first_match = service_matches[0]
			port = first_match["port"]
			name = first_match["name"]
			addr = first_match["host"]
			flag = 1

			print ("conectando a \"%s\" em %s na porta %s" % (name, host, port))

		sock = BluetoothSocket(RFCOMM)
		addr = self.addr
		sock.connect((addr, port))

		print ("CONECTADO")

		self.procb = Process(target=bluetoothRead.leitura_bluetooth_driver, args=(self.bluetooth_queue, sock))
		self.procb.start()

	def save_preferences(self, win, entries):
		i = 0
		for entry in entries:
			if (entry[1].get() != ''):
				if (i == 0):
					self.constant = float(entry[1].get())
				elif (i==1):
					self.offset = float(entry[1].get())
					print(self.offset)
				elif (i==2):
					self.gain = float(entry[1].get())
				elif (i==3):
					self.baud_rate = int(entry[1].get())
				elif (i==4):
					self.sampling_rate = float(entry[1].get())	
			i+=1
		
		win.destroy()
		self.module_frame()    

	def vertical_gain(self, gain):
		self.vertical_limit = (((self.tupla[0][1] * 25.4) / dpi) * vertical_scale) / gain

		if self.horizontal_limit_1 != 0:
			self.subplot.axis([self.horizontal_limit_0, self.horizontal_limit_1, -(self.vertical_limit), self.vertical_limit])
		else:   
			self.subplot.axis([self.subplot.get_xlim()[0], self.subplot.get_xlim()[1], -(self.vertical_limit), self.vertical_limit])

		self.canvas.draw()
		print ("ganho vertical setado para %.2f mm/mV" % gain)
	 
	def horizontal_gain(self, gain):
		#limite superior
		if (self.subplot.get_xlim()[1] - self.subplot.get_xlim()[0]) == horizontal_scale:
			self.horizontal_limit_1 = ((((self.tupla[1][0] * 25.4) / dpi) * horizontal_scale) / gain) + self.subplot.get_xlim()[0]
			print (self.horizontal_limit_1)
		else:
			if self.subplot.get_xlim()[0] > 0:
				self.horizontal_limit_1 = (((self.tupla[1][0] * 25.4) / dpi) * (horizontal_scale+self.subplot.get_xlim()[0])) / gain
			else:
				self.horizontal_limit_1 = (((self.tupla[1][0] * 25.4) / dpi) * horizontal_scale) / gain

		#limite inferior
		self.horizontal_limit_0 = self.subplot.get_xlim()[0]

		if self.vertical_limit != 0:
			self.subplot.axis([self.horizontal_limit_0, self.horizontal_limit_1, -(self.vertical_limit), self.vertical_limit])
		else:
			self.subplot.axis([self.horizontal_limit_0, self.horizontal_limit_1, -(vertical_scale), vertical_scale])

		self.canvas.draw()
		print ("ganho horizontal setado para %.2f mm/s" % gain)

	def serial_ports(self):
		""" Lists serial port names

			:raises EnvironmentError:
				On unsupported or unknown platforms
			:returns:
				A list of the serial ports available on the system
		"""
		if sys.platform.startswith('win'):
			ports = ['COM%s' % (i + 1) for i in range(256)]
		elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
			# this excludes your current terminal "/dev/tty"
			ports = glob.glob('/dev/tty[A-Za-z]*')
		elif sys.platform.startswith('darwin'):
			ports = glob.glob('/dev/tty.*')
		else:
			raise EnvironmentError('Unsupported platform')

		result = []
		for port in ports:
			try:
				s = serial.Serial(port)
				s.close()
				result.append(port)
			except (OSError, serial.SerialException):
				pass
		return result 

	def gdfConstruct(self, win, entries, cb_valor1, cb_valor2, cb_valor3, cb_valor4, cb_valor5, cb_valor6, cb_valor7, cb_valor8):
		if self.flag_file == 1:
			self.GDFile = open("gdf_data_" + time.strftime("%H:%M") +".dat", "wb")

		i = 0
		out = ''
		versionId = 'GDF 2.10' 
		self.GDFile.write(struct.pack('8s', versionId))
		#out = ''.join(format(ord(i),'b').zfill(8) for i in versionId)

		saida = []
		saida.extend((cb_valor1.get(), cb_valor2.get(), cb_valor3.get(), cb_valor4.get(), cb_valor5.get(), cb_valor6.get(), cb_valor7.get(), cb_valor8.get()))

		j = 0	
		for entry in entries:
			if j == 0:
				self.GDFile.write(struct.pack('66s', entry[1].get()))
				#out += ''.join(format(ord(i),'b').zfill(8) for i in idP)
				
				#campo reservado
				self.GDFile.write(struct.pack('QH', 0, 0))

				i = 0
				while i<4:
					if saida[i] == 'Desconhecido':
						out += '00'
					elif saida[i] == 'Sim':
						out += '10'
					else:
						out += '01'
					i+=1

				self.GDFile.write(struct.pack('s', out))		
			
			if (j == 1 or j == 2 or j == 5):
				if entry[1].get() != '':
					self.GDFile.write(struct.pack('B', int(float(entry[1].get()))))
					#out += '{0:08b}'.format(int(float(entry[1].get())))
				if j == 2:
					out = ''
					i=0
					while i < 4:
						if i == 0:
							if saida[i] == 'Masculino':
								out += '01'
							elif saida[i] == 'Feminino':
								out+= '10'
							else:
								out += '11'	
						elif i == 1:
							if saida[i] == 'Desconhecido':
								out += '00'
							elif saida[i] == 'Destro':
								out += '01'
							elif saida[i] == 'Canhoto':
								out += '10'
							else:
								out+= '11'
						else:
							if saida[i] == 'Desconhecido':
								out += '00'
							elif unicode(saida[i]) == unicode(u'Não'):
								out += '01'
							elif saida[i] == 'Sim':
								out += '10'
							else:
								out+= '11'
						i+=1
					
					self.GDFile.write(struct.pack('s', out))

			if j == 3:
				self.GDFile.write(struct.pack('I', int(time.strftime("%d%m"))))
				self.GDFile.write(struct.pack('I', int(time.strftime("%H%M"))))

				#startdate = time.strftime("%d%m") + time.strftime("%H%M")
				#for sd in startdate:
				#	print '{0:08b}'.format(int(sd))	

				dates = entry[1].get().translate(None, "/")
				for date in dates:
					#out += '{0:08b}'.format(int(date))
					self.GDFile.write(struct.pack('>i', int(date)))	

			elif j == 4:		
				self.GDFile.write(struct.pack('6s', entry[1].get()))

			elif (j == 6 or j == 7):
				#eletrodo positions	

				#number of data records
				self.GDFile.write(struct.pack('q', -1))

				
			j+=1

		self.flag_file = 1	
		win.destroy()	   

	def save_figure(self):
		ftypes = [('PNG', '*.png')]
		filename = tkFileDialog.asksaveasfilename(initialdir = "/home", filetypes = ftypes)
		self.figure.savefig(filename, bbox_inches='tight') 
Example #17
0
class Viewer(tk.Frame):
    def __init__(self, parent, collection=None, with_toolbar=True):
        tk.Frame.__init__(self, parent)
        # toolbar
        if with_toolbar:
            self.create_toolbar()

        # canvas
        #canvas_frame = tk.Frame(self)
        #canvas_frame.pack(side=tk.LEFT,fill=tk.BOTH,expand=1)
        #title_frame = tk.Frame(canvas_frame)
        #title_frame.pack(side=tk.TOP,anchor=tk.NW)
        #tk.Label(title_frame,text=" Plot Title: ").pack(side=tk.LEFT)
        #self._title = tk.Entry(title_frame,width=30)
        #self._title.pack(side=tk.LEFT)
        #tk.Button(title_frame, text='Set', command=lambda: self.updateTitle()
        #        ).pack(side=tk.LEFT)

        self.fig = plt.Figure(figsize=(8, 6))
        self.ax = self.fig.add_subplot(111)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self)
        self.setupMouseNavigation()
        self.navbar = ToolBar(self.canvas, self,
                              self.ax)  # for matplotlib features
        self.setupNavBarExtras(self.navbar)
        self.canvas.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH, expand=1)
        # spectra list
        self.create_listbox()
        # toggle options
        self.mean = False
        self.median = False
        self.max = False
        self.min = False
        self.std = False

        self.spectrum_mode = False
        self.show_flagged = True
        # data
        self.collection = collection
        self.head = 0
        self.flag_filepath = os.path.abspath('./flagged_spectra.txt')
        if collection:
            self.update_artists(new_lim=True)
            self.update_list()

        # pack
        self.pack(fill=tk.BOTH, expand=1)
        self.color = '#000000'

    def returnToSelectMode(self):
        if self.ax.get_navigate_mode() == 'PAN':
            #Turn panning off
            self.navbar.pan()
        elif self.ax.get_navigate_mode() == 'ZOOM':
            #Turn zooming off
            self.navbar.zoom()

    def setupNavBarExtras(self, navbar):
        working_dir = os.path.dirname(os.path.abspath(__file__))
        img = Image.open(os.path.join(working_dir, "select.png"))
        #self.select_icon = tk.PhotoImage(file=os.path.join(working_dir,"select.png"))
        self.select_icon = tk.PhotoImage(img)

        self.select_button = tk.Button(navbar,
                                       width="24",
                                       height="24",
                                       image=img,
                                       command=self.returnToSelectMode).pack(
                                           side=tk.LEFT, anchor=tk.W)

        self.dirLbl = tk.Label(navbar, text="Viewing: None")
        self.dirLbl.pack(side=tk.LEFT, anchor=tk.W)

    def plotConfig(self):
        config = PlotConfigDialog(self,
                                  title=self.ax.get_title(),
                                  xlabel=self.ax.get_xlabel(),
                                  ylabel=self.ax.get_ylabel(),
                                  xlim=self.ax.get_xlim(),
                                  ylim=self.ax.get_ylim())
        if (config.applied):
            print(config.title)
            print(config.xlim)
            self.ax.set_title(config.title)
            self.ax.set_xlabel(config.xlabel)
            self.ax.set_ylabel(config.ylabel)
            self.ax.set_xlim(*config.xlim)
            self.ax.set_ylim(*config.ylim)
            self.canvas.draw()

    def rectangleStartEvent(self, event):
        self._rect = None
        self._rect_start = event

    def rectangleMoveEvent(self, event):
        try:
            dx = event.xdata - self._rect_start.xdata
            dy = event.ydata - self._rect_start.ydata
        except TypeError:
            #we're out of canvas bounds
            return

        if self._rect is not None:
            self._rect.remove()

        self._rect = Rectangle(
            (self._rect_start.xdata, self._rect_start.ydata),
            dx,
            dy,
            color='k',
            ls='--',
            lw=1,
            fill=False)
        self.ax.add_patch(self._rect)
        self.ax.draw_artist(self._rect)

    def rectangleEndEvent(self, event):
        if self._rect is not None:
            self._rect.remove()
        else:
            #make a small, fake rectangle
            class FakeEvent(object):
                def __init__(self, x, y):
                    self.xdata, self.ydata = x, y

            dy = (self.ax.get_ylim()[1] - self.ax.get_ylim()[0]) / 100.
            self._rect_start = FakeEvent(event.xdata - 10, event.ydata + dy)
            event = FakeEvent(event.xdata + 10, event.ydata - dy)

        if not self.collection is None:
            x0 = min(self._rect_start.xdata, event.xdata)
            x1 = max(self._rect_start.xdata, event.xdata)
            y0 = min(self._rect_start.ydata, event.ydata)
            y1 = max(self._rect_start.ydata, event.ydata)
            try:
                #if our data is sorted, we can easily isolate it
                x_data = self.collection.data.loc[x0:x1]
            except:
                #Pandas builtin throws an error, use another pandas builtin
                data = self.collection.data
                in_xrange = (data.index >= x0) & (data.index <= x1)
                x_data = data.iloc[in_xrange]

            ylim = sorted([self._rect_start.ydata, event.ydata])
            is_in_box = ((x_data > y0) & (x_data < y1)).any()

            highlighted = is_in_box.index[is_in_box].tolist()
            key_list = list(self.collection._spectra.keys())

            self.update_selected(highlighted)
            flags = self.collection.flags
            for highlight in highlighted:
                #O(n^2) woof
                if (not (highlight in flags)) or self.show_flagged:
                    pos = key_list.index(highlight)
                    self.listbox.selection_set(pos)

    def setupMouseNavigation(self):
        self.clicked = False
        self.select_mode = 'rectangle'
        self._bg_cache = None

        START_EVENTS = {'rectangle': self.rectangleStartEvent}

        MOVE_EVENTS = {'rectangle': self.rectangleMoveEvent}

        END_EVENTS = {'rectangle': self.rectangleEndEvent}

        def onMouseDown(event):
            if self.ax.get_navigate_mode() is None:
                self._bg_cache = self.canvas.copy_from_bbox(self.ax.bbox)
                self.clicked = True
                START_EVENTS[self.select_mode](event)

        def onMouseUp(event):
            if self.ax.get_navigate_mode() is None:
                self.canvas.restore_region(self._bg_cache)
                self.canvas.blit(self.ax.bbox)
                self.clicked = False
                END_EVENTS[self.select_mode](event)

        def onMouseMove(event):
            if self.ax.get_navigate_mode() is None:
                if (self.clicked):
                    self.canvas.restore_region(self._bg_cache)
                    MOVE_EVENTS[self.select_mode](event)
                    self.canvas.blit(self.ax.bbox)

        self.canvas.mpl_connect('button_press_event', onMouseDown)
        self.canvas.mpl_connect('button_release_event', onMouseUp)
        self.canvas.mpl_connect('motion_notify_event', onMouseMove)

    @property
    def head(self):
        return self._head

    @head.setter
    def head(self, value):
        if not hasattr(self, '_head'):
            self._head = 0
        else:
            self._head = value % len(self.collection)

    def set_head(self, value):
        if isinstance(value, Iterable):
            if len(value) > 0:
                value = value[0]
            else:
                value = 0
        self.head = value
        if self.spectrum_mode:
            self.update()
        self.update_selected()

    @property
    def collection(self):
        return self._collection

    @collection.setter
    def collection(self, value):
        if isinstance(value, Spectrum):
            # create new collection
            self._collection = Collection(name=Spectrum.name, spectra=[value])
        if isinstance(value, Collection):
            self._collection = value
        else:
            self._collection = None

    def move_selected_to_top(self):
        selected = self.listbox.curselection()
        keys = [self.collection.spectra[s].name for s in selected]
        for s in selected[::-1]:
            self.listbox.delete(s)
        self.listbox.insert(0, *keys)
        self.listbox.selection_set(0, len(keys))

    def unselect_all(self):
        self.listbox.selection_clear(0, tk.END)
        self.update_selected()

    def select_all(self):
        self.listbox.selection_set(0, tk.END)
        self.update_selected()

    def invert_selection(self):
        for i in range(self.listbox.size()):
            if self.listbox.selection_includes(i):
                self.listbox.selection_clear(i)
            else:
                self.listbox.selection_set(i)
        self.update_selected()

    def change_color(self):
        cpicker = ColorPickerDialog(self)
        #rgb,color = askcolor(self.color)
        if cpicker.applied:
            self.color = cpicker.color
            self.color_pick.config(bg=self.color)
            #update our list of chosen colors
            selected = self.listbox.curselection()
            selected_keys = [self.collection.spectra[s].name for s in selected]

            for key in selected_keys:
                self.colors[key] = self.color
            self.update()

    def select_by_name(self):
        pattern = self.name_filter.get()
        for i in range(self.listbox.size()):
            if pattern in self.listbox.get(i):
                self.listbox.selection_set(i)
            else:
                self.listbox.selection_clear(i)
        self.update_selected()

    def create_listbox(self):
        self._sbframe = tk.Frame(self)

        list_label = tk.Frame(self._sbframe)
        list_label.pack(side=tk.TOP, anchor=tk.N, fill=tk.X)
        tk.Label(list_label, text="Name:").pack(side=tk.LEFT, anchor=tk.W)
        self.name_filter = tk.Entry(list_label, width=14)
        self.name_filter.pack(side=tk.LEFT, anchor=tk.W)
        tk.Button(list_label,
                  text="Select",
                  command=lambda: self.select_by_name()).pack(side=tk.LEFT,
                                                              anchor=tk.W)
        self.sblabel = tk.Label(list_label, text="Showing: 0")
        self.sblabel.pack(side=tk.RIGHT)

        self.scrollbar = tk.Scrollbar(self._sbframe)
        self.listbox = tk.Listbox(self._sbframe,
                                  yscrollcommand=self.scrollbar.set,
                                  selectmode=tk.EXTENDED,
                                  width=30)
        self.scrollbar.config(command=self.listbox.yview)

        self.list_tools = tk.Frame(self._sbframe)
        tk.Button(self.list_tools,
                  text="To Top",
                  command=lambda: self.move_selected_to_top()).pack(
                      side=tk.TOP, anchor=tk.NW, fill=tk.X)
        tk.Button(self.list_tools,
                  text="Select All",
                  command=lambda: self.select_all()).pack(side=tk.TOP,
                                                          anchor=tk.NW,
                                                          fill=tk.X)
        tk.Button(self.list_tools,
                  text="Clear",
                  command=lambda: self.unselect_all()).pack(side=tk.TOP,
                                                            anchor=tk.NW,
                                                            fill=tk.X)
        tk.Button(self.list_tools,
                  text="Invert",
                  command=lambda: self.invert_selection()).pack(side=tk.TOP,
                                                                anchor=tk.NW,
                                                                fill=tk.X)

        self.color_field = tk.Frame(self.list_tools)
        tk.Label(self.color_field, text="Color:").pack(side=tk.LEFT)

        self.color_pick = tk.Button(self.color_field,
                                    text="",
                                    command=lambda: self.change_color(),
                                    bg='#000000')
        self.color_pick.pack(side=tk.RIGHT,
                             anchor=tk.NW,
                             fill=tk.X,
                             expand=True)

        self.color_field.pack(side=tk.TOP, anchor=tk.NW, fill=tk.X)

        self.list_tools.pack(side=tk.RIGHT, anchor=tk.NW)
        self.scrollbar.pack(side=tk.RIGHT, anchor=tk.E, fill=tk.Y)
        self.listbox.pack(side=tk.RIGHT, anchor=tk.E, fill=tk.Y)
        self.listbox.bind('<<ListboxSelect>>',
                          lambda x: self.set_head(self.listbox.curselection()))
        self._sbframe.pack(side=tk.RIGHT, anchor=tk.E, fill=tk.Y)

    def create_toolbar(self):
        self.toolbar = tk.Frame(self)
        tk.Button(self.toolbar, text='Read',
                  command=lambda: self.read_dir()).pack(side=tk.LEFT,
                                                        fill=tk.X,
                                                        expand=1)
        tk.Button(self.toolbar,
                  text='Mode',
                  command=lambda: self.toggle_mode()).pack(side=tk.LEFT,
                                                           fill=tk.X,
                                                           expand=1)
        tk.Button(self.toolbar,
                  text="Plot Config",
                  command=lambda: self.plotConfig()).pack(side=tk.LEFT,
                                                          fill=tk.X,
                                                          expand=1)
        tk.Button(self.toolbar,
                  text='Show/Hide Flagged',
                  command=lambda: self.toggle_show_flagged()).pack(
                      side=tk.LEFT, fill=tk.X, expand=1)
        tk.Button(self.toolbar,
                  text='Flag/Unflag',
                  command=lambda: self.toggle_flag()).pack(side=tk.LEFT,
                                                           fill=tk.X,
                                                           expand=1)
        tk.Button(self.toolbar,
                  text='Unflag all',
                  command=lambda: self.unflag_all()).pack(side=tk.LEFT,
                                                          fill=tk.X,
                                                          expand=1)
        #tk.Button(self.toolbar, text='Save Flag', command=lambda:
        #          self.save_flag()).pack(side=tk.LEFT,fill=tk.X,expand=1)
        tk.Button(self.toolbar,
                  text='Save Flags',
                  command=lambda: self.save_flag_as()).pack(side=tk.LEFT,
                                                            fill=tk.X,
                                                            expand=1)
        tk.Button(self.toolbar, text='Stitch',
                  command=lambda: self.stitch()).pack(side=tk.LEFT,
                                                      fill=tk.X,
                                                      expand=1)
        tk.Button(self.toolbar,
                  text='Jump_Correct',
                  command=lambda: self.jump_correct()).pack(side=tk.LEFT,
                                                            fill=tk.X,
                                                            expand=1)
        tk.Button(self.toolbar,
                  text='mean',
                  command=lambda: self.toggle_mean()).pack(side=tk.LEFT,
                                                           fill=tk.X,
                                                           expand=1)
        tk.Button(self.toolbar,
                  text='median',
                  command=lambda: self.toggle_median()).pack(side=tk.LEFT,
                                                             fill=tk.X,
                                                             expand=1)
        tk.Button(self.toolbar, text='max',
                  command=lambda: self.toggle_max()).pack(side=tk.LEFT,
                                                          fill=tk.X,
                                                          expand=1)
        tk.Button(self.toolbar, text='min',
                  command=lambda: self.toggle_min()).pack(side=tk.LEFT,
                                                          fill=tk.X,
                                                          expand=1)
        tk.Button(self.toolbar, text='std',
                  command=lambda: self.toggle_std()).pack(side=tk.LEFT,
                                                          fill=tk.X,
                                                          expand=1)
        self.toolbar.pack(side=tk.TOP, fill=tk.X)

    def updateTitle(self):
        print("Hello world!")
        self.ax.set_title(self._title.get())
        self.canvas.draw()

    def set_collection(self, collection):
        new_lim = True if self.collection is None else False
        self.collection = collection
        self.update_artists(new_lim=new_lim)
        self.update()
        self.update_list()

    def read_dir(self):
        try:
            directory = os.path.split(
                filedialog.askopenfilename(filetypes=(
                    ("Supported types", "*.asd *.sed *.sig *.pico"),
                    ("All files", "*"),
                )))[0]
        except:
            return
        if not directory:
            return
        c = Collection(name="collection", directory=directory)
        self.set_collection(c)
        self.dirLbl.config(text="Viewing: " + directory)

    def reset_stats(self):
        if self.mean_line:
            self.mean_line.remove()
            self.mean_line = None
            self.mean = False
        if self.median_line:
            self.median_line.remove()
            self.median_line = None
            self.median = False
        if self.max_line:
            self.max_line.remove()
            self.max_line = None
            self.max = False
        if self.min_line:
            self.min_line.remove()
            self.min_line = None
            self.min = False
        if self.std_line:
            self.std_line.remove()
            self.std_line = None
            self.std = False

    def toggle_mode(self):
        if self.spectrum_mode:
            self.spectrum_mode = False
        else:
            self.spectrum_mode = True
        self.update()

    def toggle_show_flagged(self):
        if self.show_flagged:
            self.show_flagged = False
        else:
            self.show_flagged = True
        self.update()

    def unflag_all(self):
        #new flags -> new statistics
        self.reset_stats()

        for spectrum in list(self.collection.flags):
            self.collection.unflag(spectrum)
        self.update()
        self.update_list()

    def toggle_flag(self):
        #new flags -> new statistics
        self.reset_stats()

        selected = self.listbox.curselection()
        keys = [self.listbox.get(s) for s in selected]

        for i, key in enumerate(keys):
            print(i, key)
            spectrum = key
            if spectrum in self.collection.flags:
                self.collection.unflag(spectrum)
                self.listbox.itemconfigure(selected[i], foreground='black')
            else:
                self.collection.flag(spectrum)
                self.listbox.itemconfigure(selected[i], foreground='red')
        # update figure
        self.update()

    def save_flag(self):
        ''' save flag to self.flag_filepath'''
        with open(self.flag_filepath, 'w') as f:
            for spectrum in self.collection.flags:
                print(spectrum, file=f)

    def save_flag_as(self):
        ''' modify self.flag_filepath and call save_flag()'''
        flag_filepath = filedialog.asksaveasfilename()
        if os.path.splitext(flag_filepath)[1] == '':
            flag_filepath = flag_filepath + '.txt'
        self.flag_filepath = flag_filepath
        self.save_flag()

    def update_list(self):
        self.listbox.delete(0, tk.END)
        for i, spectrum in enumerate(self.collection.spectra):
            self.listbox.insert(tk.END, spectrum.name)
            if spectrum.name in self.collection.flags:
                self.listbox.itemconfigure(i, foreground='red')
        self.update_selected()

    def ask_for_draw(self):
        #debounce canvas updates
        now = datetime.now()
        print(now - self.last_draw)
        if ((now - self.last_draw).total_seconds() > 0.5):
            self.canvas.draw()
            self.last_draw = now

    def update_artists(self, new_lim=False):
        if self.collection is None:
            return
        #update values being plotted -> redo statistics
        self.mean_line = None
        self.median_line = None
        self.max_line = None
        self.min_line = None
        self.std_line = None
        # save limits
        if new_lim == False:
            xlim = self.ax.get_xlim()
            ylim = self.ax.get_ylim()
        # plot
        self.ax.clear()
        # show statistics
        if self.spectrum_mode:
            idx = self.listbox.curselection()
            if len(idx) == 0:
                idx = [self.head]
            spectra = [self.collection.spectra[i] for i in idx]
            flags = [s.name in self.collection.flags for s in spectra]
            print("flags = ", flags)
            flag_style = ' '
            if self.show_flagged:
                flag_style = 'r'
            artists = Collection(name='selection', spectra=spectra).plot(
                ax=self.ax,
                style=list(np.where(flags, flag_style, self.color)),
                picker=1)
            self.ax.set_title('selection')
            # c = str(np.where(spectrum.name in self.collection.flags, 'r', 'k'))
            # spectrum.plot(ax=self.ax, label=spectrum.name, c=c)
        else:
            # red curves for flagged spectra
            flag_style = ' '
            if self.show_flagged:
                flag_style = 'r'
            flags = [
                s.name in self.collection.flags
                for s in self.collection.spectra
            ]
            print("flags = ", flags)
            self.collection.plot(ax=self.ax,
                                 style=list(np.where(flags, flag_style, 'k')),
                                 picker=1)
            #self.ax.set_title(self.collection.name)

        keys = [s.name for s in self.collection.spectra]
        artists = self.ax.lines
        self.artist_dict = {key: artist for key, artist in zip(keys, artists)}
        self.colors = {key: 'black' for key in keys}
        self.ax.legend().remove()
        self.navbar.setHome(self.ax.get_xlim(), self.ax.get_ylim())
        self.canvas.draw()
        self.sblabel.config(text="Showing: {}".format(len(artists)))

    def update_selected(self, to_add=None):
        """ Update, only on flaged"""
        if self.collection is None:
            return

        if to_add:
            for key in to_add:
                self.artist_dict[key].set_linestyle('--')
        else:
            keys = [s.name for s in self.collection.spectra]
            selected = self.listbox.curselection()
            selected_keys = [self.collection.spectra[s].name for s in selected]
            for key in keys:
                if key in selected_keys:
                    self.artist_dict[key].set_linestyle('--')
                else:
                    self.artist_dict[key].set_linestyle('-')
        self.canvas.draw()

    def update(self):
        """ Update the plot """
        if self.collection is None:
            return
        # show statistics
        if self.spectrum_mode:
            self.ax.clear()
            idx = self.listbox.curselection()
            if len(idx) == 0:
                idx = [self.head]
            spectra = [self.collection.spectra[i] for i in idx]
            flags = [s.name in self.collection.flags for s in spectra]
            print("flags = ", flags)
            flag_style = ' '
            if self.show_flagged:
                flag_style = 'r'
            Collection(name='selection', spectra=spectra).plot(
                ax=self.ax,
                style=list(np.where(flags, flag_style, 'k')),
                picker=1)
            self.ax.set_title('selection')
            # c = str(np.where(spectrum.name in self.collection.flags, 'r', 'k'))
            # spectrum.plot(ax=self.ax, label=spectrum.name, c=c)
        else:
            # red curves for flagged spectra

            keys = [s.name for s in self.collection.spectra]
            for key in keys:
                if key in self.collection.flags:
                    if self.show_flagged:
                        self.artist_dict[key].set_visible(True)
                        self.artist_dict[key].set_color('red')
                    else:
                        self.artist_dict[key].set_visible(False)
                else:
                    self.artist_dict[key].set_color(self.colors[key])
                    self.artist_dict[key].set_visible(True)

            if self.show_flagged:
                self.sblabel.config(
                    text="Showing: {}".format(len(self.artist_dict)))
            else:
                self.sblabel.config(text="Showing: {}".format(
                    len(self.artist_dict) - len(self.collection.flags)))
            '''
            self.collection.plot(ax=self.ax,
                                 style=list(np.where(flags, flag_style, 'k')),
                                 picker=1)
            self.ax.set_title(self.collection.name)
            '''

        if self.spectrum_mode:
            #self.ax.legend()
            pass
        else:
            #self.ax.legend().remove()
            pass
        self.ax.set_ylabel(self.collection.measure_type)
        #toggle appearance of statistics
        if self.mean_line != None: self.mean_line.set_visible(self.mean)
        if self.median_line != None: self.median_line.set_visible(self.median)
        if self.max_line != None: self.max_line.set_visible(self.max)
        if self.min_line != None: self.min_line.set_visible(self.min)
        if self.std_line != None: self.std_line.set_visible(self.std)
        self.canvas.draw()

    def next_spectrum(self):
        if not self.spectrum_mode:
            return
        self.head = (self.head + 1) % len(self.collection)
        self.update()

    def stitch(self):
        ''' 
        Known Bugs
        ----------
        Can't stitch one spectrum and plot the collection
        '''
        self.collection.stitch()
        self.update_artists()

    def jump_correct(self):
        ''' 
        Known Bugs
        ----------
        Only performs jump correction on 1000 and 1800 wvls and 1 reference
        '''
        self.collection.jump_correct([1000, 1800], 1)
        self.update_artists()

    def toggle_mean(self):
        if self.mean:
            self.mean = False

        else:
            self.mean = True
            if not self.mean_line:
                self.collection.mean().plot(ax=self.ax,
                                            c='b',
                                            label=self.collection.name +
                                            '_mean',
                                            lw=3)
                self.mean_line = self.ax.lines[-1]
        self.update()

    def toggle_median(self):
        if self.median:
            self.median = False
        else:
            self.median = True
            if not self.median_line:
                self.collection.median().plot(ax=self.ax,
                                              c='g',
                                              label=self.collection.name +
                                              '_median',
                                              lw=3)
                self.median_line = self.ax.lines[-1]
        self.update()

    def toggle_max(self):
        if self.max:
            self.max = False
        else:
            self.max = True
            if not self.max_line:
                self.collection.max().plot(ax=self.ax,
                                           c='y',
                                           label=self.collection.name + '_max',
                                           lw=3)
                self.max_line = self.ax.lines[-1]
        self.update()

    def toggle_min(self):
        if self.min:
            self.min = False
        else:
            self.min = True
            if not self.min_line:
                self.collection.min().plot(ax=self.ax,
                                           c='m',
                                           label=self.collection.name + '_min',
                                           lw=3)
                self.min_line = self.ax.lines[-1]
        self.update()

    def toggle_std(self):
        if self.std:
            self.std = False
        else:
            self.std = True
            if not self.std_line:
                self.collection.std().plot(ax=self.ax,
                                           c='c',
                                           label=self.collection.name + '_std',
                                           lw=3)
                self.std_line = self.ax.lines[-1]
        self.update()
Example #18
0
    ax = fig.add_subplot(111)
    canvas = FigureCanvasTkAgg(fig, root)  # A tk.DrawingArea
    canvas.get_tk_widget().pack(side='top', fill='both',
                                expand=1)  # Add fig to Tk Window

    ax.grid(which='both', linestyle='--')
    ax.set_xlabel("Time (s)")

    line, = ax.plot(evo.time, evo.data)
    ax.set_ylim([0, 100])

    ax.get_xaxis().set_animated(True)
    #ax.get_yaxis().set_animated(True)
    line.set_animated(True)
    canvas.draw()
    background = canvas.copy_from_bbox(fig.bbox)

    # now redraw and blit
    ax.draw_artist(ax.get_xaxis())
    ax.draw_artist(line)
    canvas.blit(ax.clipbox)

    while True:
        evo.update()

        line.set_xdata(evo.time)
        line.set_ydata(evo.getData())
        ax.set_xlim([evo.time[0], evo.time[-1]])
        #ax.set_ylim([max(evo.data),min(evo.data)])

        # restore the background, draw animation,blit
Example #19
0
class FittingWindow:
    
    
    def __init__(self, master,ramanspectrum =None):
        global guessplot,dataplot
        
        self.master  = master
        self.textframe= Frame(master = self.master)
        
        self.scroll = Tkinter.Scrollbar(self.textframe)
        self.scroll.grid(row=0,column=1)
        self.t = Tkinter.Text(self.textframe,yscrollcommand=self.scroll.set,width=30)
        self.scroll.config(command=self.t.yview)
        self.t.grid(row=0,column=0)
        
        self.plotframe = Frame(master = self.master)
        
        self.frame = Frame(master = self.master)
        
        self.textframe.grid(row=0,column=0,columnspan=3)
        self.plotframe.grid(row = 0, column = 3, columnspan = 11,sticky = 'ew')
        self.frame.grid(column = 1, row = 1,columnspan = 11, rowspan = 3,sticky = 'snew')
        self.buttonframe = Frame(master = self.master)
        self.buttonframe.grid(column=0, row =1)
        ##############################
        self.menubar = Menu(self.master)
        
        self.filemenu = Menu(self.menubar, tearoff=0)
        self.filemenu.add_command(label="New window", command = lambda: FittingWindow(Toplevel()))
        self.filemenu.add_command(label="Open", command = self.open_data)
        self.filemenu.add_command(label="Save",command = None)
        self.filemenu.add_command(label="SaveFig",command = None)
        self.filemenu.add_command(label="ViewNotebook",command = None)
        self.filemenu.add_command(label="Exit", command = self.quitproc)
        self.menubar.add_cascade(label="File", menu=self.filemenu)
        
        self.master.config(menu= self.menubar)
        ##############################
        
        self.fit_button = Tkinter.Button(master = self.buttonframe, command = self.fit_and_draw, width  = 5, text = 'FitNow')
        self.fit_button.grid(row = 3, column = 0)
        self.open_button =  Tkinter.Button(master = self.buttonframe, command = self.open_data, width  = 5, text = 'open')
        self.open_button.grid(row = 4, column = 0)
#        self.open_ref_button =  Tkinter.Button(master = self.buttonframe, command = self.open_ref, width  = 5, text = 'Choose reference')
#        self.open_ref_button.grid(row = 5, column = 0)
        
#        self.open_bkg_button =  Tkinter.Button(master = self.buttonframe, command = self.open_bkg, width  = 5, text = 'Choose background')
#        self.open_bkg_button.grid(row = 6, column = 0)
#        
#        self.ref_label =  Tkinter.Label(master = self.buttonframe, text = '')
#        self.ref_label.grid(row = 7, column = 0)
#        
#        self.bkg_label =  Tkinter.Label(master = self.buttonframe, text = '')
#        self.bkg_label.grid(row = 8, column = 0)
        
        self.smoothbutton = Tkinter.Button(master = self.buttonframe, command = self.smoothdata, width  = 5, text = 'Smooth')
        self.smoothbutton.grid(row = 5, column = 0)
 
       
        
        self.function_list=[
                              'OneGaussian',
                              'TwoGaussian',
                              'ThreeGaussian',
                              'FourGaussian',
                              'FiveGaussian']
        
        self.var_func = StringVar()
        self.var_func.set(self.function_list[0])
        
        
       
       
        self.MotorMenu = OptionMenu(self.buttonframe,self.var_func, *self.function_list, command = self.init_function)
        self.MotorMenu.grid(row = 3,column =1,sticky = W)
        
        self.normalization_constant = 1
        self.scale_list = []
        self.var_list = []
        
        self.fig = Figure(figsize=(5,3))
        self.ax1  = self.fig.add_subplot(111)
        dataplot = self.ax1.plot(arange(2800,3605,5),zeros((161,)),animated = True)[0]#(ax = self.ax1).lines[-1]
        
        guessplot = self.ax1.plot(arange(2800,3605,5),zeros((161,)),animated = True)[0]
        
        
        self.canvas = FigureCanvasTkAgg(self.fig,master = self.plotframe)
        
        self.canvas.show()
        
        
        self.canvas._tkcanvas.pack(side=TOP, fill = BOTH,expand =True)
        
        
        self.toolbar = NavigationToolbar2TkAgg(self.canvas, self.plotframe)
        self.toolbar.update()
        self.toolbar.pack(side= BOTTOM, fill = BOTH,expand =True)#,expand = True)#fill=BOTH)#, expand=1)
        
        self.canvas.draw()
        self.canvas.show()
        self.background = self.canvas.copy_from_bbox(self.ax1.bbox)
            
         
        self.reference = numpy.ndarray((161,))
        self.reference[:] = 1
        self.reference_name  = ''
        self.guess = list()

        self.name = ['']
        if ramanspectrum is None:
            self.a = pandas.Series(zeros(161),arange(2800,3605,5))
        else:
            self.a = copy(ramanspectrum)
            print self.a
           
            self.t.insert(END,'data multiplied by'+str(1/max(self.a)))
            self.a[:]/=max(self.a.values)
            
        self.startfreq_text = Entry(self.buttonframe,width = 5)
        self.startfreq = min(array(self.a.index))
        self.startfreq_text.insert(END,str(self.startfreq))
        self.startfreq_text.bind("<Return>", self.update_limits)
        self.startfreq_text.grid(row = 0 , column =1,sticky = W)
        
        
        self.endfreq_text = Entry(self.buttonframe,width = 5)
        self.endfreq = max(array(self.a.index))
        self.endfreq_text.insert(END,str(self.endfreq))
        self.endfreq_text.bind("<Return>", self.update_limits)
        self.endfreq_text.grid(row = 1 , column =1,sticky = W)
        
        if self.init_function('OneLorentzian') == -1:
            self.t.insert(END, 'error initializing fit function')
        
        self.ax1.cla()
        self.canvas.show()
        self.background = self.canvas.copy_from_bbox(self.ax1.bbox)
        

        dataplot = self.ax1.plot(array(self.a.index),self.a.values,animated=True)[0]
        x= array(self.a.index)
        guessplot = self.ax1.plot(x,zeros(self.a.size),animated=True)[0]
        self.ax1.set_xlim(min(self.a.index),max(self.a.index))
        self.ax1.set_ylim(min(self.a.values),1)
        
        self.canvas.show()

        
        
       
        self.raw = self.a.copy   
        self.startidx = 0
        self.endidx = -1
           
        self.update_limits(0)
        return None
        
    def nothing(self):
        return 0
    def quitproc(self):
            self.master.destroy()
            return 0
        
        
    def init_function(self,functiontype):
        global function
        import inspect
        
        if functiontype == None:
            functiontype = self.var_func.get()
        
        self.functiontype = functiontype
        
      
                    
        if functiontype == 'OneLorentzian':
            def function(x,A1,w1,G1,m,b): return m*x/1000+b + A1**2/((x-w1)**2+G1**2)
        elif functiontype == 'TwoLorentzian':
            def function(x,A1,A2,w1,w2,G1,G2,m,b): return m*x/1000+b + A1**2/((x-w1)**2+G1**2) +A2**2/((x-w2)**2+G2**2)
    
        elif functiontype == 'ThreeLorentzian':
            def function(x,A1,A2,A3,w1,w2,w3,G1,G2,G3,m,b): return m*x/1000+b + A1**2/((x-w1)**2+G1**2) +A2**2/((x-w2)**2+G2**2) +A3**2/((x-w3)**2+G3**2)
        elif functiontype == 'FourLorentzian':
            def function(x,A1,A2,A3,A4,w1,w2,w3,w4,G1,G2,G3,G4,m,b): return m*x/1000+b + A1**2/((x-w1)**2+G1**2) +A2**2/((x-w2)**2+G2**2) +A3**2/((x-w3)**2+G3**2) +A4**2/((x-w4)**2+G4**2)
             
        elif functiontype == 'FiveLorentzian':
            def function(x,A1,A2,A3,A4,A5,w1,w2,w3,w4,w5,G1,G2,G3,G4,G5,m,b): return m*x/1000+b + A1**2/((x-w1)**2+G1**2) +A2**2/((x-w2)**2+G2**2) +A3**2/((x-w3)**2+G3**2) +A4**2/((x-w4)**2+G4**2)+A5**2/((x-w5)**2+G5**2)
        elif functiontype == 'OneGaussian':
            def function(x,A1,w1,G1,m,b): return m*x/1000+b + A1*exp(-(x-w1)**2/G1)
        elif functiontype == 'TwoGaussian':
            def function(x,A1,A2,w1,w2,G1,G2,m,b): return A1*exp(-(x-w1)**2/G1) +A2*exp(-(x-w2)**2/G2) +m*x/1000+b 
    
        elif functiontype == 'ThreeGaussian':
            def function(x,A1,A2,A3,w1,w2,w3,G1,G2,G3,m,b): return m*x/1000+b + A1*exp(-(x-w1)**2/G1) +A2*exp(-(x-w2)**2/G2) +A3*exp(-(x-w3)**2/G3) 
        elif functiontype == 'FourGaussian':
            def function(x,A1,A2,A3,A4,w1,w2,w3,w4,G1,G2,G3,G4,m,b): return m*x/1000+b +A1*exp(-(x-w1)**2/G1) +A2*exp(-(x-w2)**2/G2)  +A3*exp(-(x-w3)**2/G3) +A4*exp(-(x-w4)**2/G4) 
             
        elif functiontype == 'FiveGaussian':
            def function(x,A1,A2,A3,A4,A5,w1,w2,w3,w4,w5,G1,G2,G3,G4,G5,m,b): return m*x/1000+b + (A1/G1*numpy.sqrt(2*pi))*exp(-(x-w1)**2/(2*G1**2)) +(A2/G2*numpy.sqrt(2*pi))*exp(-(x-w2)**2/(2*G2**2))  +(A3/G3*numpy.sqrt(2*pi))*exp(-(x-w3)**2/(2*G3**2))  +(A4/G4*numpy.sqrt(2*pi))*exp(-(x-w4)**2/(2*G4**2)) +(A5/G5*numpy.sqrt(2*pi))*exp(-(x-w5)**2/(2*G5**2)) 
        else:
            tkMessageBox.showerror('Not regconized function')
            def function(x,m,b): return m*x/1000+b
       
         

#==============================================================================
        self.w_name = list() 
        self.w_name = inspect.getargspec(function).args[1:]
        
        self.guess= []
       
        for w in self.w_name:
            if 'A' in w:
                self.guess.append(0.1)
            elif 'w' in w:
                self.guess.append(1000)
            elif 'G' in w:
                self.guess.append(10)
            else:
                self.guess.append(0)
#================================================================================
        
        for i in range(len(self.scale_list),len(self.w_name)):
                self.scale_list.append(Scale(master  = self.frame,command = self.guessdraw))
                
        for i in range(len(self.w_name),len(self.scale_list)):
                self.scale_list[i].grid_forget()
           
        for i in range(len(self.w_name)):
                self.scale_list[i].config(label = self.w_name[i])
                self.scale_list[i].grid(row = int(i/8), column = i%8)
                
                if self.w_name[i][0] == 'A':
                     self.scale_list[i].config(from_ =0, to =  5,resolution = 0.1)
                     
                     self.scale_list[i].set(1)
                elif self.w_name[i][0] == 'w':
                    self.scale_list[i].config(from_ = self.startfreq-20, to =  self.endfreq+20,resolution = 1)
                    self.scale_list[i].set(2800)
                elif self.w_name[i][0] == 'G':
                    self.scale_list[i].config(from_ = 1, to =  50)
                    self.scale_list[i].set(7)
                elif self.w_name[i][0] == 'm':
                    self.scale_list[i].config(from_ = -5, to =  5, resolution = 0.05)
                    self.scale_list[i].set(0)
                elif self.w_name[i][0] == 'b':
                    self.scale_list[i].config(from_ = -5, to =  5, resolution = 0.05)
                    self.scale_list[i].set(0)
                else:
                    self.t.insert(END, "Variable not recognized:", self.w_name[i] )
                self.scale_list[i].bind('<B1-Motion>',self.guessdraw)
        return 0
        
        
    def smoothdata(self):
        self.a.smoooth()
        self.guessdraw(0)
        
        
        
    def update_limits(self,extra):
        functiontype = self.var_func.get()
        
        self.startfreq = max(float(self.startfreq_text.get()),min(array(self.a.index)))
        self.endfreq = min(float(self.endfreq_text.get()),max(array(self.a.index)))
        
        
        
        self.startidx = self.a.nearest(self.startfreq)
        self.endidx =  self.a.nearest(self.endfreq)        
        
        
        for i in range(len(self.guess)):
            self.guess[i] = self.scale_list[i].get()

        self.ax1.cla()
        self.canvas.show()
        self.background = self.canvas.copy_from_bbox(self.ax1.bbox)
        

        dataplot = self.ax1.plot(array(self.a.index[self.startidx:self.endidx]),self.a.values[self.startidx:self.endidx],animated=True)[0]#(ax = self.ax1).lines[-1]
        x= array(self.a.index[self.startidx:self.endidx])
        guessplot = self.ax1.plot(x,zeros(x.size),animated=True)[0]
        
        
        #self.ax1.set_xlim(min(self.a.index),max(self.a.index))
        #self.ax1.set_ylim(min(self.a.values),1)
        
        self.canvas.show()
        self.guessdraw(0)

        
        
        return 0
            
    def open_data(self): 
        global dataplot,guessplot
        self.name = self.DisplaySpectrum()
       
        if self.name == -1:
            return 0
        try:
            self.a = RamanSpectrum(self.name)
            self.normalization_constant= 1/max(self.a)
            self.startfreq = min(array(self.a.index))
            self.startfreq_text.insert(END,str(self.startfreq))
            self.endfreq = max(array(self.a.index))
            self.endfreq_text.insert(END,str(self.endfreq))
            
        except:
            self.t.insert(END, 'error opening spectrum')
            return -1
        
        
        self.raw = self.a.copy
        self.ax1.cla()
        self.canvas.show()
        self.background = self.canvas.copy_from_bbox(self.ax1.bbox)
        

        dataplot = self.ax1.plot(array(self.a.index),self.a.values,animated=True)[0]#(ax = self.ax1).lines[-1]
        x= array(self.a.index)
        guessplot = self.ax1.plot(x,zeros(self.a.size),animated=True)[0]
        self.ax1.set_xlim(min(self.a.index),max(self.a.index))
        self.ax1.set_ylim(min(self.a.values),1)
        
        self.canvas.show()

        self.update_limits(0)
        
        
       
        
        return 0
    
    def open_ref(self):

        pass
        
        return 0 
        
    def open_bkg(self):

        pass
        return 0 
        
            
        
    def recalc_data(self):
        if self.raw.shape == self.reference.shape:
            self.a= SG_Smooth(self.raw,width = 11,order = 3)/self.reference/self.normalization_constant
            self.ax1.cla()
            plot(self.a[0],self.raw/self.reference)
            plot(self.a[0],self.a[1])
        else:
            self.t.insert(END, "reference invalid")
            self.reference_name = "No IR Reference"
            
            self.ax1.cla()
            self.ax1.plot(self.a[0],self.a[1])
            self.canvas.draw()
        
        return 0
        

    def guessdraw(self,ex):
        global function,guessplot,dataplot
        
        
        x = array(self.a.index[self.startidx:self.endidx+1])
        
        
        for i in range(len(self.guess)):
            self.guess[i] = self.scale_list[i].get()
        
        self.canvas.restore_region(self.background)
        self.ax1.lines[-1].set_xdata(x)
        self.ax1.lines[-1].set_ydata(function(x,*self.guess))
        
        
        for l in self.ax1.lines:

            self.ax1.draw_artist(l)
           
        self.canvas.blit(self.ax1.bbox)
        
        
            
        

        return 0
    def fit_and_draw(self):
        
        global function
        print type(self.a)
        if type(self.a) == pandas.core.series.Series:
            self.a = RamanSpectrum(self.a)
        #result = fitspectrum(self.a, (float(self.a.index[self.startidx]),float(self.a.index[self.endidx+1])),'Custom',self.guess,function = function)
        print self.guess
        result = fitspectrum(self.a, (self.startfreq,self.endfreq),'Custom',self.guess,function = function)
        fittingparameters = result[0]
        xfit = result[1]
        yfit = result[2]
        if result == -1:
            tkMessageBox.showerror('Fit Failed')
            return 0

        z = list(fittingparameters[0])            
        self.canvas.restore_region(self.background)
        self.ax1.lines[-1].set_xdata(xfit)
        self.ax1.lines[-1].set_ydata(yfit)
        
        
        for l in self.ax1.lines:

            self.ax1.draw_artist(l)
        for i in range(len(self.w_name)):
            #self.scale_list[i].set(result[0][i])
            if "w" in self.w_name[i]:
                self.ax1.axvline(x = z[i], ymin = 0, ymax = 1 ,color = 'r')
           
        self.canvas.blit(self.ax1.bbox)

        self.t.insert(END, "  \nResult Found for " + str(self.name))
        self.t.insert(END, " \nReferenced to IR spectrum " +self.reference_name)
        self.t.insert(END, "  \nNormalized by constant "+str(self.normalization_constant))
        for i in range(len(self.w_name)):
            self.t.insert(END, ' \n'+self.w_name[i]+': '+str(z[i]))
        
                
        
        return 0
    def DisplaySpectrum(self):
        import re
        global name_list, str_name_list
        file_opt = options = {}
        options['defaultextension'] = '.spe'
        options['filetypes'] = [('all files', '.*'),('SPE files', '.SPE'), ('csv files','.csv'),('text files','.txt')]
        options['title'] = 'Open Spectrum...'
        options['initialdir'] = '/home/chris/Documents/DataWeiss'

        str_name_list = tkFileDialog.askopenfilename(**options)
        if str_name_list == '':
            return -1
        return str_name_list                        
class StripChartWdg(tkinter.Frame):
    """A widget to changing values in real time as a strip chart
    
    Usage Hints:
    - For each variable quantity to display:
      - Call addLine once to specify the quantity
      - Call addPoint for each new data point you wish to display

    - For each constant line (e.g. limit) to display call addConstantLine
    
    - To make sure a plot includes one or two y values (e.g. 0 or a range of values) call showY

    - To manually scale a Y axis call setYLimits (by default all y axes are autoscaled).
    
    - All supplied times are POSIX timestamps (e.g. as supplied by time.time()).
        You may choose the kind of time displayed on the time axis (e.g. UTC or local time) using cnvTimeFunc
        and the format of that time using dateFormat.
    
    Known Issues:
    matplotlib's defaults present a number of challenges for making a nice strip chart display.
    Some issues and manual solutions are discussed in the main file's document string.
        
    Potentially Useful Attributes:
    - canvas: the matplotlib FigureCanvas
    - figure: the matplotlib Figure
    - subplotArr: list of subplots, from top to bottom; each is a matplotlib Subplot object,
        which is basically an Axes object but specialized to live in a rectangular grid
    - xaxis: the x axis shared by all subplots
    """
    def __init__(self,
        master,
        timeRange = 3600,
        numSubplots = 1,
        width = 8,
        height = 2,
        showGrid = True,
        dateFormat = "%H:%M:%S",
        updateInterval = None,
        cnvTimeFunc = None,
    ):
        """Construct a StripChartWdg with the specified time range
        
        Inputs:
        - master: Tk parent widget
        - timeRange: range of time displayed (seconds)
        - width: width of graph in inches
        - height: height of graph in inches
        - numSubplots: the number of subplots
        - showGrid: if True a grid is shown
        - dateFormat: format for major axis labels, using time.strftime format
        - updateInterval: now often the time axis is updated (seconds); if None a value is calculated
        - cnvTimeFunc: a function that takes a POSIX timestamp (e.g. time.time()) and returns matplotlib days;
            typically an instance of TimeConverter; defaults to TimeConverter(useUTC=False)
        """
        tkinter.Frame.__init__(self, master)
        
        self._timeRange = timeRange
        self._isVisible = self.winfo_ismapped()
        self._isFirst = True
        if updateInterval is None:
            updateInterval = max(0.1, min(5.0, timeRange / 2000.0))
        self.updateInterval = float(updateInterval)
#         print "updateInterval=", self.updateInterval

        if cnvTimeFunc is None:
            cnvTimeFunc = TimeConverter(useUTC=False)
        self._cnvTimeFunc = cnvTimeFunc

        # how many time axis updates occur before purging old data
        self._maxPurgeCounter = max(1, int(0.5 + (5.0 / self.updateInterval)))
        self._purgeCounter = 0

        self.figure = matplotlib.figure.Figure(figsize=(width, height), frameon=True)
        self.canvas = FigureCanvasTkAgg(self.figure, self)
        self.canvas.get_tk_widget().grid(row=0, column=0, sticky="news")
        self.canvas.mpl_connect('draw_event', self._handleDrawEvent)
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        bottomSubplot = self.figure.add_subplot(numSubplots, 1, numSubplots)
        self.subplotArr = [self.figure.add_subplot(numSubplots, 1, n+1, sharex=bottomSubplot) \
            for n in range(numSubplots-1)] + [bottomSubplot]
        if showGrid:
            for subplot in self.subplotArr:
                subplot.grid(True)

        self.xaxis = bottomSubplot.xaxis
        bottomSubplot.xaxis_date()
        self.xaxis.set_major_formatter(matplotlib.dates.DateFormatter(dateFormat))

        # dictionary of constant line name: (matplotlib Line2D, matplotlib Subplot)
        self._constLineDict = dict()

        for subplot in self.subplotArr:
            subplot._scwLines = [] # a list of contained _Line objects;
                # different than the standard lines property in that:
                # - lines contains Line2D objects
                # - lines contains constant lines as well as data lines
            subplot._scwBackground = None # background for animation
            subplot.label_outer() # disable axis labels on all but the bottom subplot
            subplot.set_ylim(auto=True) # set auto scaling for the y axis
        
        self.bind("<Map>", self._handleMap)
        self.bind("<Unmap>", self._handleUnmap)
        self._timeAxisTimer = Timer()
        self._updateTimeAxis()

    def addConstantLine(self, y, subplotInd=0, **kargs):
        """Add a new constant to plot
        
        Inputs:
        - y: value of constant line
        - subplotInd: index of subplot
        - All other keyword arguments are sent to the matplotlib Line2D constructor
          to control the appearance of the data. See addLine for more information.
        """
        subplot = self.subplotArr[subplotInd]
        line2d = subplot.axhline(y, **kargs)
        yMin, yMax = subplot.get_ylim()
        if subplot.get_autoscaley_on() and numpy.isfinite(y) and not (yMin <= y <= yMax):
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)
        return line2d

    def addLine(self, subplotInd=0, **kargs):
        """Add a new quantity to plot
        
        Inputs:
        - subplotInd: index of subplot
        - All other keyword arguments are sent to the matplotlib Line2D constructor
          to control the appearance of the data. Useful arguments include:
          - label: name of line (displayed in a Legend)
          - color: color of line
          - linestyle: style of line (defaults to a solid line); "" for no line, "- -" for dashed, etc.
          - marker: marker shape, e.g. "+"
          Please do not attempt to control other sorts of line properties, such as its data.
          Arguments to avoid include: animated, data, xdata, ydata, zdata, figure.
        """
        subplot = self.subplotArr[subplotInd]
        return _Line(
            subplot = subplot,
            cnvTimeFunc = self._cnvTimeFunc,
            wdg = self,
        **kargs)
    
    def clear(self):
        """Clear data in all non-constant lines
        """
        for subplot in self.subplotArr:
            for line in subplot._scwLines:
                line.clear()

    def getDoAutoscale(self, subplotInd=0):
        return self.subplotArr[subplotInd].get_autoscaley_on()
    
    def removeLine(self, line):
        """Remove an existing line added by addLine or addConstantLine
        
        Raise an exception if the line is not found
        """
        if isinstance(line, _Line):
            # a _Line object needs to be removed from _scwLines as well as the subplot
            line2d = line.line2d
            subplot = line.subplot
            subplot._scwLines.remove(line)
        else:
            # a constant line is just a matplotlib Line2D instance
            line2d = line
            subplot = line.axes

        subplot.lines.remove(line2d)
        if subplot.get_autoscaley_on():
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)
        self.canvas.draw()

    def setDoAutoscale(self, doAutoscale, subplotInd=0):
        """Turn autoscaling on or off for the specified subplot
        
        You can also turn off autoscaling by calling setYLimits.
        """
        doAutoscale = bool(doAutoscale)
        subplot = self.subplotArr[subplotInd]
        subplot.set_ylim(auto=doAutoscale)
        if doAutoscale:
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)
    
    def setYLimits(self, minY, maxY, subplotInd=0):
        """Set y limits for the specified subplot and disable autoscaling.
        
        Note: if you want to autoscale with a minimum range, use showY.
        """
        self.subplotArr[subplotInd].set_ylim(minY, maxY, auto=False)
    
    def showY(self, y0, y1=None, subplotInd=0):
        """Specify one or two values to always show in the y range.
        
        Inputs:
        - subplotInd: index of subplot
        - y0: first y value to show
        - y1: second y value to show; None to omit

        Warning: setYLimits overrides this method (but the values are remembered in case you turn
        autoscaling back on).
        """
        subplot = self.subplotArr[subplotInd]
        yMin, yMax = subplot.get_ylim()
        
        if y1 is not None:
            yList = [y0, y1]
        else:
            yList = [y0]
        doRescale = False
        for y in yList:
            subplot.axhline(y, linestyle=" ")
            if subplot.get_autoscaley_on() and numpy.isfinite(y) and not (yMin <= y <= yMax):
                doRescale = True
        if doRescale:
            subplot.relim()
            subplot.autoscale_view(scalex=False, scaley=True)

    def _handleDrawEvent(self, event=None):
        """Handle draw event
        """
#         print "handleDrawEvent"
        for subplot in self.subplotArr:
            subplot._scwBackground = self.canvas.copy_from_bbox(subplot.bbox)
            for line in subplot._scwLines:
                subplot.draw_artist(line.line2d)
            self.canvas.blit(subplot.bbox)
    
    def _handleMap(self, evt):
        """Handle map event (widget made visible)
        """
        self._isVisible = True
        self._handleDrawEvent()
        self._updateTimeAxis()
    
    def _handleUnmap(self, evt):
        """Handle unmap event (widget made not visible)
        """
        self._isVisible = False
    
    def _updateTimeAxis(self):
        """Update the time axis; calls itself
        """
        tMax = time.time() + self.updateInterval
        tMin = tMax - self._timeRange
        minMplDays = self._cnvTimeFunc(tMin)
        maxMplDays = self._cnvTimeFunc(tMax)
        
        self._purgeCounter = (self._purgeCounter + 1) % self._maxPurgeCounter
        doPurge = self._purgeCounter == 0

        if doPurge:
            for subplot in self.subplotArr:
                for line in subplot._scwLines:
                    line._purgeOldData(minMplDays)
        
        if self._isVisible or self._isFirst:
            for subplot in self.subplotArr:
                subplot.set_xlim(minMplDays, maxMplDays)
                if doPurge:
                    if subplot.get_autoscaley_on():
                        # since data is being purged the y limits may have changed
                        subplot.relim()
                        subplot.autoscale_view(scalex=False, scaley=True)
            self._isFirst = False
            self.canvas.draw()
        self._timeAxisTimer.start(self.updateInterval, self._updateTimeAxis)
Example #21
0
class PlotFrame(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.fwidth = 512
        self.fheight = 720
        self.configure(bd=2,
                       width=self.fwidth,
                       height=self.fheight,
                       relief='sunken')
        self.grid_propagate(0)
        self.dpi = 100
        self.f = Figure(figsize=(self.fwidth / self.dpi,
                                 self.fheight / self.dpi),
                        dpi=self.dpi,
                        facecolor=(1, 1, 1, 0))
        self.canvas = FigureCanvasTkAgg(self.f, self)

        self.top = self.f.add_subplot(311)
        self.middle = self.f.add_subplot(312)
        self.bottom = self.f.add_subplot(313)

        self.xData = np.linspace(0, 100 * np.pi, 1000, endpoint=False)
        self.yDataB = np.sin(self.xData)
        self.yDataM = np.sin(self.xData) * np.sin(self.xData * 0.5 + .4)
        self.yDataT = np.sin(self.xData)**2 + np.cos(self.xData * 1.1 + 0.15)

        self.startTime = time.time()
        self.canvas.draw()
        self.backgroundB = self.canvas.copy_from_bbox(self.bottom.bbox)
        self.backgroundT = self.canvas.copy_from_bbox(self.top.bbox)
        self.backgroundM = self.canvas.copy_from_bbox(self.middle.bbox)
        self.pointsB = self.bottom.plot(self.xData, self.yDataB)[0]
        self.pointsM = self.middle.plot(self.xData, self.yDataM)[0]
        self.pointsT = self.top.plot(self.xData, self.yDataT)[0]

    def animate2(self, reScaled):
        scale = True

        if reScaled:
            self.f.clf()
            self.showCanvas.grid_forget()
            self.f = Figure(figsize=(self.fwidth / self.dpi,
                                     self.fheight / self.dpi),
                            dpi=self.dpi,
                            facecolor=(1, 1, 1, 0))
            self.canvas = FigureCanvasTkAgg(self.f, self)

            self.top = self.f.add_subplot(311)
            self.middle = self.f.add_subplot(312)
            self.bottom = self.f.add_subplot(313)

            self.canvas.draw()

            self.backgroundB = self.canvas.copy_from_bbox(self.bottom.bbox)
            self.backgroundT = self.canvas.copy_from_bbox(self.top.bbox)
            self.backgroundM = self.canvas.copy_from_bbox(self.middle.bbox)

            self.pointsB = self.bottom.plot(self.xData, self.yDataB)[0]
            self.pointsM = self.middle.plot(self.xData, self.yDataM)[0]
            self.pointsT = self.top.plot(self.xData, self.yDataT)[0]
            scale = False

        if scale:
            t = time.time() - self.startTime
            N = len(self.xData)
            currentIdx = int(N * ((t / 4) % 1))
            scalingNumber = N * 0.1
            waveShape = np.exp(-np.arange(N) / scalingNumber)[::-1]

            colorArray = np.array([(1, 0, 0, a)
                                   for a in np.roll(waveShape, currentIdx)])

            self.yDataB = np.roll(self.yDataB, 1)
            self.yDataT = np.roll(self.yDataT, 1)
            self.yDataM = np.roll(self.yDataM, 1)

            self.pointsB.set_data(self.xData, self.yDataB)
            self.pointsT.set_data(self.xData, self.yDataT)
            self.pointsM.set_data(self.xData, self.yDataM)

            self.canvas.restore_region(self.backgroundB)
            self.canvas.restore_region(self.backgroundT)
            self.canvas.restore_region(self.backgroundM)

            self.bottom.draw_artist(self.pointsB)
            self.middle.draw_artist(self.pointsM)
            self.top.draw_artist(self.pointsT)

            self.canvas.blit(self.bottom.bbox)
            self.canvas.blit(self.top.bbox)
            self.canvas.blit(self.middle.bbox)

            self.showCanvas = self.canvas.get_tk_widget()
            self.showCanvas.grid()