Ejemplo n.º 1
0
    def __init__(self):
        wx.Frame.__init__(self, None, -1, self.title)

        self.serial_data = SerialData()

        self.plot = [-1, -1, -1, -1]
        # it reads the data from the ReceivingSerialData.py to a four-elements array
        for i in range(len(self.plot)):
            self.plot[i] = [self.serial_data.next(0)]

        self.paused = False
        self.menu_bar = wx.MenuBar()
        self.create_menu()
        self.create_status_bar()
        self.create_main_panel()

        self.redraw_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
        self.redraw_timer.Start(REFRESH_INTERVAL_MS)
Ejemplo n.º 2
0
    def __init__(self):
        wx.Frame.__init__(self, None, -1, self.title)

        self.serial_data = SerialData()

        self.plot = [-1, -1, -1, -1]
        # it reads the data from the ReceivingSerialData.py to a four-elements array
        for i in range(len(self.plot)):
            self.plot[i] = [self.serial_data.next(0)]

        self.paused = False
        self.menu_bar = wx.MenuBar()
        self.create_menu()
        self.create_status_bar()
        self.create_main_panel()

        self.redraw_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
        self.redraw_timer.Start(REFRESH_INTERVAL_MS)
Ejemplo n.º 3
0
class GraphFrame(wx.Frame):
    """ The main frame of the application
    """
    title = 'Demo: dynamic matplotlib graph'

    def __init__(self):
        wx.Frame.__init__(self, None, -1, self.title)

        self.serial_data = SerialData()

        self.plot = [-1, -1, -1, -1]
        # it reads the data from the ReceivingSerialData.py to a four-elements array
        for i in range(len(self.plot)):
            self.plot[i] = [self.serial_data.next(0)]

        self.paused = False
        self.menu_bar = wx.MenuBar()
        self.create_menu()
        self.create_status_bar()
        self.create_main_panel()

        self.redraw_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
        self.redraw_timer.Start(REFRESH_INTERVAL_MS)

    def create_menu(self):
        menu_file = wx.Menu()
        m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S", "Save plot to file")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
        self.Bind(wx.EVT_MENU, self.on_exit, m_exit)

        self.menu_bar.Append(menu_file, "&File")
        self.SetMenuBar(self.menu_bar)

    def create_main_panel(self):
        self.panel = wx.Panel(self)

        self.init_plot()
        self.canvas = FigCanvas(self.panel, -1, self.fig)

        # it sets min i max for X and Y axis.
        self.xmin_control = BoundControlBox(self.panel, -1, "X min", 0)
        self.xmax_control = BoundControlBox(self.panel, -1, "X max", (20*60*60)/2)  # min * sec * ms = 10min
        self.ymin_control = BoundControlBox(self.panel, -1, "Y min", 0)
        self.ymax_control = BoundControlBox(self.panel, -1, "Y max", 1000)

        self.pause_button = wx.Button(self.panel, -1, "Pause")
        self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button)
        self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button, self.pause_button)

        self.cb_grid = wx.CheckBox(self.panel, -1, "Show Grid", style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)
        self.cb_grid.SetValue(True)

        self.cb_xlab = wx.CheckBox(self.panel, -1, "Show X labels", style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab)
        self.cb_xlab.SetValue(True)

        self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox1.Add(self.pause_button, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(20)
        self.hbox1.Add(self.cb_grid, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(10)
        self.hbox1.Add(self.cb_xlab, border=5, flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)

        self.hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox2.Add(self.xmin_control, border=5, flag=wx.ALL)
        self.hbox2.Add(self.xmax_control, border=5, flag=wx.ALL)
        self.hbox2.AddSpacer(24)
        self.hbox2.Add(self.ymin_control, border=5, flag=wx.ALL)
        self.hbox2.Add(self.ymax_control, border=5, flag=wx.ALL)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW)
        self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP)
        self.vbox.Add(self.hbox2, 0, flag=wx.ALIGN_LEFT | wx.TOP)

        self.panel.SetSizer(self.vbox)
        self.vbox.Fit(self)

    def create_status_bar(self):
        self.statusbar = self.CreateStatusBar()

    def init_plot(self):
        self.dpi = 100
        self.fig = Figure((12.0, 5.0), dpi=self.dpi)

        self.axes = self.fig.add_subplot(111)
        self.axes.set_axis_bgcolor('white')
        self.axes.set_title('Arduino Serial Data', size=12)

        pylab.setp(self.axes.get_xticklabels(), fontsize=8)
        pylab.setp(self.axes.get_yticklabels(), fontsize=8)

        # plot the data as a line series, and save the reference
        # to the plotted line series

        self.plot_data = [0, 0, 0, 0]

        # it determines the look of the plots.
        # looking for other colours? - http://stackoverflow.com/questions/22408237/named-colors-in-matplotlib
        self.plot_data[0] = self.axes.plot(self.plot[0], linewidth=2, color="darkorange")[0]
        self.plot_data[1] = self.axes.plot(self.plot[1], linewidth=2, color="forestgreen")[0]
        self.plot_data[2] = self.axes.plot(self.plot[2], linewidth=2, color="mediumvioletred")[0]
        self.plot_data[3] = self.axes.plot(self.plot[3], linewidth=2, color="royalblue")[0]

    def draw_plot(self):
        """ Redraws the plot
        """
        # when xmin is on auto, it "follows" xmax to produce a
        # sliding window effect. therefore, xmin is assigned after
        # xmax.

        if self.xmax_control.is_auto():
            for i in range(len(self.plot) - 1):
                if len(self.plot[i]) > len(self.plot[i+1]):
                    xmax = len(self.plot[i+1])
                else:
                    xmax = len(self.plot[0])

        else:
            xmax = int(self.xmax_control.manual_value())
        if self.xmin_control.is_auto():
            xmin = 0#xmax - 500
        else:
            xmin = int(self.xmin_control.manual_value())

        # for ymin and ymax, find the minimal and maximal values
        # in the data set and add a mininal margin.
        #
        # note that it's easy to change this scheme to the
        # minimal/maximal value in the current display, and not
        # the whole data set.

        if self.ymin_control.is_auto():
            for i in range(len(self.plot) - 1):
                if round(min(self.plot[i]), 0) - 1 < round(min(self.plot[i+1]), 0) - 1:
                    ymin = round(min(self.plot[i]), 0) - 1
                else:
                    ymin = round(min(self.plot[i+1]), 0) - 1
        else:
            ymin = int(self.ymin_control.manual_value())

        if self.ymax_control.is_auto():
            for i in range(len(self.plot) - 1):
                if round(max(self.plot[i]), 0) - 1 > round(max(self.plot[i+1]), 0) - 1:
                    ymax = round(max(self.plot[i]), 0) - 1
                else:
                    ymax = round(max(self.plot[i+1]), 0) - 1
        else:
            ymax = int(self.ymax_control.manual_value())

        # added to clarification
        ymax += 100

        self.axes.set_xbound(lower=xmin, upper=xmax)
        self.axes.set_ybound(lower=ymin, upper=ymax)

        # anecdote: axes.grid assumes b=True if any other flag is
        # given even if b is set to False.
        # so just passing the flag into the first statement won't
        # work.

        if self.cb_grid.IsChecked():
            self.axes.grid(True, color='gray')
        else:
            self.axes.grid(False)

        # Using setp here is convenient, because get_xticklabels
        # returns a list over which one needs to explicitly
        # iterate, and setp already handles this.

        pylab.setp(self.axes.get_xticklabels(), visible=self.cb_xlab.IsChecked())

        for i in range(len(self.plot_data)):
            self.plot_data[i].set_xdata(np.arange(len(self.plot[i])))
            self.plot_data[i].set_ydata(np.array(self.plot[i]))
        self.canvas.draw()

    def on_pause_button(self, event):
        self.paused = not self.paused

    def on_update_pause_button(self, event):
        label = "Resume" if self.paused else "Pause"
        self.pause_button.SetLabel(label)

    def on_cb_grid(self, event):
        self.draw_plot()

    def on_cb_xlab(self, event):
        self.draw_plot()

    def on_save_plot(self, event):
        file_choices = "PNG (*.png)|*.png"

        dlg = wx.FileDialog(
            self,
            message="Save plot as...",
            defaultDir=os.getcwd(),
            defaultFile="plot.png",
            wildcard=file_choices,
            style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=self.dpi)
            self.flash_status_message("Saved to %s" % path)

    def on_redraw_timer(self, event):
        # if paused do not add data, but still redraw the plot
        # (to respond to scale modifications, grid change, etc.)

        if not self.paused:
            for i in range(len(self.plot_data)):
                self.plot[i].append(self.serial_data.next(i))
        self.draw_plot()

    def on_exit(self, event):
        self.Destroy()

    def flash_status_message(self, msg, flash_len_ms=1500):
        self.statusbar.SetStatusText(msg)
        self.timeroff = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_flash_status_off, self.timeroff)
        self.timeroff.Start(flash_len_ms, oneShot=True)

    def on_flash_status_off(self, event):
        self.statusbar.SetStatusText('')
Ejemplo n.º 4
0
class GraphFrame(wx.Frame):
    """ The main frame of the application
    """
    title = 'Demo: dynamic matplotlib graph'

    def __init__(self):
        wx.Frame.__init__(self, None, -1, self.title)

        self.serial_data = SerialData()

        self.plot = [-1, -1, -1, -1]
        # it reads the data from the ReceivingSerialData.py to a four-elements array
        for i in range(len(self.plot)):
            self.plot[i] = [self.serial_data.next(0)]

        self.paused = False
        self.menu_bar = wx.MenuBar()
        self.create_menu()
        self.create_status_bar()
        self.create_main_panel()

        self.redraw_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
        self.redraw_timer.Start(REFRESH_INTERVAL_MS)

    def create_menu(self):
        menu_file = wx.Menu()
        m_expt = menu_file.Append(-1, "&Save plot\tCtrl-S",
                                  "Save plot to file")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
        self.Bind(wx.EVT_MENU, self.on_exit, m_exit)

        self.menu_bar.Append(menu_file, "&File")
        self.SetMenuBar(self.menu_bar)

    def create_main_panel(self):
        self.panel = wx.Panel(self)

        self.init_plot()
        self.canvas = FigCanvas(self.panel, -1, self.fig)

        # it sets min i max for X and Y axis.
        self.xmin_control = BoundControlBox(self.panel, -1, "X min", 0)
        self.xmax_control = BoundControlBox(self.panel, -1, "X max",
                                            (20 * 60 * 60) /
                                            2)  # min * sec * ms = 10min
        self.ymin_control = BoundControlBox(self.panel, -1, "Y min", 0)
        self.ymax_control = BoundControlBox(self.panel, -1, "Y max", 1000)

        self.pause_button = wx.Button(self.panel, -1, "Pause")
        self.Bind(wx.EVT_BUTTON, self.on_pause_button, self.pause_button)
        self.Bind(wx.EVT_UPDATE_UI, self.on_update_pause_button,
                  self.pause_button)

        self.cb_grid = wx.CheckBox(self.panel,
                                   -1,
                                   "Show Grid",
                                   style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_grid, self.cb_grid)
        self.cb_grid.SetValue(True)

        self.cb_xlab = wx.CheckBox(self.panel,
                                   -1,
                                   "Show X labels",
                                   style=wx.ALIGN_RIGHT)
        self.Bind(wx.EVT_CHECKBOX, self.on_cb_xlab, self.cb_xlab)
        self.cb_xlab.SetValue(True)

        self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox1.Add(self.pause_button,
                       border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(20)
        self.hbox1.Add(self.cb_grid,
                       border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)
        self.hbox1.AddSpacer(10)
        self.hbox1.Add(self.cb_xlab,
                       border=5,
                       flag=wx.ALL | wx.ALIGN_CENTER_VERTICAL)

        self.hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox2.Add(self.xmin_control, border=5, flag=wx.ALL)
        self.hbox2.Add(self.xmax_control, border=5, flag=wx.ALL)
        self.hbox2.AddSpacer(24)
        self.hbox2.Add(self.ymin_control, border=5, flag=wx.ALL)
        self.hbox2.Add(self.ymax_control, border=5, flag=wx.ALL)

        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, 1, flag=wx.LEFT | wx.TOP | wx.GROW)
        self.vbox.Add(self.hbox1, 0, flag=wx.ALIGN_LEFT | wx.TOP)
        self.vbox.Add(self.hbox2, 0, flag=wx.ALIGN_LEFT | wx.TOP)

        self.panel.SetSizer(self.vbox)
        self.vbox.Fit(self)

    def create_status_bar(self):
        self.statusbar = self.CreateStatusBar()

    def init_plot(self):
        self.dpi = 100
        self.fig = Figure((12.0, 5.0), dpi=self.dpi)

        self.axes = self.fig.add_subplot(111)
        self.axes.set_axis_bgcolor('white')
        self.axes.set_title('Arduino Serial Data', size=12)

        pylab.setp(self.axes.get_xticklabels(), fontsize=8)
        pylab.setp(self.axes.get_yticklabels(), fontsize=8)

        # plot the data as a line series, and save the reference
        # to the plotted line series

        self.plot_data = [0, 0, 0, 0]

        # it determines the look of the plots.
        # looking for other colours? - http://stackoverflow.com/questions/22408237/named-colors-in-matplotlib
        self.plot_data[0] = self.axes.plot(self.plot[0],
                                           linewidth=2,
                                           color="darkorange")[0]
        self.plot_data[1] = self.axes.plot(self.plot[1],
                                           linewidth=2,
                                           color="forestgreen")[0]
        self.plot_data[2] = self.axes.plot(self.plot[2],
                                           linewidth=2,
                                           color="mediumvioletred")[0]
        self.plot_data[3] = self.axes.plot(self.plot[3],
                                           linewidth=2,
                                           color="royalblue")[0]

    def draw_plot(self):
        """ Redraws the plot
        """
        # when xmin is on auto, it "follows" xmax to produce a
        # sliding window effect. therefore, xmin is assigned after
        # xmax.

        if self.xmax_control.is_auto():
            for i in range(len(self.plot) - 1):
                if len(self.plot[i]) > len(self.plot[i + 1]):
                    xmax = len(self.plot[i + 1])
                else:
                    xmax = len(self.plot[0])

        else:
            xmax = int(self.xmax_control.manual_value())
        if self.xmin_control.is_auto():
            xmin = 0  #xmax - 500
        else:
            xmin = int(self.xmin_control.manual_value())

        # for ymin and ymax, find the minimal and maximal values
        # in the data set and add a mininal margin.
        #
        # note that it's easy to change this scheme to the
        # minimal/maximal value in the current display, and not
        # the whole data set.

        if self.ymin_control.is_auto():
            for i in range(len(self.plot) - 1):
                if round(min(self.plot[i]), 0) - 1 < round(
                        min(self.plot[i + 1]), 0) - 1:
                    ymin = round(min(self.plot[i]), 0) - 1
                else:
                    ymin = round(min(self.plot[i + 1]), 0) - 1
        else:
            ymin = int(self.ymin_control.manual_value())

        if self.ymax_control.is_auto():
            for i in range(len(self.plot) - 1):
                if round(max(self.plot[i]), 0) - 1 > round(
                        max(self.plot[i + 1]), 0) - 1:
                    ymax = round(max(self.plot[i]), 0) - 1
                else:
                    ymax = round(max(self.plot[i + 1]), 0) - 1
        else:
            ymax = int(self.ymax_control.manual_value())

        # added to clarification
        ymax += 100

        self.axes.set_xbound(lower=xmin, upper=xmax)
        self.axes.set_ybound(lower=ymin, upper=ymax)

        # anecdote: axes.grid assumes b=True if any other flag is
        # given even if b is set to False.
        # so just passing the flag into the first statement won't
        # work.

        if self.cb_grid.IsChecked():
            self.axes.grid(True, color='gray')
        else:
            self.axes.grid(False)

        # Using setp here is convenient, because get_xticklabels
        # returns a list over which one needs to explicitly
        # iterate, and setp already handles this.

        pylab.setp(self.axes.get_xticklabels(),
                   visible=self.cb_xlab.IsChecked())

        for i in range(len(self.plot_data)):
            self.plot_data[i].set_xdata(np.arange(len(self.plot[i])))
            self.plot_data[i].set_ydata(np.array(self.plot[i]))
        self.canvas.draw()

    def on_pause_button(self, event):
        self.paused = not self.paused

    def on_update_pause_button(self, event):
        label = "Resume" if self.paused else "Pause"
        self.pause_button.SetLabel(label)

    def on_cb_grid(self, event):
        self.draw_plot()

    def on_cb_xlab(self, event):
        self.draw_plot()

    def on_save_plot(self, event):
        file_choices = "PNG (*.png)|*.png"

        dlg = wx.FileDialog(self,
                            message="Save plot as...",
                            defaultDir=os.getcwd(),
                            defaultFile="plot.png",
                            wildcard=file_choices,
                            style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=self.dpi)
            self.flash_status_message("Saved to %s" % path)

    def on_redraw_timer(self, event):
        # if paused do not add data, but still redraw the plot
        # (to respond to scale modifications, grid change, etc.)

        if not self.paused:
            for i in range(len(self.plot_data)):
                self.plot[i].append(self.serial_data.next(i))
        self.draw_plot()

    def on_exit(self, event):
        self.Destroy()

    def flash_status_message(self, msg, flash_len_ms=1500):
        self.statusbar.SetStatusText(msg)
        self.timeroff = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_flash_status_off, self.timeroff)
        self.timeroff.Start(flash_len_ms, oneShot=True)

    def on_flash_status_off(self, event):
        self.statusbar.SetStatusText('')