예제 #1
0
    def testSelection(self, data):
        """
        Given a

        Parameters
        ----------
        data : (N, 2) array
            Point coordinates

        """
        if len(data) == 0:
            return numpy.zeros(0, dtype=bool)

        def contained(a, left, top, right, bottom):
            assert left <= right and bottom <= top
            x, y = a.T
            return (x >= left) & (x <= right) & (y <= top) & (y >= bottom)

        data = numpy.asarray(data)
        selected = numpy.zeros(len(data), dtype=bool)
        for p1, p2 in self.selection:
            r = QRectF(p1, p2).normalized()
            # Note the inverted top/bottom (Qt coordinate system)
            selected |= contained(data, r.left(), r.bottom(), r.right(),
                                  r.top())
        return selected
예제 #2
0
    def testSelection(self, data):
        """
        Given a

        Parameters
        ----------
        data : (N, 2) array
            Point coordinates

        """
        if len(data) == 0:
            return numpy.zeros(0, dtype=bool)

        def contained(a, left, top, right, bottom):
            assert left <= right and bottom <= top
            x, y = a.T
            return (x >= left) & (x <= right) & (y <= top) & (y >= bottom)

        data = numpy.asarray(data)
        selected = numpy.zeros(len(data), dtype=bool)
        for p1, p2 in self.selection:
            r = QRectF(p1, p2).normalized()
            # Note the inverted top/bottom (Qt coordinate system)
            selected |= contained(data, r.left(), r.bottom(),
                                  r.right(), r.top())
        return selected
예제 #3
0
    def _fetch_tile_layer(self, timestamp, ims, transform, tile_nr, stack_id, ims_req, cache):
        """
        Fetch a single tile from a layer (ImageSource).
        
        Parameters
        ----------
        timestamp
            The timestamp at which ims_req was created
        ims
            The layer (image source) we're fetching from
        transform
            The transform to apply to the fetched data, before storing it in the cache
        tile_nr
            The ID of the fetched tile
        stack_id
            The stack ID of the tile we're fetching (e.g. which T-slice and Z-slice this tile belongs to) 
        ims_req
            A request object (e.g. GrayscaleImageRequest) with a wait() method that produces an item of 
            the appropriate type for the layer (i.e. either a QImage or a QGraphicsItem)
        cache
            The value of self._cache at the time the ims_req was created.
            (The cache can be replaced occasionally. See TileProvider._onSizeChanged().)
        """
        try:
            try:
                with cache:
                    layerTimestamp = cache.layerTimestamp(stack_id, ims, tile_nr)
            except KeyError:
                # May not be a timestamp yet (especially when prefetching)
                layerTimestamp = 0

            tile_rect = QRectF( self.tiling.imageRects[tile_nr] )

            if timestamp > layerTimestamp:
                img = ims_req.wait()
                if isinstance(img, QImage):
                    img = img.transformed(transform)
                elif isinstance(img, QGraphicsItem):
                    # FIXME: It *seems* like applying the same transform to QImages and QGraphicsItems
                    #        makes sense here, but for some strange reason it isn't right.
                    #        For QGraphicsItems, it seems obvious that this is the correct transform.
                    #        I do not understand the formula that produces 'transform', which is used for QImage tiles.
                    img.setTransform(QTransform.fromTranslate(tile_rect.left(), tile_rect.top()), combine=True)
                    img.setTransform(self.tiling.data2scene, combine=True)
                else:
                    assert False, "Unexpected image type: {}".format( type(img) )

                with cache:
                    try:
                        cache.updateTileIfNecessary(stack_id, ims, tile_nr, timestamp, img)
                    except KeyError:
                        pass

                if stack_id == self._current_stack_id \
                        and cache is self._cache:
                    self.sceneRectChanged.emit( tile_rect )
        except BaseException:
            sys.excepthook( *sys.exc_info() )
예제 #4
0
    def _fetch_tile_layer(self, timestamp, ims, transform, tile_nr, stack_id, ims_req, cache):
        """
        Fetch a single tile from a layer (ImageSource).
        
        Parameters
        ----------
        timestamp
            The timestamp at which ims_req was created
        ims
            The layer (image source) we're fetching from
        transform
            The transform to apply to the fetched data, before storing it in the cache
        tile_nr
            The ID of the fetched tile
        stack_id
            The stack ID of the tile we're fetching (e.g. which T-slice and Z-slice this tile belongs to) 
        ims_req
            A request object (e.g. GrayscaleImageRequest) with a wait() method that produces an item of 
            the appropriate type for the layer (i.e. either a QImage or a QGraphicsItem)
        cache
            The value of self._cache at the time the ims_req was created.
            (The cache can be replaced occasionally. See TileProvider._onSizeChanged().)
        """
        try:
            try:
                with cache:
                    layerTimestamp = cache.layerTimestamp(stack_id, ims, tile_nr)
            except KeyError:
                # May not be a timestamp yet (especially when prefetching)
                layerTimestamp = 0

            tile_rect = QRectF( self.tiling.imageRects[tile_nr] )

            if timestamp > layerTimestamp:
                img = ims_req.wait()
                if isinstance(img, QImage):
                    img = img.transformed(transform)
                elif isinstance(img, QGraphicsItem):
                    # FIXME: It *seems* like applying the same transform to QImages and QGraphicsItems
                    #        makes sense here, but for some strange reason it isn't right.
                    #        For QGraphicsItems, it seems obvious that this is the correct transform.
                    #        I do not understand the formula that produces 'transform', which is used for QImage tiles.
                    img.setTransform(QTransform.fromTranslate(tile_rect.left(), tile_rect.top()), combine=True)
                    img.setTransform(self.tiling.data2scene, combine=True)
                else:
                    assert False, "Unexpected image type: {}".format( type(img) )

                with cache:
                    try:
                        cache.updateTileIfNecessary(stack_id, ims, tile_nr, timestamp, img)
                    except KeyError:
                        pass

                if stack_id == self._current_stack_id \
                        and cache is self._cache:
                    self.sceneRectChanged.emit( tile_rect )
        except BaseException:
            sys.excepthook( *sys.exc_info() )
예제 #5
0
 def inputLocation( self ):
     """
     Returns the input location for this connection.
     
     :return     <XConnectionLocation>
     """
     if ( not self.autoCalculateInputLocation() ):
         return self._inputLocation
     
     # auto calculate directions based on the scene
     if ( self._outputNode ):
         outputRect = self._outputNode.sceneRect()
     else:
         y = self._outputPoint.y()
         outputRect = QRectF( self._outputPoint.x(), y, 0, 0 )
     
     if ( self._inputNode ):
         inputRect  = self._inputNode.sceneRect()
     else:
         y = self._inputPoint.y()
         inputRect  = QRectF( self._inputPoint.x(), y, 0, 0 )
     
     # use the input location as potential places where it can be
     iloc    = self._inputLocation
     left    = XConnectionLocation.Left
     right   = XConnectionLocation.Right
     top     = XConnectionLocation.Top
     bot     = XConnectionLocation.Bottom
     
     if ( self._inputNode == self._outputNode ):
         if ( iloc & right ):
             return right
         elif ( iloc & left ):
             return left
         elif ( iloc & top ):
             return top
         else:
             return bot
             
     elif ( (iloc & left)    and outputRect.right() < inputRect.left() ):
         return left
     elif ( (iloc & right)   and inputRect.right() < outputRect.left() ):
         return right
     elif ( (iloc & top)     and outputRect.bottom() < inputRect.top() ):
         return top
     elif ( (iloc & bot) ):
         return bot
     elif ( (iloc & left) ):
         return left
     elif ( (iloc & right) ):
         return right
     elif ( (iloc & top) ):
         return top
     else:
         return left
예제 #6
0
 def outputLocation( self ):
     """
     Returns the location for the output source position.
     
     :return     <XConnectionLocation>
     """
     if ( not self.autoCalculateOutputLocation() ):
         return self._outputLocation
     
     # auto calculate directions based on the scene
     if ( self._outputNode ):
         outputRect = self._outputNode.sceneRect()
     else:
         y = self._outputPoint.y()
         outputRect = QRectF( self._outputPoint.x(), y, 0, 0 )
     
     if ( self._inputNode ):
         inputRect  = self._inputNode.sceneRect()
     else:
         y = self._inputPoint.y()
         inputRect  = QRectF( self._inputPoint.x(), y, 0, 0 )
         
     oloc    = self._outputLocation
     left    = XConnectionLocation.Left
     right   = XConnectionLocation.Right
     top     = XConnectionLocation.Top
     bot     = XConnectionLocation.Bottom
     
     if ( self._inputNode == self._outputNode ):
         if ( oloc & right ):
             return right
         elif ( oloc & left ):
             return left
         elif ( oloc & top ):
             return top
         else:
             return bot
             
     elif ( (oloc & right)   and outputRect.right() < inputRect.left() ):
         return right
     elif ( (oloc & left)    and inputRect.right() < outputRect.left() ):
         return left
     elif ( (oloc & bot)     and outputRect.bottom() < inputRect.top() ):
         return bot
     elif ( (oloc & top) ):
         return top
     elif ( (oloc & right) ):
         return right
     elif ( (oloc & left) ):
         return left
     elif ( (oloc & bot) ):
         return bot
     else:
         return right
예제 #7
0
    def toSearchRect(self, point):
        size = 20
        rect = QRectF()
        rect.setLeft(point.x() - size)
        rect.setRight(point.x() + size)
        rect.setTop(point.y() - size)
        rect.setBottom(point.y() + size)

        transform = self.canvas.getCoordinateTransform()
        ll = transform.toMapCoordinates(rect.left(), rect.bottom())
        ur = transform.toMapCoordinates(rect.right(), rect.top())

        rect = QgsRectangle(ur, ll)
        return rect
예제 #8
0
    def toSearchRect(self, point):
        size = 20
        rect = QRectF()
        rect.setLeft(point.x() - size)
        rect.setRight(point.x() + size)
        rect.setTop(point.y() - size)
        rect.setBottom(point.y() + size)

        transform = self.canvas.getCoordinateTransform()
        ll = transform.toMapCoordinates(rect.left(), rect.bottom())
        ur = transform.toMapCoordinates(rect.right(), rect.top())

        rect = QgsRectangle(ur, ll)
        return rect
예제 #9
0
class GradientLegendItem(QGraphicsObject, GraphicsWidgetAnchor):
    gradient_width = 20

    def __init__(self, title, palette, values, parent):
        QGraphicsObject.__init__(self, parent)
        GraphicsWidgetAnchor.__init__(self)
        self.parent = self.legend = parent
        self.palette = palette
        self.values = values

        self.title = QGraphicsTextItem('%s:' % title, self)
        f = self.title.font()
        f.setBold(True)
        self.title.setFont(f)
        self.title_item = QGraphicsRectItem(self.title.boundingRect(), self)
        self.title_item.setPen(QPen(Qt.NoPen))
        self.title_item.stackBefore(self.title)

        self.label_items = [QGraphicsTextItem(text, self) for text in values]
        for i in self.label_items:
            i.setTextWidth(50)

        self.rect = QRectF()

        self.gradient_item = QGraphicsRectItem(self)
        self.gradient = QLinearGradient()
        self.gradient.setStops([(v * 0.1, self.palette[v * 0.1])
                                for v in range(11)])
        self.orientation = Qt.Horizontal
        self.set_orientation(Qt.Vertical)

        self.setFlag(QGraphicsItem.ItemIgnoresTransformations, True)
        self.setFlag(QGraphicsItem.ItemIsMovable, True)

    def set_orientation(self, orientation):
        return
        if self.orientation == orientation:
            return

        self.orientation = orientation

        if self.orientation == Qt.Vertical:
            height = max(item.boundingRect().height()
                         for item in self.label_items)
            total_height = height * max(5, len(self.label_items))
            interval = (total_height -
                        self.label_items[-1].boundingRect().height()
                        ) / (len(self.label_items) - 1)
            self.gradient_item.setRect(10, 0, self.gradient_width, total_height)
            self.gradient.setStart(10, 0)
            self.gradient.setFinalStop(10, total_height)
            self.gradient_item.setBrush(QBrush(self.gradient))
            self.gradient_item.setPen(QPen(Qt.NoPen))
            y = -20   # hja, no; dela --> pri boundingRect() zato pristejem +20
            x = 0
            move_item_xy(self.title, x, y, False)
            y = 10
            x = 30
            for item in self.label_items:
                move_item_xy(item, x, y, False)
                                       # self.parent.graph.animate_plot)
                y += interval
            self.rect = QRectF(10, 0,
                               self.gradient_width +
                               max(item.boundingRect().width()
                                   for item in self.label_items),
                               self.label_items[0].boundingRect().height() *
                               max(5, len(self.label_items)))
        else:
            # za horizontalno orientacijo nisem dodajal title-a
            width = 50
            height = max(item.boundingRect().height()
                         for item in self.label_items)
            total_width = width * max(5, len(self.label_items))
            interval = (total_width -
                        self.label_items[-1].boundingRect().width()
                        ) / (len(self.label_items) - 1)

            self.gradient_item.setRect(0, 0, total_width, self.gradient_width)
            self.gradient.setStart(0, 0)
            self.gradient.setFinalStop(total_width, 0)
            self.gradient_item.setBrush(QBrush(self.gradient))
            self.gradient_item.setPen(QPen(Qt.NoPen))
            x = 0
            y = 30
            for item in self.label_items:
                move_item_xy(item, x, y, False)
                                       # self.parent.graph.animate_plot)
                x += interval
            self.rect = QRectF(0, 0, total_width, self.gradient_width + height)

    # noinspection PyPep8Naming
    def boundingRect(self):
        width = max(self.rect.width(), self.title_item.boundingRect().width())
        height = self.rect.height() + self.title_item.boundingRect().height()
        return QRectF(self.rect.left(), self.rect.top(), width, height)

    def paint(self, painter, option, widget):
        pass
예제 #10
0
class ZoomSlider(QFrame):
    """
    Two way slider representing narrowing of a view.
    The sliders coorespond to factors: a min value and a max value in the range [0, 1]
    Emits zoomValueChanged(float, float) whenever the markers are adjusted. (float, float) -> (min, max)
    """
    def __init__(self, parent=None, horizontal=True):
        QFrame.__init__(self, parent)

        self.horizontal = horizontal
        if horizontal:
            self.setFrameShape(QFrame.HLine)
            self.setMinimumHeight(21)
            self.tilt = 90
        else:
            self.setFrameShape(QFrame.VLine)
            self.setMinimumWidth(21)
            self.tilt = 180

        self.setFrameShadow(QFrame.Sunken)
        self.setMidLineWidth(3)

        self.setMouseTracking(True)

        self.size = 12

        self.min_value = 0.0
        self.max_value = 1.0

        self.setDefaultColors()
        self.button = Qt.NoButton
        self.selected_marker = 'none'

    def paintEvent(self, paint_event):
        QFrame.paintEvent(self, paint_event)
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        w = self.width()
        h = self.height()

        if self.horizontal:
            self.min_marker = QRectF(w * self.min_value, 4, self.size,
                                     self.size)
            self.max_marker = QRectF(w * self.max_value - self.size - 1, 4,
                                     self.size, self.size)
        else:
            self.min_marker = QRectF(4, h - h * self.min_value - self.size - 1,
                                     self.size, self.size)
            self.max_marker = QRectF(4, h - h * self.max_value, self.size,
                                     self.size)

        pen = painter.pen()
        pen.setWidth(0)
        pen.setColor(QApplication.palette().background().color().dark())
        painter.setPen(pen)

        painter.setBrush(self.min_marker_brush)
        painter.drawPie(self.min_marker, self.tilt * 16, 180 * 16)

        painter.setBrush(self.max_marker_brush)
        painter.drawPie(self.max_marker, self.tilt * 16, -180 * 16)

    def resizeEvent(self, resize_event):
        QFrame.resizeEvent(self, resize_event)

    def _getMinTestMarker(self):
        """Returns the "real" marker bounds. Adjusted for the missing part of an arc."""
        if self.horizontal:
            return QRectF(self.min_marker.left(), self.min_marker.top(),
                          self.min_marker.width() / 2.0,
                          self.min_marker.height())
        else:
            return QRectF(
                self.min_marker.left(),
                self.min_marker.top() + self.min_marker.height() / 2.0,
                self.min_marker.width(),
                self.min_marker.height() / 2.0)

    def _getMaxTestMarker(self):
        """Returns the "real" marker bounds. Adjusted for the missing part of an arc."""
        if self.horizontal:
            return QRectF(
                self.max_marker.left() + self.max_marker.width() / 2.0,
                self.max_marker.top(),
                self.max_marker.width() / 2.0, self.max_marker.height())

        else:
            return QRectF(self.max_marker.left(), self.max_marker.top(),
                          self.max_marker.width(),
                          self.max_marker.height() / 2.0)

    def mouseMoveEvent(self, mouse_event):
        """Dragging or highlighting the markers."""
        self.setDefaultColors()

        min_test_marker = self._getMinTestMarker()

        if min_test_marker.contains(
                mouse_event.x(),
                mouse_event.y()) or self.selected_marker == 'min':
            self.min_marker_brush = self.getDefaultHighlightColor()

        if self.selected_marker == 'min':
            if self.horizontal:
                value = mouse_event.x() / float(self.width())
            else:
                value = (self.height() - mouse_event.y()) / float(
                    self.height())

            self.setMinValue(value, False)

        max_test_marker = self._getMaxTestMarker()

        if max_test_marker.contains(
                mouse_event.x(),
                mouse_event.y()) or self.selected_marker == 'max':
            self.max_marker_brush = self.getDefaultHighlightColor()

        if self.selected_marker == 'max':
            if self.horizontal:
                value = mouse_event.x() / float(self.width())
            else:
                value = (self.height() - mouse_event.y()) / float(
                    self.height())

            self.setMaxValue(value, False)

        self.update()

    def mousePressEvent(self, mouse_event):
        """Selecting a marker."""
        if mouse_event.button() == Qt.LeftButton:
            min_test_marker = self._getMinTestMarker()

            if min_test_marker.contains(mouse_event.x(), mouse_event.y()):
                self.selected_marker = 'min'

            max_test_marker = self._getMaxTestMarker()

            if max_test_marker.contains(mouse_event.x(), mouse_event.y()):
                self.selected_marker = 'max'

    def mouseReleaseEvent(self, mouse_event):
        self.selected_marker = 'none'

    def leaveEvent(self, event):
        self.setDefaultColors()

    def getDefaultMarkerColor(self):
        return QApplication.palette().background().color().light(175)

    def getDefaultHighlightColor(self):
        return QApplication.palette().highlight().color()

    def setDefaultColors(self):
        self.min_marker_brush = self.getDefaultMarkerColor()
        self.max_marker_brush = self.getDefaultMarkerColor()
        self.update()

    def setMaxValue(self, max_value, update=True):
        """The the position of the max marker."""
        if self.horizontal:
            m = float(self.width())
        else:
            m = float(self.height())

        marker_offset = (self.size + 1) / m

        if not self.max_value == max_value:
            self.max_value = max_value
            if self.max_value - marker_offset <= self.min_value:
                self.max_value = self.min_value + marker_offset
            if self.max_value > 1.0:
                self.max_value = 1

            #print "max:", self.min_value, self.max_value

            self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value,
                      self.max_value)

            if update:
                self.update()

    def setMinValue(self, min_value, update=True):
        """The the position of the min marker."""
        if self.horizontal:
            m = float(self.width())
        else:
            m = float(self.height())

        marker_offset = (self.size + 1) / m

        if not self.min_value == min_value:
            self.min_value = min_value
            if self.min_value + marker_offset >= self.max_value:
                self.min_value = self.max_value - marker_offset
            if self.min_value < 0.0:
                self.min_value = 0.0

            #print "min:", self.min_value, self.max_value

            self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value,
                      self.max_value)

            if update:
                self.update()
예제 #11
0
    def draw(self, painter, size=None):
        """
        :Arguments:
            painter : QPainter
                Opened painter on which to draw
        """
        bounding_rect = QRectF()
        position = self.position
        transfer_function = self.transfer_function
        font = QFont(self.font)
        text_color = self.text_color
        line_color = self.line_color
        line_thickness = self.line_thickness
        value_range = self.value_range
        if size is None:
            viewport = painter.viewport()  # viewport rectangle
            mat, ok = painter.worldMatrix().inverted()
            if not ok:
                raise ValueError(
                    "Transformation matrix of painter is singular.")
            viewport = mat.mapRect(viewport)
        else:
            viewport = size
# First, prepare the gradient
        w = viewport.width()
        h = viewport.height()
        #print("Size of viewport: {0}x{1}".format(w, h))
        gr = QLinearGradient()
        nb_values = ceil(w / 5.0)
        brush_color = QColor()
        for i in range(int(nb_values)):
            brush_color.setRgbF(*transfer_function.rgba(i / nb_values))
            gr.setColorAt(i / nb_values, brush_color)
# Second, find its position
        metric = QFontMetricsF(font, painter.device())
        font_test = [str(i) * 5 for i in range(10)]
        lim_width = 0
        lim_height = 0
        for t in font_test:
            rect = metric.boundingRect(t)
            lim_width = max(lim_width, rect.width())
            lim_height = max(lim_height, rect.height())
        lim_height *= 3
        length = self.scale_length
        shift_length = (1 - length) / 2
        width = self.scale_width
        shift_width = self.scale_shift_width
        delta_value = value_range[1] - value_range[0]
        if position == "Top":
            scale_rect = QRectF(shift_length * w, shift_width * h, length * w,
                                width * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.bottomRight()
        elif position == "Right":
            scale_rect = QRectF((1 - shift_width - width) * w,
                                shift_length * h, width * w, length * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.topLeft()
        elif position == "Bottom":
            scale_rect = QRectF(shift_length * w,
                                (1 - shift_width - width) * h, length * w,
                                width * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.topLeft()
            end_pos = scale_rect.topRight()
        elif position == "Left":
            scale_rect = QRectF(shift_width * w, shift_length * h, width * w,
                                length * h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomRight()
            end_pos = scale_rect.topRight()
        else:
            raise ValueError("Invalid scale position: %s" % position)
        shift_pos = (end_pos - start_pos) / delta_value
        if position in ["Left", "Right"]:
            is_vertical = True
            length = scale_rect.height()
        else:
            is_vertical = False
            length = scale_rect.width()
# Get the ticks
        ticks = self.selectValues(length, is_vertical, painter)
        if len(ticks) == 0:
            return
        ticks_str, ticks_extra = self._tick2str(ticks)
        # Figure the shifts
        dist_to_bar = self.text_to_bar
        max_width = 0
        max_height = 0
        for t in ticks_str:
            rect = metric.boundingRect(t)
            max_width = max(rect.width(), max_width)
            max_height = max(rect.height(), max_height)
        if position == "Left":
            shift_left = dist_to_bar
            shift_top = None
        elif position == "Right":
            shift_left = -dist_to_bar - max_width
            shift_top = None
        elif position == "Top":
            shift_left = None
            shift_top = dist_to_bar
        else:
            shift_left = None
            shift_top = -dist_to_bar - max_height
        painter.save()
        painter.translate(viewport.topLeft())
        #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top()))
        painter.setBrush(gr)
        line_pen = QPen(line_color)
        line_pen.setWidth(line_thickness)
        painter.setPen(line_pen)
        painter.drawRect(scale_rect)
        bounding_rect |= scale_rect
        #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(),
        #scale_rect.top(), scale_rect.width(), scale_rect.height()))
        painter.setFont(font)
        painter.setPen(text_color)
        for ts, t in zip(ticks_str, ticks):
            r = metric.boundingRect(ts)
            pos = start_pos + shift_pos * (t - value_range[0])
            if shift_left is None:
                pos.setX(pos.x() - r.width() / 2)
            else:
                pos.setX(pos.x() + shift_left)
            if shift_top is None:
                pos.setY(pos.y() - r.height() / 2)
            else:
                pos.setY(pos.y() + shift_top)
            r.moveTo(pos)
            real_rect = painter.drawText(
                r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts)
            bounding_rect |= real_rect
        if ticks_extra is not None or self.unit:
            unit = self.unit
            exp_width = width = space_width = 0
            exp_txt = ""
            r = exp_r = unit_r = QRectF()
            exp_font = None
            if ticks_extra is not None:
                exp_txt = u"×10"
                r = metric.boundingRect(exp_txt)
                exp_font = QFont(font)
                exp_size = self.exp_size
                if exp_font.pixelSize() != -1:
                    exp_font.setPixelSize(exp_size * exp_font.pixelSize())
                else:
                    exp_font.setPointSizeF(exp_size * exp_font.pointSizeF())
                exp_metric = QFontMetricsF(exp_font, painter.device())
                exp_r = exp_metric.boundingRect(ticks_extra)
            if unit:
                unit_r = metric.boundingRect(unit)
            total_width = r.width() + exp_r.width() + unit_r.width()
            total_height = max(r.height(),
                               unit_r.height()) + exp_r.height() / 2
            pos = scale_rect.topRight()
            log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y()))
            log_debug("Size of image = (%d,%d)" % (w, h))
            log_debug("Size of text = (%g,%g)" % (total_width, total_height))
            if position == "Bottom":
                pos.setY(pos.y() + scale_rect.height() + dist_to_bar)
                pos.setX(pos.x() - total_width)
            elif position == "Top":
                pos.setY(pos.y() - dist_to_bar - total_height)
                pos.setX(pos.x() - total_width)
            else:  # position == "left" or "right"
                pos.setX(pos.x() - (scale_rect.width() + total_width) / 2)
                if pos.x() < 0:
                    pos.setX(dist_to_bar)
                elif pos.x() + total_width + dist_to_bar > w:
                    pos.setX(w - total_width - dist_to_bar)
                pos.setY(pos.y() - dist_to_bar - total_height)
            log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y()))

            if ticks_extra is not None:
                r.moveTo(pos)
                real_rect = painter.drawText(
                    r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter,
                    exp_txt)
                bounding_rect |= real_rect
                pos.setX(pos.x() + r.width())
                pos.setY(pos.y() - metric.ascent() / 2)
                exp_r.moveTo(pos)
                painter.setFont(exp_font)
                real_rect = painter.drawText(
                    exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter,
                    ticks_extra)
                bounding_rect |= real_rect
                pos.setY(pos.y() + metric.ascent() / 2)
            if unit:
                pos.setX(pos.x() + space_width + exp_r.width())
                unit_r.moveTo(pos)
                painter.setFont(font)
                real_rect = painter.drawText(
                    unit_r,
                    Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit)
                bounding_rect |= real_rect
        # Draw the ticks now
        painter.setPen(line_pen)
        tick_size = self.tick_size
        if is_vertical:
            width = scale_rect.width() * tick_size
        else:
            width = scale_rect.height() * tick_size
        pen_width = painter.pen().widthF()
        if pen_width == 0:
            pen_width = 1.0
        for t in ticks:
            pos1 = start_pos + shift_pos * (t - value_range[0])
            pos2 = QPointF(pos1)
            if is_vertical:
                pos1.setX(scale_rect.left() + pen_width)
                pos2.setX(pos1.x() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setX(scale_rect.right() - pen_width)
                pos2.setX(pos1.x() - width + pen_width)
                painter.drawLine(pos1, pos2)
            else:
                pos1.setY(scale_rect.top() + pen_width)
                pos2.setY(pos1.y() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setY(scale_rect.bottom() - pen_width)
                pos2.setY(pos1.y() - width + pen_width)
                painter.drawLine(pos1, pos2)
        painter.restore()
        bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width,
                                               pen_width, pen_width)
        return bounding_rect
예제 #12
0
class ZoomSlider(QFrame):
    """
    Two way slider representing narrowing of a view.
    The sliders coorespond to factors: a min value and a max value in the range [0, 1]
    Emits zoomValueChanged(float, float) whenever the markers are adjusted. (float, float) -> (min, max)
    """
    def __init__(self, parent=None, horizontal=True):
        QFrame.__init__(self, parent)

        self.horizontal = horizontal
        if horizontal:
            self.setFrameShape(QFrame.HLine)
            self.setMinimumHeight(21)
            self.tilt = 90
        else:
            self.setFrameShape(QFrame.VLine)
            self.setMinimumWidth(21)
            self.tilt = 180

        self.setFrameShadow(QFrame.Sunken)
        self.setMidLineWidth(3)

        self.setMouseTracking(True)

        self.size = 12

        self.min_value = 0.0
        self.max_value = 1.0

        self.setDefaultColors()
        self.button = Qt.NoButton
        self.selected_marker = 'none'


    def paintEvent(self, paint_event):
        QFrame.paintEvent(self, paint_event)
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        w = self.width()
        h = self.height()

        if self.horizontal:
            self.min_marker = QRectF(w * self.min_value, 4, self.size, self.size)
            self.max_marker = QRectF(w * self.max_value - self.size - 1, 4, self.size, self.size)
        else:
            self.min_marker = QRectF(4, h - h * self.min_value - self.size - 1, self.size, self.size)
            self.max_marker = QRectF(4, h - h * self.max_value, self.size, self.size)

        pen = painter.pen()
        pen.setWidth(0)
        pen.setColor(QApplication.palette().background().color().dark())
        painter.setPen(pen)

        painter.setBrush(self.min_marker_brush)
        painter.drawPie(self.min_marker, self.tilt * 16, 180 * 16)

        painter.setBrush(self.max_marker_brush)
        painter.drawPie(self.max_marker, self.tilt * 16, -180 * 16)

    def resizeEvent (self, resize_event):
        QFrame.resizeEvent(self, resize_event)


    def _getMinTestMarker(self):
        """Returns the "real" marker bounds. Adjusted for the missing part of an arc."""
        if self.horizontal:
            return QRectF(self.min_marker.left(),
                          self.min_marker.top(),
                          self.min_marker.width() / 2.0,
                          self.min_marker.height())
        else:
            return QRectF(self.min_marker.left(),
                          self.min_marker.top() + self.min_marker.height() / 2.0,
                          self.min_marker.width(),
                          self.min_marker.height() / 2.0)

    def _getMaxTestMarker(self):
        """Returns the "real" marker bounds. Adjusted for the missing part of an arc."""
        if self.horizontal:
            return QRectF(self.max_marker.left() + self.max_marker.width() / 2.0,
                          self.max_marker.top(),
                          self.max_marker.width() / 2.0,
                          self.max_marker.height())

        else:
            return QRectF(self.max_marker.left(),
                          self.max_marker.top(),
                          self.max_marker.width(),
                          self.max_marker.height() / 2.0)

    def mouseMoveEvent (self, mouse_event):
        """Dragging or highlighting the markers."""
        self.setDefaultColors()

        min_test_marker = self._getMinTestMarker()

        if min_test_marker.contains(mouse_event.x(), mouse_event.y()) or self.selected_marker == 'min':
            self.min_marker_brush = self.getDefaultHighlightColor()

        if self.selected_marker == 'min':
            if self.horizontal:
                value = mouse_event.x() / float(self.width())
            else:
                value = (self.height() - mouse_event.y()) / float(self.height())

            self.setMinValue(value, False)

        max_test_marker = self._getMaxTestMarker()

        if max_test_marker.contains(mouse_event.x(), mouse_event.y()) or self.selected_marker == 'max':
            self.max_marker_brush = self.getDefaultHighlightColor()

        if self.selected_marker == 'max':
            if self.horizontal:
                value = mouse_event.x() / float(self.width())
            else:
                value = (self.height() - mouse_event.y()) / float(self.height())
                
            self.setMaxValue(value, False)

        self.update()


    def mousePressEvent (self, mouse_event):
        """Selecting a marker."""
        if mouse_event.button() == Qt.LeftButton:
            min_test_marker = self._getMinTestMarker()

            if min_test_marker.contains(mouse_event.x(), mouse_event.y()):
                self.selected_marker = 'min'

            max_test_marker = self._getMaxTestMarker()

            if max_test_marker.contains(mouse_event.x(), mouse_event.y()):
                self.selected_marker = 'max'


    def mouseReleaseEvent (self, mouse_event):
        self.selected_marker = 'none'

    def leaveEvent (self, event):
        self.setDefaultColors()

    def getDefaultMarkerColor(self):
        return QApplication.palette().background().color().light(175)

    def getDefaultHighlightColor(self):
        return QApplication.palette().highlight().color()

    def setDefaultColors(self):
        self.min_marker_brush = self.getDefaultMarkerColor()
        self.max_marker_brush = self.getDefaultMarkerColor()
        self.update()

    def setMaxValue(self, max_value, update=True):
        """The the position of the max marker."""
        if self.horizontal:
            m = float(self.width())
        else:
            m = float(self.height())

        marker_offset = (self.size + 1) / m

        if not self.max_value == max_value:
            self.max_value = max_value
            if self.max_value - marker_offset <= self.min_value:
                self.max_value = self.min_value + marker_offset
            if self.max_value > 1.0:
                self.max_value = 1


            self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value)

            if update:
                self.update()

    def setMinValue(self, min_value, update=True):
        """The the position of the min marker."""
        if self.horizontal:
            m = float(self.width())
        else:
            m = float(self.height())

        marker_offset = (self.size + 1) / m

        if not self.min_value == min_value:
            self.min_value = min_value
            if self.min_value + marker_offset >= self.max_value:
                self.min_value = self.max_value - marker_offset
            if self.min_value < 0.0:
                self.min_value = 0.0


            self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value)

            if update:
                self.update()
예제 #13
0
    def run_loader(self):
        filename = self.result
        try:
            self.retryObject = None
# First, prepare the data by getting the images and computing how big they
# should be
            f = open(filename)
            first_line = f.readline()
            f.close()
            if first_line.startswith("TRKR_VERSION"):
                result = Result(None)
                result.load(self.result, **self._loading_arguments)
                result_type = "Growth"
            else:
                result = TrackingData()
                result.load(self.result, **self._loading_arguments)
                result_type = "Data"
            self.result = result
            self.result_type = result_type
            if result_type == "Data":
                data = result
                images = data.images_name
                if data.cells:
                    self.has_cells = True
                    self.has_walls = True
                else:
                    self.has_cells = False
                    self.has_walls = False
                self.has_points = bool(data.cell_points)
            else:
                data = result.data
                images = result.images
                self.has_cells = False
                self.has_walls = False
                self.has_points = False
            self.images = images
            cache = image_cache.cache
            self.update_nb_images(len(result))
            bbox = QRectF()
            ms = data.minScale()
            for i in range(len(result)):
                img_name = images[i]
                img_data = data[img_name]
                img = cache.image(data.image_path(img_name))
                matrix = QTransform()
                matrix = img_data.matrix()
                sc = QTransform()
                sc.scale(1.0/ms, 1.0/ms)
                matrix *= sc
                r = QRectF(img.rect())
                rbox = matrix.map(QPolygonF(r)).boundingRect()
                bbox |= rbox
                log_debug("Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" %
                             (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(),
                              bbox.width(), bbox.height(), bbox.left(), bbox.top()))
                log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" %
                            (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy()))
                if result_type == "Growth":
                    if result.cells[i]:
                        self.has_cells = True
                    if result.walls[i]:
                        self.has_walls = True
                    self.has_points = bool(result.data.cell_points)
                self.nextImage()
            translate = bbox.topLeft()
            translate *= -1
            self.translate = translate
            size = bbox.size().toSize()
            self.img_size = size
            self._crop = QRect(QPoint(0,0), size)
            self.finished()
            self._loading_arguments = {} # All done, we don't need that anymore
        except RetryTrackingDataException as ex:
            ex.filename = filename
            self.retryObject = ex
            self.finished()
            return
        except Exception as ex:
            _, _, exceptionTraceback = sys.exc_info()
            self.abort(ex, traceback=exceptionTraceback)
            raise
예제 #14
0
    def layout(self,
               scene,
               nodes,
               center=None,
               padX=None,
               padY=None,
               direction=None,
               animationGroup=None):
        """
        Lays out the nodes for this scene based on a block layering algorithm.
        
        :param      scene          | <XNodeScene>
                    nodes          | [<XNode>, ..]
                    center         | <QPointF> || None
                    padX           | <int> || None
                    padY           | <int> || None
                    direction      | <Qt.Direction>
                    animationGroup | <QAnimationGroup> || None
        
        :return     {<XNode>: <QRectF>, ..} | new rects per affected node
        """
        nodes = filter(lambda x: x is not None and x.isVisible(), nodes)

        # make sure we have at least 1 node, otherwise, it is already laid out
        if not nodes or len(nodes) == 1:
            return {}

        # calculate the default padding based on the scene
        if padX == None:
            if direction == Qt.Vertical:
                padX = 2 * scene.cellWidth()
            else:
                padX = 4 * scene.cellWidth()

        if padY == None:
            if direction == Qt.Vertical:
                padY = 4 * scene.cellHeight()
            else:
                padY = 2 * scene.cellWidth()

        # step 1: create a mapping of the connections
        connection_map = self.connectionMap(scene, nodes)

        # step 2: organize the nodes into layers based on their connection chain
        layers = self.generateLayers(scene, nodes, connection_map)
        layers = list(reversed(layers))

        # step 3: calculate the total dimensions for the layout
        bounds = QRectF()

        # step 3.1: compare the nodes together that have common connections
        layer_widths = []
        layer_heights = []
        node_heights = {}
        node_widths = {}

        for layer_index, layer in enumerate(layers):
            layer_w = 0
            layer_h = 0

            layer_node_w = []
            layer_node_h = []

            self.organizeLayer(layer, connection_map)

            for node in layer:
                rect = node.rect()

                layer_node_w.append(rect.width())
                layer_node_h.append(rect.height())

                if direction == Qt.Vertical:
                    layer_w += rect.width()
                    layer_h = max(rect.height(), layer_h)
                else:
                    layer_w = max(rect.width(), layer_w)
                    layer_h += rect.height()

            # update the bounding area
            if direction == Qt.Vertical:
                layer_w += padX * 1 - len(layer)
                bounds.setWidth(max(layer_w, bounds.width()))
                bounds.setHeight(bounds.height() + layer_h)
            else:
                layer_h += padY * 1 - len(layer)
                bounds.setWidth(bounds.width() + layer_w)
                bounds.setHeight(max(layer_h, bounds.height()))

            node_widths[layer_index] = layer_node_w
            node_heights[layer_index] = layer_node_h

            layer_widths.append(layer_w)
            layer_heights.append(layer_h)

        if not center:
            center = scene.sceneRect().center()

        w = bounds.width()
        h = bounds.height()
        bounds.setX(center.x() - bounds.width() / 2.0)
        bounds.setY(center.y() - bounds.height() / 2.0)
        bounds.setWidth(w)
        bounds.setHeight(h)

        # step 4: assign positions for each node by layer
        processed_nodes = {}
        layer_grps = [(i, layer) for i, layer in enumerate(layers)]
        layer_grps.sort(key=lambda x: len(x[1]))

        for layer_index, layer in reversed(layer_grps):
            layer_width = layer_widths[layer_index]
            layer_height = layer_heights[layer_index]

            # determine the starting point for this layer
            if direction == Qt.Vertical:
                offset = layer_index * padY + sum(layer_heights[:layer_index])
                point = QPointF(bounds.x(), offset + bounds.y())
            else:
                offset = layer_index * padX + sum(layer_widths[:layer_index])
                point = QPointF(offset + bounds.x(), bounds.y())

            # assign node positions based on existing connections
            for node_index, node in enumerate(layer):
                max_, min_ = (None, None)
                inputs, outputs = connection_map[node]
                for connected_node in inputs + outputs:
                    if not connected_node in processed_nodes:
                        continue

                    npos = processed_nodes[connected_node]
                    nrect = connected_node.rect()
                    rect = QRectF(npos.x(), npos.y(), nrect.width(),
                                  nrect.height())

                    if direction == Qt.Vertical:
                        if min_ is None:
                            min_ = rect.left()
                        min_ = min(rect.left(), min_)
                        max_ = max(rect.right(), max_)
                    else:
                        if min_ is None:
                            min_ = rect.top()
                        min_ = min(rect.top(), min_)
                        max_ = max(rect.bottom(), max_)

                if direction == Qt.Vertical:
                    off_x = 0
                    off_y = (layer_height - node.rect().height()) / 2.0
                    start_x = (bounds.width() - layer_width)
                    start_y = 0
                else:
                    off_x = (layer_width - node.rect().width()) / 2.0
                    off_y = 0
                    start_x = 0
                    start_y = (bounds.height() - layer_height)

                # align against existing nodes
                if not None in (min_, max):
                    if direction == Qt.Vertical:
                        off_x = (max_ - min_) / 2.0 - node.rect().width() / 2.0
                        point_x = min_ + off_x
                        point_y = point.y() + off_y
                    else:
                        off_y = (max_ -
                                 min_) / 2.0 - node.rect().height() / 2.0
                        point_x = point.x() + off_x
                        point_y = min_ + off_y

                # otherwise, align based on its position in the layer
                else:
                    if direction == Qt.Vertical:
                        off_x = sum(node_widths[layer_index][:node_index])
                        off_x += node_index * padX
                        off_x += start_x

                        point_x = point.x() + off_x
                        point_y = point.y() + off_y
                    else:
                        off_y = sum(node_heights[layer_index][:node_index])
                        off_y += node_index * padY
                        off_y += start_y

                        point_x = point.x() + off_x
                        point_y = point.y() + off_y

                if not animationGroup:
                    node.setPos(point_x, point_y)
                else:
                    anim = XNodeAnimation(node, 'setPos')
                    anim.setStartValue(node.pos())
                    anim.setEndValue(QPointF(point_x, point_y))
                    animationGroup.addAnimation(anim)

                processed_nodes[node] = QPointF(point_x, point_y)

                if self._testing:
                    QApplication.processEvents()
                    time.sleep(1)

        return processed_nodes
예제 #15
0
class TreeNode(object):
	"""store data for a class and manage hierarchy"""
	def __init__(self, classid,name,rect=None,color=None,pos=None,accu = 1.0,parent=None):
		super(TreeNode, self).__init__()
		self.classid = classid
		self.name = name
		self.parent = parent
		self.accu = accu
		self.rect = QRectF(*rect) if rect else rect
		self.color = QColor(color) if color else color
		self.pos = QPointF(*pos) if pos else pos 
		self.children = []
		if parent:
			parent.children.append(self)

	# def __init__(self,jsonobj):
	# 	self.__init__(jsonobj['id'],jsonobj['name'],jsonobj['rect'],jsonobj['color'],jsonobj['pos'])
	# 	for child in jsonobj['children']:
	# 		childItem = TreeNode(child)
	# 		self.children.append(childItem)
	# 		childItem.parent = self

	def isLeaf(self):
		if self.children:
			return False
		else:
			return True

	def isRoot(self):
		if self.parent:
			return False
		else:
			return True

	def toJSON(self):
		jsonObj = {}
		jsonObj['id']= self.classid
		jsonObj['name'] = self.name
		jsonObj['rect'] = [self.rect.left(),self.rect.top(),self.rect.width(),self.rect.height()] if self.rect else self.rect
		jsonObj['color'] = str(self.color.name()) if self.color else self.color
		jsonObj['pos'] = [self.pos.x(),self.pos.y()] if isinstance(self.pos,QPointF) else self.pos
		jsonObj['accu'] = self.accu
		jsonObj['children'] = []
		for child in self.children:
			jsonObj['children'].append(child.toJSON())
		return jsonObj

	def __str__(self):
		tempstr = "%s   %s\n" % (self.classid,self.name)
		for child in self.children:
			tempstr+= '   '+str(child)
		return tempstr 

	def findNode(self,id):
		if self.classid == id:
			return self
		for child in self.children:
			result = child.findNode(id)
			if result:
				return result
		return None

	def toplogicalDistance(self,id1,id2):
		if id1==id2:
			return 0
		else:
			node1 = self.findNode(id1)
			node2 = self.findNode(id2)
			if node1 and node2:
				if node1.parent == node2.parent:
					return 1
				else:
					return 2
		return 0

	def matrixDistance(self,id1,id2):
		if id1==id2:
			return 0
		else:
			node1 = self.findNode(id1)
			node2 = self.findNode(id2)
			if node1 and node2:
					pos1 = node1.pos + node1.parent.pos
					pos2 = node2.pos + node2.parent.pos
					return QLineF(pos1,pos2).length()
		return 2000.0

	def transactionPossibility(self,id1,id2):
		node1 = self.findNode(id1)
		node2 = self.findNode(id2)
		if node1 and node2:
			return node1.accu * node2.accu
		else:
			return 1.0
예제 #16
0
 def run_loader(self):
     filename = self.result
     try:
         self.retryObject = None
         # First, prepare the data by getting the images and computing how big they
         # should be
         f = open(filename)
         first_line = f.readline()
         f.close()
         if first_line.startswith("TRKR_VERSION"):
             result = Result(None)
             result.load(self.result, **self._loading_arguments)
             result_type = "Growth"
         else:
             result = TrackingData()
             result.load(self.result, **self._loading_arguments)
             result_type = "Data"
         self.result = result
         self.result_type = result_type
         if result_type == "Data":
             data = result
             images = data.images_name
             if data.cells:
                 self.has_cells = True
                 self.has_walls = True
             else:
                 self.has_cells = False
                 self.has_walls = False
             self.has_points = bool(data.cell_points)
         else:
             data = result.data
             images = result.images
             self.has_cells = False
             self.has_walls = False
             self.has_points = False
         self.images = images
         cache = image_cache.cache
         self.update_nb_images(len(result))
         bbox = QRectF()
         ms = data.minScale()
         for i in range(len(result)):
             img_name = images[i]
             img_data = data[img_name]
             img = cache.image(data.image_path(img_name))
             matrix = QTransform()
             matrix = img_data.matrix()
             sc = QTransform()
             sc.scale(1.0 / ms, 1.0 / ms)
             matrix *= sc
             r = QRectF(img.rect())
             rbox = matrix.map(QPolygonF(r)).boundingRect()
             bbox |= rbox
             log_debug(
                 "Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n"
                 % (img_name, r.width(), r.height(), rbox.width(),
                    rbox.height(), rbox.left(), rbox.top(), bbox.width(),
                    bbox.height(), bbox.left(), bbox.top()))
             log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" %
                       (matrix.m11(), matrix.m12(), matrix.dx(),
                        matrix.m21(), matrix.m22(), matrix.dy()))
             if result_type == "Growth":
                 if result.cells[i]:
                     self.has_cells = True
                 if result.walls[i]:
                     self.has_walls = True
                 self.has_points = bool(result.data.cell_points)
             self.nextImage()
         translate = bbox.topLeft()
         translate *= -1
         self.translate = translate
         size = bbox.size().toSize()
         self.img_size = size
         self._crop = QRect(QPoint(0, 0), size)
         self.finished()
         self._loading_arguments = {
         }  # All done, we don't need that anymore
     except RetryTrackingDataException as ex:
         ex.filename = filename
         self.retryObject = ex
         self.finished()
         return
     except Exception as ex:
         _, _, exceptionTraceback = sys.exc_info()
         self.abort(ex, traceback=exceptionTraceback)
         raise
예제 #17
0
    def draw(self, painter, size = None):
        """
        :Arguments:
            painter : QPainter
                Opened painter on which to draw
        """
        bounding_rect = QRectF()
        position = self.position
        transfer_function = self.transfer_function
        font = QFont(self.font)
        text_color = self.text_color
        line_color = self.line_color
        line_thickness = self.line_thickness
        value_range = self.value_range
        if size is None:
            viewport = painter.viewport() # viewport rectangle
            mat, ok = painter.worldMatrix().inverted()
            if not ok:
                raise ValueError("Transformation matrix of painter is singular.")
            viewport = mat.mapRect(viewport)
        else:
            viewport = size
# First, prepare the gradient
        w = viewport.width()
        h = viewport.height()
        #print("Size of viewport: {0}x{1}".format(w, h))
        gr = QLinearGradient()
        nb_values = ceil(w/5.0)
        brush_color = QColor()
        for i in range(int(nb_values)):
            brush_color.setRgbF(*transfer_function.rgba(i/nb_values))
            gr.setColorAt(i/nb_values, brush_color)
# Second, find its position
        metric = QFontMetricsF(font, painter.device())
        font_test = [ str(i)*5 for i in range(10) ]
        lim_width = 0
        lim_height = 0
        for t in font_test:
            rect = metric.boundingRect(t)
            lim_width  = max(lim_width,  rect.width())
            lim_height = max(lim_height, rect.height())
        lim_height *= 3
        length = self.scale_length
        shift_length = (1-length)/2
        width = self.scale_width
        shift_width = self.scale_shift_width
        delta_value = value_range[1]-value_range[0]
        if position == "Top":
            scale_rect = QRectF(shift_length*w, shift_width*h, length*w, width*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.bottomRight()
        elif position == "Right":
            scale_rect = QRectF((1-shift_width-width)*w, shift_length*h, width*w, length*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomLeft()
            end_pos = scale_rect.topLeft()
        elif position == "Bottom":
            scale_rect = QRectF(shift_length*w, (1-shift_width-width)*h, length*w, width*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.left(), scale_rect.center().y())
            gr.setFinalStop(scale_rect.right(), scale_rect.center().y())
            start_pos = scale_rect.topLeft()
            end_pos = scale_rect.topRight()
        elif position == "Left":
            scale_rect = QRectF(shift_width*w, shift_length*h, width*w, length*h)
            limit_rect(scale_rect, viewport, lim_width, lim_height)
            gr.setStart(scale_rect.center().x(), scale_rect.bottom())
            gr.setFinalStop(scale_rect.center().x(), scale_rect.top())
            start_pos = scale_rect.bottomRight()
            end_pos = scale_rect.topRight()
        else:
            raise ValueError("Invalid scale position: %s" % position)
        shift_pos = (end_pos-start_pos)/delta_value
        if position in ["Left", "Right"]:
            is_vertical = True
            length = scale_rect.height()
        else:
            is_vertical = False
            length = scale_rect.width()
# Get the ticks
        ticks = self.selectValues(length, is_vertical, painter)
        if len(ticks) == 0:
            return
        ticks_str, ticks_extra = self._tick2str(ticks)
# Figure the shifts
        dist_to_bar = self.text_to_bar
        max_width = 0
        max_height = 0
        for t in ticks_str:
            rect = metric.boundingRect(t)
            max_width = max(rect.width(), max_width)
            max_height = max(rect.height(), max_height)
        if position == "Left":
            shift_left = dist_to_bar
            shift_top = None
        elif position == "Right":
            shift_left = -dist_to_bar-max_width
            shift_top = None
        elif position == "Top":
            shift_left = None
            shift_top = dist_to_bar
        else:
            shift_left = None
            shift_top = -dist_to_bar-max_height
        painter.save()
        painter.translate(viewport.topLeft())
        #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top()))
        painter.setBrush(gr)
        line_pen = QPen(line_color)
        line_pen.setWidth(line_thickness)
        painter.setPen(line_pen)
        painter.drawRect(scale_rect)
        bounding_rect |= scale_rect
        #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(),
            #scale_rect.top(), scale_rect.width(), scale_rect.height()))
        painter.setFont(font)
        painter.setPen(text_color)
        for ts,t in zip(ticks_str, ticks):
            r = metric.boundingRect(ts)
            pos = start_pos+shift_pos*(t-value_range[0])
            if shift_left is None:
                pos.setX( pos.x() - r.width()/2 )
            else:
                pos.setX( pos.x() + shift_left )
            if shift_top is None:
                pos.setY( pos.y() - r.height()/2)
            else:
                pos.setY( pos.y() + shift_top )
            r.moveTo(pos)
            real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts)
            bounding_rect |= real_rect
        if ticks_extra is not None or self.unit:
            unit = self.unit
            exp_width = width = space_width = 0
            exp_txt = ""
            r = exp_r = unit_r = QRectF()
            exp_font = None
            if ticks_extra is not None:
                exp_txt = u"×10"
                r = metric.boundingRect(exp_txt)
                exp_font = QFont(font)
                exp_size = self.exp_size
                if exp_font.pixelSize() != -1:
                    exp_font.setPixelSize(exp_size*exp_font.pixelSize())
                else:
                    exp_font.setPointSizeF(exp_size*exp_font.pointSizeF())
                exp_metric = QFontMetricsF(exp_font, painter.device())
                exp_r = exp_metric.boundingRect(ticks_extra)
            if unit:
                unit_r = metric.boundingRect(unit)
            total_width = r.width()+exp_r.width()+unit_r.width()
            total_height = max(r.height(),unit_r.height())+exp_r.height()/2
            pos = scale_rect.topRight()
            log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y()))
            log_debug("Size of image = (%d,%d)" % (w,h))
            log_debug("Size of text = (%g,%g)" % (total_width, total_height))
            if position == "Bottom":
                pos.setY(pos.y() + scale_rect.height() + dist_to_bar)
                pos.setX(pos.x() - total_width)
            elif position == "Top":
                pos.setY(pos.y() - dist_to_bar - total_height)
                pos.setX(pos.x() - total_width)
            else: # position == "left" or "right"
                pos.setX(pos.x() - (scale_rect.width() + total_width)/2)
                if pos.x() < 0:
                    pos.setX(dist_to_bar)
                elif pos.x()+total_width+dist_to_bar > w:
                    pos.setX(w - total_width - dist_to_bar)
                pos.setY(pos.y() - dist_to_bar - total_height)
            log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y()))

            if ticks_extra is not None:
                r.moveTo(pos)
                real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, exp_txt)
                bounding_rect |= real_rect
                pos.setX( pos.x() + r.width() )
                pos.setY( pos.y() - metric.ascent()/2 )
                exp_r.moveTo(pos)
                painter.setFont(exp_font)
                real_rect = painter.drawText(exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ticks_extra)
                bounding_rect |= real_rect
                pos.setY(pos.y() + metric.ascent()/2)
            if unit:
                pos.setX(pos.x() + space_width + exp_r.width())
                unit_r.moveTo(pos)
                painter.setFont(font)
                real_rect = painter.drawText(unit_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit)
                bounding_rect |= real_rect
        # Draw the ticks now
        painter.setPen(line_pen)
        tick_size = self.tick_size
        if is_vertical:
            width = scale_rect.width()*tick_size
        else:
            width = scale_rect.height()*tick_size
        pen_width = painter.pen().widthF()
        if pen_width == 0:
            pen_width = 1.0
        for t in ticks:
            pos1 = start_pos + shift_pos*(t-value_range[0])
            pos2 = QPointF(pos1)
            if is_vertical:
                pos1.setX(scale_rect.left() + pen_width)
                pos2.setX(pos1.x() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setX(scale_rect.right() - pen_width)
                pos2.setX(pos1.x() - width + pen_width)
                painter.drawLine(pos1, pos2)
            else:
                pos1.setY(scale_rect.top() + pen_width)
                pos2.setY(pos1.y() + width - pen_width)
                painter.drawLine(pos1, pos2)
                pos1.setY(scale_rect.bottom() - pen_width)
                pos2.setY(pos1.y() - width + pen_width)
                painter.drawLine(pos1, pos2)
        painter.restore()
        bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width, pen_width, pen_width)
        return bounding_rect
예제 #18
0
class DrawManager(QObject):
    """
    DEPRECATED.
    Will be replaced with BrushingModel, BrushingControler, BrushStroke.
    """
     
    brushSizeChanged  = pyqtSignal(int)
    brushColorChanged = pyqtSignal(QColor)
    
    minBrushSize       = 1
    maxBrushSize       = 61
    defaultBrushSize   = 3
    defaultDrawnNumber = 1
    defaultColor       = Qt.white
    erasingColor       = Qt.black
    
    def __init__(self):
        QObject.__init__(self)
        self.shape = None
        self.bb    = QRect() #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self.drawnNumber = self.defaultDrawnNumber

        self.penVis  = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.penDraw = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
        self.pos = None
        self.erasing = False
        
        #on which layer do we want to draw when self.drawingEnabled?
        self.drawOnto = None
        
        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def growBoundingBox(self):
        self.bb.setLeft(  max(0, self.bb.left()-self.brushSize-1))
        self.bb.setTop(   max(0, self.bb.top()-self.brushSize-1 ))
        self.bb.setRight( min(self.shape[0], self.bb.right()+self.brushSize+1))
        self.bb.setBottom(min(self.shape[1], self.bb.bottom()+self.brushSize+1))

    def toggleErase(self):
        self.erasing = not(self.erasing)

    def setErasing(self):
        self.erasing = True
        self.brushColorChanged.emit(self.erasingColor)
    
    def disableErasing(self):
        self.erasing = False
        self.brushColorChanged.emit(self.drawColor)

    def setBrushSize(self, size):
        self.brushSize = size
        self.penVis.setWidth(size)
        self.penDraw.setWidth(size)
        self.brushSizeChanged.emit(self.brushSize)
    
    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)
        
    def getBrushSize(self):
        return self.brushSize
    
    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b-1)
        
    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b+1)
        
    def setBrushColor(self, color):
        self.drawColor = color
        self.penVis.setColor(color)
        self.emit.brushColorChanged(self.drawColor)
        
    def beginDrawing(self, pos, shape):
        self.shape = shape
        self.bb = QRectF(0, 0, self.shape[0], self.shape[1])
        self.scene.clear()
        if self.erasing:
            self.penVis.setColor(self.erasingColor)
        else:
            self.penVis.setColor(self.drawColor)
        self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001)
        line = self.moveTo(pos)
        return line

    def endDrawing(self, pos):
        self.moveTo(pos)
        self.growBoundingBox()

        tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        
        self.scene.render(painter, QRectF(QPointF(0,0), self.bb.size()), self.bb)
        
        return (self.bb.left(), self.bb.top(), tempi) #TODO: hackish, probably return a class ??

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.shape)
        return res

    def moveTo(self, pos):    
        lineVis = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y())
        lineVis.setPen(self.penVis)
        
        line = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y())
        line.setPen(self.penDraw)
        self.scene.addItem(line)

        self.pos = pos
        x = pos.x()
        y = pos.y()
        #update bounding Box :
        if x > self.bb.right():
            self.bb.setRight(x)
        if x < self.bb.left():
            self.bb.setLeft(x)
        if y > self.bb.bottom():
            self.bb.setBottom(y)
        if y < self.bb.top():
            self.bb.setTop(y)
        return lineVis