Compare commits

...

403 Commits

Author SHA1 Message Date
Kyle Sunden 6fa4a0a3eb
Merge pull request #2012 from j9ac9k/prep-0.12.3-release
Prep for 0.12.3 Release
2021-10-10 22:01:10 -05:00
Kyle Sunden 0f3804e32c
Merge pull request #2013 from ksunden/rel_action
Add python publishing workflow
2021-10-10 22:00:18 -05:00
Ogi Moore af8c766de3 Update changelog 2021-10-09 15:28:28 -07:00
Ogi Moore 58325ee91b
Merge pull request #2014 from j9ac9k/fix-some-imports
Fix Some Import Issues
2021-10-09 15:26:44 -07:00
Ogi Moore 936108ec60 Import Dock class not module 2021-10-09 15:06:51 -07:00
Ogi Moore 9b67e51230 Switch to relative imports for some parameterTypes 2021-10-09 15:06:51 -07:00
Ogi Moore db74522003 Have parameter types imports use non __init__
When using isort, the order of parametertree/__init__.py imports broke many
of the parameter-types imports.  This commit modifies the import statement to
not use the imports from __init__.py but import the respective classes from the
the non-__init__ modules
2021-10-09 15:06:51 -07:00
Kyle Sunden 9ae38e6d21
Update .github/workflows/python-publish.yml 2021-10-09 13:04:01 -05:00
Kyle Sunden 34c6981b0f Update version number in __init__ 2021-10-09 00:37:49 -05:00
Ogi Moore b8ca314597 Update changelog for 0.12.3 2021-10-08 22:27:35 -07:00
Kyle Sunden ae484ba411 Add python publishing workflow 2021-10-09 00:26:29 -05:00
Ogi Moore fd6985565c
Merge pull request #2009 from pijyoi/fix_imageview_roi
unhide ImageView roi curves
2021-10-08 21:05:08 -07:00
KIU Shueng Chuan 2da769d6a5 unhide ImageView roi curves 2021-10-08 22:01:41 +08:00
Ogi Moore fb809e5260
Merge pull request #2007 from pijyoi/skip_missing_scipy
skip tests using scipy if not installed
2021-10-07 21:22:24 -07:00
KIU Shueng Chuan 4aeb0ce1dd skip tests using scipy if not installed 2021-10-08 11:52:52 +08:00
Martin Chase a6bb2c6edd
Allow ThreadTrace to save to a file (#1998)
* allow ThreadTrace to save to a file

* make sure we close our output file

* fix the egregious errors in the file
 - no mutable default args
 - import things before using them
 - variable named obj did not exist, but try/except ignored it

* if it's dumb, and it works, it's not dumb

* linux requires a flush; remove commented code

* always close the file handle, even if its stdout

* it may work for us, but just in case, protect with finally

* turns out: lots of things like to use stdout!

Co-authored-by: Luke Campagnola <lukec@alleninstitute.org>
Co-authored-by: Ogi Moore <ognyan.moore@gmail.com>
2021-10-07 12:25:38 -07:00
Ogi Moore e8b77a11e5
Merge pull request #2006 from j9ac9k/revise-reload-skip-condition
Remove python 3.10 skip condition for test_reload
2021-10-06 23:43:05 -07:00
Ogi Moore e04ecdf554 Remove python 3.10 skip condition for test_reload 2021-10-06 23:01:40 -07:00
Nils Nemitz 0cc3580687
Traditional log10 mode for PlotDataItem (by adding "mapped data" stage) (#1992)
* make PlotDataItem aware of mapped data

* inf suppression, metadata storage and refactor of data structures

* cleanup, test, and documentation pass

* re-added prepareForPaint, added PlotDataset to sphinx index

* strip more print statements

* indicate (internal) PlotDataset documentation as orphaned to avoid sphinx error

* Do not export PlotDataset

* replacement example

* example comments
2021-10-06 22:40:38 -07:00
Ogi Moore bc542ae1c4
Merge pull request #2003 from j9ac9k/fix-py310-drawText-call
Fix Python 3.10 GLGradientLegendItem call to QPainter.drawText
2021-10-06 06:35:12 -07:00
Ogi Moore 5917e5e666 QPainter.drawText needs QPointF not x, y 2021-10-05 20:47:15 -07:00
Ogi Moore 95c302fd0d
Merge pull request #1999 from pijyoi/mpl_qt6
Re-enable Matplotlib Exporter Test for Qt6
2021-09-29 09:54:37 -07:00
KIU Shueng Chuan 4b59734629 enable matplotlib exporter test for qt6 2021-09-24 19:47:20 +08:00
ntjess 8d3e6cbd22
Better parameter tree testing (#1953)
* Allows values to be numpy arrays

* Bugfix: Slider now works when limits didn't change during `optsChanged`

* Improved testing + layout of param tree example

* Also fix numpy-like values in list `setValue`

* use proper hex formatting for  value

* Fix code warnings

* Avoids use of configfile in parametertree

* Avoid shadowing variable names

* Add explanatory comment to `makeAllParamTypes`

* Allow string options to be 'unset' in file, etc. parameters example

* Bugfix: unintunitive option unsetting for file window title

* don't use lambda in signal connect

* Remove unused import
2021-09-23 21:06:00 -07:00
Ogi Moore e9d3b6ddd2
Merge pull request #1995 from Achilles1515/colorbutton-padding
Change hardcoded padding into initialization parameter
2021-09-23 17:19:08 -07:00
Dane Owens 1132c138a4 Change hardcoded padding into initialization parameter 2021-09-17 09:51:26 -04:00
Ogi Moore b075035b0d
Merge pull request #1987 from jkotan/regiontypo
Issue 1986: fix for autoLevel of RGB histograms
2021-09-08 11:22:37 -07:00
Jan Kotanski 4334cd14de fix for autoLevel of RGB histograms 2021-09-08 09:20:12 +02:00
Ogi Moore 126b7e0925
Merge pull request #1985 from pijyoi/workaround_float_lut
delegate float luts to makeARGB()
2021-09-07 21:48:15 -07:00
magnium 6f4b6b1b88
Fix ImageView levelMode (#1974)
* fixes #1769

* Automatically set image to ImageView if imageItem is provided.
Added a test for correct initialization of ImageView with imageItem and levelMode.
2021-09-07 21:27:26 -07:00
ntjess babd037cf7
Adds checklist parameter (#1952)
* Alphabetize parameter registration

* Implements a checklist parameter

* Several checklist updates
- Correct indentation
- Allow dict-like setting + non-string values
- Fix several bugs associated with 'exclusive' behavior

* Add 'checklist' to param tree example

* Add documentation

* Removes unneeded code

* Forgot to rebuilt RST doc

* `exclusive` checklist uses radio buttons

* better checklist change logic

Co-authored-by: Ogi Moore <ognyan.moore@gmail.com>
2021-09-07 21:25:17 -07:00
Petras Jokubauskas 745b04baa5
Fix: updateDecimate should not unhide intentionaly hidden curves (#1973)
* Update PlotItem.py

make update decimate to not unhide curves when items added/removed,
while preserving the Max Traces well behaviour

* Update PlotItem.py

fix typo

* Update PlotItem.py

fix: typo with self as argument

* give better name for the function which handles MaxTraces checkstate change

rename it to _handle_max_traces_toggle

* add doc string to updateDecimation

* add test for PlotItem for external curve visibility control

check if hidden curve would stay hidden when adding or removing other items.

* remove additional empty line between methods
2021-09-07 21:19:22 -07:00
Ogi Moore 2a66460afc
Merge pull request #1954 from ntjess/deprecate-values-opt
Deprecate `values` opt for list parameter
2021-09-07 20:57:27 -07:00
Ogi Moore 446a2c324c
Merge pull request #1721 from j9ac9k/test-pr807
Implement a GLGraphItem according to #807
2021-09-07 20:47:19 -07:00
Ogi Moore d54da71138 Add docs page 2021-09-07 20:28:57 -07:00
Ogi Moore 13ab4de209 Add really basic GLGraphItem example 2021-09-07 20:28:57 -07:00
Ogi Moore c3dba791d1 Make equivalent to #807 2021-09-07 20:28:57 -07:00
KIU Shueng Chuan b5475cad6b warn about usage of non-uint8 LUTs 2021-09-08 09:52:46 +08:00
KIU Shueng Chuan 6763b14fb9 delegate float luts to makeARGB() 2021-09-07 00:04:42 +08:00
Ogi Moore 98d7bcf560
Merge pull request #1969 from pijyoi/fix_clip_nop 2021-08-17 07:29:10 -07:00
KIU Shueng Chuan 6f1ea29fe4 bugfix: result of clip_array() not assigned 2021-08-17 22:14:13 +08:00
Ogi Moore 175f84ecbc
Merge pull request #1968 from pijyoi/imageview_scale 2021-08-14 07:37:51 -07:00
KIU Shueng Chuan 11b4a1bb47 fix: ImageView calling deprecated QGraphicsItem.scale() 2021-08-14 14:05:18 +08:00
Ogi Moore e752336b55
Merge pull request #1965 from pijyoi/qpath_chunks
perform arrayToQPath in chunks
2021-08-13 10:37:14 -07:00
KIU Shueng Chuan 0cd926ff8e merge finiteCheck branches 2021-08-14 00:00:59 +08:00
KIU Shueng Chuan e541c9ba1e hoist duplicate code 2021-08-13 18:53:58 +08:00
KIU Shueng Chuan 44e32f00c7 _fill_nonfinite() -> _compute_backfill_indices()
this allows us to defer the backfilling
2021-08-11 21:55:54 +08:00
KIU Shueng Chuan 679c1002c1 break up arrayToQPath
this restructuring removes inter-dependencies between the various modes.
this makes it easier to reason about and modify the various codepaths.
2021-08-11 06:55:21 +08:00
KIU Shueng Chuan 7e31a5e4ee setup codepath for connect=='all' and all-finite
"all-finite" includes the case where user requests to skip finiteCheck.
2021-08-10 11:57:19 +08:00
KIU Shueng Chuan fa826bd4cb add benchmarks/arrayToQPath.py 2021-08-10 11:57:19 +08:00
Ogi Moore 0d8eba36a6
Merge pull request #1957 from j9ac9k/bump-numpy-per-nep29
Bump minimum numpy up per NEP-29 schedule
2021-08-07 10:13:49 -07:00
Ogi Moore 690a416d5d Bump minimum numpy up per NEP-29 schedule 2021-08-07 09:37:19 -07:00
Ogi Moore a537bc2b23
Merge pull request #1956 from pijyoi/zerocopy_qba
arrayToQPath: use QByteArray as backing store
2021-08-06 22:22:09 -07:00
KIU Shueng Chuan 287ec9fbea arrayToQPath: use QByteArray as backing store
this avoids:
1) allocation and zero-ing of bytearray
2) copy of bytearray to QByteArray
2021-08-07 08:56:11 +08:00
Nathan Jessurun 503507ba50 Don't specify a version for deprecation 2021-08-06 08:04:51 -04:00
Nathan Jessurun 3d15ca1038 Catch remaining 'values' usages 2021-08-06 08:04:51 -04:00
Nathan Jessurun 6f44d27f2d Deprecate `values` opt for list parameter 2021-08-05 15:48:09 -04:00
Ogi Moore f16125c378
Merge pull request #1951 from timgates42/bugfix_typos
docs: Fix a few typos
2021-08-04 22:01:50 -07:00
Tim Gates a2078f8a87
docs: Fix a few typos
There are small typos in:
- doc/source/how_to_use.rst
- doc/source/region_of_interest.rst
- examples/ViewBox.py
- pyqtgraph/flowchart/Node.py
- pyqtgraph/graphicsItems/AxisItem.py
- pyqtgraph/graphicsItems/PColorMeshItem.py
- pyqtgraph/graphicsItems/PlotDataItem.py
- pyqtgraph/graphicsItems/TargetItem.py
- pyqtgraph/graphicsItems/ViewBox/ViewBox.py
- pyqtgraph/widgets/RawImageWidget.py

Fixes:
- Should read `mapped` rather than `maped`.
- Should read `vector` rather than `vetctor`.
- Should read `value` rather than `vaule`.
- Should read `preferable` rather than `preferrable`.
- Should read `output` rather than `ouptut`.
- Should read `information` rather than `inforation`.
- Should read `information` rather than `infomation`.
- Should read `exempt` rather than `excempt`.
- Should read `emphasizing` rather than `emphacizing`.
- Should read `construction` rather than `constrution`.
2021-08-05 06:47:08 +10:00
Ogi Moore 239e15a6f8
Merge pull request #1944 from pijyoi/getset_color_nih
use more of QColor functions / methods
2021-08-03 22:53:53 -07:00
KIU Shueng Chuan 178e693a4d add SVG named color support 2021-08-04 09:19:46 +08:00
KIU Shueng Chuan 371facb17f SVGExporter.py : fix background color
1) blue and green were swapped
2) %f used for integer rgb components
3) %d used for float opacity component
2021-08-04 09:19:46 +08:00
KIU Shueng Chuan 482b92d700 GLGradientLegendItem: remove opengl code
change fontColor to take a mkColor() argument

use hyperlink when referring to other functions
2021-08-04 09:19:46 +08:00
KIU Shueng Chuan efa662415e use QColor methods and functions 2021-08-04 09:19:34 +08:00
ntjess 4bf1866c2a
Organize paramtypes (#1919)
* Registered parameter types go in their own files

* Moves [int, float] item definitions outside `WidgetParameterItem`

* Moves [int, float] parameter definitions outside `WidgetParameterItem`

* Allow registering ParameterItems for easy parameter defs

* Finalizes moving simple parameters to their own files

* removes accidentally committed file

* Provides class qualnames in rst

* Address docstring build issues

* Address recent review comments
- `registerParameterItemType`:
  * added to docs and parametertree.__init__
  * Remove unsed PARAM_TYPES global
  * Hyperlink to `registerParameterType`
- parameter tree rst:
  * Alphabetize entries
  * Rebuild RST without fully qualified class name
  * Add note at file header that it is auto generated

* Remove spurious space during rst doc creation

* Ensure created/modified files end with newline

* Address CodeQL warnings

* toPlainText also returns str

* `QTreeWidgetItem.text` returns str
2021-08-02 10:47:55 -07:00
Ogi Moore fb2e684f45
Merge pull request #1943 from ntjess/rm-py2-codepaths
Remove python 2 code paths
2021-08-02 10:19:29 -07:00
ntjess e18d1fb1f2
arrayToQPath can handle empty paths (#1920)
* Fixes #1888

* Improve test coverage of arrayToQPath

* Use early exit to solve empty path instead of slice manipulation

* address codeql qualms: Unused import, uneven tuple
2021-08-02 10:18:25 -07:00
Ogi Moore d0961cc320
Merge pull request #1942 from ntjess/add-newlines
Adds EOF newline to files missing it
2021-08-02 09:09:27 -07:00
njessurun c0eb3267d2 Remove python 2 code paths 2021-08-02 12:07:25 -04:00
Ogi Moore b0bcec1ff2
Merge pull request #1941 from ntjess/more-rm-py2_3
Remove unnecessary casting of `toPlainText` to str
2021-08-02 09:01:22 -07:00
njessurun ef99d3fbf6 Adds EOF newline to files missing it.
Note: intentionally avoids files moved / already adjusted from #1919
2021-08-02 11:51:28 -04:00
Nathan Jessurun 84b491fb9b toPlainText also returns str
Note: intentionally leaves out instance in parametertypes.py to avoid merge conflict with #1919
2021-08-02 11:23:04 -04:00
Kyle Sunden a472f8c5de
Remove all usage of python2_3.py (#1939)
* Remove all usage of python2_3.py

Technically these functions were exported at the top level of the library, this removes them without warning... If we want to we can bring them back for there, but I honestly don't think its needed, as we are py3 only now and have been for multiple releases.

This may introduce a number of 'useless cast' or similar but those were always happening anyway

This PR brought to you by sed

* Update varname in hdf example to avoid collision with builtin

* Clean up some leftover comments surrounding imports of compat code

* Unnecessary string casts

* Additional unnecessary casts

* syntax error fix

* more unnecessary casts

* Yet more unnecessary casts
2021-08-01 21:43:32 -07:00
Ogi Moore 1ddbfc8321
Merge pull request #1940 from pijyoi/fix_logmode
fix log mode by reverting to previous formulation
2021-07-31 20:50:36 -07:00
KIU Shueng Chuan aebc66dcaa fix log mode by reverting to previous formulation
this formulation is in the documentation for setLogMode()
2021-08-01 11:11:41 +08:00
Kyle Sunden 6a59b7e5b5
Many unused import cleanups (#1935)
* Many unused import cleanups

Ignored some star imports, some vendored code in colorama, only looked within pyqtgraph the library, not e.g. examples

* SpinBox decimal imported with both import and from import
2021-07-31 07:35:23 -07:00
Ogi Moore 2d90e54441
Merge pull request #1936 from pijyoi/empty_qpolygonf
Handle empty QPolygonF
2021-07-31 07:30:20 -07:00
KIU Shueng Chuan 04673ac98b rename: qimage_to_ndarray -> ndarray_from_qimage 2021-07-31 21:10:34 +08:00
KIU Shueng Chuan f64290be9e test that binding provides a write-thru QImage 2021-07-31 21:00:54 +08:00
KIU Shueng Chuan 9355ecf469 support padded QImage 2021-07-31 20:58:51 +08:00
KIU Shueng Chuan 75654b8495 handle zero-sized QPolygonF
depending on the implementation, a zero-sized QPolygonF may not
have any underlying buffer allocated and may return a null pointer when
queried for its "data()"

this null pointer is returned to Python as a "None" which breaks code
not expecting it.
2021-07-31 17:25:03 +08:00
KIU Shueng Chuan 9913f7c1e7 import shiboken{2,6} as shiboken 2021-07-31 15:58:56 +08:00
Ogi Moore 7aa5d0cbf4
Merge pull request #1910 from pijyoi/paramtree_plotspeed
PlotSpeedTest: add param tree control panel
2021-07-30 22:51:36 -07:00
KIU Shueng Chuan 643dd87800 add option to allow useOpenGL toggle 2021-07-31 13:01:40 +08:00
Ogi Moore fe10b5e8dc
Merge pull request #1711 from j9ac9k/test-feature-merge
Add GLGradientLegendItem (Reimplement #663)
2021-07-30 20:37:29 -07:00
Ogi Moore 0cfc9cd440 Add GLGradientLegendItem to pyqtgraph
Huge thank you to @feketeimre for the initial PR for this feature
Thank you to @pijyoi for re-implementing with no changes needed to
GLViewWidget and supporting QOpenGLWidget vs. QGLWidget.
2021-07-30 20:19:27 -07:00
Ogi Moore d3755520d0
Merge pull request #1892 from pijyoi/glpainteritem 2021-07-30 18:23:51 -07:00
KIU Shueng Chuan 0afd8adcd8 add Big Sur conditional examples from utils.py 2021-07-31 08:28:45 +08:00
Martin Schulz 96cccd96ec
make antialiasing optional for paintGL in PlotCurveItem (#1932)
* make antialiasing optional for paintGL in PlotCurveItem

* reversion to standard values if aa is disabled

* remove unnecessary lines
2021-07-30 12:19:02 -07:00
Nils Nemitz 5084d9b537
Reduce ColorMap inefficiencies (#1927)
* Avoid regenerating QColor lists, speed up generation where unavoidable

* whitespace and typo reduction
2021-07-29 20:50:10 -07:00
Martin Chase eb8965c2f4
Restore previous signature on TargetItem.setPos() (#1928)
* Restore previous signature on TargetItem.setPos()

* star means something to sphinx

Co-authored-by: Luke Campagnola <luke.campagnola@gmail.com>
2021-07-27 18:04:24 -07:00
KIU Shueng Chuan 1a34c8857f PlotSpeedTest: add param tree control panel
inspired by ScatterPlotSpeedTest.
2021-07-24 07:41:25 +08:00
Nils Nemitz 7009084e4c
more readable names for color map references in ColorBarItem API (#1908)
* more readable names for color map references

* changed example code

* activated deprecation warnings

* added accessor methods for cmap/colorMap
2021-07-23 14:45:57 -07:00
ntjess 81823768c0
feature More parameter item types (#1844)
* feature More parameter item types

Pen: Pops up a dialouge that allows the user to customize a pen. Setting pen value is not working yet.
Progress bar: For indication things.
Slider: Easier way to set values that dont require precision.
Fonts: Picking font types. Next thing could be a Font dialog.
Calendar: For picking dates or intervals
Open/save file/files/directory: Pops up an open/save file/directory dialog to select a file/directory. Filter string and caption can be defined too.

A PenSelectorDialog widget was created for the pen parameter item too.

Also added these parameter items to the example.

* PyQt/Side6 compatibility fixup

* Revisions from intial PR

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialog.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/parametertree/parameterTypes.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/parametertree/parameterTypes.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialog.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Update pyqtgraph/widgets/PenSelectorDialogbox.py

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

Apply suggestions from code review

Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>

* Bugfix: module instead of class import on param tree example

* Enrich the slider parameter

* Address pijyoi comments on pen style parameter

* Different file picker for easier porting

* Better organization and formatting, minor refactoring

* PyQt6/PySide6 fixup for file dialog

* Minor adjustment to file picker

* Bugfix: for 'None' sigChanged

'None' is explicitly allowed for a WidgetParameterItem's `sigChanged` value. However, this raises an error on a changed value unless the commit's fix is applied

* Calendar works better as sub item

* Fixes bugs in pen parameter's dialog + makes it resizable

* more bugfixes and recommended changes, lets pen serialize its options

* better pen save state

* Fixes file parameter qualms

* Fixes font parameter qualms

* Fixes calendar parameter qualms

* Fixes multiply-defined slider optsChanged

* Fixes pen parameter qualms

* ptree example minor bugfix

* Pen dialog bugfixes

* File dialog bugfixes / mild improvements

* unto ptree save state regression

* file fixup

* Adds parameter descriptions to docstrings

* Improved parameter documentation

* adds 'relativeTo' option for file parameter

* Less abuse of Qt enums during or-operations

* More uniform handling of relative paths

* More cleanup of enum setting

* better name for window title (matches qt name)

* Favor os.path over pathlib

* Exposes 'directory', 'windowTitle' to file parameter

* Fixup and add comparison to parameter tree state restoration

* Exposes "cosmetic" in pen parameter

* Indicate defaults in parameter documentation

* QtEnumParameter works for enums outside QtCore.Qt

* see if altering pytest report fixes ci bug

* Cleanup unused import and redundant `self.widget` assignments

Co-authored-by: Fekete Imre <feketeimre87@gmail.com>
Co-authored-by: ChristophRose <42769515+ChristophRose@users.noreply.github.com>
2021-07-23 14:40:49 -07:00
Nils Nemitz 8f96c78715
Extend ColorMap with HSL cycles and subset generation (#1911)
* Extend ColorMap with HSL cycles and subset generation

* relaxed color palette data

* added hex to be installed in colors/maps/
2021-07-23 14:38:17 -07:00
Ogi Moore d396d33799
Remove the use of pyqtgraph.ptime (#1914)
* Remove the use of pyqtgraph.ptime

With us supporting python3.7+, we have no more need for the ptime module
and can instead safely use perf_counter for everything.

* Address small issues PR turned up

* Reword comment in ImageView
2021-07-22 20:57:50 -07:00
Martin Chase 1d40d50b89
push bullet lists over 2 spaces to get them to show up as such in the… (#1912)
* push bullet lists over 2 spaces to get them to show up as such in the docs

* separate the literal block from the bullet list
2021-07-21 07:12:35 -07:00
KIU Shueng Chuan 1184e3fcce avoid converting dict to set 2021-07-19 08:31:54 +08:00
KIU Shueng Chuan 394b0dd75c implement set/get for cameraParams 2021-07-19 06:57:07 +08:00
KIU Shueng Chuan 8a6640c419 treat self.opts as private. provide accessors 2021-07-19 04:52:49 +08:00
Ogi Moore 66ec0996f4
Merge pull request #1610 from j9ac9k/boost-plotline-performance
Boost plotline performance
2021-07-18 13:44:01 -07:00
Ogi Moore 699ed578f4
Merge pull request #1913 from ixjlyons/update-sphinx
Bump sphinx and theme versions
2021-07-18 12:46:09 -07:00
Kenneth Lyons 0ae6b753fc Bump sphinx and theme versions 2021-07-18 12:37:29 -07:00
Ogi Moore 4e293dd17d
Merge pull request #1909 from NilsNemitz/None-check_AxisItem_label
None-check AxisItem.label before access
2021-07-18 10:44:48 -07:00
Nils Nemitz 8b4db67ae9 None-check self.label before access 2021-07-18 17:24:55 +09:00
KIU Shueng Chuan d9726dbcc1 implement GLPainterItem 2021-07-18 14:14:13 +08:00
Ogi Moore d5990bf32c Uncomment ViewBox.itemChange
This handles calls for ViewBox.prepareForPaint
2021-07-17 22:30:36 -07:00
Dennis Goeries cdb427ff2f Provide a different plot test 2021-07-17 22:29:06 -07:00
Ogi Moore ed66eef203
Merge pull request #1902 from pijyoi/simpler_mvp
simplify modelview projection computation
2021-07-17 22:03:32 -07:00
Ogi Moore 58aac09387
Merge pull request #1903 from pijyoi/cleanup_glv
Cleanup GLViewWidget
2021-07-17 21:59:40 -07:00
Kenneth Lyons ba7129a719
Add option to limit LinearRegionitem bounds to a secondary item (#1834)
* Added clipItem option to LinearRegionItem

* Added a clipItem option to LinearRegionItem

Handle case when no self.viewBox() is yet available

* Implement LinearRegionItem clipItem

* Undo unnecessary change

* Update clipItem doc

* Fixup docstring formatting

* Cleanup

* Support clearing clipItem via setBounds. Fix initialization bug

* Add tests for LinearRegionItem clipItem

* Better clipItem demo in crosshair example

* Another test to verify claim in docstring

Co-authored-by: Arjun Chennu <arjun.chennu@gmail.com>
Co-authored-by: Ogi Moore <ognyan.moore@gmail.com>
Co-authored-by: Arjun Chennu <achennu@mpi-bremen.de>
2021-07-17 21:02:06 -07:00
KIU Shueng Chuan cbc9b4d310 catch specific KeyError exception 2021-07-18 10:45:58 +08:00
Ogi Moore ddab4180e9
Merge pull request #1907 from pijyoi/fix_glvol_arm64
fix GLVolumeItem example for arm64
2021-07-17 18:16:52 -07:00
KIU Shueng Chuan 6f49ede5c1 glDisable(GL_TEXTURE_3D) -> glDisable(GL_TEXTURE_2D) 2021-07-18 09:09:57 +08:00
Ogi Moore 76f3612245
Merge pull request #1904 from Artturin/tests-h5py-optional
tests/exporters/test_hdf5.py: skip if no h5py
2021-07-17 16:35:30 -07:00
Artturin 2de5cd78da tests/exporters/test_hdf5.py: skip if no h5py 2021-07-18 01:26:22 +03:00
Ogi Moore ddf73c2ecf
Merge pull request #1901 from outofculture/where-will-metaarray-be
put new MetaArray location in deprecation warning
2021-07-17 09:50:16 -07:00
KIU Shueng Chuan fa77dae941 render upright image (was previously transposed image) 2021-07-17 21:19:48 +08:00
KIU Shueng Chuan 5283eeb71b remove override of devicePixelRatio() 2021-07-17 18:55:55 +08:00
KIU Shueng Chuan aca627ac8c GLTextItem: use device independent pixels for viewport 2021-07-17 18:39:59 +08:00
KIU Shueng Chuan 31e10fdc1d raise ValueError instead of ctypes.ArgumentError
ctypes.ArgumentError got imported through PyOpenGL import *
2021-07-17 18:29:42 +08:00
KIU Shueng Chuan f85a1015ad fix GLTextItem to use relative imports 2021-07-17 18:28:09 +08:00
KIU Shueng Chuan e10dbfd9e1 change examples to use setCameraPosition 2021-07-17 18:25:21 +08:00
KIU Shueng Chuan 6ca81fdddb Revert "restore opts['viewport'] after clobbering"
This reverts commit 7a17cda956.
2021-07-17 18:25:21 +08:00
KIU Shueng Chuan 7a17cda956 restore opts['viewport'] after clobbering 2021-07-17 16:14:25 +08:00
KIU Shueng Chuan dfd5b5dc1b fix attribute access in failure branch 2021-07-17 16:06:44 +08:00
KIU Shueng Chuan 5b2674c9d5 change some deviceWidth() to width()
viewport / region use device pixels: deviceWidth()
anywhere else uses device independent pixels : width()
2021-07-17 15:59:14 +08:00
KIU Shueng Chuan f43f795950 don't check opengl version again during paint
we already fail upfront at initializeGL(), so any error that occurs
here won't be due to OpenGL version < 2.0
2021-07-17 15:59:14 +08:00
KIU Shueng Chuan 9bf6c01f58 fix renderToArray() broken for hidpi
define opts['viewport'] to be in device pixels.

note from the removed comments that there was one place assuming
opts['viewport'] was in device pixels and the other assuming that it was
in device independent pixels.
2021-07-17 14:49:47 +08:00
KIU Shueng Chuan bc52a2afe0 return ValueError for wrong argument, not RuntimeError 2021-07-17 13:46:11 +08:00
KIU Shueng Chuan fab505a431 remove unneeded call to makeCurrent()
in any case, context will not be valid until the widget is shown.
2021-07-17 13:32:33 +08:00
KIU Shueng Chuan 1814ff535d fail upfront for OpenGL ES instead of during item add 2021-07-17 13:30:20 +08:00
KIU Shueng Chuan f698ccc06e load background color from configOption 2021-07-17 13:05:40 +08:00
KIU Shueng Chuan ce4c6d95ed fix setCameraPosition not setting ele and azi in euler mode 2021-07-17 11:04:32 +08:00
KIU Shueng Chuan b5fc3d2a7e add comment about definition of viewport 2021-07-17 10:40:27 +08:00
KIU Shueng Chuan 1b00d3448a reimplement readQImage()
tested that call to repaint() is not needed
2021-07-17 10:34:27 +08:00
KIU Shueng Chuan 5d7dd101f2 load matrix instead of multiplying to identity 2021-07-17 10:21:26 +08:00
KIU Shueng Chuan 025ca08574 delete empty resizeGL() 2021-07-17 10:17:31 +08:00
KIU Shueng Chuan ee9b1565bd don't redefine width() and height()
Qt widgets define width() and height() to be in device independent
pixels. Don't change that meaning.
2021-07-17 10:14:53 +08:00
KIU Shueng Chuan e158034c07 remove devicePixelRatio argument. only needed for Qt4 2021-07-17 09:49:51 +08:00
KIU Shueng Chuan 31f9d0024a simplify modelview projection computation
1) no need to get rect(), which is actually defined as
	QRect(0, 0, width(), height())
2) use col-maj data() instead of row-maj copyDataTo()
   - glLoadMatrixf() takes col-maj
2021-07-17 07:56:21 +08:00
Martin Chase bcb629495c put new location in deprecation warning 2021-07-16 15:59:23 -07:00
Ogi Moore d28e1c8075
Merge pull request #1895 from j9ac9k/update-contributing-guide
Update contributing guide ahead of scipy sprints
2021-07-15 21:01:07 -07:00
Ogi Moore b79171dc3a Update contributing guide ahead of scipy sprints 2021-07-15 20:42:32 -07:00
Ogi Moore 910142aa6f
Merge pull request #1897 from pijyoi/fix_win32_plotcurveitem_opengl
PlotCurveItem: setup modelview and projection
2021-07-15 19:48:20 -07:00
KIU Shueng Chuan 7442ab1e52 PlotCurveItem: setup modelview and projection 2021-07-15 23:16:26 +08:00
Ogi Moore b9e079b10c
Merge pull request #1889 from swt2c/gltextitem_py310
Fix GLTextItem with Python 3.10
2021-07-12 09:57:01 -07:00
Scott Talbert db8180d88e Fix GLTextItem with Python 3.10
drawText() expects int arguments and Python 3.10 does not allow for
implicit rounding.
2021-07-11 22:04:00 -04:00
Ogi Moore 1ce9da36d3
Merge pull request #1891 from ixjlyons/readme-redundant-optional-deps 2021-07-11 13:14:59 -07:00
Kenneth Lyons bb94290d8e Clean up redundancy in README 2021-07-11 09:57:09 -07:00
KIU Shueng Chuan e17428b018 fix GLVolumeItem example for arm64 2021-07-09 21:12:58 +08:00
Ogi Moore 6b4385ce0d
Merge pull request #1885 from jennifer-manriquez/issue
Raise TypeError instead of Exception
2021-07-08 14:50:48 -07:00
Jennifer Manriquez 0c074ea005 Raise TypeError instead of Exception 2021-07-08 13:35:22 -05:00
Kyle Sunden fda6071ae5
Merge pull request #1884 from pyqtgraph/ksunden-patch-1
Update version number
2021-07-08 02:33:07 -05:00
Kyle Sunden 53fc415813
Update version number 2021-07-08 01:18:00 -05:00
Kyle Sunden 49a97351e7
Merge pull request #1838 from j9ac9k/prep-for-release
Prep for 0.12.2 release
2021-07-08 01:16:25 -05:00
Ogi Moore 0c38ff2754 Add one more PR to the changelog 2021-07-07 22:47:49 -07:00
Kyle Sunden 89958dbaab
Merge branch 'master' into prep-for-release 2021-07-08 00:38:57 -05:00
Kyle Sunden e12ac50a05
Merge pull request #1870 from edumur/master
Update README
2021-07-08 00:35:56 -05:00
Etienne Dumur 804f6b6649 Clarify markdown 2021-07-05 21:46:40 +02:00
Ogi Moore d82a47b864 First go of a changelog for 0.12.2 2021-07-03 22:04:14 -07:00
Nils Nemitz 523b31e97f
Draw GradientLegend in ViewBox coordinates (#1864)
* draw GradientLegend in ViewBox coordinates

* some cleanup

* do not proceed with dummy values

* correct bar and label order, add some styling options

* remove debugging code
2021-07-03 21:43:39 -07:00
Ogi Moore 4b7dfdef88
Merge pull request #1876 from ixjlyons/fix-lineroi-coords
Fix LineROI handle positions
2021-07-03 08:23:13 -07:00
Ogi Moore e83b91e9af
Merge pull request #1871 from pijyoi/opengl_init
Allow adding items to GLViewWidget before show
2021-07-03 08:10:35 -07:00
ntjess 820c1604dd
Set focus to the example filter + Ctrl+F listener for focus (#1873)
* Set focus to the example filter + Ctrl+F listener for focus

* Early return on detecting "F"
2021-07-03 07:58:51 -07:00
Kenneth Lyons 7ebae20c5d Fix LineROI handle positions 2021-07-03 07:51:23 -07:00
KIU Shueng Chuan e9ee11f010 simplify calls needed to initialize items 2021-07-03 15:53:17 +08:00
Ogi Moore 02909999dc
Merge pull request #1875 from pijyoi/fix_pyqt6_mouse_event
bug: PyQt6 does not have localPos()
2021-07-02 13:26:19 -07:00
KIU Shueng Chuan 6fc02711a8 bug: PyQt6 does not have localPos()
this bug must have existed since the removal of the mouse shims
from Qt.py.
2021-07-02 10:14:19 +08:00
KIU Shueng Chuan e76328ab0e bug: PyQt6 does not have localPos()
this bug must have existed since the removal of the mouse shims
from Qt.py.
2021-07-01 15:11:55 +08:00
KIU Shueng Chuan f9f5d46589 missing import of pg
CI passed because of the way the example gets invoked.
2021-07-01 08:56:47 +08:00
KIU Shueng Chuan 96f7ce1325 remove empty initializeGL() 2021-07-01 08:56:47 +08:00
KIU Shueng Chuan b843214f66 remove Qt4 mouse wheel handling 2021-07-01 08:56:47 +08:00
KIU Shueng Chuan 1a29cf7579 defer init if we do not have an OpenGL context yet 2021-07-01 08:56:33 +08:00
Etienne Dumur f5563501ed Modify optional libraries style 2021-06-30 09:02:24 +02:00
Etienne Dumur da39e8f460 Iterative improvement of the README file
Replace "pyqtgraph" by "PyQtGraph".
Replace the optional libraries list by an "Optional added functionalities" section.
More precise on the role of each optional library.
Add numba in optional library.
2021-06-29 11:26:51 +02:00
Etienne Dumur 08e460ad34 Update README
Add matplotlib as optional library.
Replace hdf5 by h5py.
Add links towards the github page or website of the different linraries.
2021-06-28 09:24:55 +02:00
ntjess 4a921ddf71
Filter examples (#1868)
* Allows filtering of examples

* For some reason, the ui designer ignored the courier font family so I manually inserted it into the .ui file

* Allows filtering by file content, too

* Respects dark mode (maybe?), fixes policy setting on code layout

* Prevents "run edited code" from showing unless the actual content changes

* Looks like black font is always best against highlight background

* Left test code in commit...

* Fix broken highlighting on PyQt6

* Address #133

* Better highlighting for both dark and light mode

* Minor refactoring/cleanup, uses combo box instead of checkbox

* Combo box below text edit to avoid clipping

Co-authored-by: njessurun <ntjessu@gmail.com>
2021-06-26 17:51:34 -07:00
Nils Nemitz e79dacf805
Fix Matplotlib color map import, add CC0 maps locally (#1865)
* accept Matplotlib colormap data as numpy array, add CC0 Matplotlib maps locally

* add cividis, prioritize lower case in example/atlas
2021-06-26 08:41:57 -07:00
Ogi Moore 5e8f200aa0
Merge pull request #1869 from NilsNemitz/colorbaritem_ticks
Disable unused ColorBarItem ticks
2021-06-26 08:06:37 -07:00
Nils Nemitz c07b95812c clear out ticks instead of hiding them 2021-06-26 20:42:11 +09:00
Ogi Moore 93fa8664cb
Merge pull request #1846 from pijyoi/import_hygiene
reduce pollution of pg namespace
2021-06-25 23:26:26 -07:00
KIU Shueng Chuan 5d55f3facf remove imports subdir 2021-06-26 07:54:03 +08:00
Ogi Moore 82da8f122e
Merge pull request #1867 from j9ac9k/fix-numpy-deprecation
Use built-in int as dtype
2021-06-25 09:15:44 -07:00
Ogi Moore 418a181691 Use built-in int as dtype 2021-06-25 08:45:02 -07:00
KIU Shueng Chuan 3a1b74df6f move Qt.py to Qt/__init__.py 2021-06-25 21:33:05 +08:00
KIU Shueng Chuan 11bf824c0a deprecate ordereddict.OrderedDict on instantiation 2021-06-25 21:19:34 +08:00
KIU Shueng Chuan 427128ece1 add imports used by ACQ4 2021-06-25 21:19:34 +08:00
KIU Shueng Chuan 81baa182c5 add __all__ to various files 2021-06-25 21:19:33 +08:00
Ogi Moore 3fbb4f6b02
Merge pull request #1862 from j9ac9k/deprecate-metaarray
Deprecate MetaArray Entirely (for 0.14 release)
2021-06-24 10:46:14 -07:00
Ogi Moore 27ad41a10c Add deprecation warning to MetaArray.__init__ 2021-06-23 21:27:21 -07:00
Martin Chase f764e2d3ff
progress dialog fix (#1861) 2021-06-23 19:34:55 -07:00
Nils Nemitz 775f1d629c
Separate out mouse events stolen by AxisItem (#1845)
* separate out mouse events on main plot area

* work in scenepositions so that detection also works in a layout

* added comments/remove debug statements
2021-06-22 16:17:39 -07:00
Ogi Moore addb92f592
Merge pull request #1853 from NilsNemitz/getColor-getStops
make getColors and getStops behavior more consistent; add tests
2021-06-22 11:50:34 -07:00
Ogi Moore 98e9ea9b79
Merge pull request #1860 from pijyoi/remote_venv
remote: exchange pids if running in Windows venv
2021-06-22 11:28:18 -07:00
KIU Shueng Chuan 30f4af5913 remote: exchange pids if running in Windows venv 2021-06-22 21:59:39 +08:00
Nils Nemitz 362fbaa53a fixed docstring 2021-06-22 03:32:12 +09:00
Nils Nemitz f79d0dfa14 make getColors and getStops behavior more consistent; add tests 2021-06-22 01:19:07 +09:00
Ogi Moore ba517aba0e
Merge pull request #1840 from jennifer-manriquez/master
Allow border=False in GraphicsLayout
2021-06-16 20:17:35 -07:00
Jennifer Manriquez 2899143e84 Allow border=False in GraphicsLayout 2021-06-16 19:35:42 -05:00
Ogi Moore 663bb75da4 add numba optional dependency to README.md 2021-06-15 22:43:53 -07:00
Ogi Moore 30bc13831d
Merge pull request #1837 from pyqtgraph/revert-1835-skip_monkey
Revert "skip pytest monkeypatch"
2021-06-15 20:45:49 -07:00
Ogi Moore ee602ac243
Revert "skip pytest monkeypatch" 2021-06-15 20:28:08 -07:00
Ogi Moore 61dedcb4a5
Merge pull request #1794 from pijyoi/numba_lookup 2021-06-15 16:42:54 -07:00
KIU Shueng Chuan 5dcea9bdac rename private function and its arguments 2021-06-16 06:50:51 +08:00
Ogi Moore c376c6fdcc
Merge pull request #1829 from pijyoi/pixmap_fragments
try using QPainter.drawPixmapFragments
2021-06-15 10:06:50 -07:00
KIU Shueng Chuan f63d1e4206 document PyQt boxing and unboxing 2021-06-15 11:40:27 +08:00
KIU Shueng Chuan 7c6d9fe6d5 cleanup python2 and unused imports 2021-06-15 11:06:37 +08:00
Ogi Moore fff2bc82c8
Merge pull request #1835 from pijyoi/skip_monkey
skip pytest monkeypatch
2021-06-14 19:58:30 -07:00
KIU Shueng Chuan 89f6c7da81 remove codepaths other than pixmap fragments codepath 2021-06-15 09:43:31 +08:00
KIU Shueng Chuan abeae0b7fa init so that pointers are present 2021-06-15 06:50:31 +08:00
KIU Shueng Chuan 6bfb516768 skip pytest monkeypatch 2021-06-14 21:06:19 +08:00
KIU Shueng Chuan a1845cddbc don't truncate floating point target coords 2021-06-14 19:24:39 +08:00
KIU Shueng Chuan 6839ec937a reuse pixmap fragment objects 2021-06-14 06:49:52 +08:00
KIU Shueng Chuan ad3e3a6b8b ScatterPlotSpeedTest: add toggle for drawPixmapFragments 2021-06-13 08:00:45 +08:00
KIU Shueng Chuan 380ec2e0b2 implement usage of QPainter.drawPixmapFragments 2021-06-13 08:00:45 +08:00
Ogi Moore cb4af3ac97
Merge pull request #1833 from pijyoi/fix_pyqt61_scatterplot
fix ScatterPlot render issues on PyQt6 6.1
2021-06-12 08:36:01 -07:00
KIU Shueng Chuan 98a020d1bb ROI.py::renderShapeMask : fix little-endian assumption 2021-06-12 20:25:28 +08:00
KIU Shueng Chuan afe47def28 fix ScatterPlot render issues on PyQt6 6.1 2021-06-12 14:05:47 +08:00
Ogi Moore e2b0a5ffae
Merge pull request #1830 from j9ac9k/Address-missing-enums
Add missing enums
2021-06-11 08:46:20 -07:00
Ogi Moore e892ad37aa Add missing enums 2021-06-10 21:28:19 -07:00
Ogi Moore 7e8d34ecd8
Merge pull request #1824 from pijyoi/less_endian
remove little-endian assumption for image export
2021-06-09 15:02:48 -07:00
Martin Chase 2fb04b754c
Fix BusyCursor to use internal stack provided by setOverrideCursor/restoreOverrideCursor (#1827)
* un-busy as many times as needed

* lint

* add test to prove cursor behavior

* tentative change in the hopes that all supported qt versions behave properly

* remove unnecessary code

* use contextmanager decorator instead of class

* use full path to WaitCursor

* restore docstring; refactor variable for clarity

* fix docstring whitespace

* break up long lines

* use variable to shorten instead
2021-06-09 13:32:24 -07:00
KIU Shueng Chuan 6a2bfa5c84 fix PyQt6 long spelling for enums 2021-06-10 03:33:04 +08:00
KIU Shueng Chuan b3e8f332fb add test for export to qimage 2021-06-10 03:18:12 +08:00
KIU Shueng Chuan 765f9648cd remove little-endian assumption for image export 2021-06-10 03:18:12 +08:00
Ogi Moore 6f0ffcbf8f
Merge pull request #1818 from j9ac9k/convert-enums
Convert Qt Enums to Qt6 Namespace
2021-06-08 21:57:45 -07:00
Ogi Moore d974544053 Split up Execution of examples and tests in CI
There seems to be some unintentional side effect when running examples and the
same time.  This change breaks up the execution into two separate calls to
pytest in an attempt to bypass whatever issue is being created.
2021-06-08 21:23:49 -07:00
Ogi Moore f225724f26 Close instead of clear test_scatterplotitm 2021-06-08 21:23:49 -07:00
Ogi Moore 3c352dd1a9 Fix documentation misalignment 2021-06-08 21:23:49 -07:00
Ogi Moore 2f1f297f39 Fix case of int-conversion for MouseButtons
This has been demonstrated to not work in PyQt6.
2021-06-08 21:23:49 -07:00
Ogi Moore cc081af528 New Template Files for PyQt6 6.1
Update PySide6 templates to Qt 6.1
2021-06-08 21:23:49 -07:00
Ogi Moore 195a1a6fa3 Remove Qt 6.0 support
Simplify some PyQt6 code branches
2021-06-08 21:23:49 -07:00
Ogi Moore d455da9aec Use Qt6 Enum Namespace
This namespace appears to be valid in PySide2/PyQt5 5.12+ so we may as
well migrate to the newer namespace ourselves.
2021-06-08 21:23:49 -07:00
Ogi Moore 29bdf9949e Skip GLTextIem on some conditions on macOS 2021-06-08 21:11:24 -07:00
Nils Nemitz 7d41e8a878
Color map linearization (#1797)
* extended color map functions

* assertion string, documentation pass, comment purge

* fix some documentation links

* simplify assert statement

* removed comments and redundancy, renamed modulated bar

* include modulatedBarData in documentation

* test running matplotlib with dummy backend

* skip color maps example on OSX/PySide6.1.1

* removed skipping of tests

* reverted some accidental whitespace, removed unneeded numpy import

* removed unneded alpha parameter
2021-06-08 20:41:46 -07:00
Nils Nemitz f002d70adc
Expose number of subsamples in ImageItem auto-level determination (#1638)
* exposed number of subsamples in auto-level determination

* Removing print statement at @NilsNemitz's request

* make levelSamples count pixels, not pixels * channels

* minimum number of samples can be 2 if we look at pixels anyway

* adjusted minimum levelSamples to 4: Otherwise a 2x2 image downsamples to a single pixel

* extended docstring for level to make the user aware of auto-level subsampling

* subsample towards square array for auto-leveling

* eliminated duplicated code between level downsampling and samples and QuickMinMax method

Co-authored-by: Ogi Moore <ognyan.moore@gmail.com>
2021-06-08 10:25:47 -07:00
Ogi Moore 823988d51c
Merge pull request #1821 from pijyoi/case_sensitive_exception 2021-06-08 05:39:35 -07:00
KIU Shueng Chuan 1715d5a6fa error on presence of "Exception:" and "Error:" 2021-06-08 15:13:17 +08:00
Nils Nemitz 61f067bf7c
Add axis convenience methods and matrix display example (#1726)
* add axis convenient methods and matrix display example

* wrestled wayward space back into docstring

* color map names are case sensitive on Linux

* docstring fix for PlotItem

* protect AxisItem.linkToView from being obscured by DateAxisItem override

* replaced setOrigin method by promoted setPos and setScale

* made tri-state axes switching explicit

* reverted setRect behavior, documentation pass for ImageItem

* minor text adjustment

* implmented some suggested revisions

* fix input parsing for setRect and add tests so that I don't break it again

* don't try to re-add transform after clearing it

* changed example and doc image generators to pg.exec()

* removed commented-out code

* cleaned up transform eqaulity assertion

* restored devoured comment

* restored devoured comment
2021-06-07 07:44:19 -07:00
Ogi Moore 3a3d05b16f
Merge pull request #1817 from pijyoi/split_finite
implement QPolygonF codepath for connect="finite"
2021-06-06 21:55:51 -07:00
bsobhani d863907163
add function to disable autoscaling (#1819) 2021-06-06 21:19:23 -07:00
shikishima-TasakiLab f13002b251
Add "GLTextItem" (#1776)
* Add GLTextItem

* Fixed DocString.

* Delete unnecessary function.

* Add `from .items.GLTextItem import *`

* Add an example.

* [Combines two `isinstance()` into one.](https://github.com/pyqtgraph/pyqtgraph/pull/1776#discussion_r633046120)

* [Combines two `isinstance()` into one.](https://github.com/pyqtgraph/pyqtgraph/pull/1776#discussion_r633046120)

* [The long code has been broken up into separate lines.](https://github.com/pyqtgraph/pyqtgraph/pull/1776#discussion_r633046234)

* [Moved `pos`, `color`, `text`, and `font` to the `__init__` method.](https://github.com/pyqtgraph/pyqtgraph/pull/1776#discussion_r633047216)

* Add `import initExample` and fix `mkQApp().exec_()` to `pg.exec()` (https://github.com/pyqtgraph/pyqtgraph/pull/1776#discussion_r633046878, https://github.com/pyqtgraph/pyqtgraph/pull/1776#discussion_r633046781)

* Fix `pg.exec()` to `pg.mkQApp().exec()`

* Revert "Fix `pg.exec()` to `pg.mkQApp().exec()`"

This reverts commit 67d397d803.

* Remove type-hints.

* Fix `glColor4d(float(self.color[0]), float(self.color[1]), float(self.color[2]), float(self.color[3]))` to `glColor4d(*self.color)`

* Add `value = fn.glColor(value)`

* Remove debug print.

* Add GLGridItem and GLAxisItem

* Remove if-check for "color" argument

* Draw text without using GLUT.

* Divide the text position by the device pixel ratio

* Fixed bare exceptions to ValueError and TypeError.

* Add 'GLTextItem.py' to utils.py.

* Fixed a bare exception to ArgumentErrror.

* Add `__all__ = ['GLTextItem']`
2021-06-05 08:19:54 -07:00
KIU Shueng Chuan ecc3563f6d special-case all-finite 2021-06-05 20:13:07 +08:00
KIU Shueng Chuan 8997cfa07c test the QPolygonF codepath 2021-06-05 15:09:59 +08:00
KIU Shueng Chuan c8e6920443 use multiple polygons for "finite" 2021-06-05 15:09:59 +08:00
Ogi Moore e206ea5ae9
Merge pull request #1796 from j9ac9k/test-polyline
If arrayToQPath uses connect=all, use a different construction for QPainterPath
2021-06-04 21:33:45 -07:00
Ogi Moore 145ab2e9e3 Merge branch 'master' into test-polyline 2021-06-04 21:06:52 -07:00
Ogi Moore 5c54577c26
Merge pull request #1807 from j9ac9k/merge-test-data
Merge test data + make tests directory which contain tests
2021-06-04 21:06:11 -07:00
Ogi Moore 55e42aabfd make numpy style docstring of arrayToQPath
The function had many comments/explanations, decided to convert to
numpy docstring style, which is the direction pyqtgraph is going in
as it stands
2021-06-03 22:53:09 -07:00
Ogi Moore 649757eb31 Remove use of QPolygonF in non-finite cases
With some experimentation, it was determined that when the QPainterPath
is drawn with a QPen that has a thickness greater than 1, the end result
is quite broken.  Due to us trying to exploit non-advertised behavior
we are removing this optimization step.
2021-06-03 22:53:09 -07:00
Ogi Moore 31b4210f4e
Merge branch 'master' into merge-test-data 2021-06-02 22:15:46 -07:00
Ogi Moore bd11e5e401
Merge pull request #1816 from ntjess/rich-param-cmp
Fix #1814
2021-06-02 09:19:28 -07:00
njessurun c0ebf8a432 Fix #1814 2021-06-02 11:03:22 -04:00
Ogi Moore c0b9f3e26e
Merge pull request #1795 from pijyoi/avoid_writable_qimage
don't rely on QImage-wrapped buffer being writable
2021-06-01 23:05:01 -07:00
Ogi Moore 45cf6fa232 Remove comment about QImage data references
Comment was out of date and no longer relevant, removing at @pijyoi's
suggestion.
2021-06-01 22:50:02 -07:00
Nils Nemitz 39f705fd7f
Sanitize input for plotItem.showGrid (was documentation fix for plotItem.showGrid alpha setting) (#1809)
* documentation fix for plotItem.showGrid alpha setting

* revert to 0-1 scale
2021-06-01 22:43:58 -07:00
Ogi Moore 0da1958ff1
Merge pull request #1768 from pijyoi/rgb32_alpha_chan
Format_RGB32 will always have alpha equal 255
2021-06-01 22:25:08 -07:00
3DAlgoLab 28b1499f09
Force cameraPosition() to return Vector class. (#1799)
* Update GLViewWidget.py

Fix the wrong conversion of QVector3D to numpy array.

* new way to fix the conversion error

* Recover prev. version of pixelSize

Co-authored-by: Jaeyoon Jeong <diem389@gmail.com>
2021-06-01 22:21:50 -07:00
Ogi Moore 4264219144 Add PyQt6 version check for QByteArray creation 2021-06-01 22:01:58 -07:00
Ogi Moore f01f3d473f Have debug.printExc emits RuntimeWarning
Several bugs have snuck through due to being wrapped with printExc,
which would prevent the exception from raising, but printing the trace
to the console.  In pytest, this output is not captured at all, and is
invisible unless the -s parameter is added.

This PR changes the print statement to a runtime warning, which pytest
will capture.
2021-05-31 21:06:16 -07:00
Ogi Moore c7675ca8bb Fix unraisable exception in test_examples
The way we called subprocess.Popen, it looks like we didn't close all
the pipes; this PR addresses the warning that pytest generates when
running the examples.

In addition, we toggle the pytest setting to error on any warning
2021-05-31 21:06:16 -07:00
Ogi Moore d72be799d7 Catch and Address Warnings in test_svg and pytest.ini
On Windows, pyreadline is emitting a deprecation warning we can ignore.
Furthermore, test_svg was using NamedTemporaryFile in a manner that was
causing permission denied errors, so this commit switches to the use of
pytest friendly temporary files
2021-05-31 21:06:16 -07:00
Ogi Moore d859cec95a Replace uses of tempfile.mktemp with tempfile.NamedTemporaryFile
This issue was flagged as a security issue in the static code analyzer
2021-05-31 21:06:16 -07:00
Ogi Moore ceeacf4e5f Remove test_exit_crash.py
This file contains two tests, one of which has been skipped forever,
and the second (test_pg_exit) has been a flakey test that does not test
in general, testing a use-case we likely do not see any more.  So
therefore I am removing this test from the library.
2021-05-31 21:06:16 -07:00
Ogi Moore ab792a73a6 Address in-tree-build deprecation issue in pip 2021-05-31 21:06:16 -07:00
Ogi Moore 4224fe5664 Avoid permissions issues on windows CI 2021-05-31 21:06:16 -07:00
Ogi Moore 1d55fde41a Suppress non-relevant deprecation warning 2021-05-31 21:06:16 -07:00
Ogi Moore d519630d14 Fix check for equality between floats
While this fix prevents an assertion error, the assertion error was
being suppressed; and was only noticeable via pytest -s where the error
was printed to console.  Future work should be done to minimize the use
of bare exceptions so these tests do not fail silently
2021-05-31 21:06:16 -07:00
Ogi Moore 648b8c7df4 Fix issue with int comparson impacting Qt6 2021-05-31 21:06:16 -07:00
Ogi Moore ee951331be Close the example app after it launches 2021-05-31 21:06:16 -07:00
Ogi Moore e7a30b9324 Clean up test files
Remove if __name__ == "__main__" bits, replace some == None to is None
checks

Cleanup variety of static code checker issue

Removed missing imports, restructured some logic to make a little
cleaner, fixed a function in test_dockarea, unfortunately broke the test
so now I tell pytest to expect the Exception.
2021-05-31 21:06:16 -07:00
Ogi Moore 0160de22fb Remove QApplication.instance() deleteLater call
the test_signalproxy.py had a fixture for the QApplication instance,
only problem is at the end of each use of the fixture, it would mark
the application instance for deletion, which is most definitely not what
we want
2021-05-31 21:06:16 -07:00
Ogi Moore a6971c768d Move and Update test-data repo into pyqtgraph repo
To reduce complexity, and make it easier to add more images and tests,
the images in the `test-data` repository should be merged with the main
repository.  Furthermore, we can remove a lot of the subprocess work in
the image_testing.py file, as we no longer need to have it interact with
git.

The images are not the same.  Images were regenerated with Qt6, and now
have proper big and little endian handling thanks to @pijyoi

Second commit is a slightly modified variant of
2e135ab282d6007b34a3854921be54d0e9efb241 authored by @pijyoi
it is to convert qimages to RGBA8888 for testing.  Image
files were regenerated images for the big/little handling

Fixed issue with bogus test from test_NonUniformImage and generated a
new image
2021-05-31 21:05:00 -07:00
KIU Shueng Chuan cabcf6cd29 pairs: allocate and manipulate dest polygon buffer directly 2021-05-27 23:31:05 -07:00
KIU Shueng Chuan 8f4104a9ab use qpolygonf underlying buffer as backstore 2021-05-27 19:07:50 -07:00
Ogi Moore 270fc59cab Insert NaN values for connect='pairs' in Qt6
Since the QPainterPath.addPolygon(QPolygonF) does not filter out the NaN
values, we can insert NaN values to create discontinuities in the Lines,
and thus supporting connect='pairs' functionality
2021-05-27 09:38:23 -07:00
Ogi Moore 78e678c1b9 Support connect=finite for qt6 2021-05-27 09:37:23 -07:00
Luke Campagnola e29f86578f
Revert Point.angle behavior change (#1806)
* Revert behavior change of Point.angle

* Propagate Point.angle revert
2021-05-27 08:51:06 -07:00
Martin Chase 1735effea7
fix click bug on removable ROIs; test (#1804) 2021-05-26 17:14:08 -07:00
Ogi Moore 62165bbe45 Revert "Speed up arrayToQPath when connect='pairs'"
This reverts commit d62d3b182f.

Through testing, this was shown to perform quite poorly.
2021-05-25 23:30:06 -07:00
Ogi Moore c6f1d2df94 Cleanup old code, conform comments to pep8 2021-05-25 22:32:26 -07:00
Ogi Moore 07ba7be2a4 Add basic tests for arrayToQPath 2021-05-25 22:32:26 -07:00
Ogi Moore d62d3b182f Speed up arrayToQPath when connect='pairs'
As discussed earlier, the process of QDataStream >> QPainterPath is
quite slow, so this commit makes an improvement on QPainterPath creation
for the case of connect='pairs' by using a naive method of moving the
path and drawing a line on the path.  This was the fastest method
identified during testing.
2021-05-25 21:58:58 -07:00
Ogi Moore aaae0b9e1c Have MultiPlotSpeedTest use skipFiniteCheck 2021-05-25 21:58:58 -07:00
Ogi Moore 7860d641ab Perform finiteCheck on PlotCurveItem.setData
The check for NaN values in arrayToQPath is expensive, this change
attempts to do the check one time, and if no NaN values are present,
an optional flag is passed along telling arrayToQPath that the check
can be skipped
2021-05-25 21:58:58 -07:00
Ogi Moore f08d239578 Use QPolygonF for connect='all'
Since QDataStream >> QPainterPath is an expensive operation, we can
construct our QPainterPath from an open polygon instead but only if the
connect='all' mode is present.  Future optimizations work can likely
be had with constructing a polygon from each connected segment
2021-05-25 21:58:58 -07:00
KIU Shueng Chuan d220e8a6e9 Restructuring of QPainterPath ByteArray 2021-05-25 21:36:27 -07:00
Ogi Moore 7bc5f215c0
Merge pull request #1802 from fbordignon/cx_freeze_example
update cx_freeze example and add a workaround for templates
2021-05-24 14:13:07 -07:00
Fernando Bordignon a4de137535 update cx_freeze example and add a workaround for templates 2021-05-24 17:50:24 -03:00
Ogi Moore ed1653f3c5
Merge pull request #1800 from wubella/master
Fixing GLMeshItem memory leak in face drawing on 64-bit Linux (#1783)
2021-05-23 21:22:31 -07:00
Wyatt Ubellacker 7e5c90a7a4 Fixing GLMeshItem memory leak in face drawing on 64-bit Linux (#1783) 2021-05-23 18:31:49 -07:00
KIU Shueng Chuan 7499c3b375 clip values can be derived from lut shape
also makes it clear that indices won't be out of range
2021-05-22 11:34:20 +08:00
KIU Shueng Chuan 9426ef0391 don't rely on QImage-wrapped buffer being writable 2021-05-22 09:10:03 +08:00
KIU Shueng Chuan 03ddf92839 implement numba lookup 2021-05-22 08:23:47 +08:00
Martin Chase ac84f45787
callable luts still need to be put onto a substrate (#1791) 2021-05-20 07:22:49 -07:00
Kenneth Lyons bcb6a5d66a
Merge pull request #1779 from manschloemark/master
Use fallback minStep in dec mode SpinBox (Issue 1756)
2021-05-19 18:15:10 -07:00
Martin Chase a91953e93d
Bypass makeARGB in some cases (#1786)
* refactor out _ndarray_to_qimage()

* combine levels back with lut

* make use of Grayscale8, RGB888 and Indexed8 QImage formats

Grayscale8 and RGB888 images are those that are ready for display
without further processing.

* add Grayscale16

* apply the efflut early for uint16 mono/rgb, uint8 rgb

* ndarray indexing is faster than np.take

* handle uint16 rgb(a) with no levels same as levels=[0, 65535]

* add support for Format_RGBA64

* fix: support colormaps of shape (h, 1)

* check ImageItem uint8 and uint16 QImage formats

* uint16 mono with rgb lut -> RGBX8888

* got width and height swapped in array dimensions

* set ImageItem as row-major

* no need to form a 1d 32-bit lut for array indexing

you can index (y, x) into a lookup table of shape (nentry, 3) or
(nentry, 4) and get an output of shape (y, x, 3) or (y, x, 4)

* Revert "no need to form a 1d 32-bit lut for array indexing"

This reverts commit 45cf3100de.

* distinguish between levels_lut and colors_lut

this allows uint16 images with user lut to be rendered as
Format_Indexed8

* uint8 (1-chan) images should always combine to efflut

this efflut will then be used for Indexed8 format color table.

previously, we would be taking a performance hit with doing a numpy
lookup with levels_lut.

* adapt benchmarks/makeARGB.py to renderImageItem.py

* restructure uint8 and uint16 codepaths

* normalize 1-chan images to ndim==2 earlier up

* refactor long code into functions

* bug: qimage may not be assigned

* fix: assign to self.qimage only if not None

* for uint16, do rescale rather than do levels_lut lookup

* cases 2,3 are already handled

i.e. no more using lut to do rescale of uint16 image data.

* rescale rgb images by computation, not by memory lookup

* setImage() does not take an output argument

* try to be cupy compatible

use "xp" instead of numpy module

* add numba to benchmarking

* fix: lut_big is dtype uint8 with more than 256 entries

* bug: applying colors_lut needs C-order

* support float with no nans

* fix: variable could be uninitialized

* add float32 format tests

* avoid explicitly forcing to C-contiguous

* cache effective lut only if combination took place

every one of the four branches now does its own return.
this makes it easier to follow.

* fix cupy benchmark : typo in renderQImage

* remove for loop of 1 iteration

* use float32 for floating point benchmark

* superceded by renderImageItem.py

* lint

* benchmark without lut conversion

* put the lut onto the substrate

* fix editor complaints

* handle lack of cupy

* leading underscores imply privacy

Co-authored-by: KIU Shueng Chuan <nixchuan@gmail.com>
2021-05-19 17:21:12 -07:00
Mark Schloeman 1c1212e5e9 Set minStep in dec stepping SpinBox example 2021-05-16 17:37:33 -04:00
Mark Schloeman c9ea25eed6 SpinBox in dec mode sets minStep to step as fallback 2021-05-16 17:37:33 -04:00
Ogi Moore 9566e2ba36
Merge pull request #1778 from j9ac9k/fix-glvolumeitem-example
Do not attempt to avoid np.log(0), instead ignore the warning in GLVolumeItem Example
2021-05-16 10:38:07 -07:00
Ogi Moore 9624b2a049 Do not attempt to avoid np.log(0), instead ignore the warning
Fixes #1775, also took the opportunity to clean the file a bit.
2021-05-16 10:18:23 -07:00
Ogi Moore d3e0d041de
Merge pull request #1774 from pijyoi/pg_exec
implement pg.exec()
2021-05-15 22:42:59 -07:00
Martin Chase 253055003b
Add a Code of Conduct (#1773)
* Code of Conduct adapted from PuPPy and matplotlib

* improve wording; transparency in moderation; fix link
2021-05-13 15:37:07 -07:00
KIU Shueng Chuan dfddb39ce0 Revert "add QApplication.exec() to Qt5 bindings"
This reverts commit 2dad9862cb.
2021-05-14 06:16:21 +08:00
KIU Shueng Chuan 0fb0209e43 Revert "provide QApplication.exec() for PySide6 6.0"
This reverts commit 3eb69e6d9b.
2021-05-14 06:16:21 +08:00
KIU Shueng Chuan 0754602c3c fix in-library uses of exec_() 2021-05-14 06:16:21 +08:00
KIU Shueng Chuan 21296cd4f3 change all examples to use pg.exec() 2021-05-14 06:16:21 +08:00
KIU Shueng Chuan 61badc88b3 implement pg.exec() 2021-05-14 06:16:21 +08:00
Ogi Moore 1905f83047
Merge pull request #1772 from pijyoi/fix_remote
don't print out expected Exception
2021-05-13 12:22:00 -07:00
KIU Shueng Chuan 381147450d pass through any AttributeError 2021-05-13 14:43:28 +08:00
KIU Shueng Chuan 210203d628 don't print out expected Exception 2021-05-13 13:58:06 +08:00
Ogi Moore eed220e874
Merge pull request #1771 from pijyoi/fix_pyside6.1
some fixes PySide6 6.1.0
2021-05-12 21:51:01 -07:00
KIU Shueng Chuan 3eb69e6d9b provide QApplication.exec() for PySide6 6.0 2021-05-13 09:48:47 +08:00
KIU Shueng Chuan 2dad9862cb add QApplication.exec() to Qt5 bindings 2021-05-13 09:02:42 +08:00
KIU Shueng Chuan 3b32e27083 RemoteGraphicsView.py : fix deprecated mouse positions 2021-05-13 08:57:15 +08:00
KIU Shueng Chuan 70c123a95c fix localPos() deprecated warnings 2021-05-13 08:42:45 +08:00
KIU Shueng Chuan 60661f586f fix: QVector3D has no copy constructor 2021-05-13 08:23:06 +08:00
Ogi Moore 96e83b7d43
Merge pull request #1766 from pijyoi/vst_numba_toggle
VideoSpeedTest.py : Add numba checkbox
2021-05-07 08:40:03 -07:00
KIU Shueng Chuan 0503f96121 Format_RGB32 will always have alpha equal 255
this also fixes the assumption that we are on little-endian.

In [18]: qimg = QtGui.QImage(1, 1, QtGui.QImage.Format.Format_RGB32)

In [19]: qimg.fill(QtCore.Qt.GlobalColor.transparent)

In [20]: np.frombuffer(qimg.bits(), dtype=np.uint8)
Out[20]: array([  0,   0,   0, 255], dtype=uint8)
2021-05-07 18:09:02 +08:00
KIU Shueng Chuan 09ce81655d VideoSpeedTest.py : Add numba checkbox 2021-05-07 15:35:27 +08:00
Nils Nemitz bfc63bb730
Make plotting with gradients more fun (#1742)
* added convenience functions to better handle plotting with gradients

* docstring correction, example name correction

* retrying to get  documentation format right

* another attempt at cleaning up docs

* Don't hardcode timer type (and docs fixing attempt)

* more docstring re-formatting

* linebreaks in docstrings

* more documentation adjustments

* documentation pass

* some corrections to documentation

* more adjustments to documentation

* again?

* removed some whitespace and redundant blank lines, changed some checks '== None' to 'is None'

* fixed mis-spelling QColor as Qcolor
2021-05-06 23:20:21 -07:00
Martin Chase 2fb7cdafbd
more complete test yields more complete behavior (#1765) 2021-05-05 18:07:34 -07:00
Martin Chase fa1be1e5bf
show and hide properly for maxTraces; +test (#1764) 2021-05-05 17:08:04 -07:00
Kenneth Lyons cafe079910
Support horizontal HistogramLUT{Item,Widget} (#1757)
* Improve HistogramLUTItem docs, a few cosmetic changes

* Initial implementation of horizontally-oriented HistogramLUTItem

- Also adds support in HistogramLUTWidget
- Fixes AxisItem orientation bug for vertical orientation
- Make use of GradientEditorItem orientation (fixes another bug for
  vertical orientation)
- Use horizontal orientation in an example for demonstration

* Remove unused HistogramLUTItem option

* A few more minor fixups

* Copy paste bug

* Use f-strings

* Update from review and a couple more minor updates

* Woops

* Add doc for orientation arg

* Add top/bottom orientation to doc. Expand on levelMode doc a bit
2021-05-04 21:25:42 -07:00
Ogi Moore 7dd033c03b
Merge pull request #1759 from alimustafashah/master
#1758 Fixed typo in InfiniteLine (sigclicked vs. sigClicked)
2021-05-03 20:31:51 -07:00
shahmustafa54 e1b1410260 Fixed typo in InfiniteLine (sigclicked vs. sigClicked) 2021-05-04 06:03:17 +05:00
Ogi Moore cf70cf4395
Merge pull request #1754 from j9ac9k/remove-pytest-extensions-from-ci
Remove pytest extensions from ci
2021-05-01 21:28:49 -07:00
Ogi Moore 2fd5337215 Run processEvents twice to make sure plot is redrawn 2021-05-01 18:05:33 -07:00
Ogi Moore cb48ce0548 Remove pytest-cov 2021-05-01 14:23:33 -07:00
Ogi Moore 6163a60198 Remove pytest-xdist 2021-05-01 14:23:28 -07:00
Martin Chase 85e2574230
useCupy option should be settable after ImageItem init (#1749)
* do not cache the cupy so the config option can be set later

* getCupy will always return None if the option is not set

* test of failing behavior

* divorce skip from option; restore option after test
2021-04-30 10:41:11 -07:00
Fernando Bordignon 7dc4823cc6
Update symbols documentation and inverted up and down arrows of scatterplotitem (#1747) 2021-04-29 19:34:19 -07:00
pijyoi 4d6a8e4998
add usage of numba (for rescale) (#1695)
* implement rescale using numba

* workaround to pass test_makeARGB.py

* key on (input, output) manually

* remove minimum version check

* signature needs to be a list of signatures

numba considers it a mistake for single-item non-list but works around
it internally

* add numba test to test_makeARGB.py

* add numba as dependency in CI

* handle properly the case where useNumba was already True

* restore useCupy setting after test

* filter numba nan warning

* don't make changes to test_cupy_makeARGB_...
2021-04-28 22:29:09 -07:00
Nils Nemitz a7bc2b9a63
clean-up of PlotDataItem downsample methods (#1725)
* clean-up of PlotDataItem downsample methods

* high end of range at low end, not zero

Co-authored-by: Ogi Moore <ognyan.moore@gmail.com>
2021-04-28 22:07:24 -07:00
Martin Chase 4ee1fe4388
fix bug when plotting boolean arrays (#1748)
* test and fix for plotting boolean arrays

* smaller is faster

* oh, that bool went away

* tests should keep up with optimizations
2021-04-28 21:35:27 -07:00
Ogi Moore a534132c62
Various performance improvements to pg.Point (#1741)
This change makes use of QPointF methods which perform faster than the python
equivalent methods.  Furthermore, some tests are added.

* Set __slots__ to empty tuple for pg.Point
* Make Point.angle() behave as Vector.angle()
2021-04-28 21:29:47 -07:00
Ogi Moore fe66f3fd12
Merge pull request #1746 from pijyoi/fix_cprint_remote
fix: cprint of remote output needs decode()
2021-04-28 20:46:24 -07:00
KIU Shueng Chuan 306e9c2498 fix: cprint of remote output needs decode() 2021-04-28 16:38:15 +08:00
Ogi Moore 2cbc86bee1
Merge pull request #1743 from j9ac9k/cleanup-some-static-code-checks
Cleanup some static code checks
2021-04-25 22:01:06 -07:00
Ogi Moore 2d8d1d6d32 Add tmp_module fixture for test_reload 2021-04-25 21:36:42 -07:00
Ogi Moore 7c48233bfa Remove unreachable code 2021-04-25 21:36:23 -07:00
Ogi Moore 38dccf8642 Fix indentation bug with flowchart 2021-04-25 20:10:54 -07:00
Ogi Moore 00a0ddb0d4 Do not import value of mutable attribute
This was brought to the attention via the stack type checker, Easy fix so it is being
implemented.
2021-04-25 20:08:47 -07:00
Ogi Moore 4d388ee633 Use open context-manager instead of file.open()
Static code checker identified multiple places where a file is opened
but is not necessarily closed.  This commit addressed that with the
exception of RemoteGraphicsView.py
2021-04-25 17:05:05 -07:00
Ogi Moore cf95964678
Merge pull request #1738 from pijyoi/fix_font
use Format_RGB32 when using QImage as paint device
2021-04-24 09:43:42 -07:00
Ogi Moore d9a3774f6c
Merge pull request #1739 from pijyoi/manual_form
Export dialog: ParameterTree needs 2 columns
2021-04-24 09:41:40 -07:00
Ogi Moore 6a708dc203
Merge pull request #1724 from j9ac9k/use-math-module-for-single-values
Use math module methods for scalars
2021-04-23 23:10:17 -07:00
Ogi Moore 03ea368454 Clean up Errors for CodeQL analyzer
CodeQL identified some errors and warnings, which this commit cleans up.
2021-04-23 22:44:29 -07:00
Ogi Moore 329423f525 Use QTransform.rotateRadians when appropriate
In a few places in the library, we are doing the conversion from radians
to degrees just so we can call QTransform.rotate(), but there is a
QTransform.rotateRadians() method which would be more suitable, thus
making it so we do not have to handle the conversions ourselves
2021-04-23 22:43:57 -07:00
Ogi Moore e1415cb3a8 Use np.pi or math.pi instead of just pi 2021-04-23 22:43:57 -07:00
Ogi Moore 6a386e723b Fix overflow warning in QColor by using np.isfinite 2021-04-23 22:43:57 -07:00
Ogi Moore 3ea92736b8 Do not use list comprehensions with any or all
python any and all are able to break early the moment they come across a
member of the iterable that meets the condition; but having a list
comprehension nested within breaks that ability to exit early, as the
list comprehension has to finish being constructed first before it can
be evaluated
2021-04-23 22:43:57 -07:00
Ogi Moore 314121192a Use math module for isfinite or isnan for scalars
Various places in the library attempt to check if scalars are finite
via numpy methods, which are intended to be used on numpy arrays.  Using
the math module equivalent functions on scalars is significantly faster.

In a few places, I also use numpy methods explicitly (np.all vs. all)
2021-04-23 22:43:57 -07:00
Ogi Moore b0769f4be9 Use math.radians and math.degrees
Many places in the library were doing radian to degree conversion
via the manual calculation.  Doing timeit benchmarks on my system, I
am able to get a 4x speedup by using math.degrees or math.radians
instead
2021-04-23 22:43:51 -07:00
Ogi Moore 1138c67d45 Use math module trig functions for scalars
This commit replaces the use of np.sin/np.cos/np.tan uses throughout
the library with math.sin/math.cos/math.tan for scalar values
2021-04-23 22:42:46 -07:00
KIU Shueng Chuan e3372fddc5 specify that ParameterTree needs 2 columns in .ui 2021-04-24 11:21:12 +08:00
Ogi Moore c4a1cf11a1 Use clip_array or clip_scalar instead of np.clip
Significant performance issues have been identified with np.clip
and thus clip_array was created to speed up the operation.  In addition
clip_scalar was created to clip a scalar value between two other values
this commit replaces many uses of np.clip from operating on scalars to
using clip_scalar instead
2021-04-23 11:53:00 -07:00
Ogi Moore 85c726e49a Replace uses of np.log on scalers with math.log 2021-04-23 11:53:00 -07:00
Ogi Moore b01e0e0895 Remove unused function and change line calc
Using @pijyoi's suggestion regarding line calculation broadcasting
2021-04-23 11:53:00 -07:00
Ogi Moore f60fa3b534 Use clip_array instead of np.clip in GLVolumeItem 2021-04-23 11:53:00 -07:00
Ogi Moore f8cefa6284 Use hypot method to avoid over/underflow errors
Use hypot instead of manual calculation
2021-04-23 11:53:00 -07:00
Ogi Moore b0a3849960 Use math module methods for singular values
Using numpy methods that are intended for vectorized operations is
substantially slower than using the math module, so when feasible the
math module methods should be used.
2021-04-23 11:53:00 -07:00
KIU Shueng Chuan fbc86cd2c5 use Format_RGB32 when using QImage as paint device
this allows sub-pixel font antialiasing to take place.
2021-04-23 18:54:21 +08:00
Ogi Moore a9161e0794
Merge pull request #1735 from pijyoi/fix_dpr
unify _dpiRatio() and devicePixelRatio()
2021-04-22 09:52:09 -07:00
Ogi Moore 9a77c223f0
Merge pull request #1736 from pijyoi/remote_dpr
be hidpi-aware for remote rendering
2021-04-22 09:51:19 -07:00
KIU Shueng Chuan 51871cd01e be hidpi-aware for remote rendering 2021-04-22 17:26:46 +08:00
KIU Shueng Chuan f4ed46773f unify _dpiRatio() and devicePixelRatio() 2021-04-22 11:51:10 +08:00
Ogi Moore ec4d613037
Merge pull request #1730 from pijyoi/fix_powershell 2021-04-21 07:02:28 -07:00
Martin Chase d531a808e1
allow gradient position to be configured on a histogram (#1729)
* NEW features for HistgramLUTItem

* gradientPosition=('left', 'right')
* only paint if item is visible (is faster)
* link hisogram to other histograms

* fixes to be able to merge

 * drop linkHistogram (rgba needs to be better integrated)
 * make sure defaults to same as current behavior
 * draw connecting lines correctly on each side
 * add example use
2021-04-20 19:57:15 -07:00
KIU Shueng Chuan 0781f9392b use Popen instead of os.spawnle 2021-04-21 07:31:03 +08:00
Nils Nemitz a6f9a2be12
ColorMap: keep RGBA values as uint8, clean up docstrings (#1722)
* keep RGBA values as uint8, clean up docstrings

* ColorMap docstring correction

* enum mapping fix 2
2021-04-19 23:03:44 -07:00
Ogi Moore c62e51f4d8
Merge pull request #1723 from NilsNemitz/fixed_data_ordering_for_colorbaritem
Set fixed data ordering for ColorBarItem
2021-04-17 08:00:56 -07:00
Nils Nemitz 515ae5f6e3 add axisOrder='col-major' 2021-04-17 18:18:14 +09:00
Ogi Moore 2b2b8d34c2
Merge pull request #1716 from j9ac9k/cleanup-pytest-opts
Update pytest and tox configs, fix misc warnings
2021-04-16 22:52:27 -07:00
Ogi Moore 1326ebe2f4 Update numpy version used in CI from 1.19 to 1.20 2021-04-16 22:33:59 -07:00
Ogi Moore 41eadd678b Remove build docs CI job
Now that readthedocs supports building docs on pull requests, we no
longer need to build the docs ourselves as part of the CI pipeline.
2021-04-16 22:32:14 -07:00
Ogi Moore 7740de4a26 Update README table show not-supported configs 2021-04-16 22:18:11 -07:00
Ogi Moore a231c9ffb0 Update tox.ini config 2021-04-16 22:18:11 -07:00
Ogi Moore 342fbb053f Avoid implicit int conversion for mouse buttons 2021-04-15 22:50:50 -07:00
Ogi Moore 52de9554bb Emit warning about pyside2 bug preventing loading 2021-04-15 22:50:16 -07:00
Ogi Moore e735d2d9b8 Block pyopenGL tests on more macOS platforms
When running on macOS Big Sur, pyopenGL is unable to find the bindings

Previously this was assumed that it would be fixed in later versions
of Python 3.8, but that has not happened.
2021-04-15 22:08:50 -07:00
Ogi Moore 435c54d20b Adjust pytest.ini warning suppressions
Show standard library Deprecation and PendingDeprecation warnings
Remove warning filters used for older Qt bindings no longer supported
2021-04-15 21:09:11 -07:00
Ogi Moore 5c67f03b0e skip test without generating warning 2021-04-15 21:02:49 -07:00
Ogi Moore 314e4eb480 Unescaped sequence and fix typo 2021-04-15 21:02:29 -07:00
Martin Chase 6fed6d42b3
Protect makeARGB with tests and benchmarks (#1697)
* update to working

* cupy tests, too

* doubling up and down

* add more realism to the benchmarks

* name to reflect scale

* use different numbers to mean different numbers

(that sure does sound tautological)

* more sensible: order, error

* thorough check of lots of makeARGB arg combos

* docstring for tool usage

* no print needed

* better error messages

* test makeARGB using cupy, too

* skip without cupy available

* switch from conda to venv

* skip cupy runs when not available

* use endian-proof makeARGB shim in tests

* generate the asv conf to suit the system

* document running asv

* comments for future matrix goals

* put all makeARGB tests together; name for clarity

* subprocess.check_output is standard for all supported pythons

* better handle lack of git version

* use makeARGB shim

* small fixes and improvements
2021-04-15 15:51:21 -07:00
Martin Chase a465f93d9b
small TargetItem fixes (#1715)
* angle is just an int, not a method

* more TargetItem use in the example

* offset is needed before super sometimes

* use setLabel, too
2021-04-14 10:44:03 -07:00
Ogi Moore dfa225f56f
Merge pull request #1714 from j9ac9k/merge-519-in-master
Expose the `clickable` property of `PlotDataItem`. (#519)
2021-04-13 23:20:11 -07:00
Christopher Mullins 10c1e83cd7 Expose the `clickable` property of `PlotDataItem`. (#519)
* Fix the `clickable` property of `PlotDataItem`.

Currently if you attempt to set the `clickable` property of a PlotDataItem,
this property is silently ignored. The expected behavior is to set the
`clickable` property of the underlying PlotCurveItem.

* Use setCurvesClickable and curvesClickable instead

* curve is singular
2021-04-13 22:31:26 -07:00
Ogi Moore 6f74d56266
Merge pull request #1710 from pijyoi/reorder_tests
run pyqtgraph tests before examples
2021-04-11 08:10:53 -07:00
Ogi Moore d2e1f99b5e
Merge pull request #1708 from j9ac9k/remove-infiniteline-from-others-example
Remove infiniteline from others in examples
2021-04-11 08:08:25 -07:00
KIU Shueng Chuan 8cb53d321b run pyqtgraph tests before examples 2021-04-11 21:51:44 +08:00
Ogi Moore fe6ad52262 Remove infiniteline from others in examples 2021-04-10 23:10:12 -07:00
Ogi Moore 5a08650853
Improve target item - incorporate bits from PR 313 (#1318)
Overhaul TargetItem based on @lesauxvi 's PR #313
2021-04-10 22:42:44 -07:00
Ogi Moore bb90ef1ec9
Merge pull request #1707 from pijyoi/pyqt61_compat
add PyQt6 6.1 forwards compatibility
2021-04-10 20:27:04 -07:00
Ogi Moore a3443571f2
Merge pull request #1706 from ntjess/update-mkPen
promote use of '#' in mkPen
2021-04-10 20:21:53 -07:00
KIU Shueng Chuan 2aed5c36d5 no need to reconstruct PyQt6 enums
PyQt6 can serialize / deserialize enums and flags w/o us manually
casting them to int.

In PyQt6 6.0, it was okay to pass the already deserialized flag
back to the class constructor.
In PyQt6 6.1, the flags MouseButtons and KeyboardModifiers have
been renamed to MouseButton and KeyboardModifier respectively.

skipping the reconstruction allows it to work on both PyQt6 6.0 and 6.1.
note that this was already done in deserialize_mouse_event()
2021-04-11 09:53:49 +08:00
KIU Shueng Chuan 64702981d4 temporarily let PyQt6 6.1 run on PyQt6 6.0 ui files 2021-04-11 09:02:58 +08:00
KIU Shueng Chuan 4699bbad6b fix keyboard modifiers default value 2021-04-11 09:00:52 +08:00
Nathan Jessurun e890d832e0 promote use of '#' in mkPen 2021-04-10 17:52:51 -04:00
Ogi Moore 10d924818c
Merge pull request #1701 from pijyoi/fix_overflow_warning
avoid numpy scalar overflow
2021-04-08 21:54:23 -07:00
KIU Shueng Chuan 3be8cafff4 avoid numpy scalar overflow
the "offset" argument passed into rescaleData() is typically an element
of an ndarray, i.e. it comes from the lower bound value of the "levels"
ndarray. as such, arithmetic operations on it can overflow.

this triggers a runtime warning in the test suite.

the workaround is to convert it to a Python (integer) scalar.
2021-04-09 10:14:23 +08:00
Martin Chase 0f94c17d86
Fix roi get array region (#1700)
* ROI.py, getArrayRegion: Fix return mapped coordinates

The *getArrayRegion* method is defined as returning a tuple of the points
in the selected region and the mapped coordinates if the
*returnMappedCoords* keyword argument is set to True in the parent class
*ROI*.

In the *EllipseROI* class, *getArrayRegion* was overriden, however it
ignores the *returnMappedCoords* keyword argument, leading to unintended
bugs because of the change in interface between the parent class and
the subclass.

This patch fixes the above bug.
If *returnMappedCoords* is set to False, then only *arr* containing the
array region is returned. If *returnMappedCoords* is set to True, a
tuple of the array region and the mapped coordinates is returned.

NB: At the time of this commit, the same bug is present in several classes
extending *ROI*. This commit only fixes the issue for the *EllipseROI* class.

* ROI.py, PolyLineROI.getArrayRegion: Fix return mapped coordinats

The *getArrayRegion* method is defined as returning a tuple of the
points in the selected region and the mapped coordinates if the
*returnMappedCoords* keyword argument is set to True in the parent class
*ROI*.

In the *PolyLineROI* class, *getArrayRegion* was overriden, however it
ignores the *returnMappedCoords* keyword argument, leading to unintended
bugs because of the change in interface between the parent class and the
subclass.

This patch fixes the above bug.  If *returnMappedCoords* is set to
False, then only *arr* containing the array region is returned. If
*returnMappedCoords* is set to True, a tuple of the array region and the
mapped coordinates is returned.

* remove merge conflict cruft

* lint

Co-authored-by: Malik Olivier Boussejra <malik@boussejra.com>
2021-04-08 13:43:30 -07:00
501 changed files with 18381 additions and 7048 deletions

46
.flake8
View File

@ -3,47 +3,5 @@ exclude = .git,.tox,__pycache__,doc,old,build,dist
show_source = True
statistics = True
verbose = 2
select =
E101,
E112,
E122,
E125,
E133,
E223,
E224,
E242,
E273,
E274,
E901,
E902,
W191,
W601,
W602,
W603,
W604,
E124,
E231,
E211,
E261,
E271,
E272,
E304,
F401,
F402,
F403,
F404,
E501,
E502,
E702,
E703,
E711,
E712,
E721,
F811,
F812,
F821,
F822,
F823,
F831,
F841,
W292
max-line-length = 88
extend-ignore = E203, W503

View File

@ -16,35 +16,30 @@ jobs:
- python-version: "3.7"
qt-lib: "pyqt"
qt-version: "PyQt5~=5.12.0"
numpy-version: "~=1.17.0"
numpy-version: "~=1.18.0"
- python-version: "3.7"
qt-lib: "pyside"
qt-version: "PySide2~=5.12.0"
numpy-version: "~=1.17.0"
numpy-version: "~=1.18.0"
- python-version: "3.8"
qt-lib: "pyqt"
qt-version: "PyQt5~=5.15.0"
numpy-version: "~=1.19.0"
numpy-version: "~=1.21.0"
- python-version: "3.8"
qt-lib: "pyside"
qt-version: "PySide2~=5.15.0"
numpy-version: "~=1.19.0"
numpy-version: "~=1.21.0"
- python-version: "3.9"
qt-lib: "pyqt"
qt-version: "PyQt6"
numpy-version: "~=1.19.0"
numpy-version: "~=1.21.0"
- python-version: "3.9"
qt-lib: "pyside"
qt-version: "PySide6"
numpy-version: "~=1.19.0"
numpy-version: "~=1.21.0"
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Checkout test-data
uses: actions/checkout@v2
with:
repository: pyqtgraph/test-data
path: .pyqtgraph/test-data
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
@ -69,10 +64,10 @@ jobs:
shell: cmd
- name: Install Dependencies
run: |
pip install --upgrade pip
pip install ${{ matrix.qt-version }} numpy${{ matrix.numpy-version }} scipy pyopengl h5py matplotlib
pip install .
pip install pytest pytest-cov pytest-xdist coverage
python -m pip install --upgrade pip setuptools wheel
python -m pip install ${{ matrix.qt-version }} numpy${{ matrix.numpy-version }} scipy pyopengl h5py matplotlib numba
python -m pip install --use-feature=in-tree-build .
python -m pip install pytest
- name: "Install Linux VirtualDisplay"
if: runner.os == 'Linux'
run: |
@ -80,14 +75,14 @@ jobs:
sudo apt-get install -y libxkbcommon-x11-0 x11-utils
sudo apt-get install --no-install-recommends -y libyaml-dev libegl1-mesa libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0
sudo apt-get install -y libopengl0
pip install pytest-xvfb
python -m pip install pytest-xvfb
- name: 'Debug Info'
run: |
echo python location: `which python`
echo python version: `python --version`
echo pytest location: `which pytest`
echo installed packages
pip list
python -m pip list
echo pyqtgraph system info
python -c "import pyqtgraph as pg; pg.systemInfo()"
shell: bash
@ -106,10 +101,8 @@ jobs:
- name: Run Tests
run: |
mkdir $SCREENSHOT_DIR
pytest . -v \
-n auto \
--junitxml pytest.xml \
--cov pyqtgraph --cov-report=xml --cov-report=html
pytest tests -v
pytest examples -v
shell: bash
- name: Upload Screenshots
uses: actions/upload-artifact@v2
@ -120,29 +113,9 @@ jobs:
env:
SCREENSHOT_DIR: ./screenshots
build-docs:
name: build docs
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.9
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install Dependencies
run: |
cd doc
python -m pip install -r requirements.txt
- name: Build Documentation
run: |
cd doc
make html SPHINXOPTS='-W --keep-going -v'
build-wheel:
name: build wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Python 3.9

33
.github/workflows/python-publish.yml vendored Normal file
View File

@ -0,0 +1,33 @@
# This workflows will upload a Python Package using setup.py/twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Upload Python Package
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install wheel twine setuptools
- name: Build and publish
env:
TWINE_USERNAME: __token__
# The PYPI_PASSWORD must be a pypi token with the "pypi-" prefix with sufficient permissions to upload this package
# https://pypi.org/help/#apitoken
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py sdist bdist_wheel
twine upload dist/*

1
.gitignore vendored
View File

@ -108,3 +108,4 @@ rtr.cvs
.tags*
.asv/
asv.conf.json

139
CHANGELOG
View File

@ -1,3 +1,142 @@
pyqtgraph-0.12.3
Highlights:
- PlotCurveItem render speed is now substantially faster
- #1868/#1873 Example app now has filter text input
- #1910 PlotSpeedTest now has parameter tree control panel
New Features:
- #1844 More parameter item types (File, Calendar, ProgressBar, Font, Pen, Slider)
- #1865 Matplotlib colormaps viridis, plasma, magma and inferno are now included in pyqtgraph
- #1911 Extend Colormap with HSL cycles and subset generation
- #1932 Make anti-aliasing optional for paintGL in PlotCurveItem
- #1944 Expand use of QColor functions/methods, including setNamedColor
- #1952 Add checklist parameter item
- #1998 ThreadTrace can now save to a file
Performance Enhancement:
- #1927 Reduce ColorMap inefficiencies
- #1956 use QByteArray as backing store in arrayToQPath
- #1965 perform arrayToQPath in chunks
Bug Fixes:
- #1845 Fix zoom behavior with showGrid by separating mouse events stolen by AxisItem
- #1860 RemoteGraphicsView and RemoteSpeedTest now work under windows venv environments
- #1865 Fixed matplotlib colormap importer code
- #1869 Fix ColorBarItem tick position on export
- #1871 Allow adding items to GLViewWidget before showing plot
- #1875 Fix calls in mouse methods in GLViewWidgets due to missing event.localPos() in PyQt6
- #1876 Fix for improper placement of ROI handle positions in some cases
- #1889/#2003 Fix call to drawText in GLTextItem and GLGradientLegendItem on Python 3.10
- #1897/#1902 Re-enable "experimental" feature with fix for PlotCurveItem with OpenGL on Windows
- #1907 Fix GLVolumeItem example for arm64 platforms
- #1909 Check if AxisItem.label is None before and exit early in resizeEvent
- #1920 arrayToQPath can handle empty paths
- #1936 QPolygonF creation can now handle empty arrays
- #1968 Fix output of clip_array in colormap.modulatedBarData not being assigned
- #1973 Fix PlotItem.updateDecimate unhiding intentionally hidden curves
- #1974 Fix ImageView levelMode with levelMode == 'rgba'
- #1987 Fix HistogramLUTItem itemChanged with use of autoLevel
- #2009 Fix ROI curves hidding in ImageView
API/Behavior Changes:
- #1992 Reverted to traditional log10 mode for PlotDataItem
- #1840 Allow border=False in GraphicsLayout
- #1846 Reduced pollution to pg.namespace
- #1853 ColorMap.getColors and getStops behavior changes
- #1864 Draw GradientLegend in ViewBox coordinates
- #1885 Raise TypeError instead of general Exception if functions.eq is unable to determine equality
- #1903 Cleanup GLViewWidget
- #1908 More readable parameters for ColorBarItem
- #1914 Emit deprecation warning for use of pyqtgraph.ptime
- #1928 Restore previous signature of TargetItem.setPos
- #1940 fix log mode by reverting to previous formulation
- #1954 Deprecate use of values opt for list parameter type
- #1995 ColorButton now takes optional padding argument instead of hardcoded value of 6
Other:
- #1862/#1901 MetaArray now under deprecation warning, to be removed in a future version
- #1892 Add GLPainterItem Example
- #1844 Debugged elusive intermitted CI segfault
- #1870/#1891 Updated README.md
- #1895 Update CONTRIBUTING.md
- #1913 Bump sphinx and theme versions
- #1919 Re-organize paramtypes
- #1935 Remove some unused imports
- #1939 Remove usage of python2_3.py
- #1941 Remove str casting of QTextEdit.toPlainText output
- #1942 Add EOF newline to files missing it
- #1943 Remove python2 code paths
- #1951 Fix typos in docs
- #1957 Bump minimum numpy version to 1.18
- #1968 Fix ImageView calling deprecated QGraphicsItem.scale()
- #1985 delegate float LUTs to makeARGB with warning
- #2014 Replace couple absolute imports with relative imports
pyqtgraph-0.12.2
Highlights
- Qt6 6.0 support has been removed in favor of Qt6 6.1+
- More numba utilization, specifically for makeARGB
- Substantial ImageItem performance improvements have been made thanks to @pijyoi and @outofculture
- Significant performance improvements made to ScatterPlotItem and LinePlots
- More ColorMap features/support (more are coming!)
New Features
- #1318 Added TargetItem
- #1707 Added Qt 6.1 support
- #1729 Allow gradient position to be configured on a histogram
- #1742 Better support for plotting with gradients
- #1776 Add GLTextItem
- #1797 Add ColorMap linearization (using CIELab calculations), colorDistance functionality
- #1865 Include viridis, magma, plasma, inferno, and cividis colormaps
- #1868/#1873 Example app now has a filter text box to search for relevant examples
Performance enhancement:
- #1738, #1695, 1786, #1768, 1794 - ImageItem/makeARGB performance improvements
- #1724 Use math module for scalar values math instead of numpy functions
- #1796 Greatly speed up line plots with use-case of connect='all'
- #1817 Speed up some cases of connect='finite' (few discontinuities)
- #1829 Use QPainter.drawPixmapFragments for ScatterPlotItem
Bug Fixes:
- #1700 Fixed ROI getArrayRegion
- #1748 Fixed bug when plotting boolean arrays in PlotDataItem
- #1791 Callable LUTs being used on the ImageItem substrates
- #1783 Fix memory leak in GLMeshItem
- #1802 Updated cx_freeze example and added workaround for template files
- #1804 Fix mouseClick handling for Qt6 on ROIs
- #1799 Force cameraPosition() to return a Vector in GLViewWidget
- #1809 Sanitize ShowGrid Alpha Input PlotItem
- #1816 Fix bug with Parameter value failing with numpy array-like values
- #1827 Fix BusyCursor to use internal stack provided by setOverrideCursor/restoreOverrideCursor
- #1833 Fix ScatterPlot render issues for PyQt6 6.1.0
- #1843 Fix zoom only applied to y-axis with show grid
- #1860 Fix pyqtgraph multiprocessing on Windows inside a venv environment
- #1869 Fix color bar ticks not being drawn correctly during export
- #1865 Fix matplotlib colormap import code
- #1876 Fix LineROI handle positions being way off-base in some circumstances
- #1871 Allow adding items to GLViewWidget before calling GLViewWidget.show()
- #1864 Draw GradientLegend in ViewBox coordinate system with correct orientation
- #1875 Fixed mouse events in GLViewWidget for PyQt6 bindings
API/Behavior Changes:
- #519 Expose clickable property in PlotDataItem
- #1772 Keep ColorMap values for RGBA as uint8
- #1736 RemoteGraphicsView is now hidpi aware
- #1779 Have SpinBox use fallback minStep in dec mode
- #1706 Colors defined with hex string values must start with a #
- #1819 Added method to disable autoscaling for HistogramLUTItem
- #1638 Expose number of subsamples in ImageItem auto-level determination
- #1824 Remove little-endian assumption for image export
Other
- #1807 Merge pyqtgraph/test-data repo into main repo, move test files to tests directory
- #1862 Scheduled deprecation for MetaArray module
- #1846 Cleaned up pg namespace
pyqtgraph-0.12.1
New Features

135
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,135 @@
# Code of Conduct
Diversity is one of our huge strengths, but it can also lead to communication issues. To support a welcoming environment
for all, regardless of individual differences, we have a few ground rules that we ask people to adhere to when they
participate in this community. These rules apply equally to founders, organizers, contributors, users and affiliates —
in short, to all participants.
This isnt an exhaustive list of things that you must do, or cant do. Rather, take it in the spirit in which its
intended. Its a guide to make it easier to enrich all of us and the technical communities in which we participate, and
which we represent.
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for
everyone, regardless of background or identity. This includes, but is not limited to, members of any race, ethnicity,
culture, national origin, color, immigration status, social and economic class, educational level, sex, sexual
orientation, gender identity and expression, age, size, family status, political belief, religion, level of experience,
and mental or physical ability.
We pledge to be respectful. Not all of us will agree all the time, but disagreement is no excuse for poor behavior and
poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a
personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a
productive one. Members of the PyQtGraph community should be respectful when dealing with each other as well as with
people outside the community.
We pledge to be welcoming, supportive, kind and professional. We pledge to act and interact in ways that contribute to
an open, diverse, inclusive, and healthy community. We pledge not insult or put down other participants, individually or
as a group. Harassment and other exclusionary behavior arent acceptable.
## Examples
Examples of behavior that contributes to a positive environment for our community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall community
Examples of unacceptable behavior include:
* Violent threats or language directed against another person.
* Discriminatory jokes and language.
* Posting sexually explicit or violent material.
* Posting (or threatening to post) other peoples personally identifying information ("doxing").
* Personal insults, especially those using racist or sexist terms.
* Unwelcome sexual attention.
* Repeated harassment of others. In general, if someone asks you to stop, then stop.
* Advocating for, or encouraging, any of the above behavior.
## Where does this code of conduct apply
This Code of Conduct applies within all online community spaces, official organized meetups, and when an individual is
officially representing the community in public spaces, online or offline.
## What to do in case of violations
If you believe someone is violating the code of conduct, we ask that you report it by contacting any of the following
individuals, being sure to include mention of your message being about a "PyQtGraph conduct violation":
* Ognyan Moore @j9ac9k <ognyan.moore@gmail.com>
* Martin Chase @outofculture <outofculture@gmail.com>
* Nathan Jessurun @ntjess <ntjessu@gmail.com>
All complaints will be reviewed and investigated promptly and fairly. All reports will be kept confidential. In some
cases, we may determine that a public statement will need to be made. If thats the case, the identities of all victims
and reporters will remain confidential unless those individuals instruct us otherwise.
If you believe anyone is in physical danger, please notify appropriate law enforcement first. If you are unsure which
law enforcement agency is appropriate, please include this in your report and we will attempt to notify them.
### What to include in the report
* Your contact information (so we can get in touch with you if we need to follow up)
* Names of any individuals involved (real names, nicknames, or pseudonyms). If there were other witnesses besides you,
please try to include them as well.
* When and where the incident occurred. Please be as specific as possible.
* Your account of what occurred. If there is a publicly available record (e.g., a mailing list archive or a public chat
logger) please include a link. Our Slack is currently on a free plan that does not retain more than 10,000 messages of
history, if an incident occurred on Slack please take a screenshot so it is not lost.
* Any extra context you believe existed for the incident.
* Whether you believe this incident is ongoing.
* Any other information you believe we should have.
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take
appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for
moderation decisions when appropriate. This removal should be as transparent as possible, with information available in
the same scope of context as the original moderated content, linking to an incident report, the acting moderators,
and/or this document as appropriate.
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
Upon receiving a report of misconduct, the staff must review the incident and determine the following:
* What happened.
* Whether this event constitutes a code of conduct violation.
* Who the bad actor(s) was.
* Whether this is an ongoing situation.
* If any previous disiplinary measures are relevent and in effect.
* If there is a threat to anyones physical safety.
* What impact this has had on the community.
After the conduct committee has a complete account of the events they need to make a decision as to how to resolve the
case. Resolutions might include:
* Nothing (if we determine no violation occurred).
* A private reprimand from the staff to the individual(s) involved, providing clarity around the nature of the
violation, and an explanation of why the behavior was inappropriate.
* A request for a public or private apology.
* A public reprimand.
* An imposed vacation (for example, asking someone to "take a week off" from Slack).
* A permanent or temporary ban from some or all PyQtGraph spaces (Slack, github, mailing list or events) or from
communicating, in public or in private, with some are all of the members of our community.
* Contacting law enforcement.
A response must be sent within one week to the person who filed the report with either a resolution or an explanation of
why the situation is not yet resolved.
A Code of Conduct transparency report will then be published
to [the PyQtGraph users' list](https://groups.google.com/g/pyqtgraph) with anonymized information about any violations
that might have occurred. This report should be handled with care not to divulge personally identifying information
about victims, reporters, and violators, and should serve as a means to ensure that members will be comfortable
reporting violations and that our community will be kept accountable for supporting and encouraging safe spaces.
## Attribution
This Code of Conduct is adapted from
the [Contributor Covenant, version 2.0](https://www.contributor-covenant.org/version/2/0/code_of_conduct.html) and
the [PuPPy Code of Conduct](https://www.pspython.com/pages/code-of-conduct/).

View File

@ -1,72 +1,92 @@
# Contributing to PyQtGraph
Contributions to pyqtgraph are welcome!
Contributions to pyqtgraph are welcome! Be kind and respectful! See [our Code of Conduct](CODE_OF_CONDUCT.md) for details.
Please use the following guidelines when preparing changes:
## Submitting Code Changes
## Development Environment Creation
* The preferred method for submitting changes is by github pull request against the "master" branch.
* Pull requests should include only a focused and related set of changes. Mixed features and unrelated changes may be rejected.
* For major changes, it is recommended to discuss your plans on the mailing list or in a github issue before putting in too much effort.
* The following deprecations are being considered by the maintainers
* `pyqtgraph.opengl` may be deprecated and replaced with `VisPy` functionality
* After v0.11, pyqtgraph will adopt [NEP-29](https://numpy.org/neps/nep-0029-deprecation_policy.html) which will effectively mean that python2 support will be deprecated
* Qt4 will be deprecated shortly, as well as Qt5<5.9 (and potentially <5.12)
First thing to do is fork the repository, and clone your own fork to your local computer.
```bash
git clone https://github.com/<username>/pyqtgraph.git
cd pyqtgraph
```
While there is nothing preventing users from using `conda` environments, as a general principle, we recommend using the `venv` module for creating an otherwise empty virtual environment. Furthermore, at this time, WSL is not supported (it can likely be made to work, but you're on your own if you go down this route).
```bash
python3.9 -m venv .venv
source .venv/bin/activate
# on windows this would be .venv/Scripts/activate
python -m pip install --upgrade wheel setuptools pip
python -m pip install numpy scipy pyside6 -e .
```
Before making changes to the code-base, create a different branch with a name that should be unique (this makes it easier for maintainers to examine the proposed changes locally).
```bash
git switch -c my-new-feature
```
When you're ready to submit the pull request, do so via the github, and the target of the pull request should be the `master` branch in the pyqtgraph repo.
Pull requests should include only a focused and related set of changes. Mixed features and unrelated changes may be rejected.
For major changes, it is recommended to discuss your plans on the mailing list or in a github issue/discussion before putting in too much effort.
PyQtGraph has adopted [NEP-29](https://numpy.org/neps/nep-0029-deprecation_policy.html) which governs the timeline for phasing out support for numpy and python versions.
## Documentation
* Writing proper documentation and unit tests is highly encouraged. PyQtGraph uses pytest style testing, so tests should usually be included in a tests/ directory adjacent to the relevant code.
* Documentation is generated with sphinx; please check that docstring changes compile correctly
* Writing proper documentation and unit tests is highly encouraged. PyQtGraph uses [`pytest`](https://docs.pytest.org/) for testing.
* Documentation is generated with sphinx, and usage of [numpy-docstyle](https://numpydoc.readthedocs.io/en/latest/format.html) is encouraged (many places in the library do not use this docstring style at present, it's a gradual process to migrate).
* The docs built for this PR can be previewed by clicking on the "Details" link for the read-the-docs entry in the checks section of the PR conversation page.
## Style guidelines
### Rules
### Formatting ~~Rules~~ Suggestions
* PyQtGraph prefers PEP8 for most style issues, but this is not enforced rigorously as long as the code is clean and readable.
* Use `python setup.py style` to see whether your code follows the mandatory style guidelines checked by flake8.
* Exception 1: All variable names should use camelCase rather than underscore_separation. This is done for consistency with Qt
* Exception 2: Function docstrings use ReStructuredText tables for describing arguments:
```text
============== ========================================================
**Arguments:**
argName1 (type) Description of argument
argName2 (type) Description of argument. Longer descriptions must
be wrapped within the column guidelines defined by the
"====" header and footer.
============== ========================================================
```
QObject subclasses that implement new signals should also describe
these in a similar table.
* Variable and Function/Methods that are intended to be part of the public API should be camelCase.
* "Private" methods/variables should have a leading underscore (`_`) before the name.
### Pre-Commit
PyQtGraph developers are highly encouraged to (but not required) to use [`pre-commit`](https://pre-commit.com/). `pre-commit` does a number of checks when attempting to commit the code to ensure it conforms to various standards, such as `flake8`, utf-8 encoding pragma, line-ending fixers, and so on. If any of the checks fail, the commit will be rejected, and you will have the opportunity to make the necessary fixes before adding and committing a file again. This ensures that every commit made conforms to (most) of the styling standards that the library enforces; and you will most likely pass the code style checks by the CI.
PyQtGraph developers are highly encouraged to (but not required) to use [`pre-commit`](https://pre-commit.com/). `pre-commit` does a number of checks when attempting to commit the code to being committed, such as ensuring no large files are accidentally added, address mixed-line-endings types and so on. Check the [pre-commit documentation](https://pre-commit.com) on how to setup.
To make use of `pre-commit`, have it available in your `$PATH` and run `pre-commit install` from the root directory of PyQtGraph.
## Testing
## Testing Setting up a test environment
### Dependencies
### Basic Setup
* tox
* tox-conda
* pytest
* pytest-cov
* pytest-xdist
* Optional: pytest-xvfb
* Optional: pytest-xvfb (used on linux with headless displays)
If you have `pytest<5` (used in python2), you may also want to install `pytest-faulthandler==1.6` plugin to output extra debugging information in case of test failures. This isn't necessary with `pytest>=5`
To run the test suite, after installing the above dependencies run
```bash
python -m pytest examples tests
```
### Tox
As PyQtGraph supports a wide array of Qt-bindings, and python versions, we make use of `tox` to test against most of the configurations in our test matrix. As some of the qt-bindings are only installable via `conda`, `conda` needs to be in your `PATH`, and we utilize the `tox-conda` plugin.
As PyQtGraph supports a wide array of Qt-bindings, and python versions, we make use of `tox` to test against as many supported configurations as feasible. With tox installed, simply run `tox` and it will run through all the configurations. This should be done if there is uncertainty regarding changes working on specific combinations of PyQt bindings and/or python versions.
* Tests for a module should ideally cover all code in that module, i.e., statement coverage should be at 100%.
* To measure the test coverage, un `pytest --cov -n 4` to run the test suite with coverage on 4 cores.
### Continuous Integration
### Continous Integration
For our Continuous Integration, we utilize Github Actions. Tested configurations are visible on [README](README.md).
For our Continuous Integration, we utilize Azure Pipelines. Tested configurations are visible on [README](README.md). More information on coverage and test failures can be found on the respective tabs of the [build results page](https://dev.azure.com/pyqtgraph/pyqtgraph/_build?definitionId=1)
### Benchmarks
( *Still under development* ) To ensure this library is performant, we use [Air Speed Velocity (asv)](https://asv.readthedocs.io/en/stable/) to run benchmarks. For developing on core functions and classes, be aware of any impact your changes have on their speed. To configure and run asv:
```bash
pip install asv
python setup.py asv_config
asv run
```
( TODO publish results )

View File

@ -23,29 +23,47 @@ 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:
* All minor versions of Python released 42 months prior to the project, and at minimum the two latest minor versions.
* All minor versions of numpy released in the 24 months prior to the project, and at minimum the last three minor versions.
* All minor versions of Qt 5 and Qt 6 currently supported by upstream Qt
* All Qt5 versions from 5.12-5.15, and Qt6 6.1
Currently this means:
* Python 3.7+
* Qt 5.12-6.0
* Required
* PyQt5, PyQt6, PySide2 or PySide6
* `numpy` 1.17+
* Optional
* `scipy` for image processing
* `pyopengl` for 3D graphics
* `pyopengl` on macOS Big Sur only works with python 3.9.1+
* `hdf5` for large hdf5 binary format support
* `colorcet` for supplemental colormaps
* [`cupy`](https://docs.cupy.dev/en/stable/install.html) for CUDA-enhanced image processing
* On Windows, CUDA toolkit must be >= 11.1
* Qt 5.12-5.15, 6.1
* [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.18+
### 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`] | <ul><li> Image processing through [`ndimage`]</li><li> Data array filtering through [`signal`] </li><ul> |
| [`pyopengl`] | <ul><li> 3D graphics </li><li> Faster image processing </li><li>Note: on macOS Big Sur only works with python 3.9.1+</li></ul> |
| [`h5py`] | <ul><li> Export in hdf5 format </li></ul> |
| [`colorcet`] | <ul><li> Add a collection of perceptually uniform colormaps </li></ul> |
| [`matplotlib`] | <ul><li> Export of PlotItem in matplotlib figure </li><li> Add matplotlib collection of colormaps </li></ul> |
| [`cupy`] | <ul><li> CUDA-enhanced image processing </li><li> Note: On Windows, CUDA toolkit must be >= 11.1 </li></ul> |
| [`numba`] | <ul><li> Faster image processing </li></ul> |
[`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
-----------------------
@ -55,11 +73,14 @@ The following table represents the python environments we test in our CI system.
| Qt-Bindings | Python 3.7 | Python 3.8 | Python 3.9 |
| :------------- | :----------------: | :----------------: | :----------------: |
| PySide2-5.12 | :white_check_mark: | :x: | :x: |
| PyQt5-5.12 | :white_check_mark: | :x: | :x: |
| PySide2-5.15 | :x: | :white_check_mark: | :x: |
| PyQt5-5.15 | :x: | :white_check_mark: | :x: |
| PySide6-6.0 | :x: | :x: | :white_check_mark: |
| PyQt6-6.0 | :x: | :x: | :white_check_mark: |
| PyQt5-5.12 | :white_check_mark: | | :x: |
| PySide2-5.15 | | :white_check_mark: | |
| PyQt5-5.15 | | :white_check_mark: | |
| PySide6-6.1 | | | :white_check_mark: |
| PyQt6-6.1 | | | :white_check_mark: |
* :x: - Not compatible
* :white_check_mark: - Tested
Support
-------
@ -70,14 +91,14 @@ Support
Installation Methods
--------------------
* From PyPI:
* From PyPI:
* Last released version: `pip install pyqtgraph`
* Latest development version: `pip install git+https://github.com/pyqtgraph/pyqtgraph@master`
* From conda
* Last released version: `conda install -c conda-forge pyqtgraph`
* To install system-wide from source distribution: `python setup.py install`
* Many linux package repositories have release versions.
* To use with a specific project, simply copy the pyqtgraph subdirectory
* To use with a specific project, simply copy the PyQtGraph subdirectory
anywhere that is importable from your project.
Documentation
@ -85,7 +106,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
-------

View File

@ -1,140 +0,0 @@
{
// The version of the config file format. Do not change, unless
// you know what you are doing.
"version": 1,
// The name of the project being benchmarked
"project": "pyqtgraph",
// The project's homepage
"project_url": "http://pyqtgraph.org/",
// The URL or local path of the source code repository for the
// project being benchmarked
"repo": ".",
// List of branches to benchmark. If not provided, defaults to "master"
// (for git) or "default" (for mercurial).
"branches": ["master"], // for git
// "branches": ["default"], // for mercurial
// The DVCS being used. If not set, it will be automatically
// determined from "repo" by looking at the protocol in the URL
// (if remote), or by looking for special directories, such as
// ".git" (if local).
// "dvcs": "git",
// The tool to use to create environments. May be "conda",
// "virtualenv" or other value depending on the plugins in use.
// If missing or the empty string, the tool will be automatically
// determined by looking for tools on the PATH environment
// variable.
"environment_type": "conda",
// timeout in seconds for installing any dependencies in environment
// defaults to 10 min
//"install_timeout": 600,
// the base URL to show a commit for the project.
"show_commit_url": "http://github.com/pyqtgraph/pyqtgraph/commit/",
// The Pythons you'd like to test against. If not provided, defaults
// to the current version of Python used to run `asv`.
"pythons": ["2.7", "3.8"],
// The matrix of dependencies to test. Each key is the name of a
// package (in PyPI) and the values are version numbers. An empty
// list or empty string indicates to just test against the default
// (latest) version. null indicates that the package is to not be
// installed. If the package to be tested is only available from
// PyPi, and the 'environment_type' is conda, then you can preface
// the package name by 'pip+', and the package will be installed via
// pip (with all the conda available packages installed first,
// followed by the pip installed packages).
//
"matrix": {
"numpy": [],
"numba": [],
"pyqt": ["4", "5"],
},
// Combinations of libraries/python versions can be excluded/included
// from the set to test. Each entry is a dictionary containing additional
// key-value pairs to include/exclude.
//
// An exclude entry excludes entries where all values match. The
// values are regexps that should match the whole string.
//
// An include entry adds an environment. Only the packages listed
// are installed. The 'python' key is required. The exclude rules
// do not apply to includes.
//
// In addition to package names, the following keys are available:
//
// - python
// Python version, as in the *pythons* variable above.
// - environment_type
// Environment type, as above.
// - sys_platform
// Platform, as in sys.platform. Possible values for the common
// cases: 'linux2', 'win32', 'cygwin', 'darwin'.
//
"exclude": [
{"python": "3.8", "pyqt": "4"},
],
//
// "include": [
// // additional env for python2.7
// {"python": "2.7", "numpy": "1.8"},
// // additional env if run on windows+conda
// {"platform": "win32", "environment_type": "conda", "python": "2.7", "libpython": ""},
// ],
// The directory (relative to the current directory) that benchmarks are
// stored in. If not provided, defaults to "benchmarks"
"benchmark_dir": "benchmarks",
// The directory (relative to the current directory) to cache the Python
// environments in. If not provided, defaults to "env"
"env_dir": ".asv/env",
// The directory (relative to the current directory) that raw benchmark
// results are stored in. If not provided, defaults to "results".
"results_dir": ".asv/results",
// The directory (relative to the current directory) that the html tree
// should be written to. If not provided, defaults to "html".
"html_dir": ".asv/html",
// The number of characters to retain in the commit hashes.
// "hash_length": 8,
// `asv` will cache wheels of the recent builds in each
// environment, making them faster to install next time. This is
// number of builds to keep, per environment.
"build_cache_size": 5
// The commits after which the regression search in `asv publish`
// should start looking for regressions. Dictionary whose keys are
// regexps matching to benchmark names, and values corresponding to
// the commit (exclusive) after which to start looking for
// regressions. The default is to start from the first commit
// with results. If the commit is `null`, regression detection is
// skipped for the matching benchmark.
//
// "regressions_first_commits": {
// "some_benchmark": "352cdf", // Consider regressions only after this commit
// "another_benchmark": null, // Skip regression detection altogether
// }
// The thresholds for relative change in results, after which `asv
// publish` starts reporting regressions. Dictionary of the same
// form as in ``regressions_first_commits``, with values
// indicating the thresholds. If multiple entries match, the
// maximum is taken. If no entry matches, the default is 5%.
//
// "regressions_thresholds": {
// "some_benchmark": 0.01, // Threshold of 1%
// "another_benchmark": 0.5, // Threshold of 50%
// }
}

View File

@ -0,0 +1,30 @@
import numpy as np
import pyqtgraph as pg
rng = np.random.default_rng(12345)
class _TimeSuite:
params = ([10_000, 100_000, 1_000_000], ['all', 'finite', 'pairs', 'array'])
def setup(self, nelems, connect):
self.xdata = np.arange(nelems, dtype=np.float64)
self.ydata = rng.standard_normal(nelems, dtype=np.float64)
if connect == 'array':
self.connect_array = np.ones(nelems, dtype=bool)
if self.have_nonfinite:
self.ydata[::5000] = np.nan
def time_test(self, nelems, connect):
if connect == 'array':
connect = self.connect_array
pg.arrayToQPath(self.xdata, self.ydata, connect=connect)
class TimeSuiteAllFinite(_TimeSuite):
def __init__(self):
super().__init__()
self.have_nonfinite = False
class TimeSuiteWithNonFinite(_TimeSuite):
def __init__(self):
super().__init__()
self.have_nonfinite = True

View File

@ -1,72 +0,0 @@
import numpy as np
from pyqtgraph.functions import makeARGB
class TimeSuite(object):
def __init__(self):
self.c_map = None
self.float_data = None
self.uint8_data = None
self.uint8_lut = None
self.uint16_data = None
self.uint16_lut = None
def setup(self):
size = (500, 500)
self.float_data = {
'data': np.random.normal(size=size),
'levels': [-4., 4.],
}
self.uint16_data = {
'data': np.random.randint(100, 4500, size=size).astype('uint16'),
'levels': [250, 3000],
}
self.uint8_data = {
'data': np.random.randint(0, 255, size=size).astype('ubyte'),
'levels': [20, 220],
}
self.c_map = np.array([
[-500., 255.],
[-255., 255.],
[0., 500.],
])
self.uint8_lut = np.zeros((256, 4), dtype='ubyte')
for i in range(3):
self.uint8_lut[:, i] = np.clip(np.linspace(self.c_map[i][0], self.c_map[i][1], 256), 0, 255)
self.uint8_lut[:, 3] = 255
self.uint16_lut = np.zeros((2 ** 16, 4), dtype='ubyte')
for i in range(3):
self.uint16_lut[:, i] = np.clip(np.linspace(self.c_map[i][0], self.c_map[i][1], 2 ** 16), 0, 255)
self.uint16_lut[:, 3] = 255
def make_test(dtype, use_levels, lut_name, func_name):
def time_test(self):
data = getattr(self, dtype + '_data')
makeARGB(
data['data'],
lut=getattr(self, lut_name + '_lut', None),
levels=use_levels and data['levels'],
)
time_test.__name__ = func_name
return time_test
for dt in ['float', 'uint16', 'uint8']:
for levels in [True, False]:
for ln in [None, 'uint8', 'uint16']:
name = f'time_makeARGB_{dt}_{"" if levels else "no"}levels_{ln or "no"}lut'
setattr(TimeSuite, name, make_test(dt, levels, ln, name))
if __name__ == "__main__":
ts = TimeSuite()
ts.setup()

View File

@ -0,0 +1,139 @@
# -*- coding: utf-8 -*-
import numpy as np
import pyqtgraph as pg
try:
import cupy as cp
pg.setConfigOption("useCupy", True)
except ImportError:
cp = None
try:
import numba
except ImportError:
numba = None
def renderQImage(*args, **kwargs):
imgitem = pg.ImageItem(axisOrder='row-major')
if 'autoLevels' not in kwargs:
kwargs['autoLevels'] = False
imgitem.setImage(*args, **kwargs)
imgitem.render()
def prime_numba():
shape = (64, 64)
lut_small = np.random.randint(256, size=(256, 3), dtype=np.uint8)
lut_big = np.random.randint(256, size=(512, 3), dtype=np.uint8)
for lut in [lut_small, lut_big]:
renderQImage(np.zeros(shape, dtype=np.uint8), levels=(20, 220), lut=lut)
renderQImage(np.zeros(shape, dtype=np.uint16), levels=(250, 3000), lut=lut)
renderQImage(np.zeros(shape, dtype=np.float32), levels=(-4.0, 4.0), lut=lut)
class _TimeSuite(object):
def __init__(self):
super(_TimeSuite, self).__init__()
self.size = None
self.float_data = None
self.uint8_data = None
self.uint8_lut = None
self.uint16_data = None
self.uint16_lut = None
self.cupy_uint16_lut = None
self.cupy_uint8_lut = None
def setup(self):
size = (self.size, self.size)
self.float_data, self.uint16_data, self.uint8_data, self.uint16_lut, self.uint8_lut = self._create_data(
size, np
)
if numba is not None:
# ensure JIT compilation
pg.setConfigOption("useNumba", True)
prime_numba()
pg.setConfigOption("useNumba", False)
if cp:
_d1, _d2, _d3, self.cupy_uint16_lut, self.cupy_uint8_lut = self._create_data(size, cp)
renderQImage(cp.asarray(self.uint16_data["data"])) # prime the gpu
@property
def numba_uint16_lut(self):
return self.uint16_lut
@property
def numba_uint8_lut(self):
return self.uint8_lut
@property
def numpy_uint16_lut(self):
return self.uint16_lut
@property
def numpy_uint8_lut(self):
return self.uint8_lut
@staticmethod
def _create_data(size, xp):
float_data = {
"data": xp.random.normal(size=size).astype("float32"),
"levels": [-4.0, 4.0],
}
uint16_data = {
"data": xp.random.randint(100, 4500, size=size).astype("uint16"),
"levels": [250, 3000],
}
uint8_data = {
"data": xp.random.randint(0, 255, size=size).astype("ubyte"),
"levels": [20, 220],
}
c_map = xp.array([[-500.0, 255.0], [-255.0, 255.0], [0.0, 500.0]])
uint8_lut = xp.zeros((256, 4), dtype="ubyte")
for i in range(3):
uint8_lut[:, i] = xp.clip(xp.linspace(c_map[i][0], c_map[i][1], 256), 0, 255)
uint8_lut[:, 3] = 255
uint16_lut = xp.zeros((2 ** 16, 4), dtype="ubyte")
for i in range(3):
uint16_lut[:, i] = xp.clip(xp.linspace(c_map[i][0], c_map[i][1], 2 ** 16), 0, 255)
uint16_lut[:, 3] = 255
return float_data, uint16_data, uint8_data, uint16_lut, uint8_lut
def make_test(dtype, kind, use_levels, lut_name, func_name):
def time_test(self):
data = getattr(self, dtype + "_data")
levels = data["levels"] if use_levels else None
lut = getattr(self, f"{kind}_{lut_name}_lut", None) if lut_name is not None else None
pg.setConfigOption("useNumba", kind == "numba")
img_data = data["data"]
if kind == "cupy":
img_data = cp.asarray(img_data)
renderQImage(img_data, lut=lut, levels=levels)
time_test.__name__ = func_name
return time_test
for option in ["cupy", "numba", "numpy"]:
if option == "cupy" and cp is None:
continue
if option == "numba" and numba is None:
continue
for data_type in ["float", "uint16", "uint8"]:
for lvls in [True, False]:
if data_type == "float" and not lvls:
continue
for lutname in [None, "uint8", "uint16"]:
name = (
f'time_1x_renderImageItem_{option}_{data_type}_{"" if lvls else "no"}levels_{lutname or "no"}lut'
)
setattr(_TimeSuite, name, make_test(data_type, option, lvls, lutname, name))
class Time4096Suite(_TimeSuite):
def __init__(self):
super(Time4096Suite, self).__init__()
self.size = 4096

View File

@ -1,5 +1,5 @@
pyside2
numpy
pyopengl
sphinx==3.4.3
sphinx_rtd_theme==0.5.1
sphinx==4.1.1
sphinx_rtd_theme==0.5.2

View File

@ -0,0 +1,7 @@
GLGraphItem
===========
.. autoclass:: pyqtgraph.opengl.GLGraphItem
:members:
.. automethod:: pyqtgraph.opengl.GLGraphItem.__init__

View File

@ -19,6 +19,7 @@ Contents:
glviewwidget
glgriditem
glgraphitem
glsurfaceplotitem
glvolumeitem
glimageitem

View File

@ -1,8 +1,84 @@
ColorMap
========
Color Maps
==========
A color map defines a relationship between scalar data values and a range of colors. Color maps are
commonly used to generate false color images, color scatter-plot points, and illustrate the height
of surface plots.
PyQtGraph's :class:`~pyqtgraph.ColorMap` can conveniently be applied to images and interactively
adjusted by using :class:`~pyqtgraph.ColorBarItem`.
To provide interactively user-defined color mappings, see
:class:`~pyqtgraph.GradientEditorItem` and :class:`~pyqtgraph.GradientWidget`, which wraps it.
:class:`~pyqtgraph.GradientEditorItem` combines the editing with a histogram and controls for
interactively adjusting image levels.
ColorMap can also be used a convenient source of colors from a consistent palette or to generate
QPen and QBrush objects used to draw lines and fills that are colored according to their values
along the horizontal or vertical axis.
Sources for color maps
----------------------
Color maps can be user defined by assigning a number of *stops* over the range of 0 to 1. A color
is given for each stop, and the in-between values are generated by interpolation.
When map colors directly represent values, an improperly designed map can obscure detail over
certain ranges of values, while creating false detail in others. PyQtGraph includes the
perceptually uniform color maps provided by the
`Colorcet project <https://colorcet.holoviz.org/>`_. Color maps can also be imported from the
``colorcet`` library or from ``matplotlib``, if either of these is installed.
To see all available color maps, please run the `ColorMap` demonstration available in the suite of
:ref:`examples`.
Examples
--------
False color display of a 2D data set. Display levels are controlled by
a :class:`ColorBarItem <pyqtgraph.ColorBarItem>`:
.. literalinclude:: images/gen_example_false_color_image.py
:lines: 18-28
:dedent: 8
Using QtGui.QPen and QtGui.QBrush to color plots according to the plotted value:
.. literalinclude:: images/gen_example_gradient_plot.py
:lines: 16-33
:dedent: 8
.. image::
images/example_false_color_image.png
:width: 49%
:alt: Example of a false color image
.. image::
images/example_gradient_plot.png
:width: 49%
:alt: Example of drawing and filling plots with gradients
The use of color maps is also demonstrated in the `ImageView`, `Color Gradient Plots` and `ColorBarItem`
:ref:`examples`.
API Reference
-------------
.. autofunction:: pyqtgraph.colormap.listMaps
.. autofunction:: pyqtgraph.colormap.get
.. autofunction:: pyqtgraph.colormap.getFromMatplotlib
.. autofunction:: pyqtgraph.colormap.getFromColorcet
.. autofunction:: pyqtgraph.colormap.modulatedBarData
.. autoclass:: pyqtgraph.ColorMap
:members:
.. automethod:: pyqtgraph.ColorMap.__init__

View File

@ -41,23 +41,33 @@ Export Formats
Exporting from the API
----------------------
To export a file programatically, follow this example::
To export a file programatically, follow this example:
import pyqtgraph as pg
import pyqtgraph.exporters
.. code-block:: python
import pyqtgraph as pg
import pyqtgraph.exporters
# generate something to export
plt = pg.plot([1,5,2,4,3])
# generate something to export
plt = pg.plot([1,5,2,4,3])
# create an exporter instance, as an argument give it
# the item you wish to export
exporter = pg.exporters.ImageExporter(plt.plotItem)
# create an exporter instance, as an argument give it
# the item you wish to export
exporter = pg.exporters.ImageExporter(plt.plotItem)
# set export parameters if needed
exporter.parameters()['width'] = 100 # (note this also affects height parameter)
# set export parameters if needed
exporter.parameters()['width'] = 100 # (note this also affects height parameter)
# save to file
exporter.export('fileName.png')
# save to file
exporter.export('fileName.png')
To export the overall layout of a GraphicsLayoutWidget `grl`, the exporter initialization is
.. code-block:: python
exporter = pg.exporters.ImageExporter( grl.scene() )
instead.
Exporting 3D Graphics
@ -69,5 +79,3 @@ generate an image from a GLViewWidget by using QGLWidget.grabFrameBuffer or QGLW
glview.grabFrameBuffer().save('fileName.png')
See the Qt documentation for more information.

View File

@ -30,11 +30,11 @@ Qt uses the classes QColor, QPen, and QBrush to determine how to draw lines and
.. autofunction:: pyqtgraph.intColor
.. autofunction:: pyqtgraph.colorTuple
.. autofunction:: pyqtgraph.CIELabColor
.. autofunction:: pyqtgraph.colorStr
.. autofunction:: pyqtgraph.colorCIELab
.. autofunction:: pyqtgraph.glColor
.. autofunction:: pyqtgraph.colorDistance
Data Slicing
@ -102,3 +102,16 @@ Miscellaneous Functions
.. autofunction:: pyqtgraph.systemInfo
.. autofunction:: pyqtgraph.exit
Legacy Color Helper Functions
-------------------------------
The following helper functions should no longer be used. The functionality that they implement is trivial and it is suggested that the user use the equivalent QColor methods directly.
.. autofunction:: pyqtgraph.colorTuple
.. autofunction:: pyqtgraph.colorStr
.. autofunction:: pyqtgraph.glColor

View File

@ -0,0 +1,7 @@
ColorBarItem
============
.. autoclass:: pyqtgraph.ColorBarItem
:members:
.. automethod:: pyqtgraph.ColorBarItem.__init__

View File

@ -1,8 +1,66 @@
ImageItem
=========
:class:`~pyqtgraph.ImageItem` displays images inside a :class:`~pyqtgraph.GraphicsView`, or a
:class:`~pyqtgraph.ViewBox`, which may itself be part of a :class:`~pyqtgraph.PlotItem`. It is designed
for rapid updates as needed for a video display. The supplied data is optionally scaled (see
:func:`~pyqtgraph.ImageItem.setLevels`) and/or colored according to a
lookup table (see :func:`~pyqtgraph.ImageItem.setLookupTable`.
Data is provided as a NumPy array with an ordering of either
* `col-major`, where the shape of the array represents (width, height) or
* `row-major`, where the shape of the array represents (height, width).
While `col-major` is the default, `row-major` ordering typically has the best performance. In either ordering,
a third dimension can be added to the array to hold individual
``[R,G,B]`` or ``[R,G,B,A]`` components.
Notes
-----
Data ordering can be set for each ImageItem, or in the :ref:`global configuration options <apiref_config>` by ::
pyqtgraph.setConfigOption('imageAxisOrder', 'row-major') # best performance
An image can be placed into a plot area of a given extent directly through the
:func:`~pyqtgraph.ImageItem.setRect` method or the ``rect`` keyword. This is internally realized through
assigning a ``QtGui.QTransform``. For other translation, scaling or rotations effects that
persist for all later image data, the user can also directly define and assign such a
transform, as shown in the example below.
ImageItem is frequently used in conjunction with :class:`~pyqtgraph.ColorBarItem` to provide
a color map display and interactive level adjustments, or with
:class:`~pyqtgraph.HistogramLUTItem` or :class:`~pyqtgraph.HistogramLUTWidget` for a full GUI
to control the levels and lookup table used to display the image.
If performance is critial, the following points may be worth investigating:
* Use row-major ordering and C-contiguous image data.
* Manually provide ``level`` information to avoid autoLevels sampling of the image.
* Prefer `float32` to `float64` for floating point data, avoid NaN values.
* Use lookup tables with <= 256 entries for false color images.
* Avoid individual level adjustments RGB components.
* Use the latest version of NumPy. Notably, SIMD code added in version 1.20 significantly improved performance on Linux platforms.
* Enable Numba with ``pyqtgraph.setConfigOption('useNumba', True)``, although the JIT compilation will only accelerate repeated image display.
.. _ImageItem_examples:
Examples
--------
.. literalinclude:: ../images/gen_example_imageitem_transform.py
:lines: 19-28
:dedent: 8
.. image::
../images/example_imageitem_transform.png
:width: 49%
:alt: Example of transformed image display
.. autoclass:: pyqtgraph.ImageItem
:members:
.. automethod:: pyqtgraph.ImageItem.__init__

View File

@ -12,6 +12,7 @@ Contents:
plotdataitem
plotitem
imageitem
colorbaritem
pcolormeshitem
graphitem
viewbox
@ -46,3 +47,4 @@ Contents:
uigraphicsitem
graphicswidgetanchor
dateaxisitem
targetitem

View File

@ -0,0 +1,17 @@
TargetItem
==========
.. autoclass:: pyqtgraph.TargetItem
:members:
.. automethod:: pyqtgraph.TargetItem.__init__
TargetLabel
==================
.. autoclass:: pyqtgraph.TargetLabel
:members:
.. automethod:: pyqtgraph.TargetLabel.__init__

View File

@ -101,7 +101,7 @@ Embedding PyQtGraph as a sub-package of a larger project
When writing applications or python packages that make use of pyqtgraph, it is most common to install pyqtgraph system-wide (or within a virtualenv) and simply call `import pyqtgraph` from within your application. The main benefit to this is that pyqtgraph is configured independently of your application and thus you (or your users) are free to install newer versions of pyqtgraph without changing anything in your application. This is standard practice when developing with python.
Occasionally, a specific program needs to be kept in working order for an extended amount of time after development has been completed. This is often the case for single-purpose scientific applications. If we want to ensure that the software will still work ten years later, then it is preferrable to tie it to a very specific version of pyqtgraph and *avoid* importing the system-installed version, which may be much newer and potentially incompatible. This is especially true when the application requires site-specific modifications to the pyqtgraph package.
Occasionally, a specific program needs to be kept in working order for an extended amount of time after development has been completed. This is often the case for single-purpose scientific applications. If we want to ensure that the software will still work ten years later, then it is preferable to tie it to a very specific version of pyqtgraph and *avoid* importing the system-installed version, which may be much newer and potentially incompatible. This is especially true when the application requires site-specific modifications to the pyqtgraph package.
To support such a separate local installation, all internal import statements in pyqtgraph are relative. That means that pyqtgraph never refers to itself internally as 'pyqtgraph'. This allows the package to be renamed or used as a sub-package without any naming conflicts with other versions of pyqtgraph on the system.

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -0,0 +1,45 @@
"""
generates 'example_false_color_image.png'
"""
import numpy as np
import pyqtgraph as pg
import pyqtgraph.exporters as exp
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets, mkQApp
class MainWindow(pg.GraphicsLayoutWidget):
""" example application main window """
def __init__(self):
super().__init__()
self.resize(420,400)
self.show()
plot = self.addPlot() # title="non-interactive")
# prepare demonstration data:
data = np.fromfunction(lambda i, j: (1+0.3*np.sin(i)) * (i)**2 + (j)**2, (100, 100))
noisy_data = data * (1 + 0.2 * np.random.random(data.shape) )
# Example: False color image with interactive level adjustment
img = pg.ImageItem(image=noisy_data) # create monochrome image from demonstration data
plot.addItem( img ) # add to PlotItem 'plot'
cm = pg.colormap.get('CET-L9') # prepare a linear color map
bar = pg.ColorBarItem( values= (0, 20_000), cmap=cm ) # prepare interactive color bar
# Have ColorBarItem control colors of img and appear in 'plot':
bar.setImageItem( img, insert_in=plot )
self.timer = pg.QtCore.QTimer( singleShot=True )
self.timer.timeout.connect(self.export)
self.timer.start(100)
def export(self):
print('exporting')
exporter = exp.ImageExporter(self.scene())
exporter.parameters()['width'] = 420
exporter.export('example_false_color_image.png')
mkQApp("False color image example")
main_window = MainWindow()
## Start Qt event loop
if __name__ == '__main__':
pg.exec()

View File

@ -0,0 +1,55 @@
"""
generates 'example_gradient_plot.png'
"""
import numpy as np
import pyqtgraph as pg
import pyqtgraph.exporters as exp
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets, mkQApp
class MainWindow(pg.GraphicsLayoutWidget):
""" example application main window """
def __init__(self):
super().__init__()
self.resize(420,400)
self.show()
# Prepare demonstration data
raw = np.linspace(0.0, 2.0, 400)
y_data1 = ( (raw+0.1)%1 ) ** 4
y_data2 = ( (raw+0.1)%1 ) ** 4 - ( (raw+0.6)%1 ) ** 4
# Example 1: Gradient pen
cm = pg.colormap.get('CET-L17') # prepare a linear color map
cm.reverse() # reverse it to put light colors at the top
pen = cm.getPen( span=(0.0,1.0), width=5 ) # gradient from blue (y=0) to white (y=1)
# plot a curve drawn with a pen colored according to y value:
curve1 = pg.PlotDataItem( y=y_data1, pen=pen )
# Example 2: Gradient brush
cm = pg.colormap.get('CET-D1') # prepare a diverging color map
cm.setMappingMode('diverging') # set mapping mode
brush = cm.getBrush( span=(-1., 1.) ) # gradient from blue at -1 to red at +1
# plot a curve that is filled to zero with the gradient brush:
curve2 = pg.PlotDataItem( y=y_data2, pen='w', brush=brush, fillLevel=0.0 )
for idx, curve in enumerate( (curve1, curve2) ):
plot = self.addPlot(row=idx, col=0)
plot.getAxis('left').setWidth(25)
plot.addItem( curve )
self.timer = pg.QtCore.QTimer( singleShot=True )
self.timer.timeout.connect(self.export)
self.timer.start(100)
def export(self):
print('exporting')
exporter = exp.ImageExporter(self.scene())
exporter.parameters()['width'] = 420
exporter.export('example_gradient_plot.png')
mkQApp("Gradient plotting example")
main_window = MainWindow()
## Start Qt event loop
if __name__ == '__main__':
pg.exec()

View File

@ -0,0 +1,45 @@
"""
generates 'example_false_color_image.png'
"""
import numpy as np
import pyqtgraph as pg
import pyqtgraph.exporters as exp
from pyqtgraph.Qt import QtGui, mkQApp
class MainWindow(pg.GraphicsLayoutWidget):
""" example application main window """
def __init__(self):
super().__init__()
self.resize(420,400)
self.show()
plot = self.addPlot()
# Example: Transformed display of ImageItem
tr = QtGui.QTransform() # prepare ImageItem transformation:
tr.scale(6.0, 3.0) # scale horizontal and vertical axes
tr.translate(-1.5, -1.5) # move 3x3 image to locate center at axis origin
img = pg.ImageItem( image=np.eye(3), levels=(0,1) ) # create example image
img.setTransform(tr) # assign transform
plot.addItem( img ) # add ImageItem to PlotItem
plot.showAxes(True) # frame it with a full set of axes
plot.invertY(True) # vertical axis counts top to bottom
self.timer = pg.QtCore.QTimer( singleShot=True )
self.timer.timeout.connect(self.export)
self.timer.start(100)
def export(self):
print('exporting')
exporter = exp.ImageExporter(self.scene())
exporter.parameters()['width'] = 420
exporter.export('example_imageitem_transform.png')
mkQApp("ImageItem transform example")
main_window = MainWindow()
## Start Qt event loop
if __name__ == '__main__':
pg.exec()

View File

@ -3,6 +3,8 @@ Parameter
.. autofunction:: pyqtgraph.parametertree.registerParameterType
.. autofunction:: pyqtgraph.parametertree.registerParameterItemType
.. autoclass:: pyqtgraph.parametertree.Parameter
:members:

View File

@ -1,3 +1,7 @@
..
This file is auto-generated from pyqtgraph/tools/rebuildPtreeRst.py. Do not modify by hand! Instead, rerun the
generation script with `python pyqtgraph/tools/rebuildPtreeRst.py`.
Built-in Parameter Types
========================
@ -6,7 +10,25 @@ Built-in Parameter Types
Parameters
----------
.. autoclass:: SimpleParameter
.. autoclass:: ActionParameter
:members:
.. autoclass:: CalendarParameter
:members:
.. autoclass:: ChecklistParameter
:members:
.. autoclass:: ColorMapParameter
:members:
.. autoclass:: ColorParameter
:members:
.. autoclass:: FileParameter
:members:
.. autoclass:: FontParameter
:members:
.. autoclass:: GroupParameter
@ -15,16 +37,46 @@ Parameters
.. autoclass:: ListParameter
:members:
.. autoclass:: TextParameter
.. autoclass:: PenParameter
:members:
.. autoclass:: ActionParameter
.. autoclass:: ProgressBarParameter
:members:
.. autoclass:: SimpleParameter
:members:
.. autoclass:: SliderParameter
:members:
.. autoclass:: TextParameter
:members:
ParameterItems
--------------
.. autoclass:: WidgetParameterItem
.. autoclass:: ActionParameterItem
:members:
.. autoclass:: BoolParameterItem
:members:
.. autoclass:: CalendarParameterItem
:members:
.. autoclass:: ChecklistParameterItem
:members:
.. autoclass:: ColorMapParameterItem
:members:
.. autoclass:: ColorParameterItem
:members:
.. autoclass:: FileParameterItem
:members:
.. autoclass:: FontParameterItem
:members:
.. autoclass:: GroupParameterItem
@ -33,8 +85,20 @@ ParameterItems
.. autoclass:: ListParameterItem
:members:
.. autoclass:: TextParameterItem
.. autoclass:: NumericParameterItem
:members:
.. autoclass:: ActionParameterItem
.. autoclass:: PenParameterItem
:members:
.. autoclass:: ProgressBarParameterItem
:members:
.. autoclass:: SliderParameterItem
:members:
.. autoclass:: StrParameterItem
:members:
.. autoclass:: TextParameterItem
:members:

View File

@ -16,7 +16,7 @@ To select a 2D region from an image, pyqtgraph uses the :class:`ROI <pyqtgraph.R
To automatically extract a region of image data using an ROI and an ImageItem, use :func:`ROI.getArrayRegion <pyqtgraph.ROI.getArrayRegion>`. ROI classes use the :func:`affineSlice <pyqtgraph.affineSlice>` function to perform this extraction.
ROI can also be used as a control for moving/rotating/scaling items in a scene similar to most vetctor graphics editing applications.
ROI can also be used as a control for moving/rotating/scaling items in a scene similar to most vector graphics editing applications.
See the ROITypes example for more information.

View File

@ -51,4 +51,4 @@ anim = a.makeAnimation(loop=-1)
anim.start()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -35,4 +35,4 @@ bg = BarGraph(x=x, y=y1*0.3+2, height=0.4+y1*0.2, width=0.8)
win.addItem(bg)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -19,4 +19,4 @@ data = np.random.normal(size=(500,500))
pg.image(data, title="Simplest possible image example")
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -41,7 +41,7 @@ class MainWindow(QtWidgets.QMainWindow):
cmap = pg.colormap.get('CET-L9')
bar = pg.ColorBarItem(
interactive=False, values= (0, 30_000), cmap=cmap,
interactive=False, values= (0, 30_000), colorMap=cmap,
label='vertical fixed color bar'
)
bar.setImageItem( i1, insert_in=p1 )
@ -59,11 +59,11 @@ class MainWindow(QtWidgets.QMainWindow):
cmap = pg.colormap.get('CET-L4')
bar = pg.ColorBarItem(
values = (0, 30_000),
cmap=cmap,
colorMap=cmap,
label='horizontal color bar',
limits = (0, None),
rounding=1000,
orientation = 'horizontal',
orientation = 'h',
pen='#8888FF', hoverPen='#EEEEFF', hoverBrush='#EEEEFF80'
)
bar.setImageItem( i2, insert_in=p2 )
@ -83,7 +83,7 @@ class MainWindow(QtWidgets.QMainWindow):
limits = (-30_000, 30_000), # start with full range...
rounding=1000,
width = 10,
cmap=cmap )
colorMap=cmap )
bar.setImageItem( [i3, i4] )
bar.setLevels( low=-5_000, high=15_000) # ... then adjust to retro sunset.
@ -97,4 +97,4 @@ main_window = MainWindow()
## Start Qt event loop
if __name__ == '__main__':
mkQApp().exec_()
pg.exec()

View File

@ -27,4 +27,4 @@ btn.sigColorChanging.connect(change)
btn.sigColorChanged.connect(done)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -0,0 +1,147 @@
# -*- coding: utf-8 -*-
"""
This example demonstrates plotting with color gradients.
It also shows multiple plots with timed rolling updates
"""
# Add path to library (just for examples; you do not need this)
import initExample
import numpy as np
import time
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets, mkQApp
import pyqtgraph as pg
class DataSource(object):
""" source of buffered demonstration data """
def __init__(self, sample_rate=200., signal_period=0.55, negative_period=None, max_length=300):
""" prepare, but don't start yet """
self.rate = sample_rate
self.period = signal_period
self.neg_period = negative_period
self.start_time = 0.
self.sample_idx = 0 # number of next sample to be taken
def start(self, timestamp):
""" start acquiring simulated data """
self.start_time = timestamp
self.sample_idx = 0
def get_data(self, timestamp, max_length=6000):
""" return all data acquired since last get_data call """
next_idx = int( (timestamp - self.start_time) * self.rate )
if next_idx - self.sample_idx > max_length:
self.sample_idx = next_idx - max_length # catch up if needed
# create some mildly intersting data:
sample_phases = np.arange( self.sample_idx, next_idx, dtype=np.float64 )
self.sample_idx = next_idx
sample_phase_pos = sample_phases / (self.period*self.rate)
sample_phase_pos %= 1.0
if self.neg_period is None:
return sample_phase_pos**4
sample_phase_neg = sample_phases / (self.neg_period*self.rate)
sample_phase_neg %= 1.0
return sample_phase_pos**4 - sample_phase_neg**4
class MainWindow(pg.GraphicsLayoutWidget):
""" example application main window """
def __init__(self):
super().__init__()
self.setWindowTitle('pyqtgraph example: gradient plots')
self.resize(800,800)
self.show()
layout = self # we are using a GraphicsLayoutWidget as main window for convenience
cm = pg.colormap.get('CET-L17')
cm.reverse()
pen0 = cm.getPen( span=(0.0,1.0), width=5 )
curve0 = pg.PlotDataItem(pen=pen0 )
comment0 = 'Clipped color map applied to vertical axis'
cm = pg.colormap.get('CET-D1')
cm.setMappingMode('diverging')
brush = cm.getBrush( span=(-1., 1.), orientation='vertical' )
curve1 = pg.PlotDataItem(pen='w', brush=brush, fillLevel=0.0 )
comment1 = 'Diverging vertical color map used as brush'
cm = pg.colormap.get('CET-L17')
cm.setMappingMode('mirror')
pen2 = cm.getPen( span=(400.0,600.0), width=5, orientation='horizontal' )
curve2 = pg.PlotDataItem(pen=pen2 )
comment2 = 'Mirrored color map applied to horizontal axis'
cm = pg.colormap.get('CET-C2')
cm.setMappingMode('repeat')
pen3 = cm.getPen( span=(100, 200), width=5, orientation='horizontal' )
curve3 = pg.PlotDataItem(pen=pen3 ) # vertical diverging fill
comment3 = 'Repeated color map applied to horizontal axis'
curves = (curve0, curve1, curve2, curve3)
comments = (comment0, comment1, comment2, comment3)
length = int( 3.0 * 200. ) # length of display in samples
self.top_plot = None
for idx, (curve, comment) in enumerate( zip(curves,comments) ):
plot = layout.addPlot(row=idx+1, col=0)
text = pg.TextItem( comment, anchor=(0,1) )
text.setPos(0.,1.)
if self.top_plot is None:
self.top_plot = plot
else:
plot.setXLink( self.top_plot )
plot.addItem( curve )
plot.addItem( text )
plot.setXRange( 0, length )
if idx != 1: plot.setYRange( 0. , 1.1 )
else : plot.setYRange( -1. , 1.2 ) # last plot include positive/negative data
self.traces = (
{'crv': curve0, 'buf': np.zeros( length ), 'ptr':0, 'ds': DataSource( signal_period=0.55 ) },
{'crv': curve1, 'buf': np.zeros( length ), 'ptr':0, 'ds': DataSource( signal_period=0.61, negative_period=0.55 ) },
{'crv': curve2, 'buf': np.zeros( length ), 'ptr':0, 'ds': DataSource( signal_period=0.65 ) },
{'crv': curve3, 'buf': np.zeros( length ), 'ptr':0, 'ds': DataSource( signal_period=0.52 ) },
)
self.timer = QtCore.QTimer(timerType=QtCore.Qt.TimerType.PreciseTimer)
self.timer.timeout.connect(self.update)
timestamp = time.perf_counter()
for dic in self.traces:
dic['ds'].start( timestamp )
self.last_update = time.perf_counter()
self.mean_dt = None
self.timer.start(33)
def update(self):
""" called by timer at 30 Hz """
timestamp = time.perf_counter()
# measure actual update rate:
dt = timestamp - self.last_update
if self.mean_dt is None:
self.mean_dt = dt
else:
self.mean_dt = 0.95 * self.mean_dt + 0.05 * dt # average over fluctuating measurements
self.top_plot.setTitle(
'refresh: {:0.1f}ms -> {:0.1f} fps'.format( 1000*self.mean_dt, 1/self.mean_dt )
)
# handle rolling buffer:
self.last_update = timestamp
for dic in self.traces:
new_data = dic['ds'].get_data( timestamp )
idx_a = dic['ptr']
idx_b = idx_a + len( new_data )
len_buffer = dic['buf'].shape[0]
if idx_b < len_buffer: # data does not cross buffer boundary
dic['buf'][idx_a:idx_b] = new_data
else: # part of the new data needs to roll over to beginning of buffer
len_1 = len_buffer - idx_a # this many elements still fit
dic['buf'][idx_a:idx_a+len_1] = new_data[:len_1] # first part of data at end
idx_b = len(new_data) - len_1
dic['buf'][0:idx_b] = new_data[len_1:] # second part of data at re-start
dic['ptr'] = idx_b
dic['crv'].setData( dic['buf'] )
mkQApp("Gradient plotting example")
main_window = MainWindow()
## Start Qt event loop
if __name__ == '__main__':
pg.exec()

View File

@ -30,4 +30,4 @@ c.show()
c.setWindowTitle('pyqtgraph example: ConsoleWidget')
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -51,7 +51,7 @@ class Graph(pg.GraphItem):
def mouseDragEvent(self, ev):
if ev.button() != QtCore.Qt.LeftButton:
if ev.button() != QtCore.Qt.MouseButton.LeftButton:
ev.ignore()
return
@ -130,4 +130,4 @@ g.setData(pos=pos, adj=adj, pen=lines, size=1, symbol=symbols, pxMode=False, tex
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -58,4 +58,4 @@ imv1.setLevels(-0.003, 0.003)
update()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -43,4 +43,4 @@ tree.resize(600,600)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -27,4 +27,4 @@ w.setWindowTitle('pyqtgraph example: DateAxisItem')
w.show()
if __name__ == '__main__':
app.exec_()
pg.exec()

View File

@ -43,4 +43,4 @@ window.setWindowTitle('pyqtgraph example: DateAxisItem_QtDesigner')
window.show()
if __name__ == '__main__':
app.exec_()
pg.exec()

View File

@ -46,4 +46,4 @@ tree.resize(1000, 800)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -43,4 +43,4 @@ img.setDrawKernel(kern, mask=kern, center=(1,1), mode='add')
img.setLevels([0, 10])
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -27,4 +27,4 @@ plt.addItem(err)
plt.plot(x, y, symbol='o', pen={'color': 0.8, 'width': 2})
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -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.
"""
@ -41,9 +43,11 @@ def format(color, style=''):
_format = QTextCharFormat()
_format.setForeground(_color)
if 'bold' in style:
_format.setFontWeight(QFont.Bold)
_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.Expanding,QtGui.QSizePolicy.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
@ -301,15 +423,15 @@ class ExampleLoader(QtGui.QMainWindow):
# first, a dark background
c = QtGui.QColor('#171717')
p = self.ui.codeView.palette()
p.setColor(QtGui.QPalette.Active, QtGui.QPalette.Base, c)
p.setColor(QtGui.QPalette.Inactive, QtGui.QPalette.Base, c)
p.setColor(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Base, c)
p.setColor(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Base, c)
self.ui.codeView.setPalette(p)
# then, a light font
f = QtGui.QTextCharFormat()
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
@ -360,39 +481,67 @@ class ExampleLoader(QtGui.QMainWindow):
fn = self.currentFile()
if fn is None:
return
if sys.platform.startswith('win'):
args = [os.P_NOWAIT, sys.executable, '"'+sys.executable+'"', '"' + fn + '"']
else:
args = [os.P_NOWAIT, sys.executable, sys.executable, fn]
if env is None:
os.spawnl(*args)
else:
args.append(env)
os.spawnle(*args)
subprocess.Popen([sys.executable, fn], env=env)
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')
text = open(fn).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()
app.exec_()
loader.ui.exampleTree.setCurrentIndex(
loader.ui.exampleTree.model().index(0,0)
)
pg.exec()
if __name__ == '__main__':
main()

View File

@ -46,4 +46,4 @@ timer.start(30)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -76,4 +76,4 @@ fc.connectTerminals(fNode['Out'], pw2Node['In'])
fc.connectTerminals(fNode['Out'], fc['dataOut'])
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -151,4 +151,4 @@ fc.connectTerminals(fNode['dataOut'], v2Node['data'])
fc.connectTerminals(fNode['dataOut'], fc['dataOut'])
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
Demonstrate use of GLLinePlotItem to draw cross-sections of a surface.
This example demonstrates the use of GLBarGraphItem.
"""
## Add path to library (just for examples; you do not need this)
@ -13,9 +13,9 @@ import numpy as np
app = pg.mkQApp("GLBarGraphItem Example")
w = gl.GLViewWidget()
w.opts['distance'] = 40
w.show()
w.setWindowTitle('pyqtgraph example: GLBarGraphItem')
w.setCameraPosition(distance=40)
gx = gl.GLGridItem()
gx.rotate(90, 0, 1, 0)
@ -40,4 +40,4 @@ bg = gl.GLBarGraphItem(pos, size)
w.addItem(bg)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -0,0 +1,43 @@
import initExample
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import numpy
app = pg.mkQApp()
w = gl.GLViewWidget()
w.show()
w.setWindowTitle("pyqtgraph example: GLGradientLegendItem")
w.setCameraPosition(distance=60)
gx = gl.GLGridItem()
gx.rotate(90, 0, 1, 0)
w.addItem(gx)
md = gl.MeshData.cylinder(rows=10, cols=20, radius=[5.0, 5], length=20.0)
md._vertexes[:, 2] = md._vertexes[:, 2] - 10
# set color based on z coordinates
color_map = pg.colormap.get("CET-L10")
h = md.vertexes()[:, 2]
# remember these
h_max, h_min = h.max(), h.min()
h = (h - h_min) / (h_max - h_min)
colors = color_map.map(h, mode="float")
md.setFaceColors(colors)
m = gl.GLMeshItem(meshdata=md, smooth=True)
w.addItem(m)
legendLabels = numpy.linspace(h_max, h_min, 5)
legendPos = numpy.linspace(1, 0, 5)
legend = dict(zip(map(str, legendLabels), legendPos))
gll = gl.GLGradientLegendItem(
pos=(10, 10), size=(50, 300), gradient=color_map, labels=legend
)
w.addItem(gll)
## Start Qt event loop unless running in interactive mode.
if __name__ == "__main__":
pg.exec()

47
examples/GLGraphItem.py Normal file
View File

@ -0,0 +1,47 @@
"""
Demonstrates use of GLGraphItem
"""
## Add path to library (just for examples; you do not need this)
import initExample
import pyqtgraph as pg
import pyqtgraph.opengl as gl
import numpy as np
app = pg.mkQApp("GLGraphItem Example")
w = gl.GLViewWidget()
w.setCameraPosition(distance=20)
w.show()
edges = np.array([
[0, 2],
[0, 3],
[1, 2],
[1, 3],
[2, 3]
])
nodes = np.array(
[
[0, 0, 0],
[1, 0, 0],
[0, 1, 0],
[1, 1, 1]
]
)
edgeColor=pg.glColor("w")
gi = gl.GLGraphItem(
edges=edges,
nodePositions=nodes,
edgeWidth=1.,
nodeSize=10.
)
w.addItem(gi)
if __name__ == "__main__":
pg.exec()

View File

@ -15,9 +15,9 @@ import numpy as np
app = pg.mkQApp("GLImageItem Example")
w = gl.GLViewWidget()
w.opts['distance'] = 200
w.show()
w.setWindowTitle('pyqtgraph example: GLImageItem')
w.setCameraPosition(distance=200)
## create volume data set to slice three images from
shape = (100,100,70)
@ -51,4 +51,4 @@ ax = gl.GLAxisItem()
w.addItem(ax)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -7,7 +7,7 @@ This example uses the isosurface function to convert a scalar field
## Add path to library (just for examples; you do not need this)
import initExample
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import pyqtgraph as pg
import pyqtgraph.opengl as gl
@ -22,23 +22,16 @@ g = gl.GLGridItem()
g.scale(2,2,1)
w.addItem(g)
import numpy as np
## Define a scalar field from which we will generate an isosurface
def psi(i, j, k, offset=(25, 25, 50)):
x = i-offset[0]
y = j-offset[1]
z = k-offset[2]
th = np.arctan2(z, (x**2+y**2)**0.5)
phi = np.arctan2(y, x)
r = (x**2 + y**2 + z **2)**0.5
th = np.arctan2(z, np.hypot(x, y))
r = np.sqrt(x**2 + y**2 + z **2)
a0 = 1
#ps = (1./81.) * (2./np.pi)**0.5 * (1./a0)**(3/2) * (6 - r/a0) * (r/a0) * np.exp(-r/(3*a0)) * np.cos(th)
ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1)
return ps
#return ((1./81.) * (1./np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * (r/a0) * np.exp(-r/(3*a0)) * np.sin(th) * np.cos(th) * np.exp(2 * 1j * phi))**2
print("Generating scalar field..")
@ -67,4 +60,4 @@ w.addItem(m2)
m2.translate(-25, -25, -50)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -6,16 +6,15 @@ Demonstrate use of GLLinePlotItem to draw cross-sections of a surface.
## Add path to library (just for examples; you do not need this)
import initExample
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
import pyqtgraph as pg
import numpy as np
app = pg.mkQApp("GLLinePlotItem Example")
w = gl.GLViewWidget()
w.opts['distance'] = 40
w.show()
w.setWindowTitle('pyqtgraph example: GLLinePlotItem')
w.setCameraPosition(distance=40)
gx = gl.GLGridItem()
gx.rotate(90, 0, 1, 0)
@ -29,19 +28,16 @@ gz = gl.GLGridItem()
gz.translate(0, 0, -10)
w.addItem(gz)
def fn(x, y):
return np.cos((x**2 + y**2)**0.5)
n = 51
y = np.linspace(-10,10,n)
x = np.linspace(-10,10,100)
for i in range(n):
yi = np.array([y[i]]*100)
d = (x**2 + yi**2)**0.5
yi = y[i]
d = np.hypot(x, yi)
z = 10 * np.cos(d) / (d+1)
pts = np.vstack([x,yi,z]).transpose()
plt = gl.GLLinePlotItem(pos=pts, color=pg.glColor((i,n*1.3)), width=(i+1)/10., antialias=True)
pts = np.column_stack([x, np.full_like(x, yi), z])
plt = gl.GLLinePlotItem(pos=pts, color=pg.mkColor((i,n*1.3)), width=(i+1)/10., antialias=True)
w.addItem(plt)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -118,4 +118,4 @@ w.addItem(m5)
w.addItem(m6)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

94
examples/GLPainterItem.py Normal file
View File

@ -0,0 +1,94 @@
"""
Demonstrate using QPainter on a subclass of GLGraphicsItem.
"""
## Add path to library (just for examples; you do not need this)
import initExample
import pyqtgraph as pg
import pyqtgraph.opengl
from pyqtgraph.Qt import QtCore, QtGui
import OpenGL.GL as GL
SIZE = 32
class GLPainterItem(pg.opengl.GLGraphicsItem.GLGraphicsItem):
def __init__(self, **kwds):
super().__init__()
glopts = kwds.pop('glOptions', 'additive')
self.setGLOptions(glopts)
def compute_projection(self):
modelview = GL.glGetDoublev(GL.GL_MODELVIEW_MATRIX)
projection = GL.glGetDoublev(GL.GL_PROJECTION_MATRIX)
mvp = projection.T @ modelview.T
mvp = QtGui.QMatrix4x4(mvp.ravel().tolist())
# note that QRectF.bottom() != QRect.bottom()
rect = QtCore.QRectF(self.view().rect())
ndc_to_viewport = QtGui.QMatrix4x4()
ndc_to_viewport.viewport(rect.left(), rect.bottom(), rect.width(), -rect.height())
return ndc_to_viewport * mvp
def paint(self):
self.setupGLState()
painter = QtGui.QPainter(self.view())
self.draw(painter)
painter.end()
def draw(self, painter):
painter.setPen(QtCore.Qt.GlobalColor.white)
painter.setRenderHints(QtGui.QPainter.RenderHint.Antialiasing | QtGui.QPainter.RenderHint.TextAntialiasing)
rect = self.view().rect()
af = QtCore.Qt.AlignmentFlag
painter.drawText(rect, af.AlignTop | af.AlignRight, 'TR')
painter.drawText(rect, af.AlignBottom | af.AlignLeft, 'BL')
painter.drawText(rect, af.AlignBottom | af.AlignRight, 'BR')
opts = self.view().cameraParams()
lines = []
center = opts['center']
lines.append(f"center : ({center.x():.1f}, {center.y():.1f}, {center.z():.1f})")
for key in ['distance', 'fov', 'elevation', 'azimuth']:
lines.append(f"{key} : {opts[key]:.1f}")
xyz = self.view().cameraPosition()
lines.append(f"xyz : ({xyz.x():.1f}, {xyz.y():.1f}, {xyz.z():.1f})")
info = "\n".join(lines)
painter.drawText(rect, af.AlignTop | af.AlignLeft, info)
project = self.compute_projection()
hsize = SIZE // 2
for xi in range(-hsize, hsize+1):
for yi in range(-hsize, hsize+1):
if xi == -hsize and yi == -hsize:
# skip one corner for visual orientation
continue
vec3 = QtGui.QVector3D(xi, yi, 0)
pos = project.map(vec3).toPointF()
painter.drawEllipse(pos, 1, 1)
pg.mkQApp("GLPainterItem Example")
glv = pg.opengl.GLViewWidget()
glv.show()
glv.setWindowTitle('pyqtgraph example: GLPainterItem')
glv.setCameraPosition(distance=50, elevation=90, azimuth=0)
griditem = pg.opengl.GLGridItem()
griditem.setSize(SIZE, SIZE)
griditem.setSpacing(1, 1)
glv.addItem(griditem)
axisitem = pg.opengl.GLAxisItem()
axisitem.setSize(SIZE/2, SIZE/2, 1)
glv.addItem(axisitem)
paintitem = GLPainterItem()
glv.addItem(paintitem)
if __name__ == '__main__':
pg.exec()

View File

@ -8,15 +8,16 @@ Demonstrates use of GLScatterPlotItem with rapidly-updating plots.
import initExample
import pyqtgraph as pg
from pyqtgraph import functions as fn
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
import numpy as np
app = pg.mkQApp("GLScatterPlotItem Example")
w = gl.GLViewWidget()
w.opts['distance'] = 20
w.show()
w.setWindowTitle('pyqtgraph example: GLScatterPlotItem')
w.setCameraPosition(distance=20)
g = gl.GLGridItem()
w.addItem(g)
@ -84,10 +85,10 @@ def update():
global phase, sp2, d2
s = -np.cos(d2*2+phase)
color = np.empty((len(d2),4), dtype=np.float32)
color[:,3] = np.clip(s * 0.1, 0, 1)
color[:,0] = np.clip(s * 3.0, 0, 1)
color[:,1] = np.clip(s * 1.0, 0, 1)
color[:,2] = np.clip(s ** 3, 0, 1)
color[:,3] = fn.clip_array(s * 0.1, 0., 1.)
color[:,0] = fn.clip_array(s * 3.0, 0., 1.)
color[:,1] = fn.clip_array(s * 1.0, 0., 1.)
color[:,2] = fn.clip_array(s ** 3, 0., 1.)
sp2.setData(color=color)
phase -= 0.1
@ -107,4 +108,4 @@ t.timeout.connect(update)
t.start(50)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -93,4 +93,4 @@ timer.timeout.connect(update)
timer.start(30)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

35
examples/GLTextItem.py Normal file
View File

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
"""
Simple examples demonstrating the use of GLTextItem.
"""
import initExample
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui, mkQApp
import pyqtgraph.opengl as gl
app = mkQApp("GLTextItem Example")
gvw = gl.GLViewWidget()
gvw.show()
gvw.setWindowTitle('pyqtgraph example: GLTextItem')
griditem = gl.GLGridItem()
griditem.setSize(10, 10)
griditem.setSpacing(1, 1)
gvw.addItem(griditem)
axisitem = gl.GLAxisItem()
gvw.addItem(axisitem)
txtitem1 = gl.GLTextItem(pos=(0.0, 0.0, 0.0), text='text1')
gvw.addItem(txtitem1)
txtitem2 = gl.GLTextItem()
txtitem2.setData(pos=(1.0, -1.0, 2.0), color=(127, 255, 127, 255), text='text2')
gvw.addItem(txtitem2)
if __name__ == '__main__':
pg.exec()

View File

@ -6,14 +6,14 @@ 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()
w.setWindowTitle('pyqtgraph example: GLViewWidget')
w.setCameraPosition(distance=20)
ax = gl.GLAxisItem()
ax.setSize(5,5,5)
@ -28,4 +28,4 @@ ax2.setParentItem(b)
b.translate(1,1,1)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -7,47 +7,66 @@ Demonstrates GLVolumeItem for displaying volumetric data.
## Add path to library (just for examples; you do not need this)
import initExample
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph.opengl as gl
from pyqtgraph import functions as fn
app = pg.mkQApp("GLVolumeItem Example")
w = gl.GLViewWidget()
w.opts['distance'] = 200
w.show()
w.setWindowTitle('pyqtgraph example: GLVolumeItem')
w.setCameraPosition(distance=200)
#b = gl.GLBoxItem()
#w.addItem(b)
g = gl.GLGridItem()
g.scale(10, 10, 1)
w.addItem(g)
import numpy as np
## Hydrogen electron probability density
def psi(i, j, k, offset=(50,50,100)):
x = i-offset[0]
y = j-offset[1]
z = k-offset[2]
th = np.arctan2(z, (x**2+y**2)**0.5)
phi = np.arctan2(y, x)
r = (x**2 + y**2 + z **2)**0.5
th = np.arctan2(z, np.hypot(x, y))
r = np.sqrt(x**2 + y**2 + z **2)
a0 = 2
#ps = (1./81.) * (2./np.pi)**0.5 * (1./a0)**(3/2) * (6 - r/a0) * (r/a0) * np.exp(-r/(3*a0)) * np.cos(th)
ps = (1./81.) * 1./(6.*np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * np.exp(-r/(3*a0)) * (3 * np.cos(th)**2 - 1)
return ps
#return ((1./81.) * (1./np.pi)**0.5 * (1./a0)**(3/2) * (r/a0)**2 * (r/a0) * np.exp(-r/(3*a0)) * np.sin(th) * np.cos(th) * np.exp(2 * 1j * phi))**2
return (
(1.0 / 81.0)
* 1.0 / (6.0 * np.pi) ** 0.5
* (1.0 / a0) ** (3 / 2)
* (r / a0) ** 2
* np.exp(-r / (3 * a0))
* (3 * np.cos(th) ** 2 - 1)
)
data = np.fromfunction(psi, (100,100,200))
positive = np.log(np.clip(data, 0, data.max())**2)
negative = np.log(np.clip(-data, 0, -data.min())**2)
with np.errstate(divide = 'ignore'):
positive = np.log(fn.clip_array(data, 0, data.max())**2)
negative = np.log(fn.clip_array(-data, 0, -data.min())**2)
d2 = np.empty(data.shape + (4,), dtype=np.ubyte)
d2[..., 0] = positive * (255./positive.max())
d2[..., 1] = negative * (255./negative.max())
# Original Code
# d2[..., 0] = positive * (255./positive.max())
# d2[..., 1] = negative * (255./negative.max())
# Reformulated Code
# Both positive.max() and negative.max() are negative-valued.
# Thus the next 2 lines are _not_ bounded to [0, 255]
positive = positive * (255./positive.max())
negative = negative * (255./negative.max())
# When casting to ubyte, the original code relied on +Inf to be
# converted to 0. On arm64, it gets converted to 255.
# Thus the next 2 lines change +Inf explicitly to 0 instead.
positive[np.isinf(positive)] = 0
negative[np.isinf(negative)] = 0
# When casting to ubyte, the original code relied on the conversion
# to do modulo 256. The next 2 lines do it explicitly instead as
# documentation.
d2[..., 0] = positive.astype(int) % 256
d2[..., 1] = negative.astype(int) % 256
d2[..., 2] = d2[...,1]
d2[..., 3] = d2[..., 0]*0.3 + d2[..., 1]*0.3
d2[..., 3] = (d2[..., 3].astype(float) / 255.) **2 * 255
@ -64,4 +83,4 @@ ax = gl.GLAxisItem()
w.addItem(ax)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -9,6 +9,7 @@ used to affect the appearance of a surface.
## Add path to library (just for examples; you do not need this)
import initExample
import numpy as np
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
import pyqtgraph.opengl as gl
@ -23,9 +24,6 @@ g = gl.GLGridItem()
g.scale(2,2,1)
w.addItem(g)
import numpy as np
md = gl.MeshData.sphere(rows=10, cols=20)
x = np.linspace(-8, 8, 6)
@ -102,4 +100,4 @@ w.addItem(m6)
#m2.translate(-25, -25, -50)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -21,4 +21,4 @@ ge = pg.GradientEditorItem()
mw.setCentralItem(ge)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -48,7 +48,7 @@ l.addWidget(w4, 1, 0)
l.addWidget(label, 1, 1)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -58,4 +58,4 @@ lines = np.array([
g.setData(pos=pos, adj=adj, pen=lines, size=1, symbol=symbols, pxMode=False)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -79,4 +79,4 @@ p4.plot([1,3,2,4,3,5])
p5.plot([1,3,2,4,3,5])
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -59,4 +59,4 @@ g = pg.GridItem()
vb.addItem(g)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -3,45 +3,49 @@
Use a HistogramLUTWidget to control the contrast / coloration of an image.
"""
## Add path to library (just for examples; you do not need this)
# Add path to library (just for examples; you do not need this)
import initExample
import numpy as np
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
app = pg.mkQApp("Histogram Lookup Table Example")
win = QtGui.QMainWindow()
win.resize(800,600)
win.resize(880, 600)
win.show()
win.setWindowTitle('pyqtgraph example: Histogram LUT')
cw = QtGui.QWidget()
win.setCentralWidget(cw)
l = QtGui.QGridLayout()
cw.setLayout(l)
l.setSpacing(0)
layout = QtGui.QGridLayout()
cw.setLayout(layout)
layout.setSpacing(0)
v = pg.GraphicsView()
view = pg.GraphicsView()
vb = pg.ViewBox()
vb.setAspectLocked()
v.setCentralItem(vb)
l.addWidget(v, 0, 0, 3, 1)
view.setCentralItem(vb)
layout.addWidget(view, 0, 1, 3, 1)
hist = pg.HistogramLUTWidget(gradientPosition="left")
layout.addWidget(hist, 0, 2)
w = pg.HistogramLUTWidget()
l.addWidget(w, 0, 1)
monoRadio = QtGui.QRadioButton('mono')
rgbaRadio = QtGui.QRadioButton('rgba')
l.addWidget(monoRadio, 1, 1)
l.addWidget(rgbaRadio, 2, 1)
layout.addWidget(monoRadio, 1, 2)
layout.addWidget(rgbaRadio, 2, 2)
monoRadio.setChecked(True)
def setLevelMode():
mode = 'mono' if monoRadio.isChecked() else 'rgba'
w.setLevelMode(mode)
hist.setLevelMode(mode)
monoRadio.toggled.connect(setLevelMode)
data = pg.gaussianFilter(np.random.normal(size=(256, 256, 3)), (20, 20, 0))
@ -52,7 +56,7 @@ img = pg.ImageItem(data)
vb.addItem(img)
vb.autoRange()
w.setImageItem(img)
hist.setImageItem(img)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -9,7 +9,7 @@ import initExample
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
import pyqtgraph as pg
import pyqtgraph.ptime as ptime
from time import perf_counter
app = pg.mkQApp("ImageItem Example")
@ -33,30 +33,30 @@ view.setRange(QtCore.QRectF(0, 0, 600, 600))
data = np.random.normal(size=(15, 600, 600), loc=1024, scale=64).astype(np.uint16)
i = 0
updateTime = ptime.time()
fps = 0
updateTime = perf_counter()
elapsed = 0
timer = QtCore.QTimer()
timer.setSingleShot(True)
# not using QTimer.singleShot() because of persistence on PyQt. see PR #1605
def updateData():
global img, data, i, updateTime, fps
global img, data, i, updateTime, elapsed
## Display the data
img.setImage(data[i])
i = (i+1) % data.shape[0]
timer.start(1)
now = ptime.time()
fps2 = 1.0 / (now-updateTime)
now = perf_counter()
elapsed_now = now - updateTime
updateTime = now
fps = fps * 0.9 + fps2 * 0.1
#print "%0.1f fps" % fps
elapsed = elapsed * 0.9 + elapsed_now * 0.1
# print(f"{1 / elapsed:.1f} fps")
timer.timeout.connect(updateData)
updateData()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -64,4 +64,4 @@ imv.ui.roiBtn.setChecked(True)
imv.roiClicked()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -32,10 +32,54 @@ p1.addItem(inf1)
p1.addItem(inf2)
p1.addItem(inf3)
targetItem1 = pg.TargetItem()
targetItem2 = pg.TargetItem(
pos=(30, 5),
size=20,
symbol="star",
pen="#F4511E",
label="vert={1:0.2f}",
labelOpts={
"offset": QtCore.QPoint(15, 15)
}
)
targetItem2.label().setAngle(45)
targetItem3 = pg.TargetItem(
pos=(10, 10),
size=10,
symbol="x",
pen="#00ACC1",
)
targetItem3.setLabel(
"Third Label",
{
"anchor": QtCore.QPointF(0.5, 0.5),
"offset": QtCore.QPointF(30, 0),
"color": "#558B2F",
"rotateAxis": (0, 1)
}
)
def callableFunction(x, y):
return f"Square Values: ({x**2:.4f}, {y**2:.4f})"
targetItem4 = pg.TargetItem(
pos=(10, -10),
label=callableFunction
)
p1.addItem(targetItem1)
p1.addItem(targetItem2)
p1.addItem(targetItem3)
p1.addItem(targetItem4)
# Add a linear region with a label
lr = pg.LinearRegionItem(values=[70, 80])
p1.addItem(lr)
label = pg.InfLineLabel(lr.lines[1], "region 1", position=0.95, rotateAxis=(1,0), anchor=(1, 1))
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -47,4 +47,4 @@ timer.timeout.connect(update)
timer.start(30)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -40,4 +40,4 @@ legend.addItem(c2, 'curve2')
legend.addItem(s1, 'scatter')
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -31,4 +31,4 @@ p5.setLogMode(x=True, y=False)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -0,0 +1,62 @@
# -*- coding: utf-8 -*-
"""
This example demonstrates ViewBox and AxisItem configuration to plot a correlation matrix.
"""
## Add path to library (just for examples; you do not need this)
import initExample
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtWidgets, mkQApp, QtGui
class MainWindow(QtWidgets.QMainWindow):
""" example application main window """
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
gr_wid = pg.GraphicsLayoutWidget(show=True)
self.setCentralWidget(gr_wid)
self.setWindowTitle('pyqtgraph example: Correlation matrix display')
self.resize(600,500)
self.show()
corrMatrix = np.array([
[ 1. , 0.5184571 , -0.70188642],
[ 0.5184571 , 1. , -0.86094096],
[-0.70188642, -0.86094096, 1. ]
])
columns = ["A", "B", "C"]
pg.setConfigOption('imageAxisOrder', 'row-major') # Switch default order to Row-major
correlogram = pg.ImageItem()
# create transform to center the corner element on the origin, for any assigned image:
tr = QtGui.QTransform().translate(-0.5, -0.5)
correlogram.setTransform(tr)
correlogram.setImage(corrMatrix)
plotItem = gr_wid.addPlot() # add PlotItem to the main GraphicsLayoutWidget
plotItem.invertY(True) # orient y axis to run top-to-bottom
plotItem.setDefaultPadding(0.0) # plot without padding data range
plotItem.addItem(correlogram) # display correlogram
# show full frame, label tick marks at top and left sides, with some extra space for labels:
plotItem.showAxes( True, showValues=(True, True, False, False), size=20 )
# define major tick marks and labels:
ticks = [ (idx, label) for idx, label in enumerate( columns ) ]
for side in ('left','top','right','bottom'):
plotItem.getAxis(side).setTicks( (ticks, []) ) # add list of major ticks; no minor ticks
plotItem.getAxis('bottom').setHeight(10) # include some additional space at bottom of figure
colorMap = pg.colormap.get("CET-D1") # choose perceptually uniform, diverging color map
# generate an adjustabled color bar, initially spanning -1 to 1:
bar = pg.ColorBarItem( values=(-1,1), cmap=colorMap)
# link color bar and color map to correlogram, and show it in plotItem:
bar.setImageItem(correlogram, insert_in=plotItem)
mkQApp("Correlation matrix display")
main_window = MainWindow()
## Start Qt event loop
if __name__ == '__main__':
pg.exec()

View File

@ -31,4 +31,4 @@ for c in curves:
c.sigClicked.connect(plotClicked)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -11,7 +11,9 @@ import initExample
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
from pyqtgraph.ptime import time
from time import perf_counter
# pg.setConfigOptions(useOpenGL=True)
app = pg.mkQApp("MultiPlot Speed Test")
plot = pg.plot()
@ -22,7 +24,7 @@ nPlots = 100
nSamples = 500
curves = []
for idx in range(nPlots):
curve = pg.PlotCurveItem(pen=(idx,nPlots*1.3))
curve = pg.PlotCurveItem(pen=({'color': (idx, nPlots*1.3), 'width': 1}), skipFiniteCheck=True)
plot.addItem(curve)
curve.setPos(0,idx*6)
curves.append(curve)
@ -37,7 +39,7 @@ plot.addItem(rgn)
data = np.random.normal(size=(nPlots*23,nSamples))
ptr = 0
lastTime = time()
lastTime = perf_counter()
fps = None
count = 0
def update():
@ -48,7 +50,7 @@ def update():
curves[i].setData(data[(ptr+i)%data.shape[0]])
ptr += nPlots
now = time()
now = perf_counter()
dt = now - lastTime
lastTime = now
if fps is None:
@ -63,4 +65,4 @@ timer.timeout.connect(update)
timer.start(0)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -33,5 +33,5 @@ ma = MetaArray(data, info=[
pw.plot(ma, pen='y')
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -61,4 +61,4 @@ p2.addItem(pg.PlotCurveItem([10,20,40,80,40,20], pen='b'))
p3.addItem(pg.PlotCurveItem([3200,1600,800,400,200,100], pen='r'))
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -52,10 +52,11 @@ win.setWindowTitle('pyqtgraph example: Non-uniform Image')
p = cw.addPlot(title="Power Losses [W]", row=0, col=0)
lut = pg.HistogramLUTItem()
lut = pg.HistogramLUTItem(orientation="horizontal")
p.setMouseEnabled(x=False, y=False)
cw.nextRow()
cw.addItem(lut)
# load the gradient
@ -79,4 +80,4 @@ p.axes['bottom']['item'].setZValue(1000)
p.axes['left']['item'].setZValue(1000)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -6,10 +6,9 @@ Demonstrates very basic use of PColorMeshItem
## Add path to library (just for examples; you do not need this)
import initExample
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.Qt import QtCore
import numpy as np
import pyqtgraph as pg
import pyqtgraph.ptime as ptime
app = pg.mkQApp("PColorMesh Example")
@ -84,4 +83,4 @@ timer.timeout.connect(updateData)
updateData()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -31,4 +31,4 @@ timer.timeout.connect(update)
timer.start(50)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -41,4 +41,4 @@ timer.timeout.connect(update)
timer.start(50)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -7,46 +7,200 @@ Update a simple plot as rapidly as possible to measure speed.
## Add path to library (just for examples; you do not need this)
import initExample
from pyqtgraph.Qt import QtGui, QtCore
from collections import deque
from pyqtgraph.Qt import QtCore, QtGui, QtWidgets, QT_LIB
import numpy as np
import pyqtgraph as pg
from pyqtgraph.ptime import time
from time import perf_counter
import pyqtgraph.parametertree as ptree
import pyqtgraph.functions as fn
import itertools
import argparse
if QT_LIB.startswith('PyQt'):
wrapinstance = pg.Qt.sip.wrapinstance
else:
wrapinstance = pg.Qt.shiboken.wrapInstance
# defaults here result in the same configuration as the original PlotSpeedTest
parser = argparse.ArgumentParser()
parser.add_argument('--noise', dest='noise', action='store_true')
parser.add_argument('--no-noise', dest='noise', action='store_false')
parser.set_defaults(noise=True)
parser.add_argument('--nsamples', default=5000, type=int)
parser.add_argument('--frames', default=50, type=int)
parser.add_argument('--fsample', default=1000, type=float)
parser.add_argument('--frequency', default=0, type=float)
parser.add_argument('--amplitude', default=5, type=float)
parser.add_argument('--opengl', dest='use_opengl', action='store_true')
parser.add_argument('--no-opengl', dest='use_opengl', action='store_false')
parser.set_defaults(use_opengl=None)
parser.add_argument('--allow-opengl-toggle', action='store_true',
help="""Allow on-the-fly change of OpenGL setting. This may cause unwanted side effects.
""")
args = parser.parse_args()
if args.use_opengl is not None:
pg.setConfigOption('useOpenGL', args.use_opengl)
pg.setConfigOption('enableExperimental', args.use_opengl)
# don't limit frame rate to vsync
sfmt = QtGui.QSurfaceFormat()
sfmt.setSwapInterval(0)
QtGui.QSurfaceFormat.setDefaultFormat(sfmt)
class LineInstances:
def __init__(self):
self.alloc(0)
def alloc(self, size):
self.arr = np.empty((size, 4), dtype=np.float64)
self.ptrs = list(map(wrapinstance,
itertools.count(self.arr.ctypes.data, self.arr.strides[0]),
itertools.repeat(QtCore.QLineF, self.arr.shape[0])))
def array(self, size):
if size > self.arr.shape[0]:
self.alloc(size + 16)
return self.arr[:size]
def instances(self, size):
return self.ptrs[:size]
class MonkeyCurveItem(pg.PlotCurveItem):
def __init__(self, *args, **kwds):
super().__init__(*args, **kwds)
self.monkey_mode = ''
self._lineInstances = LineInstances()
def setMethod(self, param, value):
self.monkey_mode = value
def paint(self, painter, opt, widget):
if self.monkey_mode not in ['drawPolyline', 'drawLines']:
return super().paint(painter, opt, widget)
painter.setRenderHint(painter.RenderHint.Antialiasing, self.opts['antialias'])
painter.setPen(pg.mkPen(self.opts['pen']))
if self.monkey_mode == 'drawPolyline':
painter.drawPolyline(fn.arrayToQPolygonF(self.xData, self.yData))
elif self.monkey_mode == 'drawLines':
lines = self._lineInstances
npts = len(self.xData)
even_slice = slice(0, 0+(npts-0)//2*2)
odd_slice = slice(1, 1+(npts-1)//2*2)
for sl in [even_slice, odd_slice]:
npairs = (sl.stop - sl.start) // 2
memory = lines.array(npairs).reshape((-1, 2))
memory[:, 0] = self.xData[sl]
memory[:, 1] = self.yData[sl]
painter.drawLines(lines.instances(npairs))
app = pg.mkQApp("Plot Speed Test")
p = pg.plot()
p.setWindowTitle('pyqtgraph example: PlotSpeedTest')
p.setRange(QtCore.QRectF(0, -10, 5000, 20))
p.setLabel('bottom', 'Index', units='B')
curve = p.plot()
default_pen = pg.mkPen()
#curve.setFillBrush((0, 0, 100, 100))
#curve.setFillLevel(0)
children = [
dict(name='sigopts', title='Signal Options', type='group', children=[
dict(name='noise', type='bool', value=args.noise),
dict(name='nsamples', type='int', limits=[0, None], value=args.nsamples),
dict(name='frames', type='int', limits=[1, None], value=args.frames),
dict(name='fsample', title='sample rate', type='float', value=args.fsample, units='Hz'),
dict(name='frequency', type='float', value=args.frequency, units='Hz'),
dict(name='amplitude', type='float', value=args.amplitude),
]),
dict(name='useOpenGL', type='bool', value=pg.getConfigOption('useOpenGL'),
readonly=not args.allow_opengl_toggle),
dict(name='enableExperimental', type='bool', value=pg.getConfigOption('enableExperimental')),
dict(name='pen', type='pen', value=default_pen),
dict(name='antialias', type='bool', value=pg.getConfigOption('antialias')),
dict(name='connect', type='list', limits=['all', 'pairs', 'finite', 'array'], value='all'),
dict(name='skipFiniteCheck', type='bool', value=False),
dict(name='plotMethod', title='Plot Method', type='list', limits=['pyqtgraph', 'drawPolyline', 'drawLines'])
]
#lr = pg.LinearRegionItem([100, 4900])
#p.addItem(lr)
params = ptree.Parameter.create(name='Parameters', type='group', children=children)
pt = ptree.ParameterTree(showHeader=False)
pt.setParameters(params)
pw = pg.PlotWidget()
splitter = QtWidgets.QSplitter()
splitter.addWidget(pt)
splitter.addWidget(pw)
splitter.show()
data = np.random.normal(size=(50,5000))
ptr = 0
lastTime = time()
fps = None
pw.setWindowTitle('pyqtgraph example: PlotSpeedTest')
pw.setLabel('bottom', 'Index', units='B')
curve = MonkeyCurveItem(pen=default_pen)
pw.addItem(curve)
rollingAverageSize = 1000
elapsed = deque(maxlen=rollingAverageSize)
def resetTimings(*args):
elapsed.clear()
def makeData(*args):
global data, connect_array, ptr
sigopts = params.child('sigopts')
nsamples = sigopts['nsamples']
frames = sigopts['frames']
Fs = sigopts['fsample']
A = sigopts['amplitude']
F = sigopts['frequency']
ttt = np.arange(frames * nsamples, dtype=np.float64) / Fs
data = A*np.sin(2*np.pi*F*ttt).reshape((frames, nsamples))
if sigopts['noise']:
data += np.random.normal(size=data.shape)
connect_array = np.ones(data.shape[-1], dtype=bool)
ptr = 0
pw.setRange(QtCore.QRectF(0, -10, nsamples, 20))
def onUseOpenGLChanged(param, enable):
pw.useOpenGL(enable)
def onEnableExperimentalChanged(param, enable):
pg.setConfigOption('enableExperimental', enable)
def onPenChanged(param, pen):
curve.setPen(pen)
params.child('sigopts').sigTreeStateChanged.connect(makeData)
params.child('useOpenGL').sigValueChanged.connect(onUseOpenGLChanged)
params.child('enableExperimental').sigValueChanged.connect(onEnableExperimentalChanged)
params.child('pen').sigValueChanged.connect(onPenChanged)
params.child('plotMethod').sigValueChanged.connect(curve.setMethod)
params.sigTreeStateChanged.connect(resetTimings)
makeData()
fpsLastUpdate = perf_counter()
def update():
global curve, data, ptr, p, lastTime, fps
curve.setData(data[ptr%10])
ptr += 1
now = time()
dt = now - lastTime
lastTime = now
if fps is None:
fps = 1.0/dt
else:
s = np.clip(dt*3., 0, 1)
fps = fps * (1-s) + (1.0/dt) * s
p.setTitle('%0.2f fps' % fps)
app.processEvents() ## force complete redraw for every plot
global curve, data, ptr, elapsed, fpsLastUpdate
options = ['antialias', 'connect', 'skipFiniteCheck']
kwds = { k : params[k] for k in options }
if kwds['connect'] == 'array':
kwds['connect'] = connect_array
# Measure
t_start = perf_counter()
curve.setData(data[ptr], **kwds)
app.processEvents(QtCore.QEventLoop.ProcessEventsFlag.AllEvents)
t_end = perf_counter()
elapsed.append(t_end - t_start)
ptr = (ptr + 1) % data.shape[0]
# update fps at most once every 0.2 secs
if t_end - fpsLastUpdate > 0.2:
fpsLastUpdate = t_end
average = np.mean(elapsed)
fps = 1 / average
pw.setTitle('%0.2f fps - %0.1f ms avg' % (fps, average * 1_000))
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -87,4 +87,4 @@ pw3.addItem(line)
line.setBounds([0,200])
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -96,4 +96,4 @@ p9.sigXRangeChanged.connect(updateRegion)
updatePlot()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -158,4 +158,4 @@ def remove():
r4.sigRemoveRequested.connect(remove)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -119,4 +119,4 @@ t.timeout.connect(updateImage)
t.start(50)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -27,4 +27,4 @@ v.setCentralItem(plt)
plt.plot([1,4,2,3,6,2,3,4,2,3], pen='g')
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -16,6 +16,7 @@ from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import pyqtgraph.widgets.RemoteGraphicsView
import numpy as np
from time import perf_counter
app = pg.mkQApp()
@ -45,7 +46,7 @@ rplt = view.pg.PlotItem()
rplt._setProxyOptions(deferGetattr=True) ## speeds up access to rplt.plot
view.setCentralItem(rplt)
lastUpdate = pg.ptime.time()
lastUpdate = perf_counter()
avgFps = 0.0
def update():
@ -62,7 +63,7 @@ def update():
if lcheck.isChecked():
lplt.plot(data, clear=True)
now = pg.ptime.time()
now = perf_counter()
fps = 1.0 / (now - lastUpdate)
lastUpdate = now
avgFps = avgFps * 0.8 + fps * 0.2
@ -73,4 +74,4 @@ timer.timeout.connect(update)
timer.start(0)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

23
examples/RunExampleApp.py Normal file
View File

@ -0,0 +1,23 @@
import initExample ## Add path to library (just for examples; you do not need this)
import pyqtgraph as pg
from pyqtgraph.Qt import QtTest
from examples.ExampleApp import ExampleLoader
"""
This file is used by test_examples.py for ensuring the Example App works.
It is not named test_ExampleApp.py as that way the Example application is
not run twice.
"""
pg.mkQApp()
def test_ExampleLoader():
loader = ExampleLoader()
QtTest.QTest.qWaitForWindowExposed(loader)
QtTest.QTest.qWait(200)
loader.close()
if __name__ == "__main__":
test_ExampleLoader()
pg.exec()

View File

@ -25,4 +25,4 @@ scale.setParentItem(vb)
scale.anchor((1, 1), (1, 1), offset=(-20, -20))
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -135,4 +135,4 @@ w4.addItem(s4)
s4.sigClicked.connect(clicked)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -12,9 +12,9 @@ import initExample
import numpy as np
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore, QtWidgets
from pyqtgraph.ptime import time
import pyqtgraph.parametertree as ptree
import pyqtgraph.graphicsItems.ScatterPlotItem
from time import perf_counter
translate = QtCore.QCoreApplication.translate
@ -24,10 +24,9 @@ param = ptree.Parameter.create(name=translate('ScatterPlot', 'Parameters'), type
dict(name='count', title=translate('ScatterPlot', 'Count: '), type='int', limits=[1, None], value=500, step=100),
dict(name='size', title=translate('ScatterPlot', 'Size: '), type='int', limits=[1, None], value=10),
dict(name='randomize', title=translate('ScatterPlot', 'Randomize: '), type='bool', value=False),
dict(name='_USE_QRECT', title='_USE_QRECT: ', type='bool', value=pyqtgraph.graphicsItems.ScatterPlotItem._USE_QRECT),
dict(name='pxMode', title='pxMode: ', type='bool', value=True),
dict(name='useCache', title='useCache: ', type='bool', value=True),
dict(name='mode', title=translate('ScatterPlot', 'Mode: '), type='list', values={translate('ScatterPlot', 'New Item'): 'newItem', translate('ScatterPlot', 'Reuse Item'): 'reuseItem', translate('ScatterPlot', 'Simulate Pan/Zoom'): 'panZoom', translate('ScatterPlot', 'Simulate Hover'): 'hover'}, value='reuseItem'),
dict(name='mode', title=translate('ScatterPlot', 'Mode: '), type='list', limits={translate('ScatterPlot', 'New Item'): 'newItem', translate('ScatterPlot', 'Reuse Item'): 'reuseItem', translate('ScatterPlot', 'Simulate Pan/Zoom'): 'panZoom', translate('ScatterPlot', 'Simulate Hover'): 'hover'}, value='reuseItem'),
])
for c in param.children():
c.setDefault(c.value())
@ -44,7 +43,7 @@ data = {}
item = pg.ScatterPlotItem()
hoverBrush = pg.mkBrush('y')
ptr = 0
lastTime = time()
lastTime = perf_counter()
fps = None
timer = QtCore.QTimer()
@ -68,7 +67,6 @@ def mkDataAndItem():
def mkItem():
global item
pyqtgraph.graphicsItems.ScatterPlotItem._USE_QRECT = param['_USE_QRECT']
item = pg.ScatterPlotItem(pxMode=param['pxMode'], **getData())
item.opts['useCache'] = param['useCache']
p.clear()
@ -106,7 +104,7 @@ def update():
new.setBrush(hoverBrush)
ptr += 1
now = time()
now = perf_counter()
dt = now - lastTime
lastTime = now
if fps is None:
@ -122,11 +120,11 @@ def update():
mkDataAndItem()
for name in ['count', 'size']:
param.child(name).sigValueChanged.connect(mkDataAndItem)
for name in ['_USE_QRECT', 'useCache', 'pxMode', 'randomize']:
for name in ['useCache', 'pxMode', 'randomize']:
param.child(name).sigValueChanged.connect(mkItem)
param.child('paused').sigValueChanged.connect(lambda _, v: timer.stop() if v else timer.start())
timer.timeout.connect(update)
timer.start(0)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -63,4 +63,4 @@ spw.setData(data)
spw.show()
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -6,4 +6,4 @@ import numpy as np
plt = pg.plot(np.random.normal(size=100), title="Simplest possible plotting example")
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

View File

@ -129,4 +129,4 @@ layout.addWidget(changedLabel, 2, 1)
if __name__ == '__main__':
pg.mkQApp().exec_()
pg.exec()

Some files were not shown because too many files have changed in this diff Show More