├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── __init__.py ├── apicompat ├── __init__.py ├── qgiscoreqgis.py ├── qgisutilsqgis.py ├── qgsgeometry.py ├── qgsmaplayer.py ├── qgspointxy.py ├── qgsproject.py └── qgswkbtypes.py ├── dxfwrite ├── __init__.py ├── acadctb.py ├── algebra │ ├── __init__.py │ ├── base.py │ ├── bezier.py │ ├── circle.py │ ├── clothoid.py │ ├── cspline.py │ └── ray.py ├── allplancfg.py ├── base.py ├── const.py ├── curves.py ├── dimlines.py ├── drawing.py ├── engine.py ├── entities.py ├── hdrvars.py ├── helpers.py ├── htmlcolors.py ├── insert2.py ├── mixins.py ├── mtext.py ├── rect.py ├── sections.py ├── std.py ├── table.py ├── tableentries.py ├── tables.py ├── ucs.py ├── util.py ├── vector2d.py └── vector3d.py ├── i18n ├── profiletool.pro ├── profiletool_de.qm └── profiletool_de.ts ├── icons └── profileIcon.png ├── metadata.txt ├── profile_points └── profile_points.qml ├── profileplugin.py ├── pyqtgraph ├── GraphicsScene │ ├── GraphicsScene.py │ ├── __init__.py │ ├── exportDialog.py │ ├── exportDialogTemplate.ui │ ├── exportDialogTemplate_generic.py │ └── mouseEvents.py ├── PlotData.py ├── Point.py ├── Qt │ ├── QtCore │ │ ├── __init__.py │ │ └── __init__.pyi │ ├── QtGui │ │ ├── __init__.py │ │ └── __init__.pyi │ ├── QtSvg.pyi │ ├── QtTest.pyi │ ├── QtWidgets │ │ ├── __init__.py │ │ └── __init__.pyi │ ├── __init__.py │ ├── __init__.pyi │ ├── compat │ │ └── __init__.py │ └── internals.py ├── SRTTransform.py ├── SRTTransform3D.py ├── SignalProxy.py ├── ThreadsafeTimer.py ├── Transform3D.py ├── Vector.py ├── WidgetGroup.py ├── __init__.py ├── canvas │ ├── Canvas.py │ ├── CanvasItem.py │ ├── CanvasManager.py │ ├── CanvasTemplate.ui │ ├── CanvasTemplate_generic.py │ ├── TransformGuiTemplate.ui │ ├── TransformGuiTemplate_generic.py │ └── __init__.py ├── colormap.py ├── colors │ ├── __init__.py │ ├── maps │ │ ├── CC-BY license - applies to CET color map data.txt │ │ ├── CC0 legal code - applies to virids, magma, plasma, inferno and cividis.txt │ │ ├── CET-C1.csv │ │ ├── CET-C1s.csv │ │ ├── CET-C2.csv │ │ ├── CET-C2s.csv │ │ ├── CET-C3.csv │ │ ├── CET-C3s.csv │ │ ├── CET-C4.csv │ │ ├── CET-C4s.csv │ │ ├── CET-C5.csv │ │ ├── CET-C5s.csv │ │ ├── CET-C6.csv │ │ ├── CET-C6s.csv │ │ ├── CET-C7.csv │ │ ├── CET-C7s.csv │ │ ├── CET-CBC1.csv │ │ ├── CET-CBC2.csv │ │ ├── CET-CBD1.csv │ │ ├── CET-CBL1.csv │ │ ├── CET-CBL2.csv │ │ ├── CET-CBTC1.csv │ │ ├── CET-CBTC2.csv │ │ ├── CET-CBTD1.csv │ │ ├── CET-CBTL1.csv │ │ ├── CET-CBTL2.csv │ │ ├── CET-D1.csv │ │ ├── CET-D10.csv │ │ ├── CET-D11.csv │ │ ├── CET-D12.csv │ │ ├── CET-D13.csv │ │ ├── CET-D1A.csv │ │ ├── CET-D2.csv │ │ ├── CET-D3.csv │ │ ├── CET-D4.csv │ │ ├── CET-D6.csv │ │ ├── CET-D7.csv │ │ ├── CET-D8.csv │ │ ├── CET-D9.csv │ │ ├── CET-I1.csv │ │ ├── CET-I2.csv │ │ ├── CET-I3.csv │ │ ├── CET-L1.csv │ │ ├── CET-L10.csv │ │ ├── CET-L11.csv │ │ ├── CET-L12.csv │ │ ├── CET-L13.csv │ │ ├── CET-L14.csv │ │ ├── CET-L15.csv │ │ ├── CET-L16.csv │ │ ├── CET-L17.csv │ │ ├── CET-L18.csv │ │ ├── CET-L19.csv │ │ ├── CET-L2.csv │ │ ├── CET-L3.csv │ │ ├── CET-L4.csv │ │ ├── CET-L5.csv │ │ ├── CET-L6.csv │ │ ├── CET-L7.csv │ │ ├── CET-L8.csv │ │ ├── CET-L9.csv │ │ ├── CET-R1.csv │ │ ├── CET-R2.csv │ │ ├── CET-R3.csv │ │ ├── CET-R4.csv │ │ ├── PAL-relaxed.hex │ │ ├── PAL-relaxed_bright.hex │ │ ├── cividis.csv │ │ ├── inferno.csv │ │ ├── magma.csv │ │ ├── plasma.csv │ │ ├── turbo.csv │ │ └── viridis.csv │ └── palette.py ├── configfile.py ├── console │ ├── CmdInput.py │ ├── Console.py │ ├── __init__.py │ ├── exception_widget.py │ ├── repl_widget.py │ └── stackwidget.py ├── debug.py ├── dockarea │ ├── Container.py │ ├── Dock.py │ ├── DockArea.py │ ├── DockDrop.py │ └── __init__.py ├── examples │ ├── Arrow.py │ ├── AxisItem_label_overlap.py │ ├── BarGraphItem.py │ ├── CLIexample.py │ ├── ColorBarItem.py │ ├── ColorButton.py │ ├── ColorGradientPlots.py │ ├── ConsoleWidget.py │ ├── CustomGraphItem.py │ ├── DataSlicing.py │ ├── DataTreeWidget.py │ ├── DateAxisItem.py │ ├── DateAxisItem_QtDesigner.py │ ├── DateAxisItem_QtDesigner.ui │ ├── DiffTreeWidget.py │ ├── Draw.py │ ├── ErrorBarItem.py │ ├── ExampleApp.py │ ├── FillBetweenItem.py │ ├── Flowchart.py │ ├── FlowchartCustomNode.py │ ├── GLBarGraphItem.py │ ├── GLGradientLegendItem.py │ ├── GLGraphItem.py │ ├── GLImageItem.py │ ├── GLIsosurface.py │ ├── GLLinePlotItem.py │ ├── GLMeshItem.py │ ├── GLPainterItem.py │ ├── GLScatterPlotItem.py │ ├── GLSurfacePlot.py │ ├── GLTextItem.py │ ├── GLViewWidget.py │ ├── GLVolumeItem.py │ ├── GLshaders.py │ ├── GradientEditor.py │ ├── GradientWidget.py │ ├── GraphItem.py │ ├── GraphicsLayout.py │ ├── GraphicsScene.py │ ├── HistogramLUT.py │ ├── ImageItem.py │ ├── ImageView.py │ ├── InfiniteLine.py │ ├── InteractiveParameter.py │ ├── JoystickButton.py │ ├── Legend.py │ ├── LogPlotTest.py │ ├── MatrixDisplayExample.py │ ├── MouseSelection.py │ ├── MultiDataPlot.py │ ├── MultiPlotSpeedTest.py │ ├── MultiplePlotAxes.py │ ├── NonUniformImage.py │ ├── PColorMeshItem.py │ ├── PanningPlot.py │ ├── PlotAutoRange.py │ ├── PlotSpeedTest.py │ ├── PlotWidget.py │ ├── Plotting.py │ ├── ProgressDialog.py │ ├── ROIExamples.py │ ├── ROItypes.py │ ├── RemoteGraphicsView.py │ ├── RemoteSpeedTest.py │ ├── RunExampleApp.py │ ├── ScaleBar.py │ ├── ScatterPlot.py │ ├── ScatterPlotSpeedTest.py │ ├── ScatterPlotWidget.py │ ├── SimplePlot.py │ ├── SpinBox.py │ ├── Symbols.py │ ├── TableWidget.py │ ├── TreeWidget.py │ ├── VideoSpeedTest.py │ ├── VideoTemplate.ui │ ├── VideoTemplate_generic.py │ ├── ViewBox.py │ ├── ViewBoxFeatures.py │ ├── ViewLimits.py │ ├── __init__.py │ ├── __main__.py │ ├── _buildParamTypes.py │ ├── _paramtreecfg.py │ ├── beeswarm.py │ ├── colorMaps.py │ ├── colorMapsLinearized.py │ ├── console_exception_inspection.py │ ├── contextMenu.py │ ├── crosshair.py │ ├── customGraphicsItem.py │ ├── customPlot.py │ ├── cx_freeze │ │ ├── plotTest.py │ │ └── setup.py │ ├── designerExample.py │ ├── designerExample.ui │ ├── dockarea.py │ ├── exampleLoaderTemplate.ui │ ├── exampleLoaderTemplate_generic.py │ ├── fractal.py │ ├── glow.py │ ├── hdf5.py │ ├── histogram.py │ ├── imageAnalysis.py │ ├── infiniteline_performance.py │ ├── isocurve.py │ ├── jupyter_console_example.py │ ├── linkedViews.py │ ├── logAxis.py │ ├── multiplePlotSpeedTest.py │ ├── multiprocess.py │ ├── notebooks │ │ ├── ImageAnalysis.ipynb │ │ ├── PColorMeshItem.ipynb │ │ ├── Plotting.ipynb │ │ ├── ROIExamples.ipynb │ │ ├── ScatterPlot.ipynb │ │ └── simple.ipynb │ ├── optics │ │ ├── __init__.py │ │ ├── pyoptic.py │ │ └── schott_glasses.csv.gz │ ├── optics_demos.py │ ├── parallelize.py │ ├── parametertree.py │ ├── py2exe │ │ ├── plotTest.py │ │ └── setup.py │ ├── relativity │ │ ├── __init__.py │ │ ├── presets │ │ │ ├── Grid Expansion.cfg │ │ │ ├── Twin Paradox (grid).cfg │ │ │ └── Twin Paradox.cfg │ │ └── relativity.py │ ├── relativity_demo.py │ ├── scrollingPlots.py │ ├── syntax.py │ ├── template.py │ ├── test_examples.py │ ├── text.py │ ├── utils.py │ ├── verlet_chain │ │ ├── __init__.py │ │ ├── chain.py │ │ ├── make │ │ ├── relax.c │ │ └── relax.py │ └── verlet_chain_demo.py ├── exceptionHandling.py ├── exporters │ ├── CSVExporter.py │ ├── Exporter.py │ ├── HDF5Exporter.py │ ├── ImageExporter.py │ ├── Matplotlib.py │ ├── PrintExporter.py │ ├── SVGExporter.py │ └── __init__.py ├── flowchart │ ├── Flowchart.py │ ├── FlowchartCtrlTemplate.ui │ ├── FlowchartCtrlTemplate_generic.py │ ├── FlowchartGraphicsView.py │ ├── Node.py │ ├── NodeLibrary.py │ ├── Terminal.py │ ├── __init__.py │ └── library │ │ ├── Data.py │ │ ├── Display.py │ │ ├── Filters.py │ │ ├── Operators.py │ │ ├── __init__.py │ │ ├── common.py │ │ └── functions.py ├── frozenSupport.py ├── functions.py ├── functions_numba.py ├── functions_qimage.py ├── graphicsItems │ ├── ArrowItem.py │ ├── AxisItem.py │ ├── BarGraphItem.py │ ├── ButtonItem.py │ ├── ColorBarItem.py │ ├── CurvePoint.py │ ├── DateAxisItem.py │ ├── ErrorBarItem.py │ ├── FillBetweenItem.py │ ├── GradientEditorItem.py │ ├── GradientLegend.py │ ├── GradientPresets.py │ ├── GraphItem.py │ ├── GraphicsItem.py │ ├── GraphicsLayout.py │ ├── GraphicsObject.py │ ├── GraphicsWidget.py │ ├── GraphicsWidgetAnchor.py │ ├── GridItem.py │ ├── HistogramLUTItem.py │ ├── ImageItem.py │ ├── InfiniteLine.py │ ├── IsocurveItem.py │ ├── ItemGroup.py │ ├── LabelItem.py │ ├── LegendItem.py │ ├── LinearRegionItem.py │ ├── MultiPlotItem.py │ ├── NonUniformImage.py │ ├── PColorMeshItem.py │ ├── PlotCurveItem.py │ ├── PlotDataItem.py │ ├── PlotItem │ │ ├── PlotItem.py │ │ ├── __init__.py │ │ ├── plotConfigTemplate.ui │ │ └── plotConfigTemplate_generic.py │ ├── ROI.py │ ├── ScaleBar.py │ ├── ScatterPlotItem.py │ ├── TargetItem.py │ ├── TextItem.py │ ├── UIGraphicsItem.py │ ├── VTickGroup.py │ ├── ViewBox │ │ ├── ViewBox.py │ │ ├── ViewBoxMenu.py │ │ ├── __init__.py │ │ ├── axisCtrlTemplate.ui │ │ └── axisCtrlTemplate_generic.py │ └── __init__.py ├── icons │ ├── __init__.py │ ├── auto.png │ ├── ctrl.png │ ├── default.png │ ├── icons.svg │ ├── invisibleEye.svg │ ├── lock.png │ └── peegee │ │ ├── peegee.svg │ │ ├── peegee_128px.png │ │ ├── peegee_128px@2x.png │ │ ├── peegee_192px.png │ │ ├── peegee_256px.png │ │ ├── peegee_256px@2x.png │ │ ├── peegee_512px.png │ │ └── peegee_512px@2x.png ├── imageview │ ├── ImageView.py │ ├── ImageViewTemplate.ui │ ├── ImageViewTemplate_generic.py │ └── __init__.py ├── jupyter │ ├── GraphicsView.py │ └── __init__.py ├── metaarray │ ├── MetaArray.py │ ├── __init__.py │ ├── license.txt │ └── readMeta.m ├── multiprocess │ ├── __init__.py │ ├── bootstrap.py │ ├── parallelizer.py │ ├── processes.py │ └── remoteproxy.py ├── opengl │ ├── GLGraphicsItem.py │ ├── GLViewWidget.py │ ├── MeshData.py │ ├── __init__.py │ ├── items │ │ ├── GLAxisItem.py │ │ ├── GLBarGraphItem.py │ │ ├── GLBoxItem.py │ │ ├── GLGradientLegendItem.py │ │ ├── GLGraphItem.py │ │ ├── GLGridItem.py │ │ ├── GLImageItem.py │ │ ├── GLLinePlotItem.py │ │ ├── GLMeshItem.py │ │ ├── GLScatterPlotItem.py │ │ ├── GLSurfacePlotItem.py │ │ ├── GLTextItem.py │ │ ├── GLVolumeItem.py │ │ └── __init__.py │ └── shaders.py ├── parametertree │ ├── Parameter.py │ ├── ParameterItem.py │ ├── ParameterSystem.py │ ├── ParameterTree.py │ ├── SystemSolver.py │ ├── __init__.py │ ├── interactive.py │ └── parameterTypes │ │ ├── __init__.py │ │ ├── action.py │ │ ├── actiongroup.py │ │ ├── basetypes.py │ │ ├── bool.py │ │ ├── calendar.py │ │ ├── checklist.py │ │ ├── color.py │ │ ├── colormap.py │ │ ├── colormaplut.py │ │ ├── file.py │ │ ├── font.py │ │ ├── list.py │ │ ├── numeric.py │ │ ├── pen.py │ │ ├── progress.py │ │ ├── qtenum.py │ │ ├── slider.py │ │ ├── str.py │ │ └── text.py ├── reload.py ├── units.py ├── util │ ├── __init__.py │ ├── colorama │ │ ├── LICENSE.txt │ │ ├── README.txt │ │ ├── __init__.py │ │ ├── win32.py │ │ └── winterm.py │ ├── cprint.py │ ├── cupy_helper.py │ ├── garbage_collector.py │ ├── get_resolution.py │ ├── glinfo.py │ ├── mutex.py │ └── numba_helper.py └── widgets │ ├── BusyCursor.py │ ├── CheckTable.py │ ├── ColorButton.py │ ├── ColorMapButton.py │ ├── ColorMapMenu.py │ ├── ColorMapWidget.py │ ├── ComboBox.py │ ├── DataFilterWidget.py │ ├── DataTreeWidget.py │ ├── DiffTreeWidget.py │ ├── FeedbackButton.py │ ├── FileDialog.py │ ├── GradientWidget.py │ ├── GraphicsLayoutWidget.py │ ├── GraphicsView.py │ ├── GroupBox.py │ ├── HistogramLUTWidget.py │ ├── JoystickButton.py │ ├── LayoutWidget.py │ ├── MatplotlibWidget.py │ ├── MultiPlotWidget.py │ ├── PathButton.py │ ├── PenPreviewLabel.py │ ├── PlotWidget.py │ ├── ProgressDialog.py │ ├── RawImageWidget.py │ ├── RemoteGraphicsView.py │ ├── ScatterPlotWidget.py │ ├── SpinBox.py │ ├── TableWidget.py │ ├── TreeWidget.py │ ├── ValueLabel.py │ ├── VerticalLabel.py │ └── __init__.py ├── resources.py ├── resources.qrc ├── tests └── test_dist.py ├── tools ├── __init__.py ├── dataReaderTool.py ├── plottingtool.py ├── profilers.py ├── profiletool_core.py ├── ptmaptool.py ├── selectlinetool.py ├── tableviewtool.py └── utils.py └── ui ├── __init__.py ├── about.ui ├── dlgabout.py ├── profiletool.ui └── ptdockwidget.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__ 3 | .venv 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Profile Tool ![image](https://github.com/PANOimagen/profiletool/blob/master/icons/profileIcon.png?raw=true) 2 | 3 | This tool plots profile lines from raster layers or point vector layer with elevation field. 4 | Supports multiple lines as well as graph export to svg, pdf, png or csv file. 5 | Supports 3D polyline export to dxf. 6 | 7 | **Authors:** Borys Jurgiel - Patrice Verchere - Etienne Tourigny - Javier Becerra 8 | 9 | **Current mantainer:** PANOimagen S.L. 10 | 11 | **email:** *javier@panoimagen.com* 12 | 13 | Fork of etiennesky/profiletool QGis plugin. We add support to select all 14 | the features in a Layer and visualization of slope profile in addition to height profile. 15 | This work has been partially funded by the C.A. La Rioja 16 | 17 | **Profile Tool license:** 18 | 19 | This program is free software: you can redistribute it and/or modify 20 | it under the terms of the GNU General Public License as published by 21 | the Free Software Foundation, either version 2 of the License, or 22 | (at your option) any later version. 23 | 24 | This program is distributed in the hope that it will be useful, 25 | but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 | GNU General Public License for more details. 28 | 29 | You should have received a copy of the GNU General Public License 30 | along with this program. If not, see . 31 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------- 2 | # 3 | # Profile 4 | # Copyright (C) 2008 Borys Jurgiel 5 | # Copyright (C) 2012 Patrice Verchere 6 | # ----------------------------------------------------------- 7 | # 8 | # licensed under the terms of GNU GPL 2 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License along 21 | # with this program; if not, write to the Free Software Foundation, Inc., 22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | # 24 | # --------------------------------------------------------------------- 25 | from . import apicompat 26 | 27 | 28 | def classFactory(iface): 29 | from .profileplugin import ProfilePlugin 30 | 31 | return ProfilePlugin(iface) 32 | -------------------------------------------------------------------------------- /apicompat/__init__.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import qgis.utils 3 | 4 | # Based on qgis2compat plugin from opengis.ch 5 | 6 | # Dealing with a QGIS 2 version, monkey patch some things 7 | # also guard with initialized so monkeypatching happens only once 8 | initialized = False 9 | if not initialized and hasattr(qgis.utils, "QGis"): 10 | initialized = True 11 | # log('Running apicompat on QGIS version %s' % QGIS_VERSION) 12 | 13 | # Here import all the compatibility fixes modules 14 | import qgiscoreqgis 15 | import qgisutilsqgis 16 | import qgsgeometry 17 | import qgsmaplayer 18 | import qgspointxy 19 | import qgsproject 20 | import qgswkbtypes 21 | -------------------------------------------------------------------------------- /apicompat/qgiscoreqgis.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import qgis.core 4 | 5 | # QGis in QGIS version 2 was renamed to Qgis in QGIS version 3 6 | 7 | qgis.core.Qgis = qgis.core.QGis 8 | -------------------------------------------------------------------------------- /apicompat/qgisutilsqgis.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import qgis.utils 4 | 5 | # QGis in QGIS version 2 was renamed to Qgis in QGIS version 3 6 | 7 | qgis.utils.Qgis = qgis.utils.QGis 8 | -------------------------------------------------------------------------------- /apicompat/qgsgeometry.py: -------------------------------------------------------------------------------- 1 | import qgis.core 2 | 3 | # fromPoint() was renamed to fromPointXY() in QGis3 4 | # The same with the other QgsGeometries -- from [geometry] in QGIS 2 to [geometry]XY in QGIS 3 5 | qgis.core.QgsGeometry.fromPointXY = qgis.core.QgsGeometry.fromPoint 6 | qgis.core.QgsGeometry.fromPolylineXY = qgis.core.QgsGeometry.fromPolyline 7 | qgis.core.QgsGeometry.fromMultiPolylineXY = qgis.core.QgsGeometry.fromMultiPolyline 8 | -------------------------------------------------------------------------------- /apicompat/qgsmaplayer.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import qgis.core 4 | 5 | 6 | # log('Monkeypatching QgsPointXY') 7 | # hasGeometryType has been replaced by isSpatial in QGis 3.0 api 8 | def isSpatial(self): 9 | # Will raise AttributeError when used with layers that are not 10 | # QgsVectorLayer, but that is the expected behaviour in Qgis 2.x 11 | return self.hasGeometryType() 12 | 13 | 14 | qgis.core.QgsMapLayer.isSpatial = isSpatial 15 | # MeshLayer is defined in QGis 3.x, should not appear in QGis 2.x 16 | qgis.core.QgsMapLayer.MeshLayer = 3 17 | -------------------------------------------------------------------------------- /apicompat/qgspointxy.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | 3 | import qgis.core 4 | 5 | # log('Monkeypatching QgsPointXY') 6 | # QgsPoint has been renamed to QgsPoint in QGis 3.0 api 7 | qgis.core.QgsPointXY = qgis.core.QgsPoint 8 | -------------------------------------------------------------------------------- /apicompat/qgsproject.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | """Monkey patching for QgsProject - QGis 3 compatibility in QGis 2. 3 | 4 | From qgis2compat plugin by opengis.ch 5 | """ 6 | import qgis.core 7 | import qgis.utils 8 | from PyQt4.QtCore import QFileInfo 9 | 10 | # from qgis2compat import log 11 | 12 | 13 | # log('Monkeypatching QgsProject') 14 | 15 | 16 | def visibilityPresetCollection(self): 17 | return self.visibilityPresetCollection() 18 | 19 | 20 | qgis.core.QgsProject.mapThemeCollection = visibilityPresetCollection 21 | 22 | 23 | def mapLayers(self): 24 | return qgis.core.QgsMapLayerRegistry.instance().mapLayers() 25 | 26 | 27 | qgis.core.QgsProject.mapLayers = mapLayers 28 | 29 | 30 | def mapLayersByName(self, layerName): 31 | return qgis.core.QgsMapLayerRegistry.instance().mapLayersByName(layerName) 32 | 33 | 34 | qgis.core.QgsProject.mapLayersByName = mapLayersByName 35 | 36 | 37 | def removeMapLayer(self, layer): 38 | return qgis.core.QgsMapLayerRegistry.instance().removeMapLayer(layer) 39 | 40 | 41 | qgis.core.QgsProject.removeMapLayer = removeMapLayer 42 | 43 | 44 | def addMapLayer(self, mapLayer, addToLegend=True, takeOwnership=True): 45 | return qgis.core.QgsMapLayerRegistry.instance().addMapLayer(mapLayer, addToLegend) 46 | 47 | 48 | qgis.core.QgsProject.addMapLayer = addMapLayer 49 | 50 | 51 | def mapLayer(self, layerId): 52 | return qgis.core.QgsMapLayerRegistry.instance().mapLayer(layerId) 53 | 54 | 55 | qgis.core.QgsProject.mapLayer = mapLayer 56 | 57 | original_QgsProject_write = qgis.core.QgsProject.write 58 | 59 | 60 | def write(self, filename): 61 | return original_QgsProject_write(self, QFileInfo(filename)) 62 | 63 | 64 | qgis.core.QgsProject.write = write 65 | 66 | original_QgsProject_read = qgis.core.QgsProject.read 67 | 68 | 69 | def read(self, param=None): 70 | if param: 71 | try: 72 | return original_QgsProject_read(self, QFileInfo(param)) 73 | except TypeError: 74 | return original_QgsProject_read(self, param) 75 | else: 76 | return original_QgsProject_read(self) 77 | 78 | 79 | qgis.core.QgsProject.read = read 80 | -------------------------------------------------------------------------------- /apicompat/qgswkbtypes.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import qgis.core 4 | 5 | 6 | class QgsWkbTypes: 7 | 8 | Point = qgis.core.QGis.WKBPoint 9 | # 2- qgis.core.QGis.WKBPoint -> 3- qgis.core.QgsWkbTypes.Point 10 | LineString = qgis.core.QGis.WKBLineString 11 | # 2- qgis.core.QGis.WKBLineString -> 3- qgis.core.QgsWkbTypes.MultiLineString 12 | # qgis.core.QGis.WKBMultiLineString = qgis.core.QgsWkbTypes.MultiLineString 13 | MultiLineString = qgis.core.QGis.WKBMultiLineString 14 | # 2- qgis.core.QGis.WKBMultiLineString -> 3- qgis.core.QgsWkbTypes.MultiLineString 15 | # qgis.core.QGis.WKBPolygon = qgis.core.QgsWkbTypes.Polygon 16 | Polygon = qgis.core.QGis.WKBPolygon 17 | 18 | LineGeometry = qgis.core.QGis.Line 19 | PointGeometry = qgis.core.QGis.Point 20 | 21 | 22 | qgis.core.QgsWkbTypes = QgsWkbTypes 23 | -------------------------------------------------------------------------------- /dxfwrite/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | # Purpose: write DXF R12 files 4 | # Based on the ideas of Stani Michiels(Stani) sdxf.py and 5 | # Remigiusz Fiedler(migius) dxflibrary133.py 6 | # Created: 14.03.2010 7 | # Copyright (C) 2010, Manfred Moitzi 8 | # License: MIT License 9 | 10 | from .const import * 11 | from .base import * 12 | from .engine import DXFEngine 13 | 14 | 15 | version = (1, 2, 1) 16 | VERSION = "%d.%d.%d" % version 17 | 18 | CYEAR = "2010-2017" 19 | AUTHOR_NAME = "Manfred Moitzi" 20 | AUTHOR_EMAIL = "mozman@gmx.at" 21 | LICENSE = "MIT License" 22 | 23 | __author__ = "mozman " 24 | __doc__ = """A Python library to create DXF R12 drawings. 25 | 26 | Copyright %s 27 | Version %s 28 | License %s 29 | 30 | IMPLEMENTED R12 WRITING: 31 | - POINT 32 | - LINE 33 | - CIRCLE 34 | - ARC 35 | - TEXT 36 | - SOLID 37 | - TRACE 38 | - FACE3D 39 | - POLYLINE (POLYMESH, POLYFACE) 40 | - BLOCK 41 | - INSERT 42 | - ATTDEF 43 | - ATTRIB 44 | 45 | NOT IMPLEMENTED: 46 | - DIMENSION (use LinearDimension, AngularDimension, ArcDimension or 47 | RadialDimension) 48 | """ % (AUTHOR_NAME, VERSION, LICENSE,) 49 | -------------------------------------------------------------------------------- /dxfwrite/algebra/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | # Purpose: algebra lib to calculate with geometric forms 4 | # Created: 27.03.2010 5 | # License: MIT License 6 | 7 | 8 | 9 | import math 10 | 11 | from .base import * 12 | from .ray import Ray2D, ParallelRaysError 13 | from .clothoid import Clothoid 14 | from .circle import Circle 15 | from .bezier import CubicBezierCurve 16 | from .cspline import CubicSpline 17 | 18 | __version__ = "v0.2 - 2010.03.27" 19 | __author__ = "mozman " 20 | __license__ = "MIT License" 21 | 22 | __doc__ = """A library to calculate with geometric forms. 23 | 24 | Copyright %s 25 | Version %s 26 | License %s 27 | """ % (__author__,__version__,__license__,) 28 | 29 | # -------------------------------------------------------------------------- 30 | # algebra: copyright (C) 2010 by Manfred Moitzi (mozman) 31 | # -------------------------------------------------------------------------- 32 | # ***** BEGIN GPL LICENSE BLOCK ***** 33 | # 34 | # This program is free software; you can redistribute it and/or 35 | # modify it under the terms of the GNU General Public License 36 | # as published by the Free Software Foundation; either version 2 37 | # of the License, or (at your option) any later version. 38 | # 39 | # This program is distributed in the hope that it will be useful, 40 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 41 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 42 | # GNU General Public License for more details. 43 | # 44 | # You should have received a copy of the GNU General Public License 45 | # along with this program; if not, write to the Free Software Foundation, 46 | # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 47 | # 48 | # ***** END GPL LICENCE BLOCK ***** 49 | -------------------------------------------------------------------------------- /dxfwrite/algebra/base.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | # Purpose: 4 | # Created: 27.03.2010 5 | 6 | __author__ = "mozman " 7 | 8 | import math 9 | 10 | HALF_PI = math.pi / 2. 11 | THREE_PI_HALF = 1.5 * math.pi 12 | DOUBLE_PI = math.pi * 2. 13 | 14 | def rotate_2d(point, angle): 15 | """ rotate point around origin point about angle """ 16 | x = point[0] * math.cos(angle) - point[1] * math.sin(angle) 17 | y = point[1] * math.cos(angle) + point[0] * math.sin(angle) 18 | return (x, y) 19 | 20 | def equals_almost(v1, v2, places=7): 21 | """compare two float values 22 | places: significant decimal places 23 | """ 24 | return round(v1, places) == round(v2, places) 25 | 26 | def normalize_angle(angle): 27 | """ return an angle between 0 and 2*pi """ 28 | angle = math.fmod(angle, DOUBLE_PI) 29 | if angle < 0: 30 | angle += DOUBLE_PI 31 | return angle 32 | 33 | def is_vertical_angle(angle, places=7): 34 | """ returns True for 1/2pi and 3/2pi """ 35 | angle = normalize_angle(angle) 36 | return (equals_almost(angle, HALF_PI, places) or 37 | equals_almost(angle, THREE_PI_HALF, places)) 38 | 39 | def get_angle(p1, p2): 40 | """calc angle between the line p1-p2 and the x-axis 41 | input: points as tuples 42 | result: angle in radians 43 | """ 44 | dx = p2[0] - p1[0] 45 | dy = p2[1] - p1[1] 46 | return math.atan2(dy, dx) 47 | 48 | def right_of_line(point, p1, p2): 49 | """ True if the point self is right of the line p1 -> p2 50 | """ 51 | return not left_of_line(point, p1, p2) 52 | 53 | def left_of_line(point, p1, p2): 54 | """ True if the point self is left of the line p1 -> p2 55 | """ 56 | # check if a and b are on the same vertical line 57 | if p1[0] == p2[0]: 58 | # compute # on which site of the line self should be 59 | should_be_left = p1[1] < p2[1] 60 | if should_be_left: 61 | return point[0] < p1[0] 62 | else: 63 | return point[0] > p1[0] 64 | else: 65 | # get pitch of line 66 | pitch = (p2[1] - p1[1]) / (p2[0] - p1[0]) 67 | 68 | # get y-value at c's x-position 69 | y = pitch * (point[0] - p1[0]) + p1[1] 70 | 71 | # compute if point should be above or below the line 72 | should_be_above = p1[0] < p2[0] 73 | if should_be_above : 74 | return point[1] > y 75 | else: 76 | return point[1] < y 77 | -------------------------------------------------------------------------------- /dxfwrite/algebra/clothoid.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | # Purpose: 2d clothoid 4 | # module belongs to package: dxfwrite.py 5 | # Created: 26.03.2010 6 | # License: MIT License 7 | 8 | __author__ = "mozman " 9 | 10 | import sys 11 | if sys.version_info[0] > 2: 12 | xrange = range 13 | 14 | import math 15 | 16 | class Clothoid(object): 17 | """This object represents a clothoid (a.k.a. Euler spiral) for parameter 18 | . The curve always starts at the coordinate system origin = (0, 0). 19 | """ 20 | def __init__(self, paramA=1.0): 21 | self.A = paramA # Clothiod Parameter A 22 | self.powersA = [paramA**power for power in xrange(19)] 23 | self.coords = {} # coordinates cache 24 | 25 | def get_radius(self, L): 26 | """Get radius of circle at distance .""" 27 | if L > 0.: 28 | return self.powersA[2] / L 29 | else : 30 | return 0. # radius = infinite 31 | 32 | def get_tau(self, L): 33 | """Get tangent angle at distance in radians.""" 34 | return L**2 / (2. * self.powersA[2]) 35 | 36 | def get_L(self, radius): 37 | """Get distance L from origin for .""" 38 | return self.powersA[2] / float(radius) 39 | 40 | def get_xy(self, L): 41 | """Get xy-coordinates of curve point at distance .""" 42 | def term(powerL, powerA, const): 43 | return L**powerL/(const * self.powersA[powerA]) 44 | if L not in self.coords: 45 | y = term(3, 2, 6.) - term(7, 6, 336.) + term(11, 10, 42240.) - \ 46 | term(15, 14, 9676800.) + term(19, 18, 3530096640.) 47 | x = L - term(5, 4, 40.) + term(9, 8, 3456.) - term(13, 12, 599040.) + \ 48 | term(17, 16, 175472640.) 49 | self.coords[L] = (x, y) 50 | return self.coords[L] 51 | 52 | def approximate(self, length, segments): 53 | """Approximate curve of with line-segments. 54 | 55 | Generates +1 2D points (float, float). 56 | """ 57 | delta_l = float(length) / float(segments) 58 | yield (0., 0.) 59 | for index in xrange(1, segments+1): 60 | yield self.get_xy(delta_l * index) 61 | 62 | def get_center(self, L): 63 | """Get center point of circle at point L.""" 64 | x, y = self.get_xy(L) 65 | r = self.get_radius(L) 66 | tau = self.get_tau(L) 67 | xm = x - r * math.sin(tau) 68 | ym = y + r * math.cos(tau) 69 | return (xm, ym) 70 | -------------------------------------------------------------------------------- /dxfwrite/helpers.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | # Purpose: normalize dxf chunks 4 | # Created: 24.02.2011 5 | # Copyright (C) 2011, Manfred Moitzi 6 | # License: MIT License 7 | 8 | __author__ = "mozman " 9 | 10 | 11 | def normalize_dxf_chunk(dxfstr): 12 | def round_floats_but_not_ints(tag, places=7): 13 | try: 14 | return int(tag) 15 | except ValueError: 16 | pass 17 | try: 18 | value = float(tag) 19 | return round(value, places) 20 | except ValueError: 21 | return tag 22 | 23 | return [round_floats_but_not_ints(tag) for tag in dxfstr.split('\n')] 24 | -------------------------------------------------------------------------------- /dxfwrite/mixins.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #coding:utf-8 3 | # Purpose: provide class mixins 4 | # Created: 11.12.11 5 | # Copyright (C) 2011, Manfred Moitzi 6 | # License: MIT License 7 | 8 | __author__ = "mozman " 9 | 10 | 11 | class SubscriptAttributes(object): 12 | def __getitem__(self, item): 13 | if hasattr(self, item): 14 | return getattr(self, item) 15 | else: 16 | raise KeyError(item) 17 | 18 | def __setitem__(self, key, value): 19 | if hasattr(self, key): 20 | setattr(self, key, value) 21 | else: 22 | raise KeyError(key) 23 | 24 | def __contains__(self, item): 25 | return hasattr(self, item) 26 | -------------------------------------------------------------------------------- /dxfwrite/tables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | # Purpose: tables R12 4 | # module belongs to package: dxfwrite.py 5 | # Created: 09.02.2010 6 | # Copyright (C) 2010, Manfred Moitzi 7 | # License: MIT License 8 | 9 | __author__ = "mozman " 10 | 11 | __all__ = ['create_table'] 12 | 13 | from .base import * 14 | 15 | 16 | def create_table(name): 17 | """ Table factory. 18 | """ 19 | if name == 'VPORT': 20 | return Viewports() 21 | elif name in ['LTYPE', 'LAYER', 'STYLE', 'VIEW', 'APPID', 'UCS']: 22 | return _Table(name) 23 | else: 24 | raise ValueError("unknown table '%s'" % str(name)) 25 | 26 | 27 | class _Table(object): 28 | """ Base table class. 29 | """ 30 | 31 | def __init__(self, tablename): 32 | self.tablename = tablename 33 | self._entries = {} # use only add() for adding objects 34 | 35 | def __dxf__(self): 36 | return dxfstr(self.__dxftags__()) 37 | 38 | def __dxftags__(self): 39 | return DXFList(( 40 | DXFAtom('TABLE'), 41 | DXFName(self.tablename), 42 | DXFInt(len(self._entries)), 43 | DXFList(self._get_values()), 44 | DXFAtom('ENDTAB') 45 | )) 46 | 47 | def __contains__(self, name): 48 | return name in self._entries 49 | 50 | def __getitem__(self, name): 51 | """ Get table entry by `name` -> TableEntry. 52 | """ 53 | return self._entries[name] 54 | 55 | def clear(self): 56 | self._entries.clear() 57 | 58 | def _get_values(self): 59 | return self._entries.values() 60 | 61 | def add(self, entry): 62 | """ Add a table entry. 63 | """ 64 | self._entries[entry['name']] = entry 65 | 66 | 67 | class Viewports(_Table): 68 | def __init__(self): 69 | super(Viewports, self).__init__('VPORT') 70 | # because the VPORT-table can have multiple entries with the same name 71 | # use a list() instead of a dict(). 72 | self._entries = [] 73 | 74 | def __getitem__(self, name): 75 | """ Get all table entries `name`, because multiple entries are possible -> list 76 | """ 77 | return [entry for entry in self._entries if entry['name'] == name] 78 | 79 | def _get_values(self): 80 | return self._entries 81 | 82 | def add(self, viewport): 83 | self._entries.append(viewport) 84 | 85 | def clear(self): 86 | self._entries = [] 87 | 88 | -------------------------------------------------------------------------------- /dxfwrite/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | # Purpose: utility functions 4 | # module belongs to package dxfwrite 5 | # Created: 09.02.2010 6 | # Copyright (C) 2010, Manfred Moitzi 7 | # License: MIT License 8 | 9 | __author__ = "mozman " 10 | 11 | import sys 12 | PYTHON3 = sys.version_info[0] > 2 13 | 14 | if PYTHON3: 15 | from io import StringIO 16 | izip = zip 17 | 18 | def is_string(value): 19 | return isinstance(value, str) 20 | 21 | def to_unicode(value): 22 | return str(value) 23 | 24 | def to_string(value): 25 | if not isinstance(value, str): 26 | return str(value) 27 | else: 28 | escaped_value = value.encode("raw_unicode_escape") 29 | if b'\\u' in escaped_value: 30 | return str(escaped_value.replace(b'\\u', b'\\U+'), 'utf-8') 31 | else: 32 | return value 33 | else: # PYTHON2 34 | from itertools import izip 35 | from StringIO import StringIO 36 | 37 | def is_string(value): 38 | return isinstance(value, basestring) 39 | 40 | def to_unicode(value): 41 | return str(value).decode('utf-8') 42 | 43 | def to_string(value): 44 | if not isinstance(value, basestring): 45 | return str(value) 46 | else: 47 | escaped_value = value.encode("raw_unicode_escape") 48 | if '\\u' in escaped_value: 49 | return escaped_value.replace('\\u', '\\U+') 50 | else: 51 | return value 52 | 53 | # end of Python 2/3 adaption 54 | 55 | 56 | def int2hex(value): 57 | return hex(value)[2:].upper() 58 | 59 | 60 | def hex2int(string): 61 | return int(string, 16) 62 | 63 | 64 | def set_flag(value, bitmask, switch_on=True): 65 | if switch_on: 66 | return value | bitmask 67 | else: 68 | return value & ~bitmask 69 | 70 | 71 | def iterflatlist(alist): 72 | for element in alist: 73 | if hasattr(element, "__iter__") and not is_string(element): 74 | for item in iterflatlist(element): 75 | yield item 76 | else: 77 | yield element 78 | -------------------------------------------------------------------------------- /dxfwrite/vector2d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | # Purpose: 2d vector math 4 | # module belongs to package dxfwrite 5 | # Created: 16.03.2010 6 | # Copyright (C) 2010, Manfred Moitzi 7 | # License: MIT License 8 | """ 9 | 2d vector math module 10 | """ 11 | 12 | __author__ = "mozman " 13 | 14 | from math import hypot, atan2, sin, cos 15 | 16 | 17 | def vector2d(vector): 18 | """ return a 2d vector """ 19 | return (float(vector[0]), float(vector[1])) 20 | 21 | 22 | def vector2angle(vector): 23 | """ get angle of vector """ 24 | return atan2(vector[1], vector[0]) 25 | 26 | 27 | def angle2uv(angle): 28 | """ get unit_vector from angle """ 29 | return (cos(angle), sin(angle)) 30 | 31 | 32 | def magnitude(vector): 33 | """ length of a 2d vector """ 34 | return hypot(vector[0], vector[1]) 35 | 36 | 37 | def unit_vector(vector): 38 | """ 2d unit vector """ 39 | return vdiv_scalar(vector, magnitude(vector)) 40 | 41 | 42 | def normal_vector(vector): 43 | """ 2d perpendicular vector """ 44 | return (-vector[1], vector[0]) 45 | 46 | 47 | def distance(point1, point2): 48 | """ calc distance between two 2d points """ 49 | return hypot(point1[0] - point2[0], point1[1] - point2[1]) 50 | 51 | 52 | def midpoint(point1, point2): 53 | """ calc midpoint between point1 and point2 """ 54 | return ((point1[0] + point2[0]) * .5, (point1[1] + point2[1]) * .5) 55 | 56 | 57 | def vsub(vector1, vector2): 58 | """ substract vectors """ 59 | return (vector1[0] - vector2[0], vector1[1] - vector2[1]) 60 | 61 | 62 | def vadd(vector1, vector2): 63 | """ add vectors """ 64 | return (vector1[0] + vector2[0], vector1[1] + vector2[1]) 65 | 66 | 67 | def vdiv_scalar(vector, scalar): 68 | """ div vectors """ 69 | return (vector[0] / scalar, vector[1] / scalar) 70 | 71 | 72 | def vmul_scalar(vector, scalar): 73 | """ mul vector with scalar """ 74 | return (vector[0] * scalar, vector[1] * scalar) 75 | -------------------------------------------------------------------------------- /dxfwrite/vector3d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding:utf-8 3 | # Created: 27.03.2010 4 | # Purpose: 3d vectormath 5 | # module belongs to package dxfwrite 6 | # Copyright (C) 2010, Manfred Moitzi 7 | # License: MIT License 8 | """ 9 | 3d vector math module 10 | """ 11 | 12 | __author__ = "mozman " 13 | 14 | 15 | def vector3d(vector): 16 | """ return a 3d vector """ 17 | if len(vector) == 2: 18 | return float(vector[0]), float(vector[1]), 0. 19 | else: 20 | return float(vector[0]), float(vector[1]), float(vector[2]) 21 | 22 | 23 | def magnitude(vector): 24 | """ get magnitude (length) of vector """ 25 | return (vector[0] ** 2 + vector[1] ** 2 + vector[2] ** 2) ** .5 26 | 27 | 28 | def unit_vector(vector): 29 | """ get unit-vector of 3D vector (magnitude = 1.0) """ 30 | m = magnitude(vector) 31 | return vector[0] / m, vector[1] / m, vector[2] / m 32 | 33 | 34 | def dot_product(vector1, vector2): 35 | """ get dot-product for vectors """ 36 | return reduce(lambda x, y: x + y, 37 | (a * b for a, b in zip(vector1, vector2))) 38 | 39 | 40 | def cross_product(vector1, vector2): 41 | """ get cross-product for 3D vectors """ 42 | a1, a2, a3 = vector1 43 | b1, b2, b3 = vector2 44 | return a2 * b3 - a3 * b2, a3 * b1 - a1 * b3, a1 * b2 - a2 * b1 45 | 46 | 47 | def distance(point1, point2): 48 | """ calc distance between two 3d points """ 49 | return ((point1[0] - point2[0]) ** 2 + 50 | (point1[1] - point2[1]) ** 2 + 51 | (point1[2] - point2[2]) ** 2) ** 0.5 52 | 53 | 54 | def midpoint(point1, point2): 55 | """ calc midpoint between point1 and point2 """ 56 | return ((point1[0] + point2[0]) * .5, 57 | (point1[1] + point2[1]) * .5, 58 | (point1[2] + point2[2]) * .5) 59 | -------------------------------------------------------------------------------- /i18n/profiletool.pro: -------------------------------------------------------------------------------- 1 | FORMS = ../ui/profiletool.ui \ 2 | ../ui/about.ui 3 | 4 | SOURCES = ../profileplugin.py \ 5 | ../ui/ptdockwidget.py \ 6 | ../ui/dlgabout.py 7 | 8 | TRANSLATIONS = profiletool_de.ts 9 | -------------------------------------------------------------------------------- /i18n/profiletool_de.qm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/i18n/profiletool_de.qm -------------------------------------------------------------------------------- /icons/profileIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/icons/profileIcon.png -------------------------------------------------------------------------------- /pyqtgraph/GraphicsScene/__init__.py: -------------------------------------------------------------------------------- 1 | from .GraphicsScene import * 2 | -------------------------------------------------------------------------------- /pyqtgraph/PlotData.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | class PlotData(object): 5 | """ 6 | Class used for managing plot data 7 | - allows data sharing between multiple graphics items (curve, scatter, graph..) 8 | - each item may define the columns it needs 9 | - column groupings ('pos' or x, y, z) 10 | - efficiently appendable 11 | - log, fft transformations 12 | - color mode conversion (float/byte/qcolor) 13 | - pen/brush conversion 14 | - per-field cached masking 15 | - allows multiple masking fields (different graphics need to mask on different criteria) 16 | - removal of nan/inf values 17 | - option for single value shared by entire column 18 | - cached downsampling 19 | - cached min / max / hasnan / isuniform 20 | """ 21 | def __init__(self): 22 | self.fields = {} 23 | 24 | self.maxVals = {} ## cache for max/min 25 | self.minVals = {} 26 | 27 | def addFields(self, **fields): 28 | for f in fields: 29 | if f not in self.fields: 30 | self.fields[f] = None 31 | 32 | def hasField(self, f): 33 | return f in self.fields 34 | 35 | def __getitem__(self, field): 36 | return self.fields[field] 37 | 38 | def __setitem__(self, field, val): 39 | self.fields[field] = val 40 | 41 | def max(self, field): 42 | mx = self.maxVals.get(field, None) 43 | if mx is None: 44 | mx = np.max(self[field]) 45 | self.maxVals[field] = mx 46 | return mx 47 | 48 | def min(self, field): 49 | mn = self.minVals.get(field, None) 50 | if mn is None: 51 | mn = np.min(self[field]) 52 | self.minVals[field] = mn 53 | return mn 54 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtCore/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/Qt/QtCore/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtCore/__init__.pyi: -------------------------------------------------------------------------------- 1 | # Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py 2 | from PySide2.QtCore import * 3 | from PyQt5.QtCore import * 4 | from PySide6.QtCore import * 5 | from PyQt6.QtCore import * 6 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtGui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/Qt/QtGui/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtGui/__init__.pyi: -------------------------------------------------------------------------------- 1 | # Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py 2 | from PySide2.QtGui import * 3 | from PyQt5.QtGui import * 4 | from PySide6.QtGui import * 5 | from PyQt6.QtGui import * 6 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtSvg.pyi: -------------------------------------------------------------------------------- 1 | # Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py 2 | from PySide2.QtSvg import * 3 | from PyQt5.QtSvg import * 4 | from PySide6.QtSvg import * 5 | from PyQt6.QtSvg import * 6 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtTest.pyi: -------------------------------------------------------------------------------- 1 | # Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py 2 | from PySide2.QtTest import * 3 | from PyQt5.QtTest import * 4 | from PySide6.QtTest import * 5 | from PyQt6.QtTest import * 6 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtWidgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/Qt/QtWidgets/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/Qt/QtWidgets/__init__.pyi: -------------------------------------------------------------------------------- 1 | # Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py 2 | from PySide2.QtWidgets import * 3 | from PyQt5.QtWidgets import * 4 | from PySide6.QtWidgets import * 5 | from PyQt6.QtWidgets import * 6 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/__init__.pyi: -------------------------------------------------------------------------------- 1 | """ 2 | This stub file is to aid in the PyCharm and VSCode auto-completion of the Qt imports. 3 | """ 4 | 5 | from . import QtCore as QtCore 6 | from . import QtGui as QtGui 7 | from . import QtSvg as QtSvg 8 | from . import QtTest as QtTest 9 | from . import QtWidgets as QtWidgets 10 | 11 | App: QtWidgets.QApplication 12 | VERSION_INFO: str 13 | QT_LIB: str 14 | QtVersion: str 15 | 16 | def exec_() -> QtWidgets.QApplication: ... 17 | def mkQApp(name: str | None = None) -> QtWidgets.QApplication: ... 18 | def isQObjectAlive(obj: QtCore.QObject) -> bool: ... 19 | -------------------------------------------------------------------------------- /pyqtgraph/Qt/compat/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/Qt/compat/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/ThreadsafeTimer.py: -------------------------------------------------------------------------------- 1 | from .Qt import QtCore 2 | 3 | __all__ = ['ThreadsafeTimer'] 4 | 5 | class ThreadsafeTimer(QtCore.QObject): 6 | """ 7 | Thread-safe replacement for QTimer. 8 | """ 9 | 10 | timeout = QtCore.Signal() 11 | sigTimerStopRequested = QtCore.Signal() 12 | sigTimerStartRequested = QtCore.Signal(object) 13 | 14 | def __init__(self): 15 | QtCore.QObject.__init__(self) 16 | self.timer = QtCore.QTimer() 17 | self.timer.timeout.connect(self.timerFinished) 18 | self.timer.moveToThread(QtCore.QCoreApplication.instance().thread()) 19 | self.moveToThread(QtCore.QCoreApplication.instance().thread()) 20 | self.sigTimerStopRequested.connect(self.stop, QtCore.Qt.ConnectionType.QueuedConnection) 21 | self.sigTimerStartRequested.connect(self.start, QtCore.Qt.ConnectionType.QueuedConnection) 22 | 23 | 24 | def start(self, timeout): 25 | isGuiThread = QtCore.QThread.currentThread() == QtCore.QCoreApplication.instance().thread() 26 | if isGuiThread: 27 | #print "start timer", self, "from gui thread" 28 | self.timer.start(int(timeout)) 29 | else: 30 | #print "start timer", self, "from remote thread" 31 | self.sigTimerStartRequested.emit(timeout) 32 | 33 | def stop(self): 34 | isGuiThread = QtCore.QThread.currentThread() == QtCore.QCoreApplication.instance().thread() 35 | if isGuiThread: 36 | #print "stop timer", self, "from gui thread" 37 | self.timer.stop() 38 | else: 39 | #print "stop timer", self, "from remote thread" 40 | self.sigTimerStopRequested.emit() 41 | 42 | def timerFinished(self): 43 | self.timeout.emit() 44 | -------------------------------------------------------------------------------- /pyqtgraph/Transform3D.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from . import functions as fn 4 | from .Qt import QtGui 5 | from .Vector import Vector 6 | 7 | 8 | class Transform3D(QtGui.QMatrix4x4): 9 | """ 10 | Extension of QMatrix4x4 with some helpful methods added. 11 | """ 12 | def __init__(self, *args): 13 | if len(args) == 1: 14 | if isinstance(args[0], (list, tuple, np.ndarray)): 15 | args = [x for y in args[0] for x in y] 16 | if len(args) != 16: 17 | raise TypeError("Single argument to Transform3D must have 16 elements.") 18 | elif isinstance(args[0], QtGui.QMatrix4x4): 19 | args = list(args[0].copyDataTo()) 20 | 21 | QtGui.QMatrix4x4.__init__(self, *args) 22 | 23 | def matrix(self, nd=3): 24 | if nd == 3: 25 | return np.array(self.copyDataTo()).reshape(4,4) 26 | elif nd == 2: 27 | m = np.array(self.copyDataTo()).reshape(4,4) 28 | m[2] = m[3] 29 | m[:,2] = m[:,3] 30 | return m[:3,:3] 31 | else: 32 | raise Exception("Argument 'nd' must be 2 or 3") 33 | 34 | def map(self, obj): 35 | """ 36 | Extends QMatrix4x4.map() to allow mapping (3, ...) arrays of coordinates 37 | """ 38 | if isinstance(obj, np.ndarray) and obj.shape[0] in (2,3): 39 | if obj.ndim >= 2: 40 | return fn.transformCoordinates(self, obj) 41 | elif obj.ndim == 1: 42 | v = QtGui.QMatrix4x4.map(self, Vector(obj)) 43 | return np.array([v.x(), v.y(), v.z()])[:obj.shape[0]] 44 | elif isinstance(obj, (list, tuple)): 45 | v = QtGui.QMatrix4x4.map(self, Vector(obj)) 46 | return type(obj)([v.x(), v.y(), v.z()])[:len(obj)] 47 | else: 48 | return QtGui.QMatrix4x4.map(self, obj) 49 | 50 | def inverted(self): 51 | inv, b = QtGui.QMatrix4x4.inverted(self) 52 | return Transform3D(inv), b 53 | -------------------------------------------------------------------------------- /pyqtgraph/canvas/TransformGuiTemplate.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 224 10 | 117 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | PyQtGraph 21 | 22 | 23 | 24 | 1 25 | 26 | 27 | 0 28 | 29 | 30 | 31 | 32 | Translate: 33 | 34 | 35 | 36 | 37 | 38 | 39 | Rotate: 40 | 41 | 42 | 43 | 44 | 45 | 46 | Scale: 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Mirror 59 | 60 | 61 | 62 | 63 | 64 | 65 | Reflect 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /pyqtgraph/canvas/__init__.py: -------------------------------------------------------------------------------- 1 | from .Canvas import * 2 | from .CanvasItem import * 3 | -------------------------------------------------------------------------------- /pyqtgraph/colors/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/colors/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/colors/maps/PAL-relaxed.hex: -------------------------------------------------------------------------------- 1 | ; PyQtGraph's "relaxed" plot color palette 2 | ; This is the darker variant for plotting on a light background ("light mode") 3 | ; 4 | #f97f10 ; orange 5 | #e5bb00 ; yellow 6 | #94ab00 ; grass 7 | #12a12a ; green 8 | #007c8c ; sea 9 | #0e56c2 ; blue 10 | #813be3 ; indigo 11 | #c01188 ; purple 12 | #e23512 ; red 13 | #f97f10 ; orange 14 | -------------------------------------------------------------------------------- /pyqtgraph/colors/maps/PAL-relaxed_bright.hex: -------------------------------------------------------------------------------- 1 | ; PyQtGraph's "relaxed" plot color palette 2 | ; This is the brighter variant for plotting on a dark background ("dark mode") 3 | ; 4 | #ff9d47 ; orange 5 | #f7e100 ; yellow 6 | #b3cf00 ; grass 7 | #1ec23a ; green 8 | #00a0b5 ; sea 9 | #1f78ff ; blue 10 | #a54dff ; indigo 11 | #e22ca8 ; purple 12 | #ff532b ; red 13 | #ff9d47 ; orange 14 | -------------------------------------------------------------------------------- /pyqtgraph/console/CmdInput.py: -------------------------------------------------------------------------------- 1 | from ..Qt import QtCore, QtWidgets 2 | 3 | 4 | class CmdInput(QtWidgets.QLineEdit): 5 | 6 | sigExecuteCmd = QtCore.Signal(object) 7 | 8 | def __init__(self, parent): 9 | QtWidgets.QLineEdit.__init__(self, parent) 10 | self.ps1 = ">>> " 11 | self.ps2 = "... " 12 | self.history = [""] 13 | self.ptr = 0 14 | self.setMultiline(False) 15 | 16 | def setMultiline(self, ml): 17 | if ml: 18 | self.setPlaceholderText(self.ps2) 19 | else: 20 | self.setPlaceholderText(self.ps1) 21 | 22 | def keyPressEvent(self, ev): 23 | if ev.key() == QtCore.Qt.Key.Key_Up: 24 | if self.ptr < len(self.history) - 1: 25 | self.setHistory(self.ptr+1) 26 | ev.accept() 27 | return 28 | elif ev.key() == QtCore.Qt.Key.Key_Down: 29 | if self.ptr > 0: 30 | self.setHistory(self.ptr-1) 31 | ev.accept() 32 | return 33 | elif ev.key() in (QtCore.Qt.Key.Key_Return, QtCore.Qt.Key.Key_Enter): 34 | self.execCmd() 35 | else: 36 | super().keyPressEvent(ev) 37 | self.history[0] = self.text() 38 | 39 | def execCmd(self): 40 | cmd = self.text() 41 | if len(self.history) == 1 or cmd != self.history[1]: 42 | self.history.insert(1, cmd) 43 | self.history[0] = "" 44 | self.setHistory(0) 45 | self.sigExecuteCmd.emit(cmd) 46 | 47 | def setHistory(self, num): 48 | self.ptr = num 49 | self.setText(self.history[self.ptr]) 50 | -------------------------------------------------------------------------------- /pyqtgraph/console/__init__.py: -------------------------------------------------------------------------------- 1 | from .Console import ConsoleWidget 2 | -------------------------------------------------------------------------------- /pyqtgraph/dockarea/__init__.py: -------------------------------------------------------------------------------- 1 | from .Dock import Dock, DockLabel 2 | from .DockArea import DockArea 3 | -------------------------------------------------------------------------------- /pyqtgraph/examples/Arrow.py: -------------------------------------------------------------------------------- 1 | """ 2 | Display an animated arrowhead following a curve. 3 | This example uses the CurveArrow class, which is a combination 4 | of ArrowItem and CurvePoint. 5 | 6 | To place a static arrow anywhere in a scene, use ArrowItem. 7 | To attach other types of item to a curve, use CurvePoint. 8 | """ 9 | 10 | import numpy as np 11 | 12 | import pyqtgraph as pg 13 | from pyqtgraph.Qt import QtCore, QtWidgets 14 | 15 | app = pg.mkQApp("Arrow Example") 16 | 17 | w = QtWidgets.QMainWindow() 18 | cw = pg.GraphicsLayoutWidget() 19 | w.show() 20 | w.resize(400,600) 21 | w.setCentralWidget(cw) 22 | w.setWindowTitle('pyqtgraph example: Arrow') 23 | 24 | p = cw.addPlot(row=0, col=0) 25 | p2 = cw.addPlot(row=1, col=0) 26 | 27 | ## variety of arrow shapes 28 | a1 = pg.ArrowItem(angle=-160, tipAngle=60, headLen=40, tailLen=40, tailWidth=20, pen={'color': 'w', 'width': 3}) 29 | a2 = pg.ArrowItem(angle=-120, tipAngle=30, baseAngle=20, headLen=40, tailLen=40, tailWidth=8, pen=None, brush='y') 30 | a3 = pg.ArrowItem(angle=-60, baseAngle=20, headLen=40, headWidth=20, tailLen=None, brush=None) 31 | a4 = pg.ArrowItem(angle=-20, tipAngle=30, baseAngle=-30, headLen=40, tailLen=None) 32 | a2.setPos(10,0) 33 | a3.setPos(20,0) 34 | a4.setPos(30,0) 35 | p.addItem(a1) 36 | p.addItem(a2) 37 | p.addItem(a3) 38 | p.addItem(a4) 39 | p.setRange(QtCore.QRectF(-20, -10, 60, 20)) 40 | 41 | 42 | ## Animated arrow following curve 43 | c = p2.plot(x=np.sin(np.linspace(0, 2*np.pi, 1000)), y=np.cos(np.linspace(0, 6*np.pi, 1000))) 44 | a = pg.CurveArrow(c) 45 | a.setStyle(headLen=40) 46 | p2.addItem(a) 47 | anim = a.makeAnimation(loop=-1) 48 | anim.start() 49 | 50 | if __name__ == '__main__': 51 | pg.exec() 52 | -------------------------------------------------------------------------------- /pyqtgraph/examples/AxisItem_label_overlap.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example demonstrates many of the 2D plotting capabilities 3 | in pyqtgraph. All of the plots may be panned/scaled by dragging with 4 | the left/right mouse buttons. Right click on any plot to show a context menu. 5 | """ 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | from pyqtgraph.Qt import QtGui 11 | 12 | app = pg.mkQApp("AxisItem - label overlap settings") 13 | 14 | win = pg.GraphicsLayoutWidget(show=True, title="AxisItem - label overlap settings") 15 | win.resize(800,600) 16 | win.setWindowTitle("AxisItem - label overlap settings") 17 | 18 | # Enable antialiasing for prettier plots 19 | pg.setConfigOptions(antialias=True) 20 | 21 | x_data = np.arange(101) + 1_000. 22 | y_data = np.random.normal(scale=40., size=101) 23 | 24 | font = QtGui.QFont() 25 | font.setPointSize(14) # A larger font makes the effects more visible 26 | 27 | p1 = win.addPlot(title="Default settings: Overlap allowed for y axis", x=x_data, y=y_data) 28 | for axis_key in ('top', 'bottom', 'left', 'right'): 29 | ax = p1.getAxis(axis_key) 30 | ax.setTickFont( font ) 31 | 32 | p2 = win.addPlot(title="Overlap allowed for X axis", x=x_data, y=y_data) 33 | for axis_key, hide_overlap in ( 34 | ('top' , False), 35 | ('bottom', False), 36 | ('left' , True ), 37 | ('right' , True ) 38 | ): 39 | ax = p2.getAxis(axis_key) 40 | ax.setStyle( hideOverlappingLabels = hide_overlap ) 41 | ax.setTickFont( font ) 42 | 43 | win.nextRow() 44 | 45 | p3 = win.addPlot(title="All overlap disabled", x=x_data, y=y_data) 46 | for axis_key in ('top', 'bottom', 'left', 'right'): 47 | ax = p3.getAxis(axis_key) 48 | ax.setStyle( hideOverlappingLabels = True ) 49 | ax.setTickFont( font ) 50 | 51 | p4 = win.addPlot(title="All overlap enabled, custom tolerances", x=x_data, y=y_data) 52 | for axis_key, tolerance in ( 53 | ('top' , 15 ), 54 | ('bottom', 200 ), 55 | ('left' , 100 ), 56 | ('right' , 15 ) 57 | ): 58 | ax = p4.getAxis(axis_key) 59 | ax.setStyle( hideOverlappingLabels = tolerance ) 60 | ax.setTickFont( font ) 61 | 62 | # Link all axes and set viewing range with no padding: 63 | for p in (p1, p2, p3, p4): 64 | p.showAxes(True, showValues=(True, True, True, True)) 65 | if p != p1: 66 | p.setXLink(p1) 67 | p.setYLink(p1) 68 | ax.setTickFont( font ) 69 | p1.setXRange( 1_000., 1_100., padding=0.0) 70 | p1.setYRange(-60., 60., padding=0.0) 71 | 72 | 73 | if __name__ == '__main__': 74 | pg.exec() 75 | -------------------------------------------------------------------------------- /pyqtgraph/examples/BarGraphItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple example using BarGraphItem 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | win = pg.plot() 10 | win.setWindowTitle('pyqtgraph example: BarGraphItem') 11 | 12 | x = np.arange(10) 13 | y1 = np.sin(x) 14 | y2 = 1.1 * np.sin(x+1) 15 | y3 = 1.2 * np.sin(x+2) 16 | 17 | bg1 = pg.BarGraphItem(x=x, height=y1, width=0.3, brush='r') 18 | bg2 = pg.BarGraphItem(x=x+0.33, height=y2, width=0.3, brush='g') 19 | bg3 = pg.BarGraphItem(x=x+0.66, height=y3, width=0.3, brush='b') 20 | 21 | win.addItem(bg1) 22 | win.addItem(bg2) 23 | win.addItem(bg3) 24 | 25 | 26 | # Final example shows how to handle mouse clicks: 27 | class BarGraph(pg.BarGraphItem): 28 | def mouseClickEvent(self, event): 29 | print("clicked") 30 | 31 | 32 | bg = BarGraph(x=x, y=y1*0.3+2, height=0.4+y1*0.2, width=0.8) 33 | win.addItem(bg) 34 | 35 | if __name__ == '__main__': 36 | pg.exec() 37 | -------------------------------------------------------------------------------- /pyqtgraph/examples/CLIexample.py: -------------------------------------------------------------------------------- 1 | """ 2 | Display a plot and an image with minimal setup. 3 | 4 | pg.plot() and pg.image() are indended to be used from an interactive prompt 5 | to allow easy data inspection (but note that PySide unfortunately does not 6 | call the Qt event loop while the interactive prompt is running, in this case 7 | it is necessary to call QApplication.exec_() to make the windows appear). 8 | """ 9 | 10 | import numpy as np 11 | 12 | import pyqtgraph as pg 13 | 14 | data = np.random.normal(size=1000) 15 | pg.plot(data, title="Simplest possible plotting example") 16 | 17 | data = np.random.normal(size=(500,500)) 18 | pg.image(data, title="Simplest possible image example") 19 | 20 | if __name__ == '__main__': 21 | pg.exec() 22 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ColorButton.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple example demonstrating a button which displays a colored rectangle 3 | and allows the user to select a new color by clicking on the button. 4 | """ 5 | 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtWidgets 9 | 10 | app = pg.mkQApp("ColorButton Example") 11 | win = QtWidgets.QMainWindow() 12 | btn = pg.ColorButton() 13 | win.setCentralWidget(btn) 14 | win.show() 15 | win.setWindowTitle('pyqtgraph example: ColorButton') 16 | 17 | def change(btn): 18 | print("change", btn.color()) 19 | def done(btn): 20 | print("done", btn.color()) 21 | 22 | btn.sigColorChanging.connect(change) 23 | btn.sigColorChanged.connect(done) 24 | 25 | if __name__ == '__main__': 26 | pg.exec() 27 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ConsoleWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | ConsoleWidget is used to allow execution of user-supplied python commands 3 | in an application. It also includes a command history and functionality for trapping 4 | and inspecting stack traces. 5 | 6 | """ 7 | 8 | import numpy as np 9 | 10 | import pyqtgraph as pg 11 | import pyqtgraph.console 12 | 13 | app = pg.mkQApp() 14 | 15 | ## build an initial namespace for console commands to be executed in (this is optional; 16 | ## the user can always import these modules manually) 17 | namespace = {'pg': pg, 'np': np} 18 | 19 | ## initial text to display in the console 20 | text = """ 21 | This is an interactive python console. The numpy and pyqtgraph modules have already been imported 22 | as 'np' and 'pg'. 23 | 24 | Go, play. 25 | """ 26 | c = pyqtgraph.console.ConsoleWidget(namespace=namespace, text=text) 27 | c.resize(800, 400) 28 | c.show() 29 | c.setWindowTitle('pyqtgraph example: ConsoleWidget') 30 | 31 | if __name__ == '__main__': 32 | pg.exec() 33 | -------------------------------------------------------------------------------- /pyqtgraph/examples/DataSlicing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrate a simple data-slicing task: given 3D data (displayed at top), select 3 | a 2D plane and interpolate data along that plane to generate a slice image 4 | (displayed at bottom). 5 | """ 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | from pyqtgraph.Qt import QtWidgets 11 | 12 | app = pg.mkQApp("Data Slicing Example") 13 | 14 | ## Create window with two ImageView widgets 15 | win = QtWidgets.QMainWindow() 16 | win.resize(800,800) 17 | win.setWindowTitle('pyqtgraph example: DataSlicing') 18 | cw = QtWidgets.QWidget() 19 | win.setCentralWidget(cw) 20 | l = QtWidgets.QGridLayout() 21 | cw.setLayout(l) 22 | imv1 = pg.ImageView() 23 | imv2 = pg.ImageView() 24 | l.addWidget(imv1, 0, 0) 25 | l.addWidget(imv2, 1, 0) 26 | win.show() 27 | 28 | roi = pg.LineSegmentROI([[10, 64], [120,64]], pen='r') 29 | imv1.addItem(roi) 30 | 31 | x1 = np.linspace(-30, 10, 128)[:, np.newaxis, np.newaxis] 32 | x2 = np.linspace(-20, 20, 128)[:, np.newaxis, np.newaxis] 33 | y = np.linspace(-30, 10, 128)[np.newaxis, :, np.newaxis] 34 | z = np.linspace(-20, 20, 128)[np.newaxis, np.newaxis, :] 35 | d1 = np.sqrt(x1**2 + y**2 + z**2) 36 | d2 = 2*np.sqrt(x1[::-1]**2 + y**2 + z**2) 37 | d3 = 4*np.sqrt(x2**2 + y[:,::-1]**2 + z**2) 38 | data = (np.sin(d1) / d1**2) + (np.sin(d2) / d2**2) + (np.sin(d3) / d3**2) 39 | 40 | def update(): 41 | global data, imv1, imv2 42 | d2 = roi.getArrayRegion(data, imv1.imageItem, axes=(1,2)) 43 | imv2.setImage(d2) 44 | 45 | roi.sigRegionChanged.connect(update) 46 | 47 | 48 | ## Display the data 49 | imv1.setImage(data) 50 | imv1.setHistogramRange(-0.01, 0.01) 51 | imv1.setLevels(-0.003, 0.003) 52 | 53 | update() 54 | 55 | if __name__ == '__main__': 56 | pg.exec() 57 | -------------------------------------------------------------------------------- /pyqtgraph/examples/DataTreeWidget.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Simple use of DataTreeWidget to display a structure of nested dicts, lists, and arrays 4 | """ 5 | 6 | import numpy as np 7 | 8 | import pyqtgraph as pg 9 | 10 | 11 | # for generating a traceback object to display 12 | def some_func1(): 13 | return some_func2() 14 | def some_func2(): 15 | try: 16 | raise Exception() 17 | except: 18 | import sys 19 | return sys.exc_info()[2] 20 | 21 | 22 | app = pg.mkQApp("DataTreeWidget Example") 23 | d = { 24 | 'a list': [1,2,3,4,5,6, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"], 25 | 'a dict': { 26 | 'x': 1, 27 | 'y': 2, 28 | 'z': 'three' 29 | }, 30 | 'an array': np.random.randint(10, size=(40,10)), 31 | 'a traceback': some_func1(), 32 | 'a function': some_func1, 33 | 'a class': pg.DataTreeWidget, 34 | } 35 | 36 | tree = pg.DataTreeWidget(data=d) 37 | tree.show() 38 | tree.setWindowTitle('pyqtgraph example: DataTreeWidget') 39 | tree.resize(600,600) 40 | 41 | 42 | if __name__ == '__main__': 43 | pg.exec() 44 | -------------------------------------------------------------------------------- /pyqtgraph/examples/DateAxisItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates the usage of DateAxisItem to display properly-formatted 3 | timestamps on x-axis which automatically adapt to current zoom level. 4 | 5 | """ 6 | 7 | import time 8 | 9 | import numpy as np 10 | 11 | import pyqtgraph as pg 12 | 13 | app = pg.mkQApp("DateAxisItem Example") 14 | 15 | # Create a plot with a date-time axis 16 | w = pg.PlotWidget(axisItems = {'bottom': pg.DateAxisItem()}) 17 | w.showGrid(x=True, y=True) 18 | 19 | # Plot sin(1/x^2) with timestamps in the last 100 years 20 | now = time.time() 21 | x = np.linspace(2*np.pi, 1000*2*np.pi, 8301) 22 | w.plot(now-(2*np.pi/x)**2*100*np.pi*1e7, np.sin(x), symbol='o') 23 | 24 | w.setWindowTitle('pyqtgraph example: DateAxisItem') 25 | w.show() 26 | 27 | if __name__ == '__main__': 28 | pg.exec() 29 | -------------------------------------------------------------------------------- /pyqtgraph/examples/DateAxisItem_QtDesigner.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates the usage of DateAxisItem in a layout created with Qt Designer. 3 | 4 | The spotlight here is on the 'setAxisItems' method, without which 5 | one would have to subclass plotWidget in order to attach a dateaxis to it. 6 | """ 7 | 8 | import os 9 | import time 10 | 11 | import numpy as np 12 | 13 | import pyqtgraph as pg 14 | from pyqtgraph.Qt import QtWidgets, loadUiType 15 | 16 | pg.setConfigOption('background', 'w') 17 | pg.setConfigOption('foreground', 'k') 18 | 19 | BLUE = pg.mkPen('#1f77b4') 20 | 21 | path = os.path.dirname(os.path.abspath(__file__)) 22 | uiFile = os.path.join(path, 'DateAxisItem_QtDesigner.ui') 23 | Design, _ = loadUiType(uiFile) 24 | 25 | class ExampleApp(QtWidgets.QMainWindow, Design): 26 | def __init__(self): 27 | super().__init__() 28 | self.setupUi(self) 29 | now = time.time() 30 | # Plot random values with timestamps in the last 6 months 31 | timestamps = np.linspace(now - 6*30*24*3600, now, 100) 32 | self.curve = self.plotWidget.plot(x=timestamps, y=np.random.rand(100), 33 | symbol='o', symbolSize=5, pen=BLUE) 34 | # 'o' circle 't' triangle 'd' diamond '+' plus 's' square 35 | self.plotWidget.setAxisItems({'bottom': pg.DateAxisItem()}) 36 | self.plotWidget.showGrid(x=True, y=True) 37 | 38 | app = pg.mkQApp("DateAxisItem_QtDesigner Example") 39 | window = ExampleApp() 40 | window.setWindowTitle('pyqtgraph example: DateAxisItem_QtDesigner') 41 | window.show() 42 | 43 | if __name__ == '__main__': 44 | pg.exec() 45 | -------------------------------------------------------------------------------- /pyqtgraph/examples/DateAxisItem_QtDesigner.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 536 10 | 381 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 0 27 | 0 28 | 536 29 | 18 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | PlotWidget 38 | QGraphicsView 39 |
pyqtgraph
40 |
41 |
42 | 43 | 44 |
45 | -------------------------------------------------------------------------------- /pyqtgraph/examples/DiffTreeWidget.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | Simple use of DiffTreeWidget to display differences between structures of 4 | nested dicts, lists, and arrays. 5 | """ 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | 11 | app = pg.mkQApp("DiffTreeWidget Example") 12 | A = { 13 | 'a list': [1,2,2,4,5,6, {'nested1': 'aaaa', 'nested2': 'bbbbb'}, "seven"], 14 | 'a dict': { 15 | 'x': 1, 16 | 'y': 2, 17 | 'z': 'three' 18 | }, 19 | 'an array': np.random.randint(10, size=(40,10)), 20 | #'a traceback': some_func1(), 21 | #'a function': some_func1, 22 | #'a class': pg.DataTreeWidget, 23 | } 24 | 25 | B = { 26 | 'a list': [1,2,3,4,5,5, {'nested1': 'aaaaa', 'nested2': 'bbbbb'}, "seven"], 27 | 'a dict': { 28 | 'x': 2, 29 | 'y': 2, 30 | 'z': 'three', 31 | 'w': 5 32 | }, 33 | 'another dict': {1:2, 2:3, 3:4}, 34 | 'an array': np.random.randint(10, size=(40,10)), 35 | } 36 | 37 | tree = pg.DiffTreeWidget() 38 | tree.setData(A, B) 39 | tree.show() 40 | tree.setWindowTitle('pyqtgraph example: DiffTreeWidget') 41 | tree.resize(1000, 800) 42 | 43 | 44 | if __name__ == '__main__': 45 | pg.exec() 46 | -------------------------------------------------------------------------------- /pyqtgraph/examples/Draw.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrate ability of ImageItem to be used as a canvas for painting with 3 | the mouse. 4 | """ 5 | 6 | import numpy as np 7 | 8 | import pyqtgraph as pg 9 | from pyqtgraph.Qt import QtCore 10 | 11 | app = pg.mkQApp("Draw Example") 12 | 13 | ## Create window with GraphicsView widget 14 | w = pg.GraphicsView() 15 | w.show() 16 | w.resize(800,800) 17 | w.setWindowTitle('pyqtgraph example: Draw') 18 | 19 | view = pg.ViewBox() 20 | w.setCentralItem(view) 21 | 22 | ## lock the aspect ratio 23 | view.setAspectLocked(True) 24 | 25 | ## Create image item 26 | img = pg.ImageItem(np.zeros((200,200))) 27 | view.addItem(img) 28 | 29 | ## Set initial view bounds 30 | view.setRange(QtCore.QRectF(0, 0, 200, 200)) 31 | 32 | ## start drawing with 3x3 brush 33 | kern = np.array([ 34 | [0.0, 0.5, 0.0], 35 | [0.5, 1.0, 0.5], 36 | [0.0, 0.5, 0.0] 37 | ]) 38 | img.setDrawKernel(kern, mask=kern, center=(1,1), mode='add') 39 | img.setLevels([0, 10]) 40 | 41 | if __name__ == '__main__': 42 | pg.exec() 43 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ErrorBarItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates basic use of ErrorBarItem 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | pg.setConfigOptions(antialias=True) 10 | 11 | x = np.arange(10) 12 | y = np.arange(10) %3 13 | top = np.linspace(1.0, 3.0, 10) 14 | bottom = np.linspace(2, 0.5, 10) 15 | 16 | plt = pg.plot() 17 | plt.setWindowTitle('pyqtgraph example: ErrorBarItem') 18 | err = pg.ErrorBarItem(x=x, y=y, top=top, bottom=bottom, beam=0.5) 19 | plt.addItem(err) 20 | plt.plot(x, y, symbol='o', pen={'color': 0.8, 'width': 2}) 21 | 22 | if __name__ == '__main__': 23 | pg.exec() 24 | -------------------------------------------------------------------------------- /pyqtgraph/examples/FillBetweenItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates use of FillBetweenItem to fill the space between two plot curves. 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtCore 9 | 10 | #FIXME: When running on Qt5, not as perfect as on Qt4 11 | 12 | win = pg.plot() 13 | win.setWindowTitle('pyqtgraph example: FillBetweenItem') 14 | win.setXRange(-10, 10) 15 | win.setYRange(-10, 10) 16 | 17 | N = 200 18 | x = np.linspace(-10, 10, N) 19 | gauss = np.exp(-x**2 / 20.) 20 | mn = mx = np.zeros(len(x)) 21 | curves = [win.plot(x=x, y=np.zeros(len(x)), pen='k') for i in range(4)] 22 | brushes = [0.5, (100, 100, 255), 0.5] 23 | fills = [pg.FillBetweenItem(curves[0], curves[3], brushes[0]), 24 | pg.FillBetweenItem(curves[1], curves[2], brushes[1])] 25 | for f in fills: 26 | win.addItem(f) 27 | 28 | def update(): 29 | global mx, mn, curves, gauss, x 30 | a = 5 / abs(np.random.normal(loc=1, scale=0.2)) 31 | y1 = -np.abs(a*gauss + np.random.normal(size=len(x))) 32 | y2 = np.abs(a*gauss + np.random.normal(size=len(x))) 33 | 34 | s = 0.01 35 | mn = np.where(y1mx, y2, mx) * (1-s) + y2 * s 37 | curves[0].setData(x, mn) 38 | curves[1].setData(x, y1) 39 | curves[2].setData(x, y2) 40 | curves[3].setData(x, mx) 41 | 42 | 43 | timer = QtCore.QTimer() 44 | timer.timeout.connect(update) 45 | timer.start(30) 46 | 47 | 48 | if __name__ == '__main__': 49 | pg.exec() 50 | -------------------------------------------------------------------------------- /pyqtgraph/examples/Flowchart.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example demonstrates a very basic use of flowcharts: filter data, 3 | displaying both the input and output of the filter. The behavior of 4 | the filter can be reprogrammed by the user. 5 | 6 | Basic steps are: 7 | - create a flowchart and two plots 8 | - input noisy data to the flowchart 9 | - flowchart connects data to the first plot, where it is displayed 10 | - add a gaussian filter to lowpass the data, then display it in the second plot. 11 | """ 12 | 13 | import numpy as np 14 | 15 | import pyqtgraph as pg 16 | import pyqtgraph.metaarray as metaarray 17 | from pyqtgraph.flowchart import Flowchart 18 | from pyqtgraph.Qt import QtWidgets 19 | 20 | app = pg.mkQApp("Flowchart Example") 21 | 22 | ## Create main window with grid layout 23 | win = QtWidgets.QMainWindow() 24 | win.setWindowTitle('pyqtgraph example: Flowchart') 25 | cw = QtWidgets.QWidget() 26 | win.setCentralWidget(cw) 27 | layout = QtWidgets.QGridLayout() 28 | cw.setLayout(layout) 29 | 30 | ## Create flowchart, define input/output terminals 31 | fc = Flowchart(terminals={ 32 | 'dataIn': {'io': 'in'}, 33 | 'dataOut': {'io': 'out'} 34 | }) 35 | w = fc.widget() 36 | 37 | ## Add flowchart control panel to the main window 38 | layout.addWidget(fc.widget(), 0, 0, 2, 1) 39 | 40 | ## Add two plot widgets 41 | pw1 = pg.PlotWidget() 42 | pw2 = pg.PlotWidget() 43 | layout.addWidget(pw1, 0, 1) 44 | layout.addWidget(pw2, 1, 1) 45 | 46 | win.show() 47 | 48 | ## generate signal data to pass through the flowchart 49 | data = np.random.normal(size=1000) 50 | data[200:300] += 1 51 | data += np.sin(np.linspace(0, 100, 1000)) 52 | data = metaarray.MetaArray(data, info=[{'name': 'Time', 'values': np.linspace(0, 1.0, len(data))}, {}]) 53 | 54 | ## Feed data into the input terminal of the flowchart 55 | fc.setInput(dataIn=data) 56 | 57 | ## populate the flowchart with a basic set of processing nodes. 58 | ## (usually we let the user do this) 59 | plotList = {'Top Plot': pw1, 'Bottom Plot': pw2} 60 | 61 | pw1Node = fc.createNode('PlotWidget', pos=(0, -150)) 62 | pw1Node.setPlotList(plotList) 63 | pw1Node.setPlot(pw1) 64 | 65 | pw2Node = fc.createNode('PlotWidget', pos=(150, -150)) 66 | pw2Node.setPlot(pw2) 67 | pw2Node.setPlotList(plotList) 68 | 69 | fNode = fc.createNode('GaussianFilter', pos=(0, 0)) 70 | fNode.ctrls['sigma'].setValue(5) 71 | fc.connectTerminals(fc['dataIn'], fNode['In']) 72 | fc.connectTerminals(fc['dataIn'], pw1Node['In']) 73 | fc.connectTerminals(fNode['Out'], pw2Node['In']) 74 | fc.connectTerminals(fNode['Out'], fc['dataOut']) 75 | 76 | if __name__ == '__main__': 77 | pg.exec() 78 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLBarGraphItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example demonstrates the use of GLBarGraphItem. 3 | 4 | """ 5 | 6 | import numpy as np 7 | 8 | import pyqtgraph as pg 9 | import pyqtgraph.opengl as gl 10 | 11 | app = pg.mkQApp("GLBarGraphItem Example") 12 | w = gl.GLViewWidget() 13 | w.show() 14 | w.setWindowTitle('pyqtgraph example: GLBarGraphItem') 15 | w.setCameraPosition(distance=40) 16 | 17 | gx = gl.GLGridItem() 18 | gx.rotate(90, 0, 1, 0) 19 | gx.translate(-10, 0, 10) 20 | w.addItem(gx) 21 | gy = gl.GLGridItem() 22 | gy.rotate(90, 1, 0, 0) 23 | gy.translate(0, -10, 10) 24 | w.addItem(gy) 25 | gz = gl.GLGridItem() 26 | gz.translate(0, 0, 0) 27 | w.addItem(gz) 28 | 29 | # regular grid of starting positions 30 | pos = np.mgrid[0:10, 0:10, 0:1].reshape(3,10,10).transpose(1,2,0) 31 | # fixed widths, random heights 32 | size = np.empty((10,10,3)) 33 | size[...,0:2] = 0.4 34 | size[...,2] = np.random.normal(size=(10,10)) 35 | 36 | bg = gl.GLBarGraphItem(pos, size) 37 | w.addItem(bg) 38 | 39 | if __name__ == '__main__': 40 | pg.exec() 41 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLGradientLegendItem.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | 3 | import pyqtgraph as pg 4 | import pyqtgraph.opengl as gl 5 | 6 | app = pg.mkQApp() 7 | w = gl.GLViewWidget() 8 | w.show() 9 | w.setWindowTitle("pyqtgraph example: GLGradientLegendItem") 10 | w.setCameraPosition(distance=60) 11 | 12 | gx = gl.GLGridItem() 13 | gx.rotate(90, 0, 1, 0) 14 | w.addItem(gx) 15 | 16 | md = gl.MeshData.cylinder(rows=10, cols=20, radius=[5.0, 5], length=20.0) 17 | md._vertexes[:, 2] = md._vertexes[:, 2] - 10 18 | 19 | # set color based on z coordinates 20 | color_map = pg.colormap.get("CET-L10") 21 | 22 | h = md.vertexes()[:, 2] 23 | # remember these 24 | h_max, h_min = h.max(), h.min() 25 | h = (h - h_min) / (h_max - h_min) 26 | colors = color_map.map(h, mode="float") 27 | md.setFaceColors(colors) 28 | m = gl.GLMeshItem(meshdata=md, smooth=True) 29 | w.addItem(m) 30 | 31 | legendLabels = numpy.linspace(h_max, h_min, 5) 32 | legendPos = numpy.linspace(1, 0, 5) 33 | legend = dict(zip(map(str, legendLabels), legendPos)) 34 | 35 | gll = gl.GLGradientLegendItem( 36 | pos=(10, 10), size=(50, 300), gradient=color_map, labels=legend 37 | ) 38 | w.addItem(gll) 39 | 40 | ## Start Qt event loop unless running in interactive mode. 41 | if __name__ == "__main__": 42 | pg.exec() 43 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLGraphItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates use of GLGraphItem 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | import pyqtgraph.opengl as gl 9 | 10 | app = pg.mkQApp("GLGraphItem Example") 11 | w = gl.GLViewWidget() 12 | w.setCameraPosition(distance=20) 13 | w.show() 14 | 15 | edges = np.array([ 16 | [0, 2], 17 | [0, 3], 18 | [1, 2], 19 | [1, 3], 20 | [2, 3] 21 | ]) 22 | 23 | nodes = np.array( 24 | [ 25 | [0, 0, 0], 26 | [1, 0, 0], 27 | [0, 1, 0], 28 | [1, 1, 1] 29 | ] 30 | ) 31 | 32 | edgeColor=pg.glColor("w") 33 | 34 | gi = gl.GLGraphItem( 35 | edges=edges, 36 | nodePositions=nodes, 37 | edgeWidth=1., 38 | nodeSize=10. 39 | ) 40 | 41 | w.addItem(gi) 42 | 43 | if __name__ == "__main__": 44 | pg.exec() 45 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLImageItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use GLImageItem to display image data on rectangular planes. 3 | 4 | In this example, the image data is sampled from a volume and the image planes 5 | placed as if they slice through the volume. 6 | """ 7 | 8 | import numpy as np 9 | 10 | import pyqtgraph as pg 11 | import pyqtgraph.opengl as gl 12 | 13 | app = pg.mkQApp("GLImageItem Example") 14 | w = gl.GLViewWidget() 15 | w.show() 16 | w.setWindowTitle('pyqtgraph example: GLImageItem') 17 | w.setCameraPosition(distance=200) 18 | 19 | ## create volume data set to slice three images from 20 | shape = (100,100,70) 21 | data = pg.gaussianFilter(np.random.normal(size=shape), (4,4,4)) 22 | data += pg.gaussianFilter(np.random.normal(size=shape), (15,15,15))*15 23 | 24 | ## slice out three planes, convert to RGBA for OpenGL texture 25 | levels = (-0.08, 0.08) 26 | tex1 = pg.makeRGBA(data[shape[0]//2], levels=levels)[0] # yz plane 27 | tex2 = pg.makeRGBA(data[:,shape[1]//2], levels=levels)[0] # xz plane 28 | tex3 = pg.makeRGBA(data[:,:,shape[2]//2], levels=levels)[0] # xy plane 29 | #tex1[:,:,3] = 128 30 | #tex2[:,:,3] = 128 31 | #tex3[:,:,3] = 128 32 | 33 | ## Create three image items from textures, add to view 34 | v1 = gl.GLImageItem(tex1) 35 | v1.translate(-shape[1]/2, -shape[2]/2, 0) 36 | v1.rotate(90, 0,0,1) 37 | v1.rotate(-90, 0,1,0) 38 | w.addItem(v1) 39 | v2 = gl.GLImageItem(tex2) 40 | v2.translate(-shape[0]/2, -shape[2]/2, 0) 41 | v2.rotate(-90, 1,0,0) 42 | w.addItem(v2) 43 | v3 = gl.GLImageItem(tex3) 44 | v3.translate(-shape[0]/2, -shape[1]/2, 0) 45 | w.addItem(v3) 46 | 47 | ax = gl.GLAxisItem() 48 | w.addItem(ax) 49 | 50 | if __name__ == '__main__': 51 | pg.exec() 52 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLIsosurface.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example uses the isosurface function to convert a scalar field 3 | (a hydrogen orbital) into a mesh for 3D display. 4 | """ 5 | 6 | import numpy as np 7 | 8 | import pyqtgraph as pg 9 | import pyqtgraph.opengl as gl 10 | 11 | app = pg.mkQApp("GLIsosurface Example") 12 | w = gl.GLViewWidget() 13 | w.show() 14 | w.setWindowTitle('pyqtgraph example: GLIsosurface') 15 | 16 | w.setCameraPosition(distance=40) 17 | 18 | g = gl.GLGridItem() 19 | g.scale(2,2,1) 20 | w.addItem(g) 21 | 22 | ## Define a scalar field from which we will generate an isosurface 23 | def psi(i, j, k, offset=(25, 25, 50)): 24 | x = i-offset[0] 25 | y = j-offset[1] 26 | z = k-offset[2] 27 | th = np.arctan2(z, np.hypot(x, y)) 28 | r = np.sqrt(x**2 + y**2 + z **2) 29 | a0 = 1 30 | ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1) 31 | return ps 32 | 33 | 34 | print("Generating scalar field..") 35 | data = np.abs(np.fromfunction(psi, (50,50,100))) 36 | 37 | 38 | print("Generating isosurface..") 39 | verts, faces = pg.isosurface(data, data.max()/4.) 40 | 41 | md = gl.MeshData(vertexes=verts, faces=faces) 42 | 43 | colors = np.ones((md.faceCount(), 4), dtype=float) 44 | colors[:,3] = 0.2 45 | colors[:,2] = np.linspace(0, 1, colors.shape[0]) 46 | md.setFaceColors(colors) 47 | m1 = gl.GLMeshItem(meshdata=md, smooth=False, shader='balloon') 48 | m1.setGLOptions('additive') 49 | 50 | #w.addItem(m1) 51 | m1.translate(-25, -25, -20) 52 | 53 | m2 = gl.GLMeshItem(meshdata=md, smooth=True, shader='balloon') 54 | m2.setGLOptions('additive') 55 | 56 | w.addItem(m2) 57 | m2.translate(-25, -25, -50) 58 | 59 | if __name__ == '__main__': 60 | pg.exec() 61 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLLinePlotItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrate use of GLLinePlotItem to draw cross-sections of a surface. 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | import pyqtgraph.opengl as gl 9 | 10 | app = pg.mkQApp("GLLinePlotItem Example") 11 | w = gl.GLViewWidget() 12 | w.show() 13 | w.setWindowTitle('pyqtgraph example: GLLinePlotItem') 14 | w.setCameraPosition(distance=40) 15 | 16 | gx = gl.GLGridItem() 17 | gx.rotate(90, 0, 1, 0) 18 | gx.translate(-10, 0, 0) 19 | w.addItem(gx) 20 | gy = gl.GLGridItem() 21 | gy.rotate(90, 1, 0, 0) 22 | gy.translate(0, -10, 0) 23 | w.addItem(gy) 24 | gz = gl.GLGridItem() 25 | gz.translate(0, 0, -10) 26 | w.addItem(gz) 27 | 28 | n = 51 29 | y = np.linspace(-10,10,n) 30 | x = np.linspace(-10,10,100) 31 | for i in range(n): 32 | yi = y[i] 33 | d = np.hypot(x, yi) 34 | z = 10 * np.cos(d) / (d+1) 35 | pts = np.column_stack([x, np.full_like(x, yi), z]) 36 | plt = gl.GLLinePlotItem(pos=pts, color=pg.mkColor((i,n*1.3)), width=(i+1)/10., antialias=True) 37 | w.addItem(plt) 38 | 39 | if __name__ == '__main__': 40 | pg.exec() 41 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLTextItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple examples demonstrating the use of GLTextItem. 3 | 4 | """ 5 | 6 | import pyqtgraph as pg 7 | import pyqtgraph.opengl as gl 8 | from pyqtgraph.Qt import mkQApp 9 | 10 | app = mkQApp("GLTextItem Example") 11 | 12 | gvw = gl.GLViewWidget() 13 | gvw.show() 14 | gvw.setWindowTitle('pyqtgraph example: GLTextItem') 15 | 16 | griditem = gl.GLGridItem() 17 | griditem.setSize(10, 10) 18 | griditem.setSpacing(1, 1) 19 | gvw.addItem(griditem) 20 | 21 | axisitem = gl.GLAxisItem() 22 | gvw.addItem(axisitem) 23 | 24 | txtitem1 = gl.GLTextItem(pos=(0.0, 0.0, 0.0), text='text1') 25 | gvw.addItem(txtitem1) 26 | 27 | txtitem2 = gl.GLTextItem() 28 | txtitem2.setData(pos=(1.0, -1.0, 2.0), color=(127, 255, 127, 255), text='text2') 29 | gvw.addItem(txtitem2) 30 | 31 | if __name__ == '__main__': 32 | pg.exec() 33 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GLViewWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Very basic 3D graphics example; create a view widget and add a few items. 3 | 4 | """ 5 | 6 | import pyqtgraph as pg 7 | import pyqtgraph.opengl as gl 8 | 9 | pg.mkQApp("GLViewWidget Example") 10 | w = gl.GLViewWidget() 11 | w.show() 12 | w.setWindowTitle('pyqtgraph example: GLViewWidget') 13 | w.setCameraPosition(distance=20) 14 | 15 | ax = gl.GLAxisItem() 16 | ax.setSize(5,5,5) 17 | w.addItem(ax) 18 | 19 | b = gl.GLBoxItem() 20 | w.addItem(b) 21 | 22 | ax2 = gl.GLAxisItem() 23 | ax2.setParentItem(b) 24 | 25 | b.translate(1,1,1) 26 | 27 | if __name__ == '__main__': 28 | pg.exec() 29 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GradientEditor.py: -------------------------------------------------------------------------------- 1 | 2 | import pyqtgraph as pg 3 | 4 | app = pg.mkQApp("Gradiant Editor Example") 5 | mw = pg.GraphicsView() 6 | mw.resize(800,800) 7 | mw.show() 8 | 9 | #ts = pg.TickSliderItem() 10 | #mw.setCentralItem(ts) 11 | #ts.addTick(0.5, 'r') 12 | #ts.addTick(0.9, 'b') 13 | 14 | ge = pg.GradientEditorItem() 15 | mw.setCentralItem(ge) 16 | 17 | if __name__ == '__main__': 18 | pg.exec() 19 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GradientWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates the appearance / interactivity of GradientWidget 3 | (without actually doing anything useful with it) 4 | """ 5 | 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtWidgets 9 | 10 | app = pg.mkQApp("Gradiant Widget Example") 11 | w = QtWidgets.QMainWindow() 12 | w.show() 13 | w.setWindowTitle('pyqtgraph example: GradientWidget') 14 | w.setGeometry(10, 50, 400, 400) 15 | cw = QtWidgets.QWidget() 16 | w.setCentralWidget(cw) 17 | 18 | l = QtWidgets.QGridLayout() 19 | l.setSpacing(0) 20 | cw.setLayout(l) 21 | 22 | w1 = pg.GradientWidget(orientation='top') 23 | w2 = pg.GradientWidget(orientation='right', allowAdd=False) 24 | #w2.setTickColor(1, QtGui.QColor(255,255,255)) 25 | w3 = pg.GradientWidget(orientation='bottom', allowAdd=False, allowRemove=False) 26 | w4 = pg.GradientWidget(orientation='left') 27 | w4.loadPreset('spectrum') 28 | label = QtWidgets.QLabel(""" 29 | - Click a triangle to change its color 30 | - Drag triangles to move 31 | - Right-click a gradient to load triangle presets 32 | - Click in an empty area to add a new color 33 | (adding is disabled for the bottom-side and right-side widgets) 34 | - Right click a triangle to remove 35 | (only possible if more than two triangles are visible) 36 | (removing is disabled for the bottom-side widget) 37 | """) 38 | 39 | l.addWidget(w1, 0, 1) 40 | l.addWidget(w2, 1, 2) 41 | l.addWidget(w3, 2, 1) 42 | l.addWidget(w4, 1, 0) 43 | l.addWidget(label, 1, 1) 44 | 45 | if __name__ == '__main__': 46 | pg.exec() 47 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GraphItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple example of GraphItem use. 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | # Enable antialiasing for prettier plots 10 | pg.setConfigOptions(antialias=True) 11 | 12 | w = pg.GraphicsLayoutWidget(show=True) 13 | w.setWindowTitle('pyqtgraph example: GraphItem') 14 | v = w.addViewBox() 15 | v.setAspectLocked() 16 | 17 | g = pg.GraphItem() 18 | v.addItem(g) 19 | 20 | ## Define positions of nodes 21 | pos = np.array([ 22 | [0,0], 23 | [10,0], 24 | [0,10], 25 | [10,10], 26 | [5,5], 27 | [15,5] 28 | ]) 29 | 30 | ## Define the set of connections in the graph 31 | adj = np.array([ 32 | [0,1], 33 | [1,3], 34 | [3,2], 35 | [2,0], 36 | [1,5], 37 | [3,5], 38 | ]) 39 | 40 | ## Define the symbol to use for each node (this is optional) 41 | symbols = ['o','o','o','o','t','+'] 42 | 43 | ## Define the line style for each connection (this is optional) 44 | lines = np.array([ 45 | (255,0,0,255,1), 46 | (255,0,255,255,2), 47 | (255,0,255,255,3), 48 | (255,255,0,255,2), 49 | (255,0,0,255,1), 50 | (255,255,255,255,4), 51 | ], dtype=[('red',np.ubyte),('green',np.ubyte),('blue',np.ubyte),('alpha',np.ubyte),('width',float)]) 52 | 53 | ## Update the graph 54 | g.setData(pos=pos, adj=adj, pen=lines, size=1, symbol=symbols, pxMode=False) 55 | 56 | if __name__ == '__main__': 57 | pg.exec() 58 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GraphicsLayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrate the use of layouts to control placement of multiple plots / views / 3 | labels 4 | """ 5 | 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | 11 | app = pg.mkQApp("Gradiant Layout Example") 12 | view = pg.GraphicsView() 13 | l = pg.GraphicsLayout(border=(100,100,100)) 14 | view.setCentralItem(l) 15 | view.show() 16 | view.setWindowTitle('pyqtgraph example: GraphicsLayout') 17 | view.resize(800,600) 18 | 19 | ## Title at top 20 | text = """ 21 | This example demonstrates the use of GraphicsLayout to arrange items in a grid.
22 | The items added to the layout must be subclasses of QGraphicsWidget (this includes
23 | PlotItem, ViewBox, LabelItem, and GrphicsLayout itself). 24 | """ 25 | l.addLabel(text, col=1, colspan=4) 26 | l.nextRow() 27 | 28 | ## Put vertical label on left side 29 | l.addLabel('Long Vertical Label', angle=-90, rowspan=3) 30 | 31 | ## Add 3 plots into the first row (automatic position) 32 | p1 = l.addPlot(title="Plot 1") 33 | p2 = l.addPlot(title="Plot 2") 34 | vb = l.addViewBox(lockAspect=True) 35 | img = pg.ImageItem(np.random.normal(size=(100,100))) 36 | vb.addItem(img) 37 | vb.autoRange() 38 | 39 | 40 | ## Add a sub-layout into the second row (automatic position) 41 | ## The added item should avoid the first column, which is already filled 42 | l.nextRow() 43 | l2 = l.addLayout(colspan=3, border=(50,0,0)) 44 | l2.setContentsMargins(10, 10, 10, 10) 45 | l2.addLabel("Sub-layout: this layout demonstrates the use of shared axes and axis labels", colspan=3) 46 | l2.nextRow() 47 | l2.addLabel('Vertical Axis Label', angle=-90, rowspan=2) 48 | p21 = l2.addPlot() 49 | p22 = l2.addPlot() 50 | l2.nextRow() 51 | p23 = l2.addPlot() 52 | p24 = l2.addPlot() 53 | l2.nextRow() 54 | l2.addLabel("HorizontalAxisLabel", col=1, colspan=2) 55 | 56 | ## hide axes on some plots 57 | p21.hideAxis('bottom') 58 | p22.hideAxis('bottom') 59 | p22.hideAxis('left') 60 | p24.hideAxis('left') 61 | p21.hideButtons() 62 | p22.hideButtons() 63 | p23.hideButtons() 64 | p24.hideButtons() 65 | 66 | 67 | ## Add 2 more plots into the third row (manual position) 68 | p4 = l.addPlot(row=3, col=1) 69 | p5 = l.addPlot(row=3, col=2, colspan=2) 70 | 71 | ## show some content in the plots 72 | p1.plot([1,3,2,4,3,5]) 73 | p2.plot([1,3,2,4,3,5]) 74 | p4.plot([1,3,2,4,3,5]) 75 | p5.plot([1,3,2,4,3,5]) 76 | 77 | if __name__ == '__main__': 78 | pg.exec() 79 | -------------------------------------------------------------------------------- /pyqtgraph/examples/GraphicsScene.py: -------------------------------------------------------------------------------- 1 | import pyqtgraph as pg 2 | from pyqtgraph.Qt import QtCore, QtWidgets 3 | 4 | app = pg.mkQApp("GraphicsScene Example") 5 | win = pg.GraphicsView() 6 | win.show() 7 | 8 | 9 | class Obj(QtWidgets.QGraphicsObject): 10 | def __init__(self): 11 | QtWidgets.QGraphicsObject.__init__(self) 12 | 13 | def paint(self, p, *args): 14 | p.setPen(pg.mkPen(200,200,200)) 15 | p.drawRect(self.boundingRect()) 16 | 17 | def boundingRect(self): 18 | return QtCore.QRectF(0, 0, 20, 20) 19 | 20 | def mouseClickEvent(self, ev): 21 | if ev.double(): 22 | print("double click") 23 | else: 24 | print("click") 25 | ev.accept() 26 | 27 | #def mouseDragEvent(self, ev): 28 | #print "drag" 29 | #ev.accept() 30 | #self.setPos(self.pos() + ev.pos()-ev.lastPos()) 31 | 32 | 33 | 34 | vb = pg.ViewBox() 35 | win.setCentralItem(vb) 36 | 37 | obj = Obj() 38 | vb.addItem(obj) 39 | 40 | obj2 = Obj() 41 | win.addItem(obj2) 42 | 43 | def clicked(): 44 | print("button click") 45 | btn = QtWidgets.QPushButton("BTN") 46 | btn.clicked.connect(clicked) 47 | prox = QtWidgets.QGraphicsProxyWidget() 48 | prox.setWidget(btn) 49 | prox.setPos(100,0) 50 | vb.addItem(prox) 51 | 52 | g = pg.GridItem() 53 | vb.addItem(g) 54 | 55 | if __name__ == '__main__': 56 | pg.exec() 57 | -------------------------------------------------------------------------------- /pyqtgraph/examples/HistogramLUT.py: -------------------------------------------------------------------------------- 1 | """ 2 | Use a HistogramLUTWidget to control the contrast / coloration of an image. 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtWidgets 9 | 10 | app = pg.mkQApp("Histogram Lookup Table Example") 11 | win = QtWidgets.QMainWindow() 12 | win.resize(880, 600) 13 | win.show() 14 | win.setWindowTitle('pyqtgraph example: Histogram LUT') 15 | 16 | cw = QtWidgets.QWidget() 17 | win.setCentralWidget(cw) 18 | 19 | layout = QtWidgets.QGridLayout() 20 | cw.setLayout(layout) 21 | layout.setSpacing(0) 22 | 23 | view = pg.GraphicsView() 24 | vb = pg.ViewBox() 25 | vb.setAspectLocked() 26 | view.setCentralItem(vb) 27 | layout.addWidget(view, 0, 1, 3, 1) 28 | 29 | hist = pg.HistogramLUTWidget(gradientPosition="left") 30 | layout.addWidget(hist, 0, 2) 31 | 32 | 33 | monoRadio = QtWidgets.QRadioButton('mono') 34 | rgbaRadio = QtWidgets.QRadioButton('rgba') 35 | layout.addWidget(monoRadio, 1, 2) 36 | layout.addWidget(rgbaRadio, 2, 2) 37 | monoRadio.setChecked(True) 38 | 39 | 40 | def setLevelMode(): 41 | mode = 'mono' if monoRadio.isChecked() else 'rgba' 42 | hist.setLevelMode(mode) 43 | 44 | 45 | monoRadio.toggled.connect(setLevelMode) 46 | 47 | data = pg.gaussianFilter(np.random.normal(size=(256, 256, 3)), (20, 20, 0)) 48 | for i in range(32): 49 | for j in range(32): 50 | data[i*8, j*8] += .1 51 | img = pg.ImageItem(data) 52 | vb.addItem(img) 53 | vb.autoRange() 54 | 55 | hist.setImageItem(img) 56 | 57 | if __name__ == '__main__': 58 | pg.exec() 59 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ImageItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates very basic use of ImageItem to display image data inside a ViewBox. 3 | """ 4 | 5 | from time import perf_counter 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | from pyqtgraph.Qt import QtCore 11 | 12 | app = pg.mkQApp("ImageItem Example") 13 | 14 | ## Create window with GraphicsView widget 15 | win = pg.GraphicsLayoutWidget() 16 | win.show() ## show widget alone in its own window 17 | win.setWindowTitle('pyqtgraph example: ImageItem') 18 | view = win.addViewBox() 19 | 20 | ## lock the aspect ratio so pixels are always square 21 | view.setAspectLocked(True) 22 | 23 | ## Create image item 24 | img = pg.ImageItem(border='w') 25 | view.addItem(img) 26 | 27 | ## Set initial view bounds 28 | view.setRange(QtCore.QRectF(0, 0, 600, 600)) 29 | 30 | ## Create random image 31 | data = np.random.normal(size=(15, 600, 600), loc=1024, scale=64).astype(np.uint16) 32 | i = 0 33 | 34 | updateTime = perf_counter() 35 | elapsed = 0 36 | 37 | timer = QtCore.QTimer() 38 | timer.setSingleShot(True) 39 | # not using QTimer.singleShot() because of persistence on PyQt. see PR #1605 40 | 41 | def updateData(): 42 | global img, data, i, updateTime, elapsed 43 | 44 | ## Display the data 45 | img.setImage(data[i]) 46 | i = (i+1) % data.shape[0] 47 | 48 | timer.start(1) 49 | now = perf_counter() 50 | elapsed_now = now - updateTime 51 | updateTime = now 52 | elapsed = elapsed * 0.9 + elapsed_now * 0.1 53 | 54 | # print(f"{1 / elapsed:.1f} fps") 55 | 56 | timer.timeout.connect(updateData) 57 | updateData() 58 | 59 | if __name__ == '__main__': 60 | pg.exec() 61 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ImageView.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example demonstrates the use of ImageView with 3-color image stacks. 3 | ImageView is a high-level widget for displaying and analyzing 2D and 3D data. 4 | ImageView provides: 5 | 6 | 1. A zoomable region (ViewBox) for displaying the image 7 | 2. A combination histogram and gradient editor (HistogramLUTItem) for 8 | controlling the visual appearance of the image 9 | 3. A timeline for selecting the currently displayed frame (for 3D data only). 10 | 4. Tools for very basic analysis of image data (see ROI and Norm buttons) 11 | 12 | """ 13 | 14 | import numpy as np 15 | 16 | import pyqtgraph as pg 17 | from pyqtgraph.Qt import QtWidgets 18 | 19 | # Interpret image data as row-major instead of col-major 20 | pg.setConfigOptions(imageAxisOrder='row-major') 21 | 22 | app = pg.mkQApp("ImageView Example") 23 | 24 | ## Create window with ImageView widget 25 | win = QtWidgets.QMainWindow() 26 | win.resize(800,800) 27 | imv = pg.ImageView(discreteTimeLine=True, levelMode='rgba') 28 | win.setCentralWidget(imv) 29 | win.show() 30 | win.setWindowTitle('pyqtgraph example: ImageView') 31 | imv.setHistogramLabel("Histogram label goes here") 32 | 33 | ## Create random 3D data set with time varying signals 34 | dataRed = np.ones((100, 200, 200)) * np.linspace(90, 150, 100)[:, np.newaxis, np.newaxis] 35 | dataRed += pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 100 36 | dataGrn = np.ones((100, 200, 200)) * np.linspace(90, 180, 100)[:, np.newaxis, np.newaxis] 37 | dataGrn += pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 100 38 | dataBlu = np.ones((100, 200, 200)) * np.linspace(180, 90, 100)[:, np.newaxis, np.newaxis] 39 | dataBlu += pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 100 40 | 41 | data = np.concatenate( 42 | (dataRed[:, :, :, np.newaxis], dataGrn[:, :, :, np.newaxis], dataBlu[:, :, :, np.newaxis]), axis=3 43 | ) 44 | 45 | 46 | # Display the data and assign each frame a time value from 1.0 to 3.0 47 | imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0])) 48 | imv.play(10) 49 | 50 | # Start up with an ROI 51 | imv.ui.roiBtn.setChecked(True) 52 | imv.roiClicked() 53 | 54 | if __name__ == '__main__': 55 | pg.exec() 56 | -------------------------------------------------------------------------------- /pyqtgraph/examples/JoystickButton.py: -------------------------------------------------------------------------------- 1 | """ 2 | JoystickButton is a button with x/y values. When the button is depressed and the 3 | mouse dragged, the x/y values change to follow the mouse. 4 | When the mouse button is released, the x/y values change to 0,0 (rather like 5 | letting go of the joystick). 6 | """ 7 | 8 | import pyqtgraph as pg 9 | from pyqtgraph.Qt import QtCore, QtWidgets 10 | 11 | app = pg.mkQApp("Joystick Button Example") 12 | mw = QtWidgets.QMainWindow() 13 | mw.resize(300,50) 14 | mw.setWindowTitle('pyqtgraph example: JoystickButton') 15 | cw = QtWidgets.QWidget() 16 | mw.setCentralWidget(cw) 17 | layout = QtWidgets.QGridLayout() 18 | cw.setLayout(layout) 19 | mw.show() 20 | 21 | l1 = pg.ValueLabel(siPrefix=True, suffix='m') 22 | l2 = pg.ValueLabel(siPrefix=True, suffix='m') 23 | jb = pg.JoystickButton() 24 | jb.setFixedWidth(30) 25 | jb.setFixedHeight(30) 26 | 27 | 28 | layout.addWidget(l1, 0, 0) 29 | layout.addWidget(l2, 0, 1) 30 | layout.addWidget(jb, 0, 2) 31 | 32 | x = 0 33 | y = 0 34 | def update(): 35 | global x, y, l1, l2, jb 36 | dx, dy = jb.getState() 37 | x += dx * 1e-3 38 | y += dy * 1e-3 39 | l1.setValue(x) 40 | l2.setValue(y) 41 | timer = QtCore.QTimer() 42 | timer.timeout.connect(update) 43 | timer.start(30) 44 | 45 | if __name__ == '__main__': 46 | pg.exec() 47 | -------------------------------------------------------------------------------- /pyqtgraph/examples/Legend.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates basic use of LegendItem 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | win = pg.plot() 10 | win.setWindowTitle('pyqtgraph example: BarGraphItem') 11 | 12 | # # option1: only for .plot(), following c1,c2 for example----------------------- 13 | # win.addLegend(frame=False, colCount=2) 14 | 15 | # bar graph 16 | x = np.arange(10) 17 | y = np.sin(x+2) * 3 18 | bg1 = pg.BarGraphItem(x=x, height=y, width=0.3, brush='b', pen='w', name='bar') 19 | win.addItem(bg1) 20 | 21 | # curve 22 | c1 = win.plot([np.random.randint(0,8) for i in range(10)], pen='r', symbol='t', symbolPen='r', symbolBrush='g', name='curve1') 23 | c2 = win.plot([2,1,4,3,1,3,2,4,3,2], pen='g', fillLevel=0, fillBrush=(255,255,255,30), name='curve2') 24 | 25 | # scatter plot 26 | s1 = pg.ScatterPlotItem(size=10, pen=pg.mkPen(None), brush=pg.mkBrush(255, 255, 255, 120), name='scatter') 27 | spots = [{'pos': [i, np.random.randint(-3, 3)], 'data': 1} for i in range(10)] 28 | s1.addPoints(spots) 29 | win.addItem(s1) 30 | 31 | # # option2: generic method------------------------------------------------ 32 | legend = pg.LegendItem((80,60), offset=(70,20)) 33 | legend.setParentItem(win.graphicsItem()) 34 | legend.addItem(bg1, 'bar') 35 | legend.addItem(c1, 'curve1') 36 | legend.addItem(c2, 'curve2') 37 | legend.addItem(s1, 'scatter') 38 | 39 | if __name__ == '__main__': 40 | pg.exec() 41 | -------------------------------------------------------------------------------- /pyqtgraph/examples/LogPlotTest.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple logarithmic plotting test 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | app = pg.mkQApp("Log Plot Example") 10 | 11 | win = pg.GraphicsLayoutWidget(show=True, title="Basic plotting examples") 12 | win.resize(1000,600) 13 | win.setWindowTitle('pyqtgraph example: LogPlotTest') 14 | 15 | 16 | p5 = win.addPlot(title="Scatter plot, axis labels, log scale") 17 | x = np.random.normal(size=1000) * 1e-5 18 | y = x*1000 + 0.005 * np.random.normal(size=1000) 19 | y -= y.min()-1.0 20 | mask = x > 1e-15 21 | x = x[mask] 22 | y = y[mask] 23 | p5.plot(x, y, pen=None, symbol='t', symbolPen=None, symbolSize=10, symbolBrush=(100, 100, 255, 50)) 24 | p5.setLabel('left', "Y Axis", units='A') 25 | p5.setLabel('bottom', "Y Axis", units='s') 26 | p5.setLogMode(x=True, y=False) 27 | 28 | 29 | if __name__ == '__main__': 30 | pg.exec() 31 | -------------------------------------------------------------------------------- /pyqtgraph/examples/MouseSelection.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates selecting plot curves by mouse click 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | win = pg.plot() 10 | win.setWindowTitle('pyqtgraph example: Plot data selection') 11 | 12 | curves = [ 13 | pg.PlotCurveItem(y=np.sin(np.linspace(0, 20, 1000)), pen='r', clickable=True), 14 | pg.PlotCurveItem(y=np.sin(np.linspace(1, 21, 1000)), pen='g', clickable=True), 15 | pg.PlotCurveItem(y=np.sin(np.linspace(2, 22, 1000)), pen='b', clickable=True), 16 | ] 17 | 18 | def plotClicked(curve): 19 | global curves 20 | for i,c in enumerate(curves): 21 | if c is curve: 22 | c.setPen('rgb'[i], width=3) 23 | else: 24 | c.setPen('rgb'[i], width=1) 25 | 26 | 27 | for c in curves: 28 | win.addItem(c) 29 | c.sigClicked.connect(plotClicked) 30 | 31 | if __name__ == '__main__': 32 | pg.exec() 33 | -------------------------------------------------------------------------------- /pyqtgraph/examples/MultiDataPlot.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | import numpy as np 3 | 4 | import pyqtgraph as pg 5 | from pyqtgraph.graphicsItems.ScatterPlotItem import name_list 6 | from pyqtgraph.Qt import QtWidgets, QtCore 7 | from pyqtgraph.parametertree import interact, ParameterTree, Parameter 8 | import random 9 | 10 | pg.mkQApp() 11 | 12 | rng = np.random.default_rng(10) 13 | random.seed(10) 14 | 15 | 16 | def sortedRandint(low, high, size): 17 | return np.sort(rng.integers(low, high, size)) 18 | 19 | 20 | def isNoneOrScalar(value): 21 | return value is None or np.isscalar(value[0]) 22 | 23 | 24 | values = { 25 | # Convention 1 26 | "None (replaced by integer indices)": None, 27 | # Convention 2 28 | "Single curve values": sortedRandint(0, 20, 15), 29 | # Convention 3 list form 30 | "container of (optionally) mixed-size curve values": [ 31 | sortedRandint(0, 20, 15), 32 | *[sortedRandint(0, 20, 15) for _ in range(4)], 33 | ], 34 | # Convention 3 array form 35 | "2D matrix": np.row_stack([sortedRandint(20, 40, 15) for _ in range(6)]), 36 | } 37 | 38 | 39 | def next_plot(xtype="random", ytype="random", symbol="o", symbolBrush="#f00"): 40 | constKwargs = locals() 41 | x = y = None 42 | if xtype == "random": 43 | xtype = random.choice(list(values)) 44 | if ytype == "random": 45 | ytype = random.choice(list(values)) 46 | x = values[xtype] 47 | y = values[ytype] 48 | textbox.setValue(f"x={xtype}\ny={ytype}") 49 | pltItem.clear() 50 | try: 51 | pltItem.multiDataPlot( 52 | x=x, y=y, pen=cmap.getLookupTable(nPts=6), constKwargs=constKwargs 53 | ) 54 | except Exception as e: 55 | QtWidgets.QMessageBox.critical(widget, "Error", traceback.format_exc()) 56 | 57 | 58 | cmap = pg.colormap.get("viridis") 59 | widget = pg.PlotWidget() 60 | pltItem: pg.PlotItem = widget.plotItem 61 | 62 | xytype = dict(type="list", values=list(values)) 63 | topParam = interact( 64 | next_plot, 65 | symbolBrush=dict(type="color"), 66 | symbol=dict(type="list", values=name_list), 67 | xtype=xytype, 68 | ytype=xytype, 69 | ) 70 | tree = ParameterTree() 71 | tree.setMinimumWidth(150) 72 | tree.addParameters(topParam, showTop=True) 73 | 74 | textbox = Parameter.create(name="text", type="text", readonly=True) 75 | tree.addParameters(textbox) 76 | 77 | win = QtWidgets.QWidget() 78 | win.setLayout(lay := QtWidgets.QHBoxLayout()) 79 | lay.addWidget(widget) 80 | lay.addWidget(tree) 81 | if __name__ == "__main__": 82 | win.show() 83 | pg.exec() 84 | -------------------------------------------------------------------------------- /pyqtgraph/examples/MultiPlotSpeedTest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | """ 3 | Test the speed of rapidly updating multiple plot curves 4 | """ 5 | import argparse 6 | import itertools 7 | 8 | import numpy as np 9 | from utils import FrameCounter 10 | 11 | import pyqtgraph as pg 12 | from pyqtgraph.Qt import QtCore 13 | 14 | parser = argparse.ArgumentParser() 15 | parser.add_argument('--iterations', default=float('inf'), type=float, 16 | help="Number of iterations to run before exiting" 17 | ) 18 | args = parser.parse_args() 19 | iterations_counter = itertools.count() 20 | 21 | # pg.setConfigOptions(useOpenGL=True) 22 | app = pg.mkQApp("MultiPlot Speed Test") 23 | 24 | plot = pg.plot() 25 | plot.setWindowTitle('pyqtgraph example: MultiPlotSpeedTest') 26 | plot.setLabel('bottom', 'Index', units='B') 27 | 28 | nPlots = 100 29 | nSamples = 500 30 | curves = [] 31 | for idx in range(nPlots): 32 | curve = pg.PlotCurveItem(pen=({'color': (idx, nPlots*1.3), 'width': 1}), skipFiniteCheck=True) 33 | plot.addItem(curve) 34 | curve.setPos(0,idx*6) 35 | curves.append(curve) 36 | 37 | plot.setYRange(0, nPlots*6) 38 | plot.setXRange(0, nSamples) 39 | plot.resize(600,900) 40 | 41 | rgn = pg.LinearRegionItem([nSamples/5.,nSamples/3.]) 42 | plot.addItem(rgn) 43 | 44 | 45 | data = np.random.normal(size=(nPlots*23,nSamples)) 46 | ptr = 0 47 | def update(): 48 | global ptr 49 | if next(iterations_counter) > args.iterations: 50 | timer.stop() 51 | app.quit() 52 | return None 53 | for i in range(nPlots): 54 | curves[i].setData(data[(ptr+i)%data.shape[0]]) 55 | 56 | ptr += nPlots 57 | framecnt.update() 58 | 59 | timer = QtCore.QTimer() 60 | timer.timeout.connect(update) 61 | timer.start(0) 62 | 63 | framecnt = FrameCounter() 64 | framecnt.sigFpsUpdate.connect(lambda fps: plot.setTitle(f'{fps:.1f} fps')) 65 | 66 | if __name__ == '__main__': 67 | pg.exec() 68 | -------------------------------------------------------------------------------- /pyqtgraph/examples/MultiplePlotAxes.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates a way to put multiple axes around a single plot. 3 | 4 | (This will eventually become a built-in feature of PlotItem) 5 | """ 6 | 7 | 8 | import pyqtgraph as pg 9 | 10 | pg.mkQApp() 11 | 12 | pw = pg.PlotWidget() 13 | pw.show() 14 | pw.setWindowTitle('pyqtgraph example: MultiplePlotAxes') 15 | p1 = pw.plotItem 16 | p1.setLabels(left='axis 1') 17 | 18 | ## create a new ViewBox, link the right axis to its coordinate system 19 | p2 = pg.ViewBox() 20 | p1.showAxis('right') 21 | p1.scene().addItem(p2) 22 | p1.getAxis('right').linkToView(p2) 23 | p2.setXLink(p1) 24 | p1.getAxis('right').setLabel('axis2', color='#0000ff') 25 | 26 | ## create third ViewBox. 27 | ## this time we need to create a new axis as well. 28 | p3 = pg.ViewBox() 29 | ax3 = pg.AxisItem('right') 30 | p1.layout.addItem(ax3, 2, 3) 31 | p1.scene().addItem(p3) 32 | ax3.linkToView(p3) 33 | p3.setXLink(p1) 34 | ax3.setZValue(-10000) 35 | ax3.setLabel('axis 3', color='#ff0000') 36 | 37 | 38 | ## Handle view resizing 39 | def updateViews(): 40 | ## view has resized; update auxiliary views to match 41 | global p1, p2, p3 42 | p2.setGeometry(p1.vb.sceneBoundingRect()) 43 | p3.setGeometry(p1.vb.sceneBoundingRect()) 44 | 45 | ## need to re-update linked axes since this was called 46 | ## incorrectly while views had different shapes. 47 | ## (probably this should be handled in ViewBox.resizeEvent) 48 | p2.linkedViewChanged(p1.vb, p2.XAxis) 49 | p3.linkedViewChanged(p1.vb, p3.XAxis) 50 | 51 | updateViews() 52 | p1.vb.sigResized.connect(updateViews) 53 | 54 | 55 | p1.plot([1,2,4,8,16,32]) 56 | p2.addItem(pg.PlotCurveItem([10,20,40,80,40,20], pen='b')) 57 | p3.addItem(pg.PlotCurveItem([3200,1600,800,400,200,100], pen='r')) 58 | 59 | if __name__ == '__main__': 60 | pg.exec() 61 | -------------------------------------------------------------------------------- /pyqtgraph/examples/NonUniformImage.py: -------------------------------------------------------------------------------- 1 | """ 2 | Display a non-uniform image. 3 | This example displays 2-d data as an image with non-uniformly 4 | distributed sample points. 5 | """ 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | from pyqtgraph.graphicsItems.NonUniformImage import NonUniformImage 11 | 12 | RPM2RADS = 2 * np.pi / 60 13 | RADS2RPM = 1 / RPM2RADS 14 | 15 | kfric = 1 # [Ws/rad] angular damping coefficient [0;100] 16 | kfric3 = 1.5e-6 # [Ws3/rad3] angular damping coefficient (3rd order) [0;10-3] 17 | psi = 0.2 # [Vs] flux linkage [0.001;10] 18 | res = 5e-3 # [Ohm] resistance [0;100] 19 | v_ref = 200 # [V] reference DC voltage [0;1000] 20 | k_v = 5 # linear voltage coefficient [-100;100] 21 | 22 | # create the (non-uniform) scales 23 | tau = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 220], dtype=np.float32) 24 | w = np.array([0, 250, 500, 750, 1000, 1500, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000], dtype=np.float32) * RPM2RADS 25 | v = 380 26 | 27 | # calculate the power losses 28 | TAU, W = np.meshgrid(tau, w, indexing='ij') 29 | V = np.ones_like(TAU) * v 30 | 31 | P_loss = kfric * W + kfric3 * W ** 3 + (res * (TAU / psi) ** 2) + k_v * (V - v_ref) 32 | 33 | P_mech = TAU * W 34 | P_loss[P_mech > 1.5e5] = np.nan 35 | 36 | app = pg.mkQApp("NonUniform Image Example") 37 | 38 | win = pg.GraphicsLayoutWidget() 39 | win.show() 40 | win.resize(600, 400) 41 | win.setWindowTitle('pyqtgraph example: Non-uniform Image') 42 | 43 | p = win.addPlot(title="Power Losses [W]", row=0, col=0) 44 | hist = pg.HistogramLUTItem(orientation="horizontal") 45 | 46 | p.setMouseEnabled(x=False, y=False) 47 | 48 | win.nextRow() 49 | win.addItem(hist) 50 | 51 | image = NonUniformImage(w * RADS2RPM, tau, P_loss.T) 52 | image.setZValue(-1) 53 | p.addItem(image) 54 | 55 | # green - orange - red 56 | cmap = pg.ColorMap([0.0, 0.5, 1.0], [(74, 158, 71), (255, 230, 0), (191, 79, 76)]) 57 | hist.gradient.setColorMap(cmap) 58 | hist.setImageItem(image) 59 | 60 | p.showGrid(x=True, y=True) 61 | 62 | p.setLabel(axis='bottom', text='Speed [rpm]') 63 | p.setLabel(axis='left', text='Torque [Nm]') 64 | 65 | # elevate the grid lines 66 | p.axes['bottom']['item'].setZValue(1000) 67 | p.axes['left']['item'].setZValue(1000) 68 | 69 | if __name__ == '__main__': 70 | pg.exec() 71 | -------------------------------------------------------------------------------- /pyqtgraph/examples/PanningPlot.py: -------------------------------------------------------------------------------- 1 | """ 2 | Shows use of PlotWidget to display panning data 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtCore 9 | 10 | win = pg.GraphicsLayoutWidget(show=True) 11 | win.setWindowTitle('pyqtgraph example: PanningPlot') 12 | 13 | plt = win.addPlot() 14 | #plt.setAutoVisibleOnly(y=True) 15 | curve = plt.plot() 16 | 17 | data = [] 18 | count = 0 19 | def update(): 20 | global data, curve, count 21 | data.append(np.random.normal(size=10) + np.sin(count * 0.1) * 5) 22 | if len(data) > 100: 23 | data.pop(0) 24 | curve.setData(np.hstack(data)) 25 | count += 1 26 | 27 | timer = QtCore.QTimer() 28 | timer.timeout.connect(update) 29 | timer.start(50) 30 | 31 | if __name__ == '__main__': 32 | pg.exec() 33 | -------------------------------------------------------------------------------- /pyqtgraph/examples/PlotAutoRange.py: -------------------------------------------------------------------------------- 1 | 2 | """ 3 | This example demonstrates the different auto-ranging capabilities of ViewBoxes 4 | """ 5 | 6 | import time 7 | 8 | import numpy as np 9 | 10 | import pyqtgraph as pg 11 | from pyqtgraph.Qt import QtCore 12 | 13 | app = pg.mkQApp("Plot Auto Range Example") 14 | 15 | win = pg.GraphicsLayoutWidget(show=True, title="Plot auto-range examples") 16 | win.resize(800,600) 17 | win.setWindowTitle('pyqtgraph example: PlotAutoRange') 18 | 19 | d = np.random.normal(size=100) 20 | d[50:54] += 10 21 | p1 = win.addPlot(title="95th percentile range", y=d) 22 | p1.enableAutoRange('y', 0.95) 23 | 24 | 25 | p2 = win.addPlot(title="Auto Pan Only") 26 | p2.setAutoPan(y=True) 27 | curve = p2.plot() 28 | t0 = time.time() 29 | 30 | def update(): 31 | t = time.time() - t0 32 | 33 | data = np.ones(100) * np.sin(t) 34 | data[50:60] += np.sin(t) 35 | curve.setData(data) 36 | 37 | timer = QtCore.QTimer() 38 | timer.timeout.connect(update) 39 | timer.start(50) 40 | 41 | if __name__ == '__main__': 42 | pg.exec() 43 | -------------------------------------------------------------------------------- /pyqtgraph/examples/PlotWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates use of PlotWidget class. This is little more than a 3 | GraphicsView with a PlotItem placed in its center. 4 | """ 5 | 6 | import numpy as np 7 | 8 | import pyqtgraph as pg 9 | from pyqtgraph.Qt import QtCore, QtWidgets 10 | 11 | app = pg.mkQApp() 12 | mw = QtWidgets.QMainWindow() 13 | mw.setWindowTitle('pyqtgraph example: PlotWidget') 14 | mw.resize(800,800) 15 | cw = QtWidgets.QWidget() 16 | mw.setCentralWidget(cw) 17 | l = QtWidgets.QVBoxLayout() 18 | cw.setLayout(l) 19 | 20 | pw = pg.PlotWidget(name='Plot1') ## giving the plots names allows us to link their axes together 21 | l.addWidget(pw) 22 | pw2 = pg.PlotWidget(name='Plot2') 23 | l.addWidget(pw2) 24 | pw3 = pg.PlotWidget() 25 | l.addWidget(pw3) 26 | 27 | mw.show() 28 | 29 | ## Create an empty plot curve to be filled later, set its pen 30 | p1 = pw.plot() 31 | p1.setPen((200,200,100)) 32 | 33 | ## Add in some extra graphics 34 | rect = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, 1, 5e-11)) 35 | rect.setPen(pg.mkPen(100, 200, 100)) 36 | pw.addItem(rect) 37 | 38 | pw.setLabel('left', 'Value', units='V') 39 | pw.setLabel('bottom', 'Time', units='s') 40 | pw.setXRange(0, 2) 41 | pw.setYRange(0, 1e-10) 42 | 43 | def rand(n): 44 | data = np.random.random(n) 45 | data[int(n*0.1):int(n*0.13)] += .5 46 | data[int(n*0.18)] += 2 47 | data[int(n*0.1):int(n*0.13)] *= 5 48 | data[int(n*0.18)] *= 20 49 | data *= 1e-12 50 | return data, np.arange(n, n+len(data)) / float(n) 51 | 52 | 53 | def updateData(): 54 | yd, xd = rand(10000) 55 | p1.setData(y=yd, x=xd) 56 | 57 | ## Start a timer to rapidly update the plot in pw 58 | t = QtCore.QTimer() 59 | t.timeout.connect(updateData) 60 | t.start(50) 61 | #updateData() 62 | 63 | ## Multiple parameterized plots--we can autogenerate averages for these. 64 | for i in range(0, 5): 65 | for j in range(0, 3): 66 | yd, xd = rand(10000) 67 | pw2.plot(y=yd*(j+1), x=xd, params={'iter': i, 'val': j}) 68 | 69 | ## Test large numbers 70 | curve = pw3.plot(np.random.normal(size=100)*1e0, clickable=True) 71 | curve.curve.setClickable(True) 72 | curve.setPen('w') ## white pen 73 | curve.setShadowPen(pg.mkPen((70,70,30), width=6, cosmetic=True)) 74 | 75 | def clicked(): 76 | print("curve clicked") 77 | curve.sigClicked.connect(clicked) 78 | 79 | lr = pg.LinearRegionItem([1, 30], bounds=[0,100], movable=True) 80 | pw3.addItem(lr) 81 | line = pg.InfiniteLine(angle=90, movable=True) 82 | pw3.addItem(line) 83 | line.setBounds([0,200]) 84 | 85 | if __name__ == '__main__': 86 | pg.exec() 87 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ProgressDialog.py: -------------------------------------------------------------------------------- 1 | """ 2 | Using ProgressDialog to show progress updates in a nested process. 3 | 4 | """ 5 | 6 | import time 7 | 8 | import pyqtgraph as pg 9 | 10 | app = pg.mkQApp("Progress Dialog Example") 11 | 12 | 13 | def runStage(i): 14 | """Waste time for 2 seconds while incrementing a progress bar. 15 | """ 16 | with pg.ProgressDialog("Running stage %s.." % i, maximum=100, nested=True) as dlg: 17 | for j in range(100): 18 | time.sleep(0.02) 19 | dlg += 1 20 | if dlg.wasCanceled(): 21 | print("Canceled stage %s" % i) 22 | break 23 | 24 | 25 | def runManyStages(i): 26 | """Iterate over runStage() 3 times while incrementing a progress bar. 27 | """ 28 | with pg.ProgressDialog("Running stage %s.." % i, maximum=3, nested=True, wait=0) as dlg: 29 | for j in range(1,4): 30 | runStage('%d.%d' % (i, j)) 31 | dlg += 1 32 | if dlg.wasCanceled(): 33 | print("Canceled stage %s" % i) 34 | break 35 | 36 | 37 | with pg.ProgressDialog("Doing a multi-stage process..", maximum=5, nested=True, wait=0) as dlg1: 38 | for i in range(1,6): 39 | if i == 3: 40 | # this stage will have 3 nested progress bars 41 | runManyStages(i) 42 | else: 43 | # this stage will have 2 nested progress bars 44 | runStage(i) 45 | 46 | dlg1 += 1 47 | if dlg1.wasCanceled(): 48 | print("Canceled process") 49 | break 50 | -------------------------------------------------------------------------------- /pyqtgraph/examples/RemoteGraphicsView.py: -------------------------------------------------------------------------------- 1 | """ 2 | Very simple example demonstrating RemoteGraphicsView. 3 | 4 | This allows graphics to be rendered in a child process and displayed in the 5 | parent, which can improve CPU usage on multi-core processors. 6 | """ 7 | 8 | import pyqtgraph as pg 9 | from pyqtgraph.widgets.RemoteGraphicsView import RemoteGraphicsView 10 | 11 | app = pg.mkQApp() 12 | 13 | ## Create the widget 14 | v = RemoteGraphicsView(debug=False) # setting debug=True causes both processes to print information 15 | # about interprocess communication 16 | v.show() 17 | v.setWindowTitle('pyqtgraph example: RemoteGraphicsView') 18 | 19 | ## v.pg is a proxy to the remote process' pyqtgraph module. All attribute 20 | ## requests and function calls made with this object are forwarded to the 21 | ## remote process and executed there. See pyqtgraph.multiprocess.remoteproxy 22 | ## for more inormation. 23 | plt = v.pg.PlotItem() 24 | v.setCentralItem(plt) 25 | plt.plot([1,4,2,3,6,2,3,4,2,3], pen='g') 26 | 27 | if __name__ == '__main__': 28 | pg.exec() 29 | -------------------------------------------------------------------------------- /pyqtgraph/examples/RunExampleApp.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is used by test_examples.py for ensuring the Example App works. 3 | It is not named test_ExampleApp.py as that way the Example application is 4 | not run twice. 5 | """ 6 | 7 | from ExampleApp import ExampleLoader 8 | 9 | import pyqtgraph as pg 10 | from pyqtgraph.Qt import QtTest 11 | 12 | pg.mkQApp() 13 | 14 | def test_ExampleLoader(): 15 | loader = ExampleLoader() 16 | QtTest.QTest.qWaitForWindowExposed(loader) 17 | QtTest.QTest.qWait(200) 18 | loader.close() 19 | 20 | if __name__ == "__main__": 21 | test_ExampleLoader() 22 | pg.exec() 23 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ScaleBar.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates ScaleBar 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | pg.mkQApp() 10 | win = pg.GraphicsLayoutWidget(show=True) 11 | win.setWindowTitle('pyqtgraph example: ScaleBar') 12 | 13 | vb = win.addViewBox() 14 | vb.setAspectLocked() 15 | 16 | img = pg.ImageItem() 17 | img.setImage(np.random.normal(size=(100,100))) 18 | img.setScale(0.01) 19 | vb.addItem(img) 20 | 21 | scale = pg.ScaleBar(size=0.1) 22 | scale.setParentItem(vb) 23 | scale.anchor((1, 1), (1, 1), offset=(-20, -20)) 24 | 25 | if __name__ == '__main__': 26 | pg.exec() 27 | -------------------------------------------------------------------------------- /pyqtgraph/examples/SimplePlot.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import pyqtgraph as pg 4 | 5 | plt = pg.plot(np.random.normal(size=100), title="Simplest possible plotting example") 6 | 7 | if __name__ == '__main__': 8 | pg.exec() 9 | -------------------------------------------------------------------------------- /pyqtgraph/examples/TableWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple demonstration of TableWidget, which is an extension of QTableWidget 3 | that automatically displays a variety of tabluar data formats. 4 | """ 5 | 6 | import numpy as np 7 | 8 | import pyqtgraph as pg 9 | 10 | app = pg.mkQApp("Table Widget Example") 11 | 12 | w = pg.TableWidget() 13 | w.show() 14 | w.resize(500,500) 15 | w.setWindowTitle('pyqtgraph example: TableWidget') 16 | 17 | 18 | data = np.array([ 19 | (1, 1.6, 'x'), 20 | (3, 5.4, 'y'), 21 | (8, 12.5, 'z'), 22 | (443, 1e-12, 'w'), 23 | ], dtype=[('Column 1', int), ('Column 2', float), ('Column 3', object)]) 24 | 25 | w.setData(data) 26 | 27 | if __name__ == '__main__': 28 | pg.exec() 29 | -------------------------------------------------------------------------------- /pyqtgraph/examples/TreeWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple demonstration of TreeWidget, which is an extension of QTreeWidget 3 | that allows widgets to be added and dragged within the tree more easily. 4 | """ 5 | 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtWidgets 9 | 10 | app = pg.mkQApp("TreeWidget Example") 11 | 12 | w = pg.TreeWidget() 13 | w.setColumnCount(2) 14 | w.show() 15 | w.setWindowTitle('pyqtgraph example: TreeWidget') 16 | 17 | i1 = QtWidgets.QTreeWidgetItem(["Item 1"]) 18 | i11 = QtWidgets.QTreeWidgetItem(["Item 1.1"]) 19 | i12 = QtWidgets.QTreeWidgetItem(["Item 1.2"]) 20 | i2 = QtWidgets.QTreeWidgetItem(["Item 2"]) 21 | i21 = QtWidgets.QTreeWidgetItem(["Item 2.1"]) 22 | i211 = pg.TreeWidgetItem(["Item 2.1.1"]) 23 | i212 = pg.TreeWidgetItem(["Item 2.1.2"]) 24 | i22 = pg.TreeWidgetItem(["Item 2.2"]) 25 | i3 = pg.TreeWidgetItem(["Item 3"]) 26 | i4 = pg.TreeWidgetItem(["Item 4"]) 27 | i5 = pg.TreeWidgetItem(["Item 5"]) 28 | b5 = QtWidgets.QPushButton('Button') 29 | i5.setWidget(1, b5) 30 | 31 | 32 | 33 | w.addTopLevelItem(i1) 34 | w.addTopLevelItem(i2) 35 | w.addTopLevelItem(i3) 36 | w.addTopLevelItem(i4) 37 | w.addTopLevelItem(i5) 38 | i1.addChild(i11) 39 | i1.addChild(i12) 40 | i2.addChild(i21) 41 | i21.addChild(i211) 42 | i21.addChild(i212) 43 | i2.addChild(i22) 44 | 45 | b1 = QtWidgets.QPushButton("Button") 46 | w.setItemWidget(i1, 1, b1) 47 | 48 | if __name__ == '__main__': 49 | pg.exec() 50 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ViewBoxFeatures.py: -------------------------------------------------------------------------------- 1 | """ 2 | ViewBox is the general-purpose graphical container that allows the user to 3 | zoom / pan to inspect any area of a 2D coordinate system. 4 | 5 | This example demonstrates many of the features ViewBox provides. 6 | """ 7 | 8 | import numpy as np 9 | 10 | import pyqtgraph as pg 11 | 12 | x = np.arange(1000, dtype=float) 13 | y = np.random.normal(size=1000) 14 | y += 5 * np.sin(x/100) 15 | 16 | win = pg.GraphicsLayoutWidget(show=True) 17 | win.setWindowTitle('pyqtgraph example: ____') 18 | win.resize(1000, 800) 19 | win.ci.setBorder((50, 50, 100)) 20 | 21 | sub1 = win.addLayout() 22 | sub1.addLabel("Standard mouse interaction:
left-drag to pan, right-drag to zoom.") 23 | sub1.nextRow() 24 | v1 = sub1.addViewBox() 25 | l1 = pg.PlotDataItem(y) 26 | v1.addItem(l1) 27 | 28 | 29 | sub2 = win.addLayout() 30 | sub2.addLabel("One-button mouse interaction:
left-drag zoom to box, wheel to zoom out.") 31 | sub2.nextRow() 32 | v2 = sub2.addViewBox() 33 | v2.setMouseMode(v2.RectMode) 34 | l2 = pg.PlotDataItem(y) 35 | v2.addItem(l2) 36 | 37 | win.nextRow() 38 | 39 | sub3 = win.addLayout() 40 | sub3.addLabel("Locked aspect ratio when zooming.") 41 | sub3.nextRow() 42 | v3 = sub3.addViewBox() 43 | v3.setAspectLocked(1.0) 44 | l3 = pg.PlotDataItem(y) 45 | v3.addItem(l3) 46 | 47 | sub4 = win.addLayout() 48 | sub4.addLabel("View limits:
prevent panning or zooming past limits.") 49 | sub4.nextRow() 50 | v4 = sub4.addViewBox() 51 | v4.setLimits(xMin=-100, xMax=1100, 52 | minXRange=20, maxXRange=500, 53 | yMin=-10, yMax=10, 54 | minYRange=1, maxYRange=10) 55 | l4 = pg.PlotDataItem(y) 56 | v4.addItem(l4) 57 | 58 | win.nextRow() 59 | 60 | sub5 = win.addLayout() 61 | sub5.addLabel("Linked axes: Data in this plot is always X-aligned to
the plot above.") 62 | sub5.nextRow() 63 | v5 = sub5.addViewBox() 64 | v5.setXLink(v3) 65 | l5 = pg.PlotDataItem(y) 66 | v5.addItem(l5) 67 | 68 | sub6 = win.addLayout() 69 | sub6.addLabel("Disable mouse: Per-axis control over mouse input.
" 70 | "Auto-scale-visible: Automatically fit *visible* data within view
" 71 | "(try panning left-right).") 72 | sub6.nextRow() 73 | v6 = sub6.addViewBox() 74 | v6.setMouseEnabled(x=True, y=False) 75 | v6.enableAutoRange(x=False, y=True) 76 | v6.setXRange(300, 450) 77 | v6.setAutoVisible(x=False, y=True) 78 | l6 = pg.PlotDataItem(y) 79 | v6.addItem(l6) 80 | 81 | if __name__ == '__main__': 82 | pg.exec() 83 | -------------------------------------------------------------------------------- /pyqtgraph/examples/ViewLimits.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | import pyqtgraph as pg 4 | 5 | plt = pg.plot(np.random.normal(size=100), title="View limit example") 6 | plt.centralWidget.vb.setLimits(xMin=-20, xMax=120, minXRange=5, maxXRange=100) 7 | 8 | if __name__ == '__main__': 9 | pg.exec() 10 | -------------------------------------------------------------------------------- /pyqtgraph/examples/__init__.py: -------------------------------------------------------------------------------- 1 | from .ExampleApp import main as run 2 | -------------------------------------------------------------------------------- /pyqtgraph/examples/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | if __name__ == '__main__': 4 | from .ExampleApp import main as run 5 | run() 6 | -------------------------------------------------------------------------------- /pyqtgraph/examples/beeswarm.py: -------------------------------------------------------------------------------- 1 | """ 2 | Example beeswarm / bar chart 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | win = pg.plot() 10 | win.setWindowTitle('pyqtgraph example: beeswarm') 11 | 12 | data = np.random.normal(size=(4,20)) 13 | data[0] += 5 14 | data[1] += 7 15 | data[2] += 5 16 | data[3] = 10 + data[3] * 2 17 | 18 | ## Make bar graph 19 | #bar = pg.BarGraphItem(x=range(4), height=data.mean(axis=1), width=0.5, brush=0.4) 20 | #win.addItem(bar) 21 | 22 | ## add scatter plots on top 23 | for i in range(4): 24 | xvals = pg.pseudoScatter(data[i], spacing=0.4, bidir=True) * 0.2 25 | win.plot(x=xvals+i, y=data[i], pen=None, symbol='o', symbolBrush=pg.intColor(i,6,maxValue=128)) 26 | 27 | ## Make error bars 28 | err = pg.ErrorBarItem(x=np.arange(4), y=data.mean(axis=1), height=data.std(axis=1), beam=0.5, pen={'color':'w', 'width':2}) 29 | win.addItem(err) 30 | 31 | 32 | if __name__ == '__main__': 33 | pg.exec() 34 | -------------------------------------------------------------------------------- /pyqtgraph/examples/colorMaps.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example displays all color maps currently available, either as local data 3 | or imported from Matplotlib of ColorCET. 4 | """ 5 | 6 | import pyqtgraph as pg 7 | from pyqtgraph.Qt import QtCore, QtWidgets 8 | 9 | app = pg.mkQApp() 10 | 11 | win = QtWidgets.QMainWindow() 12 | win.resize(1000,800) 13 | 14 | lw = pg.GraphicsLayoutWidget() 15 | lw.setFixedWidth(1000) 16 | lw.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) 17 | 18 | scr = QtWidgets.QScrollArea() 19 | scr.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOn) 20 | scr.setWidget(lw) 21 | win.setCentralWidget(scr) 22 | win.setWindowTitle('pyqtgraph example: Color maps') 23 | win.show() 24 | 25 | bar_width = 32 26 | bar_data = pg.colormap.modulatedBarData(width=bar_width) 27 | 28 | num_bars = 0 29 | 30 | def add_heading(lw, name): 31 | global num_bars 32 | lw.addLabel('=== '+name+' ===') 33 | num_bars += 1 34 | lw.nextRow() 35 | 36 | def add_bar(lw, name, cm): 37 | global num_bars 38 | lw.addLabel(name) 39 | imi = pg.ImageItem( bar_data ) 40 | imi.setLookupTable( cm.getLookupTable(alpha=True) ) 41 | vb = lw.addViewBox(lockAspect=True, enableMouse=False) 42 | vb.addItem( imi ) 43 | num_bars += 1 44 | lw.nextRow() 45 | 46 | add_heading(lw, 'local color maps') 47 | list_of_maps = pg.colormap.listMaps() 48 | list_of_maps = sorted( list_of_maps, key=lambda x: x.swapcase() ) 49 | for map_name in list_of_maps: 50 | cm = pg.colormap.get(map_name) 51 | add_bar(lw, map_name, cm) 52 | 53 | add_heading(lw, 'Matplotlib import') 54 | list_of_maps = pg.colormap.listMaps('matplotlib') 55 | list_of_maps = sorted( list_of_maps, key=lambda x: x.lower() ) 56 | for map_name in list_of_maps: 57 | cm = pg.colormap.get(map_name, source='matplotlib', skipCache=True) 58 | if cm is not None: 59 | add_bar(lw, map_name, cm) 60 | 61 | add_heading(lw, 'ColorCET import') 62 | list_of_maps = pg.colormap.listMaps('colorcet') 63 | list_of_maps = sorted( list_of_maps, key=lambda x: x.lower() ) 64 | for map_name in list_of_maps: 65 | cm = pg.colormap.get(map_name, source='colorcet', skipCache=True) 66 | if cm is not None: 67 | add_bar(lw, map_name, cm) 68 | 69 | lw.setFixedHeight(num_bars * (bar_width+5) ) 70 | 71 | if __name__ == '__main__': 72 | pg.exec() 73 | -------------------------------------------------------------------------------- /pyqtgraph/examples/customGraphicsItem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrate creation of a custom graphic (a candlestick plot) 3 | 4 | """ 5 | 6 | import pyqtgraph as pg 7 | from pyqtgraph import QtCore, QtGui 8 | 9 | 10 | ## Create a subclass of GraphicsObject. 11 | ## The only required methods are paint() and boundingRect() 12 | ## (see QGraphicsItem documentation) 13 | class CandlestickItem(pg.GraphicsObject): 14 | def __init__(self, data): 15 | pg.GraphicsObject.__init__(self) 16 | self.data = data ## data must have fields: time, open, close, min, max 17 | self.generatePicture() 18 | 19 | def generatePicture(self): 20 | ## pre-computing a QPicture object allows paint() to run much more quickly, 21 | ## rather than re-drawing the shapes every time. 22 | self.picture = QtGui.QPicture() 23 | p = QtGui.QPainter(self.picture) 24 | p.setPen(pg.mkPen('w')) 25 | w = (self.data[1][0] - self.data[0][0]) / 3. 26 | for (t, open, close, min, max) in self.data: 27 | p.drawLine(QtCore.QPointF(t, min), QtCore.QPointF(t, max)) 28 | if open > close: 29 | p.setBrush(pg.mkBrush('r')) 30 | else: 31 | p.setBrush(pg.mkBrush('g')) 32 | p.drawRect(QtCore.QRectF(t-w, open, w*2, close-open)) 33 | p.end() 34 | 35 | def paint(self, p, *args): 36 | p.drawPicture(0, 0, self.picture) 37 | 38 | def boundingRect(self): 39 | ## boundingRect _must_ indicate the entire area that will be drawn on 40 | ## or else we will get artifacts and possibly crashing. 41 | ## (in this case, QPicture does all the work of computing the bouning rect for us) 42 | return QtCore.QRectF(self.picture.boundingRect()) 43 | 44 | data = [ ## fields are (time, open, close, min, max). 45 | (1., 10, 13, 5, 15), 46 | (2., 13, 17, 9, 20), 47 | (3., 17, 14, 11, 23), 48 | (4., 14, 15, 5, 19), 49 | (5., 15, 9, 8, 22), 50 | (6., 9, 15, 8, 16), 51 | ] 52 | item = CandlestickItem(data) 53 | plt = pg.plot() 54 | plt.addItem(item) 55 | plt.setWindowTitle('pyqtgraph example: customGraphicsItem') 56 | 57 | if __name__ == '__main__': 58 | pg.exec() 59 | -------------------------------------------------------------------------------- /pyqtgraph/examples/cx_freeze/plotTest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pyqtgraph as pg 4 | from pyqtgraph.Qt import QtWidgets 5 | 6 | # For packages that require scipy, these may be needed: 7 | # from scipy.stats import futil 8 | # from scipy.sparse.csgraph import _validation 9 | 10 | pg.setConfigOption('background','w') 11 | pg.setConfigOption('foreground','k') 12 | app = QtWidgets.QApplication(sys.argv) 13 | 14 | pw = pg.plot(x = [0, 1, 2, 4], y = [4, 5, 9, 6]) 15 | pw.showGrid(x=True,y=True) 16 | text = pg.TextItem(html='
%s
' % "here",anchor=(0.0, 0.0)) 17 | text.setPos(1.0, 5.0) 18 | pw.addItem(text) 19 | status = app.exec_() 20 | sys.exit(status) 21 | -------------------------------------------------------------------------------- /pyqtgraph/examples/cx_freeze/setup.py: -------------------------------------------------------------------------------- 1 | # Build with `python setup.py build_exe` 2 | import shutil 3 | from pathlib import Path 4 | 5 | from cx_Freeze import Executable, setup 6 | 7 | # Remove the build folder 8 | shutil.rmtree("build", ignore_errors=True) 9 | shutil.rmtree("dist", ignore_errors=True) 10 | import sys 11 | 12 | includes = ['pyqtgraph.graphicsItems', 13 | 'numpy', 'atexit'] 14 | excludes = ['cvxopt','_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger', 15 | 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl','tables', 16 | 'Tkconstants', 'Tkinter', 'zmq','PySide','pysideuic','scipy','matplotlib'] 17 | 18 | # Workaround for making sure the templates are included in the frozen app package 19 | include_files = [] 20 | import pyqtgraph 21 | 22 | pg_folder = Path(pyqtgraph.__file__).parent 23 | templates = pg_folder.rglob('*template*.py') 24 | sources = [str(w) for w in templates] 25 | destinations = ['lib' + w.replace(str(pg_folder.parent), '') for w in sources] 26 | for a in zip(sources, destinations): 27 | include_files.append(a) 28 | 29 | print(include_files) 30 | 31 | if sys.version[0] == '2': 32 | # causes syntax error on py2 33 | excludes.append('PyQt4.uic.port_v3') 34 | 35 | base = None 36 | if sys.platform == "win32": 37 | base = "Win32GUI" 38 | 39 | build_exe_options = {'excludes': excludes, 40 | 'includes':includes, 'include_msvcr':True, 41 | 'optimize':1, "include_files": include_files,} 42 | 43 | setup(name = "cx_freeze plot test", 44 | version = "0.2", 45 | description = "cx_freeze plot test", 46 | options = {"build_exe": build_exe_options}, 47 | executables = [Executable("plotTest.py", base=base)]) 48 | -------------------------------------------------------------------------------- /pyqtgraph/examples/designerExample.py: -------------------------------------------------------------------------------- 1 | """ 2 | Simple example of loading UI template created with Qt Designer. 3 | 4 | This example uses uic.loadUiType to parse and load the ui at runtime. It is also 5 | possible to pre-compile the .ui file using pyuic (see VideoSpeedTest and 6 | ScatterPlotSpeedTest examples; these .ui files have been compiled with the 7 | tools/rebuildUi.py script). 8 | """ 9 | 10 | import os 11 | 12 | import numpy as np 13 | 14 | import pyqtgraph as pg 15 | 16 | pg.mkQApp() 17 | 18 | ## Define main window class from template 19 | path = os.path.dirname(os.path.abspath(__file__)) 20 | uiFile = os.path.join(path, 'designerExample.ui') 21 | WindowTemplate, TemplateBaseClass = pg.Qt.loadUiType(uiFile) 22 | 23 | class MainWindow(TemplateBaseClass): 24 | def __init__(self): 25 | TemplateBaseClass.__init__(self) 26 | self.setWindowTitle('pyqtgraph example: Qt Designer') 27 | 28 | # Create the main window 29 | self.ui = WindowTemplate() 30 | self.ui.setupUi(self) 31 | self.ui.plotBtn.clicked.connect(self.plot) 32 | 33 | self.show() 34 | 35 | def plot(self): 36 | self.ui.plot.plot(np.random.normal(size=100), clear=True) 37 | 38 | win = MainWindow() 39 | 40 | if __name__ == '__main__': 41 | pg.exec() 42 | -------------------------------------------------------------------------------- /pyqtgraph/examples/designerExample.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 400 10 | 300 11 | 12 | 13 | 14 | PyQtGraph 15 | 16 | 17 | 18 | 19 | 20 | Plot! 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | PlotWidget 32 | QGraphicsView 33 |
pyqtgraph
34 |
35 |
36 | 37 | 38 |
39 | -------------------------------------------------------------------------------- /pyqtgraph/examples/histogram.py: -------------------------------------------------------------------------------- 1 | """ 2 | In this example we draw two different kinds of histogram. 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | win = pg.GraphicsLayoutWidget(show=True) 10 | win.resize(800,480) 11 | win.setWindowTitle('pyqtgraph example: Histogram') 12 | plt1 = win.addPlot() 13 | plt2 = win.addPlot() 14 | 15 | ## make interesting distribution of values 16 | vals = np.hstack([np.random.normal(size=500), np.random.normal(size=260, loc=4)]) 17 | 18 | ## compute standard histogram 19 | y,x = np.histogram(vals, bins=np.linspace(-3, 8, 40)) 20 | 21 | ## Using stepMode="center" causes the plot to draw two lines for each sample. 22 | ## notice that len(x) == len(y)+1 23 | plt1.plot(x, y, stepMode="center", fillLevel=0, fillOutline=True, brush=(0,0,255,150)) 24 | 25 | ## Now draw all points as a nicely-spaced scatter plot 26 | psy = pg.pseudoScatter(vals, spacing=0.15) 27 | plt2.plot(vals, psy, pen=None, symbol='o', symbolSize=5, symbolPen=(255,255,255,200), symbolBrush=(0,0,255,150)) 28 | 29 | # draw histogram using BarGraphItem 30 | win.nextRow() 31 | plt3 = win.addPlot() 32 | bgi = pg.BarGraphItem(x0=x[:-1], x1=x[1:], height=y, pen='w', brush=(0,0,255,150)) 33 | plt3.addItem(bgi) 34 | 35 | if __name__ == '__main__': 36 | pg.exec() 37 | -------------------------------------------------------------------------------- /pyqtgraph/examples/infiniteline_performance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import numpy as np 4 | 5 | import pyqtgraph as pg 6 | from pyqtgraph.Qt import QtCore 7 | from utils import FrameCounter 8 | 9 | app = pg.mkQApp("Infinite Line Performance") 10 | 11 | p = pg.plot() 12 | p.setWindowTitle('pyqtgraph performance: InfiniteLine') 13 | p.setRange(QtCore.QRectF(0, -10, 5000, 20)) 14 | p.setLabel('bottom', 'Index', units='B') 15 | curve = p.plot() 16 | 17 | # Add a large number of horizontal InfiniteLine to plot 18 | for i in range(100): 19 | line = pg.InfiniteLine(pos=np.random.randint(5000), movable=True) 20 | p.addItem(line) 21 | 22 | data = np.random.normal(size=(50, 5000)) 23 | ptr = 0 24 | 25 | def update(): 26 | global ptr 27 | curve.setData(data[ptr % 10]) 28 | ptr += 1 29 | framecnt.update() 30 | 31 | 32 | timer = QtCore.QTimer() 33 | timer.timeout.connect(update) 34 | timer.start(0) 35 | 36 | framecnt = FrameCounter() 37 | framecnt.sigFpsUpdate.connect(lambda fps: p.setTitle(f'{fps:.1f} fps')) 38 | 39 | if __name__ == '__main__': 40 | pg.exec() 41 | -------------------------------------------------------------------------------- /pyqtgraph/examples/isocurve.py: -------------------------------------------------------------------------------- 1 | """ 2 | Tests use of IsoCurve item displayed with image 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtCore 9 | 10 | app = pg.mkQApp("Isocurve Example") 11 | 12 | ## make pretty looping data 13 | frames = 200 14 | data = np.random.normal(size=(frames,30,30), loc=0, scale=100) 15 | data = np.concatenate([data, data], axis=0) 16 | data = pg.gaussianFilter(data, (10, 10, 10))[frames//2:frames + frames//2] 17 | data[:, 15:16, 15:17] += 1 18 | 19 | win = pg.GraphicsLayoutWidget(show=True) 20 | win.setWindowTitle('pyqtgraph example: Isocurve') 21 | vb = win.addViewBox() 22 | img = pg.ImageItem(data[0]) 23 | vb.addItem(img) 24 | vb.setAspectLocked() 25 | 26 | ## generate empty curves 27 | curves = [] 28 | levels = np.linspace(data.min(), data.max(), 10) 29 | for i in range(len(levels)): 30 | v = levels[i] 31 | ## generate isocurve with automatic color selection 32 | c = pg.IsocurveItem(level=v, pen=(i, len(levels)*1.5)) 33 | c.setParentItem(img) ## make sure isocurve is always correctly displayed over image 34 | c.setZValue(10) 35 | curves.append(c) 36 | 37 | ## animate! 38 | ptr = 0 39 | imgLevels = (data.min(), data.max() * 2) 40 | def update(): 41 | global data, curves, img, ptr, imgLevels 42 | ptr = (ptr + 1) % data.shape[0] 43 | data[ptr] 44 | img.setImage(data[ptr], levels=imgLevels) 45 | for c in curves: 46 | c.setData(data[ptr]) 47 | 48 | timer = QtCore.QTimer() 49 | timer.timeout.connect(update) 50 | timer.start(50) 51 | 52 | if __name__ == '__main__': 53 | pg.exec() 54 | -------------------------------------------------------------------------------- /pyqtgraph/examples/linkedViews.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example demonstrates the ability to link the axes of views together 3 | Views can be linked manually using the context menu, but only if they are given 4 | names. 5 | """ 6 | 7 | import numpy as np 8 | 9 | import pyqtgraph as pg 10 | 11 | app = pg.mkQApp("Linked Views Example") 12 | #mw = QtWidgets.QMainWindow() 13 | #mw.resize(800,800) 14 | 15 | x = np.linspace(-50, 50, 1000) 16 | y = np.sin(x) / x 17 | 18 | win = pg.GraphicsLayoutWidget(show=True, title="pyqtgraph example: Linked Views") 19 | win.resize(800,600) 20 | 21 | win.addLabel("Linked Views", colspan=2) 22 | win.nextRow() 23 | 24 | p1 = win.addPlot(x=x, y=y, name="Plot1", title="Plot1") 25 | p2 = win.addPlot(x=x, y=y, name="Plot2", title="Plot2: Y linked with Plot1") 26 | p2.setLabel('bottom', "Label to test offset") 27 | p2.setYLink('Plot1') ## test linking by name 28 | 29 | 30 | ## create plots 3 and 4 out of order 31 | p4 = win.addPlot(x=x, y=y, name="Plot4", title="Plot4: X -> Plot3 (deferred), Y -> Plot1", row=2, col=1) 32 | p4.setXLink('Plot3') ## Plot3 has not been created yet, but this should still work anyway. 33 | p4.setYLink(p1) 34 | p3 = win.addPlot(x=x, y=y, name="Plot3", title="Plot3: X linked with Plot1", row=2, col=0) 35 | p3.setXLink(p1) 36 | p3.setLabel('left', "Label to test offset") 37 | #QtWidgets.QApplication.processEvents() 38 | 39 | if __name__ == '__main__': 40 | pg.exec() 41 | -------------------------------------------------------------------------------- /pyqtgraph/examples/logAxis.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrate programmatic setting of log transformation modes. 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | 9 | app = pg.mkQApp("Log Axis Example") 10 | 11 | w = pg.GraphicsLayoutWidget(show=True) 12 | w.resize(800,800) 13 | w.setWindowTitle('pyqtgraph example: Log Axis, or How to Recognise Different Types of Curves from Quite a Long Way Away') 14 | 15 | p0 = w.addPlot(0,0, title="Linear") 16 | p1 = w.addPlot(0,1, title="X Semilog") 17 | p2 = w.addPlot(1,0, title="Y Semilog") 18 | p3 = w.addPlot(1,1, title="XY Log") 19 | # configure logarithmic axis scaling: 20 | p1.setLogMode(True, False) 21 | p2.setLogMode(False, True) 22 | p3.setLogMode(True, True) 23 | 24 | # 1000 points from 0.1 to 10, chosen to give a compatible range of values across curves: 25 | x = np.logspace(-1, 1, 1000) 26 | plotdata = ( # legend entry, color, and plotted equation: 27 | ('1 / 3x' , '#ff9d47', 1./(3*x) ), 28 | ('sqrt x' , '#b3cf00', 1/np.sqrt(x) ), 29 | ('exp. decay', '#00a0b5', 5 * np.exp(-x/1) ), 30 | ('-log x' , '#a54dff', - np.log10(x) ) 31 | ) 32 | p0.addLegend(offset=(-20,20)) # include legend only in top left plot 33 | for p in (p0, p1, p2, p3): # draw identical numerical data in all four plots 34 | p.showGrid(True, True) # turn on grid for all four plots 35 | p.showAxes(True, size=(40,None)) # show a full frame, and reserve identical room for y labels 36 | for name, color, y in plotdata: # draw all four curves as defined in plotdata 37 | pen = pg.mkPen(color, width=2) 38 | p.plot( x,y, pen=pen, name=name ) 39 | 40 | w.show() 41 | 42 | if __name__ == '__main__': 43 | pg.exec() 44 | -------------------------------------------------------------------------------- /pyqtgraph/examples/multiplePlotSpeedTest.py: -------------------------------------------------------------------------------- 1 | from time import perf_counter 2 | 3 | import numpy as np 4 | 5 | import pyqtgraph as pg 6 | 7 | app = pg.mkQApp() 8 | plt = pg.PlotWidget() 9 | 10 | app.processEvents() 11 | 12 | ## Putting this at the beginning or end does not have much effect 13 | plt.show() 14 | 15 | ## The auto-range is recomputed after each item is added, 16 | ## so disabling it before plotting helps 17 | plt.enableAutoRange(False, False) 18 | 19 | def plot(): 20 | start = perf_counter() 21 | n = 15 22 | pts = 100 23 | x = np.linspace(0, 0.8, pts) 24 | y = np.random.random(size=pts)*0.8 25 | for i in range(n): 26 | for j in range(n): 27 | ## calling PlotWidget.plot() generates a PlotDataItem, which 28 | ## has a bit more overhead than PlotCurveItem, which is all 29 | ## we need here. This overhead adds up quickly and makes a big 30 | ## difference in speed. 31 | 32 | plt.addItem(pg.PlotCurveItem(x=x+i, y=y+j)) 33 | 34 | dt = perf_counter() - start 35 | print(f"Create plots took: {dt * 1000:.3f} ms") 36 | 37 | ## Plot and clear 5 times, printing the time it took 38 | for _ in range(5): 39 | plt.clear() 40 | plot() 41 | app.processEvents() 42 | plt.autoRange() 43 | 44 | 45 | 46 | 47 | 48 | def fastPlot(): 49 | ## Different approach: generate a single item with all data points. 50 | ## This runs many times faster. 51 | start = perf_counter() 52 | n = 15 53 | pts = 100 54 | x = np.linspace(0, 0.8, pts) 55 | y = np.random.random(size=pts)*0.8 56 | shape = (n, n, pts) 57 | xdata = np.empty(shape) 58 | xdata[:] = x + np.arange(shape[1]).reshape((1,-1,1)) 59 | ydata = np.empty(shape) 60 | ydata[:] = y + np.arange(shape[0]).reshape((-1,1,1)) 61 | conn = np.ones(shape, dtype=bool) 62 | conn[...,-1] = False # make sure plots are disconnected 63 | item = pg.PlotCurveItem() 64 | item.setData(xdata.ravel(), ydata.ravel(), connect=conn.ravel()) 65 | plt.addItem(item) 66 | 67 | dt = perf_counter() - start 68 | print("Create plots took: %0.3fms" % (dt*1000)) 69 | 70 | 71 | ## Plot and clear 5 times, printing the time it took 72 | for _ in range(5): 73 | plt.clear() 74 | fastPlot() 75 | app.processEvents() 76 | plt.autoRange() 77 | 78 | if __name__ == '__main__': 79 | pg.exec() 80 | -------------------------------------------------------------------------------- /pyqtgraph/examples/multiprocess.py: -------------------------------------------------------------------------------- 1 | 2 | import numpy as np 3 | 4 | import pyqtgraph as pg 5 | import pyqtgraph.multiprocess as mp 6 | 7 | print("\n=================\nStart Process") 8 | proc = mp.Process() 9 | import os 10 | 11 | print("parent:", os.getpid(), "child:", proc.proc.pid) 12 | print("started") 13 | rnp = proc._import('numpy') 14 | arr = rnp.array([1,2,3,4]) 15 | print(repr(arr)) 16 | print(str(arr)) 17 | print("return value:", repr(arr.mean(_returnType='value'))) 18 | print( "return proxy:", repr(arr.mean(_returnType='proxy'))) 19 | print( "return auto: ", repr(arr.mean(_returnType='auto'))) 20 | proc.join() 21 | print( "process finished") 22 | 23 | 24 | 25 | print( "\n=================\nStart ForkedProcess") 26 | proc = mp.ForkedProcess() 27 | rnp = proc._import('numpy') 28 | arr = rnp.array([1,2,3,4]) 29 | print( repr(arr)) 30 | print( str(arr)) 31 | print( repr(arr.mean())) 32 | proc.join() 33 | print( "process finished") 34 | 35 | 36 | 37 | 38 | import pyqtgraph as pg 39 | 40 | app = pg.mkQApp("Multiprocess Example") 41 | 42 | print( "\n=================\nStart QtProcess") 43 | import sys 44 | 45 | if (sys.flags.interactive != 1): 46 | print( " (not interactive; remote process will exit immediately.)") 47 | proc = mp.QtProcess() 48 | d1 = proc.transfer(np.random.normal(size=1000)) 49 | d2 = proc.transfer(np.random.normal(size=1000)) 50 | rpg = proc._import('pyqtgraph') 51 | plt = rpg.plot(d1+d2) 52 | -------------------------------------------------------------------------------- /pyqtgraph/examples/optics/__init__.py: -------------------------------------------------------------------------------- 1 | from .pyoptic import * 2 | -------------------------------------------------------------------------------- /pyqtgraph/examples/optics/schott_glasses.csv.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/examples/optics/schott_glasses.csv.gz -------------------------------------------------------------------------------- /pyqtgraph/examples/parallelize.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | import pyqtgraph as pg 4 | import pyqtgraph.multiprocess as mp 5 | 6 | print( "\n=================\nParallelize") 7 | 8 | ## Do a simple task: 9 | ## for x in range(N): 10 | ## sum([x*i for i in range(M)]) 11 | ## 12 | ## We'll do this three times 13 | ## - once without Parallelize 14 | ## - once with Parallelize, but forced to use a single worker 15 | ## - once with Parallelize automatically determining how many workers to use 16 | ## 17 | 18 | tasks = range(10) 19 | results = [None] * len(tasks) 20 | results2 = results[:] 21 | results3 = results[:] 22 | size = 2000000 23 | 24 | pg.mkQApp() 25 | 26 | ### Purely serial processing 27 | start = time.time() 28 | with pg.ProgressDialog('processing serially..', maximum=len(tasks)) as dlg: 29 | for i, x in enumerate(tasks): 30 | tot = 0 31 | for j in range(size): 32 | tot += j * x 33 | results[i] = tot 34 | dlg += 1 35 | if dlg.wasCanceled(): 36 | raise Exception('processing canceled') 37 | print( "Serial time: %0.2f" % (time.time() - start)) 38 | 39 | ### Use parallelize, but force a single worker 40 | ### (this simulates the behavior seen on windows, which lacks os.fork) 41 | start = time.time() 42 | with mp.Parallelize(enumerate(tasks), results=results2, workers=1, progressDialog='processing serially (using Parallelizer)..') as tasker: 43 | for i, x in tasker: 44 | tot = 0 45 | for j in range(size): 46 | tot += j * x 47 | tasker.results[i] = tot 48 | print( "\nParallel time, 1 worker: %0.2f" % (time.time() - start)) 49 | print( "Results match serial: %s" % str(results2 == results)) 50 | 51 | ### Use parallelize with multiple workers 52 | start = time.time() 53 | with mp.Parallelize(enumerate(tasks), results=results3, progressDialog='processing in parallel..') as tasker: 54 | for i, x in tasker: 55 | tot = 0 56 | for j in range(size): 57 | tot += j * x 58 | tasker.results[i] = tot 59 | print( "\nParallel time, %d workers: %0.2f" % (mp.Parallelize.suggestedWorkerCount(), time.time() - start)) 60 | print( "Results match serial: %s" % str(results3 == results)) 61 | -------------------------------------------------------------------------------- /pyqtgraph/examples/py2exe/plotTest.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pyqtgraph as pg 4 | 5 | # For packages that require scipy, these may be needed: 6 | # from scipy.stats import futil 7 | # from scipy.sparse.csgraph import _validation 8 | 9 | pg.setConfigOption('background','w') 10 | pg.setConfigOption('foreground','k') 11 | app = QtWidgets.QApplication(sys.argv) 12 | 13 | pw = pg.plot(x = [0, 1, 2, 4], y = [4, 5, 9, 6]) 14 | pw.showGrid(x=True,y=True) 15 | text = pg.TextItem(html='
%s
' % "here",anchor=(0.0, 0.0)) 16 | text.setPos(1.0, 5.0) 17 | pw.addItem(text) 18 | status = app.exec_() 19 | sys.exit(status) 20 | -------------------------------------------------------------------------------- /pyqtgraph/examples/py2exe/setup.py: -------------------------------------------------------------------------------- 1 | import shutil 2 | from distutils.core import setup 3 | 4 | # Remove the build folder 5 | shutil.rmtree("build", ignore_errors=True) 6 | shutil.rmtree("dist", ignore_errors=True) 7 | import sys 8 | 9 | includes = ['PyQt4', 'PyQt4.QtGui', 'PyQt4.QtSvg', 'sip', 'pyqtgraph.graphicsItems'] 10 | excludes = ['_gtkagg', '_tkagg', 'bsddb', 'curses', 'email', 'pywin.debugger', 11 | 'pywin.debugger.dbgcon', 'pywin.dialogs', 'tcl', 12 | 'Tkconstants', 'Tkinter', 'zmq'] 13 | if sys.version[0] == '2': 14 | # causes syntax error on py2 15 | excludes.append('PyQt4.uic.port_v3') 16 | 17 | packages = [] 18 | dll_excludes = ['libgdk-win32-2.0-0.dll', 'libgobject-2.0-0.dll', 'tcl84.dll', 19 | 'tk84.dll', 'MSVCP90.dll'] 20 | icon_resources = [] 21 | bitmap_resources = [] 22 | other_resources = [] 23 | data_files = [] 24 | setup( 25 | data_files=data_files, 26 | console=['plotTest.py'] , 27 | options={"py2exe": {"excludes": excludes, 28 | "includes": includes, 29 | "dll_excludes": dll_excludes, 30 | "optimize": 0, 31 | "compressed": 2, 32 | "bundle_files": 1}}, 33 | zipfile=None, 34 | ) 35 | -------------------------------------------------------------------------------- /pyqtgraph/examples/relativity/__init__.py: -------------------------------------------------------------------------------- 1 | from .relativity import * 2 | -------------------------------------------------------------------------------- /pyqtgraph/examples/relativity_demo.py: -------------------------------------------------------------------------------- 1 | """ 2 | Special relativity simulation 3 | """ 4 | 5 | from relativity import RelativityGUI 6 | 7 | import pyqtgraph as pg 8 | 9 | pg.mkQApp() 10 | win = RelativityGUI() 11 | win.setWindowTitle("Relativity!") 12 | win.resize(1100,700) 13 | win.show() 14 | win.loadPreset(None, 'Twin Paradox (grid)') 15 | 16 | if __name__ == '__main__': 17 | pg.exec() 18 | -------------------------------------------------------------------------------- /pyqtgraph/examples/template.py: -------------------------------------------------------------------------------- 1 | """ 2 | Description of example 3 | """ 4 | 5 | import numpy as np 6 | 7 | import pyqtgraph as pg 8 | from pyqtgraph.Qt import QtCore, QtGui, QtWidgets, mkQApp 9 | 10 | app = mkQApp() 11 | 12 | # win.setWindowTitle('pyqtgraph example: ____') 13 | 14 | if __name__ == '__main__': 15 | pg.exec() 16 | -------------------------------------------------------------------------------- /pyqtgraph/examples/text.py: -------------------------------------------------------------------------------- 1 | """ 2 | This example shows how to insert text into a scene using TextItem. This class 3 | is for displaying text that is anchored to a particular location in the data 4 | coordinate system, but which is always displayed unscaled. 5 | 6 | For text that scales with the data, use QTextItem. 7 | For text that can be placed in a layout, use LabelItem. 8 | """ 9 | 10 | import numpy as np 11 | 12 | import pyqtgraph as pg 13 | from pyqtgraph.Qt import QtCore 14 | 15 | x = np.linspace(-20, 20, 1000) 16 | y = np.sin(x) / x 17 | plot = pg.plot() ## create an empty plot widget 18 | plot.setYRange(-1, 2) 19 | plot.setWindowTitle('pyqtgraph example: text') 20 | curve = plot.plot(x,y) ## add a single curve 21 | 22 | ## Create text object, use HTML tags to specify color/size 23 | text = pg.TextItem(html='
This is the
PEAK
', anchor=(-0.3,0.5), angle=45, border='w', fill=(0, 0, 255, 100)) 24 | plot.addItem(text) 25 | text.setPos(0, y.max()) 26 | 27 | ## Draw an arrowhead next to the text box 28 | arrow = pg.ArrowItem(pos=(0, y.max()), angle=-45) 29 | plot.addItem(arrow) 30 | 31 | 32 | ## Set up an animated arrow and text that track the curve 33 | curvePoint = pg.CurvePoint(curve) 34 | plot.addItem(curvePoint) 35 | text2 = pg.TextItem("test", anchor=(0.5, -1.0)) 36 | text2.setParentItem(curvePoint) 37 | arrow2 = pg.ArrowItem(angle=90) 38 | arrow2.setParentItem(curvePoint) 39 | 40 | ## update position every 10ms 41 | index = 0 42 | def update(): 43 | global curvePoint, index 44 | index = (index + 1) % len(x) 45 | curvePoint.setPos(float(index)/(len(x)-1)) 46 | text2.setText('[%0.1f, %0.1f]' % (x[index], y[index])) 47 | 48 | timer = QtCore.QTimer() 49 | timer.timeout.connect(update) 50 | timer.start(10) 51 | 52 | if __name__ == '__main__': 53 | pg.exec() 54 | -------------------------------------------------------------------------------- /pyqtgraph/examples/verlet_chain/__init__.py: -------------------------------------------------------------------------------- 1 | from .chain import ChainSim 2 | -------------------------------------------------------------------------------- /pyqtgraph/examples/verlet_chain/make: -------------------------------------------------------------------------------- 1 | gcc -fPIC -c relax.c 2 | gcc -shared -o maths.so relax.o 3 | -------------------------------------------------------------------------------- /pyqtgraph/examples/verlet_chain/relax.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void relax( 5 | double* pos, 6 | long* links, 7 | double* mrel1, 8 | double* mrel2, 9 | double* lengths, 10 | char* push, 11 | char* pull, 12 | int nlinks, 13 | int iters) 14 | { 15 | int i, l, p1, p2; 16 | double x1, x2, y1, y2, dx, dy, dist, change; 17 | // printf("%d, %d\n", iters, nlinks); 18 | for( i=0; i lengths[l] ) 36 | dist = lengths[l]; 37 | 38 | change = (lengths[l]-dist) / dist; 39 | dx *= change; 40 | dy *= change; 41 | 42 | pos[p1] -= mrel2[l] * dx; 43 | pos[p1+1] -= mrel2[l] * dy; 44 | pos[p2] += mrel1[l] * dx; 45 | pos[p2+1] += mrel1[l] * dy; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /pyqtgraph/examples/verlet_chain/relax.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import os 3 | 4 | so = os.path.join(os.path.dirname(__file__), 'maths.so') 5 | try: 6 | lib = ctypes.CDLL(so) 7 | COMPILED = True 8 | except OSError: 9 | COMPILED = False 10 | 11 | 12 | if COMPILED: 13 | lib.relax.argtypes = [ 14 | ctypes.c_void_p, 15 | ctypes.c_void_p, 16 | ctypes.c_void_p, 17 | ctypes.c_void_p, 18 | ctypes.c_void_p, 19 | ctypes.c_void_p, 20 | ctypes.c_void_p, 21 | ctypes.c_int, 22 | ctypes.c_int, 23 | ] 24 | 25 | def relax(pos, links, mrel1, mrel2, lengths, push, pull, iters): 26 | nlinks = links.shape[0] 27 | lib.relax(pos.ctypes, links.ctypes, mrel1.ctypes, mrel2.ctypes, lengths.ctypes, push.ctypes, pull.ctypes, nlinks, iters) 28 | 29 | else: 30 | def relax(pos, links, mrel1, mrel2, lengths, push, pull, iters): 31 | lengths2 = lengths**2 32 | for i in range(iters): 33 | #p1 = links[:, 0] 34 | #p2 = links[:, 1] 35 | #x1 = pos[p1] 36 | #x2 = pos[p2] 37 | 38 | #dx = x2 - x1 39 | 40 | #dist = (dx**2).sum(axis=1)**0.5 41 | 42 | #mask = (npush & (dist < lengths)) | (npull & (dist > lengths)) 43 | ##dist[mask] = lengths[mask] 44 | #change = (lengths-dist) / dist 45 | #change[mask] = 0 46 | 47 | #dx *= change[:, np.newaxis] 48 | #print dx 49 | 50 | ##pos[p1] -= mrel2 * dx 51 | ##pos[p2] += mrel1 * dx 52 | #for j in range(links.shape[0]): 53 | #pos[links[j,0]] -= mrel2[j] * dx[j] 54 | #pos[links[j,1]] += mrel1[j] * dx[j] 55 | 56 | 57 | for l in range(links.shape[0]): 58 | p1, p2 = links[l]; 59 | x1 = pos[p1] 60 | x2 = pos[p2] 61 | 62 | dx = x2 - x1 63 | dist2 = (dx**2).sum() 64 | 65 | if (push[l] and dist2 < lengths2[l]) or (pull[l] and dist2 > lengths2[l]): 66 | dist = dist2 ** 0.5 67 | change = (lengths[l]-dist) / dist 68 | dx *= change 69 | pos[p1] -= mrel2[l] * dx 70 | pos[p2] += mrel1[l] * dx 71 | -------------------------------------------------------------------------------- /pyqtgraph/exporters/__init__.py: -------------------------------------------------------------------------------- 1 | from .CSVExporter import * 2 | from .Exporter import Exporter 3 | from .HDF5Exporter import * 4 | from .ImageExporter import * 5 | from .Matplotlib import * 6 | from .PrintExporter import * 7 | from .SVGExporter import * 8 | 9 | 10 | def listExporters(): 11 | return Exporter.Exporters[:] 12 | -------------------------------------------------------------------------------- /pyqtgraph/flowchart/FlowchartGraphicsView.py: -------------------------------------------------------------------------------- 1 | from ..graphicsItems.ViewBox import ViewBox 2 | from ..Qt import QtCore, QtGui, QtWidgets 3 | from ..widgets.GraphicsView import GraphicsView 4 | 5 | translate = QtCore.QCoreApplication.translate 6 | 7 | class FlowchartGraphicsView(GraphicsView): 8 | 9 | sigHoverOver = QtCore.Signal(object) 10 | sigClicked = QtCore.Signal(object) 11 | 12 | def __init__(self, widget, *args): 13 | GraphicsView.__init__(self, *args, useOpenGL=False) 14 | self._vb = FlowchartViewBox(widget, lockAspect=True, invertY=True) 15 | self.setCentralItem(self._vb) 16 | self.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True) 17 | 18 | def viewBox(self): 19 | return self._vb 20 | 21 | 22 | class FlowchartViewBox(ViewBox): 23 | 24 | def __init__(self, widget, *args, **kwargs): 25 | ViewBox.__init__(self, *args, **kwargs) 26 | self.widget = widget 27 | 28 | def getMenu(self, ev): 29 | ## called by ViewBox to create a new context menu 30 | self._fc_menu = QtWidgets.QMenu() 31 | self._subMenus = self.getContextMenus(ev) 32 | for menu in self._subMenus: 33 | self._fc_menu.addMenu(menu) 34 | return self._fc_menu 35 | 36 | def getContextMenus(self, ev): 37 | ## called by scene to add menus on to someone else's context menu 38 | menu = self.widget.buildMenu(ev.scenePos()) 39 | menu.setTitle(translate("Context Menu", "Add node")) 40 | return [menu, ViewBox.getMenu(self, ev)] 41 | -------------------------------------------------------------------------------- /pyqtgraph/flowchart/__init__.py: -------------------------------------------------------------------------------- 1 | from .Flowchart import * 2 | from .library import getNodeTree, getNodeType, registerNodeType 3 | -------------------------------------------------------------------------------- /pyqtgraph/flowchart/library/__init__.py: -------------------------------------------------------------------------------- 1 | from ..NodeLibrary import NodeLibrary, isNodeClass 2 | from . import Data, Display, Filters, Operators 3 | 4 | # Build default library 5 | LIBRARY = NodeLibrary() 6 | 7 | # For backward compatibility, expose the default library's properties here: 8 | NODE_LIST = LIBRARY.nodeList 9 | NODE_TREE = LIBRARY.nodeTree 10 | registerNodeType = LIBRARY.addNodeType 11 | getNodeTree = LIBRARY.getNodeTree 12 | getNodeType = LIBRARY.getNodeType 13 | 14 | # Add all nodes to the default library 15 | for mod in [Data, Display, Filters, Operators]: 16 | nodes = [getattr(mod, name) for name in dir(mod) if isNodeClass(getattr(mod, name))] 17 | for node in nodes: 18 | LIBRARY.addNodeType(node, [(mod.__name__.split('.')[-1],)]) 19 | 20 | -------------------------------------------------------------------------------- /pyqtgraph/frozenSupport.py: -------------------------------------------------------------------------------- 1 | ## Definitions helpful in frozen environments (eg py2exe) 2 | import os 3 | import sys 4 | import zipfile 5 | 6 | 7 | def listdir(path): 8 | """Replacement for os.listdir that works in frozen environments.""" 9 | if not hasattr(sys, 'frozen'): 10 | return os.listdir(path) 11 | 12 | (zipPath, archivePath) = splitZip(path) 13 | if archivePath is None: 14 | return os.listdir(path) 15 | 16 | with zipfile.ZipFile(zipPath, "r") as zipobj: 17 | contents = zipobj.namelist() 18 | results = set() 19 | for name in contents: 20 | # components in zip archive paths are always separated by forward slash 21 | if name.startswith(archivePath) and len(name) > len(archivePath): 22 | name = name[len(archivePath):].split('/')[0] 23 | results.add(name) 24 | return list(results) 25 | 26 | def isdir(path): 27 | """Replacement for os.path.isdir that works in frozen environments.""" 28 | if not hasattr(sys, 'frozen'): 29 | return os.path.isdir(path) 30 | 31 | (zipPath, archivePath) = splitZip(path) 32 | if archivePath is None: 33 | return os.path.isdir(path) 34 | with zipfile.ZipFile(zipPath, "r") as zipobj: 35 | contents = zipobj.namelist() 36 | archivePath = archivePath.rstrip('/') + '/' ## make sure there's exactly one '/' at the end 37 | for c in contents: 38 | if c.startswith(archivePath): 39 | return True 40 | return False 41 | 42 | 43 | def splitZip(path): 44 | """Splits a path containing a zip file into (zipfile, subpath). 45 | If there is no zip file, returns (path, None)""" 46 | components = os.path.normpath(path).split(os.sep) 47 | for index, component in enumerate(components): 48 | if component.endswith('.zip'): 49 | zipPath = os.sep.join(components[0:index+1]) 50 | archivePath = ''.join([x+'/' for x in components[index+1:]]) 51 | return (zipPath, archivePath) 52 | else: 53 | return (path, None) 54 | 55 | 56 | -------------------------------------------------------------------------------- /pyqtgraph/functions_numba.py: -------------------------------------------------------------------------------- 1 | import numba 2 | import numpy as np 3 | 4 | rescale_functions = {} 5 | 6 | def rescale_clip_source(xx, scale, offset, vmin, vmax, yy): 7 | for i in range(xx.size): 8 | val = (xx[i] - offset) * scale 9 | yy[i] = min(max(val, vmin), vmax) 10 | 11 | def rescaleData(data, scale, offset, dtype, clip): 12 | data_out = np.empty_like(data, dtype=dtype) 13 | key = (data.dtype.name, data_out.dtype.name) 14 | func = rescale_functions.get(key) 15 | if func is None: 16 | func = numba.guvectorize( 17 | [f'{key[0]}[:],f8,f8,f8,f8,{key[1]}[:]'], 18 | '(n),(),(),(),()->(n)', 19 | nopython=True)(rescale_clip_source) 20 | rescale_functions[key] = func 21 | func(data, scale, offset, clip[0], clip[1], out=data_out) 22 | return data_out 23 | 24 | @numba.jit(nopython=True) 25 | def rescale_and_lookup(data, scale, offset, lut): 26 | # data should be floating point and 2d 27 | # lut is 1d 28 | vmin, vmax = 0, lut.shape[0] - 1 29 | out = np.empty_like(data, dtype=lut.dtype) 30 | for (x, y) in np.nditer((data, out)): 31 | val = (x - offset) * scale 32 | val = min(max(val, vmin), vmax) 33 | y[...] = lut[int(val)] 34 | return out 35 | 36 | @numba.jit(nopython=True) 37 | def rescale_and_clip(data, scale, offset, vmin, vmax): 38 | # vmin and vmax <= 255 39 | out = np.empty_like(data, dtype=np.uint8) 40 | for (x, y) in np.nditer((data, out)): 41 | val = (x - offset) * scale 42 | val = min(max(val, vmin), vmax) 43 | y[...] = val 44 | return out 45 | 46 | @numba.jit(nopython=True) 47 | def numba_take(lut, data): 48 | # numba supports only the 1st two arguments of np.take 49 | return np.take(lut, data) 50 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/ButtonItem.py: -------------------------------------------------------------------------------- 1 | from ..Qt import QtCore, QtGui 2 | from .GraphicsObject import GraphicsObject 3 | 4 | __all__ = ['ButtonItem'] 5 | class ButtonItem(GraphicsObject): 6 | """Button graphicsItem displaying an image.""" 7 | 8 | clicked = QtCore.Signal(object) 9 | 10 | def __init__(self, imageFile=None, width=None, parentItem=None, pixmap=None): 11 | self.enabled = True 12 | GraphicsObject.__init__(self) 13 | if imageFile is not None: 14 | self.setImageFile(imageFile) 15 | elif pixmap is not None: 16 | self.setPixmap(pixmap) 17 | 18 | self._width = width 19 | if self._width is None: 20 | self._width = self.pixmap.width() / self.pixmap.devicePixelRatio() 21 | 22 | if parentItem is not None: 23 | self.setParentItem(parentItem) 24 | self.setOpacity(0.7) 25 | 26 | def setImageFile(self, imageFile): 27 | self.setPixmap(QtGui.QPixmap(imageFile)) 28 | 29 | def setPixmap(self, pixmap): 30 | self.pixmap = pixmap 31 | self.update() 32 | 33 | def mouseClickEvent(self, ev): 34 | if self.enabled: 35 | self.clicked.emit(self) 36 | 37 | def hoverEvent(self, ev): 38 | if not self.enabled: 39 | return 40 | if ev.isEnter(): 41 | self.setOpacity(1.0) 42 | elif ev.isExit(): 43 | self.setOpacity(0.7) 44 | 45 | def disable(self): 46 | self.enabled = False 47 | self.setOpacity(0.4) 48 | 49 | def enable(self): 50 | self.enabled = True 51 | self.setOpacity(0.7) 52 | 53 | def paint(self, p, *args): 54 | p.setRenderHint(p.RenderHint.Antialiasing) 55 | tgtRect = QtCore.QRectF(0, 0, self._width, self._width) 56 | srcRect = QtCore.QRectF(self.pixmap.rect()) 57 | p.drawPixmap(tgtRect, self.pixmap, srcRect) 58 | 59 | def boundingRect(self): 60 | return QtCore.QRectF(0, 0, self._width, self._width) 61 | 62 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/GradientPresets.py: -------------------------------------------------------------------------------- 1 | __all__ = ['Gradients'] 2 | 3 | 4 | Gradients = dict([ 5 | ('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}), 6 | ('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}), 7 | ('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ), 8 | ('bipolar', {'ticks': [(0.0, (0, 255, 255, 255)), (1.0, (255, 255, 0, 255)), (0.5, (0, 0, 0, 255)), (0.25, (0, 0, 255, 255)), (0.75, (255, 0, 0, 255))], 'mode': 'rgb'}), 9 | ('spectrum', {'ticks': [(1.0, (255, 0, 255, 255)), (0.0, (255, 0, 0, 255))], 'mode': 'hsv'}), 10 | ('cyclic', {'ticks': [(0.0, (255, 0, 4, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'hsv'}), 11 | ('greyclip', {'ticks': [(0.0, (0, 0, 0, 255)), (0.99, (255, 255, 255, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'rgb'}), 12 | ('grey', {'ticks': [(0.0, (0, 0, 0, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'}), 13 | # Perceptually uniform sequential colormaps from Matplotlib 2.0 14 | ('viridis', {'ticks': [(0.0, (68, 1, 84, 255)), (0.25, (58, 82, 139, 255)), (0.5, (32, 144, 140, 255)), (0.75, (94, 201, 97, 255)), (1.0, (253, 231, 36, 255))], 'mode': 'rgb'}), 15 | ('inferno', {'ticks': [(0.0, (0, 0, 3, 255)), (0.25, (87, 15, 109, 255)), (0.5, (187, 55, 84, 255)), (0.75, (249, 142, 8, 255)), (1.0, (252, 254, 164, 255))], 'mode': 'rgb'}), 16 | ('plasma', {'ticks': [(0.0, (12, 7, 134, 255)), (0.25, (126, 3, 167, 255)), (0.5, (203, 71, 119, 255)), (0.75, (248, 149, 64, 255)), (1.0, (239, 248, 33, 255))], 'mode': 'rgb'}), 17 | ('magma', {'ticks': [(0.0, (0, 0, 3, 255)), (0.25, (80, 18, 123, 255)), (0.5, (182, 54, 121, 255)), (0.75, (251, 136, 97, 255)), (1.0, (251, 252, 191, 255))], 'mode': 'rgb'}), 18 | # turbo from https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html 19 | ('turbo', {'ticks': [(0.0, (51, 27, 61, 255)), (0.125, (77, 110, 223, 255)), (0.25, (61, 185, 233, 255)), (0.375, (68, 238, 154, 255)), (0.5, (164, 250, 80, 255)), 20 | (0.625, (235, 206, 76, 255)), (0.75, (247, 129, 55, 255)), (0.875, (206, 58, 32, 255)), (1.0, (119, 21, 19, 255))], 'mode': 'rgb'}), 21 | ]) 22 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/GraphicsObject.py: -------------------------------------------------------------------------------- 1 | import warnings 2 | from ..Qt import QT_LIB, QtCore, QtWidgets 3 | from .GraphicsItem import GraphicsItem 4 | 5 | __all__ = ['GraphicsObject'] 6 | class GraphicsObject(GraphicsItem, QtWidgets.QGraphicsObject): 7 | """ 8 | **Bases:** :class:`GraphicsItem `, :class:`QtWidgets.QGraphicsObject` 9 | 10 | Extension of QGraphicsObject with some useful methods (provided by :class:`GraphicsItem `) 11 | """ 12 | _qtBaseClass = QtWidgets.QGraphicsObject 13 | def __init__(self, *args): 14 | self.__inform_view_on_changes = True 15 | QtWidgets.QGraphicsObject.__init__(self, *args) 16 | self.setFlag(self.GraphicsItemFlag.ItemSendsGeometryChanges) 17 | GraphicsItem.__init__(self) 18 | 19 | def itemChange(self, change, value): 20 | ret = super().itemChange(change, value) 21 | if change in [self.GraphicsItemChange.ItemParentHasChanged, self.GraphicsItemChange.ItemSceneHasChanged]: 22 | if self.__class__.__dict__.get('parentChanged') is not None: 23 | # user's GraphicsObject subclass has a parentChanged() method 24 | warnings.warn( 25 | "parentChanged() is deprecated and will be removed in the future. " 26 | "Use changeParent() instead.", 27 | DeprecationWarning, stacklevel=2 28 | ) 29 | if QT_LIB == 'PySide6' and QtCore.__version_info__ == (6, 2, 2): 30 | # workaround PySide6 6.2.2 issue https://bugreports.qt.io/browse/PYSIDE-1730 31 | # note that the bug exists also in PySide6 6.2.2.1 / Qt 6.2.2 32 | getattr(self.__class__, 'parentChanged')(self) 33 | else: 34 | self.parentChanged() 35 | else: 36 | self.changeParent() 37 | try: 38 | inform_view_on_change = self.__inform_view_on_changes 39 | except AttributeError: 40 | # It's possible that the attribute was already collected when the itemChange happened 41 | # (if it was triggered during the gc of the object). 42 | pass 43 | else: 44 | if inform_view_on_change and change in [self.GraphicsItemChange.ItemPositionHasChanged, self.GraphicsItemChange.ItemTransformHasChanged]: 45 | self.informViewBoundsChanged() 46 | 47 | return ret 48 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/ItemGroup.py: -------------------------------------------------------------------------------- 1 | from ..Qt import QtCore 2 | from .GraphicsObject import GraphicsObject 3 | 4 | __all__ = ['ItemGroup'] 5 | class ItemGroup(GraphicsObject): 6 | """ 7 | Replacement for QGraphicsItemGroup 8 | """ 9 | 10 | def __init__(self, *args): 11 | GraphicsObject.__init__(self, *args) 12 | self.setFlag(self.GraphicsItemFlag.ItemHasNoContents) 13 | 14 | def boundingRect(self): 15 | return QtCore.QRectF() 16 | 17 | def paint(self, *args): 18 | pass 19 | 20 | def addItem(self, item): 21 | item.setParentItem(self) 22 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/PlotItem/__init__.py: -------------------------------------------------------------------------------- 1 | from .PlotItem import PlotItem 2 | 3 | __all__ = ['PlotItem'] 4 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/ViewBox/__init__.py: -------------------------------------------------------------------------------- 1 | from .ViewBox import ViewBox 2 | 3 | __all__ = ['ViewBox'] 4 | -------------------------------------------------------------------------------- /pyqtgraph/graphicsItems/__init__.py: -------------------------------------------------------------------------------- 1 | ### just import everything from sub-modules 2 | 3 | #import os 4 | 5 | #d = os.path.split(__file__)[0] 6 | #files = [] 7 | #for f in os.listdir(d): 8 | #if os.path.isdir(os.path.join(d, f)): 9 | #files.append(f) 10 | #elif f[-3:] == '.py' and f != '__init__.py': 11 | #files.append(f[:-3]) 12 | 13 | #for modName in files: 14 | #mod = __import__(modName, globals(), locals(), fromlist=['*']) 15 | #if hasattr(mod, '__all__'): 16 | #names = mod.__all__ 17 | #else: 18 | #names = [n for n in dir(mod) if n[0] != '_'] 19 | #for k in names: 20 | ##print modName, k 21 | #globals()[k] = getattr(mod, k) 22 | -------------------------------------------------------------------------------- /pyqtgraph/icons/__init__.py: -------------------------------------------------------------------------------- 1 | import os.path as op 2 | import warnings 3 | 4 | from ..Qt import QtGui, QtWidgets 5 | 6 | __all__ = ['getGraphIcon', 'getGraphPixmap'] 7 | 8 | _ICON_REGISTRY = {} 9 | 10 | 11 | class GraphIcon: 12 | """An icon place holder for lazy loading of QIcons 13 | 14 | The icon must reside in the icons folder and the path refers to the full 15 | name including suffix of the icon file, e.g.: 16 | 17 | tiny = GraphIcon("tiny.png") 18 | 19 | Icons can be later retrieved via the function `getGraphIcon` and providing 20 | the name: 21 | 22 | tiny = getGraphIcon("tiny") 23 | """ 24 | 25 | def __init__(self, path): 26 | self._path = path 27 | name = path.split('.')[0] 28 | _ICON_REGISTRY[name] = self 29 | self._icon = None 30 | 31 | def _build_qicon(self): 32 | icon = QtGui.QIcon(op.join(op.dirname(__file__), self._path)) 33 | name = self._path.split('.')[0] 34 | _ICON_REGISTRY[name] = icon 35 | self._icon = icon 36 | 37 | @property 38 | def qicon(self): 39 | if self._icon is None: 40 | self._build_qicon() 41 | 42 | return self._icon 43 | 44 | 45 | def getGraphIcon(name): 46 | """Return a `PyQtGraph` icon from the registry by `name`""" 47 | icon = _ICON_REGISTRY[name] 48 | if isinstance(icon, GraphIcon): 49 | icon = icon.qicon 50 | _ICON_REGISTRY[name] = icon 51 | 52 | return icon 53 | 54 | 55 | def getGraphPixmap(name, size=(20, 20)): 56 | """Return a `QPixmap` from the registry by `name`""" 57 | icon = getGraphIcon(name) 58 | 59 | return icon.pixmap(*size) 60 | 61 | 62 | # Note: List all graph icons here ... 63 | auto = GraphIcon("auto.png") 64 | ctrl = GraphIcon("ctrl.png") 65 | default = GraphIcon("default.png") 66 | invisibleEye = GraphIcon("invisibleEye.svg") 67 | lock = GraphIcon("lock.png") 68 | -------------------------------------------------------------------------------- /pyqtgraph/icons/auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/auto.png -------------------------------------------------------------------------------- /pyqtgraph/icons/ctrl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/ctrl.png -------------------------------------------------------------------------------- /pyqtgraph/icons/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/default.png -------------------------------------------------------------------------------- /pyqtgraph/icons/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/lock.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_128px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_128px.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_128px@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_128px@2x.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_192px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_192px.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_256px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_256px.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_256px@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_256px@2x.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_512px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_512px.png -------------------------------------------------------------------------------- /pyqtgraph/icons/peegee/peegee_512px@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/icons/peegee/peegee_512px@2x.png -------------------------------------------------------------------------------- /pyqtgraph/imageview/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Widget used for display and analysis of 2D and 3D image data. 3 | Includes ROI plotting over time and image normalization. 4 | """ 5 | 6 | from .ImageView import ImageView 7 | 8 | __all__ = ['ImageView'] 9 | -------------------------------------------------------------------------------- /pyqtgraph/jupyter/__init__.py: -------------------------------------------------------------------------------- 1 | from .GraphicsView import GraphicsLayoutWidget 2 | from .GraphicsView import PlotWidget 3 | 4 | -------------------------------------------------------------------------------- /pyqtgraph/metaarray/__init__.py: -------------------------------------------------------------------------------- 1 | from .MetaArray import * 2 | -------------------------------------------------------------------------------- /pyqtgraph/metaarray/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Luke Campagnola ('luke.campagnola@%s.com' % 'gmail') 2 | The MIT License 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /pyqtgraph/metaarray/readMeta.m: -------------------------------------------------------------------------------- 1 | function f = readMeta(file) 2 | info = hdf5info(file); 3 | f = readMetaRecursive(info.GroupHierarchy.Groups(1)); 4 | end 5 | 6 | 7 | function f = readMetaRecursive(root) 8 | typ = 0; 9 | for i = 1:length(root.Attributes) 10 | if strcmp(root.Attributes(i).Shortname, '_metaType_') 11 | typ = root.Attributes(i).Value.Data; 12 | break 13 | end 14 | end 15 | if typ == 0 16 | printf('group has no _metaType_') 17 | typ = 'dict'; 18 | end 19 | 20 | list = 0; 21 | if strcmp(typ, 'list') || strcmp(typ, 'tuple') 22 | data = {}; 23 | list = 1; 24 | elseif strcmp(typ, 'dict') 25 | data = struct(); 26 | else 27 | printf('Unrecognized meta type %s', typ); 28 | data = struct(); 29 | end 30 | 31 | for i = 1:length(root.Attributes) 32 | name = root.Attributes(i).Shortname; 33 | if strcmp(name, '_metaType_') 34 | continue 35 | end 36 | val = root.Attributes(i).Value; 37 | if isa(val, 'hdf5.h5string') 38 | val = val.Data; 39 | end 40 | if list 41 | ind = str2num(name)+1; 42 | data{ind} = val; 43 | else 44 | data.(name) = val; 45 | end 46 | end 47 | 48 | for i = 1:length(root.Datasets) 49 | fullName = root.Datasets(i).Name; 50 | name = stripName(fullName); 51 | file = root.Datasets(i).Filename; 52 | data2 = hdf5read(file, fullName); 53 | if list 54 | ind = str2num(name)+1; 55 | data{ind} = data2; 56 | else 57 | data.(name) = data2; 58 | end 59 | end 60 | 61 | for i = 1:length(root.Groups) 62 | name = stripName(root.Groups(i).Name); 63 | data2 = readMetaRecursive(root.Groups(i)); 64 | if list 65 | ind = str2num(name)+1; 66 | data{ind} = data2; 67 | else 68 | data.(name) = data2; 69 | end 70 | end 71 | f = data; 72 | return; 73 | end 74 | 75 | 76 | function f = stripName(str) 77 | inds = strfind(str, '/'); 78 | if isempty(inds) 79 | f = str; 80 | else 81 | f = str(inds(length(inds))+1:length(str)); 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /pyqtgraph/multiprocess/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Multiprocessing utility library 3 | (parallelization done the way I like it) 4 | 5 | Luke Campagnola 6 | 2012.06.10 7 | 8 | This library provides: 9 | 10 | - simple mechanism for starting a new python interpreter process that can be controlled from the original process 11 | (this allows, for example, displaying and manipulating plots in a remote process 12 | while the parent process is free to do other work) 13 | - proxy system that allows objects hosted in the remote process to be used as if they were local 14 | - Qt signal connection between processes 15 | - very simple in-line parallelization (fork only; does not work on windows) for number-crunching 16 | 17 | TODO: 18 | allow remote processes to serve as rendering engines that pass pixmaps back to the parent process for display 19 | (RemoteGraphicsView class) 20 | """ 21 | 22 | from .parallelizer import CanceledError, Parallelize 23 | from .processes import * 24 | from .remoteproxy import ClosedError, NoResultError, proxy 25 | -------------------------------------------------------------------------------- /pyqtgraph/multiprocess/bootstrap.py: -------------------------------------------------------------------------------- 1 | """For starting up remote processes""" 2 | import importlib 3 | import os 4 | import pickle 5 | import sys 6 | 7 | if __name__ == '__main__': 8 | if hasattr(os, 'setpgrp'): 9 | os.setpgrp() ## prevents signals (notably keyboard interrupt) being forwarded from parent to this process 10 | #name, port, authkey, ppid, targetStr, path, pyside = pickle.load(sys.stdin.buffer) 11 | opts = pickle.load(sys.stdin.buffer) 12 | #print "key:", ' '.join([str(ord(x)) for x in authkey]) 13 | path = opts.pop('path', None) 14 | if path is not None: 15 | if isinstance(path, str): 16 | # if string, just insert this into the path 17 | sys.path.insert(0, path) 18 | else: 19 | # if list, then replace the entire sys.path 20 | ## modify sys.path in place--no idea who already has a reference to the existing list. 21 | while len(sys.path) > 0: 22 | sys.path.pop() 23 | sys.path.extend(path) 24 | 25 | qt_lib = opts.pop('qt_lib', None) 26 | if qt_lib is not None: 27 | globals()[qt_lib] = importlib.import_module(qt_lib) 28 | 29 | targetStr = opts.pop('targetStr') 30 | try: 31 | target = pickle.loads(targetStr) ## unpickling the target should import everything we need 32 | except: 33 | print("Current sys.path:", sys.path) 34 | raise 35 | target(**opts) ## Send all other options to the target function 36 | sys.exit(0) 37 | -------------------------------------------------------------------------------- /pyqtgraph/opengl/__init__.py: -------------------------------------------------------------------------------- 1 | from . import shaders 2 | from .GLViewWidget import GLViewWidget 3 | from .items.GLAxisItem import * 4 | from .items.GLBarGraphItem import * 5 | from .items.GLBoxItem import * 6 | from .items.GLGradientLegendItem import * 7 | from .items.GLGraphItem import * 8 | from .items.GLGridItem import * 9 | from .items.GLImageItem import * 10 | from .items.GLLinePlotItem import * 11 | from .items.GLMeshItem import * 12 | from .items.GLScatterPlotItem import * 13 | from .items.GLSurfacePlotItem import * 14 | from .items.GLTextItem import * 15 | from .items.GLVolumeItem import * 16 | from .MeshData import MeshData 17 | 18 | ## dynamic imports cause too many problems. 19 | #from .. import importAll 20 | #importAll('items', globals(), locals()) 21 | 22 | 23 | ## for backward compatibility: 24 | #MeshData.MeshData = MeshData ## breaks autodoc. 25 | -------------------------------------------------------------------------------- /pyqtgraph/opengl/items/GLAxisItem.py: -------------------------------------------------------------------------------- 1 | from OpenGL.GL import * # noqa 2 | from ... import QtGui 3 | from ..GLGraphicsItem import GLGraphicsItem 4 | 5 | __all__ = ['GLAxisItem'] 6 | 7 | class GLAxisItem(GLGraphicsItem): 8 | """ 9 | **Bases:** :class:`GLGraphicsItem ` 10 | 11 | Displays three lines indicating origin and orientation of local coordinate system. 12 | 13 | """ 14 | 15 | def __init__(self, size=None, antialias=True, glOptions='translucent', parentItem=None): 16 | super().__init__(parentItem=parentItem) 17 | if size is None: 18 | size = QtGui.QVector3D(1,1,1) 19 | self.antialias = antialias 20 | self.setSize(size=size) 21 | self.setGLOptions(glOptions) 22 | 23 | def setSize(self, x=None, y=None, z=None, size=None): 24 | """ 25 | Set the size of the axes (in its local coordinate system; this does not affect the transform) 26 | Arguments can be x,y,z or size=QVector3D(). 27 | """ 28 | if size is not None: 29 | x = size.x() 30 | y = size.y() 31 | z = size.z() 32 | self.__size = [x,y,z] 33 | self.update() 34 | 35 | def size(self): 36 | return self.__size[:] 37 | 38 | 39 | def paint(self): 40 | 41 | #glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) 42 | #glEnable( GL_BLEND ) 43 | #glEnable( GL_ALPHA_TEST ) 44 | self.setupGLState() 45 | 46 | if self.antialias: 47 | glEnable(GL_LINE_SMOOTH) 48 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST) 49 | 50 | glBegin( GL_LINES ) 51 | 52 | x,y,z = self.size() 53 | glColor4f(0, 1, 0, .6) # z is green 54 | glVertex3f(0, 0, 0) 55 | glVertex3f(0, 0, z) 56 | 57 | glColor4f(1, 1, 0, .6) # y is yellow 58 | glVertex3f(0, 0, 0) 59 | glVertex3f(0, y, 0) 60 | 61 | glColor4f(0, 0, 1, .6) # x is blue 62 | glVertex3f(0, 0, 0) 63 | glVertex3f(x, 0, 0) 64 | glEnd() 65 | -------------------------------------------------------------------------------- /pyqtgraph/opengl/items/GLBarGraphItem.py: -------------------------------------------------------------------------------- 1 | __all__ = ["GLBarGraphItem"] 2 | 3 | import numpy as np 4 | 5 | from ..MeshData import MeshData 6 | from .GLMeshItem import GLMeshItem 7 | 8 | 9 | class GLBarGraphItem(GLMeshItem): 10 | def __init__(self, pos, size, parentItem=None): 11 | """ 12 | pos is (...,3) array of the bar positions (the corner of each bar) 13 | size is (...,3) array of the sizes of each bar 14 | """ 15 | nCubes = np.prod(pos.shape[:-1]) 16 | cubeVerts = np.mgrid[0:2,0:2,0:2].reshape(3,8).transpose().reshape(1,8,3) 17 | cubeFaces = np.array([ 18 | [0,1,2], [3,2,1], 19 | [4,5,6], [7,6,5], 20 | [0,1,4], [5,4,1], 21 | [2,3,6], [7,6,3], 22 | [0,2,4], [6,4,2], 23 | [1,3,5], [7,5,3]]).reshape(1,12,3) 24 | size = size.reshape((nCubes, 1, 3)) 25 | pos = pos.reshape((nCubes, 1, 3)) 26 | verts = cubeVerts * size + pos 27 | faces = cubeFaces + (np.arange(nCubes) * 8).reshape(nCubes,1,1) 28 | md = MeshData(verts.reshape(nCubes*8,3), faces.reshape(nCubes*12,3)) 29 | 30 | super().__init__(meshdata=md, shader='shaded', smooth=False, parentItem=parentItem) 31 | -------------------------------------------------------------------------------- /pyqtgraph/opengl/items/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/opengl/items/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/parametertree/__init__.py: -------------------------------------------------------------------------------- 1 | from . import parameterTypes as types 2 | from .Parameter import Parameter, registerParameterItemType, registerParameterType 3 | from .ParameterItem import ParameterItem 4 | from .ParameterSystem import ParameterSystem, SystemSolver 5 | from .ParameterTree import ParameterTree 6 | from .interactive import RunOptions, interact, InteractiveFunction, Interactor 7 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/bool.py: -------------------------------------------------------------------------------- 1 | from ...Qt import QtWidgets 2 | from .basetypes import WidgetParameterItem 3 | 4 | 5 | class BoolParameterItem(WidgetParameterItem): 6 | """ 7 | Registered parameter type which displays a QCheckBox 8 | """ 9 | def makeWidget(self): 10 | w = QtWidgets.QCheckBox() 11 | w.sigChanged = w.toggled 12 | w.value = w.isChecked 13 | w.setValue = w.setChecked 14 | self.hideWidget = False 15 | return w 16 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/calendar.py: -------------------------------------------------------------------------------- 1 | from ...Qt import QtCore, QtWidgets 2 | from ..Parameter import Parameter 3 | from .basetypes import WidgetParameterItem 4 | 5 | 6 | class CalendarParameterItem(WidgetParameterItem): 7 | def makeWidget(self): 8 | self.asSubItem = True 9 | w = QtWidgets.QCalendarWidget() 10 | w.setMaximumHeight(200) 11 | w.sigChanged = w.selectionChanged 12 | w.value = w.selectedDate 13 | w.setValue = w.setSelectedDate 14 | self.hideWidget = False 15 | self.param.opts.setdefault('default', QtCore.QDate.currentDate()) 16 | return w 17 | 18 | 19 | class CalendarParameter(Parameter): 20 | """ 21 | Displays a Qt calendar whose date is specified by a 'format' option. 22 | 23 | ============== ======================================================== 24 | **Options:** 25 | format Format for displaying the date and converting from a string. Can be any value accepted by 26 | `QDate.toString` and `fromString`, or a stringified version of a QDateFormat enum, i.e. 'ISODate', 27 | 'TextDate' (default), etc. 28 | ============== ======================================================== 29 | """ 30 | 31 | itemClass = CalendarParameterItem 32 | 33 | def __init__(self, **opts): 34 | opts.setdefault('format', 'TextDate') 35 | super().__init__(**opts) 36 | 37 | def _interpretFormat(self, fmt=None): 38 | fmt = fmt or self.opts.get('format') 39 | if hasattr(QtCore.Qt.DateFormat, fmt): 40 | fmt = getattr(QtCore.Qt.DateFormat, fmt) 41 | return fmt 42 | 43 | def _interpretValue(self, v): 44 | if isinstance(v, str): 45 | fmt = self._interpretFormat() 46 | if fmt is None: 47 | raise ValueError('Cannot parse date string without a set format') 48 | v = QtCore.QDate.fromString(v, fmt) 49 | return v 50 | 51 | def saveState(self, filter=None): 52 | state = super().saveState(filter) 53 | fmt = self._interpretFormat() 54 | if state.get('value', None) is not None: 55 | state['value'] = state['value'].toString(fmt) 56 | return state 57 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/color.py: -------------------------------------------------------------------------------- 1 | from ... import functions as fn 2 | from ...widgets.ColorButton import ColorButton 3 | from .basetypes import SimpleParameter, WidgetParameterItem 4 | 5 | 6 | class ColorParameterItem(WidgetParameterItem): 7 | """Registered parameter type which displays a :class:`ColorButton ` """ 8 | def makeWidget(self): 9 | w = ColorButton() 10 | w.sigChanged = w.sigColorChanged 11 | w.sigChanging = w.sigColorChanging 12 | w.value = w.color 13 | w.setValue = w.setColor 14 | self.hideWidget = False 15 | w.setFlat(True) 16 | return w 17 | 18 | 19 | class ColorParameter(SimpleParameter): 20 | itemClass = ColorParameterItem 21 | 22 | def _interpretValue(self, v): 23 | return fn.mkColor(v) 24 | 25 | def value(self): 26 | value = super().value() 27 | if value is None: 28 | return None 29 | return fn.mkColor(value) 30 | 31 | def saveState(self, filter=None): 32 | state = super().saveState(filter) 33 | state['value'] = self.value().getRgb() 34 | return state 35 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/colormap.py: -------------------------------------------------------------------------------- 1 | from ...colormap import ColorMap 2 | from ...Qt import QtCore 3 | from ...widgets.GradientWidget import GradientWidget 4 | from .basetypes import SimpleParameter, WidgetParameterItem 5 | 6 | 7 | class ColorMapParameterItem(WidgetParameterItem): 8 | """Registered parameter type which displays a :class:`GradientWidget `""" 9 | def makeWidget(self): 10 | w = GradientWidget(orientation='bottom') 11 | w.sizeHint = lambda: QtCore.QSize(300, 35) 12 | w.sigChanged = w.sigGradientChangeFinished 13 | w.sigChanging = w.sigGradientChanged 14 | w.value = w.colorMap 15 | w.setValue = w.setColorMap 16 | self.hideWidget = False 17 | self.asSubItem = True 18 | return w 19 | 20 | 21 | class ColorMapParameter(SimpleParameter): 22 | itemClass = ColorMapParameterItem 23 | 24 | def _interpretValue(self, v): 25 | if v is not None and not isinstance(v, ColorMap): 26 | raise TypeError("Cannot set colormap parameter from object %r" % v) 27 | return v 28 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/colormaplut.py: -------------------------------------------------------------------------------- 1 | from ... import colormap 2 | from ...widgets.ColorMapButton import ColorMapButton 3 | from .basetypes import Parameter, WidgetParameterItem 4 | 5 | 6 | class ColorMapLutParameterItem(WidgetParameterItem): 7 | def makeWidget(self): 8 | w = ColorMapButton() 9 | w.sigChanged = w.sigColorMapChanged 10 | w.value = w.colorMap 11 | w.setValue = w.setColorMap 12 | self.hideWidget = False 13 | return w 14 | 15 | 16 | class ColorMapLutParameter(Parameter): 17 | itemClass = ColorMapLutParameterItem 18 | 19 | def _interpretValue(self, v): 20 | if isinstance(v, str): 21 | v = colormap.get(v) 22 | if v is not None and not isinstance(v, colormap.ColorMap): 23 | raise TypeError("Cannot set colormap parameter from object %r" % v) 24 | return v 25 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/font.py: -------------------------------------------------------------------------------- 1 | from ...Qt import QtGui, QtWidgets 2 | from ..Parameter import Parameter 3 | from .basetypes import WidgetParameterItem 4 | 5 | 6 | class FontParameterItem(WidgetParameterItem): 7 | def makeWidget(self): 8 | w = QtWidgets.QFontComboBox() 9 | w.setMaximumHeight(20) 10 | w.sigChanged = w.currentFontChanged 11 | w.value = w.currentFont 12 | w.setValue = w.setCurrentFont 13 | self.hideWidget = False 14 | return w 15 | 16 | def updateDisplayLabel(self, value=None): 17 | if value is None: 18 | value = self.widget.currentText() 19 | super().updateDisplayLabel(value) 20 | 21 | 22 | class FontParameter(Parameter): 23 | """ 24 | Creates and controls a QFont value. Be careful when selecting options from the font dropdown. since not all 25 | fonts are available on all systems 26 | """ 27 | itemClass = FontParameterItem 28 | 29 | def _interpretValue(self, v): 30 | if isinstance(v, str): 31 | newVal = QtGui.QFont() 32 | if not newVal.fromString(v): 33 | raise ValueError(f'Error parsing font "{v}"') 34 | v = newVal 35 | return v 36 | 37 | def saveState(self, filter=None): 38 | state = super().saveState(filter) 39 | state['value'] = state['value'].toString() 40 | return state 41 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/numeric.py: -------------------------------------------------------------------------------- 1 | from ...widgets.SpinBox import SpinBox 2 | from .basetypes import WidgetParameterItem 3 | 4 | 5 | class NumericParameterItem(WidgetParameterItem): 6 | """ 7 | Subclasses `WidgetParameterItem` to provide the following types: 8 | 9 | ========================== ============================================================= 10 | **Registered Types:** 11 | int Displays a :class:`SpinBox ` in integer 12 | mode. 13 | float Displays a :class:`SpinBox `. 14 | ========================== ============================================================= 15 | """ 16 | def makeWidget(self): 17 | opts = self.param.opts 18 | t = opts['type'] 19 | defs = { 20 | 'value': 0, 'min': None, 'max': None, 21 | 'step': 1.0, 'dec': False, 22 | 'siPrefix': False, 'suffix': '', 'decimals': 3, 23 | } 24 | if t == 'int': 25 | defs['int'] = True 26 | defs['minStep'] = 1.0 27 | for k in defs: 28 | if k in opts: 29 | defs[k] = opts[k] 30 | if opts.get('limits') is not None: 31 | defs['min'], defs['max'] = opts['limits'] 32 | w = SpinBox() 33 | w.setOpts(**defs) 34 | w.sigChanged = w.sigValueChanged 35 | w.sigChanging = w.sigValueChanging 36 | return w 37 | 38 | def updateDisplayLabel(self, value=None): 39 | if value is None: 40 | value = self.widget.lineEdit().text() 41 | super().updateDisplayLabel(value) 42 | 43 | def showEditor(self): 44 | super().showEditor() 45 | self.widget.selectNumber() # select the numerical portion of the text for quick editing 46 | 47 | def limitsChanged(self, param, limits): 48 | self.widget.setOpts(bounds=limits) 49 | 50 | def optsChanged(self, param, opts): 51 | super().optsChanged(param, opts) 52 | sbOpts = {} 53 | if 'units' in opts and 'suffix' not in opts: 54 | sbOpts['suffix'] = opts['units'] 55 | for k, v in opts.items(): 56 | if k in self.widget.opts: 57 | sbOpts[k] = v 58 | self.widget.setOpts(**sbOpts) 59 | self.updateDisplayLabel() 60 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/progress.py: -------------------------------------------------------------------------------- 1 | from ...Qt import QtWidgets 2 | from ..Parameter import Parameter 3 | from .basetypes import WidgetParameterItem 4 | 5 | 6 | class ProgressBarParameterItem(WidgetParameterItem): 7 | def makeWidget(self): 8 | w = QtWidgets.QProgressBar() 9 | w.setMaximumHeight(20) 10 | w.sigChanged = w.valueChanged 11 | self.hideWidget = False 12 | return w 13 | 14 | 15 | class ProgressBarParameter(Parameter): 16 | """ 17 | Displays a progress bar whose value can be set between 0 and 100 18 | """ 19 | itemClass = ProgressBarParameterItem 20 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/str.py: -------------------------------------------------------------------------------- 1 | from ...Qt import QtWidgets 2 | from .basetypes import WidgetParameterItem 3 | 4 | 5 | class StrParameterItem(WidgetParameterItem): 6 | """Registered parameter type which displays a QLineEdit""" 7 | 8 | def makeWidget(self): 9 | w = QtWidgets.QLineEdit() 10 | w.setStyleSheet('border: 0px') 11 | w.sigChanged = w.editingFinished 12 | w.value = w.text 13 | w.setValue = w.setText 14 | w.sigChanging = w.textChanged 15 | return w 16 | -------------------------------------------------------------------------------- /pyqtgraph/parametertree/parameterTypes/text.py: -------------------------------------------------------------------------------- 1 | from ...Qt import QtCore, QtWidgets 2 | from ..Parameter import Parameter 3 | from .basetypes import WidgetParameterItem 4 | 5 | 6 | class TextParameterItem(WidgetParameterItem): 7 | """ParameterItem displaying a QTextEdit widget.""" 8 | 9 | def makeWidget(self): 10 | self.hideWidget = False 11 | self.asSubItem = True 12 | self.textBox = w = QtWidgets.QTextEdit() 13 | w.sizeHint = lambda: QtCore.QSize(300, 100) 14 | w.value = w.toPlainText 15 | w.setValue = w.setPlainText 16 | w.sigChanged = w.textChanged 17 | return w 18 | 19 | 20 | class TextParameter(Parameter): 21 | """Editable string, displayed as large text box in the tree.""" 22 | itemClass = TextParameterItem 23 | -------------------------------------------------------------------------------- /pyqtgraph/units.py: -------------------------------------------------------------------------------- 1 | # Very simple unit support: 2 | # - creates variable names like 'mV' and 'kHz' 3 | # - the value assigned to the variable corresponds to the scale prefix 4 | # (mV = 0.001) 5 | # - the actual units are purely cosmetic for making code clearer: 6 | # 7 | # x = 20*pA is identical to x = 20*1e-12 8 | # 9 | # No unicode variable names (μ,Ω) allowed until python 3, but just assigning 10 | # them to the globals dict doesn't error in python 2. 11 | import unicodedata 12 | 13 | # All unicode identifiers get normalized automatically 14 | SI_PREFIXES = unicodedata.normalize("NFKC", u"yzafpnµm kMGTPEZY") 15 | UNITS = unicodedata.normalize("NFKC", u"m,s,g,W,J,V,A,F,T,Hz,Ohm,Ω,S,N,C,px,b,B,Pa").split(",") 16 | allUnits = {} 17 | 18 | 19 | def addUnit(prefix, val): 20 | g = globals() 21 | for u in UNITS: 22 | g[prefix + u] = val 23 | allUnits[prefix + u] = val 24 | 25 | 26 | for pre in SI_PREFIXES: 27 | v = SI_PREFIXES.index(pre) - 8 28 | if pre == " ": 29 | pre = "" 30 | addUnit(pre, 1000 ** v) 31 | 32 | addUnit("c", 0.01) 33 | addUnit("d", 0.1) 34 | addUnit("da", 10) 35 | addUnit("h", 100) 36 | # py2 compatibility 37 | addUnit("u", 1e-6) 38 | 39 | 40 | def evalUnits(unitStr): 41 | """ 42 | Evaluate a unit string into ([numerators,...], [denominators,...]) 43 | Examples: 44 | N m/s^2 => ([N, m], [s, s]) 45 | A*s / V => ([A, s], [V,]) 46 | """ 47 | pass 48 | 49 | 50 | def formatUnits(units): 51 | """ 52 | Format a unit specification ([numerators,...], [denominators,...]) 53 | into a string (this is the inverse of evalUnits) 54 | """ 55 | pass 56 | 57 | 58 | def simplify(units): 59 | """ 60 | Cancel units that appear in both numerator and denominator, then attempt to replace 61 | groups of units with single units where possible (ie, J/s => W) 62 | """ 63 | pass 64 | -------------------------------------------------------------------------------- /pyqtgraph/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/util/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/util/colorama/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Jonathan Hartley 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of the copyright holders, nor those of its contributors 15 | may be used to endorse or promote products derived from this software without 16 | specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /pyqtgraph/util/colorama/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/util/colorama/__init__.py -------------------------------------------------------------------------------- /pyqtgraph/util/cupy_helper.py: -------------------------------------------------------------------------------- 1 | import os 2 | from warnings import warn 3 | 4 | from .. import getConfigOption 5 | 6 | 7 | def getCupy(): 8 | if getConfigOption("useCupy"): 9 | try: 10 | import cupy 11 | except ImportError: 12 | warn("cupy library could not be loaded, but 'useCupy' is set.") 13 | return None 14 | if os.name == "nt" and cupy.cuda.runtime.runtimeGetVersion() < 11000: 15 | warn("In Windows, CUDA toolkit should be version 11 or higher, or some functions may misbehave.") 16 | return cupy 17 | else: 18 | return None 19 | -------------------------------------------------------------------------------- /pyqtgraph/util/garbage_collector.py: -------------------------------------------------------------------------------- 1 | import gc 2 | 3 | from ..Qt import QtCore 4 | 5 | 6 | class GarbageCollector(object): 7 | ''' 8 | Disable automatic garbage collection and instead collect manually 9 | on a timer. 10 | 11 | This is done to ensure that garbage collection only happens in the GUI 12 | thread, as otherwise Qt can crash. 13 | 14 | Credit: Erik Janssens 15 | Source: http://pydev.blogspot.com/2014/03/should-python-garbage-collector-be.html 16 | ''' 17 | 18 | def __init__(self, interval=1.0, debug=False): 19 | self.debug = debug 20 | if debug: 21 | gc.set_debug(gc.DEBUG_LEAK) 22 | 23 | self.timer = QtCore.QTimer() 24 | self.timer.timeout.connect(self.check) 25 | 26 | self.threshold = gc.get_threshold() 27 | gc.disable() 28 | self.timer.start(int(interval * 1000)) 29 | 30 | def check(self): 31 | #return self.debug_cycles() # uncomment to just debug cycles 32 | l0, l1, l2 = gc.get_count() 33 | if self.debug: 34 | print('gc_check called:', l0, l1, l2) 35 | if l0 > self.threshold[0]: 36 | num = gc.collect(0) 37 | if self.debug: 38 | print('collecting gen 0, found: %d unreachable' % num) 39 | if l1 > self.threshold[1]: 40 | num = gc.collect(1) 41 | if self.debug: 42 | print('collecting gen 1, found: %d unreachable' % num) 43 | if l2 > self.threshold[2]: 44 | num = gc.collect(2) 45 | if self.debug: 46 | print('collecting gen 2, found: %d unreachable' % num) 47 | 48 | def debug_cycles(self): 49 | gc.collect() 50 | for obj in gc.garbage: 51 | print(obj, repr(obj), type(obj)) 52 | -------------------------------------------------------------------------------- /pyqtgraph/util/get_resolution.py: -------------------------------------------------------------------------------- 1 | from .. import mkQApp 2 | from ..Qt import QtGui 3 | 4 | 5 | def test_screenInformation(): 6 | # a qApp is still needed, otherwise screen is None 7 | qApp = mkQApp() # noqa 8 | screen = QtGui.QGuiApplication.primaryScreen() 9 | screens = QtGui.QGuiApplication.screens() 10 | resolution = screen.size() 11 | availableResolution = screen.availableSize() 12 | print("Screen resolution: {}x{}".format(resolution.width(), resolution.height())) 13 | print("Available geometry: {}x{}".format(availableResolution.width(), availableResolution.height())) 14 | print("Number of Screens: {}".format(len(screens))) 15 | return None 16 | 17 | 18 | if __name__ == "__main__": 19 | test_screenInformation() 20 | -------------------------------------------------------------------------------- /pyqtgraph/util/glinfo.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | 3 | from ..Qt import QT_LIB, QtGui 4 | 5 | GL_VENDOR = 7936 6 | GL_RENDERER = 7937 7 | GL_VERSION = 7938 8 | 9 | 10 | def print_version(funcs): 11 | glGetString = funcs.glGetString 12 | print('VENDOR:', glGetString(GL_VENDOR)) 13 | print('RENDERER:', glGetString(GL_RENDERER)) 14 | print('VERSION:', glGetString(GL_VERSION)) 15 | 16 | 17 | def print_extensions(ctx): 18 | extensions = sorted([ext.data().decode() for ext in ctx.extensions()]) 19 | print("Extensions:") 20 | for ext in extensions: 21 | print(f" {ext}") 22 | 23 | 24 | app = QtGui.QGuiApplication([]) 25 | surf = QtGui.QOffscreenSurface() 26 | surf.create() 27 | ctx = QtGui.QOpenGLContext() 28 | ctx.create() 29 | ctx.makeCurrent(surf) 30 | 31 | if QT_LIB == 'PySide2': 32 | funcs = ctx.functions() 33 | elif QT_LIB == 'PyQt5': 34 | profile = QtGui.QOpenGLVersionProfile() 35 | profile.setVersion(2, 0) 36 | funcs = ctx.versionFunctions(profile) 37 | elif QT_LIB in ['PyQt6', 'PySide6']: 38 | QtOpenGL = importlib.import_module(f'{QT_LIB}.QtOpenGL') 39 | profile = QtOpenGL.QOpenGLVersionProfile() 40 | profile.setVersion(2, 0) 41 | funcs_factory = QtOpenGL.QOpenGLVersionFunctionsFactory() 42 | funcs = funcs_factory.get(profile, ctx) 43 | 44 | print('isOpenGLES:', ctx.isOpenGLES()) 45 | print_version(funcs) 46 | print_extensions(ctx) 47 | -------------------------------------------------------------------------------- /pyqtgraph/util/numba_helper.py: -------------------------------------------------------------------------------- 1 | from warnings import warn 2 | 3 | from .. import getConfigOption 4 | 5 | 6 | def getNumbaFunctions(): 7 | if getConfigOption("useNumba"): 8 | try: 9 | import numba # noqa 10 | except ImportError: 11 | warn("numba library could not be loaded, but 'useNumba' is set.") 12 | return None 13 | 14 | from .. import functions_numba 15 | return functions_numba 16 | else: 17 | return None 18 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/BusyCursor.py: -------------------------------------------------------------------------------- 1 | from contextlib import contextmanager 2 | 3 | from ..Qt import QtCore, QtGui, QtWidgets 4 | 5 | __all__ = ["BusyCursor"] 6 | 7 | 8 | @contextmanager 9 | def BusyCursor(): 10 | """ 11 | Display a busy mouse cursor during long operations. 12 | Usage:: 13 | 14 | with BusyCursor(): 15 | doLongOperation() 16 | 17 | May be nested. If called from a non-gui thread, then the cursor will not be affected. 18 | """ 19 | app = QtCore.QCoreApplication.instance() 20 | in_gui_thread = (app is not None) and (QtCore.QThread.currentThread() == app.thread()) 21 | try: 22 | if in_gui_thread: 23 | guard = QtWidgets.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.CursorShape.WaitCursor)) 24 | # on PySide6 6.3.0, setOverrideCursor() returns a QOverrideCursorGuard object 25 | # that, on its destruction, calls restoreOverrideCursor() if the user had not 26 | # already done so. 27 | # if the user wants to call it manually, they must do it via the returned object, 28 | # and not via the QtWidgets.QApplication static method; otherwise the restore 29 | # would get called twice. 30 | yield 31 | finally: 32 | if in_gui_thread: 33 | if hasattr(guard, 'restoreOverrideCursor'): 34 | guard.restoreOverrideCursor() 35 | else: 36 | QtWidgets.QApplication.restoreOverrideCursor() 37 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/FileDialog.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from ..Qt import QtWidgets 4 | 5 | __all__ = ['FileDialog'] 6 | 7 | class FileDialog(QtWidgets.QFileDialog): 8 | ## Compatibility fix for OSX: 9 | ## For some reason the native dialog doesn't show up when you set AcceptMode to AcceptSave on OS X, so we don't use the native dialog 10 | 11 | def __init__(self, *args): 12 | QtWidgets.QFileDialog.__init__(self, *args) 13 | 14 | if sys.platform == 'darwin': 15 | self.setOption(QtWidgets.QFileDialog.Option.DontUseNativeDialog) 16 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/HistogramLUTWidget.py: -------------------------------------------------------------------------------- 1 | """ 2 | Widget displaying an image histogram along with gradient editor. Can be used to adjust 3 | the appearance of images. This is a wrapper around HistogramLUTItem 4 | """ 5 | 6 | from ..graphicsItems.HistogramLUTItem import HistogramLUTItem 7 | from ..Qt import QtCore, QtWidgets 8 | from .GraphicsView import GraphicsView 9 | 10 | __all__ = ['HistogramLUTWidget'] 11 | 12 | 13 | class HistogramLUTWidget(GraphicsView): 14 | """QWidget wrapper for :class:`~pyqtgraph.HistogramLUTItem`. 15 | 16 | All parameters are passed along in creating the HistogramLUTItem. 17 | """ 18 | 19 | def __init__(self, parent=None, *args, **kargs): 20 | background = kargs.pop('background', 'default') 21 | GraphicsView.__init__(self, parent, useOpenGL=False, background=background) 22 | self.item = HistogramLUTItem(*args, **kargs) 23 | self.setCentralItem(self.item) 24 | 25 | self.orientation = kargs.get('orientation', 'vertical') 26 | if self.orientation == 'vertical': 27 | self.setSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) 28 | self.setMinimumWidth(95) 29 | else: 30 | self.setSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred) 31 | self.setMinimumHeight(95) 32 | 33 | def sizeHint(self): 34 | if self.orientation == 'vertical': 35 | return QtCore.QSize(115, 200) 36 | else: 37 | return QtCore.QSize(200, 115) 38 | 39 | def __getattr__(self, attr): 40 | return getattr(self.item, attr) 41 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/MatplotlibWidget.py: -------------------------------------------------------------------------------- 1 | from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas 2 | from matplotlib.backends.backend_qtagg import NavigationToolbar2QT as NavigationToolbar 3 | from matplotlib.figure import Figure 4 | 5 | from ..Qt import QtWidgets 6 | import typing 7 | 8 | __all__ = ['MatplotlibWidget'] 9 | 10 | 11 | class MatplotlibWidget(QtWidgets.QWidget): 12 | """ 13 | Implements a Matplotlib figure inside a QWidget. 14 | Use getFigure() and redraw() to interact with matplotlib. 15 | 16 | Example:: 17 | 18 | mw = MatplotlibWidget() 19 | subplot = mw.getFigure().add_subplot(111) 20 | subplot.plot(x,y) 21 | mw.draw() 22 | """ 23 | 24 | parent_default = None 25 | figsize_default = (5.0, 4.0) 26 | dpi_default = 100 27 | 28 | @typing.overload 29 | def __init__(self, figsize=(5.0, 4.0), dpi=100, parent=None): 30 | pass 31 | 32 | @typing.overload 33 | def __init__(self, parent=None, figsize=(5.0, 4.0), dpi=100): 34 | pass 35 | 36 | def __init__(self, *args, **kwargs): 37 | if (args and not isinstance(args[0], QtWidgets.QWidget)): 38 | figsize = args[0] if len(args) > 0 \ 39 | else kwargs.get("figsize", MatplotlibWidget.figsize_default) 40 | dpi = args[1] if len(args) > 1 \ 41 | else kwargs.get("dpi", MatplotlibWidget.dpi_default) 42 | parent = args[2] if len(args) > 2 \ 43 | else kwargs.get("parent", MatplotlibWidget.parent_default) 44 | else: 45 | parent = args[0] if len(args) > 0 \ 46 | else kwargs.get("parent", MatplotlibWidget.parent_default) 47 | figsize = args[1] if len(args) > 1 \ 48 | else kwargs.get("figsize", MatplotlibWidget.figsize_default) 49 | dpi = args[2] if len(args) > 2 \ 50 | else kwargs.get("dpi", MatplotlibWidget.dpi_default) 51 | super().__init__(parent) 52 | 53 | self.fig = Figure(figsize, dpi=dpi) 54 | self.canvas = FigureCanvas(self.fig) 55 | self.canvas.setParent(self) 56 | self.toolbar = NavigationToolbar(self.canvas, self) 57 | 58 | self.vbox = QtWidgets.QVBoxLayout() 59 | self.vbox.addWidget(self.toolbar) 60 | self.vbox.addWidget(self.canvas) 61 | 62 | self.setLayout(self.vbox) 63 | 64 | def getFigure(self): 65 | return self.fig 66 | 67 | def draw(self): 68 | self.canvas.draw() 69 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/PathButton.py: -------------------------------------------------------------------------------- 1 | from .. import functions as fn 2 | from ..Qt import QtCore, QtGui, QtWidgets 3 | 4 | __all__ = ['PathButton'] 5 | 6 | 7 | class PathButton(QtWidgets.QPushButton): 8 | """Simple PushButton extension that paints a QPainterPath centered on its face. 9 | """ 10 | def __init__(self, parent=None, path=None, pen='default', brush=None, size=(30,30), margin=7): 11 | QtWidgets.QPushButton.__init__(self, parent) 12 | self.margin = margin 13 | self.path = None 14 | if pen == 'default': 15 | pen = 'k' 16 | self.setPen(pen) 17 | self.setBrush(brush) 18 | if path is not None: 19 | self.setPath(path) 20 | if size is not None: 21 | self.setFixedWidth(size[0]) 22 | self.setFixedHeight(size[1]) 23 | 24 | def setBrush(self, brush): 25 | self.brush = fn.mkBrush(brush) 26 | 27 | def setPen(self, *args, **kwargs): 28 | self.pen = fn.mkPen(*args, **kwargs) 29 | 30 | def setPath(self, path): 31 | self.path = path 32 | self.update() 33 | 34 | def paintEvent(self, ev): 35 | super().paintEvent(ev) 36 | margin = self.margin 37 | geom = QtCore.QRectF(0, 0, self.width(), self.height()).adjusted(margin, margin, -margin, -margin) 38 | rect = self.path.boundingRect() 39 | scale = min(geom.width() / float(rect.width()), geom.height() / float(rect.height())) 40 | 41 | p = QtGui.QPainter(self) 42 | p.setRenderHint(p.RenderHint.Antialiasing) 43 | p.translate(geom.center()) 44 | p.scale(scale, scale) 45 | p.translate(-rect.center()) 46 | p.setPen(self.pen) 47 | p.setBrush(self.brush) 48 | p.drawPath(self.path) 49 | p.end() 50 | 51 | 52 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/PenPreviewLabel.py: -------------------------------------------------------------------------------- 1 | from ..Qt import QtWidgets, QtGui, QtCore 2 | from ..functions import mkPen 3 | 4 | 5 | class PenPreviewLabel(QtWidgets.QLabel): 6 | def __init__(self, param): 7 | super().__init__() 8 | self.param = param 9 | self.pen = QtGui.QPen(self.param.pen) 10 | param.sigValueChanging.connect(self.onPenChanging) 11 | 12 | def onPenChanging(self, param, val): 13 | self.pen = QtGui.QPen(val) 14 | self.update() 15 | 16 | def paintEvent(self, ev): 17 | path = QtGui.QPainterPath() 18 | displaySize = self.size() 19 | w, h = displaySize.width(), displaySize.height() 20 | # draw a squiggle with the pen 21 | path.moveTo(w * .2, h * .2) 22 | path.lineTo(w * .4, h * .8) 23 | path.cubicTo(w * .5, h * .1, w * .7, h * .1, w * .8, h * .8) 24 | 25 | painter = QtGui.QPainter(self) 26 | painter.setPen(self.pen) 27 | painter.drawPath(path) 28 | 29 | # No indication of "cosmetic" from just the paint path, so add something extra in that case 30 | if self.pen.isCosmetic(): 31 | painter.setPen(mkPen('k')) 32 | painter.drawText(QtCore.QPointF(w * 0.81, 12), 'C') 33 | painter.end() 34 | -------------------------------------------------------------------------------- /pyqtgraph/widgets/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/pyqtgraph/widgets/__init__.py -------------------------------------------------------------------------------- /resources.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/profileIcon.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/test_dist.py: -------------------------------------------------------------------------------- 1 | import qgis 2 | 3 | 4 | vl = iface.activeLayer() 5 | 6 | crs1 = vl.crs() 7 | crs2 = iface.mapCanvas().mapSettings().destinationCrs() 8 | 9 | dist = qgis.core.QgsDistanceArea() 10 | #dist.setEllipsoid(qgis.core.QgsProject().instance().ellipsoid()) 11 | #dist.setEllipsoidalMode(True) 12 | dist.setSourceCrs(crs2) 13 | 14 | dist2 = qgis.core.QgsDistanceArea() 15 | #dist2.setEllipsoid(qgis.core.QgsProject().instance().ellipsoid()) 16 | #dist2.setEllipsoidalMode(True) 17 | dist2.setSourceCrs(crs1) 18 | 19 | print(dist.convertLengthMeasurement(1.0, crs1.mapUnits()) ) 20 | print(dist2.convertLengthMeasurement(1.0, crs2.mapUnits()) ) 21 | 22 | -------------------------------------------------------------------------------- /tools/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/tools/__init__.py -------------------------------------------------------------------------------- /tools/profilers.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # ----------------------------------------------------------- 3 | # 4 | # Profilers 5 | # Copyright (C) 2017 Javier Becerra 6 | # ----------------------------------------------------------- 7 | # 8 | # licensed under the terms of GNU GPL 2 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License along 21 | # with this program; if not, print to the Free Software Foundation, Inc., 22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | # 24 | # --------------------------------------------------------------------- 25 | 26 | import numpy as np 27 | 28 | 29 | def height(p): 30 | """Return the height profile for given track p. 31 | 32 | Returns the x (distance from origin) and y (height) 33 | coordinates for the plot. 34 | """ 35 | return p["l"], p["z"] 36 | 37 | 38 | def slopes_pct(p): 39 | """Return a profile's slope in percentage. 40 | 41 | Returns the x (distance from origin) and y (slope in percentage) 42 | coordinates for the plot. 43 | """ 44 | x = np.array(p["l"], dtype=float) 45 | y = np.array(p["z"], dtype=float) 46 | slope_pct = 100.0 * (y[1:] - y[:-1]) / (x[1:] - x[:-1]) 47 | slope_pct = np.concatenate( 48 | (slope_pct[0:1], 0.5 * (slope_pct[1:] + slope_pct[:-1]), slope_pct[-1:]) 49 | ) 50 | slope_pct[np.isnan(slope_pct)] = 0 51 | slope_pct[np.isinf(slope_pct)] = 0 52 | return x, slope_pct 53 | 54 | 55 | def slopes_deg(p): 56 | """Return a profile's slope in degrees. 57 | 58 | Returns the x (distance from origin) and y (slope in degrees) 59 | coordinates for the plot. 60 | """ 61 | x, slope_pct = slopes_pct(p) 62 | slope_deg = np.degrees(np.arctan(slope_pct / 100.0)) 63 | return x, slope_deg 64 | 65 | 66 | PLOT_PROFILERS = {"Height": height, "Slope (%)": slopes_pct, "Slope (°)": slopes_deg} 67 | -------------------------------------------------------------------------------- /tools/utils.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # ----------------------------------------------------------- 3 | # 4 | # Profile 5 | # Copyright (C) 2013 Peter Wells 6 | # ----------------------------------------------------------- 7 | # 8 | # licensed under the terms of GNU GPL 2 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License along 21 | # with this program; if not, print to the Free Software Foundation, Inc., 22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | # 24 | # --------------------------------------------------------------------- 25 | 26 | from qgis.core import QgsWkbTypes 27 | 28 | 29 | def isProfilable(layer): 30 | """Returns True if layer can be profiled, else returns False""" 31 | return ( 32 | (layer.type() == layer.RasterLayer) 33 | or (layer.type() == layer.MeshLayer) 34 | or (layer.type() == layer.PluginLayer and layer.LAYER_TYPE == "selafin_viewer") 35 | or (layer.type() == layer.VectorLayer and layer.geometryType() == QgsWkbTypes.PointGeometry) 36 | ) 37 | -------------------------------------------------------------------------------- /ui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PANOimagen/profiletool/0fec10efe93ce437eec7c6128869c1b997e8a836/ui/__init__.py -------------------------------------------------------------------------------- /ui/dlgabout.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # ----------------------------------------------------------- 3 | # 4 | # Profile 5 | # Copyright (C) 2012 Patrice Verchere 6 | # ----------------------------------------------------------- 7 | # 8 | # licensed under the terms of GNU GPL 2 9 | # 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2 of the License, or 13 | # (at your option) any later version. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License along 21 | # with this program; if not, print to the Free Software Foundation, Inc., 22 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 | # 24 | # --------------------------------------------------------------------- 25 | 26 | import os 27 | import platform 28 | 29 | from qgis.PyQt import uic 30 | from qgis.PyQt.QtCore import * 31 | from qgis.PyQt.QtGui import * 32 | from qgis.PyQt.QtWidgets import QDialog 33 | 34 | uiFilePath = os.path.abspath(os.path.join(os.path.dirname(__file__), "about.ui")) 35 | FormClass = uic.loadUiType(uiFilePath)[0] 36 | 37 | 38 | class DlgAbout(QDialog, FormClass): 39 | def __init__(self, parent=None): 40 | QDialog.__init__(self, parent) 41 | self.setupUi(self) 42 | 43 | fp = os.path.join( 44 | os.path.abspath(os.path.join(os.path.dirname(__file__), "..")), "metadata.txt" 45 | ) 46 | 47 | iniText = QSettings(fp, QSettings.IniFormat) 48 | verno = iniText.value("version") 49 | name = iniText.value("name") 50 | description = iniText.value("description") 51 | 52 | self.title.setText(name) 53 | self.description.setText(description + " - " + verno) 54 | --------------------------------------------------------------------------------