Example #1
0
 def _setup_display_objects(self):
     self._overview_layout = qtgraph.GraphicsLayoutWidget()
     self._overview_view = self._overview_layout.addPlot(row=0, col=0)
     self._overview = qtgraph.ImageItem(parent=self._overview_layout)
     self._overview_view.addItem(self._overview)
     self._surface_view = glgraph.GLViewWidget()
     self._surface_view.setCameraPosition(distance=3, azimuth=-45)
     self._setup_surface_object()
     self._setup_axis()
     self._info = InfoFrame(info_groups=self._displayed_groups)
Example #2
0
 def _init_gui(self):
     """Create gui elements"""
     self.setMinimumWidth(_MINIMUM_WIDTH)
     self.setMinimumHeight(_MINIMUM_HEIGHT)
     self._splitter = qtgui.QSplitter(parent=self.parent(),
                                      orientation=qtcore.Qt.Horizontal)
     self._graphics_layout = qtgraph.GraphicsLayoutWidget()
     self._plot = self._graphics_layout.addPlot(row=0, col=0)
     self._info = InfoFrame(parent=self._splitter,
                            info_groups=self._displayed_groups)
     # setup plot
     for leaf, color in zip(self._leafs,
                            itertools.cycle(plotutils.PLOT_COLORS)):
         self._plot.plot(leaf, pen=color)
     plotutils.set_window_title(self, self._leafs)
     # signals and slots
     self._cross_proxy = plotutils.add_crosshair_to(self._plot)
     # combine objects
     self._splitter.addWidget(self._graphics_layout)
     self._splitter.addWidget(self._info)
     # only stretch plot window
     self._splitter.setStretchFactor(0, 1)
     self._splitter.setStretchFactor(1, 0)
     self.setWidget(self._splitter)
Example #3
0
class SinglePlot(qtgui.QMdiSubWindow):
    """Adapter for vitables."""
    _STAT_FUNCTION_DICT = {'min': np.amin, 'mean': np.mean, 'max': np.amax, 
                           'std': np.std}
    def __init__(self, parent=None, index=None, leafs=None):
        super(SinglePlot, self).__init__(parent)
        # things to display on the right
        self._stat_groups = ['max', 'mean', 'std', 'min']
        self._displayed_groups = [_POSITION_GROUP, _VALUE_GROUP] \
                                 + self._stat_groups
        # store some vars
        self._leafs = leafs if leafs else []
        self._value_names = [l.name for l in self._leafs]
        # stuff that vitables looks for
        self.dbt_leaf = plugin_utils.getVTGui().dbs_tree_model.nodeFromIndex(index)
        self.pindex = qtcore.QPersistentModelIndex(index)
        self.is_context_menu_custom = True
        # gui init stuff
        self.setAttribute(qtcore.Qt.WA_DeleteOnClose)
        self._init_gui()
        # set text edits with some stuff and adjust their size
        plotutils.update_position_info(self._plot, self._info, _POSITION_GROUP)
        self._update_values_info()
        self._update_statistics_info()
        self._info.fit_content()
        # signal slots
        self._mouse_position_proxy = qtgraph.SignalProxy(
            self._plot.scene().sigMouseMoved, rateLimit=30,
            slot=ft.partial(plotutils.update_position_info, self._plot, 
                            self._info, _POSITION_GROUP))
        self._mouse_value_proxy = qtgraph.SignalProxy(
            self._plot.scene().sigMouseMoved, rateLimit=10,
            slot=self._update_values_info)
        self._range_change_proxy = qtgraph.SignalProxy(
            self._plot.sigRangeChanged, rateLimit=10,
            slot=self._update_statistics_info)

    def _init_gui(self):
        """Create gui elements"""
        self.setMinimumWidth(_MINIMUM_WIDTH)
        self.setMinimumHeight(_MINIMUM_HEIGHT)
        self._splitter = qtgui.QSplitter(parent=self.parent(),
                                         orientation=qtcore.Qt.Horizontal)
        self._graphics_layout = qtgraph.GraphicsLayoutWidget()
        self._plot = self._graphics_layout.addPlot(row=0, col=0)
        self._info = InfoFrame(parent=self._splitter,
                               info_groups=self._displayed_groups)
        # setup plot
        for leaf, color in zip(self._leafs,
                               itertools.cycle(plotutils.PLOT_COLORS)):
            self._plot.plot(leaf, pen=color)
        plotutils.set_window_title(self, self._leafs)
        # signals and slots
        self._cross_proxy = plotutils.add_crosshair_to(self._plot)
        # combine objects
        self._splitter.addWidget(self._graphics_layout)
        self._splitter.addWidget(self._info)
        # only stretch plot window
        self._splitter.setStretchFactor(0, 1)
        self._splitter.setStretchFactor(1, 0)
        self.setWidget(self._splitter)

    def _update_info(self, info_name, values):
        colors = [plotutils.get_data_item_color(di) 
                  for di in self._plot.listDataItems()]
        legend = []
        for value, name, color in zip(values, self._value_names, colors):
            legend.append(plotutils.LEGEND_LINE.format(name=name, value=value, 
                                              color=color))
        self._info.update_entry(info_name, '<br/>'.join(legend))

    def _update_values_info(self, event=None):
        """Update info text on mouse move event.

        Uses proxy to reduce number of events.
        """
        if event:
            x, y = plotutils.mouse_event_to_coordinates(self._plot, event)
            if not x:
                return
            values = [plotutils.get_data_item_value(di, x)
                      for di in self._plot.listDataItems()]
        else:
            values = len(self._plot.listDataItems())*[float('nan')]
        self._update_info(_VALUE_GROUP, values)


    def _update_statistics_info(self, unused=None):
        """Update the statistics text edit on the info pane."""
        x_range = self._plot.viewRange()[0]
        for stat_name in self._stat_groups:
            stat_values = plotutils.calculate_statistics(
                plot=self._plot, function=self._STAT_FUNCTION_DICT[stat_name],
                range_=x_range)
            self._update_info(stat_name, stat_values)
        self.on_range_changed(x_range)

    def on_range_changed(self, range_):
        """Place holder for child to redefine."""
        pass
Example #4
0
class SurfPlot(qtgui.QMdiSubWindow):
    """Adapter for vitables."""

    _STAT_FUNCTION_DICT = {'min': np.amin, 'mean': np.mean, 'max': np.amax,
                           'std': np.std}

    def __init__(self, parent=None, index=None, leaf=None, leaf_name=None):
        super(SurfPlot, self).__init__(parent)
        self._leaf_name = leaf_name if leaf_name else 'none'
        self._data = leaf
        self._stat_groups = ['max', 'mean', 'min']
        self._displayed_groups = [_CURSOR_GROUP,
                                  _ROI_GROUP] + self._stat_groups
        # gui stuff
        self.setAttribute(qtcore.Qt.WA_DeleteOnClose)
        self._init_gui()
        # stuff that vitables looks for
        self.dbt_leaf = plugin_utils.getVTGui().dbs_tree_model.nodeFromIndex(index)
        self.pindex = qtcore.QPersistentModelIndex(index)
        self.is_context_menu_custom = True

    def _init_gui(self):
        self.setMinimumWidth(_MINIMUM_WIDTH)
        self.setMinimumHeight(_MINIMUM_HEIGHT)
        self.setWindowTitle('Plot - ' + self._leaf_name)
        self._setup_display_objects()
        self._setup_slice_plots()
        self._draw_overview()
        self._update_cursor_info()
        self._info.fit_content()
        self._setup_splitter()

    def _setup_display_objects(self):
        self._overview_layout = qtgraph.GraphicsLayoutWidget()
        self._overview_view = self._overview_layout.addPlot(row=0, col=0)
        self._overview = qtgraph.ImageItem(parent=self._overview_layout)
        self._overview_view.addItem(self._overview)
        self._surface_view = glgraph.GLViewWidget()
        self._surface_view.setCameraPosition(distance=3, azimuth=-45)
        self._setup_surface_object()
        self._setup_axis()
        self._info = InfoFrame(info_groups=self._displayed_groups)

    def _setup_slice_plots(self):
        self._slice_layout = qtgraph.GraphicsLayoutWidget()
        self._vertical_slice = self._slice_layout.addPlot(row=0, col=0)
        self._vertical_curve = self._vertical_slice.plot(
            self._data[0, ...], pen='b')
        self._horizontal_slice = self._slice_layout.addPlot(row=1, col=0)
        self._horizontal_curve = self._horizontal_slice.plot(
            self._data[..., 0], pen='b')

    def _setup_surface_object(self):
        self._surface = glgraph.GLSurfacePlotItem(
            shader='heightColor', smooth=False, computeNormals=False)
        split = 1/3.0
        self._surface.shader()['colorMap'] = np.array(
            [1/split, -split, 1,
             -1/split, -3*split, 1,
             -1/split, -split, 1])
        self._surface_view.addItem(self._surface)
        self._overview.setImage(image=self._data, autoLevels=True)

    def _setup_axis(self):
        self._overview_axis = glgraph.GLAxisItem(glOptions='opaque')
        self._overview_axis.setSize(1.5, 1.5, 1.5)
        self._surface_view.addItem(self._overview_axis)

    def _setup_splitter(self):
        self._splitter = qtgui.QSplitter(orientation=qtcore.Qt.Horizontal)
        self._overview_splitter = qtgui.QSplitter(
            orientation=qtcore.Qt.Vertical)
        # append objects
        self._overview_splitter.addWidget(self._overview_layout)
        self._overview_splitter.addWidget(self._slice_layout)
        self._splitter.addWidget(self._overview_splitter)
        self._splitter.addWidget(self._surface_view)
        self._splitter.addWidget(self._info)
        # setup overview splitter
        self._overview_splitter.setStretchFactor(0, 3)
        self._overview_splitter.setStretchFactor(1, 1)
        # make sure info pane does not change size
        self._splitter.setStretchFactor(0, 1)
        self._splitter.setStretchFactor(1, 1)
        self._splitter.setStretchFactor(2, 0)
        self.setWidget(self._splitter)

    def _draw_overview(self):
        # roi and its controls
        x_count, y_count = self._data.shape
        x_size = max(min(x_count, _ROI_MIN_SIZE), x_count*_ROI_FRACTION)
        y_size = max(min(y_count, _ROI_MIN_SIZE), y_count*_ROI_FRACTION)
        self._overview_roi = qtgraph.RectROI([0, 0], [x_size, y_size], 
                                             pen=(0,9))
        self._overview_roi.addScaleHandle(pos=[0, 0], center=[1, 1])
        self._overview_roi.addScaleHandle(pos=[0, 1], center=[1, 0])
        self._overview_roi.addScaleHandle(pos=[1, 0], center=[0, 1])
        self._overview_view.addItem(self._overview_roi)
        # connect signals
        self._overview_roi.sigRegionChangeFinished.connect(self._roi_update)
        self._roi_update()
        self._mouse_position_proxy = qtgraph.SignalProxy(
            self._overview.scene().sigMouseMoved, rateLimit=30,
            slot=self._update_cursor_info)
        self._slice_graph_proxy = qtgraph.SignalProxy(
            self._overview.scene().sigMouseMoved, rateLimit=10,
            slot=self._update_slice_graphs)

    def _roi_update(self):
        boundaries, transformation = self._overview_roi.getArraySlice(
            self._data, self._overview, returnSlice=False)
        max_x, max_y = self._data.shape
        x_range = (boundaries[0][0], min(max_x - 1, boundaries[0][1]))
        y_range = (boundaries[1][0], min(max_y - 1, boundaries[1][1]))
        self._update_surface(x_range, y_range)
        self._update_roi_info(x_range, y_range)

    def _set_shader_spread(self, spread):
        incline = 3.0/2/spread
        self._surface.shader()['colorMap'] = np.array(
            [incline, spread/3, 1,
             -incline, -spread, 1,
             -incline, spread/3, 1])

    def _update_surface(self, x_range, y_range):
        data = np.copy(self._data[x_range[0]:x_range[1],
                                  y_range[0]:y_range[1]])
        std = np.std(data)
        data -= np.mean(data)
        data /= 8*std
        x_data = np.linspace(-1, 1, x_range[1] - x_range[0])
        y_data = np.linspace(-1, 1, y_range[1] - y_range[0])
        self._set_shader_spread(0.3)
        self._surface.setData(x=x_data, y=y_data, z=data)

    def _update_roi_info(self, x_range=None, y_range=None):
        if not x_range or not y_range:
            self._update_roi_boundaries_info()
            return
        min_x, max_x = x_range
        min_y, max_y = y_range
        self._update_roi_boundaries_info(min_x, max_x, min_y, max_y)
        self._update_roi_statistics_info(min_x, max_x, min_y, max_y)

    def _update_roi_boundaries_info(self, min_x=float('nan'), 
                                    max_x=float('nan'), min_y=float('nan'), 
                                    max_y=float('nan')):
        legend = [_RANGE_TEMPLATE.format(name='x', min_=min_x, max_=max_x),
                  _RANGE_TEMPLATE.format(name='y', min_=min_y, max_=max_y)]
        self._info.update_entry(_ROI_GROUP, '<br/>'.join(legend))

    def _update_roi_statistics_info(self, min_x=None, max_x=None, min_y=None, 
                                    max_y=None):
        if not min_x or not max_x or not min_y or not max_y:
            for stat_name in self._stat_groups:
                self._info.update_entry(stat_name, 'nan')
        x_count, y_count = self._data.shape
        min_x = max(0, min_x)
        max_x = min(x_count, max_x)
        min_y = max(0, min_y)
        max_y = min(y_count, max_y)
        data_slice = self._data[min_x:max_x, min_y:max_y]
        for stat_name in self._stat_groups:
                self._info.update_entry(
                    stat_name, '{0:.5g}'.format(
                        self._STAT_FUNCTION_DICT[stat_name](data_slice)))

    def _update_cursor_info(self, event=None):
        x, y, value = float('nan'), float('nan'), float('nan')
        if event:
            x, y = plotutils.mouse_event_to_coordinates(self._overview, event)
            if not x:
                return
            x, y = int(x), int(y)
            if x >= 0 and x < self._data.shape[0] \
               and y >= 0 and y < self._data.shape[1]:
                value = self._data[x, y]
        legend = ['x = {0}'.format(x), 'y = {0}'.format(y),
                  'value = {0:.5g}'.format(value)]
        self._info.update_entry(_CURSOR_GROUP, '<br/>'.join(legend))

    def _update_slice_graphs(self, event=None):
        if event is None:
            return
        x, y = plotutils.mouse_event_to_coordinates(self._overview, event)
        if not x:
            return
        x, y = int(x), int(y)
        if x < 0 or x >= self._data.shape[0] \
           or y < 0 or y >= self._data.shape[1]:
            return
        self._vertical_curve.setData(y=self._data[x, ...])
        self._horizontal_curve.setData(y=self._data[..., y])