Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

lp:~luke-campagnola/pyqtgraph/dev/revision/105

  • Loading branch information...
commit 6e781030a3a315d0719cfe3d4c6f3cd0a90e3c7c 1 parent 190528c
Ingo Breßler authored
11  documentation/source/graphicsItems/gradienteditoritem.rst
Source Rendered
@@ -5,4 +5,15 @@ GradientEditorItem
5 5
     :members:
6 6
 
7 7
     .. automethod:: pyqtgraph.GradientEditorItem.__init__
  8
+    
  9
+    
  10
+TickSliderItem
  11
+==================
  12
+
  13
+.. autoclass:: pyqtgraph.TickSliderItem
  14
+    :members:
  15
+
  16
+    .. automethod:: pyqtgraph.TickSliderItem.__init__
  17
+    
  18
+
8 19
 
1  documentation/source/graphicsItems/index.rst
Source Rendered
@@ -19,6 +19,7 @@ Contents:
19 19
     graphicslayout
20 20
     plotcurveitem
21 21
     scatterplotitem
  22
+    isocurveitem
22 23
     axisitem
23 24
     arrowitem
24 25
     curvepoint
1  exporters/ImageExporter.py
@@ -59,6 +59,7 @@ def export(self, fileName=None):
59 59
         painter = QtGui.QPainter(self.png)
60 60
         try:
61 61
             self.setExportMode(True, {'antialias': self.params['antialias'], 'background': self.params['background']})
  62
+            painter.setRenderHint(QtGui.QPainter.Antialiasing, self.params['antialias'])
62 63
             self.getScene().render(painter, QtCore.QRectF(targetRect), sourceRect)
63 64
         finally:
64 65
             self.setExportMode(False)
33  flowchart/Flowchart.py
@@ -84,14 +84,18 @@ def __init__(self, terminals=None, name=None, filePath=None):
84 84
         
85 85
         self.widget()
86 86
         
87  
-        self.inputNode = Node('Input', allowRemove=False)
88  
-        self.outputNode = Node('Output', allowRemove=False)
  87
+        self.inputNode = Node('Input', allowRemove=False, allowAddOutput=True)
  88
+        self.outputNode = Node('Output', allowRemove=False, allowAddInput=True)
89 89
         self.addNode(self.inputNode, 'Input', [-150, 0])
90 90
         self.addNode(self.outputNode, 'Output', [300, 0])
91 91
         
92 92
         self.outputNode.sigOutputChanged.connect(self.outputChanged)
93 93
         self.outputNode.sigTerminalRenamed.connect(self.internalTerminalRenamed)
94 94
         self.inputNode.sigTerminalRenamed.connect(self.internalTerminalRenamed)
  95
+        self.outputNode.sigTerminalRemoved.connect(self.internalTerminalRemoved)
  96
+        self.inputNode.sigTerminalRemoved.connect(self.internalTerminalRemoved)
  97
+        self.outputNode.sigTerminalAdded.connect(self.internalTerminalAdded)
  98
+        self.inputNode.sigTerminalAdded.connect(self.internalTerminalAdded)
95 99
         
96 100
         self.viewBox.autoRange(padding = 0.04)
97 101
             
@@ -121,11 +125,20 @@ def addTerminal(self, name, **opts):
121 125
         if opts['io'] == 'in':  ## inputs to the flowchart become outputs on the input node
122 126
             opts['io'] = 'out'
123 127
             opts['multi'] = False
124  
-            term2 = self.inputNode.addTerminal(name, **opts)
  128
+            self.inputNode.sigTerminalAdded.disconnect(self.internalTerminalAdded)
  129
+            try:
  130
+                term2 = self.inputNode.addTerminal(name, **opts)
  131
+            finally:
  132
+                self.inputNode.sigTerminalAdded.connect(self.internalTerminalAdded)
  133
+                
125 134
         else:
126 135
             opts['io'] = 'in'
127 136
             #opts['multi'] = False
128  
-            term2 = self.outputNode.addTerminal(name, **opts)
  137
+            self.outputNode.sigTerminalAdded.disconnect(self.internalTerminalAdded)
  138
+            try:
  139
+                term2 = self.outputNode.addTerminal(name, **opts)
  140
+            finally:
  141
+                self.outputNode.sigTerminalAdded.connect(self.internalTerminalAdded)
129 142
         return term
130 143
 
131 144
     def removeTerminal(self, name):
@@ -138,6 +151,16 @@ def removeTerminal(self, name):
138 151
     def internalTerminalRenamed(self, term, oldName):
139 152
         self[oldName].rename(term.name())
140 153
         
  154
+    def internalTerminalAdded(self, node, term):
  155
+        if term._io == 'in':
  156
+            io = 'out'
  157
+        else:
  158
+            io = 'in'
  159
+        Node.addTerminal(self, term.name(), io=io, renamable=term.isRenamable(), removable=term.isRemovable(), multiable=term.isMultiable())
  160
+        
  161
+    def internalTerminalRemoved(self, node, term):
  162
+        Node.removeTerminal(self, term.name())
  163
+        
141 164
     def terminalRenamed(self, term, oldName):
142 165
         newName = term.name()
143 166
         #print "flowchart rename", newName, oldName
@@ -475,7 +498,7 @@ def restoreState(self, state, clear=False):
475 498
             self.inputNode.restoreState(state.get('inputNode', {}))
476 499
             self.outputNode.restoreState(state.get('outputNode', {}))
477 500
                 
478  
-            #self.restoreTerminals(state['terminals'])
  501
+            self.restoreTerminals(state['terminals'])
479 502
             for n1, t1, n2, t2 in state['connects']:
480 503
                 try:
481 504
                     self.connectTerminals(self._nodes[n1][t1], self._nodes[n2][t2])
17  flowchart/Node.py
@@ -20,7 +20,9 @@ class Node(QtCore.QObject):
20 20
     sigOutputChanged = QtCore.Signal(object)   # self
21 21
     sigClosed = QtCore.Signal(object)
22 22
     sigRenamed = QtCore.Signal(object, object)
23  
-    sigTerminalRenamed = QtCore.Signal(object, object)
  23
+    sigTerminalRenamed = QtCore.Signal(object, object)  # term, oldName
  24
+    sigTerminalAdded = QtCore.Signal(object, object)  # self, term
  25
+    sigTerminalRemoved = QtCore.Signal(object, object)  # self, term
24 26
 
25 27
     
26 28
     def __init__(self, name, terminals=None, allowAddInput=False, allowAddOutput=False, allowRemove=True):
@@ -77,6 +79,8 @@ def removeTerminal(self, term):
77 79
         if name in self._outputs:
78 80
             del self._outputs[name]
79 81
         self.graphicsItem().updateTerminals()
  82
+        self.sigTerminalRemoved.emit(self, term)
  83
+        
80 84
         
81 85
     def terminalRenamed(self, term, oldName):
82 86
         """Called after a terminal has been renamed"""
@@ -107,6 +111,7 @@ def addTerminal(self, name, **opts):
107 111
         elif term.isOutput():
108 112
             self._outputs[name] = term
109 113
         self.graphicsItem().updateTerminals()
  114
+        self.sigTerminalAdded.emit(self, term)
110 115
         return term
111 116
 
112 117
         
@@ -527,16 +532,22 @@ def raiseContextMenu(self, ev):
527 532
     def buildMenu(self):
528 533
         self.menu = QtGui.QMenu()
529 534
         self.menu.setTitle("Node")
530  
-        a = self.menu.addAction("Add input", self.node.addInput)
  535
+        a = self.menu.addAction("Add input", self.addInputFromMenu)
531 536
         if not self.node._allowAddInput:
532 537
             a.setEnabled(False)
533  
-        a = self.menu.addAction("Add output", self.node.addOutput)
  538
+        a = self.menu.addAction("Add output", self.addOutputFromMenu)
534 539
         if not self.node._allowAddOutput:
535 540
             a.setEnabled(False)
536 541
         a = self.menu.addAction("Remove node", self.node.close)
537 542
         if not self.node._allowRemove:
538 543
             a.setEnabled(False)
539 544
         
  545
+    def addInputFromMenu(self):  ## called when add input is clicked in context menu
  546
+        self.node.addInput(renamable=True, removable=True, multiable=True)
  547
+        
  548
+    def addOutputFromMenu(self):  ## called when add output is clicked in context menu
  549
+        self.node.addOutput(renamable=True, removable=True, multiable=False)
  550
+        
540 551
     #def menuTriggered(self, action):
541 552
         ##print "node.menuTriggered called. action:", action
542 553
         #act = str(action.text())
81  flowchart/Terminal.py
@@ -8,15 +8,23 @@
8 8
 from eq import *
9 9
 
10 10
 class Terminal:
11  
-    def __init__(self, node, name, io, optional=False, multi=False, pos=None, renamable=False, bypass=None):
12  
-        """Construct a new terminal. Optiona are:
13  
-        node     - the node to which this terminal belongs
14  
-        name     - string, the name of the terminal
15  
-        io       - 'in' or 'out'
16  
-        optional - bool, whether the node may process without connection to this terminal
17  
-        multi    - bool, for inputs: whether this terminal may make multiple connections
18  
-                   for outputs: whether this terminal creates a different value for each connection
19  
-        pos      - [x, y], the position of the terminal within its node's boundaries
  11
+    def __init__(self, node, name, io, optional=False, multi=False, pos=None, renamable=False, removable=False, multiable=False, bypass=None):
  12
+        """
  13
+        Construct a new terminal. 
  14
+        
  15
+        ==============  =================================================================================
  16
+        **Arguments:**
  17
+        node            the node to which this terminal belongs
  18
+        name            string, the name of the terminal
  19
+        io              'in' or 'out'
  20
+        optional        bool, whether the node may process without connection to this terminal
  21
+        multi           bool, for inputs: whether this terminal may make multiple connections
  22
+                        for outputs: whether this terminal creates a different value for each connection
  23
+        pos             [x, y], the position of the terminal within its node's boundaries
  24
+        renamable       (bool) Whether the terminal can be renamed by the user
  25
+        removable       (bool) Whether the terminal can be removed by the user
  26
+        multiable       (bool) Whether the user may toggle the *multi* option for this terminal
  27
+        ==============  =================================================================================
20 28
         """
21 29
         self._io = io
22 30
         #self._isOutput = opts[0] in ['out', 'io']
@@ -27,6 +35,8 @@ def __init__(self, node, name, io, optional=False, multi=False, pos=None, renama
27 35
         self._node = weakref.ref(node)
28 36
         self._name = name
29 37
         self._renamable = renamable
  38
+        self._removable = removable
  39
+        self._multiable = multiable
30 40
         self._connections = {}
31 41
         self._graphicsItem = TerminalGraphicsItem(self, parent=self._node().graphicsItem())
32 42
         self._bypass = bypass
@@ -121,6 +131,10 @@ def isInput(self):
121 131
     
122 132
     def isMultiValue(self):
123 133
         return self._multi
  134
+    
  135
+    def setMultiValue(self, b):
  136
+        """Set whether this is a multi-value terminal."""
  137
+        self._multi = b
124 138
 
125 139
     def isOutput(self):
126 140
         return self._io == 'out'
@@ -128,6 +142,12 @@ def isOutput(self):
128 142
     def isRenamable(self):
129 143
         return self._renamable
130 144
 
  145
+    def isRemovable(self):
  146
+        return self._removable
  147
+
  148
+    def isMultiable(self):
  149
+        return self._multiable
  150
+
131 151
     def name(self):
132 152
         return self._name
133 153
         
@@ -278,7 +298,7 @@ def close(self):
278 298
             item.scene().removeItem(item)
279 299
         
280 300
     def saveState(self):
281  
-        return {'io': self._io, 'multi': self._multi, 'optional': self._optional}
  301
+        return {'io': self._io, 'multi': self._multi, 'optional': self._optional, 'renamable': self._renamable, 'removable': self._removable, 'multiable': self._multiable}
282 302
 
283 303
 
284 304
 #class TerminalGraphicsItem(QtGui.QGraphicsItem):
@@ -357,40 +377,46 @@ def updateConnections(self):
357 377
             
358 378
     def mousePressEvent(self, ev):
359 379
         #ev.accept()
360  
-        ev.ignore()
  380
+        ev.ignore() ## necessary to allow click/drag events to process correctly
361 381
 
362 382
     def mouseClickEvent(self, ev):
363 383
         if ev.button() == QtCore.Qt.LeftButton:
364 384
             ev.accept()
365 385
             self.label.setFocus(QtCore.Qt.MouseFocusReason)
366  
-        if ev.button() == QtCore.Qt.RightButton:
367  
-            if self.raiseContextMenu(ev):
368  
-                ev.accept()
  386
+        elif ev.button() == QtCore.Qt.RightButton:
  387
+            ev.accept()
  388
+            self.raiseContextMenu(ev)
369 389
             
370 390
     def raiseContextMenu(self, ev):
371 391
         ## only raise menu if this terminal is removable
372 392
         menu = self.getMenu()
373  
-        if menu is None:
374  
-            return False
375 393
         menu = self.scene().addParentContextMenus(self, menu, ev)
376 394
         pos = ev.screenPos()
377 395
         menu.popup(QtCore.QPoint(pos.x(), pos.y()))
378  
-        return True
379 396
         
380 397
     def getMenu(self):
381 398
         if self.menu is None:
382  
-            if self.removable():
383  
-                self.menu = QtGui.QMenu()
384  
-                self.menu.setTitle("Terminal")
385  
-                self.menu.addAction("Remove terminal", self.removeSelf)
386  
-            else:
387  
-                return None
  399
+            self.menu = QtGui.QMenu()
  400
+            self.menu.setTitle("Terminal")
  401
+            remAct = QtGui.QAction("Remove terminal", self.menu)
  402
+            remAct.triggered.connect(self.removeSelf)
  403
+            self.menu.addAction(remAct)
  404
+            self.menu.remAct = remAct
  405
+            if not self.term.isRemovable():
  406
+                remAct.setEnabled(False)
  407
+            multiAct = QtGui.QAction("Multi-value", self.menu)
  408
+            multiAct.setCheckable(True)
  409
+            multiAct.setChecked(self.term.isMultiValue())
  410
+            multiAct.triggered.connect(self.toggleMulti)
  411
+            self.menu.addAction(multiAct)
  412
+            self.menu.multiAct = multiAct
  413
+            if self.term.isMultiable():
  414
+                multiAct.setEnabled = False
388 415
         return self.menu
389 416
 
390  
-    def removable(self):
391  
-        return (
392  
-            (self.term.isOutput() and self.term.node()._allowAddOutput) or 
393  
-            (self.term.isInput()  and self.term.node()._allowAddInput))
  417
+    def toggleMulti(self):
  418
+        multi = self.menu.multiAct.isChecked()
  419
+        self.term.setMultiValue(multi)
394 420
         
395 421
     ## probably never need this
396 422
     #def getContextMenus(self, ev):
@@ -441,6 +467,7 @@ def mouseDragEvent(self, ev):
441 467
     def hoverEvent(self, ev):
442 468
         if not ev.isExit() and ev.acceptDrags(QtCore.Qt.LeftButton):
443 469
             ev.acceptClicks(QtCore.Qt.LeftButton) ## we don't use the click, but we also don't want anyone else to use it.
  470
+            ev.acceptClicks(QtCore.Qt.RightButton)
444 471
             self.box.setBrush(fn.mkBrush('w'))
445 472
         else:
446 473
             self.box.setBrush(self.brush)
20  flowchart/library/Data.py
@@ -195,31 +195,31 @@ def __init__(self, name):
195 195
         
196 196
         self.ui = QtGui.QWidget()
197 197
         self.layout = QtGui.QGridLayout()
198  
-        self.addInBtn = QtGui.QPushButton('+Input')
199  
-        self.addOutBtn = QtGui.QPushButton('+Output')
  198
+        #self.addInBtn = QtGui.QPushButton('+Input')
  199
+        #self.addOutBtn = QtGui.QPushButton('+Output')
200 200
         self.text = QtGui.QTextEdit()
201 201
         self.text.setTabStopWidth(30)
202 202
         self.text.setPlainText("# Access inputs as args['input_name']\nreturn {'output': None} ## one key per output terminal")
203  
-        self.layout.addWidget(self.addInBtn, 0, 0)
204  
-        self.layout.addWidget(self.addOutBtn, 0, 1)
  203
+        #self.layout.addWidget(self.addInBtn, 0, 0)
  204
+        #self.layout.addWidget(self.addOutBtn, 0, 1)
205 205
         self.layout.addWidget(self.text, 1, 0, 1, 2)
206 206
         self.ui.setLayout(self.layout)
207 207
         
208 208
         #QtCore.QObject.connect(self.addInBtn, QtCore.SIGNAL('clicked()'), self.addInput)
209  
-        self.addInBtn.clicked.connect(self.addInput)
  209
+        #self.addInBtn.clicked.connect(self.addInput)
210 210
         #QtCore.QObject.connect(self.addOutBtn, QtCore.SIGNAL('clicked()'), self.addOutput)
211  
-        self.addOutBtn.clicked.connect(self.addOutput)
  211
+        #self.addOutBtn.clicked.connect(self.addOutput)
212 212
         self.text.focusOutEvent = self.focusOutEvent
213 213
         self.lastText = None
214 214
         
215 215
     def ctrlWidget(self):
216 216
         return self.ui
217 217
         
218  
-    def addInput(self):
219  
-        Node.addInput(self, 'input', renamable=True)
  218
+    #def addInput(self):
  219
+        #Node.addInput(self, 'input', renamable=True)
220 220
         
221  
-    def addOutput(self):
222  
-        Node.addOutput(self, 'output', renamable=True)
  221
+    #def addOutput(self):
  222
+        #Node.addOutput(self, 'output', renamable=True)
223 223
         
224 224
     def focusOutEvent(self, ev):
225 225
         text = str(self.text.toPlainText())
32  flowchart/library/Display.py
@@ -5,6 +5,7 @@
5 5
 from pyqtgraph.Qt import QtCore, QtGui
6 6
 from pyqtgraph.graphicsItems.ScatterPlotItem import ScatterPlotItem
7 7
 from pyqtgraph.graphicsItems.PlotCurveItem import PlotCurveItem
  8
+from pyqtgraph import PlotDataItem
8 9
 
9 10
 from common import *
10 11
 import numpy as np
@@ -44,7 +45,7 @@ def process(self, In, display=True):
44 45
                     
45 46
                 for val in vals:
46 47
                     vid = id(val)
47  
-                    if vid in self.items:
  48
+                    if vid in self.items and self.items[vid].scene() is self.plot.scene():
48 49
                         items.add(vid)
49 50
                     else:
50 51
                         #if isinstance(val, PlotCurveItem):
@@ -66,6 +67,11 @@ def process(self, In, display=True):
66 67
                     self.plot.removeItem(self.items[vid])
67 68
                     del self.items[vid]
68 69
             
  70
+    def processBypassed(self, args):
  71
+        for item in self.items.values():
  72
+            self.plot.removeItem(item)
  73
+        self.items = {}
  74
+        
69 75
     #def setInput(self, **args):
70 76
         #for k in args:
71 77
             #self.plot.plot(args[k])
@@ -117,6 +123,30 @@ def process(self, In, display=True):
117 123
                     del self.items[vid]
118 124
 
119 125
 
  126
+class PlotCurve(CtrlNode):
  127
+    """Generates a plot curve from x/y data"""
  128
+    nodeName = 'PlotCurve'
  129
+    uiTemplate = [
  130
+        ('color', 'color'),
  131
+    ]
  132
+    
  133
+    def __init__(self, name):
  134
+        CtrlNode.__init__(self, name, terminals={
  135
+            'x': {'io': 'in'},
  136
+            'y': {'io': 'in'},
  137
+            'plot': {'io': 'out'}
  138
+        })
  139
+        self.item = PlotDataItem()
  140
+    
  141
+    def process(self, x, y, display=True):
  142
+        #print "scatterplot process"
  143
+        if not display:
  144
+            return {'plot': None}
  145
+        
  146
+        self.item.setData(x, y, pen=self.ctrls['color'].color())
  147
+        return {'plot': self.item}
  148
+        
  149
+        
120 150
 
121 151
 
122 152
 class ScatterPlot(CtrlNode):
235  graphicsItems/GradientEditorItem.py
@@ -21,8 +21,23 @@
21 21
 
22 22
 
23 23
 class TickSliderItem(GraphicsWidget):
  24
+    ## public class
  25
+    """**Bases:** :class:`GraphicsWidget <pyqtgraph.GraphicsWidget>`
  26
+    
  27
+    A rectangular item with tick marks along its length that can (optionally) be moved by the user."""
24 28
         
25 29
     def __init__(self, orientation='bottom', allowAdd=True, **kargs):
  30
+        """
  31
+        ============= =================================================================================
  32
+        **Arguments**
  33
+        orientation   Set the orientation of the gradient. Options are: 'left', 'right'
  34
+                      'top', and 'bottom'.
  35
+        allowAdd      Specifies whether ticks can be added to the item by the user.
  36
+        tickPen       Default is white. Specifies the color of the outline of the ticks.
  37
+                      Can be any of the valid arguments for :func:`mkPen <pyqtgraph.mkPen>`
  38
+        ============= =================================================================================        
  39
+        """
  40
+        ## public
26 41
         GraphicsWidget.__init__(self)
27 42
         self.orientation = orientation
28 43
         self.length = 100
@@ -77,10 +92,21 @@ def setMaxDim(self, mx=None):
77 92
             self.setMaximumHeight(16777215)
78 93
             
79 94
     
80  
-    def setOrientation(self, ort):
81  
-        self.orientation = ort
  95
+    def setOrientation(self, orientation):
  96
+        ## public
  97
+        """Set the orientation of the TickSliderItem.
  98
+        
  99
+        ============= ===================================================================
  100
+        **Arguments**
  101
+        orientation   Options are: 'left', 'right', 'top', 'bottom'
  102
+                      The orientation option specifies which side of the slider the
  103
+                      ticks are on, as well as whether the slider is vertical ('right'
  104
+                      and 'left') or horizontal ('top' and 'bottom').
  105
+        ============= ===================================================================
  106
+        """
82 107
         self.setMaxDim()
83 108
         self.resetTransform()
  109
+        ort = orientation
84 110
         if ort == 'top':
85 111
             self.scale(1, -1)
86 112
             self.translate(0, -self.height())
@@ -92,10 +118,25 @@ def setOrientation(self, ort):
92 118
             self.rotate(270)
93 119
             self.translate(-self.height(), 0)
94 120
             #self.setPos(0, -self.height())
  121
+        elif ort != 'bottom':
  122
+            raise Exception("%s is not a valid orientation. Options are 'left', 'right', 'top', and 'bottom'" %str(ort))
95 123
         
96 124
         self.translate(self.tickSize/2., 0)
97 125
     
98 126
     def addTick(self, x, color=None, movable=True):
  127
+        ## public
  128
+        """
  129
+        Add a tick to the item.
  130
+        
  131
+        ============= ==================================================================
  132
+        **Arguments**
  133
+        x             Position where tick should be added.
  134
+        color         Color of added tick. If color is not specified, the color will be
  135
+                      white.
  136
+        movable       Specifies whether the tick is movable with the mouse.
  137
+        ============= ==================================================================
  138
+        """        
  139
+        
99 140
         if color is None:
100 141
             color = QtGui.QColor(255,255,255)
101 142
         tick = Tick(self, [x*self.length, 0], color, movable, self.tickSize, pen=self.tickPen)
@@ -104,6 +145,10 @@ def addTick(self, x, color=None, movable=True):
104 145
         return tick
105 146
     
106 147
     def removeTick(self, tick):
  148
+        ## public
  149
+        """
  150
+        Removes the specified tick.
  151
+        """
107 152
         del self.ticks[tick]
108 153
         tick.setParentItem(None)
109 154
         if self.scene() is not None:
@@ -138,6 +183,7 @@ def resizeEvent(self, ev):
138 183
         #self.fitInView(bounds, QtCore.Qt.KeepAspectRatio)
139 184
         
140 185
     def setLength(self, newLen):
  186
+        #private
141 187
         for t, x in self.ticks.items():
142 188
             t.setPos(x * newLen, t.pos().y())
143 189
         self.length = float(newLen)
@@ -206,12 +252,36 @@ def showMenu(self, ev):
206 252
         pass
207 253
 
208 254
     def setTickColor(self, tick, color):
  255
+        """Set the color of the specified tick.
  256
+        
  257
+        ============= ==================================================================
  258
+        **Arguments** 
  259
+        tick          Can be either an integer corresponding to the index of the tick 
  260
+                      or a Tick object. Ex: if you had a slider with 3 ticks and you 
  261
+                      wanted to change the middle tick, the index would be 1.
  262
+        color         The color to make the tick. Can be any argument that is valid for 
  263
+                      :func:`mkBrush <pyqtgraph.mkBrush>`
  264
+        ============= ==================================================================
  265
+        """
209 266
         tick = self.getTick(tick)
210 267
         tick.color = color
211 268
         tick.update()
212 269
         #tick.setBrush(QtGui.QBrush(QtGui.QColor(tick.color)))
213 270
 
214 271
     def setTickValue(self, tick, val):
  272
+        ## public
  273
+        """
  274
+        Set the position (along the slider) of the tick.
  275
+        
  276
+        ============= ==================================================================
  277
+        **Arguments** 
  278
+        tick          Can be either an integer corresponding to the index of the tick 
  279
+                      or a Tick object. Ex: if you had a slider with 3 ticks and you 
  280
+                      wanted to change the middle tick, the index would be 1.
  281
+        val           The desired position of the tick. If val is < 0, position will be 
  282
+                      set to 0. If val is > 1, position will be set to 1.
  283
+        ============= ==================================================================        
  284
+        """
215 285
         tick = self.getTick(tick)
216 286
         val = min(max(0.0, val), 1.0)
217 287
         x = val * self.length
@@ -221,10 +291,29 @@ def setTickValue(self, tick, val):
221 291
         self.ticks[tick] = val
222 292
         
223 293
     def tickValue(self, tick):
  294
+        ## public
  295
+        """Return the value (from 0.0 to 1.0) of the specified tick.
  296
+        
  297
+        ============= ==================================================================
  298
+        **Arguments** 
  299
+        tick          Can be either an integer corresponding to the index of the tick 
  300
+                      or a Tick object. Ex: if you had a slider with 3 ticks and you 
  301
+                      wanted the value of the middle tick, the index would be 1.
  302
+        ============= ==================================================================        
  303
+        """
224 304
         tick = self.getTick(tick)
225 305
         return self.ticks[tick]
226 306
         
227 307
     def getTick(self, tick):
  308
+        ## public
  309
+        """Return the Tick object at the specified index.
  310
+        
  311
+        ============= ==================================================================
  312
+        **Arguments**       
  313
+        tick          An integer corresponding to the index of the desired tick. If the 
  314
+                      argument is not an integer it will be returned unchanged.  
  315
+        ============= ==================================================================
  316
+        """
228 317
         if type(tick) is int:
229 318
             tick = self.listTicks()[tick][0]
230 319
         return tick
@@ -233,17 +322,46 @@ def getTick(self, tick):
233 322
         #QtGui.QGraphicsView.mouseMoveEvent(self, ev)
234 323
 
235 324
     def listTicks(self):
  325
+        """Return a sorted list of all the Tick objects on the slider."""
  326
+        ## public
236 327
         ticks = self.ticks.items()
237 328
         ticks.sort(lambda a,b: cmp(a[1], b[1]))
238 329
         return ticks
239 330
 
240 331
 
241 332
 class GradientEditorItem(TickSliderItem):
  333
+    """
  334
+    **Bases:** :class:`TickSliderItem <pyqtgraph.TickSliderItem>`
  335
+    
  336
+    An item that can be used to define a color gradient. Implements common pre-defined gradients that are 
  337
+    customizable by the user. :class: `GradientWidget <pyqtgraph.widgets.GradientWidget>` provides a widget
  338
+    with a GradientEditorItem that can be added to a GUI. 
  339
+    
  340
+    ======================== ===========================================================
  341
+    **Signals**
  342
+    sigGradientChanged(self) Signal is emitted anytime the gradient changes. The signal 
  343
+                             is emitted in real time while ticks are being dragged or 
  344
+                             colors are being changed.
  345
+    ======================== ===========================================================    
  346
+ 
  347
+    """
242 348
     
243 349
     sigGradientChanged = QtCore.Signal(object)
244 350
     
245 351
     def __init__(self, *args, **kargs):
246  
-        
  352
+        """
  353
+        Create a new GradientEditorItem. 
  354
+        All arguments are passed to :func:`TickSliderItem.__init__ <pyqtgraph.TickSliderItem.__init__>`
  355
+        
  356
+        ============= =================================================================================
  357
+        **Arguments**
  358
+        orientation   Set the orientation of the gradient. Options are: 'left', 'right'
  359
+                      'top', and 'bottom'.
  360
+        allowAdd      Default is True. Specifies whether ticks can be added to the item.
  361
+        tickPen       Default is white. Specifies the color of the outline of the ticks.
  362
+                      Can be any of the valid arguments for :func:`mkPen <pyqtgraph.mkPen>'
  363
+        ============= =================================================================================
  364
+        """
247 365
         self.currentTick = None
248 366
         self.currentTickColor = None
249 367
         self.rectSize = 15
@@ -308,22 +426,47 @@ def __init__(self, *args, **kargs):
308 426
         self.setColorMode('rgb')
309 427
         self.updateGradient()
310 428
     
311  
-    def setOrientation(self, ort):
312  
-        TickSliderItem.setOrientation(self, ort)
  429
+    def setOrientation(self, orientation):
  430
+        ## public
  431
+        """
  432
+        Set the orientation of the GradientEditorItem. 
  433
+        
  434
+        ============= ===================================================================
  435
+        **Arguments**
  436
+        orientation   Options are: 'left', 'right', 'top', 'bottom'
  437
+                      The orientation option specifies which side of the gradient the
  438
+                      ticks are on, as well as whether the gradient is vertical ('right'
  439
+                      and 'left') or horizontal ('top' and 'bottom').
  440
+        ============= ===================================================================
  441
+        """
  442
+        TickSliderItem.setOrientation(self, orientation)
313 443
         self.translate(0, self.rectSize)
314 444
     
315 445
     def showMenu(self, ev):
  446
+        #private
316 447
         self.menu.popup(ev.screenPos().toQPoint())
317 448
     
318 449
     def contextMenuClicked(self, b=None):
319  
-        global Gradients
  450
+        #private
  451
+        #global Gradients
320 452
         act = self.sender()
321 453
         self.loadPreset(act.name)
322 454
         
323 455
     def loadPreset(self, name):
  456
+        """
  457
+        Load a predefined gradient. 
  458
+    
  459
+        """ ## TODO: provide image with names of defined gradients
  460
+        #global Gradients
324 461
         self.restoreState(Gradients[name])
325 462
     
326 463
     def setColorMode(self, cm):
  464
+        """
  465
+        Set the color mode for the gradient. Options are: 'hsv', 'rgb'
  466
+        
  467
+        """
  468
+        
  469
+        ## public
327 470
         if cm not in ['rgb', 'hsv']:
328 471
             raise Exception("Unknown color mode %s. Options are 'rgb' and 'hsv'." % str(cm))
329 472
         
@@ -339,26 +482,31 @@ def setColorMode(self, cm):
339 482
         self.updateGradient()
340 483
         
341 484
     def updateGradient(self):
  485
+        #private
342 486
         self.gradient = self.getGradient()
343 487
         self.gradRect.setBrush(QtGui.QBrush(self.gradient))
344 488
         self.sigGradientChanged.emit(self)
345 489
         
346 490
     def setLength(self, newLen):
  491
+        #private (but maybe public)
347 492
         TickSliderItem.setLength(self, newLen)
348 493
         self.backgroundRect.setRect(0, -self.rectSize, newLen, self.rectSize)
349 494
         self.gradRect.setRect(0, -self.rectSize, newLen, self.rectSize)
350 495
         self.updateGradient()
351 496
         
352 497
     def currentColorChanged(self, color):
  498
+        #private
353 499
         if color.isValid() and self.currentTick is not None:
354 500
             self.setTickColor(self.currentTick, color)
355 501
             self.updateGradient()
356 502
             
357 503
     def currentColorRejected(self):
  504
+        #private
358 505
         self.setTickColor(self.currentTick, self.currentTickColor)
359 506
         self.updateGradient()
360 507
         
361 508
     def tickClicked(self, tick, ev):
  509
+        #private
362 510
         if ev.button() == QtCore.Qt.LeftButton:
363 511
             if not tick.colorChangeAllowed:
364 512
                 return
@@ -378,11 +526,13 @@ def tickClicked(self, tick, ev):
378 526
                 self.updateGradient()
379 527
                 
380 528
     def tickMoved(self, tick, pos):
  529
+        #private
381 530
         TickSliderItem.tickMoved(self, tick, pos)
382 531
         self.updateGradient()
383 532
 
384 533
 
385 534
     def getGradient(self):
  535
+        """Return a QLinearGradient object."""
386 536
         g = QtGui.QLinearGradient(QtCore.QPointF(0,0), QtCore.QPointF(self.length,0))
387 537
         if self.colorMode == 'rgb':
388 538
             ticks = self.listTicks()
@@ -403,6 +553,15 @@ def getGradient(self):
403 553
         return g
404 554
         
405 555
     def getColor(self, x, toQColor=True):
  556
+        """
  557
+        Return a color for a given value.
  558
+        
  559
+        ============= ==================================================================
  560
+        **Arguments** 
  561
+        x             Value (position on gradient) of requested color.
  562
+        toQColor      If true, returns a QColor object, else returns a (r,g,b,a) tuple.
  563
+        ============= ==================================================================
  564
+        """
406 565
         ticks = self.listTicks()
407 566
         if x <= ticks[0][1]:
408 567
             c = ticks[0][0].color
@@ -453,8 +612,19 @@ def getColor(self, x, toQColor=True):
453 612
             else:
454 613
                 return (c.red(), c.green(), c.blue(), c.alpha())
455 614
                     
456  
-    def getLookupTable(self, nPts, alpha=True):
457  
-        """Return an RGB/A lookup table."""
  615
+    def getLookupTable(self, nPts, alpha=None):
  616
+        """
  617
+        Return an RGB(A) lookup table (ndarray). 
  618
+        
  619
+        ============= ============================================================================
  620
+        **Arguments**
  621
+        nPts           The number of points in the returned lookup table.
  622
+        alpha          True, False, or None - Specifies whether or not alpha values are included 
  623
+                       in the table.If alpha is None, alpha will be automatically determined.
  624
+        ============= ============================================================================
  625
+        """
  626
+        if alpha is None:
  627
+            alpha = self.usesAlpha()
458 628
         if alpha:
459 629
             table = np.empty((nPts,4), dtype=np.ubyte)
460 630
         else:
@@ -466,9 +636,19 @@ def getLookupTable(self, nPts, alpha=True):
466 636
             table[i] = color[:table.shape[1]]
467 637
             
468 638
         return table
  639
+    
  640
+    def usesAlpha(self):
  641
+        """Return True if any ticks have an alpha < 255"""
  642
+        
  643
+        ticks = self.listTicks()
  644
+        for t in ticks:
  645
+            if t[0].color.alpha() < 255:
  646
+                return True
  647
+            
  648
+        return False
469 649
             
470 650
     def isLookupTrivial(self):
471  
-        """Return true if the gradient has exactly two stops in it: black at 0.0 and white at 1.0"""
  651
+        """Return True if the gradient has exactly two stops in it: black at 0.0 and white at 1.0"""
472 652
         ticks = self.listTicks()
473 653
         if len(ticks) != 2:
474 654
             return False
@@ -482,10 +662,24 @@ def isLookupTrivial(self):
482 662
 
483 663
 
484 664
     def mouseReleaseEvent(self, ev):
  665
+        #private
485 666
         TickSliderItem.mouseReleaseEvent(self, ev)
486 667
         self.updateGradient()
487 668
         
488 669
     def addTick(self, x, color=None, movable=True):
  670
+        """
  671
+        Add a tick to the gradient. Return the tick.
  672
+        
  673
+        ============= ==================================================================
  674
+        **Arguments**
  675
+        x             Position where tick should be added.
  676
+        color         Color of added tick. If color is not specified, the color will be
  677
+                      the color of the gradient at the specified position.
  678
+        movable       Specifies whether the tick is movable with the mouse.
  679
+        ============= ==================================================================
  680
+        """
  681
+        
  682
+        
489 683
         if color is None:
490 684
             color = self.getColor(x)
491 685
         t = TickSliderItem.addTick(self, x, color=color, movable=movable)
@@ -494,6 +688,13 @@ def addTick(self, x, color=None, movable=True):
494 688
         return t
495 689
         
496 690
     def saveState(self):
  691
+        """
  692
+        Return a dictionary with parameters for rebuilding the gradient. Keys will include:
  693
+        
  694
+           - 'mode': hsv or rgb
  695
+           - 'ticks': a list of tuples (pos, (r,g,b,a))
  696
+        """
  697
+        ## public
497 698
         ticks = []
498 699
         for t in self.ticks:
499 700
             c = t.color
@@ -502,6 +703,21 @@ def saveState(self):
502 703
         return state
503 704
         
504 705
     def restoreState(self, state):
  706
+        """
  707
+        Restore the gradient specified in state.
  708
+        
  709
+        ============= ====================================================================
  710
+        **Arguments**
  711
+        state         A dictionary with same structure as those returned by 
  712
+                      :func:`saveState <pyqtgraph.GradientEditorItem.saveState>`
  713
+                      
  714
+                      Keys must include:
  715
+                      
  716
+                         - 'mode': hsv or rgb
  717
+                         - 'ticks': a list of tuples (pos, (r,g,b,a))
  718
+        ============= ====================================================================
  719
+        """
  720
+        ## public
505 721
         self.setColorMode(state['mode'])
506 722
         for t in self.ticks.keys():
507 723
             self.removeTick(t)
@@ -512,6 +728,7 @@ def restoreState(self, state):
512 728
 
513 729
 
514 730
 class Tick(GraphicsObject):
  731
+    ## private class
515 732
     
516 733
     sigMoving = QtCore.Signal(object)
517 734
     sigMoved = QtCore.Signal(object)
2  graphicsItems/GridItem.py
@@ -6,6 +6,8 @@
6 6
 __all__ = ['GridItem']
7 7
 class GridItem(UIGraphicsItem):
8 8
     """
  9
+    **Bases:** `UIGraphicsItem <pyqtgraph.UIGraphicsItem>'
  10
+    
9 11
     Displays a rectangular grid of lines indicating major divisions within a coordinate system.
10 12
     Automatically determines what divisions to use.
11 13
     """
2  graphicsItems/HistogramLUTItem.py
@@ -160,7 +160,7 @@ def gradientChanged(self):
160 160
             #self.imageItem.setLookupTable(self.gradient.getLookupTable(512))
161 161
         self.sigLookupTableChanged.emit(self)
162 162
 
163  
-    def getLookupTable(self, img=None, n=None, alpha=False):
  163
+    def getLookupTable(self, img=None, n=None, alpha=None):
164 164
         if n is None:
165 165
             if img.dtype == np.uint8:
166 166
                 n = 256
2  graphicsItems/ImageItem.py
@@ -258,6 +258,8 @@ def render(self):
258 258
             lut = self.lut(self.image)
259 259
         else:
260 260
             lut = self.lut
  261
+        #print lut.shape
  262
+        #print self.lut
261 263
             
262 264
         argb, alpha = fn.makeARGB(self.image, lut=lut, levels=self.levels)
263 265
         self.qimage = fn.makeQImage(argb, alpha)
36  graphicsItems/InfiniteLine.py
@@ -9,8 +9,17 @@
9 9
 __all__ = ['InfiniteLine']
10 10
 class InfiniteLine(UIGraphicsItem):
11 11
     """
  12
+    **Bases:** :class:`UIGraphicsItem <pyqtgraph.UIGraphicsItem>`
  13
+    
12 14
     Displays a line of infinite length.
13 15
     This line may be dragged to indicate a position in data coordinates.
  16
+    
  17
+    =============================== ===================================================
  18
+    **Signals**
  19
+    sigDragged(self)
  20
+    sigPositionChangeFinished(self)
  21
+    sigPositionChanged(self)
  22
+    =============================== ===================================================
14 23
     """
15 24
     
16 25
     sigDragged = QtCore.Signal(object)
@@ -19,12 +28,18 @@ class InfiniteLine(UIGraphicsItem):
19 28
     
20 29
     def __init__(self, pos=None, angle=90, pen=None, movable=False, bounds=None):
21 30
         """
22  
-        Initialization options:
23  
-            pos      - Position of the line. This can be a QPointF or a single value for vertical/horizontal lines.
24  
-            angle    - Angle of line in degrees. 0 is horizontal, 90 is vertical.
25  
-            pen      - Pen to use when drawing line
26  
-            movable  - If True, the line can be dragged to a new position by the user
27  
-            bounds   - Optional [min, max] bounding values. Bounds are only valid if the line is vertical or horizontal.
  31
+        ============= ==================================================================
  32
+        **Arguments**
  33
+        pos           Position of the line. This can be a QPointF or a single value for
  34
+                      vertical/horizontal lines.
  35
+        angle         Angle of line in degrees. 0 is horizontal, 90 is vertical.
  36
+        pen           Pen to use when drawing line. Can be any arguments that are valid 
  37
+                      for :func:`mkPen <pyqtgraph.mkPen>`. Default pen is transparent 
  38
+                      yellow.
  39
+        movable       If True, the line can be dragged to a new position by the user.
  40
+        bounds        Optional [min, max] bounding values. Bounds are only valid if the
  41
+                      line is vertical or horizontal.
  42
+        ============= ==================================================================
28 43
         """
29 44
         
30 45
         UIGraphicsItem.__init__(self)
@@ -49,6 +64,7 @@ def __init__(self, pos=None, angle=90, pen=None, movable=False, bounds=None):
49 64
         #self.setFlag(self.ItemSendsScenePositionChanges)
50 65
       
51 66
     def setMovable(self, m):
  67
+        """Set whether the line is movable by the user."""
52 68
         self.movable = m
53 69
         self.setAcceptHoverEvents(m)
54 70
       
@@ -58,6 +74,8 @@ def setBounds(self, bounds):
58 74
         self.setValue(self.value())
59 75
         
60 76
     def setPen(self, pen):
  77
+        """Set the pen for drawing the line. Allowable arguments are any that are valid 
  78
+        for :func:`mkPen <pyqtgraph.mkPen>`."""
61 79
         self.pen = fn.mkPen(pen)
62 80
         self.currentPen = self.pen
63 81
         self.update()
@@ -76,6 +94,7 @@ def setAngle(self, angle):
76 94
         self.update()
77 95
         
78 96
     def setPos(self, pos):
  97
+        
79 98
         if type(pos) in [list, tuple]:
80 99
             newPos = pos
81 100
         elif isinstance(pos, QtCore.QPointF):
@@ -116,6 +135,8 @@ def getPos(self):
116 135
         return self.p
117 136
 
118 137
     def value(self):
  138
+        """Return the value of the line. Will be a single number for horizontal and 
  139
+        vertical lines, and a list of [x,y] values for diagonal lines."""
119 140
         if self.angle%180 == 0:
120 141
             return self.getYPos()
121 142
         elif self.angle%180 == 90:
@@ -124,6 +145,9 @@ def value(self):
124 145
             return self.getPos()
125 146
                 
126 147
     def setValue(self, v):
  148
+        """Set the position of the line. If line is horizontal or vertical, v can be 
  149
+        a single value. Otherwise, a 2D coordinate must be specified (list, tuple and 
  150
+        QPointF are all acceptable)."""
127 151
         self.setPos(v)
128 152
 
129 153
     ## broken in 4.7
57  graphicsItems/IsocurveItem.py
@@ -7,22 +7,51 @@
7 7
 
8 8
 class IsocurveItem(GraphicsObject):
9 9
     """
10  
-    Item displaying an isocurve of a 2D array.
  10
+    **Bases:** :class:`GraphicsObject <pyqtgraph.GraphicsObject>`
11 11
     
12  
-    To align this item correctly with an ImageItem,
13  
-    call isocurve.setParentItem(image)
  12
+    Item displaying an isocurve of a 2D array.To align this item correctly with an 
  13
+    ImageItem,call isocurve.setParentItem(image)
14 14
     """
15 15
     
  16
+
16 17
     def __init__(self, data=None, level=0, pen='w'):
  18
+        """
  19
+        Create a new isocurve item. 
  20
+        
  21
+        ============= ===============================================================
  22
+        **Arguments**
  23
+        data          A 2-dimensional ndarray. Can be initialized as None, and set 
  24
+                      later using :func:`setData <pyqtgraph.IsocurveItem.setData>`
  25
+        level         The cutoff value at which to draw the isocurve.
  26
+        pen           The color of the curve item. Can be anything valid for 
  27
+                      :func:`mkPen <pyqtgraph.mkPen>`
  28
+        ============= ===============================================================
  29
+        """
17 30
         GraphicsObject.__init__(self)
18  
-        self.level = 0
  31
+
  32
+        self.level = level
19 33
         self.data = None
20 34
         self.path = None
21  
-        self.setData(data, level)
22 35
         self.setPen(pen)
  36
+        self.setData(data, level)
  37
+        
23 38
         
  39
+
  40
+        #if data is not None and level is not None:
  41
+            #self.updateLines(data, level)
  42
+            
24 43
     
25 44
     def setData(self, data, level=None):
  45
+        """
  46
+        Set the data/image to draw isocurves for.
  47
+        
  48
+        ============= ================================================================
  49
+        **Arguments**
  50
+        data          A 2-dimensional ndarray.
  51
+        level         The cutoff value at which to draw the curve. If level is not specified,
  52
+                      the previous level is used.
  53
+        ============= ================================================================
  54
+        """
26 55
         if level is None:
27 56
             level = self.level
28 57
         self.level = level
@@ -31,15 +60,33 @@ def setData(self, data, level=None):
31 60
         self.prepareGeometryChange()
32 61
         self.update()
33 62
         
  63
+
34 64
     def setLevel(self, level):
  65
+        """Set the level at which the isocurve is drawn."""
35 66
         self.level = level
36 67
         self.path = None
37 68
         self.update()
38 69
     
  70
+
39 71
     def setPen(self, *args, **kwargs):
  72
+        """Set the pen used to draw the isocurve. Arguments can be any that are valid 
  73
+        for :func:`mkPen <pyqtgraph.mkPen>`"""
40 74
         self.pen = fn.mkPen(*args, **kwargs)
41 75
         self.update()
42 76
 
  77
+        
  78
+    def updateLines(self, data, level):
  79
+        ##print "data:", data
  80
+        ##print "level", level
  81
+        #lines = fn.isocurve(data, level)
  82
+        ##print len(lines)
  83
+        #self.path = QtGui.QPainterPath()
  84
+        #for line in lines:
  85
+            #self.path.moveTo(*line[0])
  86
+            #self.path.lineTo(*line[1])
  87
+        #self.update()
  88
+        self.setData(data, level)
  89
+
43 90
     def boundingRect(self):
44 91
         if self.path is None:
45 92
             return QtCore.QRectF()
38  graphicsItems/LinearRegionItem.py
@@ -28,6 +28,23 @@ class LinearRegionItem(UIGraphicsItem):
28 28
     Horizontal = 1
29 29
     
30 30
     def __init__(self, values=[0,1], orientation=None, brush=None, movable=True, bounds=None):
  31
+        """Create a new LinearRegionItem.
  32
+        
  33
+        ============= =====================================================================
  34
+        **Arguments**
  35
+        values        A list of the positions of the lines in the region. These are not 
  36
+                      limits; limits can be set by specifying bounds.
  37
+        orientation   Options are LinearRegionItem.Vertical or LinearRegionItem.Horizontal.
  38
+                      If not specified it will be vertical.
  39
+        brush         Defines the brush that fills the region. Can be any arguments that 
  40
+                      are valid for :func:`mkBrush <pyqtgraph.mkBrush>`. Default is 
  41
+                      transparent blue.
  42
+        movable       If True, the region and individual lines are movable by the user; if 
  43
+                      False, they are static.
  44
+        bounds        Optional [min, max] bounding values for the region
  45
+        ============= =====================================================================
  46
+        """
  47
+        
31 48
         UIGraphicsItem.__init__(self)
32 49
         if orientation is None:
33 50
             orientation = LinearRegionItem.Vertical
@@ -70,6 +87,13 @@ def getRegion(self):
70 87
         return (min(r), max(r))
71 88
 
72 89
     def setRegion(self, rgn):
  90
+        """Set the values for the edges of the region.
  91
+        
  92
+        ============= ==============================================
  93
+        **Arguments** 
  94
+        rgn           A list or tuple of the lower and upper values.
  95
+        ============= ==============================================
  96
+        """
73 97
         if self.lines[0].value() == rgn[0] and self.lines[1].value() == rgn[1]:
74 98
             return
75 99
         self.blockLineSignal = True
@@ -80,15 +104,25 @@ def setRegion(self, rgn):
80 104
         self.lineMoved()
81 105
         self.lineMoveFinished()
82 106
 
83  
-    def setBrush(self, br):
84  
-        self.brush = fn.mkBrush(br)
  107
+    def setBrush(self, *br, **kargs):