コード例 #1
0
    def __init__(self,
                 palette,
                 values,
                 parent,
                 font=None,
                 orientation=Qt.Vertical):
        if orientation == Qt.Vertical:
            super().__init__(Qt.Horizontal)
        else:
            super().__init__(Qt.Vertical)

        self.__parent = parent
        self.__palette = palette
        self.__values = values

        self.__gradient = LegendGradient(palette, parent, orientation)
        self.__labels_layout = QGraphicsLinearLayout(orientation)

        str_vals = self._format_values(values)

        self.__start_label = LegendItemTitle(str_vals[0], parent, font=font)
        self.__end_label = LegendItemTitle(str_vals[1], parent, font=font)
        self.__labels_layout.addItem(self.__start_label)
        self.__labels_layout.addStretch(1)
        self.__labels_layout.addItem(self.__end_label)

        # Gradient should be to the left, then labels on the right if vertical
        if orientation == Qt.Vertical:
            self.addItem(self.__gradient)
            self.addItem(self.__labels_layout)
        # Gradient should be on the bottom, labels on top if horizontal
        elif orientation == Qt.Horizontal:
            self.addItem(self.__labels_layout)
            self.addItem(self.__gradient)
コード例 #2
0
    def __init__(self,
                 pixmap,
                 parentItem=None,
                 crop=False,
                 in_subset=True,
                 **kwargs):
        super().__init__(parentItem, **kwargs)
        self.setFocusPolicy(Qt.StrongFocus)
        self._size = QSizeF()

        layout = QGraphicsLinearLayout(Qt.Vertical, self)
        layout.setSpacing(1)
        layout.setContentsMargins(5, 5, 5, 5)
        self.setContentsMargins(0, 0, 0, 0)

        self.pixmapWidget = GraphicsPixmapWidget(pixmap, self)
        self.pixmapWidget.setCrop(crop)
        self.pixmapWidget.setSubset(in_subset)
        self.selectionBrush = DEFAULT_SELECTION_BRUSH
        self.selectionPen = DEFAULT_SELECTION_PEN

        layout.addItem(self.pixmapWidget)
        layout.setAlignment(self.pixmapWidget, Qt.AlignCenter)

        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
コード例 #3
0
ファイル: ownomogram.py プロジェクト: rowhit/orange3
class NomogramItem(QGraphicsWidget):
    def __init__(self):
        super().__init__()
        self._items = []
        self.layout = QGraphicsLinearLayout(Qt.Vertical)
        self.setLayout(self.layout)

    def add_items(self, items):
        self._items = items
        for item in items:
            self.layout.addItem(item)
コード例 #4
0
ファイル: owlegend.py プロジェクト: lhenry15/tods-gui
    def _setup_layout(self):
        self._clear_layout()

        self._layout = QGraphicsLinearLayout(self.orientation)
        self._layout.setContentsMargins(10, 5, 10, 5)
        # If horizontal, there needs to be horizontal space between the items
        if self.orientation == Qt.Horizontal:
            self._layout.setSpacing(10)
        # If vertical spacing, vertical space is provided by child layouts
        else:
            self._layout.setSpacing(0)
        self.setLayout(self._layout)
コード例 #5
0
class StripePlot(QGraphicsWidget):
    HEIGHT = 400
    SPACING = 20
    HMARGIN = 30
    VMARGIN = 20

    def __init__(self):
        super().__init__()
        self.__height = None  # type: int
        self.__range = None  # type: Tuple[float, float]

        self.__layout = QGraphicsLinearLayout()
        self.__layout.setOrientation(Qt.Horizontal)
        self.__layout.setSpacing(self.SPACING)
        self.__layout.setContentsMargins(self.HMARGIN, self.VMARGIN,
                                         self.HMARGIN, self.VMARGIN)
        self.setLayout(self.__layout)

        self.__stripe_item = StripeItem(self)
        self.__left_axis = AxisItem([
            self.__stripe_item.model_output_ind,
            self.__stripe_item.base_value_ind
        ],
                                    parent=self,
                                    orientation="left",
                                    maxTickLength=7,
                                    pen=QPen(Qt.black))

        self.__layout.addItem(self.__left_axis)
        self.__layout.addItem(self.__stripe_item)

    @property
    def height(self) -> float:
        return self.HEIGHT + 10 * self.__height

    def set_data(self, data: PlotData, height: float):
        diff = (data.value_range[1] - data.value_range[0]) * 0.01
        self.__range = (data.value_range[0] - diff, data.value_range[1] + diff)
        self.__left_axis.setRange(*self.__range)
        self.__height = height
        self.__stripe_item.set_data(data, self.__range, self.height)

    def set_height(self, height: float):
        self.__height = height
        self.__stripe_item.set_height(self.height)
        self.updateGeometry()

    def sizeHint(self, *_) -> QSizeF:
        return QSizeF(
            self.__left_axis.boundingRect().width() +
            self.__stripe_item.total_width + self.HMARGIN * 2,
            self.height + self.VMARGIN * 2)
コード例 #6
0
    def _draw_histogram(self):
        if self.distributions.ndim > 1:
            largest_bin_count = self.distributions.sum(axis=1).max()
        else:
            largest_bin_count = self.distributions.max()

        bar_size = self._plot_width / self.n_bins

        for distr, bin_colors in zip(self.distributions, self._get_colors()):
            bin_count = distr.sum()
            bar_height = bin_count / largest_bin_count * self._plot_height

            bar_layout = QGraphicsLinearLayout(Qt.Vertical)
            bar_layout.setSpacing(0)
            bar_layout.addStretch()
            self.__layout.addItem(bar_layout)

            bar = ProportionalBarItem(
                distribution=distr,
                colors=bin_colors,
                height=bar_height,
                bar_size=bar_size,
            )
            bar_layout.addItem(bar)

        self.layout()
コード例 #7
0
ファイル: owlegend.py プロジェクト: astaric/orange3
    def __init__(self, palette, values, parent, font=None,
                 orientation=Qt.Vertical):
        if orientation == Qt.Vertical:
            super().__init__(Qt.Horizontal)
        else:
            super().__init__(Qt.Vertical)

        self.__parent = parent
        self.__palette = palette
        self.__values = values

        self.__gradient = LegendGradient(palette, parent, orientation)
        self.__labels_layout = QGraphicsLinearLayout(orientation)

        str_vals = self._format_values(values)

        self.__start_label = LegendItemTitle(str_vals[0], parent, font=font)
        self.__end_label = LegendItemTitle(str_vals[1], parent, font=font)
        self.__labels_layout.addItem(self.__start_label)
        self.__labels_layout.addStretch(1)
        self.__labels_layout.addItem(self.__end_label)

        # Gradient should be to the left, then labels on the right if vertical
        if orientation == Qt.Vertical:
            self.addItem(self.__gradient)
            self.addItem(self.__labels_layout)
        # Gradient should be on the bottom, labels on top if horizontal
        elif orientation == Qt.Horizontal:
            self.addItem(self.__labels_layout)
            self.addItem(self.__gradient)
コード例 #8
0
ファイル: owlegend.py プロジェクト: astaric/orange3
    def _setup_layout(self):
        self._clear_layout()

        self._layout = QGraphicsLinearLayout(self.orientation)
        self._layout.setContentsMargins(10, 5, 10, 5)
        # If horizontal, there needs to be horizontal space between the items
        if self.orientation == Qt.Horizontal:
            self._layout.setSpacing(10)
        # If vertical spacing, vertical space is provided by child layouts
        else:
            self._layout.setSpacing(0)
        self.setLayout(self._layout)
コード例 #9
0
ファイル: owlegend.py プロジェクト: lhenry15/tods-gui
class ContinuousLegendItem(QGraphicsLinearLayout):
    """Continuous legend item.

    Contains a gradient bar with the color ranges, as well as two labels - one
    on each side of the gradient bar.

    Parameters
    ----------
    palette : iterable[QColor]
    values : iterable[float...]
        The number of values must match the number of colors in passed in the
        color palette.
    parent : QGraphicsWidget
    font : QFont
    orientation : Qt.Orientation

    """
    def __init__(self,
                 palette,
                 values,
                 parent,
                 font=None,
                 orientation=Qt.Vertical):
        if orientation == Qt.Vertical:
            super().__init__(Qt.Horizontal)
        else:
            super().__init__(Qt.Vertical)

        self.__parent = parent
        self.__palette = palette
        self.__values = values

        if isinstance(palette, ContinuousPalette):
            self.__gradient = ColorStripItem(palette, parent, orientation)
        else:
            self.__gradient = LegendGradient(palette, parent, orientation)
        self.__labels_layout = QGraphicsLinearLayout(orientation)

        str_vals = self._format_values(values)

        self.__start_label = LegendItemTitle(str_vals[0], parent, font=font)
        self.__end_label = LegendItemTitle(str_vals[1], parent, font=font)
        self.__labels_layout.addItem(self.__start_label)
        self.__labels_layout.addStretch(1)
        self.__labels_layout.addItem(self.__end_label)

        # Gradient should be to the left, then labels on the right if vertical
        if orientation == Qt.Vertical:
            self.addItem(self.__gradient)
            self.addItem(self.__labels_layout)
        # Gradient should be on the bottom, labels on top if horizontal
        elif orientation == Qt.Horizontal:
            self.addItem(self.__labels_layout)
            self.addItem(self.__gradient)

    @staticmethod
    def _format_values(values):
        """Get the formatted values to output."""
        return ['{:.3f}'.format(v) for v in values]
コード例 #10
0
    def __init__(self):
        super().__init__()
        self.__height = None  # type: int
        self.__range = None  # type: Tuple[float, float]

        self.__layout = QGraphicsLinearLayout()
        self.__layout.setOrientation(Qt.Horizontal)
        self.__layout.setSpacing(self.SPACING)
        self.__layout.setContentsMargins(self.HMARGIN, self.VMARGIN,
                                         self.HMARGIN, self.VMARGIN)
        self.setLayout(self.__layout)

        self.__stripe_item = StripeItem(self)
        self.__left_axis = AxisItem([
            self.__stripe_item.model_output_ind,
            self.__stripe_item.base_value_ind
        ],
                                    parent=self,
                                    orientation="left",
                                    maxTickLength=7,
                                    pen=QPen(Qt.black))

        self.__layout.addItem(self.__left_axis)
        self.__layout.addItem(self.__stripe_item)
コード例 #11
0
    def __init__(self,
                 parent=None,
                 direction=Qt.LeftToRight,
                 node=None,
                 icon=None,
                 iconSize=None,
                 **args):
        super().__init__(parent, **args)
        self.setAcceptedMouseButtons(Qt.NoButton)
        self.__direction = direction

        self.setLayout(QGraphicsLinearLayout(Qt.Horizontal))

        # Set the maximum size, otherwise the layout can't grow beyond its
        # sizeHint (and we need it to grow so the widget can grow and keep the
        # contents centered vertically.
        self.layout().setMaximumSize(QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))

        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.__iconSize = iconSize or QSize(64, 64)
        self.__icon = icon

        self.__iconItem = QGraphicsPixmapItem(self)
        self.__iconLayoutItem = GraphicsItemLayoutItem(item=self.__iconItem)

        self.__channelLayout = QGraphicsGridLayout()
        self.channelAnchors = []

        if self.__direction == Qt.LeftToRight:
            self.layout().addItem(self.__iconLayoutItem)
            self.layout().addItem(self.__channelLayout)
            channel_alignemnt = Qt.AlignRight

        else:
            self.layout().addItem(self.__channelLayout)
            self.layout().addItem(self.__iconLayoutItem)
            channel_alignemnt = Qt.AlignLeft

        self.layout().setAlignment(self.__iconLayoutItem, Qt.AlignCenter)
        self.layout().setAlignment(self.__channelLayout,
                                   Qt.AlignVCenter | channel_alignemnt)

        self.node: Optional[SchemeNode] = None
        self.channels: Union[List[InputSignal], List[OutputSignal]] = []
        if node is not None:
            self.setSchemeNode(node)
コード例 #12
0
    def __init__(self, pixmap, parentItem=None, crop=False, in_subset=True, **kwargs):
        super().__init__(parentItem, **kwargs)
        self.setFocusPolicy(Qt.StrongFocus)
        self._size = QSizeF()

        layout = QGraphicsLinearLayout(Qt.Vertical, self)
        layout.setSpacing(1)
        layout.setContentsMargins(5, 5, 5, 5)
        self.setContentsMargins(0, 0, 0, 0)

        self.pixmapWidget = GraphicsPixmapWidget(pixmap, self)
        self.pixmapWidget.setCrop(crop)
        self.pixmapWidget.setSubset(in_subset)
        self.selectionBrush = DEFAULT_SELECTION_BRUSH
        self.selectionPen = DEFAULT_SELECTION_PEN

        layout.addItem(self.pixmapWidget)
        layout.setAlignment(self.pixmapWidget, Qt.AlignCenter)

        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
コード例 #13
0
ファイル: owlegend.py プロジェクト: astaric/orange3
class ContinuousLegendItem(QGraphicsLinearLayout):
    """Continuous legend item.

    Contains a gradient bar with the color ranges, as well as two labels - one
    on each side of the gradient bar.

    Parameters
    ----------
    palette : iterable[QColor]
    values : iterable[float...]
        The number of values must match the number of colors in passed in the
        color palette.
    parent : QGraphicsWidget
    font : QFont
    orientation : Qt.Orientation

    """

    def __init__(self, palette, values, parent, font=None,
                 orientation=Qt.Vertical):
        if orientation == Qt.Vertical:
            super().__init__(Qt.Horizontal)
        else:
            super().__init__(Qt.Vertical)

        self.__parent = parent
        self.__palette = palette
        self.__values = values

        self.__gradient = LegendGradient(palette, parent, orientation)
        self.__labels_layout = QGraphicsLinearLayout(orientation)

        str_vals = self._format_values(values)

        self.__start_label = LegendItemTitle(str_vals[0], parent, font=font)
        self.__end_label = LegendItemTitle(str_vals[1], parent, font=font)
        self.__labels_layout.addItem(self.__start_label)
        self.__labels_layout.addStretch(1)
        self.__labels_layout.addItem(self.__end_label)

        # Gradient should be to the left, then labels on the right if vertical
        if orientation == Qt.Vertical:
            self.addItem(self.__gradient)
            self.addItem(self.__labels_layout)
        # Gradient should be on the bottom, labels on top if horizontal
        elif orientation == Qt.Horizontal:
            self.addItem(self.__labels_layout)
            self.addItem(self.__gradient)

    @staticmethod
    def _format_values(values):
        """Get the formatted values to output."""
        return ['{:.3f}'.format(v) for v in values]
コード例 #14
0
ファイル: histogram.py プロジェクト: szzyiit/orange3
    def _draw_histogram(self):
        # In case the data for the variable were all NaNs, then the
        # distributions will be empty, and we don't need to display any bars
        if self.x.size == 0:
            return

        # In case we have a target var, but the values are all NaNs, then there
        # is no sense in displaying anything
        if self.target_var:
            y_nn = self.y[~np.isnan(self.y)]
            if y_nn.size == 0:
                return

        if self.distributions.ndim > 1:
            largest_bin_count = self.distributions.sum(axis=1).max()
        else:
            largest_bin_count = self.distributions.max()

        bar_size = self._plot_width / self.n_bins

        for distr, bin_colors in zip(self.distributions, self._get_colors()):
            bin_count = distr.sum()
            bar_height = bin_count / largest_bin_count * self._plot_height

            bar_layout = QGraphicsLinearLayout(Qt.Vertical)
            bar_layout.setSpacing(0)
            bar_layout.addStretch()
            self.__layout.addItem(bar_layout)

            bar = ProportionalBarItem(  # pylint: disable=blacklisted-name
                distribution=distr,
                colors=bin_colors,
                height=bar_height,
                bar_size=bar_size,
            )
            bar_layout.addItem(bar)

        self.layout()
コード例 #15
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setAcceptedMouseButtons(Qt.LeftButton | Qt.RightButton)

        self.source = None
        self.sink = None

        # QGraphicsWidget/Items in the scene.
        self.sourceNodeWidget = None
        self.sourceNodeTitle = None
        self.sinkNodeWidget = None
        self.sinkNodeTitle = None

        self.__links = []  # type: List[IOPair]

        self.__textItems = []
        self.__iconItems = []
        self.__tmpLine = None
        self.__dragStartItem = None

        self.setLayout(QGraphicsLinearLayout(Qt.Vertical))
        self.layout().setContentsMargins(0, 0, 0, 0)
コード例 #16
0
ファイル: histogram.py プロジェクト: PrimozGodec/orange3
    def _draw_histogram(self):
        # In case the data for the variable were all NaNs, then the
        # distributions will be empty, and we don't need to display any bars
        if self.x.size == 0:
            return

        # In case we have a target var, but the values are all NaNs, then there
        # is no sense in displaying anything
        if self.target_var:
            y_nn = self.y[~np.isnan(self.y)]
            if y_nn.size == 0:
                return

        if self.distributions.ndim > 1:
            largest_bin_count = self.distributions.sum(axis=1).max()
        else:
            largest_bin_count = self.distributions.max()

        bar_size = self._plot_width / self.n_bins

        for distr, bin_colors in zip(self.distributions, self._get_colors()):
            bin_count = distr.sum()
            bar_height = bin_count / largest_bin_count * self._plot_height

            bar_layout = QGraphicsLinearLayout(Qt.Vertical)
            bar_layout.setSpacing(0)
            bar_layout.addStretch()
            self.__layout.addItem(bar_layout)

            bar = ProportionalBarItem(  # pylint: disable=blacklisted-name
                distribution=distr, colors=bin_colors, height=bar_height,
                bar_size=bar_size,
            )
            bar_layout.addItem(bar)

        self.layout()
コード例 #17
0
ファイル: histogram.py プロジェクト: PrimozGodec/orange3
class Histogram(QGraphicsWidget):
    """A basic histogram widget.

    Parameters
    ----------
        data : Table
        variable : Union[int, str, Variable]
        parent : QObject
        height : Union[int, float]
        width : Union[int, float]
        side_padding : Union[int, float]
            Specify the padding between the edges of the histogram and the
            first and last bars.
        top_padding : Union[int, float]
            Specify the padding between the top of the histogram and the
            highest bar.
        bar_spacing : Union[int, float]
            Specify the amount of spacing to place between individual bars.
        border : Union[Tuple[Union[int, float]], int, float]
            Can be anything that can go into the ``'QColor'`` constructor.
            Draws a border around the entire histogram in a given color.
        border_color : Union[QColor, str]
        class_index : int
            The index of the target variable in ``'data'``.
        n_bins : int

    """

    def __init__(self, data, variable, parent=None, height=200,
                 width=300, side_padding=5, top_padding=20, bar_spacing=4,
                 border=0, border_color=None, color_attribute=None, n_bins=10):
        super().__init__(parent)
        self.height, self.width = height, width
        self.padding = side_padding
        self.bar_spacing = bar_spacing

        self.data = data
        self.attribute = data.domain[variable]

        self.x = data.get_column_view(self.attribute)[0].astype(np.float64)
        self.x_nans = np.isnan(self.x)
        self.x = self.x[~self.x_nans]

        if self.attribute.is_discrete:
            self.n_bins = len(self.attribute.values)
        elif self.attribute.is_continuous:
            # If the attribute is continuous but contains fewer values than the
            # bins, it is better to assign each their own bin. We will require
            # at least 2 bins so that the histogram still visually makes sense
            # except if there is only a single value, then we use 3 bins for
            # symmetry
            num_unique = ut.nanunique(self.x).shape[0]
            if num_unique == 1:
                self.n_bins = 3
            else:
                self.n_bins = min(max(2, num_unique), n_bins)

        # Handle target variable index
        self.color_attribute = color_attribute
        if self.color_attribute is not None:
            self.target_var = data.domain[color_attribute]
            self.y = data.get_column_view(color_attribute)[0]
            self.y = self.y[~self.x_nans]
            if not np.issubdtype(self.y.dtype, np.number):
                self.y = self.y.astype(np.float64)
        else:
            self.target_var, self.y = None, None

        # Borders
        self.border_color = border_color if border_color is not None else '#000'
        if isinstance(border, tuple):
            assert len(border) == 4, 'Border tuple must be of size 4.'
            self.border = border
        else:
            self.border = (border, border, border, border)
        t, r, b, l = self.border

        def _draw_border(point_1, point_2, border_width, parent):
            pen = QPen(QColor(self.border_color))
            pen.setCosmetic(True)
            pen.setWidth(border_width)
            line = QGraphicsLineItem(QLineF(point_1, point_2), parent)
            line.setPen(pen)
            return line

        top_left = QPointF(0, 0)
        bottom_left = QPointF(0, self.height)
        top_right = QPointF(self.width, 0)
        bottom_right = QPointF(self.width, self.height)

        self.border_top = _draw_border(top_left, top_right, t, self) if t else None
        self.border_bottom = _draw_border(bottom_left, bottom_right, b, self) if b else None
        self.border_left = _draw_border(top_left, bottom_left, l, self) if l else None
        self.border_right = _draw_border(top_right, bottom_right, r, self) if r else None

        # _plot_`dim` accounts for all the paddings and spacings
        self._plot_height = self.height
        self._plot_height -= top_padding
        self._plot_height -= t / 4 + b / 4

        self._plot_width = self.width
        self._plot_width -= 2 * side_padding
        self._plot_width -= (self.n_bins - 2) * bar_spacing
        self._plot_width -= l / 4 + r / 4

        self.__layout = QGraphicsLinearLayout(Qt.Horizontal, self)
        self.__layout.setContentsMargins(
            side_padding + r / 2,
            top_padding + t / 2,
            side_padding + l / 2,
            b / 2
        )
        self.__layout.setSpacing(bar_spacing)

        # If the data contains any non-NaN values, we can draw a histogram
        if self.x.size > 0:
            self.edges, self.distributions = self._histogram()
            self._draw_histogram()

    def _get_histogram_edges(self):
        """Get the edges in the histogram based on the attribute type.

        In case of a continuous variable, we split the variable range into
        n bins. In case of a discrete variable, bins don't make sense, so we
        just return the attribute values.

        This will return the staring and ending edge, not just the edges in
        between (in the case of a continuous variable).

        Returns
        -------
        np.ndarray

        """
        if self.attribute.is_discrete:
            return np.array([self.attribute.to_val(v) for v in self.attribute.values])
        else:
            edges = np.linspace(ut.nanmin(self.x), ut.nanmax(self.x), self.n_bins)
            edge_diff = edges[1] - edges[0]
            edges = np.hstack((edges, [edges[-1] + edge_diff]))

            # If the variable takes on a single value, we still need to spit
            # out some reasonable bin edges
            if np.all(edges == edges[0]):
                edges = np.array([edges[0] - 1, edges[0], edges[0] + 1])

            return edges

    def _get_bin_distributions(self, bin_indices):
        """Compute the distribution of instances within bins.

        Parameters
        ----------
        bin_indices : np.ndarray
            An array with same shape as `x` but containing the bin index of the
            instance.

        Returns
        -------
        np.ndarray
            A 2d array; the first dimension represents different bins, the
            second - the counts of different target values.

        """
        if self.target_var and self.target_var.is_discrete:
            y = self.y
            # TODO This probably also isn't the best handling of sparse data...
            if sp.issparse(y):
                y = np.squeeze(np.array(y.todense()))

            # Since y can contain missing values, we need to filter them out as
            # well as their corresponding `x` values
            y_nan_mask = np.isnan(y)
            y, bin_indices = y[~y_nan_mask], bin_indices[~y_nan_mask]

            y = one_hot(y)
            # In the event that y does not take up all the values and the
            # largest discrete value does not appear at all, one hot encoding
            # will produce too few columns. This causes problems, so we need to
            # pad y with zeros to properly compute the distribution
            if y.shape[1] != len(self.target_var.values):
                n_missing_columns = len(self.target_var.values) - y.shape[1]
                y = np.hstack((y, np.zeros((y.shape[0], n_missing_columns))))

            bins = np.arange(self.n_bins)[:, np.newaxis]
            mask = bin_indices == bins
            distributions = np.zeros((self.n_bins, y.shape[1]))
            for bin_idx in range(self.n_bins):
                distributions[bin_idx] = y[mask[bin_idx]].sum(axis=0)
        else:
            distributions, _ = ut.bincount(bin_indices.astype(np.int64))
            # To keep things consistent across different variable types, we
            # want to return a 2d array where the first dim represent different
            # bins, and the second the distributions.
            distributions = distributions[:, np.newaxis]

        return distributions

    def _histogram(self):
        assert self.x.size > 0, 'Cannot calculate histogram on empty array'
        edges = self._get_histogram_edges()

        if self.attribute.is_discrete:
            bin_indices = self.x
            # TODO It probably isn't a very good idea to convert a sparse row
            # to a dense array... Converts sparse to 1d numpy array
            if sp.issparse(bin_indices):
                bin_indices = np.squeeze(np.asarray(
                    bin_indices.todense(), dtype=np.int64
                ))
        elif self.attribute.is_continuous:
            bin_indices = ut.digitize(self.x, bins=edges[1:-1]).flatten()

        distributions = self._get_bin_distributions(bin_indices)

        return edges, distributions

    def _draw_histogram(self):
        # In case the data for the variable were all NaNs, then the
        # distributions will be empty, and we don't need to display any bars
        if self.x.size == 0:
            return

        # In case we have a target var, but the values are all NaNs, then there
        # is no sense in displaying anything
        if self.target_var:
            y_nn = self.y[~np.isnan(self.y)]
            if y_nn.size == 0:
                return

        if self.distributions.ndim > 1:
            largest_bin_count = self.distributions.sum(axis=1).max()
        else:
            largest_bin_count = self.distributions.max()

        bar_size = self._plot_width / self.n_bins

        for distr, bin_colors in zip(self.distributions, self._get_colors()):
            bin_count = distr.sum()
            bar_height = bin_count / largest_bin_count * self._plot_height

            bar_layout = QGraphicsLinearLayout(Qt.Vertical)
            bar_layout.setSpacing(0)
            bar_layout.addStretch()
            self.__layout.addItem(bar_layout)

            bar = ProportionalBarItem(  # pylint: disable=blacklisted-name
                distribution=distr, colors=bin_colors, height=bar_height,
                bar_size=bar_size,
            )
            bar_layout.addItem(bar)

        self.layout()

    def _get_colors(self):
        """Compute colors for different kinds of histograms."""
        if self.target_var and self.target_var.is_discrete:
            colors = [[QColor(*color) for color in self.target_var.colors]] * self.n_bins

        elif self.target_var and self.target_var.is_continuous:
            palette = ContinuousPaletteGenerator(*self.target_var.colors)

            bins = np.arange(self.n_bins)[:, np.newaxis]
            edges = self.edges if self.attribute.is_discrete else self.edges[1:-1]
            # Need to digitize on `right` here so the samples will be assigned
            # to the correct bin for coloring
            bin_indices = ut.digitize(self.x, bins=edges, right=True)
            mask = bin_indices == bins

            colors = []
            for bin_idx in range(self.n_bins):
                biny = self.y[mask[bin_idx]]
                if np.isfinite(biny).any():
                    mean = ut.nanmean(biny) / ut.nanmax(self.y)
                else:
                    mean = 0  # bin is empty, color does not matter
                colors.append([palette[mean]])

        else:
            colors = [[QColor('#ccc')]] * self.n_bins

        return colors

    def boundingRect(self):
        return QRectF(0, 0, self.width, self.height)

    def sizeHint(self, which, constraint):
        return QSizeF(self.width, self.height)

    def sizePolicy(self):
        return QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
コード例 #18
0
ファイル: owlegend.py プロジェクト: astaric/orange3
class Legend(Anchorable):
    """Base legend class.

    This class provides common attributes for any legend subclasses:
      - Behaviour on `QGraphicsScene`
      - Appearance of legend

    Parameters
    ----------
    parent : QGraphicsItem, optional
    orientation : Qt.Orientation, optional
        The default orientation is vertical
    domain : Orange.data.domain.Domain, optional
        This field is left optional as in some cases, we may want to simply
        pass in a list that represents the legend.
    items : Iterable[QColor, str]
    bg_color : QColor, optional
    font : QFont, optional
    color_indicator_cls : ColorIndicator
        The color indicator class that will be used to render the indicators.

    See Also
    --------
    OWDiscreteLegend
    OWContinuousLegend
    OWContinuousLegend

    Notes
    -----
    .. warning:: If the domain parameter is supplied, the items parameter will
        be ignored.

    """

    def __init__(self, parent=None, orientation=Qt.Vertical, domain=None,
                 items=None, bg_color=QColor(232, 232, 232, 196),
                 font=None, color_indicator_cls=LegendItemSquare, **kwargs):
        super().__init__(parent, **kwargs)

        self._layout = None
        self.orientation = orientation
        self.bg_color = QBrush(bg_color)
        self.color_indicator_cls = color_indicator_cls

        # Set default font if none is given
        if font is None:
            self.font = QFont()
            self.font.setPointSize(10)
        else:
            self.font = font

        self.setFlags(QGraphicsWidget.ItemIsMovable |
                      QGraphicsItem.ItemIgnoresTransformations)

        self._setup_layout()
        if domain is not None:
            self.set_domain(domain)
        elif items is not None:
            self.set_items(items)

    def _clear_layout(self):
        self._layout = None
        for child in self.children():
            child.setParent(None)

    def _setup_layout(self):
        self._clear_layout()

        self._layout = QGraphicsLinearLayout(self.orientation)
        self._layout.setContentsMargins(10, 5, 10, 5)
        # If horizontal, there needs to be horizontal space between the items
        if self.orientation == Qt.Horizontal:
            self._layout.setSpacing(10)
        # If vertical spacing, vertical space is provided by child layouts
        else:
            self._layout.setSpacing(0)
        self.setLayout(self._layout)

    def set_domain(self, domain):
        """Handle receiving the domain object.

        Parameters
        ----------
        domain : Orange.data.domain.Domain

        Returns
        -------

        Raises
        ------
        AttributeError
            If the domain does not contain the correct type of class variable.

        """
        raise NotImplementedError()

    def set_items(self, values):
        """Handle receiving an array of items.

        Parameters
        ----------
        values : iterable[object, QColor]

        Returns
        -------

        """
        raise NotImplementedError()

    @staticmethod
    def _convert_to_color(obj):
        if isinstance(obj, QColor):
            return obj
        elif isinstance(obj, tuple) or isinstance(obj, list):
            assert len(obj) in (3, 4)
            return QColor(*obj)
        else:
            return QColor(obj)

    def setVisible(self, is_visible):
        """Only display the legend if it contains any items."""
        return super().setVisible(is_visible and len(self._layout) > 0)

    def paint(self, painter, options, widget=None):
        painter.save()
        pen = QPen(QColor(196, 197, 193, 200), 1)
        brush = QBrush(QColor(self.bg_color))

        painter.setPen(pen)
        painter.setBrush(brush)
        painter.drawRect(self.contentsRect())
        painter.restore()
コード例 #19
0
    def __init__(self,
                 pixmap,
                 parentItem=None,
                 crop=False,
                 in_subset=True,
                 add_label=False,
                 text="",
                 **kwargs):
        super().__init__(parentItem, **kwargs)
        self.setFocusPolicy(Qt.StrongFocus)
        self._size = QSizeF()

        layout = QGraphicsLinearLayout(Qt.Vertical, self)
        layout.setSpacing(1)
        layout.setContentsMargins(5, 5, 5, 5)
        self.setContentsMargins(0, 0, 0, 0)

        self.pixmapWidget = GraphicsPixmapWidget(pixmap, self)
        self.pixmapWidget.setCrop(crop)
        self.pixmapWidget.setSubset(in_subset)
        self.selectionBrush = DEFAULT_SELECTION_BRUSH
        self.selectionPen = DEFAULT_SELECTION_PEN

        layout.addItem(self.pixmapWidget)

        self.label = None
        if add_label:
            l1 = ElidedLabel(text)
            l1.setStyleSheet("background-color: rgba(255, 255, 255, 10);")
            l1.setAlignment(Qt.AlignCenter)
            l1.setFixedHeight(16)

            self.label = l1
            gs = QGraphicsScene()
            w = gs.addWidget(l1)
            layout.addItem(w)

        layout.setAlignment(self.pixmapWidget, Qt.AlignCenter)
        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
コード例 #20
0
ファイル: owlegend.py プロジェクト: lhenry15/tods-gui
class Legend(Anchorable):
    """Base legend class.

    This class provides common attributes for any legend subclasses:
      - Behaviour on `QGraphicsScene`
      - Appearance of legend

    Parameters
    ----------
    parent : QGraphicsItem, optional
    orientation : Qt.Orientation, optional
        The default orientation is vertical
    domain : Orange.data.domain.Domain, optional
        This field is left optional as in some cases, we may want to simply
        pass in a list that represents the legend.
    items : Iterable[QColor, str]
    bg_color : QColor, optional
    font : QFont, optional
    color_indicator_cls : ColorIndicator
        The color indicator class that will be used to render the indicators.

    See Also
    --------
    OWDiscreteLegend
    OWContinuousLegend
    OWContinuousLegend

    Notes
    -----
    .. warning:: If the domain parameter is supplied, the items parameter will
        be ignored.

    """
    def __init__(self,
                 parent=None,
                 orientation=Qt.Vertical,
                 domain=None,
                 items=None,
                 bg_color=QColor(232, 232, 232, 196),
                 font=None,
                 color_indicator_cls=LegendItemSquare,
                 **kwargs):
        super().__init__(parent, **kwargs)

        self._layout = None
        self.orientation = orientation
        self.bg_color = QBrush(bg_color)
        self.color_indicator_cls = color_indicator_cls

        # Set default font if none is given
        if font is None:
            self.font = QFont()
            self.font.setPointSize(10)
        else:
            self.font = font

        self.setFlags(QGraphicsWidget.ItemIsMovable
                      | QGraphicsItem.ItemIgnoresTransformations)

        self._setup_layout()
        if domain is not None:
            self.set_domain(domain)
        elif items is not None:
            self.set_items(items)

    def _clear_layout(self):
        self._layout = None
        for child in self.children():
            child.setParent(None)

    def _setup_layout(self):
        self._clear_layout()

        self._layout = QGraphicsLinearLayout(self.orientation)
        self._layout.setContentsMargins(10, 5, 10, 5)
        # If horizontal, there needs to be horizontal space between the items
        if self.orientation == Qt.Horizontal:
            self._layout.setSpacing(10)
        # If vertical spacing, vertical space is provided by child layouts
        else:
            self._layout.setSpacing(0)
        self.setLayout(self._layout)

    def set_domain(self, domain):
        """Handle receiving the domain object.

        Parameters
        ----------
        domain : Orange.data.domain.Domain

        Returns
        -------

        Raises
        ------
        AttributeError
            If the domain does not contain the correct type of class variable.

        """
        raise NotImplementedError()

    def set_items(self, values):
        """Handle receiving an array of items.

        Parameters
        ----------
        values : iterable[object, QColor]

        Returns
        -------

        """
        raise NotImplementedError()

    @staticmethod
    def _convert_to_color(obj):
        if isinstance(obj, QColor):
            return obj
        elif isinstance(obj, tuple) or isinstance(obj, list) \
                or isinstance(obj, np.ndarray):
            assert len(obj) in (3, 4)
            return QColor(*obj)
        else:
            return QColor(obj)

    def setVisible(self, is_visible):
        """Only display the legend if it contains any items."""
        return super().setVisible(is_visible and len(self._layout) > 0)

    def paint(self, painter, options, widget=None):
        painter.save()
        pen = QPen(QColor(196, 197, 193, 200), 1)
        brush = QBrush(QColor(self.bg_color))

        painter.setPen(pen)
        painter.setBrush(brush)
        painter.drawRect(self.contentsRect())
        painter.restore()
コード例 #21
0
    def __init__(self, pixmap, title="", parentItem=None, **kwargs):
        super().__init__(parentItem, **kwargs)
        self.setFocusPolicy(Qt.StrongFocus)
        self._title = None
        self._size = QSizeF()

        layout = QGraphicsLinearLayout(Qt.Vertical, self)
        layout.setSpacing(2)
        layout.setContentsMargins(5, 5, 5, 5)
        self.setContentsMargins(0, 0, 0, 0)

        self.pixmapWidget = GraphicsPixmapWidget(pixmap, self)
        self.labelWidget = GraphicsTextWidget(title, self)

        layout.addItem(self.pixmapWidget)
        layout.addItem(self.labelWidget)
        layout.addStretch()
        layout.setAlignment(self.pixmapWidget, Qt.AlignCenter)
        layout.setAlignment(self.labelWidget, Qt.AlignHCenter | Qt.AlignBottom)

        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        self.setFlag(QGraphicsItem.ItemIsSelectable, True)

        self.setTitle(title)
        self.setTitleWidth(100)
コード例 #22
0
ファイル: histogram.py プロジェクト: szzyiit/orange3
class Histogram(QGraphicsWidget):
    """A basic histogram widget.

    Parameters
    ----------
        data : Table
        variable : Union[int, str, Variable]
        parent : QObject
        height : Union[int, float]
        width : Union[int, float]
        side_padding : Union[int, float]
            Specify the padding between the edges of the histogram and the
            first and last bars.
        top_padding : Union[int, float]
            Specify the padding between the top of the histogram and the
            highest bar.
        bar_spacing : Union[int, float]
            Specify the amount of spacing to place between individual bars.
        border : Union[Tuple[Union[int, float]], int, float]
            Can be anything that can go into the ``'QColor'`` constructor.
            Draws a border around the entire histogram in a given color.
        border_color : Union[QColor, str]
        class_index : int
            The index of the target variable in ``'data'``.
        n_bins : int

    """
    def __init__(self,
                 data,
                 variable,
                 parent=None,
                 height=200,
                 width=300,
                 side_padding=5,
                 top_padding=20,
                 bottom_padding=0,
                 bar_spacing=4,
                 border=0,
                 border_color=None,
                 color_attribute=None,
                 n_bins=10):
        super().__init__(parent)
        self.height, self.width = height, width
        self.padding = side_padding
        self.bar_spacing = bar_spacing

        self.data = data
        self.attribute = data.domain[variable]

        self.x = data.get_column_view(self.attribute)[0].astype(np.float64)
        self.x_nans = np.isnan(self.x)
        self.x = self.x[~self.x_nans]

        if self.attribute.is_discrete:
            self.n_bins = len(self.attribute.values)
        elif self.attribute.is_continuous:
            # If the attribute is continuous but contains fewer values than the
            # bins, it is better to assign each their own bin. We will require
            # at least 2 bins so that the histogram still visually makes sense
            # except if there is only a single value, then we use 3 bins for
            # symmetry
            num_unique = ut.nanunique(self.x).shape[0]
            if num_unique == 1:
                self.n_bins = 3
            else:
                self.n_bins = min(max(2, num_unique), n_bins)

        # Handle target variable index
        self.color_attribute = color_attribute
        if self.color_attribute is not None:
            self.target_var = data.domain[color_attribute]
            self.y = data.get_column_view(color_attribute)[0]
            self.y = self.y[~self.x_nans]
            if not np.issubdtype(self.y.dtype, np.number):
                self.y = self.y.astype(np.float64)
        else:
            self.target_var, self.y = None, None

        # Borders
        self.border_color = border_color if border_color is not None else '#000'
        if isinstance(border, tuple):
            assert len(border) == 4, 'Border tuple must be of size 4.'
            self.border = border
        else:
            self.border = (border, border, border, border)
        t, r, b, l = self.border

        def _draw_border(point_1, point_2, border_width, parent):
            pen = QPen(QColor(self.border_color))
            pen.setCosmetic(True)
            pen.setWidth(border_width)
            line = QGraphicsLineItem(QLineF(point_1, point_2), parent)
            line.setPen(pen)
            return line

        top_left = QPointF(0, 0)
        bottom_left = QPointF(0, self.height)
        top_right = QPointF(self.width, 0)
        bottom_right = QPointF(self.width, self.height)

        self.border_top = _draw_border(top_left, top_right, t,
                                       self) if t else None
        self.border_bottom = _draw_border(bottom_left, bottom_right, b,
                                          self) if b else None
        self.border_left = _draw_border(top_left, bottom_left, l,
                                        self) if l else None
        self.border_right = _draw_border(top_right, bottom_right, r,
                                         self) if r else None

        # _plot_`dim` accounts for all the paddings and spacings
        self._plot_height = self.height
        self._plot_height -= top_padding + bottom_padding
        self._plot_height -= t / 4 + b / 4

        self._plot_width = self.width
        self._plot_width -= 2 * side_padding
        self._plot_width -= (self.n_bins - 2) * bar_spacing
        self._plot_width -= l / 4 + r / 4

        self.__layout = QGraphicsLinearLayout(Qt.Horizontal, self)
        self.__layout.setContentsMargins(side_padding + r / 2,
                                         top_padding + t / 2,
                                         side_padding + l / 2,
                                         bottom_padding + b / 2)
        self.__layout.setSpacing(bar_spacing)

        # If the data contains any non-NaN values, we can draw a histogram
        if self.x.size > 0:
            self.edges, self.distributions = self._histogram()
            self._draw_histogram()

    def _get_histogram_edges(self):
        """Get the edges in the histogram based on the attribute type.

        In case of a continuous variable, we split the variable range into
        n bins. In case of a discrete variable, bins don't make sense, so we
        just return the attribute values.

        This will return the staring and ending edge, not just the edges in
        between (in the case of a continuous variable).

        Returns
        -------
        np.ndarray

        """
        if self.attribute.is_discrete:
            return np.array(
                [self.attribute.to_val(v) for v in self.attribute.values])
        else:
            edges = np.linspace(ut.nanmin(self.x), ut.nanmax(self.x),
                                self.n_bins)
            edge_diff = edges[1] - edges[0]
            edges = np.hstack((edges, [edges[-1] + edge_diff]))

            # If the variable takes on a single value, we still need to spit
            # out some reasonable bin edges
            if np.all(edges == edges[0]):
                edges = np.array([edges[0] - 1, edges[0], edges[0] + 1])

            return edges

    def _get_bin_distributions(self, bin_indices):
        """Compute the distribution of instances within bins.

        Parameters
        ----------
        bin_indices : np.ndarray
            An array with same shape as `x` but containing the bin index of the
            instance.

        Returns
        -------
        np.ndarray
            A 2d array; the first dimension represents different bins, the
            second - the counts of different target values.

        """
        if self.target_var and self.target_var.is_discrete:
            y = self.y
            # TODO This probably also isn't the best handling of sparse data...
            if sp.issparse(y):
                y = np.squeeze(np.array(y.todense()))

            # Since y can contain missing values, we need to filter them out as
            # well as their corresponding `x` values
            y_nan_mask = np.isnan(y)
            y, bin_indices = y[~y_nan_mask], bin_indices[~y_nan_mask]
            y = one_hot(y, dim=len(self.target_var.values))

            bins = np.arange(self.n_bins)[:, np.newaxis]
            mask = bin_indices == bins
            distributions = np.zeros((self.n_bins, y.shape[1]))
            for bin_idx in range(self.n_bins):
                distributions[bin_idx] = y[mask[bin_idx]].sum(axis=0)
        else:
            distributions, _ = ut.bincount(bin_indices.astype(np.int64))
            # To keep things consistent across different variable types, we
            # want to return a 2d array where the first dim represent different
            # bins, and the second the distributions.
            distributions = distributions[:, np.newaxis]

        return distributions

    def _histogram(self):
        assert self.x.size > 0, 'Cannot calculate histogram on empty array'
        edges = self._get_histogram_edges()

        if self.attribute.is_discrete:
            bin_indices = self.x
            # TODO It probably isn't a very good idea to convert a sparse row
            # to a dense array... Converts sparse to 1d numpy array
            if sp.issparse(bin_indices):
                bin_indices = np.squeeze(
                    np.asarray(bin_indices.todense(), dtype=np.int64))
        elif self.attribute.is_continuous:
            bin_indices = ut.digitize(self.x, bins=edges[1:-1]).flatten()

        distributions = self._get_bin_distributions(bin_indices)

        return edges, distributions

    def _draw_histogram(self):
        # In case the data for the variable were all NaNs, then the
        # distributions will be empty, and we don't need to display any bars
        if self.x.size == 0:
            return

        # In case we have a target var, but the values are all NaNs, then there
        # is no sense in displaying anything
        if self.target_var:
            y_nn = self.y[~np.isnan(self.y)]
            if y_nn.size == 0:
                return

        if self.distributions.ndim > 1:
            largest_bin_count = self.distributions.sum(axis=1).max()
        else:
            largest_bin_count = self.distributions.max()

        bar_size = self._plot_width / self.n_bins

        for distr, bin_colors in zip(self.distributions, self._get_colors()):
            bin_count = distr.sum()
            bar_height = bin_count / largest_bin_count * self._plot_height

            bar_layout = QGraphicsLinearLayout(Qt.Vertical)
            bar_layout.setSpacing(0)
            bar_layout.addStretch()
            self.__layout.addItem(bar_layout)

            bar = ProportionalBarItem(  # pylint: disable=blacklisted-name
                distribution=distr,
                colors=bin_colors,
                height=bar_height,
                bar_size=bar_size,
            )
            bar_layout.addItem(bar)

        self.layout()

    def _get_colors(self):
        """Compute colors for different kinds of histograms."""
        target = self.target_var
        if target and target.is_discrete:
            colors = [list(target.palette)[:len(target.values)]] * self.n_bins

        elif self.target_var and self.target_var.is_continuous:
            palette = self.target_var.palette

            bins = np.arange(self.n_bins)[:, np.newaxis]
            edges = self.edges if self.attribute.is_discrete else self.edges[
                1:-1]
            bin_indices = ut.digitize(self.x, bins=edges)
            mask = bin_indices == bins

            colors = []
            for bin_idx in range(self.n_bins):
                biny = self.y[mask[bin_idx]]
                if np.isfinite(biny).any():
                    mean = ut.nanmean(biny) / ut.nanmax(self.y)
                else:
                    mean = 0  # bin is empty, color does not matter
                colors.append([palette.value_to_qcolor(mean)])

        else:
            colors = [[QColor('#ccc')]] * self.n_bins

        return colors

    def boundingRect(self):
        return QRectF(0, 0, self.width, self.height)

    def sizeHint(self, which, constraint):
        return QSizeF(self.width, self.height)

    def sizePolicy(self):
        return QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
コード例 #23
0
ファイル: histogram.py プロジェクト: szzyiit/orange3
    def __init__(self,
                 data,
                 variable,
                 parent=None,
                 height=200,
                 width=300,
                 side_padding=5,
                 top_padding=20,
                 bottom_padding=0,
                 bar_spacing=4,
                 border=0,
                 border_color=None,
                 color_attribute=None,
                 n_bins=10):
        super().__init__(parent)
        self.height, self.width = height, width
        self.padding = side_padding
        self.bar_spacing = bar_spacing

        self.data = data
        self.attribute = data.domain[variable]

        self.x = data.get_column_view(self.attribute)[0].astype(np.float64)
        self.x_nans = np.isnan(self.x)
        self.x = self.x[~self.x_nans]

        if self.attribute.is_discrete:
            self.n_bins = len(self.attribute.values)
        elif self.attribute.is_continuous:
            # If the attribute is continuous but contains fewer values than the
            # bins, it is better to assign each their own bin. We will require
            # at least 2 bins so that the histogram still visually makes sense
            # except if there is only a single value, then we use 3 bins for
            # symmetry
            num_unique = ut.nanunique(self.x).shape[0]
            if num_unique == 1:
                self.n_bins = 3
            else:
                self.n_bins = min(max(2, num_unique), n_bins)

        # Handle target variable index
        self.color_attribute = color_attribute
        if self.color_attribute is not None:
            self.target_var = data.domain[color_attribute]
            self.y = data.get_column_view(color_attribute)[0]
            self.y = self.y[~self.x_nans]
            if not np.issubdtype(self.y.dtype, np.number):
                self.y = self.y.astype(np.float64)
        else:
            self.target_var, self.y = None, None

        # Borders
        self.border_color = border_color if border_color is not None else '#000'
        if isinstance(border, tuple):
            assert len(border) == 4, 'Border tuple must be of size 4.'
            self.border = border
        else:
            self.border = (border, border, border, border)
        t, r, b, l = self.border

        def _draw_border(point_1, point_2, border_width, parent):
            pen = QPen(QColor(self.border_color))
            pen.setCosmetic(True)
            pen.setWidth(border_width)
            line = QGraphicsLineItem(QLineF(point_1, point_2), parent)
            line.setPen(pen)
            return line

        top_left = QPointF(0, 0)
        bottom_left = QPointF(0, self.height)
        top_right = QPointF(self.width, 0)
        bottom_right = QPointF(self.width, self.height)

        self.border_top = _draw_border(top_left, top_right, t,
                                       self) if t else None
        self.border_bottom = _draw_border(bottom_left, bottom_right, b,
                                          self) if b else None
        self.border_left = _draw_border(top_left, bottom_left, l,
                                        self) if l else None
        self.border_right = _draw_border(top_right, bottom_right, r,
                                         self) if r else None

        # _plot_`dim` accounts for all the paddings and spacings
        self._plot_height = self.height
        self._plot_height -= top_padding + bottom_padding
        self._plot_height -= t / 4 + b / 4

        self._plot_width = self.width
        self._plot_width -= 2 * side_padding
        self._plot_width -= (self.n_bins - 2) * bar_spacing
        self._plot_width -= l / 4 + r / 4

        self.__layout = QGraphicsLinearLayout(Qt.Horizontal, self)
        self.__layout.setContentsMargins(side_padding + r / 2,
                                         top_padding + t / 2,
                                         side_padding + l / 2,
                                         bottom_padding + b / 2)
        self.__layout.setSpacing(bar_spacing)

        # If the data contains any non-NaN values, we can draw a histogram
        if self.x.size > 0:
            self.edges, self.distributions = self._histogram()
            self._draw_histogram()
コード例 #24
0
ファイル: ownomogram.py プロジェクト: rowhit/orange3
 def __init__(self):
     super().__init__()
     self._items = []
     self.layout = QGraphicsLinearLayout(Qt.Vertical)
     self.setLayout(self.layout)
コード例 #25
0
ファイル: histogram.py プロジェクト: PrimozGodec/orange3
    def __init__(self, data, variable, parent=None, height=200,
                 width=300, side_padding=5, top_padding=20, bar_spacing=4,
                 border=0, border_color=None, color_attribute=None, n_bins=10):
        super().__init__(parent)
        self.height, self.width = height, width
        self.padding = side_padding
        self.bar_spacing = bar_spacing

        self.data = data
        self.attribute = data.domain[variable]

        self.x = data.get_column_view(self.attribute)[0].astype(np.float64)
        self.x_nans = np.isnan(self.x)
        self.x = self.x[~self.x_nans]

        if self.attribute.is_discrete:
            self.n_bins = len(self.attribute.values)
        elif self.attribute.is_continuous:
            # If the attribute is continuous but contains fewer values than the
            # bins, it is better to assign each their own bin. We will require
            # at least 2 bins so that the histogram still visually makes sense
            # except if there is only a single value, then we use 3 bins for
            # symmetry
            num_unique = ut.nanunique(self.x).shape[0]
            if num_unique == 1:
                self.n_bins = 3
            else:
                self.n_bins = min(max(2, num_unique), n_bins)

        # Handle target variable index
        self.color_attribute = color_attribute
        if self.color_attribute is not None:
            self.target_var = data.domain[color_attribute]
            self.y = data.get_column_view(color_attribute)[0]
            self.y = self.y[~self.x_nans]
            if not np.issubdtype(self.y.dtype, np.number):
                self.y = self.y.astype(np.float64)
        else:
            self.target_var, self.y = None, None

        # Borders
        self.border_color = border_color if border_color is not None else '#000'
        if isinstance(border, tuple):
            assert len(border) == 4, 'Border tuple must be of size 4.'
            self.border = border
        else:
            self.border = (border, border, border, border)
        t, r, b, l = self.border

        def _draw_border(point_1, point_2, border_width, parent):
            pen = QPen(QColor(self.border_color))
            pen.setCosmetic(True)
            pen.setWidth(border_width)
            line = QGraphicsLineItem(QLineF(point_1, point_2), parent)
            line.setPen(pen)
            return line

        top_left = QPointF(0, 0)
        bottom_left = QPointF(0, self.height)
        top_right = QPointF(self.width, 0)
        bottom_right = QPointF(self.width, self.height)

        self.border_top = _draw_border(top_left, top_right, t, self) if t else None
        self.border_bottom = _draw_border(bottom_left, bottom_right, b, self) if b else None
        self.border_left = _draw_border(top_left, bottom_left, l, self) if l else None
        self.border_right = _draw_border(top_right, bottom_right, r, self) if r else None

        # _plot_`dim` accounts for all the paddings and spacings
        self._plot_height = self.height
        self._plot_height -= top_padding
        self._plot_height -= t / 4 + b / 4

        self._plot_width = self.width
        self._plot_width -= 2 * side_padding
        self._plot_width -= (self.n_bins - 2) * bar_spacing
        self._plot_width -= l / 4 + r / 4

        self.__layout = QGraphicsLinearLayout(Qt.Horizontal, self)
        self.__layout.setContentsMargins(
            side_padding + r / 2,
            top_padding + t / 2,
            side_padding + l / 2,
            b / 2
        )
        self.__layout.setSpacing(bar_spacing)

        # If the data contains any non-NaN values, we can draw a histogram
        if self.x.size > 0:
            self.edges, self.distributions = self._histogram()
            self._draw_histogram()
コード例 #26
0
ファイル: owimageviewer.py プロジェクト: RachitKansal/orange3
    def __init__(self, pixmap, title="", parentItem=None, **kwargs):
        super().__init__(parentItem, **kwargs)
        self.setFocusPolicy(Qt.StrongFocus)
        self._title = None
        self._size = QSizeF()

        layout = QGraphicsLinearLayout(Qt.Vertical, self)
        layout.setSpacing(2)
        layout.setContentsMargins(5, 5, 5, 5)
        self.setContentsMargins(0, 0, 0, 0)

        self.pixmapWidget = GraphicsPixmapWidget(pixmap, self)
        self.labelWidget = GraphicsTextWidget(title, self)

        layout.addItem(self.pixmapWidget)
        layout.addItem(self.labelWidget)
        layout.addStretch()
        layout.setAlignment(self.pixmapWidget, Qt.AlignCenter)
        layout.setAlignment(self.labelWidget, Qt.AlignHCenter | Qt.AlignBottom)

        self.setLayout(layout)

        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        self.setFlag(QGraphicsItem.ItemIsSelectable, True)

        self.setTitle(title)
        self.setTitleWidth(100)