Features:
- Canvas: added per-item context menus - Isocurve: option to extend curves to array boundaries option to generate QPainterPath instead of vertex array - Isosurface is a bajillion times faster - ViewBox added clear() method added locate(item) method (shows where an item is for debugging) Bugfixes: - automated example testing working properly - Exporter gets incorrect source rect when operating on PlotWidget - Set correct DPI and size for SVG exporter - GLMeshItem works properly with whole-mesh color specified as sequence - bugfix in functions.transformCoordinates for rotated matrices - reload library checks for modules that are imported multiple times - GraphicsObject, UIGraphicsItem: added workaround for PyQt / itemChange bug - ScatterPlotItem: disable cached render during export Other: - added documentation for several functions - minor updates to setup.py
This commit is contained in:
commit
b25e34f564
@ -92,6 +92,15 @@ class Canvas(QtGui.QWidget):
|
||||
if name is not None:
|
||||
self.registeredName = CanvasManager.instance().registerCanvas(self, name)
|
||||
self.ui.redirectCombo.setHostName(self.registeredName)
|
||||
|
||||
self.menu = QtGui.QMenu()
|
||||
#self.menu.setTitle("Image")
|
||||
remAct = QtGui.QAction("Remove item", self.menu)
|
||||
remAct.triggered.connect(self.removeClicked)
|
||||
self.menu.addAction(remAct)
|
||||
self.menu.remAct = remAct
|
||||
self.ui.itemList.contextMenuEvent = self.itemListContextMenuEvent
|
||||
|
||||
|
||||
def storeSvg(self):
|
||||
self.ui.view.writeSvg()
|
||||
@ -513,10 +522,20 @@ class Canvas(QtGui.QWidget):
|
||||
listItem.setCheckState(0, QtCore.Qt.Unchecked)
|
||||
|
||||
def removeItem(self, item):
|
||||
if isinstance(item, QtGui.QTreeWidgetItem):
|
||||
item = item.canvasItem()
|
||||
|
||||
|
||||
if isinstance(item, CanvasItem):
|
||||
item.setCanvas(None)
|
||||
self.itemList.removeTopLevelItem(item.listItem)
|
||||
listItem = item.listItem
|
||||
listItem.canvasItem = None
|
||||
item.listItem = None
|
||||
self.itemList.removeTopLevelItem(listItem)
|
||||
self.items.remove(item)
|
||||
ctrl = item.ctrlWidget()
|
||||
ctrl.hide()
|
||||
self.ui.ctrlLayout.removeWidget(ctrl)
|
||||
else:
|
||||
if hasattr(item, '_canvasItem'):
|
||||
self.removeItem(item._canvasItem)
|
||||
@ -555,7 +574,15 @@ class Canvas(QtGui.QWidget):
|
||||
#self.emit(QtCore.SIGNAL('itemTransformChangeFinished'), self, item)
|
||||
self.sigItemTransformChangeFinished.emit(self, item)
|
||||
|
||||
|
||||
def itemListContextMenuEvent(self, ev):
|
||||
self.menuItem = self.itemList.itemAt(ev.pos())
|
||||
self.menu.popup(ev.globalPos())
|
||||
|
||||
def removeClicked(self):
|
||||
self.removeItem(self.menuItem)
|
||||
self.menuItem = None
|
||||
import gc
|
||||
gc.collect()
|
||||
|
||||
class SelectBox(ROI):
|
||||
def __init__(self, scalable=False):
|
||||
|
@ -208,8 +208,11 @@ class ConsoleWidget(QtGui.QWidget):
|
||||
#self.stdout.write("</div><br><div style='font-weight: normal; background-color: #FFF;'>")
|
||||
self.output.insertPlainText(strn)
|
||||
#self.stdout.write(strn)
|
||||
|
||||
|
||||
def displayException(self):
|
||||
"""
|
||||
Display the current exception and stack.
|
||||
"""
|
||||
tb = traceback.format_exc()
|
||||
lines = []
|
||||
indent = 4
|
||||
|
@ -8,7 +8,7 @@ Simple Data Display Functions
|
||||
|
||||
.. autofunction:: pyqtgraph.image
|
||||
|
||||
|
||||
.. autofunction:: pyqtgraph.dbg
|
||||
|
||||
Color, Pen, and Brush Functions
|
||||
-------------------------------
|
||||
@ -34,6 +34,8 @@ Qt uses the classes QColor, QPen, and QBrush to determine how to draw lines and
|
||||
|
||||
.. autofunction:: pyqtgraph.colorStr
|
||||
|
||||
.. autofunction:: pyqtgraph.glColor
|
||||
|
||||
|
||||
Data Slicing
|
||||
------------
|
||||
@ -41,6 +43,18 @@ Data Slicing
|
||||
.. autofunction:: pyqtgraph.affineSlice
|
||||
|
||||
|
||||
Coordinate Transformation
|
||||
-------------------------
|
||||
|
||||
.. autofunction:: pyqtgraph.transformToArray
|
||||
|
||||
.. autofunction:: pyqtgraph.transformCoordinates
|
||||
|
||||
.. autofunction:: pyqtgraph.solve3DTransform
|
||||
|
||||
.. autofunction:: pyqtgraph.solveBilinearTransform
|
||||
|
||||
|
||||
|
||||
SI Unit Conversion Functions
|
||||
----------------------------
|
||||
@ -59,6 +73,12 @@ Image Preparation Functions
|
||||
|
||||
.. autofunction:: pyqtgraph.makeQImage
|
||||
|
||||
.. autofunction:: pyqtgraph.applyLookupTable
|
||||
|
||||
.. autofunction:: pyqtgraph.rescaleData
|
||||
|
||||
.. autofunction:: pyqtgraph.imageToArray
|
||||
|
||||
|
||||
Mesh Generation Functions
|
||||
-------------------------
|
||||
@ -68,4 +88,13 @@ Mesh Generation Functions
|
||||
.. autofunction:: pyqtgraph.isosurface
|
||||
|
||||
|
||||
Miscellaneous Functions
|
||||
-----------------------
|
||||
|
||||
.. autofunction:: pyqtgraph.pseudoScatter
|
||||
|
||||
.. autofunction:: pyqtgraph.systemInfo
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -45,9 +45,9 @@ data = np.abs(np.fromfunction(psi, (50,50,100)))
|
||||
|
||||
|
||||
print("Generating isosurface..")
|
||||
verts = pg.isosurface(data, data.max()/4.)
|
||||
verts, faces = pg.isosurface(data, data.max()/4.)
|
||||
|
||||
md = gl.MeshData(vertexes=verts)
|
||||
md = gl.MeshData(vertexes=verts, faces=faces)
|
||||
|
||||
colors = np.ones((md.faceCount(), 4), dtype=float)
|
||||
colors[:,3] = 0.2
|
||||
|
@ -175,8 +175,11 @@ def testFile(name, f, exe, lib):
|
||||
try:
|
||||
%s
|
||||
import %s
|
||||
import sys
|
||||
print("test complete")
|
||||
sys.stdout.flush()
|
||||
import pyqtgraph as pg
|
||||
import time
|
||||
while True: ## run a little event loop
|
||||
pg.QtGui.QApplication.processEvents()
|
||||
time.sleep(0.01)
|
||||
@ -186,7 +189,7 @@ except:
|
||||
|
||||
""" % ("import %s" % lib if lib != '' else "", os.path.splitext(os.path.split(fn)[1])[0])
|
||||
#print code
|
||||
process = subprocess.Popen(['%s -i' % (exe)], shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
process = subprocess.Popen(['exec %s -i' % (exe)], shell=True, stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
process.stdin.write(code.encode('UTF-8'))
|
||||
#process.stdin.close()
|
||||
output = ''
|
||||
@ -202,10 +205,11 @@ except:
|
||||
fail = True
|
||||
break
|
||||
time.sleep(1)
|
||||
process.terminate()
|
||||
process.kill()
|
||||
#process.wait()
|
||||
res = process.communicate()
|
||||
#if 'exception' in res[1].lower() or 'error' in res[1].lower():
|
||||
if fail:
|
||||
|
||||
if fail or 'exception' in res[1].decode().lower() or 'error' in res[1].decode().lower():
|
||||
print('.' * (50-len(name)) + 'FAILED')
|
||||
print(res[0].decode())
|
||||
print(res[1].decode())
|
||||
|
@ -19,6 +19,7 @@ frames = 200
|
||||
data = np.random.normal(size=(frames,30,30), loc=0, scale=100)
|
||||
data = np.concatenate([data, data], axis=0)
|
||||
data = ndi.gaussian_filter(data, (10, 10, 10))[frames/2:frames + frames/2]
|
||||
data[:, 15:16, 15:17] += 1
|
||||
|
||||
win = pg.GraphicsWindow()
|
||||
vb = win.addViewBox()
|
||||
|
@ -73,7 +73,8 @@ class Exporter(object):
|
||||
|
||||
def getSourceRect(self):
|
||||
if isinstance(self.item, pg.GraphicsScene):
|
||||
return self.item.getViewWidget().viewRect()
|
||||
w = self.item.getViewWidget()
|
||||
return w.viewportTransform().inverted()[0].mapRect(w.rect())
|
||||
else:
|
||||
return self.item.sceneBoundingRect()
|
||||
|
||||
|
@ -36,11 +36,14 @@ class SVGExporter(Exporter):
|
||||
return
|
||||
self.svg = QtSvg.QSvgGenerator()
|
||||
self.svg.setFileName(fileName)
|
||||
self.svg.setSize(QtCore.QSize(100,100))
|
||||
#self.svg.setResolution(600)
|
||||
dpi = QtGui.QDesktopWidget().physicalDpiX()
|
||||
## not really sure why this works, but it seems to be important:
|
||||
self.svg.setSize(QtCore.QSize(self.params['width']*dpi/90., self.params['height']*dpi/90.))
|
||||
self.svg.setResolution(dpi)
|
||||
#self.svg.setViewBox()
|
||||
targetRect = QtCore.QRect(0, 0, self.params['width'], self.params['height'])
|
||||
sourceRect = self.getSourceRect()
|
||||
|
||||
painter = QtGui.QPainter(self.svg)
|
||||
try:
|
||||
self.setExportMode(True)
|
||||
|
963
functions.py
963
functions.py
File diff suppressed because it is too large
Load Diff
@ -3,6 +3,7 @@ from pyqtgraph.GraphicsScene import GraphicsScene
|
||||
from pyqtgraph.Point import Point
|
||||
import pyqtgraph.functions as fn
|
||||
import weakref
|
||||
import operator
|
||||
|
||||
class GraphicsItem(object):
|
||||
"""
|
||||
@ -395,8 +396,16 @@ class GraphicsItem(object):
|
||||
## disconnect from previous view
|
||||
if oldView is not None:
|
||||
#print "disconnect:", self, oldView
|
||||
oldView.sigRangeChanged.disconnect(self.viewRangeChanged)
|
||||
oldView.sigTransformChanged.disconnect(self.viewTransformChanged)
|
||||
try:
|
||||
oldView.sigRangeChanged.disconnect(self.viewRangeChanged)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
try:
|
||||
oldView.sigTransformChanged.disconnect(self.viewTransformChanged)
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
self._connectedView = None
|
||||
|
||||
## connect to new view
|
||||
@ -449,4 +458,22 @@ class GraphicsItem(object):
|
||||
view = self.getViewBox()
|
||||
if view is not None and hasattr(view, 'implements') and view.implements('ViewBox'):
|
||||
view.itemBoundsChanged(self) ## inform view so it can update its range if it wants
|
||||
|
||||
|
||||
def childrenShape(self):
|
||||
"""Return the union of the shapes of all descendants of this item in local coordinates."""
|
||||
childs = self.allChildItems()
|
||||
shapes = [self.mapFromItem(c, c.shape()) for c in self.allChildItems()]
|
||||
return reduce(operator.add, shapes)
|
||||
|
||||
def allChildItems(self, root=None):
|
||||
"""Return list of the entire item tree descending from this item."""
|
||||
if root is None:
|
||||
root = self
|
||||
tree = []
|
||||
for ch in root.childItems():
|
||||
tree.append(ch)
|
||||
tree.extend(self.allChildItems(ch))
|
||||
return tree
|
||||
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
from pyqtgraph.Qt import QtGui, QtCore, USE_PYSIDE
|
||||
if not USE_PYSIDE:
|
||||
import sip
|
||||
from .GraphicsItem import GraphicsItem
|
||||
|
||||
__all__ = ['GraphicsObject']
|
||||
@ -20,4 +22,10 @@ class GraphicsObject(GraphicsItem, QtGui.QGraphicsObject):
|
||||
self._updateView()
|
||||
if change in [self.ItemPositionHasChanged, self.ItemTransformHasChanged]:
|
||||
self.informViewBoundsChanged()
|
||||
|
||||
## workaround for pyqt bug:
|
||||
## http://www.riverbankcomputing.com/pipermail/pyqt/2012-August/031818.html
|
||||
if not USE_PYSIDE and change == self.ItemParentChange and isinstance(ret, QtGui.QGraphicsItem):
|
||||
ret = sip.cast(ret, QtGui.QGraphicsItem)
|
||||
|
||||
return ret
|
||||
|
@ -45,12 +45,12 @@ class IsocurveItem(GraphicsObject):
|
||||
"""
|
||||
Set the data/image to draw isocurves for.
|
||||
|
||||
============= ================================================================
|
||||
============= ========================================================================
|
||||
**Arguments**
|
||||
data A 2-dimensional ndarray.
|
||||
level The cutoff value at which to draw the curve. If level is not specified,
|
||||
the previous level is used.
|
||||
============= ================================================================
|
||||
the previously set level is used.
|
||||
============= ========================================================================
|
||||
"""
|
||||
if level is None:
|
||||
level = self.level
|
||||
@ -74,6 +74,12 @@ class IsocurveItem(GraphicsObject):
|
||||
self.pen = fn.mkPen(*args, **kwargs)
|
||||
self.update()
|
||||
|
||||
def setBrush(self, *args, **kwargs):
|
||||
"""Set the brush used to draw the isocurve. Arguments can be any that are valid
|
||||
for :func:`mkBrush <pyqtgraph.mkBrush>`"""
|
||||
self.brush = fn.mkBrush(*args, **kwargs)
|
||||
self.update()
|
||||
|
||||
|
||||
def updateLines(self, data, level):
|
||||
##print "data:", data
|
||||
@ -88,22 +94,28 @@ class IsocurveItem(GraphicsObject):
|
||||
self.setData(data, level)
|
||||
|
||||
def boundingRect(self):
|
||||
if self.path is None:
|
||||
if self.data is None:
|
||||
return QtCore.QRectF()
|
||||
if self.path is None:
|
||||
self.generatePath()
|
||||
return self.path.boundingRect()
|
||||
|
||||
def generatePath(self):
|
||||
self.path = QtGui.QPainterPath()
|
||||
if self.data is None:
|
||||
self.path = None
|
||||
return
|
||||
lines = fn.isocurve(self.data, self.level)
|
||||
lines = fn.isocurve(self.data, self.level, connected=True, extendToEdge=True)
|
||||
self.path = QtGui.QPainterPath()
|
||||
for line in lines:
|
||||
self.path.moveTo(*line[0])
|
||||
self.path.lineTo(*line[1])
|
||||
for p in line[1:]:
|
||||
self.path.lineTo(*p)
|
||||
|
||||
def paint(self, p, *args):
|
||||
if self.data is None:
|
||||
return
|
||||
if self.path is None:
|
||||
self.generatePath()
|
||||
p.setPen(self.pen)
|
||||
p.drawPath(self.path)
|
||||
|
||||
|
@ -233,7 +233,7 @@ class ScatterPlotItem(GraphicsObject):
|
||||
self.bounds = [None, None] ## caches data bounds
|
||||
self._maxSpotWidth = 0 ## maximum size of the scale-variant portion of all spots
|
||||
self._maxSpotPxWidth = 0 ## maximum size of the scale-invariant portion of all spots
|
||||
self.opts = {'pxMode': True, 'useCache': True} ## If useCache is False, symbols are re-drawn on every paint.
|
||||
self.opts = {'pxMode': True, 'useCache': True, 'exportMode': False} ## If useCache is False, symbols are re-drawn on every paint.
|
||||
|
||||
self.setPen(200,200,200, update=False)
|
||||
self.setBrush(100,100,150, update=False)
|
||||
@ -664,10 +664,14 @@ class ScatterPlotItem(GraphicsObject):
|
||||
rect = QtCore.QRectF(y, x, h, w)
|
||||
self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect))
|
||||
|
||||
def setExportMode(self, enabled, opts):
|
||||
self.opts['exportMode'] = enabled
|
||||
|
||||
|
||||
def paint(self, p, *args):
|
||||
#p.setPen(fn.mkPen('r'))
|
||||
#p.drawRect(self.boundingRect())
|
||||
if self.opts['pxMode']:
|
||||
if self.opts['pxMode'] is True:
|
||||
atlas = self.fragmentAtlas.getAtlas()
|
||||
#arr = fn.imageToArray(atlas.toImage(), copy=True)
|
||||
#if hasattr(self, 'lastAtlas'):
|
||||
@ -681,7 +685,7 @@ class ScatterPlotItem(GraphicsObject):
|
||||
|
||||
p.resetTransform()
|
||||
|
||||
if not USE_PYSIDE and self.opts['useCache']:
|
||||
if not USE_PYSIDE and self.opts['useCache'] and self.opts['exportMode'] is False:
|
||||
p.drawPixmapFragments(self.fragments, atlas)
|
||||
else:
|
||||
for i in range(len(self.data)):
|
||||
|
@ -7,7 +7,7 @@ class TextItem(UIGraphicsItem):
|
||||
"""
|
||||
GraphicsItem displaying unscaled text (the text will always appear normal even inside a scaled ViewBox).
|
||||
"""
|
||||
def __init__(self, text='', color=(200,200,200), html=None, anchor=(0,0), border=None, fill=None):
|
||||
def __init__(self, text='', color=(200,200,200), html=None, anchor=(0,0), border=None, fill=None, angle=0):
|
||||
"""
|
||||
=========== =================================================================================
|
||||
Arguments:
|
||||
@ -22,6 +22,12 @@ class TextItem(UIGraphicsItem):
|
||||
*fill* A brush to use when filling within the border
|
||||
=========== =================================================================================
|
||||
"""
|
||||
|
||||
## not working yet
|
||||
#*angle* Angle in degrees to rotate text (note that the rotation assigned in this item's
|
||||
#transformation will be ignored)
|
||||
|
||||
|
||||
UIGraphicsItem.__init__(self)
|
||||
self.textItem = QtGui.QGraphicsTextItem()
|
||||
self.lastTransform = None
|
||||
@ -33,6 +39,7 @@ class TextItem(UIGraphicsItem):
|
||||
self.anchor = pg.Point(anchor)
|
||||
self.fill = pg.mkBrush(fill)
|
||||
self.border = pg.mkPen(border)
|
||||
self.angle = angle
|
||||
#self.setFlag(self.ItemIgnoresTransformations) ## This is required to keep the text unscaled inside the viewport
|
||||
|
||||
def setText(self, text, color=(200,200,200)):
|
||||
@ -115,9 +122,11 @@ class TextItem(UIGraphicsItem):
|
||||
|
||||
#p.fillRect(tbr)
|
||||
p.resetTransform()
|
||||
p.drawRect(tbr)
|
||||
#p.drawRect(tbr)
|
||||
|
||||
|
||||
p.translate(tbr.left(), tbr.top())
|
||||
p.rotate(self.angle)
|
||||
p.drawRect(QtCore.QRectF(0, 0, tbr.width(), tbr.height()))
|
||||
self.textItem.paint(p, QtGui.QStyleOptionGraphicsItem(), None)
|
||||
|
@ -1,6 +1,8 @@
|
||||
from pyqtgraph.Qt import QtGui, QtCore
|
||||
from pyqtgraph.Qt import QtGui, QtCore, USE_PYSIDE
|
||||
import weakref
|
||||
from .GraphicsObject import GraphicsObject
|
||||
if not USE_PYSIDE:
|
||||
import sip
|
||||
|
||||
__all__ = ['UIGraphicsItem']
|
||||
class UIGraphicsItem(GraphicsObject):
|
||||
@ -44,9 +46,12 @@ class UIGraphicsItem(GraphicsObject):
|
||||
|
||||
def itemChange(self, change, value):
|
||||
ret = GraphicsObject.itemChange(self, change, value)
|
||||
#if change == self.ItemParentHasChanged or change == self.ItemSceneHasChanged: ## handled by GraphicsItem now.
|
||||
##print "caught parent/scene change:", self.parentItem(), self.scene()
|
||||
#self.updateView()
|
||||
|
||||
## workaround for pyqt bug:
|
||||
## http://www.riverbankcomputing.com/pipermail/pyqt/2012-August/031818.html
|
||||
if not USE_PYSIDE and change == self.ItemParentChange and isinstance(ret, QtGui.QGraphicsItem):
|
||||
ret = sip.cast(ret, QtGui.QGraphicsItem)
|
||||
|
||||
if change == self.ItemScenePositionHasChanged:
|
||||
self.setNewBounds()
|
||||
return ret
|
||||
|
@ -111,6 +111,7 @@ class ViewBox(GraphicsWidget):
|
||||
}
|
||||
self._updatingRange = False ## Used to break recursive loops. See updateAutoRange.
|
||||
|
||||
self.locateGroup = None ## items displayed when using ViewBox.locate(item)
|
||||
|
||||
self.setFlag(self.ItemClipsChildrenToShape)
|
||||
self.setFlag(self.ItemIsFocusable, True) ## so we can receive key presses
|
||||
@ -286,6 +287,12 @@ class ViewBox(GraphicsWidget):
|
||||
self.scene().removeItem(item)
|
||||
self.updateAutoRange()
|
||||
|
||||
def clear(self):
|
||||
for i in self.addedItems[:]:
|
||||
self.removeItem(i)
|
||||
for ch in self.childGroup.childItems():
|
||||
ch.setParent(None)
|
||||
|
||||
def resizeEvent(self, ev):
|
||||
#self.setRange(self.range, padding=0)
|
||||
#self.updateAutoRange()
|
||||
@ -1231,6 +1238,46 @@ class ViewBox(GraphicsWidget):
|
||||
k.destroyed.disconnect()
|
||||
except RuntimeError: ## signal is already disconnected.
|
||||
pass
|
||||
|
||||
def locate(self, item, timeout=3.0, children=False):
|
||||
"""
|
||||
Temporarily display the bounding rect of an item and lines connecting to the center of the view.
|
||||
This is useful for determining the location of items that may be out of the range of the ViewBox.
|
||||
if allChildren is True, then the bounding rect of all item's children will be shown instead.
|
||||
"""
|
||||
self.clearLocate()
|
||||
|
||||
if item.scene() is not self.scene():
|
||||
raise Exception("Item does not share a scene with this ViewBox.")
|
||||
|
||||
c = self.viewRect().center()
|
||||
if children:
|
||||
br = self.mapFromItemToView(item, item.childrenBoundingRect()).boundingRect()
|
||||
else:
|
||||
br = self.mapFromItemToView(item, item.boundingRect()).boundingRect()
|
||||
|
||||
g = ItemGroup()
|
||||
g.setParentItem(self.childGroup)
|
||||
self.locateGroup = g
|
||||
g.box = QtGui.QGraphicsRectItem(br)
|
||||
g.box.setParentItem(g)
|
||||
g.lines = []
|
||||
for p in (br.topLeft(), br.bottomLeft(), br.bottomRight(), br.topRight()):
|
||||
line = QtGui.QGraphicsLineItem(c.x(), c.y(), p.x(), p.y())
|
||||
line.setParentItem(g)
|
||||
g.lines.append(line)
|
||||
|
||||
for item in g.childItems():
|
||||
item.setPen(fn.mkPen(color='y', width=3))
|
||||
item.setZValue(1000000)
|
||||
|
||||
QtCore.QTimer.singleShot(timeout*1000, self.clearLocate)
|
||||
|
||||
def clearLocate(self):
|
||||
if self.locateGroup is None:
|
||||
return
|
||||
self.scene().removeItem(self.locateGroup)
|
||||
self.locateGroup = None
|
||||
|
||||
|
||||
from .ViewBoxMenu import ViewBoxMenu
|
||||
|
@ -158,7 +158,7 @@ class GLMeshItem(GLGraphicsItem):
|
||||
if self.colors is None:
|
||||
color = self.opts['color']
|
||||
if isinstance(color, QtGui.QColor):
|
||||
glColor4f(*fn.glColor(color))
|
||||
glColor4f(*pg.glColor(color))
|
||||
else:
|
||||
glColor4f(*color)
|
||||
else:
|
||||
|
@ -53,6 +53,7 @@ if sys.version_info[0] == 3:
|
||||
else:
|
||||
return 0
|
||||
builtins.cmp = cmp
|
||||
builtins.xrange = range
|
||||
#else: ## don't use __builtin__ -- this confuses things like pyshell and ActiveState's lazy import recipe
|
||||
#import __builtin__
|
||||
#__builtin__.asUnicode = asUnicode
|
||||
|
12
reload.py
12
reload.py
@ -35,6 +35,7 @@ def reloadAll(prefix=None, debug=False):
|
||||
- if prefix is None, checks all loaded modules
|
||||
"""
|
||||
failed = []
|
||||
changed = []
|
||||
for modName, mod in list(sys.modules.items()): ## don't use iteritems; size may change during reload
|
||||
if not inspect.ismodule(mod):
|
||||
continue
|
||||
@ -50,10 +51,11 @@ def reloadAll(prefix=None, debug=False):
|
||||
## ignore if the .pyc is newer than the .py (or if there is no pyc or py)
|
||||
py = os.path.splitext(mod.__file__)[0] + '.py'
|
||||
pyc = py + 'c'
|
||||
if os.path.isfile(pyc) and os.path.isfile(py) and os.stat(pyc).st_mtime >= os.stat(py).st_mtime:
|
||||
if py not in changed and os.path.isfile(pyc) and os.path.isfile(py) and os.stat(pyc).st_mtime >= os.stat(py).st_mtime:
|
||||
#if debug:
|
||||
#print "Ignoring module %s; unchanged" % str(mod)
|
||||
continue
|
||||
changed.append(py) ## keep track of which modules have changed to insure that duplicate-import modules get reloaded.
|
||||
|
||||
try:
|
||||
reload(mod, debug=debug)
|
||||
@ -73,7 +75,7 @@ def reload(module, debug=False, lists=False, dicts=False):
|
||||
- Requires that class and function names have not changed
|
||||
"""
|
||||
if debug:
|
||||
print("Reloading", module)
|
||||
print("Reloading %s" % str(module))
|
||||
|
||||
## make a copy of the old module dictionary, reload, then grab the new module dictionary for comparison
|
||||
oldDict = module.__dict__.copy()
|
||||
@ -158,7 +160,7 @@ def updateClass(old, new, debug):
|
||||
if isinstance(ref, old) and ref.__class__ is old:
|
||||
ref.__class__ = new
|
||||
if debug:
|
||||
print(" Changed class for", safeStr(ref))
|
||||
print(" Changed class for %s" % safeStr(ref))
|
||||
elif inspect.isclass(ref) and issubclass(ref, old) and old in ref.__bases__:
|
||||
ind = ref.__bases__.index(old)
|
||||
|
||||
@ -174,7 +176,7 @@ def updateClass(old, new, debug):
|
||||
## (and I presume this may slow things down?)
|
||||
ref.__bases__ = ref.__bases__[:ind] + (new,old) + ref.__bases__[ind+1:]
|
||||
if debug:
|
||||
print(" Changed superclass for", safeStr(ref))
|
||||
print(" Changed superclass for %s" % safeStr(ref))
|
||||
#else:
|
||||
#if debug:
|
||||
#print " Ignoring reference", type(ref)
|
||||
@ -208,7 +210,7 @@ def updateClass(old, new, debug):
|
||||
for attr in dir(new):
|
||||
if not hasattr(old, attr):
|
||||
if debug:
|
||||
print(" Adding missing attribute", attr)
|
||||
print(" Adding missing attribute %s" % attr)
|
||||
setattr(old, attr, getattr(new, attr))
|
||||
|
||||
## finally, update any previous versions still hanging around..
|
||||
|
18
setup.py
18
setup.py
@ -9,7 +9,11 @@ all_packages = ['.'.join(p) for p in subdirs]
|
||||
setup(name='pyqtgraph',
|
||||
version='',
|
||||
description='Scientific Graphics and GUI Library for Python',
|
||||
long_description="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.",
|
||||
long_description="""\
|
||||
PyQtGraph is a pure-python graphics and GUI library built on PyQt4/PySide 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.
|
||||
""",
|
||||
license='MIT',
|
||||
url='http://www.pyqtgraph.org',
|
||||
author='Luke Campagnola',
|
||||
@ -17,5 +21,17 @@ setup(name='pyqtgraph',
|
||||
packages=all_packages,
|
||||
package_dir = {'pyqtgraph': '.'},
|
||||
package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']},
|
||||
classifiers = [
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Development Status :: 4 - Beta",
|
||||
"Environment :: Other Environment",
|
||||
"Intended Audience :: Science/Research",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Scientific/Engineering :: Visualization",
|
||||
"Topic :: Software Development :: User Interfaces",
|
||||
],
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user