diff --git a/examples/Arrow.py b/examples/Arrow.py index 665bbab1..2cbff113 100644 --- a/examples/Arrow.py +++ b/examples/Arrow.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- +""" +Display an animated arrowhead following a curve. +This example uses the CurveArrow class, which is a combination +of ArrowItem and CurvePoint. -## Display an animated arrowhead following a curve. -## This example uses the CurveArrow class, which is a combination -## of ArrowItem and CurvePoint. -## -## To place a static arrow anywhere in a scene, use ArrowItem. -## To attach other types of item to a curve, use CurvePoint. +To place a static arrow anywhere in a scene, use ArrowItem. +To attach other types of item to a curve, use CurvePoint. +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -21,6 +22,7 @@ cw = pg.GraphicsLayoutWidget() w.show() w.resize(400,600) w.setCentralWidget(cw) +w.setWindowTitle('pyqtgraph example: Arrow') p = cw.addPlot(row=0, col=0) p2 = cw.addPlot(row=1, col=0) diff --git a/examples/CLIexample.py b/examples/CLIexample.py index a412698f..f32cf81c 100644 --- a/examples/CLIexample.py +++ b/examples/CLIexample.py @@ -1,21 +1,26 @@ +""" +Display a plot and an image with minimal setup. + +pg.plot() and pg.image() are indended to be used from an interactive prompt +to allow easy data inspection (but note that PySide unfortunately does not +call the Qt event loop while the interactive prompt is running, in this case +it is necessary to call QApplication.exec_() to make the windows appear). +""" import initExample ## Add path to library (just for examples; you do not need this) -from pyqtgraph.Qt import QtGui, QtCore + import numpy as np import pyqtgraph as pg -app = QtGui.QApplication([]) - - data = np.random.normal(size=1000) pg.plot(data, title="Simplest possible plotting example") data = np.random.normal(size=(500,500)) -pg.show(data, title="Simplest possible image example") +pg.image(data, title="Simplest possible image example") ## Start Qt event loop unless running in interactive mode or using pyside. if __name__ == '__main__': import sys if sys.flags.interactive != 1 or not hasattr(QtCore, 'PYQT_VERSION'): - app.exec_() + pg.QtGui.QApplication.exec_() diff --git a/examples/ColorButton.py b/examples/ColorButton.py index 4199c8bc..321ee735 100644 --- a/examples/ColorButton.py +++ b/examples/ColorButton.py @@ -1,11 +1,12 @@ # -*- coding: utf-8 -*- -import initExample ## Add path to library (just for examples; you do not need this) - """ Simple example demonstrating a button which displays a colored rectangle and allows the user to select a new color by clicking on the button. """ +import initExample ## Add path to library (just for examples; you do not need this) + + import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np @@ -15,6 +16,7 @@ win = QtGui.QMainWindow() btn = pg.ColorButton() win.setCentralWidget(btn) win.show() +win.setWindowTitle('pyqtgraph example: ColorButton') def change(btn): print("change", btn.color()) diff --git a/examples/ConsoleWidget.py b/examples/ConsoleWidget.py index 52fc022e..8234269d 100644 --- a/examples/ConsoleWidget.py +++ b/examples/ConsoleWidget.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" +ConsoleWidget is used to allow execution of user-supplied python commands +in an application. It also includes a command history and functionality for trapping +and inspecting stack traces. + +""" import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg @@ -21,6 +27,7 @@ Go, play. """ c = pyqtgraph.console.ConsoleWidget(namespace=namespace, text=text) c.show() +c.setWindowTitle('pyqtgraph example: ConsoleWidget') ## Start Qt event loop unless running in interactive mode or using pyside. if __name__ == '__main__': diff --git a/examples/DataSlicing.py b/examples/DataSlicing.py index 6b83a592..bd201832 100644 --- a/examples/DataSlicing.py +++ b/examples/DataSlicing.py @@ -1,4 +1,12 @@ # -*- coding: utf-8 -*- +""" +Demonstrate a simple data-slicing task: given 3D data (displayed at top), select +a 2D plane and interpolate data along that plane to generate a slice image +(displayed at bottom). + + +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -12,6 +20,7 @@ app = QtGui.QApplication([]) ## Create window with two ImageView widgets win = QtGui.QMainWindow() win.resize(800,800) +win.setWindowTitle('pyqtgraph example: DataSlicing') cw = QtGui.QWidget() win.setCentralWidget(cw) l = QtGui.QGridLayout() diff --git a/examples/DataTreeWidget.py b/examples/DataTreeWidget.py index 01c66b2a..8365db2a 100644 --- a/examples/DataTreeWidget.py +++ b/examples/DataTreeWidget.py @@ -4,8 +4,6 @@ Simple use of DataTreeWidget to display a structure of nested dicts, lists, and arrays """ - - import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg @@ -26,6 +24,7 @@ d = { tree = pg.DataTreeWidget(data=d) tree.show() +tree.setWindowTitle('pyqtgraph example: DataTreeWidget') tree.resize(600,600) diff --git a/examples/Draw.py b/examples/Draw.py index 2abf0280..cc137db3 100644 --- a/examples/Draw.py +++ b/examples/Draw.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" +Demonstrate ability of ImageItem to be used as a canvas for painting with +the mouse. + +""" + import initExample ## Add path to library (just for examples; you do not need this) @@ -12,6 +18,7 @@ app = QtGui.QApplication([]) w = pg.GraphicsView() w.show() w.resize(800,800) +w.setWindowTitle('pyqtgraph example: Draw') view = pg.ViewBox() w.setCentralItem(view) diff --git a/examples/ErrorBarItem.py b/examples/ErrorBarItem.py index 816e8474..3bbf06d1 100644 --- a/examples/ErrorBarItem.py +++ b/examples/ErrorBarItem.py @@ -21,6 +21,7 @@ top = np.linspace(1.0, 3.0, 10) bottom = np.linspace(2, 0.5, 10) plt = pg.plot() +plt.setWindowTitle('pyqtgraph example: ErrorBarItem') err = pg.ErrorBarItem(x=x, y=y, top=top, bottom=bottom, beam=0.5) plt.addItem(err) plt.plot(x, y, symbol='o', pen={'color': 0.8, 'width': 2}) diff --git a/examples/Flowchart.py b/examples/Flowchart.py index ade647fc..09ea1f93 100644 --- a/examples/Flowchart.py +++ b/examples/Flowchart.py @@ -23,6 +23,7 @@ app = QtGui.QApplication([]) ## Create main window with grid layout win = QtGui.QMainWindow() +win.setWindowTitle('pyqtgraph example: Flowchart') cw = QtGui.QWidget() win.setCentralWidget(cw) layout = QtGui.QGridLayout() diff --git a/examples/FlowchartCustomNode.py b/examples/FlowchartCustomNode.py index 9ed3d6da..bce37982 100644 --- a/examples/FlowchartCustomNode.py +++ b/examples/FlowchartCustomNode.py @@ -18,6 +18,7 @@ app = QtGui.QApplication([]) ## Create main window with a grid layout inside win = QtGui.QMainWindow() +win.setWindowTitle('pyqtgraph example: FlowchartCustomNode') cw = QtGui.QWidget() win.setCentralWidget(cw) layout = QtGui.QGridLayout() diff --git a/examples/GLImageItem.py b/examples/GLImageItem.py index 1d8faa3f..8b52ac09 100644 --- a/examples/GLImageItem.py +++ b/examples/GLImageItem.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" +Use GLImageItem to display image data on rectangular planes. + +In this example, the image data is sampled from a volume and the image planes +placed as if they slice through the volume. +""" ## Add path to library (just for examples; you do not need this) import initExample @@ -12,6 +18,7 @@ app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 200 w.show() +w.setWindowTitle('pyqtgraph example: GLImageItem') ## create volume data set to slice three images from shape = (100,100,70) diff --git a/examples/GLIsosurface.py b/examples/GLIsosurface.py index 97fc4874..a9403ffb 100644 --- a/examples/GLIsosurface.py +++ b/examples/GLIsosurface.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- - -## This example uses the isosurface function to convert a scalar field -## (a hydrogen orbital) into a mesh for 3D display. +""" +This example uses the isosurface function to convert a scalar field +(a hydrogen orbital) into a mesh for 3D display. +""" ## Add path to library (just for examples; you do not need this) import initExample @@ -13,6 +14,7 @@ import pyqtgraph.opengl as gl app = QtGui.QApplication([]) w = gl.GLViewWidget() w.show() +w.setWindowTitle('pyqtgraph example: GLIsosurface') w.setCameraPosition(distance=40) diff --git a/examples/GLLinePlotItem.py b/examples/GLLinePlotItem.py index 2194a51f..ab2fd75b 100644 --- a/examples/GLLinePlotItem.py +++ b/examples/GLLinePlotItem.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +Demonstrate use of GLLinePlotItem to draw cross-sections of a surface. + +""" ## Add path to library (just for examples; you do not need this) import initExample @@ -11,6 +15,7 @@ app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 40 w.show() +w.setWindowTitle('pyqtgraph example: GLLinePlotItem') gx = gl.GLGridItem() gx.rotate(90, 0, 1, 0) diff --git a/examples/GLMeshItem.py b/examples/GLMeshItem.py index 49923913..9056fbd6 100644 --- a/examples/GLMeshItem.py +++ b/examples/GLMeshItem.py @@ -14,7 +14,7 @@ import pyqtgraph.opengl as gl app = QtGui.QApplication([]) w = gl.GLViewWidget() w.show() - +w.setWindowTitle('pyqtgraph example: GLMeshItem') w.setCameraPosition(distance=40) g = gl.GLGridItem() diff --git a/examples/GLScatterPlotItem.py b/examples/GLScatterPlotItem.py index 2d25ae12..53a9a752 100644 --- a/examples/GLScatterPlotItem.py +++ b/examples/GLScatterPlotItem.py @@ -1,4 +1,9 @@ # -*- coding: utf-8 -*- +""" +Demonstrates use of GLScatterPlotItem with rapidly-updating plots. + +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -10,6 +15,7 @@ app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 20 w.show() +w.setWindowTitle('pyqtgraph example: GLScatterPlotItem') g = gl.GLGridItem() w.addItem(g) diff --git a/examples/GLSurfacePlot.py b/examples/GLSurfacePlot.py index d2151c46..963cf4cf 100644 --- a/examples/GLSurfacePlot.py +++ b/examples/GLSurfacePlot.py @@ -17,6 +17,7 @@ import numpy as np app = QtGui.QApplication([]) w = gl.GLViewWidget() w.show() +w.setWindowTitle('pyqtgraph example: GLSurfacePlot') w.setCameraPosition(distance=50) ## Add a grid to the view diff --git a/examples/GLViewWidget.py b/examples/GLViewWidget.py index 4989e8a2..a5207838 100644 --- a/examples/GLViewWidget.py +++ b/examples/GLViewWidget.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +Very basic 3D graphics example; create a view widget and add a few items. + +""" ## Add path to library (just for examples; you do not need this) import initExample @@ -9,6 +13,7 @@ app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 20 w.show() +w.setWindowTitle('pyqtgraph example: GLViewWidget') ax = gl.GLAxisItem() ax.setSize(5,5,5) diff --git a/examples/GLVolumeItem.py b/examples/GLVolumeItem.py index d11730a5..ca20b127 100644 --- a/examples/GLVolumeItem.py +++ b/examples/GLVolumeItem.py @@ -1,4 +1,9 @@ # -*- coding: utf-8 -*- +""" +Demonstrates GLVolumeItem for displaying volumetric data. + +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -9,7 +14,7 @@ app = QtGui.QApplication([]) w = gl.GLViewWidget() w.opts['distance'] = 200 w.show() - +w.setWindowTitle('pyqtgraph example: GLVolumeItem') #b = gl.GLBoxItem() #w.addItem(b) diff --git a/examples/GLshaders.py b/examples/GLshaders.py index d9d6f00c..ce00fc7a 100644 --- a/examples/GLshaders.py +++ b/examples/GLshaders.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- """ -Demonstration of some of the shader programs included with pyqtgraph. +Demonstration of some of the shader programs included with pyqtgraph that can be +used to affect the appearance of a surface. """ @@ -15,7 +16,7 @@ import pyqtgraph.opengl as gl app = QtGui.QApplication([]) w = gl.GLViewWidget() w.show() - +w.setWindowTitle('pyqtgraph example: GL Shaders') w.setCameraPosition(distance=15, azimuth=-90) g = gl.GLGridItem() diff --git a/examples/GradientWidget.py b/examples/GradientWidget.py index 1a6458ce..ef7d0fa6 100644 --- a/examples/GradientWidget.py +++ b/examples/GradientWidget.py @@ -1,4 +1,9 @@ # -*- coding: utf-8 -*- +""" +Demonstrates the appearance / interactivity of GradientWidget +(without actually doing anything useful with it) + +""" import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg @@ -10,6 +15,7 @@ import numpy as np app = QtGui.QApplication([]) w = QtGui.QMainWindow() w.show() +w.setWindowTitle('pyqtgraph example: GradientWidget') w.resize(400,400) cw = QtGui.QWidget() w.setCentralWidget(cw) diff --git a/examples/GraphItem.py b/examples/GraphItem.py index baeaf6c4..effa6b0b 100644 --- a/examples/GraphItem.py +++ b/examples/GraphItem.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- """ -Simple example of GridItem use. +Simple example of GraphItem use. """ @@ -11,6 +11,7 @@ from pyqtgraph.Qt import QtCore, QtGui import numpy as np w = pg.GraphicsWindow() +w.setWindowTitle('pyqtgraph example: GraphItem') v = w.addViewBox() v.setAspectLocked() diff --git a/examples/GraphicsLayout.py b/examples/GraphicsLayout.py index 90e773c7..70da7e5c 100644 --- a/examples/GraphicsLayout.py +++ b/examples/GraphicsLayout.py @@ -1,3 +1,10 @@ +""" +Demonstrate the use of layouts to control placement of multiple plots / views / +labels + + +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -10,6 +17,7 @@ view = pg.GraphicsView() l = pg.GraphicsLayout(border=(100,100,100)) view.setCentralItem(l) view.show() +view.setWindowTitle('pyqtgraph example: GraphicsLayout') view.resize(800,600) ## Title at top diff --git a/examples/HistogramLUT.py b/examples/HistogramLUT.py index 9f606457..5d66cb5d 100644 --- a/examples/HistogramLUT.py +++ b/examples/HistogramLUT.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +Use a HistogramLUTWidget to control the contrast / coloration of an image. +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -12,6 +16,7 @@ app = QtGui.QApplication([]) win = QtGui.QMainWindow() win.resize(800,600) win.show() +win.setWindowTitle('pyqtgraph example: Histogram LUT') cw = QtGui.QWidget() win.setCentralWidget(cw) diff --git a/examples/ImageItem.py b/examples/ImageItem.py index 4e40f56e..a2dc7af3 100644 --- a/examples/ImageItem.py +++ b/examples/ImageItem.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +Demonstrates very basic use of ImageItem to display image data inside a ViewBox. +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -10,19 +14,17 @@ import pyqtgraph.ptime as ptime app = QtGui.QApplication([]) ## Create window with GraphicsView widget -view = pg.GraphicsView() -view.show() ## show view alone in its own window - -## Allow mouse scale/pan. Normally we use a ViewBox for this, but -## for simple examples this is easier. -view.enableMouse() +win = pg.GraphicsLayoutWidget() +win.show() ## show widget alone in its own window +win.setWindowTitle('pyqtgraph example: ImageItem') +view = win.addViewBox() ## lock the aspect ratio so pixels are always square view.setAspectLocked(True) ## Create image item img = pg.ImageItem(border='w') -view.scene().addItem(img) +view.addItem(img) ## Set initial view bounds view.setRange(QtCore.QRectF(0, 0, 600, 600)) diff --git a/examples/ImageView.py b/examples/ImageView.py index f11ce0f7..d0bbd31b 100644 --- a/examples/ImageView.py +++ b/examples/ImageView.py @@ -26,6 +26,7 @@ win.resize(800,800) imv = pg.ImageView() win.setCentralWidget(imv) win.show() +win.setWindowTitle('pyqtgraph example: ImageView') ## Create random 3D data set with noisy signals img = scipy.ndimage.gaussian_filter(np.random.normal(size=(200, 200)), (5, 5)) * 20 + 100 diff --git a/examples/JoystickButton.py b/examples/JoystickButton.py index 49d310a0..03c79706 100644 --- a/examples/JoystickButton.py +++ b/examples/JoystickButton.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- """ -JoystickButton is a button with x/y values. When the button is depressed and the mouse dragged, the x/y values change to follow the mouse. -When the mouse button is released, the x/y values change to 0,0 (rather like litting go of the joystick). +JoystickButton is a button with x/y values. When the button is depressed and the +mouse dragged, the x/y values change to follow the mouse. +When the mouse button is released, the x/y values change to 0,0 (rather like +letting go of the joystick). """ import initExample ## Add path to library (just for examples; you do not need this) @@ -13,6 +15,7 @@ import pyqtgraph as pg app = QtGui.QApplication([]) mw = QtGui.QMainWindow() mw.resize(300,50) +mw.setWindowTitle('pyqtgraph example: JoystickButton') cw = QtGui.QWidget() mw.setCentralWidget(cw) layout = QtGui.QGridLayout() diff --git a/examples/Legend.py b/examples/Legend.py index 3d6d5730..2cd982ea 100644 --- a/examples/Legend.py +++ b/examples/Legend.py @@ -1,11 +1,15 @@ # -*- coding: utf-8 -*- +""" +Demonstrates basic use of LegendItem + +""" import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui plt = pg.plot() - +plt.setWindowTitle('pyqtgraph example: Legend') plt.addLegend() #l = pg.LegendItem((100,60), offset=(70,30)) # args are (size, offset) #l.setParentItem(plt.graphicsItem()) # Note we do NOT call plt.addItem in this case diff --git a/examples/LogPlotTest.py b/examples/LogPlotTest.py index a5b07520..d408a2b4 100644 --- a/examples/LogPlotTest.py +++ b/examples/LogPlotTest.py @@ -1,9 +1,7 @@ # -*- coding: utf-8 -*- - -## This example demonstrates many of the 2D plotting capabilities -## in pyqtgraph. All of the plots may be panned/scaled by dragging with -## the left/right mouse buttons. Right click on any plot to show a context menu. - +""" +Simple logarithmic plotting test +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -12,14 +10,11 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg -#QtGui.QApplication.setGraphicsSystem('raster') app = QtGui.QApplication([]) -#mw = QtGui.QMainWindow() -#mw.resize(800,800) win = pg.GraphicsWindow(title="Basic plotting examples") win.resize(1000,600) - +win.setWindowTitle('pyqtgraph example: LogPlotTest') p5 = win.addPlot(title="Scatter plot, axis labels, log scale") diff --git a/examples/MultiPlotSpeedTest.py b/examples/MultiPlotSpeedTest.py index e25de42e..e38c90e2 100644 --- a/examples/MultiPlotSpeedTest.py +++ b/examples/MultiPlotSpeedTest.py @@ -1,5 +1,9 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +""" +Test the speed of rapidly updating multiple plot curves +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -14,6 +18,7 @@ app = QtGui.QApplication([]) #mw.resize(800,800) p = pg.plot() +p.setWindowTitle('pyqtgraph example: MultiPlotSpeedTest') #p.setRange(QtCore.QRectF(0, -10, 5000, 20)) p.setLabel('bottom', 'Index', units='B') diff --git a/examples/PlotAutoRange.py b/examples/PlotAutoRange.py index 3c25b193..46aa3a44 100644 --- a/examples/PlotAutoRange.py +++ b/examples/PlotAutoRange.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- -## This example demonstrates the different auto-ranging capabilities of ViewBoxes - +""" +This example demonstrates the different auto-ranging capabilities of ViewBoxes +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -17,7 +18,7 @@ app = QtGui.QApplication([]) win = pg.GraphicsWindow(title="Plot auto-range examples") win.resize(800,600) - +win.setWindowTitle('pyqtgraph example: PlotAutoRange') d = np.random.normal(size=100) d[50:54] += 10 diff --git a/examples/PlotSpeedTest.py b/examples/PlotSpeedTest.py index cb200429..03c9537f 100644 --- a/examples/PlotSpeedTest.py +++ b/examples/PlotSpeedTest.py @@ -1,5 +1,9 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +""" +Update a simple plot as rapidly as possible to measure speed. +""" + ## Add path to library (just for examples; you do not need this) import initExample @@ -8,12 +12,10 @@ from pyqtgraph.Qt import QtGui, QtCore import numpy as np import pyqtgraph as pg from pyqtgraph.ptime import time -#QtGui.QApplication.setGraphicsSystem('raster') app = QtGui.QApplication([]) -#mw = QtGui.QMainWindow() -#mw.resize(800,800) p = pg.plot() +p.setWindowTitle('pyqtgraph example: PlotSpeedTest') p.setRange(QtCore.QRectF(0, -10, 5000, 20)) p.setLabel('bottom', 'Index', units='B') curve = p.plot() diff --git a/examples/PlotWidget.py b/examples/PlotWidget.py index 2aa118f2..88236ba0 100644 --- a/examples/PlotWidget.py +++ b/examples/PlotWidget.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" +Demonstrates use of PlotWidget class. This is little more than a +GraphicsView with a PlotItem placed in its center. +""" + + import initExample ## Add path to library (just for examples; you do not need this) @@ -9,6 +15,7 @@ import pyqtgraph as pg #QtGui.QApplication.setGraphicsSystem('raster') app = QtGui.QApplication([]) mw = QtGui.QMainWindow() +mw.setWindowTitle('pyqtgraph example: PlotWidget') mw.resize(800,800) cw = QtGui.QWidget() mw.setCentralWidget(cw) diff --git a/examples/Plotting.py b/examples/Plotting.py index 7842ad3d..6a3a1d11 100644 --- a/examples/Plotting.py +++ b/examples/Plotting.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- - -## This example demonstrates many of the 2D plotting capabilities -## in pyqtgraph. All of the plots may be panned/scaled by dragging with -## the left/right mouse buttons. Right click on any plot to show a context menu. - +""" +This example demonstrates many of the 2D plotting capabilities +in pyqtgraph. All of the plots may be panned/scaled by dragging with +the left/right mouse buttons. Right click on any plot to show a context menu. +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -19,6 +19,7 @@ app = QtGui.QApplication([]) win = pg.GraphicsWindow(title="Basic plotting examples") win.resize(1000,600) +win.setWindowTitle('pyqtgraph example: Plotting') diff --git a/examples/ROIExamples.py b/examples/ROIExamples.py index d8ad3dd0..56d6b13c 100644 --- a/examples/ROIExamples.py +++ b/examples/ROIExamples.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" +Demonstrates a variety of uses for ROI. This class provides a user-adjustable +region of interest marker. It is possible to customize the layout and +function of the scale/rotate handles in very flexible ways. +""" + import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg @@ -22,6 +28,7 @@ arr += np.random.normal(size=(100,100)) ## create GUI app = QtGui.QApplication([]) w = pg.GraphicsWindow(size=(800,800), border=True) +w.setWindowTitle('pyqtgraph example: ROI Examples') text = """Data Selection From Image.
\n Drag an ROI or its handles to update the selected image.
diff --git a/examples/RemoteGraphicsView.py b/examples/RemoteGraphicsView.py index 137b5e87..5b4e7ef4 100644 --- a/examples/RemoteGraphicsView.py +++ b/examples/RemoteGraphicsView.py @@ -1,18 +1,25 @@ # -*- coding: utf-8 -*- +""" +Very simple example demonstrating RemoteGraphicsView +""" import initExample ## Add path to library (just for examples; you do not need this) from pyqtgraph.Qt import QtGui, QtCore import pyqtgraph as pg +from pyqtgraph.widgets.RemoteGraphicsView import RemoteGraphicsView app = pg.mkQApp() -v = pg.RemoteGraphicsView() +v = RemoteGraphicsView() v.show() +v.setWindowTitle('pyqtgraph example: RemoteGraphicsView') +## v.pg is a proxy to the remote process' pyqtgraph module. All attribute +## requests and function calls made with this object are forwarded to the +## remote process and executed there. plt = v.pg.PlotItem() v.setCentralItem(plt) plt.plot([1,4,2,3,6,2,3,4,2,3], pen='g') - ## Start Qt event loop unless running in interactive mode or using pyside. if __name__ == '__main__': import sys diff --git a/examples/RemoteSpeedTest.py b/examples/RemoteSpeedTest.py index b3415a9d..03b4430b 100644 --- a/examples/RemoteSpeedTest.py +++ b/examples/RemoteSpeedTest.py @@ -22,6 +22,7 @@ app = pg.mkQApp() view = pg.widgets.RemoteGraphicsView.RemoteGraphicsView() pg.setConfigOptions(antialias=True) ## this will be expensive for the local plot view.pg.setConfigOptions(antialias=True) ## prettier plots at no cost to the main process! +view.setWindowTitle('pyqtgraph example: RemoteSpeedTest') label = QtGui.QLabel() rcheck = QtGui.QCheckBox('plot remote') diff --git a/examples/ScatterPlot.py b/examples/ScatterPlot.py index e72e2631..805cf09f 100644 --- a/examples/ScatterPlot.py +++ b/examples/ScatterPlot.py @@ -1,4 +1,10 @@ # -*- coding: utf-8 -*- +""" +Example demonstrating a variety of scatter plot features. +""" + + + ## Add path to library (just for examples; you do not need this) import initExample @@ -12,6 +18,7 @@ mw.resize(800,800) view = pg.GraphicsLayoutWidget() ## GraphicsView with GraphicsLayout inserted by default mw.setCentralWidget(view) mw.show() +mw.setWindowTitle('pyqtgraph example: ScatterPlot') ## create four areas to add plots w1 = view.addPlot() diff --git a/examples/ScatterPlotSpeedTest.py b/examples/ScatterPlotSpeedTest.py index 545071b1..b79c6641 100644 --- a/examples/ScatterPlotSpeedTest.py +++ b/examples/ScatterPlotSpeedTest.py @@ -1,5 +1,13 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +""" +For testing rapid updates of ScatterPlotItem under various conditions. + +(Scatter plots are still rather slow to draw; expect about 20fps) +""" + + + ## Add path to library (just for examples; you do not need this) import initExample @@ -18,6 +26,7 @@ else: from ScatterPlotSpeedTestTemplate_pyqt import Ui_Form win = QtGui.QWidget() +win.setWindowTitle('pyqtgraph example: ScatterPlotSpeedTest') ui = Ui_Form() ui.setupUi(win) win.show() diff --git a/examples/SpinBox.py b/examples/SpinBox.py index 488e995b..ef20e757 100644 --- a/examples/SpinBox.py +++ b/examples/SpinBox.py @@ -1,4 +1,13 @@ # -*- coding: utf-8 -*- +""" +This example demonstrates the SpinBox widget, which is an extension of +QDoubleSpinBox providing some advanced features: + + * SI-prefixed units + * Non-linear stepping modes + * Bounded/unbounded values + +""" import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg @@ -20,6 +29,7 @@ spins = [ win = QtGui.QMainWindow() +win.setWindowTitle('pyqtgraph example: SpinBox') cw = QtGui.QWidget() layout = QtGui.QGridLayout() cw.setLayout(layout) diff --git a/examples/TableWidget.py b/examples/TableWidget.py new file mode 100644 index 00000000..cfeac399 --- /dev/null +++ b/examples/TableWidget.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +""" +Simple demonstration of TableWidget, which is an extension of QTableWidget +that automatically displays a variety of tabluar data formats. +""" +import initExample ## Add path to library (just for examples; you do not need this) + +import pyqtgraph as pg +from pyqtgraph.Qt import QtCore, QtGui +import numpy as np + +app = QtGui.QApplication([]) + +w = pg.TableWidget() +w.show() +w.resize(500,500) +w.setWindowTitle('pyqtgraph example: TableWidget') + + +data = np.array([ + (1, 1.6, 'x'), + (3, 5.4, 'y'), + (8, 12.5, 'z'), + (443, 1e-12, 'w'), + ], dtype=[('Column 1', int), ('Column 2', float), ('Column 3', object)]) + +w.setData(data) + + +## Start Qt event loop unless running in interactive mode or using pyside. +if __name__ == '__main__': + import sys + if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + QtGui.QApplication.instance().exec_() diff --git a/examples/TreeWidget.py b/examples/TreeWidget.py index 80e9bd24..b1ad3847 100644 --- a/examples/TreeWidget.py +++ b/examples/TreeWidget.py @@ -1,4 +1,8 @@ # -*- coding: utf-8 -*- +""" +Simple demonstration of TreeWidget, which is an extension of QTreeWidget +that allows widgets to be added and dragged within the tree more easily. +""" import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg @@ -11,6 +15,7 @@ app = QtGui.QApplication([]) w = pg.TreeWidget() w.setColumnCount(2) w.show() +w.setWindowTitle('pyqtgraph example: TreeWidget') i1 = QtGui.QTreeWidgetItem(["Item 1"]) i11 = QtGui.QTreeWidgetItem(["Item 1.1"]) diff --git a/examples/VideoSpeedTest.py b/examples/VideoSpeedTest.py index 1d0fa58c..dd392189 100644 --- a/examples/VideoSpeedTest.py +++ b/examples/VideoSpeedTest.py @@ -29,6 +29,7 @@ app = QtGui.QApplication([]) #mw.resize(800,800) win = QtGui.QMainWindow() +win.setWindowTitle('pyqtgraph example: VideoSpeedTest') ui = VideoTemplate.Ui_MainWindow() ui.setupUi(win) win.show() diff --git a/examples/ViewBox.py b/examples/ViewBox.py index f2269176..2dcbb758 100644 --- a/examples/ViewBox.py +++ b/examples/ViewBox.py @@ -1,5 +1,14 @@ #!/usr/bin/python # -*- coding: utf-8 -*- +""" +ViewBox is the general-purpose graphical container that allows the user to +zoom / pan to inspect any area of a 2D coordinate system. + +This unimaginative example demonstrates the constrution of a ViewBox-based +plot area with axes, very similar to the way PlotItem is built. +""" + + ## Add path to library (just for examples; you do not need this) import initExample @@ -12,29 +21,22 @@ import pyqtgraph as pg app = QtGui.QApplication([]) mw = QtGui.QMainWindow() -#cw = QtGui.QWidget() -#vl = QtGui.QVBoxLayout() -#cw.setLayout(vl) -#mw.setCentralWidget(cw) +mw.setWindowTitle('pyqtgraph example: ViewBox') mw.show() mw.resize(800, 600) gv = pg.GraphicsView() mw.setCentralWidget(gv) -#gv.enableMouse(False) ## Mouse interaction will be handled by the ViewBox l = QtGui.QGraphicsGridLayout() l.setHorizontalSpacing(0) l.setVerticalSpacing(0) -#vl.addWidget(gv) - vb = pg.ViewBox() -#grid = pg.GridItem() -#vb.addItem(grid) p1 = pg.PlotDataItem() vb.addItem(p1) +## Just something to play with inside the ViewBox class movableRect(QtGui.QGraphicsRectItem): def __init__(self, *args): QtGui.QGraphicsRectItem.__init__(self, *args) @@ -55,8 +57,6 @@ class movableRect(QtGui.QGraphicsRectItem): def mouseMoveEvent(self, ev): self.setPos(self.mapToParent(ev.pos()) - self.pressDelta) - -#rect = QtGui.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 1)) rect = movableRect(QtCore.QRectF(0, 0, 1, 1)) rect.setPen(QtGui.QPen(QtGui.QColor(100, 200, 100))) vb.addItem(rect) diff --git a/examples/__main__.py b/examples/__main__.py index 096edba0..c46d7065 100644 --- a/examples/__main__.py +++ b/examples/__main__.py @@ -22,6 +22,7 @@ examples = OrderedDict([ ('Dock widgets', 'dockarea.py'), ('Console', 'ConsoleWidget.py'), ('Histograms', 'histogram.py'), + ('Auto-range', 'PlotAutoRange.py'), ('Remote Plotting', 'RemoteSpeedTest.py'), ('GraphicsItems', OrderedDict([ ('Scatter Plot', 'ScatterPlot.py'), @@ -38,6 +39,7 @@ examples = OrderedDict([ ('Linked Views', 'linkedViews.py'), ('Arrow', 'Arrow.py'), ('ViewBox', 'ViewBox.py'), + ('Custom Graphics', 'customGraphicsItem.py'), ])), ('Benchmarks', OrderedDict([ ('Video speed test', 'VideoSpeedTest.py'), @@ -58,17 +60,18 @@ examples = OrderedDict([ ('PlotWidget', 'PlotWidget.py'), ('SpinBox', 'SpinBox.py'), ('ConsoleWidget', 'ConsoleWidget.py'), + ('Histogram / lookup table', 'HistogramLUT.py'), ('TreeWidget', 'TreeWidget.py'), ('DataTreeWidget', 'DataTreeWidget.py'), ('GradientWidget', 'GradientWidget.py'), - #('TableWidget', '../widgets/TableWidget.py'), + ('TableWidget', 'TableWidget.py'), ('ColorButton', 'ColorButton.py'), #('CheckTable', '../widgets/CheckTable.py'), #('VerticalLabel', '../widgets/VerticalLabel.py'), ('JoystickButton', 'JoystickButton.py'), ])), - ('GraphicsScene', 'GraphicsScene.py'), + #('GraphicsScene', 'GraphicsScene.py'), ('Flowcharts', 'Flowchart.py'), ('Custom Flowchart Nodes', 'FlowchartCustomNode.py'), #('Canvas', '../canvas'), @@ -85,7 +88,15 @@ class ExampleLoader(QtGui.QMainWindow): self.setCentralWidget(self.cw) self.ui.setupUi(self.cw) + self.codeBtn = QtGui.QPushButton('Run Edited Code') + self.codeLayout = QtGui.QGridLayout() + self.ui.codeView.setLayout(self.codeLayout) + self.codeLayout.addItem(QtGui.QSpacerItem(100,100,QtGui.QSizePolicy.Expanding,QtGui.QSizePolicy.Expanding), 0, 0) + self.codeLayout.addWidget(self.codeBtn, 1, 1) + self.codeBtn.hide() + global examples + self.itemCache = [] self.populateTree(self.ui.exampleTree.invisibleRootItem(), examples) self.ui.exampleTree.expandAll() @@ -97,6 +108,8 @@ class ExampleLoader(QtGui.QMainWindow): self.ui.exampleTree.itemDoubleClicked.connect(self.loadFile) self.ui.pyqtCheck.toggled.connect(self.pyqtToggled) self.ui.pysideCheck.toggled.connect(self.pysideToggled) + self.ui.codeView.textChanged.connect(self.codeEdited) + self.codeBtn.clicked.connect(self.runEditedCode) def pyqtToggled(self, b): if b: @@ -110,6 +123,9 @@ class ExampleLoader(QtGui.QMainWindow): def populateTree(self, root, examples): for key, val in examples.items(): item = QtGui.QTreeWidgetItem([key]) + self.itemCache.append(item) # PyQt 4.9.6 no longer keeps references to these wrappers, + # so we need to make an explicit reference or else the .file + # attribute will disappear. if isinstance(val, basestring): item.file = val else: @@ -124,8 +140,8 @@ class ExampleLoader(QtGui.QMainWindow): return os.path.join(path, item.file) return None - def loadFile(self): - fn = self.currentFile() + def loadFile(self, edited=False): + extra = [] if self.ui.pyqtCheck.isChecked(): extra.append('pyqt') @@ -135,13 +151,26 @@ class ExampleLoader(QtGui.QMainWindow): if self.ui.forceGraphicsCheck.isChecked(): extra.append(str(self.ui.forceGraphicsCombo.currentText())) - if fn is None: - return - if sys.platform.startswith('win'): - os.spawnl(os.P_NOWAIT, sys.executable, '"'+sys.executable+'"', '"' + fn + '"', *extra) - else: - os.spawnl(os.P_NOWAIT, sys.executable, sys.executable, fn, *extra) + #if sys.platform.startswith('win'): + #os.spawnl(os.P_NOWAIT, sys.executable, '"'+sys.executable+'"', '"' + fn + '"', *extra) + #else: + #os.spawnl(os.P_NOWAIT, sys.executable, sys.executable, fn, *extra) + + if edited: + path = os.path.abspath(os.path.dirname(__file__)) + proc = subprocess.Popen([sys.executable, '-'] + extra, stdin=subprocess.PIPE, cwd=path) + code = str(self.ui.codeView.toPlainText()).encode('UTF-8') + proc.stdin.write(code) + proc.stdin.close() + else: + fn = self.currentFile() + if fn is None: + return + if sys.platform.startswith('win'): + os.spawnl(os.P_NOWAIT, sys.executable, '"'+sys.executable+'"', '"' + fn + '"', *extra) + else: + os.spawnl(os.P_NOWAIT, sys.executable, sys.executable, fn, *extra) def showFile(self): fn = self.currentFile() @@ -152,6 +181,14 @@ class ExampleLoader(QtGui.QMainWindow): fn = os.path.join(fn, '__main__.py') text = open(fn).read() self.ui.codeView.setPlainText(text) + self.ui.loadedFileLabel.setText(fn) + self.codeBtn.hide() + + def codeEdited(self): + self.codeBtn.show() + + def runEditedCode(self): + self.loadFile(edited=True) def run(): app = QtGui.QApplication([]) @@ -202,9 +239,13 @@ except: """ % (import1, graphicsSystem, import2) - 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() + if sys.platform.startswith('win'): + process = subprocess.Popen([exe], stdin=subprocess.PIPE, stderr=subprocess.PIPE, stdout=subprocess.PIPE) + process.stdin.write(code.encode('UTF-8')) + process.stdin.close() + else: + 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')) output = '' fail = False while True: diff --git a/examples/crosshair.py b/examples/crosshair.py index a99f097b..c41dfff1 100644 --- a/examples/crosshair.py +++ b/examples/crosshair.py @@ -1,3 +1,10 @@ +""" +Demonstrates some customized mouse interaction by drawing a crosshair that follows +the mouse. + + +""" + import initExample ## Add path to library (just for examples; you do not need this) import numpy as np import scipy.ndimage as ndi @@ -5,9 +12,10 @@ import pyqtgraph as pg from pyqtgraph.Qt import QtGui, QtCore from pyqtgraph.Point import Point -#genearte layout +#generate layout app = QtGui.QApplication([]) win = pg.GraphicsWindow() +win.setWindowTitle('pyqtgraph example: crosshair') label = pg.LabelItem(justify='right') win.addItem(label) p1 = win.addPlot(row=1, col=0) diff --git a/examples/customGraphicsItem.py b/examples/customGraphicsItem.py index 263ce0c5..9723b83a 100644 --- a/examples/customGraphicsItem.py +++ b/examples/customGraphicsItem.py @@ -1,6 +1,15 @@ +""" +Demonstrate creation of a custom graphic (a candlestick plot) + +""" +import initExample ## Add path to library (just for examples; you do not need this) + import pyqtgraph as pg from pyqtgraph import QtCore, QtGui +## Create a subclass of GraphicsObject. +## The only required methods are paint() and boundingRect() +## (see QGraphicsItem documentation) class CandlestickItem(pg.GraphicsObject): def __init__(self, data): pg.GraphicsObject.__init__(self) @@ -8,6 +17,8 @@ class CandlestickItem(pg.GraphicsObject): self.generatePicture() def generatePicture(self): + ## pre-computing a QPicture object allows paint() to run much more quickly, + ## rather than re-drawing the shapes every time. self.picture = QtGui.QPicture() p = QtGui.QPainter(self.picture) p.setPen(pg.mkPen('w')) @@ -25,6 +36,9 @@ class CandlestickItem(pg.GraphicsObject): p.drawPicture(0, 0, self.picture) def boundingRect(self): + ## boundingRect _must_ indicate the entire area that will be drawn on + ## or else we will get artifacts and possibly crashing. + ## (in this case, QPicture does all the work of computing the bouning rect for us) return QtCore.QRectF(self.picture.boundingRect()) data = [ ## fields are (time, open, close, min, max). @@ -38,5 +52,10 @@ data = [ ## fields are (time, open, close, min, max). item = CandlestickItem(data) plt = pg.plot() plt.addItem(item) +plt.setWindowTitle('pyqtgraph example: customGraphicsItem') -QtGui.QApplication.exec_() \ No newline at end of file +## Start Qt event loop unless running in interactive mode or using pyside. +if __name__ == '__main__': + import sys + if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'): + QtGui.QApplication.instance().exec_() diff --git a/examples/customPlot.py b/examples/customPlot.py index 1c3b2489..b523fd17 100644 --- a/examples/customPlot.py +++ b/examples/customPlot.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -## -## This example demonstrates the creation of a plot with a customized -## AxisItem and ViewBox. -## +""" +This example demonstrates the creation of a plot with a customized +AxisItem and ViewBox. +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -72,6 +72,7 @@ pw = pg.PlotWidget(viewBox=vb, axisItems={'bottom': axis}, enableMenu=False, tit dates = np.arange(8) * (3600*24*356) pw.plot(x=dates, y=[1,6,2,4,3,5,6,8], symbol='o') pw.show() +pw.setWindowTitle('pyqtgraph example: customPlot') r = pg.PolyLineROI([(0,0), (10, 10)]) pw.addItem(r) diff --git a/examples/dockarea.py b/examples/dockarea.py index 8b668cf1..2b33048d 100644 --- a/examples/dockarea.py +++ b/examples/dockarea.py @@ -29,6 +29,7 @@ win = QtGui.QMainWindow() area = DockArea() win.setCentralWidget(area) win.resize(1000,500) +win.setWindowTitle('pyqtgraph example: dockarea') ## Create docks, place them into the window one at a time. ## Note that size arguments are only a suggestion; docks will still have to diff --git a/examples/exampleLoaderTemplate.ui b/examples/exampleLoaderTemplate.ui index cd5ce921..2da57800 100644 --- a/examples/exampleLoaderTemplate.ui +++ b/examples/exampleLoaderTemplate.ui @@ -6,8 +6,8 @@ 0 0 - 762 - 302 + 623 + 380 @@ -25,7 +25,7 @@ Qt::Horizontal - + @@ -90,19 +90,40 @@ - Load Example + Run Example - - - - Monospace - 10 - - + + + + + + + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + + FreeMono + + + + + diff --git a/examples/exampleLoaderTemplate_pyqt.py b/examples/exampleLoaderTemplate_pyqt.py index f359cc32..836640c6 100644 --- a/examples/exampleLoaderTemplate_pyqt.py +++ b/examples/exampleLoaderTemplate_pyqt.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file './examples/exampleLoaderTemplate.ui' +# Form implementation generated from reading ui file './exampleLoaderTemplate.ui' # -# Created: Mon Dec 24 00:33:38 2012 -# by: PyQt4 UI code generator 4.9.1 +# Created: Mon Feb 25 09:02:09 2013 +# by: PyQt4 UI code generator 4.9.3 # # WARNING! All changes made in this file will be lost! @@ -17,7 +17,7 @@ except AttributeError: class Ui_Form(object): def setupUi(self, Form): Form.setObjectName(_fromUtf8("Form")) - Form.resize(762, 302) + Form.resize(623, 380) self.gridLayout = QtGui.QGridLayout(Form) self.gridLayout.setMargin(0) self.gridLayout.setSpacing(0) @@ -25,46 +25,60 @@ class Ui_Form(object): self.splitter = QtGui.QSplitter(Form) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setObjectName(_fromUtf8("splitter")) - self.layoutWidget = QtGui.QWidget(self.splitter) - self.layoutWidget.setObjectName(_fromUtf8("layoutWidget")) - self.verticalLayout = QtGui.QVBoxLayout(self.layoutWidget) + self.widget = QtGui.QWidget(self.splitter) + self.widget.setObjectName(_fromUtf8("widget")) + self.verticalLayout = QtGui.QVBoxLayout(self.widget) self.verticalLayout.setMargin(0) self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) - self.exampleTree = QtGui.QTreeWidget(self.layoutWidget) + self.exampleTree = QtGui.QTreeWidget(self.widget) self.exampleTree.setObjectName(_fromUtf8("exampleTree")) self.exampleTree.headerItem().setText(0, _fromUtf8("1")) self.exampleTree.header().setVisible(False) self.verticalLayout.addWidget(self.exampleTree) self.horizontalLayout = QtGui.QHBoxLayout() self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) - self.pyqtCheck = QtGui.QCheckBox(self.layoutWidget) + self.pyqtCheck = QtGui.QCheckBox(self.widget) self.pyqtCheck.setObjectName(_fromUtf8("pyqtCheck")) self.horizontalLayout.addWidget(self.pyqtCheck) - self.pysideCheck = QtGui.QCheckBox(self.layoutWidget) + self.pysideCheck = QtGui.QCheckBox(self.widget) self.pysideCheck.setObjectName(_fromUtf8("pysideCheck")) self.horizontalLayout.addWidget(self.pysideCheck) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_2 = QtGui.QHBoxLayout() self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2")) - self.forceGraphicsCheck = QtGui.QCheckBox(self.layoutWidget) + self.forceGraphicsCheck = QtGui.QCheckBox(self.widget) self.forceGraphicsCheck.setObjectName(_fromUtf8("forceGraphicsCheck")) self.horizontalLayout_2.addWidget(self.forceGraphicsCheck) - self.forceGraphicsCombo = QtGui.QComboBox(self.layoutWidget) + self.forceGraphicsCombo = QtGui.QComboBox(self.widget) self.forceGraphicsCombo.setObjectName(_fromUtf8("forceGraphicsCombo")) self.forceGraphicsCombo.addItem(_fromUtf8("")) self.forceGraphicsCombo.addItem(_fromUtf8("")) self.forceGraphicsCombo.addItem(_fromUtf8("")) self.horizontalLayout_2.addWidget(self.forceGraphicsCombo) self.verticalLayout.addLayout(self.horizontalLayout_2) - self.loadBtn = QtGui.QPushButton(self.layoutWidget) + self.loadBtn = QtGui.QPushButton(self.widget) self.loadBtn.setObjectName(_fromUtf8("loadBtn")) self.verticalLayout.addWidget(self.loadBtn) - self.codeView = QtGui.QTextBrowser(self.splitter) + self.widget1 = QtGui.QWidget(self.splitter) + self.widget1.setObjectName(_fromUtf8("widget1")) + self.verticalLayout_2 = QtGui.QVBoxLayout(self.widget1) + self.verticalLayout_2.setMargin(0) + self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) + self.loadedFileLabel = QtGui.QLabel(self.widget1) font = QtGui.QFont() - font.setFamily(_fromUtf8("Monospace")) - font.setPointSize(10) + font.setBold(True) + font.setWeight(75) + self.loadedFileLabel.setFont(font) + self.loadedFileLabel.setText(_fromUtf8("")) + self.loadedFileLabel.setAlignment(QtCore.Qt.AlignCenter) + self.loadedFileLabel.setObjectName(_fromUtf8("loadedFileLabel")) + self.verticalLayout_2.addWidget(self.loadedFileLabel) + self.codeView = QtGui.QPlainTextEdit(self.widget1) + font = QtGui.QFont() + font.setFamily(_fromUtf8("FreeMono")) self.codeView.setFont(font) self.codeView.setObjectName(_fromUtf8("codeView")) + self.verticalLayout_2.addWidget(self.codeView) self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) self.retranslateUi(Form) @@ -78,5 +92,5 @@ class Ui_Form(object): self.forceGraphicsCombo.setItemText(0, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8)) self.forceGraphicsCombo.setItemText(1, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8)) self.forceGraphicsCombo.setItemText(2, QtGui.QApplication.translate("Form", "opengl", None, QtGui.QApplication.UnicodeUTF8)) - self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load Example", None, QtGui.QApplication.UnicodeUTF8)) + self.loadBtn.setText(QtGui.QApplication.translate("Form", "Run Example", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/examples/exampleLoaderTemplate_pyside.py b/examples/exampleLoaderTemplate_pyside.py index 113c1654..f596e566 100644 --- a/examples/exampleLoaderTemplate_pyside.py +++ b/examples/exampleLoaderTemplate_pyside.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -# Form implementation generated from reading ui file './examples/exampleLoaderTemplate.ui' +# Form implementation generated from reading ui file './exampleLoaderTemplate.ui' # -# Created: Mon Dec 24 00:33:39 2012 -# by: pyside-uic 0.2.13 running on PySide 1.1.2 +# Created: Mon Feb 25 09:02:09 2013 +# by: pyside-uic 0.2.13 running on PySide 1.1.1 # # WARNING! All changes made in this file will be lost! @@ -12,7 +12,7 @@ from PySide import QtCore, QtGui class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") - Form.resize(762, 302) + Form.resize(623, 380) self.gridLayout = QtGui.QGridLayout(Form) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setSpacing(0) @@ -20,46 +20,60 @@ class Ui_Form(object): self.splitter = QtGui.QSplitter(Form) self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setObjectName("splitter") - self.layoutWidget = QtGui.QWidget(self.splitter) - self.layoutWidget.setObjectName("layoutWidget") - self.verticalLayout = QtGui.QVBoxLayout(self.layoutWidget) + self.widget = QtGui.QWidget(self.splitter) + self.widget.setObjectName("widget") + self.verticalLayout = QtGui.QVBoxLayout(self.widget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") - self.exampleTree = QtGui.QTreeWidget(self.layoutWidget) + self.exampleTree = QtGui.QTreeWidget(self.widget) self.exampleTree.setObjectName("exampleTree") self.exampleTree.headerItem().setText(0, "1") self.exampleTree.header().setVisible(False) self.verticalLayout.addWidget(self.exampleTree) self.horizontalLayout = QtGui.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") - self.pyqtCheck = QtGui.QCheckBox(self.layoutWidget) + self.pyqtCheck = QtGui.QCheckBox(self.widget) self.pyqtCheck.setObjectName("pyqtCheck") self.horizontalLayout.addWidget(self.pyqtCheck) - self.pysideCheck = QtGui.QCheckBox(self.layoutWidget) + self.pysideCheck = QtGui.QCheckBox(self.widget) self.pysideCheck.setObjectName("pysideCheck") self.horizontalLayout.addWidget(self.pysideCheck) self.verticalLayout.addLayout(self.horizontalLayout) self.horizontalLayout_2 = QtGui.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.forceGraphicsCheck = QtGui.QCheckBox(self.layoutWidget) + self.forceGraphicsCheck = QtGui.QCheckBox(self.widget) self.forceGraphicsCheck.setObjectName("forceGraphicsCheck") self.horizontalLayout_2.addWidget(self.forceGraphicsCheck) - self.forceGraphicsCombo = QtGui.QComboBox(self.layoutWidget) + self.forceGraphicsCombo = QtGui.QComboBox(self.widget) self.forceGraphicsCombo.setObjectName("forceGraphicsCombo") self.forceGraphicsCombo.addItem("") self.forceGraphicsCombo.addItem("") self.forceGraphicsCombo.addItem("") self.horizontalLayout_2.addWidget(self.forceGraphicsCombo) self.verticalLayout.addLayout(self.horizontalLayout_2) - self.loadBtn = QtGui.QPushButton(self.layoutWidget) + self.loadBtn = QtGui.QPushButton(self.widget) self.loadBtn.setObjectName("loadBtn") self.verticalLayout.addWidget(self.loadBtn) - self.codeView = QtGui.QTextBrowser(self.splitter) + self.widget1 = QtGui.QWidget(self.splitter) + self.widget1.setObjectName("widget1") + self.verticalLayout_2 = QtGui.QVBoxLayout(self.widget1) + self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.loadedFileLabel = QtGui.QLabel(self.widget1) font = QtGui.QFont() - font.setFamily("Monospace") - font.setPointSize(10) + font.setWeight(75) + font.setBold(True) + self.loadedFileLabel.setFont(font) + self.loadedFileLabel.setText("") + self.loadedFileLabel.setAlignment(QtCore.Qt.AlignCenter) + self.loadedFileLabel.setObjectName("loadedFileLabel") + self.verticalLayout_2.addWidget(self.loadedFileLabel) + self.codeView = QtGui.QPlainTextEdit(self.widget1) + font = QtGui.QFont() + font.setFamily("FreeMono") self.codeView.setFont(font) self.codeView.setObjectName("codeView") + self.verticalLayout_2.addWidget(self.codeView) self.gridLayout.addWidget(self.splitter, 0, 0, 1, 1) self.retranslateUi(Form) @@ -73,5 +87,5 @@ class Ui_Form(object): self.forceGraphicsCombo.setItemText(0, QtGui.QApplication.translate("Form", "native", None, QtGui.QApplication.UnicodeUTF8)) self.forceGraphicsCombo.setItemText(1, QtGui.QApplication.translate("Form", "raster", None, QtGui.QApplication.UnicodeUTF8)) self.forceGraphicsCombo.setItemText(2, QtGui.QApplication.translate("Form", "opengl", None, QtGui.QApplication.UnicodeUTF8)) - self.loadBtn.setText(QtGui.QApplication.translate("Form", "Load Example", None, QtGui.QApplication.UnicodeUTF8)) + self.loadBtn.setText(QtGui.QApplication.translate("Form", "Run Example", None, QtGui.QApplication.UnicodeUTF8)) diff --git a/examples/histogram.py b/examples/histogram.py index fdde7da1..057abffd 100644 --- a/examples/histogram.py +++ b/examples/histogram.py @@ -12,13 +12,14 @@ import numpy as np win = pg.GraphicsWindow() win.resize(800,350) +win.setWindowTitle('pyqtgraph example: Histogram') plt1 = win.addPlot() plt2 = win.addPlot() ## make interesting distribution of values vals = np.hstack([np.random.normal(size=500), np.random.normal(size=260, loc=4)]) -## draw standard histogram +## compute standard histogram y,x = np.histogram(vals, bins=np.linspace(-3, 8, 40)) ## notice that len(x) == len(y)+1 diff --git a/examples/initExample.py b/examples/initExample.py index 204a1ead..d8022aba 100644 --- a/examples/initExample.py +++ b/examples/initExample.py @@ -4,7 +4,10 @@ import sys, os if not hasattr(sys, 'frozen'): - path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) + if __file__ == '': + path = os.getcwd() + else: + path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) path.rstrip(os.path.sep) if 'pyqtgraph' in os.listdir(path): sys.path.insert(0, path) ## examples adjacent to pyqtgraph (as in source tree) diff --git a/examples/isocurve.py b/examples/isocurve.py index 14a3e56a..fa451063 100644 --- a/examples/isocurve.py +++ b/examples/isocurve.py @@ -22,6 +22,7 @@ data = ndi.gaussian_filter(data, (10, 10, 10))[frames/2:frames + frames/2] data[:, 15:16, 15:17] += 1 win = pg.GraphicsWindow() +win.setWindowTitle('pyqtgraph example: Isocurve') vb = win.addViewBox() img = pg.ImageItem(data[0]) vb.addItem(img) diff --git a/examples/linkedViews.py b/examples/linkedViews.py index 9d9cd7f5..e7eb18af 100644 --- a/examples/linkedViews.py +++ b/examples/linkedViews.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- - -## This example demonstrates the ability to link the axes of views together -## Views can be linked manually using the context menu, but only if they are given names. - +""" +This example demonstrates the ability to link the axes of views together +Views can be linked manually using the context menu, but only if they are given +names. +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -19,7 +20,7 @@ app = QtGui.QApplication([]) x = np.linspace(-50, 50, 1000) y = np.sin(x) / x -win = pg.GraphicsWindow(title="View Linking Examples") +win = pg.GraphicsWindow(title="pyqtgraph example: Linked Views") win.resize(800,600) win.addLabel("Linked Views", colspan=2) diff --git a/examples/logAxis.py b/examples/logAxis.py index 77ee66e5..a0c7fc53 100644 --- a/examples/logAxis.py +++ b/examples/logAxis.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- - +""" +Test programmatically setting log transformation modes. +""" import initExample ## Add path to library (just for examples; you do not need this) import numpy as np @@ -10,6 +12,7 @@ import pyqtgraph as pg app = QtGui.QApplication([]) w = pg.GraphicsWindow() +w.setWindowTitle('pyqtgraph example: logAxis') p1 = w.addPlot(0,0, title="X Semilog") p2 = w.addPlot(1,0, title="Y Semilog") p3 = w.addPlot(2,0, title="XY Log") diff --git a/examples/multiplePlotSpeedTest.py b/examples/multiplePlotSpeedTest.py index bc54bb51..cea59a35 100644 --- a/examples/multiplePlotSpeedTest.py +++ b/examples/multiplePlotSpeedTest.py @@ -39,7 +39,7 @@ def plot(): #plt.addItem(item) dt = pg.ptime.time() - start - print "Create plots took: %0.3fms" % (dt*1000) + print("Create plots took: %0.3fms" % (dt*1000)) ## Plot and clear 5 times, printing the time it took for i in range(5): @@ -72,7 +72,7 @@ def fastPlot(): plt.addItem(item) dt = pg.ptime.time() - start - print "Create plots took: %0.3fms" % (dt*1000) + print("Create plots took: %0.3fms" % (dt*1000)) ## Plot and clear 5 times, printing the time it took @@ -82,7 +82,7 @@ if hasattr(pg, 'arrayToQPath'): fastPlot() app.processEvents() else: - print "Skipping fast tests--arrayToQPath function is missing." + print("Skipping fast tests--arrayToQPath function is missing.") plt.autoRange() diff --git a/examples/parametertree.py b/examples/parametertree.py index 9bcbc5d2..4c5d7275 100644 --- a/examples/parametertree.py +++ b/examples/parametertree.py @@ -140,6 +140,7 @@ p.param('Save/Restore functionality', 'Restore State').sigActivated.connect(rest t = ParameterTree() t.setParameters(p, showTop=False) t.show() +t.setWindowTitle('pyqtgraph example: Parameter Tree') t.resize(400,800) t2 = ParameterTree() t2.setParameters(p, showTop=False) diff --git a/examples/template.py b/examples/template.py index 76b14361..1198e317 100644 --- a/examples/template.py +++ b/examples/template.py @@ -1,10 +1,18 @@ # -*- coding: utf-8 -*- +""" + +Description of example + + +""" import initExample ## Add path to library (just for examples; you do not need this) import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui import numpy as np +# win.setWindowTitle('pyqtgraph example: ____') + ## Start Qt event loop unless running in interactive mode or using pyside. if __name__ == '__main__': import sys diff --git a/examples/text.py b/examples/text.py index f9300064..23f527e3 100644 --- a/examples/text.py +++ b/examples/text.py @@ -1,6 +1,12 @@ # -*- coding: utf-8 -*- -## This example shows how to insert text into a scene using QTextItem +""" +This example shows how to insert text into a scene using TextItem. This class +is for displaying text that is anchored to a particular location in the data +coordinate system, but which is always displayed unscaled. +For text that scales with the data, use QTextItem. +For text that can be placed in a layout, use LabelItem. +""" import initExample ## Add path to library (just for examples; you do not need this) @@ -13,6 +19,7 @@ x = np.linspace(-20, 20, 1000) y = np.sin(x) / x plot = pg.plot() ## create an empty plot widget plot.setYRange(-1, 2) +plot.setWindowTitle('pyqtgraph example: text') curve = plot.plot(x,y) ## add a single curve ## Create text object, use HTML tags to specify color/size diff --git a/pyqtgraph/GraphicsScene/exportDialog.py b/pyqtgraph/GraphicsScene/exportDialog.py index 73a8c83f..436d5e42 100644 --- a/pyqtgraph/GraphicsScene/exportDialog.py +++ b/pyqtgraph/GraphicsScene/exportDialog.py @@ -34,8 +34,12 @@ class ExportDialog(QtGui.QWidget): def show(self, item=None): if item is not None: + ## Select next exportable parent of the item originally clicked on while not isinstance(item, pg.ViewBox) and not isinstance(item, pg.PlotItem) and item is not None: item = item.parentItem() + ## if this is a ViewBox inside a PlotItem, select the parent instead. + if isinstance(item, pg.ViewBox) and isinstance(item.parentItem(), pg.PlotItem): + item = item.parentItem() self.updateItemList(select=item) self.setVisible(True) self.activateWindow() diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 71880fbd..67eb712e 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -55,6 +55,7 @@ CONFIG_OPTIONS = { 'useWeave': True, ## Use weave to speed up some operations, if it is available 'weaveDebug': False, ## Print full error message if weave compile fails 'exitCleanup': True, ## Attempt to work around some exit crash bugs in PyQt and PySide + 'enableExperimental': False, ## Enable experimental features (the curious can search for this key in the code) } diff --git a/pyqtgraph/configfile.py b/pyqtgraph/configfile.py index db7dc732..f709c786 100644 --- a/pyqtgraph/configfile.py +++ b/pyqtgraph/configfile.py @@ -10,7 +10,7 @@ as it can be converted to/from a string using repr and eval. """ import re, os, sys -from pgcollections import OrderedDict +from .pgcollections import OrderedDict GLOBAL_PATH = None # so not thread safe. from . import units from .python2_3 import asUnicode @@ -199,4 +199,4 @@ key2: ##comment print("============") data = readConfigFile(fn) print(data) - os.remove(fn) \ No newline at end of file + os.remove(fn) diff --git a/pyqtgraph/exporters/CSVExporter.py b/pyqtgraph/exporters/CSVExporter.py index 629b2789..0439fc35 100644 --- a/pyqtgraph/exporters/CSVExporter.py +++ b/pyqtgraph/exporters/CSVExporter.py @@ -14,6 +14,7 @@ class CSVExporter(Exporter): Exporter.__init__(self, item) self.params = Parameter(name='params', type='group', children=[ {'name': 'separator', 'type': 'list', 'value': 'comma', 'values': ['comma', 'tab']}, + {'name': 'precision', 'type': 'int', 'value': 10, 'limits': [0, None]}, ]) def parameters(self): @@ -42,18 +43,15 @@ class CSVExporter(Exporter): fd.write(sep.join(header) + '\n') i = 0 - while True: - done = True + numFormat = '%%0.%dg' % self.params['precision'] + numRows = reduce(max, [len(d[0]) for d in data]) + for i in range(numRows): for d in data: if i < len(d[0]): - fd.write('%g%s%g%s'%(d[0][i], sep, d[1][i], sep)) - done = False + fd.write(numFormat % d[0][i] + sep + numFormat % d[1][i] + sep) else: fd.write(' %s %s' % (sep, sep)) fd.write('\n') - if done: - break - i += 1 fd.close() diff --git a/pyqtgraph/flowchart/FlowchartTemplate.ui b/pyqtgraph/flowchart/FlowchartTemplate.ui index e4530800..31b1359c 100644 --- a/pyqtgraph/flowchart/FlowchartTemplate.ui +++ b/pyqtgraph/flowchart/FlowchartTemplate.ui @@ -90,7 +90,7 @@ FlowchartGraphicsView QGraphicsView -
FlowchartGraphicsView
+
pyqtgraph.flowchart.FlowchartGraphicsView
diff --git a/pyqtgraph/flowchart/FlowchartTemplate_pyqt.py b/pyqtgraph/flowchart/FlowchartTemplate_pyqt.py index 2e9ea312..c07dd734 100644 --- a/pyqtgraph/flowchart/FlowchartTemplate_pyqt.py +++ b/pyqtgraph/flowchart/FlowchartTemplate_pyqt.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file './flowchart/FlowchartTemplate.ui' # -# Created: Sun Sep 9 14:41:29 2012 -# by: PyQt4 UI code generator 4.9.1 +# Created: Sun Feb 24 19:47:29 2013 +# by: PyQt4 UI code generator 4.9.3 # # WARNING! All changes made in this file will be lost! @@ -56,4 +56,4 @@ class Ui_Form(object): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) from pyqtgraph.widgets.DataTreeWidget import DataTreeWidget -from FlowchartGraphicsView import FlowchartGraphicsView +from pyqtgraph.flowchart.FlowchartGraphicsView import FlowchartGraphicsView diff --git a/pyqtgraph/flowchart/FlowchartTemplate_pyside.py b/pyqtgraph/flowchart/FlowchartTemplate_pyside.py index d49d3083..c73f3c00 100644 --- a/pyqtgraph/flowchart/FlowchartTemplate_pyside.py +++ b/pyqtgraph/flowchart/FlowchartTemplate_pyside.py @@ -2,8 +2,8 @@ # Form implementation generated from reading ui file './flowchart/FlowchartTemplate.ui' # -# Created: Sun Sep 9 14:41:30 2012 -# by: pyside-uic 0.2.13 running on PySide 1.1.0 +# Created: Sun Feb 24 19:47:30 2013 +# by: pyside-uic 0.2.13 running on PySide 1.1.1 # # WARNING! All changes made in this file will be lost! @@ -51,4 +51,4 @@ class Ui_Form(object): Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8)) from pyqtgraph.widgets.DataTreeWidget import DataTreeWidget -from FlowchartGraphicsView import FlowchartGraphicsView +from pyqtgraph.flowchart.FlowchartGraphicsView import FlowchartGraphicsView diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 62f69cb1..84a5c573 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -1109,10 +1109,15 @@ def arrayToQPath(x, y, connect='all'): arr.data[lastInd:lastInd+4] = struct.pack('>i', 0) #prof.mark('footer') # create datastream object and stream into path - buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here + + ## Avoiding this method because QByteArray(str) leaks memory in PySide + #buf = QtCore.QByteArray(arr.data[12:lastInd+4]) # I think one unnecessary copy happens here + + path.strn = arr.data[12:lastInd+4] # make sure data doesn't run away + buf = QtCore.QByteArray.fromRawData(path.strn) #prof.mark('create buffer') ds = QtCore.QDataStream(buf) - #prof.mark('create datastream') + ds >> path #prof.mark('load') diff --git a/pyqtgraph/graphicsItems/AxisItem.py b/pyqtgraph/graphicsItems/AxisItem.py index 9ef64763..9d1684bd 100644 --- a/pyqtgraph/graphicsItems/AxisItem.py +++ b/pyqtgraph/graphicsItems/AxisItem.py @@ -309,10 +309,18 @@ class AxisItem(GraphicsWidget): oldView.sigXRangeChanged.disconnect(self.linkedViewChanged) view.sigXRangeChanged.connect(self.linkedViewChanged) - def linkedViewChanged(self, view, newRange): + if oldView is not None: + oldView.sigResized.disconnect(self.linkedViewChanged) + view.sigResized.connect(self.linkedViewChanged) + + def linkedViewChanged(self, view, newRange=None): if self.orientation in ['right', 'left'] and view.yInverted(): + if newRange is None: + newRange = view.viewRange()[1] self.setRange(*newRange[::-1]) else: + if newRange is None: + newRange = view.viewRange()[0] self.setRange(*newRange) def boundingRect(self): diff --git a/pyqtgraph/graphicsItems/GradientEditorItem.py b/pyqtgraph/graphicsItems/GradientEditorItem.py index 5439c731..955106d8 100644 --- a/pyqtgraph/graphicsItems/GradientEditorItem.py +++ b/pyqtgraph/graphicsItems/GradientEditorItem.py @@ -782,7 +782,8 @@ class GradientEditorItem(TickSliderItem): self.sigGradientChangeFinished.emit(self) -class Tick(GraphicsObject): +class Tick(QtGui.QGraphicsObject): ## NOTE: Making this a subclass of GraphicsObject instead results in + ## activating this bug: https://bugreports.qt-project.org/browse/PYSIDE-86 ## private class sigMoving = QtCore.Signal(object) @@ -802,7 +803,7 @@ class Tick(GraphicsObject): self.pg.lineTo(QtCore.QPointF(scale/3**0.5, scale)) self.pg.closeSubpath() - GraphicsObject.__init__(self) + QtGui.QGraphicsObject.__init__(self) self.setPos(pos[0], pos[1]) if self.movable: self.setZValue(1) diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py index 35a38ae7..c5a8ec3f 100644 --- a/pyqtgraph/graphicsItems/PlotCurveItem.py +++ b/pyqtgraph/graphicsItems/PlotCurveItem.py @@ -1,4 +1,10 @@ from pyqtgraph.Qt import QtGui, QtCore +try: + from pyqtgraph.Qt import QtOpenGL + HAVE_OPENGL = True +except: + HAVE_OPENGL = False + from scipy.fftpack import fft import numpy as np import scipy.stats @@ -370,12 +376,11 @@ class PlotCurveItem(GraphicsObject): prof = debug.Profiler('PlotCurveItem.paint '+str(id(self)), disabled=True) if self.xData is None: return - #if self.opts['spectrumMode']: - #if self.specPath is None: - - #self.specPath = self.generatePath(*self.getData()) - #path = self.specPath - #else: + + if HAVE_OPENGL and pg.getConfigOption('enableExperimental') and isinstance(widget, QtOpenGL.QGLWidget): + self.paintGL(p, opt, widget) + return + x = None y = None if self.path is None: @@ -385,7 +390,6 @@ class PlotCurveItem(GraphicsObject): self.path = self.generatePath(x,y) self.fillPath = None - path = self.path prof.mark('generate path') @@ -440,6 +444,65 @@ class PlotCurveItem(GraphicsObject): #p.setPen(QtGui.QPen(QtGui.QColor(255,0,0))) #p.drawRect(self.boundingRect()) + def paintGL(self, p, opt, widget): + p.beginNativePainting() + import OpenGL.GL as gl + + ## set clipping viewport + view = self.getViewBox() + if view is not None: + rect = view.mapRectToItem(self, view.boundingRect()) + #gl.glViewport(int(rect.x()), int(rect.y()), int(rect.width()), int(rect.height())) + + #gl.glTranslate(-rect.x(), -rect.y(), 0) + + gl.glEnable(gl.GL_STENCIL_TEST) + gl.glColorMask(gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE, gl.GL_FALSE) # disable drawing to frame buffer + gl.glDepthMask(gl.GL_FALSE) # disable drawing to depth buffer + gl.glStencilFunc(gl.GL_NEVER, 1, 0xFF) + gl.glStencilOp(gl.GL_REPLACE, gl.GL_KEEP, gl.GL_KEEP) + + ## draw stencil pattern + gl.glStencilMask(0xFF); + gl.glClear(gl.GL_STENCIL_BUFFER_BIT) + gl.glBegin(gl.GL_TRIANGLES) + gl.glVertex2f(rect.x(), rect.y()) + gl.glVertex2f(rect.x()+rect.width(), rect.y()) + gl.glVertex2f(rect.x(), rect.y()+rect.height()) + gl.glVertex2f(rect.x()+rect.width(), rect.y()+rect.height()) + gl.glVertex2f(rect.x()+rect.width(), rect.y()) + gl.glVertex2f(rect.x(), rect.y()+rect.height()) + gl.glEnd() + + gl.glColorMask(gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE, gl.GL_TRUE) + gl.glDepthMask(gl.GL_TRUE) + gl.glStencilMask(0x00) + gl.glStencilFunc(gl.GL_EQUAL, 1, 0xFF) + + try: + x, y = self.getData() + pos = np.empty((len(x), 2)) + pos[:,0] = x + pos[:,1] = y + gl.glEnableClientState(gl.GL_VERTEX_ARRAY) + try: + gl.glVertexPointerf(pos) + pen = fn.mkPen(self.opts['pen']) + color = pen.color() + gl.glColor4f(color.red()/255., color.green()/255., color.blue()/255., color.alpha()/255.) + width = pen.width() + if pen.isCosmetic() and width < 1: + width = 1 + gl.glPointSize(width) + gl.glEnable(gl.GL_LINE_SMOOTH) + gl.glEnable(gl.GL_BLEND) + gl.glBlendFunc(gl.GL_SRC_ALPHA, gl.GL_ONE_MINUS_SRC_ALPHA) + gl.glHint(gl.GL_LINE_SMOOTH_HINT, gl.GL_NICEST); + gl.glDrawArrays(gl.GL_LINE_STRIP, 0, pos.size / pos.shape[-1]) + finally: + gl.glDisableClientState(gl.GL_VERTEX_ARRAY) + finally: + p.endNativePainting() def clear(self): self.xData = None ## raw values diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py index 18d9ebf3..84c05478 100644 --- a/pyqtgraph/graphicsItems/ScatterPlotItem.py +++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py @@ -495,8 +495,8 @@ class ScatterPlotItem(GraphicsObject): if isinstance(size, np.ndarray) or isinstance(size, list): sizes = size - if kargs['mask'] is not None: - sizes = sizes[kargs['mask']] + if mask is not None: + sizes = sizes[mask] if len(sizes) != len(dataSet): raise Exception("Number of sizes does not match number of points (%d != %d)" % (len(sizes), len(dataSet))) dataSet['size'] = sizes @@ -508,13 +508,13 @@ class ScatterPlotItem(GraphicsObject): if update: self.updateSpots(dataSet) - def setPointData(self, data, dataSet=None): + def setPointData(self, data, dataSet=None, mask=None): if dataSet is None: dataSet = self.data if isinstance(data, np.ndarray) or isinstance(data, list): - if kargs['mask'] is not None: - data = data[kargs['mask']] + if mask is not None: + data = data[mask] if len(data) != len(dataSet): raise Exception("Length of meta data does not match number of points (%d != %d)" % (len(data), len(dataSet))) @@ -683,6 +683,9 @@ class ScatterPlotItem(GraphicsObject): rec = self.data[i] pos = QtCore.QPointF(pts[0,i], pts[1,i]) x,y,w,h = rec['fragCoords'] + if abs(w) > 10000 or abs(h) > 10000: + print self.data + raise Exception("fragment corrupt") rect = QtCore.QRectF(y, x, h, w) self.fragments.append(QtGui.QPainter.PixmapFragment.create(pos, rect)) diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index 21d74efd..f8d9e9a4 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -50,6 +50,7 @@ class ViewBox(GraphicsWidget): #sigActionPositionChanged = QtCore.Signal(object) sigStateChanged = QtCore.Signal(object) sigTransformChanged = QtCore.Signal(object) + sigResized = QtCore.Signal(object) ## mouse modes PanMode = 3 @@ -304,6 +305,7 @@ class ViewBox(GraphicsWidget): #self._itemBoundsCache.clear() #self.linkedXChanged() #self.linkedYChanged() + self.sigResized.emit(self) def viewRange(self): """Return a the view's visible range as a list: [[xmin, xmax], [ymin, ymax]]""" @@ -451,7 +453,7 @@ class ViewBox(GraphicsWidget): if item is None: bounds = self.childrenBoundingRect(items=items) else: - print "Warning: ViewBox.autoRange(item=__) is deprecated. Use 'items' argument instead." + print("Warning: ViewBox.autoRange(item=__) is deprecated. Use 'items' argument instead.") bounds = self.mapFromItemToView(item, item.boundingRect()).boundingRect() if bounds is not None: @@ -1046,10 +1048,10 @@ class ViewBox(GraphicsWidget): xr = item.dataBounds(0, frac=frac[0], orthoRange=orthoRange[0]) yr = item.dataBounds(1, frac=frac[1], orthoRange=orthoRange[1]) pxPad = 0 if not hasattr(item, 'pixelPadding') else item.pixelPadding() - if xr is None or (xr[0] is None and xr[1] is None): + if xr is None or (xr[0] is None and xr[1] is None) or np.isnan(xr).any() or np.isinf(xr).any(): useX = False xr = (0,0) - if yr is None or (yr[0] is None and yr[1] is None): + if yr is None or (yr[0] is None and yr[1] is None) or np.isnan(yr).any() or np.isinf(yr).any(): useY = False yr = (0,0) diff --git a/pyqtgraph/widgets/TableWidget.py b/pyqtgraph/widgets/TableWidget.py index dc4f875b..8ffe7291 100644 --- a/pyqtgraph/widgets/TableWidget.py +++ b/pyqtgraph/widgets/TableWidget.py @@ -6,27 +6,26 @@ import numpy as np try: import metaarray HAVE_METAARRAY = True -except: +except ImportError: HAVE_METAARRAY = False __all__ = ['TableWidget'] class TableWidget(QtGui.QTableWidget): """Extends QTableWidget with some useful functions for automatic data handling - and copy / export context menu. Can automatically format and display: - - - numpy arrays - - numpy record arrays - - metaarrays - - list-of-lists [[1,2,3], [4,5,6]] - - dict-of-lists {'x': [1,2,3], 'y': [4,5,6]} - - list-of-dicts [{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, ...] + and copy / export context menu. Can automatically format and display a variety + of data types (see :func:`setData() ` for more + information. """ - def __init__(self, *args): + def __init__(self, *args, **kwds): QtGui.QTableWidget.__init__(self, *args) self.setVerticalScrollMode(self.ScrollPerPixel) self.setSelectionMode(QtGui.QAbstractItemView.ContiguousSelection) + self.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Preferred) + self.setSortingEnabled(True) self.clear() + editable = kwds.get('editable', False) + self.setEditable(editable) self.contextMenu = QtGui.QMenu() self.contextMenu.addAction('Copy Selection').triggered.connect(self.copySel) self.contextMenu.addAction('Copy All').triggered.connect(self.copyAll) @@ -34,6 +33,7 @@ class TableWidget(QtGui.QTableWidget): self.contextMenu.addAction('Save All').triggered.connect(self.saveAll) def clear(self): + """Clear all contents from the table.""" QtGui.QTableWidget.clear(self) self.verticalHeadersSet = False self.horizontalHeadersSet = False @@ -42,8 +42,19 @@ class TableWidget(QtGui.QTableWidget): self.setColumnCount(0) def setData(self, data): + """Set the data displayed in the table. + Allowed formats are: + + * numpy arrays + * numpy record arrays + * metaarrays + * list-of-lists [[1,2,3], [4,5,6]] + * dict-of-lists {'x': [1,2,3], 'y': [4,5,6]} + * list-of-dicts [{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, ...] + """ self.clear() self.appendData(data) + self.resizeColumnsToContents() def appendData(self, data): """Types allowed: @@ -60,26 +71,19 @@ class TableWidget(QtGui.QTableWidget): first = next(it0) except StopIteration: return - #if type(first) == type(np.float64(1)): - # return fn1, header1 = self.iteratorFn(first) if fn1 is None: self.clear() return - #print fn0, header0 - #print fn1, header1 firstVals = [x for x in fn1(first)] self.setColumnCount(len(firstVals)) - #print header0, header1 if not self.verticalHeadersSet and header0 is not None: - #print "set header 0:", header0 self.setRowCount(len(header0)) self.setVerticalHeaderLabels(header0) self.verticalHeadersSet = True if not self.horizontalHeadersSet and header1 is not None: - #print "set header 1:", header1 self.setHorizontalHeaderLabels(header1) self.horizontalHeadersSet = True @@ -88,10 +92,15 @@ class TableWidget(QtGui.QTableWidget): for row in it0: self.setRow(i, [x for x in fn1(row)]) i += 1 + + def setEditable(self, editable=True): + self.editable = editable + for item in self.items: + item.setEditable(editable) def iteratorFn(self, data): - """Return 1) a function that will provide an iterator for data and 2) a list of header strings""" - if isinstance(data, list): + ## Return 1) a function that will provide an iterator for data and 2) a list of header strings + if isinstance(data, list) or isinstance(data, tuple): return lambda d: d.__iter__(), None elif isinstance(data, dict): return lambda d: iter(d.values()), list(map(str, data.keys())) @@ -110,13 +119,16 @@ class TableWidget(QtGui.QTableWidget): elif data is None: return (None,None) else: - raise Exception("Don't know how to iterate over data type: %s" % str(type(data))) + msg = "Don't know how to iterate over data type: {!s}".format(type(data)) + raise TypeError(msg) def iterFirstAxis(self, data): for i in range(data.shape[0]): yield data[i] - def iterate(self, data): ## for numpy.void, which can be iterated but mysteriously has no __iter__ (??) + def iterate(self, data): + # for numpy.void, which can be iterated but mysteriously + # has no __iter__ (??) for x in data: yield x @@ -124,32 +136,39 @@ class TableWidget(QtGui.QTableWidget): self.appendData([data]) def addRow(self, vals): - #print "add row:", vals row = self.rowCount() - self.setRowCount(row+1) + self.setRowCount(row + 1) self.setRow(row, vals) def setRow(self, row, vals): - if row > self.rowCount()-1: - self.setRowCount(row+1) - for col in range(self.columnCount()): + if row > self.rowCount() - 1: + self.setRowCount(row + 1) + for col in range(len(vals)): val = vals[col] - if isinstance(val, float) or isinstance(val, np.floating): - s = "%0.3g" % val - else: - s = str(val) - item = QtGui.QTableWidgetItem(s) - item.value = val - #print "add item to row %d:"%row, item, item.value + item = TableWidgetItem(val) + item.setEditable(self.editable) self.items.append(item) self.setItem(row, col, item) - + + def sizeHint(self): + # based on http://stackoverflow.com/a/7195443/54056 + width = sum(self.columnWidth(i) for i in range(self.columnCount())) + width += self.verticalHeader().sizeHint().width() + width += self.verticalScrollBar().sizeHint().width() + width += self.frameWidth() * 2 + height = sum(self.rowHeight(i) for i in range(self.rowCount())) + height += self.verticalHeader().sizeHint().height() + height += self.horizontalScrollBar().sizeHint().height() + return QtCore.QSize(width, height) + def serialize(self, useSelection=False): """Convert entire table (or just selected area) into tab-separated text values""" if useSelection: selection = self.selectedRanges()[0] - rows = list(range(selection.topRow(), selection.bottomRow()+1)) - columns = list(range(selection.leftColumn(), selection.rightColumn()+1)) + rows = list(range(selection.topRow(), + selection.bottomRow() + 1)) + columns = list(range(selection.leftColumn(), + selection.rightColumn() + 1)) else: rows = list(range(self.rowCount())) columns = list(range(self.columnCount())) @@ -215,6 +234,28 @@ class TableWidget(QtGui.QTableWidget): else: ev.ignore() +class TableWidgetItem(QtGui.QTableWidgetItem): + def __init__(self, val): + if isinstance(val, float) or isinstance(val, np.floating): + s = "%0.3g" % val + else: + s = str(val) + QtGui.QTableWidgetItem.__init__(self, s) + self.value = val + flags = QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled + self.setFlags(flags) + + def setEditable(self, editable): + if editable: + self.setFlags(self.flags() | QtCore.Qt.ItemIsEditable) + else: + self.setFlags(self.flags() & ~QtCore.Qt.ItemIsEditable) + + def __lt__(self, other): + if hasattr(other, 'value'): + return self.value < other.value + else: + return self.text() < other.text() if __name__ == '__main__': diff --git a/pyqtgraph/rebuildUi.py b/tools/rebuildUi.py similarity index 100% rename from pyqtgraph/rebuildUi.py rename to tools/rebuildUi.py