__init__.py 10 KB
Newer Older
Luke Campagnola's avatar
Luke Campagnola committed
1
# -*- coding: utf-8 -*-
2 3 4 5 6
"""
PyQtGraph - Scientific Graphics and GUI Library for Python
www.pyqtgraph.org
"""

7
__version__ = None
8

Luke Campagnola's avatar
Luke Campagnola committed
9 10
### import all the goodies and add some helper functions for easy CLI use

11 12
## 'Qt' is a local module; it is intended mainly to cover up the differences
## between PyQt4 and PySide.
13
from .Qt import QtGui
14

15
## not really safe--If we accidentally create another QApplication, the process hangs (and it is very difficult to trace the cause)
16 17 18
#if QtGui.QApplication.instance() is None:
    #app = QtGui.QApplication([])

19
import os, sys
20 21

## check python version
Luke Campagnola's avatar
Luke Campagnola committed
22
## Allow anything >= 2.7
23 24
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]))
25

26 27 28
## helpers for 2/3 compatibility
from . import python2_3

Luke Campagnola's avatar
Luke Campagnola committed
29
## install workarounds for numpy bugs
30
from . import numpy_fix
Luke Campagnola's avatar
Luke Campagnola committed
31

32
## in general openGL is poorly supported with Qt+GraphicsView.
33 34
## we only enable it where the performance benefit is critical.
## Note this only applies to 2D graphics; 3D graphics always use OpenGL.
Luke Campagnola's avatar
Luke Campagnola committed
35 36
if 'linux' in sys.platform:  ## linux has numerous bugs in opengl implementation
    useOpenGL = False
37
elif 'darwin' in sys.platform: ## openGL can have a major impact on mac, but also has serious bugs
38 39 40 41
    useOpenGL = False
    if QtGui.QApplication.instance() is not None:
        print('Warning: QApplication was created before pyqtgraph was imported; there may be problems (to avoid bugs, call QApplication.setGraphicsSystem("raster") before the QApplication is created).')
    QtGui.QApplication.setGraphicsSystem('raster')  ## work around a variety of bugs in the native graphics system 
Luke Campagnola's avatar
Luke Campagnola committed
42
else:
Luke Campagnola's avatar
Luke Campagnola committed
43
    useOpenGL = False  ## on windows there's a more even performance / bugginess tradeoff. 
Luke Campagnola's avatar
Luke Campagnola committed
44
                
45
CONFIG_OPTIONS = {
46
    'useOpenGL': useOpenGL, ## by default, this is platform-dependent (see widgets/GraphicsView). Set to True or False to explicitly enable/disable opengl.
47
    'leftButtonPan': True,  ## if false, left button drags a rubber band for zooming in viewbox
48 49
    'foreground': (150, 150, 150),  ## default foreground color for axes, labels, etc.
    'background': (0, 0, 0),        ## default background for GraphicsWidget
50
    'antialias': False,
51
    'editorCommand': None,  ## command used to invoke code editor from ConsoleWidgets
52
} 
53

54

55 56 57
def setConfigOption(opt, value):
    CONFIG_OPTIONS[opt] = value

Luke Campagnola's avatar
Luke Campagnola committed
58
def setConfigOptions(**opts):
59 60
    CONFIG_OPTIONS.update(opts)

61 62 63
def getConfigOption(opt):
    return CONFIG_OPTIONS[opt]

64

65
def systemInfo():
66 67
    print("sys.platform: %s" % sys.platform)
    print("sys.version: %s" % sys.version)
68
    from .Qt import VERSION_INFO
69
    print("qt bindings: %s" % VERSION_INFO)
70
    
71 72 73 74
    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')
75
        if os.path.exists(lastRevFile):
76
            rev = open(lastRevFile, 'r').read().strip()
77
    
78
    print("pyqtgraph: %s; %s" % (__version__, rev))
79
    print("config:")
80 81 82
    import pprint
    pprint.pprint(CONFIG_OPTIONS)

83
## Rename orphaned .pyc files. This is *probably* safe :)
84 85
## We only do this if __version__ is None, indicating the code was probably pulled
## from the repository. 
86 87 88 89
def renamePyc(startDir):
    ### Used to rename orphaned .pyc files
    ### When a python file changes its location in the repository, usually the .pyc file
    ### is left behind, possibly causing mysterious and difficult to track bugs. 
90 91 92 93

    ### Note that this is no longer necessary for python 3.2; from PEP 3147:
    ### "If the py source file is missing, the pyc file inside __pycache__ will be ignored. 
    ### This eliminates the problem of accidental stale pyc file imports."
94 95 96 97
    
    printed = False
    startDir = os.path.abspath(startDir)
    for path, dirs, files in os.walk(startDir):
98 99
        if '__pycache__' in path:
            continue
100 101 102 103 104 105
        for f in files:
            fileName = os.path.join(path, f)
            base, ext = os.path.splitext(fileName)
            py = base + ".py"
            if ext == '.pyc' and not os.path.isfile(py):
                if not printed:
106
                    print("NOTE: Renaming orphaned .pyc files:")
107 108 109 110 111 112 113
                    printed = True
                n = 1
                while True:
                    name2 = fileName + ".renamed%d" % n
                    if not os.path.exists(name2):
                        break
                    n += 1
114 115
                print("  " + fileName + "  ==>")
                print("  " + name2)
116 117 118
                os.rename(fileName, name2)
                
path = os.path.split(__file__)[0]
119
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.
120
    renamePyc(path)
121 122


123 124 125
## Import almost everything to make it available from a single namespace
## don't import the more complex systems--canvas, parametertree, flowchart, dockarea
## these must be imported separately.
126
from . import frozenSupport
127 128 129 130 131 132 133 134 135 136
def importModules(path, globals, locals, excludes=()):
    """Import all modules residing within *path*, return a dict of name: module pairs.
    
    Note that *path* MUST be relative to the module doing the import.    
    """
    d = os.path.join(os.path.split(globals['__file__'])[0], path)
    files = set()
    for f in frozenSupport.listdir(d):
        if frozenSupport.isdir(os.path.join(d, f)) and f != '__pycache__':
            files.add(f)
137
        elif f[-3:] == '.py' and f != '__init__.py':
138 139 140
            files.add(f[:-3])
        elif f[-4:] == '.pyc' and f != '__init__.pyc':
            files.add(f[:-4])
141
        
142 143
    mods = {}
    path = path.replace(os.sep, '.')
144
    for modName in files:
Luke Campagnola's avatar
Luke Campagnola committed
145 146
        if modName in excludes:
            continue
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
        try:
            if len(path) > 0:
                modName = path + '.' + modName
            mod = __import__(modName, globals, locals, fromlist=['*'])
            mods[modName] = mod
        except:
            import traceback
            traceback.print_stack()
            sys.excepthook(*sys.exc_info())
            print("[Error importing module: %s]" % modName)
            
    return mods

def importAll(path, globals, locals, excludes=()):
    """Given a list of modules, import all names from each module into the global namespace."""
    mods = importModules(path, globals, locals, excludes)
    for mod in mods.values():
164 165 166 167 168 169
        if hasattr(mod, '__all__'):
            names = mod.__all__
        else:
            names = [n for n in dir(mod) if n[0] != '_']
        for k in names:
            if hasattr(mod, k):
170
                globals[k] = getattr(mod, k)
171

172 173
importAll('graphicsItems', globals(), locals())
importAll('widgets', globals(), locals(), excludes=['MatplotlibWidget', 'RemoteGraphicsView'])
174

175 176 177
from .imageview import *
from .WidgetGroup import *
from .Point import Point
Luke Campagnola's avatar
Luke Campagnola committed
178
from .Vector import Vector
179
from .SRTTransform import SRTTransform
180
from .Transform3D import Transform3D
181
from .SRTTransform3D import SRTTransform3D
182 183 184 185
from .functions import *
from .graphicsWindows import *
from .SignalProxy import *
from .ptime import time
186 187


188 189
import atexit
def cleanup():
Luke Campagnola's avatar
Luke Campagnola committed
190 191 192 193 194 195
    ViewBox.quit()  ## tell ViewBox that it doesn't need to deregister views anymore.
    
    ## Workaround for Qt exit crash:
    ## ALL QGraphicsItems must have a scene before they are deleted.
    ## This is potentially very expensive, but preferred over crashing.
    ## Note: this appears to be fixed in PySide as of 2012.12, but it should be left in for a while longer..
196 197 198 199 200 201 202 203 204 205 206
    if QtGui.QApplication.instance() is None:
        return
    import gc
    s = QtGui.QGraphicsScene()
    for o in gc.get_objects():
        try:
            if isinstance(o, QtGui.QGraphicsItem) and o.scene() is None:
                s.addItem(o)
        except RuntimeError:  ## occurs if a python wrapper no longer has its underlying C++ object
            continue
atexit.register(cleanup)
207 208 209



210
## Convenience functions for command-line use
Luke Campagnola's avatar
Luke Campagnola committed
211 212 213 214 215 216

plots = []
images = []
QAPP = None

def plot(*args, **kargs):
217
    """
Luke Campagnola's avatar
Luke Campagnola committed
218 219 220 221
    Create and return a :class:`PlotWindow <pyqtgraph.PlotWindow>` 
    (this is just a window with :class:`PlotWidget <pyqtgraph.PlotWidget>` inside), plot data in it.
    Accepts a *title* argument to set the title of the window.
    All other arguments are used to plot data. (see :func:`PlotItem.plot() <pyqtgraph.PlotItem.plot>`)
222
    """
Luke Campagnola's avatar
Luke Campagnola committed
223
    mkQApp()
224 225 226 227 228 229 230
    #if 'title' in kargs:
        #w = PlotWindow(title=kargs['title'])
        #del kargs['title']
    #else:
        #w = PlotWindow()
    #if len(args)+len(kargs) > 0:
        #w.plot(*args, **kargs)
Luke Campagnola's avatar
Luke Campagnola committed
231
        
Luke Campagnola's avatar
Luke Campagnola committed
232
    pwArgList = ['title', 'labels', 'name', 'left', 'right', 'top', 'bottom']
Luke Campagnola's avatar
Luke Campagnola committed
233 234 235 236 237 238 239 240 241 242
    pwArgs = {}
    dataArgs = {}
    for k in kargs:
        if k in pwArgList:
            pwArgs[k] = kargs[k]
        else:
            dataArgs[k] = kargs[k]
        
    w = PlotWindow(**pwArgs)
    w.plot(*args, **dataArgs)
Luke Campagnola's avatar
Luke Campagnola committed
243 244 245 246
    plots.append(w)
    w.show()
    return w
    
247 248
def image(*args, **kargs):
    """
Luke Campagnola's avatar
Luke Campagnola committed
249 250 251 252 253
    Create and return an :class:`ImageWindow <pyqtgraph.ImageWindow>` 
    (this is just a window with :class:`ImageView <pyqtgraph.ImageView>` widget inside), show image data inside.
    Will show 2D or 3D image data.
    Accepts a *title* argument to set the title of the window.
    All other arguments are used to show data. (see :func:`ImageView.setImage() <pyqtgraph.ImageView.setImage>`)
254
    """
Luke Campagnola's avatar
Luke Campagnola committed
255 256 257 258 259
    mkQApp()
    w = ImageWindow(*args, **kargs)
    images.append(w)
    w.show()
    return w
260
show = image  ## for backward compatibility
Luke Campagnola's avatar
Luke Campagnola committed
261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

def dbg():
    """
    Create a console window and begin watching for exceptions.
    """
    mkQApp()
    import console
    c = console.ConsoleWidget()
    c.catchAllExceptions()
    c.show()
    global consoles
    try:
        consoles.append(c)
    except NameError:
        consoles = [c]
276
    
Luke Campagnola's avatar
Luke Campagnola committed
277 278
    
def mkQApp():
279
    global QAPP
Luke Campagnola's avatar
Luke Campagnola committed
280 281
    inst = QtGui.QApplication.instance()
    if inst is None:
282
        QAPP = QtGui.QApplication([])
Luke Campagnola's avatar
Luke Campagnola committed
283 284
    else:
        QAPP = inst
285
    return QAPP
286