diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..02d67f6f --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,8 @@ +recursive-include pyqtgraph *.py *.ui *.m README *.txt +recursive-include tests *.py *.ui +recursive-include examples *.py *.ui +recursive-include doc *.rst *.py *.svg *.png *.jpg +recursive-include doc/build/html * +recursive-include tools * +include doc/Makefile doc/make.bat README.txt LICENSE.txt + diff --git a/doc/source/conf.py b/doc/source/conf.py index 2fd718e4..236cb807 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,8 +17,7 @@ import sys, os # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. path = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, os.path.join(path, '..', '..', '..')) -print sys.path +sys.path.insert(0, os.path.join(path, '..', '..')) # -- General configuration ----------------------------------------------------- @@ -50,9 +49,9 @@ copyright = '2011, Luke Campagnola' # built documents. # # The short X.Y version. -version = '1.8' +version = '' # The full version, including alpha/beta/rc tags. -release = '1.8' +release = '' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/index.rst b/doc/source/index.rst index 5d606061..cc89f3d8 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,8 +3,8 @@ You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. -Welcome to the documentation for pyqtgraph 1.8 -============================================== +Welcome to the documentation for pyqtgraph +========================================== Contents: diff --git a/examples/initExample.py b/examples/initExample.py index f95a0cb0..38dd3edc 100644 --- a/examples/initExample.py +++ b/examples/initExample.py @@ -2,10 +2,10 @@ import sys, os path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) path.rstrip(os.path.sep) -if path.endswith('pyqtgraph'): - sys.path.insert(0, os.path.join(path, '..')) ## examples installed inside pyqtgraph package -elif 'pyqtgraph' in os.listdir(path): +if 'pyqtgraph' in os.listdir(path): sys.path.insert(0, path) ## examples adjacent to pyqtgraph (as in source) +elif path.endswith('pyqtgraph'): + sys.path.insert(0, os.path.abspath(os.path.join(path, '..'))) ## examples installed inside pyqtgraph package ## should force example to use PySide instead of PyQt if 'pyside' in sys.argv: diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 6e950770..93d9f7b8 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -1,5 +1,10 @@ # -*- coding: utf-8 -*- -REVISION = None +""" +PyQtGraph - Scientific Graphics and GUI Library for Python +www.pyqtgraph.org +""" + +__version__ = None ### import all the goodies and add some helper functions for easy CLI use @@ -63,19 +68,21 @@ def systemInfo(): from .Qt import VERSION_INFO print("qt bindings: %s" % VERSION_INFO) - global REVISION - if REVISION is None: ## this code was probably checked out from bzr; look up the last-revision file - lastRevFile = os.path.join(os.path.dirname(__file__), '.bzr', 'branch', 'last-revision') + global __version__ + rev = None + if __version__ is None: ## this code was probably checked out from bzr; look up the last-revision file + lastRevFile = os.path.join(os.path.dirname(__file__), '..', '.bzr', 'branch', 'last-revision') if os.path.exists(lastRevFile): - REVISION = open(lastRevFile, 'r').read().strip() + rev = open(lastRevFile, 'r').read().strip() - print("pyqtgraph: %s" % REVISION) + print("pyqtgraph: %s; %s" % (__version__, rev)) print("config:") import pprint pprint.pprint(CONFIG_OPTIONS) ## Rename orphaned .pyc files. This is *probably* safe :) - +## We only do this if __version__ is None, indicating the code was probably pulled +## from the repository. def renamePyc(startDir): ### Used to rename orphaned .pyc files ### When a python file changes its location in the repository, usually the .pyc file @@ -108,9 +115,8 @@ def renamePyc(startDir): print(" " + name2) os.rename(fileName, name2) -import os path = os.path.split(__file__)[0] -if not hasattr(sys, 'frozen'): ## If we are frozen, there's a good chance we don't have the original .py files anymore. +if __version__ is None and not hasattr(sys, 'frozen') and sys.version_info[0] == 2: ## If we are frozen, there's a good chance we don't have the original .py files anymore. renamePyc(path) diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index ce05b82d..70f1f632 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -17,6 +17,9 @@ class SVGExporter(Exporter): self.params = Parameter(name='params', type='group', children=[ #{'name': 'width', 'type': 'float', 'value': tr.width(), 'limits': (0, None)}, #{'name': 'height', 'type': 'float', 'value': tr.height(), 'limits': (0, None)}, + #{'name': 'viewbox clipping', 'type': 'bool', 'value': True}, + #{'name': 'normalize coordinates', 'type': 'bool', 'value': True}, + #{'name': 'normalize line width', 'type': 'bool', 'value': True}, ]) #self.params.param('width').sigValueChanged.connect(self.widthChanged) #self.params.param('height').sigValueChanged.connect(self.heightChanged) @@ -83,7 +86,7 @@ class SVGExporter(Exporter): return bytes(xml) else: with open(fileName, 'w') as fh: - fh.write(xml) + fh.write(xml.encode('UTF-8')) xmlHeader = """\ @@ -171,8 +174,16 @@ def _generateItemSvg(item, nodes=None, root=None): doc = xml.parseString(xmlStr) else: childs = item.childItems() - tr = itemTransform(item, root) + tr = itemTransform(item, item.scene()) + ## offset to corner of root item + if isinstance(root, QtGui.QGraphicsScene): + rootPos = QtCore.QPoint(0,0) + else: + rootPos = root.scenePos() + tr2 = QtGui.QTransform() + tr2.translate(-rootPos.x(), -rootPos.y()) + tr = tr * tr2 #print item, pg.SRTTransform(tr) #tr.translate(item.pos().x(), item.pos().y()) @@ -239,17 +250,23 @@ def _generateItemSvg(item, nodes=None, root=None): nodes[name] = g1 g1.setAttribute('id', name) - ## If this item clips its children, we need to take car of that. + ## If this item clips its children, we need to take care of that. childGroup = g1 ## add children directly to this node unless we are clipping if not isinstance(item, QtGui.QGraphicsScene): ## See if this item clips its children if int(item.flags() & item.ItemClipsChildrenToShape) > 0: ## Generate svg for just the path - if isinstance(root, QtGui.QGraphicsScene): - path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) - else: - path = QtGui.QGraphicsPathItem(root.mapToParent(item.mapToItem(root, item.shape()))) - pathNode = _generateItemSvg(path, root=root).getElementsByTagName('path')[0] + #if isinstance(root, QtGui.QGraphicsScene): + #path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) + #else: + #path = QtGui.QGraphicsPathItem(root.mapToParent(item.mapToItem(root, item.shape()))) + path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) + item.scene().addItem(path) + try: + pathNode = _generateItemSvg(path, root=root).getElementsByTagName('path')[0] + finally: + item.scene().removeItem(path) + ## and for the clipPath element clip = name + '_clip' clipNode = g1.ownerDocument.createElement('clipPath') @@ -294,7 +311,10 @@ def correctCoordinates(node, item): elif ch.tagName == 'path': removeTransform = True newCoords = '' - for c in ch.getAttribute('d').strip().split(' '): + oldCoords = ch.getAttribute('d').strip() + if oldCoords == '': + continue + for c in oldCoords.split(' '): x,y = c.split(',') if x[0].isalpha(): t = x[0] @@ -317,8 +337,18 @@ def correctCoordinates(node, item): #fs = c[1]-c[2] #fs = (fs**2).sum()**0.5 #ch.setAttribute('font-size', str(fs)) - else: - print('warning: export not implemented for SVG tag %s (from item %s)' % (ch.tagName, item)) + + ## Correct some font information + families = ch.getAttribute('font-family').split(',') + if len(families) == 1: + font = QtGui.QFont(families[0].strip('" ')) + if font.style() == font.SansSerif: + families.append('sans-serif') + elif font.style() == font.Serif: + families.append('serif') + elif font.style() == font.Courier: + families.append('monospace') + ch.setAttribute('font-family', ', '.join([f if ' ' not in f else '"%s"'%f for f in families])) ## correct line widths if needed if removeTransform and ch.getAttribute('vector-effect') != 'non-scaling-stroke': diff --git a/pyqtgraph/graphicsItems/ArrowItem.py b/pyqtgraph/graphicsItems/ArrowItem.py index 153ea712..22d0065b 100644 --- a/pyqtgraph/graphicsItems/ArrowItem.py +++ b/pyqtgraph/graphicsItems/ArrowItem.py @@ -54,3 +54,8 @@ class ArrowItem(QtGui.QGraphicsPathItem): def paint(self, p, *args): p.setRenderHint(QtGui.QPainter.Antialiasing) QtGui.QGraphicsPathItem.paint(self, p, *args) + + def shape(self): + #if not self.opts['pxMode']: + #return QtGui.QGraphicsPathItem.shape(self) + return self.path \ No newline at end of file diff --git a/pyqtgraph/graphicsItems/GraphicsItem.py b/pyqtgraph/graphicsItems/GraphicsItem.py index 6a0825dd..2018fb4c 100644 --- a/pyqtgraph/graphicsItems/GraphicsItem.py +++ b/pyqtgraph/graphicsItems/GraphicsItem.py @@ -63,7 +63,10 @@ class GraphicsItem(object): if self._viewBox is None: p = self while True: - p = p.parentItem() + try: + p = p.parentItem() + except RuntimeError: ## sometimes happens as items are being removed from a scene and collected. + return None if p is None: vb = self.getViewWidget() if vb is None: @@ -496,4 +499,4 @@ class GraphicsItem(object): #self._exportOpts['antialias'] = True else: self._exportOpts = False - \ No newline at end of file + diff --git a/pyqtgraph/graphicsItems/TextItem.py b/pyqtgraph/graphicsItems/TextItem.py index b5666f6e..911057f4 100644 --- a/pyqtgraph/graphicsItems/TextItem.py +++ b/pyqtgraph/graphicsItems/TextItem.py @@ -115,9 +115,10 @@ class TextItem(UIGraphicsItem): self.viewRangeChanged() self.lastTransform = tr - p.setPen(self.border) - p.setBrush(self.fill) - p.setRenderHint(p.Antialiasing, True) - p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect())) + if self.border.style() != QtCore.Qt.NoPen or self.fill.style() != QtCore.Qt.NoBrush: + p.setPen(self.border) + p.setBrush(self.fill) + p.setRenderHint(p.Antialiasing, True) + p.drawPolygon(self.textItem.mapToParent(self.textItem.boundingRect())) \ No newline at end of file diff --git a/setup.py b/setup.py index e4dc07cf..8128a851 100644 --- a/setup.py +++ b/setup.py @@ -1,11 +1,19 @@ from distutils.core import setup +import distutils.dir_util import os ## generate list of all sub-packages -subdirs = [i[0].split(os.path.sep)[1:] for i in os.walk('./pyqtgraph') if '__init__.py' in i[2]] -subdirs = filter(lambda p: len(p) == 1 or p[1] != 'build', subdirs) +path = os.path.abspath(os.path.dirname(__file__)) +n = len(path.split(os.path.sep)) +subdirs = [i[0].split(os.path.sep)[n:] for i in os.walk(os.path.join(path, 'pyqtgraph')) if '__init__.py' in i[2]] all_packages = ['.'.join(p) for p in subdirs] + ['pyqtgraph.examples'] + +## Make sure build directory is clean before installing +buildPath = os.path.join(path, 'build') +if os.path.isdir(buildPath): + distutils.dir_util.remove_tree(buildPath) + setup(name='pyqtgraph', version='', description='Scientific Graphics and GUI Library for Python', @@ -23,6 +31,9 @@ It is intended for use in mathematics / scientific / engineering applications. D #package_data={'pyqtgraph': ['graphicsItems/PlotItem/*.png']}, classifiers = [ "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Development Status :: 4 - Beta", "Environment :: Other Environment", @@ -33,7 +44,7 @@ It is intended for use in mathematics / scientific / engineering applications. D "Topic :: Scientific/Engineering :: Visualization", "Topic :: Software Development :: User Interfaces", ], - requires = [ + install_requires = [ 'numpy', 'scipy', ], diff --git a/tools/debian/changelog b/tools/debian/changelog new file mode 100644 index 00000000..1edf45f3 --- /dev/null +++ b/tools/debian/changelog @@ -0,0 +1,5 @@ +python-pyqtgraph (0.9.1-1) UNRELEASED; urgency=low + + * Initial release. + + -- Luke Sat, 29 Dec 2012 01:07:23 -0500 diff --git a/tools/debian/compat b/tools/debian/compat new file mode 100644 index 00000000..45a4fb75 --- /dev/null +++ b/tools/debian/compat @@ -0,0 +1 @@ +8 diff --git a/tools/debian/control b/tools/debian/control new file mode 100644 index 00000000..7ab6f28a --- /dev/null +++ b/tools/debian/control @@ -0,0 +1,18 @@ +Source: python-pyqtgraph +Maintainer: Luke Campagnola +Section: python +Priority: optional +Standards-Version: 3.9.3 +Build-Depends: debhelper (>= 8) + +Package: python-pyqtgraph +Architecture: all +Homepage: http://luke.campagnola.me/code/pyqtgraph +Depends: python (>= 2.6), python-support (>= 0.90), python-qt4 | python-pyside, python-scipy, python-numpy, ${misc:Depends} +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. diff --git a/tools/debian/copyright b/tools/debian/copyright new file mode 100644 index 00000000..22791ae3 --- /dev/null +++ b/tools/debian/copyright @@ -0,0 +1,10 @@ +Copyright (c) 2012 University of North Carolina at Chapel Hill +Luke Campagnola ('luke.campagnola@%s.com' % 'gmail') + +The MIT License +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + diff --git a/tools/debian/files b/tools/debian/files new file mode 100644 index 00000000..4af05533 --- /dev/null +++ b/tools/debian/files @@ -0,0 +1 @@ +python-pyqtgraph_0.9.1-1_all.deb python optional diff --git a/tools/debian/postrm b/tools/debian/postrm new file mode 100755 index 00000000..e1eae9f2 --- /dev/null +++ b/tools/debian/postrm @@ -0,0 +1,3 @@ +#!/bin/sh -e +#DEBHELPER# +rm -rf /usr/lib/python2.7/dist-packages/pyqtgraph diff --git a/tools/debian/rules b/tools/debian/rules new file mode 100755 index 00000000..2d33f6ac --- /dev/null +++ b/tools/debian/rules @@ -0,0 +1,4 @@ +#!/usr/bin/make -f + +%: + dh $@ diff --git a/tools/debian/source/format b/tools/debian/source/format new file mode 100644 index 00000000..163aaf8d --- /dev/null +++ b/tools/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt)