예제 #1
0
파일: _matplot.py 프로젝트: Amberimzyj/UI
class Matplot(object):
    def __init__(self):
        # 新建一个Figure
        self.figure = Figure()
        # 将Figure转换为Qt4 Widget控件以便插入Qt4界面
        self.canvas = FigureCanvas(self.figure)


    def _change(self, _list1,_list2,_list3):
        # self.figure.clear()
       
        self.x = range(100)
        # y = [100]*100
        # y = [0]*100
        
        self.ax.clear()
        self.ax.plot(self.x,_list1,"y-",linewidth=3,label='Light(lx)')
        self.ax.plot(self.x,_list2,"m-",linewidth=3,label='Tempure(℃)')
        self.ax.plot(self.x,_list3,"c-",linewidth=3,label='Humid(%RH)')
        
        
        #设置图例
        self.ax.legend(loc='upperright')   #   显示图例,loc设置图例位置
        # ax.set_subplots_adjust(bottom = 0.15) 
        

        # self.ax.show()

        # self.figure.suptitle("F3 fata diagram")

        self.canvas.draw()

    def set_diagram(self,n):
        
        
        self.ax = self.figure.add_subplot(111)
        #设置坐标轴范围
        self.ax.set_xlim((0, 110))
        self.ax.set_ylim((0, 150))

        #设置坐标轴刻度
        my_x_ticks = np.arange(0,110, 10)
        my_y_ticks = np.arange(0, 150, 10)

        ymajorLocator   = MultipleLocator(10)
        self.ax.set_xticks(my_x_ticks)
        self.figure.gca().invert_xaxis()
        # self.figure.gca().invert_xticks()
        self.ax.set_yticks(my_y_ticks)
        self.ax.yaxis.set_major_locator(ymajorLocator)
        self.ax.set_xticklabels(('220s','200s','180s','160s','140s','120s','100s','80s','60s','40s','20s'))

        self.figure.subplots_adjust(left=0.05, bottom=0.07, right=0.97, top=0.93,hspace=0.2, wspace=0.2)
        self.ax.set_title('F'+str(n)+'节点数据折线图',fontproperties='SimHei',fontsize=14)
        self.canvas.draw()
예제 #2
0
class MathTextLabel(QWidget):
    def __init__(self,
                 parent=None,
                 math_text=None,
                 horizontalalignment='left',
                 verticalalignment='top',
                 **kwargs):
        QWidget.__init__(self, parent, **kwargs)

        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        r, g, b, a = self.palette().base().color().getRgbF()

        self._figure = Figure(edgecolor=(r, g, b), facecolor=(r, g, b))
        self._canvas = FigureCanvas(self._figure)

        layout.addWidget(self._canvas)

        self._figure.clear()
        self._display_text = self._figure.suptitle(
            math_text,
            x=0.0,
            y=1.0,
            horizontalalignment=horizontalalignment,
            verticalalignment=verticalalignment,
            size=QApplication.font().pointSize() * 2)
        self._canvas.draw()

        (x0, y0), (x1,
                   y1) = self._display_text.get_window_extent().get_points()
        w = x1 - x0
        h = y1 - y0

        self._figure.set_size_inches(w / 80, h / 80)
        self.setFixedSize(w, h)

    def set_math_text(self, math_text):
        self._display_text.set_text(math_text)
        self._canvas.draw_idle()
예제 #3
0
class CalibrationViewer(QtGui.QMainWindow):
    trialsChanged = QtCore.pyqtSignal()

    def __init__(self):
        self.filters = list()
        super(CalibrationViewer, self).__init__()
        self.setWindowTitle('Olfa Calibration')
        self.statusBar()
        self.trial_selected_list = []
        self.trialsChanged.connect(self._trial_selection_changed)

        mainwidget = QtGui.QWidget(self)
        self.setCentralWidget(mainwidget)
        layout = QtGui.QGridLayout(mainwidget)
        mainwidget.setLayout(layout)

        menu = self.menuBar()
        filemenu = menu.addMenu("&File")
        toolsmenu = menu.addMenu("&Tools")

        openAction = QtGui.QAction("&Open recording...", self)
        openAction.triggered.connect(self._openAction_triggered)
        openAction.setStatusTip("Open a HDF5 data file with calibration recording.")
        openAction.setShortcut("Ctrl+O")
        filemenu.addAction(openAction)
        saveFigsAction = QtGui.QAction('&Save figures...', self)
        saveFigsAction.triggered.connect(self._saveFiguresAction_triggered)
        saveFigsAction.setShortcut('Ctrl+S')
        openAction.setStatusTip("Saves current figures.")
        filemenu.addAction(saveFigsAction)
        exitAction = QtGui.QAction("&Quit", self)
        exitAction.setShortcut("Ctrl+Q")
        exitAction.setStatusTip("Quit program.")
        exitAction.triggered.connect(QtGui.qApp.quit)
        filemenu.addAction(exitAction)
        removeTrialAction = QtGui.QAction("&Remove trials", self)
        removeTrialAction.setStatusTip('Permanently removes selected trials (bad trials) from trial list.')
        removeTrialAction.triggered.connect(self._remove_trials)
        removeTrialAction.setShortcut('Ctrl+R')
        toolsmenu.addAction(removeTrialAction)

        trial_group_list_box = QtGui.QGroupBox()
        trial_group_list_box.setTitle('Trial Groups')
        self.trial_group_list = TrialGroupListWidget()
        trial_group_layout = QtGui.QVBoxLayout()
        trial_group_list_box.setLayout(trial_group_layout)
        trial_group_layout.addWidget(self.trial_group_list)
        layout.addWidget(trial_group_list_box, 0, 0)
        self.trial_group_list.itemSelectionChanged.connect(self._trial_group_selection_changed)

        trial_select_list_box = QtGui.QGroupBox()
        trial_select_list_box.setMouseTracking(True)
        trial_select_list_layout = QtGui.QVBoxLayout()
        trial_select_list_box.setLayout(trial_select_list_layout)
        trial_select_list_box.setTitle('Trials')
        self.trial_select_list = TrialListWidget()
        self.trial_select_list.setMouseTracking(True)
        trial_select_list_layout.addWidget(self.trial_select_list)
        self.trial_select_list.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.trial_select_list.itemSelectionChanged.connect(self._trial_selection_changed)
        layout.addWidget(trial_select_list_box, 0, 1)
        self.trial_select_list.createGroupSig.connect(self.trial_group_list.create_group)

        filters_box = QtGui.QGroupBox("Trial filters.")
        filters_box_layout = QtGui.QVBoxLayout(filters_box)
        filters_scroll_area = QtGui.QScrollArea()
        filters_buttons = QtGui.QHBoxLayout()
        filters_all = QtGui.QPushButton('Select all', self)
        filters_all.clicked.connect(self._select_all_filters)
        filters_none = QtGui.QPushButton('Select none', self)
        filters_none.clicked.connect(self._select_none_filters)
        filters_buttons.addWidget(filters_all)
        filters_buttons.addWidget(filters_none)
        filters_box_layout.addLayout(filters_buttons)
        filters_box_layout.addWidget(filters_scroll_area)
        filters_wid = QtGui.QWidget()
        filters_scroll_area.setWidget(filters_wid)
        filters_scroll_area.setWidgetResizable(True)
        filters_scroll_area.setFixedWidth(300)
        self.filters_layout = QtGui.QVBoxLayout()
        filters_wid.setLayout(self.filters_layout)
        layout.addWidget(filters_box, 0, 2)

        plots_box = QtGui.QGroupBox()
        plots_box.setTitle('Plots')
        plots_layout = QtGui.QHBoxLayout()

        self.figure = Figure((9, 5))
        self.figure.patch.set_facecolor('None')
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setParent(plots_box)
        self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        plots_layout.addWidget(self.canvas)
        plots_box.setLayout(plots_layout)
        layout.addWidget(plots_box, 0, 3)
        self.ax_pid = self.figure.add_subplot(2, 1, 1)
        self.ax_pid.set_title('PID traces')
        self.ax_pid.set_ylabel('')
        self.ax_pid.set_xlabel('t (ms)')
        # self.ax_pid.set_yscale('log')
        self.ax_mean_plots = self.figure.add_subplot(2, 1, 2)
        self.ax_mean_plots.set_title('Mean value')
        self.ax_mean_plots.set_ylabel('value')
        self.ax_mean_plots.set_xlabel('Concentration')
        self.ax_mean_plots.autoscale(enable=True, axis=u'both', tight=False)
        self.figure.tight_layout()

    @QtCore.pyqtSlot()
    def _list_context_menu_trig(self):
        pass

    @QtCore.pyqtSlot()
    def _filters_changed(self):
        mask = np.ones_like(self.trial_mask)
        for v in self.filters:
            mask *= v.trial_mask
        self.trial_mask = mask
        self.trial_select_list.itemSelectionChanged.disconnect(self._trial_selection_changed)
        for i in xrange(len(self.trial_mask)):
            hide = not self.trial_mask[i]
            it = self.trial_select_list.item(i)
            it.setHidden(hide)
            select = it.isSelected() * self.trial_mask[i]
            it.setSelected(select)
        self.trial_select_list.itemSelectionChanged.connect(self._trial_selection_changed)
        self.trial_select_list.itemSelectionChanged.emit()  # emit that something changed so that we redraw.

    @QtCore.pyqtSlot()
    def _openAction_triggered(self):
        filedialog = QtGui.QFileDialog(self)
        if os.path.exists('D:\\experiment\\raw_data'):
            startpath = 'D:\\experiment\\raw_data\\mouse_o_cal_cw\\sess_001'
        else:
            startpath = ''
        fn = filedialog.getOpenFileName(self, "Select a data file.", startpath, "HDF5 (*.h5)")
        if fn:
            data = CalibrationFile(str(fn))
            self.data = data
            self.trial_actions = []
            trial_num_list = []
            self.trial_select_list.clear()
            trials = self.data.trials
            for i, t in enumerate(trials):
                tstr = "Trial {0}".format(i)
                it = QtGui.QListWidgetItem(tstr, self.trial_select_list)
                # trial = trials[i]
                # odor = trial['odor']
                # vialconc = trial['vialconc']
                # odorconc = trial['odorconc']
                # dilution = 1000 - trial['dilution'][0]
                # trst = 'Odor: {0}, vialconc: {1}, odorconc: {2}, dilution: {3}'.format(odor, vialconc, odorconc,
                #                                                                        dilution)
                # it.setStatusTip(trst)
                trial_num_list.append(i)
            self.trial_select_list.trial_num_list = np.array(trial_num_list)
            self.trial_mask = np.ones(len(self.trial_select_list.trial_num_list), dtype=bool)
            self.build_filters(trials)
        else:
            print('No file selected.')
        return

    def build_filters(self, trials):
        while self.filters_layout.itemAt(0):
            self.filters_layout.takeAt(0)
        if self.filters:
            for f in self.filters:
                f.deleteLater()
        self.filters = list()
        colnames = trials.dtype.names
        if 'odorconc' not in colnames:
            self.error = QtGui.QErrorMessage()
            self.error.showMessage('Data file must have "odorconc" field to allow plotting.')
        start_strings = ('odorconc', 'olfas', 'dilutors')
        filter_fields = []
        for ss in start_strings:
            for fieldname in colnames:
                if fieldname.startswith(ss):
                    filter_fields.append(fieldname)

        for field in filter_fields:
            filter = FiltersListWidget(field)
            filter.populate_list(self.data.trials)
            filter.setVisible(False)
            self.filters.append(filter)
            box = QtGui.QWidget()
            box.setSizePolicy(0, 0)
            # box.setTitle(filter.fieldname)
            show_button = QtGui.QPushButton(filter.fieldname)
            show_button.setStyleSheet('text-align:left; border:0px')
            show_button.clicked.connect(filter.toggle_visible)
            _filt_layout = QtGui.QVBoxLayout(box)
            _filt_layout.addWidget(show_button)
            _filt_layout.addWidget(filter)
            _filt_layout.setSpacing(0)
            self.filters_layout.addWidget(box)
            filter.filterChanged.connect(self._filters_changed)
        for v in self.filters:
            assert isinstance(v, FiltersListWidget)

        # self.filters_layout.addWidget(QtGui.QSpacerItem())
        self.filters_layout.addStretch()
        self.filters_layout.setSpacing(0)

        return

    @QtCore.pyqtSlot()
    def _saveFiguresAction_triggered(self):
        # TODO: add figure saving functionality with filedialog.getSaveFileName.
        self.saveDialog = QtGui.QFileDialog()
        saveloc = self.saveDialog.getSaveFileName(self, 'Save figure', '', 'PDF (*.pdf);;JPEG (*.jpg);;TIFF (*.tif)')
        saveloc = str(saveloc)
        self.figure.savefig(saveloc)

    @QtCore.pyqtSlot()
    def _remove_trials(self):
        selected_idxes = self.trial_select_list.selectedIndexes()
        remove_idxes = []
        for id in selected_idxes:
            idx = id.row()
            remove_idxes.append(idx)
        while self.trial_select_list.selectedIndexes():
            selected_idxes = self.trial_select_list.selectedIndexes()
            idx = selected_idxes[0].row()
            self.trial_select_list.takeItem(idx)
        new_trials_array = np.zeros(len(self.trial_select_list.trial_num_list)-len(remove_idxes), dtype=np.int)
        ii = 0
        remove_trialnums = []
        new_trials_mask = np.zeros_like(new_trials_array, dtype=bool)
        for i in xrange(len(self.trial_select_list.trial_num_list)):
            if i not in remove_idxes:
                new_trials_mask[ii] = self.trial_mask[i]
                new_trials_array[ii] = self.trial_select_list.trial_num_list[i]
                ii += 1
            else:
                remove_trialnums.append(self.trial_select_list.trial_num_list[i])
        self.trial_mask = new_trials_mask
        self.trial_select_list.trial_num_list = new_trials_array

        for f in self.filters:
            f.remove_trials(remove_idxes)
        self.trial_group_list._remove_trials(remove_trialnums)

    @QtCore.pyqtSlot()
    def _trial_selection_changed(self):
        selected_idxes = self.trial_select_list.selectedIndexes()
        selected_trial_nums = []
        for id in selected_idxes:
            idx = id.row()
            trialnum = self.trial_select_list.trial_num_list[idx]
            selected_trial_nums.append(trialnum)
        self.update_plots(selected_trial_nums)
        self.trial_group_list.blockSignals(True)
        for i, g in zip(xrange(self.trial_group_list.count()), self.trial_group_list.trial_groups):
            it = self.trial_group_list.item(i)
            all_in = True
            group_trials = g['trial_nums']
            for t in group_trials:
                if t not in selected_trial_nums:
                    all_in = False
            if not all_in:
                it.setSelected(False)
            elif all_in:
                it.setSelected(True)
        self.trial_group_list.blockSignals(False)
        return

    @QtCore.pyqtSlot()
    def _trial_group_selection_changed(self):
        selected_idxes = self.trial_group_list.selectedIndexes()
        self._select_all_filters()
        selected_trial_nums = []
        for id in selected_idxes:
            idx = id.row()
            trialnums = self.trial_group_list.trial_groups[idx]['trial_nums']
            selected_trial_nums.extend(trialnums)
        self.trial_select_list.blockSignals(True)
        for i in range(self.trial_select_list.count()):
            item = self.trial_select_list.item(i)
            self.trial_select_list.setItemSelected(item, False)
        for i in selected_trial_nums:
            idx = np.where(self.trial_select_list.trial_num_list == i)[0][0]
            it = self.trial_select_list.item(idx)
            if not it.isSelected():
                it.setSelected(True)
        self.trial_select_list.blockSignals(False)
        self._trial_selection_changed()

    def update_plots(self, trials):
        padding = (2000, 2000)  #TODO: make this changable - this is the number of ms before/afterr trial to extract for stream.
        trial_streams = []
        trial_colors = []
        while self.ax_pid.lines:
            self.ax_pid.lines.pop(0)
        while self.ax_mean_plots.lines:
            self.ax_mean_plots.lines.pop(0)
        groups_by_trial = []
        all_groups = set()
        ntrials = len(trials)
        vals = np.empty(ntrials)
        concs = np.empty_like(vals)
        if trials:
            a = max([1./len(trials), .25])
            for i, tn in enumerate(trials):
                color = self.trial_group_list.get_trial_color(tn)
                groups = self.trial_group_list.get_trial_groups(tn)
                trial_colors.append(color)
                groups_by_trial.append(groups)
                all_groups.update(groups)
                trial = self.data.return_trial(tn, padding=padding)
                stream = remove_stream_trend(trial.streams['sniff'], (0, padding[0]))
                stream -= stream[0:padding[0]].min()
                # TODO: remove baseline (N2) trial average from this.
                trial_streams.append(stream)
                self.ax_pid.plot(stream, color=color, alpha=a)
                conc = trial.trials['odorconc']
                baseline = np.mean(stream[:2000])
                val = np.mean(stream[3000:4000]) - baseline
                vals[i] = val
                concs[i] = conc
                self.ax_mean_plots.plot(conc, val, '.', color=color)
        minlen = 500000000
        for i in trial_streams:
            minlen = min(len(i), minlen)
        streams_array = np.empty((ntrials, minlen))
        for i in xrange(ntrials):
            streams_array[i, :] = trial_streams[i][:minlen]
        for g in all_groups:
            mask = np.empty(ntrials, dtype=bool)
            for i in xrange(ntrials):
                groups = groups_by_trial[i]
                mask[i] = g in groups
            c = concs[mask]
            groupstreams = streams_array[mask]
            if len(np.unique(c)) < 2:
                self.ax_pid.plot(groupstreams.mean(axis=0), color='k', linewidth=2)
            else:
                v = vals[mask]
                a, b, _, _, _ = stats.linregress(c, v)
                color = self.trial_group_list.get_group_color(g)
                minn, maxx = self.ax_mean_plots.get_xlim()
                x = np.array([minn, maxx])
                self.ax_mean_plots.plot(x, a*x + b, color=color)
        self.ax_pid.relim()
        self.ax_mean_plots.set_yscale('log')
        self.ax_mean_plots.set_xscale('log')
        self.ax_mean_plots.relim()

        self.canvas.draw()

    @QtCore.pyqtSlot()
    def _select_none_filters(self):
        for filter in self.filters:
            filter.filterChanged.disconnect(self._filters_changed)
            filter.clearSelection()
            filter.filterChanged.connect(self._filters_changed)
        self._filters_changed()

    @QtCore.pyqtSlot()
    def _select_all_filters(self):
        for filter in self.filters:
            filter.filterChanged.disconnect(self._filters_changed)
            filter.selectAll()
            filter.filterChanged.connect(self._filters_changed)
        self._filters_changed()
예제 #4
0
class CalibrationViewer(QtGui.QMainWindow):
    trialsChanged = QtCore.pyqtSignal()

    def __init__(self):
        self.filters = list()
        super(CalibrationViewer, self).__init__()
        self.setWindowTitle('Olfa Calibration')
        self.statusBar()
        self.trial_selected_list = []
        self.trialsChanged.connect(self._trial_selection_changed)

        mainwidget = QtGui.QWidget(self)
        self.setCentralWidget(mainwidget)
        layout = QtGui.QGridLayout(mainwidget)
        mainwidget.setLayout(layout)

        menu = self.menuBar()
        filemenu = menu.addMenu("&File")
        toolsmenu = menu.addMenu("&Tools")

        openAction = QtGui.QAction("&Open recording...", self)
        openAction.triggered.connect(self._openAction_triggered)
        openAction.setStatusTip(
            "Open a HDF5 data file with calibration recording.")
        openAction.setShortcut("Ctrl+O")
        filemenu.addAction(openAction)
        saveFigsAction = QtGui.QAction('&Save figures...', self)
        saveFigsAction.triggered.connect(self._saveFiguresAction_triggered)
        saveFigsAction.setShortcut('Ctrl+S')
        openAction.setStatusTip("Saves current figures.")
        filemenu.addAction(saveFigsAction)
        exitAction = QtGui.QAction("&Quit", self)
        exitAction.setShortcut("Ctrl+Q")
        exitAction.setStatusTip("Quit program.")
        exitAction.triggered.connect(QtGui.qApp.quit)
        filemenu.addAction(exitAction)
        removeTrialAction = QtGui.QAction("&Remove trials", self)
        removeTrialAction.setStatusTip(
            'Permanently removes selected trials (bad trials) from trial list.'
        )
        removeTrialAction.triggered.connect(self._remove_trials)
        removeTrialAction.setShortcut('Ctrl+R')
        toolsmenu.addAction(removeTrialAction)

        trial_group_list_box = QtGui.QGroupBox()
        trial_group_list_box.setTitle('Trial Groups')
        self.trial_group_list = TrialGroupListWidget()
        trial_group_layout = QtGui.QVBoxLayout()
        trial_group_list_box.setLayout(trial_group_layout)
        trial_group_layout.addWidget(self.trial_group_list)
        layout.addWidget(trial_group_list_box, 0, 0)
        self.trial_group_list.itemSelectionChanged.connect(
            self._trial_group_selection_changed)

        trial_select_list_box = QtGui.QGroupBox()
        trial_select_list_box.setMouseTracking(True)
        trial_select_list_layout = QtGui.QVBoxLayout()
        trial_select_list_box.setLayout(trial_select_list_layout)
        trial_select_list_box.setTitle('Trials')
        self.trial_select_list = TrialListWidget()
        self.trial_select_list.setMouseTracking(True)
        trial_select_list_layout.addWidget(self.trial_select_list)
        self.trial_select_list.setSelectionMode(
            QtGui.QAbstractItemView.ExtendedSelection)
        self.trial_select_list.itemSelectionChanged.connect(
            self._trial_selection_changed)
        layout.addWidget(trial_select_list_box, 0, 1)
        self.trial_select_list.createGroupSig.connect(
            self.trial_group_list.create_group)

        filters_box = QtGui.QGroupBox("Trial filters.")
        filters_box_layout = QtGui.QVBoxLayout(filters_box)
        filters_scroll_area = QtGui.QScrollArea()
        filters_buttons = QtGui.QHBoxLayout()
        filters_all = QtGui.QPushButton('Select all', self)
        filters_all.clicked.connect(self._select_all_filters)
        filters_none = QtGui.QPushButton('Select none', self)
        filters_none.clicked.connect(self._select_none_filters)
        filters_buttons.addWidget(filters_all)
        filters_buttons.addWidget(filters_none)
        filters_box_layout.addLayout(filters_buttons)
        filters_box_layout.addWidget(filters_scroll_area)
        filters_wid = QtGui.QWidget()
        filters_scroll_area.setWidget(filters_wid)
        filters_scroll_area.setWidgetResizable(True)
        filters_scroll_area.setFixedWidth(300)
        self.filters_layout = QtGui.QVBoxLayout()
        filters_wid.setLayout(self.filters_layout)
        layout.addWidget(filters_box, 0, 2)

        plots_box = QtGui.QGroupBox()
        plots_box.setTitle('Plots')
        plots_layout = QtGui.QHBoxLayout()

        self.figure = Figure((9, 5))
        self.figure.patch.set_facecolor('None')
        self.canvas = FigureCanvas(self.figure)
        self.canvas.setParent(plots_box)
        self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,
                                  QtGui.QSizePolicy.Expanding)
        plots_layout.addWidget(self.canvas)
        plots_box.setLayout(plots_layout)
        layout.addWidget(plots_box, 0, 3)
        self.ax_pid = self.figure.add_subplot(2, 1, 1)
        self.ax_pid.set_title('PID traces')
        self.ax_pid.set_ylabel('')
        self.ax_pid.set_xlabel('t (ms)')
        # self.ax_pid.set_yscale('log')
        self.ax_mean_plots = self.figure.add_subplot(2, 1, 2)
        self.ax_mean_plots.set_title('Mean value')
        self.ax_mean_plots.set_ylabel('value')
        self.ax_mean_plots.set_xlabel('Concentration')
        self.ax_mean_plots.autoscale(enable=True, axis=u'both', tight=False)
        self.figure.tight_layout()

    @QtCore.pyqtSlot()
    def _list_context_menu_trig(self):
        pass

    @QtCore.pyqtSlot()
    def _filters_changed(self):
        mask = np.ones_like(self.trial_mask)
        for v in self.filters:
            mask *= v.trial_mask
        self.trial_mask = mask
        self.trial_select_list.itemSelectionChanged.disconnect(
            self._trial_selection_changed)
        for i in xrange(len(self.trial_mask)):
            hide = not self.trial_mask[i]
            it = self.trial_select_list.item(i)
            it.setHidden(hide)
            select = it.isSelected() * self.trial_mask[i]
            it.setSelected(select)
        self.trial_select_list.itemSelectionChanged.connect(
            self._trial_selection_changed)
        self.trial_select_list.itemSelectionChanged.emit(
        )  # emit that something changed so that we redraw.

    @QtCore.pyqtSlot()
    def _openAction_triggered(self):
        filedialog = QtGui.QFileDialog(self)
        if os.path.exists('D:\\experiment\\raw_data'):
            startpath = 'D:\\experiment\\raw_data\\mouse_o_cal_cw\\sess_001'
        else:
            startpath = ''
        fn = filedialog.getOpenFileName(self, "Select a data file.", startpath,
                                        "HDF5 (*.h5)")
        if fn:
            data = CalibrationFile(str(fn))
            self.data = data
            self.trial_actions = []
            trial_num_list = []
            self.trial_select_list.clear()
            trials = self.data.trials
            for i, t in enumerate(trials):
                tstr = "Trial {0}".format(i)
                it = QtGui.QListWidgetItem(tstr, self.trial_select_list)
                # trial = trials[i]
                # odor = trial['odor']
                # vialconc = trial['vialconc']
                # odorconc = trial['odorconc']
                # dilution = 1000 - trial['dilution'][0]
                # trst = 'Odor: {0}, vialconc: {1}, odorconc: {2}, dilution: {3}'.format(odor, vialconc, odorconc,
                #                                                                        dilution)
                # it.setStatusTip(trst)
                trial_num_list.append(i)
            self.trial_select_list.trial_num_list = np.array(trial_num_list)
            self.trial_mask = np.ones(len(
                self.trial_select_list.trial_num_list),
                                      dtype=bool)
            self.build_filters(trials)
        else:
            print('No file selected.')
        return

    def build_filters(self, trials):
        while self.filters_layout.itemAt(0):
            self.filters_layout.takeAt(0)
        if self.filters:
            for f in self.filters:
                f.deleteLater()
        self.filters = list()
        colnames = trials.dtype.names
        if 'odorconc' not in colnames:
            self.error = QtGui.QErrorMessage()
            self.error.showMessage(
                'Data file must have "odorconc" field to allow plotting.')
        start_strings = ('odorconc', 'olfas', 'dilutors')
        filter_fields = []
        for ss in start_strings:
            for fieldname in colnames:
                if fieldname.startswith(ss):
                    filter_fields.append(fieldname)

        for field in filter_fields:
            filter = FiltersListWidget(field)
            filter.populate_list(self.data.trials)
            filter.setVisible(False)
            self.filters.append(filter)
            box = QtGui.QWidget()
            box.setSizePolicy(0, 0)
            # box.setTitle(filter.fieldname)
            show_button = QtGui.QPushButton(filter.fieldname)
            show_button.setStyleSheet('text-align:left; border:0px')
            show_button.clicked.connect(filter.toggle_visible)
            _filt_layout = QtGui.QVBoxLayout(box)
            _filt_layout.addWidget(show_button)
            _filt_layout.addWidget(filter)
            _filt_layout.setSpacing(0)
            self.filters_layout.addWidget(box)
            filter.filterChanged.connect(self._filters_changed)
        for v in self.filters:
            assert isinstance(v, FiltersListWidget)

        # self.filters_layout.addWidget(QtGui.QSpacerItem())
        self.filters_layout.addStretch()
        self.filters_layout.setSpacing(0)

        return

    @QtCore.pyqtSlot()
    def _saveFiguresAction_triggered(self):
        # TODO: add figure saving functionality with filedialog.getSaveFileName.
        self.saveDialog = QtGui.QFileDialog()
        saveloc = self.saveDialog.getSaveFileName(
            self, 'Save figure', '', 'PDF (*.pdf);;JPEG (*.jpg);;TIFF (*.tif)')
        saveloc = str(saveloc)
        self.figure.savefig(saveloc)

    @QtCore.pyqtSlot()
    def _remove_trials(self):
        selected_idxes = self.trial_select_list.selectedIndexes()
        remove_idxes = []
        for id in selected_idxes:
            idx = id.row()
            remove_idxes.append(idx)
        while self.trial_select_list.selectedIndexes():
            selected_idxes = self.trial_select_list.selectedIndexes()
            idx = selected_idxes[0].row()
            self.trial_select_list.takeItem(idx)
        new_trials_array = np.zeros(
            len(self.trial_select_list.trial_num_list) - len(remove_idxes),
            dtype=np.int)
        ii = 0
        remove_trialnums = []
        new_trials_mask = np.zeros_like(new_trials_array, dtype=bool)
        for i in xrange(len(self.trial_select_list.trial_num_list)):
            if i not in remove_idxes:
                new_trials_mask[ii] = self.trial_mask[i]
                new_trials_array[ii] = self.trial_select_list.trial_num_list[i]
                ii += 1
            else:
                remove_trialnums.append(
                    self.trial_select_list.trial_num_list[i])
        self.trial_mask = new_trials_mask
        self.trial_select_list.trial_num_list = new_trials_array

        for f in self.filters:
            f.remove_trials(remove_idxes)
        self.trial_group_list._remove_trials(remove_trialnums)

    @QtCore.pyqtSlot()
    def _trial_selection_changed(self):
        selected_idxes = self.trial_select_list.selectedIndexes()
        selected_trial_nums = []
        for id in selected_idxes:
            idx = id.row()
            trialnum = self.trial_select_list.trial_num_list[idx]
            selected_trial_nums.append(trialnum)
        self.update_plots(selected_trial_nums)
        self.trial_group_list.blockSignals(True)
        for i, g in zip(xrange(self.trial_group_list.count()),
                        self.trial_group_list.trial_groups):
            it = self.trial_group_list.item(i)
            all_in = True
            group_trials = g['trial_nums']
            for t in group_trials:
                if t not in selected_trial_nums:
                    all_in = False
            if not all_in:
                it.setSelected(False)
            elif all_in:
                it.setSelected(True)
        self.trial_group_list.blockSignals(False)
        return

    @QtCore.pyqtSlot()
    def _trial_group_selection_changed(self):
        selected_idxes = self.trial_group_list.selectedIndexes()
        self._select_all_filters()
        selected_trial_nums = []
        for id in selected_idxes:
            idx = id.row()
            trialnums = self.trial_group_list.trial_groups[idx]['trial_nums']
            selected_trial_nums.extend(trialnums)
        self.trial_select_list.blockSignals(True)
        for i in range(self.trial_select_list.count()):
            item = self.trial_select_list.item(i)
            self.trial_select_list.setItemSelected(item, False)
        for i in selected_trial_nums:
            idx = np.where(self.trial_select_list.trial_num_list == i)[0][0]
            it = self.trial_select_list.item(idx)
            if not it.isSelected():
                it.setSelected(True)
        self.trial_select_list.blockSignals(False)
        self._trial_selection_changed()

    def update_plots(self, trials):
        padding = (
            2000, 2000
        )  #TODO: make this changable - this is the number of ms before/afterr trial to extract for stream.
        trial_streams = []
        trial_colors = []
        while self.ax_pid.lines:
            self.ax_pid.lines.pop(0)
        while self.ax_mean_plots.lines:
            self.ax_mean_plots.lines.pop(0)
        groups_by_trial = []
        all_groups = set()
        ntrials = len(trials)
        vals = np.empty(ntrials)
        concs = np.empty_like(vals)
        if trials:
            a = max([1. / len(trials), .25])
            for i, tn in enumerate(trials):
                color = self.trial_group_list.get_trial_color(tn)
                groups = self.trial_group_list.get_trial_groups(tn)
                trial_colors.append(color)
                groups_by_trial.append(groups)
                all_groups.update(groups)
                trial = self.data.return_trial(tn, padding=padding)
                stream = remove_stream_trend(trial.streams['sniff'],
                                             (0, padding[0]))
                stream -= stream[0:padding[0]].min()
                # TODO: remove baseline (N2) trial average from this.
                trial_streams.append(stream)
                self.ax_pid.plot(stream, color=color, alpha=a)
                conc = trial.trials['odorconc']
                baseline = np.mean(stream[:2000])
                val = np.mean(stream[3000:4000]) - baseline
                vals[i] = val
                concs[i] = conc
                self.ax_mean_plots.plot(conc, val, '.', color=color)
        minlen = 500000000
        for i in trial_streams:
            minlen = min(len(i), minlen)
        streams_array = np.empty((ntrials, minlen))
        for i in xrange(ntrials):
            streams_array[i, :] = trial_streams[i][:minlen]
        for g in all_groups:
            mask = np.empty(ntrials, dtype=bool)
            for i in xrange(ntrials):
                groups = groups_by_trial[i]
                mask[i] = g in groups
            c = concs[mask]
            groupstreams = streams_array[mask]
            if len(np.unique(c)) < 2:
                self.ax_pid.plot(groupstreams.mean(axis=0),
                                 color='k',
                                 linewidth=2)
            else:
                v = vals[mask]
                a, b, _, _, _ = stats.linregress(c, v)
                color = self.trial_group_list.get_group_color(g)
                minn, maxx = self.ax_mean_plots.get_xlim()
                x = np.array([minn, maxx])
                self.ax_mean_plots.plot(x, a * x + b, color=color)
        self.ax_pid.relim()
        self.ax_mean_plots.set_yscale('log')
        self.ax_mean_plots.set_xscale('log')
        self.ax_mean_plots.relim()

        self.canvas.draw()

    @QtCore.pyqtSlot()
    def _select_none_filters(self):
        for filter in self.filters:
            filter.filterChanged.disconnect(self._filters_changed)
            filter.clearSelection()
            filter.filterChanged.connect(self._filters_changed)
        self._filters_changed()

    @QtCore.pyqtSlot()
    def _select_all_filters(self):
        for filter in self.filters:
            filter.filterChanged.disconnect(self._filters_changed)
            filter.selectAll()
            filter.filterChanged.connect(self._filters_changed)
        self._filters_changed()