diff --git a/README.md b/README.md
index 45a6239c..5b045004 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ heavy leverage of numpy for number crunching, Qt's GraphicsView framework for
Requirements
------------
-pyqtgraph has adopted [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html).
+PyQtGraph has adopted [NEP 29](https://numpy.org/neps/nep-0029-deprecation_policy.html).
This project supports:
@@ -36,8 +36,8 @@ Currently this means:
* Python 3.7+
* Qt 5.12-5.15, 6.1
* Required
- * PyQt5, PyQt6, PySide2 or PySide6
- * `numpy` 1.17+
+ * [PyQt5](https://www.riverbankcomputing.com/software/pyqt/), [PyQt6](https://www.riverbankcomputing.com/software/pyqt/), [PySide2](https://wiki.qt.io/Qt_for_Python) or [PySide6](https://wiki.qt.io/Qt_for_Python)
+ * [`numpy`](https://github.com/numpy/numpy) 1.17+
* Optional
* `scipy` for image processing
* `pyopengl` for 3D graphics
@@ -48,6 +48,32 @@ Currently this means:
* On Windows, CUDA toolkit must be >= 11.1
* [`numba`] used to accelerate repeated image display for ImageItem
+
+Optional added functionalities
+------------------------------
+
+Through 3rd part libraries, additional functionality may be added to PyQtGraph, see the table below for a summary.
+
+| Library | Added functionality |
+|----------------|-|
+| [`scipy`] |
- Image processing through [`ndimage`]
- Data array filtering through [`signal`]
|
+| [`pyopengl`] | - 3D graphics
- Faster image processing
- Note: on macOS Big Sur only works with python 3.9.1+
|
+| [`h5py`] | |
+| [`colorcet`] | - Add a collection of perceptually uniform colormaps
|
+| [`matplotlib`] | - Export of PlotItem in matplotlib figure
- Add matplotlib collection of colormaps
|
+| [`cupy`] | - CUDA-enhanced image processing
- Note: On Windows, CUDA toolkit must be >= 11.1
|
+| [`numba`] | |
+
+[`scipy`]: https://github.com/scipy/scipy
+[`ndimage`]: https://docs.scipy.org/doc/scipy/reference/ndimage.html
+[`signal`]: https://docs.scipy.org/doc/scipy/reference/signal.html
+[`pyopengl`]: https://github.com/mcfletch/pyopengl
+[`h5py`]: https://github.com/h5py/h5py
+[`colorcet`]: https://github.com/holoviz/colorcet
+[`matplotlib`]: https://github.com/matplotlib/matplotlib
+[`numba`]: https://github.com/numba/numba
+[`cupy`]: https://docs.cupy.dev/en/stable/install.html
+
Qt Bindings Test Matrix
-----------------------
@@ -81,7 +107,7 @@ Installation Methods
* 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
+* To use with a specific project, simply copy the PyQtGraph subdirectory
anywhere that is importable from your project.
Documentation
@@ -89,7 +115,7 @@ Documentation
The official documentation lives at [pyqtgraph.readthedocs.io](https://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.
+The easiest way to learn PyQtGraph is to browse through the examples; run `python -m pyqtgraph.examples` to launch the examples application.
Used By
-------
diff --git a/examples/ExampleApp.py b/examples/ExampleApp.py
index fbbb07dc..2f55884e 100644
--- a/examples/ExampleApp.py
+++ b/examples/ExampleApp.py
@@ -4,10 +4,12 @@ import re
import sys
import subprocess
from argparse import Namespace
+
import pyqtgraph as pg
-from pyqtgraph.Qt import QtGui, QtCore, QT_LIB
+from pyqtgraph.Qt import QtWidgets, QtGui, QtCore, QT_LIB
from collections import OrderedDict
-from .utils import examples
+from .utils import examples_
+from functools import lru_cache
path = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, path)
@@ -28,7 +30,7 @@ QTextCharFormat = QtGui.QTextCharFormat
QSyntaxHighlighter = QtGui.QSyntaxHighlighter
-def format(color, style=''):
+def charFormat(color, style='', background=None):
"""
Return a QTextCharFormat with the given attributes.
"""
@@ -44,6 +46,8 @@ def format(color, style=''):
_format.setFontWeight(QFont.Weight.Bold)
if 'italic' in style:
_format.setFontItalic(True)
+ if background is not None:
+ _format.setBackground(pg.mkColor(background))
return _format
@@ -95,28 +99,28 @@ class DarkThemeColors:
LIGHT_STYLES = {
- 'keyword': format(LightThemeColors.Blue, 'bold'),
- 'operator': format(LightThemeColors.Red, 'bold'),
- 'brace': format(LightThemeColors.Purple),
- 'defclass': format(LightThemeColors.Indigo, 'bold'),
- 'string': format(LightThemeColors.Amber),
- 'string2': format(LightThemeColors.DeepPurple),
- 'comment': format(LightThemeColors.Green, 'italic'),
- 'self': format(LightThemeColors.Blue, 'bold'),
- 'numbers': format(LightThemeColors.Teal),
+ 'keyword': charFormat(LightThemeColors.Blue, 'bold'),
+ 'operator': charFormat(LightThemeColors.Red, 'bold'),
+ 'brace': charFormat(LightThemeColors.Purple),
+ 'defclass': charFormat(LightThemeColors.Indigo, 'bold'),
+ 'string': charFormat(LightThemeColors.Amber),
+ 'string2': charFormat(LightThemeColors.DeepPurple),
+ 'comment': charFormat(LightThemeColors.Green, 'italic'),
+ 'self': charFormat(LightThemeColors.Blue, 'bold'),
+ 'numbers': charFormat(LightThemeColors.Teal),
}
DARK_STYLES = {
- 'keyword': format(DarkThemeColors.Blue, 'bold'),
- 'operator': format(DarkThemeColors.Red, 'bold'),
- 'brace': format(DarkThemeColors.Purple),
- 'defclass': format(DarkThemeColors.Indigo, 'bold'),
- 'string': format(DarkThemeColors.Amber),
- 'string2': format(DarkThemeColors.DeepPurple),
- 'comment': format(DarkThemeColors.Green, 'italic'),
- 'self': format(DarkThemeColors.Blue, 'bold'),
- 'numbers': format(DarkThemeColors.Teal),
+ 'keyword': charFormat(DarkThemeColors.Blue, 'bold'),
+ 'operator': charFormat(DarkThemeColors.Red, 'bold'),
+ 'brace': charFormat(DarkThemeColors.Purple),
+ 'defclass': charFormat(DarkThemeColors.Indigo, 'bold'),
+ 'string': charFormat(DarkThemeColors.Amber),
+ 'string2': charFormat(DarkThemeColors.DeepPurple),
+ 'comment': charFormat(DarkThemeColors.Green, 'italic'),
+ 'self': charFormat(DarkThemeColors.Blue, 'bold'),
+ 'numbers': charFormat(DarkThemeColors.Teal),
}
@@ -145,7 +149,7 @@ class PythonHighlighter(QSyntaxHighlighter):
]
def __init__(self, document):
- QSyntaxHighlighter.__init__(self, document)
+ super().__init__(document)
# Multi-line strings (expression, flag, style)
self.tri_single = (QRegularExpression("'''"), 1, 'string2')
@@ -185,17 +189,19 @@ class PythonHighlighter(QSyntaxHighlighter):
(r'#[^\n]*', 0, 'comment'),
]
self.rules = rules
+ self.searchText = None
@property
def styles(self):
- app = QtGui.QApplication.instance()
+ app = QtWidgets.QApplication.instance()
return DARK_STYLES if app.property('darkMode') else LIGHT_STYLES
def highlightBlock(self, text):
"""Apply syntax highlighting to the given block of text.
"""
# Do other syntax formatting
- for expression, nth, format in self.rules:
+ rules = self.rules.copy()
+ for expression, nth, format in rules:
format = self.styles[format]
for n, match in enumerate(re.finditer(expression, text)):
@@ -204,6 +210,8 @@ class PythonHighlighter(QSyntaxHighlighter):
start = match.start()
length = match.end() - start
self.setFormat(start, length, format)
+
+ self.applySearchHighlight(text)
self.setCurrentBlockState(0)
# Do multi-line strings
@@ -249,39 +257,86 @@ class PythonHighlighter(QSyntaxHighlighter):
length = len(text) - start + add
# Apply formatting
self.setFormat(start, length, self.styles[style])
+ # Highlighting sits on top of this formatting
# Look for the next match
match = delimiter.match(text, start + length)
start = match.capturedStart()
+ self.applySearchHighlight(text)
+
# Return True if still inside a multi-line string, False otherwise
if self.currentBlockState() == in_state:
return True
else:
return False
+ def applySearchHighlight(self, text):
+ if not self.searchText:
+ return
+ expr = f'(?i){self.searchText}'
+ palette: QtGui.QPalette = app.palette()
+ color = palette.highlight().color()
+ fgndColor = palette.color(palette.ColorGroup.Current,
+ palette.ColorRole.Text).name()
+ style = charFormat(fgndColor, background=color.name())
+ for match in re.finditer(expr, text):
+ start = match.start()
+ length = match.end() - start
+ self.setFormat(start, length, style)
-class ExampleLoader(QtGui.QMainWindow):
+def unnestedDict(exDict):
+ """Converts a dict-of-dicts to a singly nested dict for non-recursive parsing"""
+ out = {}
+ for kk, vv in exDict.items():
+ if isinstance(vv, dict):
+ out.update(unnestedDict(vv))
+ else:
+ out[kk] = vv
+ return out
+
+
+
+class ExampleLoader(QtWidgets.QMainWindow):
def __init__(self):
- QtGui.QMainWindow.__init__(self)
+ QtWidgets.QMainWindow.__init__(self)
self.ui = ui_template.Ui_Form()
- self.cw = QtGui.QWidget()
+ self.cw = QtWidgets.QWidget()
self.setCentralWidget(self.cw)
self.ui.setupUi(self.cw)
self.setWindowTitle("PyQtGraph Examples")
- self.codeBtn = QtGui.QPushButton('Run Edited Code')
- self.codeLayout = QtGui.QGridLayout()
+ self.codeBtn = QtWidgets.QPushButton('Run Edited Code')
+ self.codeLayout = QtWidgets.QGridLayout()
self.ui.codeView.setLayout(self.codeLayout)
self.hl = PythonHighlighter(self.ui.codeView.document())
- app = QtGui.QApplication.instance()
+ app = QtWidgets.QApplication.instance()
app.paletteChanged.connect(self.updateTheme)
- self.codeLayout.addItem(QtGui.QSpacerItem(100,100,QtGui.QSizePolicy.Policy.Expanding,QtGui.QSizePolicy.Policy.Expanding), 0, 0)
+ policy = QtWidgets.QSizePolicy.Policy.Expanding
+ self.codeLayout.addItem(QtWidgets.QSpacerItem(100,100, policy, policy), 0, 0)
self.codeLayout.addWidget(self.codeBtn, 1, 1)
self.codeBtn.hide()
- global examples
+ textFil = self.ui.exampleFilter
+ self.curListener = None
+ self.ui.exampleFilter.setFocus()
+
+ def onComboChanged(searchType):
+ if self.curListener is not None:
+ self.curListener.disconnect()
+ self.curListener = textFil.textChanged
+ if searchType == 'Content Search':
+ self.curListener.connect(self.filterByContent)
+ else:
+ self.hl.searchText = None
+ self.curListener.connect(self.filterByTitle)
+ # Fire on current text, too
+ self.curListener.emit(textFil.text())
+
+ self.ui.searchFiles.currentTextChanged.connect(onComboChanged)
+ onComboChanged(self.ui.searchFiles.currentText())
+
self.itemCache = []
- self.populateTree(self.ui.exampleTree.invisibleRootItem(), examples)
+ self.populateTree(self.ui.exampleTree.invisibleRootItem(), examples_)
self.ui.exampleTree.expandAll()
self.resize(1000,500)
@@ -290,9 +345,76 @@ class ExampleLoader(QtGui.QMainWindow):
self.ui.loadBtn.clicked.connect(self.loadFile)
self.ui.exampleTree.currentItemChanged.connect(self.showFile)
self.ui.exampleTree.itemDoubleClicked.connect(self.loadFile)
- self.ui.codeView.textChanged.connect(self.codeEdited)
+
+ # textChanged fires when the highlighter is reassigned the same document. Prevent this
+ # from showing "run edited code" by checking for actual content change
+ oldText = self.ui.codeView.toPlainText()
+ def onTextChange():
+ nonlocal oldText
+ newText = self.ui.codeView.toPlainText()
+ if newText != oldText:
+ oldText = newText
+ self.codeEdited()
+
+ self.ui.codeView.textChanged.connect(onTextChange)
self.codeBtn.clicked.connect(self.runEditedCode)
+ def filterByTitle(self, text):
+ self.showExamplesByTitle(self.getMatchingTitles(text))
+ self.hl.setDocument(self.ui.codeView.document())
+
+ def filterByContent(self, text=None):
+ # Don't filter very short strings
+ checkDict = unnestedDict(examples_)
+ self.hl.searchText = text
+ # Need to reapply to current document
+ self.hl.setDocument(self.ui.codeView.document())
+ titles = []
+ text = text.lower()
+ for kk, vv in checkDict.items():
+ if isinstance(vv, Namespace):
+ vv = vv.filename
+ filename = os.path.join(path, vv)
+ contents = self.getExampleContent(filename).lower()
+ if text in contents:
+ titles.append(kk)
+ self.showExamplesByTitle(titles)
+
+ def getMatchingTitles(self, text, exDict=None, acceptAll=False):
+ if exDict is None:
+ exDict = examples_
+ text = text.lower()
+ titles = []
+ for kk, vv in exDict.items():
+ matched = acceptAll or text in kk.lower()
+ if isinstance(vv, dict):
+ titles.extend(self.getMatchingTitles(text, vv, acceptAll=matched))
+ elif matched:
+ titles.append(kk)
+ return titles
+
+ def showExamplesByTitle(self, titles):
+ QTWI = QtWidgets.QTreeWidgetItemIterator
+ flag = QTWI.IteratorFlag.NoChildren
+ treeIter = QTWI(self.ui.exampleTree, flag)
+ item = treeIter.value()
+ while item is not None:
+ parent = item.parent()
+ show = (item.childCount() or item.text(0) in titles)
+ item.setHidden(not show)
+
+ # If all children of a parent are gone, hide it
+ if parent:
+ hideParent = True
+ for ii in range(parent.childCount()):
+ if not parent.child(ii).isHidden():
+ hideParent = False
+ break
+ parent.setHidden(hideParent)
+
+ treeIter += 1
+ item = treeIter.value()
+
def simulate_black_mode(self):
"""
used to simulate MacOS "black mode" on other platforms
@@ -309,7 +431,7 @@ class ExampleLoader(QtGui.QMainWindow):
f.setForeground(QtGui.QColor('white'))
self.ui.codeView.setCurrentCharFormat(f)
# finally, override application automatic detection
- app = QtGui.QApplication.instance()
+ app = QtWidgets.QApplication.instance()
app.setProperty('darkMode', True)
def updateTheme(self):
@@ -318,7 +440,7 @@ class ExampleLoader(QtGui.QMainWindow):
def populateTree(self, root, examples):
bold_font = None
for key, val in examples.items():
- item = QtGui.QTreeWidgetItem([key])
+ item = QtWidgets.QTreeWidgetItem([key])
self.itemCache.append(item) # PyQt 4.9.6 no longer keeps references to these wrappers,
# so we need to make an explicit reference or else the .file
# attribute will disappear.
@@ -338,7 +460,6 @@ class ExampleLoader(QtGui.QMainWindow):
def currentFile(self):
item = self.ui.exampleTree.currentItem()
if hasattr(item, 'file'):
- global path
return os.path.join(path, item.file)
return None
@@ -364,27 +485,62 @@ class ExampleLoader(QtGui.QMainWindow):
def showFile(self):
fn = self.currentFile()
- if fn is None:
- self.ui.codeView.clear()
- return
- if os.path.isdir(fn):
- fn = os.path.join(fn, '__main__.py')
- with open(fn, "r") as currentFile:
- text = currentFile.read()
+ text = self.getExampleContent(fn)
self.ui.codeView.setPlainText(text)
self.ui.loadedFileLabel.setText(fn)
self.codeBtn.hide()
+ @lru_cache(100)
+ def getExampleContent(self, filename):
+ if filename is None:
+ self.ui.codeView.clear()
+ return
+ if os.path.isdir(filename):
+ filename = os.path.join(filename, '__main__.py')
+ with open(filename, "r") as currentFile:
+ text = currentFile.read()
+ return text
+
def codeEdited(self):
self.codeBtn.show()
def runEditedCode(self):
self.loadFile(edited=True)
+ def keyPressEvent(self, event):
+ ret = super().keyPressEvent(event)
+ if not QtCore.Qt.KeyboardModifier.ControlModifier & event.modifiers():
+ return ret
+ key = event.key()
+ Key = QtCore.Qt.Key
+
+ # Allow quick navigate to search
+ if key == Key.Key_F:
+ self.ui.exampleFilter.setFocus()
+ event.accept()
+ return
+
+ if key not in [Key.Key_Plus, Key.Key_Minus, Key.Key_Underscore, Key.Key_Equal, Key.Key_0]:
+ return ret
+ font = self.ui.codeView.font()
+ oldSize = font.pointSize()
+ if key == Key.Key_Plus or key == Key.Key_Equal:
+ font.setPointSize(oldSize + max(oldSize*.15, 1))
+ elif key == Key.Key_Minus or key == Key.Key_Underscore:
+ newSize = oldSize - max(oldSize*.15, 1)
+ font.setPointSize(max(newSize, 1))
+ elif key == Key.Key_0:
+ # Reset to original size
+ font.setPointSize(10)
+ self.ui.codeView.setFont(font)
+ event.accept()
def main():
app = pg.mkQApp()
loader = ExampleLoader()
+ loader.ui.exampleTree.setCurrentIndex(
+ loader.ui.exampleTree.model().index(0,0)
+ )
pg.exec()
if __name__ == '__main__':
diff --git a/examples/GLViewWidget.py b/examples/GLViewWidget.py
index 5bc23ba6..910fa8eb 100644
--- a/examples/GLViewWidget.py
+++ b/examples/GLViewWidget.py
@@ -6,10 +6,10 @@ Very basic 3D graphics example; create a view widget and add a few items.
## Add path to library (just for examples; you do not need this)
import initExample
-from pyqtgraph.Qt import QtCore, QtGui, mkQApp
+import pyqtgraph as pg
import pyqtgraph.opengl as gl
-app = mkQApp("GLViewWidget Example")
+pg.mkQApp("GLViewWidget Example")
w = gl.GLViewWidget()
w.opts['distance'] = 20
w.show()
diff --git a/examples/colorMaps.py b/examples/colorMaps.py
index df8559a8..16c573c2 100644
--- a/examples/colorMaps.py
+++ b/examples/colorMaps.py
@@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
"""
-This example demonstrates generating ColorMap objects from external data.
-It displays the full list of color maps available as local files or by import
-from Matplotlib or ColorCET.
+This example displays all color maps currently available, either as local data
+or imported from Matplotlib of ColorCET.
"""
## Add path to library (just for examples; you do not need this)
import initExample
@@ -49,19 +48,22 @@ def add_bar(lw, name, cm):
add_heading(lw, 'local color maps')
list_of_maps = pg.colormap.listMaps()
+list_of_maps = sorted( list_of_maps, key=lambda x: x.swapcase() )
for map_name in list_of_maps:
cm = pg.colormap.get(map_name)
add_bar(lw, map_name, cm)
add_heading(lw, 'Matplotlib import')
list_of_maps = pg.colormap.listMaps('matplotlib')
+list_of_maps = sorted( list_of_maps, key=lambda x: x.lower() )
for map_name in list_of_maps:
cm = pg.colormap.get(map_name, source='matplotlib', skipCache=True)
if cm is not None:
add_bar(lw, map_name, cm)
add_heading(lw, 'ColorCET import')
-list_of_maps = pg.colormap.listMaps('colorcet')
+list_of_maps = pg.colormap.listMaps('colorcet')
+list_of_maps = sorted( list_of_maps, key=lambda x: x.lower() )
for map_name in list_of_maps:
cm = pg.colormap.get(map_name, source='colorcet', skipCache=True)
if cm is not None:
diff --git a/examples/exampleLoaderTemplate.ui b/examples/exampleLoaderTemplate.ui
index 67a725ea..22a213e6 100644
--- a/examples/exampleLoaderTemplate.ui
+++ b/examples/exampleLoaderTemplate.ui
@@ -14,26 +14,14 @@
PyQtGraph
- -
+
-
Qt::Horizontal
-
+
-
-
-
-
- false
-
-
-
- 1
-
-
-
-
- -
+
-
-
@@ -62,23 +50,56 @@
- -
-
-
- Qt Library:
-
-
-
- -
+
-
Run Example
+ -
+
+
+ false
+
+
+
+ 1
+
+
+
+
+ -
+
+
+ Qt Library:
+
+
+
+ -
+
+
+ Type to filter...
+
+
+
+ -
+
+
-
+
+ Title Search
+
+
+ -
+
+ Content Search
+
+
+
+
-
+
-
diff --git a/examples/exampleLoaderTemplate_pyqt5.py b/examples/exampleLoaderTemplate_pyqt5.py
index c39b55ab..665c1dd5 100644
--- a/examples/exampleLoaderTemplate_pyqt5.py
+++ b/examples/exampleLoaderTemplate_pyqt5.py
@@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'exampleLoaderTemplate.ui'
+# Form implementation generated from reading ui file 'examples/exampleLoaderTemplate.ui'
#
-# Created by: PyQt5 UI code generator 5.12.3
+# Created by: PyQt5 UI code generator 5.15.4
#
-# WARNING! All changes made in this file will be lost!
+# WARNING: Any manual changes made to this file will be lost when pyuic5 is
+# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
@@ -19,36 +20,44 @@ class Ui_Form(object):
self.splitter = QtWidgets.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setObjectName("splitter")
- self.widget = QtWidgets.QWidget(self.splitter)
- self.widget.setObjectName("widget")
- self.gridLayout = QtWidgets.QGridLayout(self.widget)
+ self.layoutWidget = QtWidgets.QWidget(self.splitter)
+ self.layoutWidget.setObjectName("layoutWidget")
+ self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
- self.exampleTree = QtWidgets.QTreeWidget(self.widget)
- self.exampleTree.setObjectName("exampleTree")
- self.exampleTree.headerItem().setText(0, "1")
- self.exampleTree.header().setVisible(False)
- self.gridLayout.addWidget(self.exampleTree, 0, 0, 1, 2)
- self.qtLibCombo = QtWidgets.QComboBox(self.widget)
+ self.qtLibCombo = QtWidgets.QComboBox(self.layoutWidget)
self.qtLibCombo.setObjectName("qtLibCombo")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
- self.gridLayout.addWidget(self.qtLibCombo, 1, 1, 1, 1)
- self.label = QtWidgets.QLabel(self.widget)
- self.label.setObjectName("label")
- self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
- self.loadBtn = QtWidgets.QPushButton(self.widget)
+ self.gridLayout.addWidget(self.qtLibCombo, 4, 1, 1, 1)
+ self.loadBtn = QtWidgets.QPushButton(self.layoutWidget)
self.loadBtn.setObjectName("loadBtn")
- self.gridLayout.addWidget(self.loadBtn, 3, 1, 1, 1)
- self.widget1 = QtWidgets.QWidget(self.splitter)
- self.widget1.setObjectName("widget1")
- self.verticalLayout = QtWidgets.QVBoxLayout(self.widget1)
+ self.gridLayout.addWidget(self.loadBtn, 6, 1, 1, 1)
+ self.exampleTree = QtWidgets.QTreeWidget(self.layoutWidget)
+ self.exampleTree.setObjectName("exampleTree")
+ self.exampleTree.headerItem().setText(0, "1")
+ self.exampleTree.header().setVisible(False)
+ self.gridLayout.addWidget(self.exampleTree, 3, 0, 1, 2)
+ self.label = QtWidgets.QLabel(self.layoutWidget)
+ self.label.setObjectName("label")
+ self.gridLayout.addWidget(self.label, 4, 0, 1, 1)
+ self.exampleFilter = QtWidgets.QLineEdit(self.layoutWidget)
+ self.exampleFilter.setObjectName("exampleFilter")
+ self.gridLayout.addWidget(self.exampleFilter, 0, 0, 1, 2)
+ self.searchFiles = QtWidgets.QComboBox(self.layoutWidget)
+ self.searchFiles.setObjectName("searchFiles")
+ self.searchFiles.addItem("")
+ self.searchFiles.addItem("")
+ self.gridLayout.addWidget(self.searchFiles, 1, 0, 1, 2)
+ self.layoutWidget1 = QtWidgets.QWidget(self.splitter)
+ self.layoutWidget1.setObjectName("layoutWidget1")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget1)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
- self.loadedFileLabel = QtWidgets.QLabel(self.widget1)
+ self.loadedFileLabel = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setBold(True)
self.loadedFileLabel.setFont(font)
@@ -56,13 +65,13 @@ class Ui_Form(object):
self.loadedFileLabel.setAlignment(QtCore.Qt.AlignCenter)
self.loadedFileLabel.setObjectName("loadedFileLabel")
self.verticalLayout.addWidget(self.loadedFileLabel)
- self.codeView = QtWidgets.QPlainTextEdit(self.widget1)
+ self.codeView = QtWidgets.QPlainTextEdit(self.layoutWidget1)
font = QtGui.QFont()
font.setFamily("Courier New")
self.codeView.setFont(font)
self.codeView.setObjectName("codeView")
self.verticalLayout.addWidget(self.codeView)
- self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.splitter, 1, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
@@ -75,5 +84,8 @@ class Ui_Form(object):
self.qtLibCombo.setItemText(2, _translate("Form", "PySide2"))
self.qtLibCombo.setItemText(3, _translate("Form", "PySide6"))
self.qtLibCombo.setItemText(4, _translate("Form", "PyQt6"))
- self.label.setText(_translate("Form", "Qt Library:"))
self.loadBtn.setText(_translate("Form", "Run Example"))
+ self.label.setText(_translate("Form", "Qt Library:"))
+ self.exampleFilter.setPlaceholderText(_translate("Form", "Type to filter..."))
+ self.searchFiles.setItemText(0, _translate("Form", "Title Search"))
+ self.searchFiles.setItemText(1, _translate("Form", "Content Search"))
diff --git a/examples/exampleLoaderTemplate_pyqt6.py b/examples/exampleLoaderTemplate_pyqt6.py
index f448078c..cbaa058b 100644
--- a/examples/exampleLoaderTemplate_pyqt6.py
+++ b/examples/exampleLoaderTemplate_pyqt6.py
@@ -1,6 +1,6 @@
# Form implementation generated from reading ui file 'examples/exampleLoaderTemplate.ui'
#
-# Created by: PyQt6 UI code generator 6.1.0
+# Created by: PyQt6 UI code generator 6.1.1
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again. Do not edit this file unless you know what you are doing.
@@ -18,36 +18,44 @@ class Ui_Form(object):
self.splitter = QtWidgets.QSplitter(Form)
self.splitter.setOrientation(QtCore.Qt.Orientation.Horizontal)
self.splitter.setObjectName("splitter")
- self.widget = QtWidgets.QWidget(self.splitter)
- self.widget.setObjectName("widget")
- self.gridLayout = QtWidgets.QGridLayout(self.widget)
+ self.layoutWidget = QtWidgets.QWidget(self.splitter)
+ self.layoutWidget.setObjectName("layoutWidget")
+ self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.gridLayout.setObjectName("gridLayout")
- self.exampleTree = QtWidgets.QTreeWidget(self.widget)
- self.exampleTree.setObjectName("exampleTree")
- self.exampleTree.headerItem().setText(0, "1")
- self.exampleTree.header().setVisible(False)
- self.gridLayout.addWidget(self.exampleTree, 0, 0, 1, 2)
- self.qtLibCombo = QtWidgets.QComboBox(self.widget)
+ self.qtLibCombo = QtWidgets.QComboBox(self.layoutWidget)
self.qtLibCombo.setObjectName("qtLibCombo")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
- self.gridLayout.addWidget(self.qtLibCombo, 1, 1, 1, 1)
- self.label = QtWidgets.QLabel(self.widget)
- self.label.setObjectName("label")
- self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
- self.loadBtn = QtWidgets.QPushButton(self.widget)
+ self.gridLayout.addWidget(self.qtLibCombo, 4, 1, 1, 1)
+ self.loadBtn = QtWidgets.QPushButton(self.layoutWidget)
self.loadBtn.setObjectName("loadBtn")
- self.gridLayout.addWidget(self.loadBtn, 3, 1, 1, 1)
- self.widget1 = QtWidgets.QWidget(self.splitter)
- self.widget1.setObjectName("widget1")
- self.verticalLayout = QtWidgets.QVBoxLayout(self.widget1)
+ self.gridLayout.addWidget(self.loadBtn, 6, 1, 1, 1)
+ self.exampleTree = QtWidgets.QTreeWidget(self.layoutWidget)
+ self.exampleTree.setObjectName("exampleTree")
+ self.exampleTree.headerItem().setText(0, "1")
+ self.exampleTree.header().setVisible(False)
+ self.gridLayout.addWidget(self.exampleTree, 3, 0, 1, 2)
+ self.label = QtWidgets.QLabel(self.layoutWidget)
+ self.label.setObjectName("label")
+ self.gridLayout.addWidget(self.label, 4, 0, 1, 1)
+ self.exampleFilter = QtWidgets.QLineEdit(self.layoutWidget)
+ self.exampleFilter.setObjectName("exampleFilter")
+ self.gridLayout.addWidget(self.exampleFilter, 0, 0, 1, 2)
+ self.searchFiles = QtWidgets.QComboBox(self.layoutWidget)
+ self.searchFiles.setObjectName("searchFiles")
+ self.searchFiles.addItem("")
+ self.searchFiles.addItem("")
+ self.gridLayout.addWidget(self.searchFiles, 1, 0, 1, 2)
+ self.layoutWidget1 = QtWidgets.QWidget(self.splitter)
+ self.layoutWidget1.setObjectName("layoutWidget1")
+ self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget1)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
- self.loadedFileLabel = QtWidgets.QLabel(self.widget1)
+ self.loadedFileLabel = QtWidgets.QLabel(self.layoutWidget1)
font = QtGui.QFont()
font.setBold(True)
self.loadedFileLabel.setFont(font)
@@ -55,13 +63,13 @@ class Ui_Form(object):
self.loadedFileLabel.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.loadedFileLabel.setObjectName("loadedFileLabel")
self.verticalLayout.addWidget(self.loadedFileLabel)
- self.codeView = QtWidgets.QPlainTextEdit(self.widget1)
+ self.codeView = QtWidgets.QPlainTextEdit(self.layoutWidget1)
font = QtGui.QFont()
font.setFamily("Courier New")
self.codeView.setFont(font)
self.codeView.setObjectName("codeView")
self.verticalLayout.addWidget(self.codeView)
- self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.splitter, 1, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
@@ -74,5 +82,8 @@ class Ui_Form(object):
self.qtLibCombo.setItemText(2, _translate("Form", "PySide2"))
self.qtLibCombo.setItemText(3, _translate("Form", "PySide6"))
self.qtLibCombo.setItemText(4, _translate("Form", "PyQt6"))
- self.label.setText(_translate("Form", "Qt Library:"))
self.loadBtn.setText(_translate("Form", "Run Example"))
+ self.label.setText(_translate("Form", "Qt Library:"))
+ self.exampleFilter.setPlaceholderText(_translate("Form", "Type to filter..."))
+ self.searchFiles.setItemText(0, _translate("Form", "Title Search"))
+ self.searchFiles.setItemText(1, _translate("Form", "Content Search"))
diff --git a/examples/exampleLoaderTemplate_pyside2.py b/examples/exampleLoaderTemplate_pyside2.py
index ac803862..7d6bc031 100644
--- a/examples/exampleLoaderTemplate_pyside2.py
+++ b/examples/exampleLoaderTemplate_pyside2.py
@@ -1,79 +1,120 @@
# -*- coding: utf-8 -*-
-# Form implementation generated from reading ui file 'exampleLoaderTemplate.ui',
-# licensing of 'exampleLoaderTemplate.ui' applies.
-#
-# Created: Mon Feb 22 18:33:36 2021
-# by: pyside2-uic running on PySide2 5.12.6
-#
-# WARNING! All changes made in this file will be lost!
+################################################################################
+## Form generated from reading UI file 'exampleLoaderTemplate.ui'
+##
+## Created by: Qt User Interface Compiler version 5.15.2
+##
+## WARNING! All changes made in this file will be lost when recompiling UI file!
+################################################################################
+
+from PySide2.QtCore import *
+from PySide2.QtGui import *
+from PySide2.QtWidgets import *
-from PySide2 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
- Form.setObjectName("Form")
+ if not Form.objectName():
+ Form.setObjectName(u"Form")
Form.resize(846, 552)
- self.gridLayout_2 = QtWidgets.QGridLayout(Form)
- self.gridLayout_2.setObjectName("gridLayout_2")
- self.splitter = QtWidgets.QSplitter(Form)
- self.splitter.setOrientation(QtCore.Qt.Horizontal)
- self.splitter.setObjectName("splitter")
- self.widget = QtWidgets.QWidget(self.splitter)
- self.widget.setObjectName("widget")
- self.gridLayout = QtWidgets.QGridLayout(self.widget)
+ self.gridLayout_2 = QGridLayout(Form)
+ self.gridLayout_2.setObjectName(u"gridLayout_2")
+ self.splitter = QSplitter(Form)
+ self.splitter.setObjectName(u"splitter")
+ self.splitter.setOrientation(Qt.Horizontal)
+ self.layoutWidget = QWidget(self.splitter)
+ self.layoutWidget.setObjectName(u"layoutWidget")
+ self.gridLayout = QGridLayout(self.layoutWidget)
+ self.gridLayout.setObjectName(u"gridLayout")
self.gridLayout.setContentsMargins(0, 0, 0, 0)
- self.gridLayout.setObjectName("gridLayout")
- self.exampleTree = QtWidgets.QTreeWidget(self.widget)
- self.exampleTree.setObjectName("exampleTree")
- self.exampleTree.headerItem().setText(0, "1")
+ self.qtLibCombo = QComboBox(self.layoutWidget)
+ self.qtLibCombo.addItem("")
+ self.qtLibCombo.addItem("")
+ self.qtLibCombo.addItem("")
+ self.qtLibCombo.addItem("")
+ self.qtLibCombo.addItem("")
+ self.qtLibCombo.setObjectName(u"qtLibCombo")
+
+ self.gridLayout.addWidget(self.qtLibCombo, 4, 1, 1, 1)
+
+ self.loadBtn = QPushButton(self.layoutWidget)
+ self.loadBtn.setObjectName(u"loadBtn")
+
+ self.gridLayout.addWidget(self.loadBtn, 6, 1, 1, 1)
+
+ self.exampleTree = QTreeWidget(self.layoutWidget)
+ __qtreewidgetitem = QTreeWidgetItem()
+ __qtreewidgetitem.setText(0, u"1");
+ self.exampleTree.setHeaderItem(__qtreewidgetitem)
+ self.exampleTree.setObjectName(u"exampleTree")
self.exampleTree.header().setVisible(False)
- self.gridLayout.addWidget(self.exampleTree, 0, 0, 1, 2)
- self.qtLibCombo = QtWidgets.QComboBox(self.widget)
- self.qtLibCombo.setObjectName("qtLibCombo")
- self.qtLibCombo.addItem("")
- self.qtLibCombo.addItem("")
- self.qtLibCombo.addItem("")
- self.qtLibCombo.addItem("")
- self.qtLibCombo.addItem("")
- self.gridLayout.addWidget(self.qtLibCombo, 1, 1, 1, 1)
- self.label = QtWidgets.QLabel(self.widget)
- self.label.setObjectName("label")
- self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
- self.loadBtn = QtWidgets.QPushButton(self.widget)
- self.loadBtn.setObjectName("loadBtn")
- self.gridLayout.addWidget(self.loadBtn, 3, 1, 1, 1)
- self.widget1 = QtWidgets.QWidget(self.splitter)
- self.widget1.setObjectName("widget1")
- self.verticalLayout = QtWidgets.QVBoxLayout(self.widget1)
+
+ self.gridLayout.addWidget(self.exampleTree, 3, 0, 1, 2)
+
+ self.label = QLabel(self.layoutWidget)
+ self.label.setObjectName(u"label")
+
+ self.gridLayout.addWidget(self.label, 4, 0, 1, 1)
+
+ self.exampleFilter = QLineEdit(self.layoutWidget)
+ self.exampleFilter.setObjectName(u"exampleFilter")
+
+ self.gridLayout.addWidget(self.exampleFilter, 0, 0, 1, 2)
+
+ self.searchFiles = QComboBox(self.layoutWidget)
+ self.searchFiles.addItem("")
+ self.searchFiles.addItem("")
+ self.searchFiles.setObjectName(u"searchFiles")
+
+ self.gridLayout.addWidget(self.searchFiles, 1, 0, 1, 2)
+
+ self.splitter.addWidget(self.layoutWidget)
+ self.layoutWidget1 = QWidget(self.splitter)
+ self.layoutWidget1.setObjectName(u"layoutWidget1")
+ self.verticalLayout = QVBoxLayout(self.layoutWidget1)
+ self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
- self.verticalLayout.setObjectName("verticalLayout")
- self.loadedFileLabel = QtWidgets.QLabel(self.widget1)
- font = QtGui.QFont()
+ self.loadedFileLabel = QLabel(self.layoutWidget1)
+ self.loadedFileLabel.setObjectName(u"loadedFileLabel")
+ font = QFont()
font.setBold(True)
self.loadedFileLabel.setFont(font)
- self.loadedFileLabel.setText("")
- self.loadedFileLabel.setAlignment(QtCore.Qt.AlignCenter)
- self.loadedFileLabel.setObjectName("loadedFileLabel")
+ self.loadedFileLabel.setAlignment(Qt.AlignCenter)
+
self.verticalLayout.addWidget(self.loadedFileLabel)
- self.codeView = QtWidgets.QPlainTextEdit(self.widget1)
- font = QtGui.QFont()
- font.setFamily("Courier New")
- self.codeView.setFont(font)
- self.codeView.setObjectName("codeView")
+
+ self.codeView = QPlainTextEdit(self.layoutWidget1)
+ self.codeView.setObjectName(u"codeView")
+ font1 = QFont()
+ font1.setFamily(u"Courier New")
+ self.codeView.setFont(font1)
+
self.verticalLayout.addWidget(self.codeView)
- self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1)
+
+ self.splitter.addWidget(self.layoutWidget1)
+
+ self.gridLayout_2.addWidget(self.splitter, 1, 0, 1, 1)
+
self.retranslateUi(Form)
- QtCore.QMetaObject.connectSlotsByName(Form)
+
+ QMetaObject.connectSlotsByName(Form)
+ # setupUi
def retranslateUi(self, Form):
- Form.setWindowTitle(QtWidgets.QApplication.translate("Form", "PyQtGraph", None, -1))
- self.qtLibCombo.setItemText(0, QtWidgets.QApplication.translate("Form", "default", None, -1))
- self.qtLibCombo.setItemText(1, QtWidgets.QApplication.translate("Form", "PyQt5", None, -1))
- self.qtLibCombo.setItemText(2, QtWidgets.QApplication.translate("Form", "PySide2", None, -1))
- self.qtLibCombo.setItemText(3, QtWidgets.QApplication.translate("Form", "PySide6", None, -1))
- self.qtLibCombo.setItemText(4, QtWidgets.QApplication.translate("Form", "PyQt6", None, -1))
- self.label.setText(QtWidgets.QApplication.translate("Form", "Qt Library:", None, -1))
- self.loadBtn.setText(QtWidgets.QApplication.translate("Form", "Run Example", None, -1))
+ Form.setWindowTitle(QCoreApplication.translate("Form", u"PyQtGraph", None))
+ self.qtLibCombo.setItemText(0, QCoreApplication.translate("Form", u"default", None))
+ self.qtLibCombo.setItemText(1, QCoreApplication.translate("Form", u"PyQt5", None))
+ self.qtLibCombo.setItemText(2, QCoreApplication.translate("Form", u"PySide2", None))
+ self.qtLibCombo.setItemText(3, QCoreApplication.translate("Form", u"PySide6", None))
+ self.qtLibCombo.setItemText(4, QCoreApplication.translate("Form", u"PyQt6", None))
+ self.loadBtn.setText(QCoreApplication.translate("Form", u"Run Example", None))
+ self.label.setText(QCoreApplication.translate("Form", u"Qt Library:", None))
+ self.exampleFilter.setPlaceholderText(QCoreApplication.translate("Form", u"Type to filter...", None))
+ self.searchFiles.setItemText(0, QCoreApplication.translate("Form", u"Title Search", None))
+ self.searchFiles.setItemText(1, QCoreApplication.translate("Form", u"Content Search", None))
+
+ self.loadedFileLabel.setText("")
+ # retranslateUi
\ No newline at end of file
diff --git a/examples/exampleLoaderTemplate_pyside6.py b/examples/exampleLoaderTemplate_pyside6.py
index 7b8bda33..4b6100c2 100644
--- a/examples/exampleLoaderTemplate_pyside6.py
+++ b/examples/exampleLoaderTemplate_pyside6.py
@@ -3,14 +3,14 @@
################################################################################
## Form generated from reading UI file 'exampleLoaderTemplate.ui'
##
-## Created by: Qt User Interface Compiler version 6.1.0
+## Created by: Qt User Interface Compiler version 6.1.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
-from PySide6.QtCore import *
-from PySide6.QtGui import *
-from PySide6.QtWidgets import *
+from PySide6.QtCore import * # type: ignore
+from PySide6.QtGui import * # type: ignore
+from PySide6.QtWidgets import * # type: ignore
class Ui_Form(object):
@@ -23,21 +23,12 @@ class Ui_Form(object):
self.splitter = QSplitter(Form)
self.splitter.setObjectName(u"splitter")
self.splitter.setOrientation(Qt.Horizontal)
- self.widget = QWidget(self.splitter)
- self.widget.setObjectName(u"widget")
- self.gridLayout = QGridLayout(self.widget)
+ self.layoutWidget = QWidget(self.splitter)
+ self.layoutWidget.setObjectName(u"layoutWidget")
+ self.gridLayout = QGridLayout(self.layoutWidget)
self.gridLayout.setObjectName(u"gridLayout")
self.gridLayout.setContentsMargins(0, 0, 0, 0)
- self.exampleTree = QTreeWidget(self.widget)
- __qtreewidgetitem = QTreeWidgetItem()
- __qtreewidgetitem.setText(0, u"1");
- self.exampleTree.setHeaderItem(__qtreewidgetitem)
- self.exampleTree.setObjectName(u"exampleTree")
- self.exampleTree.header().setVisible(False)
-
- self.gridLayout.addWidget(self.exampleTree, 0, 0, 1, 2)
-
- self.qtLibCombo = QComboBox(self.widget)
+ self.qtLibCombo = QComboBox(self.layoutWidget)
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
self.qtLibCombo.addItem("")
@@ -45,25 +36,46 @@ class Ui_Form(object):
self.qtLibCombo.addItem("")
self.qtLibCombo.setObjectName(u"qtLibCombo")
- self.gridLayout.addWidget(self.qtLibCombo, 1, 1, 1, 1)
+ self.gridLayout.addWidget(self.qtLibCombo, 4, 1, 1, 1)
- self.label = QLabel(self.widget)
- self.label.setObjectName(u"label")
-
- self.gridLayout.addWidget(self.label, 1, 0, 1, 1)
-
- self.loadBtn = QPushButton(self.widget)
+ self.loadBtn = QPushButton(self.layoutWidget)
self.loadBtn.setObjectName(u"loadBtn")
- self.gridLayout.addWidget(self.loadBtn, 3, 1, 1, 1)
+ self.gridLayout.addWidget(self.loadBtn, 6, 1, 1, 1)
- self.splitter.addWidget(self.widget)
- self.widget1 = QWidget(self.splitter)
- self.widget1.setObjectName(u"widget1")
- self.verticalLayout = QVBoxLayout(self.widget1)
+ self.exampleTree = QTreeWidget(self.layoutWidget)
+ __qtreewidgetitem = QTreeWidgetItem()
+ __qtreewidgetitem.setText(0, u"1");
+ self.exampleTree.setHeaderItem(__qtreewidgetitem)
+ self.exampleTree.setObjectName(u"exampleTree")
+ self.exampleTree.header().setVisible(False)
+
+ self.gridLayout.addWidget(self.exampleTree, 3, 0, 1, 2)
+
+ self.label = QLabel(self.layoutWidget)
+ self.label.setObjectName(u"label")
+
+ self.gridLayout.addWidget(self.label, 4, 0, 1, 1)
+
+ self.exampleFilter = QLineEdit(self.layoutWidget)
+ self.exampleFilter.setObjectName(u"exampleFilter")
+
+ self.gridLayout.addWidget(self.exampleFilter, 0, 0, 1, 2)
+
+ self.searchFiles = QComboBox(self.layoutWidget)
+ self.searchFiles.addItem("")
+ self.searchFiles.addItem("")
+ self.searchFiles.setObjectName(u"searchFiles")
+
+ self.gridLayout.addWidget(self.searchFiles, 1, 0, 1, 2)
+
+ self.splitter.addWidget(self.layoutWidget)
+ self.layoutWidget1 = QWidget(self.splitter)
+ self.layoutWidget1.setObjectName(u"layoutWidget1")
+ self.verticalLayout = QVBoxLayout(self.layoutWidget1)
self.verticalLayout.setObjectName(u"verticalLayout")
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
- self.loadedFileLabel = QLabel(self.widget1)
+ self.loadedFileLabel = QLabel(self.layoutWidget1)
self.loadedFileLabel.setObjectName(u"loadedFileLabel")
font = QFont()
font.setBold(True)
@@ -72,7 +84,7 @@ class Ui_Form(object):
self.verticalLayout.addWidget(self.loadedFileLabel)
- self.codeView = QPlainTextEdit(self.widget1)
+ self.codeView = QPlainTextEdit(self.layoutWidget1)
self.codeView.setObjectName(u"codeView")
font1 = QFont()
font1.setFamilies([u"Courier New"])
@@ -80,9 +92,9 @@ class Ui_Form(object):
self.verticalLayout.addWidget(self.codeView)
- self.splitter.addWidget(self.widget1)
+ self.splitter.addWidget(self.layoutWidget1)
- self.gridLayout_2.addWidget(self.splitter, 0, 0, 1, 1)
+ self.gridLayout_2.addWidget(self.splitter, 1, 0, 1, 1)
self.retranslateUi(Form)
@@ -98,8 +110,11 @@ class Ui_Form(object):
self.qtLibCombo.setItemText(3, QCoreApplication.translate("Form", u"PySide6", None))
self.qtLibCombo.setItemText(4, QCoreApplication.translate("Form", u"PyQt6", None))
- self.label.setText(QCoreApplication.translate("Form", u"Qt Library:", None))
self.loadBtn.setText(QCoreApplication.translate("Form", u"Run Example", None))
- self.loadedFileLabel.setText("")
- # retranslateUi
+ self.label.setText(QCoreApplication.translate("Form", u"Qt Library:", None))
+ self.exampleFilter.setPlaceholderText(QCoreApplication.translate("Form", u"Type to filter...", None))
+ self.searchFiles.setItemText(0, QCoreApplication.translate("Form", u"Title Search", None))
+ self.searchFiles.setItemText(1, QCoreApplication.translate("Form", u"Content Search", None))
+ self.loadedFileLabel.setText("")
+ # retranslateUi
\ No newline at end of file
diff --git a/examples/test_examples.py b/examples/test_examples.py
index 6b66e512..473a161a 100644
--- a/examples/test_examples.py
+++ b/examples/test_examples.py
@@ -32,7 +32,7 @@ def buildFileList(examples, files=None):
path = os.path.abspath(os.path.dirname(__file__))
files = [("Example App", "RunExampleApp.py")]
-for ex in [utils.examples, utils.others]:
+for ex in [utils.examples_, utils.others]:
files = buildFileList(ex, files)
files = sorted(set(files))
frontends = {
diff --git a/examples/utils.py b/examples/utils.py
index 04471e8c..8f8ff609 100644
--- a/examples/utils.py
+++ b/examples/utils.py
@@ -1,8 +1,8 @@
from collections import OrderedDict
from argparse import Namespace
-
-examples = OrderedDict([
+# Avoid clash with module name
+examples_ = OrderedDict([
('Command-line usage', 'CLIexample.py'),
('Basic Plotting', Namespace(filename='Plotting.py', recommended=True)),
('ImageView', 'ImageView.py'),
diff --git a/pyqtgraph/Qt/QtCore/__init__.py b/pyqtgraph/Qt/QtCore/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pyqtgraph/Qt/QtGui/__init__.py b/pyqtgraph/Qt/QtGui/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pyqtgraph/Qt/QtWidgets/__init__.py b/pyqtgraph/Qt/QtWidgets/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/pyqtgraph/Qt.py b/pyqtgraph/Qt/__init__.py
similarity index 89%
rename from pyqtgraph/Qt.py
rename to pyqtgraph/Qt/__init__.py
index a4df83a1..9c825785 100644
--- a/pyqtgraph/Qt.py
+++ b/pyqtgraph/Qt/__init__.py
@@ -12,7 +12,7 @@ This module exists to smooth out some of the differences between PySide and PyQt
import os, sys, re, time, subprocess, warnings
-from .python2_3 import asUnicode
+from ..python2_3 import asUnicode
PYSIDE = 'PySide'
PYSIDE2 = 'PySide2'
@@ -130,11 +130,30 @@ def _loadUiType(uiFile):
return form_class, base_class
+# For historical reasons, pyqtgraph maintains a Qt4-ish interface back when
+# there wasn't a QtWidgets module. This _was_ done by monkey-patching all of
+# QtWidgets into the QtGui module. This monkey-patching modifies QtGui at a
+# global level.
+# To avoid this, we now maintain a local "mirror" of QtCore, QtGui and QtWidgets.
+# Thus, when monkey-patching happens later on in this file, they will only affect
+# the local modules and not the global modules.
+def _copy_attrs(src, dst):
+ for o in dir(src):
+ if not hasattr(dst, o):
+ setattr(dst, o, getattr(src, o))
+
+from . import QtCore, QtGui, QtWidgets
+
if QT_LIB == PYQT5:
# We're using PyQt5 which has a different structure so we're going to use a shim to
# recreate the Qt4 structure for Qt5
- from PyQt5 import QtGui, QtCore, QtWidgets, sip, uic
-
+ import PyQt5.QtCore, PyQt5.QtGui, PyQt5.QtWidgets
+ _copy_attrs(PyQt5.QtCore, QtCore)
+ _copy_attrs(PyQt5.QtGui, QtGui)
+ _copy_attrs(PyQt5.QtWidgets, QtWidgets)
+
+ from PyQt5 import sip, uic
+
try:
from PyQt5 import QtSvg
except ImportError as err:
@@ -147,7 +166,12 @@ if QT_LIB == PYQT5:
VERSION_INFO = 'PyQt5 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
elif QT_LIB == PYQT6:
- from PyQt6 import QtGui, QtCore, QtWidgets, sip, uic
+ import PyQt6.QtCore, PyQt6.QtGui, PyQt6.QtWidgets
+ _copy_attrs(PyQt6.QtCore, QtCore)
+ _copy_attrs(PyQt6.QtGui, QtGui)
+ _copy_attrs(PyQt6.QtWidgets, QtWidgets)
+
+ from PyQt6 import sip, uic
try:
from PyQt6 import QtSvg
@@ -165,7 +189,10 @@ elif QT_LIB == PYQT6:
VERSION_INFO = 'PyQt6 ' + QtCore.PYQT_VERSION_STR + ' Qt ' + QtCore.QT_VERSION_STR
elif QT_LIB == PYSIDE2:
- from PySide2 import QtGui, QtCore, QtWidgets
+ import PySide2.QtCore, PySide2.QtGui, PySide2.QtWidgets
+ _copy_attrs(PySide2.QtCore, QtCore)
+ _copy_attrs(PySide2.QtGui, QtGui)
+ _copy_attrs(PySide2.QtWidgets, QtWidgets)
try:
from PySide2 import QtSvg
@@ -182,7 +209,10 @@ elif QT_LIB == PYSIDE2:
VERSION_INFO = 'PySide2 ' + PySide2.__version__ + ' Qt ' + QtCore.__version__
elif QT_LIB == PYSIDE6:
- from PySide6 import QtGui, QtCore, QtWidgets
+ import PySide6.QtCore, PySide6.QtGui, PySide6.QtWidgets
+ _copy_attrs(PySide6.QtCore, QtCore)
+ _copy_attrs(PySide6.QtGui, QtGui)
+ _copy_attrs(PySide6.QtWidgets, QtWidgets)
try:
from PySide6 import QtSvg
diff --git a/pyqtgraph/ThreadsafeTimer.py b/pyqtgraph/ThreadsafeTimer.py
index 47bf3ed5..2dc4b9bd 100644
--- a/pyqtgraph/ThreadsafeTimer.py
+++ b/pyqtgraph/ThreadsafeTimer.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
from .Qt import QtCore, QtGui
+__all__ = ['ThreadsafeTimer']
+
class ThreadsafeTimer(QtCore.QObject):
"""
Thread-safe replacement for QTimer.
diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py
index 3edd7a20..a80be296 100644
--- a/pyqtgraph/__init__.py
+++ b/pyqtgraph/__init__.py
@@ -10,7 +10,7 @@ __version__ = '0.12.1'
## 'Qt' is a local module; it is intended mainly to cover up the differences
## between PyQt4 and PySide.
-from .Qt import QtGui, mkQApp
+from .Qt import QtCore, QtGui, mkQApp
from .Qt import exec_ as exec
## not really safe--If we accidentally create another QApplication, the process hangs (and it is very difficult to trace the cause)
@@ -280,6 +280,15 @@ from .ptime import time
from .Qt import isQObjectAlive
from .ThreadsafeTimer import *
+# indirect imports used within library
+from .GraphicsScene import GraphicsScene
+from .python2_3 import asUnicode
+from .util.cupy_helper import getCupy
+
+# indirect imports known to be used outside of the library
+from .metaarray import MetaArray
+from .ordereddict import OrderedDict
+
##############################################################
## PyQt and PySide both are prone to crashing on exit.
diff --git a/pyqtgraph/colormap.py b/pyqtgraph/colormap.py
index 5f58da67..c1bb6ddf 100644
--- a/pyqtgraph/colormap.py
+++ b/pyqtgraph/colormap.py
@@ -5,6 +5,8 @@ from os import path, listdir
from collections.abc import Callable, Sequence
import warnings
+__all__ = ['ColorMap']
+
_mapCache = {}
def listMaps(source=None):
@@ -102,7 +104,6 @@ def _getFromFile(name):
else:
csv_mode = False
for line in fh:
- name = None
line = line.strip()
if len(line) == 0: continue # empty line
if line[0] == ';': continue # comment
@@ -149,7 +150,7 @@ def getFromMatplotlib(name):
col_map = mpl_plt.get_cmap(name)
if hasattr(col_map, '_segmentdata'): # handle LinearSegmentedColormap
data = col_map._segmentdata
- if ('red' in data) and isinstance(data['red'], Sequence):
+ if ('red' in data) and isinstance(data['red'], (Sequence, np.ndarray)):
positions = set() # super-set of handle positions in individual channels
for key in ['red','green','blue']:
for tup in data[key]:
@@ -598,32 +599,45 @@ class ColorMap(object):
pen.setCosmetic(True)
return pen
- def getColors(self, mode=None):
- """Returns a list of all color stops, converted to the specified mode.
- If `mode` is None, no conversion is performed.
+ def getColors(self, mode=BYTE):
+ """
+ Returns a list of the colors associated with the stops of the color map.
+
+ The parameter `mode` can be one of
+ - `ColorMap.BYTE` or 'byte' to return colors as RGBA tuples in byte format (0 to 255)
+ - `ColorMap.FLOAT` or 'float' to return colors as RGBA tuples in float format (0.0 to 1.0)
+ - `ColorMap.QCOLOR` or 'qcolor' to return a list of QColors
+
+ The default is byte format.
+ """
+ stops, color = self.getStops(mode=mode)
+ return color
+
+ def getStops(self, mode=BYTE):
+ """
+ Returns a tuple (stops, colors) containing a list of all stops (ranging 0.0 to 1.0)
+ and a list of the associated colors.
+
+ The parameter `mode` can be one of
+ - `ColorMap.BYTE` or 'byte' to return colors as RGBA tuples in byte format (0 to 255)
+ - `ColorMap.FLOAT` or 'float' to return colors as RGBA tuples in float format (0.0 to 1.0)
+ - `ColorMap.QCOLOR` or 'qcolor' to return a list of QColors
+
+ The default is byte format.
"""
if isinstance(mode, str):
mode = self.enumMap[mode.lower()]
- color = self.color
- if mode in [self.BYTE, self.QCOLOR] and color.dtype.kind == 'f':
- color = (color * 255).astype(np.ubyte)
- elif mode == self.FLOAT and color.dtype.kind != 'f':
- color = color.astype(float) / 255.
-
- if mode == self.QCOLOR:
- color = [QtGui.QColor(*x) for x in color]
-
- return color
-
- def getStops(self, mode):
- ## Get fully-expanded set of RGBA stops in either float or byte mode.
if mode not in self.stopsCache:
color = self.color
if mode == self.BYTE and color.dtype.kind == 'f':
color = (color*255).astype(np.ubyte)
elif mode == self.FLOAT and color.dtype.kind != 'f':
color = color.astype(float) / 255.
+ elif mode == self.QCOLOR:
+ if color.dtype.kind == 'f':
+ color = (color*255).astype(np.ubyte)
+ color = [QtGui.QColor(*x) for x in color]
self.stopsCache[mode] = (self.pos, color)
return self.stopsCache[mode]
diff --git a/pyqtgraph/colors/maps/CC0 legal code - applies to virids, magma, plasma, inferno and cividis.txt b/pyqtgraph/colors/maps/CC0 legal code - applies to virids, magma, plasma, inferno and cividis.txt
new file mode 100644
index 00000000..0e259d42
--- /dev/null
+++ b/pyqtgraph/colors/maps/CC0 legal code - applies to virids, magma, plasma, inferno and cividis.txt
@@ -0,0 +1,121 @@
+Creative Commons Legal Code
+
+CC0 1.0 Universal
+
+ CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
+ LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
+ ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
+ INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
+ REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
+ PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
+ THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
+ HEREUNDER.
+
+Statement of Purpose
+
+The laws of most jurisdictions throughout the world automatically confer
+exclusive Copyright and Related Rights (defined below) upon the creator
+and subsequent owner(s) (each and all, an "owner") of an original work of
+authorship and/or a database (each, a "Work").
+
+Certain owners wish to permanently relinquish those rights to a Work for
+the purpose of contributing to a commons of creative, cultural and
+scientific works ("Commons") that the public can reliably and without fear
+of later claims of infringement build upon, modify, incorporate in other
+works, reuse and redistribute as freely as possible in any form whatsoever
+and for any purposes, including without limitation commercial purposes.
+These owners may contribute to the Commons to promote the ideal of a free
+culture and the further production of creative, cultural and scientific
+works, or to gain reputation or greater distribution for their Work in
+part through the use and efforts of others.
+
+For these and/or other purposes and motivations, and without any
+expectation of additional consideration or compensation, the person
+associating CC0 with a Work (the "Affirmer"), to the extent that he or she
+is an owner of Copyright and Related Rights in the Work, voluntarily
+elects to apply CC0 to the Work and publicly distribute the Work under its
+terms, with knowledge of his or her Copyright and Related Rights in the
+Work and the meaning and intended legal effect of CC0 on those rights.
+
+1. Copyright and Related Rights. A Work made available under CC0 may be
+protected by copyright and related or neighboring rights ("Copyright and
+Related Rights"). Copyright and Related Rights include, but are not
+limited to, the following:
+
+ i. the right to reproduce, adapt, distribute, perform, display,
+ communicate, and translate a Work;
+ ii. moral rights retained by the original author(s) and/or performer(s);
+iii. publicity and privacy rights pertaining to a person's image or
+ likeness depicted in a Work;
+ iv. rights protecting against unfair competition in regards to a Work,
+ subject to the limitations in paragraph 4(a), below;
+ v. rights protecting the extraction, dissemination, use and reuse of data
+ in a Work;
+ vi. database rights (such as those arising under Directive 96/9/EC of the
+ European Parliament and of the Council of 11 March 1996 on the legal
+ protection of databases, and under any national implementation
+ thereof, including any amended or successor version of such
+ directive); and
+vii. other similar, equivalent or corresponding rights throughout the
+ world based on applicable law or treaty, and any national
+ implementations thereof.
+
+2. Waiver. To the greatest extent permitted by, but not in contravention
+of, applicable law, Affirmer hereby overtly, fully, permanently,
+irrevocably and unconditionally waives, abandons, and surrenders all of
+Affirmer's Copyright and Related Rights and associated claims and causes
+of action, whether now known or unknown (including existing as well as
+future claims and causes of action), in the Work (i) in all territories
+worldwide, (ii) for the maximum duration provided by applicable law or
+treaty (including future time extensions), (iii) in any current or future
+medium and for any number of copies, and (iv) for any purpose whatsoever,
+including without limitation commercial, advertising or promotional
+purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
+member of the public at large and to the detriment of Affirmer's heirs and
+successors, fully intending that such Waiver shall not be subject to
+revocation, rescission, cancellation, termination, or any other legal or
+equitable action to disrupt the quiet enjoyment of the Work by the public
+as contemplated by Affirmer's express Statement of Purpose.
+
+3. Public License Fallback. Should any part of the Waiver for any reason
+be judged legally invalid or ineffective under applicable law, then the
+Waiver shall be preserved to the maximum extent permitted taking into
+account Affirmer's express Statement of Purpose. In addition, to the
+extent the Waiver is so judged Affirmer hereby grants to each affected
+person a royalty-free, non transferable, non sublicensable, non exclusive,
+irrevocable and unconditional license to exercise Affirmer's Copyright and
+Related Rights in the Work (i) in all territories worldwide, (ii) for the
+maximum duration provided by applicable law or treaty (including future
+time extensions), (iii) in any current or future medium and for any number
+of copies, and (iv) for any purpose whatsoever, including without
+limitation commercial, advertising or promotional purposes (the
+"License"). The License shall be deemed effective as of the date CC0 was
+applied by Affirmer to the Work. Should any part of the License for any
+reason be judged legally invalid or ineffective under applicable law, such
+partial invalidity or ineffectiveness shall not invalidate the remainder
+of the License, and in such case Affirmer hereby affirms that he or she
+will not (i) exercise any of his or her remaining Copyright and Related
+Rights in the Work or (ii) assert any associated claims and causes of
+action with respect to the Work, in either case contrary to Affirmer's
+express Statement of Purpose.
+
+4. Limitations and Disclaimers.
+
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
+ surrendered, licensed or otherwise affected by this document.
+ b. Affirmer offers the Work as-is and makes no representations or
+ warranties of any kind concerning the Work, express, implied,
+ statutory or otherwise, including without limitation warranties of
+ title, merchantability, fitness for a particular purpose, non
+ infringement, or the absence of latent or other defects, accuracy, or
+ the present or absence of errors, whether or not discoverable, all to
+ the greatest extent permissible under applicable law.
+ c. Affirmer disclaims responsibility for clearing rights of other persons
+ that may apply to the Work or any use thereof, including without
+ limitation any person's Copyright and Related Rights in the Work.
+ Further, Affirmer disclaims responsibility for obtaining any necessary
+ consents, permissions or other rights required for any use of the
+ Work.
+ d. Affirmer understands and acknowledges that Creative Commons is not a
+ party to this document and has no duty or obligation with respect to
+ this CC0 or use of the Work.
diff --git a/pyqtgraph/colors/maps/cividis.csv b/pyqtgraph/colors/maps/cividis.csv
new file mode 100644
index 00000000..34101b64
--- /dev/null
+++ b/pyqtgraph/colors/maps/cividis.csv
@@ -0,0 +1,266 @@
+; cividis colormap, optimized with consideration for color vision deficiency
+; to enable accurate interpretation of scientific data
+;
+; Published by Jamie R. Nuñez, Christopher R. Anderton and Ryan S. Renslow
+; in PLoS ONE 13(7): e0199239. https://doi.org/10.1371/journal.pone.0199239
+; available under Creative Commons CC0 public domain dedication.
+;
+; You should have received a copy of the CC0 legalcode along with this
+; work. If not, see .
+;
+0.000000,0.126200,0.301500
+0.000000,0.129200,0.307700
+0.000000,0.132100,0.314200
+0.000000,0.135000,0.320500
+0.000000,0.137900,0.326900
+0.000000,0.140800,0.333400
+0.000000,0.143700,0.340000
+0.000000,0.146500,0.346700
+0.000000,0.149200,0.353700
+0.000000,0.151900,0.360600
+0.000000,0.154600,0.367600
+0.000000,0.157400,0.374600
+0.000000,0.160100,0.381700
+0.000000,0.162900,0.388800
+0.000000,0.165700,0.396000
+0.000000,0.168500,0.403100
+0.000000,0.171400,0.410200
+0.000000,0.174300,0.417200
+0.000000,0.177300,0.424100
+0.000000,0.179800,0.430700
+0.000000,0.181700,0.434700
+0.000000,0.183400,0.436300
+0.000000,0.185200,0.436800
+0.000000,0.187200,0.436800
+0.000000,0.190100,0.436500
+0.000000,0.193000,0.436100
+0.000000,0.195800,0.435600
+0.000000,0.198700,0.434900
+0.000000,0.201500,0.434300
+0.000000,0.204400,0.433600
+0.000000,0.207300,0.432900
+0.005500,0.210100,0.432200
+0.023600,0.213000,0.431400
+0.041600,0.215800,0.430800
+0.057600,0.218700,0.430100
+0.071000,0.221500,0.429300
+0.082700,0.224400,0.428700
+0.093200,0.227200,0.428000
+0.103000,0.230000,0.427400
+0.112000,0.232900,0.426800
+0.120400,0.235700,0.426200
+0.128300,0.238500,0.425600
+0.135900,0.241400,0.425100
+0.143100,0.244200,0.424500
+0.150000,0.247000,0.424100
+0.156600,0.249800,0.423600
+0.163000,0.252600,0.423200
+0.169200,0.255500,0.422800
+0.175200,0.258300,0.422400
+0.181100,0.261100,0.422000
+0.186800,0.263900,0.421700
+0.192300,0.266700,0.421400
+0.197700,0.269500,0.421200
+0.203000,0.272300,0.420900
+0.208200,0.275100,0.420700
+0.213300,0.278000,0.420500
+0.218300,0.280800,0.420400
+0.223200,0.283600,0.420300
+0.228100,0.286400,0.420200
+0.232800,0.289200,0.420100
+0.237500,0.292000,0.420000
+0.242100,0.294800,0.420000
+0.246600,0.297600,0.420000
+0.251100,0.300400,0.420100
+0.255600,0.303200,0.420100
+0.259900,0.306000,0.420200
+0.264300,0.308800,0.420300
+0.268600,0.311600,0.420500
+0.272800,0.314400,0.420600
+0.277000,0.317200,0.420800
+0.281100,0.320000,0.421000
+0.285300,0.322800,0.421200
+0.289400,0.325600,0.421500
+0.293400,0.328400,0.421800
+0.297400,0.331200,0.422100
+0.301400,0.334000,0.422400
+0.305400,0.336800,0.422700
+0.309300,0.339600,0.423100
+0.313200,0.342400,0.423600
+0.317000,0.345300,0.424000
+0.320900,0.348100,0.424400
+0.324700,0.350900,0.424900
+0.328500,0.353700,0.425400
+0.332300,0.356500,0.425900
+0.336100,0.359300,0.426400
+0.339800,0.362200,0.427000
+0.343500,0.365000,0.427600
+0.347200,0.367800,0.428200
+0.350900,0.370600,0.428800
+0.354600,0.373400,0.429400
+0.358200,0.376300,0.430200
+0.361900,0.379100,0.430800
+0.365500,0.381900,0.431600
+0.369100,0.384800,0.432200
+0.372700,0.387600,0.433100
+0.376300,0.390400,0.433800
+0.379800,0.393300,0.434600
+0.383400,0.396100,0.435500
+0.386900,0.399000,0.436400
+0.390500,0.401800,0.437200
+0.394000,0.404700,0.438100
+0.397500,0.407500,0.439000
+0.401000,0.410400,0.440000
+0.404500,0.413200,0.440900
+0.408000,0.416100,0.441900
+0.411400,0.418900,0.443000
+0.414900,0.421800,0.444000
+0.418300,0.424700,0.445000
+0.421800,0.427500,0.446200
+0.425200,0.430400,0.447300
+0.428600,0.433300,0.448500
+0.432000,0.436200,0.449600
+0.435400,0.439000,0.450800
+0.438800,0.441900,0.452100
+0.442200,0.444800,0.453400
+0.445600,0.447700,0.454700
+0.448900,0.450600,0.456100
+0.452300,0.453500,0.457500
+0.455600,0.456400,0.458900
+0.458900,0.459300,0.460400
+0.462200,0.462200,0.462000
+0.465600,0.465100,0.463500
+0.468900,0.468000,0.465000
+0.472200,0.470900,0.466500
+0.475600,0.473800,0.467900
+0.479000,0.476700,0.469100
+0.482500,0.479700,0.470100
+0.486100,0.482600,0.470700
+0.489700,0.485600,0.471400
+0.493400,0.488600,0.471900
+0.497100,0.491500,0.472300
+0.500800,0.494500,0.472700
+0.504500,0.497500,0.473000
+0.508300,0.500500,0.473200
+0.512100,0.503500,0.473400
+0.515800,0.506500,0.473600
+0.519600,0.509500,0.473700
+0.523400,0.512500,0.473800
+0.527200,0.515500,0.473900
+0.531000,0.518600,0.473900
+0.534900,0.521600,0.473800
+0.538700,0.524600,0.473900
+0.542500,0.527700,0.473800
+0.546400,0.530700,0.473600
+0.550200,0.533800,0.473500
+0.554100,0.536800,0.473300
+0.557900,0.539900,0.473200
+0.561800,0.543000,0.472900
+0.565700,0.546100,0.472700
+0.569600,0.549100,0.472300
+0.573500,0.552200,0.472000
+0.577400,0.555300,0.471700
+0.581300,0.558400,0.471400
+0.585200,0.561500,0.470900
+0.589200,0.564600,0.470500
+0.593100,0.567800,0.470100
+0.597000,0.570900,0.469600
+0.601000,0.574000,0.469100
+0.605000,0.577200,0.468500
+0.608900,0.580300,0.468000
+0.612900,0.583500,0.467300
+0.616800,0.586600,0.466800
+0.620800,0.589800,0.466200
+0.624800,0.592900,0.465500
+0.628800,0.596100,0.464900
+0.632800,0.599300,0.464100
+0.636800,0.602500,0.463200
+0.640800,0.605700,0.462500
+0.644900,0.608900,0.461700
+0.648900,0.612100,0.460900
+0.652900,0.615300,0.460000
+0.657000,0.618500,0.459100
+0.661000,0.621700,0.458300
+0.665100,0.625000,0.457300
+0.669100,0.628200,0.456200
+0.673200,0.631500,0.455300
+0.677300,0.634700,0.454300
+0.681300,0.638000,0.453200
+0.685400,0.641200,0.452100
+0.689500,0.644500,0.451100
+0.693600,0.647800,0.449900
+0.697700,0.651100,0.448700
+0.701800,0.654400,0.447500
+0.706000,0.657700,0.446300
+0.710100,0.661000,0.445000
+0.714200,0.664300,0.443700
+0.718400,0.667600,0.442400
+0.722500,0.671000,0.440900
+0.726700,0.674300,0.439600
+0.730800,0.677600,0.438200
+0.735000,0.681000,0.436800
+0.739200,0.684400,0.435200
+0.743400,0.687700,0.433800
+0.747600,0.691100,0.432200
+0.751800,0.694500,0.430700
+0.756000,0.697900,0.429000
+0.760200,0.701300,0.427300
+0.764400,0.704700,0.425800
+0.768600,0.708100,0.424100
+0.772900,0.711500,0.422300
+0.777100,0.715000,0.420500
+0.781400,0.718400,0.418800
+0.785600,0.721800,0.416800
+0.789900,0.725300,0.415000
+0.794200,0.728800,0.412900
+0.798500,0.732200,0.411100
+0.802700,0.735700,0.409000
+0.807000,0.739200,0.407000
+0.811400,0.742700,0.404900
+0.815700,0.746200,0.402800
+0.820000,0.749700,0.400700
+0.824300,0.753200,0.398400
+0.828700,0.756800,0.396100
+0.833000,0.760300,0.393800
+0.837400,0.763900,0.391500
+0.841700,0.767400,0.389200
+0.846100,0.771000,0.386900
+0.850500,0.774500,0.384300
+0.854800,0.778100,0.381800
+0.859200,0.781700,0.379300
+0.863600,0.785300,0.376600
+0.868100,0.788900,0.373900
+0.872500,0.792600,0.371200
+0.876900,0.796200,0.368400
+0.881300,0.799800,0.365700
+0.885800,0.803500,0.362700
+0.890200,0.807100,0.359900
+0.894700,0.810800,0.356900
+0.899200,0.814500,0.353800
+0.903700,0.818200,0.350700
+0.908200,0.821900,0.347400
+0.912700,0.825600,0.344200
+0.917200,0.829300,0.340900
+0.921700,0.833000,0.337400
+0.926200,0.836700,0.334000
+0.930800,0.840500,0.330600
+0.935300,0.844200,0.326800
+0.939900,0.848000,0.323200
+0.944400,0.851800,0.319500
+0.949000,0.855600,0.315500
+0.953600,0.859300,0.311600
+0.958200,0.863200,0.307600
+0.962800,0.867000,0.303400
+0.967400,0.870800,0.299000
+0.972100,0.874600,0.294700
+0.976700,0.878500,0.290100
+0.981400,0.882300,0.285600
+0.986000,0.886200,0.280700
+0.990700,0.890100,0.275900
+0.995400,0.894000,0.270800
+1.000000,0.897900,0.265500
+1.000000,0.901800,0.260000
+1.000000,0.905700,0.259300
+1.000000,0.909400,0.263400
+1.000000,0.913100,0.268000
+1.000000,0.916900,0.273100
diff --git a/pyqtgraph/colors/maps/inferno.csv b/pyqtgraph/colors/maps/inferno.csv
new file mode 100644
index 00000000..5b123d08
--- /dev/null
+++ b/pyqtgraph/colors/maps/inferno.csv
@@ -0,0 +1,270 @@
+; New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,
+; and (in the case of viridis) Eric Firing.
+;
+; This file and the colormaps in it are released under the CC0 license /
+; public domain dedication. The creators would appreciate credit if you use or
+; redistribute these colormaps, but do not impose any legal restrictions.
+;
+; To the extent possible under law, the persons who associated CC0 with
+; mpl-colormaps have waived all copyright and related or neighboring rights
+; to mpl-colormaps.
+;
+; You should have received a copy of the CC0 legalcode along with this
+; work. If not, see .
+;
+0.001462,0.000466,0.013866
+0.002267,0.001270,0.018570
+0.003299,0.002249,0.024239
+0.004547,0.003392,0.030909
+0.006006,0.004692,0.038558
+0.007676,0.006136,0.046836
+0.009561,0.007713,0.055143
+0.011663,0.009417,0.063460
+0.013995,0.011225,0.071862
+0.016561,0.013136,0.080282
+0.019373,0.015133,0.088767
+0.022447,0.017199,0.097327
+0.025793,0.019331,0.105930
+0.029432,0.021503,0.114621
+0.033385,0.023702,0.123397
+0.037668,0.025921,0.132232
+0.042253,0.028139,0.141141
+0.046915,0.030324,0.150164
+0.051644,0.032474,0.159254
+0.056449,0.034569,0.168414
+0.061340,0.036590,0.177642
+0.066331,0.038504,0.186962
+0.071429,0.040294,0.196354
+0.076637,0.041905,0.205799
+0.081962,0.043328,0.215289
+0.087411,0.044556,0.224813
+0.092990,0.045583,0.234358
+0.098702,0.046402,0.243904
+0.104551,0.047008,0.253430
+0.110536,0.047399,0.262912
+0.116656,0.047574,0.272321
+0.122908,0.047536,0.281624
+0.129285,0.047293,0.290788
+0.135778,0.046856,0.299776
+0.142378,0.046242,0.308553
+0.149073,0.045468,0.317085
+0.155850,0.044559,0.325338
+0.162689,0.043554,0.333277
+0.169575,0.042489,0.340874
+0.176493,0.041402,0.348111
+0.183429,0.040329,0.354971
+0.190367,0.039309,0.361447
+0.197297,0.038400,0.367535
+0.204209,0.037632,0.373238
+0.211095,0.037030,0.378563
+0.217949,0.036615,0.383522
+0.224763,0.036405,0.388129
+0.231538,0.036405,0.392400
+0.238273,0.036621,0.396353
+0.244967,0.037055,0.400007
+0.251620,0.037705,0.403378
+0.258234,0.038571,0.406485
+0.264810,0.039647,0.409345
+0.271347,0.040922,0.411976
+0.277850,0.042353,0.414392
+0.284321,0.043933,0.416608
+0.290763,0.045644,0.418637
+0.297178,0.047470,0.420491
+0.303568,0.049396,0.422182
+0.309935,0.051407,0.423721
+0.316282,0.053490,0.425116
+0.322610,0.055634,0.426377
+0.328921,0.057827,0.427511
+0.335217,0.060060,0.428524
+0.341500,0.062325,0.429425
+0.347771,0.064616,0.430217
+0.354032,0.066925,0.430906
+0.360284,0.069247,0.431497
+0.366529,0.071579,0.431994
+0.372768,0.073915,0.432400
+0.379001,0.076253,0.432719
+0.385228,0.078591,0.432955
+0.391453,0.080927,0.433109
+0.397674,0.083257,0.433183
+0.403894,0.085580,0.433179
+0.410113,0.087896,0.433098
+0.416331,0.090203,0.432943
+0.422549,0.092501,0.432714
+0.428768,0.094790,0.432412
+0.434987,0.097069,0.432039
+0.441207,0.099338,0.431594
+0.447428,0.101597,0.431080
+0.453651,0.103848,0.430498
+0.459875,0.106089,0.429846
+0.466100,0.108322,0.429125
+0.472328,0.110547,0.428334
+0.478558,0.112764,0.427475
+0.484789,0.114974,0.426548
+0.491022,0.117179,0.425552
+0.497257,0.119379,0.424488
+0.503493,0.121575,0.423356
+0.509730,0.123769,0.422156
+0.515967,0.125960,0.420887
+0.522206,0.128150,0.419549
+0.528444,0.130341,0.418142
+0.534683,0.132534,0.416667
+0.540920,0.134729,0.415123
+0.547157,0.136929,0.413511
+0.553392,0.139134,0.411829
+0.559624,0.141346,0.410078
+0.565854,0.143567,0.408258
+0.572081,0.145797,0.406369
+0.578304,0.148039,0.404411
+0.584521,0.150294,0.402385
+0.590734,0.152563,0.400290
+0.596940,0.154848,0.398125
+0.603139,0.157151,0.395891
+0.609330,0.159474,0.393589
+0.615513,0.161817,0.391219
+0.621685,0.164184,0.388781
+0.627847,0.166575,0.386276
+0.633998,0.168992,0.383704
+0.640135,0.171438,0.381065
+0.646260,0.173914,0.378359
+0.652369,0.176421,0.375586
+0.658463,0.178962,0.372748
+0.664540,0.181539,0.369846
+0.670599,0.184153,0.366879
+0.676638,0.186807,0.363849
+0.682656,0.189501,0.360757
+0.688653,0.192239,0.357603
+0.694627,0.195021,0.354388
+0.700576,0.197851,0.351113
+0.706500,0.200728,0.347777
+0.712396,0.203656,0.344383
+0.718264,0.206636,0.340931
+0.724103,0.209670,0.337424
+0.729909,0.212759,0.333861
+0.735683,0.215906,0.330245
+0.741423,0.219112,0.326576
+0.747127,0.222378,0.322856
+0.752794,0.225706,0.319085
+0.758422,0.229097,0.315266
+0.764010,0.232554,0.311399
+0.769556,0.236077,0.307485
+0.775059,0.239667,0.303526
+0.780517,0.243327,0.299523
+0.785929,0.247056,0.295477
+0.791293,0.250856,0.291390
+0.796607,0.254728,0.287264
+0.801871,0.258674,0.283099
+0.807082,0.262692,0.278898
+0.812239,0.266786,0.274661
+0.817341,0.270954,0.270390
+0.822386,0.275197,0.266085
+0.827372,0.279517,0.261750
+0.832299,0.283913,0.257383
+0.837165,0.288385,0.252988
+0.841969,0.292933,0.248564
+0.846709,0.297559,0.244113
+0.851384,0.302260,0.239636
+0.855992,0.307038,0.235133
+0.860533,0.311892,0.230606
+0.865006,0.316822,0.226055
+0.869409,0.321827,0.221482
+0.873741,0.326906,0.216886
+0.878001,0.332060,0.212268
+0.882188,0.337287,0.207628
+0.886302,0.342586,0.202968
+0.890341,0.347957,0.198286
+0.894305,0.353399,0.193584
+0.898192,0.358911,0.188860
+0.902003,0.364492,0.184116
+0.905735,0.370140,0.179350
+0.909390,0.375856,0.174563
+0.912966,0.381636,0.169755
+0.916462,0.387481,0.164924
+0.919879,0.393389,0.160070
+0.923215,0.399359,0.155193
+0.926470,0.405389,0.150292
+0.929644,0.411479,0.145367
+0.932737,0.417627,0.140417
+0.935747,0.423831,0.135440
+0.938675,0.430091,0.130438
+0.941521,0.436405,0.125409
+0.944285,0.442772,0.120354
+0.946965,0.449191,0.115272
+0.949562,0.455660,0.110164
+0.952075,0.462178,0.105031
+0.954506,0.468744,0.099874
+0.956852,0.475356,0.094695
+0.959114,0.482014,0.089499
+0.961293,0.488716,0.084289
+0.963387,0.495462,0.079073
+0.965397,0.502249,0.073859
+0.967322,0.509078,0.068659
+0.969163,0.515946,0.063488
+0.970919,0.522853,0.058367
+0.972590,0.529798,0.053324
+0.974176,0.536780,0.048392
+0.975677,0.543798,0.043618
+0.977092,0.550850,0.039050
+0.978422,0.557937,0.034931
+0.979666,0.565057,0.031409
+0.980824,0.572209,0.028508
+0.981895,0.579392,0.026250
+0.982881,0.586606,0.024661
+0.983779,0.593849,0.023770
+0.984591,0.601122,0.023606
+0.985315,0.608422,0.024202
+0.985952,0.615750,0.025592
+0.986502,0.623105,0.027814
+0.986964,0.630485,0.030908
+0.987337,0.637890,0.034916
+0.987622,0.645320,0.039886
+0.987819,0.652773,0.045581
+0.987926,0.660250,0.051750
+0.987945,0.667748,0.058329
+0.987874,0.675267,0.065257
+0.987714,0.682807,0.072489
+0.987464,0.690366,0.079990
+0.987124,0.697944,0.087731
+0.986694,0.705540,0.095694
+0.986175,0.713153,0.103863
+0.985566,0.720782,0.112229
+0.984865,0.728427,0.120785
+0.984075,0.736087,0.129527
+0.983196,0.743758,0.138453
+0.982228,0.751442,0.147565
+0.981173,0.759135,0.156863
+0.980032,0.766837,0.166353
+0.978806,0.774545,0.176037
+0.977497,0.782258,0.185923
+0.976108,0.789974,0.196018
+0.974638,0.797692,0.206332
+0.973088,0.805409,0.216877
+0.971468,0.813122,0.227658
+0.969783,0.820825,0.238686
+0.968041,0.828515,0.249972
+0.966243,0.836191,0.261534
+0.964394,0.843848,0.273391
+0.962517,0.851476,0.285546
+0.960626,0.859069,0.298010
+0.958720,0.866624,0.310820
+0.956834,0.874129,0.323974
+0.954997,0.881569,0.337475
+0.953215,0.888942,0.351369
+0.951546,0.896226,0.365627
+0.950018,0.903409,0.380271
+0.948683,0.910473,0.395289
+0.947594,0.917399,0.410665
+0.946809,0.924168,0.426373
+0.946392,0.930761,0.442367
+0.946403,0.937159,0.458592
+0.946903,0.943348,0.474970
+0.947937,0.949318,0.491426
+0.949545,0.955063,0.507860
+0.951740,0.960587,0.524203
+0.954529,0.965896,0.540361
+0.957896,0.971003,0.556275
+0.961812,0.975924,0.571925
+0.966249,0.980678,0.587206
+0.971162,0.985282,0.602154
+0.976511,0.989753,0.616760
+0.982257,0.994109,0.631017
+0.988362,0.998364,0.644924
diff --git a/pyqtgraph/colors/maps/magma.csv b/pyqtgraph/colors/maps/magma.csv
new file mode 100644
index 00000000..d8185ed2
--- /dev/null
+++ b/pyqtgraph/colors/maps/magma.csv
@@ -0,0 +1,270 @@
+; New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,
+; and (in the case of viridis) Eric Firing.
+;
+; This file and the colormaps in it are released under the CC0 license /
+; public domain dedication. The creators would appreciate credit if you use or
+; redistribute these colormaps, but do not impose any legal restrictions.
+;
+; To the extent possible under law, the persons who associated CC0 with
+; mpl-colormaps have waived all copyright and related or neighboring rights
+; to mpl-colormaps.
+;
+; You should have received a copy of the CC0 legalcode along with this
+; work. If not, see .
+;
+0.001462,0.000466,0.013866
+0.002258,0.001295,0.018331
+0.003279,0.002305,0.023708
+0.004512,0.003490,0.029965
+0.005950,0.004843,0.037130
+0.007588,0.006356,0.044973
+0.009426,0.008022,0.052844
+0.011465,0.009828,0.060750
+0.013708,0.011771,0.068667
+0.016156,0.013840,0.076603
+0.018815,0.016026,0.084584
+0.021692,0.018320,0.092610
+0.024792,0.020715,0.100676
+0.028123,0.023201,0.108787
+0.031696,0.025765,0.116965
+0.035520,0.028397,0.125209
+0.039608,0.031090,0.133515
+0.043830,0.033830,0.141886
+0.048062,0.036607,0.150327
+0.052320,0.039407,0.158841
+0.056615,0.042160,0.167446
+0.060949,0.044794,0.176129
+0.065330,0.047318,0.184892
+0.069764,0.049726,0.193735
+0.074257,0.052017,0.202660
+0.078815,0.054184,0.211667
+0.083446,0.056225,0.220755
+0.088155,0.058133,0.229922
+0.092949,0.059904,0.239164
+0.097833,0.061531,0.248477
+0.102815,0.063010,0.257854
+0.107899,0.064335,0.267289
+0.113094,0.065492,0.276784
+0.118405,0.066479,0.286321
+0.123833,0.067295,0.295879
+0.129380,0.067935,0.305443
+0.135053,0.068391,0.315000
+0.140858,0.068654,0.324538
+0.146785,0.068738,0.334011
+0.152839,0.068637,0.343404
+0.159018,0.068354,0.352688
+0.165308,0.067911,0.361816
+0.171713,0.067305,0.370771
+0.178212,0.066576,0.379497
+0.184801,0.065732,0.387973
+0.191460,0.064818,0.396152
+0.198177,0.063862,0.404009
+0.204935,0.062907,0.411514
+0.211718,0.061992,0.418647
+0.218512,0.061158,0.425392
+0.225302,0.060445,0.431742
+0.232077,0.059889,0.437695
+0.238826,0.059517,0.443256
+0.245543,0.059352,0.448436
+0.252220,0.059415,0.453248
+0.258857,0.059706,0.457710
+0.265447,0.060237,0.461840
+0.271994,0.060994,0.465660
+0.278493,0.061978,0.469190
+0.284951,0.063168,0.472451
+0.291366,0.064553,0.475462
+0.297740,0.066117,0.478243
+0.304081,0.067835,0.480812
+0.310382,0.069702,0.483186
+0.316654,0.071690,0.485380
+0.322899,0.073782,0.487408
+0.329114,0.075972,0.489287
+0.335308,0.078236,0.491024
+0.341482,0.080564,0.492631
+0.347636,0.082946,0.494121
+0.353773,0.085373,0.495501
+0.359898,0.087831,0.496778
+0.366012,0.090314,0.497960
+0.372116,0.092816,0.499053
+0.378211,0.095332,0.500067
+0.384299,0.097855,0.501002
+0.390384,0.100379,0.501864
+0.396467,0.102902,0.502658
+0.402548,0.105420,0.503386
+0.408629,0.107930,0.504052
+0.414709,0.110431,0.504662
+0.420791,0.112920,0.505215
+0.426877,0.115395,0.505714
+0.432967,0.117855,0.506160
+0.439062,0.120298,0.506555
+0.445163,0.122724,0.506901
+0.451271,0.125132,0.507198
+0.457386,0.127522,0.507448
+0.463508,0.129893,0.507652
+0.469640,0.132245,0.507809
+0.475780,0.134577,0.507921
+0.481929,0.136891,0.507989
+0.488088,0.139186,0.508011
+0.494258,0.141462,0.507988
+0.500438,0.143719,0.507920
+0.506629,0.145958,0.507806
+0.512831,0.148179,0.507648
+0.519045,0.150383,0.507443
+0.525270,0.152569,0.507192
+0.531507,0.154739,0.506895
+0.537755,0.156894,0.506551
+0.544015,0.159033,0.506159
+0.550287,0.161158,0.505719
+0.556571,0.163269,0.505230
+0.562866,0.165368,0.504692
+0.569172,0.167454,0.504105
+0.575490,0.169530,0.503466
+0.581819,0.171596,0.502777
+0.588158,0.173652,0.502035
+0.594508,0.175701,0.501241
+0.600868,0.177743,0.500394
+0.607238,0.179779,0.499492
+0.613617,0.181811,0.498536
+0.620005,0.183840,0.497524
+0.626401,0.185867,0.496456
+0.632805,0.187893,0.495332
+0.639216,0.189921,0.494150
+0.645633,0.191952,0.492910
+0.652056,0.193986,0.491611
+0.658483,0.196027,0.490253
+0.664915,0.198075,0.488836
+0.671349,0.200133,0.487358
+0.677786,0.202203,0.485819
+0.684224,0.204286,0.484219
+0.690661,0.206384,0.482558
+0.697098,0.208501,0.480835
+0.703532,0.210638,0.479049
+0.709962,0.212797,0.477201
+0.716387,0.214982,0.475290
+0.722805,0.217194,0.473316
+0.729216,0.219437,0.471279
+0.735616,0.221713,0.469180
+0.742004,0.224025,0.467018
+0.748378,0.226377,0.464794
+0.754737,0.228772,0.462509
+0.761077,0.231214,0.460162
+0.767398,0.233705,0.457755
+0.773695,0.236249,0.455289
+0.779968,0.238851,0.452765
+0.786212,0.241514,0.450184
+0.792427,0.244242,0.447543
+0.798608,0.247040,0.444848
+0.804752,0.249911,0.442102
+0.810855,0.252861,0.439305
+0.816914,0.255895,0.436461
+0.822926,0.259016,0.433573
+0.828886,0.262229,0.430644
+0.834791,0.265540,0.427671
+0.840636,0.268953,0.424666
+0.846416,0.272473,0.421631
+0.852126,0.276106,0.418573
+0.857763,0.279857,0.415496
+0.863320,0.283729,0.412403
+0.868793,0.287728,0.409303
+0.874176,0.291859,0.406205
+0.879464,0.296125,0.403118
+0.884651,0.300530,0.400047
+0.889731,0.305079,0.397002
+0.894700,0.309773,0.393995
+0.899552,0.314616,0.391037
+0.904281,0.319610,0.388137
+0.908884,0.324755,0.385308
+0.913354,0.330052,0.382563
+0.917689,0.335500,0.379915
+0.921884,0.341098,0.377376
+0.925937,0.346844,0.374959
+0.929845,0.352734,0.372677
+0.933606,0.358764,0.370541
+0.937221,0.364929,0.368567
+0.940687,0.371224,0.366762
+0.944006,0.377643,0.365136
+0.947180,0.384178,0.363701
+0.950210,0.390820,0.362468
+0.953099,0.397563,0.361438
+0.955849,0.404400,0.360619
+0.958464,0.411324,0.360014
+0.960949,0.418323,0.359630
+0.963310,0.425390,0.359469
+0.965549,0.432519,0.359529
+0.967671,0.439703,0.359810
+0.969680,0.446936,0.360311
+0.971582,0.454210,0.361030
+0.973381,0.461520,0.361965
+0.975082,0.468861,0.363111
+0.976690,0.476226,0.364466
+0.978210,0.483612,0.366025
+0.979645,0.491014,0.367783
+0.981000,0.498428,0.369734
+0.982279,0.505851,0.371874
+0.983485,0.513280,0.374198
+0.984622,0.520713,0.376698
+0.985693,0.528148,0.379371
+0.986700,0.535582,0.382210
+0.987646,0.543015,0.385210
+0.988533,0.550446,0.388365
+0.989363,0.557873,0.391671
+0.990138,0.565296,0.395122
+0.990871,0.572706,0.398714
+0.991558,0.580107,0.402441
+0.992196,0.587502,0.406299
+0.992785,0.594891,0.410283
+0.993326,0.602275,0.414390
+0.993834,0.609644,0.418613
+0.994309,0.616999,0.422950
+0.994738,0.624350,0.427397
+0.995122,0.631696,0.431951
+0.995480,0.639027,0.436607
+0.995810,0.646344,0.441361
+0.996096,0.653659,0.446213
+0.996341,0.660969,0.451160
+0.996580,0.668256,0.456192
+0.996775,0.675541,0.461314
+0.996925,0.682828,0.466526
+0.997077,0.690088,0.471811
+0.997186,0.697349,0.477182
+0.997254,0.704611,0.482635
+0.997325,0.711848,0.488154
+0.997351,0.719089,0.493755
+0.997351,0.726324,0.499428
+0.997341,0.733545,0.505167
+0.997285,0.740772,0.510983
+0.997228,0.747981,0.516859
+0.997138,0.755190,0.522806
+0.997019,0.762398,0.528821
+0.996898,0.769591,0.534892
+0.996727,0.776795,0.541039
+0.996571,0.783977,0.547233
+0.996369,0.791167,0.553499
+0.996162,0.798348,0.559820
+0.995932,0.805527,0.566202
+0.995680,0.812706,0.572645
+0.995424,0.819875,0.579140
+0.995131,0.827052,0.585701
+0.994851,0.834213,0.592307
+0.994524,0.841387,0.598983
+0.994222,0.848540,0.605696
+0.993866,0.855711,0.612482
+0.993545,0.862859,0.619299
+0.993170,0.870024,0.626189
+0.992831,0.877168,0.633109
+0.992440,0.884330,0.640099
+0.992089,0.891470,0.647116
+0.991688,0.898627,0.654202
+0.991332,0.905763,0.661309
+0.990930,0.912915,0.668481
+0.990570,0.920049,0.675675
+0.990175,0.927196,0.682926
+0.989815,0.934329,0.690198
+0.989434,0.941470,0.697519
+0.989077,0.948604,0.704863
+0.988717,0.955742,0.712242
+0.988367,0.962878,0.719649
+0.988033,0.970012,0.727077
+0.987691,0.977154,0.734536
+0.987387,0.984288,0.742002
+0.987053,0.991438,0.749504
diff --git a/pyqtgraph/colors/maps/plasma.csv b/pyqtgraph/colors/maps/plasma.csv
new file mode 100644
index 00000000..c6c40d2d
--- /dev/null
+++ b/pyqtgraph/colors/maps/plasma.csv
@@ -0,0 +1,270 @@
+; New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,
+; and (in the case of viridis) Eric Firing.
+;
+; This file and the colormaps in it are released under the CC0 license /
+; public domain dedication. The creators would appreciate credit if you use or
+; redistribute these colormaps, but do not impose any legal restrictions.
+;
+; To the extent possible under law, the persons who associated CC0 with
+; mpl-colormaps have waived all copyright and related or neighboring rights
+; to mpl-colormaps.
+;
+; You should have received a copy of the CC0 legalcode along with this
+; work. If not, see .
+;
+0.050383,0.029803,0.527975
+0.063536,0.028426,0.533124
+0.075353,0.027206,0.538007
+0.086222,0.026125,0.542658
+0.096379,0.025165,0.547103
+0.105980,0.024309,0.551368
+0.115124,0.023556,0.555468
+0.123903,0.022878,0.559423
+0.132381,0.022258,0.563250
+0.140603,0.021687,0.566959
+0.148607,0.021154,0.570562
+0.156421,0.020651,0.574065
+0.164070,0.020171,0.577478
+0.171574,0.019706,0.580806
+0.178950,0.019252,0.584054
+0.186213,0.018803,0.587228
+0.193374,0.018354,0.590330
+0.200445,0.017902,0.593364
+0.207435,0.017442,0.596333
+0.214350,0.016973,0.599239
+0.221197,0.016497,0.602083
+0.227983,0.016007,0.604867
+0.234715,0.015502,0.607592
+0.241396,0.014979,0.610259
+0.248032,0.014439,0.612868
+0.254627,0.013882,0.615419
+0.261183,0.013308,0.617911
+0.267703,0.012716,0.620346
+0.274191,0.012109,0.622722
+0.280648,0.011488,0.625038
+0.287076,0.010855,0.627295
+0.293478,0.010213,0.629490
+0.299855,0.009561,0.631624
+0.306210,0.008902,0.633694
+0.312543,0.008239,0.635700
+0.318856,0.007576,0.637640
+0.325150,0.006915,0.639512
+0.331426,0.006261,0.641316
+0.337683,0.005618,0.643049
+0.343925,0.004991,0.644710
+0.350150,0.004382,0.646298
+0.356359,0.003798,0.647810
+0.362553,0.003243,0.649245
+0.368733,0.002724,0.650601
+0.374897,0.002245,0.651876
+0.381047,0.001814,0.653068
+0.387183,0.001434,0.654177
+0.393304,0.001114,0.655199
+0.399411,0.000859,0.656133
+0.405503,0.000678,0.656977
+0.411580,0.000577,0.657730
+0.417642,0.000564,0.658390
+0.423689,0.000646,0.658956
+0.429719,0.000831,0.659425
+0.435734,0.001127,0.659797
+0.441732,0.001540,0.660069
+0.447714,0.002080,0.660240
+0.453677,0.002755,0.660310
+0.459623,0.003574,0.660277
+0.465550,0.004545,0.660139
+0.471457,0.005678,0.659897
+0.477344,0.006980,0.659549
+0.483210,0.008460,0.659095
+0.489055,0.010127,0.658534
+0.494877,0.011990,0.657865
+0.500678,0.014055,0.657088
+0.506454,0.016333,0.656202
+0.512206,0.018833,0.655209
+0.517933,0.021563,0.654109
+0.523633,0.024532,0.652901
+0.529306,0.027747,0.651586
+0.534952,0.031217,0.650165
+0.540570,0.034950,0.648640
+0.546157,0.038954,0.647010
+0.551715,0.043136,0.645277
+0.557243,0.047331,0.643443
+0.562738,0.051545,0.641509
+0.568201,0.055778,0.639477
+0.573632,0.060028,0.637349
+0.579029,0.064296,0.635126
+0.584391,0.068579,0.632812
+0.589719,0.072878,0.630408
+0.595011,0.077190,0.627917
+0.600266,0.081516,0.625342
+0.605485,0.085854,0.622686
+0.610667,0.090204,0.619951
+0.615812,0.094564,0.617140
+0.620919,0.098934,0.614257
+0.625987,0.103312,0.611305
+0.631017,0.107699,0.608287
+0.636008,0.112092,0.605205
+0.640959,0.116492,0.602065
+0.645872,0.120898,0.598867
+0.650746,0.125309,0.595617
+0.655580,0.129725,0.592317
+0.660374,0.134144,0.588971
+0.665129,0.138566,0.585582
+0.669845,0.142992,0.582154
+0.674522,0.147419,0.578688
+0.679160,0.151848,0.575189
+0.683758,0.156278,0.571660
+0.688318,0.160709,0.568103
+0.692840,0.165141,0.564522
+0.697324,0.169573,0.560919
+0.701769,0.174005,0.557296
+0.706178,0.178437,0.553657
+0.710549,0.182868,0.550004
+0.714883,0.187299,0.546338
+0.719181,0.191729,0.542663
+0.723444,0.196158,0.538981
+0.727670,0.200586,0.535293
+0.731862,0.205013,0.531601
+0.736019,0.209439,0.527908
+0.740143,0.213864,0.524216
+0.744232,0.218288,0.520524
+0.748289,0.222711,0.516834
+0.752312,0.227133,0.513149
+0.756304,0.231555,0.509468
+0.760264,0.235976,0.505794
+0.764193,0.240396,0.502126
+0.768090,0.244817,0.498465
+0.771958,0.249237,0.494813
+0.775796,0.253658,0.491171
+0.779604,0.258078,0.487539
+0.783383,0.262500,0.483918
+0.787133,0.266922,0.480307
+0.790855,0.271345,0.476706
+0.794549,0.275770,0.473117
+0.798216,0.280197,0.469538
+0.801855,0.284626,0.465971
+0.805467,0.289057,0.462415
+0.809052,0.293491,0.458870
+0.812612,0.297928,0.455338
+0.816144,0.302368,0.451816
+0.819651,0.306812,0.448306
+0.823132,0.311261,0.444806
+0.826588,0.315714,0.441316
+0.830018,0.320172,0.437836
+0.833422,0.324635,0.434366
+0.836801,0.329105,0.430905
+0.840155,0.333580,0.427455
+0.843484,0.338062,0.424013
+0.846788,0.342551,0.420579
+0.850066,0.347048,0.417153
+0.853319,0.351553,0.413734
+0.856547,0.356066,0.410322
+0.859750,0.360588,0.406917
+0.862927,0.365119,0.403519
+0.866078,0.369660,0.400126
+0.869203,0.374212,0.396738
+0.872303,0.378774,0.393355
+0.875376,0.383347,0.389976
+0.878423,0.387932,0.386600
+0.881443,0.392529,0.383229
+0.884436,0.397139,0.379860
+0.887402,0.401762,0.376494
+0.890340,0.406398,0.373130
+0.893250,0.411048,0.369768
+0.896131,0.415712,0.366407
+0.898984,0.420392,0.363047
+0.901807,0.425087,0.359688
+0.904601,0.429797,0.356329
+0.907365,0.434524,0.352970
+0.910098,0.439268,0.349610
+0.912800,0.444029,0.346251
+0.915471,0.448807,0.342890
+0.918109,0.453603,0.339529
+0.920714,0.458417,0.336166
+0.923287,0.463251,0.332801
+0.925825,0.468103,0.329435
+0.928329,0.472975,0.326067
+0.930798,0.477867,0.322697
+0.933232,0.482780,0.319325
+0.935630,0.487712,0.315952
+0.937990,0.492667,0.312575
+0.940313,0.497642,0.309197
+0.942598,0.502639,0.305816
+0.944844,0.507658,0.302433
+0.947051,0.512699,0.299049
+0.949217,0.517763,0.295662
+0.951344,0.522850,0.292275
+0.953428,0.527960,0.288883
+0.955470,0.533093,0.285490
+0.957469,0.538250,0.282096
+0.959424,0.543431,0.278701
+0.961336,0.548636,0.275305
+0.963203,0.553865,0.271909
+0.965024,0.559118,0.268513
+0.966798,0.564396,0.265118
+0.968526,0.569700,0.261721
+0.970205,0.575028,0.258325
+0.971835,0.580382,0.254931
+0.973416,0.585761,0.251540
+0.974947,0.591165,0.248151
+0.976428,0.596595,0.244767
+0.977856,0.602051,0.241387
+0.979233,0.607532,0.238013
+0.980556,0.613039,0.234646
+0.981826,0.618572,0.231287
+0.983041,0.624131,0.227937
+0.984199,0.629718,0.224595
+0.985301,0.635330,0.221265
+0.986345,0.640969,0.217948
+0.987332,0.646633,0.214648
+0.988260,0.652325,0.211364
+0.989128,0.658043,0.208100
+0.989935,0.663787,0.204859
+0.990681,0.669558,0.201642
+0.991365,0.675355,0.198453
+0.991985,0.681179,0.195295
+0.992541,0.687030,0.192170
+0.993032,0.692907,0.189084
+0.993456,0.698810,0.186041
+0.993814,0.704741,0.183043
+0.994103,0.710698,0.180097
+0.994324,0.716681,0.177208
+0.994474,0.722691,0.174381
+0.994553,0.728728,0.171622
+0.994561,0.734791,0.168938
+0.994495,0.740880,0.166335
+0.994355,0.746995,0.163821
+0.994141,0.753137,0.161404
+0.993851,0.759304,0.159092
+0.993482,0.765499,0.156891
+0.993033,0.771720,0.154808
+0.992505,0.777967,0.152855
+0.991897,0.784239,0.151042
+0.991209,0.790537,0.149377
+0.990439,0.796859,0.147870
+0.989587,0.803205,0.146529
+0.988648,0.809579,0.145357
+0.987621,0.815978,0.144363
+0.986509,0.822401,0.143557
+0.985314,0.828846,0.142945
+0.984031,0.835315,0.142528
+0.982653,0.841812,0.142303
+0.981190,0.848329,0.142279
+0.979644,0.854866,0.142453
+0.977995,0.861432,0.142808
+0.976265,0.868016,0.143351
+0.974443,0.874622,0.144061
+0.972530,0.881250,0.144923
+0.970533,0.887896,0.145919
+0.968443,0.894564,0.147014
+0.966271,0.901249,0.148180
+0.964021,0.907950,0.149370
+0.961681,0.914672,0.150520
+0.959276,0.921407,0.151566
+0.956808,0.928152,0.152409
+0.954287,0.934908,0.152921
+0.951726,0.941671,0.152925
+0.949151,0.948435,0.152178
+0.946602,0.955190,0.150328
+0.944152,0.961916,0.146861
+0.941896,0.968590,0.140956
+0.940015,0.975158,0.131326
diff --git a/pyqtgraph/colors/maps/viridis.csv b/pyqtgraph/colors/maps/viridis.csv
new file mode 100644
index 00000000..5f2b5fb5
--- /dev/null
+++ b/pyqtgraph/colors/maps/viridis.csv
@@ -0,0 +1,270 @@
+; New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt,
+; and (in the case of viridis) Eric Firing.
+;
+; This file and the colormaps in it are released under the CC0 license /
+; public domain dedication. The creators would appreciate credit if you use or
+; redistribute these colormaps, but do not impose any legal restrictions.
+;
+; To the extent possible under law, the persons who associated CC0 with
+; mpl-colormaps have waived all copyright and related or neighboring rights
+; to mpl-colormaps.
+;
+; You should have received a copy of the CC0 legalcode along with this
+; work. If not, see .
+;
+0.267004,0.004874,0.329415
+0.268510,0.009605,0.335427
+0.269944,0.014625,0.341379
+0.271305,0.019942,0.347269
+0.272594,0.025563,0.353093
+0.273809,0.031497,0.358853
+0.274952,0.037752,0.364543
+0.276022,0.044167,0.370164
+0.277018,0.050344,0.375715
+0.277941,0.056324,0.381191
+0.278791,0.062145,0.386592
+0.279566,0.067836,0.391917
+0.280267,0.073417,0.397163
+0.280894,0.078907,0.402329
+0.281446,0.084320,0.407414
+0.281924,0.089666,0.412415
+0.282327,0.094955,0.417331
+0.282656,0.100196,0.422160
+0.282910,0.105393,0.426902
+0.283091,0.110553,0.431554
+0.283197,0.115680,0.436115
+0.283229,0.120777,0.440584
+0.283187,0.125848,0.444960
+0.283072,0.130895,0.449241
+0.282884,0.135920,0.453427
+0.282623,0.140926,0.457517
+0.282290,0.145912,0.461510
+0.281887,0.150881,0.465405
+0.281412,0.155834,0.469201
+0.280868,0.160771,0.472899
+0.280255,0.165693,0.476498
+0.279574,0.170599,0.479997
+0.278826,0.175490,0.483397
+0.278012,0.180367,0.486697
+0.277134,0.185228,0.489898
+0.276194,0.190074,0.493001
+0.275191,0.194905,0.496005
+0.274128,0.199721,0.498911
+0.273006,0.204520,0.501721
+0.271828,0.209303,0.504434
+0.270595,0.214069,0.507052
+0.269308,0.218818,0.509577
+0.267968,0.223549,0.512008
+0.266580,0.228262,0.514349
+0.265145,0.232956,0.516599
+0.263663,0.237631,0.518762
+0.262138,0.242286,0.520837
+0.260571,0.246922,0.522828
+0.258965,0.251537,0.524736
+0.257322,0.256130,0.526563
+0.255645,0.260703,0.528312
+0.253935,0.265254,0.529983
+0.252194,0.269783,0.531579
+0.250425,0.274290,0.533103
+0.248629,0.278775,0.534556
+0.246811,0.283237,0.535941
+0.244972,0.287675,0.537260
+0.243113,0.292092,0.538516
+0.241237,0.296485,0.539709
+0.239346,0.300855,0.540844
+0.237441,0.305202,0.541921
+0.235526,0.309527,0.542944
+0.233603,0.313828,0.543914
+0.231674,0.318106,0.544834
+0.229739,0.322361,0.545706
+0.227802,0.326594,0.546532
+0.225863,0.330805,0.547314
+0.223925,0.334994,0.548053
+0.221989,0.339161,0.548752
+0.220057,0.343307,0.549413
+0.218130,0.347432,0.550038
+0.216210,0.351535,0.550627
+0.214298,0.355619,0.551184
+0.212395,0.359683,0.551710
+0.210503,0.363727,0.552206
+0.208623,0.367752,0.552675
+0.206756,0.371758,0.553117
+0.204903,0.375746,0.553533
+0.203063,0.379716,0.553925
+0.201239,0.383670,0.554294
+0.199430,0.387607,0.554642
+0.197636,0.391528,0.554969
+0.195860,0.395433,0.555276
+0.194100,0.399323,0.555565
+0.192357,0.403199,0.555836
+0.190631,0.407061,0.556089
+0.188923,0.410910,0.556326
+0.187231,0.414746,0.556547
+0.185556,0.418570,0.556753
+0.183898,0.422383,0.556944
+0.182256,0.426184,0.557120
+0.180629,0.429975,0.557282
+0.179019,0.433756,0.557430
+0.177423,0.437527,0.557565
+0.175841,0.441290,0.557685
+0.174274,0.445044,0.557792
+0.172719,0.448791,0.557885
+0.171176,0.452530,0.557965
+0.169646,0.456262,0.558030
+0.168126,0.459988,0.558082
+0.166617,0.463708,0.558119
+0.165117,0.467423,0.558141
+0.163625,0.471133,0.558148
+0.162142,0.474838,0.558140
+0.160665,0.478540,0.558115
+0.159194,0.482237,0.558073
+0.157729,0.485932,0.558013
+0.156270,0.489624,0.557936
+0.154815,0.493313,0.557840
+0.153364,0.497000,0.557724
+0.151918,0.500685,0.557587
+0.150476,0.504369,0.557430
+0.149039,0.508051,0.557250
+0.147607,0.511733,0.557049
+0.146180,0.515413,0.556823
+0.144759,0.519093,0.556572
+0.143343,0.522773,0.556295
+0.141935,0.526453,0.555991
+0.140536,0.530132,0.555659
+0.139147,0.533812,0.555298
+0.137770,0.537492,0.554906
+0.136408,0.541173,0.554483
+0.135066,0.544853,0.554029
+0.133743,0.548535,0.553541
+0.132444,0.552216,0.553018
+0.131172,0.555899,0.552459
+0.129933,0.559582,0.551864
+0.128729,0.563265,0.551229
+0.127568,0.566949,0.550556
+0.126453,0.570633,0.549841
+0.125394,0.574318,0.549086
+0.124395,0.578002,0.548287
+0.123463,0.581687,0.547445
+0.122606,0.585371,0.546557
+0.121831,0.589055,0.545623
+0.121148,0.592739,0.544641
+0.120565,0.596422,0.543611
+0.120092,0.600104,0.542530
+0.119738,0.603785,0.541400
+0.119512,0.607464,0.540218
+0.119423,0.611141,0.538982
+0.119483,0.614817,0.537692
+0.119699,0.618490,0.536347
+0.120081,0.622161,0.534946
+0.120638,0.625828,0.533488
+0.121380,0.629492,0.531973
+0.122312,0.633153,0.530398
+0.123444,0.636809,0.528763
+0.124780,0.640461,0.527068
+0.126326,0.644107,0.525311
+0.128087,0.647749,0.523491
+0.130067,0.651384,0.521608
+0.132268,0.655014,0.519661
+0.134692,0.658636,0.517649
+0.137339,0.662252,0.515571
+0.140210,0.665859,0.513427
+0.143303,0.669459,0.511215
+0.146616,0.673050,0.508936
+0.150148,0.676631,0.506589
+0.153894,0.680203,0.504172
+0.157851,0.683765,0.501686
+0.162016,0.687316,0.499129
+0.166383,0.690856,0.496502
+0.170948,0.694384,0.493803
+0.175707,0.697900,0.491033
+0.180653,0.701402,0.488189
+0.185783,0.704891,0.485273
+0.191090,0.708366,0.482284
+0.196571,0.711827,0.479221
+0.202219,0.715272,0.476084
+0.208030,0.718701,0.472873
+0.214000,0.722114,0.469588
+0.220124,0.725509,0.466226
+0.226397,0.728888,0.462789
+0.232815,0.732247,0.459277
+0.239374,0.735588,0.455688
+0.246070,0.738910,0.452024
+0.252899,0.742211,0.448284
+0.259857,0.745492,0.444467
+0.266941,0.748751,0.440573
+0.274149,0.751988,0.436601
+0.281477,0.755203,0.432552
+0.288921,0.758394,0.428426
+0.296479,0.761561,0.424223
+0.304148,0.764704,0.419943
+0.311925,0.767822,0.415586
+0.319809,0.770914,0.411152
+0.327796,0.773980,0.406640
+0.335885,0.777018,0.402049
+0.344074,0.780029,0.397381
+0.352360,0.783011,0.392636
+0.360741,0.785964,0.387814
+0.369214,0.788888,0.382914
+0.377779,0.791781,0.377939
+0.386433,0.794644,0.372886
+0.395174,0.797475,0.367757
+0.404001,0.800275,0.362552
+0.412913,0.803041,0.357269
+0.421908,0.805774,0.351910
+0.430983,0.808473,0.346476
+0.440137,0.811138,0.340967
+0.449368,0.813768,0.335384
+0.458674,0.816363,0.329727
+0.468053,0.818921,0.323998
+0.477504,0.821444,0.318195
+0.487026,0.823929,0.312321
+0.496615,0.826376,0.306377
+0.506271,0.828786,0.300362
+0.515992,0.831158,0.294279
+0.525776,0.833491,0.288127
+0.535621,0.835785,0.281908
+0.545524,0.838039,0.275626
+0.555484,0.840254,0.269281
+0.565498,0.842430,0.262877
+0.575563,0.844566,0.256415
+0.585678,0.846661,0.249897
+0.595839,0.848717,0.243329
+0.606045,0.850733,0.236712
+0.616293,0.852709,0.230052
+0.626579,0.854645,0.223353
+0.636902,0.856542,0.216620
+0.647257,0.858400,0.209861
+0.657642,0.860219,0.203082
+0.668054,0.861999,0.196293
+0.678489,0.863742,0.189503
+0.688944,0.865448,0.182725
+0.699415,0.867117,0.175971
+0.709898,0.868751,0.169257
+0.720391,0.870350,0.162603
+0.730889,0.871916,0.156029
+0.741388,0.873449,0.149561
+0.751884,0.874951,0.143228
+0.762373,0.876424,0.137064
+0.772852,0.877868,0.131109
+0.783315,0.879285,0.125405
+0.793760,0.880678,0.120005
+0.804182,0.882046,0.114965
+0.814576,0.883393,0.110347
+0.824940,0.884720,0.106217
+0.835270,0.886029,0.102646
+0.845561,0.887322,0.099702
+0.855810,0.888601,0.097452
+0.866013,0.889868,0.095953
+0.876168,0.891125,0.095250
+0.886271,0.892374,0.095374
+0.896320,0.893616,0.096335
+0.906311,0.894855,0.098125
+0.916242,0.896091,0.100717
+0.926106,0.897330,0.104071
+0.935904,0.898570,0.108131
+0.945636,0.899815,0.112838
+0.955300,0.901065,0.118128
+0.964894,0.902323,0.123941
+0.974417,0.903590,0.130215
+0.983868,0.904867,0.136897
+0.993248,0.906157,0.143936
diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py
index 7706a44c..b08b1d3c 100644
--- a/pyqtgraph/functions.py
+++ b/pyqtgraph/functions.py
@@ -26,6 +26,31 @@ from .metaarray import MetaArray
from collections import OrderedDict
from .python2_3 import asUnicode, basestring
+# in order of appearance in this file.
+# add new functions to this list only if they are to reside in pg namespace.
+__all__ = [
+ 'siScale', 'siFormat', 'siParse', 'siEval', 'siApply',
+ 'Color', 'mkColor', 'mkBrush', 'mkPen', 'hsvColor',
+ 'CIELabColor', 'colorCIELab', 'colorDistance',
+ 'colorTuple', 'colorStr', 'intColor', 'glColor',
+ 'makeArrowPath', 'eq',
+ 'affineSliceCoords', 'affineSlice',
+ 'interweaveArrays', 'interpolateArray', 'subArray',
+ 'transformToArray', 'transformCoordinates',
+ 'solve3DTransform', 'solveBilinearTransform',
+ 'clip_scalar', 'clip_array', 'rescaleData', 'applyLookupTable',
+ 'makeRGBA', 'makeARGB',
+ # 'try_fastpath_argb', 'ndarray_to_qimage',
+ 'makeQImage',
+ # 'qimage_to_ndarray',
+ 'imageToArray', 'colorToAlpha',
+ 'gaussianFilter', 'downsample', 'arrayToQPath',
+ # 'ndarray_from_qpolygonf', 'create_qpolygonf', 'arrayToQPolygonF',
+ 'isocurve', 'traceImage', 'isosurface',
+ 'invertQTransform',
+ 'pseudoScatter', 'toposort', 'disconnect', 'SignalBlock']
+
+
Colors = {
'b': QtGui.QColor(0,0,255,255),
'g': QtGui.QColor(0,255,0,255),
diff --git a/pyqtgraph/graphicsItems/AxisItem.py b/pyqtgraph/graphicsItems/AxisItem.py
index e4f37fc5..97baebc4 100644
--- a/pyqtgraph/graphicsItems/AxisItem.py
+++ b/pyqtgraph/graphicsItems/AxisItem.py
@@ -1151,7 +1151,7 @@ class AxisItem(GraphicsWidget):
pen, p1, p2 = axisSpec
p.setPen(pen)
p.drawLine(p1, p2)
- p.translate(0.5,0) ## resolves some damn pixel ambiguity
+ # p.translate(0.5,0) ## resolves some damn pixel ambiguity
## draw ticks
for pen, p1, p2 in tickSpecs:
@@ -1184,20 +1184,31 @@ class AxisItem(GraphicsWidget):
else:
self._updateHeight()
- def wheelEvent(self, ev):
+ def wheelEvent(self, event):
lv = self.linkedView()
if lv is None:
return
- if self.orientation in ['left', 'right']:
- lv.wheelEvent(ev, axis=1)
+ # Did the event occur inside the linked ViewBox (and not over the axis iteself)?
+ if lv.sceneBoundingRect().contains(event.scenePos()):
+ # pass event to linked ViewBox without marking it as single axis zoom
+ lv.wheelEvent(event)
else:
- lv.wheelEvent(ev, axis=0)
- ev.accept()
+ # pass event to linked viewbox with appropriate single axis zoom parameter
+ if self.orientation in ['left', 'right']:
+ lv.wheelEvent(event, axis=1)
+ else:
+ lv.wheelEvent(event, axis=0)
+ event.accept()
def mouseDragEvent(self, event):
lv = self.linkedView()
if lv is None:
return
+ # Did the mouse down event occur inside the linked ViewBox (and not the axis)?
+ if lv.sceneBoundingRect().contains(event.buttonDownScenePos()):
+ # pass event to linked ViewBox without marking it as single axis pan
+ return lv.mouseDragEvent(event)
+ # otherwise pass event to linked viewbox with appropriate single axis parameter
if self.orientation in ['left', 'right']:
return lv.mouseDragEvent(event, axis=1)
else:
diff --git a/pyqtgraph/graphicsItems/ColorBarItem.py b/pyqtgraph/graphicsItems/ColorBarItem.py
index 86b7e9c8..f4fe0591 100644
--- a/pyqtgraph/graphicsItems/ColorBarItem.py
+++ b/pyqtgraph/graphicsItems/ColorBarItem.py
@@ -85,7 +85,7 @@ class ColorBarItem(PlotItem):
for key in ['left','right','top','bottom']:
self.showAxis(key)
axis = self.getAxis(key)
- axis.setZValue(1)
+ axis.setZValue(0.5)
# select main axis:
if self.horizontal and key == 'bottom':
self.axis = axis
@@ -93,7 +93,8 @@ class ColorBarItem(PlotItem):
self.axis = axis
self.axis.setWidth(45)
else: # show other axes to create frame
- axis.setStyle( showValues=False, tickLength=0 )
+ axis.setTicks( [] )
+ axis.setStyle( showValues=False )
self.axis.setStyle( showValues=True )
self.axis.unlinkFromView()
self.axis.setRange( self.values[0], self.values[1] )
diff --git a/pyqtgraph/graphicsItems/FillBetweenItem.py b/pyqtgraph/graphicsItems/FillBetweenItem.py
index 02c5feca..8c09f7a0 100644
--- a/pyqtgraph/graphicsItems/FillBetweenItem.py
+++ b/pyqtgraph/graphicsItems/FillBetweenItem.py
@@ -3,6 +3,8 @@ from .. import functions as fn
from .PlotDataItem import PlotDataItem
from .PlotCurveItem import PlotCurveItem
+__all__ = ['FillBetweenItem']
+
class FillBetweenItem(QtGui.QGraphicsPathItem):
"""
GraphicsItem filling the space between two PlotDataItems.
diff --git a/pyqtgraph/graphicsItems/GradientLegend.py b/pyqtgraph/graphicsItems/GradientLegend.py
index 9f98eeec..da6b3cd5 100644
--- a/pyqtgraph/graphicsItems/GradientLegend.py
+++ b/pyqtgraph/graphicsItems/GradientLegend.py
@@ -15,17 +15,25 @@ class GradientLegend(UIGraphicsItem):
self.offset = offset
UIGraphicsItem.__init__(self)
self.setAcceptedMouseButtons(QtCore.Qt.MouseButton.NoButton)
- self.brush = QtGui.QBrush(QtGui.QColor(200,0,0))
+ self.brush = QtGui.QBrush(QtGui.QColor(255,255,255,100)) # background color
self.pen = QtGui.QPen(QtGui.QColor(0,0,0))
+ self.textPen = QtGui.QPen(QtGui.QColor(0,0,0))
self.labels = {'max': 1, 'min': 0}
self.gradient = QtGui.QLinearGradient()
self.gradient.setColorAt(0, QtGui.QColor(0,0,0))
self.gradient.setColorAt(1, QtGui.QColor(255,0,0))
+ self.setZValue(100) # draw on top of ordinary plots
def setGradient(self, g):
self.gradient = g
self.update()
+ def setColorMap(self, colormap):
+ """
+ Set displayed gradient from a :class:`~pyqtgraph.ColorMap` object.
+ """
+ self.gradient = colormap.getGradient()
+
def setIntColorScale(self, minVal, maxVal, *args, **kargs):
colors = [fn.intColor(i, maxVal-minVal, *args, **kargs) for i in range(minVal, maxVal)]
g = QtGui.QLinearGradient()
@@ -45,14 +53,15 @@ class GradientLegend(UIGraphicsItem):
def paint(self, p, opt, widget):
UIGraphicsItem.paint(self, p, opt, widget)
- rect = self.boundingRect() ## Boundaries of visible area in scene coords.
- unit = self.pixelSize() ## Size of one view pixel in scene coords.
- if unit[0] is None:
- return
-
- ## Have to scale painter so that text and gradients are correct size and not upside down
- p.scale(unit[0], -unit[1])
+ view = self.getViewBox()
+ if view is None:
+ return
+ p.save() # save painter state before we change transformation
+ trans = view.sceneTransform()
+ p.setTransform( trans ) # draw in ViewBox pixel coordinates
+ rect = view.rect()
+
## determine max width of all labels
labelWidth = 0
labelHeight = 0
@@ -63,10 +72,10 @@ class GradientLegend(UIGraphicsItem):
textPadding = 2 # in px
- xR = rect.right() / unit[0]
- xL = rect.left() / unit[0]
- yB = -(rect.top() / unit[1])
- yT = -(rect.bottom() / unit[1])
+ xR = rect.right()
+ xL = rect.left()
+ yT = rect.top()
+ yB = rect.bottom()
# coordinates describe edges of text and bar, additional margins will be added for background
if self.offset[0] < 0:
@@ -87,7 +96,7 @@ class GradientLegend(UIGraphicsItem):
## Draw background
p.setPen(self.pen)
- p.setBrush(QtGui.QBrush(QtGui.QColor(255,255,255,100)))
+ p.setBrush(self.brush) # background color
rect = QtCore.QRectF(
QtCore.QPointF(x1 - textPadding, y1-labelHeight/2 - textPadding), # extra left/top padding
QtCore.QPointF(x3 + textPadding, y2+labelHeight/2 + textPadding) # extra bottom/right padding
@@ -95,20 +104,22 @@ class GradientLegend(UIGraphicsItem):
p.drawRect(rect)
## Draw color bar
- self.gradient.setStart(0, y1)
- self.gradient.setFinalStop(0, y2)
+ self.gradient.setStart(0, y2)
+ self.gradient.setFinalStop(0, y1)
p.setBrush(self.gradient)
rect = QtCore.QRectF(
- QtCore.QPointF(x1, y1),
+ QtCore.QPointF(x1, y1),
QtCore.QPointF(x2, y2)
)
p.drawRect(rect)
## draw labels
- p.setPen(QtGui.QPen(QtGui.QColor(0,0,0)))
+ p.setPen(self.textPen)
tx = x2 + 2 * textPadding # margin between bar and text
lh = labelHeight
lw = labelWidth
for k in self.labels:
- y = y1 + self.labels[k] * (y2-y1)
+ y = y2 - self.labels[k] * (y2-y1)
p.drawText(QtCore.QRectF(tx, y - lh/2, lw, lh), QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter, str(k))
+
+ p.restore() # restore QPainter transform to original state
diff --git a/pyqtgraph/graphicsItems/GraphicsItem.py b/pyqtgraph/graphicsItems/GraphicsItem.py
index cc3b06da..8db52fe9 100644
--- a/pyqtgraph/graphicsItems/GraphicsItem.py
+++ b/pyqtgraph/graphicsItems/GraphicsItem.py
@@ -9,6 +9,7 @@ from .. import functions as fn
import weakref
import operator
+__all__ = ['GraphicsItem']
# Recipe from https://docs.python.org/3.8/library/collections.html#collections.OrderedDict
# slightly adapted for Python 3.7 compatibility
diff --git a/pyqtgraph/graphicsItems/GraphicsLayout.py b/pyqtgraph/graphicsItems/GraphicsLayout.py
index a6d8666f..7aa3842e 100644
--- a/pyqtgraph/graphicsItems/GraphicsLayout.py
+++ b/pyqtgraph/graphicsItems/GraphicsLayout.py
@@ -13,11 +13,12 @@ class GraphicsLayout(GraphicsWidget):
This is usually created automatically as part of a :class:`GraphicsWindow ` or :class:`GraphicsLayoutWidget `.
"""
-
def __init__(self, parent=None, border=None):
GraphicsWidget.__init__(self, parent)
if border is True:
border = (100,100,100)
+ elif border is False:
+ border = None
self.border = border
self.layout = QtGui.QGraphicsGridLayout()
self.setLayout(self.layout)
diff --git a/pyqtgraph/graphicsItems/GraphicsWidgetAnchor.py b/pyqtgraph/graphicsItems/GraphicsWidgetAnchor.py
index 251bc0c8..78eed4f2 100644
--- a/pyqtgraph/graphicsItems/GraphicsWidgetAnchor.py
+++ b/pyqtgraph/graphicsItems/GraphicsWidgetAnchor.py
@@ -1,6 +1,7 @@
from ..Qt import QtGui, QtCore
from ..Point import Point
+__all__ = ['GraphicsWidgetAnchor']
class GraphicsWidgetAnchor(object):
"""
diff --git a/pyqtgraph/graphicsItems/HistogramLUTItem.py b/pyqtgraph/graphicsItems/HistogramLUTItem.py
index e71d5008..dbe4f27a 100644
--- a/pyqtgraph/graphicsItems/HistogramLUTItem.py
+++ b/pyqtgraph/graphicsItems/HistogramLUTItem.py
@@ -12,6 +12,7 @@ from .ViewBox import *
from .GradientEditorItem import *
from .LinearRegionItem import *
from .PlotDataItem import *
+from .PlotCurveItem import *
from .AxisItem import *
from .GridItem import *
from ..Point import Point
diff --git a/pyqtgraph/graphicsItems/ImageItem.py b/pyqtgraph/graphicsItems/ImageItem.py
index 01c5a605..abcf320a 100644
--- a/pyqtgraph/graphicsItems/ImageItem.py
+++ b/pyqtgraph/graphicsItems/ImageItem.py
@@ -900,7 +900,7 @@ class ImageItem(GraphicsObject):
step = int(self._xp.ceil((mx - mn) / 500.))
bins = []
if step > 0.0:
- bins = self._xp.arange(mn, mx + 1.01 * step, step, dtype=self._xp.int)
+ bins = self._xp.arange(mn, mx + 1.01 * step, step, dtype=int)
else:
# for float data, let numpy select the bins.
bins = self._xp.linspace(mn, mx, 500)
diff --git a/pyqtgraph/graphicsItems/IsocurveItem.py b/pyqtgraph/graphicsItems/IsocurveItem.py
index 03ebc69f..880cc1db 100644
--- a/pyqtgraph/graphicsItems/IsocurveItem.py
+++ b/pyqtgraph/graphicsItems/IsocurveItem.py
@@ -3,6 +3,7 @@ from .GraphicsObject import *
from .. import functions as fn
from ..Qt import QtGui, QtCore
+__all__ = ['IsocurveItem']
class IsocurveItem(GraphicsObject):
"""
diff --git a/pyqtgraph/graphicsItems/NonUniformImage.py b/pyqtgraph/graphicsItems/NonUniformImage.py
index fc42bf27..9647e37e 100644
--- a/pyqtgraph/graphicsItems/NonUniformImage.py
+++ b/pyqtgraph/graphicsItems/NonUniformImage.py
@@ -6,6 +6,7 @@ from .GraphicsObject import GraphicsObject
from .. import mkBrush, mkPen
from .. import functions as fn
+__all__ = ['NonUniformImage']
class NonUniformImage(GraphicsObject):
"""
diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py
index 5e269bb2..c6413319 100644
--- a/pyqtgraph/graphicsItems/PlotDataItem.py
+++ b/pyqtgraph/graphicsItems/PlotDataItem.py
@@ -11,6 +11,7 @@ from .. import functions as fn
from .. import debug as debug
from .. import getConfigOption
+__all__ = ['PlotDataItem']
class PlotDataItem(GraphicsObject):
"""
diff --git a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py
index 522cee03..0db2abd6 100644
--- a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py
+++ b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py
@@ -14,9 +14,11 @@ from ..InfiniteLine import InfiniteLine
from ..LabelItem import LabelItem
from ..LegendItem import LegendItem
from ..PlotDataItem import PlotDataItem
+from ..PlotCurveItem import PlotCurveItem
+from ..ScatterPlotItem import ScatterPlotItem
from ..ViewBox import ViewBox
from ... import functions as fn
-from ... import icons, PlotCurveItem, ScatterPlotItem
+from ... import icons
from ...Qt import QtGui, QtCore, QT_LIB
from ...WidgetGroup import WidgetGroup
from ...python2_3 import basestring
diff --git a/pyqtgraph/graphicsItems/PlotItem/__init__.py b/pyqtgraph/graphicsItems/PlotItem/__init__.py
index d797978c..5cdfea6e 100644
--- a/pyqtgraph/graphicsItems/PlotItem/__init__.py
+++ b/pyqtgraph/graphicsItems/PlotItem/__init__.py
@@ -1 +1,3 @@
from .PlotItem import PlotItem
+
+__all__ = ['PlotItem']
diff --git a/pyqtgraph/graphicsItems/ROI.py b/pyqtgraph/graphicsItems/ROI.py
index f58042f0..66b09d39 100644
--- a/pyqtgraph/graphicsItems/ROI.py
+++ b/pyqtgraph/graphicsItems/ROI.py
@@ -1676,8 +1676,8 @@ class LineROI(ROI):
pos2 = Point(pos2)
d = pos2-pos1
l = d.length()
- ra = Point(1, 0).angle(d, units="radians")
- c = Point(-width/2. * sin(ra), -width/2. * cos(ra))
+ ra = d.angle(Point(1, 0), units="radians")
+ c = Point(width/2. * sin(ra), -width/2. * cos(ra))
pos1 = pos1 + c
ROI.__init__(self, pos1, size=Point(l, width), angle=degrees(ra), **args)
diff --git a/pyqtgraph/graphicsItems/TargetItem.py b/pyqtgraph/graphicsItems/TargetItem.py
index ca8cf44d..9724e0c0 100644
--- a/pyqtgraph/graphicsItems/TargetItem.py
+++ b/pyqtgraph/graphicsItems/TargetItem.py
@@ -10,6 +10,7 @@ from .ViewBox import ViewBox
import string
import warnings
+__all__ = ['TargetItem', 'TargetLabel']
class TargetItem(UIGraphicsItem):
"""Draws a draggable target symbol (circle plus crosshair).
diff --git a/pyqtgraph/graphicsItems/TextItem.py b/pyqtgraph/graphicsItems/TextItem.py
index 9b5dff8f..d71f9f34 100644
--- a/pyqtgraph/graphicsItems/TextItem.py
+++ b/pyqtgraph/graphicsItems/TextItem.py
@@ -4,6 +4,7 @@ from ..Point import Point
from .. import functions as fn
from .GraphicsObject import GraphicsObject
+__all__ = ['TextItem']
class TextItem(GraphicsObject):
"""
diff --git a/pyqtgraph/graphicsItems/ViewBox/__init__.py b/pyqtgraph/graphicsItems/ViewBox/__init__.py
index 685a314d..07b90fb1 100644
--- a/pyqtgraph/graphicsItems/ViewBox/__init__.py
+++ b/pyqtgraph/graphicsItems/ViewBox/__init__.py
@@ -1 +1,3 @@
from .ViewBox import ViewBox
+
+__all__ = ['ViewBox']
diff --git a/pyqtgraph/graphicsWindows.py b/pyqtgraph/graphicsWindows.py
index 02206d35..dd42880b 100644
--- a/pyqtgraph/graphicsWindows.py
+++ b/pyqtgraph/graphicsWindows.py
@@ -6,6 +6,8 @@ it is possible to place any widget into its own window by simply calling its
show() method.
"""
+__all__ = ['GraphicsWindow', 'TabWindow', 'PlotWindow', 'ImageWindow']
+
from .Qt import QtCore, QtGui, mkQApp
from .widgets.PlotWidget import *
from .imageview import *
diff --git a/pyqtgraph/imageview/__init__.py b/pyqtgraph/imageview/__init__.py
index 0060e823..47781939 100644
--- a/pyqtgraph/imageview/__init__.py
+++ b/pyqtgraph/imageview/__init__.py
@@ -4,3 +4,5 @@ Includes ROI plotting over time and image normalization.
"""
from .ImageView import ImageView
+
+__all__ = ['ImageView']
\ No newline at end of file
diff --git a/pyqtgraph/metaarray/MetaArray.py b/pyqtgraph/metaarray/MetaArray.py
index 92930cae..f4eac1da 100644
--- a/pyqtgraph/metaarray/MetaArray.py
+++ b/pyqtgraph/metaarray/MetaArray.py
@@ -132,6 +132,10 @@ class MetaArray(object):
def __init__(self, data=None, info=None, dtype=None, file=None, copy=False, **kwargs):
object.__init__(self)
+ warnings.warn(
+ 'MetaArray is deprecated and will be removed in 0.14.',
+ DeprecationWarning, stacklevel=2
+ )
self._isHDF = False
if file is not None:
diff --git a/pyqtgraph/multiprocess/processes.py b/pyqtgraph/multiprocess/processes.py
index 6e9da206..1d213582 100644
--- a/pyqtgraph/multiprocess/processes.py
+++ b/pyqtgraph/multiprocess/processes.py
@@ -122,13 +122,24 @@ class Process(RemoteEventHandler):
targetStr = pickle.dumps(target) ## double-pickle target so that child has a chance to
## set its sys.path properly before unpickling the target
pid = os.getpid() # we must send pid to child because windows does not have getppid
-
+
+ # When running in a venv on Windows platform, since Python >= 3.7.3, the launched
+ # subprocess is a grandchild instead of a child, leading to self.proc.pid not being
+ # the pid of the launched subprocess.
+ # https://bugs.python.org/issue38905
+ #
+ # As a workaround, when we detect such a situation, we perform exchange of pids via
+ # the multiprocessing connection. Technically, only the launched subprocess needs to
+ # send its pid back. Practically, we hijack the ppid parameter to indicate to the
+ # subprocess that pid exchange is needed.
+ xchg_pids = sys.platform == 'win32' and os.getenv('VIRTUAL_ENV') is not None
+
## Send everything the remote process needs to start correctly
data = dict(
name=name+'_child',
port=port,
authkey=authkey,
- ppid=pid,
+ ppid=pid if not xchg_pids else None,
targetStr=targetStr,
path=sysPath,
qt_lib=QT_LIB,
@@ -150,7 +161,14 @@ class Process(RemoteEventHandler):
else:
raise
- RemoteEventHandler.__init__(self, conn, name+'_parent', pid=self.proc.pid, debug=self.debug)
+ child_pid = self.proc.pid
+ if xchg_pids:
+ # corresponding code is in:
+ # remoteproxy.py::RemoteEventHandler.__init__()
+ conn.send(pid)
+ child_pid = conn.recv()
+
+ RemoteEventHandler.__init__(self, conn, name+'_parent', pid=child_pid, debug=self.debug)
self.debugMsg('Connected to child process.')
atexit.register(self.join)
diff --git a/pyqtgraph/multiprocess/remoteproxy.py b/pyqtgraph/multiprocess/remoteproxy.py
index 8509cc57..7f6e4750 100644
--- a/pyqtgraph/multiprocess/remoteproxy.py
+++ b/pyqtgraph/multiprocess/remoteproxy.py
@@ -86,6 +86,13 @@ class RemoteEventHandler(object):
# Mutexes to help prevent issues when multiple threads access the same RemoteEventHandler
self.processLock = threading.RLock()
self.sendLock = threading.RLock()
+
+ # parent sent us None as its pid, wants us to exchange pids
+ # corresponding code is in:
+ # processes.py::Process.__init__()
+ if pid is None:
+ connection.send(os.getpid())
+ pid = connection.recv()
RemoteEventHandler.handlers[pid] = self ## register this handler as the one communicating with pid
diff --git a/pyqtgraph/opengl/GLGraphicsItem.py b/pyqtgraph/opengl/GLGraphicsItem.py
index a2c2708a..66a21f32 100644
--- a/pyqtgraph/opengl/GLGraphicsItem.py
+++ b/pyqtgraph/opengl/GLGraphicsItem.py
@@ -1,8 +1,7 @@
from OpenGL.GL import *
from OpenGL import GL
-from ..Qt import QtGui, QtCore
+from ..Qt import QtCore
from .. import Transform3D
-from ..python2_3 import basestring
GLOptions = {
@@ -42,6 +41,7 @@ class GLGraphicsItem(QtCore.QObject):
self.__children = set()
self.__transform = Transform3D()
self.__visible = True
+ self.__initialized = False
self.setParentItem(parentItem)
self.setDepthValue(0)
self.__glOpts = {}
@@ -91,7 +91,7 @@ class GLGraphicsItem(QtCore.QObject):
"""
- if isinstance(opts, basestring):
+ if isinstance(opts, str):
opts = GLOptions[opts]
self.__glOpts = opts.copy()
self.update()
@@ -228,6 +228,12 @@ class GLGraphicsItem(QtCore.QObject):
view, as it may be obscured or outside of the current view area."""
return self.__visible
+ def initialize(self):
+ self.initializeGL()
+ self.__initialized = True
+
+ def isInitialized(self):
+ return self.__initialized
def initializeGL(self):
"""
@@ -245,7 +251,7 @@ class GLGraphicsItem(QtCore.QObject):
for k,v in self.__glOpts.items():
if v is None:
continue
- if isinstance(k, basestring):
+ if isinstance(k, str):
func = getattr(GL, k)
func(*v)
else:
diff --git a/pyqtgraph/opengl/GLViewWidget.py b/pyqtgraph/opengl/GLViewWidget.py
index 8896bdc0..7096b7b4 100644
--- a/pyqtgraph/opengl/GLViewWidget.py
+++ b/pyqtgraph/opengl/GLViewWidget.py
@@ -1,4 +1,4 @@
-from ..Qt import QtCore, QtGui, QtWidgets, QT_LIB
+from ..Qt import QtCore, QtGui, QtWidgets
from OpenGL.GL import *
import OpenGL.GL.framebufferobjects as glfbo
import numpy as np
@@ -8,7 +8,6 @@ import warnings
from math import cos, sin, tan, radians
##Vector = QtGui.QVector3D
-ShareWidget = None
class GLViewWidget(QtWidgets.QOpenGLWidget):
@@ -99,10 +98,11 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
def addItem(self, item):
self.items.append(item)
- if hasattr(item, 'initializeGL'):
+
+ if self.isValid():
self.makeCurrent()
try:
- item.initializeGL()
+ item.initialize()
except:
self.checkOpenGLVersion('Error while adding item %s to GLViewWidget.' % str(item))
@@ -128,7 +128,12 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
self.update()
def initializeGL(self):
- self.resizeGL(self.width(), self.height())
+ """
+ Initialize items that were not initialized during addItem().
+ """
+ for item in self.items:
+ if not item.isInitialized():
+ item.initialize()
def setBackgroundColor(self, *args, **kwds):
"""
@@ -430,10 +435,11 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
return xDist / self.width()
def mousePressEvent(self, ev):
- self.mousePos = ev.localPos()
+ lpos = ev.position() if hasattr(ev, 'position') else ev.localPos()
+ self.mousePos = lpos
def mouseMoveEvent(self, ev):
- lpos = ev.localPos()
+ lpos = ev.position() if hasattr(ev, 'position') else ev.localPos()
diff = lpos - self.mousePos
self.mousePos = lpos
@@ -462,13 +468,9 @@ class GLViewWidget(QtWidgets.QOpenGLWidget):
#self.swapBuffers()
def wheelEvent(self, ev):
- delta = 0
- if QT_LIB in ['PyQt4', 'PySide']:
- delta = ev.delta()
- else:
- delta = ev.angleDelta().x()
- if delta == 0:
- delta = ev.angleDelta().y()
+ delta = ev.angleDelta().x()
+ if delta == 0:
+ delta = ev.angleDelta().y()
if (ev.modifiers() & QtCore.Qt.KeyboardModifier.ControlModifier):
self.opts['fov'] *= 0.999**delta
else:
diff --git a/pyqtgraph/opengl/items/GLLinePlotItem.py b/pyqtgraph/opengl/items/GLLinePlotItem.py
index 2daf78ba..dcc98cc0 100644
--- a/pyqtgraph/opengl/items/GLLinePlotItem.py
+++ b/pyqtgraph/opengl/items/GLLinePlotItem.py
@@ -54,9 +54,6 @@ class GLLinePlotItem(GLGraphicsItem):
#self.vbo.pop(arg, None)
self.update()
- def initializeGL(self):
- pass
-
def paint(self):
if self.pos is None:
return
diff --git a/pyqtgraph/ordereddict.py b/pyqtgraph/ordereddict.py
index a562c8b8..b587437b 100644
--- a/pyqtgraph/ordereddict.py
+++ b/pyqtgraph/ordereddict.py
@@ -1,137 +1,12 @@
-# Copyright (c) 2009 Raymond Hettinger
-#
-# 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:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# 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.
-
+import collections
import warnings
-warnings.warn(
- "OrderedDict is in the standard library for supported versions of Python. Will be removed in 0.13",
- DeprecationWarning, stacklevel=2
-)
-import sys
-if sys.version[0] > '2':
- from collections import OrderedDict
-else:
- from UserDict import DictMixin
- class OrderedDict(dict, DictMixin):
-
- def __init__(self, *args, **kwds):
- if len(args) > 1:
- raise TypeError('expected at most 1 arguments, got %d' % len(args))
- try:
- self.__end
- except AttributeError:
- self.clear()
- self.update(*args, **kwds)
-
- def clear(self):
- self.__end = end = []
- end += [None, end, end] # sentinel node for doubly linked list
- self.__map = {} # key --> [key, prev, next]
- dict.clear(self)
-
- def __setitem__(self, key, value):
- if key not in self:
- end = self.__end
- curr = end[1]
- curr[2] = end[1] = self.__map[key] = [key, curr, end]
- dict.__setitem__(self, key, value)
-
- def __delitem__(self, key):
- dict.__delitem__(self, key)
- key, prev, next = self.__map.pop(key)
- prev[2] = next
- next[1] = prev
-
- def __iter__(self):
- end = self.__end
- curr = end[2]
- while curr is not end:
- yield curr[0]
- curr = curr[2]
-
- def __reversed__(self):
- end = self.__end
- curr = end[1]
- while curr is not end:
- yield curr[0]
- curr = curr[1]
-
- def popitem(self, last=True):
- if not self:
- raise KeyError('dictionary is empty')
- if last:
- key = reversed(self).next()
- else:
- key = iter(self).next()
- value = self.pop(key)
- return key, value
-
- def __reduce__(self):
- items = [[k, self[k]] for k in self]
- tmp = self.__map, self.__end
- del self.__map, self.__end
- inst_dict = vars(self).copy()
- self.__map, self.__end = tmp
- if inst_dict:
- return (self.__class__, (items,), inst_dict)
- return self.__class__, (items,)
-
- def keys(self):
- return list(self)
-
- setdefault = DictMixin.setdefault
- update = DictMixin.update
- pop = DictMixin.pop
- values = DictMixin.values
- items = DictMixin.items
- iterkeys = DictMixin.iterkeys
- itervalues = DictMixin.itervalues
- iteritems = DictMixin.iteritems
-
- def __repr__(self):
- if not self:
- return '%s()' % (self.__class__.__name__,)
- return '%s(%r)' % (self.__class__.__name__, self.items())
-
- def copy(self):
- return self.__class__(self)
-
- @classmethod
- def fromkeys(cls, iterable, value=None):
- d = cls()
- for key in iterable:
- d[key] = value
- return d
-
- def __eq__(self, other):
- if isinstance(other, OrderedDict):
- if len(self) != len(other):
- return False
- for p, q in zip(self.items(), other.items()):
- if p != q:
- return False
- return True
- return dict.__eq__(self, other)
-
- def __ne__(self, other):
- return not self == other
+class OrderedDict(collections.OrderedDict):
+ def __init__(self, *args, **kwds):
+ warnings.warn(
+ "OrderedDict is in the standard library for supported versions of Python. Will be removed in 0.13",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ super().__init__(*args, **kwds)
\ No newline at end of file
diff --git a/pyqtgraph/widgets/ComboBox.py b/pyqtgraph/widgets/ComboBox.py
index 5c977832..eb04dafc 100644
--- a/pyqtgraph/widgets/ComboBox.py
+++ b/pyqtgraph/widgets/ComboBox.py
@@ -4,6 +4,7 @@ from ..SignalProxy import SignalProxy
from collections import OrderedDict
from ..python2_3 import asUnicode, basestring
+__all__ = ['ComboBox']
class ComboBox(QtGui.QComboBox):
"""Extends QComboBox to add extra functionality.
diff --git a/pyqtgraph/widgets/GraphicsView.py b/pyqtgraph/widgets/GraphicsView.py
index 036f2f05..ed73cca5 100644
--- a/pyqtgraph/widgets/GraphicsView.py
+++ b/pyqtgraph/widgets/GraphicsView.py
@@ -317,13 +317,9 @@ class GraphicsView(QtGui.QGraphicsView):
super().wheelEvent(ev)
if not self.mouseEnabled:
return
- delta = 0
- if QT_LIB in ['PyQt4', 'PySide']:
- delta = ev.delta()
- else:
- delta = ev.angleDelta().x()
- if delta == 0:
- delta = ev.angleDelta().y()
+ delta = ev.angleDelta().x()
+ if delta == 0:
+ delta = ev.angleDelta().y()
sc = 1.001 ** delta
#self.scale *= sc
diff --git a/pyqtgraph/widgets/GroupBox.py b/pyqtgraph/widgets/GroupBox.py
index 53b07b41..233e3ae3 100644
--- a/pyqtgraph/widgets/GroupBox.py
+++ b/pyqtgraph/widgets/GroupBox.py
@@ -2,6 +2,7 @@ from ..Qt import QtGui, QtCore
from .PathButton import PathButton
from ..python2_3 import basestring
+__all__ = ['GroupBox']
class GroupBox(QtGui.QGroupBox):
"""Subclass of QGroupBox that implements collapse handle.
diff --git a/pyqtgraph/widgets/MatplotlibWidget.py b/pyqtgraph/widgets/MatplotlibWidget.py
index b3868e8f..2c305397 100644
--- a/pyqtgraph/widgets/MatplotlibWidget.py
+++ b/pyqtgraph/widgets/MatplotlibWidget.py
@@ -6,6 +6,8 @@ from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as Navigatio
from matplotlib.figure import Figure
+__all__ = ['MatplotlibWidget']
+
class MatplotlibWidget(QtGui.QWidget):
"""
Implements a Matplotlib figure inside a QWidget.
diff --git a/pyqtgraph/widgets/ProgressDialog.py b/pyqtgraph/widgets/ProgressDialog.py
index a4c9b58c..2af135d2 100644
--- a/pyqtgraph/widgets/ProgressDialog.py
+++ b/pyqtgraph/widgets/ProgressDialog.py
@@ -73,7 +73,7 @@ class ProgressDialog(QtGui.QProgressDialog):
else:
self.setMinimumDuration(wait)
- self.setWindowModality(QtCore.Qt.WindowType.WindowModality.WindowModal)
+ self.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
self.setValue(self.minimum())
if noCancel:
self.setCancelButton(None)
@@ -206,7 +206,7 @@ class ProgressDialog(QtGui.QProgressDialog):
# Qt docs say this should happen automatically, but that doesn't seem
# to be the case.
- if self.windowModality() == QtCore.Qt.WindowType.WindowModality.WindowModal:
+ if self.windowModality() == QtCore.Qt.WindowModality.WindowModal:
now = ptime.time()
if self._lastProcessEvents is None or (now - self._lastProcessEvents) > 0.2:
QtGui.QApplication.processEvents()
diff --git a/pyqtgraph/widgets/RawImageWidget.py b/pyqtgraph/widgets/RawImageWidget.py
index 1b404b72..2a12127f 100644
--- a/pyqtgraph/widgets/RawImageWidget.py
+++ b/pyqtgraph/widgets/RawImageWidget.py
@@ -18,6 +18,7 @@ except (ImportError, AttributeError):
# AttributeError upon import
HAVE_OPENGL = False
+__all__ = ['RawImageWidget']
class RawImageWidget(QtGui.QWidget):
"""
@@ -78,6 +79,7 @@ class RawImageWidget(QtGui.QWidget):
if HAVE_OPENGL:
+ __all__.append('RawImageGLWidget')
class RawImageGLWidget(QOpenGLWidget):
"""
Similar to RawImageWidget, but uses a GL widget to do all drawing.
diff --git a/tests/exporters/test_csv.py b/tests/exporters/test_csv.py
index bcb7fcaf..c66d1b52 100644
--- a/tests/exporters/test_csv.py
+++ b/tests/exporters/test_csv.py
@@ -2,6 +2,7 @@
CSV export test
"""
from __future__ import division, print_function, absolute_import
+import numpy as np
import pyqtgraph as pg
import csv
import tempfile
@@ -19,11 +20,11 @@ def test_CSVExporter():
plt.plot(y=y1, name='myPlot')
y2 = [3,4,6,1,2,4,2,3,5,3,5,1,3]
- x2 = pg.np.linspace(0, 1.0, len(y2))
+ x2 = np.linspace(0, 1.0, len(y2))
plt.plot(x=x2, y=y2)
y3 = [1,5,2,3,4,6,1,2,4,2,3,5,3]
- x3 = pg.np.linspace(0, 1.0, len(y3)+1)
+ x3 = np.linspace(0, 1.0, len(y3)+1)
plt.plot(x=x3, y=y3, stepMode="center")
ex = pg.exporters.CSVExporter(plt.plotItem)
diff --git a/tests/exporters/test_matplotlib.py b/tests/exporters/test_matplotlib.py
index 3e3e98dd..1e4468b7 100644
--- a/tests/exporters/test_matplotlib.py
+++ b/tests/exporters/test_matplotlib.py
@@ -7,7 +7,7 @@ pytest.importorskip("matplotlib")
app = pg.mkQApp()
skip_qt6 = pytest.mark.skipif(
- pg.QT_LIB in ["PySide6", "PyQt6"],
+ pg.Qt.QT_LIB in ["PySide6", "PyQt6"],
reason= (
"Matplotlib has no Qt6 support yet, "
"see https://github.com/matplotlib/matplotlib/pull/19255"
diff --git a/tests/graphicsItems/test_ImageItem.py b/tests/graphicsItems/test_ImageItem.py
index 99d70449..41802c4d 100644
--- a/tests/graphicsItems/test_ImageItem.py
+++ b/tests/graphicsItems/test_ImageItem.py
@@ -229,7 +229,7 @@ def test_setRect():
def test_dividebyzero():
- im = pg.image(pg.np.random.normal(size=(100,100)))
+ im = pg.image(np.random.normal(size=(100,100)))
im.imageItem.setAutoDownsample(True)
im.view.setRange(xRange=[-5+25, 5e+25],yRange=[-5e+25, 5e+25])
app.processEvents()
diff --git a/tests/graphicsItems/test_ROI.py b/tests/graphicsItems/test_ROI.py
index 68a59544..b2db38fd 100644
--- a/tests/graphicsItems/test_ROI.py
+++ b/tests/graphicsItems/test_ROI.py
@@ -6,6 +6,7 @@ import platform
from pyqtgraph.Qt import QtCore, QtGui, QtTest
from tests.image_testing import assertImageApproved
from tests.ui_testing import mouseMove, mouseDrag, mouseClick, resizeWindow
+import math
app = pg.mkQApp()
pg.setConfigOption("mouseRateLimit", 0)
@@ -251,4 +252,22 @@ def test_PolyLineROI():
assert len(r.getState()['points']) == 3
plt.hide()
-
+
+
+@pytest.mark.parametrize("p1,p2", [
+ ((1, 1), (2, 5)),
+ ((0.1, 0.1), (-1, 5)),
+ ((3, -1), (5, -6)),
+ ((-2, 1), (-4, -8)),
+])
+def test_LineROI_coords(p1, p2):
+ pw = pg.plot()
+
+ lineroi = pg.LineROI(p1, p2, width=0.5, pen="r")
+ pw.addItem(lineroi)
+
+ # first two handles are the scale-rotate handles positioned by pos1, pos2
+ for expected, (name, scenepos) in zip([p1, p2], lineroi.getSceneHandlePositions()):
+ got = lineroi.mapSceneToParent(scenepos)
+ assert math.isclose(got.x(), expected[0])
+ assert math.isclose(got.y(), expected[1])
diff --git a/tests/test_colormap.py b/tests/test_colormap.py
new file mode 100644
index 00000000..35e62d34
--- /dev/null
+++ b/tests/test_colormap.py
@@ -0,0 +1,75 @@
+import pytest
+import pyqtgraph as pg
+from pyqtgraph.Qt import QtGui
+
+pos = [0.0, 0.5, 1.0]
+qcols = [
+ QtGui.QColor('#FF0000'),
+ QtGui.QColor('#00FF00'),
+ QtGui.QColor('#0000FF')
+]
+float_tuples = [
+ (1.0, 0.0, 0.0, 1.0),
+ (0.0, 1.0, 0.0, 1.0),
+ (0.0, 0.0, 1.0, 1.0)
+]
+int_tuples = [
+ (255, 0, 0,255),
+ ( 0,255, 0,255),
+ ( 0, 0,255,255)
+]
+
+@pytest.mark.parametrize("color_list", (qcols, int_tuples))
+def test_ColorMap_getStops(color_list):
+ cm = pg.ColorMap(pos, color_list, name='test')
+ # default is byte format:
+ stops, colors = cm.getStops()
+ assert (stops == pos).all()
+ assert (colors == int_tuples).all()
+
+ # manual byte format:
+ stops, colors = cm.getStops(pg.ColorMap.BYTE)
+ assert (stops == pos).all()
+ assert (colors == int_tuples).all()
+
+ stops, colors = cm.getStops('bYTe')
+ assert (stops == pos).all()
+ assert (colors == int_tuples).all()
+
+ # manual float format:
+ stops, colors = cm.getStops(pg.ColorMap.FLOAT)
+ assert (stops == pos).all()
+ assert (colors == float_tuples).all()
+
+ stops, colors = cm.getStops('floaT')
+ assert (stops == pos).all()
+ assert (colors == float_tuples).all()
+
+ # manual QColor format:
+ stops, colors = cm.getStops(pg.ColorMap.QCOLOR)
+ assert (stops == pos).all()
+ for actual, good in zip(colors, qcols):
+ assert actual.getRgbF() == good.getRgbF()
+
+ stops, colors = cm.getStops('qColor')
+ assert (stops == pos).all()
+ for actual, good in zip(colors, qcols):
+ assert actual.getRgbF() == good.getRgbF()
+
+
+@pytest.mark.parametrize("color_list", (qcols, int_tuples))
+def test_ColorMap_getColors(color_list):
+ cm = pg.ColorMap(pos, color_list, name='from QColors')
+
+ colors = cm.getColors()
+ assert (colors == int_tuples).all()
+
+ colors = cm.getColors('byte')
+ assert (colors == int_tuples).all()
+
+ colors = cm.getColors('float')
+ assert (colors == float_tuples).all()
+
+ colors = cm.getColors('qcolor')
+ for actual, good in zip(colors, qcols):
+ assert actual.getRgbF() == good.getRgbF()
diff --git a/tests/test_ref_cycles.py b/tests/test_ref_cycles.py
index 986a2a14..8d84d772 100644
--- a/tests/test_ref_cycles.py
+++ b/tests/test_ref_cycles.py
@@ -37,7 +37,7 @@ def test_PlotWidget():
with warnings.catch_warnings():
warnings.simplefilter("ignore")
w = pg.PlotWidget(*args, **kwds)
- data = pg.np.array([1,5,2,4,3])
+ data = np.array([1,5,2,4,3])
c = w.plot(data, name='stuff')
w.addLegend()
diff --git a/tests/widgets/test_progressdialog.py b/tests/widgets/test_progressdialog.py
new file mode 100644
index 00000000..6e7dfb79
--- /dev/null
+++ b/tests/widgets/test_progressdialog.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+from pyqtgraph import mkQApp, ProgressDialog
+
+mkQApp()
+
+
+def test_progress_dialog():
+ with ProgressDialog("test", 0, 1) as dlg:
+ dlg += 1