Merged from Ingo B. with changes
Implements single axis scaling by mouse wheel over tick marks
This commit is contained in:
commit
a5668a1a26
83
ColorButton.py
Normal file
83
ColorButton.py
Normal file
@ -0,0 +1,83 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from PyQt4 import QtGui, QtCore
|
||||
if not hasattr(QtCore, 'Signal'):
|
||||
QtCore.Signal = QtCore.pyqtSignal
|
||||
import functions
|
||||
|
||||
class ColorButton(QtGui.QPushButton):
|
||||
|
||||
sigColorChanging = QtCore.Signal(object) ## emitted whenever a new color is picked in the color dialog
|
||||
sigColorChanged = QtCore.Signal(object) ## emitted when the selected color is accepted (user clicks OK)
|
||||
|
||||
def __init__(self, color=(128,128,128)):
|
||||
QtGui.QPushButton.__init__(self)
|
||||
self.setColor(color)
|
||||
self.colorDialog = QtGui.QColorDialog()
|
||||
self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
|
||||
self.colorDialog.setOption(QtGui.QColorDialog.DontUseNativeDialog, True)
|
||||
self.colorDialog.currentColorChanged.connect(self.dialogColorChanged)
|
||||
self.colorDialog.rejected.connect(self.colorRejected)
|
||||
self.colorDialog.colorSelected.connect(self.colorSelected)
|
||||
#QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('currentColorChanged(const QColor&)'), self.currentColorChanged)
|
||||
#QtCore.QObject.connect(self.colorDialog, QtCore.SIGNAL('rejected()'), self.currentColorRejected)
|
||||
self.clicked.connect(self.selectColor)
|
||||
self.setMinimumHeight(15)
|
||||
self.setMinimumWidth(15)
|
||||
|
||||
def paintEvent(self, ev):
|
||||
QtGui.QPushButton.paintEvent(self, ev)
|
||||
p = QtGui.QPainter(self)
|
||||
p.setBrush(functions.mkBrush(self._color))
|
||||
p.drawRect(self.rect().adjusted(5, 5, -5, -5))
|
||||
p.end()
|
||||
|
||||
def setColor(self, color, finished=True):
|
||||
self._color = functions.mkColor(color)
|
||||
if finished:
|
||||
self.sigColorChanged.emit(self)
|
||||
else:
|
||||
self.sigColorChanging.emit(self)
|
||||
self.update()
|
||||
|
||||
def selectColor(self):
|
||||
self.origColor = self.color()
|
||||
self.colorDialog.setCurrentColor(self.color())
|
||||
self.colorDialog.open()
|
||||
|
||||
def dialogColorChanged(self, color):
|
||||
if color.isValid():
|
||||
self.setColor(color, finished=False)
|
||||
|
||||
def colorRejected(self):
|
||||
self.setColor(self.origColor, finished=False)
|
||||
|
||||
def colorSelected(self, color):
|
||||
self.setColor(self._color, finished=True)
|
||||
|
||||
def saveState(self):
|
||||
return functions.colorTuple(self._color)
|
||||
|
||||
def restoreState(self, state):
|
||||
self.setColor(state)
|
||||
|
||||
def color(self):
|
||||
return functions.mkColor(self._color)
|
||||
|
||||
def widgetGroupInterface(self):
|
||||
return (self.sigColorChanged, ColorButton.saveState, ColorButton.restoreState)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtGui.QApplication([])
|
||||
win = QtGui.QMainWindow()
|
||||
btn = ColorButton()
|
||||
win.setCentralWidget(btn)
|
||||
win.show()
|
||||
|
||||
def change(btn):
|
||||
print "change", btn.color()
|
||||
def done(btn):
|
||||
print "done", btn.color()
|
||||
|
||||
btn.sigColorChanging.connect(change)
|
||||
btn.sigColorChanged.connect(done)
|
||||
|
@ -254,15 +254,14 @@ class GraphicsView(QtGui.QGraphicsView):
|
||||
|
||||
|
||||
def wheelEvent(self, ev):
|
||||
QtGui.QGraphicsView.wheelEvent(self, ev)
|
||||
if not self.mouseEnabled:
|
||||
return
|
||||
QtGui.QGraphicsView.wheelEvent(self, ev)
|
||||
sc = 1.001 ** ev.delta()
|
||||
#self.scale *= sc
|
||||
#self.updateMatrix()
|
||||
self.scale(sc, sc)
|
||||
|
||||
|
||||
def setAspectLocked(self, s):
|
||||
self.aspectLocked = s
|
||||
|
||||
|
@ -1037,6 +1037,10 @@ class PlotItem(QtGui.QGraphicsWidget):
|
||||
mode = False
|
||||
return mode
|
||||
|
||||
#def wheelEvent(self, ev):
|
||||
# disables panning the whole scene by mousewheel
|
||||
#ev.accept()
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
self.ctrlBtn.move(0, self.size().height() - self.ctrlBtn.size().height())
|
||||
self.autoBtn.move(self.ctrlBtn.width(), self.size().height() - self.autoBtn.size().height())
|
||||
@ -1088,7 +1092,7 @@ class PlotItem(QtGui.QGraphicsWidget):
|
||||
if arr.ndim != 1:
|
||||
raise Exception("Array must be 1D to plot (shape is %s)" % arr.shape)
|
||||
if x is None:
|
||||
x = arange(arr.shape[0])
|
||||
x = np.arange(arr.shape[0])
|
||||
if x.ndim != 1:
|
||||
raise Exception("X array must be 1D to plot (shape is %s)" % x.shape)
|
||||
c = PlotCurveItem(arr, x=x)
|
||||
|
28
examples/test_Arrow.py
Normal file
28
examples/test_Arrow.py
Normal file
@ -0,0 +1,28 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
import numpy as np
|
||||
from PyQt4 import QtGui, QtCore
|
||||
import pyqtgraph as pg
|
||||
|
||||
|
||||
app = QtGui.QApplication([])
|
||||
mw = QtGui.QMainWindow()
|
||||
|
||||
p = pg.PlotWidget()
|
||||
mw.setCentralWidget(p)
|
||||
c = p.plot(x=np.sin(np.linspace(0, 2*np.pi, 100)), y=np.cos(np.linspace(0, 2*np.pi, 100)))
|
||||
a = pg.CurveArrow(c)
|
||||
p.addItem(a)
|
||||
|
||||
mw.show()
|
||||
|
||||
anim = a.makeAnimation(loop=-1)
|
||||
anim.start()
|
||||
|
||||
## Start Qt event loop unless running in interactive mode.
|
||||
if sys.flags.interactive != 1:
|
||||
app.exec_()
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
import numpy as np
|
||||
|
@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
from scipy import random
|
||||
|
2
examples/test_PlotWidget.py
Executable file → Normal file
2
examples/test_PlotWidget.py
Executable file → Normal file
@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path = [os.path.join(os.path.dirname(__file__), '..', '..')] + sys.path
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
@ -2,7 +2,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
## Add path to library (just for examples; you do not need this)
|
||||
import sys, os
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||
|
||||
## This example uses a ViewBox to create a PlotWidget-like interface
|
||||
|
||||
|
@ -1524,8 +1524,10 @@ class ScaleItem(QtGui.QGraphicsWidget):
|
||||
else:
|
||||
xs = bounds.width() / dif
|
||||
|
||||
tickPositions = set() # remembers positions of previously drawn ticks
|
||||
## draw ticks and text
|
||||
for i in [i1, i1+1, i1+2]: ## draw three different intervals
|
||||
## draw three different intervals, long ticks first
|
||||
for i in reversed([i1, i1+1, i1+2]):
|
||||
if i > len(intervals):
|
||||
continue
|
||||
## spacing for this interval
|
||||
@ -1569,7 +1571,11 @@ class ScaleItem(QtGui.QGraphicsWidget):
|
||||
if p1[1-axis] < 0:
|
||||
continue
|
||||
p.setPen(QtGui.QPen(QtGui.QColor(100, 100, 100, a)))
|
||||
p.drawLine(Point(p1), Point(p2))
|
||||
# draw tick only if there is none
|
||||
tickPos = p1[1-axis]
|
||||
if tickPos not in tickPositions:
|
||||
p.drawLine(Point(p1), Point(p2))
|
||||
tickPositions.add(tickPos)
|
||||
if i == textLevel:
|
||||
if abs(v) < .001 or abs(v) >= 10000:
|
||||
vstr = "%g" % (v * self.scale)
|
||||
@ -1635,11 +1641,15 @@ class ScaleItem(QtGui.QGraphicsWidget):
|
||||
else:
|
||||
self.setHeight(0)
|
||||
QtGui.QGraphicsWidget.hide(self)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def wheelEvent(self, ev):
|
||||
if self.linkedView is None or self.linkedView() is None: return
|
||||
if self.orientation in ['left', 'right']:
|
||||
self.linkedView().wheelEvent(ev, axis=1)
|
||||
else:
|
||||
self.linkedView().wheelEvent(ev, axis=0)
|
||||
ev.accept()
|
||||
|
||||
|
||||
|
||||
class ViewBox(QtGui.QGraphicsWidget):
|
||||
@ -1655,7 +1665,7 @@ class ViewBox(QtGui.QGraphicsWidget):
|
||||
#self.gView = view
|
||||
#self.showGrid = showGrid
|
||||
self.range = [[0,1], [0,1]] ## child coord. range visible [[xmin, xmax], [ymin, ymax]]
|
||||
|
||||
self.wheelScaleFactor = -1.0 / 8.0
|
||||
self.aspectLocked = False
|
||||
self.setFlag(QtGui.QGraphicsItem.ItemClipsChildrenToShape)
|
||||
#self.setFlag(QtGui.QGraphicsItem.ItemClipsToShape)
|
||||
@ -1800,7 +1810,19 @@ class ViewBox(QtGui.QGraphicsWidget):
|
||||
#self.replot(autoRange=False)
|
||||
#self.updateMatrix()
|
||||
|
||||
|
||||
def wheelEvent(self, ev, axis=None):
|
||||
mask = np.array(self.mouseEnabled, dtype=np.float)
|
||||
if axis is not None and axis >= 0 and axis < len(mask):
|
||||
mv = mask[axis]
|
||||
mask[:] = 0
|
||||
mask[axis] = mv
|
||||
s = ((mask * 0.02) + 1) ** (ev.delta() * self.wheelScaleFactor) # actual scaling factor
|
||||
# scale 'around' mouse cursor position
|
||||
center = Point(self.childGroup.transform().inverted()[0].map(ev.pos()))
|
||||
self.scaleBy(s, center)
|
||||
self.emit(QtCore.SIGNAL('rangeChangedManually'), self.mouseEnabled)
|
||||
ev.accept()
|
||||
|
||||
def mouseMoveEvent(self, ev):
|
||||
QtGui.QGraphicsWidget.mouseMoveEvent(self, ev)
|
||||
pos = np.array([ev.pos().x(), ev.pos().y()])
|
||||
@ -1812,7 +1834,7 @@ class ViewBox(QtGui.QGraphicsWidget):
|
||||
mask = np.array(self.mouseEnabled, dtype=np.float)
|
||||
|
||||
## Scale or translate based on mouse button
|
||||
if ev.buttons() & QtCore.Qt.LeftButton:
|
||||
if ev.buttons() & (QtCore.Qt.LeftButton | QtCore.Qt.MidButton):
|
||||
if not self.yInverted:
|
||||
mask *= np.array([1, -1])
|
||||
tr = dif*mask
|
||||
|
Loading…
Reference in New Issue
Block a user