Commit a41d330c authored by Luke Campagnola's avatar Luke Campagnola
Browse files

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
parent f81e9406
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.python2_3 import sortList
#try:
#from PyQt4 import QtOpenGL
#HAVE_OPENGL = True
......
......@@ -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']
......
......@@ -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
......
......@@ -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):
......
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.python2_3 import asUnicode
class CmdInput(QtGui.QLineEdit):
......
......@@ -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])
\ No newline at end of file
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
......
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
......
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):
......
......@@ -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])
......
......@@ -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()
......
......@@ -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())
......
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):
......
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'])
......
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
......
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
......
......@@ -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
# -*- 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
......
# -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtGui, QtCore
from pyqtgraph.python2_3 import asUnicode
import numpy as np
try:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment