Fast data visualization and GUI tools for scientific / engineering applications

PyQtGraph

PyPi conda-forge Build Status CodeQL Status Documentation Status Total alerts Language grade: Python

A pure-Python graphics library for PyQt5/PyQt6/PySide2/PySide6

Copyright 2020 Luke Campagnola, University of North Carolina at Chapel Hill

http://www.pyqtgraph.org

PyQtGraph is intended for use in mathematics / scientific / engineering applications. Despite being written entirely in python, the library is fast due to its heavy leverage of numpy for number crunching, Qt's GraphicsView framework for 2D display, and OpenGL for 3D display.

Requirements

pyqtgraph has adopted NEP 29.

This project supports:

  • All minor versions of Python released 42 months prior to the project, and at minimum the two latest minor versions.
  • All minor versions of numpy released in the 24 months prior to the project, and at minimum the last three minor versions.
  • All minor versions of Qt 5 and Qt 6 currently supported by upstream Qt

Currently this means:

  • Python 3.7+
  • Qt 5.12-6.0
  • Required
    • PyQt5, PyQt6, PySide2 or PySide6
    • numpy 1.17+
  • Optional
    • scipy for image processing
    • pyopengl for 3D graphics
      • pyopengl on macOS Big Sur only works with python 3.9.1+
    • hdf5 for large hdf5 binary format support
    • colorcet for supplemental colormaps
    • cupy for CUDA-enhanced image processing
      • On Windows, CUDA toolkit must be >= 11.1

Qt Bindings Test Matrix

The following table represents the python environments we test in our CI system. Our CI system uses Ubuntu 20.04, Windows Server 2019, and macOS 10.15 base images.

Qt-Bindings Python 3.7 Python 3.8 Python 3.9
PySide2-5.12
PyQt5-5.12
PySide2-5.15
PyQt5-5.15
PySide6-6.0
PyQt6-6.0

Support

Installation Methods

  • From PyPI:
    • Last released version: pip install pyqtgraph
    • Latest development version: pip install git+https://github.com/pyqtgraph/[email protected]
  • From conda
    • Last released version: conda install -c conda-forge pyqtgraph
  • To install system-wide from source distribution: python setup.py install
  • Many linux package repositories have release versions.
  • To use with a specific project, simply copy the pyqtgraph subdirectory anywhere that is importable from your project.

Documentation

The official documentation lives at pyqtgraph.readthedocs.io

The easiest way to learn pyqtgraph is to browse through the examples; run python -m pyqtgraph.examples to launch the examples application.

Comments
  • If arrayToQPath uses connect=all, use a different construction for QPainterPath

    If arrayToQPath uses connect=all, use a different construction for QPainterPath

    It's been discussed that the QDataStream >> QPainterPath operationis a real bottle-neck in arrayToQPath. Here is a stack overflow post that points out that QDataStream >> QPainterPath operation is really slow.

    Taking a peak at what PythonQwt does, that project constructs an open QPolygonF and draw that. QPainterPath does have an addPolygon method, so we can generate a QPainterPath that is made up of a QPolygonF.

    Doing some testing on examples/MultiPlotSpeedTest.py shows a significant performance boost when doing this. This PR shows 35 fps while master branch is at 25 fps.

    This PR also incorporates a second optimization, it checks for NaN values on PlotCurveItem.updateData() instead of at arrayToQPath check, and allows for an optimization parameter to be passed to skip the NaN check which does cause a performance hit.

    So first thing, the function is largely lifted from PythonQwt, so huge thanks to that project for figuring out this optimization.

    ~Some caveats, this does not work w/ Qt6; so definitely not ready for merging.~ Works with Qt6 now.

    EDIT: on second thought, this NaN check might not be buying us anything... doesn't look like arrayToQPath is called any more often than PlotCurveItem.updateData... so we're just moving the calculation from one part of the library to another...

  • Optimize makeARGB for ubyte images

    Optimize makeARGB for ubyte images

    This PR optimizes the channel reordering portion of makeARGB by using the conversion routines of QImage.

    It only optimizes for row major ubyte images and defers to the original code for the rest. Improvement in fps is measurable with VideoSpeedTest

    Would such a PR that optimizes for specific data types be acceptable? Tagging @outofculture

  • Add support for Qt5

    Add support for Qt5

    Are there any plans to add support for PyQt5?

    I see you've got a nice wrapper around the Qt imports to support PySide/PyQt4. I had hoped that would mean a simple copy-pasta PyQt4 > PyQt5 but unfortunately you get hit with errors elsewhere (QApplication now being in QWidgets for example).

    I can have a go at creating a PyQt5 fork in a branch and see how much I have to mangle it before it works, but I wanted to check nobody else was doing this first.

  • Avoid using ``np.linalg.inv()`` for transform inversion

    Avoid using ``np.linalg.inv()`` for transform inversion

    This fixes not only latency but high CPU usage when inverting a Qt transform matrix.

    There is a known recent issue in numpy pertaining to this: numpy/numpy/issues/17166

    I've ripped off the "hard coded" solution from that issue verbatim and using it has reduced both latency and CPU usage in pretty much all mouse related interaction with ViewBox. I'm happy to write up profiling and test code for this in case there are any doubts.

    There are even faster solutions inside the referenced issue that might be worth exploring as well; I know we have to keep py2 in mind but it might be worth some flag logic in this case since invertQTransform() seems to be used throughout ViewBox and GraphicsItem. This would explain why I'm seeing improvements outside my original use case (calling GraphicsObject.mapFromView() on label coordinates fed from the mouse).

    I also would like to benchmark using *np.ravel() to pass the matrix results to QtGui.QTransform() since I've done that with good results in QPicture() drawings and it should in theory be faster then the existing multiple element access.

    Update

    Commit that changed away from using the internal transform is a41d330 Relevant Qt bug reports are:

    • https://bugreports.qt.io/browse/QTBUG-52070
    • https://bugreports.qt.io/browse/QTBUG-8014
    • https://bugreports.qt.io/browse/QTBUG-8557
    • troublesome underlying function is https://doc.qt.io/qt-5/qtglobal.html#qFuzzyIsNull
  • Implemented pColorMeshItem

    Implemented pColorMeshItem

    As discussed in the issue #1262 I proposed here a minimal implementation of an item mimicking the pcolormesh function of matplotlib. As I didn't know what to do to make the pull request valid I decided to make it as minimal as possible. I am willing to integrate it more into pyqtgraph if someone gives me some directions. In particular a I think a kind of pColorMeshWidget with axis and Histogram would be an excellent end result of this work.

    Fixes #146 Fixes #1262

  • experimental line drawing mode for thick lines

    experimental line drawing mode for thick lines

    Proof of concept using drawLines code from PlotSpeedTest.py. Drawing thick lines probably involves a polygon flood fill by Qt, which gets slower the more complicated the polygon gets. So the idea here is to draw many many short line segments. This has its own overhead but is far less than before.

    To see it in action in PlotSpeedTest.py, ~~check enableExperimental,~~ set to line width more than 1 ~~and check skipFiniteCheck.~~

    ~~It's only meant to support fully finite data.~~

    I don't use thick lines myself, so feel free to take over this PR.

  • Scatter Plot Improvements

    Scatter Plot Improvements

    • Fixes various bugs and performance issues.
    • Adds a hovering API to ScatterPlotItem which lets the user specify a separate style for the hovered points and show a tool tip containing information about them. A signal is also emitted during hovering.
  • plots not showing with NaN

    plots not showing with NaN

    Short description

    Plotting data with np.nan results in an empty plot.

    Code to reproduce

    import numpy as np
    import pyqtgraph as pg
    
    data = np.random.normal(size=1000)
    data2 = np.random.normal(size=1000)
    data2[0] = np.nan
    
    pg.plot(data, title="no NaN")
    pg.plot(data2, title="one NaN")
    
    pg.QtGui.QApplication.exec_()
    

    Expected behavior

    Two plots with random data.

    Real behavior

    First plot shows as normal. Second plot is empty.

    An error occurred?
    Post the full traceback inside these 'code fences'!
    

    Tested environment(s)

    • PyQtGraph version: 0.11.0.dev0+ged6586c

    • Qt Python binding: PySide2 5.13.1 Qt 5.13.1

    • Python version: 3.7.3

    • NumPy version: 1.17.2

    • Operating system: Windows 10, x64

    • Installation method: python from python.org installer. numpy from pip. pyqtgraph from git and / "python setup.py install" in pyqtgraph directory

    • PyQtGraph version: 0.11.0.dev0+ged6586c

    • Qt Python binding: PySide2 5.13.1 Qt 5.13.1

    • Python version: 3.7.3

    • NumPy version: 1.17.2

    • Operating system: Centos 7

    • Installation method: python built from source. numpy from pip. pyqtgraph from git and / "python setup.py install" in pyqtgraph directory

    Additional context

  • Adding TextItem to plot changes the axis range (appears on Ver. 0.11, the bug was not present on 0.10)

    Adding TextItem to plot changes the axis range (appears on Ver. 0.11, the bug was not present on 0.10)

    Now that I am migrating to Version 0.11, I have noticed an annoying problem that was not present on 0.10.

    When I add ArrowItem and TextItem to an existing plot, I get this:

    Ticks_wrong

    Whereas I would expect this (pyqtgraph ver. 0.10):

    Ticks_right

    I noticed that this happens only if I label the peaks by calling:

        def label_peaks(self, plot_wg2, pos_peaks, GLS = True, o_c = False, activity = False, MLP = False, DFT=False):
    
            if GLS == True and DFT == False and self.avoid_GLS_RV_alias.isChecked():
                x_peaks = pos_peaks[0][pos_peaks[0]>1.2]
                y_peaks = pos_peaks[1][pos_peaks[0]>1.2]
            else:
                x_peaks = pos_peaks[0]
                y_peaks = pos_peaks[1]
    
    
            if GLS == True:
                N_peaks = int(self.N_GLS_peak_to_point.value())
                if o_c == True:
                    log = self.radioButton_RV_o_c_GLS_period.isChecked()
                elif activity == True:
                    log = self.radioButton_act_GLS_period.isChecked()
                elif MLP == True:
                    log = self.radioButton_RV_MLP_period.isChecked()
                    N_peaks = int(self.N_MLP_peak_to_point.value())
                elif DFT == True:
                    log = self.radioButton_RV_WF_period.isChecked()
                    N_peaks = int(self.N_window_peak_to_point.value())
    
                else:
                    log = self.radioButton_RV_GLS_period.isChecked()
    
                type_per = "GLS"
            else:
                N_peaks = int(self.N_TLS_peak_to_point.value())
                log = False
                type_per = "TLS"
    
            if len(x_peaks) <  N_peaks:
                N_peaks = len(x_peaks)
                print("You have reached the maximum number of %s peaks."%type_per)
    
            for i in range(N_peaks):
    
                text_arrow = pg.TextItem("", anchor=(0.5,1.9))
    
                if log == True:
                    arrow = pg.ArrowItem(pos=(np.log10(x_peaks[i]), y_peaks[i]), angle=270)
                    text_arrow.setText('%0.2f d' % (x_peaks[i]))
                    text_arrow.setPos(np.log10(x_peaks[i]),y_peaks[i])
                    
                elif log == False and GLS == True:   
                    arrow = pg.ArrowItem(pos=(1/x_peaks[i], y_peaks[i]), angle=270)
                    text_arrow.setText('%0.2f d' % (x_peaks[i]))
                    text_arrow.setPos(1/x_peaks[i],y_peaks[i])
                    
                elif log == False and GLS == False: 
                    arrow = pg.ArrowItem(pos=(x_peaks[i], y_peaks[i]), angle=270)
                    text_arrow.setText('%0.2f d' % (x_peaks[i]))
                    text_arrow.setPos(x_peaks[i],y_peaks[i])
    
    
                plot_wg2.addItem(arrow)
                plot_wg2.addItem(text_arrow) 
    
    

    The "bug" appears only if I use TextItem. Adding ArrowItem behaves OK. So what changed w.r.t. version 0.10?

  • change GroupParameterItem palette to address issue in darkmode on mac

    change GroupParameterItem palette to address issue in darkmode on mac

    This partially addresses #1958

    These changes will still need to be tested on windows/Linux.

    Group title colors were changed to the color of QPalette.TextRole but it could easily be changed back to the original in dark mode.

    Light unknown-1 Dark unknown-2

  • [CI-fail] Segfault with pytest --cov

    [CI-fail] Segfault with pytest --cov

    Moving some notes over from slack:

    We're seeing a segmentation fault when running pytest --cov pyqtgraph both locally and in CI. It occurs right after the tests are completed (just before the coverage report is produced).

    Environment:

    • PySide2 5.12
    • Python 3.7
    • Either venv or conda
    • pytest-cov 2.7

    I noticed this occurs when using bash but not fish. @j9ac9k reported the segfault with zsh as well.

    Running coverage run -m pytest does not result in a segfault.

    pytest-cov's README says this:

    Consistent pytest behavior. If you run coverage run -m pytest you will have slightly different sys.path (CWD will be in it, unlike when running pytest).

    Edit: added pytest-cov version to list

  • Options passed PenParameter are not applied

    Options passed PenParameter are not applied

    Short description

    pTypes.PenParameter(name="Line Style", width=5) should initialize the wrapped pen with width of 5, but it remains at 1. Same applies for other style options.

    Tested environment(s)

    • PyQtGraph version: 0.12.4
    • Qt Python binding: PyQt6
    • Python version: 3.10
    • Installation method: venv / pip
  • Bug in ROI rotation in conjunction with maxBounds

    Bug in ROI rotation in conjunction with maxBounds

    Short description

    When using the maxBounds parameter of ROI to limit the ROI to the image size, the ROI can be moved over the boundaries in case it has been rotated. Moreover, it cannot read some regions of the image anymore. See the modified example of pyqtgraph.examples where the ROI is in its maximum upper right position:

    example

    Code to reproduce

    Simply use the Image Analysis of pyqtgraph.examples and modify one line and add one line. See the two lines below "# Custom ROI for selecting an image region" in the screenshot:

    code

    Expected behavior

    Rotated and bounded ROI should be bounded to the image.

    Real behavior

    Rotated and bounded ROI can be moved outside image and some image regions cannot be reached at all.

    Additional context

    To fix this behaviour, the following change in the method "def stateRect(self, state)" of ROI.py can be made: tr.rotate(-state['angle']) ->tr.rotate(state['angle'])

  • Issue #2203 Potential Fix: Disabled FlowchartCtrlWidget.nodeRenamed o…

    Issue #2203 Potential Fix: Disabled FlowchartCtrlWidget.nodeRenamed o…

    …n Input/Output node

    In FlowechartCtrlWidget.nodeRenamed, the items dictionary is being used, but the Input and Output nodes are not added to items due to the if statement at line 195. I added the logic of excluding the Input and Output nodes to Flowchart.nodeRenamed.

    This maintains current functionality according to issue #2203, unclear if this is expected functionality.

  • Modify CSV exporter to output original data without log mapping

    Modify CSV exporter to output original data without log mapping

    This is my attempt to address what is pointed out in #2238 and its precursors, within PlotDataItem's framework of original, mapped and displayed data sets. Many thanks to @StSav012 for continuing to bring this to our attention and for submitting PRs to address it!

    I share the opinion that a user selecting [CSV export] is almost certainly interested in the original data, and that it has been accidental that the output now provides the processed data, potentially mapped as log10.

    This PR changes the CSV exporter to access the original data set kept by PlotDataItem through a new interface getOriginalDataset(). If this is not available, for example in a user provided variant item, it will fall back to getData(), which should be guaranteed to exist and provide the previous behavior.

    With this PR we officially commit to maintaining a copy of the original data in PlotDataItem, but that has already been necessary anyway.

    I do not think this commitment extends to other items like PlotCurveItem, and does not block the potential implementation of proposed fast-append code that works directly on the Qt path, without necessarily maintaining a "raw" data set. In the interest of performance, we do not want these items to implement (log-)mapping functionality independently. Where this is needed, the user code should go through PlotDataItem. In the long term, we might want to reconsider the interface declaration 'plotData' and add some distinctions there.

    @StSav012 , please let us know if this addresses your issue, I don't have a good test case right now. I'll be happy to work with you on the fine-tuning. Sorry to bypass your own PR, but I currently think that the approach here is less intrusive for the internal workings of the library, and less likely to conflict with custom user code.

  • Right-clicking adds to plotItem.vb.menu.actions()

    Right-clicking adds to plotItem.vb.menu.actions()

    Short description

    Opening the context-menu via right-clicking adds an entry to the list returned by plotItem.vb.menu.actions(). Tbh this behaviour didn't lead to complications for me, but I don't think it should behave like this.

    Code to reproduce

    In REPL

    import pyqtgraph as pg
    
    p = pg.plot([1,2,3,[4,5,6])
    len(p.plotItem.vb.menu.actions()) # = 4
    # now right-click in plot window
    len(p.plotItem.vb.menu.actions()) # = 7
    # now right-click in plot window
    len(p.plotItem.vb.menu.actions()) # = 8
    # repeated right clicking and evaluation of len(...) shows always + 1
    

    Expected behavior

    After first right-click, the actions-list should be constant (at 7 in this case).

    Tested environment(s)

    • PyQtGraph version: 0.12.4
    • Qt Python binding: PyQt6 6.3.0 Qt 6.3.0
    • Python version: 3.9.2

    Additional context

    It might be due to what GraphicsScene.addParentContextMenus is doing: https://github.com/pyqtgraph/pyqtgraph/blob/e0b3a30becef0c473dd99e9efd3a53ef12444eae/pyqtgraph/GraphicsScene/GraphicsScene.py#L492-L506 where it looks like it might in this case always call addSeparator. I'm not entirely sure, though.

    BTW: the reason I came to this was, because I wanted to remove some of the entries of the contextmenu, as they don't work with the data I am plotting (different points have different brushes which clashes with some plot options).

    Cheers

Fast data visualization and GUI tools for scientific / engineering applications

PyQtGraph A pure-Python graphics library for PyQt5/PyQt6/PySide2/PySide6 Copyright 2020 Luke Campagnola, University of North Carolina at Chapel Hill h

Feb 17, 2021
Scientific Visualization: Python + Matplotlib
 Scientific Visualization: Python + Matplotlib

An open access book on scientific visualization using python and matplotlib

May 17, 2022
FURY - A software library for scientific visualization in Python
FURY -  A software library for scientific visualization in Python

Free Unified Rendering in Python A software library for scientific visualization in Python. General Information • Key Features • Installation • How to

Apr 30, 2022
This is a super simple visualization toolbox (script) for transformer attention visualization ✌
This is a super simple visualization toolbox (script) for transformer attention visualization ✌

Trans_attention_vis This is a super simple visualization toolbox (script) for transformer attention visualization ✌ 1. How to prepare your attention m

Jan 12, 2022
GUI for visualization and interactive editing of SMPL-family body models ie. SMPL, SMPL-X, MANO, FLAME.

Body Model Visualizer Introduction This is a simple Open3D-based GUI for SMPL-family body models. This GUI lets you play with the shape, expression, a

May 17, 2022
Jan 5, 2022
A Python package that provides evaluation and visualization tools for the DexYCB dataset
A Python package that provides evaluation and visualization tools for the DexYCB dataset

DexYCB Toolkit DexYCB Toolkit is a Python package that provides evaluation and visualization tools for the DexYCB dataset. The dataset and results wer

May 13, 2022
Python histogram library - histograms as updateable, fully semantic objects with visualization tools. [P]ython [HYST]ograms.
Python histogram library - histograms as updateable, fully semantic objects with visualization tools. [P]ython [HYST]ograms.

physt P(i/y)thon h(i/y)stograms. Inspired (and based on) numpy.histogram, but designed for humans(TM) on steroids(TM). The goal is to unify different

May 5, 2022
Python Package for CanvasXpress JS Visualization Tools
Python Package for CanvasXpress JS Visualization Tools

CanvasXpress Python Library About CanvasXpress for Python CanvasXpress was developed as the core visualization component for bioinformatics and system

Feb 1, 2022
Fast visualization of radar_scenes based on oleschum/radar_scenes
Fast visualization of radar_scenes based on oleschum/radar_scenes

RadarScenes Tools About This python package provides fast visualization for the RadarScenes dataset. The Open GL based visualizer is smoother than ole

Dec 9, 2021
Apache Superset is a Data Visualization and Data Exploration Platform
Apache Superset is a Data Visualization and Data Exploration Platform

Superset A modern, enterprise-ready business intelligence web application. Why Superset? | Supported Databases | Installation and Configuration | Rele

May 14, 2022
Apache Superset is a Data Visualization and Data Exploration Platform
Apache Superset is a Data Visualization and Data Exploration Platform

Apache Superset is a Data Visualization and Data Exploration Platform

May 15, 2022
Automatic data visualization in atom with the nteract data-explorer
Automatic data visualization in atom with the nteract data-explorer

Data Explorer Interactively explore your data directly in atom with hydrogen! The nteract data-explorer provides automatic data visualization, so you

Apr 14, 2022
Data-FX is an addon for Blender (2.9) that allows for the visualization of data with different charts
Data-FX is an addon for Blender (2.9) that allows for the visualization of data with different charts

Data-FX Data-FX is an addon for Blender (2.9) that allows for the visualization of data with different charts Currently, there are only 2 chart option

May 10, 2022
Glue is a python project to link visualizations of scientific datasets across many files.
Glue is a python project to link visualizations of scientific datasets across many files.

Glue Glue is a python project to link visualizations of scientific datasets across many files. Click on the image for a quick demo: Features Interacti

May 11, 2022
Plot-configurations for scientific publications, purely based on matplotlib

TUEplots Plot-configurations for scientific publications, purely based on matplotlib. Usage Please have a look at the examples in the example/ directo

May 2, 2022
Debugging, monitoring and visualization for Python Machine Learning and Data Science
Debugging, monitoring and visualization for Python Machine Learning and Data Science

Welcome to TensorWatch TensorWatch is a debugging and visualization tool designed for data science, deep learning and reinforcement learning from Micr

May 20, 2022
Exploratory analysis and data visualization of aircraft accidents and incidents in Brazil.
Exploratory analysis and data visualization of aircraft accidents and incidents in Brazil.

Exploring aircraft accidents in Brazil Occurrencies with aircraft in Brazil are investigated by the Center for Investigation and Prevention of Aircraf

Dec 14, 2021
Data Visualization Guide for Presentations, Reports, and Dashboards
Data Visualization Guide for Presentations, Reports, and Dashboards

This is a highly practical and example-based guide on visually representing data in reports and dashboards.

May 19, 2022