Added preliminary support for python 2.6

Fixed setup.py to automatically search for all sub-packages
This commit is contained in:
Luke Campagnola 2012-09-13 10:12:59 -04:00
parent c022f3a10f
commit ca9d0ed147
21 changed files with 584 additions and 574 deletions

View File

@ -15,8 +15,8 @@ import os, sys
## check python version
## 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]))
if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 6):
raise Exception("Pyqtgraph requires Python version 2.6 or greater (this is %d.%d)" % (sys.version_info[0], sys.version_info[1]))
## helpers for 2/3 compatibility
from . import python2_3

View File

@ -10,7 +10,7 @@ as it can be converted to/from a string using repr and eval.
"""
import re, os, sys
from collections import OrderedDict
from pgcollections import OrderedDict
GLOBAL_PATH = None # so not thread safe.
from . import units
from .python2_3 import asUnicode

View File

@ -9,7 +9,7 @@ else:
from exampleLoaderTemplate_pyqt import Ui_Form
import os, sys
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
examples = OrderedDict([
('Command-line usage', 'CLIexample.py'),

View File

@ -14,7 +14,6 @@ import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import collections
app = QtGui.QApplication([])
import pyqtgraph.parametertree.parameterTypes as pTypes
from pyqtgraph.parametertree import Parameter, ParameterTree, ParameterItem, registerParameterType

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtCore, QtGui, USE_PYSIDE
from .Node import *
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
from pyqtgraph.widgets.TreeWidget import *
## pyside and pyqt use incompatible ui files.

View File

@ -3,7 +3,7 @@ from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.graphicsItems.GraphicsObject import GraphicsObject
import pyqtgraph.functions as fn
from .Terminal import *
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
from pyqtgraph.debug import *
import numpy as np
from .eq import *

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
import os, types
from pyqtgraph.debug import printExc
from ..Node import Node

View File

@ -42,7 +42,7 @@ class ArrowItem(QtGui.QGraphicsPathItem):
def setStyle(self, **opts):
self.opts = opts
opt = {k:self.opts[k] for k in ['headLen', 'tipAngle', 'baseAngle', 'tailLen', 'tailWidth']}
opt = dict([(k,self.opts[k]) for k in ['headLen', 'tipAngle', 'baseAngle', 'tailLen', 'tailWidth']])
self.path = fn.makeArrowPath(**opt)
self.setPath(self.path)

View File

@ -3,13 +3,14 @@ from pyqtgraph.python2_3 import sortList
import pyqtgraph.functions as fn
from .GraphicsObject import GraphicsObject
from .GraphicsWidget import GraphicsWidget
import weakref, collections
import weakref
from pyqtgraph.pgcollections import OrderedDict
import numpy as np
__all__ = ['TickSliderItem', 'GradientEditorItem']
Gradients = collections.OrderedDict([
Gradients = OrderedDict([
('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}),
('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}),
('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ),

View File

@ -35,7 +35,6 @@ from .. LabelItem import LabelItem
from .. GraphicsWidget import GraphicsWidget
from .. ButtonItem import ButtonItem
from pyqtgraph.WidgetGroup import WidgetGroup
import collections
__all__ = ['PlotItem']

View File

@ -7,7 +7,7 @@ import numpy as np
import scipy.stats
import weakref
import pyqtgraph.debug as debug
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
#import pyqtgraph as pg
__all__ = ['ScatterPlotItem', 'SpotItem']

View File

@ -9,7 +9,6 @@ from pyqtgraph.GraphicsScene import GraphicsScene
import pyqtgraph
import weakref
from copy import deepcopy
import collections
__all__ = ['ViewBox']
@ -111,12 +110,6 @@ class ViewBox(GraphicsWidget):
}
#self.exportMethods = collections.OrderedDict([
#('SVG', self.saveSvg),
#('Image', self.saveImage),
#('Print', self.savePrint),
#])
self.setFlag(self.ItemClipsChildrenToShape)
self.setFlag(self.ItemIsFocusable, True) ## so we can receive key presses

View File

@ -1,5 +1,6 @@
from pyqtgraph.Qt import QtGui, QtCore
import collections, os, weakref, re
import os, weakref, re
from pyqtgraph.pgcollections import OrderedDict
from .ParameterItem import ParameterItem
PARAM_TYPES = {}
@ -216,7 +217,7 @@ class Parameter(QtCore.QObject):
def getValues(self):
"""Return a tree of all values that are children of this parameter"""
vals = collections.OrderedDict()
vals = OrderedDict()
for ch in self:
vals[ch.name()] = (ch.value(), ch.getValues())
return vals
@ -227,7 +228,7 @@ class Parameter(QtCore.QObject):
The tree state may be restored from this structure using restoreState()
"""
state = self.opts.copy()
state['children'] = collections.OrderedDict([(ch.name(), ch.saveState()) for ch in self])
state['children'] = OrderedDict([(ch.name(), ch.saveState()) for ch in self])
if state['type'] is None:
global PARAM_NAMES
state['type'] = PARAM_NAMES.get(type(self), None)
@ -363,7 +364,7 @@ class Parameter(QtCore.QObject):
most parameters will accept a common set of options: value, name, limits,
default, readonly, removable, renamable, visible, and enabled.
"""
changed = collections.OrderedDict()
changed = OrderedDict()
for k in opts:
if k == 'value':
self.setValue(opts[k])

View File

@ -1,5 +1,5 @@
from pyqtgraph.Qt import QtGui, QtCore
import collections, os, weakref, re
import os, weakref, re
class ParameterItem(QtGui.QTreeWidgetItem):
"""

View File

@ -1,6 +1,6 @@
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.widgets.TreeWidget import TreeWidget
import collections, os, weakref, re
import os, weakref, re
#import functions as fn

View File

@ -5,7 +5,8 @@ from .ParameterItem import ParameterItem
from pyqtgraph.widgets.SpinBox import SpinBox
from pyqtgraph.widgets.ColorButton import ColorButton
import pyqtgraph as pg
import os, collections
import os
from pyqtgraph.pgcollections import OrderedDict
class WidgetParameterItem(ParameterItem):
"""
@ -481,8 +482,6 @@ class ListParameterItem(WidgetParameterItem):
def limitsChanged(self, param, limits):
# set up forward / reverse mappings for name:value
#self.forward = collections.OrderedDict([('', None)]) ## name: value
#self.reverse = collections.OrderedDict([(None, '')]) ## value: name
if len(limits) == 0:
limits = [''] ## Can never have an empty list--there is always at least a singhe blank item.
@ -507,8 +506,8 @@ class ListParameter(Parameter):
itemClass = ListParameterItem
def __init__(self, **opts):
self.forward = collections.OrderedDict() ## name: value
self.reverse = collections.OrderedDict() ## value: name
self.forward = OrderedDict() ## name: value
self.reverse = OrderedDict() ## value: name
## Parameter uses 'limits' option to define the set of allowed values
if 'values' in opts:
@ -528,8 +527,8 @@ class ListParameter(Parameter):
@staticmethod
def mapping(limits):
## Return forward and reverse mapping dictionaries given a limit specification
forward = collections.OrderedDict() ## name: value
reverse = collections.OrderedDict() ## value: name
forward = OrderedDict() ## name: value
reverse = OrderedDict() ## value: name
if isinstance(limits, dict):
for k, v in limits.items():
forward[k] = v

543
pgcollections.py Normal file
View File

@ -0,0 +1,543 @@
# -*- coding: utf-8 -*-
"""
advancedTypes.py - Basic data structures not included with python
Copyright 2010 Luke Campagnola
Distributed under MIT/X11 license. See license.txt for more infomation.
Includes:
- OrderedDict - Dictionary which preserves the order of its elements
- BiDict, ReverseDict - Bi-directional dictionaries
- ThreadsafeDict, ThreadsafeList - Self-mutexed data structures
"""
import threading, sys, copy, collections
#from debug import *
try:
from collections import OrderedDict
except:
# Deprecated; this class is now present in Python 2.7 as collections.OrderedDict
# Only keeping this around for python2.6 support.
class OrderedDict(dict):
"""extends dict so that elements are iterated in the order that they were added.
Since this class can not be instantiated with regular dict notation, it instead uses
a list of tuples:
od = OrderedDict([(key1, value1), (key2, value2), ...])
items set using __setattr__ are added to the end of the key list.
"""
def __init__(self, data=None):
self.order = []
if data is not None:
for i in data:
self[i[0]] = i[1]
def __setitem__(self, k, v):
if not self.has_key(k):
self.order.append(k)
dict.__setitem__(self, k, v)
def __delitem__(self, k):
self.order.remove(k)
dict.__delitem__(self, k)
def keys(self):
return self.order[:]
def items(self):
it = []
for k in self.keys():
it.append((k, self[k]))
return it
def values(self):
return [self[k] for k in self.order]
def remove(self, key):
del self[key]
#self.order.remove(key)
def __iter__(self):
for k in self.order:
yield k
def update(self, data):
"""Works like dict.update, but accepts list-of-tuples as well as dict."""
if isinstance(data, dict):
for k, v in data.iteritems():
self[k] = v
else:
for k,v in data:
self[k] = v
def copy(self):
return OrderedDict(self.items())
def itervalues(self):
for k in self.order:
yield self[k]
def iteritems(self):
for k in self.order:
yield (k, self[k])
def __deepcopy__(self, memo):
return OrderedDict([(k, copy.deepcopy(v, memo)) for k, v in self.iteritems()])
class ReverseDict(dict):
"""extends dict so that reverse lookups are possible by requesting the key as a list of length 1:
d = BiDict({'x': 1, 'y': 2})
d['x']
1
d[[2]]
'y'
"""
def __init__(self, data=None):
if data is None:
data = {}
self.reverse = {}
for k in data:
self.reverse[data[k]] = k
dict.__init__(self, data)
def __getitem__(self, item):
if type(item) is list:
return self.reverse[item[0]]
else:
return dict.__getitem__(self, item)
def __setitem__(self, item, value):
self.reverse[value] = item
dict.__setitem__(self, item, value)
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
class BiDict(dict):
"""extends dict so that reverse lookups are possible by adding each reverse combination to the dict.
This only works if all values and keys are unique."""
def __init__(self, data=None):
if data is None:
data = {}
dict.__init__(self)
for k in data:
self[data[k]] = k
def __setitem__(self, item, value):
dict.__setitem__(self, item, value)
dict.__setitem__(self, value, item)
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
class ThreadsafeDict(dict):
"""Extends dict so that getitem, setitem, and contains are all thread-safe.
Also adds lock/unlock functions for extended exclusive operations
Converts all sub-dicts and lists to threadsafe as well.
"""
def __init__(self, *args, **kwargs):
self.mutex = threading.RLock()
dict.__init__(self, *args, **kwargs)
for k in self:
if type(self[k]) is dict:
self[k] = ThreadsafeDict(self[k])
def __getitem__(self, attr):
self.lock()
try:
val = dict.__getitem__(self, attr)
finally:
self.unlock()
return val
def __setitem__(self, attr, val):
if type(val) is dict:
val = ThreadsafeDict(val)
self.lock()
try:
dict.__setitem__(self, attr, val)
finally:
self.unlock()
def __contains__(self, attr):
self.lock()
try:
val = dict.__contains__(self, attr)
finally:
self.unlock()
return val
def __len__(self):
self.lock()
try:
val = dict.__len__(self)
finally:
self.unlock()
return val
def clear(self):
self.lock()
try:
dict.clear(self)
finally:
self.unlock()
def lock(self):
self.mutex.acquire()
def unlock(self):
self.mutex.release()
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
class ThreadsafeList(list):
"""Extends list so that getitem, setitem, and contains are all thread-safe.
Also adds lock/unlock functions for extended exclusive operations
Converts all sub-lists and dicts to threadsafe as well.
"""
def __init__(self, *args, **kwargs):
self.mutex = threading.RLock()
list.__init__(self, *args, **kwargs)
for k in self:
self[k] = mkThreadsafe(self[k])
def __getitem__(self, attr):
self.lock()
try:
val = list.__getitem__(self, attr)
finally:
self.unlock()
return val
def __setitem__(self, attr, val):
val = makeThreadsafe(val)
self.lock()
try:
list.__setitem__(self, attr, val)
finally:
self.unlock()
def __contains__(self, attr):
self.lock()
try:
val = list.__contains__(self, attr)
finally:
self.unlock()
return val
def __len__(self):
self.lock()
try:
val = list.__len__(self)
finally:
self.unlock()
return val
def lock(self):
self.mutex.acquire()
def unlock(self):
self.mutex.release()
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
def makeThreadsafe(obj):
if type(obj) is dict:
return ThreadsafeDict(obj)
elif type(obj) is list:
return ThreadsafeList(obj)
elif type(obj) in [str, int, float, bool, tuple]:
return obj
else:
raise Exception("Not sure how to make object of type %s thread-safe" % str(type(obj)))
class Locker:
def __init__(self, lock):
self.lock = lock
self.lock.acquire()
def __del__(self):
try:
self.lock.release()
except:
pass
class CaselessDict(OrderedDict):
"""Case-insensitive dict. Values can be set and retrieved using keys of any case.
Note that when iterating, the original case is returned for each key."""
def __init__(self, *args):
OrderedDict.__init__(self, {}) ## requirement for the empty {} here seems to be a python bug?
self.keyMap = OrderedDict([(k.lower(), k) for k in OrderedDict.keys(self)])
if len(args) == 0:
return
elif len(args) == 1 and isinstance(args[0], dict):
for k in args[0]:
self[k] = args[0][k]
else:
raise Exception("CaselessDict may only be instantiated with a single dict.")
#def keys(self):
#return self.keyMap.values()
def __setitem__(self, key, val):
kl = key.lower()
if kl in self.keyMap:
OrderedDict.__setitem__(self, self.keyMap[kl], val)
else:
OrderedDict.__setitem__(self, key, val)
self.keyMap[kl] = key
def __getitem__(self, key):
kl = key.lower()
if kl not in self.keyMap:
raise KeyError(key)
return OrderedDict.__getitem__(self, self.keyMap[kl])
def __contains__(self, key):
return key.lower() in self.keyMap
def update(self, d):
for k, v in d.iteritems():
self[k] = v
def copy(self):
return CaselessDict(OrderedDict.copy(self))
def __delitem__(self, key):
kl = key.lower()
if kl not in self.keyMap:
raise KeyError(key)
OrderedDict.__delitem__(self, self.keyMap[kl])
del self.keyMap[kl]
def __deepcopy__(self, memo):
raise Exception("deepcopy not implemented")
def clear(self):
OrderedDict.clear(self)
self.keyMap.clear()
class ProtectedDict(dict):
"""
A class allowing read-only 'view' of a dict.
The object can be treated like a normal dict, but will never modify the original dict it points to.
Any values accessed from the dict will also be read-only.
"""
def __init__(self, data):
self._data_ = data
## List of methods to directly wrap from _data_
wrapMethods = ['_cmp_', '__contains__', '__eq__', '__format__', '__ge__', '__gt__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'has_key', 'iterkeys', 'keys', ]
## List of methods which wrap from _data_ but return protected results
protectMethods = ['__getitem__', '__iter__', 'get', 'items', 'values']
## List of methods to disable
disableMethods = ['__delitem__', '__setitem__', 'clear', 'pop', 'popitem', 'setdefault', 'update']
## Template methods
def wrapMethod(methodName):
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
def protectMethod(methodName):
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
def error(self, *args, **kargs):
raise Exception("Can not modify read-only list.")
## Directly (and explicitly) wrap some methods from _data_
## Many of these methods can not be intercepted using __getattribute__, so they
## must be implemented explicitly
for methodName in wrapMethods:
locals()[methodName] = wrapMethod(methodName)
## Wrap some methods from _data_ with the results converted to protected objects
for methodName in protectMethods:
locals()[methodName] = protectMethod(methodName)
## Disable any methods that could change data in the list
for methodName in disableMethods:
locals()[methodName] = error
## Add a few extra methods.
def copy(self):
raise Exception("It is not safe to copy protected dicts! (instead try deepcopy, but be careful.)")
def itervalues(self):
for v in self._data_.itervalues():
yield protect(v)
def iteritems(self):
for k, v in self._data_.iteritems():
yield (k, protect(v))
def deepcopy(self):
return copy.deepcopy(self._data_)
def __deepcopy__(self, memo):
return copy.deepcopy(self._data_, memo)
class ProtectedList(collections.Sequence):
"""
A class allowing read-only 'view' of a list or dict.
The object can be treated like a normal list, but will never modify the original list it points to.
Any values accessed from the list will also be read-only.
Note: It would be nice if we could inherit from list or tuple so that isinstance checks would work.
However, doing this causes tuple(obj) to return unprotected results (importantly, this means
unpacking into function arguments will also fail)
"""
def __init__(self, data):
self._data_ = data
#self.__mro__ = (ProtectedList, object)
## List of methods to directly wrap from _data_
wrapMethods = ['__contains__', '__eq__', '__format__', '__ge__', '__gt__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'index']
## List of methods which wrap from _data_ but return protected results
protectMethods = ['__getitem__', '__getslice__', '__mul__', '__reversed__', '__rmul__']
## List of methods to disable
disableMethods = ['__delitem__', '__delslice__', '__iadd__', '__imul__', '__setitem__', '__setslice__', 'append', 'extend', 'insert', 'pop', 'remove', 'reverse', 'sort']
## Template methods
def wrapMethod(methodName):
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
def protectMethod(methodName):
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
def error(self, *args, **kargs):
raise Exception("Can not modify read-only list.")
## Directly (and explicitly) wrap some methods from _data_
## Many of these methods can not be intercepted using __getattribute__, so they
## must be implemented explicitly
for methodName in wrapMethods:
locals()[methodName] = wrapMethod(methodName)
## Wrap some methods from _data_ with the results converted to protected objects
for methodName in protectMethods:
locals()[methodName] = protectMethod(methodName)
## Disable any methods that could change data in the list
for methodName in disableMethods:
locals()[methodName] = error
## Add a few extra methods.
def __iter__(self):
for item in self._data_:
yield protect(item)
def __add__(self, op):
if isinstance(op, ProtectedList):
return protect(self._data_.__add__(op._data_))
elif isinstance(op, list):
return protect(self._data_.__add__(op))
else:
raise TypeError("Argument must be a list.")
def __radd__(self, op):
if isinstance(op, ProtectedList):
return protect(op._data_.__add__(self._data_))
elif isinstance(op, list):
return protect(op.__add__(self._data_))
else:
raise TypeError("Argument must be a list.")
def deepcopy(self):
return copy.deepcopy(self._data_)
def __deepcopy__(self, memo):
return copy.deepcopy(self._data_, memo)
def poop(self):
raise Exception("This is a list. It does not poop.")
class ProtectedTuple(collections.Sequence):
"""
A class allowing read-only 'view' of a tuple.
The object can be treated like a normal tuple, but its contents will be returned as protected objects.
Note: It would be nice if we could inherit from list or tuple so that isinstance checks would work.
However, doing this causes tuple(obj) to return unprotected results (importantly, this means
unpacking into function arguments will also fail)
"""
def __init__(self, data):
self._data_ = data
## List of methods to directly wrap from _data_
wrapMethods = ['__contains__', '__eq__', '__format__', '__ge__', '__getnewargs__', '__gt__', '__hash__', '__le__', '__len__', '__lt__', '__ne__', '__reduce__', '__reduce_ex__', '__repr__', '__str__', 'count', 'index']
## List of methods which wrap from _data_ but return protected results
protectMethods = ['__getitem__', '__getslice__', '__iter__', '__add__', '__mul__', '__reversed__', '__rmul__']
## Template methods
def wrapMethod(methodName):
return lambda self, *a, **k: getattr(self._data_, methodName)(*a, **k)
def protectMethod(methodName):
return lambda self, *a, **k: protect(getattr(self._data_, methodName)(*a, **k))
## Directly (and explicitly) wrap some methods from _data_
## Many of these methods can not be intercepted using __getattribute__, so they
## must be implemented explicitly
for methodName in wrapMethods:
locals()[methodName] = wrapMethod(methodName)
## Wrap some methods from _data_ with the results converted to protected objects
for methodName in protectMethods:
locals()[methodName] = protectMethod(methodName)
## Add a few extra methods.
def deepcopy(self):
return copy.deepcopy(self._data_)
def __deepcopy__(self, memo):
return copy.deepcopy(self._data_, memo)
def protect(obj):
if isinstance(obj, dict):
return ProtectedDict(obj)
elif isinstance(obj, list):
return ProtectedList(obj)
elif isinstance(obj, tuple):
return ProtectedTuple(obj)
else:
return obj
if __name__ == '__main__':
d = {'x': 1, 'y': [1,2], 'z': ({'a': 2, 'b': [3,4], 'c': (5,6)}, 1, 2)}
dp = protect(d)
l = [1, 'x', ['a', 'b'], ('c', 'd'), {'x': 1, 'y': 2}]
lp = protect(l)
t = (1, 'x', ['a', 'b'], ('c', 'd'), {'x': 1, 'y': 2})
tp = protect(t)

View File

@ -1,4 +1,10 @@
from distutils.core import setup
import os
## generate list of all sub-packages
subdirs = [['pyqtgraph'] + i[0].split(os.path.sep)[1:] for i in os.walk('.') if '__init__.py' in i[2]]
subdirs = filter(lambda p: len(p) == 1 or p[1] != 'build', subdirs)
all_packages = ['.'.join(p) for p in subdirs]
setup(name='pyqtgraph',
version='',
@ -8,24 +14,8 @@ setup(name='pyqtgraph',
author='Luke Campagnola',
author_email='luke.campagnola@gmail.com',
url='',
packages=['pyqtgraph', 'pyqtgraph.console', 'pyqtgraph.graphicsItems', 'pyqtgraph.widgets', 'pyqtgraph.metaarray', 'pyqtgraph.parametertree', 'pyqtgraph.flowchart', 'pyqtgraph.imageview', 'pyqtgraph.dockarea', 'pyqtgraph.examples', 'pyqtgraph.canvas', 'pyqtgraph.exporters', 'pyqtgraph.GraphicsScene', 'pyqtgraph.multiprocess', 'pyqtgraph.opengl'],
packages=all_packages,
package_dir = {'pyqtgraph': '.'},
package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']},
)
#Package: python-pyqtgraph
#Version: 196
#Section: custom
#Priority: optional
#Architecture: all
#Essential: no
#Installed-Size: 4652
#Maintainer: Luke Campagnola <luke.campagnola@gmail.com>
#Homepage: http://luke.campagnola.me/code/pyqtgraph
#Depends: python (>= 2.7), python-qt4 | python-pyside, python-scipy
#Suggests: python-opengl, python-qt4-gl
#Description: Scientific Graphics and GUI Library for Python
#PyQtGraph is a pure-python graphics and GUI library built on PyQt4 and numpy. It is intended for use in mathematics / scientific / engineering applications. Despite being written entirely in python, the library is very fast due to its heavy leverage of numpy for number crunching and Qt's GraphicsView framework for fast display.

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtGui, QtCore
from collections import OrderedDict
from pyqtgraph.pgcollections import OrderedDict
import types, traceback
import numpy as np

View File

@ -4,7 +4,6 @@ from .GraphicsView import GraphicsView
from pyqtgraph.graphicsItems.GradientEditorItem import GradientEditorItem
import weakref
import numpy as np
import collections
__all__ = ['TickSlider', 'GradientWidget', 'BlackWhiteSlider']
@ -53,525 +52,3 @@ class GradientWidget(GraphicsView):
return getattr(self.item, attr)
#Gradients = collections.OrderedDict([
#('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}),
#('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}),
#('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ),
#('bipolar', {'ticks': [(0.0, (0, 255, 255, 255)), (1.0, (255, 255, 0, 255)), (0.5, (0, 0, 0, 255)), (0.25, (0, 0, 255, 255)), (0.75, (255, 0, 0, 255))], 'mode': 'rgb'}),
#('spectrum', {'ticks': [(1.0, (255, 0, 255, 255)), (0.0, (255, 0, 0, 255))], 'mode': 'hsv'}),
#('cyclic', {'ticks': [(0.0, (255, 0, 4, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'hsv'}),
#('greyclip', {'ticks': [(0.0, (0, 0, 0, 255)), (0.99, (255, 255, 255, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'rgb'}),
#])
#class TickSlider(GraphicsView):
#def __init__(self, parent=None, orientation='bottom', allowAdd=True, **kargs):
#self.orientation = orientation
#self.length = 100
#self.tickSize = 15
#self.ticks = {}
#self.maxDim = 20
#GraphicsView.__init__(self, parent, useOpenGL=False)
#self.allowAdd = allowAdd
##self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
##self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
##self.setTransformationAnchor(QtGui.QGraphicsView.NoAnchor)
##self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
#self.setRenderHints(QtGui.QPainter.Antialiasing | QtGui.QPainter.TextAntialiasing)
#self.orientations = {
#'left': (270, 1, -1),
#'right': (270, 1, 1),
#'top': (0, 1, -1),
#'bottom': (0, 1, 1)
#}
##self.scene = QtGui.QGraphicsScene()
##self.setScene(self.scene)
#self.setOrientation(orientation)
#self.setFrameStyle(QtGui.QFrame.NoFrame | QtGui.QFrame.Plain)
#self.setBackgroundRole(QtGui.QPalette.NoRole)
#self.setMouseTracking(True)
#def keyPressEvent(self, ev):
#ev.ignore()
#def setMaxDim(self, mx=None):
#if mx is None:
#mx = self.maxDim
#else:
#self.maxDim = mx
#if self.orientation in ['bottom', 'top']:
#self.setFixedHeight(mx)
#self.setMaximumWidth(16777215)
#else:
#self.setFixedWidth(mx)
#self.setMaximumHeight(16777215)
#def setOrientation(self, ort):
#self.orientation = ort
#self.resetTransform()
#self.rotate(self.orientations[ort][0])
#self.scale(*self.orientations[ort][1:])
#self.setMaxDim()
#def addTick(self, x, color=None, movable=True):
#if color is None:
#color = QtGui.QColor(255,255,255)
#tick = Tick(self, [x*self.length, 0], color, movable, self.tickSize)
#self.ticks[tick] = x
#self.scene.addItem(tick)
#return tick
#def removeTick(self, tick):
#del self.ticks[tick]
#self.scene.removeItem(tick)
#def tickMoved(self, tick, pos):
##print "tick changed"
### Correct position of tick if it has left bounds.
#newX = min(max(0, pos.x()), self.length)
#pos.setX(newX)
#tick.setPos(pos)
#self.ticks[tick] = float(newX) / self.length
#def tickClicked(self, tick, ev):
#if ev.button() == QtCore.Qt.RightButton:
#self.removeTick(tick)
#def widgetLength(self):
#if self.orientation in ['bottom', 'top']:
#return self.width()
#else:
#return self.height()
#def resizeEvent(self, ev):
#wlen = max(40, self.widgetLength())
#self.setLength(wlen-self.tickSize)
#bounds = self.scene().itemsBoundingRect()
#bounds.setLeft(min(-self.tickSize*0.5, bounds.left()))
#bounds.setRight(max(self.length + self.tickSize, bounds.right()))
##bounds.setTop(min(bounds.top(), self.tickSize))
##bounds.setBottom(max(0, bounds.bottom()))
#self.setSceneRect(bounds)
#self.fitInView(bounds, QtCore.Qt.KeepAspectRatio)
#def setLength(self, newLen):
#for t, x in self.ticks.items():
#t.setPos(x * newLen, t.pos().y())
#self.length = float(newLen)
#def mousePressEvent(self, ev):
#QtGui.QGraphicsView.mousePressEvent(self, ev)
#self.ignoreRelease = False
#for i in self.items(ev.pos()):
#if isinstance(i, Tick):
#self.ignoreRelease = True
#break
##if len(self.items(ev.pos())) > 0: ## Let items handle their own clicks
##self.ignoreRelease = True
#def mouseReleaseEvent(self, ev):
#QtGui.QGraphicsView.mouseReleaseEvent(self, ev)
#if self.ignoreRelease:
#return
#pos = self.mapToScene(ev.pos())
#if ev.button() == QtCore.Qt.LeftButton and self.allowAdd:
#if pos.x() < 0 or pos.x() > self.length:
#return
#if pos.y() < 0 or pos.y() > self.tickSize:
#return
#pos.setX(min(max(pos.x(), 0), self.length))
#self.addTick(pos.x()/self.length)
#elif ev.button() == QtCore.Qt.RightButton:
#self.showMenu(ev)
#def showMenu(self, ev):
#pass
#def setTickColor(self, tick, color):
#tick = self.getTick(tick)
#tick.color = color
#tick.setBrush(QtGui.QBrush(QtGui.QColor(tick.color)))
#def setTickValue(self, tick, val):
#tick = self.getTick(tick)
#val = min(max(0.0, val), 1.0)
#x = val * self.length
#pos = tick.pos()
#pos.setX(x)
#tick.setPos(pos)
#self.ticks[tick] = val
#def tickValue(self, tick):
#tick = self.getTick(tick)
#return self.ticks[tick]
#def getTick(self, tick):
#if type(tick) is int:
#tick = self.listTicks()[tick][0]
#return tick
#def mouseMoveEvent(self, ev):
#QtGui.QGraphicsView.mouseMoveEvent(self, ev)
##print ev.pos(), ev.buttons()
#def listTicks(self):
#ticks = self.ticks.items()
#ticks.sort(lambda a,b: cmp(a[1], b[1]))
#return ticks
#class GradientWidget(TickSlider):
#sigGradientChanged = QtCore.Signal(object)
#def __init__(self, *args, **kargs):
#self.currentTick = None
#self.currentTickColor = None
#self.rectSize = 15
#self.gradRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
#self.backgroundRect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, -self.rectSize, 100, self.rectSize))
#self.backgroundRect.setBrush(QtGui.QBrush(QtCore.Qt.DiagCrossPattern))
#self.colorMode = 'rgb'
#TickSlider.__init__(self, *args, **kargs)
#self.colorDialog = QtGui.QColorDialog()
#self.colorDialog.setOption(QtGui.QColorDialog.ShowAlphaChannel, True)
#self.colorDialog.setOption(QtGui.QColorDialog.DontUseNativeDialog, True)
#self.colorDialog.currentColorChanged.connect(self.currentColorChanged)
#self.colorDialog.rejected.connect(self.currentColorRejected)
##self.gradient = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(100,0))
#self.scene.addItem(self.backgroundRect)
#self.scene.addItem(self.gradRect)
#self.setMaxDim(self.rectSize + self.tickSize)
##self.btn = QtGui.QPushButton('RGB')
##self.btnProxy = self.scene.addWidget(self.btn)
##self.btnProxy.setFlag(self.btnProxy.ItemIgnoresTransformations)
##self.btnProxy.scale(0.7, 0.7)
##self.btnProxy.translate(-self.btnProxy.sceneBoundingRect().width()+self.tickSize/2., 0)
##if self.orientation == 'bottom':
##self.btnProxy.translate(0, -self.rectSize)
#self.rgbAction = QtGui.QAction('RGB', self)
#self.rgbAction.setCheckable(True)
#self.rgbAction.triggered.connect(lambda: self.setColorMode('rgb'))
#self.hsvAction = QtGui.QAction('HSV', self)
#self.hsvAction.setCheckable(True)
#self.hsvAction.triggered.connect(lambda: self.setColorMode('hsv'))
#self.menu = QtGui.QMenu()
### build context menu of gradients
#global Gradients
#for g in Gradients:
#px = QtGui.QPixmap(100, 15)
#p = QtGui.QPainter(px)
#self.restoreState(Gradients[g])
#grad = self.getGradient()
#brush = QtGui.QBrush(grad)
#p.fillRect(QtCore.QRect(0, 0, 100, 15), brush)
#p.end()
#label = QtGui.QLabel()
#label.setPixmap(px)
#label.setContentsMargins(1, 1, 1, 1)
#act = QtGui.QWidgetAction(self)
#act.setDefaultWidget(label)
#act.triggered.connect(self.contextMenuClicked)
#act.name = g
#self.menu.addAction(act)
#self.menu.addSeparator()
#self.menu.addAction(self.rgbAction)
#self.menu.addAction(self.hsvAction)
#for t in self.ticks.keys():
#self.removeTick(t)
#self.addTick(0, QtGui.QColor(0,0,0), True)
#self.addTick(1, QtGui.QColor(255,0,0), True)
#self.setColorMode('rgb')
#self.updateGradient()
#def showMenu(self, ev):
#self.menu.popup(ev.globalPos())
#def contextMenuClicked(self, b):
#global Gradients
#act = self.sender()
#self.restoreState(Gradients[act.name])
#def setColorMode(self, cm):
#if cm not in ['rgb', 'hsv']:
#raise Exception("Unknown color mode %s. Options are 'rgb' and 'hsv'." % str(cm))
#try:
#self.rgbAction.blockSignals(True)
#self.hsvAction.blockSignals(True)
#self.rgbAction.setChecked(cm == 'rgb')
#self.hsvAction.setChecked(cm == 'hsv')
#finally:
#self.rgbAction.blockSignals(False)
#self.hsvAction.blockSignals(False)
#self.colorMode = cm
#self.updateGradient()
#def updateGradient(self):
#self.gradient = self.getGradient()
#self.gradRect.setBrush(QtGui.QBrush(self.gradient))
#self.sigGradientChanged.emit(self)
#def setLength(self, newLen):
#TickSlider.setLength(self, newLen)
#self.backgroundRect.setRect(0, -self.rectSize, newLen, self.rectSize)
#self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize)
#self.updateGradient()
#def currentColorChanged(self, color):
#if color.isValid() and self.currentTick is not None:
#self.setTickColor(self.currentTick, color)
#self.updateGradient()
#def currentColorRejected(self):
#self.setTickColor(self.currentTick, self.currentTickColor)
#self.updateGradient()
#def tickClicked(self, tick, ev):
#if ev.button() == QtCore.Qt.LeftButton:
#if not tick.colorChangeAllowed:
#return
#self.currentTick = tick
#self.currentTickColor = tick.color
#self.colorDialog.setCurrentColor(tick.color)
#self.colorDialog.open()
##color = QtGui.QColorDialog.getColor(tick.color, self, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
##if color.isValid():
##self.setTickColor(tick, color)
##self.updateGradient()
#elif ev.button() == QtCore.Qt.RightButton:
#if not tick.removeAllowed:
#return
#if len(self.ticks) > 2:
#self.removeTick(tick)
#self.updateGradient()
#def tickMoved(self, tick, pos):
#TickSlider.tickMoved(self, tick, pos)
#self.updateGradient()
#def getGradient(self):
#g = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(self.length,0))
#if self.colorMode == 'rgb':
#ticks = self.listTicks()
#g.setStops([(x, QtGui.QColor(t.color)) for t,x in ticks])
#elif self.colorMode == 'hsv': ## HSV mode is approximated for display by interpolating 10 points between each stop
#ticks = self.listTicks()
#stops = []
#stops.append((ticks[0][1], ticks[0][0].color))
#for i in range(1,len(ticks)):
#x1 = ticks[i-1][1]
#x2 = ticks[i][1]
#dx = (x2-x1) / 10.
#for j in range(1,10):
#x = x1 + dx*j
#stops.append((x, self.getColor(x)))
#stops.append((x2, self.getColor(x2)))
#g.setStops(stops)
#return g
#def getColor(self, x, toQColor=True):
#ticks = self.listTicks()
#if x <= ticks[0][1]:
#c = ticks[0][0].color
#if toQColor:
#return QtGui.QColor(c) # always copy colors before handing them out
#else:
#return (c.red(), c.green(), c.blue(), c.alpha())
#if x >= ticks[-1][1]:
#c = ticks[-1][0].color
#if toQColor:
#return QtGui.QColor(c) # always copy colors before handing them out
#else:
#return (c.red(), c.green(), c.blue(), c.alpha())
#x2 = ticks[0][1]
#for i in range(1,len(ticks)):
#x1 = x2
#x2 = ticks[i][1]
#if x1 <= x and x2 >= x:
#break
#dx = (x2-x1)
#if dx == 0:
#f = 0.
#else:
#f = (x-x1) / dx
#c1 = ticks[i-1][0].color
#c2 = ticks[i][0].color
#if self.colorMode == 'rgb':
#r = c1.red() * (1.-f) + c2.red() * f
#g = c1.green() * (1.-f) + c2.green() * f
#b = c1.blue() * (1.-f) + c2.blue() * f
#a = c1.alpha() * (1.-f) + c2.alpha() * f
#if toQColor:
#return QtGui.QColor(r, g, b,a)
#else:
#return (r,g,b,a)
#elif self.colorMode == 'hsv':
#h1,s1,v1,_ = c1.getHsv()
#h2,s2,v2,_ = c2.getHsv()
#h = h1 * (1.-f) + h2 * f
#s = s1 * (1.-f) + s2 * f
#v = v1 * (1.-f) + v2 * f
#c = QtGui.QColor()
#c.setHsv(h,s,v)
#if toQColor:
#return c
#else:
#return (c.red(), c.green(), c.blue(), c.alpha())
#def getLookupTable(self, nPts, alpha=True):
#"""Return an RGB/A lookup table."""
#if alpha:
#table = np.empty((nPts,4), dtype=np.ubyte)
#else:
#table = np.empty((nPts,3), dtype=np.ubyte)
#for i in range(nPts):
#x = float(i)/(nPts-1)
#color = self.getColor(x, toQColor=False)
#table[i] = color[:table.shape[1]]
#return table
#def mouseReleaseEvent(self, ev):
#TickSlider.mouseReleaseEvent(self, ev)
#self.updateGradient()
#def addTick(self, x, color=None, movable=True):
#if color is None:
#color = self.getColor(x)
#t = TickSlider.addTick(self, x, color=color, movable=movable)
#t.colorChangeAllowed = True
#t.removeAllowed = True
#return t
#def saveState(self):
#ticks = []
#for t in self.ticks:
#c = t.color
#ticks.append((self.ticks[t], (c.red(), c.green(), c.blue(), c.alpha())))
#state = {'mode': self.colorMode, 'ticks': ticks}
#return state
#def restoreState(self, state):
#self.setColorMode(state['mode'])
#for t in self.ticks.keys():
#self.removeTick(t)
#for t in state['ticks']:
#c = QtGui.QColor(*t[1])
#self.addTick(t[0], c)
#self.updateGradient()
#class BlackWhiteSlider(GradientWidget):
#def __init__(self, parent):
#GradientWidget.__init__(self, parent)
#self.getTick(0).colorChangeAllowed = False
#self.getTick(1).colorChangeAllowed = False
#self.allowAdd = False
#self.setTickColor(self.getTick(1), QtGui.QColor(255,255,255))
#self.setOrientation('right')
#def getLevels(self):
#return (self.tickValue(0), self.tickValue(1))
#def setLevels(self, black, white):
#self.setTickValue(0, black)
#self.setTickValue(1, white)
#class GammaWidget(TickSlider):
#pass
#class Tick(QtGui.QGraphicsPolygonItem):
#def __init__(self, view, pos, color, movable=True, scale=10):
##QObjectWorkaround.__init__(self)
#self.movable = movable
#self.view = weakref.ref(view)
#self.scale = scale
#self.color = color
##self.endTick = endTick
#self.pg = QtGui.QPolygonF([QtCore.QPointF(0,0), QtCore.QPointF(-scale/3**0.5,scale), QtCore.QPointF(scale/3**0.5,scale)])
#QtGui.QGraphicsPolygonItem.__init__(self, self.pg)
#self.setPos(pos[0], pos[1])
#self.setFlags(QtGui.QGraphicsItem.ItemIsMovable | QtGui.QGraphicsItem.ItemIsSelectable)
#self.setBrush(QtGui.QBrush(QtGui.QColor(self.color)))
#if self.movable:
#self.setZValue(1)
#else:
#self.setZValue(0)
##def x(self):
##return self.pos().x()/100.
#def mouseMoveEvent(self, ev):
##print self, "move", ev.scenePos()
#if not self.movable:
#return
#if not ev.buttons() & QtCore.Qt.LeftButton:
#return
#newPos = ev.scenePos() + self.mouseOffset
#newPos.setY(self.pos().y())
##newPos.setX(min(max(newPos.x(), 0), 100))
#self.setPos(newPos)
#self.view().tickMoved(self, newPos)
#self.movedSincePress = True
##self.emit(QtCore.SIGNAL('tickChanged'), self)
#ev.accept()
#def mousePressEvent(self, ev):
#self.movedSincePress = False
#if ev.button() == QtCore.Qt.LeftButton:
#ev.accept()
#self.mouseOffset = self.pos() - ev.scenePos()
#self.pressPos = ev.scenePos()
#elif ev.button() == QtCore.Qt.RightButton:
#ev.accept()
##if self.endTick:
##return
##self.view.tickChanged(self, delete=True)
#def mouseReleaseEvent(self, ev):
##print self, "release", ev.scenePos()
#if not self.movedSincePress:
#self.view().tickClicked(self, ev)
##if ev.button() == QtCore.Qt.LeftButton and ev.scenePos() == self.pressPos:
##color = QtGui.QColorDialog.getColor(self.color, None, "Select Color", QtGui.QColorDialog.ShowAlphaChannel)
##if color.isValid():
##self.color = color
##self.setBrush(QtGui.QBrush(QtGui.QColor(self.color)))
###self.emit(QtCore.SIGNAL('tickChanged'), self)
##self.view.tickChanged(self)

View File

@ -120,6 +120,14 @@ class GraphicsView(QtGui.QGraphicsView):
self.scaleCenter = False ## should scaling center around view center (True) or mouse click (False)
self.clickAccepted = False
def setAntialiasing(self, aa):
"""Enable or disable default antialiasing.
Note that this will only affect items that do not specify their own antialiasing options."""
if aa:
self.setRenderHints(self.renderHints() | QtGui.QPainter.Antialiasing)
else:
self.setRenderHints(self.renderHints() & ~QtGui.QPainter.Antialiasing)
def setBackground(self, background):
"""
Set the background color of the GraphicsView.