def move(self, vb, xv=None):
     if vb is not None:
         if xv is None:
             xv = self.pos().x()
         ys = vb.geometry().top()
         yv = vb.mapSceneToView(pg.Point(0.0, ys)).y()
         self.setPos(pg.Point(xv, yv))
Exemple #2
0
    def paint_flag(self, painter, p1):
        axis = self._axis()
        if axis is None:
            return
        h = axis.geometry().height()
        he = h // 3
        w2 = h // 2
        if self._shape in [None, 'none']:
            return
        if self._shape in ['right']:
            wl, wr = -w2, 0
        elif self._shape in ['left']:
            wl, wr = 0, w2
        else:
            wl, wr = -w2, w2

        brush = pg.mkBrush(self.color)
        painter.setBrush(brush)
        painter.setPen(None)
        painter.resetTransform()

        painter.translate(p1)
        painter.drawConvexPolygon([
            pg.Point(0, 0),
            pg.Point(wl, -he),
            pg.Point(wl, -h),
            pg.Point(wr, -h),
            pg.Point(wr, -he)
        ])
Exemple #3
0
    def __init__(self, delegate):
        self.delegate = delegate
        self.source = self.delegate.source
        source = self.source

        pg.ROI.__init__(
            self,
            pos=pg.Point(source.outline()[1]),
            size=pg.Point(source.width, source.length),
            angle=-source.strike,
            invertible=False,
            pen=self.pen_outline)
        self.handlePen = self.pen_handle

        self.addScaleRotateHandle([0, 0], [0, 1])
        self.addScaleRotateHandle([0, 1], [0, 0])
        self.addScaleHandle([1, .5], [0, .5],
                            lockAspect=False)

        for h in self.handles:
            h['item'].sigClicked.connect(self.sigRegionChangeStarted.emit)

        self.delegate.sourceParametersChanged.connect(
            self.updateROIPosition)
        self.sigRegionChangeFinished.connect(
            self.setSourceParametersFromROI)

        self.setAcceptedMouseButtons(QtCore.Qt.RightButton)
        self.sigClicked.connect(self.showEditingDialog)
Exemple #4
0
    def mouseDragEvent(self, event, axis=None):
        vb = self.linkedView()
        if vb is None:
            return
        pos = event.scenePos()
        if self.geometry().contains(pos):
            self.log.info('mouseDragEvent(%s)', event)
            event.accept()
            if self.config['range'] == 'manual':
                [x_min, x_max], [y_min, y_max] = vb.viewRange()
                pmin = vb.mapViewToScene(pg.Point(x_min, y_min))
                pmax = vb.mapViewToScene(pg.Point(x_max, y_max))

                yview_range = y_max - y_min
                yscene_range = pmax.y() - pmin.y()
                pnow_y = event.scenePos().y()

                if self._pan is not None:
                    dx = (pnow_y - self._pan[1]) * yview_range / yscene_range
                    self._pan[0] += dx
                    self._pan[1] = pnow_y

                if event.button() & QtCore.Qt.LeftButton:
                    if event.isFinish():
                        if self._pan is not None:
                            pan_x, self._pan = self._pan[0], None
                            self.sigPanYEvent.emit('finish', pan_x)
                    elif self._pan is None:
                        self._pan = [0.0, pnow_y]
                        self.sigPanYEvent.emit('start', 0.0)
                    else:
                        self.sigPanYEvent.emit('drag', self._pan[0])
Exemple #5
0
    def paint(self, p, opt, widget):
        vb = self._view()
        color = self._cmdp[self._instance_prefix + 'color']
        p.resetTransform()
        vb_rect = vb.geometry()
        y = self.scene_pos_y()
        p1 = pg.Point(vb_rect.left(), y)
        p2 = pg.Point(vb_rect.right(), y)

        pen = pg.mkPen(color)
        pen.setWidth(1)
        p.setPen(pen)
        p.drawLine(p1, p2)

        show_stats = self.statistics_show
        if show_stats != 'off':
            pen = pg.mkPen([255, 255, 255, 255])
            p.setPen(pen)
            if self.pair is None:
                txt = three_sig_figs(self.y, self._units)
            else:
                dy = abs(self.y - self.pair.y)
                t1 = three_sig_figs(self.y, self._units)
                t2 = three_sig_figs(dy, self._units)
                txt = f'{t1}, Δ={t2}'
            if show_stats == 'bottom':
                font = QtGui.QFont()
                h = QtGui.QFontMetrics(font).height()
                p1 += pg.Point(0, h)
            else:
                p1 += pg.Point(0, -2)

            p.drawText(p1, txt)
Exemple #6
0
    def test_mouse_drag_event(self):
        self.mock_graph.state = ZOOMING
        mock_event = Mock()
        mock_event.button.return_value = Qt.LeftButton
        mock_event.pos.return_value = pg.Point(0.6, 0.6)
        mock_event.isFinish.return_value = True
        mock_event.buttonDownPos.return_value = pg.Point(0.4, 0.4)
        self.mvb.mapToView = lambda x: x
        self.mvb.state['mouseMode'] = pg.ViewBox.RectMode

        self.mvb.match_zoom(pg.Point(0.5, 0.5))
        qrect1 = self.sr.call_args[0][0]
        zoom1 = self.mvb.get_zoom()
        self.mvb.mouseDragEvent(mock_event)
        mock_event.accept.assert_called()
        zoom2 = self.mvb.get_zoom()
        qrect2 = self.sr.call_args[0][0]
        # when selecting a smaller region zoom level should increase and
        # shown area should decrees
        self.assertTrue(zoom2 > zoom1)
        self.assertTrue(qrect2.width() < qrect1.width())

        mock_event.button.return_value = Qt.RightButton
        self.mvb.mouseDragEvent(mock_event)
        mock_event.ignore.assert_called()
Exemple #7
0
    def myMouseDragEvent(self, ev, axis=None):
        # most of this code is copied behavior mouse drag from the original code
        ev.accept()
        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif *= -1

        if ev.button() == QtCore.Qt.RightButton or \
                (ev.button() == QtCore.Qt.LeftButton and
                         ev.modifiers() & QtCore.Qt.ControlModifier):
            # determine the amount of translation
            tr = dif
            tr = self.view_box.mapToView(tr) - self.view_box.mapToView(pg.Point(0, 0))
            x = tr.x()
            y = tr.y()
            self.view_box.translateBy(x=x, y=y)
            if ev.start:
                self.range_changed_timer.start()
            if ev.isFinish():
                self.range_changed_timer.stop()
                self.emit_sig_range_changed()
        else:
            if ev.isFinish():  # This is the final move in the drag; change the view scale now
                self.auto_range = False
                self.view_box.rbScaleBox.hide()
                ax = QtCore.QRectF(pg.Point(ev.buttonDownPos(ev.button())), pg.Point(pos))
                ax = self.view_box.childGroup.mapRectFromParent(ax)
                self.view_box.showAxRect(ax)
                self.view_box.axHistoryPointer += 1
                self.view_box.axHistory = self.view_box.axHistory[:self.view_box.axHistoryPointer] + [ax]
                self.emit_sig_range_changed()
            else:
                # update shape of scale box
                self.view_box.updateScaleBox(ev.buttonDownPos(), ev.pos())
Exemple #8
0
    def updateROIPosition(self):
        source = self.source
        width = source.width

        self.setPos(pg.Point(source.outline()[1]), finish=False)
        self.setSize(pg.Point(width, source.length), finish=False)
        self.setAngle(-source.strike, finish=False)
Exemple #9
0
 def get_ab_angle(self, with_ab_vector=None):
     """
     Gets ROI.ab_angle. If with_ab_vector is given, then the angle returned is with respect to the given vector 
     """
     if with_ab_vector is not None:
         corner = pg.Point(with_ab_vector[0], with_ab_vector[1])
         return corner.angle(pg.Point(1, 0))
     else:
         return self.ab_angle
Exemple #10
0
 def __init__(self, window, x, y, kind):
     pg.GraphicsObject.__init__(self)
     window.imageview.addItem(self)
     self.window = window
     self.pts = [pg.Point(round(x), round(y))]
     self.kind = kind
     self.state = {'pos': pg.Point(x, y), 'size': pg.Point(0, 0)}
     self.color = QtGui.QColor(
         g.settings['roi_color']
     ) if g.settings['roi_color'] != 'random' else random_color()
Exemple #11
0
 def wheelEvent(self, ev, axis=None):
     scale_fact = 1.02 ** (ev.delta() * self.state['wheelScaleFactor'])
     vr = self.targetRect()
     center = pg.Point(pg.functions.invertQTransform(self.childGroup.transform()).map(ev.pos()))
     if (center.x()-vr.left())/vr.width() < 0.05: # zoom to far left => all the way left
         center = pg.Point(vr.left(), center.y())
     elif (center.x()-vr.left())/vr.width() > 0.95: # zoom to far right => all the way right
         center = pg.Point(vr.right(), center.y())
     self.zoom_rect(vr, scale_fact, center)
     ev.accept()
Exemple #12
0
 def set_range(self, x0, y0, x1, y1, pad=False):
     if np.isnan(y0) or np.isnan(y1):
         return
     if pad:
         x0 -= self.datasrc.period*0.5
         x1 += self.datasrc.period*0.5
     if self.yscale == 'log':
         y0 = np.log10(y0) if y0 > 0 else 0
         y1 = np.log10(y1) if y1 > 0 else 0
     self.setRange(QtCore.QRectF(pg.Point(x0, y0), pg.Point(x1, y1)), padding=0)
Exemple #13
0
    def coordinateSubmitted(self):
        if self.displayCtrl.params['Orientation'] != "right":
            displayError('Set Coordinate function is only supported with Right orientation')
            return
        
        coord_args = str(self.coordinateCtrl.line.text()).split(';')
        
        vxsize = self.atlas._info[-1]['vxsize'] * 1e6
        x = float(coord_args[0])
        y = float(coord_args[1])
        z = float(coord_args[2])
        
        if len(coord_args) < 3:
            return
        
        if len(coord_args) <= 4:
            # When only 4 points are given, assume point needs to be set using orientation == 'right'
            translated_x = (self.atlas_view.atlas.shape[1] - (float(coord_args[0])/vxsize)) * self.atlas_view.scale[0] 
            translated_y = (self.atlas_view.atlas.shape[2] - (float(coord_args[1])/vxsize)) * self.atlas_view.scale[0] 
            translated_z = (self.atlas_view.atlas.shape[0] - (float(coord_args[2])/vxsize)) * self.atlas_view.scale[0] 
            roi_origin = (translated_x, 0.0)
            to_size = (self.atlas_view.atlas.shape[2] * self.atlas_view.scale[1], 0.0) 
            to_ab_angle = 90
            to_ac_angle = 0
            target_p1 = translated_z 
            target_p2 = translated_y
        else:
            transform = literal_eval(coord_args[4])

            # Use LIMS matrices to get the origin and vectors of the plane
            M1, M1i = points_to_aff.lims_obj_to_aff(transform)
            origin, ab_vector, ac_vector = points_to_aff.aff_to_origin_and_vectors(M1i)
            
            target_p1, target_p2 = self.get_target_position([x, y, z, 1], M1, ab_vector, ac_vector, vxsize)
            
            # Put the origin and vectors back to view coordinates
            roi_origin = np.array(self.ccf_point_to_view(origin))
            ab_vector = -np.array(self.vector_to_view(ab_vector))
            ac_vector = -np.array(self.vector_to_view(ac_vector))
                
            to_ac_angle = self.atlas_view.line_roi.get_ac_angle(ac_vector)
            
            # Where the origin of the ROI should be
            if to_ac_angle > 0:
                roi_origin = ac_vector + roi_origin  
                
            to_size = self.atlas_view.line_roi.get_roi_size(ab_vector, ac_vector)
            to_ab_angle = self.atlas_view.line_roi.get_ab_angle(ab_vector)
        
        self.target.setPos(target_p1, target_p2)
        self.atlas_view.line_roi.setPos(pg.Point(roi_origin[0], roi_origin[1]))
        self.atlas_view.line_roi.setSize(pg.Point(to_size))
        self.atlas_view.line_roi.setAngle(to_ab_angle) 
        self.atlas_view.slider.setValue(int(to_ac_angle))
        self.target.setVisible(True)  # TODO: keep target visible when coming back to the same slice... how?
Exemple #14
0
    def get_roi_size(self, ab_vector, ac_vector):
        """
        Returns the size of the ROI expected from the given vectors.
        """
        # Find the width
        w = pg.Point(ab_vector[0], ab_vector[1])

        # Find the length
        l = pg.Point(ac_vector[0], ac_vector[1])

        return w.length(), l.length()
Exemple #15
0
    def test_match_zoom(self):
        point1 = pg.Point(0.5, 0.5)
        self.mvb.match_zoom(point1)
        qrect1 = self.sr.call_args[0][0]

        point2 = pg.Point(0.75, 0.75)
        self.mvb.match_zoom(point2, offset=True)
        qrect2 = self.sr.call_args[0][0]
        # when center is offset the new rect should also be offset
        self.assertTrue(qrect1.x() < qrect2.x())
        self.assertAlmostEqual(qrect1.width(), qrect2.width())
Exemple #16
0
 def paint(self, p, *args):
     p.setRenderHint(p.Antialiasing)
     px, py = self._px
     w = 4 * px
     h = 4 * py
     r = QtCore.QRectF(-w, -h, w * 2, h * 2)
     p.setPen(pg.mkPen(self.color))
     p.setBrush(pg.mkBrush(0, 0, 255, 100))
     p.drawEllipse(r)
     p.drawLine(pg.Point(-w * 2, 0), pg.Point(w * 2, 0))
     p.drawLine(pg.Point(0, -h * 2), pg.Point(0, h * 2))
    def simulate_mouse_drag(self, start: tuple, end: tuple):
        start = self.widget.graph.view_box.mapViewToScene(
            pg.Point(start[0], start[1])).toPoint()
        end = self.widget.graph.view_box.mapViewToScene(
            pg.Point(end[0], end[1])).toPoint()

        mouseMove(self.widget.graph, start)
        QtTest.QTest.qWait(100)
        mousePress(self.widget.graph, start, Qt.LeftButton)
        mouseMove(self.widget.graph, end, Qt.LeftButton)
        mouseRelease(self.widget.graph, end, Qt.LeftButton)
        QtTest.QTest.qWait(100)
Exemple #18
0
    def myMouseDragEvent(self, ev, axis=None):
        # most of this code is copied behavior of left click mouse drag from the original code
        ev.accept()
        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif *= -1
        ## Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.img_view_box.state['mouseEnabled'],
                                dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1 - axis] = 0.0

        if ev.button() == QtCore.Qt.RightButton or \
                (ev.button() == QtCore.Qt.LeftButton and \
                             ev.modifiers() & QtCore.Qt.ControlModifier):
            # determine the amount of translation
            tr = dif * mask
            tr = self.img_view_box.mapToView(tr) - self.img_view_box.mapToView(
                pg.Point(0, 0))
            x = tr.x()
            y = tr.y()

            self.img_view_box.translateBy(x=x, y=y)
            self.img_view_box.sigRangeChangedManually.emit(
                self.img_view_box.state['mouseEnabled'])
        else:
            if ev.isFinish(
            ):  ## This is the final move in the drag; change the view scale now
                # print "finish"
                self.img_view_box.rbScaleBox.hide()
                # ax = QtCore.QRectF(Point(self.pressPos), Point(self.mousePos))
                ax = QtCore.QRectF(pg.Point(ev.buttonDownPos(ev.button())),
                                   pg.Point(pos))
                ax = self.img_view_box.childGroup.mapRectFromParent(ax)
                self.img_view_box.showAxRect(ax)
                self.img_view_box.axHistoryPointer += 1
                self.img_view_box.axHistory = self.img_view_box.axHistory[:self
                                                                          .
                                                                          img_view_box
                                                                          .
                                                                          axHistoryPointer] + [
                                                                              ax
                                                                          ]
                self._max_range = False
            else:
                ## update shape of scale box
                self.img_view_box.updateScaleBox(ev.buttonDownPos(), ev.pos())
Exemple #19
0
 def boundingRect(self):
     if self._bounds is None:
         # too slow!
         w = self.pixelLength(pg.Point(1, 0))
         if w is None:
             return QtCore.QRectF()
         h = self.pixelLength(pg.Point(0, 1))
         # o = self.mapToScene(QtCore.QPointF(0, 0))
         # w = abs(1.0 / (self.mapToScene(QtCore.QPointF(1, 0)) - o).x())
         # h = abs(1.0 / (self.mapToScene(QtCore.QPointF(0, 1)) - o).y())
         self._px = (w, h)
         w *= 21
         h *= 21
         self._bounds = QtCore.QRectF(-w, -h, w * 2, h * 2)
     return self._bounds
Exemple #20
0
    def get_ac_angle(self, with_ac_vector=None):
        """
        Gets ROI.ac_angle. If with_ac_vector is given, then the angle returned is with respect to the given vector 
        """
        if with_ac_vector is not None:
            l = pg.Point(with_ac_vector[0], with_ac_vector[1])  # Explain this.
            corner = pg.Point(l.length(), with_ac_vector[2])

            if with_ac_vector[
                    0] < 0:  # Make sure this points to the correct direction
                corner = pg.Point(-l.length(), with_ac_vector[2])

            return pg.Point(0, 1).angle(corner)
        else:
            return self.ac_angle
Exemple #21
0
 def safe_update_scale_box(self, buttonDownPos, currentPos):
     x, y = currentPos
     if buttonDownPos[0] == x:
         x += 1
     if buttonDownPos[1] == y:
         y += 1
     self.updateScaleBox(buttonDownPos, pg.Point(x, y))
Exemple #22
0
    def myMouseDragEvent(self, ev, axis=None):
        #most of this code is copied behavior of left click mouse drag from the original code
        ev.accept()
        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif *= -1
        ## Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.img_view_box.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1 - axis] = 0.0

        if ev.button() == QtCore.Qt.RightButton or \
                (ev.button() == QtCore.Qt.LeftButton and \
                             ev.modifiers() & QtCore.Qt.ControlModifier):
            #determine the amount of translation
            tr = dif * mask
            tr = self.img_view_box.mapToView(tr) - self.img_view_box.mapToView(pg.Point(0, 0))
            x = tr.x()
            y = tr.y()

            self.img_view_box.translateBy(x=x, y=y)
            self.img_view_box.sigRangeChangedManually.emit(self.img_view_box.state['mouseEnabled'])
        else:
            pg.ViewBox.mouseDragEvent(self.img_view_box, ev)
Exemple #23
0
 def _update_marker_text(self):
     x = self._x
     style = self._time_style()
     if self._x is None:
         html = ''
     else:
         html = f'<div><span style="{style}">t={x:.6f}</span></div>'
     self._marker_time_text.setHtml(html)
     axis = self._axis()
     if axis is None:
         return
     vb = axis.linkedView()
     if vb is None or self._x is None:
         return
     g = axis.geometry()
     axis_top = g.top()
     axis_height = axis.geometry().height()
     text_offset = axis_height // 2
     x_scene = vb.mapViewToScene(pg.Point(x, 0.0)).x()
     if self._pair is None:
         self._marker_time_text.setPos(x_scene + text_offset, axis_top)
     elif self.is_left:
         self._marker_time_text.setPos(x_scene, axis_top)
         self._update_delta_time()
     else:
         self._marker_time_text.setPos(x_scene, axis_top)
         self._pair._update_delta_time()
Exemple #24
0
    def _update_offsets(self, vb=None):
        vb = self.parent.viewbox
        height = vb.height()
        n = len(self.plots)

        plot_items = sorted(self.plots.items(), reverse=True)
        for i, (key, plot) in enumerate(plot_items):
            offset = (i + 1) * height / (n + 1)
            point = self.parent.viewbox.mapToView(pg.Point(0, offset))
            plot.setPos(0, point.y())

        labels = sorted(self.labels.items(), reverse=True)
        for i, (key, label) in enumerate(labels):
            offset = (i + 1) * height / (n + 1)
            point = self.parent.viewbox_norm.mapToView(pg.Point(0, offset))
            label.setPos(0.8, point.y())
Exemple #25
0
 def boundingRect(self):
     r = pg.ROI.boundingRect(self)
     pxl = self.pixelLength(pg.Point([1, 0]))
     if pxl is None:
         return r
     pxw = 50 * pxl
     return r.adjusted(-50, -50, 50, 50)
Exemple #26
0
 def __init__(self,
              text='',
              color=(200, 200, 200),
              html=None,
              anchor=(0, 0),
              border=None,
              fill=None):
     """
     Arguments:
     *text*   The text to display 
     *color*  The color of the text (any format accepted by pg.mkColor)
     *html*   If specified, this overrides both *text* and *color*
     *anchor* A QPointF or (x,y) sequence indicating what region of the text box will 
              be anchored to the item's position. A value of (0,0) sets the upper-left corner
              of the text box to be at the position specified by setPos(), while a value of (1,1)
              sets the lower-right corner.
     *border* A pen to use when drawing the border
     *fill*   A brush to use when filling within the border
     """
     UIGraphicsItem.__init__(self)
     self.textItem = QtGui.QGraphicsTextItem()
     self.lastTransform = None
     self._bounds = QtCore.QRectF()
     if html is None:
         self.setText(text, color)
     else:
         self.setHtml(html)
     self.anchor = pg.Point(anchor)
     self.fill = pg.mkBrush(fill)
     self.border = pg.mkPen(border)
Exemple #27
0
    def myMouseDragEvent(self, ev, axis=None):
        #most of this code is copied behavior of left click mouse drag from the original code
        ev.accept()
        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif *= -1

        if ev.button() == QtCore.Qt.RightButton or \
                (ev.button() == QtCore.Qt.LeftButton and \
                             ev.modifiers() & QtCore.Qt.ControlModifier):
            #determine the amount of translation
            tr = dif
            tr = self.view_box.mapToView(tr) - self.view_box.mapToView(
                pg.Point(0, 0))
            x = tr.x()
            y = tr.y()

            self.view_box.translateBy(x=x, y=y)
        else:
            self._auto_range = False
            pg.ViewBox.mouseDragEvent(self.view_box, ev)

        self.view_box.sigRangeChangedManually.emit(
            self.view_box.state['mouseEnabled'])
Exemple #28
0
    def __updateLayout(self):
        T = self.sceneTransform()
        if T is None:
            T = QTransform()

        # map the axis spine to scene coord. system.
        viewbox_line = T.map(self._spine.line())
        angle = viewbox_line.angle()
        assert not np.isnan(angle)
        # note in Qt the y axis is inverted (90 degree angle 'points' down)
        left_quad = 270 < angle <= 360 or -0.0 <= angle < 90

        # position the text label along the viewbox_line
        label_pos = self._spine.line().pointAt(0.90)

        if left_quad:
            # Anchor the text under the axis spine
            anchor = (0.5, -0.1)
        else:
            # Anchor the text over the axis spine
            anchor = (0.5, 1.1)

        self._label.setPos(label_pos)
        self._label.setAnchor(pg.Point(*anchor))
        self._label.setRotation(-angle if left_quad else 180 - angle)

        self._arrow.setPos(self._spine.line().p2())
        self._arrow.setRotation(180 - angle)
Exemple #29
0
 def stepTo(self, t):
     data = self.clock.refData
     
     while self.i < len(data)-1 and data['t'][self.i] < t:
         self.i += 1
     while self.i > 1 and data['t'][self.i-1] >= t:
         self.i -= 1
     
     self.setPos(data['x'][self.i], self.clock.y0)
     
     t = data['pt'][self.i]
     self.hand.setRotation(-0.25 * t * 360.)
     
     self.resetTransform()
     v = data['v'][self.i]
     gam = (1.0 - v**2)**0.5
     self.setScale(gam)
     
     f = data['f'][self.i]
     self.flare.resetTransform()
     if f < 0:
         self.flare.moveBy(self.size*0.4, 0)
     else:
         self.flare.moveBy(-self.size*0.4, 0)
     
     self.flare.setScale(-f * (0.5+np.random.random()*0.1))
     
     if self._spaceline is not None:
         self._spaceline.setPos(pg.Point(data['x'][self.i], data['t'][self.i]))
         self._spaceline.setAngle(data['v'][self.i] * 45.)
Exemple #30
0
    def mouseDragEvent(self, ev, axis=None):
        ## if axis is specified, event will only affect that axis.
        ev.accept()  ## we accept all buttons

        pos = ev.pos()
        lastPos = ev.lastPos()
        dif = pos - lastPos
        dif = dif * -1

        ## Ignore axes if mouse is disabled
        mouseEnabled = np.array(self.state['mouseEnabled'], dtype=np.float)
        mask = mouseEnabled.copy()
        if axis is not None:
            mask[1 - axis] = 0.0

        ## Scale or translate based on mouse button
        if (ev.button() & QtCore.Qt.LeftButton) and (
                ev.modifiers() & QtCore.Qt.ShiftModifier):
            tr = dif * mask
            tr = self.mapToView(tr) - self.mapToView(pyqtgraph.Point(0, 0))
            x = tr.x() if mask[0] == 1 else None
            y = tr.y() if mask[1] == 1 else None

            self.translateBy(x=x, y=y)
            self.sigRangeChangedManually.emit(self.state['mouseEnabled'])
        else:
            super(CustomViewBox, self).mouseDragEvent(ev, axis)