Ejemplo n.º 1
0
    def create_color_dialogs(self):

        d = self.domain_color_dialog = DomainColorSelector()
        d.domain_color_changed.connect(self.set_domain_color)
        self.domain_colors_changed.connect(d.set_domain_colors)

        # norm = self.options['image']['norms'][self.cuboid.value_label]
        # self.cmap_dialog = MplCmapEditor(self.cuboid.value_label,
        #                                  norm.vmin, norm.vmax)
        self.cmap_dialog = MplCmapEditor()
        self.cmap_dialog.range_value_changed.connect(self.set_normalize)
        self.cmap_dialog.cmap_changed.connect(self.set_cmap)
        self.value_label_changed.connect(self.cmap_dialog.set_value_label)
        self.norm_changed.connect(self.cmap_dialog.set_boundaries)

        scolor = self.options['curve']['single_color']
        self.single_color_dialog = QtGui.QColorDialog(QtGui.QColor(scolor))
        ssc = self.set_single_curve_color
        self.single_color_dialog.currentColorChanged.connect(ssc)
Ejemplo n.º 2
0
class xndarrayPlotter(QtGui.QWidget):

    domain_colors_changed = QtCore.pyqtSignal(str, dict,
                                              name='DomainColorsChanged')
    closing = QtCore.pyqtSignal(str, name='Closing')
    focus_in = QtCore.pyqtSignal(str, name='FocusIn')

    value_label_changed = QtCore.pyqtSignal(str, name='ValueLabelChanged')
    norm_changed = QtCore.pyqtSignal(float, float, name='NormChanged')


    def __init__(self, cuboid, slice_def, orientation, cuboid_name='data',
                 parent=None):

        QtGui.QWidget.__init__(self, parent)

        self.options = {
            'view_mode' : uib.IMAGE_MODE,
            'show_axes' : True,
            'show_axis_labels' : True,
            'image' : {
                'show_colorbar' : False,
                'show_mask' : False,
                'cmaps': {},
                'norms': {},
                },
            'curve': {
                'show_legend' : False,
                'colors':{},
                'single_color': uib.DEFAULT_COLORS[0],
                }
            }
        self.cuboid_name = cuboid_name

        self.file_name_hint = [self.cuboid_name + '.']

        self.setWindowTitle('xndarray plot')
        self.setFocusPolicy(QtCore.Qt.StrongFocus)
        self.create_main_frame()
        self.create_color_dialogs()

        self.set_new_cuboid(cuboid, slice_def, orientation)


    def set_new_cuboid(self, c, slice_def, orientation):
        """
        Set the current cuboid, slice definition and orientation
        """
        self.slice_def = slice_def.copy()
        self.cuboid = c
        self.orientation = orientation

        # def is_range_domain(d):
        #     if not np.issubsctype(d.dtype, str):
        #         delta = np.diff(d)
        #         return (delta == delta[0]).all()
        #     else:
        #         return False

        self.is_range_domain = dict((an, is_range_domain(d)) \
                                    for an,d in self.cuboid.axes_domains.items())

        if not self.options['image']['norms'].has_key(self.cuboid.value_label):
            self.options['image']['norms'][self.cuboid.value_label] = \
              Normalize(self.cuboid.min(), self.cuboid.max())

        self.value_label_changed.emit(self.cuboid.value_label)
        self.norm_changed.emit(self.cuboid.min(), self.cuboid.max())

        self.update_current_cuboid()
        self.on_draw()


    def set_slice(self, slice_def, orientation):

        print 'set_slice ...'
        print 'recieve slice_def:', id(slice_def)
        print slice_def
        print 'current slice def:', id(self.slice_def)
        print self.slice_def

        # check that something acctually changed:
        need_update = False
        for k,v in slice_def.iteritems():
            if self.slice_def.get(k, None) != v:
                need_update = True
                break
        if orientation != self.orientation:
            need_update = True

        if need_update:
            self.slice_def = slice_def.copy()
            self.orientation = orientation
            self.update_current_cuboid()
            self.on_draw()

    def update_current_cuboid(self):
        sdef = self.slice_def.copy()
        [sdef.pop(a, None) for a in self.orientation]
        sdef.pop(self.cuboid.value_label, None)
        self.current_cuboid = self.cuboid.sub_cuboid(**sdef)
        print 'current_cuboid:', self.current_cuboid
        if np.isscalar(self.current_cuboid):
            self.current_cuboid = xndarray(np.array([self.current_cuboid]),
                                         axes_names=[''])
            self.orientation = self.current_cuboid.axes_names
        self.current_cuboid.set_orientation(self.orientation)
        doms = self.current_cuboid.axes_domains
        self.current_domains = [doms[an] for an in self.orientation]
        self.file_name_hint[0] = '_'.join([self.cuboid_name] + \
            ['_'.join([k,str(v)]) for k,v in sdef.items()]) + '.'

        self.domain_colors_changed.emit(*self.get_current_domain_colors())

    def closeEvent(self, event):
        """
        Override cloveEvent to emit a signal just before the widget is actually
        closed.
        """
        self.closing.emit(self.cuboid_name)
        QtGui.QWidget.closeEvent(self, event)

    def focusInEvent(self, event):
        """
        Override focusInEvent to emit a signal just before the widget actually
        gains focus.
        """
        self.focus_in.emit(self.cuboid_name)
        QtGui.QWidget.focusInEvent(self, event)

    def on_mouse_clicked(self, event):
        uib.SliceEventDispatcher().dispatch(self.slice_def)

    def on_mouse_move(self, event):
        """
        Handle mouse move event. Update current slice definition according
        to the position of the mouse.
        """
        def get_dval_from_pos(pos, dom_idx):
            """
            Translate a plot position into a domain value from the domain
            defined by dom_idx
            Args:
                - pos (float): the plot coordinate
                - dom_idx (int): the index of the domain

            Return:
                DomainValue (float|string), value index (int)

            """
            if self.orientation[dom_idx] == '': #no dims
                return 0,0
            nb_dom_vals = len(self.current_domains[dom_idx])
            if self.is_range_domain[self.orientation[dom_idx]]:
                search_in = self.current_domains[dom_idx]
            else: #search by major tick position -> integers
                search_in = np.arange(nb_dom_vals)
            dv_ix = (np.abs(search_in-pos)).argmin()
            # ix = search_in.searchsorted([pos])[0]
            # dv_ix  = int(np.floor(search_in[min(ix,nb_dom_vals-1)]))
            return  self.current_domains[dom_idx][min(dv_ix,nb_dom_vals-1)],\
              dv_ix

        x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        if self.options['view_mode'] == uib.CURVE_MODE:
            if self.current_cuboid.get_ndims() == 1:
                #x axis is mapped to domain values of 1st axis
                dv, dv_idx = get_dval_from_pos(x, 0)
                self.slice_def[self.orientation[0]] = dv
                val = self.current_cuboid.data[dv_idx]
            else:
                #x axis is mapped to domain values of 2nd axis
                dv = get_dval_from_pos(x, 1)
                self.slice_def[self.orientation[1]] = dv
                val = 'N/A'

        elif self.options['view_mode'] == uib.IMAGE_MODE:
            #y axis is mapped to domain values of 1st axis
            dv, dv_i = get_dval_from_pos(y, 0)
            self.slice_def[self.orientation[0]] = dv
            if self.current_cuboid.get_ndims() == 1:
                val = self.current_cuboid.data[dv_i]
            elif self.current_cuboid.get_ndims() == 2:
                dv, dv_j = get_dval_from_pos(x, 1)
                self.slice_def[self.orientation[1]] = dv
                val = self.current_cuboid.data[dv_i, dv_j]

        self.slice_def[self.cuboid.value_label] = val
        slice_items = self.slice_def.items()
        info = ' '.join('%s:%s'%(an,uib.format_dval(dval)) \
                        for an,dval in slice_items)
        self.slice_info.setText(info)


    def on_draw(self):
        """
        Redraws the figure
        """
        print 'on_draw!!'
        print 'options show_colorbar:'
        print self.options['image']['show_colorbar']

        if pyhrf.verbose.verbosity > 5:
            pyhrf.verbose(6, 'on_draw ..., cubdoid: %s' %self.cuboid.descrip())

        # Clear axes and create new subplot
        #self.fig.delaxes(self.axes)
        self.fig.clear()
        self.axes = self.fig.add_subplot(111)

        #self.axes.clear()

        if self.options['view_mode'] == uib.IMAGE_MODE:
            options = self.options['image']
            print 'self.cuboid.value_label:', self.cuboid.value_label
            cm = options['cmaps'].get(self.cuboid.value_label)
            norm = options['norms'].get(self.cuboid.value_label)
            plot_cub_as_image(self.axes, self.current_cuboid, cmap=cm, norm=norm,
                              show_axis_labels=self.options['show_axis_labels'],
                              show_colorbar=options['show_colorbar'])

        else: #curve mode
            options = self.options['curve']
            single_curve_color = options['single_color']
            plot_cub_as_curve(self.axes, self.current_cuboid,
                              colors=self.get_current_domain_colors()[1],
                              show_legend=options['show_legend'],
                              show_axis_labels=self.options['show_axis_labels'],
                              plot_kwargs={'color':single_curve_color})

        if not self.options['show_axes']:
            self.axes.set_axis_off()

        self.canvas.draw()


    def get_current_domain_colors(self):
        d0 = self.current_domains[0]
        if not self.options['curve']['colors'].has_key(self.orientation[0]):
            dcols = dict(zip(d0, uib.get_default_color_list(len(d0))))
            self.options['curve']['colors'][self.orientation[0]] = dcols

        return (self.orientation[0],
                self.options['curve']['colors'][self.orientation[0]])


    def create_color_dialogs(self):

        d = self.domain_color_dialog = DomainColorSelector()
        d.domain_color_changed.connect(self.set_domain_color)
        self.domain_colors_changed.connect(d.set_domain_colors)

        # norm = self.options['image']['norms'][self.cuboid.value_label]
        # self.cmap_dialog = MplCmapEditor(self.cuboid.value_label,
        #                                  norm.vmin, norm.vmax)
        self.cmap_dialog = MplCmapEditor()
        self.cmap_dialog.range_value_changed.connect(self.set_normalize)
        self.cmap_dialog.cmap_changed.connect(self.set_cmap)
        self.value_label_changed.connect(self.cmap_dialog.set_value_label)
        self.norm_changed.connect(self.cmap_dialog.set_boundaries)

        scolor = self.options['curve']['single_color']
        self.single_color_dialog = QtGui.QColorDialog(QtGui.QColor(scolor))
        ssc = self.set_single_curve_color
        self.single_color_dialog.currentColorChanged.connect(ssc)


    def set_cmap(self, aname, cmap):
        self.options['image']['cmaps'][str(aname)] = cmap
        self.on_draw()

    def set_normalize(self, aname, min_val, max_val):
        self.options['image']['norms'][str(aname)] = Normalize(min_val, max_val)
        self.on_draw()

    def set_domain_color(self, aname, dval, color):
        self.options['curve']['colors'][str(aname)][dval] = color
        self.on_draw()

    def set_single_curve_color(self, color):
        self.options['curve']['single_color'] = uib.qcolor_to_mpl_rgb(color)
        self.on_draw()

    def create_main_frame(self):
        self.main_frame = self

        # Create the mpl Figure and FigCanvas objects.
        # 5x4 inches, 100 dots-per-inch
        #
        self.dpi = 100
        self.fig = Figure((5.0, 4.0), dpi=self.dpi)
        self.canvas = FigureCanvas(self.fig)
        self.canvas.setParent(self.main_frame)

        # Since we have only one plot, we can use add_axes
        # instead of add_subplot, but then the subplot
        # configuration tool in the navigation toolbar wouldn't
        # work.
        #
        self.axes = self.fig.add_subplot(111)

        self.canvas.mpl_connect('button_press_event', self.on_mouse_clicked)
        self.canvas.mpl_connect('motion_notify_event', self.on_mouse_move)

        # Create the navigation toolbar, tied to the canvas
        #
        self.mpl_toolbar = NavigationToolbar(self.canvas, self.main_frame)
        self.mpl_toolbar.set_default_save_name(self.file_name_hint)

        # Other GUI controls
        #
        # self.textbox = QtGui.QLineEdit()
        # self.textbox.setMinimumWidth(200)
        # self.textbox.editingFinished.connect(self.on_draw)

        self.toolbar = PlotterToolbar(self.options, parent=self)
        #self.toolbar.option_changed.connect(self.set_option)
        #self.toolbar.color_button_clicked.connect(self.show_color_dialog)
        #
        # Layout with box sizers
        #
        hbox = QtGui.QHBoxLayout()
        hbox.addWidget(self.toolbar)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.canvas)
        vbox.addWidget(self.mpl_toolbar)

        self.top = QtGui.QFrame(self)
        self.top.setLayout(vbox)

        self.bottom = QtGui.QFrame(self)
        self.bottom.setLayout(hbox)

        self.splitter = QtGui.QSplitter(QtCore.Qt.Vertical)

        self.splitter.addWidget(self.top)
        self.splitter.addWidget(self.bottom)
        #vbox.addWidget()
        #vbox.addLayout(hbox)
        #self.main_frame.addWidget(splitter)
        self.mainbox = QtGui.QVBoxLayout()
        self.mainbox.addWidget(self.splitter)
        self.slice_info = QtGui.QLabel('')
        self.mainbox.addWidget(self.slice_info)
        self.main_frame.setLayout(self.mainbox)
        #self.setCentralWidget(self.main_frame)

    def show_color_dialog(self):
        if self.options['view_mode'] == uib.IMAGE_MODE:
            self.domain_color_dialog.hide()
            self.single_color_dialog.hide()
            self.cmap_dialog.show()
        if self.options['view_mode'] == uib.CURVE_MODE:
            self.cmap_dialog.hide()
            if len(self.orientation) == 1:
                self.domain_color_dialog.hide()
                self.single_color_dialog.show()
            else: #2D
                self.domain_color_dialog.show()
                self.single_color_dialog.hide()


    def switch_color_dialog(self):
        if self.domain_color_dialog.isVisible() or \
            self.single_color_dialog.isVisible() or \
            self.cmap_dialog.isVisible():
          self.show_color_dialog()

    @QtCore.pyqtSlot(tuple, object)
    def set_option(self, option_def, option_value):
        set_leaf(self.options, option_def, option_value)
        if option_def == ('view_mode',):
            self.switch_color_dialog()

        self.on_draw()