Bugfixes:

- Fixed some floating-point precision issues. (Added a workaround for QTransform.inverted() bug)
  - No longer putting asUnicode inside __builtin__ since this causes problems in some rare circumstances
    (pyshell, lazy import recipe)
  - Minor docstring updates
This commit is contained in:
Luke Campagnola 2012-07-12 15:35:58 -04:00
parent f81e94061f
commit a41d330c29
19 changed files with 82 additions and 27 deletions

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.python2_3 import sortList
#try:
#from PyQt4 import QtOpenGL
#HAVE_OPENGL = True

View File

@ -10,6 +10,7 @@ of a large group of widgets.
from .Qt import QtCore, QtGui
import weakref, inspect
from .python2_3 import asUnicode
__all__ = ['WidgetGroup']

View File

@ -14,7 +14,8 @@ from .Qt import QtGui
import os, sys
## check python version
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] != 7):
## Allow anything >= 2.7
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 7):
raise Exception("Pyqtgraph requires Python version 2.7 (this is %d.%d)" % (sys.version_info[0], sys.version_info[1]))
## helpers for 2/3 compatibility

View File

@ -13,6 +13,7 @@ import re, os, sys
from collections import OrderedDict
GLOBAL_PATH = None # so not thread safe.
from . import units
from .python2_3 import asUnicode
class ParseError(Exception):
def __init__(self, message, lineNum, line, fileName=None):

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.python2_3 import asUnicode
class CmdInput(QtGui.QLineEdit):

View File

@ -5,6 +5,7 @@ Copyright 2010 Luke Campagnola
Distributed under MIT/X11 license. See license.txt for more infomation.
"""
from .python2_3 import asUnicode
Colors = {
'b': (0,0,255,255),
'g': (0,255,0,255),
@ -1275,3 +1276,19 @@ def isosurface(data, level):
return facets
def invertQTransform(tr):
"""Return a QTransform that is the inverse of *tr*.
Rasises an exception if tr is not invertible.
Note that this function is preferred over QTransform.inverted() due to
bugs in that method. (specifically, Qt has floating-point precision issues
when determining whether a matrix is invertible)
"""
#return tr.inverted()[0]
arr = np.array([[tr.m11(), tr.m12(), tr.m13()], [tr.m21(), tr.m22(), tr.m23()], [tr.m31(), tr.m32(), tr.m33()]])
inv = scipy.linalg.inv(arr)
return QtGui.QTransform(inv[0,0], inv[0,1], inv[0,2], inv[1,0], inv[1,1], inv[1,2], inv[2,0], inv[2,1])

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.python2_3 import asUnicode
import numpy as np
from pyqtgraph.Point import Point
import pyqtgraph.debug as debug

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.python2_3 import sortList
import pyqtgraph.functions as fn
from .GraphicsObject import GraphicsObject
from .GraphicsWidget import GraphicsWidget

View File

@ -1,6 +1,7 @@
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.GraphicsScene import GraphicsScene
from pyqtgraph.Point import Point
import pyqtgraph.functions as fn
import weakref
class GraphicsItem(object):
@ -149,16 +150,32 @@ class GraphicsItem(object):
"""Return vectors in local coordinates representing the width and height of a view pixel.
If direction is specified, then return vectors parallel and orthogonal to it.
Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)."""
Return (None, None) if pixel size is not yet defined (usually because the item has not yet been displayed)
or if pixel size is below floating-point precision limit.
"""
dt = self.deviceTransform()
if dt is None:
return None, None
if direction is None:
direction = Point(1, 0)
direction = Point(1, 0)
if direction.manhattanLength() == 0:
raise Exception("Cannot compute pixel length for 0-length vector.")
## attempt to re-scale direction vector to fit within the precision of the coordinate system
if direction.x() == 0:
r = abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))
elif direction.y() == 0:
r = abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))
else:
r = ((abs(dt.m32())/(abs(dt.m12()) + abs(dt.m22()))) * (abs(dt.m31())/(abs(dt.m11()) + abs(dt.m21()))))**0.5
direction = direction * r
viewDir = Point(dt.map(direction) - dt.map(Point(0,0)))
if viewDir.manhattanLength() == 0:
return None, None ## pixel size cannot be represented on this scale
orthoDir = Point(viewDir[1], -viewDir[0]) ## orthogonal to line in pixel-space
try:
@ -168,7 +185,7 @@ class GraphicsItem(object):
raise Exception("Invalid direction %s" %direction)
dti = dt.inverted()[0]
dti = fn.invertQTransform(dt)
return Point(dti.map(normView)-dti.map(Point(0,0))), Point(dti.map(normOrtho)-dti.map(Point(0,0)))
#vt = self.deviceTransform()
@ -194,23 +211,26 @@ class GraphicsItem(object):
def pixelSize(self):
## deprecated
v = self.pixelVectors()
if v == (None, None):
return None, None
return (v[0].x()**2+v[0].y()**2)**0.5, (v[1].x()**2+v[1].y()**2)**0.5
def pixelWidth(self):
## deprecated
vt = self.deviceTransform()
if vt is None:
return 0
vt = vt.inverted()[0]
vt = fn.invertQTransform(vt)
return Point(vt.map(QtCore.QPointF(1, 0))-vt.map(QtCore.QPointF(0, 0))).length()
def pixelHeight(self):
## deprecated
vt = self.deviceTransform()
if vt is None:
return 0
vt = vt.inverted()[0]
vt = fn.invertQTransform(vt)
return Point(vt.map(QtCore.QPointF(0, 1))-vt.map(QtCore.QPointF(0, 0))).length()
@ -232,7 +252,7 @@ class GraphicsItem(object):
vt = self.deviceTransform()
if vt is None:
return None
vt = vt.inverted()[0]
vt = fn.invertQTransform(vt)
return vt.map(obj)
def mapRectToDevice(self, rect):
@ -253,7 +273,7 @@ class GraphicsItem(object):
vt = self.deviceTransform()
if vt is None:
return None
vt = vt.inverted()[0]
vt = fn.invertQTransform(vt)
return vt.mapRect(rect)
def mapToView(self, obj):
@ -272,14 +292,14 @@ class GraphicsItem(object):
vt = self.viewTransform()
if vt is None:
return None
vt = vt.inverted()[0]
vt = fn.invertQTransform(vt)
return vt.map(obj)
def mapRectFromView(self, obj):
vt = self.viewTransform()
if vt is None:
return None
vt = vt.inverted()[0]
vt = fn.invertQTransform(vt)
return vt.mapRect(obj)
def pos(self):

View File

@ -2,6 +2,7 @@ from pyqtgraph.Qt import QtGui, QtCore
from .UIGraphicsItem import *
import numpy as np
from pyqtgraph.Point import Point
import pyqtgraph.functions as fn
__all__ = ['GridItem']
class GridItem(UIGraphicsItem):
@ -47,7 +48,7 @@ class GridItem(UIGraphicsItem):
p = QtGui.QPainter()
p.begin(self.picture)
dt = self.viewTransform().inverted()[0]
dt = fn.invertQTransform(self.viewTransform())
vr = self.getViewWidget().rect()
unit = self.pixelWidth(), self.pixelHeight()
dim = [vr.width(), vr.height()]
@ -112,7 +113,7 @@ class GridItem(UIGraphicsItem):
texts.append((QtCore.QPointF(x, y), "%g"%p1[ax]))
tr = self.deviceTransform()
#tr.scale(1.5, 1.5)
p.setWorldTransform(tr.inverted()[0])
p.setWorldTransform(fn.invertQTransform(tr))
for t in texts:
x = tr.map(t[0]) + Point(0.5, 0.5)
p.drawText(x, t[1])

View File

@ -1053,6 +1053,7 @@ class PlotItem(GraphicsWidget):
s.hide()
def hideAxis(self, axis):
"""Hide one of the PlotItem's axes. ('left', 'bottom', 'right', or 'top')"""
self.showAxis(axis, False)
def showScale(self, *args, **kargs):
@ -1060,6 +1061,7 @@ class PlotItem(GraphicsWidget):
return self.showAxis(*args, **kargs)
def hideButtons(self):
"""Causes auto-scale button ('A' in lower-left corner) to be hidden for this PlotItem"""
#self.ctrlBtn.hide()
self.autoBtn.hide()

View File

@ -800,7 +800,7 @@ class ROI(GraphicsObject):
#print " dshape", dShape
## Determine transform that maps ROI bounding box to image coordinates
tr = self.sceneTransform() * img.sceneTransform().inverted()[0]
tr = self.sceneTransform() * fn.invertQTransform(img.sceneTransform())
## Modify transform to scale from image coords to data coords
#m = QtGui.QTransform()
@ -1251,7 +1251,7 @@ class Handle(UIGraphicsItem):
v = dt.map(QtCore.QPointF(1, 0)) - dt.map(QtCore.QPointF(0, 0))
va = np.arctan2(v.y(), v.x())
dti = dt.inverted()[0]
dti = fn.invertQTransform(dt)
devPos = dt.map(QtCore.QPointF(0,0))
tr = QtGui.QTransform()
tr.translate(devPos.x(), devPos.y())

View File

@ -1,6 +1,7 @@
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
from .UIGraphicsItem import *
import pyqtgraph.functions as fn
class TextItem(UIGraphicsItem):
"""
@ -87,7 +88,7 @@ class TextItem(UIGraphicsItem):
if br is None:
return
self.prepareGeometryChange()
self._bounds = self.deviceTransform().inverted()[0].mapRect(br)
self._bounds = fn.invertQTransform(self.deviceTransform()).mapRect(br)
#print self._bounds
def boundingRect(self):

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.python2_3 import sortList
import numpy as np
from pyqtgraph.Point import Point
import pyqtgraph.functions as fn
@ -451,10 +452,8 @@ class ViewBox(GraphicsWidget):
center = Point(vr.center())
else:
center = Point(center)
tl = center + (vr.topLeft()-center) * scale
br = center + (vr.bottomRight()-center) * scale
self.setRange(QtCore.QRectF(tl, br), padding=0)
def translateBy(self, t):
@ -764,7 +763,7 @@ class ViewBox(GraphicsWidget):
def mapToView(self, obj):
"""Maps from the local coordinates of the ViewBox to the coordinate system displayed inside the ViewBox"""
m = self.childTransform().inverted()[0]
m = fn.invertQTransform(self.childTransform())
return m.map(obj)
def mapFromView(self, obj):
@ -830,7 +829,7 @@ class ViewBox(GraphicsWidget):
mask[axis] = mv
s = ((mask * 0.02) + 1) ** (ev.delta() * self.state['wheelScaleFactor']) # actual scaling factor
center = Point(self.childGroup.transform().inverted()[0].map(ev.pos()))
center = Point(fn.invertQTransform(self.childGroup.transform()).map(ev.pos()))
#center = ev.pos()
self.scaleBy(s, center)
@ -913,8 +912,11 @@ class ViewBox(GraphicsWidget):
dif = np.array([dif.x(), dif.y()])
dif[0] *= -1
s = ((mask * 0.02) + 1) ** dif
center = Point(self.childGroup.transform().inverted()[0].map(ev.buttonDownPos(QtCore.Qt.RightButton)))
#center = Point(ev.buttonDownPos(QtCore.Qt.RightButton))
tr = self.childGroup.transform()
tr = fn.invertQTransform(tr)
center = Point(tr.map(ev.buttonDownPos(QtCore.Qt.RightButton)))
self.scaleBy(s, center)
self.sigRangeChangedManually.emit(self.state['mouseEnabled'])

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.python2_3 import asUnicode
from pyqtgraph.WidgetGroup import WidgetGroup
from .axisCtrlTemplate import Ui_Form as AxisCtrlTemplate
import weakref

View File

@ -1,4 +1,5 @@
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.python2_3 import asUnicode
from .Parameter import Parameter, registerParameterType
from .ParameterItem import ParameterItem
from pyqtgraph.widgets.SpinBox import SpinBox

View File

@ -42,8 +42,9 @@ def sortList(l, cmpFunc):
if sys.version_info[0] == 3:
import builtins
builtins.basestring = str
builtins.asUnicode = asUnicode
builtins.sortList = sortList
#builtins.asUnicode = asUnicode
#builtins.sortList = sortList
basestring = str
def cmp(a,b):
if a>b:
return 1
@ -52,7 +53,7 @@ if sys.version_info[0] == 3:
else:
return 0
builtins.cmp = cmp
else:
import __builtin__
__builtin__.asUnicode = asUnicode
__builtin__.sortList = sortList
#else: ## don't use __builtin__ -- this confuses things like pyshell and ActiveState's lazy import recipe
#import __builtin__
#__builtin__.asUnicode = asUnicode
#__builtin__.sortList = sortList

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.python2_3 import asUnicode
from pyqtgraph.SignalProxy import SignalProxy
import pyqtgraph.functions as fn

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.python2_3 import asUnicode
import numpy as np
try: