Пример #1
0
class Reader(object):
    def __init__(self,win_size, win_loc, title,subplot_dim=[1,1]):
        self.top = gtk.Window()
        self.top.connect('delete-event', gtk.main_quit)
        self.top.set_title(title)
        self.top.set_position(gtk.WIN_POS_CENTER)
        self.top.set_default_size(*win_size)
        
        self.fig = Figure()
        
        self.axs = [self.fig.add_subplot(subplot_dim[0],
                                           subplot_dim[1],
                                           i+1) for i in
                    range(np.prod(subplot_dim))]
        self.canvas = FigureCanvas(self.fig)
        self.top.add(self.canvas)
        self.top.show_all()
        
        self.update_background()
        
        if len(self.axs) == 1:
            self.ax = self.axs[0]
            
        
    def update_background(self):
        self.canvas.draw()
        self.backgrounds = [self.canvas.copy_from_bbox(ax.bbox) for
                            ax in self.axs]
        if len(self.backgrounds) == 1: 
            self.background = self.backgrounds[0]
            
        
        return 
    
    def draw(self):
        raise Exception('Not implemented.')
    
    def read(self):
        raise Exception('Not implemented yet.')
Пример #2
0
class Reader(object):
    def __init__(self, win_size, win_loc, title, subplot_dim=[1, 1]):
        self.top = gtk.Window()
        self.top.connect('delete-event', gtk.main_quit)
        self.top.set_title(title)
        self.top.set_position(gtk.WIN_POS_CENTER)
        self.top.set_default_size(*win_size)

        self.fig = Figure()

        self.axs = [
            self.fig.add_subplot(subplot_dim[0], subplot_dim[1], i + 1)
            for i in range(np.prod(subplot_dim))
        ]
        self.canvas = FigureCanvas(self.fig)
        self.top.add(self.canvas)
        self.top.show_all()

        self.update_background()

        if len(self.axs) == 1:
            self.ax = self.axs[0]

    def update_background(self):
        self.canvas.draw()
        self.backgrounds = [
            self.canvas.copy_from_bbox(ax.bbox) for ax in self.axs
        ]
        if len(self.backgrounds) == 1:
            self.background = self.backgrounds[0]

        return

    def draw(self):
        raise Exception('Not implemented.')

    def read(self):
        raise Exception('Not implemented yet.')
Пример #3
0
class SensorWindow(object):
    def __init__(self, mainThread, gladefile='sensor_window.glade'):
        self.builder = gtk.Builder()
        self.builder.add_from_file(gladefile)
        self.builder.connect_signals(self)

        self._stopped = False
        self.mainThread = mainThread

        self.fig = plt.figure()
        self.numLines = 1

        # lines plot
        self.ax = self.fig.add_subplot(111)
        self.ax.set_xlabel('Time')
        self.ax.set_ylabel('Power')
        self.ax.xaxis.set_animated(True)
        self.ax.yaxis.set_animated(True)
        self.ax.set_title('Light Intensity')
        self.ax.grid(True)

        self.start = time.time()
        self.background1 = None
        self.prev_time = self.start
        self.prev_pixel_offset = 0
        self.x0 = 0
        self.value = [0] * self.numLines

        self.ax.set_ylim(-1, 256)

        self.lines = []
        for i in range(self.numLines):
            line, = self.ax.plot([], [], animated=True, lw=2)
            self.lines.append(line)

        self.canvas = FigureCanvas(self.fig)

        self.graphview = self.builder.get_object("box2")
        self.graphview.pack_start(self.canvas)
        self.graphview.reorder_child(self.canvas, 0)

        self.img = self.builder.get_object("image1")
        self.img.set_from_file("off.svg")
        self.lamp = False

        self.canvas.show()

        gobject.idle_add(self.update_line)
        self.canvas.mpl_connect('draw_event', self.on_draw)

        self.barpath = []

    def close_window(self, obj):
        print "closing window"
        self.builder.get_object("window1").destroy()

    def destroy_callback(self, obj):
        print "destroying window"
        self.mainThread.stop()
        self._stopped = True

    def close_from_mainthread(self):
        print "close from mainthread"
        self.builder.get_object("window1").destroy()

    def toggle_lamp(self):
        print "toggle lamp!!"
        self.img = self.builder.get_object("image1")
        if (self.lamp):
            self.lamp = False
            self.img.set_from_file("off.svg")
        else:
            self.lamp = True
            self.img.set_from_file("on.svg")

    def update_line(self, *args):

        if self._stopped:
            self.destroy_callback(None)
            return False

        if self.background1 is None:
            return True

        cur_time = time.time()
        pixel_offset = int((cur_time - self.start) * 40.)
        dx_pixel = pixel_offset - self.prev_pixel_offset
        self.prev_pixel_offset = pixel_offset
        dx_data = self.get_dx_data(dx_pixel)  #cur_time - self.prev_time)

        x0 = self.x0
        self.x0 += dx_data
        self.prev_time = cur_time

        self.ax.set_xlim(self.x0 - 2, self.x0 + 0.1)

        # restore background which will plot lines from previous plots
        self.restore_background_shifted(dx_pixel)  #x0, self.x0)

        # now plot line segment within [x0, x0+dx_data],
        # Note that we're only plotting a line between [x0, x0+dx_data].
        xx = np.array([x0, self.x0])
        for i in range(len(self.lines)):
            line = self.lines[i]
            line.set_xdata(xx)

            # the for loop below could be improved by using collection.
            line.set_ydata(np.array([self.value[i], self.value[i]]))
            self.ax.draw_artist(line)

        self.background2 = self.canvas.copy_from_bbox(self.get_bg_bbox())

        self.ax.draw_artist(self.ax.xaxis)
        self.ax.draw_artist(self.ax.yaxis)

        self.canvas.blit(self.ax.get_figure().bbox)
        return True

    def get_dx_data(self, dx_pixel):
        tp = self.ax.transData.inverted().transform_point
        x0, y0 = tp((0, 0))
        x1, y1 = tp((dx_pixel, 0))
        return (x1 - x0)

    def get_bg_bbox(self):
        return self.ax.bbox.padded(-3)

    def save_bg(self):
        self.background1 = self.canvas.copy_from_bbox(
            self.ax.get_figure().bbox)
        self.background2 = self.canvas.copy_from_bbox(self.get_bg_bbox())

    def on_draw(self, *args):
        self.save_bg()
        return False

    def restore_background_shifted(self, dx_pixel):
        """
		restore bacground shifted by dx in data coordinate. This only
		works if the data coordinate system is linear.
		"""

        # restore the clean slate background
        self.canvas.restore_region(self.background1)

        # restore subregion (x1+dx, y1, x2, y2) of the second bg
        # in a offset position (x1-dx, y1)
        x1, y1, x2, y2 = self.background2.get_extents()
        self.canvas.restore_region(self.background2,
                                   bbox=(x1 + dx_pixel, y1, x2, y2),
                                   xy=(x1 - dx_pixel, y1))

        return dx_pixel

    def update(self, data):
        if type(data) == ListType:
            assert (len(self.lines) == len(data))
            self.value = data
        else:
            assert (len(self.lines) == 1)
            self.value = [data]
Пример #4
0
class XratersWindow(gtk.Window):
    __gtype_name__ = "XratersWindow"

    def __init__(self):
        """__init__ - This function is typically not called directly.
        Creation a XratersWindow requires redeading the associated ui
        file and parsing the ui definition extrenally,
        and then calling XratersWindow.finish_initializing().

        Use the convenience function NewXratersWindow to create
        XratersWindow object.

        """
        self._acc_cal = ((128, 128, 128), (255, 255, 255))
        self._acc = [0, 0, 0]
        self._connected = False
        self._wiiMote = None
        self._resetData()
        self._dataLock = threading.Lock()

    isConnected = property(lambda self: self._connected)

    def callback(funct):
        """A decorator used to require connection to the Wii Remote
        
        This decorator is used to implement the precondition that 
        the Wii Remote must be connected. 
        """
        def _callback(cls, *args, **kwds):
            if cls.isConnected:
                funct(cls, *args, **kwds)
                return True
            else:
                return False

        return _callback

    def _connectCallback(self, connectionMaker):
        """Callback function called upon successful connection to the Wiimote
        """
        if connectionMaker.connected:
            self._connected = True
            self._wiiMote = connectionMaker.wiiMote
            self._resetData()
            gobject.timeout_add(45, self._drawAcc)
            self.widget('actionDisconnect').set_sensitive(True)
            self.widget('actionSave').set_sensitive(True)
            self.widget('actionReset').set_sensitive(True)
            self.widget('actionPause').set_sensitive(True)
            self.widget('toolbutton1').set_related_action(
                self.widget('actionDisconnect'))
            self._acc_cal = connectionMaker.acc_cal
            self._wiiMote.mesg_callback = self._getAcc
            self._updBatteryLevel()
            gobject.timeout_add_seconds(60, self._updBatteryLevel)
        else:
            self.widget('actionWiiConnect').set_sensitive(True)

    @callback
    def _upd_background(self, event):
        """Keep a copy of the figure background
        """
        self.__background = self._accCanvas.copy_from_bbox(self._accAxis.bbox)

    def _getAcc(self, messages, theTime=0):
        """Process acceleration messages from the Wiimote
        
        This function is intended to be set as cwiid.mesg_callback
        """
        if self._Paused:
            return
        for msg in messages:
            if msg[0] == cwiid.MESG_ACC:
                # Normalize data using calibration info
                for i, axisAcc in enumerate(msg[1]):
                    self._acc[i] = float(axisAcc - self._acc_cal[0][i])
                    self._acc[i] /=(self._acc_cal[1][i]\
                                    -self._acc_cal[0][i])
                with self._dataLock:
                    # Store time and acceleration in the respective arrays
                    self._time.append(theTime - self._startTime)
                    [self._accData[i].append(self._acc[i]) for i in threeAxes]
                # We only keep about 6 seconds worth of data
                if (self._time[-1] - self._time[0] > 6):
                    with self._dataLock:
                        self._time.pop(0)
                        [self._accData[i].pop(0) for i in threeAxes]

    @callback
    def _drawAcc(self):
        """Update the acceleration graph
        
        """
        # Do nothing while paused or there's no data available
        if self._Paused or len(self._time) == 0:
            return
        draw_flag = False
        # Update axes limits if the data fall out of range
        lims = self._accAxis.get_xlim()
        if self._time[-1] > lims[1]:
            self._accAxis.set_xlim(lims[0], lims[1] + 2)
            lims = self._accAxis.get_xlim()
            draw_flag = True
        if (self._time[-1] - lims[0] > 6):
            self._accAxis.set_xlim(lims[0] + 2, lims[1])
            draw_flag = True
        if draw_flag:
            gobject.idle_add(self._accCanvas.draw)
        # Do the actual update of the background
        if self.__background != None:
            self._accCanvas.restore_region(self.__background)
        # Do the actual update of the lines
        with self._dataLock:
            [
                self._lines[i].set_data(self._time, self._accData[i])
                for i in threeAxes
            ]
        [self._accAxis.draw_artist(self._lines[i]) for i in threeAxes]
        self._accCanvas.blit(self._accAxis.bbox)

    @callback
    def _updBatteryLevel(self):
        """Callback to update the battery indicator in the status bar
        
        """
        self._wiiMote.request_status()
        self._setBatteryIndicator(
            float(self._wiiMote.state['battery']) / cwiid.BATTERY_MAX)

    def _setBatteryIndicator(self, level):
        """Actually update the battery indicator in the status bar
        
        """
        progressBar = self.widget("progressbarBattery")
        progressBar.set_fraction(level)
        progressBar.set_text("Battery: %.0f%%" % (level * 100))

    def _resetData(self):
        """Reset stored data and status flags to their defaults
        
        """
        self._accData = [list(), list(), list()]
        self._time = list()
        self._startTime = time.time()
        self._moveTime = self._startTime
        self._Paused = False

    def widget(self, name):
        """Helper function to retrieve widget handlers
        
        """
        return self.builder.get_object(name)

    def finish_initializing(self, builder):
        """finish_initalizing should be called after parsing the ui definition
        and creating a XratersWindow object with it in order to finish
        initializing the start of the new XratersWindow instance.

        """
        #get a reference to the builder and set up the signals
        self.builder = builder
        self.builder.connect_signals(self)

        #uncomment the following code to read in preferences at start up
        dlg = PreferencesXratersDialog.NewPreferencesXratersDialog()
        self.preferences = dlg.get_preferences()

        #code for other initialization actions should be added here
        self._accFigure = Figure(figsize=(8, 6), dpi=72)
        self._accAxis = self._accFigure.add_subplot(111)
        self._accAxis.set_xlabel("time (s)")
        self._accAxis.set_ylabel("acceleration (g)")
        self._lines = self._accAxis.plot(self._time,
                                         self._accData[X],
                                         self._time,
                                         self._accData[Y],
                                         self._time,
                                         self._accData[Z],
                                         animated=True)
        self._accFigure.legend(self._lines, ("X", "Y", "Z"),
                               'upper center',
                               ncol=3)
        self._accAxis.set_xlim(0, 2)
        self._accAxis.set_ylim(-3, 3)
        self._accCanvas = FigureCanvas(self._accFigure)
        self._accCanvas.mpl_connect("draw_event", self._upd_background)
        self.__background = self._accCanvas.copy_from_bbox(self._accAxis.bbox)
        self._accCanvas.show()
        self._accCanvas.set_size_request(600, 400)
        vbMain = self.widget("vboxMain")
        vbMain.pack_start(self._accCanvas, True, True)
        vbMain.show()
        vbMain.reorder_child(self._accCanvas, 2)
        self._setBatteryIndicator(0)

    def about(self, widget, data=None):
        """about - display the about box for xraters """
        about = AboutXratersDialog.NewAboutXratersDialog()
        response = about.run()
        about.destroy()

    def preferences(self, widget, data=None):
        """preferences - display the preferences window for xraters """
        prefs = PreferencesXratersDialog.NewPreferencesXratersDialog()
        response = prefs.run()
        if response == gtk.RESPONSE_OK:
            #make any updates based on changed preferences here
            self.preferences = prefs.get_preferences()
        prefs.destroy()

    def quit(self, widget, data=None):
        """quit - signal handler for closing the XratersWindow"""
        self.destroy()

    def on_destroy(self, widget, data=None):
        """on_destroy - called when the XratersWindow is close. """
        #clean up code for saving application state should be added here
        if self.isConnected:
            self.on_wiiDisconnect(widget, data)
        gtk.main_quit()

    def on_wiiConnect(self, widget, data=None):
        """Signal handler for the WiiConnect action
        
        """
        self.widget('actionWiiConnect').set_sensitive(False)
        connectionMaker = WiiConnectionMaker(self.preferences['wiiAddress'],
                                             self.widget("statusbar"),
                                             self._connectCallback)
        self._accAxis.set_xlim(0, 2)
        gobject.idle_add(self._accCanvas.draw)
        connectionMaker.start()

    def on_wiiDisconnect(self, widget, data=None):
        """Signal handler for the WiiDisconnect action
        
        """
        self._wiiMote.close()
        self._connected = False
        self.widget('actionDisconnect').set_sensitive(False)
        self.widget('actionWiiConnect').set_sensitive(True)
        self.widget('actionReset').set_sensitive(False)
        self.widget('actionPause').set_sensitive(False)
        self.widget('toolbutton1').set_related_action(
            self.widget('actionWiiConnect'))
        self.widget('actionSave').set_sensitive(True)
        self.widget('statusbar').pop(
            self.widget("statusbar").get_context_id(''))
        self._setBatteryIndicator(0)

    def on_Reset(self, widget, data=None):
        """Signal handler for the reset action
        
        """
        self._resetData()
        self._accAxis.set_xlim(0, 2)
        gobject.idle_add(self._accCanvas.draw)

    def on_Pause(self, widge, data=None):
        """Signal handler for the pause action
        
        """
        if not self._Paused:
            self.widget('actionPause').set_short_label("Un_pause")
        else:
            self.widget('actionPause').set_short_label("_Pause")
        self._Paused = not (self._Paused)

    def save(self, widget, data=None):
        """Signal handler for the save action
        
        """
        fileName = os.sep.join([
            self.preferences['outputDir'],
            "acceleration_" + time.strftime("%Y-%m-%d_%H-%M-%S") + ".dat"
        ])
        try:
            with open(fileName, 'wb') as outFile:
                writer = csv.writer(outFile, 'excel-tab')
                outFile.write(
                    writer.dialect.delimiter.join(("#time", "Ax", "Ay", "Az")))
                outFile.write(writer.dialect.lineterminator)
                outFile.write(
                    writer.dialect.delimiter.join(("#s", "g", "g", "g")))
                outFile.write(writer.dialect.lineterminator)
                with self._dataLock:
                    writer.writerows(zip(self._time, *self._accData))
        except IOError as error:
            dialog = gtk.MessageDialog(parent=None,
                                       flags=gtk.DIALOG_DESTROY_WITH_PARENT,
                                       type=gtk.MESSAGE_ERROR,
                                       buttons=gtk.BUTTONS_OK,
                                       message_format=str(error))
            dialog.set_title(error[1])
            dialog.connect('response',
                           lambda dialog, response: dialog.destroy())
            dialog.show()
Пример #5
0
class SensorWindow(object):
	def __init__(self, mainThread, gladefile = 'sensor_window.glade'):
		self.builder = gtk.Builder()
		self.builder.add_from_file(gladefile)
		self.builder.connect_signals(self)

		self._stopped = False
		self.mainThread = mainThread

		self.fig = plt.figure()
		self.numLines = 1

		# lines plot
		self.ax = self.fig.add_subplot(111)
		self.ax.set_xlabel('Time')
		self.ax.set_ylabel('Power')
		self.ax.xaxis.set_animated(True)
		self.ax.yaxis.set_animated(True)
		self.ax.set_title('Light Intensity')
		self.ax.grid(True)

		self.start = time.time()
		self.background1 = None
		self.prev_time = self.start
		self.prev_pixel_offset = 0
		self.x0 = 0
		self.value = [0] * self.numLines

		self.ax.set_ylim(-1, 256)

		self.lines = []
		for i in range(self.numLines):
			line, = self.ax.plot([], [], animated = True, lw = 2)
			self.lines.append(line)

		self.canvas = FigureCanvas(self.fig)

		self.graphview = self.builder.get_object("box2")
		self.graphview.pack_start(self.canvas)
		self.graphview.reorder_child(self.canvas, 0)

		self.img = self.builder.get_object("image1")
		self.img.set_from_file("off.svg")
		self.lamp = False

		self.canvas.show()

		gobject.idle_add(self.update_line)
		self.canvas.mpl_connect('draw_event', self.on_draw)

		self.barpath = []


	def close_window(self, obj):
		print "closing window"
		self.builder.get_object("window1").destroy()

	def destroy_callback(self, obj):
		print "destroying window"
		self.mainThread.stop()
		self._stopped = True

	def close_from_mainthread(self):
		print "close from mainthread"
		self.builder.get_object("window1").destroy()


	def toggle_lamp(self):
		print "toggle lamp!!"
		self.img = self.builder.get_object("image1")
		if(self.lamp):
			self.lamp = False
			self.img.set_from_file("off.svg")
		else:
			self.lamp = True
			self.img.set_from_file("on.svg")

	def update_line(self, *args):

		if self._stopped:
			self.destroy_callback(None)
			return False

		if self.background1 is None:
			return True

		cur_time = time.time()
		pixel_offset = int((cur_time - self.start) * 40.)
		dx_pixel = pixel_offset - self.prev_pixel_offset
		self.prev_pixel_offset = pixel_offset
		dx_data = self.get_dx_data(dx_pixel) #cur_time - self.prev_time)

		x0 = self.x0
		self.x0 += dx_data
		self.prev_time = cur_time

		self.ax.set_xlim(self.x0-2, self.x0+0.1)

		# restore background which will plot lines from previous plots
		self.restore_background_shifted(dx_pixel) #x0, self.x0)

		# now plot line segment within [x0, x0+dx_data],
		# Note that we're only plotting a line between [x0, x0+dx_data].
		xx = np.array([x0, self.x0])
		for i in range(len(self.lines)):
			line = self.lines[i]
			line.set_xdata(xx)

			# the for loop below could be improved by using collection.
			line.set_ydata(np.array([self.value[i], self.value[i]]))
			self.ax.draw_artist(line)

		self.background2 = self.canvas.copy_from_bbox(self.get_bg_bbox())

		self.ax.draw_artist(self.ax.xaxis)
		self.ax.draw_artist(self.ax.yaxis)

		self.canvas.blit(self.ax.get_figure().bbox)
		return True

	def get_dx_data(self, dx_pixel):
		tp = self.ax.transData.inverted().transform_point
		x0, y0 = tp((0, 0))
		x1, y1 = tp((dx_pixel, 0))
		return (x1 - x0)

	def get_bg_bbox(self):
		return self.ax.bbox.padded(-3)

	def save_bg(self):
		self.background1 = self.canvas.copy_from_bbox(self.ax.get_figure().bbox)
		self.background2 = self.canvas.copy_from_bbox(self.get_bg_bbox())

	def on_draw(self, *args):
		self.save_bg()
		return False

	def restore_background_shifted(self, dx_pixel):
		"""
		restore bacground shifted by dx in data coordinate. This only
		works if the data coordinate system is linear.
		"""

		# restore the clean slate background
		self.canvas.restore_region(self.background1)

		# restore subregion (x1+dx, y1, x2, y2) of the second bg
		# in a offset position (x1-dx, y1)
		x1, y1, x2, y2 = self.background2.get_extents()
		self.canvas.restore_region(self.background2,
					bbox=(x1+dx_pixel, y1, x2, y2),
					xy=(x1-dx_pixel, y1))

		return dx_pixel

	def update(self, data):
		if type(data) == ListType:
			assert(len(self.lines) == len(data))
			self.value = data
		else:
			assert(len(self.lines) == 1)
			self.value = [data]
Пример #6
0
class Plot(gtk.HBox):
    """ Base class for LivePlots. This class is an abstract class. In addition
    to inheriting from this class it is also required to take the following
    actions to achieve a functioning plot:
    Bla bla bla
    """
    
    def __init__(self, dpi=100, x_pixel_size=500, y_pixel_size=400):
        gtk.HBox.__init__(self)
        # If the class is being reinitialized, we need to remove the old plot
        [self.remove(child) for child in self.get_children()]
        self.vbox = gtk.VBox()
        self.pack_start(self.vbox)
        # this is bad with labels, I have to figure out why
        self.connect('size_allocate', self._full_update)

        self.fig = Figure(figsize=(float(x_pixel_size)/dpi,
                                   float(y_pixel_size)/dpi),
                          dpi=dpi)
        self.fig.set_facecolor('white')
        self.canvas = FigureCanvasGTKAgg(self.fig)
        self.ax = self.fig.add_subplot(111)
        self.vbox.pack_end(self.canvas)
        self.canvas.connect('button_press_event', self._on_mouse_click)

        self.first_update = True
        self.settings = {}
        self.n_lines = None
        #self.line_styles = None
        #self.line_colors = None
        self.lines = None
        self.saved_window_size = None
        self.background = None
        self.auto_x_scale = False
        self.auto_y_scale = False

    def _change_settings_common(self, number_of_lines, **kw):
        """ Change the subset of settings that are common for all plots """
        self.settings.update(kw)
        self.n_lines = number_of_lines
        self.line_styles = kw['line_styles'] if kw.has_key('line_styles')\
            else ['']*self.n_lines
        self.line_colors = kw['line_colors'] if kw.has_key('line_colors')\
            else self._get_colors(self.n_lines)
        self.lines = None
        self.background = None

        if self.settings['legends'] is not None:
            c = matplotlib.colors.ColorConverter()
            colors = [matplotlib.colors.rgb2hex(c.to_rgb(color))
                      for color in self.line_colors]
            self.legends = Legends(self.settings['legends'],
                                   colors,
                                   self.settings['legend_placement'],
                                   self.settings['legend_cols'])
            if self.settings['legend_placement'] == 'top':
                self.vbox.pack_end(self.legends, expand=False)
            else:
                self.pack_end(self.legends, expand=False)


    def _on_mouse_click(self, widget, event):
        if event.type == gtk.gdk.BUTTON_PRESS and event.button == 3:
            b1 = gtk.MenuItem("A button")
            b2 = gtk.MenuItem("Another")
            menu = gtk.Menu()
            menu.append(b1)
            menu.append(b2)
            b1.show()
            b2.show()
            menu.popup(None, None, None, event.button, event.time)

    def _update_bounds(self):
        return self._update_x_bounds() or self._update_y_bounds()

    def _update_x_bounds(self):
        if not self.auto_x_scale:
            return False

    def _update_y_bounds(self):
        modified = False
        if not self.auto_y_scale:
            return modified

        # Combine data (double loop), sort out None and get min/max
        y_min = min([inner for outer in self.y for inner in outer\
                         if inner is not None])
        y_max = max([inner for outer in self.y for inner in outer\
                         if inner is not None])
        delta = y_max - y_min
        if delta < 1E-10:
            return modified

        br = 0.2
        if y_min < self.settings['y_bounds'][0]:
            self.settings['y_bounds'] =\
                (y_min-br*delta, self.settings['y_bounds'][1])
            modified = True
        elif y_min > self.settings['y_bounds'][0] + br*delta:
            self.settings['y_bounds'] =\
                (y_min, self.settings['y_bounds'][1])
            modified = True

        if y_max > self.settings['y_bounds'][1]:
            self.settings['y_bounds'] =\
                (self.settings['y_bounds'][0], y_max+br*delta)
            modified = True
        elif y_max < self.settings['y_bounds'][1] - br*delta:
            self.settings['y_bounds'] =\
                (self.settings['y_bounds'][0], y_max)
            modified = True

        return modified

    def update_legends(self):
        if self.settings['legends'] is not None:
            for n in range(self.n_lines):
                point = self.y[n][-1]
                self.legends.set_legend_text(n, point)

    def _quick_update(self):
        if self.first_update:
            self._full_update()
            self.first_update = False
        self.canvas.restore_region(self.background)
        [line.set_ydata(y_data) for line, y_data in zip(self.lines, self.y)]
        [self.ax.draw_artist(line) for line in self.lines]
        # just redraw the axes rectangle
        self.canvas.blit(self.ax.bbox)

    def _full_update(self, widget=None, size=None):
        # This does not work properly, FIXME
        if widget is not None:
            if [size.width, size.height] != self.saved_window_size:
                self.saved_window_size = [size.width, size.height]
            else:
                return
        # Plot
        if self.first_update:
            plot = self.ax.semilogy if self.settings['logscale'] else self.ax.plot
            self.lines = [plot(x, y, style, color=color, animated=True)[0]
                          for x, y, color, style in
                          zip(self.x, self.y, self.line_colors, self.line_styles)]
            # Title and axis labels
            if self.settings['title'] is not None:
                self.ax.set_title(self.settings['title'])
            if self.settings['x_label'] is not None:
                self.ax.set_xlabel(self.settings['x_label'])
            if self.settings['y_label'] is not None:
                self.ax.set_ylabel(self.settings['y_label'])
            self.fig.subplots_adjust(left=0.25, bottom=0.15)
        else:
            [line.set_ydata(y_data) for line, y_data in zip(self.lines, self.y)]

        # Get or set boundaries
        if self.first_update:
            if self.settings['x_bounds'] is None:
                self.settings['x_bounds'] = self.ax.get_xlim()
            if self.settings['y_bounds'] is None:
                self.settings['y_bounds'] = self.ax.get_ylim()
        else:
            self.ax.set_xlim(*self.settings['x_bounds'])
            self.ax.set_ylim(*self.settings['y_bounds'])

        # Get the background for later use
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        # First draw update
        [line.set_animated(False) for line in self.lines]
        self.canvas.draw()
        [line.set_animated(True) for line in self.lines]

    def _get_colors(self, n):
        """ Generate colors for the lines if they are not provided. First use
        6 of the standard colors and then generate random colors

        Parameters:
            n -- the number of colors requested
        """
        standard = ['r', 'g', 'b', 'c', 'm', 'k']
        if n <= len(standard):
            out = standard[:n]
        else:
            out = standard
        if n > len(standard):
            for i in range(len(standard), n):
                out.append((random.random(), random.random(), random.random()))
        return out
Пример #7
0
class XratersWindow(gtk.Window):
    __gtype_name__ = "XratersWindow"
    
    def __init__(self):
        """__init__ - This function is typically not called directly.
        Creation a XratersWindow requires redeading the associated ui
        file and parsing the ui definition extrenally,
        and then calling XratersWindow.finish_initializing().

        Use the convenience function NewXratersWindow to create
        XratersWindow object.

        """
        self._acc_cal = ((128, 128, 128),
                         (255, 255, 255))
        self._acc = [0, 0, 0]
        self._connected = False
        self._wiiMote = None
        self._resetData()
        self._dataLock = threading.Lock()
        
    isConnected = property(lambda self: self._connected)
    
    def callback(funct):
        """A decorator used to require connection to the Wii Remote
        
        This decorator is used to implement the precondition that 
        the Wii Remote must be connected. 
        """
        def _callback(cls, *args, **kwds):
            if cls.isConnected:
                funct(cls, *args, **kwds)
                return True
            else:
                return False
        return _callback
    
    def _connectCallback(self, connectionMaker):
        """Callback function called upon successful connection to the Wiimote
        """
        if connectionMaker.connected:
            self._connected = True
            self._wiiMote = connectionMaker.wiiMote
            self._resetData()
            gobject.timeout_add(45, self._drawAcc)
            self.widget('actionDisconnect').set_sensitive(True)
            self.widget('actionSave').set_sensitive(True)
            self.widget('actionReset').set_sensitive(True)
            self.widget('actionPause').set_sensitive(True)
            self.widget('toolbutton1').set_related_action(self.widget('actionDisconnect'))
            self._acc_cal = connectionMaker.acc_cal
            self._wiiMote.mesg_callback = self._getAcc
            self._updBatteryLevel()
            gobject.timeout_add_seconds(60, self._updBatteryLevel)
        else:
            self.widget('actionWiiConnect').set_sensitive(True)
            
    @callback
    def _upd_background(self, event):
        """Keep a copy of the figure background
        """
        self.__background = self._accCanvas.copy_from_bbox(self._accAxis.bbox)
    
    def _getAcc(self, messages, theTime=0):
        """Process acceleration messages from the Wiimote
        
        This function is intended to be set as cwiid.mesg_callback
        """
        if self._Paused:
            return
        for msg in messages:
            if msg[0] == cwiid.MESG_ACC:
                # Normalize data using calibration info
                for i, axisAcc in enumerate(msg[1]):
                    self._acc[i] = float(axisAcc-self._acc_cal[0][i])
                    self._acc[i] /=(self._acc_cal[1][i]\
                                    -self._acc_cal[0][i])
                with self._dataLock:
                    # Store time and acceleration in the respective arrays
                    self._time.append(theTime-self._startTime)
                    [self._accData[i].append(self._acc[i]) for i in threeAxes]
                # We only keep about 6 seconds worth of data
                if (self._time[-1] - self._time[0] > 6):
                    with self._dataLock:
                        self._time.pop(0)
                        [self._accData[i].pop(0) for i in threeAxes]

    @callback
    def _drawAcc(self):
        """Update the acceleration graph
        
        """
        # Do nothing while paused or there's no data available
        if self._Paused or len(self._time)==0:
            return
        draw_flag = False
        # Update axes limits if the data fall out of range 
        lims = self._accAxis.get_xlim()
        if self._time[-1] > lims[1]:
            self._accAxis.set_xlim(lims[0], lims[1]+2)
            lims = self._accAxis.get_xlim()
            draw_flag = True
        if (self._time[-1] - lims[0] > 6):
            self._accAxis.set_xlim(lims[0]+2, lims[1])
            draw_flag = True
        if draw_flag:
            gobject.idle_add(self._accCanvas.draw)
        # Do the actual update of the background
        if self.__background != None:
            self._accCanvas.restore_region(self.__background)
        # Do the actual update of the lines
        with self._dataLock:
            [self._lines[i].set_data(self._time, self._accData[i]) for i in threeAxes]
        [self._accAxis.draw_artist(self._lines[i]) for i in threeAxes]
        self._accCanvas.blit(self._accAxis.bbox)

    @callback
    def _updBatteryLevel(self):
        """Callback to update the battery indicator in the status bar
        
        """
        self._wiiMote.request_status()
        self._setBatteryIndicator(float(self._wiiMote.state['battery']) / 
                                  cwiid.BATTERY_MAX)
        
    def _setBatteryIndicator(self, level):
        """Actually update the battery indicator in the status bar
        
        """
        progressBar = self.widget("progressbarBattery")
        progressBar.set_fraction(level)
        progressBar.set_text("Battery: %.0f%%" % (level * 100))
    
    def _resetData(self):
        """Reset stored data and status flags to their defaults
        
        """
        self._accData = [list(), list(), list()]
        self._time = list()
        self._startTime = time.time()
        self._moveTime = self._startTime
        self._Paused = False
        
    def widget(self, name):
        """Helper function to retrieve widget handlers
        
        """ 
        return self.builder.get_object(name)

    def finish_initializing(self, builder):
        """finish_initalizing should be called after parsing the ui definition
        and creating a XratersWindow object with it in order to finish
        initializing the start of the new XratersWindow instance.

        """
        #get a reference to the builder and set up the signals
        self.builder = builder
        self.builder.connect_signals(self)
        
        #uncomment the following code to read in preferences at start up
        dlg = PreferencesXratersDialog.NewPreferencesXratersDialog()
        self.preferences = dlg.get_preferences()

        #code for other initialization actions should be added here
        self._accFigure = Figure(figsize=(8,6), dpi=72)
        self._accAxis = self._accFigure.add_subplot(111)
        self._accAxis.set_xlabel("time (s)")
        self._accAxis.set_ylabel("acceleration (g)")
        self._lines = self._accAxis.plot(self._time, self._accData[X],
                                         self._time, self._accData[Y],
                                         self._time, self._accData[Z], 
                                         animated=True)
        self._accFigure.legend(self._lines, ("X", "Y", "Z"), 
                             'upper center', 
                             ncol=3)
        self._accAxis.set_xlim(0, 2)
        self._accAxis.set_ylim(-3, 3)
        self._accCanvas = FigureCanvas(self._accFigure)
        self._accCanvas.mpl_connect("draw_event", self._upd_background)
        self.__background = self._accCanvas.copy_from_bbox(self._accAxis.bbox)
        self._accCanvas.show()
        self._accCanvas.set_size_request(600, 400)
        vbMain = self.widget("vboxMain")
        vbMain.pack_start(self._accCanvas, True, True)
        vbMain.show()
        vbMain.reorder_child(self._accCanvas, 2)
        self._setBatteryIndicator(0)
        
    def about(self, widget, data=None):
        """about - display the about box for xraters """
        about = AboutXratersDialog.NewAboutXratersDialog()
        response = about.run()
        about.destroy()

    def preferences(self, widget, data=None):
        """preferences - display the preferences window for xraters """
        prefs = PreferencesXratersDialog.NewPreferencesXratersDialog()
        response = prefs.run()
        if response == gtk.RESPONSE_OK:
            #make any updates based on changed preferences here
            self.preferences = prefs.get_preferences()
        prefs.destroy()

    def quit(self, widget, data=None):
        """quit - signal handler for closing the XratersWindow"""
        self.destroy()

    def on_destroy(self, widget, data=None):
        """on_destroy - called when the XratersWindow is close. """
        #clean up code for saving application state should be added here
        if self.isConnected:
            self.on_wiiDisconnect(widget, data)
        gtk.main_quit()
        
    def on_wiiConnect(self, widget, data=None):
        """Signal handler for the WiiConnect action
        
        """
        self.widget('actionWiiConnect').set_sensitive(False)
        connectionMaker = WiiConnectionMaker(self.preferences['wiiAddress'],
                                             self.widget("statusbar"),
                                             self._connectCallback)
        self._accAxis.set_xlim(0, 2)
        gobject.idle_add(self._accCanvas.draw)
        connectionMaker.start()
        
    def on_wiiDisconnect(self, widget, data=None):
        """Signal handler for the WiiDisconnect action
        
        """
        self._wiiMote.close()
        self._connected = False
        self.widget('actionDisconnect').set_sensitive(False)
        self.widget('actionWiiConnect').set_sensitive(True)
        self.widget('actionReset').set_sensitive(False)
        self.widget('actionPause').set_sensitive(False)
        self.widget('toolbutton1').set_related_action(self.widget('actionWiiConnect'))
        self.widget('actionSave').set_sensitive(True)
        self.widget('statusbar').pop(self.widget("statusbar").get_context_id(''))
        self._setBatteryIndicator(0)
        
    def on_Reset(self, widget, data=None):
        """Signal handler for the reset action
        
        """
        self._resetData()
        self._accAxis.set_xlim(0, 2)
        gobject.idle_add(self._accCanvas.draw)
        
    def on_Pause(self, widge, data=None):
        """Signal handler for the pause action
        
        """
        if not self._Paused:
            self.widget('actionPause').set_short_label("Un_pause")
        else:
            self.widget('actionPause').set_short_label("_Pause")
        self._Paused = not (self._Paused)        

    def save(self, widget, data=None):
        """Signal handler for the save action
        
        """
        fileName = os.sep.join([self.preferences['outputDir'], 
                                "acceleration_" + 
                                time.strftime("%Y-%m-%d_%H-%M-%S") + 
                                ".dat"]) 
        try:
            with open(fileName, 'wb') as outFile:
                writer = csv.writer(outFile, 'excel-tab')
                outFile.write(writer.dialect.delimiter.join(("#time",
                                                          "Ax",
                                                          "Ay",
                                                          "Az")))
                outFile.write(writer.dialect.lineterminator)
                outFile.write(writer.dialect.delimiter.join(("#s",
                                                          "g",
                                                          "g",
                                                          "g")))
                outFile.write(writer.dialect.lineterminator)
                with self._dataLock:
                    writer.writerows(zip(self._time, *self._accData))
        except IOError as error:
            dialog = gtk.MessageDialog(parent   = None,
                                       flags    = gtk.DIALOG_DESTROY_WITH_PARENT,
                                       type     = gtk.MESSAGE_ERROR,
                                       buttons  = gtk.BUTTONS_OK,
                                       message_format = str(error))
            dialog.set_title(error[1])
            dialog.connect('response', lambda dialog, response: dialog.destroy())
            dialog.show()
Пример #8
0
class plot_data(object):
    '''
    Creates a object with a widget ready to be inserted in a GTK window, in wich we can 
    plot the current robot variables.
                    
    calling the object will update the plot with the data passed
    calling the method set_values you can change the color, units a/o length
    '''
    def __init__(self, units=None, colors=None, length=None):
        '''
         Modifiable attributes:
         colors: color of the lines - list of strings: len = 4 default: ['r', 'g', 'b', 'y']
         units: units of the plots - list of strings: len = 2 default: [rad, N*m]
         length: maximum period of time to show - int or float default: 100
        
         Accessible attributes:
         main_widget: widget to be inserted in a GTK window
        '''
        self.set_values(units, colors, length)
        # Define axis and lines labels
        self.__xlabel = 'Time - s'
        self.__ylabel = ['Angular position - '+self.__units[0], 'Angular velocity - '+self.__units[0]+'/s', 
                         'Angular acceleration - '+self.__units[0]+'/s**2', 'Torque - '+self.__units[1]]
        self.__lines_labels = ["Shoulder_X", "Shoulder_Y", "Shoulder_Z", "Elbow_Z"]
        # Define font size for the legend
        self.__font = font_manager.FontProperties(size = 8)
        # Create the Figure and the plot
        self.__figure = figure()
        self.__sub_figures = []
        self.__backgrounds = []
        self.__lines = [[], [], [], []]
        # Create the widget, a FigureCanvas containing our Figure
        self.main_widget = FigureCanvas(self.__figure)
        # Create and configure the subplots
        for index in xrange(4):
            self.__sub_figures.append(self.__figure.add_subplot(221+index))
            self.__sub_figures[index].grid(True)
            self.__sub_figures[index].set_xlabel(self.__xlabel, fontsize = 9)
            self.__sub_figures[index].set_ylabel(self.__ylabel[index], fontsize = 9)
            #FIXME: change the y limits, the currents are for test only
            self.__sub_figures[index].set_ylim(-256, 256)
            self.__sub_figures[index].set_xlim(0, self.__lenght)
            self.__sub_figures[index].tick_params(axis='both', which = 'major', labelsize = 10)
            self.__sub_figures[index].tick_params(axis='both', which = 'minor', labelsize = 8)
            for l_index in xrange(4):
                self.__lines[index].append(self.__sub_figures[index].plot([], [], self.__colors[l_index], animated = True)[0])
            #Saving the firsts background to redraw 
            self.__backgrounds.append(self.main_widget.copy_from_bbox(self.__sub_figures[index].bbox))
        #Setting up the legend box
        figlegend(self.__lines[0], self.__lines_labels, loc = "upper center", prop= self.__font)
        #Show and set initial data
        self.main_widget.draw()
        self.__reset_data()
        return
        
    def __call__(self, values, d_time):
        '''
        values: object with the current values to plot, in the form of attributes like:
            self.position = []
            self.velocity = []
            self.acceleration = []
            self.torque = []
        
        d_time: current time, since the plot starts - int or float
        '''
        self.__time.append(d_time)
        if (d_time >= (self.__time[0] + self.__lenght)):
            self.__reset_data()
            self.__time.append(d_time)
            for index in xrange(4):
                self.__sub_figures[index].set_xlim(d_time, d_time+self.__lenght)
            self.main_widget.draw()
            for index in xrange(4):
                self.__backgrounds[index] = self.main_widget.copy_from_bbox(self.__sub_figures[index].bbox)
        for index in xrange(4):
            self.main_widget.restore_region(self.__backgrounds[index])
            self.__position[index].append(values.position[index])
            self.__velocity[index].append(values.velocity[index])
            self.__acceleration[index].append(values.acceleration[index])
            self.__torque[index].append(values.torque[index])
        for index in xrange(4):
            for l_index in xrange(4):
                if index == 0:
                    self.__lines[index][l_index].set_data(self.__time, self.__position[l_index])
                elif index == 1:
                    self.__lines[index][l_index].set_data(self.__time, self.__velocity[l_index])
                elif index == 2:
                    self.__lines[index][l_index].set_data(self.__time, self.__acceleration[l_index])
                elif index == 3:
                    self.__lines[index][l_index].set_data(self.__time, self.__torque[l_index])
                self.__sub_figures[index].draw_artist(self.__lines[index][l_index])
            self.main_widget.blit(self.__sub_figures[index].bbox)
        return
        
    def __reset_data(self):
        #Create the vectors for the variables
        try: 
            type(self.__time)
        except:
            self.__time = []
            self.__position = [[], [], [], []]
            self.__velocity = [[], [], [], []]
            self.__acceleration = [[], [], [], []]
            self.__torque = [[], [], [], []]
            return
        #If the vectors are already created, then only leave the last value
        del(self.__time[-2:0:-1])
        self.__time.pop(0)
        for index in xrange(4):
            del(self.__position[index][-2:0:-1])
            del(self.__velocity[index][-2:0:-1])
            del(self.__acceleration[index][-2:0:-1])
            del(self.__torque[index][-2:0:-1])
            self.__position[index].pop(0)
            self.__velocity[index].pop(0)
            self.__acceleration[index].pop(0)
            self.__torque[index].pop(0)
        return
    
    def set_values(self, units=None, colors=None, length=None):
        self.__units = ["rad", "N*m"] if type(units) is NoneType else units
        self.__colors = ['r', 'g', 'b', 'y'] if type(colors) is NoneType else colors
        self.__lenght = 100 if type(length) is NoneType else length
        return