예제 #1
0
class SignalViewerWidget(QtGui.QWidget):
    """Shows different visualizations of a seismic signal (magnitude, envelope,
    spectrogram, characteristic function).
    Allows the user to manipulate it (navigate through it, zoom in/out,
    edit detected events, select threshold value, etc...)

    """

    CF_loaded = QtCore.Signal(bool)
    event_selected = QtCore.Signal(rc.ApasvoEvent)

    def __init__(self, parent, document=None):
        super(SignalViewerWidget, self).__init__(parent)

        self.document = document
        self.xmin = 0.0
        self.xmax = 0.0
        self.xleft = 0.0
        self.xright = 0.0
        self.time = np.array([])

        self.fs = 0.0
        self.signal = None
        self.envelope = None
        self.cf = None
        self.time = None
        self._signal_data = None
        self._envelope_data = None
        self._cf_data = None

        self.fig, _ = plt.subplots(3, 1)

        self.signal_ax = self.fig.axes[0]
        self.cf_ax = self.fig.axes[1]
        self.specgram_ax = self.fig.axes[2]

        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(
            QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding,
                              QtGui.QSizePolicy.Policy.Expanding))
        self.canvas.setMinimumHeight(320)
        self.graphArea = QtGui.QScrollArea(self)
        self.graphArea.setWidget(self.canvas)
        self.graphArea.setWidgetResizable(True)

        self.eventMarkers = {}
        self.last_right_clicked_event = None
        self.thresholdMarker = None
        self.playback_marker = None
        self.selector = SpanSelector(self.fig)
        self.minimap = MiniMap(self, self.signal_ax, None)

        # Load Spectrogram settings
        self.update_specgram_settings()

        # Animation related attributes
        self.background = None
        self.animated = False

        # Create context menus
        self.event_context_menu = QtGui.QMenu(self)
        self.takanami_on_event_action = QtGui.QAction(
            "Apply Takanami to Event", self)
        self.takanami_on_event_action.setStatusTip(
            "Refine event position by using Takanami algorithm")
        self.event_context_menu.addAction(self.takanami_on_event_action)
        self.takanami_on_event_action.triggered.connect(
            self.apply_takanami_to_selected_event)

        self.selection_context_menu = QtGui.QMenu(self)
        self.create_event_action = QtGui.QAction(
            "Create New Event on Selection", self)
        self.create_event_action.setStatusTip(
            "Create a new event on selection")
        self.takanami_on_selection_action = QtGui.QAction(
            "Apply Takanami to Selection", self)
        self.takanami_on_selection_action.setStatusTip(
            "Apply Takanami algorithm to selection")
        self.selection_context_menu.addAction(self.create_event_action)
        self.selection_context_menu.addAction(
            self.takanami_on_selection_action)
        self.create_event_action.triggered.connect(
            self.create_event_on_selection)
        self.takanami_on_selection_action.triggered.connect(
            self.apply_takanami_to_selection)

        # format axes
        formatter = FuncFormatter(lambda x, pos: clt.float_secs_2_string_date(
            x, self.document.record.starttime))
        for ax in self.fig.axes:
            ax.callbacks.connect('xlim_changed', self.on_xlim_change)
            ax.xaxis.set_major_formatter(formatter)
            plt.setp(ax.get_xticklabels(), visible=True)
            ax.grid(True, which='both')
        self.specgram_ax.callbacks.connect('ylim_changed', self.on_ylim_change)
        self.specgram_ax.set_xlabel('Time (seconds)')
        plt.setp(self.signal_ax.get_yticklabels(), visible=False)
        #self.signal_ax.set_ylabel('Signal Amp.')
        self.cf_ax.set_ylabel('CF Amp.')
        self.specgram_ax.set_ylabel('Frequency (Hz)')

        # Set the layout
        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.graphArea)
        self.layout.addWidget(self.minimap)

        self.selector.toggled.connect(self.minimap.set_selection_visible)
        self.selector.valueChanged.connect(self.minimap.set_selection_limits)
        self.selector.right_clicked.connect(self.on_selector_right_clicked)

        if self.document is not None:
            self.set_record(document)

    @property
    def data_loaded(self):
        return self.document is not None

    def set_record(self, document, step=120.0):
        self.document = document
        self.fs = self.document.record.fs
        self.signal = self.document.record.signal
        self.envelope = env.envelope(self.signal)
        self.cf = self.document.record.cf
        self.time = np.linspace(0,
                                len(self.signal) / self.fs,
                                num=len(self.signal),
                                endpoint=False)
        self.xmax = self.time[-1]
        # Draw minimap
        self.minimap.minimapSelector.set(
            visible=False)  # Hide minimap selector while loading
        self.minimap.set_record(self.document.record, step)
        # Plot signal
        step_samples = step * self.fs
        self._signal_data = self.signal_ax.plot(self.time[:step_samples],
                                                self.signal[:step_samples],
                                                color='black',
                                                rasterized=True)[0]
        # Plot envelope
        self._envelope_data = self.signal_ax.plot(self.time[:step_samples],
                                                  self.envelope[:step_samples],
                                                  color='red',
                                                  rasterized=True)[0]
        # Adjust y axis for signal plot
        signal_yaxis_max_value = max(np.max(self.signal),
                                     np.max(self.envelope))
        signal_yaxis_min_value = np.min(self.signal)
        plotting.adjust_axes_height(self.signal_ax,
                                    max_value=signal_yaxis_max_value,
                                    min_value=signal_yaxis_min_value)
        # Plot CF
        cf_loaded = (self.cf.size != 0)
        self.set_cf_visible(cf_loaded)
        self.CF_loaded.emit(cf_loaded)
        cf_step_samples = min(step_samples, len(self.cf))
        self._cf_data = self.cf_ax.plot(self.time[:cf_step_samples],
                                        self.cf[:cf_step_samples],
                                        color='black',
                                        rasterized=True)[0]
        # Adjust y axis for CF plot
        if cf_loaded:
            plotting.adjust_axes_height(self.cf_ax,
                                        max_value=np.max(self.cf),
                                        min_value=np.min(self.cf))
        self.thresholdMarker = ThresholdMarker(self.cf_ax)
        # Plot espectrogram
        plotting.plot_specgram(self.specgram_ax,
                               self.signal,
                               self.fs,
                               nfft=self.specgram_windowlen,
                               noverlap=self.specgram_noverlap,
                               window=self.specgram_window)
        # Set the span selector
        self.selector.fs = self.fs
        self.selector.set_active(False)
        self.selector.set_selection_limits(self.xmin, self.xmax)
        # Set the playback marker
        self.playback_marker = PlayBackMarker(self.fig, self)
        # Set the initial xlimits
        self.set_xlim(0, step)
        self.subplots_adjust()
        # Set event markers
        self.eventMarkers = {}
        for event in self.document.record.events:
            self.create_event(event)
        # Now activate selector again on minimap
        self.minimap.minimapSelector.set(visible=True)
        self.minimap.draw()

    def unset_record(self):
        self.document = None
        self.signal = None
        self.envelope = None
        self.cf = None
        self.time = None
        self._signal_data = None
        self._envelope_data = None
        self._cf_data = None
        self.xmin, self.xmax = 0.0, 0.0
        self.eventMarkers = {}
        # Clear axes
        self.signal_ax.lines = []
        self.cf_ax.lines = []
        self.specgram_ax.lines = []
        self.specgram_ax.images = []

        self.CF_loaded.emit(False)

    def update_cf(self):
        if self.data_loaded:
            self.cf = self.document.record.cf
            self._cf_data.set_xdata(self.time[:len(self.cf)])
            self._cf_data.set_ydata(self.cf)
            plotting.adjust_axes_height(self.cf_ax)
            cf_loaded = (self.cf.size != 0)
            self.CF_loaded.emit(cf_loaded)
            self.set_cf_visible(cf_loaded)
            self.draw()

    def create_events(self, new_events_set):
        for event in new_events_set.get(self.document.record.uuid, []):
            self.create_event(event)

    def create_event(self, event):
        event_id = event.resource_id.uuid
        if event_id not in self.eventMarkers:
            marker = EventMarker(self.fig, self.minimap, self.document, event)
            self.eventMarkers[event_id] = marker
            marker.event_selected.connect(self.event_selected.emit)
            marker.right_clicked.connect(self.on_event_right_clicked)

    def delete_events(self, new_events_set):
        for event in new_events_set.get(self.document.record.uuid, []):
            self.delete_event(event)

    def delete_event(self, event):
        event_id = event.resource_id.uuid
        self.eventMarkers[event_id].remove()
        self.eventMarkers.pop(event_id)

    def update_event(self, event):
        self.eventMarkers[event.resource_id.uuid].update()

    def set_xlim(self, l, r):
        xmin = max(0, l)
        xmax = min(self.xmax, r)
        self.signal_ax.set_xlim(xmin, xmax)

    def on_xlim_change(self, ax):
        xmin, xmax = ax.get_xlim()
        if (self.xleft, self.xright) != (xmin, xmax):
            self.xleft, self.xright = xmin, xmax
            if self.xmin <= xmin <= xmax <= self.xmax:
                # Update minimap selector
                if (xmin, xmax) != self.minimap.get_selector_limits():
                    self.minimap.set_selector_limits(xmin, xmax)

                # Update axes
                for axes in self.fig.axes:
                    if ax != axes:
                        axes.set_xlim(xmin, xmax)

                # Update data
                xmin = int(max(0, xmin) * self.fs)
                xmax = int(min(self.xmax, xmax) * self.fs)

                pixel_width = np.ceil(self.fig.get_figwidth() *
                                      self.fig.get_dpi())

                if self._signal_data is not None:
                    x_data, y_data = plotting.reduce_data(
                        self.time, self.signal, pixel_width, xmin, xmax)
                    self._signal_data.set_xdata(x_data)
                    self._signal_data.set_ydata(y_data)

                if self._envelope_data is not None:
                    x_data, y_data = plotting.reduce_data(
                        self.time, self.envelope, pixel_width, xmin, xmax)
                    self._envelope_data.set_xdata(x_data)
                    self._envelope_data.set_ydata(y_data)

                if self._cf_data is not None and self.cf_ax.get_visible():
                    x_data, y_data = plotting.reduce_data(
                        self.time[:len(self.cf)], self.cf, pixel_width, xmin,
                        xmax)
                    self._cf_data.set_xdata(x_data)
                    self._cf_data.set_ydata(y_data)
                # Draw graph
                self.draw()

            else:
                xmin = max(self.xmin, xmin)
                xmax = min(self.xmax, xmax)
                ax.set_xlim(xmin, xmax)

    def on_ylim_change(self, ax):
        if self.data_loaded:
            if ax == self.specgram_ax:
                ymin, ymax = ax.get_ylim()
                nyquist_freq = (self.fs / 2.0)
                if ymin < 0.0:
                    ax.set_ylim(0.0, ymax)
                elif ymax > nyquist_freq:
                    ax.set_ylim(ymin, nyquist_freq)

    def set_event_selection(self, events):
        event_id_list = [event.resource_id.uuid for event in events]
        for event_id in self.eventMarkers:
            self.eventMarkers[event_id].set_selected(event_id in event_id_list)
        self.draw()
        self.minimap.draw()

    def set_position(self, pos):
        """"""
        xmin, xmax = self.signal_ax.get_xlim()
        mrange = xmax - xmin
        l, r = pos - mrange / 2.0, pos + mrange / 2.0
        if l < self.xmin:
            l, r = self.xmin, mrange
        elif r > self.xmax:
            l, r = self.xmax - mrange, self.xmax
        self.set_xlim(l, r)

    def goto_event(self, event):
        if event.resource_id.uuid in self.eventMarkers:
            self.set_position(event.stime / self.fs)

    def showEvent(self, event):
        self.draw()
        self.minimap.draw_animate()

    def resizeEvent(self, event):
        self.draw()
        self.minimap.draw_animate()

    def set_signal_amplitude_visible(self, show_sa):
        if self._signal_data is not None and self._envelope_data is not None:
            if self._signal_data.get_visible() != show_sa:
                self._signal_data.set_visible(show_sa)
                show_axis = (self._signal_data.get_visible() +
                             self._envelope_data.get_visible())
                self.signal_ax.set_visible(show_axis)
                if self.data_loaded:
                    self.subplots_adjust()
                    self.draw()

    def set_signal_envelope_visible(self, show_se):
        if self._signal_data is not None and self._envelope_data is not None:
            if self._envelope_data.get_visible() != show_se:
                self._envelope_data.set_visible(show_se)
                show_axis = (self._signal_data.get_visible() +
                             self._envelope_data.get_visible())
                self.signal_ax.set_visible(show_axis)
                if self.data_loaded:
                    self.subplots_adjust()
                    self.draw()

    def set_cf_visible(self, show_cf):
        if self.cf_ax.get_visible() != show_cf:
            if self.data_loaded:
                if len(self.cf) <= 0:
                    self.cf_ax.set_visible(False)
                else:
                    self.cf_ax.set_visible(show_cf)
                    self.subplots_adjust()
                    self.draw()

    def set_espectrogram_visible(self, show_eg):
        if self.specgram_ax.get_visible() != show_eg:
            self.specgram_ax.set_visible(show_eg)
            if self.data_loaded:
                self.subplots_adjust()
                self.draw()

    def set_minimap_visible(self, show_mm):
        if self.minimap.get_visible() != show_mm:
            self.minimap.set_visible(show_mm)
            self.minimap.draw_animate()

    def set_threshold_visible(self, show_thr):
        if self.thresholdMarker:
            if self.thresholdMarker.get_visible() != show_thr:
                self.thresholdMarker.set_visible(show_thr)
                self.draw()

    def subplots_adjust(self):
        visible_subplots = [
            ax for ax in self.fig.get_axes() if ax.get_visible()
        ]
        for i, ax in enumerate(visible_subplots):
            correct_geometry = (len(visible_subplots), 1, i + 1)
            if correct_geometry != ax.get_geometry():
                ax.change_geometry(len(visible_subplots), 1, i + 1)
        # Adjust space between subplots
        self.fig.subplots_adjust(left=0.06,
                                 right=0.95,
                                 bottom=0.14,
                                 top=0.95,
                                 hspace=0.22)

    def get_selector_limits(self):
        return self.selector.get_selector_limits()

    def set_selector_limits(self, xleft, xright):
        self.selector.set_selector_limits(xleft, xright)

    def set_selection_enabled(self, value):
        self.selector.set_enabled(value)

    def set_playback_position(self, position):
        if self.playback_marker is not None:
            self.playback_marker.set_position(position)
            self.minimap.playback_marker.set_position(position)

    def set_playback_marker_visible(self, show_marker):
        if self.playback_marker is not None:
            self.playback_marker.set_visible(show_marker)
            self.minimap.playback_marker.set_visible(show_marker)

    def on_event_right_clicked(self, event):
        self.last_right_clicked_event = event
        self.event_context_menu.exec_(QtGui.QCursor.pos())

    def apply_takanami_to_selected_event(self):
        takanamidialog.TakanamiDialog(
            self.document,
            seismic_event=self.last_right_clicked_event).exec_()

    def apply_takanami_to_selection(self):
        xleft, xright = self.get_selector_limits()
        takanamidialog.TakanamiDialog(self.document, xleft, xright).exec_()

    def create_event_on_selection(self):
        xleft, xright = self.get_selector_limits()
        xleft, xright = xleft * self.fs, xright * self.fs
        cf = self.cf[xleft:xright]
        if cf.size > 0:
            time = (xleft + np.argmax(cf))
        else:
            time = (xleft + ((xright - xleft) / 2.0))
        self.document.createEvent(time=time)

    def draw(self):
        if self.animated:
            self._draw_animate()
        else:
            self.canvas.draw_idle()

    def _draw_animate(self):
        self.canvas.restore_region(self.background)
        for artist in self._get_animated_artists():
            if artist.get_visible():
                ax = artist.get_axes()
                if ax is not None:
                    if artist.get_axes().get_visible():
                        self.fig.draw_artist(artist)
                else:
                    self.fig.draw_artist(artist)
        self.canvas.blit(self.fig.bbox)

    def _set_animated(self, value):
        if self.animated != value:
            self.animated = value
            for artist in self._get_animated_artists():
                artist.set_animated(value)
            if self.animated == True:
                images = []
                for ax in self.fig.axes:
                    images.extend(ax.images)
                for image in images:
                    image.set_visible(False)

                self.canvas.draw()
                self.background = self.canvas.copy_from_bbox(self.fig.bbox)

                for image in images:
                    image.set_visible(True)

    def _get_animated_artists(self):
        artists = []
        for ax in self.fig.axes:
            artists.extend(ax.images)
            artists.extend(ax.lines)
            artists.append(ax.xaxis)
            artists.append(ax.yaxis)
            artists.extend(ax.patches)
            artists.extend(ax.spines.values())
        for artist in artists:
            yield artist

    def update_specgram_settings(self):
        # load specgram settings
        settings = QtCore.QSettings(_organization, _application_name)

        settings.beginGroup("specgram_settings")
        self.specgram_windowlen = int(
            settings.value('window_len',
                           settingsdialog.SPECGRAM_WINDOW_LENGTHS[4]))
        self.specgram_noverlap = int(
            settings.value('noverlap', self.specgram_windowlen / 2))
        self.specgram_window = settings.value('window',
                                              plotting.SPECGRAM_WINDOWS[2])
        settings.endGroup()

        if self.data_loaded:
            # Plot espectrogram
            self.specgram_ax.images = []
            # Save x-axis limits
            limits = self.signal_ax.get_xlim()
            # Draw spectrogram
            plotting.plot_specgram(self.specgram_ax,
                                   self.signal,
                                   self.fs,
                                   nfft=self.specgram_windowlen,
                                   noverlap=self.specgram_noverlap,
                                   window=self.specgram_window)
            # Restore x-axis limits
            self.signal_ax.set_xlim(*limits)

    def paintEvent(self, paintEvent):
        super(SignalViewerWidget, self).paintEvent(paintEvent)

    def on_selector_right_clicked(self):
        xleft, xright = self.get_selector_limits()
        self.takanami_on_selection_action.setEnabled(
            (xright - xleft) >= (takanamidialog.MINIMUM_MARGIN_IN_SECS * 2))
        self.selection_context_menu.exec_(QtGui.QCursor.pos())
예제 #2
0
class Plotter(QMainWindow):
    def __init__(self,groundtruthfile,n_particles,parent=None):
        # init parent class
        QMainWindow.__init__(self,parent)
        # load ground truth
        f = tables.openFile(groundtruthfile)
        self.true_traj = f.root.traj[:]
        self.true_map = f.root.staticMap[:]
        f.close()
        
        self.n_particles = n_particles
        self.create_widgets()
        self.logfiles = []
        self.frame = 0 
        self.data_loaded = False
        self.poses = []
        self.maps = []
        self.particle_poses = []
        self.weights = []

        
    def create_widgets(self):
        self.top_widget = QWidget()        
        
        self.fig = Figure(figsize=(12,6))
        self.canvas = FigureCanvas(self.fig)
        
        gs = GridSpec(2,4)        
        
        # main axes
        self.ax = self.fig.add_subplot(gs[:,0:2])
        self.ax.plot( self.true_traj[:,0], self.true_traj[:,1],'k' )
        self.ax.plot( self.true_map[:,0], self.true_map[:,1],'k*')
        
        # particle scatterplot axes
        self.ax_particles = self.fig.add_subplot(gs[0,2])
        self.ax_particles.set_xmargin(0.1)
        self.ax_particles.set_ymargin(0.1)
        
        # particle weights axes
        self.ax_weights = self.fig.add_subplot(gs[0,3])
            
        # cardinality axes
        self.ax_cn = self.fig.add_subplot(gs[1,2:])
        
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        self.background_particles = self.canvas.copy_from_bbox(self.ax_particles.bbox)
        
        # define animated artists
        init_x = [self.true_traj[0,0]]
        init_y = [self.true_traj[0,1]]
        self.est_pose, = self.ax.plot(init_x, init_y, 'rd', ms=8, mec='r', 
                                      mew=2,mfc='None',animated=True )
        self.est_traj, = self.ax.plot(init_x, init_y, 
                                      'r--',animated=True)   
        self.est_map = []
        self.zlines = []
        for i in xrange(100):
            l, = self.ax.plot([0],[0],color='b',linestyle='None',animated=True)
            self.est_map.append(l)
            l, = self.ax.plot([0],[0],color='g',linestyle='None',animated=True)
            self.zlines.append(l)
        self.particles, = self.ax.plot(init_x*ones(self.n_particles),
                                       init_y*ones(self.n_particles),color='b',
                                       animated=True,marker=',',ls='None')                                     
        self.particles2, = self.ax_particles.plot(init_x*ones(self.n_particles),
                                                  init_y*ones(self.n_particles),
                                                  color='b',animated=True,
                                                  marker='.',ls='None') 
                                                  
        self.load_button = QPushButton('Load Data')
        self.play_button = QPushButton('Play')
        self.play_button.setEnabled(False)
        self.play_button.setCheckable(True)
        self.timer = QTimer()
        self.timer.setInterval(100)
        
        # signals and slots
        self.connect(self.load_button,SIGNAL('clicked()'),self.load_callback)    
        self.connect(self.play_button,SIGNAL('clicked()'),self.play_callback)
        self.connect(self.timer,SIGNAL('timeout()'),self.timer_callback)
        
        hbox = QHBoxLayout()
        hbox.addWidget(self.load_button)
        hbox.addWidget(self.play_button)
        vbox = QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addLayout(hbox)
        self.top_widget.setLayout(vbox)                               
        self.setCentralWidget(self.top_widget)                                       
        
    def update_plot(self):
        if not self.data_loaded:
            return
            
        if self.frame >= self.n_steps:
            return
        
        # append the pose to the estimated trajectory
        pose = self.poses[self.frame,:]
        traj_x = self.poses[0:self.frame,0]
        traj_y = self.poses[0:self.frame,1]
        self.est_traj.set_xdata(traj_x)
        self.est_traj.set_ydata(traj_y)
        self.est_pose.set_xdata(pose[0])
        self.est_pose.set_ydata(pose[1])
        
        # compute feature ellipses
        features = self.maps[self.frame]
        ellipses = [ g.draw(10) for g in features ]
        
        # restore the background
        self.canvas.restore_region(self.background)
        self.canvas.restore_region(self.background_particles)

        # draw the animated elements
        particles = self.particle_poses[self.frame]
        self.ax.draw_artist(self.est_traj)
        self.ax.draw_artist(self.est_pose)
        n_features = len(ellipses)
        for i in xrange(n_features):
            l = self.est_map[i]
            e = ellipses[i]
            l.set_xdata(e[:,0])
            l.set_ydata(e[:,1])
            l.set_linestyle('-')
            self.ax.draw_artist(l)
        self.particles.set_xdata(particles[0,:])
        self.particles.set_ydata(particles[1,:])
        self.ax.draw_artist(self.particles)
        self.canvas.blit(self.ax.bbox)
        
        self.particles2.set_xdata(particles[0,:])
        self.particles2.set_ydata(particles[1,:])
        self.ax_particles.draw_artist(self.particles2)
        self.ax_particles.set_xlim( left = min(particles[0,:]), right = max(particles[0,:]))
        self.ax_particles.set_ylim( bottom = min(particles[1,:]), top = max(particles[1,:]))
        self.canvas.blit(self.ax_particles.bbox)
        self.frame += 1
        
    def keyPressEvent(self,evt):
        QMainWindow.keyPressEvent()
        print 'key pressed: ',evt.key
        if evt.key == Qt.Key_Escape:
            self.close()
            
    def resizeEvent(self,evt):
        self.ax.clear()
        self.ax.plot( self.true_traj[:,0], self.true_traj[:,1],'k' )
        self.ax.plot( self.true_map[:,0], self.true_map[:,1],'k*')
        self.ax_particles.clear()
        self.ax_cn.clear()
        self.ax_weights.clear()
        self.canvas.draw()
        
        self.background = self.canvas.copy_from_bbox(self.ax.bbox)
        self.background_particles = self.canvas.copy_from_bbox(self.ax_particles.bbox)
        
    def load_data(self):
        data_dir = QFileDialog.getExistingDirectory(plot,
                                                    'Select data directory')
        pattern = join( str(data_dir),'state_estimate*.log' )
        self.logfiles = glob.glob( pattern )
        self.logfiles.sort()
        
        self.n_steps = len(self.logfiles)
        self.frame = 0 
        self.poses = empty([self.n_steps,2])
        self.maps = []
        self.weights = []
        self.particle_poses = []
        for k in xrange(self.n_steps):
            print k
            f = open(self.logfiles[k])
            pose = fromstring( f.readline(), sep=' ' )
            map_all = fromstring( f.readline(), sep=' ' )
            particle_weights = fromstring( f.readline(), sep=' ' )
            particles = fromstring( f.readline(), sep=' ' )
            particles = vstack((particles[0::6],particles[1::6]))
            f.close()
            
            n_features = map_all.size/7
            est_map = []
            for i in xrange(n_features):
                ii = i*7
                weight = map_all[ii]
                if weight >= 0.33:
                    mean = array([map_all[ii+1],map_all[ii+2]])
                    
                    # cov matrix stored in col major format
                    cov = array([[map_all[ii+3], map_all[ii+5]],
                                 [map_all[ii+4], map_all[ii+6]]])
                    est_map.append( Gaussian2D(weight,mean,cov) )
            self.poses[k,:] = pose[0:2]
            self.weights.append(particle_weights)
            self.particle_poses.append(particles)
            self.maps.append(est_map) 
        self.data_loaded = True
        self.play_button.setEnabled(True)
        self.frame = 0
    
    def load_callback(self):
        self.load_data()
    
    def play_callback(self):
        if not self.timer.isActive():
            self.timer.start() 
            self.play_button.setChecked(True)
        else:
            self.timer.stop()
            self.play_button.setChecked(False)
        
    def timer_callback(self):
        self.update_plot()
예제 #3
0
class MiniMap(QtGui.QWidget):
    """Shows the entire signal and allows the user to navigate through it.

    Provides an scrollable selector over the entire signal.

    Attributes:
        xmin: Selector lower limit (measured in h-axis units).
        xmax: Selector upper limit (measured in h-axis units).
        step: Selector length (measured in h-axis units).
    """
    def __init__(self, parent, ax, record=None):
        super(MiniMap, self).__init__(parent)
        self.ax = ax

        self.xmin = 0.0
        self.xmax = 0.0
        self.step = 10.0
        self.xrange = np.array([])

        self.minimapFig = plt.figure()
        self.minimapFig.set_figheight(0.75)
        self.minimapFig.add_axes((0, 0, 1, 1))
        self.minimapCanvas = FigureCanvas(self.minimapFig)
        self.minimapCanvas.setFixedHeight(64)
        self.minimapSelector = self.minimapFig.axes[0].axvspan(0,
                                                               self.step,
                                                               color='gray',
                                                               alpha=0.5,
                                                               animated=True)
        self.minimapSelection = self.minimapFig.axes[0].axvspan(
            0, self.step, color='LightCoral', alpha=0.5, animated=True)
        self.minimapSelection.set_visible(False)
        self.minimapBackground = []
        self.minimapSize = (self.minimapFig.bbox.width,
                            self.minimapFig.bbox.height)

        self.press_selector = None
        self.playback_marker = None
        self.minimapCanvas.mpl_connect('button_press_event', self.onpress)
        self.minimapCanvas.mpl_connect('button_release_event', self.onrelease)
        self.minimapCanvas.mpl_connect('motion_notify_event', self.onmove)

        # Animation related attrs.
        self.background = None
        self.animated = False

        # Set the layout
        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.minimapCanvas)

        # Animation related attributes
        self.parentViewer = parent

        # Set Markers dict
        self.markers = {}

        self.record = None
        if record is not None:
            self.set_record(record)

    def set_record(self, record, step):
        self.record = record
        self.step = step
        self.xrange = np.linspace(0,
                                  len(self.record.signal) / self.record.fs,
                                  num=len(self.record.signal),
                                  endpoint=False)
        self.xmin = self.xrange[0]
        self.xmax = self.xrange[-1]
        self.markers = {}

        ax = self.minimapFig.axes[0]
        ax.lines = []
        formatter = FuncFormatter(
            lambda x, pos: str(datetime.timedelta(seconds=x)))
        ax.xaxis.set_major_formatter(formatter)
        ax.grid(True, which='both')
        # Set dataseries to plot
        xmin = self.xmin * self.record.fs
        xmax = self.xmax * self.record.fs
        pixel_width = np.ceil(self.minimapFig.get_figwidth() *
                              self.minimapFig.get_dpi())
        x_data, y_data = plotting.reduce_data(self.xrange, self.record.signal,
                                              pixel_width, xmin, xmax)
        # self._plot_data.set_xdata(x_data)
        # self._plot_data.set_ydata(y_data)
        ax.plot(x_data, y_data, color='black', rasterized=True)
        ax.set_xlim(self.xmin, self.xmax)
        plotting.adjust_axes_height(ax)
        # Set the playback marker
        self.playback_marker = PlayBackMarker(self.minimapFig, self)
        self.playback_marker.markers[0].set_animated(True)
        # Draw canvas
        self.minimapCanvas.draw()
        self.minimapBackground = self.minimapCanvas.copy_from_bbox(
            self.minimapFig.bbox)
        self.draw_animate()

    def onpress(self, event):
        self.press_selector = event
        xdata = round(self.get_xdata(event), 2)
        xmin = round(xdata - (self.step / 2.0), 2)
        xmax = round(xdata + (self.step / 2.0), 2)
        self.parentViewer._set_animated(True)
        self.set_selector_limits(xmin, xmax)

    def onrelease(self, event):
        self.press_selector = None

        # Finish parent animation
        self.parentViewer._set_animated(False)

    def onmove(self, event):
        if self.press_selector is not None:
            xdata = round(self.get_xdata(event), 2)
            xmin = round(xdata - (self.step / 2.0), 2)
            xmax = round(xdata + (self.step / 2.0), 2)
            self.set_selector_limits(xmin, xmax)

    def get_xdata(self, event):
        inv = self.minimapFig.axes[0].transData.inverted()
        xdata, _ = inv.transform((event.x, event.y))
        return xdata

    def set_selector_limits(self, xmin, xmax):
        step = xmax - xmin
        if step >= self.xmax - self.xmin:
            xleft = self.xmin
            xright = self.xmax
        if xmin < self.xmin:
            xleft = self.xmin
            xright = self.step
        elif xmax > self.xmax:
            xleft = self.xmax - step
            xright = self.xmax
        else:
            xleft = xmin
            xright = xmax
        if (xleft, xright) != (self.minimapSelector.xy[1, 0],
                               self.minimapSelector.xy[2, 0]):
            self.step = step
            self.minimapSelector.xy[:2, 0] = xleft
            self.minimapSelector.xy[2:4, 0] = xright
            self.ax.set_xlim(xleft, xright)
            self.draw_animate()
        else:
            self.parentViewer.draw()

    def get_selector_limits(self):
        return self.minimapSelector.xy[0, 0], self.minimapSelector.xy[2, 0]

    def draw(self):
        self.draw_animate()

    def draw_animate(self):
        size = self.minimapFig.bbox.width, self.minimapFig.bbox.height
        if size != self.minimapSize:
            self.minimapSize = size
            self.minimapCanvas.draw()
            self.minimapBackground = self.minimapCanvas.copy_from_bbox(
                self.minimapFig.bbox)
        self.minimapCanvas.restore_region(self.minimapBackground)
        self.minimapFig.draw_artist(self.minimapSelection)
        self.minimapFig.draw_artist(self.minimapSelector)
        self.minimapFig.draw_artist(self.playback_marker.markers[0])
        for marker in self.markers.values():
            self.minimapFig.draw_artist(marker)
        self.minimapCanvas.blit(self.minimapFig.bbox)

    def set_visible(self, value):
        self.minimapCanvas.setVisible(value)

    def get_visible(self):
        return self.minimapCanvas.isVisible()

    def set_selection_limits(self, xleft, xright):
        self.minimapSelection.xy[:2, 0] = xleft
        self.minimapSelection.xy[2:4, 0] = xright
        self.draw_animate()

    def set_selection_visible(self, value):
        self.minimapSelection.set_visible(value)
        self.draw_animate()

    def create_marker(self, key, position, **kwargs):
        if self.xmin <= position <= self.xmax:
            marker = self.minimapFig.axes[0].axvline(position, animated=True)
            self.markers[key] = marker
            self.markers[key].set(**kwargs)

    def set_marker_position(self, key, value):
        marker = self.markers.get(key)
        if marker is not None:
            if self.xmin <= value <= self.xmax:
                marker.set_xdata(value)

    def set_marker(self, key, **kwargs):
        marker = self.markers.get(key)
        if marker is not None:
            kwargs.pop(
                "animated", None
            )  # marker's animated property must be always true to be drawn properly
            marker.set(**kwargs)

    def delete_marker(self, key):
        marker = self.markers.get(key)
        if marker is not None:
            self.minimapFig.axes[0].lines.remove(marker)
            self.markers.pop(key)
예제 #4
0
class Widget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self._ind = None
        self.showVerts = True

        QVBoxLayout(self)

        self.figure = Figure()
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setParent(self)

        codes, verts = zip(*pathdata)
        path = mpath.Path(verts, codes)
        self.patch = mpatches.PathPatch(path,
                                        facecolor='red',
                                        edgecolor='yellow',
                                        alpha=0.5)
        self.axes = self.figure.add_subplot(111)
        self.axes.add_patch(self.patch)
        self.patch.set_animated(True)

        x, y = zip(*path.vertices)
        self.line, = self.axes.plot(x, y, 'go-', animated=True)

        self.axes.grid()
        self.axes.set_xlim(-3, 4)
        self.axes.set_ylim(-3, 4)

        self.axes.set_title('spline paths')

        self.canvas.mpl_connect('draw_event', self.drawCallback)
        self.canvas.mpl_connect('button_press_event', self.buttonPressCallback)
        self.canvas.mpl_connect('button_release_event',
                                self.buttonReleaseCallback)
        self.canvas.mpl_connect('motion_notify_event',
                                self.motionNotifyCallback)

        self.layout().addWidget(self.canvas)

    # Callbacks
    def drawCallback(self, event):
        self.background = self.canvas.copy_from_bbox(self.axes.bbox)
        self.axes.draw_artist(self.patch)
        self.axes.draw_artist(self.line)
        self.canvas.blit(self.axes.bbox)

    def buttonPressCallback(self, event):
        if (not self.showVerts) or (event.inaxes
                                    == None) or (event.button != 1):
            return
        self._ind = self.getIndUnderPoint(event)

    def buttonReleaseCallback(self, event):
        if (not self.showVerts) or (event.button != 1): return
        self._ind = None

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_T:
            self.showVerts = not self.showVerts
            self.line.set_visible(self.showVerts)
            if not self.showVerts: self._ind = None
            self.canvas.draw()
            event.accept()
        else:
            QWidget.keyPressEvent(self, event)

    def motionNotifyCallback(self, event):
        if (not self.showVerts) or (self._ind == None) or (
                event.inaxes == None) or (event.button != 1):
            return

        x, y = event.xdata, event.ydata
        vertices = self.patch.get_path().vertices
        vertices[self._ind] = x, y
        self.line.set_data(zip(*vertices))

        self.canvas.restore_region(self.background)
        self.axes.draw_artist(self.patch)
        self.axes.draw_artist(self.line)
        self.canvas.blit(self.axes.bbox)

    # Other methods
    def getIndUnderPoint(self, event):
        xy = np.asarray(self.patch.get_path().vertices)
        xyt = self.patch.get_transform().transform(xy)
        xt, yt = xyt[:, 0], xyt[:, 1]
        d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
        ind = d.argmin()

        if d[ind] >= epsilon: ind = None
        return ind
예제 #5
0
class live_fig(QGroupBox):
    def __init__(self, name, title, ylabel, ylim=None, scale=1.1, show=False, parent=None):
        super(live_fig, self).__init__(title, parent)
        self.name = name
        self.title = title
        self.scale = scale
        self.clear_data()

        self.layout = QHBoxLayout()
        self.add_fig(title, ylabel, ylim, scale)
        self.setLayout(self.layout)
        if not show:
            self.hide()

        self.timer = QTimer()

    def on_draw(self, event):
        self.bg = self.canvas.copy_from_bbox(self.ax.bbox)

    def add_fig(self, title, ylabel, ylim=None, scale=1.1):
        c = self.parent().palette().button().color()
        self.fig = Figure(facecolor=(c.redF(), c.greenF(), c.blueF()), edgecolor=(0,0,0))
        self.ax = self.fig.add_axes([0.15, 0.1, 0.75, 0.75])
        self.ax.set_ylabel(ylabel)
        if ylim: self.ax.set_ylim(0,ylim)
        self.ax.grid(True)
        self.ax.xaxis.set_ticks([])
        self.ax.set_color_cycle(color_cycle.values())
        self.canvas = FigureCanvas(self.fig)
        self.canvas.mpl_connect('draw_event', self.on_draw)
        self.layout.addWidget(self.canvas, 10)

    def add_node(self, node):
        self.lines[node], = self.ax.plot([0], [0], label=node.title(), animated=True)

    def update_lines(self):
        if not self.bg:
            return
        if self.pause:
            return

        self.canvas.restore_region(self.bg)
        for node in self.data:
            if node not in self.lines:
                continue
            x,y = self.data[node]
            self.ax.set_xlim(x[0], x[-1])
            self.lines[node].set_data(x, y)
            self.ax.draw_artist(self.lines[node])

        self.canvas.blit(self.ax.bbox)

    def update_data(self, node, x, y):
        self.data[node] = (range(len(x)), y)
        self.rescale(max(y))

    def clear_data(self):
        if hasattr(self, "lines"):
            # Remove lines from figure and reset color cycle
            for line in self.lines.values():
                line.remove()
            self.ax.set_color_cycle(color_cycle.values())

        # Clear data
        self.bg = None
        self.pause = False
        self.lines = {}
        self.data = {}

    def rescale(self, new_max):
        if not self.scale:
            return
        if not self.ax._cachedRenderer:
            return
        if self.pause:
            return

        # Read minimum (d) and maximum (max_view) from plot
        d,max_view = self.ax.get_ybound()
        current_max = self.current_max()

        if new_max > max_view or (max_view > 10 and current_max*2 < max_view):
            # Scale axes if new maximum has arrived
            self.ax.relim()
            self.ax.autoscale_view(scalex=False)
            self.ax.draw_artist(self.ax.yaxis)
            self.update_lines()
            self.canvas.draw()

    def current_max(self):
        current_max = 0
        for line in self.lines.values():
            m = max(line.get_ydata())
            current_max = m if m > current_max else current_max
        return current_max

    def set_animated(self, b):
        # Make sure we get animated elements
        for (node,line) in self.lines.items():
            line.set_animated(b)

    def save_fig(self):
        self.toggle_pause(True)
        filename,ext = QFileDialog.getSaveFileName(self,
                "Save plot as file",
                "",
                "Portable Document File (*.pdf);;Portable Network Graphics (*.png)")
        if filename and 'png' in ext:
            print("Saving PNG file to {}".format(filename))
            fmt = 'png'
        elif filename and 'pdf' in ext:
            print("Saving PDF file to {}".format(filename))
            fmt = 'pdf'
        else:
            self.resume()
            return

        self.save_file(filename, fmt)
        self.toggle_pause(False)

    def save_file(self, filename, fmt):
        if not filename:
            return

        self.set_animated(False)
        self.ax.set_title(self.title)
        self.fig.savefig(filename, format=fmt, transparent=True, bbox_inches='tight')
        self.ax.set_title("")
        self.set_animated(True)

    def toggle_hide(self):
        if self.isVisible():
            self.hide()
        else:
            self.show()
            self.timer.singleShot(100, self.canvas.draw)

    def toggle_pause(self, b=None):
        if b == None:
            self.pause = not self.pause
        else:
            self.pause = b
예제 #6
0
파일: graph.py 프로젝트: hundeboll/usb_mesh
class live_fig(QWidget):
    def __init__(self, title, ylabel, ylabel2=None, parent=None):
        super(live_fig, self).__init__(parent)
        self.gs = gridspec.GridSpec(1, 2, width_ratios=[1,5])
        self.clear_data()

        self.layout = QHBoxLayout()
        self.add_fig(title, ylabel, ylabel2)
        self.setLayout(self.layout)

    def on_draw(self, event):
        self.bg = self.canvas.copy_from_bbox(self.ax.bbox)

    def add_fig(self, title, ylabel, ylabel2=None):
        c = self.parent().palette().button().color()

        self.fig = Figure(facecolor=(c.redF(), c.greenF(), c.blueF()), edgecolor=(0,0,0))
        self.ax = self.fig.add_subplot(self.gs[1])
        self.ax.set_ylabel(ylabel)
        self.ax.grid(True)
        self.ax.xaxis.set_ticks([])
        self.ax.set_aspect("auto")

        if ylabel2:
            ax2 = self.ax.twinx()
            ax2.set_ylabel(ylabel2)

        #self.ax.set_color_cycle(color_cycle.values())
        self.canvas = FigureCanvas(self.fig)
        self.canvas.mpl_connect('draw_event', self.on_draw)
        self.layout.addWidget(self.canvas, 10)

    def add_line(self, key):
        ax = self.fig.add_subplot(self.gs[0])
        ax.set_axis_off()
        ax.set_aspect("auto")
        self.lines[key], = self.ax.plot([0], [0], label=key.title(), animated=True)
        l = ax.legend(self.lines.values(), self.lines.keys(), "right")
        for t in l.get_texts():
            t.set_fontsize('medium')
        self.canvas.draw()

    def update_lines(self):
        if not self.bg:
            return

        self.canvas.restore_region(self.bg)
        for key in self.data:
            x,y = self.data[key]
            self.ax.set_xlim(x[0], x[-1])
            self.lines[key].set_data(x, y)
            self.ax.draw_artist(self.lines[key])

        self.canvas.blit(self.ax.bbox)

    def update_data(self, key, x, y):
        self.data[key] = (x, y)
        self.rescale(max(y))

    def clear_data(self):
        if hasattr(self, "lines"):
            # Remove lines from figure and reset color cycle
            for line in self.lines.values():
                line.remove()
            self.ax.set_color_cycle(color_cycle.values())

        # Clear data
        self.bg = None
        self.lines = {}
        self.data = {}

    def rescale(self, new_max):
        if not self.ax._cachedRenderer:
            return

        # Read minimum (d) and maximum (max_view) from plot
        d,max_view = self.ax.get_ybound()
        current_max = self.current_max()

        if new_max > max_view or (max_view > 10 and current_max*2 < max_view):
            # Scale axes if new maximum has arrived
            self.ax.relim()
            self.ax.autoscale_view(scalex=False)
            self.ax.draw_artist(self.ax.yaxis)
            self.update_lines()
            self.canvas.draw()

    def current_max(self):
        current_max = 0
        for line in self.lines.values():
            m = max(line.get_ydata())
            current_max = m if m > current_max else current_max
        return current_max
예제 #7
0
class StreamViewerWidget(QtGui.QWidget):
    """Shows the entire signal and allows the user to navigate through it.

    Provides an scrollable selector over the entire signal.

    Attributes:
        xmin: Selector lower limit (measured in h-axis units).
        xmax: Selector upper limit (measured in h-axis units).
        step: Selector length (measured in h-axis units).
    """

    trace_selected = QtCore.Signal(int)
    selection_made = QtCore.Signal(bool)

    def __init__(self, parent, stream=None):
        super(StreamViewerWidget, self).__init__(parent)

        self.fig = plt.figure()
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding,
                                                    QtGui.QSizePolicy.Policy.Expanding))
        self.canvas.setMinimumHeight(320)
        self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas.setFocus()
        self.graphArea = QtGui.QScrollArea(self)
        self.graphArea.setWidget(self.canvas)
        self.graphArea.setWidgetResizable(True)
        self.graphArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        # Set the layout
        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.graphArea)

        # Animation related attrs.
        self.background = []
        self.animated = False
        self.size = (self.fig.bbox.width, self.fig.bbox.height)

        # Set TracePlot list
        self.trace_plots = []

        self.stream = None
        if stream is not None:
            self.set_stream(stream)

        # Event handling
        self.visible_axes = []
        self._selected_traces = set()
        self.shift_pressed = False
        self.press_selector = None
        self.fig.canvas.mpl_connect('motion_notify_event', self.on_move)
        self.fig.canvas.mpl_connect('button_press_event', self.on_press)
        self.fig.canvas.mpl_connect('key_press_event', self.on_key_press)
        self.fig.canvas.mpl_connect('key_release_event', self.on_key_release)

    @property
    def selected_traces(self):
        if self.stream is not None:
            return [self.stream.traces[i] for i in self._selected_traces]
        return []

    def on_move(self, event):
        axes_selected = False
        for i, axes in enumerate(self.fig.axes):
            if axes.get_visible():
                ymin, ymax = axes.get_position().ymin, axes.get_position().ymax
                xmin, xmax = axes.get_position().xmin, axes.get_position().xmax
                xfig, yfig = self._event_to_fig_coords(event)
                if ymin <= yfig <= ymax and xmin <= xfig <= xmax:
                    self.canvas.setToolTip(self.stream.traces[i].name)
                    axes_selected = True
                    break
        if not axes_selected:
            self.canvas.setToolTip("")

    def on_key_press(self, event):
        if event.key == 'control':
            self.shift_pressed = True

    def on_key_release(self, event):
        self.shift_pressed = False

    def on_press(self, event):
        trace_selected = False
        if event.button == 1:# and event.dblclick:
            for i, ax in enumerate(self.fig.axes):
                if ax.get_visible():
                    ymin, ymax = ax.get_position().ymin, ax.get_position().ymax
                    xmin, xmax = ax.get_position().xmin, ax.get_position().xmax
                    xfig, yfig = self._event_to_fig_coords(event)
                    if ymin <= yfig <= ymax and xmin <= xfig <= xmax:
                        trace_selected = True
                        if self.shift_pressed:
                            if self._selected_traces:
                                self.trace_selected.emit(i)
                                self.selection_made.emit(True)
                            self._selected_traces.add(i)
                        else:
                            self.trace_selected.emit(i)
                            self.selection_made.emit(True)
                            self._selected_traces = {i}
                        break
            # if the user clicked out of any trace (and he's not using shift), then deselect all
            if not trace_selected and not self.shift_pressed:
                self._selected_traces = set()
                self.selection_made.emit(False)
            # Now update selection status on plots
            for i, plot in enumerate(self.trace_plots):
                plot.set_selected(i in self._selected_traces)
            self.draw()

    def _event_to_fig_coords(self, event):
        inv = self.fig.transFigure.inverted()
        return inv.transform((event.x, event.y))

    def set_stream(self, stream):
        self.stream = stream
        self._selected_traces = set()
        # Clear canvas
        for plot in self.trace_plots:
            plot.remove()
        self.trace_plots = []
        # Plot stream traces
        for i, trace in enumerate(self.stream.traces):
            self.trace_plots.append(TracePlot(self, trace, fig_nrows=len(stream), ax_pos=i + 1))
        # Draw canvas
        self.subplots_adjust()
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.fig.bbox)
        self.draw()

    def refresh_stream_data(self):
        for plot in self.trace_plots:
            plot.update_data()

    def draw(self):
        self.canvas.draw()
        #self.draw_animate()

    def draw_animate(self):
        size = self.fig.bbox.width, self.fig.bbox.height
        if size != self.size:
            self.size = size
            self.canvas.draw()
            self.background = self.canvas.copy_from_bbox(self.fig.bbox)
        self.canvas.restore_region(self.background)
        for artist in self._get_animated_artists():
            if artist.get_visible():
                ax = artist.get_axes()
                if ax is not None:
                    if artist.get_axes().get_visible():
                        self.fig.draw_artist(artist)
                else:
                    self.fig.draw_artist(artist)
        self.canvas.blit(self.fig.bbox)

    def _get_animated_artists(self):
        artists = []
        for ax in self.fig.axes:
            artists.extend(ax.images)
            artists.extend(ax.lines)
            artists.append(ax.xaxis)
            artists.append(ax.yaxis)
            artists.extend(ax.patches)
            artists.extend(ax.spines.values())
        for artist in artists:
            if artist.get_animated():
                yield artist

    def set_visible(self, value):
        self.canvas.setVisible(value)

    def get_visible(self):
        return self.canvas.isVisible()

    def remove_trace(self, idx):
        self.trace_plots.pop(idx).remove()

    def subplots_adjust(self):
        visible_subplots = [ax for ax in self.fig.get_axes() if ax.get_visible()]
        for i, ax in enumerate(visible_subplots):
            correct_geometry = (len(visible_subplots), 1, i + 1)
            if correct_geometry != ax.get_geometry():
                ax.change_geometry(len(visible_subplots), 1, i + 1)
        # Adjust space between subplots
        self.fig.subplots_adjust(left=0.02, right=0.98, bottom=0.02,
                                 top=0.98, hspace=0.05)

    def showEvent(self, event):
        self.draw()

    def resizeEvent(self, event):
        self.draw()

    def update_markers(self):
        for plot in self.trace_plots:
            plot.update_markers()
        self.draw()

    def visualize_stream_range(self, start_trace=None, end_trace=None):
        for i, ax in enumerate(self.fig.axes):
            ax.set_visible(start_trace <= i < end_trace)
        self.subplots_adjust()
        self.canvas.draw()
예제 #8
0
class StreamViewerWidget(QtGui.QWidget):
    """Shows the entire signal and allows the user to navigate through it.

    Provides an scrollable selector over the entire signal.

    Attributes:
        xmin: Selector lower limit (measured in h-axis units).
        xmax: Selector upper limit (measured in h-axis units).
        step: Selector length (measured in h-axis units).
    """

    trace_selected = QtCore.Signal(int)
    selection_made = QtCore.Signal(bool)

    def __init__(self, parent, stream=None):
        super(StreamViewerWidget, self).__init__(parent)

        self.fig = plt.figure()
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(
            QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding,
                              QtGui.QSizePolicy.Policy.Expanding))
        self.canvas.setMinimumHeight(320)
        self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
        self.canvas.setFocus()
        self.graphArea = QtGui.QScrollArea(self)
        self.graphArea.setWidget(self.canvas)
        self.graphArea.setWidgetResizable(True)
        self.graphArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
        # Set the layout
        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.graphArea)

        # Animation related attrs.
        self.background = []
        self.animated = False
        self.size = (self.fig.bbox.width, self.fig.bbox.height)

        # Set TracePlot list
        self.trace_plots = []

        self.stream = None
        if stream is not None:
            self.set_stream(stream)

        # Event handling
        self.visible_axes = []
        self._selected_traces = set()
        self.shift_pressed = False
        self.press_selector = None
        self.fig.canvas.mpl_connect('motion_notify_event', self.on_move)
        self.fig.canvas.mpl_connect('button_press_event', self.on_press)
        self.fig.canvas.mpl_connect('key_press_event', self.on_key_press)
        self.fig.canvas.mpl_connect('key_release_event', self.on_key_release)

    @property
    def selected_traces(self):
        if self.stream is not None:
            return [self.stream.traces[i] for i in self._selected_traces]
        return []

    def on_move(self, event):
        axes_selected = False
        for i, axes in enumerate(self.fig.axes):
            if axes.get_visible():
                ymin, ymax = axes.get_position().ymin, axes.get_position().ymax
                xmin, xmax = axes.get_position().xmin, axes.get_position().xmax
                xfig, yfig = self._event_to_fig_coords(event)
                if ymin <= yfig <= ymax and xmin <= xfig <= xmax:
                    self.canvas.setToolTip(self.stream.traces[i].name)
                    axes_selected = True
                    break
        if not axes_selected:
            self.canvas.setToolTip("")

    def on_key_press(self, event):
        if event.key == 'control':
            self.shift_pressed = True

    def on_key_release(self, event):
        self.shift_pressed = False

    def on_press(self, event):
        trace_selected = False
        if event.button == 1:  # and event.dblclick:
            for i, ax in enumerate(self.fig.axes):
                if ax.get_visible():
                    ymin, ymax = ax.get_position().ymin, ax.get_position().ymax
                    xmin, xmax = ax.get_position().xmin, ax.get_position().xmax
                    xfig, yfig = self._event_to_fig_coords(event)
                    if ymin <= yfig <= ymax and xmin <= xfig <= xmax:
                        trace_selected = True
                        if self.shift_pressed:
                            if self._selected_traces:
                                self.trace_selected.emit(i)
                                self.selection_made.emit(True)
                            self._selected_traces.add(i)
                        else:
                            self.trace_selected.emit(i)
                            self.selection_made.emit(True)
                            self._selected_traces = {i}
                        break
            # if the user clicked out of any trace (and he's not using shift), then deselect all
            if not trace_selected and not self.shift_pressed:
                self._selected_traces = set()
                self.selection_made.emit(False)
            # Now update selection status on plots
            for i, plot in enumerate(self.trace_plots):
                plot.set_selected(i in self._selected_traces)
            self.draw()

    def _event_to_fig_coords(self, event):
        inv = self.fig.transFigure.inverted()
        return inv.transform((event.x, event.y))

    def set_stream(self, stream):
        self.stream = stream
        self._selected_traces = set()
        # Clear canvas
        for plot in self.trace_plots:
            plot.remove()
        self.trace_plots = []
        # Plot stream traces
        for i, trace in enumerate(self.stream.traces):
            self.trace_plots.append(
                TracePlot(self, trace, fig_nrows=len(stream), ax_pos=i + 1))
        # Draw canvas
        self.subplots_adjust()
        self.canvas.draw()
        self.background = self.canvas.copy_from_bbox(self.fig.bbox)
        self.draw()

    def refresh_stream_data(self):
        for plot in self.trace_plots:
            plot.update_data()

    def draw(self):
        self.canvas.draw()
        #self.draw_animate()

    def draw_animate(self):
        size = self.fig.bbox.width, self.fig.bbox.height
        if size != self.size:
            self.size = size
            self.canvas.draw()
            self.background = self.canvas.copy_from_bbox(self.fig.bbox)
        self.canvas.restore_region(self.background)
        for artist in self._get_animated_artists():
            if artist.get_visible():
                ax = artist.get_axes()
                if ax is not None:
                    if artist.get_axes().get_visible():
                        self.fig.draw_artist(artist)
                else:
                    self.fig.draw_artist(artist)
        self.canvas.blit(self.fig.bbox)

    def _get_animated_artists(self):
        artists = []
        for ax in self.fig.axes:
            artists.extend(ax.images)
            artists.extend(ax.lines)
            artists.append(ax.xaxis)
            artists.append(ax.yaxis)
            artists.extend(ax.patches)
            artists.extend(ax.spines.values())
        for artist in artists:
            if artist.get_animated():
                yield artist

    def set_visible(self, value):
        self.canvas.setVisible(value)

    def get_visible(self):
        return self.canvas.isVisible()

    def remove_trace(self, idx):
        self.trace_plots.pop(idx).remove()

    def subplots_adjust(self):
        visible_subplots = [
            ax for ax in self.fig.get_axes() if ax.get_visible()
        ]
        for i, ax in enumerate(visible_subplots):
            correct_geometry = (len(visible_subplots), 1, i + 1)
            if correct_geometry != ax.get_geometry():
                ax.change_geometry(len(visible_subplots), 1, i + 1)
        # Adjust space between subplots
        self.fig.subplots_adjust(left=0.02,
                                 right=0.98,
                                 bottom=0.02,
                                 top=0.98,
                                 hspace=0.05)

    def showEvent(self, event):
        self.draw()

    def resizeEvent(self, event):
        self.draw()

    def update_markers(self):
        for plot in self.trace_plots:
            plot.update_markers()
        self.draw()

    def visualize_stream_range(self, start_trace=None, end_trace=None):
        for i, ax in enumerate(self.fig.axes):
            ax.set_visible(start_trace <= i < end_trace)
        self.subplots_adjust()
        self.canvas.draw()
예제 #9
0
class Widget(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)

        self._ind=None
        self.showVerts=True

        QVBoxLayout(self)

        self.figure=Figure()
        self.canvas=FigureCanvas(self.figure)
        self.canvas.setParent(self)

        codes, verts = zip(*pathdata)
        path = mpath.Path(verts, codes)
        self.patch = mpatches.PathPatch(path, facecolor='red', edgecolor='yellow', alpha=0.5)
        self.axes=self.figure.add_subplot(111)
        self.axes.add_patch(self.patch)
        self.patch.set_animated(True)

        x,y=zip(*path.vertices)
        self.line,=self.axes.plot(x, y, 'go-', animated=True)

        self.axes.grid()
        self.axes.set_xlim(-3,4)
        self.axes.set_ylim(-3,4)

        self.axes.set_title('spline paths')

        self.canvas.mpl_connect('draw_event', self.drawCallback)
        self.canvas.mpl_connect('button_press_event', self.buttonPressCallback)
        self.canvas.mpl_connect('button_release_event', self.buttonReleaseCallback)
        self.canvas.mpl_connect('motion_notify_event', self.motionNotifyCallback)

        self.layout().addWidget(self.canvas)

    # Callbacks
    def drawCallback(self, event):
        self.background = self.canvas.copy_from_bbox(self.axes.bbox)
        self.axes.draw_artist(self.patch)
        self.axes.draw_artist(self.line)
        self.canvas.blit(self.axes.bbox)

    def buttonPressCallback(self, event):
         if (not self.showVerts) or (event.inaxes==None) or (event.button!=1): return
         self._ind=self.getIndUnderPoint(event)

    def buttonReleaseCallback(self, event):
        if (not self.showVerts) or (event.button!=1): return
        self._ind=None

    def keyPressEvent(self, event):
        if event.key()==Qt.Key_T:
            self.showVerts=not self.showVerts
            self.line.set_visible(self.showVerts)
            if not self.showVerts: self._ind=None
            self.canvas.draw()
            event.accept()
        else: QWidget.keyPressEvent(self, event)     

    def motionNotifyCallback(self, event):
        if (not self.showVerts) or (self._ind==None) or (event.inaxes==None) or (event.button!=1): return

        x,y=event.xdata,event.ydata
        vertices=self.patch.get_path().vertices
        vertices[self._ind]=x,y
        self.line.set_data(zip(*vertices))

        self.canvas.restore_region(self.background)
        self.axes.draw_artist(self.patch)
        self.axes.draw_artist(self.line)
        self.canvas.blit(self.axes.bbox)

    # Other methods
    def getIndUnderPoint(self, event):
        xy=np.asarray(self.patch.get_path().vertices)
        xyt=self.patch.get_transform().transform(xy)
        xt,yt=xyt[:,0],xyt[:,1]
        d=np.sqrt((xt-event.x)**2 + (yt-event.y)**2)
        ind=d.argmin()

        if d[ind]>=epsilon: ind=None
        return ind
예제 #10
0
class SignalViewerWidget(QtGui.QWidget):
    """Shows different visualizations of a seismic signal (magnitude, envelope,
    spectrogram, characteristic function).
    Allows the user to manipulate it (navigate through it, zoom in/out,
    edit detected events, select threshold value, etc...)

    """

    CF_loaded = QtCore.Signal(bool)
    event_selected = QtCore.Signal(rc.ApasvoEvent)

    def __init__(self, parent, document=None):
        super(SignalViewerWidget, self).__init__(parent)

        self.document = document
        self.xmin = 0.0
        self.xmax = 0.0
        self.xleft = 0.0
        self.xright = 0.0
        self.time = np.array([])

        self.fs = 0.0
        self.signal = None
        self.envelope = None
        self.cf = None
        self.time = None
        self._signal_data = None
        self._envelope_data = None
        self._cf_data = None

        self.fig, _ = plt.subplots(3, 1)

        self.signal_ax = self.fig.axes[0]
        self.cf_ax = self.fig.axes[1]
        self.specgram_ax = self.fig.axes[2]

        self.canvas = FigureCanvas(self.fig)
        self.canvas.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Policy.Expanding,
                                                    QtGui.QSizePolicy.Policy.Expanding))
        self.canvas.setMinimumHeight(320)
        self.graphArea = QtGui.QScrollArea(self)
        self.graphArea.setWidget(self.canvas)
        self.graphArea.setWidgetResizable(True)

        self.eventMarkers = {}
        self.last_right_clicked_event = None
        self.thresholdMarker = None
        self.playback_marker = None
        self.selector = SpanSelector(self.fig)
        self.minimap = MiniMap(self, self.signal_ax, None)

        # Load Spectrogram settings
        self.update_specgram_settings()

        # Animation related attributes
        self.background = None
        self.animated = False

        # Create context menus
        self.event_context_menu = QtGui.QMenu(self)
        self.takanami_on_event_action = QtGui.QAction("Apply Takanami to Event", self)
        self.takanami_on_event_action.setStatusTip("Refine event position by using Takanami algorithm")
        self.event_context_menu.addAction(self.takanami_on_event_action)
        self.takanami_on_event_action.triggered.connect(self.apply_takanami_to_selected_event)

        self.selection_context_menu = QtGui.QMenu(self)
        self.create_event_action = QtGui.QAction("Create New Event on Selection", self)
        self.create_event_action.setStatusTip("Create a new event on selection")
        self.takanami_on_selection_action = QtGui.QAction("Apply Takanami to Selection", self)
        self.takanami_on_selection_action.setStatusTip("Apply Takanami algorithm to selection")
        self.selection_context_menu.addAction(self.create_event_action)
        self.selection_context_menu.addAction(self.takanami_on_selection_action)
        self.create_event_action.triggered.connect(self.create_event_on_selection)
        self.takanami_on_selection_action.triggered.connect(self.apply_takanami_to_selection)

        # format axes
        formatter = FuncFormatter(lambda x, pos: clt.float_secs_2_string_date(x, self.document.record.starttime))
        for ax in self.fig.axes:
            ax.callbacks.connect('xlim_changed', self.on_xlim_change)
            ax.xaxis.set_major_formatter(formatter)
            plt.setp(ax.get_xticklabels(), visible=True)
            ax.grid(True, which='both')
        self.specgram_ax.callbacks.connect('ylim_changed', self.on_ylim_change)
        self.specgram_ax.set_xlabel('Time (seconds)')
        plt.setp(self.signal_ax.get_yticklabels(), visible=False)
        #self.signal_ax.set_ylabel('Signal Amp.')
        self.cf_ax.set_ylabel('CF Amp.')
        self.specgram_ax.set_ylabel('Frequency (Hz)')

        # Set the layout
        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.graphArea)
        self.layout.addWidget(self.minimap)

        self.selector.toggled.connect(self.minimap.set_selection_visible)
        self.selector.valueChanged.connect(self.minimap.set_selection_limits)
        self.selector.right_clicked.connect(self.on_selector_right_clicked)

        if self.document is not None:
            self.set_record(document)

    @property
    def data_loaded(self):
        return self.document is not None

    def set_record(self, document, step=120.0):
        self.document = document
        self.fs = self.document.record.fs
        self.signal = self.document.record.signal
        self.envelope = env.envelope(self.signal)
        self.cf = self.document.record.cf
        self.time = np.linspace(0, len(self.signal) / self.fs, num=len(self.signal), endpoint=False)
        self.xmax = self.time[-1]
        # Draw minimap
        self.minimap.minimapSelector.set(visible=False)  # Hide minimap selector while loading
        self.minimap.set_record(self.document.record, step)
        # Plot signal
        step_samples = step * self.fs
        self._signal_data = self.signal_ax.plot(self.time[:step_samples],
                                                  self.signal[:step_samples],
                                                  color='black',
                                                  rasterized=True)[0]
        # Plot envelope
        self._envelope_data = self.signal_ax.plot(self.time[:step_samples],
                                                    self.envelope[:step_samples],
                                                    color='red',
                                                    rasterized=True)[0]
        # Adjust y axis for signal plot
        signal_yaxis_max_value = max(np.max(self.signal), np.max(self.envelope))
        signal_yaxis_min_value = np.min(self.signal)
        plotting.adjust_axes_height(self.signal_ax,
                                    max_value=signal_yaxis_max_value,
                                    min_value=signal_yaxis_min_value)
        # Plot CF
        cf_loaded = (self.cf.size != 0)
        self.set_cf_visible(cf_loaded)
        self.CF_loaded.emit(cf_loaded)
        cf_step_samples = min(step_samples,len(self.cf))
        self._cf_data = self.cf_ax.plot(self.time[:cf_step_samples],
                                        self.cf[:cf_step_samples],
                                        color='black',
                                        rasterized=True)[0]
        # Adjust y axis for CF plot
        if cf_loaded:
            plotting.adjust_axes_height(self.cf_ax,
                                        max_value=np.max(self.cf),
                                        min_value=np.min(self.cf))
        self.thresholdMarker = ThresholdMarker(self.cf_ax)
        # Plot espectrogram
        plotting.plot_specgram(self.specgram_ax, self.signal, self.fs,
                               nfft=self.specgram_windowlen,
                               noverlap=self.specgram_noverlap,
                               window=self.specgram_window)
        # Set the span selector
        self.selector.fs = self.fs
        self.selector.set_active(False)
        self.selector.set_selection_limits(self.xmin, self.xmax)
        # Set the playback marker
        self.playback_marker = PlayBackMarker(self.fig, self)
        # Set the initial xlimits
        self.set_xlim(0, step)
        self.subplots_adjust()
        # Set event markers
        self.eventMarkers = {}
        for event in self.document.record.events:
            self.create_event(event)
        # Now activate selector again on minimap
        self.minimap.minimapSelector.set(visible=True)
        self.minimap.draw()

    def unset_record(self):
        self.document = None
        self.signal = None
        self.envelope = None
        self.cf = None
        self.time = None
        self._signal_data = None
        self._envelope_data = None
        self._cf_data = None
        self.xmin, self.xmax = 0.0, 0.0
        self.eventMarkers = {}
        # Clear axes
        self.signal_ax.lines = []
        self.cf_ax.lines = []
        self.specgram_ax.lines = []
        self.specgram_ax.images = []

        self.CF_loaded.emit(False)

    def update_cf(self):
        if self.data_loaded:
            self.cf = self.document.record.cf
            self._cf_data.set_xdata(self.time[:len(self.cf)])
            self._cf_data.set_ydata(self.cf)
            plotting.adjust_axes_height(self.cf_ax)
            cf_loaded = (self.cf.size != 0)
            self.CF_loaded.emit(cf_loaded)
            self.set_cf_visible(cf_loaded)
            self.draw()

    def create_events(self, new_events_set):
        for event in new_events_set.get(self.document.record.uuid, []):
            self.create_event(event)

    def create_event(self, event):
        event_id = event.resource_id.uuid
        if event_id not in self.eventMarkers:
            marker = EventMarker(self.fig, self.minimap, self.document, event)
            self.eventMarkers[event_id] = marker
            marker.event_selected.connect(self.event_selected.emit)
            marker.right_clicked.connect(self.on_event_right_clicked)

    def delete_events(self, new_events_set):
        for event in new_events_set.get(self.document.record.uuid, []):
            self.delete_event(event)

    def delete_event(self, event):
        event_id = event.resource_id.uuid
        self.eventMarkers[event_id].remove()
        self.eventMarkers.pop(event_id)

    def update_event(self, event):
        self.eventMarkers[event.resource_id.uuid].update()

    def set_xlim(self, l, r):
        xmin = max(0, l)
        xmax = min(self.xmax, r)
        self.signal_ax.set_xlim(xmin, xmax)

    def on_xlim_change(self, ax):
        xmin, xmax = ax.get_xlim()
        if (self.xleft, self.xright) != (xmin, xmax):
            self.xleft, self.xright = xmin, xmax
            if self.xmin <= xmin <= xmax <= self.xmax:
                # Update minimap selector
                if (xmin, xmax) != self.minimap.get_selector_limits():
                    self.minimap.set_selector_limits(xmin, xmax)

                # Update axes
                for axes in self.fig.axes:
                    if ax != axes:
                        axes.set_xlim(xmin, xmax)

                # Update data
                xmin = int(max(0, xmin) * self.fs)
                xmax = int(min(self.xmax, xmax) * self.fs)

                pixel_width = np.ceil(self.fig.get_figwidth() * self.fig.get_dpi())

                if self._signal_data is not None:
                    x_data, y_data = plotting.reduce_data(self.time, self.signal,
                                                          pixel_width, xmin, xmax)
                    self._signal_data.set_xdata(x_data)
                    self._signal_data.set_ydata(y_data)

                if self._envelope_data is not None:
                    x_data, y_data = plotting.reduce_data(self.time, self.envelope,
                                                          pixel_width, xmin, xmax)
                    self._envelope_data.set_xdata(x_data)
                    self._envelope_data.set_ydata(y_data)

                if self._cf_data is not None and self.cf_ax.get_visible():
                    x_data, y_data = plotting.reduce_data(self.time[:len(self.cf)],
                                                          self.cf, pixel_width,
                                                          xmin, xmax)
                    self._cf_data.set_xdata(x_data)
                    self._cf_data.set_ydata(y_data)
                # Draw graph
                self.draw()

            else:
                xmin = max(self.xmin, xmin)
                xmax = min(self.xmax, xmax)
                ax.set_xlim(xmin, xmax)

    def on_ylim_change(self, ax):
        if self.data_loaded:
            if ax == self.specgram_ax:
                ymin, ymax = ax.get_ylim()
                nyquist_freq = (self.fs / 2.0)
                if ymin < 0.0:
                    ax.set_ylim(0.0, ymax)
                elif ymax > nyquist_freq:
                    ax.set_ylim(ymin, nyquist_freq)

    def set_event_selection(self, events):
        event_id_list = [event.resource_id.uuid for event in events]
        for event_id in self.eventMarkers:
            self.eventMarkers[event_id].set_selected(event_id in event_id_list)
        self.draw()
        self.minimap.draw()

    def set_position(self, pos):
        """"""
        xmin, xmax = self.signal_ax.get_xlim()
        mrange = xmax - xmin
        l, r = pos - mrange / 2.0, pos + mrange / 2.0
        if l < self.xmin:
            l, r = self.xmin, mrange
        elif r > self.xmax:
            l, r = self.xmax - mrange, self.xmax
        self.set_xlim(l, r)

    def goto_event(self, event):
        if event.resource_id.uuid in self.eventMarkers:
            self.set_position(event.stime / self.fs)

    def showEvent(self, event):
        self.draw()
        self.minimap.draw_animate()

    def resizeEvent(self, event):
        self.draw()
        self.minimap.draw_animate()

    def set_signal_amplitude_visible(self, show_sa):
        if self._signal_data is not None and self._envelope_data is not None:
            if self._signal_data.get_visible() != show_sa:
                self._signal_data.set_visible(show_sa)
                show_axis = (self._signal_data.get_visible() +
                             self._envelope_data.get_visible())
                self.signal_ax.set_visible(show_axis)
                if self.data_loaded:
                    self.subplots_adjust()
                    self.draw()

    def set_signal_envelope_visible(self, show_se):
        if self._signal_data is not None and self._envelope_data is not None:
            if self._envelope_data.get_visible() != show_se:
                self._envelope_data.set_visible(show_se)
                show_axis = (self._signal_data.get_visible() +
                             self._envelope_data.get_visible())
                self.signal_ax.set_visible(show_axis)
                if self.data_loaded:
                    self.subplots_adjust()
                    self.draw()

    def set_cf_visible(self, show_cf):
        if self.cf_ax.get_visible() != show_cf:
            if self.data_loaded:
                if len(self.cf) <= 0:
                    self.cf_ax.set_visible(False)
                else:
                    self.cf_ax.set_visible(show_cf)
                    self.subplots_adjust()
                    self.draw()

    def set_espectrogram_visible(self, show_eg):
        if self.specgram_ax.get_visible() != show_eg:
            self.specgram_ax.set_visible(show_eg)
            if self.data_loaded:
                self.subplots_adjust()
                self.draw()

    def set_minimap_visible(self, show_mm):
        if self.minimap.get_visible() != show_mm:
            self.minimap.set_visible(show_mm)
            self.minimap.draw_animate()

    def set_threshold_visible(self, show_thr):
        if self.thresholdMarker:
            if self.thresholdMarker.get_visible() != show_thr:
                self.thresholdMarker.set_visible(show_thr)
                self.draw()

    def subplots_adjust(self):
        visible_subplots = [ax for ax in self.fig.get_axes() if ax.get_visible()]
        for i, ax in enumerate(visible_subplots):
            correct_geometry = (len(visible_subplots), 1, i + 1)
            if correct_geometry != ax.get_geometry():
                ax.change_geometry(len(visible_subplots), 1, i + 1)
        # Adjust space between subplots
        self.fig.subplots_adjust(left=0.06, right=0.95, bottom=0.14,
                                 top=0.95, hspace=0.22)

    def get_selector_limits(self):
        return self.selector.get_selector_limits()

    def set_selector_limits(self, xleft, xright):
        self.selector.set_selector_limits(xleft, xright)

    def set_selection_enabled(self, value):
        self.selector.set_enabled(value)

    def set_playback_position(self, position):
        if self.playback_marker is not None:
            self.playback_marker.set_position(position)
            self.minimap.playback_marker.set_position(position)

    def set_playback_marker_visible(self, show_marker):
        if self.playback_marker is not None:
            self.playback_marker.set_visible(show_marker)
            self.minimap.playback_marker.set_visible(show_marker)

    def on_event_right_clicked(self, event):
        self.last_right_clicked_event = event
        self.event_context_menu.exec_(QtGui.QCursor.pos())

    def apply_takanami_to_selected_event(self):
        takanamidialog.TakanamiDialog(self.document,
                                      seismic_event=self.last_right_clicked_event).exec_()

    def apply_takanami_to_selection(self):
        xleft, xright = self.get_selector_limits()
        takanamidialog.TakanamiDialog(self.document, xleft, xright).exec_()

    def create_event_on_selection(self):
        xleft, xright = self.get_selector_limits()
        xleft, xright = xleft * self.fs, xright * self.fs
        cf = self.cf[xleft:xright]
        if cf.size > 0:
            time = (xleft + np.argmax(cf))
        else:
            time = (xleft + ((xright - xleft) / 2.0))
        self.document.createEvent(time=time)

    def draw(self):
        if self.animated:
            self._draw_animate()
        else:
            self.canvas.draw_idle()

    def _draw_animate(self):
        self.canvas.restore_region(self.background)
        for artist in self._get_animated_artists():
            if artist.get_visible():
                ax = artist.get_axes()
                if ax is not None:
                    if artist.get_axes().get_visible():
                        self.fig.draw_artist(artist)
                else:
                    self.fig.draw_artist(artist)
        self.canvas.blit(self.fig.bbox)

    def _set_animated(self, value):
        if self.animated != value:
            self.animated = value
            for artist in self._get_animated_artists():
                artist.set_animated(value)
            if self.animated == True:
                images = []
                for ax in self.fig.axes:
                    images.extend(ax.images)
                for image in images:
                    image.set_visible(False)

                self.canvas.draw()
                self.background = self.canvas.copy_from_bbox(self.fig.bbox)

                for image in images:
                    image.set_visible(True)

    def _get_animated_artists(self):
        artists = []
        for ax in self.fig.axes:
            artists.extend(ax.images)
            artists.extend(ax.lines)
            artists.append(ax.xaxis)
            artists.append(ax.yaxis)
            artists.extend(ax.patches)
            artists.extend(ax.spines.values())
        for artist in artists:
            yield artist

    def update_specgram_settings(self):
        # load specgram settings
        settings = QtCore.QSettings(_organization, _application_name)

        settings.beginGroup("specgram_settings")
        self.specgram_windowlen = int(settings.value('window_len', settingsdialog.SPECGRAM_WINDOW_LENGTHS[4]))
        self.specgram_noverlap = int(settings.value('noverlap', self.specgram_windowlen / 2))
        self.specgram_window = settings.value('window', plotting.SPECGRAM_WINDOWS[2])
        settings.endGroup()

        if self.data_loaded:
            # Plot espectrogram
            self.specgram_ax.images = []
            # Save x-axis limits
            limits = self.signal_ax.get_xlim()
            # Draw spectrogram
            plotting.plot_specgram(self.specgram_ax, self.signal, self.fs,
                                   nfft=self.specgram_windowlen,
                                   noverlap=self.specgram_noverlap,
                                   window=self.specgram_window)
            # Restore x-axis limits
            self.signal_ax.set_xlim(*limits)

    def paintEvent(self, paintEvent):
        super(SignalViewerWidget, self).paintEvent(paintEvent)

    def on_selector_right_clicked(self):
        xleft, xright = self.get_selector_limits()
        self.takanami_on_selection_action.setEnabled((xright - xleft) >=
                                                     (takanamidialog.MINIMUM_MARGIN_IN_SECS * 2))
        self.selection_context_menu.exec_(QtGui.QCursor.pos())
예제 #11
0
class AnalysisEditor(QWidget):
    def __init__(self, ui):
        QWidget.__init__(self)
        self.ui = ui
        self.chooseAnalysis = QPushButton()
        self.chooseAnalysis.setText("Choose Analysis")
        self.chooseAnalysis.setFixedWidth(100)
        self.lineEdit = QLineEdit()
        self.chooseAnalysis.clicked.connect(self.selectAnalysis)
        self.analysisFig = plt.figure()
        self.analysisFig.patch.set_facecolor('white')
        self.analysisFig.clf()
        self.analysisCanvas = FigureCanvas(self.analysisFig)
        self.toolbar = NavigationToolbar(self.analysisCanvas, self)
        self.analysisOperationsLayout = self.createOperationsLayout()     
        self.analysisAx = self.analysisFig.add_subplot(1,1,1)
        #self.gridLayout.addLayout(analysisOperationsLayout,1,7)
    
    def initCanvas(self):
        self.lineEdit.clear()
        self.analysisAx.cla()
        self.analysisAx = self.analysisFig.add_subplot(1,1,1)  
        self.analysisCanvas.draw()    
        
    def analysisOptionHandler(self):
        sender = self.sender()
        if sender.isChecked():
            vec = sender.getVec()
            sender.line = self.plotAnalysis(vec)
            #sender.line, = self.analysisAx.plot(sender.getVec())
        else:
            sender.line.remove()
        self.analysisCanvas.draw()
    
    def prepareCheckBox(self, getVec, label):
        operationCheck = QCheckBox()
        operationCheck.setText(label)
        operationCheck.setFixedWidth(100)
        operationCheck.getVec = getVec
        operationCheck.clicked.connect(self.analysisOptionHandler) 
        return operationCheck
    
    def Original(self):
        self.analysisVec = self.original.vec
        return self.analysisVec 
    
    def Derivative(self):
        self.analysisVec = np.diff(self.analysisVec)
        return self.analysisVec
    
    def LPF(self):
        self.analysisVec =  ma.movingAverage(self.analysisVec, 30, 1.1)
        return self.analysisVec
    
    def cluster(self):
        pass
    
    def createOperationsLayout(self):
        analysisOptionsLayout = QVBoxLayout()
        self.original = self.prepareCheckBox(self.Original, 'Original') 
        analysisOptionsLayout.addWidget(self.original)
        analysisOptionsLayout.addWidget(self.prepareCheckBox(self.LPF, 'LPF'))
        analysisOptionsLayout.addWidget(self.prepareCheckBox(self.Derivative, 'Derivative'))
        analysisOptionsLayout.addWidget(self.prepareCheckBox(self.cluster, 'cluster'))
        return analysisOptionsLayout
        
    def selectAnalysis(self):
        dlg = QFileDialog()
        dlg.setDirectory('Laban/analysis')
        analysisFile= unicode(dlg.getOpenFileName(filter='*.py'))
        self.lineEdit.setText(analysisFile)
        if not os.path.isfile(analysisFile):
            return
        rel = os.path.relpath(analysisFile).split('.')[-2]
        rel = rel.replace('\\','.')#[1:]
        analayzer = importlib.import_module(rel)
        self.analysisVec = analayzer.analyze(self.ui.selectedFile)
        self.original.line = self.plotAnalysis(self.analysisVec)
        self.original.vec = self.analysisVec
        self.original.setChecked(True)
    
    def plotAnalysis(self, vec):
        max_height = np.max(vec)
        min_height = np.min(vec)
        ax = self.analysisAx
        ax.set_ylim(min_height, max_height)
        line, = ax.plot(vec)
        self.analysisCanvas.draw()
        return line
    
    def clearTimeMarker(self):
        self.syncSkeletonWithAnalysis = False
        self.analysisTimeLine.remove()
        self.analysisCanvas.draw()

    def initTimeMarker(self):
        ax = self.analysisAx
        self.analysisBackground = self.analysisCanvas.copy_from_bbox(ax.bbox)
        vec = self.analysisVec
        max_height = np.max(vec)
        min_height = np.min(vec)
        y1 = [min_height, max_height]
        x1 = [0, 0]
        self.analysisTimeLine, = ax.plot(x1,y1,color='r',animated=True,label='timeMarker') 
        self.updateAnalysisTimeMarker()
        
    def updateAnalysisTimeMarker(self):
        self.analysisCanvas.restore_region(self.analysisBackground)
        currTime = self.ui.mainWindow.currTime
        x1 = [currTime,currTime]
        self.analysisTimeLine.set_xdata(x1)
        self.analysisAx.draw_artist(self.analysisTimeLine)
        self.analysisCanvas.blit(self.analysisAx.bbox)
        
    def prepareAnalysisEditorBeforeSync(self, handler):
        self.analysisCanvas.mpl_connect('button_press_event',handler)
        #self.analysisCanvas.draw()
        #self.updateAnalysisTimeMarker()
예제 #12
0
class MiniMap(QtGui.QWidget):
    """Shows the entire signal and allows the user to navigate through it.

    Provides an scrollable selector over the entire signal.

    Attributes:
        xmin: Selector lower limit (measured in h-axis units).
        xmax: Selector upper limit (measured in h-axis units).
        step: Selector length (measured in h-axis units).
    """

    def __init__(self, parent, ax, record=None):
        super(MiniMap, self).__init__(parent)
        self.ax = ax

        self.xmin = 0.0
        self.xmax = 0.0
        self.step = 10.0
        self.xrange = np.array([])

        self.minimapFig = plt.figure()
        self.minimapFig.set_figheight(0.75)
        self.minimapFig.add_axes((0, 0, 1, 1))
        self.minimapCanvas = FigureCanvas(self.minimapFig)
        self.minimapCanvas.setFixedHeight(64)
        self.minimapSelector = self.minimapFig.axes[0].axvspan(0, self.step,
                                                               color='gray',
                                                               alpha=0.5,
                                                               animated=True)
        self.minimapSelection = self.minimapFig.axes[0].axvspan(0, self.step,
                                                                color='LightCoral',
                                                                alpha = 0.5,
                                                                animated=True)
        self.minimapSelection.set_visible(False)
        self.minimapBackground = []
        self.minimapSize = (self.minimapFig.bbox.width,
                            self.minimapFig.bbox.height)

        self.press_selector = None
        self.playback_marker = None
        self.minimapCanvas.mpl_connect('button_press_event', self.onpress)
        self.minimapCanvas.mpl_connect('button_release_event', self.onrelease)
        self.minimapCanvas.mpl_connect('motion_notify_event', self.onmove)

        # Animation related attrs.
        self.background = None
        self.animated = False

        # Set the layout
        self.layout = QtGui.QVBoxLayout(self)
        self.layout.addWidget(self.minimapCanvas)

        # Animation related attributes
        self.parentViewer = parent

        # Set Markers dict
        self.markers = {}

        self.record = None
        if record is not None:
            self.set_record(record)

    def set_record(self, record, step):
        self.record = record
        self.step = step
        self.xrange = np.linspace(0, len(self.record.signal) / self.record.fs,
                                  num=len(self.record.signal), endpoint=False)
        self.xmin = self.xrange[0]
        self.xmax = self.xrange[-1]
        self.markers = {}

        ax = self.minimapFig.axes[0]
        ax.lines = []
        formatter = FuncFormatter(lambda x, pos: str(datetime.timedelta(seconds=x)))
        ax.xaxis.set_major_formatter(formatter)
        ax.grid(True, which='both')
        # Set dataseries to plot
        xmin = self.xmin * self.record.fs
        xmax = self.xmax * self.record.fs
        pixel_width = np.ceil(self.minimapFig.get_figwidth() * self.minimapFig.get_dpi())
        x_data, y_data = plotting.reduce_data(self.xrange, self.record.signal, pixel_width, xmin, xmax)
        # self._plot_data.set_xdata(x_data)
        # self._plot_data.set_ydata(y_data)
        ax.plot(x_data, y_data, color='black', rasterized=True)
        ax.set_xlim(self.xmin, self.xmax)
        plotting.adjust_axes_height(ax)
        # Set the playback marker
        self.playback_marker = PlayBackMarker(self.minimapFig, self)
        self.playback_marker.markers[0].set_animated(True)
        # Draw canvas
        self.minimapCanvas.draw()
        self.minimapBackground = self.minimapCanvas.copy_from_bbox(self.minimapFig.bbox)
        self.draw_animate()

    def onpress(self, event):
        self.press_selector = event
        xdata = round(self.get_xdata(event), 2)
        xmin = round(xdata - (self.step / 2.0), 2)
        xmax = round(xdata + (self.step / 2.0), 2)
        self.parentViewer._set_animated(True)
        self.set_selector_limits(xmin, xmax)

    def onrelease(self, event):
        self.press_selector = None

        # Finish parent animation
        self.parentViewer._set_animated(False)

    def onmove(self, event):
        if self.press_selector is not None:
            xdata = round(self.get_xdata(event), 2)
            xmin = round(xdata - (self.step / 2.0), 2)
            xmax = round(xdata + (self.step / 2.0), 2)
            self.set_selector_limits(xmin, xmax)

    def get_xdata(self, event):
        inv = self.minimapFig.axes[0].transData.inverted()
        xdata, _ = inv.transform((event.x, event.y))
        return xdata

    def set_selector_limits(self, xmin, xmax):
        step = xmax - xmin
        if step >= self.xmax - self.xmin:
            xleft = self.xmin
            xright = self.xmax
        if xmin < self.xmin:
            xleft = self.xmin
            xright = self.step
        elif xmax > self.xmax:
            xleft = self.xmax - step
            xright = self.xmax
        else:
            xleft = xmin
            xright = xmax
        if (xleft, xright) != (self.minimapSelector.xy[1, 0], self.minimapSelector.xy[2, 0]):
            self.step = step
            self.minimapSelector.xy[:2, 0] = xleft
            self.minimapSelector.xy[2:4, 0] = xright
            self.ax.set_xlim(xleft, xright)
            self.draw_animate()
        else:
            self.parentViewer.draw()

    def get_selector_limits(self):
        return self.minimapSelector.xy[0, 0], self.minimapSelector.xy[2, 0]

    def draw(self):
        self.draw_animate()

    def draw_animate(self):
        size = self.minimapFig.bbox.width, self.minimapFig.bbox.height
        if size != self.minimapSize:
            self.minimapSize = size
            self.minimapCanvas.draw()
            self.minimapBackground = self.minimapCanvas.copy_from_bbox(self.minimapFig.bbox)
        self.minimapCanvas.restore_region(self.minimapBackground)
        self.minimapFig.draw_artist(self.minimapSelection)
        self.minimapFig.draw_artist(self.minimapSelector)
        self.minimapFig.draw_artist(self.playback_marker.markers[0])
        for marker in self.markers.values():
            self.minimapFig.draw_artist(marker)
        self.minimapCanvas.blit(self.minimapFig.bbox)

    def set_visible(self, value):
        self.minimapCanvas.setVisible(value)

    def get_visible(self):
        return self.minimapCanvas.isVisible()

    def set_selection_limits(self, xleft, xright):
        self.minimapSelection.xy[:2, 0] = xleft
        self.minimapSelection.xy[2:4, 0] = xright
        self.draw_animate()

    def set_selection_visible(self, value):
        self.minimapSelection.set_visible(value)
        self.draw_animate()

    def create_marker(self, key, position, **kwargs):
        if self.xmin <= position <= self.xmax:
            marker = self.minimapFig.axes[0].axvline(position, animated=True)
            self.markers[key] = marker
            self.markers[key].set(**kwargs)

    def set_marker_position(self, key, value):
        marker = self.markers.get(key)
        if marker is not None:
            if self.xmin <= value <= self.xmax:
                marker.set_xdata(value)

    def set_marker(self, key, **kwargs):
        marker = self.markers.get(key)
        if marker is not None:
            kwargs.pop("animated", None)  # marker's animated property must be always true to be drawn properly
            marker.set(**kwargs)

    def delete_marker(self, key):
        marker = self.markers.get(key)
        if marker is not None:
            self.minimapFig.axes[0].lines.remove(marker)
            self.markers.pop(key)
예제 #13
0
class Plotter(QMainWindow):
    ''' MainWindow consisting of menu bar, tab widget, tree list
    menu bar: load data
    tab widget: - dragWindow
                - widget consisting of picture viewer and two plots (raw and rms)
    tree list: to show loaded data, expand to see their channels and click to plot
    '''
    
    
    def __init__(self, parent=None):
        super(Plotter, self).__init__(parent)
        self.ui =  Ui_MainWindow()
        self.ui.setupUi(self)
        self.setCanvas()
        
        w = DragWindow()
        grid = QGridLayout()
        grid.addWidget(w)
        
        self.ui.tab_2.acceptDrops()
        self.ui.tab_2.setLayout(grid)
        
        self.moveConnection = None
        self.currentParent = None
        
        self.datas = []        
        self.offsetRecording = 0
        self.lines = [{}, {}]
    
    def setCanvas(self):
        ''' set widgets for a tab page
         - left side show image of current frame
         - right side show two plots: raw and rms
         - bot: button to edit triggers and slider to adjust 
                video-emg offset
        '''
        
        ########################
        # set matplotlib plots #
        ########################
        self.fig = Figure(dpi=70)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.ui.mainFrame)
        self.axes = self.fig.add_subplot(211)
        self.axesRMS = self.fig.add_subplot(212)
        self.mpl_toolbar = NavigationToolbar2(self.canvas, self.ui.mainFrame)
        self.canvas.mpl_connect('draw_event', self.onDraw)
        
        ####################################
        # add button to matplotlib toolbar #
        #################################### 
        redb = QPushButton('Edit Triggers')
        redb.setCheckable(True)
        self.mpl_toolbar.addWidget(redb)
        redb.clicked[bool].connect(self.toggleEditMode)
        
        # container for current frame of video 
        layout = pq.GraphicsLayoutWidget()
        vb = layout.addViewBox()
        vb.setAspectLocked(True)
        
        self.ri = pq.ImageItem()
        vb.addItem(self.ri)
        
        # layout to organize elements
        grid = QGridLayout()
        wrapper = QWidget()        
        vbox = QVBoxLayout(wrapper)
        splitter = QSplitter()
        
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)
        wrapper.setLayout(vbox)
        
        splitter.addWidget(layout)
        splitter.addWidget(wrapper)
        
        grid.addWidget(splitter)
        
        self.ri.show()
        layout.show()
        self.ui.mainFrame.setLayout(grid)
        
    def loadData(self):
        ''' open dialog for choosing files to load '''
        fileNames, ok1= QFileDialog.getOpenFileNames(
                     self, self.tr("Open data"),
                     plattform.fixpath("D:\Master\emg\Benedictus"), self.tr("Pickle Files (*.pk)"))
        if ok1:
            self.load(fileNames)
    
    def load(self, fileNames):
        ''' unpickles data and add elements to tree view
        in case loading takes a while, a progress bar shows current status 
        '''
        progress = QProgressDialog("Loading files...", "Abort Copy", 0, len(fileNames), self)
        progress.setWindowModality(Qt.WindowModal)
        i = 0
        for fileName in fileNames:
            with open(fileName, 'rb') as ifile:
                tmp = pickle.load(ifile)
                if os.path.isfile(fileName[:-2] + "oni"):
                    tmp = tmp + (fileName[:-2]+"oni",)
                if isinstance(tmp, pyHPF.pyHPF):
                    self.datas.append(tmp)
                else:
                    self.datas.append(extendedPyHPF(tmp))
                self.updateTree(fileName[-5:])
                
                i+=1
                progress.setValue(i)

    def updateTree(self, name):
        ''' adds DataItem to tree view '''
        dataItem = QTreeWidgetItem(self.ui.dataView)
        dataItem.setText(0, name)
        dataItem.setFlags(Qt.ItemIsEnabled|Qt.ItemIsEditable)
        for i in range(len(self.datas[-1].data)/4):
            x = DataItem(dataItem)
            x.setText(0, self.datas[-1].name[i*4])
            x.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable)
            x.setNumData(self.datas[-1].data[i*4])
            if hasattr(self.datas[-1], 'triggers'):
                x.triggers = self.datas[-1].triggers
            if hasattr(self.datas[-1], 'frames'):
                x.depth = self.datas[-1].seekFrame
                
    def toggleEditMode(self, toggle):
        ''' button pressed to toggle edit mode for triggers
         - if pressed in edit mode again, dialog to save changes to
           a existing file
        '''
        if toggle:
            item = self.ui.dataView.selectedItems()[-1]
            self.interactionMode = Interactor(self.canvas,
                                              [self.axes, self.axesRMS], 
                                              item.triggers, self.lines, item.emg.shape[0])
        else:
            self.interactionMode = None
            reply = QMessageBox.question(self, 'QMessageBox.question()',
                             'Update triggers?',
                             QMessageBox.Yes | QMessageBox.No)
            if reply == QMessageBox.Yes:
                fileName, ok= QFileDialog.getOpenFileName(
                                    self, self.tr("Choose which file to overwrite data"),
                
                plattform.fixpath("D:\Master\emg\Benedictus"), self.tr("Pickle Files (*.pk)"))
                if ok:
                    save(self.ui.dataView.selectedItems()[-1].triggers, fileName)
        
    def plotData(self):
        ''' clicking a DataItem will plot the raw data and rms of
        emg data
        - if oni files are present, it will connect the mouse position inside
          plots to frame number of video 
        '''
        
        #################
        #   clearing    #
        #################
        self.axes.clear()
        self.axesRMS.clear()
        if self.moveConnection is not None:
            self.canvas.mpl_disconnect(self.moveConnection)
        
        ########################
        #  get selected item   #
        ########################
        if len(self.ui.dataView.selectedItems()) > 0:
            item = self.ui.dataView.selectedItems()[-1]
            if hasattr(item, 'depth'):
                self.ui.offsetSlider.setEnabled(True)
                ''' if selected channel is from other dataset
                 - slider is available
                 - current frame of video is set
                 - and new parent is saved
                '''
                if item.parent() is not self.currentParent:
                    self.offsetRecording = 0
                    self.ui.offsetSlider.setValue(150)
                    if self.currentParent:
                        self.currentParent.child(0).depth(-1)
                    self.ri.setImage(item.depth(0))
                    self.currentParent = item.parent()
        ########################
        # if deselected, reset #
        ########################
        else:
            self.ui.offsetSlider.setEnabled(False)
            self.ri.setImage(np.zeros((1,1,1)))
        
        ##########################
        # plot selected data     #
        ##########################
        for item in self.ui.dataView.selectedItems():
            c = int(item.text(0)[-1])-1
            if c >= len(colors):
                c = c % len(colors)
            self.axes.plot(item.emg, label=item.text(0), c=colors[c])
            self.axesRMS.plot(feature.rootMeanSquare(np.abs(item.emg), 200), c=colors[c])
            
            self.lines = [{}, {}]
            for p in item.triggers:
                self.lines[0][p], = self.axes.plot([p]*2, [np.min(item.emg), np.max(item.emg)], c='k', animated = True)
                self.lines[1][p], = self.axesRMS.plot([p]*2, [np.min(item.emg), np.max(item.emg)], c='k', animated = True)
            c+=1
        
        # connect mouse position inside plots to frame index of video
        self.moveConnection = self.canvas.mpl_connect("motion_notify_event", self.updateVideo)

        self.axes.legend()
        self.canvas.draw()
        
    def onDraw(self, event):
        ''' partially updating plots
        see: http://wiki.scipy.org/Cookbook/Matplotlib/Animations#head-3d51654b8306b1585664e7fe060a60fc76e5aa08
        '''
        items = self.ui.dataView.selectedItems()
        if len(items)== 0: return
        
        for i in range(2):
            ax = [self.axes, self.axesRMS]
            for t in items[-1].triggers:
                ax[i].draw_artist(self.lines[i][t])

        self.canvas.blit()
            
    def correctOffset(self, offs):
        self.offsetRecording = offs-150
        
    def updateVideo(self, event):
        ''' set frame index according to mouse position '''
        if event.xdata is not None:
            frameIdx = int(event.xdata/2000.0*30 + self.offsetRecording)
            if frameIdx < 0:
                frameIdx = 0
            if len(self.ui.dataView.selectedItems()) > 0:
                if hasattr(self.ui.dataView.selectedItems()[-1], 'depth'):
                    self.ri.setImage(self.ui.dataView.selectedItems()[-1].depth(frameIdx)) 
예제 #14
0
class MainWindow(QMainWindow):
    analyzed_data_received_event = QtCore.Signal(object)

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self._ui = Ui_MainWindow()
        self._ui.setupUi(self)
        self.device = None
        self.analyzer = None
        self.in_error = False
        self.current_expected_pcm_clock_rate = None
        self.error_ticks = 0
        self.error_counts = 0

        self.audio = pyaudio.PyAudio()
        self.event_listener = SaleaeEventListener()
        self.event_listener.saleae_event_received.connect(self.on_saleae_event)
        self.play_sound_thread = SoundOutputRenderer(self.audio)
        self.analyzed_data_received_event.connect(self.play_sound_thread.on_data_received)
        PyDevicesManager.register_listener(self.event_listener, EVENT_ID_ONCONNECT)
        PyDevicesManager.register_listener(self.event_listener, EVENT_ID_ONDISCONNECT)
        PyDevicesManager.register_listener(self.event_listener, EVENT_ID_ONERROR)
        PyDevicesManager.register_listener(self.event_listener, EVENT_ID_ONREADDATA)
        PyDevicesManager.register_listener(self.event_listener, EVENT_ID_ONANALYZERDATA)

        self.audio_output_devices = []
        for i in range(self.audio.get_device_count()):
            info = self.audio.get_device_info_by_index(i)
            if info['maxOutputChannels'] > 0:
                self.audio_output_devices.append(info)
        self.initialize_ui_items()

        self.recording_state = STATE_IDLE
        self.last_record_start = time.clock()
        self.realtime_timer = QtCore.QTimer()
        self.realtime_timer.timeout.connect(self.realtime_timer_timeout)
        self.plot_timer = QtCore.QTimer()
        self.plot_timer.timeout.connect(self.plot_timer_timeout)

        self.figure = Figure(dpi=100)
        self.plotCanvas = FigureCanvas(self.figure)
        self.plotCanvas.setParent(self._ui.plotWidget)
        # Hook this up so we can resize the plot canvas dynamically
        self._ui.plotWidget.installEventFilter(self)
        self.fft_axis = self.figure.add_subplot(111)
        self.fft_line = None
        ytick_values = range(-140, -6, 6)
        self.fft_axis.set_yticks(ytick_values)
        self.fft_axis.set_yticklabels(["%d" % w for w in ytick_values], size='xx-small')
        self.fft_axis.set_xlabel("Frequency (kHz)", size='small')
        self.fft_axis.set_ylabel("dBFS", size='small')
        self.fft_axis.grid(True)
        self.fft_axis.autoscale(enable=False, axis='both')
        self.plot_background = None

        self.update_controls()

        self.show_message("Waiting for a Logic device to connect...")
        self.event_listener.start()
        PyDevicesManager.begin_connect()

    def initialize_ui_items(self,):
        self._ui.onDecodeErrorComboBox.addItems(ON_DECODE_ERROR_OPTS)
        self._ui.onDecodeErrorComboBox.setCurrentIndex(HALT)
        self._ui.frameAlignmentComboBox.addItems(FRAME_ALIGNMENTS)
        self._ui.frameAlignmentComboBox.setCurrentIndex(FRAME_ALIGN_LAST_BIT)
        self._ui.clockEdgeComboBox.addItems(EDGES)
        self._ui.clockEdgeComboBox.setCurrentIndex(FALLING_EDGE)
        self._ui.outputLocationLineEdit.setText(RUN_PATH)

        for item in self.audio_output_devices:
            self._ui.comboOutputDeviceSelection.addItem(item['name'], item)
        # Select the default audio output
        default = self.audio.get_default_output_device_info()
        index = self._ui.comboOutputDeviceSelection.findData(default)
        if index < 0:
            index = 0
        self._ui.comboOutputDeviceSelection.setCurrentIndex(index)

        num_channels = self._ui.channelsPerFrameSpinBox.value()
        self._ui.comboPCMChannelToListenTo.addItems(['%d' % w for w in range(1, num_channels + 1)])
        self._ui.comboPCMChannelToListenTo.setCurrentIndex(0)

    def show_message(self, msg):
        self._ui.messagesLabel.setText(msg)

    def start_recording(self, mode):
        # Create an analyzer
        channels_per_frame = self._ui.channelsPerFrameSpinBox.value()
        sampling_rate = int(self._ui.samplingRateLineEdit.text())
        bits_per_channel = self._ui.bitsPerChannelSpinBox.value()
        clock_channel = self._ui.clockChannelSpinBox.value()
        frame_channel = self._ui.frameChannelSpinBox.value()
        data_channel = self._ui.dataChannelSpinBox.value()
        clock_edge = self._ui.clockEdgeComboBox.currentIndex()
        frame_edge = LEADING_EDGE
        self.current_expected_pcm_clock_rate = \
                    channels_per_frame * sampling_rate * bits_per_channel

        if clock_edge == LEADING_EDGE:
            frame_edge = FALLING_EDGE
        decode_error = self._ui.onDecodeErrorComboBox.currentIndex()
        frame_transition = self._ui.frameAlignmentComboBox.currentIndex()
        output_dir = None
        if mode == MODE_WRITE_TO_FILE:
            output_dir = self._ui.outputLocationLineEdit.text()
        plot_spectrum = self._ui.checkboxShowSpectrum.isChecked()
        self.analyzer = PCMAnalyzer(
                               output_folder = output_dir,
                               audio_channels_per_frame = channels_per_frame,
                               audio_sampling_rate_hz = sampling_rate,
                               bits_per_channel = bits_per_channel,
                               clock_channel = clock_channel,
                               frame_channel = frame_channel,
                               data_channel = data_channel,
                               frame_align = frame_edge,
                               frame_transition = frame_transition,
                               clock_edge = clock_edge,
                               on_decode_error = decode_error,
                               calculate_ffts = plot_spectrum,
                               logging = False)     # Do not enable this unless you have a HUUUGE hard drive!
        self.device.set_analyzer(self.analyzer)
        self.device.set_active_channels(list(range(4)))
        rate = self.device.get_analyzer().get_minimum_acquisition_rate()
        self.device.set_sampling_rate_hz(rate)
        self.device.set_use_5_volts(False)
        self.recording_state = STATE_WAITING_FOR_FRAME

        self.last_record_start = time.clock()
        self.realtime_timer.start(100)
        if plot_spectrum:
            self.plot_timer.start(150)

        if mode == MODE_LISTEN:
            # Configure the audio player
            data = self._ui.comboOutputDeviceSelection.itemData(
                        self._ui.comboOutputDeviceSelection.currentIndex())
            format = pyaudio.paInt16
            if bits_per_channel > 16:
                format = pyaudio.paInt32
            self.play_sound_thread.configure(data['index'], format=format,
                    channels=1, rate = sampling_rate,
                    channel_to_play=self._ui.comboPCMChannelToListenTo.currentIndex())
            self.play_sound_thread.start()

        self.show_message("Waiting for valid frame...")
        self.device.read_start()
        self.update_controls()

    def stop_recording(self,):
        self.reset()
        self.recording_state = STATE_IDLE
        self.show_message("Recording stopped.")
        self.update_controls()
        self.validate()

    def eventFilter(self, object, event):
        if event.type() == QtCore.QEvent.Resize:
            if object == self._ui.plotWidget:
                self.update_plot_canvas()
        return QWidget.eventFilter(self, object, event)

    @QtCore.Slot()
    def on_recordButton_clicked(self,):
        if self._ui.recordButton.text() == 'Record':
            self.start_recording(MODE_WRITE_TO_FILE)
        elif self._ui.recordButton.text() == 'Listen':
            self.start_recording(MODE_LISTEN)
        else:
            self.stop_recording()

    def realtime_timer_timeout(self,):
        elapsed = time.clock() - self.last_record_start
        time_text = "%d:%02.1f" % (elapsed / 60, elapsed % 60)
        self._ui.recordTimeLabel.setText(time_text)
        if self.in_error:
            if self.error_ticks > 15:
                self._ui.messagesLabel.setStyleSheet("background-color: none;")
                self.show_message("Continuing recording (last error: %s)..." % time_text)
                self.error_ticks = 0
                self.error_counts = 0
                self.in_error = False
            else:
                self._ui.messagesLabel.setStyleSheet("background-color: red;")
                self.error_ticks += 1

    def plot_timer_timeout(self, d=None):
        if self.device is not None and self.device.get_analyzer() is not None:
            analyzer = self.device.get_analyzer()
            data = analyzer.get_latest_fft_data(purge=True)
            if data is not None:
                self.update_plot(data)

    @QtCore.Slot()
    def on_outputLocationBrowseButton_clicked(self,):
        # Prompt for file name
        dirname = QFileDialog.getExistingDirectory(self, "Select Output Folder",
                            self._ui.outputLocationLineEdit.text(),
                            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        # Returns a tuple of (filename, filetype)
        if dirname is not None and len(dirname) > 0:
            self._ui.outputLocationLineEdit.setText(dirname)

    @QtCore.Slot(int)
    def on_channelsPerFrameSpinBox_valueChanged(self, i):
        self._ui.comboPCMChannelToListenTo.clear()
        num_channels = self._ui.channelsPerFrameSpinBox.value()
        self._ui.comboPCMChannelToListenTo.addItems(['%d' % w for w in range(1, num_channels + 1)])
        self._ui.comboPCMChannelToListenTo.setCurrentIndex(0)
        self.validate()

    @QtCore.Slot(int)
    def on_clockChannelSpinBox_valueChanged(self, i):
        self.validate()

    @QtCore.Slot(int)
    def on_frameChannelSpinBox_valueChanged(self, i):
        self.validate()

    @QtCore.Slot(int)
    def on_dataChannelSpinBox_valueChanged(self, i):
        self.validate()

    @QtCore.Slot(int)
    def on_comboPCMChannelToListenTo_currentIndexChanged(self, i):
        if self.play_sound_thread is not None:
            self.play_sound_thread.channel_to_play = self._ui.comboPCMChannelToListenTo.currentIndex()

    @QtCore.Slot(int)
    def on_comboOutputDeviceSelection_currentIndexChanged(self, i):
        pass

    @QtCore.Slot()
    def on_tabOutputRenderer_currentChanged(self,):
        if self.recording_state != STATE_IDLE:
            self.stop_recording()
        self.update_controls()

    def update_controls(self,):
        is_recording = (self.recording_state != STATE_IDLE)
        if not is_recording:
            current_tab = self._ui.tabOutputRenderer.currentWidget()
            if current_tab == self._ui.recordToFile:
                self._ui.recordButton.setText("Record")
            elif current_tab == self._ui.outputToSoundCard:
                self._ui.recordButton.setText("Listen")
        else:
            self._ui.recordButton.setText("Stop")

        self._ui.comboOutputDeviceSelection.setEnabled(not is_recording)
        self._ui.outputLocationBrowseButton.setEnabled(not is_recording)
        self._ui.logicGroupBox.setEnabled(not is_recording)
        self._ui.pcmGroupBox.setEnabled(not is_recording)
        self._ui.outputGroupBox.setEnabled(not is_recording)
        self._ui.checkboxShowSpectrum.setEnabled(not is_recording)
        self.update_plot_canvas()

    def update_plot_canvas(self,):
        self.fft_axis.set_xlim(0, int(self._ui.samplingRateLineEdit.text()) / 2)
        freq_values = range(0, int(self._ui.samplingRateLineEdit.text()) / 2, 1000) + \
                            [int(self._ui.samplingRateLineEdit.text()) / 2]
        self.fft_axis.set_xticks(freq_values)
        self.fft_axis.set_xticklabels(["%d" % (w / 1000) for w in freq_values], size='xx-small')
        self.plotCanvas.resize(self._ui.plotWidget.size().width(),
                               self._ui.plotWidget.size().height())
        self.plotCanvas.draw()
        self.plot_background = None

    def validate(self,):
        valid = False
        if self.device is not None:
            if (self._ui.clockChannelSpinBox.value() != self._ui.frameChannelSpinBox.value()) and \
               (self._ui.frameChannelSpinBox.value() != self._ui.dataChannelSpinBox.value()) and \
               (self._ui.clockChannelSpinBox.value() != self._ui.dataChannelSpinBox.value()):
                dirname = self._ui.outputLocationLineEdit.text()
                if dirname is not None and len(dirname) > 0:
                    valid = True
        self.set_valid(valid)

    def set_valid(self, is_valid):
        self._ui.recordButton.setEnabled(is_valid)

    def on_saleae_event(self, event, device):
        analyzer = None
        if device is not None and device == self.device and \
                self.device.get_analyzer() is not None:
            analyzer = self.device.get_analyzer()
        if event.id == EVENT_ID_ONCONNECT:
            self.show_message("Device connected with id %d" % device.get_id())
            self.device = device
            self.update_controls()
            self.validate()
        elif event.id == EVENT_ID_ONERROR:
            if self._ui.onDecodeErrorComboBox.currentIndex() == HALT:
                self.stop_recording()
                self.show_message("ERROR: %s" % event.data)
            else:
                if not self.in_error:
                    self.in_error = True
                    self.show_message("ERROR: %s" % event.data)
                else:
                    self.error_counts += 1
                    if self.error_counts > 5:
                        self.stop_recording()
                        self.show_message("Too many errors! %s" % event.data)
        elif event.id == EVENT_ID_ONDISCONNECT:
            self.recording_state = STATE_IDLE
            self.show_message("Device id %d disconnected." % device.get_id())
            self.shutdown()
        elif event.id == EVENT_ID_ONREADDATA:
            if analyzer is not None:
                if self.recording_state == STATE_WAITING_FOR_FRAME:
                    if self.device.get_analyzer().first_valid_frame_received():
                        self.show_message("Recording. Press 'Stop' to stop recording.")
                        self.recording_state = STATE_RECORDING
        elif event.id == EVENT_ID_ONANALYZERDATA:
            if self.recording_state == STATE_RECORDING and \
                    self.current_expected_pcm_clock_rate is not None:
                # Sanity check the sampling rate with the detected clock frequency
                if analyzer is not None:
                    clock_period_samples = self.device.get_analyzer().get_average_clock_period_in_samples()
                    meas_clock_freq = self.device.get_sampling_rate_hz() / clock_period_samples
                    if (1.2 * self.current_expected_pcm_clock_rate) <  meas_clock_freq or \
                        (0.8 * self.current_expected_pcm_clock_rate) > meas_clock_freq:
                        # The user's setup is probably wrong, so bail immediately
                        self.stop_recording()
                        self.show_message("Detected a PCM clock of ~%d Hz. Check your settings!" % meas_clock_freq)

            self.analyzed_data_received_event.emit(event.data)

    def update_plot(self, data):
        if self.plot_background is None:
            self.plot_background = self.plotCanvas.copy_from_bbox(self.fft_axis.bbox)

        channel = self._ui.comboPCMChannelToListenTo.currentIndex()
        channel_data = data[channel]
        numpoints = len(channel_data)
        if self.fft_line is None:
            self.fft_line, = self.fft_axis.plot(numpy.zeros(numpoints), animated=True)

        sampling_rate = int(self._ui.samplingRateLineEdit.text())
        freqs = numpy.fft.fftfreq(numpoints * 2, d=1.0 / float(sampling_rate))

        # Restore the clean slate background (this is the 'blit' method, which
        # is much faster to render)
        self.plotCanvas.restore_region(self.plot_background, bbox=self.fft_axis.bbox)

        self.fft_line.set_ydata(channel_data)
        self.fft_line.set_xdata(freqs[:numpoints])
        # Draw the line
        self.fft_axis.draw_artist(self.fft_line)
        # Blit the canvas
        self.plotCanvas.blit(self.fft_axis.bbox)

    def reset(self,):
        self.current_expected_pcm_clock_rate = None
        if self.device is not None:
            self.device.stop()
            self.analyzer = None
        self.realtime_timer.stop()
        self.plot_timer.stop()
        if self.play_sound_thread.isRunning():
            self.play_sound_thread.quit()
            self.play_sound_thread.wait()
            
        self._ui.messagesLabel.setStyleSheet("background-color: none;")
        self.error_ticks = 0
        self.error_counts = 0
        self.in_error = False

    def shutdown(self,):
        self.recording_state = STATE_IDLE
        self.reset()
        self.device = None
        try:
            self.figure.close()
        except:
            pass
    
    def closeEvent(self, event):
        """Intercepts the close event of the MainWindow."""
        self.show_message("Closing device...")
        try:
            self.shutdown()
            self.event_listener.quit()
            self.event_listener.wait()
            self.audio.terminate()
        finally:
            super(MainWindow, self).closeEvent(event)
예제 #15
0
class RTWindowWidget(QtGui.QWidget):
    """Matplotlib wxFrame with animation effect"""
    ### connects widgets and signals ###
    def __init__(self, parent = None):
        super(RTWindowWidget, self).__init__(parent)

        # Matplotlib Figure
        self.fig = Figure((6, 4), 100)
        # bind the Figure to the backend specific canvas
        self.canvas = FigureCanvas(self.fig)
        # add a subplot
        self.ax = self.fig.add_subplot(111)

        # limit the X and Y axes dimensions
        # we prefer 2 separate functions for clarity
        self.ax.set_ylim([0, 100])
        self.ax.set_xlim([0, POINTS])
        # but we want a "frozen" window (defined by y/xlim functions)
        self.ax.set_autoscale_on(False)

        # we do not want ticks on X axis
        self.ax.set_xticks([])
        # we want a tick every 10 point on Y (101 is to have 100 too)
        self.ax.set_yticks(range(0, 101, 10))
        # disable autoscale, since we don't want the Axes to adapt
        # draw a grid (it will be only for Y)
        self.ax.grid(True)

        # generates first "empty" plots
        self.user = [None] * POINTS
        self.nice = [None] * POINTS
        self.sys  = [None] * POINTS
        self.idle = [None] * POINTS

        self.l_user, = self.ax.plot(range(POINTS), self.user, label='User %')
        self.l_nice, = self.ax.plot(range(POINTS), self.nice, label='Nice %')
        self.l_sys,  = self.ax.plot(range(POINTS),  self.sys,  label='Sys %')
        self.l_idle, = self.ax.plot(range(POINTS), self.idle, label='Idle %')

        # add the legend
        self.ax.legend(loc='upper center',
                           ncol=4,
                           prop=font_manager.FontProperties(size=10))

        # force a draw on the canvas()
        # trick to show the grid and the legend
        self.canvas.draw()

        # save the clean background - everything but the line
        # is drawn and saved in the pixel buffer background
        self.bg = self.canvas.copy_from_bbox(self.ax.bbox)

        # take a snapshot of CPU usage, needed for the update algorithm
        self.before = self.prepare_cpu_usage()


        # timerCallback = lambda: self.onTimer()
        myTimer = QtCore.QTimer()
        myTimer.timeout.connect(self.onTimer)
        myTimer.start(1000) #once a sec
        # print 1
        self.canvas.show()


    def prepare_cpu_usage(self):
        """helper function to return CPU usage info"""

        # get the CPU times using psutil module
        t = p.cpu_times()

        # return only the values we're interested in
        if hasattr(t, 'nice'):
            return [t.user, t.nice, t.system, t.idle]
        else:
            # special case for Windows, without 'nice' value
            return [t.user, 0, t.system, t.idle]


    def get_cpu_usage(self):
        """Compute CPU usage comparing previous and current measurements"""

        # take the current CPU usage information
        now = self.prepare_cpu_usage()
        # compute deltas between current and previous measurements
        delta = [now[i]-self.before[i] for i in range(len(now))]
        # compute the total (needed for percentages calculation)
        total = sum(delta)
        # save the current measurement to before object
        self.before = now
        # return the percentage of CPU usage for our 4 categories
        return [(100.0*dt)/total for dt in delta]


    def onTimer(self):
        """callback function for timer events"""

        print 1
        # get the CPU usage information
        tmp = self.get_cpu_usage()

        # restore the clean background, saved at the beginning
        self.canvas.restore_region(self.bg)

        # update the data
        self.user = self.user[1:] + [tmp[0]]
        self.nice = self.nice[1:] + [tmp[1]]
        self.sys  = self.sys[1:]  + [tmp[2]]
        self.idle = self.idle[1:] + [tmp[3]]

        # update the plot
        self.l_user.set_ydata(self.user)
        self.l_nice.set_ydata(self.nice)
        self.l_sys.set_ydata( self.sys)
        self.l_idle.set_ydata(self.idle)

        # just draw the "animated" objects
        self.ax.draw_artist(self.l_user)
        self.ax.draw_artist(self.l_nice)
        self.ax.draw_artist(self.l_sys)
        self.ax.draw_artist(self.l_idle)

        # "blit" the background with the animated lines
        self.canvas.blit(self.ax.bbox)
예제 #16
0
class guiapp(QtGui.QMainWindow, cursortest.Ui_Dialog):
    def __init__(self):
        super(self.__class__, self).__init__()

        self.setupUi(self)

        self.setupfigure()

        self.populateplt()

        self.addcursor()

        self.visible = True
        self.horizOn = True
        self.vertOn = True
        self.useblit = True
        self.background = None
        self.needclear = False

        self.canvas.setVisible(True)
        cid2 = self.canvas.mpl_connect('button_press_event', self.onmove)

    def setupfigure(self):
        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.plt2d)
        self.ax.set_title('title')
        self.ax.set_xlabel('x label')
        self.ax.set_ylabel('y label')

        # navigation toolbar
        self.navbar = NavigationToolbar(self.canvas, self.plt2d, coordinates=True)

    def populateplt(self):
        data = np.random.rand(200,200)
        self.ax.imshow(data)

    def addcursor(self):
        self.cursor = Cursor(self.ax,horizOn=True,vertOn=True,useblit=False, color='black')

        self.lineh = self.ax.axhline(self.ax.get_ybound()[0], visible=False)
        self.linev = self.ax.axvline(self.ax.get_xbound()[0], visible=False)

    def onmove(self, event):
        'on mouse motion draw the cursor if visible'
        if event.inaxes != self.ax:
            self.linev.set_visible(False)
            self.lineh.set_visible(False)

            if self.needclear:
                self.canvas.draw()
                self.needclear = False
            return
        self.needclear = True
        if not self.visible: return
        self.linev.set_xdata((event.xdata, event.xdata))

        self.lineh.set_ydata((event.ydata, event.ydata))
        self.linev.set_visible(self.visible and self.vertOn)
        self.lineh.set_visible(self.visible and self.horizOn)

        self._update()
        print('%d, %d'%(self.linev.get_xydata()[0,0],self.lineh.get_xydata()[0,1]))


    def _update(self):

        if self.useblit:
            if self.background is not None:
                self.canvas.restore_region(self.background)
            self.ax.draw_artist(self.linev)
            self.ax.draw_artist(self.lineh)
            self.canvas.blit(self.ax.bbox)
        else:
            self.canvas.draw_idle()

        return False
예제 #17
0
class mpl_widget(QWidget):
    def __init__(self, parent=None, mainWidget=None):
        self._SELECTEDCELLS = list()       # container for instances of selected cells, so we can delete them when we want
        self._SELECTEDCELLS_IJ = list()  # container for coords of selected cells, so we can delete them when we want
        self._SELECTEDCELLLINES = list()   # container for instances of selected cells, so we can delete them when we want
        self._GRIDLINES = None
        QWidget.__init__(self, parent)
        self.mainWidget = mainWidget
        self.create_main_frame()
        self.mpl_menu = mpl_menu(self)
        self.shift_is_held = False
        #self.connect(self.mpl_menu, QtCore.SIGNAL('mySignal'), self.mySlot)
        #print 'my parent is:', parent
        self.clear_selection()
        self.init_tooltips()

    def init_tooltips(self):
        self.canvas.setToolTip('If 2D plot => RMB click toggles menu <br> - RMB click selects cell <br> - selected cells are drawn with black border')
        self.grid_cb.setToolTip('If 2D plot => show computational grid <br> If 1D plot => show normal gridlines')
        self.cbar_button.setToolTip('If 2D plot => controls the color range. <br> Note: <br> - pressing UP and DOWN arrows cycles through colormaps <br> - dragging colorbar with RMB scales the color-range <br> - dragging colorbar with LMB shifts the color-range')
        self.mpl_toolbar.setToolTip('Shows coordinates (i,j, lat,lon) and data-value(z) under the cursor. <br> if you see <i>>>></i> coordinates are not visible. Enlarge the window')

    def create_main_frame(self):

        self.fig = Figure(dpi=100)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self)
        self.canvas.setFocusPolicy( Qt.ClickFocus )
        self.canvas.setFocus()

        self.mpl_toolbar = myNavigationToolbar(self.canvas, self)
        self.canvas.mpl_connect('button_press_event', self.on_click)
        self.canvas.mpl_connect('key_press_event', self.on_key_press)
        self.canvas.mpl_connect('key_release_event', self.on_key_release)
        #self.canvas.mpl_connect('button_press_event', self.disable_clicks)


        self.cbar_button = QPushButton("Color Range")
        self.cbar_button.setFocusPolicy( Qt.NoFocus )
        self.grid_cb = QCheckBox("Show Grid")
        self.grid_cb.setFocusPolicy( Qt.NoFocus )
        self.grid_cb.stateChanged.connect(self.showGrid)

        vbox = QVBoxLayout()
        hbox = QHBoxLayout()

        vbox.addWidget(self.canvas)  # the matplotlib canvas
        hbox.addWidget(self.mpl_toolbar)
        hbox.addWidget(self.cbar_button)
        hbox.addWidget(self.grid_cb)
        vbox.addLayout(hbox)
        self.setLayout(vbox)



    def on_click(self, event):
        if event.inaxes != self.get_axes()[0]: return
        #if self.get_axes()[0].format_coord(event.x, event.y) == 'outside data area': return
        if self.allow_menu():
            self.allow_popup_menu = True
            if self.shift_is_held:
                self.allow_popup_menu = False

            point = [int(event.xdata + .5), int(event.ydata + .5)]
            #print '>>>', point, '\t currently {0} selected'.format(len(self._SELECTEDCELLS))
            if event.button == 3 :  #if RMB is clicked

                # working with dialog for transect!
                if self.mainWidget.transect_dlg:
                    if self.mainWidget.transect_dlg.toogle_show_after_selected_cell:
                        realx, realy = self.get_real_xy(event.xdata, event.ydata, self.mainWidget.detect_variable_dimensions())
                        realpoint = [realy, realx]
                        #print 'real xy:', realpoint
                        if self.mainWidget.transect_dlg.toogle_show_after_selected_cell == 1:  # select point 1
                            self.allow_popup_menu = False
                            self.mainWidget.transect_dlg.data.set_p1(realpoint)
                        elif self.mainWidget.transect_dlg.toogle_show_after_selected_cell == 2:  # select point 2
                            self.allow_popup_menu = False
                            self.mainWidget.transect_dlg.data.set_p2(realpoint)

                        self.mainWidget.transect_dlg.update()
                        self.mainWidget.transect_dlg.show()
                
                # working with dialog for flux!
                if self.mainWidget.flux_dlg:
                    if self.mainWidget.flux_dlg.toogle_show_after_selected_cell:
                        if self.mainWidget.flux_dlg.toogle_show_after_selected_cell == 1:  # select point 1
                            self.allow_popup_menu = False
                            self.mainWidget.flux_dlg.data.set_p1(point)
                        elif self.mainWidget.flux_dlg.toogle_show_after_selected_cell == 2:  # select point 2
                            self.allow_popup_menu = False
                            self.mainWidget.flux_dlg.data.set_p2(point)

                        self.mainWidget.flux_dlg.update()
                        self.mainWidget.flux_dlg.show()



                if len(self._SELECTEDCELLS) == 0:  # if no cell is selected
                    self.add_selected_cell(point)


                else:  # if some cells are already selected
                    if self.mpl_menu.allow_rmb_select_cells() or self.shift_is_held:
                        # check if this point is already selected:
                        already_selected = False
                        for p in self._SELECTEDCELLS_IJ:
                            if (point[0] == p[0]) and (point[1] == p[1]):
                                already_selected = True
                                print 'cell already selected... is not added'

                        if not already_selected:
                            self.add_selected_cell(point)
                    else:
                        pass
                        #self.clear_selection()
                        #self.add_selected_cell(point)

    def cells_selected(self):
        if self._SELECTEDCELLS: return len(self._SELECTEDCELLS)
        else: return False

    def add_selected_cell(self, point):
        ''' point = [i, j]'''
        print 'selected cell:', point[0], point[1]
        c = self.draw_picked_cell(point)
        self._SELECTEDCELLS.append(c)
        self._SELECTEDCELLS_IJ.append(point)




    def get_selected_cells_ij(self):
        return self._SELECTEDCELLS_IJ

    def clear_selection(self):
        '''
        delete all graphical objects of selected cells
        redraw canvas
        '''
        print 'clearing stuff'
        if len(self._SELECTEDCELLLINES) > 0:
            for line in self._SELECTEDCELLLINES:
                l = line.pop(0)
                l.remove()
                del l
            del self._SELECTEDCELLLINES[:]
        #print 'cells ---- before:', len(self._SELECTEDCELLS)
        if len(self._SELECTEDCELLS) > 0:
            for cell in self._SELECTEDCELLS:
                for line in cell:
                    l = line.pop(0)
                    l.remove()
                    del l
            del self._SELECTEDCELLS[:]
        #print 'cells ---- left:', len(self._SELECTEDCELLS)


        #print 'cells-coords ----'
        #print len(self._SELECTEDCELLS_IJ)
        if self._SELECTEDCELLS_IJ:
            for cellcoords in self._SELECTEDCELLS_IJ:
                #cc = cellcoords.pop(0)
                #cellcoords.remove()
                del cellcoords
            del self._SELECTEDCELLS_IJ[:]
        #print 'cells ---- left,', len(self._SELECTEDCELLS_IJ)



        if len(self._SELECTEDCELLS) != 0:
            raise ValueError('List "self._SELECTEDCELLS" was not flushed')

        if len(self._SELECTEDCELLLINES) != 0:
            raise ValueError('List "self._SELECTEDCELLLINES" was not flushed')

        if len(self._SELECTEDCELLS_IJ) != 0:
            raise ValueError('List "self._SELECTEDCELLLINES" was not flushed')
        # update plot
        self.canvas.draw()
        #print 'finishing clear: cells left', len(self._SELECTEDCELLS)


    def showGrid(self, state):
        if self.fig.axes:
            current_plot = self.mainWidget.get_plotType()
            current_plot2D = self.mainWidget.get_plotType_for_timeseries()
            if state == Qt.Checked:
                if current_plot == '1D' or (current_plot2D =="2DZT"):
                    self.fig.axes[0].grid(True)
                elif current_plot == '2D' and (not current_plot2D =="2DZT"):
                    self.draw_pixel_grid(True)
            else:
                if current_plot == '1D' or (current_plot2D =="2DZT"):
                    self.fig.axes[0].grid(False)
                elif current_plot == '2D' and (not current_plot2D =="2DZT"):
                    self.draw_pixel_grid(False)
            self.canvas.draw()

    def draw_picked_cell(self, point):
        x = point[0]
        y = point[1]
        '''
        approach drawing a patch... not working
        cell_bnd = patches.Rectangle((x-.5, y-.5), 1, 1, fill=False, edgecolor="black", hatch=None, linewidth=1.)
        cell_instance = self.fig.axes[0].add_patch(cell_bnd)
        '''

        b_line = [(x-.5, x+.5), (y-.5, y-.5)]
        r_line = [(x+.5, x+.5), (y-.5, y+.5)]
        t_line = [(x-.5, x+.5), (y+.5, y+.5)]
        l_line = [(x-.5, x-.5), (y-.5, y+.5)]
        cell = [b_line, r_line, t_line, l_line]
        for i, l in enumerate(cell):
            ll = self.fig.axes[0].plot(l[0], l[1], 'k-', lw=.8)
            cell[i] = ll  # overwriting current Line2D object with object binded to an axes
        #self._SELECTEDCELLS.append(cell)  # collecting reference to this cell to be able to delete it
        #self._SELECTEDCELLS_IJ.append(point)  # collecting reference to this cell to be able to delete it

        self.canvas.draw()
        return cell


    def draw_line(self, point1, point2):
        line = [(point1[0], point2[0]), (point1[1], point2[1])]
        l = self.fig.axes[0].plot(line[0], line[1], 'k-', lw=2)
        return l

    def draw_pixel_grid(self, enable=True):
        if enable:
            dx = 1
            dy = 1
            x0 = -.5
            y0 = -.5

            if self.mainWidget.get_plotType_for_timeseries() == '2DXY':
                nx = self.mainWidget.get_nX()
                ny = self.mainWidget.get_nY()
            elif self.mainWidget.get_plotType_for_timeseries() == '2DZY':
                nx = self.mainWidget.get_nY()
                ny = self.mainWidget.get_nZ()
            elif self.mainWidget.get_plotType_for_timeseries() == '2DZX':
                nx = self.mainWidget.get_nX()
                ny = self.mainWidget.get_nZ()

            self._GRIDLINES = list()
            for n_hline in np.arange(ny+1):
                hline = [(x0, x0+nx), (y0+n_hline, y0+n_hline)]
                l = self.fig.axes[0].plot(hline[0], hline[1], 'k-', lw=.2)
                self._GRIDLINES.append(l)  # collecting reference to this line to be able to delete it

            for n_vline in np.arange(nx+1):
                vline = [(x0+n_vline, x0+n_vline), (y0, y0+ny)]
                l = self.fig.axes[0].plot(vline[0], vline[1], 'k-', lw=.2)
                self._GRIDLINES.append(l)  # collecting reference to this line to be able to delete it


        if not enable:
            #print 'deleting lines...'
            if self._GRIDLINES:  # if lines were created
                #print 'lines are here...'
                for line in self._GRIDLINES:
                    #print line
                    l = line.pop(0)
                    l.remove()
                    del l
            self.fig.canvas.draw()

    def on_key_press(self, event):
        #print 'key pressed:', event.key
        if event.key == 'shift':
            self.shift_is_held = True


    

    def on_key_release(self, event):
        #print 'key released:', event.key
        if event.key == 'shift':
            self.shift_is_held = False

        elif event.key == 'escape':
            self.clear_selection()


    def change_coordinate_formatter(self, ax, data2d,  bruteforce_flag=None, bruteforce_dims=None):
        ''' see http://stackoverflow.com/questions/14754931/matplotlib-values-under-cursor
        '''
        numrows, numcols = data2d.shape
        bruteforce_mode_on = False
        bruteforce_mode_on = (bruteforce_flag == '2DXY' and bruteforce_dims[-1] and bruteforce_dims[-2])


        def format_coord(x, y):
            col = int(x+0.5)
            row = int(y+0.5)

            if not bruteforce_mode_on:
                if col >= 0 and col < numcols and row >= 0 and row < numrows:
                    #z = data2d[row, col]
                    # sice we have artificially reversed y-coordinate axes, now reverse data!
                    # numrows-1, because if nrows=10 => row=[0:9]
                    z = data2d[numrows-1-row, col]
                    #return 'x=%1.1f y=%1.1f z=%1.6f' % (x, y, z)
                    return 'i=%d j=%d z=%.6f' % (col, row, z)
                else:
                    #return 'x=%1.4f, y=%1.4f' % (x, y)
                    return 'outside data area'

            elif bruteforce_flag == '2DXY' and bruteforce_dims[-1] and bruteforce_dims[-2]:
                '''
                our extend in X=[-0.5:numcols-0.5], Y=[-0.5:numrows-0.5], because col,row is cell center!
                '''
                if col >= 0 and col < numcols and row >= 0 and row < numrows:
                    #z = data2d[row, col]
                    # sice we have artificially reversed y-coordinate axes, now reverse data!
                    # numrows-1, because if nrows=10 => row=[0:9]
                    z = data2d[numrows-1-row, col]
                    real_x, real_y = self.get_real_xy(x, y, bruteforce_dims)

                    #return 'x=%1.1f y=%1.1f z=%1.6f' % (x, y, z)
                    #return 'i=%d j=%d z=%.3f x=%.4f y=%.4f' % (col, row, z, real_x, real_y)
                    return 'i=%d j=%d z=%.3f, %s=%.2f %s=%.2f' % (
                        col, row, z, bruteforce_dims[-1], real_x, bruteforce_dims[-2], real_y)
                else:
                    #return 'x=%1.4f, y=%1.4f' % (x, y)
                    return 'outside data area'
            else:
                raise ValueError('bruteforce_flag can be $None$ or $"2DXY"$. Passed %s' % bruteforce_flag)
        ax.format_coord = format_coord


    def allow_menu(self):
        allow = False
        #print "self.mainWidget.get_plotType():", self.mainWidget.get_plotType()
        #print "self.mainWidget.get_plotType_for_timeseries():", self.mainWidget.get_plotType_for_timeseries()
        if self.mainWidget.get_plotType() == "2D" and not self.mainWidget.get_plotType_for_timeseries() == "2DZT":
            allow = True
        return allow
    

    def get_real_xy(self, i, j, dimension_list):
        '''
        functions returns values of x,y based on passed indexes i, j

        '''
        if any(dimension_list[-2:-1]) is None:
            print 'Dimensions X,Y of current variable are not specified (variables that have same name as dimensions not found)'
            raise ValueError('Dimensions X,Y of current variable are not specified (variables that have same name as dimensions not found)')
        nc = self.mainWidget.get_selected_ncfile_instance()
        try:
            x_var = nc.variables[dimension_list[-1]]
            y_var = nc.variables[dimension_list[-2]]
            
        except:
            
            print ('Failed to load variables: {0}, {1}'.format(dimension_list[-1], dimension_list[-2]))
            raise ValueError('Failed to load variables: {0}, {1}'.format(dimension_list[-1], dimension_list[-2]))


        x_ratio = (x_var[-1]-x_var[0])/(len(x_var)-1)
        y_ratio = (y_var[-1]-y_var[0])/(len(y_var)-1)

        #x[i] = x_var[0]+x_ratio*i
        #y[j] = y_var[0]+y_ratio*j
        x = x_var[0] + x_ratio*i
        y = y_var[0] + y_ratio*j
        nc.close()
        return (x, y)

    def get_axes(self):
        return self.fig.get_axes()
    

    def fast_redraw(self, artist):
        background = [self.canvas.copy_from_bbox(self.get_axes()[0].bbox)]
        self.get_axes()[0].draw_artist(artist)
        self.canvas.restore_region(background)
        self.canvas.blit(self.get_axes()[0].bbox)
        self.canvas.update()
        self.canvas.flush_events()
예제 #18
0
class mpl_widget(QWidget):
    def __init__(self, parent=None, mainWidget=None):
        self._SELECTEDCELLS = list()       # container for instances of selected cells, so we can delete them when we want
        self._SELECTEDCELLS_IJ = list()  # container for coords of selected cells, so we can delete them when we want
        self._SELECTEDCELLLINES = list()   # container for instances of selected cells, so we can delete them when we want
        self._GRIDLINES = None
        QWidget.__init__(self, parent)
        self.mainWidget = mainWidget
        self.create_main_frame()
        self.mpl_menu = mpl_menu(self)
        self.shift_is_held = False
        #self.connect(self.mpl_menu, QtCore.SIGNAL('mySignal'), self.mySlot)
        #print 'my parent is:', parent
        self.clear_selection()
        self.init_tooltips()

    def init_tooltips(self):
        self.canvas.setToolTip('If 2D plot => RMB click toggles menu <br> - RMB click selects cell <br> - selected cells are drawn with black border')
        self.grid_cb.setToolTip('If 2D plot => show computational grid <br> If 1D plot => show normal gridlines')
        self.cbar_button.setToolTip('If 2D plot => controls the color range. <br> Note: <br> - pressing UP and DOWN arrows cycles through colormaps <br> - dragging colorbar with RMB scales the color-range <br> - dragging colorbar with LMB shifts the color-range')
        self.mpl_toolbar.setToolTip('Shows coordinates (i,j, lat,lon) and data-value(z) under the cursor. <br> if you see <i>>>></i> coordinates are not visible. Enlarge the window')

    def create_main_frame(self):

        self.fig = Figure(dpi=100)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self)
        self.canvas.setFocusPolicy( Qt.ClickFocus )
        self.canvas.setFocus()

        self.mpl_toolbar = myNavigationToolbar(self.canvas, self)
        self.canvas.mpl_connect('button_press_event', self.on_click)
        self.canvas.mpl_connect('key_press_event', self.on_key_press)
        self.canvas.mpl_connect('key_release_event', self.on_key_release)
        #self.canvas.mpl_connect('button_press_event', self.disable_clicks)


        self.cbar_button = QPushButton("Color Range")
        self.cbar_button.setFocusPolicy( Qt.NoFocus )
        self.grid_cb = QCheckBox("Show Grid")
        self.grid_cb.setFocusPolicy( Qt.NoFocus )
        self.grid_cb.stateChanged.connect(self.showGrid)

        vbox = QVBoxLayout()
        hbox = QHBoxLayout()

        vbox.addWidget(self.canvas)  # the matplotlib canvas
        hbox.addWidget(self.mpl_toolbar)
        hbox.addWidget(self.cbar_button)
        hbox.addWidget(self.grid_cb)
        vbox.addLayout(hbox)
        self.setLayout(vbox)



    def on_click(self, event):
        if event.inaxes != self.get_axes()[0]: return
        #if self.get_axes()[0].format_coord(event.x, event.y) == 'outside data area': return
        if self.allow_menu():
            self.allow_popup_menu = True
            if self.shift_is_held:
                self.allow_popup_menu = False

            point = [int(event.xdata + .5), int(event.ydata + .5)]
            #print '>>>', point, '\t currently {0} selected'.format(len(self._SELECTEDCELLS))
            if event.button == 3 :  #if RMB is clicked

                # working with dialog for transect!
                if self.mainWidget.transect_dlg:
                    if self.mainWidget.transect_dlg.toogle_show_after_selected_cell:
                        realx, realy = self.get_real_xy(event.xdata, event.ydata, self.mainWidget.detect_variable_dimensions())
                        realpoint = [realy, realx]
                        #print 'real xy:', realpoint
                        if self.mainWidget.transect_dlg.toogle_show_after_selected_cell == 1:  # select point 1
                            self.allow_popup_menu = False
                            self.mainWidget.transect_dlg.data.set_p1(realpoint)
                        elif self.mainWidget.transect_dlg.toogle_show_after_selected_cell == 2:  # select point 2
                            self.allow_popup_menu = False
                            self.mainWidget.transect_dlg.data.set_p2(realpoint)

                        self.mainWidget.transect_dlg.update()
                        self.mainWidget.transect_dlg.show()
                
                # working with dialog for flux!
                if self.mainWidget.flux_dlg:
                    if self.mainWidget.flux_dlg.toogle_show_after_selected_cell:
                        if self.mainWidget.flux_dlg.toogle_show_after_selected_cell == 1:  # select point 1
                            self.allow_popup_menu = False
                            self.mainWidget.flux_dlg.data.set_p1(point)
                        elif self.mainWidget.flux_dlg.toogle_show_after_selected_cell == 2:  # select point 2
                            self.allow_popup_menu = False
                            self.mainWidget.flux_dlg.data.set_p2(point)

                        self.mainWidget.flux_dlg.update()
                        self.mainWidget.flux_dlg.show()



                if len(self._SELECTEDCELLS) == 0:  # if no cell is selected
                    self.add_selected_cell(point)


                else:  # if some cells are already selected
                    if self.mpl_menu.allow_rmb_select_cells() or self.shift_is_held:
                        # check if this point is already selected:
                        already_selected = False
                        for p in self._SELECTEDCELLS_IJ:
                            if (point[0] == p[0]) and (point[1] == p[1]):
                                already_selected = True
                                print 'cell already selected... is not added'

                        if not already_selected:
                            self.add_selected_cell(point)
                    else:
                        pass
                        #self.clear_selection()
                        #self.add_selected_cell(point)

    def cells_selected(self):
        if self._SELECTEDCELLS: return len(self._SELECTEDCELLS)
        else: return False

    def add_selected_cell(self, point):
        ''' point = [i, j]'''
        print 'selected cell:', point[0], point[1]
        c = self.draw_picked_cell(point)
        self._SELECTEDCELLS.append(c)
        self._SELECTEDCELLS_IJ.append(point)




    def get_selected_cells_ij(self):
        return self._SELECTEDCELLS_IJ

    def clear_selection(self):
        '''
        delete all graphical objects of selected cells
        redraw canvas
        '''
        print 'clearing stuff'
        if len(self._SELECTEDCELLLINES) > 0:
            for line in self._SELECTEDCELLLINES:
                l = line.pop(0)
                l.remove()
                del l
            del self._SELECTEDCELLLINES[:]
        #print 'cells ---- before:', len(self._SELECTEDCELLS)
        if len(self._SELECTEDCELLS) > 0:
            for cell in self._SELECTEDCELLS:
                for line in cell:
                    l = line.pop(0)
                    l.remove()
                    del l
            del self._SELECTEDCELLS[:]
        #print 'cells ---- left:', len(self._SELECTEDCELLS)


        #print 'cells-coords ----'
        #print len(self._SELECTEDCELLS_IJ)
        if self._SELECTEDCELLS_IJ:
            for cellcoords in self._SELECTEDCELLS_IJ:
                #cc = cellcoords.pop(0)
                #cellcoords.remove()
                del cellcoords
            del self._SELECTEDCELLS_IJ[:]
        #print 'cells ---- left,', len(self._SELECTEDCELLS_IJ)



        if len(self._SELECTEDCELLS) != 0:
            raise ValueError('List "self._SELECTEDCELLS" was not flushed')

        if len(self._SELECTEDCELLLINES) != 0:
            raise ValueError('List "self._SELECTEDCELLLINES" was not flushed')

        if len(self._SELECTEDCELLS_IJ) != 0:
            raise ValueError('List "self._SELECTEDCELLLINES" was not flushed')
        # update plot
        self.canvas.draw()
        #print 'finishing clear: cells left', len(self._SELECTEDCELLS)


    def showGrid(self, state):
        if self.fig.axes:
            current_plot = self.mainWidget.get_plotType()
            current_plot2D = self.mainWidget.get_plotType_for_timeseries()
            if state == Qt.Checked:
                if current_plot == '1D' or (current_plot2D =="2DZT"):
                    self.fig.axes[0].grid(True)
                elif current_plot == '2D' and (not current_plot2D =="2DZT"):
                    self.draw_pixel_grid(True)
            else:
                if current_plot == '1D' or (current_plot2D =="2DZT"):
                    self.fig.axes[0].grid(False)
                elif current_plot == '2D' and (not current_plot2D =="2DZT"):
                    self.draw_pixel_grid(False)
            self.canvas.draw()

    def draw_picked_cell(self, point):
        x = point[0]
        y = point[1]
        '''
        approach drawing a patch... not working
        cell_bnd = patches.Rectangle((x-.5, y-.5), 1, 1, fill=False, edgecolor="black", hatch=None, linewidth=1.)
        cell_instance = self.fig.axes[0].add_patch(cell_bnd)
        '''

        b_line = [(x-.5, x+.5), (y-.5, y-.5)]
        r_line = [(x+.5, x+.5), (y-.5, y+.5)]
        t_line = [(x-.5, x+.5), (y+.5, y+.5)]
        l_line = [(x-.5, x-.5), (y-.5, y+.5)]
        cell = [b_line, r_line, t_line, l_line]
        for i, l in enumerate(cell):
            ll = self.fig.axes[0].plot(l[0], l[1], 'k-', lw=.8)
            cell[i] = ll  # overwriting current Line2D object with object binded to an axes
        #self._SELECTEDCELLS.append(cell)  # collecting reference to this cell to be able to delete it
        #self._SELECTEDCELLS_IJ.append(point)  # collecting reference to this cell to be able to delete it

        self.canvas.draw()
        return cell


    def draw_line(self, point1, point2):
        line = [(point1[0], point2[0]), (point1[1], point2[1])]
        l = self.fig.axes[0].plot(line[0], line[1], 'k-', lw=2)
        return l

    def draw_pixel_grid(self, enable=True):
        if enable:
            dx = 1
            dy = 1
            x0 = -.5
            y0 = -.5

            if self.mainWidget.get_plotType_for_timeseries() == '2DXY':
                nx = self.mainWidget.get_nX()
                ny = self.mainWidget.get_nY()
            elif self.mainWidget.get_plotType_for_timeseries() == '2DZY':
                nx = self.mainWidget.get_nY()
                ny = self.mainWidget.get_nZ()
            elif self.mainWidget.get_plotType_for_timeseries() == '2DZX':
                nx = self.mainWidget.get_nX()
                ny = self.mainWidget.get_nZ()

            self._GRIDLINES = list()
            for n_hline in np.arange(ny+1):
                hline = [(x0, x0+nx), (y0+n_hline, y0+n_hline)]
                l = self.fig.axes[0].plot(hline[0], hline[1], 'k-', lw=.2)
                self._GRIDLINES.append(l)  # collecting reference to this line to be able to delete it

            for n_vline in np.arange(nx+1):
                vline = [(x0+n_vline, x0+n_vline), (y0, y0+ny)]
                l = self.fig.axes[0].plot(vline[0], vline[1], 'k-', lw=.2)
                self._GRIDLINES.append(l)  # collecting reference to this line to be able to delete it


        if not enable:
            #print 'deleting lines...'
            if self._GRIDLINES:  # if lines were created
                #print 'lines are here...'
                for line in self._GRIDLINES:
                    #print line
                    l = line.pop(0)
                    l.remove()
                    del l
            self.fig.canvas.draw()

    def on_key_press(self, event):
        #print 'key pressed:', event.key
        if event.key == 'shift':
            self.shift_is_held = True


    

    def on_key_release(self, event):
        #print 'key released:', event.key
        if event.key == 'shift':
            self.shift_is_held = False

        elif event.key == 'escape':
            self.clear_selection()


    def change_coordinate_formatter(self, ax, data2d,  bruteforce_flag=None, bruteforce_dims=None):
        ''' see http://stackoverflow.com/questions/14754931/matplotlib-values-under-cursor
        '''
        numrows, numcols = data2d.shape
        bruteforce_mode_on = False
        bruteforce_mode_on = (bruteforce_flag == '2DXY' and bruteforce_dims[-1] and bruteforce_dims[-2])


        def format_coord(x, y):
            col = int(x+0.5)
            row = int(y+0.5)

            if not bruteforce_mode_on:
                if col >= 0 and col < numcols and row >= 0 and row < numrows:
                    #z = data2d[row, col]
                    # sice we have artificially reversed y-coordinate axes, now reverse data!
                    # numrows-1, because if nrows=10 => row=[0:9]
                    z = data2d[numrows-1-row, col]
                    #return 'x=%1.1f y=%1.1f z=%1.6f' % (x, y, z)
                    return 'i=%d j=%d z=%.6f' % (col, row, z)
                else:
                    #return 'x=%1.4f, y=%1.4f' % (x, y)
                    return 'outside data area'

            elif bruteforce_flag == '2DXY' and bruteforce_dims[-1] and bruteforce_dims[-2]:
                '''
                our extend in X=[-0.5:numcols-0.5], Y=[-0.5:numrows-0.5], because col,row is cell center!
                '''
                if col >= 0 and col < numcols and row >= 0 and row < numrows:
                    #z = data2d[row, col]
                    # sice we have artificially reversed y-coordinate axes, now reverse data!
                    # numrows-1, because if nrows=10 => row=[0:9]
                    z = data2d[numrows-1-row, col]
                    real_x, real_y = self.get_real_xy(x, y, bruteforce_dims)

                    #return 'x=%1.1f y=%1.1f z=%1.6f' % (x, y, z)
                    #return 'i=%d j=%d z=%.3f x=%.4f y=%.4f' % (col, row, z, real_x, real_y)
                    return 'i=%d j=%d z=%.3f, %s=%.2f %s=%.2f' % (
                        col, row, z, bruteforce_dims[-1], real_x, bruteforce_dims[-2], real_y)
                else:
                    #return 'x=%1.4f, y=%1.4f' % (x, y)
                    return 'outside data area'
            else:
                raise ValueError('bruteforce_flag can be $None$ or $"2DXY"$. Passed %s' % bruteforce_flag)
        ax.format_coord = format_coord


    def allow_menu(self):
        allow = False
        #print "self.mainWidget.get_plotType():", self.mainWidget.get_plotType()
        #print "self.mainWidget.get_plotType_for_timeseries():", self.mainWidget.get_plotType_for_timeseries()
        if self.mainWidget.get_plotType() == "2D" and not self.mainWidget.get_plotType_for_timeseries() == "2DZT":
            allow = True
        return allow
    

    def get_real_xy(self, i, j, dimension_list):
        '''
        functions returns values of x,y based on passed indexes i, j

        '''
        if any(dimension_list[-2:-1]) is None:
            print 'Dimensions X,Y of current variable are not specified (variables that have same name as dimensions not found)'
            raise ValueError('Dimensions X,Y of current variable are not specified (variables that have same name as dimensions not found)')
        nc = self.mainWidget.get_selected_ncfile_instance()
        try:
            x_var = nc.variables[dimension_list[-1]]
            y_var = nc.variables[dimension_list[-2]]
            
        except:
            
            print ('Failed to load variables: {0}, {1}'.format(dimension_list[-1], dimension_list[-2]))
            raise ValueError('Failed to load variables: {0}, {1}'.format(dimension_list[-1], dimension_list[-2]))


        x_ratio = (x_var[-1]-x_var[0])/(len(x_var)-1)
        y_ratio = (y_var[-1]-y_var[0])/(len(y_var)-1)

        #x[i] = x_var[0]+x_ratio*i
        #y[j] = y_var[0]+y_ratio*j
        x = x_var[0] + x_ratio*i
        y = y_var[0] + y_ratio*j
        nc.close()
        return (x, y)

    def get_axes(self):
        return self.fig.get_axes()
    

    def fast_redraw(self, artist):
        background = [self.canvas.copy_from_bbox(self.get_axes()[0].bbox)]
        self.get_axes()[0].draw_artist(artist)
        self.canvas.restore_region(background)
        self.canvas.blit(self.get_axes()[0].bbox)
        self.canvas.update()
        self.canvas.flush_events()