diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000000..257b4ce1bd --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,14 @@ +# These are supported funding model platforms + +github: [j9ac9k] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +polar: # Replace with a single Polar username +buy_me_a_coffee: # Replace with a single Buy Me a Coffee username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 8f09fff301..0000000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,44 +0,0 @@ -Detail the reasoning behind the code change. If there is an associated issue that this PR will resolve add - -Fixes # - -### Other Tasks - -
- Bump Dependency Versions - -### Files that need updates - -Confirm the following files have been either updated or there has been a determination that no update is needed. - -- [ ] `README.md` -- [ ] `setup.py` -- [ ] `tox.ini` -- [ ] `.github/workflows/main.yml` and associated `requirements.txt` and conda `environemt.yml` files -- [ ] `pyproject.toml` -- [ ] `binder/requirements.txt` - -
- -
- Pre-Release Checklist - -### Pre Release Checklist - -- [ ] Update version info in `__init__.py` -- [ ] Update `CHANGELOG` primarily using contents from automated changelog generation in GitHub release page -- [ ] Have git tag in the format of pyqtgraph- - -
- - -
- Post-Release Checklist - -### Steps To Complete - -- [ ] Append `.dev0` to `__version__` in `__init__.py` -- [ ] Announce on mail list -- [ ] Announce on Twitter - -
diff --git a/.github/workflows/check_prereleases.yml b/.github/workflows/check_prereleases.yml new file mode 100644 index 0000000000..86663fc324 --- /dev/null +++ b/.github/workflows/check_prereleases.yml @@ -0,0 +1,110 @@ +name: check_qt_prereleases + +on: workflow_dispatch + +env: + PIP_DISABLE_PIP_VERSION_CHECK: 1 + +concurrency: + group: ${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + test-qt-prerelease: + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + qt-lib: [pyqt6, pyside] + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: "Install Linux VirtualDisplay" + if: runner.os == 'Linux' + run: | + sudo apt-get update -y --allow-releaseinfo-change + sudo apt-get install --no-install-recommends -y \ + libxkbcommon-x11-0 \ + x11-utils \ + libyaml-dev \ + libegl1-mesa \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + libopengl0 \ + libxcb-cursor0 \ + - name: "Install Windows-Mesa OpenGL DLL" + if: runner.os == 'Windows' + run: | + curl -L --output mesa.7z --url https://github.com/pal1000/mesa-dist-win/releases/download/24.0.6/mesa3d-24.0.6-release-msvc.7z + 7z x mesa.7z -o* + powershell.exe mesa\systemwidedeploy.cmd 1 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.12' + - name: Install PySide6 + if: matrix.qt-lib == 'pyside' + run: | + python -m pip install --no-index \ + --find-links https://download.qt.io/snapshots/ci/pyside/dev/latest/pyside6/ \ + --pre \ + PySide6_Essentials + shell: bash + - name: Install PyQt6 + if: matrix.qt-lib == 'pyqt6' + run: | + python -m pip install --index-url https://www.riverbankcomputing.com/pypi/simple/ \ + --pre \ + --only-binary=PyQt6 \ + PyQt6 + shell: bash + - name: Install Regular Dependencies + run: | + python -m pip install --pre numpy scipy pyopengl pytest . + - name: Install pytest-xvfb + run: | + python -m pip install pytest-xvfb + if: runner.os == 'Linux' + - name: 'Debug Info' + run: | + echo python location: `which python` + echo python version: `python --version` + echo pytest location: `which pytest` + echo installed packages + python -m pip list + echo pyqtgraph system info + python -c "import pyqtgraph as pg; pg.systemInfo()" + shell: bash + env: + QT_DEBUG_PLUGINS: 1 + - name: 'XVFB Display Info' + run: | + xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.glinfo + xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.get_resolution + if: runner.os == 'Linux' + - name: 'Display Info' + run: | + python -m pyqtgraph.util.glinfo + python -m pyqtgraph.util.get_resolution + if: runner.os != 'Linux' + - name: Run Tests + run: | + mkdir "$SCREENSHOT_DIR" + pytest tests -v + pytest pyqtgraph/examples -v + shell: bash + - name: Upload Screenshots + if: failure() + uses: actions/upload-artifact@v4 + with: + name: Screenshots - Qt-Bindings ${{ matrix.qt-lib }} - ${{ matrix.os }}) + path: ${{ env.SCREENSHOT_DIR }} + if-no-files-found: ignore + env: + SCREENSHOT_DIR: screenshots diff --git a/.github/workflows/etc/environment-pyqt.yml b/.github/workflows/etc/environment-pyqt.yml index ddec6751dc..65afe767a9 100644 --- a/.github/workflows/etc/environment-pyqt.yml +++ b/.github/workflows/etc/environment-pyqt.yml @@ -3,7 +3,6 @@ channels: - conda-forge dependencies: - pyqt - - qt-main - numpy - nomkl - scipy diff --git a/.github/workflows/etc/environment-pyside.yml b/.github/workflows/etc/environment-pyside.yml index 6a3e8b01f6..706e5708a0 100644 --- a/.github/workflows/etc/environment-pyside.yml +++ b/.github/workflows/etc/environment-pyside.yml @@ -2,8 +2,7 @@ name: test channels: - conda-forge dependencies: - - pyside2 - - qt-main + - pyside6 - numpy - nomkl - scipy diff --git a/.github/workflows/etc/requirements.txt b/.github/workflows/etc/requirements.txt index b48d2b6484..cff23f61c0 100644 --- a/.github/workflows/etc/requirements.txt +++ b/.github/workflows/etc/requirements.txt @@ -1,22 +1,22 @@ # numpy based on python version and NEP-29 requirements -numpy; python_version == '3.10' numpy; python_version == '3.11' -numpy~=1.22.0; python_version == '3.9' +numpy; python_version == '3.12' +numpy~=1.23.0; python_version == '3.10' # image testing -scipy==1.11.2 +scipy==1.13.1 # optional high performance paths -numba==0.57.1; python_version == '3.9' +numba==0.59.1; python_version == '3.10' # optional 3D pyopengl==3.1.7 # supplimental tools -matplotlib==3.7.2 -h5py==3.9.0 +matplotlib==3.9.0 +h5py==3.11.0 # testing -pytest==7.4.0 -pytest-xdist==3.3.1 +pytest==8.2.2 +pytest-xdist==3.6.1 pytest-xvfb==3.0.0; sys_platform == 'linux' diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8c37e84893..f06012305d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -15,6 +15,40 @@ concurrency: cancel-in-progress: true jobs: + make_dash_docset: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + cache: pip + - name: Install Build Dependencies + run: | + python -m pip install --upgrade doc2dash setuptools -r doc/requirements.txt + - name: Build docset + run: | + make -C doc dash + - run: tar --exclude='.DS_Store' -cvzf pyqtgraph.tgz doc/pyqtgraph.docset + - name: Upload docset + uses: actions/upload-artifact@v4 + with: + name: pyqtgraph.docset + path: pyqtgraph.tgz + run-mypy: + runs-on: ubuntu-latest + steps: + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Checkout + uses: actions/checkout@v4 + - name: Install mypy + run: pip install mypy + - name: Run mypy + run: mypy test-pip: runs-on: ${{ matrix.os }} timeout-minutes: 30 @@ -23,77 +57,51 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] qt-lib: [pyqt, pyside] - python-version: ["3.9", "3.10", "3.11"] + python-version: ["3.10", "3.11", "3.12"] include: - - python-version: "3.9" + - python-version: "3.10" qt-lib: "pyqt" qt-version: "PyQt5~=5.15.0" - - python-version: "3.9" + - python-version: "3.10" qt-lib: "pyside" qt-version: "PySide2~=5.15.0" - - python-version: "3.10" + - python-version: "3.11" qt-lib: "pyqt" qt-version: "PyQt6~=6.2.0 PyQt6-Qt6~=6.2.0" - - python-version: "3.10" + - python-version: "3.11" qt-lib: "pyside" - qt-version: "PySide6~=6.2.0" - - python-version: "3.10" + qt-version: "PySide6-Essentials~=6.4.0" + - python-version: "3.12" qt-lib: "pyqt" qt-version: "PyQt6" - - python-version: "3.10" + - python-version: "3.12" qt-lib: "pyside" qt-version: "PySide6-Essentials" - - python-version: "3.11" - qt-lib: "pyqt" - qt-version: "PyQt6" - - python-version: "3.11" + exclude: + - os: macos-latest + python-version: "3.10" qt-lib: "pyside" - qt-version: "PySide6-Essentials" steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - # Semantic version range syntax or exact version of a Python version python-version: ${{ matrix.python-version }} cache: pip - - name: Get pip cache dir - id: pip-cache - run: | - echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT - shell: bash - - name: pip cache - uses: actions/cache@v3 - with: - path: ${{ steps.pip-cache.outputs.dir }} - key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} - restore-keys: | - ${{ runner.os }}-pip- - name: "Install Windows-Mesa OpenGL DLL" if: runner.os == 'Windows' run: | - curl -LJO https://github.com/pal1000/mesa-dist-win/releases/download/19.2.7/mesa3d-19.2.7-release-msvc.7z - 7z x mesa3d-19.2.7-release-msvc.7z - cd x64 - xcopy opengl32.dll C:\windows\system32\mesadrv.dll* - xcopy opengl32.dll C:\windows\syswow64\mesadrv.dll* - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f - shell: cmd + curl -L --output mesa.7z --url https://github.com/pal1000/mesa-dist-win/releases/download/24.0.6/mesa3d-24.0.6-release-msvc.7z + 7z x mesa.7z -o* + powershell.exe mesa\systemwidedeploy.cmd 1 - name: Install Dependencies run: | python -m pip install -r .github/workflows/etc/requirements.txt ${{ matrix.qt-version }} . - name: "Install Linux VirtualDisplay" if: runner.os == 'Linux' run: | - sudo apt-get update -y + sudo apt-get update -y --allow-releaseinfo-change sudo apt-get install --no-install-recommends -y \ libxkbcommon-x11-0 \ x11-utils \ @@ -131,18 +139,19 @@ jobs: if: runner.os != 'Linux' - name: Run Tests run: | - mkdir $SCREENSHOT_DIR + mkdir "$SCREENSHOT_DIR" pytest tests -v pytest pyqtgraph/examples -v -n 2 shell: bash - name: Upload Screenshots - uses: actions/upload-artifact@v3 + if: failure() + uses: actions/upload-artifact@v4 with: name: Screenshots (Python ${{ matrix.python-version }} - Qt-Bindings ${{ matrix.qt-lib }} - OS ${{ matrix.os }}) - path: $SCREENSHOT_DIR + path: ${{ env.SCREENSHOT_DIR }} if-no-files-found: ignore env: - SCREENSHOT_DIR: ./screenshots + SCREENSHOT_DIR: screenshots test-conda: runs-on: ${{ matrix.os }} @@ -161,82 +170,79 @@ jobs: - qt-lib: pyside environment-file: .github/workflows/etc/environment-pyside.yml steps: - - name: Checkout - uses: actions/checkout@v4 - - uses: conda-incubator/setup-miniconda@v2 - with: - miniforge-version: latest - miniforge-variant: Mambaforge - environment-file: ${{ matrix.environment-file }} - auto-update-conda: false - python-version: "3.10" - use-mamba: true - - name: "Install Test Framework" - run: pip install pytest pytest-xdist - - name: "Install Windows-Mesa OpenGL DLL" - if: runner.os == 'Windows' - run: | - curl -LJO https://github.com/pal1000/mesa-dist-win/releases/download/19.2.7/mesa3d-19.2.7-release-msvc.7z - 7z x mesa3d-19.2.7-release-msvc.7z - cd x64 - xcopy opengl32.dll C:\windows\system32\mesadrv.dll* - xcopy opengl32.dll C:\windows\syswow64\mesadrv.dll* - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DLL /t REG_SZ /d "mesadrv.dll" /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v DriverVersion /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Flags /t REG_DWORD /d 1 /f - REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\OpenGLDrivers\MSOGL" /v Version /t REG_DWORD /d 2 /f - shell: cmd - - name: "Install Linux VirtualDisplay" - if: runner.os == 'Linux' - run: | - sudo apt-get update -y - sudo apt-get install -y --no-install-recommends \ - libxkbcommon-x11-0 \ - x11-utils \ - libyaml-dev \ - libegl1-mesa \ - libxcb-icccm4 \ - libxcb-image0 \ - libxcb-keysyms1 \ - libxcb-randr0 \ - libxcb-render-util0 \ - libxcb-xinerama0 \ - libopengl0 \ - libxcb-cursor0 - 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 - conda list - pip list - echo pyqtgraph system info - python -c "import pyqtgraph as pg; pg.systemInfo()" - env: - QT_DEBUG_PLUGINS: 1 - - name: 'XVFB Display Info' - run: | - xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.glinfo - xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.get_resolution - if: runner.os == 'Linux' - - name: 'Display Info' - run: | - python -m pyqtgraph.util.glinfo - python -m pyqtgraph.util.get_resolution - if: runner.os != 'Linux' - - name: Run Tests - run: | - mkdir $SCREENSHOT_DIR - pytest tests -v - pytest pyqtgraph/examples -v -n 2 - env: - SCREENSHOT_DIR: ./screenshots + - name: Checkout + uses: actions/checkout@v4 + - uses: conda-incubator/setup-miniconda@v3 + with: + miniforge-version: latest + miniforge-variant: Mambaforge + environment-file: ${{ matrix.environment-file }} + auto-update-conda: false + python-version: "3.12" + use-mamba: true + - name: "Install Test Framework" + run: pip install pytest pytest-xdist + - name: "Install Windows-Mesa OpenGL DLL" + if: runner.os == 'Windows' + run: | + curl -L --output mesa.7z --url https://github.com/pal1000/mesa-dist-win/releases/download/24.0.6/mesa3d-24.0.6-release-msvc.7z + 7z x mesa.7z -o* + powershell.exe mesa\systemwidedeploy.cmd 1 + shell: pwsh + - name: "Install Linux VirtualDisplay" + if: runner.os == 'Linux' + run: | + sudo apt-get update -y --allow-releaseinfo-change + sudo apt-get install -y --no-install-recommends \ + libxkbcommon-x11-0 \ + x11-utils \ + libyaml-dev \ + libegl1-mesa \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + libopengl0 \ + libxcb-cursor0 + 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 + conda list + pip list + echo pyqtgraph system info + python -c "import pyqtgraph as pg; pg.systemInfo()" + env: + QT_DEBUG_PLUGINS: 1 + - name: 'XVFB Display Info' + run: | + xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.glinfo + xvfb-run --server-args="-screen 0, 1920x1200x24 -ac +extension GLX +render -noreset" python -m pyqtgraph.util.get_resolution + if: runner.os == 'Linux' + - name: 'Display Info' + run: | + python -m pyqtgraph.util.glinfo + python -m pyqtgraph.util.get_resolution + if: runner.os != 'Linux' + - name: Run Tests + run: | + mkdir "$SCREENSHOT_DIR" + pytest tests -v + pytest pyqtgraph/examples -v -n 2 + - name: Upload Screenshots + if: failure() + uses: actions/upload-artifact@v4 + with: + name: Screenshots (Conda - Qt-Bindings ${{ matrix.qt-lib }} - OS ${{ matrix.os }}) + path: ${{ env.SCREENSHOT_DIR }} + if-no-files-found: ignore + env: + SCREENSHOT_DIR: screenshots build-wheel: name: build wheel @@ -244,60 +250,46 @@ jobs: steps: - uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' + cache: pip - name: Build Wheel run: | - python -m pip install setuptools wheel - python setup.py bdist_wheel + pip install build + python -m build --wheel + - name: Upload Wheel + uses: actions/upload-artifact@v4 + with: + name: wheel + path: dist/*.whl analyze: name: analyze runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write steps: - name: Checkout repository uses: actions/checkout@v4 with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. fetch-depth: 2 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: '3.11' + python-version: '3.12' + cache: pip - name: Install Dependencies run: | python -m pip install PyQt5 numpy scipy - echo "CODEQL_PYTHON=$(which python)" >> $GITHUB_ENV - - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v2 + uses: github/codeql-action/init@v3 with: languages: 'python' - # Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python'] - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. queries: +security-and-quality - setup-python-dependencies: false - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - + uses: github/codeql-action/autobuild@v3 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000000..aad5563615 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,25 @@ +name: Upload Python Package + +on: + release: + types: [published] + +jobs: + pypi-publish: + runs-on: ubuntu-latest + permissions: + id-token: write + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install Dependencies + run: | + python -m pip install -U build + - name: Build Wheel + run: | + python -m build --wheel + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml deleted file mode 100644 index 312b2ec77c..0000000000 --- a/.github/workflows/python-publish.yml +++ /dev/null @@ -1,33 +0,0 @@ -# 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: [published] - -jobs: - deploy: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v4 - 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/* diff --git a/.gitignore b/.gitignore index 19b29428e2..f612c8830a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] +*$py.class # C extensions *.so @@ -41,6 +42,14 @@ cover/ nosetests.xml coverage.xml .coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ # Translations *.mo @@ -113,4 +122,17 @@ asv.conf.json # jupyter notebooks .ipynb_checkpoints + +# Environments +.env .venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json \ No newline at end of file diff --git a/.readthedocs.yaml b/.readthedocs.yaml index d5ba108e30..4b811855c0 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -9,6 +9,7 @@ build: python: "3" apt_packages: - libopengl0 + - graphviz sphinx: fail_on_warning: true diff --git a/CHANGELOG b/CHANGELOG index d323da6031..45956eac90 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,261 @@ +pyqtgraph-0.13.7 + +## What's Changed + +* test_PolyLineROI now passes on non-AMD64 platforms by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2999 +* Add note about NaN to int conversion by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/3007 +* remove functions.try_fastpath_argb as it triggered segfaults by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/3008 +* Allow users to specify FillRule for FillBetweenItem, undo regressionfrom #2971 by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/3006 + +pyqtgraph-0.13.6 + +## What's Changed + +* bdist_wheel needs to grab peegee icons by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/3000 + + +**Full Changelog**: https://github.com/pyqtgraph/pyqtgraph/compare/pyqtgraph-0.13.5...pyqtgraph-0.13.6 + +pyqtgraph-0.13.5 + +## What's Changed + +### Highlights + +* add fastpath for float images with nans by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2970 +* Add peegee as mkQApp application icon by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2990 +* Add stubs for Qt modules by @maflAT in https://github.com/pyqtgraph/pyqtgraph/pull/2972 +* add ColorMapMenu to ColorBarItem by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2955 + + +### API/Behavior Changes + +* add ColorMapMenu to ColorBarItem by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2955 +* Add Vertical and Horizontal Line Symbols by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2985 + + +### Bug Fixes + +* Filling correction for Fillbetweenitem by @BousquetSophie in https://github.com/pyqtgraph/pyqtgraph/pull/2971 +* Fix SpinBox SyntaxWarnings #2962 by @aaryamantriescode in https://github.com/pyqtgraph/pyqtgraph/pull/2964 +* class Handle Fix allowing dict to be passed for handlePen and removing hard reset for width and cosmetic attributes by @pdmkdz in https://github.com/pyqtgraph/pyqtgraph/pull/2907 +* numpy 2.0: workaround regression in rescaleData by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2974 + + +### Misc + +* Add peegee as mkQApp application icon by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2990 +* Add stubs for Qt modules by @maflAT in https://github.com/pyqtgraph/pyqtgraph/pull/2972 +* set SymbolAtlas dpr to primary screen's dpr by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2965 +* ImageView example: use levelMode="rgba" by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2963 +* Remove deprecated use of paletteChanged by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2993 +* Set Application Icon on windows by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2992 + + +## New Contributors + +* @aaryamantriescode made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2964 +* @maflAT made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2972 +* @BousquetSophie made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2971 +* @pdmkdz made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2907 + +**Full Changelog**: https://github.com/pyqtgraph/pyqtgraph/compare/pyqtgraph-0.13.4...pyqtgraph-0.13.5 + +pyqtgraph-0.13.4 + +## What's Changed + +### Highlights + +* Optimize clip and downsample by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2719 +* Drop python 3.8 and numpy 1.20 support by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2740 +* speed up PColorMeshItem by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2768 +* NonUniformImage improvements by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2764 +* Fix 'import pyqtgraph.canvas' crash by @nicoddemus in https://github.com/pyqtgraph/pyqtgraph/pull/2934 +* Add LabelItem font family option by @misantroop in https://github.com/pyqtgraph/pyqtgraph/pull/2919 + + +### API/Behavior Changes + +* Drop python 3.8 and numpy 1.20 support by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2740 +* Add `dataBounds()` method to `TextItem` to make autoRange more predictable by @redruin1 in https://github.com/pyqtgraph/pyqtgraph/pull/2646 +* speed up PColorMeshItem by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2768 +* NonUniformImage improvements by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2764 +* Adapt hide icon (invisible eye) to style of other icons by @stephan-senkbeil in https://github.com/pyqtgraph/pyqtgraph/pull/2731 +* Add updatePristineValues arg to Parameter.setDefault by @outofculture in https://github.com/pyqtgraph/pyqtgraph/pull/2853 +* Allow ROI context menu to show if non-removable by @samtygier in https://github.com/pyqtgraph/pyqtgraph/pull/2932 +* Add LabelItem font family option by @misantroop in https://github.com/pyqtgraph/pyqtgraph/pull/2919 +* Center exportDialog using screen geometry by @MorbidCuriosity84 in https://github.com/pyqtgraph/pyqtgraph/pull/2930 +* Give siPrefix behavior to values of zero by @outofculture in https://github.com/pyqtgraph/pyqtgraph/pull/2842 +* make ColorBarItem agnostic of the image kind by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2879 +* Allow menu selection of ColorMap(s) by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2779 +* AxisItem: Add adjustable label overlap tolerances, vertical overlap by default by @NilsNemitz in https://github.com/pyqtgraph/pyqtgraph/pull/2836 +* chg: NodeGraphicsItem in Node.py by @Doralitze in https://github.com/pyqtgraph/pyqtgraph/pull/2869 +* ScatterPlotItem: implement hidpi pixmap by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2863 +* Axis ticker update by @NilsNemitz in https://github.com/pyqtgraph/pyqtgraph/pull/2827 +* Preserve tick pen by @NilsNemitz in https://github.com/pyqtgraph/pyqtgraph/pull/2828 +* Add turbo colormap to local ColorMaps and GradientEditorItem by @ptuemmler in https://github.com/pyqtgraph/pyqtgraph/pull/2778 + + +### Bug Fixes + +* GLViewWidget: fix mouse pos jumps when mouse tracking is off by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2698 +* TypeError when using multiple pens for different lines by @adriandavidauer in https://github.com/pyqtgraph/pyqtgraph/pull/2704 +* PySide6 6.5.1 compatibility updates by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2734 +* guard against auto-downsample oscillation by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2726 +* For SVG exports, shift PlotCurveItems to be about 0,0 by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2728 +* Update TextItem.py by @dingo9 in https://github.com/pyqtgraph/pyqtgraph/pull/2761 +* Fix invisible InfiniteLine at plot edges by @bbc131 in https://github.com/pyqtgraph/pyqtgraph/pull/2762 +* Fix #2786: proper handling of slider parameter suffix by @ntjess in https://github.com/pyqtgraph/pyqtgraph/pull/2796 +* fix: wrong key set to _pixelVectorCache by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2795 +* PlotCurveItem check if args is None first by @JayanthBontha in https://github.com/pyqtgraph/pyqtgraph/pull/2835 +* fixed recursive PlotWidget.__getattr__ calls by @nleclercq in https://github.com/pyqtgraph/pyqtgraph/pull/2860 +* Do not move PlotCurveItem to origin by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2950 +* close ROI handle subpath by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2949 +* Add updatePristineValues arg to Parameter.setDefault by @outofculture in https://github.com/pyqtgraph/pyqtgraph/pull/2853 +* Use non-deprecated method to access screen info by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2938 +* coerce to dtype after creation by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2939 +* disconnect only slots that got connected by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2923 +* Prevent containerChanged from collapsing an entire container tree by @UsYer in https://github.com/pyqtgraph/pyqtgraph/pull/2888 +* fix: paint method widget argument can be None by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2903 +* Fix 'import pyqtgraph.canvas' crash by @nicoddemus in https://github.com/pyqtgraph/pyqtgraph/pull/2934 +* Fix Python 3.12 `DeprecationWarning`: `datetime.datetime.utcfromtimestamp()` by @bersbersbers in https://github.com/pyqtgraph/pyqtgraph/pull/2848 +* convert QPointF to QPoint before calling mapToScene() by @sevas in https://github.com/pyqtgraph/pyqtgraph/pull/2870 +* Numpy > 1.20 by @MalteOlle in https://github.com/pyqtgraph/pyqtgraph/pull/2739 +* Fix resizing ViewBox if aspect locked + apply ViewBox limits immediately by @bbc131 in https://github.com/pyqtgraph/pyqtgraph/pull/2799 + + +### Misc + +* bump to dev version by @ntjess in https://github.com/pyqtgraph/pyqtgraph/pull/2693 +* Don't draw InfiniteLine anti-aliased if vertical or horizontal by @bbc131 in https://github.com/pyqtgraph/pyqtgraph/pull/2709 +* Optimize clip and downsample by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2719 +* WidgetGroup: avoid lambda by using self.sender() by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2694 +* keep track of respective finiteness of x and y by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2720 +* refactor GLViewWidget code into GLViewMixin by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2659 +* Fix NumPy warning in test_functions by @swt2c in https://github.com/pyqtgraph/pyqtgraph/pull/2746 +* generate random integers directly by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2748 +* Fix tox config, bump min numpy to 1.22 by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2755 +* Simplify fps computation by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2752 +* Add iterations argparse argument to benchmarks by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2418 +* export dialog - compare items by "is" rather than "==" (operator not implemented!) by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2758 +* workaround Python 3.11.4 flag inversion issue by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2760 +* use QGraphicsPixmapItem instead of ImageItem to draw colorbar by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2781 +* ImageItem: cache nan check by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2784 +* ImageItem: request for 256-entry lut by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2808 +* update gitignore setting by @longqzh in https://github.com/pyqtgraph/pyqtgraph/pull/2834 +* workaround PYSIDE-2487 for pen parameter by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2844 +* ButtonItem: draw pixmap to logical size by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2873 +* Allow release info change during apt-get update on ubuntu by @spchamp in https://github.com/pyqtgraph/pyqtgraph/pull/2893 +* various fixes for NumPy 2.0 by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2894 +* Fix typo invloved -> involved by @NilsIrl in https://github.com/pyqtgraph/pyqtgraph/pull/2905 +* Add int typehint to ClickRadius by @robtau in https://github.com/pyqtgraph/pyqtgraph/pull/2943 +* Refactor ImageItem QImage creation routines by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2944 +* Better editable install by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2935 +* Use QColor.fromString instead of deprecated QColor.setNamedColor by @zariiii9003 in https://github.com/pyqtgraph/pyqtgraph/pull/2877 +* Add pickling to SRTTransform by @outofculture in https://github.com/pyqtgraph/pyqtgraph/pull/2914 +* pcmi: refactor setData() by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2876 + + +### Docs + +* Update .readthedocs.yaml by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2732 +* Address pydata-sphinx-theme warning by @j9ac9k in https://github.com/pyqtgraph/pyqtgraph/pull/2861 +* Docs: Update Qt binding selection details by @veractor in https://github.com/pyqtgraph/pyqtgraph/pull/2807 +* Bump pyqt6 from 6.5.0 to 6.5.1 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2741 +* Bump pyqt6 from 6.5.1 to 6.5.2 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2780 +* Bump pyqt6 from 6.5.2 to 6.5.3 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2846 +* Bump pyqt6 from 6.5.3 to 6.6.0 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2862 +* Bump pyqt6 from 6.6.0 to 6.6.1 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2895 +* Bump sphinx from 6.1.3 to 6.2.1 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2705 +* Bump sphinx from 6.2.1 to 7.1.0 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2782 +* Bump sphinx from 7.1.0 to 7.1.2 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2791 +* Bump sphinx from 7.1.2 to 7.2.2 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2802 +* Bump sphinx from 7.2.2 to 7.2.3 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2806 +* Bump sphinx from 7.2.3 to 7.2.4 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2809 +* Bump sphinx from 7.2.4 to 7.2.5 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2813 +* Bump sphinx from 7.2.5 to 7.2.6 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2821 +* Bump pydata-sphinx-theme from 0.13.3 to 0.14.1 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2825 +* Bump pydata-sphinx-theme from 0.14.2 to 0.14.3 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2865 +* Bump pydata-sphinx-theme from 0.14.3 to 0.14.4 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2889 +* Bump pydata-sphinx-theme from 0.14.4 to 0.15.2 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2916 +* Bump sphinx-design from 0.4.1 to 0.5.0 in /doc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2783 + + +### Testing/CI + +* [CI] add mypy settings for CI by @longqzh in https://github.com/pyqtgraph/pyqtgraph/pull/2845 +* fix: test Python 3.10 against Qt 6.2 by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2837 +* cast float to signed int before to unsigned int by @pijyoi in https://github.com/pyqtgraph/pyqtgraph/pull/2946 +* Bump pyopengl from 3.1.6 to 3.1.7 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2730 +* Bump h5py from 3.8.0 to 3.9.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2750 +* Bump h5py from 3.9.0 to 3.10.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2839 +* Bump pytest-xvfb from 2.0.0 to 3.0.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2735 +* Bump pytest from 7.3.0 to 7.3.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2696 +* Bump pytest from 7.3.1 to 7.3.2 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2743 +* Bump pytest from 7.3.2 to 7.4.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2753 +* Bump pytest from 7.4.0 to 7.4.2 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2817 +* Bump pytest from 7.4.2 to 7.4.3 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2856 +* Bump pytest from 7.4.3 to 8.0.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2922 +* Bump pytest from 8.0.0 to 8.0.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2942 +* Bump pytest from 8.0.1 to 8.0.2 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2945 +* Bump pytest from 8.0.2 to 8.1.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2948 +* Bump pytest-xdist from 3.2.1 to 3.3.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2722 +* Bump pytest-xdist from 3.3.0 to 3.3.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2727 +* Bump pytest-xdist from 3.3.1 to 3.4.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2880 +* Bump pytest-xdist from 3.4.0 to 3.5.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2886 +* Bump matplotlib from 3.7.1 to 3.7.2 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2766 +* Bump matplotlib from 3.7.2 to 3.7.3 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2818 +* Bump matplotlib from 3.7.3 to 3.8.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2823 +* Bump matplotlib from 3.8.0 to 3.8.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2868 +* Bump matplotlib from 3.8.1 to 3.8.2 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2885 +* Bump matplotlib from 3.8.2 to 3.8.3 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2937 +* Bump numba from 0.56.4 to 0.57.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2711 +* Bump numba from 0.57.0 to 0.57.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2751 +* Bump numba from 0.57.1 to 0.58.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2826 +* Bump numba from 0.58.0 to 0.58.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2851 +* Bump numba from 0.58.1 to 0.59.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2924 +* Bump scipy from 1.10.1 to 1.11.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2757 +* Bump scipy from 1.11.0 to 1.11.1 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2763 +* Bump scipy from 1.11.1 to 1.11.2 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2803 +* Bump scipy from 1.11.2 to 1.11.3 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2831 +* Bump scipy from 1.11.3 to 1.11.4 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2884 +* Bump scipy from 1.11.4 to 1.12.0 in /.github/workflows/etc by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2917 +* Bump actions/upload-artifact from 3 to 4 by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2902 +* Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2814 +* Bump actions/cache from 3 to 4 by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2915 +* Bump actions/setup-python from 4 to 5 by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2898 +* Bump conda-incubator/setup-miniconda from 2 to 3 by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2890 +* Bump github/codeql-action from 2 to 3 by @dependabot in https://github.com/pyqtgraph/pyqtgraph/pull/2901 + + +## New Contributors +* @adriandavidauer made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2704 +* @MalteOlle made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2739 +* @redruin1 made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2646 +* @dingo9 made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2761 +* @stephan-senkbeil made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2731 +* @ptuemmler made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2778 +* @veractor made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2807 +* @longqzh made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2834 +* @nleclercq made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2860 +* @bersbersbers made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2848 +* @JayanthBontha made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2835 +* @sevas made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2870 +* @Doralitze made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2869 +* @spchamp made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2893 +* @NilsIrl made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2905 +* @nicoddemus made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2934 +* @MorbidCuriosity84 made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2930 +* @UsYer made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2888 +* @misantroop made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2919 +* @zariiii9003 made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2877 +* @samtygier made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2932 +* @robtau made their first contribution in https://github.com/pyqtgraph/pyqtgraph/pull/2943 + +**Full Changelog**: https://github.com/pyqtgraph/pyqtgraph/compare/pyqtgraph-0.13.3...pyqtgraph-0.13.4 + + pyqtgraph-0.13.3 ## What's Changed diff --git a/README.md b/README.md index d058bcd030..00377d3935 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,13 @@ PyQtGraph [![PyPi](https://img.shields.io/pypi/v/pyqtgraph.svg)](https://pypi.org/project/pyqtgraph/) [![conda-forge](https://img.shields.io/conda/vn/conda-forge/pyqtgraph.svg)](https://anaconda.org/conda-forge/pyqtgraph) [![Build Status](https://github.com/pyqtgraph/pyqtgraph/workflows/main/badge.svg)](https://github.com/pyqtgraph/pyqtgraph/actions/?query=workflow%3Amain) -[![CodeQL Status](https://github.com/pyqtgraph/pyqtgraph/workflows/codeql/badge.svg)](https://github.com/pyqtgraph/pyqtgraph/actions/?query=workflow%3Acodeql) [![Documentation Status](https://readthedocs.org/projects/pyqtgraph/badge/?version=latest)](https://pyqtgraph.readthedocs.io/en/latest/?badge=latest) -[![Discord](https://img.shields.io/discord/946624673200893953.svg?label=PyQtGraph&logo=discord)](https://discord.gg/ufTVNNreAZ) + A pure-Python graphics library for PyQt5/PyQt6/PySide2/PySide6 -Copyright 2023 PyQtGraph developers +Copyright 2024 PyQtGraph developers - + PyQtGraph is intended for use in mathematics / scientific / engineering applications. Despite being written entirely in python, the library is fast due to its @@ -31,13 +30,13 @@ This project supports: Currently this means: -* Python 3.9+ +* Python 3.10+ * Qt 5.15, 6.2+ * [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.22+ +* [`numpy`](https://github.com/numpy/numpy) 1.23+ ### Optional added functionalities @@ -46,7 +45,7 @@ Through 3rd part libraries, additional functionality may be added to PyQtGraph, | Library | Added functionality | |----------------|-| | [`scipy`] |
  • Image processing through [`ndimage`]
  • Data array filtering through [`signal`]
    • | -| [`pyopengl`] |
      • 3D graphics
      • Faster image processing
      • Note: on macOS Big Sur only works with python 3.9.1+
      | +| [`pyopengl`] |
      • 3D graphics
      • Faster image processing
      | | [`h5py`] |
      • Export in hdf5 format
      | | [`colorcet`] |
      • Add a collection of perceptually uniform colormaps
      | | [`matplotlib`] |
      • Export of PlotItem in matplotlib figure
      • Add matplotlib collection of colormaps
      | @@ -83,10 +82,7 @@ Installation Methods * 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 - anywhere that is importable from your project. Documentation ------------- diff --git a/binder/runtime.txt b/binder/runtime.txt index fe78579270..bc905de1f3 100644 --- a/binder/runtime.txt +++ b/binder/runtime.txt @@ -1,2 +1,2 @@ -python-3.9 +python-3.10 diff --git a/doc/Makefile b/doc/Makefile index e4eb7f8b56..36448e18ec 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -55,10 +55,11 @@ dash: clean export BUILD_DASH_DOCSET=1;\ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/dash doc2dash -n pyqtgraph\ + --index-page index.html\ --online-redirect-url https://pyqtgraph.readthedocs.io/en/latest\ - --icon $(SOURCEDIR)/_static/peegee_03_square_no_bg_32_cleaned.png\ + --icon $(SOURCEDIR)/_static/docset-icon.png\ + --icon-2x $(SOURCEDIR)/_static/docset-icon@2x.png\ --force\ - -A\ $(BUILDDIR)/dash @echo diff --git a/doc/extensions/qt_doc.py b/doc/extensions/qt_doc.py deleted file mode 100644 index 75c848fc41..0000000000 --- a/doc/extensions/qt_doc.py +++ /dev/null @@ -1,149 +0,0 @@ -""" -Extension for building Qt-like documentation. - - - Method lists preceding the actual method documentation - - Inherited members documented separately - - Members inherited from Qt have links to qt-project documentation - - Signal documentation - -""" - - - -def setup(app): - # probably we will be making a wrapper around autodoc - app.setup_extension('sphinx.ext.autodoc') - - # would it be useful to define a new domain? - #app.add_domain(QtDomain) - - ## Add new configuration options - app.add_config_value('todo_include_todos', False, False) - - ## Nodes are the basic objects representing documentation directives - ## and roles - app.add_node(Todolist) - app.add_node(Todo, - html=(visit_todo_node, depart_todo_node), - latex=(visit_todo_node, depart_todo_node), - text=(visit_todo_node, depart_todo_node)) - - ## New directives like ".. todo:" - app.add_directive('todo', TodoDirective) - app.add_directive('todolist', TodolistDirective) - - ## Connect callbacks to specific hooks in the build process - app.connect('doctree-resolved', process_todo_nodes) - app.connect('env-purge-doc', purge_todos) - - -from docutils import nodes -from sphinx.util.compat import Directive -from sphinx.util.compat import make_admonition - - -# Just a general node -class Todolist(nodes.General, nodes.Element): - pass - -# .. and its directive -class TodolistDirective(Directive): - # all directives have 'run' method that returns a list of nodes - def run(self): - return [Todolist('')] - - - - -# Admonition classes are like notes or warnings -class Todo(nodes.Admonition, nodes.Element): - pass - -def visit_todo_node(self, node): - self.visit_admonition(node) - -def depart_todo_node(self, node): - self.depart_admonition(node) - -class TodoDirective(Directive): - - # this enables content in the directive - has_content = True - - def run(self): - env = self.state.document.settings.env - - # create a new target node for linking to - targetid = "todo-%d" % env.new_serialno('todo') - targetnode = nodes.target('', '', ids=[targetid]) - - # make the admonition node - ad = make_admonition(Todo, self.name, [('Todo')], self.options, - self.content, self.lineno, self.content_offset, - self.block_text, self.state, self.state_machine) - - # store a handle in a global list of all todos - if not hasattr(env, 'todo_all_todos'): - env.todo_all_todos = [] - env.todo_all_todos.append({ - 'docname': env.docname, - 'lineno': self.lineno, - 'todo': ad[0].deepcopy(), - 'target': targetnode, - }) - - # return both the linking target and the node itself - return [targetnode] + ad - - -# env data is persistent across source files so we purge whenever the source file has changed. -def purge_todos(app, env, docname): - if not hasattr(env, 'todo_all_todos'): - return - env.todo_all_todos = [todo for todo in env.todo_all_todos - if todo['docname'] != docname] - - -# called at the end of resolving phase; we will convert temporary nodes -# into finalized nodes -def process_todo_nodes(app, doctree, fromdocname): - if not app.config.todo_include_todos: - for node in doctree.traverse(Todo): - node.parent.remove(node) - - # Replace all todolist nodes with a list of the collected todos. - # Augment each todo with a backlink to the original location. - env = app.builder.env - - for node in doctree.traverse(Todolist): - if not app.config.todo_include_todos: - node.replace_self([]) - continue - - content = [] - - for todo_info in env.todo_all_todos: - para = nodes.paragraph() - filename = env.doc2path(todo_info['docname'], base=None) - description = ( - ('(The original entry is located in %s, line %d and can be found ') % - (filename, todo_info['lineno'])) - para += nodes.Text(description, description) - - # Create a reference - newnode = nodes.reference('', '') - innernode = nodes.emphasis(('here'), ('here')) - newnode['refdocname'] = todo_info['docname'] - newnode['refuri'] = app.builder.get_relative_uri( - fromdocname, todo_info['docname']) - newnode['refuri'] += '#' + todo_info['target']['refid'] - newnode.append(innernode) - para += newnode - para += nodes.Text('.)', '.)') - - # Insert into the todolist - content.append(todo_info['todo']) - content.append(para) - - node.replace_self(content) - diff --git a/doc/requirements.txt b/doc/requirements.txt index a960cf9f6f..4b26e996ab 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,7 +1,7 @@ -PyQt6==6.5.2 -sphinx==7.2.5 -pydata-sphinx-theme==0.13.3 -sphinx-design==0.5.0 +PyQt6==6.7.0 +sphinx==7.3.7 +pydata-sphinx-theme==0.15.2 +sphinx-design==0.6.0 sphinxcontrib-images==0.9.4 sphinx-favicon==1.0.1 sphinx-autodoc-typehints diff --git a/doc/source/_static/custom.css b/doc/source/_static/custom.css index 4a7219c7ae..b7d0ece4e7 100644 --- a/doc/source/_static/custom.css +++ b/doc/source/_static/custom.css @@ -58,7 +58,6 @@ Nat Methods 8, 441 (2011). https://doi.org/10.1038/nmeth.1618 } /* Main index page overview cards */ - .sd-card { background: #fff; border-radius: 0; @@ -134,7 +133,7 @@ types are assumed to be normal images. */ html[data-theme=dark] img[src*='.svg']:not(.only-dark):not(.dark-light) { filter: brightness(0.8) invert(0.82) contrast(1.2); - background: unset + background: unset; } html[data-theme=dark] .MathJax_SVG * { @@ -142,7 +141,6 @@ html[data-theme=dark] .MathJax_SVG * { } /* Main index page overview cards */ - html[data-theme=dark] .sd-card { background-color:var(--pst-color-background); border: none @@ -160,3 +158,24 @@ html[data-theme=dark] .sd-card .sd-card-header { html[data-theme=dark] .sd-card .sd-card-footer { background-color:var(--pst-color-background); } + +/* Hide TypeAlias Classes */ +dt#ColorMapSpecifier { + visibility: hidden; +} + +/* Flip the colours on graphviz graphs on dark mode */ +html[data-theme="dark"] div.graphviz > object.inheritance { + filter: brightness(0.8) invert(0.82) contrast(1.2); + color-scheme: normal; +} + +/* Make inheritance images have a scroll bar if necessary. */ +div.graphviz { + border: 1px solid #7f7f7f00; + max-height: 50em; + overflow: auto; +} +img.graphviz.inheritance { + max-width: none; +} diff --git a/doc/source/_static/docset-icon.png b/doc/source/_static/docset-icon.png new file mode 100644 index 0000000000..46659ef8fb Binary files /dev/null and b/doc/source/_static/docset-icon.png differ diff --git a/doc/source/_static/peegee_03_square_no_bg_32_cleaned.png b/doc/source/_static/docset-icon@2x.png similarity index 100% rename from doc/source/_static/peegee_03_square_no_bg_32_cleaned.png rename to doc/source/_static/docset-icon@2x.png diff --git a/doc/source/api_reference/functions.rst b/doc/source/api_reference/functions.rst index 7fe2153d57..0b8fd6fbd9 100644 --- a/doc/source/api_reference/functions.rst +++ b/doc/source/api_reference/functions.rst @@ -14,12 +14,13 @@ Color, Pen, and Brush Functions ------------------------------- Qt uses the classes QColor, QPen, and QBrush to determine how to draw lines and fill shapes. These classes are highly capable but somewhat awkward to use. PyQtGraph offers the functions :func:`~pyqtgraph.mkColor`, :func:`~pyqtgraph.mkPen`, and :func:`~pyqtgraph.mkBrush` to simplify the process of creating these classes. In most cases, however, it will be unnecessary to call these functions directly--any function or method that accepts *pen* or *brush* arguments will make use of these functions for you. For example, the following three lines all have the same effect:: - + +.. code-block:: python + pg.plot(xdata, ydata, pen='r') pg.plot(xdata, ydata, pen=pg.mkPen('r')) pg.plot(xdata, ydata, pen=QPen(QColor(255, 0, 0))) - .. autofunction:: pyqtgraph.mkColor .. autofunction:: pyqtgraph.mkPen @@ -36,13 +37,16 @@ Qt uses the classes QColor, QPen, and QBrush to determine how to draw lines and .. autofunction:: pyqtgraph.colorDistance +Color Type Aliases +^^^^^^^^^^^^^^^^^^ + +.. autoattribute:: pyqtgraph.functions.color_like Data Slicing ------------ .. autofunction:: pyqtgraph.affineSlice - Coordinate Transformation ------------------------- @@ -54,8 +58,6 @@ Coordinate Transformation .. autofunction:: pyqtgraph.solveBilinearTransform - - SI Unit Conversion Functions ---------------------------- @@ -67,20 +69,18 @@ SI Unit Conversion Functions .. autofunction:: pyqtgraph.siParse - Image Preparation Functions --------------------------- -.. autofunction:: pyqtgraph.makeARGB - -.. autofunction:: pyqtgraph.makeQImage +.. autofunction:: pyqtgraph.functions.makeARGB -.. autofunction:: pyqtgraph.applyLookupTable +.. autofunction:: pyqtgraph.functions.makeQImage -.. autofunction:: pyqtgraph.rescaleData +.. autofunction:: pyqtgraph.functions.applyLookupTable -.. autofunction:: pyqtgraph.imageToArray +.. autofunction:: pyqtgraph.functions.rescaleData +.. autofunction:: pyqtgraph.functions.imageToArray Mesh Generation Functions ------------------------- @@ -89,7 +89,6 @@ Mesh Generation Functions .. autofunction:: pyqtgraph.isosurface - Miscellaneous Functions ----------------------- @@ -103,13 +102,11 @@ Miscellaneous Functions .. 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 diff --git a/doc/source/api_reference/graphicsItems/imageitem.rst b/doc/source/api_reference/graphicsItems/imageitem.rst index 1d16c1e653..ec01915463 100644 --- a/doc/source/api_reference/graphicsItems/imageitem.rst +++ b/doc/source/api_reference/graphicsItems/imageitem.rst @@ -1,58 +1,112 @@ +.. role:: python(code) + :language: python + 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.setColorMap` and -:func:`~pyqtgraph.ImageItem.setLookupTable`). +Overview +-------- + +: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 +:meth:`ImageItem.setLevels `) and/or colored according +to a lookup table (see :meth:`ImageItem.setColorMap ` +and :meth:`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). +* `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. +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 :python:`[R,G,B]` or :python:`[R,G,B,A]` channels/components. Notes ----- -Data ordering can be set for each ImageItem, or in the :ref:`global configuration options ` by :: - - pyqtgraph.setConfigOption('imageAxisOrder', 'row-major') # best performance +:class:`~pyqtgraph.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. 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. +:meth:`ImageItem.setRect ` method or the `rect` keyword. +This is internally realized through assigning a :class:`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_performance: + +Performance +----------- + +The performance of :class:`~pyqtgraph.ImageItem` can vary *significantly* based on +attributes of the `image`, `levels` and `lut` input arguments. It should not be +assumed that the default parameters are the most performant, as the default values are +largely there to preserve backwards compatibility. + +The following guidance should be observed if performance is an important factor + +* Instantiate :class:`~pyqtgraph.ImageItem` with :python:`axisOrder='row-major'` + + * Alternatively, set the global configuration optionally + :python:`pyqtgraph.setConfigOption('imageAxisOrder', 'row-major')` + +* Use C-contiguous image data. +* For 1 or 3 channel data, use `uint8`, `uint16`, `float32`, or `float64` `image` + dtype. +* For 4-channel data, use `uint8` or `uint16` with :python:`levels=None`. +* `levels` should be set to either to ``None`` or to single channel ``[min, max]`` + + * Not setting `levels` will trigger autoLevels sampling + +* If using LUTs (lookup tables), ensure they have a dtype of `uint8` and have 256 + points or less. That can be accomplished with calling: + + * :func:`ImageItem.setColorMap ` or + * :func:`ImageItem.setLookupTable ` with + :python:`ColorMap.getLookupTable(nPts=256)` (default is :python:`nPts=512`) + +* For floating point `image` arrays, prefer `float32` dtype to `float64` and avoid + ``NaN`` values. +* Enable Numba with :python:`pyqtgraph.setConfigOption('useNumba', True)` + + * JIT compilation will only accelerate repeated image display. + +Internally, pyqtgraph attempts to directly construct a :class:`QImage` using a +combination of :class:`QImage.Format ` options and +:meth:`QImage.setColorTable ` if necessary. This does not work in +all cases that pyqtgraph supports. If pyqtgraph is unable to construct the +:class:`QImage` in such a fashion, it will fall back on +:func:`~pyqtgraph.functions.makeARGB` to manipulate the data in a manner that +:class:`QImage` can read it in. There is a *significant* performance penalty when +having to use :func:`~pyqtgraph.functions.makeARGB`. + +For applications that are *very* performance sensitive, every effort should be made so +that the arguments passed to :meth:`ImageItem.setImage ` +do not call :func:`~pyqtgraph.functions.makeARGB`. .. _ImageItem_examples: Examples -------- +Scale and Position ImageItem +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In the following example, it is demonstrated how a user scale and translate a +:class:`~pyqtgraph.ImageItem` within a :class:`~pyqtgraph.ViewBox` to occupy a specific +position and size. + .. literalinclude:: /images/gen_example_imageitem_transform.py - :lines: 19-28 - :dedent: 8 + :lines: 4-44 + :emphasize-lines: 24-33 + :language: python .. thumbnail:: /images/example_imageitem_transform.png @@ -60,8 +114,15 @@ Examples :alt: Example of transformed image display :title: Transformed Image Display +Inheritance +----------- + +.. inheritance-diagram:: pyqtgraph.graphicsItems.ImageItem.ImageItem + :top-classes: PyQt6.QtCore.QObject, PyQt6.QtWidgets.QGraphicsItem + :parts: 1 + +API +--- .. autoclass:: pyqtgraph.ImageItem :members: - - .. automethod:: pyqtgraph.ImageItem.__init__ diff --git a/doc/source/api_reference/graphicsItems/plotdataitem.rst b/doc/source/api_reference/graphicsItems/plotdataitem.rst index 8d5ecbdf7e..c3de1736d2 100644 --- a/doc/source/api_reference/graphicsItems/plotdataitem.rst +++ b/doc/source/api_reference/graphicsItems/plotdataitem.rst @@ -1,7 +1,9 @@ PlotDataItem ============ +.. inheritance-diagram:: pyqtgraph.graphicsItems.PlotDataItem.PlotDataItem + :top-classes: PyQt6.QtCore.QObject, PyQt6.QtWidgets.QGraphicsItem + :parts: 1 + .. autoclass:: pyqtgraph.PlotDataItem :members: - - .. automethod:: pyqtgraph.PlotDataItem.__init__ diff --git a/doc/source/api_reference/widgets/colormapmenu.rst b/doc/source/api_reference/widgets/colormapmenu.rst new file mode 100644 index 0000000000..956c0673d3 --- /dev/null +++ b/doc/source/api_reference/widgets/colormapmenu.rst @@ -0,0 +1,13 @@ +ColorMapMenu +============ + +.. class:: ColorMapSpecifier + +.. data:: ColorMapSpecifier + :type: str | tuple[str, str] | pyqtgraph.ColorMap + :noindex: + +.. autoclass:: pyqtgraph.ColorMapMenu + :members: + + .. automethod:: pyqtgraph.ColorMapMenu.__init__ diff --git a/doc/source/api_reference/widgets/index.rst b/doc/source/api_reference/widgets/index.rst index 06d87759eb..c4705c7248 100644 --- a/doc/source/api_reference/widgets/index.rst +++ b/doc/source/api_reference/widgets/index.rst @@ -39,3 +39,4 @@ Contents: valuelabel busycursor rawimagewidget + colormapmenu diff --git a/doc/source/conf.py b/doc/source/conf.py index 7d26cc9c16..14418d6308 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -10,39 +10,43 @@ # All configuration values have a default; values that are commented out # serve to show the default. +import importlib.util import os import sys import time -from datetime import datetime +import datetime from sphinx.application import Sphinx -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -path = os.path.dirname(os.path.abspath(__file__)) -sys.path.insert(0, os.path.join(path, '..', '..')) -sys.path.insert(0, os.path.join(path, '..', 'extensions')) -import pyqtgraph +path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..", "pyqtgraph") +spec = importlib.util.spec_from_file_location( + "pyqtgraph", + os.path.join(path, "__init__.py") +) +pyqtgraph = importlib.util.module_from_spec(spec) +sys.modules["pyqtgraph"] = pyqtgraph +spec.loader.exec_module(pyqtgraph) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' +# needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ "sphinx.ext.autodoc", "sphinx.ext.viewcode", - "sphinx.ext.napoleon", + "sphinx.ext.napoleon", # has to be loaded before sphinx_autodoc_typehints + "sphinx_autodoc_typehints", "sphinx.ext.intersphinx", "sphinx_qt_documentation", "sphinx_design", "sphinx_favicon", "sphinxext.rediraffe", "sphinxcontrib.images", - "sphinx_autodoc_typehints" + 'sphinx.ext.inheritance_diagram', + # 'sphinxcontrib.spelling' # commenting out to allow for easy usage locally ] # Add any paths that contain templates here, relative to this directory. @@ -60,17 +64,61 @@ } nitpick_ignore_regex = [ - ("py:class", r"re\.Pattern"), # doesn't seem to be a good ref in python docs + ("py:class", "re.Pattern"), # doesn't seem to be a good ref in python docs + ("py:class", "numpy._typing._array_like._SupportsArray"), + ("py:class", "numpy._typing._nested_sequence._NestedSequence") +] + +# looks way better with pydata-sphinx-theme +napoleon_use_admonition_for_examples = True +napoleon_use_admonition_for_notes = True +napoleon_use_admonition_for_references = True + +# if napoleon_use_param is True, there are issues, it merges +# Parameters Other Parameters, see https://github.com/sphinx-doc/sphinx/issues/10330 +napoleon_use_param = False +# napoleon_use_keyword = False + +# makes so Attributes/Variables aren't rendered like methods, but like Parameters +napoleon_use_ivar = True +napoleon_attr_annotations = False +napoleon_custom_sections = [ + ("Signals", "params_style"), + ("Slots", "params_style") ] napoleon_preprocess_types = True napoleon_type_aliases = { - "callable": ":class:`collections.abc.Callable`", + "callable": ":class:`~collections.abc.Callable`", "np.ndarray": ":class:`numpy.ndarray`", 'array_like': ':term:`array_like`', - 'color_like': ':func:`pyqtgraph.mkColor`' + 'color_like': ':obj:`~pyqtgraph.functions.color_like`', } +# makes things far more legible +python_use_unqualified_type_names = True +python_display_short_literal_types = True +maximum_signature_line_length = 20 + +# spelling +spelling_word_list_filename = [ + 'dictionaries/numpy.dic', + 'dictionaries/PyQt6.QtCore.dic', + 'dictionaries/PyQt6.QtGui.dic', + 'dictionaries/PyQt6.QtWidgets.dic', + 'dictionaries/pyqtgraph.dic', + 'dictionaries/custom.dic' +] + +graphviz_dot_args = ['-Gbgcolor=transparent'] +graphviz_output_format = 'svg' +inheritance_graph_attrs = dict( + rankdir="LR", + fontsize=14, + ratio='compress', + bgcolor='transparent', +) + # The encoding of source files. #source_encoding = 'utf-8-sig' @@ -79,10 +127,12 @@ # General information about the project. project = 'pyqtgraph' -now = datetime.utcfromtimestamp( - int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + +now = datetime.datetime.fromtimestamp( + int(os.environ.get('SOURCE_DATE_EPOCH', time.time())), + tz=datetime.timezone.utc ) -copyright = '2011 - {}, PyQtGraph developers'.format(now.year) +copyright = f'2011 - {now.year}, PyQtGraph developers' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the @@ -127,6 +177,24 @@ # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] +# Automatically extract typehints when specified and place them in +# descriptions of the relevant function/method. +# autodoc_typehints = "description" +autodoc_typehints = "both" +autodoc_typehints_format = 'short' +autodoc_typehints_description_target = 'documented_params' + +# sphinx-autodoc-typehints settings +always_use_bars_union = True +typehints_defaults = 'braces' + +napoleon_use_rtype = True +typehints_use_rtype = True +typehints_document_rtype = True + +typehints_use_signature = True +typehints_use_signature_return = True + autodoc_inherit_docstrings = False autodoc_mock_imports = [ "scipy", @@ -134,6 +202,8 @@ "matplotlib", ] +# autodoc_type_aliases = {} + # -- Options for HTML output --------------------------------------------------- @@ -143,23 +213,41 @@ # favicons favicons = [ - "peegee_03_square_no_bg_32_cleaned.png", - "peegee_04_square_no_bg_180_cleaned.png", + "docset-icon.png", + "docset-icon@2x.png", "peegee_03_square_no_bg_32_cleaned.ico" ] +# make right side TOC work w/ long names, makes it so method names aren't clipped +# e.g. PlotDataItem.setDerivativeMode() -> setDerivativeMode() +toc_object_entries_show_parents = "hide" + # Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. +# further. For a list of options available for each theme, see the documentation. html_theme_options = { - "github_url": "https://github.com/pyqtgraph/pyqtgraph", + "collapse_navigation": True, + "icon_links": [ + { + "name": "GitHub", + "url": "https://github.com/pyqtgraph/pyqtgraph", + "icon": "fa-brands fa-square-github", + "type": "fontawesome", + }, + { + "name": "Mastodon", + "url": "https://fosstodon.org/@pyqtgraph", + "icon": "fa-brands fa-mastodon", + "type": "fontawesome", + } + ], "navbar_end": ["theme-switcher", "navbar-icon-links"], - "twitter_url": "https://twitter.com/pyqtgraph", + "navigation_depth": 2, + "navigation_with_keys": False, + "secondary_sidebar_items": ["page-toc"], + "show_toc_level": 3, "use_edit_page_button": False, - "secondary_sidebar_items": ["page-toc"] } - if os.getenv("BUILD_DASH_DOCSET"): html_theme_options |= { 'secondary_sidebar_items': [], @@ -167,7 +255,6 @@ "collapse_navigation": True, } - # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] @@ -185,7 +272,6 @@ # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. -# html_favicon = "_static/peegee_03_square_no_bg_32_cleaned.ico" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -327,11 +413,11 @@ # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' +# html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. -#html_use_smartypants = True +# html_use_smartypants = True # Custom sidebar templates, maps document names to template names. if os.getenv("BUILD_DASH_DOCSET"): # used for building dash docsets diff --git a/doc/source/dictionaries/PyQt6.QtCore.dic b/doc/source/dictionaries/PyQt6.QtCore.dic new file mode 100644 index 0000000000..a66da3d051 --- /dev/null +++ b/doc/source/dictionaries/PyQt6.QtCore.dic @@ -0,0 +1,220 @@ +NOOP +PYQT +PyQt6.QtCore +QAbstractAnimation +QAbstractEventDispatcher +QAbstractItemModel +QAbstractListModel +QAbstractNativeEventFilter +QAbstractProxyModel +QAbstractTableModel +QAnimationGroup +QBasicTimer +QBitArray +QBluetoothPermission +QBuffer +QByteArray +QByteArrayMatcher +QCalendar +QCalendarPermission +QCameraPermission +QCborError +QCborKnownTags +QCborSimpleType +QCborStreamReader +QCborStreamWriter +QChildEvent +QCollator +QCollatorSortKey +QCommandLineOption +QCommandLineParser +QConcatenateTablesProxyModel +QContactsPermission +QCoreApplication +QCryptographicHash +QDataStream +QDate +QDateTime +QDeadlineTimer +QDir +QDirIterator +QDynamicPropertyChangeEvent +QEasingCurve +QElapsedTimer +QEvent +QEventLoop +QEventLoopLocker +QFile +QFileDevice +QFileInfo +QFileSelector +QFileSystemWatcher +QGenericArgument +QGenericReturnArgument +QIODevice +QIODeviceBase +QIdentityProxyModel +QItemSelection +QItemSelectionModel +QItemSelectionRange +QJsonDocument +QJsonParseError +QJsonValue +QKeyCombination +QLibrary +QLibraryInfo +QLine +QLineF +QLocale +QLocationPermission +QLockFile +QLoggingCategory +QMargins +QMarginsF +QMessageAuthenticationCode +QMessageLogContext +QMessageLogger +QMetaClassInfo +QMetaEnum +QMetaMethod +QMetaObject +QMetaProperty +QMetaType +QMicrophonePermission +QMimeData +QMimeDatabase +QMimeType +QModelIndex +QModelRoleData +QModelRoleDataSpan +QMutex +QMutexLocker +QNativeIpcKey +QObject +QObjectCleanupHandler +QOperatingSystemVersion +QOperatingSystemVersionBase +QParallelAnimationGroup +QPauseAnimation +QPermission +QPersistentModelIndex +QPluginLoader +QPoint +QPointF +QProcess +QProcessEnvironment +QPropertyAnimation +QRandomGenerator +QReadLocker +QReadWriteLock +QRect +QRectF +QRecursiveMutex +QRegularExpression +QRegularExpressionMatch +QRegularExpressionMatchIterator +QResource +QRunnable +QSaveFile +QSemaphore +QSemaphoreReleaser +QSequentialAnimationGroup +QSettings +QSharedMemory +QSignalBlocker +QSignalMapper +QSize +QSizeF +QSocketNotifier +QSortFilterProxyModel +QStandardPaths +QStorageInfo +QStringConverter +QStringConverterBase +QStringDecoder +QStringEncoder +QStringListModel +QSysInfo +QSystemSemaphore +QTemporaryDir +QTemporaryFile +QTextBoundaryFinder +QTextStream +QTextStreamManipulator +QThread +QThreadPool +QTime +QTimeLine +QTimeZone +QTimer +QTimerEvent +QTranslator +QTransposeProxyModel +QTypeRevision +QUrl +QUrlQuery +QUuid +QVariant +QVariantAnimation +QVersionNumber +QWaitCondition +QWriteLocker +QXmlStreamAttribute +QXmlStreamAttributes +QXmlStreamEntityDeclaration +QXmlStreamEntityResolver +QXmlStreamNamespaceDeclaration +QXmlStreamNotationDeclaration +QXmlStreamReader +QXmlStreamWriter +QtMsgType +RETURN +TRANSLATE +VERSION +pyqtBoundSignal +pyqtClassInfo +pyqtEnum +pyqtPickleProtocol +pyqtProperty +pyqtRemoveInputHook +pyqtRestoreInputHook +pyqtSetPickleProtocol +pyqtSignal +pyqtSlot +qAbs +qAddPostRoutine +qAddPreRoutine +qChecksum +qCompress +qCritical +qDebug +qEnvironmentVariable +qEnvironmentVariableIntValue +qEnvironmentVariableIsEmpty +qEnvironmentVariableIsSet +qFatal +qFloatDistance +qFormatLogMessage +qFuzzyCompare +qFuzzyIsNull +qInf +qInfo +qInstallMessageHandler +qIsFinite +qIsInf +qIsNaN +qQNaN +qRegisterResourceData +qRemovePostRoutine +qRound +qRound64 +qSNaN +qSetFieldWidth +qSetMessagePattern +qSetPadChar +qSetRealNumberPrecision +qUncompress +qUnregisterResourceData +qVersion +qWarning +qYieldCpu diff --git a/doc/source/dictionaries/PyQt6.QtGui.dic b/doc/source/dictionaries/PyQt6.QtGui.dic new file mode 100644 index 0000000000..5467a1f6ea --- /dev/null +++ b/doc/source/dictionaries/PyQt6.QtGui.dic @@ -0,0 +1,188 @@ +PyQt6.QtGui +QAbstractFileIconProvider +QAbstractTextDocumentLayout +QAction +QActionEvent +QActionGroup +QBackingStore +QBitmap +QBrush +QChildWindowEvent +QClipboard +QCloseEvent +QColor +QColorConstants +QColorSpace +QColorTransform +QConicalGradient +QContextMenuEvent +QCursor +QDesktopServices +QDoubleValidator +QDrag +QDragEnterEvent +QDragLeaveEvent +QDragMoveEvent +QDropEvent +QEnterEvent +QEventPoint +QExposeEvent +QFileOpenEvent +QFileSystemModel +QFocusEvent +QFont +QFontDatabase +QFontInfo +QFontMetrics +QFontMetricsF +QGlyphRun +QGradient +QGuiApplication +QHelpEvent +QHideEvent +QHoverEvent +QIcon +QIconDragEvent +QIconEngine +QImage +QImageIOHandler +QImageReader +QImageWriter +QInputDevice +QInputEvent +QInputMethod +QInputMethodEvent +QInputMethodQueryEvent +QIntValidator +QKeyEvent +QKeySequence +QLinearGradient +QMatrix2x2 +QMatrix2x3 +QMatrix2x4 +QMatrix3x2 +QMatrix3x3 +QMatrix3x4 +QMatrix4x2 +QMatrix4x3 +QMatrix4x4 +QMouseEvent +QMoveEvent +QMovie +QNativeGestureEvent +QOffscreenSurface +QOpenGLContext +QOpenGLContextGroup +QPageLayout +QPageRanges +QPageSize +QPagedPaintDevice +QPaintDevice +QPaintDeviceWindow +QPaintEngine +QPaintEngineState +QPaintEvent +QPainter +QPainterPath +QPainterPathStroker +QPalette +QPdfWriter +QPen +QPicture +QPixelFormat +QPixmap +QPixmapCache +QPlatformSurfaceEvent +QPointerEvent +QPointingDevice +QPointingDeviceUniqueId +QPolygon +QPolygonF +QQuaternion +QRadialGradient +QRasterWindow +QRawFont +QRegion +QRegularExpressionValidator +QResizeEvent +QRgba64 +QScreen +QScrollEvent +QScrollPrepareEvent +QSessionManager +QShortcut +QShortcutEvent +QShowEvent +QSinglePointEvent +QStandardItem +QStandardItemModel +QStaticText +QStatusTipEvent +QStyleHints +QSurface +QSurfaceFormat +QSyntaxHighlighter +QTabletEvent +QTextBlock +QTextBlockFormat +QTextBlockGroup +QTextBlockUserData +QTextCharFormat +QTextCursor +QTextDocument +QTextDocumentFragment +QTextDocumentWriter +QTextFormat +QTextFragment +QTextFrame +QTextFrameFormat +QTextImageFormat +QTextInlineObject +QTextItem +QTextLayout +QTextLength +QTextLine +QTextList +QTextListFormat +QTextObject +QTextObjectInterface +QTextOption +QTextTable +QTextTableCell +QTextTableCellFormat +QTextTableFormat +QTouchEvent +QTransform +QUndoCommand +QUndoGroup +QUndoStack +QUtiMimeConverter +QValidator +QVector2D +QVector3D +QVector4D +QWhatsThisClickedEvent +QWheelEvent +QWindow +QWindowStateChangeEvent +auto +mnemonic +qAlpha +qBlue +qFuzzyCompare +qGray +qGreen +qPixelFormatAlpha +qPixelFormatCmyk +qPixelFormatGrayscale +qPixelFormatHsl +qPixelFormatHsv +qPixelFormatRgba +qPixelFormatYuv +qPremultiply +qRed +qRgb +qRgba +qRgba64 +qUnpremultiply +sequence diff --git a/doc/source/dictionaries/PyQt6.QtWidgets.dic b/doc/source/dictionaries/PyQt6.QtWidgets.dic new file mode 100644 index 0000000000..6a78987a26 --- /dev/null +++ b/doc/source/dictionaries/PyQt6.QtWidgets.dic @@ -0,0 +1,194 @@ +PyQt6.QtWidgets +QAbstractButton +QAbstractGraphicsShapeItem +QAbstractItemDelegate +QAbstractItemView +QAbstractScrollArea +QAbstractSlider +QAbstractSpinBox +QApplication +QBoxLayout +QButtonGroup +QCalendarWidget +QCheckBox +QColorDialog +QColumnView +QComboBox +QCommandLinkButton +QCommonStyle +QCompleter +QDataWidgetMapper +QDateEdit +QDateTimeEdit +QDial +QDialog +QDialogButtonBox +QDockWidget +QDoubleSpinBox +QErrorMessage +QFileDialog +QFileIconProvider +QFocusFrame +QFontComboBox +QFontDialog +QFormLayout +QFrame +QGesture +QGestureEvent +QGestureRecognizer +QGraphicsAnchor +QGraphicsAnchorLayout +QGraphicsBlurEffect +QGraphicsColorizeEffect +QGraphicsDropShadowEffect +QGraphicsEffect +QGraphicsEllipseItem +QGraphicsGridLayout +QGraphicsItem +QGraphicsItemGroup +QGraphicsLayout +QGraphicsLayoutItem +QGraphicsLineItem +QGraphicsLinearLayout +QGraphicsObject +QGraphicsOpacityEffect +QGraphicsPathItem +QGraphicsPixmapItem +QGraphicsPolygonItem +QGraphicsProxyWidget +QGraphicsRectItem +QGraphicsRotation +QGraphicsScale +QGraphicsScene +QGraphicsSceneContextMenuEvent +QGraphicsSceneDragDropEvent +QGraphicsSceneEvent +QGraphicsSceneHelpEvent +QGraphicsSceneHoverEvent +QGraphicsSceneMouseEvent +QGraphicsSceneMoveEvent +QGraphicsSceneResizeEvent +QGraphicsSceneWheelEvent +QGraphicsSimpleTextItem +QGraphicsTextItem +QGraphicsTransform +QGraphicsView +QGraphicsWidget +QGridLayout +QGroupBox +QHBoxLayout +QHeaderView +QInputDialog +QItemDelegate +QItemEditorCreatorBase +QItemEditorFactory +QKeySequenceEdit +QLCDNumber +QLabel +QLayout +QLayoutItem +QLineEdit +QListView +QListWidget +QListWidgetItem +QMainWindow +QMdiArea +QMdiSubWindow +QMenu +QMenuBar +QMessageBox +QPanGesture +QPinchGesture +QPlainTextDocumentLayout +QPlainTextEdit +QProgressBar +QProgressDialog +QProxyStyle +QPushButton +QRadioButton +QRubberBand +QScrollArea +QScrollBar +QScroller +QScrollerProperties +QSizeGrip +QSizePolicy +QSlider +QSpacerItem +QSpinBox +QSplashScreen +QSplitter +QSplitterHandle +QStackedLayout +QStackedWidget +QStatusBar +QStyle +QStyleFactory +QStyleHintReturn +QStyleHintReturnMask +QStyleHintReturnVariant +QStyleOption +QStyleOptionButton +QStyleOptionComboBox +QStyleOptionComplex +QStyleOptionDockWidget +QStyleOptionFocusRect +QStyleOptionFrame +QStyleOptionGraphicsItem +QStyleOptionGroupBox +QStyleOptionHeader +QStyleOptionHeaderV2 +QStyleOptionMenuItem +QStyleOptionProgressBar +QStyleOptionRubberBand +QStyleOptionSizeGrip +QStyleOptionSlider +QStyleOptionSpinBox +QStyleOptionTab +QStyleOptionTabBarBase +QStyleOptionTabWidgetFrame +QStyleOptionTitleBar +QStyleOptionToolBar +QStyleOptionToolBox +QStyleOptionToolButton +QStyleOptionViewItem +QStylePainter +QStyledItemDelegate +QSwipeGesture +QSystemTrayIcon +QTabBar +QTabWidget +QTableView +QTableWidget +QTableWidgetItem +QTableWidgetSelectionRange +QTapAndHoldGesture +QTapGesture +QTextBrowser +QTextEdit +QTimeEdit +QToolBar +QToolBox +QToolButton +QToolTip +QTreeView +QTreeWidget +QTreeWidgetItem +QTreeWidgetItemIterator +QUndoView +QVBoxLayout +QWIDGETSIZE +QWhatsThis +QWidget +QWidgetAction +QWidgetItem +QWizard +QWizardPage +qDrawBorderPixmap +qDrawPlainRect +qDrawPlainRoundedRect +qDrawShadeLine +qDrawShadePanel +qDrawShadeRect +qDrawWinButton +qDrawWinPanel diff --git a/doc/source/dictionaries/custom.dic b/doc/source/dictionaries/custom.dic new file mode 100644 index 0000000000..35c18e03a3 --- /dev/null +++ b/doc/source/dictionaries/custom.dic @@ -0,0 +1,39 @@ +ipython +hidpi +downsampling +downsampled +matplotlib +virtualenv +matlab +pyside +ui +pyuic +uic +hidpi +conda +ipython +isosurfaces +str +spinbox +subclass +viridis +rgb +rgba +viewRect +autoLevels +performant +np +subclass +levelSamples +Nans +imagedata +deffered +nanmask +asnumpy +unrenderable +libopengl +graphviz +ARGB +Pixmap +apiref +literalinclude diff --git a/doc/source/dictionaries/numpy.dic b/doc/source/dictionaries/numpy.dic new file mode 100644 index 0000000000..0014513de3 --- /dev/null +++ b/doc/source/dictionaries/numpy.dic @@ -0,0 +1,1299 @@ +ABCPolyBase +ALIGN +ALLOW +ARRAY +AXIS +ArgSpec +Arrayterator +AxisConcatenator +AxisError +BOUNDS +BUFFER +BUFSIZE +BagObj +BitGenerator +BoolDType +BoolFormat +ByteDType +BytesDType +CALL +CClass +CLIP +CLongDoubleDType +Chebyshev +Complex128DType +Complex64DType +ComplexFloatingFormat +ComplexWarning +ConversionWarning +ConverterError +ConverterLockError +Counter +DATETIMEUNITS +DECIMAL +DEFAULT +DIGITS +DIVIDEBYZERO +DTypePromotionError +DataSource +DateTime64DType +DatetimeFormat +DummyArray +EXACT +EXPECTED +EigResult +EighResult +FLOATING +FUNCTIONS +False +Float16DType +Float32DType +Float64DType +FloatingFormat +GETITEM +GROWTH +Generator +HASOBJECT +Hermite +HermiteE +IGNORE +INIT +INVALID +ISeedSequence +ISpawnableSeedSequence +ITEM +IgnoreException +IndexExpression +Infinity +Int16DType +Int32DType +Int64DType +Int8DType +IntDType +IntegerFormat +KEYS +KnownFailureException +LAPACK64 +LIST +LOWER +Laguerre +Legendre +LinAlgError +LineSplitter +Lock +LongDType +LongDoubleDType +LongLongDType +MAError +MAGIC +MAXDIMS +MAxisConcatenator +MGridClass +MT19937 +MUSL +MachAr +MachArLike +Mapping +MaskError +MaskType +MaskedArray +MaskedArrayFutureWarning +MaskedConstant +MaskedIterator +ModuleDeprecationWarning +NAME +NDArray +NDArrayOperatorsMixin +NEEDS +NINF +NZERO +NameValidator +NamedTuple +NpzFile +NumpyVersion +OGridClass +OVERFLOW +ObjectDType +PCG64 +PCG64DXSM +PICKLE +PINF +POINT +POINTER +PREFIX +PRINT +PYAPI +PYPY +PYSTON +PYVALS +PZERO +Path +PathLike +Philox +Polynomial +QRResult +RAISE +RClass +REFCOUNT +RandomState +RankWarning +SETITEM +SFC64 +SHARE +SHIFT +SIZE +SUPPORT +SVDResult +ScalarType +SeedSequence +SeedlessSeedSequence +SeedlessSequence +Sequence +ShortDType +SkipTest +SlogdetResult +StrDType +StringConverter +StructuredVoidFormat +SubArrayFormat +TABLE +THREADS +TestCase +TimeDelta64DType +TimedeltaFormat +TooHardError +True +UByteDType +UFUNC +UInt16DType +UInt32DType +UInt64DType +UInt8DType +UIntDType +ULongDType +ULongLongDType +UNDERFLOW +UPPER +UShortDType +VisibleDeprecationWarning +VoidDType +WARN +WASM +WRAP +absolute +actual +aligned +alist +allTypes +allclose +allequal +allow +allows +alltrue +almost +along +amax +amin +angle +anom +anomalies +append +apply +approx +arange +arccos +arccosh +arcsin +arcsinh +arctan +arctan2 +arctanh +arg1 +arg2 +argmax +argmin +argname +argpartition +args +argsort +argwhere +around +array +array2string +arrayList +arraypad +arrayprint +arrays +arraysetops +arrayterator +asanyarray +asarray +asbytes +ascontiguousarray +asfarray +asfortranarray +asmatrix +assert +asstr +assume +astr +asunicode +atleast +atol +autostrip +average +axes +axis +bartlett +base +basestring +begin +beta +bias +binary +bincount +binomial +bitname +bitwise +blackman +block +bmat +bool +bounds +break +broadcast +build +builddir +builtins +busday +busdaycalendar +byte +byteorder +bytes +callback +capitalize +case +cast +catch +cauchy +cbrt +cdouble +ceil +center +cfile +cfloat +char +character +chararray +chararrays +cheb2poly +chebadd +chebcompanion +chebder +chebdiv +chebdomain +chebfit +chebfromroots +chebgauss +chebgrid2d +chebgrid3d +chebint +chebinterpolate +chebline +chebmul +chebmulx +chebone +chebpow +chebpts1 +chebpts2 +chebroots +chebsub +chebtrim +chebval +chebval2d +chebval3d +chebvander +chebvander2d +chebvander3d +chebweight +chebx +chebyshev +chebzero +check +chisquare +chkfinite +choice +choices +cholesky +choose +class +clear +clip +clongdouble +clongfloat +close +clump +code +collections +cols +column +comments +common +compare +comparison +compat +compile +compiled +complex +complex128 +complex64 +complexfloating +compress +compressed +concatenate +cond +condition +config +conj +conjugate +contextlib +contiguous +converters +convolve +copy +copysign +copyto +core +corrcoef +correlate +correlate2 +cosh +count +cross +csingle +ctypes +ctypeslib +cumprod +cumproduct +cumsum +cycle +cycles +data +datastring +datetime +datetime64 +datetimeparse +ddof +decimal +decimals +decode +decorate +decorator +default +defaultfmt +defaults +defmatrix +deg2rad +degrees +delete +deletechars +delimiter +deprecate +descr +desired +device +diag +diagflat +diagonal +dict +diff +digitize +digits +dimensions +dims +dirichlet +dirs +disp +dispatch +dispatcher +divide +divmod +dlpack +docs +docstring +domain +double +dragon4 +drop +dsplit +dstack +dtype +dtypes +duplicate +easy +edgeitems +edges +ediff1d +eigh +eigvals +eigvalsh +einsum +element +elements +emath +empty +encode +encoding +endian +endswith +endwith +english +equal +equiv +error +errstate +euler +eval +exception +exceptions +excludelist +exp2 +expand +expandtabs +expected +expm1 +exponential +extbuild +extend +extension +extobj +extra +extract +extras +fabs +factory +fastCopyAndTranspose +fft2 +fftfreq +fftn +fftshift +fields +file +filename +fill +filled +filler +filling +fills +find +finfo +flags +flagsobj +flatiter +flatnonzero +flatnotmasked +flatten +flexible +flip +fliplr +flipud +float +float16 +float32 +float64 +floating +floatmode +floor +fmax +fmin +fmod +fname +footer +format +formatarg +formatargspec +formats +formatter +formatvalue +formatvarargs +formatvarkw +fortran +fractional +frexp +from +fromarrays +frombuffer +fromfile +fromflex +fromfunction +fromiter +fromnumeric +frompyfunc +fromrecords +fromregex +fromstring +fspath +full +func +func1d +function +functions +functools +fxarray +gamma +gdict +generator +generic +genericTypeRank +genfromtxt +geometric +geomspace +getargspec +getbufsize +getdata +getdomain +geterr +geterrcall +geterrobj +getexception +getlimits +getmask +getmaskarray +gradient +greater +grid +gumbel +half +hamming +handler +hanning +hard +harden +header +heaviside +helper +herm2poly +hermadd +hermcompanion +hermder +hermdiv +hermdomain +herme2poly +hermeadd +hermecompanion +hermeder +hermediv +hermedomain +hermefit +hermefromroots +hermegauss +hermegrid2d +hermegrid3d +hermeint +hermeline +hermemul +hermemulx +hermeone +hermepow +hermeroots +hermesub +hermetrim +hermeval +hermeval2d +hermeval3d +hermevander +hermevander2d +hermevander3d +hermeweight +hermex +hermezero +hermfit +hermfromroots +hermgauss +hermgrid2d +hermgrid3d +hermint +hermite +hermline +hermmul +hermmulx +hermone +hermpow +hermroots +hermsub +hermtrim +hermval +hermval2d +hermval3d +hermvander +hermvander2d +hermvander3d +hermweight +hermx +hermzero +hfft +histogram +histogram2d +histogramdd +histograms +hsplit +hstack +hypergeometric +hypot +ident +identity +ifft +ifft2 +ifftn +ifftshift +ihfft +iinfo +imag +implementation +implied +import +imports +in1d +include +index +indices +inexact +info +infstr +infty +init +initialdoc +inner +innerproduct +inplace +input +insert +inside +inspect +int16 +int32 +int64 +int8 +intc +integer +integers +interp +intersect1d +intp +invalid +inverse +invert +irfft +irfft2 +irfftn +isComplexType +isMA +isMaskedArray +isalnum +isalpha +isarray +isclose +iscomplex +iscomplexobj +isdecimal +isdigit +isfileobj +isfinite +isfortran +isin +isinf +islower +isnan +isnat +isneginf +isnumeric +isposinf +isreal +isrealobj +isscalar +issctype +issequence +isspace +issubclass +issubdtype +issubsctype +istitle +isupper +itemgetter +itemsize +iterable +iters +itertools +jiffies +join +kaiser +keep +keepdims +kind +kron +kwargs +label +lag2poly +lagadd +lagcompanion +lagder +lagdiv +lagdomain +lagfit +lagfromroots +laggauss +laggrid2d +laggrid3d +lagint +lagline +lagmul +lagmulx +lagone +lagpow +lagroots +lagsub +lagtrim +laguerre +lagval +lagval2d +lagval3d +lagvander +lagvander2d +lagvander3d +lagweight +lagx +lagzero +laplace +latin1 +lbnd +ldexp +ldict +left +leg2poly +legacy +legadd +legcompanion +legder +legdiv +legdomain +legendre +legfit +legfromroots +leggauss +leggrid2d +leggrid3d +legint +legline +legmul +legmulx +legone +legpow +legroots +legsub +legtrim +legval +legval2d +legval3d +legvander +legvander2d +legvander3d +legweight +legx +legzero +less +lexsort +libname +libraries +library +like +linalg +linefeed +linewidth +link +linspace +list +little +ljust +load +loader +loadtxt +log10 +log1p +log2 +logaddexp +logaddexp2 +logical +logistic +logn +lognormal +logseries +logspace +long +longcomplex +longdouble +longfloat +longlong +lookfor +loose +lower +lstrip +lstsq +magic +major +make +mapdomain +mapparms +mask +masked +matching +math +matmul +matrix +matrixlib +maximum +maxpower +maxulp +maxwidth +mean +measure +median +memmap +memory +memusage +mesg +meshgrid +metadata +methodcaller +methods +mgrid +minimum +minor +mintypecode +missing +mixins +mmap +mode +modf +modname +module +modules +more +moveaxis +msort +mtrand +multi +multiarray +multinomial +multiply +multivariate +mvoid +name +names +nanargmax +nanargmin +nancumprod +nancumsum +nanfunctions +nanmax +nanmean +nanmedian +nanmin +nanpercentile +nanprod +nanquantile +nanstd +nanstr +nansum +nanvar +narray +nbytes +ndarray +ndenumerate +ndim +ndindex +nditer +ndmin +ndpointer +ndtype +negative +nested +newaxis +newdoc +newshape +nextafter +nomask +noncentral +none +nonzero +norm +normal +normalize +note +notmasked +npts +npyio +ntypes +nullcontext +nulp +numarray +number +numbers +numeric +numerictypes +numfmt +numpy +nxarray +obj2sctype +object +offset +ogrid +oldnumeric +ones +open +operator +opindex +option +order +outer +outerproduct +output +outputfilename +outside +over +overridable +override +overrides +overwrite +packbits +padding +parens +pareto +parser +partition +path +pathlib +percentile +permutation +pickle +piecewise +pinv +place +platform +poisson +poly +poly1d +poly2cheb +poly2herm +poly2herme +poly2lag +poly2leg +polyadd +polycompanion +polyder +polydiv +polydomain +polyfit +polyfromroots +polygrid2d +polygrid3d +polyint +polyline +polymul +polymulx +polynomial +polyone +polypow +polyroots +polysub +polytrim +polyutils +polyval +polyval2d +polyval3d +polyvalfromroots +polyvander +polyvander2d +polyvander3d +polyx +polyzero +positional +positive +power +precision +prepare +prepend +print +printoptions +printstyle +prod +product +prologue +promote +propagate +public +putmask +py3k +python +quantile +quotechar +rad2deg +radians +raise +raises +rand +randbits +randint +randn +random +ranf +rank +ravel +rayleigh +rcond +read +real +recList +recarray +recfromcsv +recfromtxt +reciprocal +record +reduce +regenerate +regex +regexp +release +remainder +remaining +repeat +replace +repr +require +requirements +reshape +resize +result +return +returned +revision +rfft +rfft2 +rfftfreq +rfftn +rfind +right +rindex +rint +rjust +roll +rollaxis +roots +rot90 +round +rowcols +rows +rowvar +rpartition +rsplit +rstrip +rtol +rundocs +runstring +runtime +safe +sample +save +savetxt +savez +scalar +scientific +scimath +sctype +sctype2char +sctypeDict +sctypes +searchsorted +seed +select +sensitive +series +setbufsize +setdiff1d +seterr +seterrcall +seterrobj +setxor1d +shape +shapes +share +shares +shift +short +show +shrink +shuffle +sign +signature +signatures +signbit +signedinteger +significant +sinc +single +singlecomplex +singleton +sinh +sixu +size +skip +skiprows +sliding +slogdet +soften +solve +sometrue +sort +source +space +spacing +sparse +split +splitlines +sqrt +square +squeeze +stack +standard +startswith +state +strchar +strict +stride +strided +strides +string +strings +strip +structured +style +subclass +subok +subprocess +subtract +suffix +suppress +swapaxes +swapcase +sysconfig +take +tanh +tempdir +temppath +tensor +tensordot +tensorinv +tensorsolve +test +testing +testmatch +textwrap +third +threshold +tile +time +timedelta64 +times +title +titles +toplevel +trace +tracemalloc +translate +transpose +trapz +triangular +tricks +tril +trim +trimcoef +trimseq +triu +true +trunc +tuple +twodim +type +typeDict +typechars +typecodes +typeinfo +typeinforanged +typename +types +typeset +ubyte +ufunc +ufunclike +ufuncs +uint +uint16 +uint32 +uint64 +uint8 +uintc +uintp +ulonglong +umath +under +unicode +uniform +union1d +unique +unmasked +unpack +unpackbits +unravel +unsignedinteger +unwrap +upper +usecols +usemask +ushort +utils +validationargs +value +values +vander +varargs +vardict +varkw +vdot +vectorize +verbose +verify +version +view +void +vonmises +vsplit +vstack +wald +warn +warning +warnings +warns +weakref +weibull +weights +what +where +width +window +with +wrap +write +writeable +zeros +zfill +zipf +zipfile diff --git a/doc/source/dictionaries/pyqtgraph.dic b/doc/source/dictionaries/pyqtgraph.dic new file mode 100644 index 0000000000..95759a58e5 --- /dev/null +++ b/doc/source/dictionaries/pyqtgraph.dic @@ -0,0 +1,3399 @@ +10x10 +10x5 +10x6 +10x8 +12x10 +12x12 +A2UI +ACCESS +ACCUM +ACTIVE +ADJACENCY +ALIASED +ALIGNMENT +ALPHA +ALPHA1 +ALPHA12 +ALPHA16 +ALPHA2 +ALPHA4 +ALPHA8 +ALREADY +ALWAYS +AMBIENT +ANISOTROPY +ANSI +APPLICATION +ARRAY +ASCII +ASTC +ATOMIC +ATTACHED +ATTACHMENT +ATTACHMENT0 +ATTACHMENT1 +ATTACHMENT10 +ATTACHMENT11 +ATTACHMENT12 +ATTACHMENT13 +ATTACHMENT14 +ATTACHMENT15 +ATTACHMENT16 +ATTACHMENT17 +ATTACHMENT18 +ATTACHMENT19 +ATTACHMENT2 +ATTACHMENT20 +ATTACHMENT21 +ATTACHMENT22 +ATTACHMENT23 +ATTACHMENT24 +ATTACHMENT25 +ATTACHMENT26 +ATTACHMENT27 +ATTACHMENT28 +ATTACHMENT29 +ATTACHMENT3 +ATTACHMENT30 +ATTACHMENT31 +ATTACHMENT4 +ATTACHMENT5 +ATTACHMENT6 +ATTACHMENT7 +ATTACHMENT8 +ATTACHMENT9 +ATTACHMENTS +ATTENUATION +ATTRIB +ATTRIBS +ATTRIBUTE +ATTRIBUTES +AUTO +AUX0 +AUX1 +AUX2 +AUX3 +AVAILABLE +ActionGroup +ActionGroupParameter +ActionGroupParameterItem +ActionParameter +ActionParameterItem +ArgumentError +ArrayDatatype +ArrowItem +AxisItem +B10F +BACK +BARRIER +BASE +BEHAVIOR +BGRA +BIAS +BINARY +BINDING +BINDINGS +BITMAP +BITS +BLACK +BLEND +BLOCK +BLOCKS +BLUE +BOOL +BORDER +BOUNDS +BPTC +BUFFER +BUFFER0 +BUFFER1 +BUFFER10 +BUFFER11 +BUFFER12 +BUFFER13 +BUFFER14 +BUFFER15 +BUFFER2 +BUFFER3 +BUFFER4 +BUFFER5 +BUFFER6 +BUFFER7 +BUFFER8 +BUFFER9 +BUFFERS +BYTE +BYTES +BarGraphItem +BoolOrRadioParameter +BoolParameterItem +BusyCursor +ButtonItem +C4UB +CALLBACK +CARE +CAVEAT +CHAR +CIELabColor +CLAMP +CLASS +CLEAR +CLIENT +CLIP +CLIPPING +CMAPS +COEFF +COHERENT +COLOR +COMBINE +COMBINED +COMMAND +COMMANDS +COMPARE +COMPATIBILITY +COMPATIBLE +COMPILE +COMPILER +COMPLETE +COMPONENT +COMPONENT16 +COMPONENT24 +COMPONENT32 +COMPONENT32F +COMPONENTS +COMPRESSED +COMPRESSION +COMPUTE +CONDITION +CONFIG +CONSERVATIVE +CONSTANT +CONTEXT +CONTROL +CONVENTION +CONVOLUTION +COORD +COORDINATE +COORDS +COPY +CORE +CORRECTION +COUNT +COUNTER +COUNTERS +COUNTS +COVERAGE +CUBE +CULL +CURRENT +CUTOFF +CYAN +CalendarParameter +CalendarParameterItem +Callable +CanceledError +CheckTable +ChecklistParameter +ChecklistParameterItem +CircleROI +ClosedError +Color +ColorBarItem +ColorButton +ColorMap +ColorMapButton +ColorMapDisplayMixin +ColorMapLutParameter +ColorMapLutParameterItem +ColorMapMenu +ColorMapParameter +ColorMapParameterItem +ColorMapWidget +ColorParameter +ColorParameterItem +Colors +ComboBox +Constant +CrosshairROI +CurveArrow +CurvePoint +DATA +DEBUG +DECAL +DECODE +DECR +DEFAULT +DELETE +DENSITY +DEPRECATED +DEPTH +DEPTH24 +DEPTH32F +DERIVATIVE +DIFFUSE +DIMENSIONS +DIMS +DIRECTION +DISCARD +DISPATCH +DISPLAY +DISTANCE +DISTANCE0 +DISTANCE1 +DISTANCE2 +DISTANCE3 +DISTANCE4 +DISTANCE5 +DISTANCE6 +DISTANCE7 +DISTANCES +DITHER +DIVISOR +DOMAIN +DONT +DOT3 +DOUBLE +DOUBLEBUFFER +DRAW +DUAL +DXT1 +DXT3 +DXT5 +DYNAMIC +DataFilterParameter +DataFilterWidget +DataTreeWidget +DateAxisItem +DeferredObjectProxy +DiffTreeWidget +EDGE +ELAPSED +ELEMENT +ELEMENTS +EMISSION +EMITTED +ENABLE +ENABLED +ENCODING +ENUM +EQUAL +EQUATION +EQUIV +ERROR +ETC2 +EVAL +EVALUATION +EVEN +EXECUTE +EXP2 +EXPIRED +EXPLICIT +EXPONENT +EXPONENTS +EXTENSIONS +Element +EllipseROI +Emitter +EnterEvent +Enum +EnumColorMapItem +EnumFilterItem +Error +ErrorBarItem +ErrorBox +EventProxy +ExitStack +FACE +FACTOR +FADE +FAIL +FAILED +FALSE +FASTEST +FEEDBACK +FENCE +FETCH +FILL +FILTER +FIRST +FIXED +FLAG +FLAGS +FLAT +FLOAT +FLOATS +FLUSH +FOLLOW +FORMAT +FORMATS +FORWARD +FRACTIONAL +FRAGMENT +FRAMEBUFFER +FROM +FRONT +FULL +FUNC +FUNCTION +FailedImport +FeedbackButton +FileDialog +FileForwarder +FileParameter +FileParameterItem +FillBetweenItem +FontParameter +FontParameterItem +ForkedProcess +Form +G11F +GATHER +GENERATE +GENERATED +GEOMETRY +GEQUAL +GLDEBUGPROC +GLDEBUGPROCAMD +GLDEBUGPROCARB +GLDEBUGPROCKHR +GLError +GLUError +GLUTError +GLUTerror +GLUerror +GLbitfield +GLboolean +GLbyte +GLchar +GLcharARB +GLclampd +GLclampf +GLclampx +GLdouble +GLeglImageOES +GLenum +GLenumArray +GLerror +GLfixed +GLfloat +GLhalfARB +GLhalfNV +GLhandle +GLhandleARB +GLint +GLint64 +GLint64EXT +GLintArray +GLintptr +GLintptrARB +GLshort +GLsizei +GLsizeiptr +GLsizeiptrARB +GLsync +GLubyte +GLuint +GLuint64 +GLuint64EXT +GLulong +GLushort +GLvdpauSurfaceNV +GLvoid +GLvoidp +GRANULARITY +GREATER +GREEN +GRID +GROUP +GUILTY +GarbageWatcher +GradientEditorItem +GradientLegend +GradientPresets +GradientWidget +Gradients +GraphIcon +GraphItem +GraphicsItem +GraphicsLayout +GraphicsLayoutWidget +GraphicsObject +GraphicsScene +GraphicsView +GraphicsWidget +GraphicsWidgetAnchor +GridItem +GroupBox +GroupParameter +GroupParameterItem +HALF +HAVE +HDF5 +HEIGHT +HIGH +HINT +HISTOGRAM +HOUR +Handle +HistogramLUTItem +HistogramLUTWidget +IGNORED +IMAGE +IMAGES +IMMUTABLE +IMPLEMENTATION +INCOMPLETE +INCR +INDEX +INDEX1 +INDEX16 +INDEX4 +INDEX8 +INDEXES +INDICES +INDIRECT +INFO +INNER +INNOCENT +INPUT +INT64 +INTEGER +INTENSITY +INTENSITY12 +INTENSITY16 +INTENSITY4 +INTENSITY8 +INTERLEAVED +INTERNAL +INTERNALFORMAT +INTERPOLATE +INTERPOLATION +INVALID +INVALIDATE +INVERT +INVERTED +INVOCATIONS +ISOLINES +ImageItem +ImageView +ImageViewTemplate +InfLineLabel +InfiniteLine +InteractiveFunction +Interactor +InvisibleRootItem +IsocurveItem +IsosurfaceDataCache +ItemGroup +ItemSample +JoystickButton +KEEP +LABEL +LANGUAGE +LARGE +LAST +LAYER +LAYERED +LAYERS +LEFT +LENGTH +LEQUAL +LESS +LEVEL +LEVELS +LIGHT +LIGHT0 +LIGHT1 +LIGHT2 +LIGHT3 +LIGHT4 +LIGHT5 +LIGHT6 +LIGHT7 +LIGHTING +LIGHTS +LINE +LINEAR +LINES +LINK +LIST +LOAD +LOCAL +LOCATION +LOCATIONS +LOGGED +LOGIC +LONG +LOOP +LOSE +LOST +LOWER +LUMINANCE +LUMINANCE12 +LUMINANCE16 +LUMINANCE4 +LUMINANCE6 +LUMINANCE8 +LabelItem +LayoutWidget +LeaveEvent +LegendItem +LineROI +LineSegmentROI +LinearRegionItem +ListParameter +ListParameterItem +LocalObjectProxy +MAGENTA +MAJOR +MANUAL +MAP1 +MAP2 +MAPPED +MARKER +MASK +MAT2 +MAT2x3 +MAT2x4 +MAT3 +MAT3x2 +MAT3x4 +MAT4 +MAT4x2 +MAT4x3 +MATERIAL +MATPLOTLIB +MATRIX +MEDIUM +MEMORY +MESSAGE +MESSAGES +METAARRAY +MINMAX +MINOR +MINUS +MINUTE +MIPMAP +MIRROR +MIRRORED +MISSING +MODE +MODEL +MODELVIEW +MODELVIEW0 +MODULATE +MONTH +MULT +MULTISAMPLE +MetaArray +MouseDragHandler +MouseEvent +MultiLineROI +MultiPlotItem +MultiPlotWidget +MultiRectROI +Mutex +NAME +NAND +NEAREST +NEGATIVE +NESTING +NEVER +NEXT +NICEST +NONE +NOOP +NORMAL +NORMALIZE +NORMALIZED +NOTEQUAL +NOTIFICATION +NoResultError +NumericParameterItem +OBJECT +OFFSET +ONLY +OPENGL +OPERAND0 +OPERAND1 +OPERAND2 +OPERATION +OPTIONS +ORDER +ORIGIN +OTHER +OUTER +OUTPUT +OUTPUTS +OVERFLOW +ObjTracker +ObjectProxy +OpenGL +Optional +OrderedDict +PACK +PARAM +PARAMETER +PARTY +PASS +PASSED +PATCH +PATCHES +PATTERN +PAUSED +PColorMeshItem +PERFORMANCE +PERSISTENT +PERSPECTIVE +PIPELINE +PIXEL +PIXELS +PLANE +PLANE0 +PLANE1 +PLANE2 +PLANE3 +PLANE4 +PLANE5 +PLANES +POINT +POINTER +POINTS +POLYGON +PORTABILITY +POSITION +POSITIVE +POST +PREFERRED +PREFIX +PREFIXES +PREVIOUS +PRIMARY +PRIMITIVE +PRIMITIVES +PRIORITY +PROFILE +PROGRAM +PROJECTION +PROVOKING +PROXY +PUNCHTHROUGH +PUSH +PYQT +PYQT4 +PYQT5 +PYQT6 +PYSIDE +PYSIDE2 +PYSIDE6 +Parallelize +Parameter +ParameterControlledButton +ParameterItem +ParameterSystem +ParameterTree +PathButton +PenParameter +PenParameterItem +PenPreviewLabel +PlotCurveItem +PlotDataItem +PlotDataset +PlotItem +PlotWidget +Point +PolyLineROI +PrimitiveArray +PrintDetector +PrivateActionData +Process +Profiler +ProgressBarParameter +ProgressBarParameterItem +ProgressDialog +ProgressWidget +PyQt6 +QAPP +QAbstractAnimation +QAbstractButton +QAbstractEventDispatcher +QAbstractFileIconProvider +QAbstractGraphicsShapeItem +QAbstractItemDelegate +QAbstractItemModel +QAbstractItemView +QAbstractListModel +QAbstractNativeEventFilter +QAbstractProxyModel +QAbstractScrollArea +QAbstractSlider +QAbstractSpinBox +QAbstractTableModel +QAbstractTextDocumentLayout +QAction +QActionEvent +QActionGroup +QAnimationGroup +QApplication +QArrayDataQt5 +QArrayDataQt6 +QBackingStore +QBasicTimer +QBitArray +QBitmap +QBluetoothPermission +QBoxLayout +QBrush +QBuffer +QButtonGroup +QByteArray +QByteArrayMatcher +QCalendar +QCalendarPermission +QCalendarWidget +QCameraPermission +QCborError +QCborKnownTags +QCborSimpleType +QCborStreamReader +QCborStreamWriter +QCheckBox +QChildEvent +QChildWindowEvent +QClipboard +QCloseEvent +QCollator +QCollatorSortKey +QColor +QColorConstants +QColorDialog +QColorSpace +QColorTransform +QColumnView +QComboBox +QCommandLineOption +QCommandLineParser +QCommandLinkButton +QCommonStyle +QCompleter +QConcatenateTablesProxyModel +QConicalGradient +QContactsPermission +QContextMenuEvent +QCoreApplication +QCryptographicHash +QCursor +QDataStream +QDataWidgetMapper +QDate +QDateEdit +QDateTime +QDateTimeEdit +QDeadlineTimer +QDesktopServices +QDial +QDialog +QDialogButtonBox +QDir +QDirIterator +QDockWidget +QDoubleSpinBox +QDoubleValidator +QDrag +QDragEnterEvent +QDragLeaveEvent +QDragMoveEvent +QDropEvent +QDynamicPropertyChangeEvent +QEasingCurve +QElapsedTimer +QEnterEvent +QErrorMessage +QEvent +QEventLoop +QEventLoopLocker +QEventPoint +QExposeEvent +QFile +QFileDevice +QFileDialog +QFileIconProvider +QFileInfo +QFileOpenEvent +QFileSelector +QFileSystemModel +QFileSystemWatcher +QFocusEvent +QFocusFrame +QFont +QFontComboBox +QFontDatabase +QFontDialog +QFontInfo +QFontMetrics +QFontMetricsF +QFormLayout +QFrame +QGenericArgument +QGenericReturnArgument +QGesture +QGestureEvent +QGestureRecognizer +QGlyphRun +QGradient +QGraphicsAnchor +QGraphicsAnchorLayout +QGraphicsBlurEffect +QGraphicsColorizeEffect +QGraphicsDropShadowEffect +QGraphicsEffect +QGraphicsEllipseItem +QGraphicsGridLayout +QGraphicsItem +QGraphicsItemGroup +QGraphicsLayout +QGraphicsLayoutItem +QGraphicsLineItem +QGraphicsLinearLayout +QGraphicsObject +QGraphicsOpacityEffect +QGraphicsPathItem +QGraphicsPixmapItem +QGraphicsPolygonItem +QGraphicsProxyWidget +QGraphicsRectItem +QGraphicsRotation +QGraphicsScale +QGraphicsScene +QGraphicsSceneContextMenuEvent +QGraphicsSceneDragDropEvent +QGraphicsSceneEvent +QGraphicsSceneHelpEvent +QGraphicsSceneHoverEvent +QGraphicsSceneMouseEvent +QGraphicsSceneMoveEvent +QGraphicsSceneResizeEvent +QGraphicsSceneWheelEvent +QGraphicsSimpleTextItem +QGraphicsTextItem +QGraphicsTransform +QGraphicsView +QGraphicsWidget +QGridLayout +QGroupBox +QGuiApplication +QHBoxLayout +QHeaderView +QHelpEvent +QHideEvent +QHoverEvent +QIODevice +QIODeviceBase +QIcon +QIconDragEvent +QIconEngine +QIdentityProxyModel +QImage +QImageIOHandler +QImageReader +QImageWriter +QInputDevice +QInputDialog +QInputEvent +QInputMethod +QInputMethodEvent +QInputMethodQueryEvent +QIntValidator +QItemDelegate +QItemEditorCreatorBase +QItemEditorFactory +QItemSelection +QItemSelectionModel +QItemSelectionRange +QJsonDocument +QJsonParseError +QJsonValue +QKeyCombination +QKeyEvent +QKeySequence +QKeySequenceEdit +QLCDNumber +QLabel +QLayout +QLayoutItem +QLibrary +QLibraryInfo +QLine +QLineEdit +QLineF +QLinearGradient +QListView +QListWidget +QListWidgetItem +QLocale +QLocationPermission +QLockFile +QLoggingCategory +QMainWindow +QMargins +QMarginsF +QMatrix2x2 +QMatrix2x3 +QMatrix2x4 +QMatrix3x2 +QMatrix3x3 +QMatrix3x4 +QMatrix4x2 +QMatrix4x3 +QMatrix4x4 +QMdiArea +QMdiSubWindow +QMenu +QMenuBar +QMessageAuthenticationCode +QMessageBox +QMessageLogContext +QMessageLogger +QMetaClassInfo +QMetaEnum +QMetaMethod +QMetaObject +QMetaProperty +QMetaType +QMicrophonePermission +QMimeData +QMimeDatabase +QMimeType +QModelIndex +QModelRoleData +QModelRoleDataSpan +QMouseEvent +QMoveEvent +QMovie +QMutex +QMutexLocker +QNativeGestureEvent +QNativeIpcKey +QObjCache +QObject +QObjectCleanupHandler +QOffscreenSurface +QOpenGLContext +QOpenGLContextGroup +QOpenGLWidget +QOperatingSystemVersion +QOperatingSystemVersionBase +QPageLayout +QPageRanges +QPageSize +QPagedPaintDevice +QPaintDevice +QPaintDeviceWindow +QPaintEngine +QPaintEngineState +QPaintEvent +QPainter +QPainterPath +QPainterPathPrivateQt5 +QPainterPathPrivateQt6 +QPainterPathStroker +QPalette +QPanGesture +QParallelAnimationGroup +QPauseAnimation +QPdfWriter +QPen +QPermission +QPersistentModelIndex +QPicture +QPinchGesture +QPixelFormat +QPixmap +QPixmapCache +QPlainTextDocumentLayout +QPlainTextEdit +QPlatformSurfaceEvent +QPluginLoader +QPoint +QPointF +QPointerEvent +QPointingDevice +QPointingDeviceUniqueId +QPolygon +QPolygonF +QProcess +QProcessEnvironment +QProgressBar +QProgressDialog +QPropertyAnimation +QProxyStyle +QPushButton +QQuaternion +QRadialGradient +QRadioButton +QRandomGenerator +QRasterWindow +QRawFont +QReadLocker +QReadWriteLock +QRect +QRectF +QRecursiveMutex +QRegion +QRegularExpression +QRegularExpressionMatch +QRegularExpressionMatchIterator +QRegularExpressionValidator +QResizeEvent +QResource +QRgba64 +QRubberBand +QRunnable +QSaveFile +QScreen +QScrollArea +QScrollBar +QScrollEvent +QScrollPrepareEvent +QScroller +QScrollerProperties +QSemaphore +QSemaphoreReleaser +QSequentialAnimationGroup +QSessionManager +QSettings +QSharedMemory +QShortcut +QShortcutEvent +QShowEvent +QSignalBlocker +QSignalMapper +QSinglePointEvent +QSize +QSizeF +QSizeGrip +QSizePolicy +QSlider +QSocketNotifier +QSortFilterProxyModel +QSpacerItem +QSpinBox +QSplashScreen +QSplitter +QSplitterHandle +QStackedLayout +QStackedWidget +QStandardItem +QStandardItemModel +QStandardPaths +QStaticText +QStatusBar +QStatusTipEvent +QStorageInfo +QStringConverter +QStringConverterBase +QStringDecoder +QStringEncoder +QStringListModel +QStyle +QStyleFactory +QStyleHintReturn +QStyleHintReturnMask +QStyleHintReturnVariant +QStyleHints +QStyleOption +QStyleOptionButton +QStyleOptionComboBox +QStyleOptionComplex +QStyleOptionDockWidget +QStyleOptionFocusRect +QStyleOptionFrame +QStyleOptionGraphicsItem +QStyleOptionGroupBox +QStyleOptionHeader +QStyleOptionHeaderV2 +QStyleOptionMenuItem +QStyleOptionProgressBar +QStyleOptionRubberBand +QStyleOptionSizeGrip +QStyleOptionSlider +QStyleOptionSpinBox +QStyleOptionTab +QStyleOptionTabBarBase +QStyleOptionTabWidgetFrame +QStyleOptionTitleBar +QStyleOptionToolBar +QStyleOptionToolBox +QStyleOptionToolButton +QStyleOptionViewItem +QStylePainter +QStyledItemDelegate +QSurface +QSurfaceFormat +QSwipeGesture +QSyntaxHighlighter +QSysInfo +QSystemSemaphore +QSystemTrayIcon +QTabBar +QTabWidget +QTableView +QTableWidget +QTableWidgetItem +QTableWidgetSelectionRange +QTabletEvent +QTapAndHoldGesture +QTapGesture +QTemporaryDir +QTemporaryFile +QTextBlock +QTextBlockFormat +QTextBlockGroup +QTextBlockUserData +QTextBoundaryFinder +QTextBrowser +QTextCharFormat +QTextCursor +QTextDocument +QTextDocumentFragment +QTextDocumentWriter +QTextEdit +QTextFormat +QTextFragment +QTextFrame +QTextFrameFormat +QTextImageFormat +QTextInlineObject +QTextItem +QTextLayout +QTextLength +QTextLine +QTextList +QTextListFormat +QTextObject +QTextObjectInterface +QTextOption +QTextStream +QTextStreamManipulator +QTextTable +QTextTableCell +QTextTableCellFormat +QTextTableFormat +QThread +QThreadPool +QTime +QTimeEdit +QTimeLine +QTimeZone +QTimer +QTimerEvent +QToolBar +QToolBox +QToolButton +QToolTip +QTouchEvent +QTransform +QTranslator +QTransposeProxyModel +QTreeView +QTreeWidget +QTreeWidgetItem +QTreeWidgetItemIterator +QTypeRevision +QUAD +QUADRATIC +QUADS +QUERY +QUndoCommand +QUndoGroup +QUndoStack +QUndoView +QUrl +QUrlQuery +QUtiMimeConverter +QUuid +QVBoxLayout +QValidator +QVariant +QVariantAnimation +QVector2D +QVector3D +QVector4D +QVersionNumber +QWIDGETSIZE +QWaitCondition +QWhatsThis +QWhatsThisClickedEvent +QWheelEvent +QWidget +QWidgetAction +QWidgetItem +QWindow +QWindowStateChangeEvent +QWizard +QWizardPage +QWriteLocker +QXmlStreamAttribute +QXmlStreamAttributes +QXmlStreamEntityDeclaration +QXmlStreamEntityResolver +QXmlStreamNamespaceDeclaration +QXmlStreamNotationDeclaration +QXmlStreamReader +QXmlStreamWriter +QtCore +QtEnumParameter +QtGui +QtMsgType +QtOpenGLWidgets +QtProcess +QtSvg +QtTest +QtVersion +QtWidgets +QuadInstances +R11F +R16F +R16I +R16UI +R32F +R32I +R32UI +R8UI +RANGE +RASTER +RASTERIZER +READ +RECT +RECTANGLE +REDUCE +REFERENCED +REFLECTION +REGEX +REGION +REGULAR +RELATIVE +RELEASE +RENDER +RENDERABLE +RENDERBUFFER +RENDERER +REPEAT +REPLACE +REPLICATE +RESCALE +RESET +RESIDENT +RESOURCES +RESTART +RESULT +RETRIEVABLE +RETURN +REVERSE +RG11 +RG16 +RG16F +RG16I +RG16UI +RG32F +RG32I +RG32UI +RG8I +RG8UI +RGB10 +RGB12 +RGB16 +RGB16F +RGB16I +RGB16UI +RGB32F +RGB32I +RGB32UI +RGB4 +RGB5 +RGB565 +RGB8 +RGB8I +RGB8UI +RGB9 +RGBA +RGBA12 +RGBA16 +RGBA16F +RGBA16I +RGBA16UI +RGBA2 +RGBA32F +RGBA32I +RGBA32UI +RGBA4 +RGBA8 +RGBA8I +RGBA8UI +RGTC1 +RGTC2 +RIGHT +ROBUST +ROIPlotItem +ROWS +RadioParameterItem +RangeColorMapItem +RangeFilterItem +RawImageGLWidget +RawImageWidget +RectROI +RecursiveMutex +RemoteEventHandler +RemoteExceptionWarning +RemoteGraphicsView +RemoteQtEventHandler +Renderer +Request +RulerROI +RunOptions +S3TC +SAMPLE +SAMPLER +SAMPLES +SATISFIED +SATURATE +SCALE +SCISSOR +SEAMLESS +SECOND +SECONDARY +SEGMENTS +SELECT +SELECTION +SEPARABLE +SEPARATE +SERVER +SEVERITY +SHADE +SHADER +SHADERS +SHADING +SHADOW +SHARED +SHIFT +SHININESS +SHORT +SIDE +SIGNALED +SIGNED +SIMULTANEOUS +SINGLE +SINK +SIZE +SKIP +SLICER +SLUMINANCE +SLUMINANCE8 +SMOOTH +SNORM +SOURCE +SOURCE0 +SOURCE1 +SOURCE2 +SPACING +SPECULAR +SPHERE +SPIR +SPOT +SPRITE +SRC0 +SRC1 +SRC2 +SRGB +SRGB8 +SRTTransform +SRTTransform3D +STACK +START +STATIC +STATUS +STDERR +STDOUT +STENCIL +STENCIL8 +STEREO +STIPPLE +STORAGE +STORE +STRATEGY +STREAM +STREAMS +STRIDE +STRIP +SUBMITTED +SUBPIXEL +SUBROUTINE +SUBROUTINES +SUBTRACT +SUPPORT +SUPPORTED +SWAP +SWIZZLE +SYNC +SYNCHRONOUS +SYSTEM +ScaleBar +ScatterPlotItem +ScatterPlotWidget +Sequence +SetConsoleTextAttribute +Signal +SignalBlock +SignalProxy +SimpleParameter +SliderParameter +SliderParameterItem +SpinBox +SpotItem +StrParameterItem +SymbolAtlas +Symbols +SystemSolver +TABLE +TARGET +TARGETS +TESS +TEST +TEXEL +TEXTURE +TEXTURE0 +TEXTURE1 +TEXTURE10 +TEXTURE11 +TEXTURE12 +TEXTURE13 +TEXTURE14 +TEXTURE15 +TEXTURE16 +TEXTURE17 +TEXTURE18 +TEXTURE19 +TEXTURE2 +TEXTURE20 +TEXTURE21 +TEXTURE22 +TEXTURE23 +TEXTURE24 +TEXTURE25 +TEXTURE26 +TEXTURE27 +TEXTURE28 +TEXTURE29 +TEXTURE3 +TEXTURE30 +TEXTURE31 +TEXTURE4 +TEXTURE5 +TEXTURE6 +TEXTURE7 +TEXTURE8 +TEXTURE9 +THIRD +THRESHOLD +THROUGH +TIME +TIMEOUT +TIMESTAMP +TOKEN +TOTAL +TRANSFORM +TRANSLATE +TRANSPOSE +TRIANGLE +TRIANGLES +TRUE +TYPE +TableWidget +TableWidgetItem +TargetItem +TargetLabel +Tasker +TestROI +TextItem +TextParameter +TextParameterItem +ThreadColor +ThreadTrace +ThreadsafeTimer +Tick +TickMenu +TickSliderItem +TickSpec +Tracer +Transform3D +TreeWidget +TreeWidgetItem +TriangleROI +UIGraphicsItem +UNDEFINED +UNDERFLOW +UNIFORM +UNIFORMS +UNITS +UNKNOWN +UNORM +UNPACK +UNSET +UNSIGNALED +UNSIGNED +UNSUPPORTED +UNSYNCHRONIZED +UPDATE +UPPER +USAGE +USER +Union +VALID +VALIDATE +VALUE +VARIABLE +VARIABLES +VARYING +VARYINGS +VEC2 +VEC3 +VEC4 +VECTOR +VECTORS +VENDOR +VERSION +VERSIONS +VERTEX +VERTICES +VIEW +VIEWER +VIEWPORT +VIEWPORTS +VOID +VTickGroup +ValueLabel +Vector +VerticalLabel +ViewBox +ViewBoxMenu +WAIT +WEEK +WEIGHT +WHITE +WIDTH +WINDOW +WORDS +WORK +WRAP +WRITE +WRITEMASK +WRITTEN +WheelEvent +WidgetGroup +WidgetParameterItem +WinColor +WinStyle +WinTerm +XYZn +YEAR +YELLOW +ZERO +ZOOM +ZoomLevel +action +actiongroup +addGradientListToDocstring +affineSlice +affineSliceCoords +allFrameObjs +allowUnicode +alpha +applyLookupTable +args +array +arrayToLineSegments +arrayToQPath +arrayToQPolygonF +arrays +atan2 +atexit +attributes +authkey +auto +axes +axis +axisCtrlTemplate +back +backtrace +baseAngle +basetypes +bidir +bisect +bool +brush +buffer +buildCetSubMenu +buildMenuEntryAction +buildMenuEntryWidget +buildUserSubMenu +builtins +bytes +cProfile +calendar +ceil +cerr +chain +char +checklist +cleanup +clip +cmap +code +collections +color +colorCIELab +colorDistance +colorStr +colorToAlpha +colorTuple +colorama +colormap +colormaplut +colors +cols +compat +connect +connected +console +constant +constants +contextdata +contextlib +contextmanager +converters +coords +copy +counter +counts +cout +cprint +create +ctrl +ctypes +cupy +data +dataType +datetime +debug +decimal +default +degrees +deps +depth +describeObj +device +dicts +directory +disconnect +downsample +drawSymbol +dtype +element +enableFaulthandler +encoding +endObj +enum +error +excepthook +exceptional +exctype +exec +exit +extendToEdge +extensions +faces +file +filename +filenames +find +findObj +findRefPath +finiteCheck +first +floor +font +fore +format +formatException +frexp +from +ftrace +func +function +functions +functools +gaussianFilter +generic +getConfigOption +getCupy +getExc +getFromColorcet +getFromMatplotlib +getGraphIcon +getGraphPixmap +getNumbaFunctions +getOffsetFromUtc +getPreviousVersion +getQDarkStyleDarkQPalette +getQDarkStyleLightQPalette +glAccum +glActiveShaderProgram +glActiveTexture +glAlphaFunc +glAreTexturesResident +glArrayElement +glAttachShader +glBegin +glBeginConditionalRender +glBeginQuery +glBeginQueryIndexed +glBeginTransformFeedback +glBindAttribLocation +glBindBuffer +glBindBufferBase +glBindBufferRange +glBindBuffersBase +glBindBuffersRange +glBindFragDataLocation +glBindFragDataLocationIndexed +glBindFramebuffer +glBindImageTexture +glBindImageTextures +glBindProgramPipeline +glBindRenderbuffer +glBindSampler +glBindSamplers +glBindTexture +glBindTextureUnit +glBindTextures +glBindTransformFeedback +glBindVertexArray +glBindVertexBuffer +glBindVertexBuffers +glBitmap +glBlendColor +glBlendEquation +glBlendEquationSeparate +glBlendEquationSeparatei +glBlendEquationi +glBlendFunc +glBlendFuncSeparate +glBlendFuncSeparatei +glBlendFunci +glBlitFramebuffer +glBlitNamedFramebuffer +glBufferData +glBufferStorage +glBufferSubData +glCallList +glCallLists +glCheckFramebufferStatus +glCheckNamedFramebufferStatus +glClampColor +glClear +glClearAccum +glClearBufferData +glClearBufferSubData +glClearBufferfi +glClearBufferfv +glClearBufferiv +glClearBufferuiv +glClearColor +glClearDepth +glClearDepthf +glClearIndex +glClearNamedBufferData +glClearNamedBufferSubData +glClearNamedFramebufferfi +glClearNamedFramebufferfv +glClearNamedFramebufferiv +glClearNamedFramebufferuiv +glClearStencil +glClearTexImage +glClearTexSubImage +glClientActiveTexture +glClientWaitSync +glClipControl +glClipPlane +glColor +glColor3b +glColor3bv +glColor3d +glColor3dv +glColor3f +glColor3fv +glColor3i +glColor3iv +glColor3s +glColor3sv +glColor3ub +glColor3ubv +glColor3ui +glColor3uiv +glColor3us +glColor3usv +glColor4b +glColor4bv +glColor4d +glColor4dv +glColor4f +glColor4fv +glColor4i +glColor4iv +glColor4s +glColor4sv +glColor4ub +glColor4ubv +glColor4ui +glColor4uiv +glColor4us +glColor4usv +glColorMask +glColorMaski +glColorMaterial +glColorP3ui +glColorP3uiv +glColorP4ui +glColorP4uiv +glColorPointer +glColorPointerb +glColorPointerd +glColorPointerf +glColorPointeri +glColorPointers +glColorPointerub +glColorPointerui +glColorPointerus +glColorSubTable +glColorTable +glColorTableParameterfv +glColorTableParameteriv +glCompileShader +glCompressedTexImage1D +glCompressedTexImage2D +glCompressedTexImage3D +glCompressedTexSubImage1D +glCompressedTexSubImage2D +glCompressedTexSubImage3D +glCompressedTextureSubImage1D +glCompressedTextureSubImage2D +glCompressedTextureSubImage3D +glConvolutionFilter1D +glConvolutionFilter2D +glConvolutionParameterf +glConvolutionParameterfv +glConvolutionParameteri +glConvolutionParameteriv +glCopyBufferSubData +glCopyColorSubTable +glCopyColorTable +glCopyConvolutionFilter1D +glCopyConvolutionFilter2D +glCopyImageSubData +glCopyNamedBufferSubData +glCopyPixels +glCopyTexImage1D +glCopyTexImage2D +glCopyTexSubImage1D +glCopyTexSubImage2D +glCopyTexSubImage3D +glCopyTextureSubImage1D +glCopyTextureSubImage2D +glCopyTextureSubImage3D +glCreateBuffers +glCreateFramebuffers +glCreateProgram +glCreateProgramPipelines +glCreateQueries +glCreateRenderbuffers +glCreateSamplers +glCreateShader +glCreateShaderProgramv +glCreateTextures +glCreateTransformFeedbacks +glCreateVertexArrays +glCullFace +glDebugMessageCallback +glDebugMessageCallbackKHR +glDebugMessageControl +glDebugMessageControlKHR +glDebugMessageInsert +glDebugMessageInsertKHR +glDeleteBuffers +glDeleteFramebuffers +glDeleteLists +glDeleteProgram +glDeleteProgramPipelines +glDeleteQueries +glDeleteRenderbuffers +glDeleteSamplers +glDeleteShader +glDeleteSync +glDeleteTextures +glDeleteTransformFeedbacks +glDeleteVertexArrays +glDepthFunc +glDepthMask +glDepthRange +glDepthRangeArrayv +glDepthRangeIndexed +glDepthRangef +glDetachShader +glDisable +glDisableClientState +glDisableVertexArrayAttrib +glDisableVertexAttribArray +glDisablei +glDispatchCompute +glDispatchComputeIndirect +glDrawArrays +glDrawArraysIndirect +glDrawArraysInstanced +glDrawArraysInstancedBaseInstance +glDrawBuffer +glDrawBuffers +glDrawElements +glDrawElementsBaseVertex +glDrawElementsIndirect +glDrawElementsInstanced +glDrawElementsInstancedBaseInstance +glDrawElementsInstancedBaseVertex +glDrawElementsInstancedBaseVertexBaseInstance +glDrawElementsub +glDrawElementsui +glDrawElementsus +glDrawPixels +glDrawPixelsb +glDrawPixelsf +glDrawPixelsi +glDrawPixelss +glDrawPixelsub +glDrawPixelsui +glDrawPixelsus +glDrawRangeElements +glDrawRangeElementsBaseVertex +glDrawTransformFeedback +glDrawTransformFeedbackInstanced +glDrawTransformFeedbackStream +glDrawTransformFeedbackStreamInstanced +glEdgeFlag +glEdgeFlagPointer +glEdgeFlagPointerb +glEdgeFlagv +glEnable +glEnableClientState +glEnableVertexArrayAttrib +glEnableVertexAttribArray +glEnablei +glEnd +glEndConditionalRender +glEndList +glEndQuery +glEndQueryIndexed +glEndTransformFeedback +glEvalCoord1d +glEvalCoord1dv +glEvalCoord1f +glEvalCoord1fv +glEvalCoord2d +glEvalCoord2dv +glEvalCoord2f +glEvalCoord2fv +glEvalMesh1 +glEvalMesh2 +glEvalPoint1 +glEvalPoint2 +glFeedbackBuffer +glFenceSync +glFinish +glFlush +glFlushMappedBufferRange +glFlushMappedNamedBufferRange +glFogCoordPointer +glFogCoordd +glFogCoorddv +glFogCoordf +glFogCoordfv +glFogf +glFogfv +glFogi +glFogiv +glFramebufferParameteri +glFramebufferRenderbuffer +glFramebufferTexture +glFramebufferTexture1D +glFramebufferTexture2D +glFramebufferTexture3D +glFramebufferTextureLayer +glFrontFace +glFrustum +glGenBuffers +glGenFramebuffers +glGenLists +glGenProgramPipelines +glGenQueries +glGenRenderbuffers +glGenSamplers +glGenTextures +glGenTransformFeedbacks +glGenVertexArrays +glGenerateMipmap +glGenerateTextureMipmap +glGetActiveAtomicCounterBufferiv +glGetActiveAttrib +glGetActiveSubroutineName +glGetActiveSubroutineUniformName +glGetActiveSubroutineUniformiv +glGetActiveUniform +glGetActiveUniformBlockName +glGetActiveUniformBlockiv +glGetActiveUniformName +glGetActiveUniformsiv +glGetAttachedShaders +glGetAttribLocation +glGetBoolean +glGetBooleani +glGetBooleanv +glGetBufferParameteri64v +glGetBufferParameteriv +glGetBufferPointerv +glGetBufferSubData +glGetClipPlane +glGetColorTable +glGetColorTableParameterfv +glGetColorTableParameteriv +glGetCompressedTexImage +glGetCompressedTextureImage +glGetCompressedTextureSubImage +glGetConvolutionFilter +glGetConvolutionParameterfv +glGetConvolutionParameteriv +glGetDebugMessageLog +glGetDebugMessageLogKHR +glGetDouble +glGetDoublei +glGetDoublev +glGetError +glGetFloat +glGetFloati +glGetFloatv +glGetFragDataIndex +glGetFragDataLocation +glGetFramebufferAttachmentParameteriv +glGetFramebufferParameteriv +glGetGraphicsResetStatus +glGetHistogram +glGetHistogramParameterfv +glGetHistogramParameteriv +glGetInteger +glGetInteger64i +glGetInteger64v +glGetIntegeri +glGetIntegerv +glGetInternalformati64v +glGetInternalformativ +glGetLightfv +glGetLightiv +glGetMapdv +glGetMapfv +glGetMapiv +glGetMaterialfv +glGetMaterialiv +glGetMinmax +glGetMinmaxParameterfv +glGetMinmaxParameteriv +glGetMultisamplefv +glGetNamedBufferParameteri64v +glGetNamedBufferParameteriv +glGetNamedBufferPointerv +glGetNamedBufferSubData +glGetNamedFramebufferAttachmentParameteriv +glGetNamedFramebufferParameteriv +glGetNamedRenderbufferParameteriv +glGetObjectLabel +glGetObjectLabelKHR +glGetObjectPtrLabel +glGetObjectPtrLabelKHR +glGetPixelMapfv +glGetPixelMapuiv +glGetPixelMapusv +glGetPointerv +glGetPointervKHR +glGetPolygonStipple +glGetPolygonStippleub +glGetProgramBinary +glGetProgramInfoLog +glGetProgramInterfaceiv +glGetProgramPipelineInfoLog +glGetProgramPipelineiv +glGetProgramResourceIndex +glGetProgramResourceLocation +glGetProgramResourceLocationIndex +glGetProgramResourceName +glGetProgramResourceiv +glGetProgramStageiv +glGetProgramiv +glGetQueryBufferObjecti64v +glGetQueryBufferObjectiv +glGetQueryBufferObjectui64v +glGetQueryBufferObjectuiv +glGetQueryIndexediv +glGetQueryObjecti64v +glGetQueryObjectiv +glGetQueryObjectui64v +glGetQueryObjectuiv +glGetQueryiv +glGetRenderbufferParameteriv +glGetSamplerParameterIiv +glGetSamplerParameterIuiv +glGetSamplerParameterfv +glGetSamplerParameteriv +glGetSeparableFilter +glGetShaderInfoLog +glGetShaderPrecisionFormat +glGetShaderSource +glGetShaderiv +glGetString +glGetStringi +glGetSubroutineIndex +glGetSubroutineUniformLocation +glGetSynciv +glGetTexEnvfv +glGetTexEnviv +glGetTexGendv +glGetTexGenfv +glGetTexGeniv +glGetTexImage +glGetTexImageb +glGetTexImaged +glGetTexImagef +glGetTexImagei +glGetTexImages +glGetTexImageub +glGetTexImageui +glGetTexImageus +glGetTexLevelParameterfv +glGetTexLevelParameteriv +glGetTexParameterIiv +glGetTexParameterIuiv +glGetTexParameterfv +glGetTexParameteriv +glGetTextureImage +glGetTextureLevelParameterfv +glGetTextureLevelParameteriv +glGetTextureParameterIiv +glGetTextureParameterIuiv +glGetTextureParameterfv +glGetTextureParameteriv +glGetTextureSubImage +glGetTransformFeedbackVarying +glGetTransformFeedbacki +glGetTransformFeedbacki64 +glGetTransformFeedbackiv +glGetUniformBlockIndex +glGetUniformIndices +glGetUniformLocation +glGetUniformSubroutineuiv +glGetUniformdv +glGetUniformfv +glGetUniformiv +glGetUniformuiv +glGetVertexArrayIndexed64iv +glGetVertexArrayIndexediv +glGetVertexArrayiv +glGetVertexAttribIiv +glGetVertexAttribIuiv +glGetVertexAttribLdv +glGetVertexAttribPointerv +glGetVertexAttribdv +glGetVertexAttribfv +glGetVertexAttribiv +glGetnColorTable +glGetnCompressedTexImage +glGetnConvolutionFilter +glGetnHistogram +glGetnMapdv +glGetnMapfv +glGetnMapiv +glGetnMinmax +glGetnPixelMapfv +glGetnPixelMapuiv +glGetnPixelMapusv +glGetnPolygonStipple +glGetnSeparableFilter +glGetnTexImage +glGetnUniformdv +glGetnUniformfv +glGetnUniformiv +glGetnUniformuiv +glHint +glHistogram +glIndexMask +glIndexPointer +glIndexPointerb +glIndexPointerd +glIndexPointerf +glIndexPointeri +glIndexPointers +glIndexPointerub +glIndexd +glIndexdv +glIndexf +glIndexfv +glIndexi +glIndexiv +glIndexs +glIndexsv +glIndexub +glIndexubv +glInitArraysOfArraysARB +glInitBaseInstanceARB +glInitClearBufferObjectARB +glInitCompressedTexturePixelStorageARB +glInitComputeShaderARB +glInitConservativeDepthARB +glInitCopyImageARB +glInitDebugKHR +glInitEs2CompatibilityARB +glInitEs3CompatibilityARB +glInitExplicitUniformLocationARB +glInitFragmentLayerViewportARB +glInitFramebufferNoAttachmentsARB +glInitGetProgramBinaryARB +glInitGl10VERSION +glInitGl11VERSION +glInitGl12VERSION +glInitGl13VERSION +glInitGl14VERSION +glInitGl15VERSION +glInitGl20VERSION +glInitGl21VERSION +glInitGl30VERSION +glInitGl31VERSION +glInitGl32VERSION +glInitGl33VERSION +glInitGl40VERSION +glInitGl41VERSION +glInitGl42VERSION +glInitGl43VERSION +glInitGl44VERSION +glInitGl45VERSION +glInitGl46VERSION +glInitImagingARB +glInitInternalformatQuery2ARB +glInitInternalformatQueryARB +glInitInvalidateSubdataARB +glInitMapBufferAlignmentARB +glInitMultiDrawIndirectARB +glInitNames +glInitProgramInterfaceQueryARB +glInitRobustBufferAccessBehaviorARB +glInitSeparateShaderObjectsARB +glInitShaderAtomicCountersARB +glInitShaderImageLoadStoreARB +glInitShaderImageSizeARB +glInitShaderPrecisionARB +glInitShaderStorageBufferObjectARB +glInitShadingLanguage420PackARB +glInitShadingLanguagePackingARB +glInitStencilTexturingARB +glInitTextureBufferRangeARB +glInitTextureQueryLevelsARB +glInitTextureStorageARB +glInitTextureStorageMultisampleARB +glInitTextureViewARB +glInitTransformFeedbackInstancedARB +glInitVertexAttrib64BitARB +glInitVertexAttribBindingARB +glInitViewportArrayARB +glInterleavedArrays +glInvalidateBufferData +glInvalidateBufferSubData +glInvalidateFramebuffer +glInvalidateNamedFramebufferData +glInvalidateNamedFramebufferSubData +glInvalidateSubFramebuffer +glInvalidateTexImage +glInvalidateTexSubImage +glIsBuffer +glIsEnabled +glIsEnabledi +glIsFramebuffer +glIsList +glIsProgram +glIsProgramPipeline +glIsQuery +glIsRenderbuffer +glIsSampler +glIsShader +glIsSync +glIsTexture +glIsTransformFeedback +glIsVertexArray +glLight +glLightModelf +glLightModelfv +glLightModeli +glLightModeliv +glLightf +glLightfv +glLighti +glLightiv +glLineStipple +glLineWidth +glLinkProgram +glListBase +glLoadIdentity +glLoadMatrixd +glLoadMatrixf +glLoadName +glLoadTransposeMatrixd +glLoadTransposeMatrixf +glLogicOp +glMap1d +glMap1f +glMap2d +glMap2f +glMapBuffer +glMapBufferRange +glMapGrid1d +glMapGrid1f +glMapGrid2d +glMapGrid2f +glMapNamedBuffer +glMapNamedBufferRange +glMaterial +glMaterialf +glMaterialfv +glMateriali +glMaterialiv +glMatrixMode +glMemoryBarrier +glMemoryBarrierByRegion +glMinSampleShading +glMinmax +glMultMatrixd +glMultMatrixf +glMultTransposeMatrixd +glMultTransposeMatrixf +glMultiDrawArrays +glMultiDrawArraysIndirect +glMultiDrawArraysIndirectCount +glMultiDrawElements +glMultiDrawElementsBaseVertex +glMultiDrawElementsIndirect +glMultiDrawElementsIndirectCount +glMultiTexCoord1d +glMultiTexCoord1dv +glMultiTexCoord1f +glMultiTexCoord1fv +glMultiTexCoord1i +glMultiTexCoord1iv +glMultiTexCoord1s +glMultiTexCoord1sv +glMultiTexCoord2d +glMultiTexCoord2dv +glMultiTexCoord2f +glMultiTexCoord2fv +glMultiTexCoord2i +glMultiTexCoord2iv +glMultiTexCoord2s +glMultiTexCoord2sv +glMultiTexCoord3d +glMultiTexCoord3dv +glMultiTexCoord3f +glMultiTexCoord3fv +glMultiTexCoord3i +glMultiTexCoord3iv +glMultiTexCoord3s +glMultiTexCoord3sv +glMultiTexCoord4d +glMultiTexCoord4dv +glMultiTexCoord4f +glMultiTexCoord4fv +glMultiTexCoord4i +glMultiTexCoord4iv +glMultiTexCoord4s +glMultiTexCoord4sv +glMultiTexCoordP1ui +glMultiTexCoordP1uiv +glMultiTexCoordP2ui +glMultiTexCoordP2uiv +glMultiTexCoordP3ui +glMultiTexCoordP3uiv +glMultiTexCoordP4ui +glMultiTexCoordP4uiv +glNamedBufferData +glNamedBufferStorage +glNamedBufferSubData +glNamedFramebufferDrawBuffer +glNamedFramebufferDrawBuffers +glNamedFramebufferParameteri +glNamedFramebufferReadBuffer +glNamedFramebufferRenderbuffer +glNamedFramebufferTexture +glNamedFramebufferTextureLayer +glNamedRenderbufferStorage +glNamedRenderbufferStorageMultisample +glNewList +glNormal +glNormal3b +glNormal3bv +glNormal3d +glNormal3dv +glNormal3f +glNormal3fv +glNormal3i +glNormal3iv +glNormal3s +glNormal3sv +glNormalP3ui +glNormalP3uiv +glNormalPointer +glNormalPointerb +glNormalPointerd +glNormalPointerf +glNormalPointeri +glNormalPointers +glObjectLabel +glObjectLabelKHR +glObjectPtrLabel +glObjectPtrLabelKHR +glOrtho +glPassThrough +glPatchParameterfv +glPatchParameteri +glPauseTransformFeedback +glPixelMapfv +glPixelMapuiv +glPixelMapusv +glPixelStoref +glPixelStorei +glPixelTransferf +glPixelTransferi +glPixelZoom +glPointParameterf +glPointParameterfv +glPointParameteri +glPointParameteriv +glPointSize +glPolygonMode +glPolygonOffset +glPolygonOffsetClamp +glPolygonStipple +glPopAttrib +glPopClientAttrib +glPopDebugGroup +glPopDebugGroupKHR +glPopMatrix +glPopName +glPrimitiveRestartIndex +glPrioritizeTextures +glProgramBinary +glProgramParameteri +glProgramUniform1d +glProgramUniform1dv +glProgramUniform1f +glProgramUniform1fv +glProgramUniform1i +glProgramUniform1iv +glProgramUniform1ui +glProgramUniform1uiv +glProgramUniform2d +glProgramUniform2dv +glProgramUniform2f +glProgramUniform2fv +glProgramUniform2i +glProgramUniform2iv +glProgramUniform2ui +glProgramUniform2uiv +glProgramUniform3d +glProgramUniform3dv +glProgramUniform3f +glProgramUniform3fv +glProgramUniform3i +glProgramUniform3iv +glProgramUniform3ui +glProgramUniform3uiv +glProgramUniform4d +glProgramUniform4dv +glProgramUniform4f +glProgramUniform4fv +glProgramUniform4i +glProgramUniform4iv +glProgramUniform4ui +glProgramUniform4uiv +glProgramUniformMatrix2dv +glProgramUniformMatrix2fv +glProgramUniformMatrix2x3dv +glProgramUniformMatrix2x3fv +glProgramUniformMatrix2x4dv +glProgramUniformMatrix2x4fv +glProgramUniformMatrix3dv +glProgramUniformMatrix3fv +glProgramUniformMatrix3x2dv +glProgramUniformMatrix3x2fv +glProgramUniformMatrix3x4dv +glProgramUniformMatrix3x4fv +glProgramUniformMatrix4dv +glProgramUniformMatrix4fv +glProgramUniformMatrix4x2dv +glProgramUniformMatrix4x2fv +glProgramUniformMatrix4x3dv +glProgramUniformMatrix4x3fv +glProvokingVertex +glPushAttrib +glPushClientAttrib +glPushDebugGroup +glPushDebugGroupKHR +glPushMatrix +glPushName +glQueryCounter +glRasterPos +glRasterPos2d +glRasterPos2dv +glRasterPos2f +glRasterPos2fv +glRasterPos2i +glRasterPos2iv +glRasterPos2s +glRasterPos2sv +glRasterPos3d +glRasterPos3dv +glRasterPos3f +glRasterPos3fv +glRasterPos3i +glRasterPos3iv +glRasterPos3s +glRasterPos3sv +glRasterPos4d +glRasterPos4dv +glRasterPos4f +glRasterPos4fv +glRasterPos4i +glRasterPos4iv +glRasterPos4s +glRasterPos4sv +glReadBuffer +glReadPixels +glReadPixelsb +glReadPixelsd +glReadPixelsf +glReadPixelsi +glReadPixelss +glReadPixelsub +glReadPixelsui +glReadPixelsus +glReadnPixels +glRectd +glRectdv +glRectf +glRectfv +glRecti +glRectiv +glRects +glRectsv +glReleaseShaderCompiler +glRenderMode +glRenderbufferStorage +glRenderbufferStorageMultisample +glResetHistogram +glResetMinmax +glResumeTransformFeedback +glRotate +glRotated +glRotatef +glSampleCoverage +glSampleMaski +glSamplerParameterIiv +glSamplerParameterIuiv +glSamplerParameterf +glSamplerParameterfv +glSamplerParameteri +glSamplerParameteriv +glScale +glScaled +glScalef +glScissor +glScissorArrayv +glScissorIndexed +glScissorIndexedv +glSecondaryColor3b +glSecondaryColor3bv +glSecondaryColor3d +glSecondaryColor3dv +glSecondaryColor3f +glSecondaryColor3fv +glSecondaryColor3i +glSecondaryColor3iv +glSecondaryColor3s +glSecondaryColor3sv +glSecondaryColor3ub +glSecondaryColor3ubv +glSecondaryColor3ui +glSecondaryColor3uiv +glSecondaryColor3us +glSecondaryColor3usv +glSecondaryColorP3ui +glSecondaryColorP3uiv +glSecondaryColorPointer +glSelectBuffer +glSeparableFilter2D +glShadeModel +glShaderBinary +glShaderSource +glShaderStorageBlockBinding +glSpecializeShader +glStencilFunc +glStencilFuncSeparate +glStencilMask +glStencilMaskSeparate +glStencilOp +glStencilOpSeparate +glTexBuffer +glTexBufferRange +glTexCoord +glTexCoord1d +glTexCoord1dv +glTexCoord1f +glTexCoord1fv +glTexCoord1i +glTexCoord1iv +glTexCoord1s +glTexCoord1sv +glTexCoord2d +glTexCoord2dv +glTexCoord2f +glTexCoord2fv +glTexCoord2i +glTexCoord2iv +glTexCoord2s +glTexCoord2sv +glTexCoord3d +glTexCoord3dv +glTexCoord3f +glTexCoord3fv +glTexCoord3i +glTexCoord3iv +glTexCoord3s +glTexCoord3sv +glTexCoord4d +glTexCoord4dv +glTexCoord4f +glTexCoord4fv +glTexCoord4i +glTexCoord4iv +glTexCoord4s +glTexCoord4sv +glTexCoordP1ui +glTexCoordP1uiv +glTexCoordP2ui +glTexCoordP2uiv +glTexCoordP3ui +glTexCoordP3uiv +glTexCoordP4ui +glTexCoordP4uiv +glTexCoordPointer +glTexCoordPointerb +glTexCoordPointerd +glTexCoordPointerf +glTexCoordPointeri +glTexCoordPointers +glTexEnvf +glTexEnvfv +glTexEnvi +glTexEnviv +glTexGend +glTexGendv +glTexGenf +glTexGenfv +glTexGeni +glTexGeniv +glTexImage1D +glTexImage1Db +glTexImage1Df +glTexImage1Di +glTexImage1Ds +glTexImage1Dub +glTexImage1Dui +glTexImage1Dus +glTexImage2D +glTexImage2DMultisample +glTexImage2Db +glTexImage2Df +glTexImage2Di +glTexImage2Ds +glTexImage2Dub +glTexImage2Dui +glTexImage2Dus +glTexImage3D +glTexImage3DMultisample +glTexImage3Db +glTexImage3Df +glTexImage3Di +glTexImage3Ds +glTexImage3Dub +glTexImage3Dui +glTexImage3Dus +glTexParameter +glTexParameterIiv +glTexParameterIuiv +glTexParameterf +glTexParameterfv +glTexParameteri +glTexParameteriv +glTexStorage1D +glTexStorage2D +glTexStorage2DMultisample +glTexStorage3D +glTexStorage3DMultisample +glTexSubImage1D +glTexSubImage1Db +glTexSubImage1Df +glTexSubImage1Di +glTexSubImage1Ds +glTexSubImage1Dub +glTexSubImage1Dui +glTexSubImage1Dus +glTexSubImage2D +glTexSubImage2Db +glTexSubImage2Df +glTexSubImage2Di +glTexSubImage2Ds +glTexSubImage2Dub +glTexSubImage2Dui +glTexSubImage2Dus +glTexSubImage3D +glTexSubImage3Db +glTexSubImage3Df +glTexSubImage3Di +glTexSubImage3Ds +glTexSubImage3Dub +glTexSubImage3Dui +glTexSubImage3Dus +glTextureBarrier +glTextureBuffer +glTextureBufferRange +glTextureParameterIiv +glTextureParameterIuiv +glTextureParameterf +glTextureParameterfv +glTextureParameteri +glTextureParameteriv +glTextureStorage1D +glTextureStorage2D +glTextureStorage2DMultisample +glTextureStorage3D +glTextureStorage3DMultisample +glTextureSubImage1D +glTextureSubImage2D +glTextureSubImage3D +glTextureView +glTransformFeedbackBufferBase +glTransformFeedbackBufferRange +glTransformFeedbackVaryings +glTranslate +glTranslated +glTranslatef +glUniform1d +glUniform1dv +glUniform1f +glUniform1fv +glUniform1i +glUniform1iv +glUniform1ui +glUniform1uiv +glUniform2d +glUniform2dv +glUniform2f +glUniform2fv +glUniform2i +glUniform2iv +glUniform2ui +glUniform2uiv +glUniform3d +glUniform3dv +glUniform3f +glUniform3fv +glUniform3i +glUniform3iv +glUniform3ui +glUniform3uiv +glUniform4d +glUniform4dv +glUniform4f +glUniform4fv +glUniform4i +glUniform4iv +glUniform4ui +glUniform4uiv +glUniformBlockBinding +glUniformMatrix2dv +glUniformMatrix2fv +glUniformMatrix2x3dv +glUniformMatrix2x3fv +glUniformMatrix2x4dv +glUniformMatrix2x4fv +glUniformMatrix3dv +glUniformMatrix3fv +glUniformMatrix3x2dv +glUniformMatrix3x2fv +glUniformMatrix3x4dv +glUniformMatrix3x4fv +glUniformMatrix4dv +glUniformMatrix4fv +glUniformMatrix4x2dv +glUniformMatrix4x2fv +glUniformMatrix4x3dv +glUniformMatrix4x3fv +glUniformSubroutinesuiv +glUnmapBuffer +glUnmapNamedBuffer +glUseProgram +glUseProgramStages +glValidateProgram +glValidateProgramPipeline +glVertex +glVertex2d +glVertex2dv +glVertex2f +glVertex2fv +glVertex2i +glVertex2iv +glVertex2s +glVertex2sv +glVertex3d +glVertex3dv +glVertex3f +glVertex3fv +glVertex3i +glVertex3iv +glVertex3s +glVertex3sv +glVertex4d +glVertex4dv +glVertex4f +glVertex4fv +glVertex4i +glVertex4iv +glVertex4s +glVertex4sv +glVertexArrayAttribBinding +glVertexArrayAttribFormat +glVertexArrayAttribIFormat +glVertexArrayAttribLFormat +glVertexArrayBindingDivisor +glVertexArrayElementBuffer +glVertexArrayVertexBuffer +glVertexArrayVertexBuffers +glVertexAttrib1d +glVertexAttrib1dv +glVertexAttrib1f +glVertexAttrib1fv +glVertexAttrib1s +glVertexAttrib1sv +glVertexAttrib2d +glVertexAttrib2dv +glVertexAttrib2f +glVertexAttrib2fv +glVertexAttrib2s +glVertexAttrib2sv +glVertexAttrib3d +glVertexAttrib3dv +glVertexAttrib3f +glVertexAttrib3fv +glVertexAttrib3s +glVertexAttrib3sv +glVertexAttrib4Nbv +glVertexAttrib4Niv +glVertexAttrib4Nsv +glVertexAttrib4Nub +glVertexAttrib4Nubv +glVertexAttrib4Nuiv +glVertexAttrib4Nusv +glVertexAttrib4bv +glVertexAttrib4d +glVertexAttrib4dv +glVertexAttrib4f +glVertexAttrib4fv +glVertexAttrib4iv +glVertexAttrib4s +glVertexAttrib4sv +glVertexAttrib4ubv +glVertexAttrib4uiv +glVertexAttrib4usv +glVertexAttribBinding +glVertexAttribDivisor +glVertexAttribFormat +glVertexAttribI1i +glVertexAttribI1iv +glVertexAttribI1ui +glVertexAttribI1uiv +glVertexAttribI2i +glVertexAttribI2iv +glVertexAttribI2ui +glVertexAttribI2uiv +glVertexAttribI3i +glVertexAttribI3iv +glVertexAttribI3ui +glVertexAttribI3uiv +glVertexAttribI4bv +glVertexAttribI4i +glVertexAttribI4iv +glVertexAttribI4sv +glVertexAttribI4ubv +glVertexAttribI4ui +glVertexAttribI4uiv +glVertexAttribI4usv +glVertexAttribIFormat +glVertexAttribIPointer +glVertexAttribL1d +glVertexAttribL1dv +glVertexAttribL2d +glVertexAttribL2dv +glVertexAttribL3d +glVertexAttribL3dv +glVertexAttribL4d +glVertexAttribL4dv +glVertexAttribLFormat +glVertexAttribLPointer +glVertexAttribP1ui +glVertexAttribP1uiv +glVertexAttribP2ui +glVertexAttribP2uiv +glVertexAttribP3ui +glVertexAttribP3uiv +glVertexAttribP4ui +glVertexAttribP4uiv +glVertexAttribPointer +glVertexBindingDivisor +glVertexP2ui +glVertexP2uiv +glVertexP3ui +glVertexP3uiv +glVertexP4ui +glVertexP4uiv +glVertexPointer +glVertexPointerb +glVertexPointerd +glVertexPointerf +glVertexPointeri +glVertexPointers +glViewport +glViewportArrayv +glViewportIndexedf +glViewportIndexedfv +glWaitSync +glWindowPos2d +glWindowPos2dv +glWindowPos2f +glWindowPos2fv +glWindowPos2i +glWindowPos2iv +glWindowPos2s +glWindowPos2sv +glWindowPos3d +glWindowPos3dv +glWindowPos3f +glWindowPos3fv +glWindowPos3i +glWindowPos3iv +glWindowPos3s +glWindowPos3sv +glget +gradient +graphicsItems +headLen +headWidth +height +helper +hsvColor +hues +hypot +icons +ignore +image +imageToArray +images +imageview +imaging +imgData +importlib +indent +index +inspect +int32 +int64 +intColor +integer +interact +interactive +internals +interpolateArray +interweaveArrays +invertQTransform +invisibleEye +isQObjectAlive +isSequence +isfinite +isinf +isnan +isocurve +isosurface +itemCls +itertools +kargs +kwargs +kwds +leftovers +length +level +levels +libOrder +lightness +list +listMaps +listObjs +listQThreads +listRedundantModules +listdir +lists +loadUiType +lock +log10 +long +lookup +make +makeARGB +makeArrowPath +makeCrosshair +makeHslCycle +makeMSStepper +makeMStepper +makeMonochrome +makeQImage +makeRGBA +makeSStepper +makeYStepper +maskNans +math +maxHue +maxLen +maxValue +maybe +menu +metaarray +method +metric +minHue +minVal +minValue +mkBrush +mkColor +mkPen +mkQApp +mmap +mnemonic +modulatedBarData +module +mouse +multiprocess +multiprocessing +mutex +name +nameFilter +names +ndarray +nelems +newMode +nodes +numba +numeric +numpy +objString +objectSize +objects +offset +open +operator +opts +order +orig +origin +output +outputType +override +painter +palette +parallelizer +parameter +parameterCls +parameterTypes +parametertree +parent +path +pathlib +perf +pickle +platform +plot +plotConfigTemplate +plots +pname +pointers +points +points1 +points2 +polyline +popupFilePicker +port +ppid +precision +prefix +preset +pretty +print +printExc +printException +printTrace +processId +processes +profile +progress +proxy +proxyId +pseudoScatter +ptree +pydoc +pyqt +pyqtBoundSignal +pyqtClassInfo +pyqtEnum +pyqtPickleProtocol +pyqtProperty +pyqtRemoveInputHook +pyqtRestoreInputHook +pyqtSetPickleProtocol +pyqtSignal +pyqtSlot +pyqtgraph +qAbs +qAddPostRoutine +qAddPreRoutine +qAlpha +qBlue +qChecksum +qCompress +qCritical +qDebug +qDrawBorderPixmap +qDrawPlainRect +qDrawPlainRoundedRect +qDrawShadeLine +qDrawShadePanel +qDrawShadeRect +qDrawWinButton +qDrawWinPanel +qEnvironmentVariable +qEnvironmentVariableIntValue +qEnvironmentVariableIsEmpty +qEnvironmentVariableIsSet +qFatal +qFloatDistance +qFormatLogMessage +qFuzzyCompare +qFuzzyIsNull +qGray +qGreen +qInf +qInfo +qInstallMessageHandler +qIsFinite +qIsInf +qIsNaN +qObjectReport +qPixelFormatAlpha +qPixelFormatCmyk +qPixelFormatGrayscale +qPixelFormatHsl +qPixelFormatHsv +qPixelFormatRgba +qPixelFormatYuv +qPremultiply +qQNaN +qRed +qRegisterResourceData +qRemovePostRoutine +qRgb +qRgba +qRgba64 +qRound +qRound64 +qSNaN +qSetFieldWidth +qSetMessagePattern +qSetPadChar +qSetRealNumberPrecision +qUncompress +qUnpremultiply +qUnregisterResourceData +qVersion +qWarning +qYieldCpu +qabort +qcol +qimage +qimg +qpainterpath +qpath +qpolygonf +qtenum +rectStr +recursive +reduce +refPathString +regex +registerParameterItemType +registerParameterType +relativeTo +reload +reloadAll +remoteproxy +renamePyc +renderSymbol +rescaleData +reset +resources +restart +returnCoords +safeStr +saturation +scalar +scale +searchRefs +seen +selectFile +sequence +serialize +setConfigOption +setConfigOptions +setPalette +shape +show +shuffle +siApply +siEval +siFormat +siParse +siScale +sigma +signal +siprefix +size +sizeof +skip +skipCache +sliceGenerator +slider +slot +smooth +solve3DTransform +solveBilinearTransform +sort +sorted +source +space +spacing +sqrt +stack +startDir +startEventLoop +startObj +startQtEventLoop +stderr +stepSize +steps +stream +stride +string +struct +style +subArray +subprocess +suffix +symbol +systemInfo +tailLen +tailWidth +target +tempfile +template +text +threadId +threadName +threading +time +timedelta +timestamp +timezone +tipAngle +toposort +traceImage +traceback +transformCoordinates +transformToArray +translate +transparentLocations +transpose +type +typeStr +types +uifile +unicode +units +unpickleObjectProxy +unwrapinstance +updateClass +updateFunction +useOpenGL +useRGBA +userList +utcfromtimestamp +util +value +values +vboimplementation +vectors +verbose +version +versionReq +visited +vmax +vmin +void +voidptr +walkQObjectTree +warn +warnOnException +warnings +weakref +widgets +width +win32 +windll +windowTitle +winset +winterm +wrapinstance +wrapper +xvals diff --git a/doc/source/dictionaries/sphinx.ext.autodoc.dic b/doc/source/dictionaries/sphinx.ext.autodoc.dic new file mode 100644 index 0000000000..545dd4d450 --- /dev/null +++ b/doc/source/dictionaries/sphinx.ext.autodoc.dic @@ -0,0 +1,140 @@ +ATTR +Attribute +AttributeDocumenter +CHECKING +Callable +ClassDocumenter +ClassLevelDocumenter +ClassVar +Config +DataDocumenter +DataDocumenterMixinBase +DecoratorDocumenter +DocstringSignatureMixin +DocstringStripSignatureMixin +Documenter +EMPTY +ENUM +Enum +ExceptionDocumenter +ExtensionMetadata +FunctionDocumenter +GenericAliasMixin +INSTANCEATTR +MethodDescriptorType +MethodDocumenter +ModuleAnalyzer +ModuleDocumenter +ModuleLevelDocumenter +NamedTuple +NonDataDescriptorMixin +ObjectMember +OptionSpec +Options +Parameter +PropertyDocumenter +PycodeError +RemovedInSphinx80Warning +RuntimeInstanceAttributeMixin +SLOTSATTR +SUPPRESS +Signature +SlotsMixin +StringList +TYPE +TypeVar +UNINITIALIZED +UninitializedGlobalVariableMixin +UninitializedInstanceAttributeMixin +allow +analyzer +annotation +annotations +attrgetter +autodoc +between +bool +class +contextlib +defargs +description +docstring +docstrings +evaluate +exclude +fields +from +functools +getannotations +getattr +getdoc +getmro +getslots +globalns +hints +identity +import +importer +importlib +inherit +inherited +inspect +isclass +isenumclass +ismock +keepempty +kwargs +lines +localns +logger +logging +mangle +marker +member +members +merge +metadata +mock +mode +modname +modnames +module +name +object +objpath +objtype +operator +option +options +order +post +prepare +restify +return +safe +seen +separate +setup +show +signature +special +sphinx +sphinx.ext.autodoc +stop +stringify +subject +tabsize +traceback +type +typehints +typename +typing +undecorate +unmangle +unqualified +unwrap +warningiserror +warnings +what + +autoclass \ No newline at end of file diff --git a/doc/source/getting_started/plotting.rst b/doc/source/getting_started/plotting.rst index 4e1ca89aa1..722d007de0 100644 --- a/doc/source/getting_started/plotting.rst +++ b/doc/source/getting_started/plotting.rst @@ -28,7 +28,7 @@ All of the above functions also return handles to the objects that are created, Organization of Plotting Classes -------------------------------- -There are several classes invloved in displaying plot data. Most of these classes are instantiated automatically, but it is useful to understand how they are organized and relate to each other. PyQtGraph is based heavily on Qt's GraphicsView framework--if you are not already familiar with this, it's worth reading about (but not essential). Most importantly: 1) Qt GUIs are composed of QWidgets, 2) A special widget called QGraphicsView is used for displaying complex graphics, and 3) QGraphicsItems define the objects that are displayed within a QGraphicsView. +There are several classes involved in displaying plot data. Most of these classes are instantiated automatically, but it is useful to understand how they are organized and relate to each other. PyQtGraph is based heavily on Qt's GraphicsView framework--if you are not already familiar with this, it's worth reading about (but not essential). Most importantly: 1) Qt GUIs are composed of QWidgets, 2) A special widget called QGraphicsView is used for displaying complex graphics, and 3) QGraphicsItems define the objects that are displayed within a QGraphicsView. * Data Classes (all subclasses of QGraphicsItem) * :class:`PlotCurveItem ` - Displays a plot line given x,y data diff --git a/doc/source/images/example_imageitem_transform.png b/doc/source/images/example_imageitem_transform.png index 648df2c2ae..da00eff59b 100644 Binary files a/doc/source/images/example_imageitem_transform.png and b/doc/source/images/example_imageitem_transform.png differ diff --git a/doc/source/images/gen_example_imageitem_transform.py b/doc/source/images/gen_example_imageitem_transform.py index 6ca17c6f57..7f51be5d15 100644 --- a/doc/source/images/gen_example_imageitem_transform.py +++ b/doc/source/images/gen_example_imageitem_transform.py @@ -6,21 +6,33 @@ import pyqtgraph.exporters as exp from pyqtgraph.Qt import QtGui, mkQApp +mkQApp("ImageItem transform example") + class MainWindow(pg.GraphicsLayoutWidget): """ example application main window """ def __init__(self): super().__init__() - self.resize(420,400) + self.resize(440,400) self.show() plot = self.addPlot() - # Example: Transformed display of ImageItem + # Set To Larger Font + leftAxis = plot.getAxis('left') + bottomAxis = plot.getAxis('bottom') + font = QtGui.QFont("Roboto", 18) + leftAxis.setTickFont(font) + bottomAxis.setTickFont(font) + + # 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 = pg.ImageItem( + image=np.eye(3), + levels=(0,1) + ) # create example image img.setTransform(tr) # assign transform plot.addItem( img ) # add ImageItem to PlotItem @@ -32,14 +44,11 @@ def __init__(self): self.timer.start(100) def export(self): - print('exporting') exporter = exp.ImageExporter(self.scene()) - exporter.parameters()['width'] = 420 + exporter.parameters()['width'] = 440 exporter.export('example_imageitem_transform.png') -mkQApp("ImageItem transform example") main_window = MainWindow() -## Start Qt event loop if __name__ == '__main__': pg.exec() diff --git a/pyproject.toml b/pyproject.toml index 74da3282d6..94e093a52d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,11 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + + [tool.black] line-length = 88 -target-version = ['py38'] +target-version = ['py310'] include = '\.pyi?$' exclude = ''' @@ -25,7 +30,7 @@ exclude = ''' profile = "black" honor_noqa = true color_output = true -py_version = 38 +py_version = 310 src_paths = ["pyqtgraph", "tests"] skip_glob = ["**/*Template*.py", "**/colorama"] skip_gitignore = true @@ -34,3 +39,30 @@ known_third_party = ["QtCore", "QtGui", "QtWidgets"] [tool.pycln] all = true exclude = '(Template|__init__.py)' + +[tool.mypy] +packages = ["pyqtgraph"] +show_error_codes = true +strict = true +disable_error_code = ["attr-defined"] +ignore_errors = true + +[[tool.mypy.overrides]] +module = "pyqtgraph.flowchart.*" # the list will increase +ignore_errors = true # will be changed to `false` when it's ready + +[tool.numpydoc_validation] +checks = [ + 'all', # report on all checks, except the below + 'EX01', # allow absence of "Examples" section + 'SA01', # allow absence of "See Also" section + 'GL08', # allow absence of docstring + 'ES01', # allow absence of Extended Summary +] +# remember to use single quotes for regex in TOML +exclude = [ # don't report on objects that match any of these regex +] + +override_GL06 = [ + 'Signals' # allow sections to start with "Signals" +] diff --git a/pyqtgraph/GraphicsScene/GraphicsScene.py b/pyqtgraph/GraphicsScene/GraphicsScene.py index e3344b5d18..e28ad8fb09 100644 --- a/pyqtgraph/GraphicsScene/GraphicsScene.py +++ b/pyqtgraph/GraphicsScene/GraphicsScene.py @@ -84,7 +84,7 @@ class GraphicsScene(QtWidgets.QGraphicsScene): ExportDirectory = None - def __init__(self, clickRadius=2, moveDistance=5, parent=None): + def __init__(self, clickRadius: int = 2, moveDistance=5, parent=None): QtWidgets.QGraphicsScene.__init__(self, parent) self.setClickRadius(clickRadius) self.setMoveDistance(moveDistance) @@ -117,14 +117,14 @@ def prepareForPaint(self): self.sigPrepareForPaint.emit() - def setClickRadius(self, r): + def setClickRadius(self, r: int): """ Set the distance away from mouse clicks to search for interacting items. When clicking, the scene searches first for items that directly intersect the click position followed by any other items that are within a rectangle that extends r pixels away from the click position. """ - self._clickRadius = r + self._clickRadius = int(r) def setMoveDistance(self, d): """ @@ -432,7 +432,7 @@ def absZValue(item): r = self._clickRadius items_within_radius = [] rgn = None - if r > 0.0: + if r > 0: rect = view.mapToScene(QtCore.QRect(0, 0, 2 * r, 2 * r)).boundingRect() w = rect.width() h = rect.height() diff --git a/pyqtgraph/GraphicsScene/exportDialog.py b/pyqtgraph/GraphicsScene/exportDialog.py index c39a6d760b..e7daf64855 100644 --- a/pyqtgraph/GraphicsScene/exportDialog.py +++ b/pyqtgraph/GraphicsScene/exportDialog.py @@ -51,10 +51,10 @@ def show(self, item=None): self.selectBox.setVisible(True) if not self.shown: self.shown = True - vcenter = self.scene.getViewWidget().geometry().center() - x = max(0, int(vcenter.x() - self.width() / 2)) - y = max(0, int(vcenter.y() - self.height() / 2)) - self.move(x, y) + center = self.screen().availableGeometry().center() + frame = self.frameGeometry() + frame.moveCenter(center) + self.move(frame.topLeft()) def updateItemList(self, select=None): self.ui.itemTree.clear() diff --git a/pyqtgraph/Qt/QtCore/__init__.pyi b/pyqtgraph/Qt/QtCore/__init__.pyi new file mode 100644 index 0000000000..ba2a2811b9 --- /dev/null +++ b/pyqtgraph/Qt/QtCore/__init__.pyi @@ -0,0 +1,6 @@ +# Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py +from PySide2.QtCore import * +from PyQt5.QtCore import * +from PySide6.QtCore import * +from PyQt6.QtCore import * +Signal = pyqtSignal diff --git a/pyqtgraph/Qt/QtGui/__init__.pyi b/pyqtgraph/Qt/QtGui/__init__.pyi new file mode 100644 index 0000000000..b275c89a4e --- /dev/null +++ b/pyqtgraph/Qt/QtGui/__init__.pyi @@ -0,0 +1,5 @@ +# Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py +from PySide2.QtGui import * +from PyQt5.QtGui import * +from PySide6.QtGui import * +from PyQt6.QtGui import * diff --git a/pyqtgraph/Qt/QtSvg.pyi b/pyqtgraph/Qt/QtSvg.pyi new file mode 100644 index 0000000000..73b917f3b2 --- /dev/null +++ b/pyqtgraph/Qt/QtSvg.pyi @@ -0,0 +1,5 @@ +# Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py +from PySide2.QtSvg import * +from PyQt5.QtSvg import * +from PySide6.QtSvg import * +from PyQt6.QtSvg import * diff --git a/pyqtgraph/Qt/QtTest.pyi b/pyqtgraph/Qt/QtTest.pyi new file mode 100644 index 0000000000..2843099e9b --- /dev/null +++ b/pyqtgraph/Qt/QtTest.pyi @@ -0,0 +1,5 @@ +# Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py +from PySide2.QtTest import * +from PyQt5.QtTest import * +from PySide6.QtTest import * +from PyQt6.QtTest import * diff --git a/pyqtgraph/Qt/QtWidgets/__init__.pyi b/pyqtgraph/Qt/QtWidgets/__init__.pyi new file mode 100644 index 0000000000..4c309454d8 --- /dev/null +++ b/pyqtgraph/Qt/QtWidgets/__init__.pyi @@ -0,0 +1,5 @@ +# Import packages in reverse libOrder as defined in pyqtgraph/Qt/__init__.py +from PySide2.QtWidgets import * +from PyQt5.QtWidgets import * +from PySide6.QtWidgets import * +from PyQt6.QtWidgets import * diff --git a/pyqtgraph/Qt/__init__.py b/pyqtgraph/Qt/__init__.py index ebc60d969f..5efb56123c 100644 --- a/pyqtgraph/Qt/__init__.py +++ b/pyqtgraph/Qt/__init__.py @@ -5,12 +5,15 @@ * Allow you to import QtCore/QtGui from pyqtgraph.Qt without specifying which Qt wrapper you want to use. """ +import contextlib import os +import platform import re import subprocess import sys import time import warnings +from importlib import resources PYSIDE = 'PySide' PYSIDE2 = 'PySide2' @@ -51,7 +54,7 @@ pass if QT_LIB is None: - raise Exception("PyQtGraph requires one of PyQt5, PyQt6, PySide2 or PySide6; none of these packages could be imported.") + raise ImportError("PyQtGraph requires one of PyQt5, PyQt6, PySide2 or PySide6; none of these packages could be imported.") class FailedImport(object): @@ -353,14 +356,11 @@ def mkQApp(name=None): """ global QAPP - def onPaletteChange(palette): - color = palette.base().color() - app = QtWidgets.QApplication.instance() - darkMode = color.lightnessF() < 0.5 - app.setProperty('darkMode', darkMode) - QAPP = QtWidgets.QApplication.instance() if QAPP is None: + # We do not have an already instantiated QApplication + # let's add some sane defaults + # hidpi handling qtVersionCompare = tuple(map(int, QtVersion.split("."))) if qtVersionCompare > (6, 0): @@ -368,20 +368,97 @@ def onPaletteChange(palette): pass elif qtVersionCompare > (5, 14): os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" - QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy(QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough) + QtWidgets.QApplication.setHighDpiScaleFactorRoundingPolicy( + QtCore.Qt.HighDpiScaleFactorRoundingPolicy.PassThrough + ) else: # qt 5.12 and 5.13 QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling) QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps) QAPP = QtWidgets.QApplication(sys.argv or ["pyqtgraph"]) - QAPP.paletteChanged.connect(onPaletteChange) - QAPP.paletteChanged.emit(QAPP.palette()) + if QtVersion.startswith("6"): + # issues with dark mode + windows + qt5 + QAPP.setStyle("fusion") + + # set the application icon + # python 3.9 won't take "pyqtgraph.icons.peegee" directly + traverse_path = resources.files("pyqtgraph.icons") + peegee_traverse_path = traverse_path.joinpath("peegee") + + # as_file requires I feed in a file from the directory... + with resources.as_file( + peegee_traverse_path.joinpath("peegee.svg") + ) as path: + # need the parent directory, not the filepath + icon_path = path.parent + + applicationIcon = QtGui.QIcon() + applicationIcon.addFile( + os.fsdecode(icon_path / "peegee.svg"), + ) + for sz in [128, 256, 512]: + pathname = os.fsdecode(icon_path / f"peegee_{sz}px.png") + applicationIcon.addFile(pathname, QtCore.QSize(sz, sz)) + + # handles the icon showing up on the windows taskbar + if platform.system() == 'Windows': + import ctypes + my_app_id = "pyqtgraph.Qt.mkQApp" + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(my_app_id) + QAPP.setWindowIcon(applicationIcon) + + # determine if dark mode + try: + # this only works in Qt 6.5+ + darkMode = QAPP.styleHints().colorScheme() == QtCore.Qt.ColorScheme.Dark + with contextlib.suppress(TypeError): + # some qt bindings raise a TypeError when using a UniqueConnection + # to an already connected signal/slot + QAPP.styleHints().colorSchemeChanged.connect( + _onColorSchemeChange, + type=QtCore.Qt.ConnectionType.UniqueConnection + ) + except AttributeError: + palette = QAPP.palette() + windowTextLightness = palette.color(QtGui.QPalette.ColorRole.WindowText).lightness() + windowLightness = palette.color(QtGui.QPalette.ColorRole.Window).lightness() + darkMode = windowTextLightness > windowLightness + with contextlib.suppress(TypeError): + # some qt bindings raise a TypeError when using a UniqueConnection + # to an already connected signal/slot + QAPP.paletteChanged.connect( + _onPaletteChange, + type=QtCore.Qt.ConnectionType.UniqueConnection + ) + QAPP.setProperty("darkMode", darkMode) if name is not None: QAPP.setApplicationName(name) return QAPP +def _onPaletteChange(palette): + # Attempt to keep darkMode attribute up to date + # QEvent.Type.PaletteChanged/ApplicationPaletteChanged will be emitted after + # paletteChanged.emit()! + # Using API deprecated in Qt 6.0 + app = mkQApp() + windowTextLightness = palette.color(QtGui.QPalette.ColorRole.WindowText).lightness() + windowLightness = palette.color(QtGui.QPalette.ColorRole.Window).lightness() + darkMode = windowTextLightness > windowLightness + app.setProperty('darkMode', darkMode) + + +def _onColorSchemeChange(colorScheme): + # Attempt to keep darkMode attribute up to date + # QEvent.Type.PaletteChanged/ApplicationPaletteChanged will be emitted before + # QStyleHint().colorSchemeChanged.emit()! + # Uses Qt 6.5+ API + app = mkQApp() + darkMode = colorScheme == QtCore.Qt.ColorScheme.Dark + app.setProperty('darkMode', darkMode) + + # exec() is used within _loadUiType, so we define as exec_() here and rename in pg namespace def exec_(): app = mkQApp() diff --git a/pyqtgraph/Qt/__init__.pyi b/pyqtgraph/Qt/__init__.pyi index fa67a0839a..33caecddea 100644 --- a/pyqtgraph/Qt/__init__.pyi +++ b/pyqtgraph/Qt/__init__.pyi @@ -1,44 +1,18 @@ """ -This stub file is to aid in the PyCharm auto-completion of the Qt imports. +This stub file is to aid in the PyCharm and VSCode auto-completion of the Qt imports. """ -from typing import Union - -try: - from PyQt5 import QtCore, QtGui, QtWidgets - - QtCore = QtCore - QtGui = QtGui - QtWidgets = QtWidgets -except ImportError: - try: - from PyQt6 import QtCore, QtGui, QtWidgets - - QtCore = QtCore - QtGui = QtGui - QtWidgets = QtWidgets - except ImportError: - try: - from PySide2 import QtCore, QtGui, QtWidgets - - QtCore = QtCore - QtGui = QtGui - QtWidgets = QtWidgets - except ImportError: - try: - from PySide6 import QtCore, QtGui, QtWidgets - - QtCore = QtCore - QtGui = QtGui - QtWidgets = QtWidgets - except ImportError as e: - raise ImportError("No suitable qt binding found") from e - +from . import QtCore as QtCore +from . import QtGui as QtGui +from . import QtSvg as QtSvg +from . import QtTest as QtTest +from . import QtWidgets as QtWidgets App: QtWidgets.QApplication VERSION_INFO: str QT_LIB: str QtVersion: str + def exec_() -> QtWidgets.QApplication: ... -def mkQApp(name: Union[str, None] = None) -> QtWidgets.QApplication: ... +def mkQApp(name: str | None = None) -> QtWidgets.QApplication: ... def isQObjectAlive(obj: QtCore.QObject) -> bool: ... diff --git a/pyqtgraph/SRTTransform.py b/pyqtgraph/SRTTransform.py index 3d0aac7ea2..cd6c5e5cb3 100644 --- a/pyqtgraph/SRTTransform.py +++ b/pyqtgraph/SRTTransform.py @@ -2,9 +2,9 @@ import numpy as np +from . import SRTTransform3D from .Point import Point from .Qt import QtGui -from . import SRTTransform3D class SRTTransform(QtGui.QTransform): @@ -33,7 +33,6 @@ def __init__(self, init=None): else: raise Exception("Cannot create SRTTransform from input type: %s" % str(type(init))) - def getScale(self): return self._state['scale'] @@ -142,10 +141,11 @@ def __mul__(self, t): def saveState(self): p = self._state['pos'] s = self._state['scale'] - #if s[0] == 0: - #raise Exception('Invalid scale: %s' % str(s)) return {'pos': (p[0], p[1]), 'scale': (s[0], s[1]), 'angle': self._state['angle']} + def __reduce__(self): + return SRTTransform, (self.saveState(),) + def restoreState(self, state): self._state['pos'] = Point(state.get('pos', (0,0))) self._state['scale'] = Point(state.get('scale', (1.,1.))) diff --git a/pyqtgraph/SRTTransform3D.py b/pyqtgraph/SRTTransform3D.py index 59dd78429c..a1c820feba 100644 --- a/pyqtgraph/SRTTransform3D.py +++ b/pyqtgraph/SRTTransform3D.py @@ -2,10 +2,10 @@ import numpy as np +from . import SRTTransform from .Qt import QtGui from .Transform3D import Transform3D from .Vector import Vector -from . import SRTTransform class SRTTransform3D(Transform3D): @@ -225,3 +225,6 @@ def matrix(self, nd=3): return m[:3,:3] else: raise Exception("Argument 'nd' must be 2 or 3") + + def __reduce__(self): + return SRTTransform3D, (self.saveState(),) diff --git a/pyqtgraph/__init__.py b/pyqtgraph/__init__.py index 436fbffc5d..51d96a7284 100644 --- a/pyqtgraph/__init__.py +++ b/pyqtgraph/__init__.py @@ -3,7 +3,7 @@ www.pyqtgraph.org """ -__version__ = '0.13.4.dev0.qps' +__version__ = '0.13.8dev0.qps' ### import all the goodies and add some helper functions for easy CLI use @@ -260,6 +260,7 @@ def renamePyc(startDir): from .widgets.BusyCursor import * from .widgets.CheckTable import * from .widgets.ColorButton import * +from .widgets.ColorMapMenu import ColorMapMenu from .widgets.ColorMapWidget import * from .widgets.ComboBox import * from .widgets.DataFilterWidget import * @@ -462,5 +463,4 @@ def setPalette(app, style): p = style else: raise TypeError('style either be a string or QPalette') - app.paletteChanged.emit(p) app.setPalette(p) diff --git a/pyqtgraph/canvas/CanvasManager.py b/pyqtgraph/canvas/CanvasManager.py index bfcc7b83f9..f2f784b326 100644 --- a/pyqtgraph/canvas/CanvasManager.py +++ b/pyqtgraph/canvas/CanvasManager.py @@ -13,8 +13,9 @@ class CanvasManager(QtCore.QObject): def __init__(self): if CanvasManager.SINGLETON is not None: raise Exception("Can only create one canvas manager.") - CanvasManager.SINGLETON = self + # It is important to save SINGLETON *after* the call to QObject.__init__, see #2838. QtCore.QObject.__init__(self) + CanvasManager.SINGLETON = self self.canvases = weakref.WeakValueDictionary() @classmethod diff --git a/pyqtgraph/colormap.py b/pyqtgraph/colormap.py index 5a2b8106b8..dfb29822a3 100644 --- a/pyqtgraph/colormap.py +++ b/pyqtgraph/colormap.py @@ -226,7 +226,7 @@ def makeHslCycle( hue=0.0, saturation=1.0, lightness=0.5, steps=36 ): lightness : float or tuple of floats, optional Lightness value for the colors in the cycle, in the range of [0 to 1]. If a (start, end) tuple is given, lightness gradually changes between these values. - The default lightness is 1.0. + The default lightness is 0.5. steps: int, optional Number of steps in the cycle. Between these steps, the color map will interpolate in RGB space. The default number of steps is 36, generating a color map with 37 stops. diff --git a/pyqtgraph/dockarea/Dock.py b/pyqtgraph/dockarea/Dock.py index 99449e1b71..26e43b26ae 100644 --- a/pyqtgraph/dockarea/Dock.py +++ b/pyqtgraph/dockarea/Dock.py @@ -210,7 +210,7 @@ def container(self): def containerChanged(self, c): if self._container is not None: # ask old container to close itself if it is no longer needed - self._container.apoptose() + self._container.apoptose(propagate=False) self._container = c if c is None: self.area = None diff --git a/pyqtgraph/examples/AxisItem_label_overlap.py b/pyqtgraph/examples/AxisItem_label_overlap.py new file mode 100644 index 0000000000..97f51c0b81 --- /dev/null +++ b/pyqtgraph/examples/AxisItem_label_overlap.py @@ -0,0 +1,74 @@ +""" +This example demonstrates many of the 2D plotting capabilities +in pyqtgraph. All of the plots may be panned/scaled by dragging with +the left/right mouse buttons. Right click on any plot to show a context menu. +""" + +import numpy as np + +import pyqtgraph as pg +from pyqtgraph.Qt import QtGui + +app = pg.mkQApp("AxisItem - label overlap settings") + +win = pg.GraphicsLayoutWidget(show=True, title="AxisItem - label overlap settings") +win.resize(800,600) +win.setWindowTitle("AxisItem - label overlap settings") + +# Enable antialiasing for prettier plots +pg.setConfigOptions(antialias=True) + +x_data = np.arange(101) + 1_000. +y_data = np.random.normal(scale=40., size=101) + +font = QtGui.QFont() +font.setPointSize(14) # A larger font makes the effects more visible + +p1 = win.addPlot(title="Default settings: Overlap allowed for y axis", x=x_data, y=y_data) +for axis_key in ('top', 'bottom', 'left', 'right'): + ax = p1.getAxis(axis_key) + ax.setTickFont( font ) + +p2 = win.addPlot(title="Overlap allowed for X axis", x=x_data, y=y_data) +for axis_key, hide_overlap in ( + ('top' , False), + ('bottom', False), + ('left' , True ), + ('right' , True ) +): + ax = p2.getAxis(axis_key) + ax.setStyle( hideOverlappingLabels = hide_overlap ) + ax.setTickFont( font ) + +win.nextRow() + +p3 = win.addPlot(title="All overlap disabled", x=x_data, y=y_data) +for axis_key in ('top', 'bottom', 'left', 'right'): + ax = p3.getAxis(axis_key) + ax.setStyle( hideOverlappingLabels = True ) + ax.setTickFont( font ) + +p4 = win.addPlot(title="All overlap enabled, custom tolerances", x=x_data, y=y_data) +for axis_key, tolerance in ( + ('top' , 15 ), + ('bottom', 200 ), + ('left' , 100 ), + ('right' , 15 ) +): + ax = p4.getAxis(axis_key) + ax.setStyle( hideOverlappingLabels = tolerance ) + ax.setTickFont( font ) + +# Link all axes and set viewing range with no padding: +for p in (p1, p2, p3, p4): + p.showAxes(True, showValues=(True, True, True, True)) + if p != p1: + p.setXLink(p1) + p.setYLink(p1) + ax.setTickFont( font ) +p1.setXRange( 1_000., 1_100., padding=0.0) +p1.setYRange(-60., 60., padding=0.0) + + +if __name__ == '__main__': + pg.exec() diff --git a/pyqtgraph/examples/ExampleApp.py b/pyqtgraph/examples/ExampleApp.py index 5151eadcbd..53c11ef2ba 100644 --- a/pyqtgraph/examples/ExampleApp.py +++ b/pyqtgraph/examples/ExampleApp.py @@ -7,6 +7,7 @@ from argparse import Namespace from collections import OrderedDict from functools import lru_cache +from typing import Optional import pyqtgraph as pg from pyqtgraph.Qt import QT_LIB, QtCore, QtGui, QtWidgets @@ -34,11 +35,7 @@ def charFormat(color, style='', background=None): """ Return a QTextCharFormat with the given attributes. """ - _color = QColor() - if type(color) is not str: - _color.setRgb(color[0], color[1], color[2]) - else: - _color.setNamedColor(color) + _color = pg.functions.mkColor(color) _format = QTextCharFormat() _format.setForeground(_color) @@ -314,7 +311,6 @@ def __init__(self): self.ui.codeView.setLayout(self.codeLayout) self.hl = PythonHighlighter(self.ui.codeView.document()) app = QtWidgets.QApplication.instance() - app.paletteChanged.connect(self.updateTheme) policy = QtWidgets.QSizePolicy.Policy.Expanding self.codeLayout.addItem(QtWidgets.QSpacerItem(100,100, policy, policy), 0, 0) self.codeLayout.addWidget(self.codeBtn, 1, 1) @@ -361,6 +357,24 @@ def onComboChanged(searchType): self.codeBtn.clicked.connect(self.runEditedCode) self.updateCodeViewTabWidth(self.ui.codeView.font()) + def event(self, event: Optional[QtCore.QEvent]): + if event is None: + return super().event(None) + if event.type() in [ + QtCore.QEvent.Type.ApplicationPaletteChange, + ]: + app = pg.mkQApp() + try: + darkMode = app.styleHints().colorScheme() == QtCore.Qt.ColorScheme.Dark + except AttributeError: + palette = app.palette() + windowTextLightness = palette.color(QtGui.QPalette.ColorRole.WindowText).lightness() + windowLightness = palette.color(QtGui.QPalette.ColorRole.Window).lightness() + darkMode = windowTextLightness > windowLightness + app.setProperty('darkMode', darkMode) + self.hl = PythonHighlighter(self.ui.codeView.document()) + return super().event(event) + def updateCodeViewTabWidth(self,font): """ Change the codeView tabStopDistance to 4 spaces based on the size of the current font @@ -481,9 +495,6 @@ def simulate_black_mode(self): app = QtWidgets.QApplication.instance() app.setProperty('darkMode', True) - def updateTheme(self): - self.hl = PythonHighlighter(self.ui.codeView.document()) - def populateTree(self, root, examples): bold_font = None for key, val in examples.items(): diff --git a/pyqtgraph/examples/FillBetweenItem.py b/pyqtgraph/examples/FillBetweenItem.py index eb1ab40678..f046a709a5 100644 --- a/pyqtgraph/examples/FillBetweenItem.py +++ b/pyqtgraph/examples/FillBetweenItem.py @@ -20,7 +20,8 @@ mn = mx = np.zeros(len(x)) curves = [win.plot(x=x, y=np.zeros(len(x)), pen='k') for i in range(4)] brushes = [0.5, (100, 100, 255), 0.5] -fills = [pg.FillBetweenItem(curves[i], curves[i+1], brushes[i]) for i in range(3)] +fills = [pg.FillBetweenItem(curves[0], curves[3], brushes[0]), + pg.FillBetweenItem(curves[1], curves[2], brushes[1])] for f in fills: win.addItem(f) diff --git a/pyqtgraph/examples/ImageView.py b/pyqtgraph/examples/ImageView.py index f8f4d85c90..0cfdc5452a 100644 --- a/pyqtgraph/examples/ImageView.py +++ b/pyqtgraph/examples/ImageView.py @@ -24,7 +24,7 @@ ## Create window with ImageView widget win = QtWidgets.QMainWindow() win.resize(800,800) -imv = pg.ImageView(discreteTimeLine=True) +imv = pg.ImageView(discreteTimeLine=True, levelMode='rgba') win.setCentralWidget(imv) win.show() win.setWindowTitle('pyqtgraph example: ImageView') @@ -47,18 +47,6 @@ imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0])) imv.play(10) -## Set a custom color map -colors = [ - (0, 0, 0), - (45, 5, 61), - (84, 42, 55), - (150, 87, 60), - (208, 171, 141), - (255, 255, 255) -] -cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors) -imv.setColorMap(cmap) - # Start up with an ROI imv.ui.roiBtn.setChecked(True) imv.roiClicked() diff --git a/pyqtgraph/examples/NonUniformImage.py b/pyqtgraph/examples/NonUniformImage.py index aa62e8127e..200a01502d 100644 --- a/pyqtgraph/examples/NonUniformImage.py +++ b/pyqtgraph/examples/NonUniformImage.py @@ -31,28 +31,31 @@ P_loss = kfric * W + kfric3 * W ** 3 + (res * (TAU / psi) ** 2) + k_v * (V - v_ref) P_mech = TAU * W -P_loss[P_mech > 1.5e5] = np.NaN +P_loss[P_mech > 1.5e5] = np.nan app = pg.mkQApp("NonUniform Image Example") -win = pg.PlotWidget() +win = pg.GraphicsLayoutWidget() win.show() win.resize(600, 400) win.setWindowTitle('pyqtgraph example: Non-uniform Image') -p = win.getPlotItem() -p.setTitle("Power Losses [W]") +p = win.addPlot(title="Power Losses [W]", row=0, col=0) +hist = pg.HistogramLUTItem(orientation="horizontal") p.setMouseEnabled(x=False, y=False) +win.nextRow() +win.addItem(hist) + image = NonUniformImage(w * RADS2RPM, tau, P_loss.T) image.setZValue(-1) p.addItem(image) # green - orange - red cmap = pg.ColorMap([0.0, 0.5, 1.0], [(74, 158, 71), (255, 230, 0), (191, 79, 76)]) -bar = pg.ColorBarItem(colorMap=cmap, orientation='h') -bar.setImageItem(image, insert_in=p) +hist.gradient.setColorMap(cmap) +hist.setImageItem(image) p.showGrid(x=True, y=True) diff --git a/pyqtgraph/examples/SpinBox.py b/pyqtgraph/examples/SpinBox.py index 461a847c9d..f69338f692 100644 --- a/pyqtgraph/examples/SpinBox.py +++ b/pyqtgraph/examples/SpinBox.py @@ -29,11 +29,13 @@ pg.SpinBox(value=1.0, suffix='V', siPrefix=True, dec=True, step=0.5, minStep=0.01)), ("Float with SI-prefixed units,
      dec step=1.0, minStep=0.001", pg.SpinBox(value=1.0, suffix='V', siPrefix=True, dec=True, step=1.0, minStep=0.001)), + ("Float with SI-prefixed units,
      scaleAtZero=1e-6, step=1e-9", + pg.SpinBox(value=0, suffix='V', siPrefix=True, scaleAtZero=1e-6, step=1e-9)), ("Float with SI prefix but no suffix", pg.SpinBox(value=1e9, siPrefix=True)), ("Float with custom formatting", pg.SpinBox(value=23.07, format='${value:0.02f}', - regex='\$?(?P(-?\d+(\.\d+)?)|(-?\.\d+))$')), + regex = r'\$?(?P(-?\d+(\.\d+)?)|(-?\.\d+))$')), ("Int with suffix", pg.SpinBox(value=999, step=1, int=True, suffix="V")), ("Int with custom formatting", diff --git a/pyqtgraph/examples/Symbols.py b/pyqtgraph/examples/Symbols.py index cdbc9cb05d..b491600163 100755 --- a/pyqtgraph/examples/Symbols.py +++ b/pyqtgraph/examples/Symbols.py @@ -30,6 +30,9 @@ plot.plot([12, 13, 14, 15, 16], pen=(189, 189, 189), symbolBrush=(189, 189, 189), symbolPen='w', symbol='arrow_left', symbolSize=22, name="symbol='arrow_left'") plot.plot([13, 14, 15, 16, 17], pen=(187, 26, 95), symbolBrush=(187, 26, 95), symbolPen='w', symbol='arrow_up', symbolSize=22, name="symbol='arrow_up'") plot.plot([14, 15, 16, 17, 18], pen=(248, 187, 208), symbolBrush=(248, 187, 208), symbolPen='w', symbol='arrow_right', symbolSize=22, name="symbol='arrow_right'") +plot.plot([15, 16, 17, 18, 19], pen=(255, 69, 58), symbolBrush=(255, 69, 58), symbolPen='w', symbol='|', symbolSize=14, name="symbol='|'") +plot.plot([16, 17, 18, 19, 20], pen=(94, 92, 230), symbolBrush=(94, 92, 230), symbolPen='w', symbol='_', symbolSize=14, name="symbol='_'") + plot.setXRange(-2, 4) if __name__ == '__main__': diff --git a/pyqtgraph/examples/VideoSpeedTest.py b/pyqtgraph/examples/VideoSpeedTest.py index 949bcede7c..da9d2c8e8c 100644 --- a/pyqtgraph/examples/VideoSpeedTest.py +++ b/pyqtgraph/examples/VideoSpeedTest.py @@ -74,6 +74,7 @@ else: ui.rawGLImg = RawImageGLWidget() ui.stack.addWidget(ui.rawGLImg) + win.destroyed.connect(ui.rawGLImg.cleanup) # read in CLI args ui.cudaCheck.setChecked(args.cuda and _has_cupy) diff --git a/pyqtgraph/examples/_buildParamTypes.py b/pyqtgraph/examples/_buildParamTypes.py index 3744e49a39..40cea4d648 100644 --- a/pyqtgraph/examples/_buildParamTypes.py +++ b/pyqtgraph/examples/_buildParamTypes.py @@ -6,10 +6,12 @@ _encounteredTypes = {'group'} + def makeChild(chType, cfgDict): _encounteredTypes.add(chType) param = Parameter.create(name='widget', type=chType) - param.setDefault(param.value()) + if param.hasValue(): + param.setDefault(param.value()) def setOpt(_param, _val): # Treat blank strings as "None" to allow 'unsetting' that option @@ -26,14 +28,17 @@ def setOpt(_param, _val): else: optsChildren.append(child) child.sigValueChanged.connect(setOpt) - # Poplate initial options + # Populate initial options for p in optsChildren: - setOpt(p, p.value()) + setOpt(p, p.value() if p.hasValue() else None) - grp = Parameter.create(name=f'Sample {chType.title()}', type='group', children=metaChildren + [param] + optsChildren) + grp = Parameter.create( + name=f'Sample {chType.title()}', type='group', children=metaChildren + [param] + optsChildren + ) grp.setOpts(expanded=False) return grp + def makeMetaChild(name, cfgDict): children = [] for chName, chOpts in cfgDict.items(): @@ -47,6 +52,7 @@ def makeMetaChild(name, cfgDict): param.setOpts(expanded=False) return param + def makeAllParamTypes(): children = [] for name, paramCfg in cfg.items(): diff --git a/pyqtgraph/examples/_paramtreecfg.py b/pyqtgraph/examples/_paramtreecfg.py index 161b24a136..89b95dc798 100644 --- a/pyqtgraph/examples/_paramtreecfg.py +++ b/pyqtgraph/examples/_paramtreecfg.py @@ -197,6 +197,7 @@ 'color': '#fff', 'bool': False, 'colormap': None, + 'cmaplut' : 'viridis', 'progress': 50, 'font': 'Inter', } diff --git a/pyqtgraph/examples/optics/pyoptic.py b/pyqtgraph/examples/optics/pyoptic.py index 3694511308..79c6f28ff7 100644 --- a/pyqtgraph/examples/optics/pyoptic.py +++ b/pyqtgraph/examples/optics/pyoptic.py @@ -148,7 +148,7 @@ def __init__(self, gitem, **params): } defaults.update(params) self._ior_cache = {} - self.roi.sigRegionChanged.connect(self.roiChanged) + self._connRoiChanged = self.roi.sigRegionChanged.connect(self.roiChanged) self.setParams(**defaults) def updateTransform(self): @@ -168,14 +168,22 @@ def paramStateChanged(self): # Move ROI to match try: - self.roi.sigRegionChanged.disconnect(self.roiChanged) + # workaround PYSIDE-2487 that affects PySide 6.5.3 by + # disconnecting through a handle + if isinstance(self._connRoiChanged, QtCore.QMetaObject.Connection): + self.roi.sigRegionChanged.disconnect(self._connRoiChanged) + else: + # this branch is for PySide2 5.15 which returns a + # boolean instead of a QMetaObject.Connection + self.roi.sigRegionChanged.disconnect(self.roiChanged) + br = self.gitem.boundingRect() o = self.gitem.mapToParent(br.topLeft()) self.roi.setAngle(self['angle']) self.roi.setPos(o) self.roi.setSize([br.width(), br.height()]) finally: - self.roi.sigRegionChanged.connect(self.roiChanged) + self._connRoiChanged = self.roi.sigRegionChanged.connect(self.roiChanged) self.sigStateChanged.emit() diff --git a/pyqtgraph/examples/parametertree.py b/pyqtgraph/examples/parametertree.py index d613b8d578..c5fa8ee6d4 100644 --- a/pyqtgraph/examples/parametertree.py +++ b/pyqtgraph/examples/parametertree.py @@ -114,7 +114,6 @@ def valueChanging(param, value): for child in p.child('Example Parameters'): if 'widget' in child.names: child.child('widget').sigValueChanging.connect(valueChanging) - def save(): global state diff --git a/pyqtgraph/examples/syntax.py b/pyqtgraph/examples/syntax.py index 66dce6999a..cdc5cb88c3 100644 --- a/pyqtgraph/examples/syntax.py +++ b/pyqtgraph/examples/syntax.py @@ -1,5 +1,6 @@ # based on https://github.com/art1415926535/PyQt5-syntax-highlighting +import pyqtgraph as pg from pyqtgraph.Qt import QtCore, QtGui, QtWidgets QRegExp = QtCore.QRegExp @@ -14,11 +15,7 @@ def format(color, style=''): """ Return a QTextCharFormat with the given attributes. """ - _color = QColor() - if type(color) is not str: - _color.setRgb(color[0], color[1], color[2]) - else: - _color.setNamedColor(color) + _color = pg.functions.mkColor(color) _format = QTextCharFormat() _format.setForeground(_color) diff --git a/pyqtgraph/examples/test_examples.py b/pyqtgraph/examples/test_examples.py index 53bbefdc70..d5f68ba8c7 100644 --- a/pyqtgraph/examples/test_examples.py +++ b/pyqtgraph/examples/test_examples.py @@ -57,12 +57,7 @@ def buildFileList(examples, files=None): frontend for frontend, isPresent in frontends.items() if isPresent ]) -darwin_opengl_broken = (platform.system() == "Darwin" and - tuple(map(int, platform.mac_ver()[0].split("."))) >= (10, 16) and - (sys.version_info < (3, 8, 10) or sys.version_info == (3, 9, 0))) -darwin_opengl_reason = ("pyopenGL cannot find openGL library on big sur: " - "https://github.com/python/cpython/pull/21241") exceptionCondition = namedtuple("exceptionCondition", ["condition", "reason"]) conditionalExamples = { @@ -80,23 +75,8 @@ def buildFileList(examples, files=None): ), } -openglExamples = ['GLViewWidget.py'] -openglExamples.extend(utils.examples_['3D Graphics'].values()) -for key in openglExamples: - conditionalExamples[key] = exceptionCondition( - not darwin_opengl_broken, - reason=darwin_opengl_reason - ) - -@pytest.mark.skipif( - Qt.QT_LIB == "PySide2" - and tuple(map(int, Qt.PySide2.__version__.split("."))) >= (5, 14) - and tuple(map(int, Qt.PySide2.__version__.split("."))) < (5, 14, 2, 2), - reason="new PySide2 doesn't have loadUi functionality" -) -@pytest.mark.parametrize( - "frontend, f", - [ + +@pytest.mark.parametrize("frontend, f", [ pytest.param( frontend, f, @@ -107,9 +87,8 @@ def buildFileList(examples, files=None): ) for frontend, f, in itertools.product(installedFrontends, files) ], - ids = [ - " {} - {} ".format(f[1], frontend) - for frontend, f in itertools.product( + ids=[ + f" {f[1]} - {frontend} " for frontend, f in itertools.product( installedFrontends, files ) @@ -122,7 +101,7 @@ def testExamples(frontend, f): os.chdir(path) sys.stdout.write(f"{name}") sys.stdout.flush() - import1 = "import %s" % frontend if frontend != '' else '' + import1 = f"import {frontend}" if frontend != '' else '' import2 = os.path.splitext(os.path.split(fn)[1])[0] code = """ try: diff --git a/pyqtgraph/examples/utils.py b/pyqtgraph/examples/utils.py index 0ce23ae75c..60711c1f2b 100644 --- a/pyqtgraph/examples/utils.py +++ b/pyqtgraph/examples/utils.py @@ -61,6 +61,7 @@ ('Linked Views', 'linkedViews.py'), ('Arrow', 'Arrow.py'), ('ViewBox', 'ViewBoxFeatures.py'), + ('AxisItem - label overlap', 'AxisItem_label_overlap.py'), ('Custom Graphics', 'customGraphicsItem.py'), ('Labeled Graph', 'CustomGraphItem.py'), ('PColorMeshItem', 'PColorMeshItem.py'), diff --git a/pyqtgraph/exceptionHandling.py b/pyqtgraph/exceptionHandling.py index 28dc53ef63..a94e058481 100644 --- a/pyqtgraph/exceptionHandling.py +++ b/pyqtgraph/exceptionHandling.py @@ -149,6 +149,7 @@ def implements(self, interface=None): ## replace built-in excepthook only if this has not already been done +# TODO this will never return False; the hook is set to the bound sys_excepthook method, not the instance itself if not (hasattr(sys.excepthook, 'implements') and sys.excepthook.implements('ExceptionHandler')): handler = ExceptionHandler() original_excepthook = handler.orig_sys_excepthook diff --git a/pyqtgraph/exporters/CSVExporter.py b/pyqtgraph/exporters/CSVExporter.py index d918b52dd8..ccb0e34499 100644 --- a/pyqtgraph/exporters/CSVExporter.py +++ b/pyqtgraph/exporters/CSVExporter.py @@ -18,14 +18,15 @@ class CSVExporter(Exporter): windows = [] def __init__(self, item): Exporter.__init__(self, item) - self.params = Parameter(name='params', type='group', children=[ + self.params = Parameter.create(name='params', type='group', children=[ {'name': 'separator', 'title': translate("Exporter", 'separator'), 'type': 'list', 'value': 'comma', 'limits': ['comma', 'tab']}, {'name': 'precision', 'title': translate("Exporter", 'precision'), 'type': 'int', 'value': 10, 'limits': [0, None]}, { 'name': 'columnMode', 'title': translate("Exporter", 'columnMode'), 'type': 'list', - 'limits': ['(x,y) per plot', '(x,y,y,y) for all plots'] + 'limits': ['(x,y) per plot', '(x,y,y,y) for all plots'], + 'value': '(x,y) per plot', } ]) diff --git a/pyqtgraph/exporters/HDF5Exporter.py b/pyqtgraph/exporters/HDF5Exporter.py index 17d55d9371..8daf22bdfc 100644 --- a/pyqtgraph/exporters/HDF5Exporter.py +++ b/pyqtgraph/exporters/HDF5Exporter.py @@ -21,10 +21,10 @@ class HDF5Exporter(Exporter): def __init__(self, item): Exporter.__init__(self, item) - self.params = Parameter(name='params', type='group', children=[ + self.params = Parameter.create(name='params', type='group', children=[ {'name': 'Name', 'title': translate("Exporter", 'Name'), 'type': 'str', 'value': 'Export', }, {'name': 'columnMode', 'title': translate("Exporter", 'columnMode'), 'type': 'list', - 'limits': ['(x,y) per plot', '(x,y,y,y) for all plots']}, + 'limits': ['(x,y) per plot', '(x,y,y,y) for all plots'], 'value': '(x,y) per plot'}, ]) def parameters(self): diff --git a/pyqtgraph/exporters/ImageExporter.py b/pyqtgraph/exporters/ImageExporter.py index 78a9134c93..b22532188a 100644 --- a/pyqtgraph/exporters/ImageExporter.py +++ b/pyqtgraph/exporters/ImageExporter.py @@ -26,7 +26,7 @@ def __init__(self, item): if bgbrush.style() == QtCore.Qt.BrushStyle.NoBrush: bg.setAlpha(0) - self.params = Parameter(name='params', type='group', children=[ + self.params = Parameter.create(name='params', type='group', children=[ {'name': 'width', 'title': translate("Exporter", 'width'), 'type': 'int', 'value': int(tr.width()), 'limits': (0, None)}, {'name': 'height', 'title': translate("Exporter", 'height'), 'type': 'int', 'value': int(tr.height()), diff --git a/pyqtgraph/exporters/Matplotlib.py b/pyqtgraph/exporters/Matplotlib.py index d55319501e..83835bf246 100644 --- a/pyqtgraph/exporters/Matplotlib.py +++ b/pyqtgraph/exporters/Matplotlib.py @@ -47,6 +47,8 @@ 'arrow_down' : 7, # caretdown 'arrow_left' : 4, # caretleft 'crosshair' : 'o', # circle + '|' : '|', # vertical line + '_' : '_' # horizontal line } diff --git a/pyqtgraph/exporters/PrintExporter.py b/pyqtgraph/exporters/PrintExporter.py index aa56eeb7b0..763a4b4a81 100644 --- a/pyqtgraph/exporters/PrintExporter.py +++ b/pyqtgraph/exporters/PrintExporter.py @@ -12,7 +12,7 @@ class PrintExporter(Exporter): def __init__(self, item): Exporter.__init__(self, item) tr = self.getTargetRect() - self.params = Parameter(name='params', type='group', children=[ + self.params = Parameter.create(name='params', type='group', children=[ {'name': 'width', 'title': translate("Exporter", 'width'), 'type': 'float', 'value': 0.1, 'limits': (0, None), 'suffix': 'm', 'siPrefix': True}, {'name': 'height', 'title': translate("Exporter", 'height'), 'type': 'float', diff --git a/pyqtgraph/exporters/SVGExporter.py b/pyqtgraph/exporters/SVGExporter.py index 575c228fb3..7f329ac6bf 100644 --- a/pyqtgraph/exporters/SVGExporter.py +++ b/pyqtgraph/exporters/SVGExporter.py @@ -6,7 +6,7 @@ import numpy as np -from .. import PlotCurveItem, ScatterPlotItem, debug +from .. import debug from .. import functions as fn from ..parametertree import Parameter from ..Qt import QtCore, QtGui, QtSvg, QtWidgets @@ -28,7 +28,7 @@ def __init__(self, item): if bgbrush.style() == QtCore.Qt.BrushStyle.NoBrush: bg.setAlpha(0) - self.params = Parameter(name='params', type='group', children=[ + self.params = Parameter.create(name='params', type='group', children=[ {'name': 'background', 'title': translate("Exporter", 'background'), 'type': 'color', 'value': bg}, {'name': 'width', 'title': translate("Exporter", 'width'), 'type': 'float', 'value': tr.width(), 'limits': (0, None)}, @@ -218,35 +218,6 @@ def _generateItemSvg(item, nodes=None, root=None, options=None): else: childs = item.childItems() - dx = dy = 0. - sx = sy = 1. - - if isinstance(item, PlotCurveItem): - # Workaround for lack of precision in SVG numbers - # We shift curves to be centered about (0, 0) and scaled such that - # they fit within the region of float32 values that we can - # distinguish between similar but different values - rect = item.viewRect() - x_range = rect.right() - rect.left() - dx = rect.left() + (x_range / 2) - - y_range = rect.top() - rect.bottom() - dy = rect.bottom() + y_range / 2 - - sx = 1 / abs(x_range) - sy = 1 / abs(y_range) - - item.blockSignals(True) - - xDataOriginal = item.xData - yDataOriginal = item.yData - # use deepcopy of data to not mess with other references... - item.setData( - (xDataOriginal.copy() - dx) * sx, (yDataOriginal.copy() - dy) * sy - ) - item.blockSignals(False) - - manipulate = QtGui.QTransform(1 / sx, 0, 0, 1 / sy, dx, dy) tr = itemTransform(item, item.scene()) # offset to corner of root item if isinstance(root, QtWidgets.QGraphicsScene): @@ -261,7 +232,8 @@ def _generateItemSvg(item, nodes=None, root=None, options=None): else: resize_x = resize_y = 1 tr2 = QtGui.QTransform(resize_x, 0, 0, resize_y, -rootPos.x(), -rootPos.y()) - tr = manipulate * tr * tr2 + tr = tr * tr2 + # tr = manipulate * tr * tr2 arr = QtCore.QByteArray() buf = QtCore.QBuffer(arr) diff --git a/pyqtgraph/flowchart/Node.py b/pyqtgraph/flowchart/Node.py index 7fdfbd1626..5118614f0f 100644 --- a/pyqtgraph/flowchart/Node.py +++ b/pyqtgraph/flowchart/Node.py @@ -482,11 +482,49 @@ def __init__(self, node): self.nameItem = TextItem(self.node.name(), self, self.labelChanged) self.nameItem.setDefaultTextColor(QtGui.QColor(50, 50, 50)) self.nameItem.moveBy(self.bounds.width()/2. - self.nameItem.boundingRect().width()/2., 0) + self._titleOffset = 25 + self._nodeOffset = 12 self.updateTerminals() #self.setZValue(10) self.menu = None self.buildMenu() + + def setTitleOffset(self, new_offset): + """ + This method sets the rendering offset introduced after the title of the node. + This method automatically updates the terminal labels. The default for this value is 25px. + + :param new_offset: The new offset to use in pixels at 100% scale. + """ + self._titleOffset = new_offset + self.updateTerminals() + + def titleOffset(self): + """ + This method returns the current title offset in use. + + :returns: The offset in px. + """ + return self._titleOffset + + def setTerminalOffset(self, new_offset): + """ + This method sets the rendering offset introduced after every terminal of the node. + This method automatically updates the terminal labels. The default for this value is 12px. + + :param new_offset: The new offset to use in pixels at 100% scale. + """ + self._nodeOffset = new_offset + self.updateTerminals() + + def terminalOffset(self): + """ + This method returns the current terminal offset in use. + + :returns: The offset in px. + """ + return self._nodeOffset #self.node.sigTerminalRenamed.connect(self.updateActionMenu) @@ -519,11 +557,9 @@ def updateTerminals(self): out = self.node.outputs() maxNode = max(len(inp), len(out)) - titleOffset = 25 - nodeOffset = 12 # calculate new height - newHeight = titleOffset+maxNode*nodeOffset + newHeight = self._titleOffset + maxNode*self._nodeOffset # if current height is not equal to new height, update if not self.bounds.height() == newHeight: @@ -531,24 +567,24 @@ def updateTerminals(self): self.update() # Populate inputs - y = titleOffset + y = self._titleOffset for i, t in inp.items(): item = t.graphicsItem() item.setParentItem(self) #item.setZValue(self.zValue()+1) item.setAnchor(0, y) self.terminals[i] = (t, item) - y += nodeOffset + y += self._nodeOffset # Populate inputs - y = titleOffset + y = self._titleOffset for i, t in out.items(): item = t.graphicsItem() item.setParentItem(self) item.setZValue(self.zValue()) item.setAnchor(self.bounds.width(), y) self.terminals[i] = (t, item) - y += nodeOffset + y += self._nodeOffset #self.buildMenu() diff --git a/pyqtgraph/functions.py b/pyqtgraph/functions.py index 2f3476e9be..585209125c 100644 --- a/pyqtgraph/functions.py +++ b/pyqtgraph/functions.py @@ -4,8 +4,6 @@ Distributed under MIT/X11 license. See license.txt for more information. """ -from __future__ import division - import decimal import math import re @@ -14,13 +12,14 @@ import warnings from collections import OrderedDict +from typing import TypeAlias, TypedDict + import numpy as np from . import Qt, debug, getConfigOption, reload from .metaarray import MetaArray from .Qt import QT_LIB, QtCore, QtGui from .util.cupy_helper import getCupy -from .util.numba_helper import getNumbaFunctions # in order of appearance in this file. # add new functions to this list only if they are to reside in pg namespace. @@ -36,7 +35,7 @@ 'solve3DTransform', 'solveBilinearTransform', 'clip_scalar', 'clip_array', 'rescaleData', 'applyLookupTable', 'makeRGBA', 'makeARGB', - # 'try_fastpath_argb', 'ndarray_to_qimage', + # 'ndarray_to_qimage', 'makeQImage', # 'ndarray_from_qimage', 'imageToArray', 'colorToAlpha', @@ -69,7 +68,29 @@ FLOAT_REGEX = re.compile(r'(?P[+-]?((((\d+(\.\d*)?)|(\d*\.\d+))([eE][+-]?\d+)?)|((?i:nan)|(inf))))\s*((?P[u' + SI_PREFIXES + r']?)(?P\w.*))?$') INT_REGEX = re.compile(r'(?P[+-]?\d+)\s*(?P[u' + SI_PREFIXES + r']?)(?P.*)$') - +class HueKeywordArgs(TypedDict): + hues: int + values: int + maxValue: int + minValue: int + maxHue: int + minHue: int + sat: int + alpha: int + +color_like: TypeAlias = ( + QtGui.QColor + | str + | float + | int + | tuple[int, int, int] + | tuple[int, int, int, int] + | tuple[float, float, float] + | tuple[float, float, float, float] + | tuple[int, HueKeywordArgs] +) + + def siScale(x, minVal=1e-25, allowUnicode=True): """ Return the recommended scale factor and SI prefix string for x. @@ -226,15 +247,15 @@ def glColor(self): def __getitem__(self, ind): return (self.red, self.green, self.blue, self.alpha)[ind]() - - -def mkColor(*args): + + +def mkColor(*args) -> QtGui.QColor: """ Convenience function for constructing QColor from a variety of argument types. Accepted arguments are: ================ ================================================ - 'c' one of: r, g, b, c, m, y, k, w + 'c' one of: r, g, b, c, m, y, k, w or an SVG color keyword R, G, B, [A] integers 0-255 (R, G, B, [A]) tuple of integers 0-255 float greyscale, 0.0-1.0 @@ -253,45 +274,22 @@ def mkColor(*args): c = args[0] if len(c) == 1: try: - return Colors[c] + return QtGui.QColor(Colors[c]) # return copy except KeyError: - raise ValueError('No color named "%s"' % c) - have_alpha = len(c) in [5, 9] and c[0] == '#' # "#RGBA" and "#RRGGBBAA" - if not have_alpha: - # try parsing SVG named colors, including "#RGB" and "#RRGGBB". - # note that QColor.setNamedColor() treats a 9-char hex string as "#AARRGGBB". - qcol = QtGui.QColor() - qcol.setNamedColor(c) - if qcol.isValid(): - return qcol - # on failure, fallback to pyqtgraph parsing - # this includes the deprecated case of non-#-prefixed hex strings - if c[0] == '#': + raise ValueError('No color named "%s"' % c) from None + if c[0] == "#" and len(c) < 10: + # match hex color codes c = c[1:] + if len(c) < 6: + # convert RGBA to RRGGBBAA + c = "".join([x + x for x in c]) + return QtGui.QColor(*bytes.fromhex(c)) else: + # 'c' might be an SVG color keyword + qcol = QtGui.QColor(c) + if qcol.isValid(): + return qcol raise ValueError(f"Unable to convert {c} to QColor") - if len(c) == 3: - r = int(c[0]*2, 16) - g = int(c[1]*2, 16) - b = int(c[2]*2, 16) - a = 255 - elif len(c) == 4: - r = int(c[0]*2, 16) - g = int(c[1]*2, 16) - b = int(c[2]*2, 16) - a = int(c[3]*2, 16) - elif len(c) == 6: - r = int(c[0:2], 16) - g = int(c[2:4], 16) - b = int(c[4:6], 16) - a = 255 - elif len(c) == 8: - r = int(c[0:2], 16) - g = int(c[2:4], 16) - b = int(c[4:6], 16) - a = int(c[6:8], 16) - else: - raise ValueError(f"Unknown how to convert string {c} to color") elif isinstance(args[0], QtGui.QColor): return QtGui.QColor(args[0]) elif np.issubdtype(type(args[0]), np.floating): @@ -1209,28 +1207,18 @@ def clip_array(arr, vmin, vmax, out=None): else: return np.core.umath.clip(arr, vmin, vmax, out=out) +if tuple(map(int, np.__version__.split(".")[:2])) >= (1, 25): + # The linked issue above has been closed as of 2023/04/25 + # and states that the issue has been fixed. + # And furthermore, because NumPy 2.0 has made np.core private, + # we will just use the native np.clip + clip_array = np.clip + def _rescaleData_nditer(data_in, scale, offset, work_dtype, out_dtype, clip): """Refer to documentation for rescaleData()""" data_out = np.empty_like(data_in, dtype=out_dtype) - # integer clip operations are faster than float clip operations - # so test to see if we can perform integer clipping - fits_int32 = False - if data_in.dtype.kind in 'ui' and out_dtype.kind in 'ui': - # estimate whether data range after rescale will fit within an int32. - # this means that the input dtype should be an 8-bit or 16-bit integer type. - # casting to an int32 will lose the fractional part, therefore the - # output dtype must be an integer kind. - lim_in = np.iinfo(data_in.dtype) - # convert numpy scalar to python scalar to avoid overflow warnings - lo = offset.item(0) if isinstance(offset, np.number) else offset - dst_bounds = scale * (lim_in.min - lo), scale * (lim_in.max - lo) - if dst_bounds[1] < dst_bounds[0]: - dst_bounds = dst_bounds[1], dst_bounds[0] - lim32 = np.iinfo(np.int32) - fits_int32 = lim32.min < dst_bounds[0] and dst_bounds[1] < lim32.max - it = np.nditer([data_in, data_out], flags=['external_loop', 'buffered'], op_flags=[['readonly'], ['writeonly', 'no_broadcast']], @@ -1246,11 +1234,7 @@ def _rescaleData_nditer(data_in, scale, offset, work_dtype, out_dtype, clip): # Clip before converting dtype to avoid overflow if clip is not None: - if fits_int32: - # converts to int32, clips back to float32 - np.core.umath.clip(y.astype(np.int32), clip[0], clip[1], out=y) - else: - clip_array(y, clip[0], clip[1], out=y) + clip_array(y, clip[0], clip[1], out=y) return data_out @@ -1283,6 +1267,14 @@ def rescaleData(data, scale, offset, dtype=None, clip=None): else: work_dtype = np.float64 + # from: https://numpy.org/devdocs/numpy_2_0_migration_guide.html#changes-to-numpy-data-type-promotion + # np.array([3], dtype=np.float32) + np.float64(3) will now return a float64 array. + # (The higher precision of the scalar is not ignored.) + # this affects us even though we are performing in-place operations. + # a solution mentioned in the link above is to convert to a Python scalar. + offset = float(offset) + scale = float(scale) + cp = getCupy() if cp and cp.get_array_module(data) == cp: # Cupy does not support nditer @@ -1299,11 +1291,6 @@ def rescaleData(data, scale, offset, dtype=None, clip=None): # don't copy if no change in dtype return data_out.astype(out_dtype, copy=False) - numba_fn = getNumbaFunctions() - if numba_fn and clip is not None: - # if we got here by makeARGB(), clip will not be None at this point - return numba_fn.rescaleData(data, scale, offset, out_dtype, clip) - return _rescaleData_nditer(data, scale, offset, work_dtype, out_dtype, clip) @@ -1376,7 +1363,9 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, maskNans=Tr The default is False, which returns in ARGB order for use with QImage (Note that 'ARGB' is a term used by the Qt documentation; the *actual* order is BGRA). - maskNans Enable or disable masking NaNs as transparent. + maskNans Enable or disable masking NaNs as transparent. Converting NaN values to ints is + undefined behavior per the C-standard, results may vary across platforms. Highly + recommend leaving this option to the default value of True. ============== ================================================================================== """ cp = getCupy() @@ -1389,7 +1378,7 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, maskNans=Tr if lut is not None and not isinstance(lut, xp.ndarray): lut = xp.array(lut) - + if levels is None: # automatically decide levels based on data dtype if data.dtype.kind == 'u': @@ -1436,6 +1425,7 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, maskNans=Tr nanMask = xp.isnan(data) if data.ndim > 2: nanMask = xp.any(nanMask, axis=-1) + # Apply levels if given if levels is not None: if isinstance(levels, xp.ndarray) and levels.ndim == 2: @@ -1487,13 +1477,8 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, maskNans=Tr dst_order = [2, 1, 0, 3] # B,G,R,A (ARGB32 little endian) else: dst_order = [1, 2, 3, 0] # A,R,G,B (ARGB32 big endian) - - # copy data into image array - fastpath = try_fastpath_argb(xp, data, imgData, useRGBA) - if fastpath: - pass - elif data.ndim == 2: + if data.ndim == 2: # This is tempting: # imgData[..., :3] = data[..., xp.newaxis] # ..but it turns out this is faster: @@ -1505,16 +1490,15 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, maskNans=Tr else: for i in range(0, data.shape[2]): imgData[..., dst_order[i]] = data[..., i] - + profile('reorder channels') - + # add opaque alpha channel if needed if data.ndim == 3 and data.shape[2] == 4: alpha = True else: alpha = False - if not fastpath: # fastpath has already filled it in - imgData[..., dst_order[3]] = 255 + imgData[..., dst_order[3]] = 255 # apply nan mask through alpha channel if nanMask is not None: @@ -1529,50 +1513,6 @@ def makeARGB(data, lut=None, levels=None, scale=None, useRGBA=False, maskNans=Tr return imgData, alpha -def try_fastpath_argb(xp, ain, aout, useRGBA): - # we only optimize for certain cases - # return False if we did not handle it - can_handle = xp is np and ain.dtype == xp.ubyte and ain.flags['C_CONTIGUOUS'] - if not can_handle: - return False - - nrows, ncols = ain.shape[:2] - nchans = 1 if ain.ndim == 2 else ain.shape[2] - - Format = QtGui.QImage.Format - - if nchans == 1: - in_fmt = Format.Format_Grayscale8 - elif nchans == 3: - in_fmt = Format.Format_RGB888 - else: - in_fmt = Format.Format_RGBA8888 - - if useRGBA: - out_fmt = Format.Format_RGBA8888 - else: - out_fmt = Format.Format_ARGB32 - - if in_fmt == out_fmt: - aout[:] = ain - return True - - npixels_chunk = 512*1024 - batch = int(npixels_chunk / ncols / nchans) - batch = max(1, batch) - row_beg = 0 - while row_beg < nrows: - row_end = min(row_beg + batch, nrows) - ain_view = ain[row_beg:row_end, ...] - aout_view = aout[row_beg:row_end, ...] - qimg = QtGui.QImage(ain_view, ncols, ain_view.shape[0], ain.strides[0], in_fmt) - qimg = qimg.convertToFormat(out_fmt) - aout_view[:] = imageToArray(qimg, copy=False, transpose=False) - row_beg = row_end - - return True - - def ndarray_to_qimage(arr, fmt): """ Low level function to encapsulate QImage creation differences between bindings. @@ -2070,11 +2010,12 @@ def arrayToQPath(x, y, connect='all', finiteCheck=True): a ``QDataStream`` object is created and the QDataStream >> QPainterPath operator is used to pass the data. The memory format is as follows - numVerts(i4) - 0(i4) x(f8) y(f8) <-- 0 means this vertex does not connect - 1(i4) x(f8) y(f8) <-- 1 means this vertex connects to the previous vertex - ... - cStart(i4) fillRule(i4) + .. code-block: + numVerts(i4) + 0(i4) x(f8) y(f8) <-- 0 means this vertex does not connect + 1(i4) x(f8) y(f8) <-- 1 means this vertex connects to the previous vertex + ... + cStart(i4) fillRule(i4) see: https://github.com/qt/qtbase/blob/dev/src/gui/painting/qpainterpath.cpp @@ -3192,12 +3133,22 @@ def disconnect(signal, slot): """ while True: try: - signal.disconnect(slot) + success = signal.disconnect(slot) + if success is None: # PyQt + success = True + except ( + TypeError, + RuntimeError, + SystemError # PySide6 6.7.1+ will emit this + ): + success = False + + if success: return True - except (TypeError, RuntimeError): - slot = reload.getPreviousVersion(slot) - if slot is None: - return False + + slot = reload.getPreviousVersion(slot) + if slot is None: + return False class SignalBlock(object): diff --git a/pyqtgraph/functions_numba.py b/pyqtgraph/functions_numba.py index 89350b405c..e2b52e8876 100644 --- a/pyqtgraph/functions_numba.py +++ b/pyqtgraph/functions_numba.py @@ -1,41 +1,27 @@ import numba import numpy as np -rescale_functions = {} - -def rescale_clip_source(xx, scale, offset, vmin, vmax, yy): - for i in range(xx.size): - val = (xx[i] - offset) * scale - yy[i] = min(max(val, vmin), vmax) - -def rescaleData(data, scale, offset, dtype, clip): - data_out = np.empty_like(data, dtype=dtype) - key = (data.dtype.name, data_out.dtype.name) - func = rescale_functions.get(key) - if func is None: - func = numba.guvectorize( - [f'{key[0]}[:],f8,f8,f8,f8,{key[1]}[:]'], - '(n),(),(),(),()->(n)', - nopython=True)(rescale_clip_source) - rescale_functions[key] = func - func(data, scale, offset, clip[0], clip[1], out=data_out) - return data_out - @numba.jit(nopython=True) -def _rescale_and_lookup1d_function(data, scale, offset, lut, out): - vmin, vmax = 0, lut.shape[0] - 1 - for r in range(data.shape[0]): - for c in range(data.shape[1]): - val = (data[r, c] - offset) * scale - val = min(max(val, vmin), vmax) - out[r, c] = lut[int(val)] - -def rescale_and_lookup1d(data, scale, offset, lut): +def rescale_and_lookup(data, scale, offset, lut): # data should be floating point and 2d # lut is 1d - data_out = np.empty_like(data, dtype=lut.dtype) - _rescale_and_lookup1d_function(data, float(scale), float(offset), lut, data_out) - return data_out + vmin, vmax = 0, lut.shape[0] - 1 + out = np.empty_like(data, dtype=lut.dtype) + for (x, y) in np.nditer((data, out)): + val = (x - offset) * scale + val = min(max(val, vmin), vmax) + y[...] = lut[int(val)] + return out + +@numba.jit(nopython=True) +def rescale_and_clip(data, scale, offset, vmin, vmax): + # vmin and vmax <= 255 + out = np.empty_like(data, dtype=np.uint8) + for (x, y) in np.nditer((data, out)): + val = (x - offset) * scale + val = min(max(val, vmin), vmax) + y[...] = val + return out @numba.jit(nopython=True) def numba_take(lut, data): diff --git a/pyqtgraph/functions_qimage.py b/pyqtgraph/functions_qimage.py new file mode 100644 index 0000000000..6671cb2904 --- /dev/null +++ b/pyqtgraph/functions_qimage.py @@ -0,0 +1,370 @@ +import numpy + +from .Qt import QtGui +from . import functions +from .util.cupy_helper import getCupy +from .util.numba_helper import getNumbaFunctions + + +def _apply_lut_for_uint(xp, image, lut): + # Note: compared to makeARGB(), we have already clipped the data to range + + # if lut is 1d, then lut[image] is fastest + # if lut is 2d, then lut.take(image, axis=0) is faster than lut[image] + lut = _convert_2dlut_to_1dlut(xp, lut) + + if xp == numpy and (fn_numba := getNumbaFunctions()) is not None: + # numba "take" supports only the 1st 2 arguments of np.take, + # therefore we have to convert the lut to 1d. + # "take" will output a c contiguous array regardless of its input. + image = fn_numba.numba_take(lut, image) + else: + # advanced indexing is memory order aware. + # its output can be either C or F contiguous. + image = lut[image] + + if image.dtype == xp.uint32: + # "view" requires c contiguous for numpy < 1.23 + image = xp.ascontiguousarray(image) + image = image[..., xp.newaxis].view(xp.uint8) + + return image + + +def _convert_lut_to_rgba(xp, lut): + # converts: + # - None to (256, 4) + # - uint8 (N,) to uint8 (N, 4) + # - uint8 (N, 1) to uint8 (N, 4) + # - uint8 (N, 3) to uint8 (N, 4) + + if not ( + lut is None + or lut.ndim == 1 + or ( + lut.ndim == 2 + and lut.shape[1] in (1, 3, 4) + ) + ): + raise ValueError("unsupported lut shape") + + N = lut.shape[0] if lut is not None else 256 + + if lut is None: + lut = xp.arange(N, dtype=xp.uint8) + + # convert (N,) to (N, 1) + if lut.ndim == 1: + lut = lut[:, xp.newaxis] + + if lut.shape[1] == 4: + return lut + + out = xp.full((N, 4), 255, dtype=xp.uint8) + out[:, 0:3] = lut + return out + + +def _convert_2dlut_to_1dlut(xp, lut): + # converts: + # - uint8 (N, 1) to uint8 (N,) + # - uint8 (N, 3) or (N, 4) to uint32 (N,) + # this allows faster lookup as 1d lookup is faster + + if lut.ndim == 1: + return lut + + if lut.shape[1] == 3: # rgb + # convert rgb lut to rgba so that it is 32-bits + lut = xp.column_stack([lut, xp.full(lut.shape[0], 255, dtype=xp.uint8)]) + if lut.shape[1] == 4: # rgba + lut = lut.view(xp.uint32) + lut = lut.ravel() + + return lut + + +def _rescale_and_lookup_float(xp, image, levels, lut, *, forceApplyLut): + # It is usually more performant to _not_ apply the lut and + # instead use it as an Indexed8 ColorTable. This is only + # applicable if the lut has <= 256 entries. + + if forceApplyLut and lut is None: + raise ValueError("forceApplyLut True but lut not provided") + + # Decide on maximum scaled value + if lut is not None: + num_colors = lut.shape[0] + max_scale_value = num_colors + else: + num_colors = 256 + max_scale_value = 255.0 + dtype = xp.min_scalar_type(num_colors - 1) + + # note: "dtype == uint16" ==> lut provided ==> mono-channel image + # i.e. multi-channel image ==> lut is None ==> dtype == uint8 + # + # the library defaults to using 256-entry luts, so + # "dtype == uint8" is the common case + + apply_lut = forceApplyLut or dtype == xp.uint16 + + minVal, maxVal = levels + rng = maxVal - minVal + rng = 1 if rng == 0 else rng + offset = minVal + scale = max_scale_value / rng + + if xp == numpy and (fn_numba := getNumbaFunctions()) is not None: + if apply_lut: + # this path does rescale and apply lut in one step + lut = _convert_2dlut_to_1dlut(xp, lut) + image = fn_numba.rescale_and_lookup(image, scale, offset, lut) + lut = None + if image.dtype == xp.uint32: + # "view" requires c contiguous for numpy < 1.23 + image = xp.ascontiguousarray(image) + image = image[..., xp.newaxis].view(xp.uint8) + else: + image = fn_numba.rescale_and_clip(image, scale, offset, 0, num_colors - 1) + else: + image = functions.rescaleData( + image, scale, offset, dtype=dtype, clip=(0, num_colors - 1) + ) + if apply_lut: + image = _apply_lut_for_uint(xp, image, lut) + lut = None + + # image is now of type uint8 + return image, lut + + +def _combine_levels_and_lut(xp, image, levels, lut): + if ( + image.dtype == xp.uint16 + and levels is None + and image.ndim == 3 + and image.shape[2] == 3 + ): + # uint16 rgb can't be directly displayed, so make it + # pass through effective lut processing + levels = [0, 65535] + + if levels is None and lut is None: + # nothing to combine + return image, lut + + # distinguish between lut for levels and colors + levels_lut = None + colors_lut = lut + + eflsize = 2 ** (image.itemsize * 8) + if levels is None: + info = xp.iinfo(image.dtype) + minlev, maxlev = info.min, info.max + else: + minlev, maxlev = levels + levdiff = maxlev - minlev + levdiff = 1 if levdiff == 0 else levdiff # don't allow division by 0 + offset = minlev + + if colors_lut is None: + scale = 255.0 / levdiff + if image.dtype == xp.ubyte and image.ndim == 2: + # uint8 mono image + ind = xp.arange(eflsize) + levels_lut = functions.rescaleData(ind, scale, offset, dtype=xp.ubyte) + # image data is not scaled. instead, levels_lut is used + # as (grayscale) Indexed8 ColorTable to get the same effect. + # due to the small size of the input to rescaleData(), we + # do not bother caching the result + return image, levels_lut + else: + # uint16 mono, uint8 rgb, uint16 rgb + # rescale image data by computation instead of by memory lookup + if xp == numpy and (fn_numba := getNumbaFunctions()) is not None: + image = fn_numba.rescale_and_clip(image, scale, offset, 0, 255) + else: + image = functions.rescaleData(image, scale, offset, dtype=xp.ubyte) + return image, colors_lut + else: + num_colors = colors_lut.shape[0] + scale = num_colors / levdiff + lutdtype = xp.min_scalar_type(num_colors - 1) + + if image.dtype == xp.ubyte or lutdtype != xp.ubyte: + # combine if either: + # 1) uint8 mono image + # 2) colors_lut has more entries than will fit within 8-bits + ind = xp.arange(eflsize) + levels_lut = functions.rescaleData( + ind, scale, offset, dtype=lutdtype, clip=(0, num_colors - 1), + ) + efflut = colors_lut[levels_lut] + + # apply the effective lut early for the following types: + if image.dtype == xp.uint16 and image.ndim == 2: + image = _apply_lut_for_uint(xp, image, efflut) + efflut = None + return image, efflut + else: + # uint16 image with colors_lut <= 256 entries + # don't combine, we will use QImage ColorTable + if xp == numpy and (fn_numba := getNumbaFunctions()) is not None: + image = fn_numba.rescale_and_clip(image, scale, offset, 0, num_colors - 1) + else: + image = functions.rescaleData( + image, scale, offset, dtype=lutdtype, clip=(0, num_colors - 1), + ) + return image, colors_lut + + +def try_make_qimage(image, *, levels, lut, transparentLocations=None): + """ + Internal function to make an QImage from an ndarray without going + through the full generality of makeARGB(). + Only certain combinations of input arguments are supported. + """ + + # this function assumes that image has no nans. + # checking for nans is an expensive operation; it is expected that + # the caller would want to cache the result rather than have this + # function check for nans unconditionally. + + cp = getCupy() + xp = cp.get_array_module(image) if cp else numpy + + # float images always need levels + if image.dtype.kind == "f" and levels is None: + return None + + if levels is not None: + levels = xp.asarray(levels) + + # can't handle multi-channel levels + if levels.ndim != 1: + return None + + # if levels is provided, multi-channel images must be 3 channels only. + # (because it doesn't make sense to scale a 4th alpha channel.) + if image.ndim == 3 and image.shape[2] != 3: + return None + + if lut is not None and lut.dtype != xp.uint8: + raise ValueError("lut dtype must be uint8") + + alpha_channel_required = ( + ( # image itself has alpha channel + image.ndim == 3 + and image.shape[2] == 4 + ) + or + ( # lut has alpha channel + lut is not None + and lut.ndim == 2 + and lut.shape[1] == 4 + ) + ) + + if image.dtype.kind == "f": + if image.ndim == 2: + # mono float images + if transparentLocations is None: + image, lut = _rescale_and_lookup_float( + xp, image, levels, lut, forceApplyLut=False + ) + levels = None + # on return, we will have an uint8 image. + # lut if not None will have <= 256 entries + else: + # this path creates an alpha channel + lut = _convert_lut_to_rgba(xp, lut) + alpha_channel_required = True + + image, lut = _rescale_and_lookup_float( + xp, image, levels, lut, forceApplyLut=True + ) + levels = None + assert lut is None + image[..., 3][transparentLocations] = 0 + else: + # RGB float images + # lut can only be None for RGB images + image, lut = _rescale_and_lookup_float( + xp, image, levels, lut, forceApplyLut=False + ) + levels = None + + if transparentLocations is not None: + alpha_channel_required = True + mask = xp.full(image.shape[:2], 255, dtype=xp.uint8) + mask[transparentLocations] = 0 + image = xp.dstack((image, mask)) + + # if the image data is a small int, then we can combine levels + lut + # into a single lut for better performance + elif image.dtype in (xp.ubyte, xp.uint16): + image, lut = _combine_levels_and_lut(xp, image, levels, lut) + levels = None + + ubyte_nolvl = image.dtype == xp.ubyte and levels is None + is_passthru8 = ubyte_nolvl and lut is None + is_indexed8 = ( + ubyte_nolvl and image.ndim == 2 and lut is not None and lut.shape[0] <= 256 + ) + is_passthru16 = image.dtype == xp.uint16 and levels is None and lut is None + can_grayscale16 = ( + is_passthru16 + and image.ndim == 2 + and hasattr(QtGui.QImage.Format, "Format_Grayscale16") + ) + is_rgba64 = is_passthru16 and image.ndim == 3 and image.shape[2] == 4 + + # bypass makeARGB for supported combinations + supported = is_passthru8 or is_indexed8 or can_grayscale16 or is_rgba64 + if not supported: + return None + + if xp == cp: + image = image.get() + + # worthwhile supporting non-contiguous arrays + image = numpy.ascontiguousarray(image) + + fmt = None + ctbl = None + if is_passthru8: + # both levels and lut are None + # these images are suitable for display directly + if image.ndim == 2: + fmt = QtGui.QImage.Format.Format_Grayscale8 + elif image.shape[2] == 3: + fmt = QtGui.QImage.Format.Format_RGB888 + elif image.shape[2] == 4: + if alpha_channel_required: + fmt = QtGui.QImage.Format.Format_RGBA8888 + else: + fmt = QtGui.QImage.Format.Format_RGBX8888 + elif is_indexed8: + # levels and/or lut --> lut-only + fmt = QtGui.QImage.Format.Format_Indexed8 + if lut.ndim == 1 or lut.shape[1] == 1: + ctbl = [QtGui.qRgb(x, x, x) for x in lut.ravel().tolist()] + elif lut.shape[1] == 3: + ctbl = [QtGui.qRgb(*rgb) for rgb in lut.tolist()] + elif lut.shape[1] == 4: + ctbl = [QtGui.qRgba(*rgba) for rgba in lut.tolist()] + elif can_grayscale16: + # single channel uint16 + # both levels and lut are None + fmt = QtGui.QImage.Format.Format_Grayscale16 + elif is_rgba64: + # uint16 rgba + # both levels and lut are None + fmt = QtGui.QImage.Format.Format_RGBA64 # endian-independent + if fmt is None: + raise ValueError("unsupported image type") + qimage = functions.ndarray_to_qimage(image, fmt) + if ctbl is not None: + qimage.setColorTable(ctbl) + return qimage diff --git a/pyqtgraph/graphicsItems/AxisItem.py b/pyqtgraph/graphicsItems/AxisItem.py index 7fafc69151..e8ce9f7f36 100644 --- a/pyqtgraph/graphicsItems/AxisItem.py +++ b/pyqtgraph/graphicsItems/AxisItem.py @@ -1,5 +1,5 @@ import weakref -from math import ceil, floor, isfinite, log, log10 +from math import ceil, floor, isfinite, log10, sqrt, frexp, floor import numpy as np @@ -52,6 +52,9 @@ def __init__(self, orientation, pen=None, textPen=None, tickPen = None, linkView raise Exception("Orientation argument must be one of 'left', 'right', 'top', or 'bottom'.") if orientation in ['left', 'right']: self.label.setRotation(-90) + hide_overlapping_labels = False # allow labels on vertical axis to extend above and below the length of the axis + else: + hide_overlapping_labels = True # stop labels on horizontal axis from overlapping so vertical axis labels have room self.style = { 'tickTextOffset': [5, 2], ## (horizontal, vertical) spacing between text and axis @@ -59,7 +62,7 @@ def __init__(self, orientation, pen=None, textPen=None, tickPen = None, linkView 'tickTextHeight': 18, 'autoExpandTextSpace': True, ## automatically expand text space if needed 'autoReduceTextSpace': True, - 'hideOverlappingLabels': True, + 'hideOverlappingLabels': hide_overlapping_labels, 'tickFont': None, 'stopAxisAtTick': (False, False), ## whether axis is drawn to edge of box or to last tick 'textFillLimits': [ ## how much of the axis to fill up with tick text, maximally. @@ -89,7 +92,8 @@ def __init__(self, orientation, pen=None, textPen=None, tickPen = None, linkView self.labelStyle = args self.logMode = False - self._tickLevels = None ## used to override the automatic ticking system with explicit ticks + self._tickDensity = 1.0 # used to adjust scale the number of automatically generated ticks + self._tickLevels = None # used to override the automatic ticking system with explicit ticks self._tickSpacing = None # used to override default tickSpacing method self.scale = 1.0 self.autoSIPrefix = True @@ -137,9 +141,12 @@ def setStyle(self, **kwds): autoExpandTextSpace (bool) Automatically expand text space if the tick strings become too long. autoReduceTextSpace (bool) Automatically shrink the axis if necessary - hideOverlappingLabels (bool) Hide tick labels which overlap the AxisItems' - geometry rectangle. If False, labels might be drawn - overlapping with tick labels from neighboring plots. + hideOverlappingLabels (bool or int) + + * *True* (default for horizontal axis): Hide tick labels which extend beyond the AxisItem's geometry rectangle. + * *False* (default for vertical axis): Labels may be drawn extending beyond the extent of the axis. + * *(int)* sets the tolerance limit for how many pixels a label is allowed to extend beyond the axis. Defaults to 15 for `hideOverlappingLabels = False`. + tickFont (QFont or None) Determines the font used for tick values. Use None for the default font. stopAxisAtTick (tuple: (bool min, bool max)) If True, the axis @@ -571,7 +578,7 @@ def setRange(self, mn, mx): self.update() def linkedView(self): - """Return the ViewBox this axis is linked to""" + """Return the ViewBox this axis is linked to.""" if self._linkedView is None: return None else: @@ -624,7 +631,17 @@ def linkedViewChanged(self, view, newRange=None): self.setRange(*newRange) def boundingRect(self): - m = 0 if self.style['hideOverlappingLabels'] else 15 + m = 0 + hide_overlapping_labels = self.style['hideOverlappingLabels'] + if hide_overlapping_labels is True: + pass # skip further checks + elif hide_overlapping_labels is False: + m = 15 + else: + try: + m = int( self.style['hideOverlappingLabels'] ) + except ValueError: pass # ignore any non-numeric value + linkedView = self.linkedView() if linkedView is None or self.grid is False: rect = self.mapRectFromParent(self.geometry()) @@ -636,7 +653,7 @@ def boundingRect(self): elif self.orientation == 'right': rect = rect.adjusted(min(0,tl), -m, 0, m) elif self.orientation == 'top': - rect = rect.adjusted(-15, 0, 15, -min(0,tl)) + rect = rect.adjusted(-m, 0, m, -min(0,tl)) elif self.orientation == 'bottom': rect = rect.adjusted(-m, min(0,tl), m, 0) return rect @@ -663,6 +680,21 @@ def paint(self, p, opt, widget): #p.setRenderHint(p.RenderHint.TextAntialiasing, True) self.picture.play(p) + + def setTickDensity(self, density=1.0): + """ + The default behavior is to show at least two major ticks for axes of up to 300 pixels in length, + then add additional major ticks, spacing them out further as the available room increases. + (Internally, the targeted number of major ticks grows with the square root of the axes length.) + + Setting a tick density different from the default value of `density = 1.0` scales the number of + major ticks that is targeted for display. This only affects the automatic generation of ticks. + """ + self._tickDensity = density + self.picture = None + self.update() + + def setTicks(self, ticks): """Explicitly determine which ticks to display. This overrides the behavior specified by tickSpacing(), tickValues(), and tickStrings() @@ -674,6 +706,7 @@ def setTicks(self, ticks): ... ] + The two levels of major and minor ticks are expected. A third tier of additional ticks is optional. If *ticks* is None, then the default tick system will be used instead. """ self._tickLevels = ticks @@ -696,7 +729,7 @@ def setTickSpacing(self, major=None, minor=None, levels=None): # two levels, all offsets = 0 axis.setTickSpacing(5, 1) # three levels, all offsets = 0 - axis.setTickSpacing([(3, 0), (1, 0), (0.25, 0)]) + axis.setTickSpacing(levels=[(3, 0), (1, 0), (0.25, 0)]) # reset to default axis.setTickSpacing() """ @@ -710,6 +743,7 @@ def setTickSpacing(self, major=None, minor=None, levels=None): self.picture = None self.update() + def tickSpacing(self, minVal, maxVal, size): """Return values describing the desired spacing and offset of ticks. @@ -732,58 +766,70 @@ def tickSpacing(self, minVal, maxVal, size): dif = abs(maxVal - minVal) if dif == 0: return [] - - ## decide optimal minor tick spacing in pixels (this is just aesthetics) - optimalTickCount = max(2., log(size)) - - ## optimal minor tick spacing - optimalSpacing = dif / optimalTickCount - - ## the largest power-of-10 spacing which is smaller than optimal - p10unit = 10 ** floor(log10(optimalSpacing)) - - ## Determine major/minor tick spacings which flank the optimal spacing. - intervals = np.array([1., 2., 10., 20., 100.]) * p10unit - minorIndex = 0 - while intervals[minorIndex+1] <= optimalSpacing: - minorIndex += 1 - + + ref_size = 300. # axes longer than this display more than the minimum number of major ticks + minNumberOfIntervals = max( + 2.25, # 2.0 ensures two tick marks. Fudged increase to 2.25 allows room for tick labels. + 2.25 * self._tickDensity * sqrt(size/ref_size) # sub-linear growth of tick spacing with size + ) + + majorMaxSpacing = dif / minNumberOfIntervals + + # We want to calculate the power of 10 just below the maximum spacing. + # Then divide by ten so that the scale factors for subdivision all become intergers. + # p10unit = 10**( floor( log10(majorMaxSpacing) ) ) / 10 + + # And we want to do it without a log operation: + mantissa, exp2 = frexp(majorMaxSpacing) # IEEE 754 float already knows its exponent, no need to calculate + p10unit = 10. ** ( # approximate a power of ten base factor just smaller than the given number + floor( # int would truncate towards zero to give wrong results for negative exponents + (exp2-1) # IEEE 754 exponent is ceiling of true exponent --> estimate floor by subtracting 1 + / 3.32192809488736 # division by log2(10)=3.32 converts base 2 exponent to base 10 exponent + ) - 1 # subtract one extra power of ten so that we can work with integer scale factors >= 5 + ) + # neglecting the mantissa can underestimate by one power of 10 when the true value is JUST above the threshold. + if 100. * p10unit <= majorMaxSpacing: # Cheaper to check this than to use a more complicated approximation. + majorScaleFactor = 10 + p10unit *= 10. + else: + for majorScaleFactor in (50, 20, 10): + if majorScaleFactor * p10unit <= majorMaxSpacing: + break # find the first value that is smaller or equal + majorInterval = majorScaleFactor * p10unit + # manual sanity check: print(f"{majorMaxSpacing:.2e} > {majorInterval:.2e} = {majorScaleFactor:.2e} x {p10unit:.2e}") + + minorMinSpacing = 2 * dif/size # no more than one minor tick per two pixels + if majorScaleFactor == 10: + trials = (5, 10) # if major interval is 1.0, try minor interval of 0.5, fall back to same as major interval + else: + trials = (10, 20, 50) # if major interval is 2.0 or 5.0, try minor interval of 1.0, increase as needed + for minorScaleFactor in trials: + minorInterval = minorScaleFactor * p10unit + if minorInterval >= minorMinSpacing: + break # find the first value that is larger or equal to allowed minimum of 1 per 2px levels = [ - (intervals[minorIndex+2], 0), - (intervals[minorIndex+1], 0), - #(intervals[minorIndex], 0) ## Pretty, but eats up CPU + (majorInterval, 0), + (minorInterval, 0) ] - - if self.style['maxTickLevel'] >= 2: - ## decide whether to include the last level of ticks - minSpacing = min(size / 20., 30.) - maxTickCount = size / minSpacing - if dif / intervals[minorIndex] <= maxTickCount: - levels.append((intervals[minorIndex], 0)) - + # extra ticks at 10% of major interval are pretty, but eat up CPU + if self.style['maxTickLevel'] >= 2: # consider only when enabled + if majorScaleFactor == 10: + trials = (1, 2, 5, 10) # start at 10% of major interval, increase if needed + elif majorScaleFactor == 20: + trials = (2, 5, 10, 20) # start at 10% of major interval, increase if needed + elif majorScaleFactor == 50: + trials = (5, 10, 50) # start at 10% of major interval, increase if needed + else: # invalid value + trials = () # skip extra interval + extraInterval = minorInterval + for extraScaleFactor in trials: + extraInterval = extraScaleFactor * p10unit + if extraInterval >= minorMinSpacing or extraInterval == minorInterval: + break # find the first value that is larger or equal to allowed minimum of 1 per 2px + if extraInterval < minorInterval: # add extra interval only if it is visible + levels.append((extraInterval, 0)) return levels - - ##### This does not work -- switching between 2/5 confuses the automatic text-level-selection - ### Determine major/minor tick spacings which flank the optimal spacing. - #intervals = np.array([1., 2., 5., 10., 20., 50., 100.]) * p10unit - #minorIndex = 0 - #while intervals[minorIndex+1] <= optimalSpacing: - #minorIndex += 1 - - ### make sure we never see 5 and 2 at the same time - #intIndexes = [ - #[0,1,3], - #[0,2,3], - #[2,3,4], - #[3,4,6], - #[3,5,6], - #][minorIndex] - - #return [ - #(intervals[intIndexes[2]], 0), - #(intervals[intIndexes[1]], 0), - #(intervals[intIndexes[0]], 0) - #] + def tickValues(self, minVal, maxVal, size): """ @@ -1042,6 +1088,12 @@ def generateDrawSpecs(self, p): raise ValueError("lineAlpha should be [0..255]") else: raise TypeError("Line Alpha should be of type None, float or int") + tickPen = self.tickPen() + if tickPen.brush().style() == QtCore.Qt.BrushStyle.SolidPattern: # only adjust simple color pens + tickPen = QtGui.QPen(tickPen) # copy to a new QPen + color = QtGui.QColor(tickPen.color()) # copy to a new QColor + color.setAlpha(int(lineAlpha)) # adjust opacity + tickPen.setColor(color) for v in ticks: ## determine actual position to draw this tick @@ -1057,10 +1109,6 @@ def generateDrawSpecs(self, p): p2[axis] = tickStop if self.grid is False: p2[axis] += tickLength*tickDir - tickPen = self.tickPen() - color = tickPen.color() - color.setAlpha(int(lineAlpha)) - tickPen.setColor(color) tickSpecs.append((tickPen, Point(p1), Point(p2))) profiler('compute ticks') diff --git a/pyqtgraph/graphicsItems/ButtonItem.py b/pyqtgraph/graphicsItems/ButtonItem.py index acacdde922..1e74580080 100644 --- a/pyqtgraph/graphicsItems/ButtonItem.py +++ b/pyqtgraph/graphicsItems/ButtonItem.py @@ -14,10 +14,11 @@ def __init__(self, imageFile=None, width=None, parentItem=None, pixmap=None): self.setImageFile(imageFile) elif pixmap is not None: self.setPixmap(pixmap) - - if width is not None and self.pixmap.width(): - s = float(width) / self.pixmap.width() - self.setScale(s) + + self._width = width + if self._width is None: + self._width = self.pixmap.width() / self.pixmap.devicePixelRatio() + if parentItem is not None: self.setParentItem(parentItem) self.setOpacity(0.7) @@ -51,8 +52,10 @@ def enable(self): def paint(self, p, *args): p.setRenderHint(p.RenderHint.Antialiasing) - p.drawPixmap(0, 0, self.pixmap) + tgtRect = QtCore.QRectF(0, 0, self._width, self._width) + srcRect = QtCore.QRectF(self.pixmap.rect()) + p.drawPixmap(tgtRect, self.pixmap, srcRect) def boundingRect(self): - return QtCore.QRectF(self.pixmap.rect()) + return QtCore.QRectF(0, 0, self._width, self._width) diff --git a/pyqtgraph/graphicsItems/ColorBarItem.py b/pyqtgraph/graphicsItems/ColorBarItem.py index 34df8972bc..12c1bb2703 100644 --- a/pyqtgraph/graphicsItems/ColorBarItem.py +++ b/pyqtgraph/graphicsItems/ColorBarItem.py @@ -7,8 +7,8 @@ from .. import functions as fn from ..Qt import QtCore, QtGui, QtWidgets from .LinearRegionItem import LinearRegionItem -from .PColorMeshItem import PColorMeshItem from .PlotItem import PlotItem +from ..widgets.ColorMapMenu import ColorMapMenu __all__ = ['ColorBarItem'] @@ -42,7 +42,8 @@ class ColorBarItem(PlotItem): def __init__(self, values=None, width=25, colorMap=None, label=None, interactive=True, limits=None, rounding=1, - orientation='vertical', pen='w', hoverPen='r', hoverBrush='#FF000080', cmap=None ): + orientation='vertical', pen='w', hoverPen='r', hoverBrush='#FF000080', + *, colorMapMenu=True): """ Creates a new ColorBarItem. @@ -72,6 +73,8 @@ def __init__(self, values=None, width=25, colorMap=None, label=None, Sets the color of adjustment handles when hovered over. hoverBrush: :class:`QBrush` or color_like Sets the color of movable center region when hovered over. + colorMapMenu: `bool` or :class:`~pyqtgraph.ColorMapMenu`, default=True + Determines whether colormap menu functionality is enabled. """ super().__init__() self.img_list = [] # list of controlled ImageItems @@ -99,6 +102,12 @@ def __init__(self, values=None, width=25, colorMap=None, label=None, if self.hi_lim is not None: self.hi_lim = self.rounding * math.ceil( self.hi_lim/self.rounding ) + if not isinstance(colorMapMenu, (bool, ColorMapMenu)): + raise ValueError("colorMapMenu must be either bool or an ColorMapMenu instance") + self.colorMapMenu = colorMapMenu + if isinstance(self.colorMapMenu, ColorMapMenu): + self.colorMapMenu.sigColorMapTriggered.connect(self.setColorMap) + self.disableAutoRange() self.hideButtons() self.setMouseEnabled(x=False, y=False) @@ -288,10 +297,7 @@ def _update_items(self, update_cmap=False): if img is None: continue # dereference weakref img.setLevels( self.values ) # (min,max) tuple if update_cmap and self._colorMap is not None: - if isinstance(img, PColorMeshItem): - img.setLookupTable( self._colorMap.getLookupTable(nPts=256, mode=self._colorMap.QCOLOR) ) - else: - img.setLookupTable( self._colorMap.getLookupTable(nPts=256) ) + img.setColorMap(self._colorMap) def _levelsChangedHandler(self, levels): """ internal: called when child item for some reason decides to update its levels without using ColorBarItem. @@ -348,3 +354,15 @@ def _regionChanging(self): self.values = (lo_new, hi_new) self._update_items() self.sigLevelsChanged.emit(self) + + def mouseClickEvent(self, ev): + if self.colorMapMenu is False: # disabled + return + + if ev.button() == QtCore.Qt.MouseButton.RightButton: + if not isinstance(self.colorMapMenu, ColorMapMenu): + self.colorMapMenu = ColorMapMenu(showColorMapSubMenus=True) + self.colorMapMenu.sigColorMapTriggered.connect(self.setColorMap) + pos = ev.screenPos() + self.colorMapMenu.popup(pos.toPoint()) + ev.accept() diff --git a/pyqtgraph/graphicsItems/DateAxisItem.py b/pyqtgraph/graphicsItems/DateAxisItem.py index f424fae9b8..d0c85e5e71 100644 --- a/pyqtgraph/graphicsItems/DateAxisItem.py +++ b/pyqtgraph/graphicsItems/DateAxisItem.py @@ -1,7 +1,7 @@ import sys import time from collections import OrderedDict -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone import numpy as np @@ -19,11 +19,12 @@ YEAR_SPACING = 365 * DAY_SPACING if sys.platform == 'win32': - _epoch = datetime.utcfromtimestamp(0) + _epoch = datetime.fromtimestamp(0, timezone.utc) def utcfromtimestamp(timestamp): return _epoch + timedelta(seconds=timestamp) else: - utcfromtimestamp = datetime.utcfromtimestamp + def utcfromtimestamp(timestamp): + return datetime.fromtimestamp(timestamp, timezone.utc) MIN_REGULAR_TIMESTAMP = (datetime(1, 1, 1) - datetime(1970,1,1)).total_seconds() MAX_REGULAR_TIMESTAMP = (datetime(9999, 1, 1) - datetime(1970,1,1)).total_seconds() diff --git a/pyqtgraph/graphicsItems/FillBetweenItem.py b/pyqtgraph/graphicsItems/FillBetweenItem.py index de4630057d..dcfa602537 100644 --- a/pyqtgraph/graphicsItems/FillBetweenItem.py +++ b/pyqtgraph/graphicsItems/FillBetweenItem.py @@ -1,5 +1,7 @@ +from typing import Union + from .. import functions as fn -from ..Qt import QtGui, QtWidgets +from ..Qt import QtGui, QtWidgets, QtCore from .PlotCurveItem import PlotCurveItem from .PlotDataItem import PlotDataItem @@ -9,33 +11,104 @@ class FillBetweenItem(QtWidgets.QGraphicsPathItem): """ GraphicsItem filling the space between two PlotDataItems. """ - def __init__(self, curve1=None, curve2=None, brush=None, pen=None): - QtWidgets.QGraphicsPathItem.__init__(self) + def __init__( + self, + curve1: Union[PlotDataItem, PlotCurveItem], + curve2: Union[PlotDataItem, PlotCurveItem], + brush=None, + pen=None, + fillRule: QtCore.Qt.FillRule=QtCore.Qt.FillRule.OddEvenFill + ): + """FillBetweenItem fills a region between two curves with a specified + :class:`~QtGui.QBrush`. + + Parameters + ---------- + curve1 : :class:`~pyqtgraph.PlotDataItem` | :class:`~pyqtgraph.PlotCurveItem` + Line to draw fill from + curve2 : :class:`~pyqtgraph.PlotDataItem` | :class:`~pyqtgraph.PlotCurveItem` + Line to draw fill to + brush : color_like, optional + Arguments accepted by :func:`~pyqtgraph.mkBrush`, used + to create the :class:`~QtGui.QBrush` instance used to draw the item + by default None + pen : color_like, optional + Arguments accepted by :func:`~pyqtgraph.mkColor`, used + to create the :class:`~QtGui.QPen` instance used to draw the item + by default ``None`` + fillRule : QtCore.Qt.FillRule, optional + FillRule to be applied to the underlying :class:`~QtGui.QPainterPath` + instance, by default ``QtCore.Qt.FillRule.OddEvenFill`` + + Raises + ------ + ValueError + Raised when ``None`` is passed in as either ``curve1`` + or ``curve2`` + TypeError + Raised when either ``curve1`` or ``curve2`` is not either + :class:`~pyqtgraph.PlotDataItem` or :class:`~pyqtgraph.PlotCurveItem` + """ + super().__init__() self.curves = None + self._fillRule = fillRule if curve1 is not None and curve2 is not None: self.setCurves(curve1, curve2) elif curve1 is not None or curve2 is not None: - raise Exception("Must specify two curves to fill between.") + raise ValueError("Must specify two curves to fill between.") if brush is not None: self.setBrush(brush) self.setPen(pen) self.updatePath() + + def fillRule(self): + return self._fillRule + + def setFillRule(self, fillRule: QtCore.Qt.FillRule=QtCore.Qt.FillRule.OddEvenFill): + """Set the underlying :class:`~QtGui.QPainterPath` to the specified + :class:`~QtCore.Qt.FillRule` + + This can be useful for allowing in the filling of voids. + + Parameters + ---------- + fillRule : QtCore.Qt.FillRule + A member of the :class:`~QtCore.Qt.FillRule` enum + """ + self._fillRule = fillRule + self.updatePath() def setBrush(self, *args, **kwds): - """Change the fill brush. Acceps the same arguments as pg.mkBrush()""" + """Change the fill brush. Accepts the same arguments as :func:`~pyqtgraph.mkBrush` + """ QtWidgets.QGraphicsPathItem.setBrush(self, fn.mkBrush(*args, **kwds)) def setPen(self, *args, **kwds): + """Change the fill pen. Accepts the same arguments as :func:`~pyqtgraph.mkColor` + """ QtWidgets.QGraphicsPathItem.setPen(self, fn.mkPen(*args, **kwds)) - def setCurves(self, curve1, curve2): - """Set the curves to fill between. - - Arguments must be instances of PlotDataItem or PlotCurveItem. - - Added in version 0.9.9 - """ + def setCurves( + self, + curve1: Union[PlotDataItem, PlotCurveItem], + curve2: Union[PlotDataItem, PlotCurveItem] + ): + """Method to set the Curves to draw the FillBetweenItem between + + Parameters + ---------- + curve1 : :class:`~pyqtgraph.PlotDataItem` | :class:`~pyqtgraph.PlotCurveItem` + Line to draw fill from + curve2 : :class:`~pyqtgraph.PlotDataItem` | :class:`~pyqtgraph.PlotCurveItem` + Line to draw fill to + + Raises + ------ + TypeError + Raised when input arguments are not either :class:`~pyqtgraph.PlotDataItem` or + :class:`~pyqtgraph.PlotCurveItem` + """ if self.curves is not None: for c in self.curves: try: @@ -45,7 +118,7 @@ def setCurves(self, curve1, curve2): curves = [curve1, curve2] for c in curves: - if not isinstance(c, PlotDataItem) and not isinstance(c, PlotCurveItem): + if not isinstance(c, (PlotDataItem, PlotCurveItem)): raise TypeError("Curves must be PlotDataItem or PlotCurveItem.") self.curves = curves curve1.sigPlotChanged.connect(self.curveChanged) @@ -55,7 +128,7 @@ def setCurves(self, curve1, curve2): def curveChanged(self): self.updatePath() - + def updatePath(self): if self.curves is None: self.setPath(QtGui.QPainterPath()) @@ -68,15 +141,17 @@ def updatePath(self): paths.append(c.getPath()) path = QtGui.QPainterPath() - transform = QtGui.QTransform() - ps1 = paths[0].toSubpathPolygons(transform) - ps2 = paths[1].toReversed().toSubpathPolygons(transform) + path.setFillRule(self.fillRule()) + + ps1 = paths[0].toSubpathPolygons() + ps2 = paths[1].toReversed().toSubpathPolygons() ps2.reverse() + if len(ps1) == 0 or len(ps2) == 0: self.setPath(QtGui.QPainterPath()) return - - + for p1, p2 in zip(ps1, ps2): path.addPolygon(p1 + p2) + self.setPath(path) diff --git a/pyqtgraph/graphicsItems/GradientEditorItem.py b/pyqtgraph/graphicsItems/GradientEditorItem.py index 7c67803d27..803e387ec6 100644 --- a/pyqtgraph/graphicsItems/GradientEditorItem.py +++ b/pyqtgraph/graphicsItems/GradientEditorItem.py @@ -1,6 +1,5 @@ import operator import weakref -from collections import OrderedDict import numpy as np @@ -8,30 +7,14 @@ from ..colormap import ColorMap from ..Qt import QtCore, QtGui, QtWidgets from ..widgets.SpinBox import SpinBox +from ..widgets.ColorMapMenu import ColorMapMenu from .GraphicsWidget import GraphicsWidget +from .GradientPresets import Gradients translate = QtCore.QCoreApplication.translate __all__ = ['TickSliderItem', 'GradientEditorItem', 'addGradientListToDocstring'] -Gradients = OrderedDict([ - ('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}), - ('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}), - ('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ), - ('bipolar', {'ticks': [(0.0, (0, 255, 255, 255)), (1.0, (255, 255, 0, 255)), (0.5, (0, 0, 0, 255)), (0.25, (0, 0, 255, 255)), (0.75, (255, 0, 0, 255))], 'mode': 'rgb'}), - ('spectrum', {'ticks': [(1.0, (255, 0, 255, 255)), (0.0, (255, 0, 0, 255))], 'mode': 'hsv'}), - ('cyclic', {'ticks': [(0.0, (255, 0, 4, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'hsv'}), - ('greyclip', {'ticks': [(0.0, (0, 0, 0, 255)), (0.99, (255, 255, 255, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'rgb'}), - ('grey', {'ticks': [(0.0, (0, 0, 0, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'}), - # Perceptually uniform sequential colormaps from Matplotlib 2.0 - ('viridis', {'ticks': [(0.0, (68, 1, 84, 255)), (0.25, (58, 82, 139, 255)), (0.5, (32, 144, 140, 255)), (0.75, (94, 201, 97, 255)), (1.0, (253, 231, 36, 255))], 'mode': 'rgb'}), - ('inferno', {'ticks': [(0.0, (0, 0, 3, 255)), (0.25, (87, 15, 109, 255)), (0.5, (187, 55, 84, 255)), (0.75, (249, 142, 8, 255)), (1.0, (252, 254, 164, 255))], 'mode': 'rgb'}), - ('plasma', {'ticks': [(0.0, (12, 7, 134, 255)), (0.25, (126, 3, 167, 255)), (0.5, (203, 71, 119, 255)), (0.75, (248, 149, 64, 255)), (1.0, (239, 248, 33, 255))], 'mode': 'rgb'}), - ('magma', {'ticks': [(0.0, (0, 0, 3, 255)), (0.25, (80, 18, 123, 255)), (0.5, (182, 54, 121, 255)), (0.75, (251, 136, 97, 255)), (1.0, (251, 252, 191, 255))], 'mode': 'rgb'}), - # turbo from https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html - ('turbo', {'ticks': [(0.0, (51, 27, 61, 255)), (0.125, (77, 110, 223, 255)), (0.25, (61, 185, 233, 255)), (0.375, (68, 238, 154, 255)), (0.5, (164, 250, 80, 255)), - (0.625, (235, 206, 76, 255)), (0.75, (247, 129, 55, 255)), (0.875, (206, 58, 32, 255)), (1.0, (119, 21, 19, 255))], 'mode': 'rgb'}), -]) def addGradientListToDocstring(): """Decorator to add list of current pre-defined gradients to the end of a function docstring.""" @@ -454,35 +437,8 @@ def __init__(self, *args, **kargs): self.hsvAction.setCheckable(True) self.hsvAction.triggered.connect(self._setColorModeToHSV) - self.menu = QtWidgets.QMenu() - - ## build context menu of gradients - l = self.length - self.length = 100 - global Gradients - for g in Gradients: - px = QtGui.QPixmap(100, 15) - p = QtGui.QPainter(px) - self.restoreState(Gradients[g]) - grad = self.getGradient() - brush = QtGui.QBrush(grad) - p.fillRect(QtCore.QRect(0, 0, 100, 15), brush) - p.end() - label = QtWidgets.QLabel() - label.setPixmap(px) - label.setContentsMargins(1, 1, 1, 1) - labelName = QtWidgets.QLabel(g) - hbox = QtWidgets.QHBoxLayout() - hbox.addWidget(labelName) - hbox.addWidget(label) - widget = QtWidgets.QWidget() - widget.setLayout(hbox) - act = QtWidgets.QWidgetAction(self) - act.setDefaultWidget(widget) - act.triggered.connect(self.contextMenuClicked) - act.name = g - self.menu.addAction(act) - self.length = l + self.menu = ColorMapMenu(showGradientSubMenu=True, showColorMapSubMenus=True) + self.menu.sigColorMapTriggered.connect(self.colorMapMenuClicked) self.menu.addSeparator() self.menu.addAction(self.rgbAction) self.menu.addAction(self.hsvAction) @@ -532,11 +488,14 @@ def showMenu(self, ev): #private self.menu.popup(ev.screenPos().toQPoint()) - def contextMenuClicked(self, b=None): + def colorMapMenuClicked(self, cmap): #private - #global Gradients - act = self.sender() - self.loadPreset(act.name) + if cmap.name.startswith("preset-gradient:"): + name = cmap.name.split(":")[1] + self.loadPreset(name) + else: + self.setColorMap(cmap) + self.showTicks(False) @addGradientListToDocstring() def loadPreset(self, name): diff --git a/pyqtgraph/graphicsItems/GradientPresets.py b/pyqtgraph/graphicsItems/GradientPresets.py new file mode 100644 index 0000000000..91f50d7021 --- /dev/null +++ b/pyqtgraph/graphicsItems/GradientPresets.py @@ -0,0 +1,21 @@ +__all__ = ['Gradients'] + + +Gradients = dict([ + ('thermal', {'ticks': [(0.3333, (185, 0, 0, 255)), (0.6666, (255, 220, 0, 255)), (1, (255, 255, 255, 255)), (0, (0, 0, 0, 255))], 'mode': 'rgb'}), + ('flame', {'ticks': [(0.2, (7, 0, 220, 255)), (0.5, (236, 0, 134, 255)), (0.8, (246, 246, 0, 255)), (1.0, (255, 255, 255, 255)), (0.0, (0, 0, 0, 255))], 'mode': 'rgb'}), + ('yellowy', {'ticks': [(0.0, (0, 0, 0, 255)), (0.2328863796753704, (32, 0, 129, 255)), (0.8362738179251941, (255, 255, 0, 255)), (0.5257586450247, (115, 15, 255, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'} ), + ('bipolar', {'ticks': [(0.0, (0, 255, 255, 255)), (1.0, (255, 255, 0, 255)), (0.5, (0, 0, 0, 255)), (0.25, (0, 0, 255, 255)), (0.75, (255, 0, 0, 255))], 'mode': 'rgb'}), + ('spectrum', {'ticks': [(1.0, (255, 0, 255, 255)), (0.0, (255, 0, 0, 255))], 'mode': 'hsv'}), + ('cyclic', {'ticks': [(0.0, (255, 0, 4, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'hsv'}), + ('greyclip', {'ticks': [(0.0, (0, 0, 0, 255)), (0.99, (255, 255, 255, 255)), (1.0, (255, 0, 0, 255))], 'mode': 'rgb'}), + ('grey', {'ticks': [(0.0, (0, 0, 0, 255)), (1.0, (255, 255, 255, 255))], 'mode': 'rgb'}), + # Perceptually uniform sequential colormaps from Matplotlib 2.0 + ('viridis', {'ticks': [(0.0, (68, 1, 84, 255)), (0.25, (58, 82, 139, 255)), (0.5, (32, 144, 140, 255)), (0.75, (94, 201, 97, 255)), (1.0, (253, 231, 36, 255))], 'mode': 'rgb'}), + ('inferno', {'ticks': [(0.0, (0, 0, 3, 255)), (0.25, (87, 15, 109, 255)), (0.5, (187, 55, 84, 255)), (0.75, (249, 142, 8, 255)), (1.0, (252, 254, 164, 255))], 'mode': 'rgb'}), + ('plasma', {'ticks': [(0.0, (12, 7, 134, 255)), (0.25, (126, 3, 167, 255)), (0.5, (203, 71, 119, 255)), (0.75, (248, 149, 64, 255)), (1.0, (239, 248, 33, 255))], 'mode': 'rgb'}), + ('magma', {'ticks': [(0.0, (0, 0, 3, 255)), (0.25, (80, 18, 123, 255)), (0.5, (182, 54, 121, 255)), (0.75, (251, 136, 97, 255)), (1.0, (251, 252, 191, 255))], 'mode': 'rgb'}), + # turbo from https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html + ('turbo', {'ticks': [(0.0, (51, 27, 61, 255)), (0.125, (77, 110, 223, 255)), (0.25, (61, 185, 233, 255)), (0.375, (68, 238, 154, 255)), (0.5, (164, 250, 80, 255)), + (0.625, (235, 206, 76, 255)), (0.75, (247, 129, 55, 255)), (0.875, (206, 58, 32, 255)), (1.0, (119, 21, 19, 255))], 'mode': 'rgb'}), +]) diff --git a/pyqtgraph/graphicsItems/GraphicsItem.py b/pyqtgraph/graphicsItems/GraphicsItem.py index 854004534a..438e6d2c25 100644 --- a/pyqtgraph/graphicsItems/GraphicsItem.py +++ b/pyqtgraph/graphicsItems/GraphicsItem.py @@ -493,10 +493,9 @@ def _updateView(self): ## disconnect from previous view if oldView is not None: - for signal, slot in [('sigRangeChanged', self.viewRangeChanged), - ('sigDeviceRangeChanged', self.viewRangeChanged), - ('sigTransformChanged', self.viewTransformChanged), - ('sigDeviceTransformChanged', self.viewTransformChanged)]: + Device = 'Device' if hasattr(oldView, 'sigDeviceRangeChanged') else '' + for signal, slot in [(f'sig{Device}RangeChanged', self.viewRangeChanged), + (f'sig{Device}TransformChanged', self.viewTransformChanged)]: try: getattr(oldView, signal).disconnect(slot) except (TypeError, AttributeError, RuntimeError): @@ -552,7 +551,7 @@ def viewRangeChanged(self): def viewTransformChanged(self): """ Called whenever the transformation matrix of the view has changed. - (eg, the view range has changed or the view was resized) + For example, when the view range has changed or the view was resized. Invalidates the viewRect cache. """ self._cachedView = None diff --git a/pyqtgraph/graphicsItems/ImageItem.py b/pyqtgraph/graphicsItems/ImageItem.py index 9a90ceccdd..936ff44356 100644 --- a/pyqtgraph/graphicsItems/ImageItem.py +++ b/pyqtgraph/graphicsItems/ImageItem.py @@ -1,11 +1,15 @@ +import os +import pathlib import warnings from collections.abc import Callable -import numpy +import numpy as np +import numpy.typing as npt from .. import colormap from .. import debug as debug from .. import functions as fn +from .. import functions_qimage from .. import getConfigOption from ..Point import Point from ..Qt import QtCore, QtGui, QtWidgets @@ -19,23 +23,48 @@ class ImageItem(GraphicsObject): """ - **Bases:** :class:`GraphicsObject ` + Graphics object used to display image data. + + ImageItem can render images with 1, 3 or 4 channels, use lookup tables to apply + false colors to images, and users can either set levels limits, or rely on + the auto-sampling. + + Performance can vary wildly based on the attributes of the inputs provided, see + :ref:`performance ` for guidance if performance is an + important factor. + + There is optional `numba` and `cupy` support. + + **Bases:** :class:`pyqtgraph.GraphicsObject` + + Parameters + ---------- + image : np.ndarray or None, default None + Image data. + **kargs : dict, optional + Arguments directed to `setImage` and `setOpts`, refer to each method for + documentation for possible arguments. + + Signals + ------- + sigImageChanged: :class:`Signal` + Emitted when the image is changed. + sigRemoveRequested: :class:`Signal` + Emitted when there is a request to remove the image. Signal emits the instance + of the :class:`~pyqtgraph.ImageItem` whose removal is requested. + + See Also + -------- + setImage : + For descriptions of available keyword arguments. + setOpts : + For information on supported formats. """ - # Overall description of ImageItem (including examples) moved to documentation text sigImageChanged = QtCore.Signal() - sigRemoveRequested = QtCore.Signal(object) # self; emitted when 'remove' is selected from context menu + sigRemoveRequested = QtCore.Signal(object) - def __init__(self, image=None, **kargs): - """ - See :func:`~pyqtgraph.ImageItem.setOpts` for further keyword arguments and - and :func:`~pyqtgraph.ImageItem.setImage` for information on supported formats. - - Parameters - ---------- - image: np.ndarray, optional - Image data - """ - GraphicsObject.__init__(self) + def __init__(self, image: np.ndarray | None=None, **kargs): + super().__init__() self.menu = None self.image = None ## original image data self.qimage = None ## rendered image for display @@ -53,15 +82,12 @@ def __init__(self, image=None, **kargs): self._xp = None # either numpy or cupy, to match the image data self._defferedLevels = None self._imageHasNans = None # None : not yet known + self._imageNanLocations = None self.axisOrder = getConfigOption('imageAxisOrder') - self._dataTransform = self._inverseDataTransform = None + self._dataTransform = self._inverseDataTransform = QtGui.QTransform() self._update_data_transforms( self.axisOrder ) # install initial transforms - # In some cases, we use a modified lookup table to handle both rescaling - # and LUT more efficiently - self._effectiveLut = None - self.drawKernel = None self.border = None self.removable = False @@ -71,81 +97,105 @@ def __init__(self, image=None, **kargs): else: self.setOpts(**kargs) - def setCompositionMode(self, mode): + def setCompositionMode(self, mode: QtGui.QPainter.CompositionMode): """ - Change the composition mode of the item. This is useful when overlaying - multiple items. + Change the composition mode of the item, useful when overlaying multiple items. Parameters ---------- - mode : ``QtGui.QPainter.CompositionMode`` + mode : :class:`QPainter.CompositionMode ` Composition of the item, often used when overlaying items. Common options include: - ``QPainter.CompositionMode.CompositionMode_SourceOver`` (Default) - Image replaces the background if it is opaque. Otherwise, it uses - the alpha channel to blend the image with the background. - - ``QPainter.CompositionMode.CompositionMode_Overlay`` Image color is - mixed with the background color to reflect the lightness or - darkness of the background - - ``QPainter.CompositionMode.CompositionMode_Plus`` Both the alpha - and color of the image and background pixels are added together. - - ``QPainter.CompositionMode.CompositionMode_Plus`` The output is the - image color multiplied by the background. - - See ``QPainter::CompositionMode`` in the Qt Documentation for more - options and details + * `QPainter.CompositionMode.CompositionMode_SourceOver` + Image replaces the background if it is opaque. Otherwise, it uses the + alpha channel to blend the image with the background, default. + * `QPainter.CompositionMode.CompositionMode_Overlay` Image color is + mixed with the background color to reflect the lightness or darkness of + the background. + * `QPainter.CompositionMode.CompositionMode_Plus` Both the alpha and + color of the image and background pixels are added together. + * `QPainter.CompositionMode.CompositionMode_Plus` The output is the + image color multiplied by the background. + + See :class:`QPainter.CompositionMode ` in the Qt + documentation for more options and details. + + See Also + -------- + :class:`QPainter.CompositionMode ` : + Details all the possible composition mode options accepted. """ self.paintMode = mode self.update() def setBorder(self, b): """ - Defines the border drawn around the image. Accepts all arguments supported by - :func:`~pyqtgraph.mkPen`. + Define the color of the border drawn around the image. + + Parameters + ---------- + b : color_like + Accepts all arguments supported by :func:`~pyqtgraph.mkPen`. """ self.border = fn.mkPen(b) self.update() - def width(self): + def width(self) -> int | None: if self.image is None: return None axis = 0 if self.axisOrder == 'col-major' else 1 return self.image.shape[axis] - def height(self): + def height(self) -> int | None: if self.image is None: return None axis = 1 if self.axisOrder == 'col-major' else 0 return self.image.shape[axis] - def channels(self): + def channels(self) -> int | None: if self.image is None: return None return self.image.shape[2] if self.image.ndim == 3 else 1 - def boundingRect(self): + def boundingRect(self) -> QtCore.QRectF: if self.image is None: return QtCore.QRectF(0., 0., 0., 0.) - return QtCore.QRectF(0., 0., float(self.width()), float(self.height())) + if (width := self.width()) is None: + width = 0. + if (height := self.height()) is None: + height = 0. + return QtCore.QRectF(0., 0., float(width), float(height)) - def setLevels(self, levels, update=True): + def setLevels(self, levels: npt.ArrayLike | None, update: bool=True): """ - Sets image scaling levels. - See :func:`makeARGB ` for more details on how levels are applied. + Set image scaling levels. + + Calling this method, even with ``levels=None`` will disable auto leveling + which is equivalent to :meth:`setImage` with ``autoLevels=False``. Parameters ---------- - levels: array_like - - ``[blackLevel, whiteLevel]`` - sets black and white levels for monochrome data and can be used with a lookup table. - - ``[[minR, maxR], [minG, maxG], [minB, maxB]]`` - sets individual scaling for RGB values. Not compatible with lookup tables. - update: bool, optional - Controls if image immediately updates to reflect the new levels. + levels : array_like or None + Sets the numerical values that correspond to the limits of the color range. + + * ``[blackLevel, whiteLevel]`` + sets black and white levels for monochrome data and can be used with a + lookup table. + * ``[[minR, maxR], [minG, maxG], [minB, maxB]]`` + sets individual scaling for RGB values. Not compatible with lookup + tables. + * ``None`` + Disables the application of levels, but setting to ``None`` prevents + the auto-levels mechanism from sampling the image. Not compatible with + images that use floating point dtypes. + update : bool, default True + Update the image immediately to reflect the new levels. + + See Also + -------- + pyqtgraph.functions.makeARGB + For more details on how levels are applied. """ if self._xp is None: self.levels = levels @@ -154,25 +204,37 @@ def setLevels(self, levels, update=True): if levels is not None: levels = self._xp.asarray(levels) self.levels = levels - self._effectiveLut = None if update: self.updateImage() - def getLevels(self): + def getLevels(self) -> np.ndarray | None: """ - Returns the list representing the current level settings. See :func:`~setLevels`. - When ``autoLevels`` is active, the format is ``[blackLevel, whiteLevel]``. + Return the array representing the current level settings. + + See :meth:`setLevels`. When `autoLevels` is active, the format is + ``[blackLevel, whiteLevel]``. + + Returns + ------- + np.ndarray or None + The value that the levels are set to. """ return self.levels - def setColorMap(self, colorMap): + def setColorMap(self, colorMap: colormap.ColorMap | str): """ - Sets a color map for false color display of a monochrome image. + Set a color map for false color display of a monochrome image. Parameters ---------- colorMap : :class:`~pyqtgraph.ColorMap` or `str` - A string argument will be passed to :func:`colormap.get() ` + A string argument will be passed to + :func:`colormap.get() `. + + Raises + ------ + TypeError + Raised when `colorMap` is not of type `str` or :class:`~pyqtgraph.ColorMap`. """ if isinstance(colorMap, colormap.ColorMap): self._colorMap = colorMap @@ -182,206 +244,289 @@ def setColorMap(self, colorMap): raise TypeError("'colorMap' argument must be ColorMap or string") self.setLookupTable( self._colorMap.getLookupTable(nPts=256) ) - def getColorMap(self): + def getColorMap(self) -> colormap.ColorMap | None: """ - Returns the assigned :class:`pyqtgraph.ColorMap`, or `None` if not available + Retrieve the :class:`~pyqtgraph.ColorMap` object currently used. + + Returns + ------- + ColorMap or None + The assigned :class:`~pyqtgraph.ColorMap`, or `None` if not available. """ return self._colorMap - def setLookupTable(self, lut, update=True): + def setLookupTable(self, lut: npt.ArrayLike | Callable, update: bool=True): """ - Sets lookup table ``lut`` to use for false color display of a monochrome image. See :func:`makeARGB ` for more - information on how this is used. Optionally, `lut` can be a callable that accepts the current image as an - argument and returns the lookup table to use. + Set lookup table `lut` to use for false color display of a monochrome image. Ordinarily, this table is supplied by a :class:`~pyqtgraph.HistogramLUTItem`, :class:`~pyqtgraph.GradientEditorItem` or :class:`~pyqtgraph.ColorBarItem`. - - Setting ``update = False`` avoids an immediate image update. + + Parameters + ---------- + lut : array_like or callable + If `lut` is an np.ndarray, ensure the dtype is `np.uint8`. Alternatively + can be a callable that accepts the current image as an argument and + returns the lookup table to use. Support for callable will be removed + in a future version of pyqtgraph. + update : bool, default True + Update the intermediate image. + + See Also + -------- + :func:`pyqtgraph.functions.makeARGB` + See this function for more information on how this is used. + :meth:`ColorMap.getLookupTable ` + Can construct a lookup table from a :class:`~pyqtgraph.ColorMap` object. + + Notes + ----- + For performance reasons, if not passing a callable, every effort should be made + to keep the number of entries to `<= 256`. """ + if lut is not self.lut: if self._xp is not None: lut = self._ensure_proper_substrate(lut, self._xp) self.lut = lut - self._effectiveLut = None if update: self.updateImage() @staticmethod - def _ensure_proper_substrate(data, substrate): - if data is None or isinstance(data, Callable) or isinstance(data, substrate.ndarray): + def _ensure_proper_substrate(data: Callable | npt.ArrayLike, substrate) -> np.ndarray: + if data is None or isinstance(data, (Callable, substrate.ndarray)): return data cupy = getCupy() if substrate == cupy and not isinstance(data, cupy.ndarray): data = cupy.asarray(data) - elif substrate == numpy: + elif substrate == np: if cupy is not None and isinstance(data, cupy.ndarray): data = data.get() else: - data = numpy.asarray(data) + data = np.asarray(data) return data - def setAutoDownsample(self, active=True): + def setAutoDownsample(self, active: bool=True): """ - Controls automatic downsampling for this ImageItem. + Control automatic downsampling for this ImageItem. - If `active` is `True`, the image is automatically downsampled to match the - screen resolution. This improves performance for large images and - reduces aliasing. If `autoDownsample` is not specified, then ImageItem will - choose whether to downsample the image based on its size. - - `False` disables automatic downsampling. + Parameters + ---------- + active : bool, default True + If `active` is ``True``, the image is automatically downsampled to match + the screen resolution. This improves performance for large images and + reduces aliasing. If `autoDownsample` is not specified, then ImageItem will + choose whether to downsample the image based on its size. ``False`` + disables automatic downsampling. """ self.autoDownsample = active self._renderRequired = True self.update() - def setOpts(self, update=True, **kargs): + def setOpts(self, update: bool=True, **kwargs): """ - Sets display and processing options for this ImageItem. :func:`~pyqtgraph.ImageItem.__init__` and - :func:`~pyqtgraph.ImageItem.setImage` support all keyword arguments listed here. + Set display and processing options for this ImageItem. + + :class:`~pyqtgraph.ImageItem` and :meth:`setImage` support all keyword + arguments listed here. Parameters ---------- - autoDownsample: bool - See :func:`~pyqtgraph.ImageItem.setAutoDownsample`. - axisOrder: str - | `'col-major'`: The shape of the array represents (width, height) of the image. This is the default. - | `'row-major'`: The shape of the array represents (height, width). - border: bool - Sets a pen to draw to draw an image border. See :func:`~pyqtgraph.ImageItem.setBorder`. - compositionMode: - See :func:`~pyqtgraph.ImageItem.setCompositionMode` - colorMap: :class:`~pyqtgraph.ColorMap` or `str` - Sets a color map. A string will be passed to :func:`colormap.get() ` - lut: array_like - Sets a color lookup table to use when displaying the image. - See :func:`~pyqtgraph.ImageItem.setLookupTable`. - levels: array_like - Shape of (min, max). Sets minimum and maximum values to use when - rescaling the image data. By default, these will be set to the - estimated minimum and maximum values in the image. If the image array - has dtype uint8, no rescaling is necessary. See - :func:`~pyqtgraph.ImageItem.setLevels`. - opacity: float - Overall opacity for an RGB image. Between 0.0-1.0. - rect: :class:`QRectF`, :class:`QRect` or array_like - Displays the current image within the specified rectangle in plot - coordinates. If ``array_like``, should be of the of ``floats - (`x`,`y`,`w`,`h`)`` . See :func:`~pyqtgraph.ImageItem.setRect`. - update : bool, optional - Controls if image immediately updates to reflect the new options. + update : bool, default True + Controls if image immediately updates to reflect the new options. + + **kwargs : dict, optional + Extra arguments that are directed to the respective methods. Expected + keys include: + + * `autoDownsample` whose value is directed to :meth:`setAutoDownsample` + * `axisOrder`, which needs to be one of {'row-major', 'col-major'}, + determines the relationship between the numpy axis and visual axis + of the data. + * `border`, whose value is directed to :meth:`setBorder` + * `colorMap`, whose value is directed to :meth:`setColorMap` + * `compositionMode`, whose value is directed to :meth:`setCompositionMode` + * `levels` whose value is directed to :meth:`setLevels` + * `lut`, whose value is directed to :meth:`setLookupTable` + * `opacify` whose value is directed to + :meth:`QGraphicsItem.setOpacity ` + * `rect` whose value is directed to :meth:`setRect` + * `removable` boolean, determines if the context menu is available + + See Also + -------- + :meth:`setAutoDownsample` + Accepts the value of ``kwargs['autoDownsample']``. + :meth:`setBorder` + Accepts the value of ``kwargs['border']``. + :meth:`setColorMap` + Accepts the value of ``kwargs['colorMap']``. + :meth:`setCompositionMode` + Accepts the value of ``kwargs['compositionMode']``. + :meth:`setImage` + Accepts the value of ``kwargs['image']``. + :meth:`setLevels` + Accepts the value of ``kwargs['levels']``. + :meth:`setLookupTable` + Accepts the value of ``kwargs['lut']``. + :meth:`QGraphicsItem.setOpacity ` + Accepts the value of ``kwargs['opacity']``. + :meth:`setRect` + Accepts the value of ``kwargs['rect']``. """ - if 'axisOrder' in kargs: - val = kargs['axisOrder'] + if 'axisOrder' in kwargs: + val = kwargs['axisOrder'] if val not in ('row-major', 'col-major'): raise ValueError("axisOrder must be either 'row-major' or 'col-major'") self.axisOrder = val self._update_data_transforms(self.axisOrder) # update cached transforms - if 'colorMap' in kargs: - self.setColorMap(kargs['colorMap']) - if 'lut' in kargs: - self.setLookupTable(kargs['lut'], update=update) - if 'levels' in kargs: - self.setLevels(kargs['levels'], update=update) + if 'colorMap' in kwargs: + self.setColorMap(kwargs['colorMap']) + if 'lut' in kwargs: + self.setLookupTable(kwargs['lut'], update=update) + if 'levels' in kwargs: + self.setLevels(kwargs['levels'], update=update) #if 'clipLevel' in kargs: #self.setClipLevel(kargs['clipLevel']) - if 'opacity' in kargs: - self.setOpacity(kargs['opacity']) - if 'compositionMode' in kargs: - self.setCompositionMode(kargs['compositionMode']) - if 'border' in kargs: - self.setBorder(kargs['border']) - if 'removable' in kargs: - self.removable = kargs['removable'] + if 'opacity' in kwargs: + self.setOpacity(kwargs['opacity']) + if 'compositionMode' in kwargs: + self.setCompositionMode(kwargs['compositionMode']) + if 'border' in kwargs: + self.setBorder(kwargs['border']) + if 'removable' in kwargs: + self.removable = kwargs['removable'] self.menu = None - if 'autoDownsample' in kargs: - self.setAutoDownsample(kargs['autoDownsample']) - if 'rect' in kargs: - self.setRect(kargs['rect']) + if 'autoDownsample' in kwargs: + self.setAutoDownsample(kwargs['autoDownsample']) + if 'rect' in kwargs: + self.setRect(kwargs['rect']) if update: self.update() def setRect(self, *args): """ - setRect(rect) or setRect(x,y,w,h) - - Sets translation and scaling of this ImageItem to display the current image within the rectangle given - as ``rect`` (:class:`QtCore.QRect` or :class:`QtCore.QRectF`), or described by parameters `x, y, w, h`, - defining starting position, width and height. + Set view rectangle for the :class:`~pyqtgraph.ImageItem` to occupy. - This method cannot be used before an image is assigned. - See the :ref:`examples ` for how to manually set transformations. + In addition to accepting a :class:`QRectF`, you can pass the numerical values + representing the `x, y, w, h`, where `x, y` represent the x, y coordinates + of the top left corner, and `w` and `h` represent the width and height + respectively. + + Parameters + ---------- + *args : tuple + Contains one of :class:`QRectF`, :class:`QRect`, or arguments that can be + used to construct :class:`QRectF`. + + See Also + -------- + :class:`QRectF` : + See constructor methods for allowable `*args`. + + Notes + ----- + This method cannot be used before an image is assigned. See the + :ref:`examples ` for how to manually set transformations. """ - if len(args) == 0: - self.resetTransform() # reset scaling and rotation when called without argument + if not args: + # reset scaling and rotation when called without argument + self.resetTransform() return if isinstance(args[0], (QtCore.QRectF, QtCore.QRect)): rect = args[0] # use QRectF or QRect directly else: if hasattr(args[0],'__len__'): args = args[0] # promote tuple or list of values - rect = QtCore.QRectF( *args ) # QRectF(x,y,w,h), but also accepts other initializers + # QRectF(x,y,w,h), but also accepts other initializers + rect = QtCore.QRectF( *args ) tr = QtGui.QTransform() tr.translate(rect.left(), rect.top()) - tr.scale(rect.width() / self.width(), rect.height() / self.height()) + + if (width := self.width()) is None: + width = 1. + + if (height := self.height()) is None: + height = 1. + + tr.scale(rect.width() / width, rect.height() / height) self.setTransform(tr) def clear(self): """ - Clears the assigned image. + Clear the assigned image. """ self.image = None self.prepareGeometryChange() self.informViewBoundsChanged() self.update() - def _buildQImageBuffer(self, shape): - self._displayBuffer = numpy.empty(shape[:2] + (4,), dtype=numpy.ubyte) + def _buildQImageBuffer(self, shape: tuple[int, int, int]): + self._displayBuffer = np.empty(shape[:2] + (4,), dtype=np.ubyte) if self._xp == getCupy(): - self._processingBuffer = self._xp.empty(shape[:2] + (4,), dtype=self._xp.ubyte) + self._processingBuffer = self._xp.empty( + shape[:2] + (4,), + dtype=self._xp.ubyte + ) else: self._processingBuffer = self._displayBuffer self.qimage = None - def setImage(self, image=None, autoLevels=None, **kargs): + def setImage( + self, + image: np.ndarray | None=None, + autoLevels: bool | None=None, + levelSamples: int = 65536, + **kwargs + ): """ - Updates the image displayed by this ImageItem. For more information on how the image - is processed before displaying, see :func:`~pyqtgraph.makeARGB`. - - For backward compatibility, image data is assumed to be in column-major order (column, row) by default. - However, most data is stored in row-major order (row, column). It can either be transposed before assignment:: - - imageitem.setImage(imagedata.T) - - or the interpretation of the data can be changed locally through the ``axisOrder`` keyword or by changing the - `imageAxisOrder` :ref:`global configuration option ` + Update the image displayed by this ImageItem. - All keywords supported by :func:`~pyqtgraph.ImageItem.setOpts` are also allowed here. + All keywords supported by :meth:`setOpts` are also allowed here. Parameters ---------- - image: np.ndarray, optional - Image data given as NumPy array with an integer or floating - point dtype of any bit depth. A 2-dimensional array describes single-valued (monochromatic) data. - A 3-dimensional array is used to give individual color components. The third dimension must - be of length 3 (RGB) or 4 (RGBA). - rect: QRectF or QRect or array_like, optional - If given, sets translation and scaling to display the image within the - specified rectangle. If ``array_like`` should be the form of floats - ``[x, y, w, h]`` See :func:`~pyqtgraph.ImageItem.setRect` - autoLevels: bool, optional - If `True`, ImageItem will automatically select levels based on the maximum and minimum values encountered - in the data. For performance reasons, this search subsamples the images and may miss individual bright or - or dark points in the data set. - - If `False`, the search will be omitted. + image : np.ndarray or None, default None + Image data given as NumPy array with an integer or floating point dtype of + any bit depth. A 2-dimensional array describes single-valued + (monochromatic) data. A 3-dimensional array is used to give individual + color components. The third dimension must be of length 3 (RGB) or 4 + (RGBA). ``np.nan`` values are treated as transparent pixels. + autoLevels : bool or None, default None + If ``True``, ImageItem will automatically select levels based on the maximum + and minimum values encountered in the data. For performance reasons, this + search sub-samples the images and may miss individual bright or dark points + in the data set. If ``False``, the search will be omitted. If ``None``, and + the levels keyword argument is given, it will switch to ``False``, if the + `levels` argument is omitted, it will switch to ``True``. + levelSamples : int, default 65536 + Only used when ``autoLevels is None``. When determining minimum and + maximum values, ImageItem only inspects a subset of pixels no larger than + this number. Setting this larger than the total number of pixels considers + all values. See `quickMinMax`. + **kwargs : dict, optional + Extra arguments that are passed to `setOpts`. + + See Also + -------- + quickMinMax + See this method for how levelSamples value is utilized. + :func:`pyqtgraph.functions.makeARGB` + See this function for how image data is modified prior to rendering. + + Notes + ----- + For backward compatibility, image data is assumed to be in column-major order + (column, row) by default. However, most data is stored in row-major order + (row, column). It can either be transposed before assignment + + .. code-block:: python - The default is `False` if a ``levels`` keyword argument is given, and `True` otherwise. - levelSamples: int, default 65536 - When determining minimum and maximum values, ImageItem - only inspects a subset of pixels no larger than this number. - Setting this larger than the total number of pixels considers all values. + imageitem.setImage(imagedata.T) + + or the interpretation of the data can be changed locally through the + `axisOrder` keyword or by changing the `imageAxisOrder` + :ref:`global configuration option `. """ profile = debug.Profiler() @@ -392,20 +537,24 @@ def setImage(self, image=None, autoLevels=None, **kargs): else: old_xp = self._xp cp = getCupy() - self._xp = cp.get_array_module(image) if cp else numpy + self._xp = cp.get_array_module(image) if cp else np gotNewData = True processingSubstrateChanged = old_xp != self._xp if processingSubstrateChanged: self._processingBuffer = None - shapeChanged = (processingSubstrateChanged or self.image is None or image.shape != self.image.shape) + shapeChanged = ( + processingSubstrateChanged or + self.image is None or + image.shape != self.image.shape + ) image = image.view() - if self.image is None or image.dtype != self.image.dtype: - self._effectiveLut = None self.image = image self._imageHasNans = None - if self.image.shape[0] > 2**15-1 or self.image.shape[1] > 2**15-1: - if 'autoDownsample' not in kargs: - kargs['autoDownsample'] = True + self._imageNanLocations = None + if 'autoDownsample' not in kwargs and ( + self.image.shape[0] > 2**15-1 or self.image.shape[1] > 2**15-1 + ): + kwargs['autoDownsample'] = True if shapeChanged: self.prepareGeometryChange() self.informViewBoundsChanged() @@ -413,22 +562,18 @@ def setImage(self, image=None, autoLevels=None, **kargs): profile() if autoLevels is None: - if 'levels' in kargs: - autoLevels = False - else: - autoLevels = True + autoLevels = 'levels' not in kwargs if autoLevels: - level_samples = kargs.pop('levelSamples', 2**16) - mn, mx = self.quickMinMax( targetSize=level_samples ) + mn, mx = self.quickMinMax( targetSize=levelSamples ) # mn and mx can still be NaN if the data is all-NaN if mn == mx or self._xp.isnan(mn) or self._xp.isnan(mx): mn = 0 mx = 255 - kargs['levels'] = [mn,mx] + kwargs['levels'] = self._xp.asarray((mn,mx)) profile() - self.setOpts(update=False, **kargs) + self.setOpts(update=False, **kwargs) profile() @@ -444,8 +589,15 @@ def setImage(self, image=None, autoLevels=None, **kargs): self._defferedLevels = None self.setLevels((levels)) - def _update_data_transforms(self, axisOrder='col-major'): - """ Sets up the transforms needed to map between input array and display """ + def _update_data_transforms(self, axisOrder: str='col-major'): + """ + Set up the transforms needed to map between input array and display. + + Parameters + ---------- + axisOrder : { 'col-major', 'row-major' } + The axis order to update the data transformation to. + """ self._dataTransform = QtGui.QTransform() self._inverseDataTransform = QtGui.QTransform() if self.axisOrder == 'row-major': # transpose both @@ -456,25 +608,37 @@ def _update_data_transforms(self, axisOrder='col-major'): def dataTransform(self): """ - Returns the transform that maps from this image's input array to its - local coordinate system. + Get the transform mapping image array to local coordinate system. - This transform corrects for the transposition that occurs when image data - is interpreted in row-major order. + This transform corrects for the transposition that occurs when image data is + interpreted in row-major order. :meta private: + + Returns + ------- + :class:`QTransform` + The transform that is used for mapping. """ # Might eventually need to account for downsampling / clipping here # transforms are updated in setOpts call. return self._dataTransform - def inverseDataTransform(self): - """Return the transform that maps from this image's local coordinate - system to its input array. - - See dataTransform() for more information. + def inverseDataTransform(self) -> QtGui.QTransform: + """ + Get the transform mapping local coordinate system to image array. :meta private: + + Returns + ------- + :class:`QTransform` + The transform that is used for mapping. + + See Also + -------- + dataTransform + See dataTransform() for more information. """ # transforms are updated in setOpts call. return self._inverseDataTransform @@ -485,35 +649,40 @@ def mapToData(self, obj): def mapFromData(self, obj): return self._dataTransform.map(obj) - def quickMinMax(self, targetSize=1e6): + def quickMinMax(self, targetSize: int=1_000_000) -> tuple[float, float]: """ - Estimates the min/max values of the image data by subsampling. - Subsampling is performed at regular strides chosen to evaluate a number of samples - equal to or less than `targetSize`. - - Returns (`min`, `max`). + Estimate the min and max values of the image data by sub-sampling. + + Sampling is performed at regular strides chosen to evaluate a number of + samples equal to or less than `targetSize`. Returns the estimated min and max + values of the image data. + + Parameters + ---------- + targetSize : int, default 1_000_000 + The number of pixels to downsample the image to. + + Returns + ------- + float, float + Estimated minimum and maximum values of the image data. """ + data = self.image - if targetSize < 2: # keep at least two pixels - targetSize = 2 + if data is None: + # image hasn't been set yet + return 0., 0. + targetSize = max(targetSize, 2) # keep at least 2 pixels while True: h, w = data.shape[:2] if h * w <= targetSize: break - if h > w: - data = data[::2, ::] # downsample first axis - else: - data = data[::, ::2] # downsample second axis + data = data[::2, ::] if h > w else data[::, ::2] return self._xp.nanmin(data), self._xp.nanmax(data) def updateImage(self, *args, **kargs): - ## used for re-rendering qimage from self.image. - - ## can we make any assumptions here that speed things up? - ## dtype, range, size are all the same? defaults = { 'autoLevels': False, - } - defaults.update(kargs) + } | kargs return self.setImage(*args, **defaults) def render(self): @@ -526,7 +695,10 @@ def render(self): if self.image.ndim == 2 or self.image.shape[2] == 1: self.lut = self._ensure_proper_substrate(self.lut, self._xp) if isinstance(self.lut, Callable): - lut = self._ensure_proper_substrate(self.lut(self.image, 256), self._xp) + lut = self._ensure_proper_substrate( + self.lut(self.image, 256), + self._xp + ) else: lut = self.lut else: @@ -558,31 +730,49 @@ def render(self): image = image.swapaxes(0, 1) levels = self.levels - augmented_alpha = False + + if self._imageHasNans is None: + # awkward, but fastest numpy native nan evaluation + self._imageHasNans = ( + image.dtype.kind == 'f' and + self._xp.isnan(image.min()) + ) + self._imageNanLocations = None + + qimage = None if lut is not None and lut.dtype != self._xp.uint8: - # Both _try_rescale_float() and _try_combine_lut() assume that - # lut is of type uint8. It is considered a usage error if that - # is not the case. - # However, the makeARGB() codepath has previously allowed such + # try_make_image() assumes that lut is of type uint8. + # It is considered a usage error if that is not the case. + # However, the makeARGB() code-path has previously allowed such # a usage to work. Rather than fail outright, we delegate this # case to makeARGB(). warnings.warn( - "Using non-uint8 LUTs is an undocumented accidental feature and may " + ("Using non-uint8 LUTs is an undocumented accidental feature and may " "be removed at some point in the future. Please open an issue if you " - "instead believe this to be worthy of protected inclusion in pyqtgraph.", - DeprecationWarning, stacklevel=2) - elif image.dtype.kind == 'f': - image, levels, lut, augmented_alpha = self._try_rescale_float(image, levels, lut) - # if we succeeded, we will have an uint8 image with levels None. - # lut if not None will have <= 256 entries - - # if the image data is a small int, then we can combine levels + lut - # into a single lut for better performance - elif image.dtype in (self._xp.ubyte, self._xp.uint16): - image, levels, lut, augmented_alpha = self._try_combine_lut(image, levels, lut) - - qimage = self._try_make_qimage(image, levels, lut, augmented_alpha) + "instead believe this to be worthy of protected inclusion in " + "pyqtgraph."), + DeprecationWarning, + stacklevel=2 + ) + + elif not self._imageHasNans: + qimage = functions_qimage.try_make_qimage(image, levels=levels, lut=lut) + + elif image.ndim in (2, 3): + # float images with nans + if self._imageNanLocations is None: + # the number of nans is expected to be small + nanmask = self._xp.isnan(image) + if nanmask.ndim == 3: + nanmask = nanmask.any(axis=2) + self._imageNanLocations = nanmask.nonzero() + qimage = functions_qimage.try_make_qimage( + image, + levels=levels, + lut=lut, + transparentLocations=self._imageNanLocations + ) if qimage is not None: self._processingBuffer = None @@ -592,278 +782,24 @@ def render(self): self._unrenderable = False return - if self._processingBuffer is None or self._processingBuffer.shape[:2] != image.shape[:2]: + if ( + self._processingBuffer is None or + self._processingBuffer.shape[:2] != image.shape[:2] + ): self._buildQImageBuffer(image.shape) fn.makeARGB(image, lut=lut, levels=levels, output=self._processingBuffer) if self._xp == getCupy(): self._processingBuffer.get(out=self._displayBuffer) - self.qimage = fn.ndarray_to_qimage(self._displayBuffer, QtGui.QImage.Format.Format_ARGB32) + self.qimage = fn.ndarray_to_qimage( + self._displayBuffer, + QtGui.QImage.Format.Format_ARGB32 + ) self._renderRequired = False self._unrenderable = False - def _try_rescale_float(self, image, levels, lut): - xp = self._xp - augmented_alpha = False - - can_handle = False - while True: - if levels is None or levels.ndim != 1: - # float images always need levels - # can't handle multi-channel levels - break - - # awkward, but fastest numpy native nan evaluation - if self._imageHasNans is None: - self._imageHasNans = xp.isnan(image.min()) - - if self._imageHasNans: - # don't handle images with nans - # this should be an uncommon case - break - - can_handle = True - break - - if not can_handle: - return image, levels, lut, augmented_alpha - - # Decide on maximum scaled value - if lut is not None: - scale = lut.shape[0] - num_colors = lut.shape[0] - else: - scale = 255. - num_colors = 256 - dtype = xp.min_scalar_type(num_colors-1) - - minVal, maxVal = levels - if minVal == maxVal: - maxVal = xp.nextafter(maxVal, 2*maxVal) - rng = maxVal - minVal - rng = 1 if rng == 0 else rng - - fn_numba = fn.getNumbaFunctions() - if xp == numpy and image.flags.c_contiguous and dtype == xp.uint16 and fn_numba is not None: - lut, augmented_alpha = self._convert_2dlut_to_1dlut(lut) - image = fn_numba.rescale_and_lookup1d(image, scale/rng, minVal, lut) - if image.dtype == xp.uint32: - image = image[..., xp.newaxis].view(xp.uint8) - return image, None, None, augmented_alpha - else: - image = fn.rescaleData(image, scale/rng, offset=minVal, dtype=dtype, clip=(0, num_colors-1)) - - levels = None - - if image.dtype == xp.uint16 and image.ndim == 2: - image, augmented_alpha = self._apply_lut_for_uint16_mono(image, lut) - lut = None - - # image is now of type uint8 - return image, levels, lut, augmented_alpha - - def _try_combine_lut(self, image, levels, lut): - augmented_alpha = False - xp = self._xp - - can_handle = False - while True: - if levels is not None and levels.ndim != 1: - # can't handle multi-channel levels - break - if image.dtype == xp.uint16 and levels is None and \ - image.ndim == 3 and image.shape[2] == 3: - # uint16 rgb can't be directly displayed, so make it - # pass through effective lut processing - levels = [0, 65535] - if levels is None and lut is None: - # nothing to combine - break - - can_handle = True - break - - if not can_handle: - return image, levels, lut, augmented_alpha - - # distinguish between lut for levels and colors - levels_lut = None - colors_lut = lut - - eflsize = 2**(image.itemsize*8) - if levels is None: - info = xp.iinfo(image.dtype) - minlev, maxlev = info.min, info.max - else: - minlev, maxlev = levels - levdiff = maxlev - minlev - levdiff = 1 if levdiff == 0 else levdiff # don't allow division by 0 - - if colors_lut is None: - if image.dtype == xp.ubyte and image.ndim == 2: - # uint8 mono image - ind = xp.arange(eflsize) - levels_lut = fn.rescaleData(ind, scale=255./levdiff, - offset=minlev, dtype=xp.ubyte) - # image data is not scaled. instead, levels_lut is used - # as (grayscale) Indexed8 ColorTable to get the same effect. - # due to the small size of the input to rescaleData(), we - # do not bother caching the result - return image, None, levels_lut, augmented_alpha - else: - # uint16 mono, uint8 rgb, uint16 rgb - # rescale image data by computation instead of by memory lookup - image = fn.rescaleData(image, scale=255./levdiff, - offset=minlev, dtype=xp.ubyte) - return image, None, colors_lut, augmented_alpha - else: - num_colors = colors_lut.shape[0] - effscale = num_colors / levdiff - lutdtype = xp.min_scalar_type(num_colors - 1) - - if image.dtype == xp.ubyte or lutdtype != xp.ubyte: - # combine if either: - # 1) uint8 mono image - # 2) colors_lut has more entries than will fit within 8-bits - if self._effectiveLut is None: - ind = xp.arange(eflsize) - levels_lut = fn.rescaleData(ind, scale=effscale, - offset=minlev, dtype=lutdtype, clip=(0, num_colors-1)) - efflut = colors_lut[levels_lut] - self._effectiveLut = efflut - efflut = self._effectiveLut - - # apply the effective lut early for the following types: - if image.dtype == xp.uint16 and image.ndim == 2: - image, augmented_alpha = self._apply_lut_for_uint16_mono(image, efflut) - efflut = None - return image, None, efflut, augmented_alpha - else: - # uint16 image with colors_lut <= 256 entries - # don't combine, we will use QImage ColorTable - image = fn.rescaleData(image, scale=effscale, - offset=minlev, dtype=lutdtype, clip=(0, num_colors-1)) - return image, None, colors_lut, augmented_alpha - - def _apply_lut_for_uint16_mono(self, image, lut): - # Note: compared to makeARGB(), we have already clipped the data to range - - xp = self._xp - augmented_alpha = False - - # if lut is 1d, then lut[image] is fastest - # if lut is 2d, then lut.take(image, axis=0) is faster than lut[image] - - if not image.flags.c_contiguous: - image = lut.take(image, axis=0) - - # if lut had dimensions (N, 1), then our resultant image would - # have dimensions (h, w, 1) - if image.ndim == 3 and image.shape[-1] == 1: - image = image[..., 0] - - return image, augmented_alpha - - # if we are contiguous, we can take a faster codepath where we - # ensure that the lut is 1d - - lut, augmented_alpha = self._convert_2dlut_to_1dlut(lut) - - fn_numba = fn.getNumbaFunctions() - if xp == numpy and fn_numba is not None: - image = fn_numba.numba_take(lut, image) - else: - image = lut[image] - - if image.dtype == xp.uint32: - image = image[..., xp.newaxis].view(xp.uint8) - - return image, augmented_alpha - - def _convert_2dlut_to_1dlut(self, lut): - # converts: - # - uint8 (N, 1) to uint8 (N,) - # - uint8 (N, 3) or (N, 4) to uint32 (N,) - # this allows faster lookup as 1d lookup is faster - xp = self._xp - augmented_alpha = False - - if lut.ndim == 1: - return lut, augmented_alpha - - if lut.shape[1] == 3: # rgb - # convert rgb lut to rgba so that it is 32-bits - lut = xp.column_stack([lut, xp.full(lut.shape[0], 255, dtype=xp.uint8)]) - augmented_alpha = True - if lut.shape[1] == 4: # rgba - lut = lut.view(xp.uint32) - lut = lut.ravel() - - return lut, augmented_alpha - - def _try_make_qimage(self, image, levels, lut, augmented_alpha): - xp = self._xp - - ubyte_nolvl = image.dtype == xp.ubyte and levels is None - is_passthru8 = ubyte_nolvl and lut is None - is_indexed8 = ubyte_nolvl and image.ndim == 2 and \ - lut is not None and lut.shape[0] <= 256 - is_passthru16 = image.dtype == xp.uint16 and levels is None and lut is None - can_grayscale16 = is_passthru16 and image.ndim == 2 and \ - hasattr(QtGui.QImage.Format, 'Format_Grayscale16') - is_rgba64 = is_passthru16 and image.ndim == 3 and image.shape[2] == 4 - - # bypass makeARGB for supported combinations - supported = is_passthru8 or is_indexed8 or can_grayscale16 or is_rgba64 - if not supported: - return None - - if self._xp == getCupy(): - image = image.get() - - # worthwhile supporting non-contiguous arrays - image = numpy.ascontiguousarray(image) - - fmt = None - ctbl = None - if is_passthru8: - # both levels and lut are None - # these images are suitable for display directly - if image.ndim == 2: - fmt = QtGui.QImage.Format.Format_Grayscale8 - elif image.shape[2] == 3: - fmt = QtGui.QImage.Format.Format_RGB888 - elif image.shape[2] == 4: - if augmented_alpha: - fmt = QtGui.QImage.Format.Format_RGBX8888 - else: - fmt = QtGui.QImage.Format.Format_RGBA8888 - elif is_indexed8: - # levels and/or lut --> lut-only - fmt = QtGui.QImage.Format.Format_Indexed8 - if lut.ndim == 1 or lut.shape[1] == 1: - ctbl = [QtGui.qRgb(x,x,x) for x in lut.ravel().tolist()] - elif lut.shape[1] == 3: - ctbl = [QtGui.qRgb(*rgb) for rgb in lut.tolist()] - elif lut.shape[1] == 4: - ctbl = [QtGui.qRgba(*rgba) for rgba in lut.tolist()] - elif can_grayscale16: - # single channel uint16 - # both levels and lut are None - fmt = QtGui.QImage.Format.Format_Grayscale16 - elif is_rgba64: - # uint16 rgba - # both levels and lut are None - fmt = QtGui.QImage.Format.Format_RGBA64 # endian-independent - if fmt is None: - raise ValueError("unsupported image type") - qimage = fn.ndarray_to_qimage(image, fmt) - if ctbl is not None: - qimage.setColorTable(ctbl) - return qimage - - def paint(self, p, *args): + def paint(self, painter, *args): profile = debug.Profiler() if self.image is None: return @@ -873,46 +809,110 @@ def paint(self, p, *args): return profile('render QImage') if self.paintMode is not None: - p.setCompositionMode(self.paintMode) + painter.setCompositionMode(self.paintMode) profile('set comp mode') - shape = self.image.shape[:2] if self.axisOrder == 'col-major' else self.image.shape[:2][::-1] - p.drawImage(QtCore.QRectF(0,0,*shape), self.qimage) + shape = ( + self.image.shape[:2] + if self.axisOrder == 'col-major' + else self.image.shape[:2][::-1] + ) + painter.drawImage(QtCore.QRectF(0,0,*shape), self.qimage) profile('p.drawImage') if self.border is not None: - p.setPen(self.border) - p.drawRect(self.boundingRect()) + painter.setPen(self.border) + painter.drawRect(self.boundingRect()) - def save(self, fileName, *args): + def save(self, fileName: str | pathlib.Path, *args) -> None: """ - Saves this image to file. Note that this saves the visible image (after scale/color changes), not the + Save this image to file. + + Note that this saves the visible image, after scale/color changes, not the original data. + + Parameters + ---------- + fileName : os.PathLike + File path to save the image data to. + *args : tuple + Arguments that are passed to :meth:`QImage.save `. + + See Also + -------- + :meth:`QImage.save ` : + ``*args`` is relayed to this method. """ + if self.qimage is None: + return None + if self._renderRequired: self.render() - self.qimage.save(fileName, *args) - def getHistogram(self, bins='auto', step='auto', perChannel=False, targetImageSize=200, - targetHistogramSize=500, **kwds): - """ - Returns `x` and `y` arrays containing the histogram values for the current image. - For an explanation of the return format, see :func:`numpy.histogram()`. + self.qimage.save(os.fsdecode(fileName), *args) - The `step` argument causes pixels to be skipped when computing the histogram to save time. - If `step` is 'auto', then a step is chosen such that the analyzed data has - dimensions approximating `targetImageSize` for each axis. + def getHistogram( + self, + bins: str | int='auto', + step: str | np.generic='auto', + perChannel: bool=False, + targetImageSize: int=200, + **kwargs + ) -> list[tuple[np.ndarray, np.ndarray]] | tuple[np.ndarray, np.ndarray] | tuple[None, None]: + """ + Generate arrays containing the histogram values. - The `bins` argument and any extra keyword arguments are passed to - :func:`numpy.histogram()`. If `bins` is `auto`, a bin number is automatically - chosen based on the image characteristics: + Similar to :func:`numpy.histogram` - * Integer images will have approximately `targetHistogramSize` bins, - with each bin having an integer width. - * All other types will have `targetHistogramSize` bins. + Parameters + ---------- + bins : int or str, default 'auto' + The `bins` argument and any extra keyword arguments are passed to + :func:`numpy.histogram()`. If ``bins == 'auto'``, a bin number is + automatically chosen based on the image characteristics. + step : int or str, default 'auto' + The `step` argument causes pixels to be skipped when computing the + histogram to save time. If `step` is 'auto', then a step is chosen such + that the analyzed data has dimensions approximating `targetImageSize` + for each axis. + perChannel : bool, default False + If ``True``, then a histogram is computed for each channel, and the output + is a list of the results. + targetImageSize : int, default 200 + This parameter is used if ``step == 'auto'``, If so, the `step` size is + calculated by ``step = ceil(image.shape[0] / targetImageSize)``. + **kwargs : dict, optional + Dictionary of arguments passed to :func:`numpy.histogram()`. + + Returns + ------- + numpy.ndarray, numpy.ndarray or None, None or list of tuple of numpy.ndarray, numpy.ndarray + Returns `x` and `y` arrays containing the histogram values for the current + image. For an explanation of the return format, see + :func:`numpy.histogram()`. + Returns ``[(numpy.ndarray, numpy.ndarray),...]`` if ``perChannel=True``, one + element per channel. + Returns ``(None, None)`` is there is no image, or image size is 0. + + Warns + ----- + RuntimeWarning + Emits when `targetHistogramSize` argument is passed in, which does nothing. + + See Also + -------- + numpy.histogram : + Describes return format in greater detail. + numpy.histogram_bin_edges: + Details the different string values accepted as the `bins` parameter. + """ + + if 'targetHistogramSize' in kwargs: + warnings.warn( + "'targetHistogramSize' option is not used", + RuntimeWarning, + stacklevel=2 + ) - If `perChannel` is `True`, then a histogram is computed for each channel, - and the output is a list of the results. - """ # This method is also used when automatically computing levels. if self.image is None or self.image.size == 0: return None, None @@ -945,7 +945,7 @@ def getHistogram(self, bins='auto', step='auto', perChannel=False, targetImageSi if len(bins) == 0: bins = self._xp.asarray((mn, mx)) - kwds['bins'] = bins + kwargs['bins'] = bins cp = getCupy() if perChannel: @@ -953,7 +953,7 @@ def getHistogram(self, bins='auto', step='auto', perChannel=False, targetImageSi for i in range(stepData.shape[-1]): stepChan = stepData[..., i] stepChan = stepChan[self._xp.isfinite(stepChan)] - h = self._xp.histogram(stepChan, **kwds) + h = self._xp.histogram(stepChan, **kwargs) if cp: hist.append((cp.asnumpy(h[1][:-1]), cp.asnumpy(h[0]))) else: @@ -961,39 +961,64 @@ def getHistogram(self, bins='auto', step='auto', perChannel=False, targetImageSi return hist else: stepData = stepData[self._xp.isfinite(stepData)] - hist = self._xp.histogram(stepData, **kwds) + hist = self._xp.histogram(stepData, **kwargs) if cp: return cp.asnumpy(hist[1][:-1]), cp.asnumpy(hist[0]) else: return hist[1][:-1], hist[0] - def setPxMode(self, b): + def setPxMode(self, b: bool): """ - Sets whether the item ignores transformations and draws directly to screen pixels. - If `True`, the item will not inherit any scale or rotation transformations from its - parent items, but its position will be transformed as usual. - (see ``GraphicsItem::ItemIgnoresTransformations`` in the Qt documentation) + Set whether item ignores transformations and draws directly to screen pixels. + + Parameters + ---------- + b : bool + If ``True``, the item will not inherit any scale or rotation + transformations from its parent items, but its position will be transformed + as usual. + + See Also + -------- + :class:`QGraphicsItem.GraphicsItemFlag ` : + Read the description of `ItemIgnoresTransformations` for more information. """ - self.setFlag(self.GraphicsItemFlag.ItemIgnoresTransformations, b) + self.setFlag( + QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemIgnoresTransformations, + b + ) def setScaledMode(self): self.setPxMode(False) - def getPixmap(self): + def getPixmap(self) -> QtGui.QPixmap | None: if self._renderRequired: self.render() if self._unrenderable: return None + if self.qimage is None: + return QtGui.QPixmap() return QtGui.QPixmap.fromImage(self.qimage) - def pixelSize(self): + def pixelSize(self) -> tuple[float, float]: """ - Returns the scene-size of a single pixel in the image + Get the `x` and `y` size of each pixel in the view coordinate system. + + Returns + ------- + float, float + The `x` and `y` size of each pixel in scene space. """ br = self.sceneBoundingRect() if self.image is None: - return 1,1 - return br.width()/self.width(), br.height()/self.height() + return 1.,1. + + if (width := self.width()) is None: + width = 0. + if (height := self.height()) is None: + height = 0. + + return br.width() / width, br.height() / height def viewTransformChanged(self): if self.autoDownsample: @@ -1006,18 +1031,18 @@ def viewTransformChanged(self): self._renderRequired = True self.update() - def _computeDownsampleFactors(self): + def _computeDownsampleFactors(self) -> tuple[int, int]: # reduce dimensions of image based on screen resolution o = self.mapToDevice(QtCore.QPointF(0, 0)) x = self.mapToDevice(QtCore.QPointF(1, 0)) y = self.mapToDevice(QtCore.QPointF(0, 1)) # scene may not be available yet if o is None: - return None, None + return 1, 1 w = Point(x - o).length() h = Point(y - o).length() if w == 0 or h == 0: - return None, None + return 1, 1 return max(1, int(1.0 / w)), max(1, int(1.0 / h)) def mouseDragEvent(self, ev): @@ -1029,9 +1054,11 @@ def mouseDragEvent(self, ev): self.drawAt(ev.pos(), ev) def mouseClickEvent(self, ev): - if ev.button() == QtCore.Qt.MouseButton.RightButton: - if self.raiseContextMenu(ev): - ev.accept() + if ( + ev.button() == QtCore.Qt.MouseButton.RightButton and + self.raiseContextMenu(ev) + ): + ev.accept() if self.drawKernel is not None and ev.button() == QtCore.Qt.MouseButton.LeftButton: self.drawAt(ev.pos(), ev) @@ -1039,6 +1066,16 @@ def raiseContextMenu(self, ev): menu = self.getMenu() if menu is None: return False + if self.scene() is None: + warnings.warn( + ( + "Attempting to raise a context menu with the GraphicsScene has " + "not been set. Returning None" + ), + RuntimeWarning, + stacklevel=2 + ) + return None menu = self.scene().addParentContextMenus(self, menu, ev) pos = ev.screenPos() menu.popup(QtCore.QPoint(int(pos.x()), int(pos.y()))) @@ -1057,17 +1094,19 @@ def getMenu(self): return self.menu def hoverEvent(self, ev): - if not ev.isExit() and self.drawKernel is not None and ev.acceptDrags(QtCore.Qt.MouseButton.LeftButton): - ev.acceptClicks(QtCore.Qt.MouseButton.LeftButton) ## we don't use the click, but we also don't want anyone else to use it. - ev.acceptClicks(QtCore.Qt.MouseButton.RightButton) - elif not ev.isExit() and self.removable: - ev.acceptClicks(QtCore.Qt.MouseButton.RightButton) ## accept context menu clicks + if not ev.isExit(): + if self.drawKernel is not None and ev.acceptDrags( + QtCore.Qt.MouseButton.LeftButton + ): + # we don't use the click, but we also don't want anyone else to use it + ev.acceptClicks(QtCore.Qt.MouseButton.LeftButton) + ev.acceptClicks(QtCore.Qt.MouseButton.RightButton) + elif self.removable: + # accept context menu clicks + ev.acceptClicks(QtCore.Qt.MouseButton.RightButton) def tabletEvent(self, ev): pass - #print(ev.device()) - #print(ev.pointerType()) - #print(ev.pressure()) def drawAt(self, pos, ev=None): if self.axisOrder == "col-major": @@ -1110,7 +1149,7 @@ def drawAt(self, pos, ev=None): elif self.drawMode == 'add': self.image[ts] += src else: - raise Exception("Unknown draw mode '%s'" % self.drawMode) + raise ValueError(f"Unknown draw mode '{self.drawMode}'") self.updateImage() def setDrawKernel(self, kernel=None, mask=None, center=(0,0), mode='set'): diff --git a/pyqtgraph/graphicsItems/LabelItem.py b/pyqtgraph/graphicsItems/LabelItem.py index 85a6d88075..f45c0d43c8 100644 --- a/pyqtgraph/graphicsItems/LabelItem.py +++ b/pyqtgraph/graphicsItems/LabelItem.py @@ -38,6 +38,7 @@ def setText(self, text, **args): ==================== ============================== **Style Arguments:** + family (str) example: 'Cantarell' color (str) example: '#CCFF00' size (str) example: '8pt' bold (bool) @@ -56,6 +57,8 @@ def setText(self, text, **args): color = getConfigOption('foreground') color = fn.mkColor(color) optlist.append('color: ' + color.name(QtGui.QColor.NameFormat.HexArgb)) + if 'family' in opts: + optlist.append('font-family: ' + opts['family']) if 'size' in opts: optlist.append('font-size: ' + opts['size']) if 'bold' in opts and opts['bold'] in [True, False]: diff --git a/pyqtgraph/graphicsItems/NonUniformImage.py b/pyqtgraph/graphicsItems/NonUniformImage.py index 065e0effef..10a026d2a9 100644 --- a/pyqtgraph/graphicsItems/NonUniformImage.py +++ b/pyqtgraph/graphicsItems/NonUniformImage.py @@ -37,11 +37,11 @@ def __init__(self, x, y, z, border=None): raise Exception("The length of x and y must match the shape of z.") # default colormap (black - white) - self.cmap = ColorMap(pos=[0.0, 1.0], color=[(0, 0, 0), (255, 255, 255)]) + self.cmap = ColorMap(None, [0.0, 1.0]) + self.lut = self.cmap.getLookupTable(nPts=256) self.data = (x, y, z) self.levels = None - self.lut = None self.border = border self.picture = None @@ -59,15 +59,15 @@ def setLookupTable(self, lut, update=True, **kwargs): lut.setImageItem(self) return + self.cmap = None # invalidate since no longer consistent with lut self.lut = lut self.picture = None if update: self.update() def setColorMap(self, cmap): + self.setLookupTable(cmap.getLookupTable(nPts=256), update=True) self.cmap = cmap - self.picture = None - self.update() def getHistogram(self, **kwds): """Returns x and y arrays containing the histogram values for the current image. @@ -106,14 +106,20 @@ def generatePicture(self): W, H = np.meshgrid(np.diff(x), np.diff(y), indexing='ij') Z = z - # get colormap, lut has precedence over cmap - if self.lut is None: - lut = self.cmap.getLookupTable(nPts=256) - elif callable(self.lut): + # get colormap + if callable(self.lut): lut = self.lut(z) else: lut = self.lut + if lut is None: + # lut can be None for a few reasons: + # 1) self.lut(z) can also return None on error + # 2) if a trivial gradient is being used, HistogramLUTItem calls + # setLookupTable(None) as an optimization for ImageItem + cmap = ColorMap(None, [0.0, 1.0]) + lut = cmap.getLookupTable(nPts=256) + # normalize and quantize mn, mx = self.getLevels() rng = mx - mn diff --git a/pyqtgraph/graphicsItems/PColorMeshItem.py b/pyqtgraph/graphicsItems/PColorMeshItem.py index ce10b50fe5..be2fe9d6f1 100644 --- a/pyqtgraph/graphicsItems/PColorMeshItem.py +++ b/pyqtgraph/graphicsItems/PColorMeshItem.py @@ -91,11 +91,11 @@ def __init__(self, *args, **kwargs): Sets the minimum and maximum values to be represented by the colormap (min, max). Values outside this range will be clipped to the colors representing min or max. ``None`` disables the limits, meaning that the colormap will autoscale - each time ``setData()`` is called - unless ``enableAutoLevels=False``. + the next time ``setData()`` is called with new data. enableAutoLevels: bool, optional, default True Causes the colormap levels to autoscale whenever ``setData()`` is called. - When enableAutoLevels is set to True, it is still possible to disable autoscaling - on a per-change-basis by using ``autoLevels=False`` when calling ``setData()``. + It is possible to override this value on a per-change-basis by using the + ``autoLevels`` keyword argument when calling ``setData()``. If ``enableAutoLevels==False`` and ``levels==None``, autoscaling will be performed once when the first z data is supplied. edgecolors : dict, optional @@ -125,7 +125,7 @@ def __init__(self, *args, **kwargs): self.edgecolors.setCosmetic(True) self.antialiasing = kwargs.get('antialiasing', False) self.levels = kwargs.get('levels', None) - self.enableautolevels = kwargs.get('enableAutoLevels', True) + self._defaultAutoLevels = kwargs.get('enableAutoLevels', True) if 'colorMap' in kwargs: cmap = kwargs.get('colorMap') @@ -213,38 +213,39 @@ def setData(self, *args, **kwargs): "ASCII from: ". - autoLevels: bool, optional, default True - When set to True, PColorMeshItem will automatically select levels - based on the minimum and maximum values encountered in the data along the z axis. - The minimum and maximum levels are mapped to the lowest and highest colors - in the colormap. The autoLevels parameter is ignored if ``enableAutoLevels is False`` + autoLevels: bool, optional + If set, overrides the value of ``enableAutoLevels`` """ - autoLevels = kwargs.get('autoLevels', True) + old_bounds = self._dataBounds + self._prepareData(args) + boundsChanged = old_bounds != self._dataBounds - # Has the view bounds changed - shapeChanged = False - if self.qpicture is None: - shapeChanged = True - elif len(args)==1: - if args[0].shape[0] != self.x[:,1][-1] or args[0].shape[1] != self.y[0][-1]: - shapeChanged = True - elif len(args)==3: - if np.any(self.x != args[0]) or np.any(self.y != args[1]): - shapeChanged = True + self._rerender( + autoLevels=kwargs.get('autoLevels', self._defaultAutoLevels) + ) - if len(args)==0: - # No data was received. - if self.z is None: - # No data is currently displayed, - # so other settings (like colormap) can not be updated - return - else: - # Got new data. Prepare it for plotting - self._prepareData(args) + if boundsChanged: + self.prepareGeometryChange() + self.informViewBoundsChanged() + self.update() - self.qpicture = QtGui.QPicture() - painter = QtGui.QPainter(self.qpicture) + def _rerender(self, *, autoLevels): + self.qpicture = None + if self.z is not None: + if (self.levels is None) or autoLevels: + # Autoscale colormap + z_min = self.z.min() + z_max = self.z.max() + self.setLevels( (z_min, z_max), update=False) + self.qpicture = self._drawPicture() + + def _drawPicture(self) -> QtGui.QPicture: + # on entry, the following members are all valid: x, y, z, levels + # this function does not alter any state (besides using self.quads) + + picture = QtGui.QPicture() + painter = QtGui.QPainter(picture) # We set the pen of all polygons once if self.edgecolors is None: painter.setPen(QtCore.Qt.PenStyle.NoPen) @@ -252,28 +253,17 @@ def setData(self, *args, **kwargs): painter.setPen(self.edgecolors) if self.antialiasing: painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) - ## Prepare colormap # First we get the LookupTable lut = self.lut_qcolor # Second we associate each z value, that we normalize, to the lut scale = len(lut) - 1 - # Decide whether to autoscale the colormap or use the same levels as before - if (self.levels is None) or (self.enableautolevels and autoLevels): - # Autoscale colormap - z_min = self.z.min() - z_max = self.z.max() - self.setLevels( (z_min, z_max), update=False) - else: - # Use consistent colormap scaling - z_min = self.levels[0] - z_max = self.levels[1] - rng = z_max - z_min + lo, hi = self.levels[0], self.levels[1] + rng = hi - lo if rng == 0: rng = 1 - norm = fn.rescaleData(self.z, scale / rng, z_min, - dtype=int, clip=(0, len(lut)-1)) + norm = fn.rescaleData(self.z, scale / rng, lo, dtype=int, clip=(0, len(lut)-1)) if Qt.QT_LIB.startswith('PyQt'): drawConvexPolygon = lambda x : painter.drawConvexPolygon(*x) @@ -299,24 +289,7 @@ def setData(self, *args, **kwargs): drawConvexPolygon(polys[idx]) painter.end() - self.update() - - self.prepareGeometryChange() - if shapeChanged: - self.informViewBoundsChanged() - - - - def _updateDisplayWithCurrentState(self, *args, **kargs): - ## Used for re-rendering mesh from self.z. - ## For example when a new colormap is applied, or the levels are adjusted - - defaults = { - 'autoLevels': False, - } - defaults.update(kargs) - return self.setData(*args, **defaults) - + return picture def setLevels(self, levels, update=True): @@ -334,9 +307,8 @@ def setLevels(self, levels, update=True): self.levels = levels self.sigLevelsChanged.emit(levels) if update: - self._updateDisplayWithCurrentState() - - + self._rerender(autoLevels=False) + self.update() def getLevels(self): """ @@ -348,39 +320,28 @@ def getLevels(self): def setLookupTable(self, lut, update=True): + self.cmap = None # invalidate since no longer consistent with lut self.lut_qcolor = lut[:] if update: - self._updateDisplayWithCurrentState() - - + self._rerender(autoLevels=False) + self.update() def getColorMap(self): return self.cmap - + def setColorMap(self, cmap): + self.setLookupTable(cmap.getLookupTable(nPts=256, mode=cmap.QCOLOR), update=True) + self.cmap = cmap def enableAutoLevels(self): - self.enableautolevels = True - - + self._defaultAutoLevels = True def disableAutoLevels(self): - self.enableautolevels = False - - + self._defaultAutoLevels = False def paint(self, p, *args): - if self.z is None: - return - - p.drawPicture(0, 0, self.qpicture) - - - def setBorder(self, b): - self.border = fn.mkPen(b) - self.update() - - + if self.qpicture is not None: + p.drawPicture(0, 0, self.qpicture) def width(self): if self._dataBounds is None: diff --git a/pyqtgraph/graphicsItems/PlotCurveItem.py b/pyqtgraph/graphicsItems/PlotCurveItem.py index 0e4b1276cb..e6e628750b 100644 --- a/pyqtgraph/graphicsItems/PlotCurveItem.py +++ b/pyqtgraph/graphicsItems/PlotCurveItem.py @@ -371,7 +371,7 @@ def invalidateBounds(self): def setPen(self, *args, **kargs): """Set the pen used to draw the curve.""" - if args[0] is None: + if args and args[0] is None: self.opts['pen'] = None else: self.opts['pen'] = fn.mkPen(*args, **kargs) @@ -385,7 +385,7 @@ def setShadowPen(self, *args, **kargs): pen to be visible. Arguments are passed to :func:`mkPen ` """ - if args[0] is None: + if args and args[0] is None: self.opts['shadowPen'] = None else: self.opts['shadowPen'] = fn.mkPen(*args, **kargs) @@ -397,7 +397,7 @@ def setBrush(self, *args, **kargs): Sets the brush used when filling the area under the curve. All arguments are passed to :func:`mkBrush `. """ - if args[0] is None: + if args and args[0] is None: self.opts['brush'] = None else: self.opts['brush'] = fn.mkBrush(*args, **kargs) diff --git a/pyqtgraph/graphicsItems/PlotDataItem.py b/pyqtgraph/graphicsItems/PlotDataItem.py index 47b9ebc7a2..f384b5cd0c 100644 --- a/pyqtgraph/graphicsItems/PlotDataItem.py +++ b/pyqtgraph/graphicsItems/PlotDataItem.py @@ -2,41 +2,99 @@ import warnings import bisect +from typing import TypedDict + import numpy as np from .. import debug as debug from .. import functions as fn from .. import getConfigOption -from ..Qt import QtCore +from ..Qt import QtCore, QtGui, QtWidgets from .GraphicsObject import GraphicsObject from .PlotCurveItem import PlotCurveItem from .ScatterPlotItem import ScatterPlotItem __all__ = ['PlotDataItem'] -class PlotDataset(object): - """ - :orphan: - .. warning:: This class is intended for internal use. The interface may change without warning. - Holds collected information for a plotable dataset. - Numpy arrays containing x and y coordinates are available as ``dataset.x`` and ``dataset.y``. - - After a search has been performed, typically during a call to :func:`dataRect() `, - ``dataset.containsNonfinite`` is `True` if any coordinate values are nonfinite (e.g. NaN or inf) or `False` if all - values are finite. If no search has been performed yet, ``dataset.containsNonfinite`` is `None`. +# For type-hints, but cannot be utilized with setData or __init__ until +# typing.Unpack is available in the library +class MetaKeywordArgs(TypedDict): + name: str + + +class PointStyleKeywordArgs(TypedDict): + symbol: str | QtGui.QPainterPath | list[str | QtGui.QPainterPath] | None + symbolPen: fn.color_like | QtGui.QPen | list[fn.color_like | QtGui.QPen] | None + symbolBrush: fn.color_like | QtGui.QBrush | list[fn.color_like | QtGui.QBrush] | None + symbolSize: int | list[int] + pxMode: bool + + +class LineStyleKeywordArgs(TypedDict): + connect: str | np.ndarray + pen: fn.color_like | QtGui.QPen | None + shadowPen: fn.color_like | QtGui.QPen | None + fillLevel: float | None + fillOutline: bool + fillBrush: fn.color_like | QtGui.QBrush | None + stepMode: str | None - For internal use in :class:`PlotDataItem `, this class should not be instantiated when no data is available. + +class OptimizationKeywordArgs(TypedDict): + useCache: bool + antialias: bool + downsample: int + downsampleMethod: str + autoDownsample: bool + clipToView: bool + dynamicRangeLimit: float | None + dynamicRangeHyst: float + skipFiniteCheck: bool + + +class PlotDataset: """ - def __init__(self, x, y, xAllFinite=None, yAllFinite=None): - """ - Parameters - ---------- - x: array - x coordinates of data points. - y: array - y coordinates of data points. - """ + Holds collected information for a plottable dataset. + + Numpy arrays containing x and y coordinates are available as ``dataset.x`` and + ``dataset.y``. + + After a search has been performed, typically during a call to + :func:`dataRect() `, ``dataset.containsNonfinite`` + is ``True`` if any coordinate values are non-finite (e.g. NaN or inf) or ``False`` + if all values are finite. If no search has been performed yet, + `dataset.containsNonfinite` is ``None``. + + Parameters + ---------- + x : np.ndarray + Coordinates for `x` data points. + y : np.ndarray + Coordinates for `y` data points. + xAllFinite : bool or None, default None + Label for `x` data points, indicating if all values are finite, or not, and + unknown if ``None``. + yAllFinite : bool or None, default None + Label for `y` data points, indicating if all values are finite, or not, and + unknown if ``None``. + + Warnings + -------- + :orphan: + .. warning:: + + This class is intended for internal use of :class:`~pyqtgraph.PlotDataItem`. + The interface may change without warning. It is not considered part of the + public API. + """ + def __init__( + self, + x: np.ndarray, + y: np.ndarray, + xAllFinite: bool | None = None, + yAllFinite: bool | None = None + ): super().__init__() self.x = x self.y = y @@ -50,7 +108,7 @@ def __init__(self, x, y, xAllFinite=None, yAllFinite=None): self.yAllFinite = True @property - def containsNonfinite(self): + def containsNonfinite(self) -> bool | None: if self.xAllFinite is None or self.yAllFinite is None: # don't know for sure yet return None @@ -58,60 +116,76 @@ def containsNonfinite(self): def _updateDataRect(self): """ - Finds bounds of plotable data and stores them as ``dataset._dataRect``, - stores information about the presence of nonfinite data points. - """ + Identify plottable bounds and presence of non-finite data. + """ if self.y is None or self.x is None: return None xmin, xmax, self.xAllFinite = self._getArrayBounds(self.x, self.xAllFinite) ymin, ymax, self.yAllFinite = self._getArrayBounds(self.y, self.yAllFinite) - self._dataRect = QtCore.QRectF( QtCore.QPointF(xmin,ymin), QtCore.QPointF(xmax,ymax) ) - - def _getArrayBounds(self, arr, all_finite): + self._dataRect = QtCore.QRectF( + QtCore.QPointF(xmin, ymin), + QtCore.QPointF(xmax, ymax) + ) + + def _getArrayBounds( + self, + arr: np.ndarray, + all_finite: bool | None + ) -> tuple[float, float, bool]: # here all_finite could be [None, False, True] - if not all_finite: # This may contain NaN values and infinites. - selection = np.isfinite(arr) # We are looking for the bounds of the plottable data set. Infinite and Nan are ignored. - all_finite = selection.all() # True if all values are finite, False if there are any non-finites - if not all_finite: + if not all_finite: # This may contain NaN or inf values. + # We are looking for the bounds of the plottable data set. Infinite and Nan + # are ignored. + selection = np.isfinite(arr) + # True if all values are finite, False if there are any non-finites + if not selection.all(): arr = arr[selection] + # here all_finite could be [False, True] - try: - amin = np.min( arr ) # find minimum of all finite values - amax = np.max( arr ) # find maximum of all finite values - except ValueError: # is raised when there are no finite values + amin = np.min( arr ) # find minimum of all finite values + amax = np.max( arr ) # find maximum of all finite values + except ValueError: # is raised when there are no finite values amin = np.nan amax = np.nan return amin, amax, all_finite - def dataRect(self): + def dataRect(self) -> QtCore.QRectF | None: """ - Returns a bounding rectangle (as :class:`QtCore.QRectF`) for the finite subset of data. - If there is an active mapping function, such as logarithmic scaling, then bounds represent the mapped data. - Will return `None` if there is no data or if all values (`x` or `y`) are NaN. + Get the bounding rectangle for the finite subset of data. + + If there is an active mapping function, such as logarithmic scaling, then bounds + represent the mapped data. + + Returns + ------- + :class:`QRectF` or None + The bounding rect of the data in view-space. Will return ``None`` if there + is no data or if all `x` and `y` values are ``NaN``. """ if self._dataRect is None: self._updateDataRect() return self._dataRect - def applyLogMapping(self, logMode): + def applyLogMapping(self, logMode: tuple[bool, bool]): """ - Applies a logarithmic mapping transformation (base 10) if requested for the respective axis. - This replaces the internal data. Values of ``-inf`` resulting from zeros in the original dataset are - replaced by ``np.NaN``. + Apply a log_10 map transformation if requested to the respective axis. + + This replaces the internal data. Values of ``-inf`` resulting from zeros in the + original dataset are replaced by ``np.nan``. Parameters ---------- - logmode: tuple or list of two bool - A `True` value requests log-scale mapping for the x and y axis (in this order). + logMode : tuple of bool + A ``True`` value requests log-scale mapping for the `x` and then `y` axis. """ if logMode[0]: with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) self.x = np.log10(self.x) - nonfinites = ~np.isfinite( self.x ) - if nonfinites.any(): - self.x[nonfinites] = np.nan # set all non-finite values to NaN + non_finites = ~np.isfinite( self.x ) + if non_finites.any(): + self.x[non_finites] = np.nan # set all non-finite values to NaN all_x_finite = False else: all_x_finite = True @@ -121,222 +195,352 @@ def applyLogMapping(self, logMode): with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) self.y = np.log10(self.y) - nonfinites = ~np.isfinite( self.y ) - if nonfinites.any(): - self.y[nonfinites] = np.nan # set all non-finite values to NaN + non_finites = ~np.isfinite( self.y ) + if non_finites.any(): + self.y[non_finites] = np.nan # set all non-finite values to NaN all_y_finite = False else: all_y_finite = True self.yAllFinite = all_y_finite - + + class PlotDataItem(GraphicsObject): """ - **Bases:** :class:`GraphicsObject ` - - :class:`PlotDataItem` provides a unified interface for displaying plot curves, scatter plots, or both. - It also contains methods to transform or decimate the original data before it is displayed. - - As pyqtgraph's standard plotting object, ``plot()`` methods such as :func:`pyqtgraph.plot` and - :func:`PlotItem.plot() ` create instances of :class:`PlotDataItem`. - - While it is possible to use :class:`PlotCurveItem ` or - :class:`ScatterPlotItem ` individually, this is recommended only - where performance is critical and the limited functionality of these classes is sufficient. - - ================================== ============================================== - **Signals:** - sigPlotChanged(self) Emitted when the data in this item is updated. - sigClicked(self, ev) Emitted when the item is clicked. - sigPointsClicked(self, points, ev) Emitted when a plot point is clicked - Sends the list of points under the mouse. - sigPointsHovered(self, points, ev) Emitted when a plot point is hovered over. - Sends the list of points under the mouse. - ================================== ============================================== - """ - - sigPlotChanged = QtCore.Signal(object) - sigClicked = QtCore.Signal(object, object) - sigPointsClicked = QtCore.Signal(object, object, object) - sigPointsHovered = QtCore.Signal(object, object, object) + Provides a unified interface for displaying plot curves, scatter plots, or both. + + The symbols of a scatter point are rendered over the "point" of the data, and the + curve connects adjacent points. + + .. code-block:: + + o-------------o---------------o---------------o + ^ ^ ^ ^ + point point point point + + This effect occurs by the combination of a :class:`~pyqtgraph.ScatterPlotItem` and a + :class:`~pyqtgraph.PlotCurveItem`. Each of these classes can be used individually, + however :class:`~pyqtgraph.PlotDataItem` does offer additional benefits. + + PlotDataItem offers a variety of optimization attributes including: + + * :meth:`setDownsampling` + * :meth:`setClipToView` + * :meth:`setSkipFiniteCheck` + + Performance of PlotDataItem can vary in unexpected ways, in addition to exploring + the methods above, consider the following. + + * Use a :class:`QPen` with ``width=1`` + * Wherever possible, re-use the same :class:`QPen` or :class:`QBrush` objects. If + passing a list of `symbolPen` or `symbolBrush`, try to pass the stored instances + instead of strings. + * Pass `x` and `y` data to :class:`PlotDataItem` or :func:`PlotDataItem.setData` as + :class:`numpy.ndarray` s, not lists. + + Lastly, PlotDataItem also contains methods to transform the original such as: + + * :meth:`setDerivativeMode` + * :meth:`setPhasemapMode` + * :meth:`setFftMode` + * :meth:`setLogMode` + + **Bases:** :class:`~pyqtgraph.GraphicsObject` + + Parameters + ---------- + *args : tuple, optional + Arguments representing the x and y data to be drawn. The following are example + ways to initialize data. + + * ``PlotDataItem(x, y)`` - `x` and `y` are array_like coordinate values. + * ``PlotDataItem(x=x, y=y)`` - same as above, but with keyword arguments. + * ``PlotDataItem(y)`` - `y` values only, `x` will automatically set to + ``np.arange(len(y))``. + * ``PlotDataItem(np.ndarray((N, 2)))`` - single :class:`numpy.ndarray` with + shape ``(N, 2)``, where ``x = data[:, 0]`` and ``y = data[:, 1]``. + + Data can be initialized with spot-style arguments as well. + + * ``PlotDataItem(recarray)`` - :class:`numpy.recarray` with + ``dtype=[('x', float), ('y', float), ...]`` + * ``PlotDataItem(list[dict[str, array_like]])`` - list of dictionaries, where + each element of the list corresponds to each point, and the dictionary, + requiring `x` and `y` keys correspond to information for the point. + * ``PlotDataItem(dict[str, array_like])`` - dictionary of lists, where each key + must correspond to a keyword argument, and each dictionary value if of type + array_like, where each element contains point specific attributes. All + dictionary values must have the same length. + + **kwargs : dict, optional + Here are a list of supported arguments. + + Point Style Keyword Arguments, see + :func:`ScatterPlotItem.setData ` for more + information. + + =========== ==================================================================== + Property Description + =========== ==================================================================== + symbol ``str``, :class:`QPainterPath`, list of ``str``, list of + :class:`QPainterPath`, or ``None``, default ``None`` + + Symbol to use for drawing points, or a list of symbols for each. If + using ``str``, needs to be a string that + :class:`~pyqtgraph.ScatterPlotItem` will recognize. + + symbolPen :class:`QPen`, list of :class:`QPen`, ``None``, or arguments + accepted by :func:`~pyqtgraph.mkPen`, default ``(200, 200, 200)`` -# **(x,y data only)** + Outline pen for drawing points, or list of pens, one per point. + + symbolBrush :class:`QBrush`, list of :class:`QBrush`, or arguments accepted by + :func:`~pyqtgraph.mkBrush`, default ``(50, 50, 150)`` - def __init__(self, *args, **kargs): - """ - There are many different ways to create a PlotDataItem. - - **Data initialization arguments:** (x,y data only) - - ========================== ========================================= - PlotDataItem(x, y) x, y: array_like coordinate values - PlotDataItem(y) y values only -- x will be - automatically set to ``range(len(y))`` - PlotDataItem(x=x, y=y) x and y given by keyword arguments - PlotDataItem(ndarray(N,2)) single numpy array with shape (N, 2), - where ``x=data[:,0]`` and ``y=data[:,1]`` - ========================== ========================================= - - **Data initialization arguments:** (x,y data AND may include spot style) - - ============================ =============================================== - PlotDataItem(recarray) numpy record array with ``dtype=[('x', float), - ('y', float), ...]`` - PlotDataItem(list-of-dicts) ``[{'x': x, 'y': y, ...}, ...]`` - PlotDataItem(dict-of-lists) ``{'x': [...], 'y': [...], ...}`` - ============================ =============================================== + Brush for filling points, or a list of brushes, one per point. - **Line style keyword arguments:** - - ============ ============================================================================== - connect Specifies how / whether vertexes should be connected. See below for details. - pen Pen to use for drawing the lines between points. - Default is solid grey, 1px width. Use None to disable line drawing. - May be a ``QPen`` or any single argument accepted by - :func:`mkPen() ` - shadowPen Pen for secondary line to draw behind the primary line. Disabled by default. - May be a ``QPen`` or any single argument accepted by - :func:`mkPen() ` - fillLevel If specified, the area between the curve and fillLevel is filled. - fillOutline (bool) If True, an outline surrounding the *fillLevel* area is drawn. - fillBrush Fill to use in the *fillLevel* area. May be any single argument accepted by - :func:`mkBrush() ` - stepMode (str or None) If specified and not None, a stepped curve is drawn. - For 'left' the specified points each describe the left edge of a step. - For 'right', they describe the right edge. - For 'center', the x coordinates specify the location of the step boundaries. - This mode is commonly used for histograms. Note that it requires an additional - x value, such that len(x) = len(y) + 1 . - - ============ ============================================================================== + symbolSize ``int`` or ``list[int]``, default ``10`` + + Diameter of the symbols, or a list of diameters. Diameter is either + in pixels or data-space coordinates depending on the value of + `pxMode`. - ``connect`` supports the following arguments: + pxMode ``bool``, default ``True`` + + If ``True``, the `symbolSize` represents the diameter in pixels. If + ``False``, the `symbolSize` represents the diameter in data + coordinates. + =========== ==================================================================== + + Line Style Keyword Arguments. - - 'all' connects all points. - - 'pairs' generates lines between every other point. - - 'finite' creates a break when a nonfinite points is encountered. - - If an ndarray is passed, it should contain `N` int32 values of 0 or 1. - Values of 1 indicate that the respective point will be connected to the next. - - In the default 'auto' mode, PlotDataItem will normally use 'all', but if any - nonfinite data points are detected, it will automatically switch to 'finite'. + =========== ==================================================================== + Property Description + =========== ==================================================================== + connect ``{ 'all', 'pairs', 'finite', 'auto', (N,) ndarray }``, default + ``'auto'`` + + - ``'auto'`` - if dataset contains non-finite values, switch to + ``'all'``, otherwise change to ``'finite'``. + - ``'all'`` - connects all points. + - ``'pairs'`` - generates lines between every other point. + - ``'finite'`` - creates a break when a non-finite points is + encountered. + - :class:`~numpy.ndarray` - it should contain `N` elements that of + integer or boolean dtypes, with values of ``0`` or ``1``. Values + of ``1`` indicate that the respective point will be connected to + the next. + + stepMode ``{ 'left', 'right', 'center' }`` or ``None``, default ``None`` + + If specified and not ``None``, a stepped curve is drawn. + + - ``'left'``- the specified points each describe the left edge of a + step. + - ``'right'``- the specified points each describe the right edge of + a step. + - ``'center'``- the x coordinates specify the location of the step + boundaries. This mode is commonly used for histograms. Note that + it requires an additional `x` value, such that + ``len(x) = len(y) + 1``. + - ``None`` - Render the curve normally, and not as a step curve. + + pen :class:`QPen`, ``None`` or args accepted by + :func:`~pyqtgraph.mkPen`, default 1px thick solid line + ``(200, 200, 200)`` + + Pen to use for drawing the lines between points. Use ``None`` to + disable line drawing. + + shadowPen :class:`QPen`, ``None`` or args accepted by + :func:`~pyqtgraph.mkPen`, default ``None`` - See :func:`arrayToQPath() ` for more details. - - **Point style keyword arguments:** (see :func:`ScatterPlotItem.setData() ` for more information) - - ============ ====================================================== - symbol Symbol to use for drawing points, or a list of symbols - for each. The default is no symbol. - symbolPen Outline pen for drawing points, or a list of pens, one - per point. May be any single argument accepted by - :func:`mkPen() `. - symbolBrush Brush for filling points, or a list of brushes, one - per point. May be any single argument accepted by - :func:`mkBrush() `. - symbolSize Diameter of symbols, or list of diameters. - pxMode (bool) If True, then symbolSize is specified in - pixels. If False, then symbolSize is - specified in data coordinates. - ============ ====================================================== - - Any symbol recognized by :class:`ScatterPlotItem ` can be specified, - including 'o' (circle), 's' (square), 't', 't1', 't2', 't3' (triangles of different orientation), - 'd' (diamond), '+' (plus sign), 'x' (x mark), 'p' (pentagon), 'h' (hexagon) and 'star'. - - Symbols can also be directly given in the form of a :class:`QtGui.QPainterPath` instance. - - **Optimization keyword arguments:** - - ================= ======================================================================= - useCache (bool) By default, generated point graphics items are cached to - improve performance. Setting this to False can improve image quality - in certain situations. - antialias (bool) By default, antialiasing is disabled to improve performance. - Note that in some cases (in particular, when ``pxMode=True``), points - will be rendered antialiased even if this is set to `False`. - downsample (int) Reduce the number of samples displayed by the given factor. - downsampleMethod 'subsample': Downsample by taking the first of N samples. - This method is fastest and least accurate. - 'mean': Downsample by taking the mean of N samples. - 'peak': Downsample by drawing a saw wave that follows the min - and max of the original data. This method produces the best - visual representation of the data but is slower. - autoDownsample (bool) If `True`, resample the data before plotting to avoid plotting - multiple line segments per pixel. This can improve performance when - viewing very high-density data, but increases the initial overhead - and memory usage. - clipToView (bool) If `True`, only data visible within the X range of the containing - :class:`ViewBox` is plotted. This can improve performance when plotting - very large data sets where only a fraction of the data is visible - at any time. - dynamicRangeLimit (float or `None`) Limit off-screen y positions of data points. - `None` disables the limiting. This can increase performance but may - cause plots to disappear at high levels of magnification. - The default of 1e6 limits data to approximately 1,000,000 times the - :class:`ViewBox` height. - dynamicRangeHyst (float) Permits changes in vertical zoom up to the given hysteresis - factor (the default is 3.0) before the limit calculation is repeated. - skipFiniteCheck (bool, default `False`) Optimization flag that can speed up plotting by not - checking and compensating for NaN values. If set to `True`, and NaN - values exist, unpredictable behavior will occur. The data may not be - displayed or the plot may take a significant performance hit. - - In the default 'auto' connect mode, `PlotDataItem` will automatically - override this setting. - ================= ======================================================================= - - **Meta-info keyword arguments:** - - ========== ================================================ - name (string) Name of item for use in the plot legend - ========== ================================================ - - **Notes on performance:** + Pen to use for drawing the secondary line to draw behind the primary + line. + + fillLevel ``float`` or ``None``, default ``None`` + + The area between the curve and value of fillLevel is filled. Use + ``None`` to disable. - Plotting lines with the default single-pixel width is the fastest available option. For such lines, - translucent colors (`alpha` < 1) do not result in a significant slowdown. + fillOutline ``bool``, default ``False`` + + Draw and outline surrounding *fillLevel*. - Wider lines increase the complexity due to the overlap of individual line segments. Translucent colors - require merging the entire plot into a single entity before the alpha value can be applied. For plots with more - than a few hundred points, this can result in excessive slowdown. + fillBrush :class:`QBrush`, ``None`` or args accepted by + :func:`~pyqtgraph.mkBrush`, default ``None`` + + Brush used to fill the *fillLevel*. + =========== ==================================================================== + + Optimization Keyword Arguments. + + =================== ============================================================ + Property Description + =================== ============================================================ + useCache ``bool``, default ``True`` + + Generated point graphics items are cached to improve + performance. Setting this to ``False`` can improve image + quality in some situations. + + antialias ``bool``, default inherited from + ``pyqtgraph.getConfigOption('antialias')`` + + Disabling can improve performance. In some cases, in + particular when ``pxMode=True``, points will be rendered + with antialiasing regardless of this setting. + + autoDownsample ``bool``, default ``False`` + + Resample the data before plotting to avoid plotting multiple + line segments per pixel. This can improve performance when + viewing very high-density data, but increases initial + overhead and memory usage. See :meth:`setDownsampling` for + more information. + + downsample ``int``, default ``1`` + + Reduce the number of sample displayed by the given factor. + See :meth:`setDownsampling` for more information. - Since version 0.12.4, this slowdown is automatically avoided by an algorithm that draws line segments - separately for fully opaque lines. Setting `alpha` < 1 reverts to the previous, slower drawing method. + downsampleMethod ``str``, default ``'peak'`` + + Method by which to downsample data. See + :meth:`setDownsampling` for more information. + + clipToView ``bool``, default ``False`` + + Clip the data to only the visible range on the x-axis. + See :meth:`setClipToView` for more information. + + dynamicRangeLimit ``float``, default ``1e6`` + + Limit off-screen y positions of data points. ``None`` + disables the limiting. This can increase performance but may + cause plots to disappear at high levels of magnification. + See :meth:`setDynamicRangeLimit` for more information. + + dynamicRangeHyst ``float``, default ``3.0`` - For lines with a width of more than 4 pixels, :func:`pyqtgraph.mkPen() ` will automatically - create a ``QPen`` with `Qt.PenCapStyle.RoundCap` to ensure a smooth connection of line segments. This incurs a - small performance penalty. + Permits changes in vertical zoom up to the given hysteresis + factor before the limit calculation is repeated. See + :meth:`setDynamicRangeLimit` for more information. + + skipFiniteCheck ``bool``, default ``False`` + + Skip the check for bypassing the checking and compensating + for ``np.nan`` values. If ``connect='auto'``, this item + will be overridden. + =================== ============================================================ + + Meta Keyword Arguments. + + =========== ==================================================================== + Property Description + =========== ==================================================================== + name ``str`` or ``None``, default ``None`` + + Name of item for use in the plot legend. + =========== ==================================================================== + + Attributes + ---------- + curve : :class:`~pyqtgraph.PlotCurveItem` + The underlying Graphics Object used to represent the curve. + scatter : :class:`~pyqtgraph.ScatterPlotItem` + The underlying Graphics Object used to the points along the curve. + xData : numpy.ndarray or None + The numpy array representing x-axis data. ``None`` if no data has been added. + yData : numpy.ndarray or None + The numpy array representing y-axis data. ``None`` if no data has been added. + + Signals + ------- + sigPlotChanged : Signal + Emits when the data in this item is updated. + sigClicked : Signal + Emits when the item is clicked. This signal emits the + :class:`~pyqtgraph.GraphicsScene.mouseEvents.MouseClickEvent`. + sigPointsClicked : Signal + Emits when a plot point is clicked. Sends the list of points under the + mouse, as well as the + :class:`~pyqtgraph.GraphicsScene.mouseEvents.MouseClickEvent`. + sigPointsHovered : Signal + Emits when a plot point is hovered over. Sends the list of points under the + mouse, s well as the :class:`~pyqtgraph.GraphicsScene.mouseEvents.HoverEvent`. + + See Also + -------- + :func:`~pyqtgraph.arrayToQPath` + Function used to convert :class:`numpy.ndarray` to :class:`QPainterPath`. + + Notes + ----- + The fastest performance results for drawing lines that have a :class:`QPen` width of + 1 pixel. + + If drawing a 1 pixel thick line, PyQtGraph converts the `x` and `y` data to a + :class:`QPainterPath` that is rendered. The render performance of + :class:`QPainterPath` when using a :class:`QPen` that has a width greater than 1 is + quite poor, but PyQtGraph falls back to constructing an array of :class:`QLine` + objects representing each line segment. Using + :meth:`QPainter.drawLines `, PyQtGraph is able to draw lines + with thickness greater than 1 pixel with a smaller performance penalty. + + For the :meth:`QPainter.drawLines ` method to work, some other + factors need to be present. - """ - GraphicsObject.__init__(self) - self.setFlag(self.GraphicsItemFlag.ItemHasNoContents) - # Original data, mapped data, and data processed for display is now all held in PlotDataset objects. - # The convention throughout PlotDataItem is that a PlotDataset is only instantiated if valid data is available. - self._dataset = None # will hold a PlotDataset for the original data, accessed by getOriginalData() - self._datasetMapped = None # will hold a PlotDataset for data after mapping transforms (e.g. log scale) - self._datasetDisplay = None # will hold a PlotDataset for data downsampled and limited for display, accessed by getData() + * ``pen.style() == QtCore.Qt.PenStyle.SolidLine`` + * ``pen.isSolid() is True`` + * ``pen.color().alphaF() == 1.0`` + * ``pyqtgraph.getConfigOption('antialias') is False`` + + If using lines with a thickness greater than 4 pixel, the :class:`QPen` instance + will be modified such that ``pen.capStyle() == QtCore.Qt.PenCapStyle.RoundCap``. + There is a small performance penalty with this change. + """ + + sigPlotChanged = QtCore.Signal(object) + sigClicked = QtCore.Signal(object, object) + sigPointsClicked = QtCore.Signal(object, object, object) + sigPointsHovered = QtCore.Signal(object, object, object) + + def __init__(self, *args, **kwargs): + super().__init__() + self.setFlag(QtWidgets.QGraphicsItem.GraphicsItemFlag.ItemHasNoContents) + # Original data, mapped data, and data processed for display is now all held in + # PlotDataset objects. + # The convention throughout PlotDataItem is that a PlotDataset is only + # instantiated if valid data is available. + # will hold a PlotDataset for the original data, accessed by getOriginalData() + self._dataset = None + # will hold a PlotDataset for data after mapping transforms (e.g. log scale) + self._datasetMapped = None + # will hold a PlotDataset for data downsampled and limited for display, + # accessed by getData() + self._datasetDisplay = None self.curve = PlotCurveItem() self.scatter = ScatterPlotItem() self.curve.setParentItem(self) self.scatter.setParentItem(self) - self.curve.sigClicked.connect(self.curveClicked) + self.curve.sigClicked.connect(self.sigClicked) self.scatter.sigClicked.connect(self.scatterClicked) - self.scatter.sigHovered.connect(self.scatterHovered) - - # self._xViewRangeWasChanged = False - # self._yViewRangeWasChanged = False - # self._styleWasChanged = True # force initial update + self.scatter.sigHovered.connect(self.sigPointsHovered) - # update-required notifications are handled through properties to allow future management through - # the QDynamicPropertyChangeEvent sent on any change. + # update-required notifications are handled through properties to allow future + # management through the QDynamicPropertyChangeEvent sent on any change. self.setProperty('xViewRangeWasChanged', False) self.setProperty('yViewRangeWasChanged', False) - self.setProperty('styleWasChanged', True) # force initial update + self.setProperty('styleWasChanged', True) # force initial update - self._drlLastClip = (0.0, 0.0) # holds last clipping points of dynamic range limiter - #self.clear() + # holds last clipping points of dynamic range limiter + self._drlLastClip = (0.0, 0.0) + self._adsLastValue = 1 + # self.clear() self.opts = { - 'connect': 'auto', # defaults to 'all', unless overridden to 'finite' for log-scaling + # defaults to 'all', unless overridden to 'finite' for log-scaling + 'connect': 'auto', 'skipFiniteCheck': False, 'fftMode': False, 'logMode': [False, False], @@ -354,7 +558,7 @@ def __init__(self, *args, **kargs): 'symbol': None, 'symbolSize': 10, - 'symbolPen': (200,200,200), + 'symbolPen': (200, 200, 200), 'symbolBrush': (50, 50, 150), 'pxMode': True, @@ -371,8 +575,8 @@ def __init__(self, *args, **kargs): 'dynamicRangeHyst': 3.0, 'data': None, } - self.setCurveClickable(kargs.get('clickable', False)) - self.setData(*args, **kargs) + self.setCurveClickable(kwargs.get('clickable', False)) + self.setData(*args, **kwargs) # Compatibility with direct property access to previous xData and yData structures: @property @@ -391,41 +595,87 @@ def implements(self, interface=None): return ints return interface in ints - def name(self): - """ Returns the name that represents this item in the legend. """ - return self.opts.get('name', None) + def name(self) -> str | None: + """ + Get the name attribute if set. + + Returns + ------- + str or None + The name that represents this item in the legend. + """ + return self.opts.get('name') - def setCurveClickable(self, state, width=None): - """ ``state=True`` sets the curve to be clickable, with a tolerance margin represented by `width`. """ + def setCurveClickable(self, state: bool, width: int | None = None): + """ + Set the attribute for the curve being clickable. + + Parameters + ---------- + state : bool + Set the curve to be clickable. + width : int + The distance tolerance margin in pixels to recognize the mouse click. + """ self.curve.setClickable(state, width) - def curveClickable(self): - """ Returns `True` if the curve is set to be clickable. """ + def curveClickable(self) -> bool: + """ + Get the attribute if the curve is clickable. + + Returns + ------- + bool + Return if the curve is set to be clickable. + """ return self.curve.clickable def boundingRect(self): - return QtCore.QRectF() ## let child items handle this + return QtCore.QRectF() # let child items handle this def setPos(self, x, y): + # super().setPos(x, y) GraphicsObject.setPos(self, x, y) # to update viewRect: self.viewTransformChanged() # to update displayed point sets, e.g. when clipping (which uses viewRect): self.viewRangeChanged() - def setAlpha(self, alpha, auto): + def setAlpha(self, alpha: float, auto: bool): + """ + Set the opacity of the item to the value passed in. + + This method is likely + + Parameters + ---------- + alpha : float + Value passed to :meth:`QGraphicsItem.setOpacity`. + auto : bool + Argument tied to the auto alpha setting in the Context Menu. + + See Also + -------- + :meth:`QGraphicsItem.setOpacity ` + This is the Qt method that the value is relayed to. + """ if self.opts['alphaHint'] == alpha and self.opts['alphaMode'] == auto: return self.opts['alphaHint'] = alpha self.opts['alphaMode'] = auto self.setOpacity(alpha) - #self.update() - def setFftMode(self, state): + def setFftMode(self, state: bool): """ - ``state = True`` enables mapping the data by a fast Fourier transform. - If the `x` values are not equidistant, the data set is resampled at - equal intervals. + Enable FFT mode. + + FFT mode enables mapping the data by a fast Fourier transform. If the `x` + values are not equidistant, the data set is resampled at equal intervals. + + Parameters + ---------- + state : bool + To enable or disable FFT mode. """ if self.opts['fftMode'] == state: return @@ -435,12 +685,20 @@ def setFftMode(self, state): self.updateItems(styleUpdate=False) self.informViewBoundsChanged() - def setLogMode(self, xState, yState): + def setLogMode(self, xState: bool, yState: bool): """ - When log mode is enabled for the respective axis by setting ``xState`` or - ``yState`` to `True`, a mapping according to ``mapped = np.log10( value )`` - is applied to the data. For negative or zero values, this results in a - `NaN` value. + Enable log mode per axis. + + When the log-mode is enabled for the respective axis, a mapping according to + ``mapped = np.log10(value)`` is applied to the data. For negative or zero + values, this results in ``NaN`` value. + + Parameters + ---------- + xState : bool + Enable log-mode on the x-axis. + yState : bool + Enable log-mode on the y-axis. """ if self.opts['logMode'] == [xState, yState]: return @@ -451,11 +709,18 @@ def setLogMode(self, xState, yState): self.updateItems(styleUpdate=False) self.informViewBoundsChanged() - def setDerivativeMode(self, state): + def setDerivativeMode(self, state: bool): """ - ``state = True`` enables derivative mode, where a mapping according to - ``y_mapped = dy / dx`` is applied, with `dx` and `dy` representing the - differences between adjacent `x` and `y` values. + Enable derivative mode. + + In derivative mode, the data is mapped according to ``y_mapped = dy / dx``, + with `dx` and `dy` representing the difference between adjacent `x` and `y` + values. + + Parameters + ---------- + state : bool + Enable derivative mode. """ if self.opts['derivativeMode'] == state: return @@ -466,12 +731,18 @@ def setDerivativeMode(self, state): self.updateItems(styleUpdate=False) self.informViewBoundsChanged() - def setPhasemapMode(self, state): + def setPhasemapMode(self, state: bool): """ - ``state = True`` enables phase map mode, where a mapping - according to ``x_mappped = y`` and ``y_mapped = dy / dx`` - is applied, plotting the numerical derivative of the data over the - original `y` values. + Enable phase map mode. + + In phase map mode, the data undergoes a mapping where ``x_mapped = y`` and + ``y_mapped = dy / dx``, where the numerical derivative of the data is plotted + over the original `y` values. + + Parameters + ---------- + state : bool + This enabled phase map mode. """ if self.opts['phasemapMode'] == state: return @@ -482,156 +753,267 @@ def setPhasemapMode(self, state): self.updateItems(styleUpdate=False) self.informViewBoundsChanged() - def setPen(self, *args, **kargs): + def setPen(self, *args, **kwargs): """ - Sets the pen used to draw lines between points. - The argument can be a :class:`QtGui.QPen` or any combination of arguments accepted by - :func:`pyqtgraph.mkPen() `. + Set the primary pen used to draw lines between points. + + Parameters + ---------- + *args : tuple or None + Arguments relayed to :func:`~pyqtgraph.mkPen` if not ``None``. Use ``None`` + to disable. + **kwargs : dict + Keyword arguments relayed to :func:`~pyqtgraph.mkPen`. + + See Also + -------- + :func:`~pyqtgraph.mkPen` + Function used to construct the :class:`QPen` instance. """ - pen = fn.mkPen(*args, **kargs) + pen = fn.mkPen(*args, **kwargs) self.opts['pen'] = pen - #self.curve.setPen(pen) - #for c in self.curves: - #c.setPen(pen) - #self.update() self.updateItems(styleUpdate=True) - def setShadowPen(self, *args, **kargs): + def setShadowPen(self, *args, **kwargs): """ - Sets the shadow pen used to draw lines between points (this is for enhancing contrast or - emphasizing data). This line is drawn behind the primary pen and should generally be assigned - greater width than the primary pen. - The argument can be a :class:`QtGui.QPen` or any combination of arguments accepted by - :func:`pyqtgraph.mkPen() `. + Set the shadow pen used to draw Lines between points. + + The shadow pen is often used for enhancing contrast or emphasizing data. The + line is drawn being the primary pen and should generally have a greater width + than the primary pen. + + Parameters + ---------- + *args : tuple or None + Arguments relayed to :func:`~pyqtgraph.mkPen` if not ``None``. Use ``None`` + to disable. + **kwargs : dict + Keyword arguments relayed to :func:`~pyqtgraph.mkPen`. + + See Also + -------- + :func:`~pyqtgraph.mkPen` + Function used to construct the :class:`QPen` instance. """ - if args[0] is None: + if args and args[0] is None: pen = None else: - pen = fn.mkPen(*args, **kargs) + pen = fn.mkPen(*args, **kwargs) self.opts['shadowPen'] = pen - #for c in self.curves: - #c.setPen(pen) - #self.update() self.updateItems(styleUpdate=True) - def setFillBrush(self, *args, **kargs): - """ - Sets the :class:`QtGui.QBrush` used to fill the area under the curve. - See :func:`mkBrush() `) for arguments. + def setFillBrush(self, *args, **kwargs): """ - if args[0] is None: + Set the :class:`QBrush` used to in the fill area under the curve. + + Parameters + ---------- + *args : tuple + Arguments directed to :func:`~pyqtgraph.mkBrush`. + **kwargs : dict + Arguments directed to :func:`~pyqtgraph.mkBrush`. + + See Also + -------- + :func:`~pyqtgraph.mkBrush` + See for supported arguments. + :func:`~pyqtgraph.mkColor` + See for supported color arguments. + """ + if args and args[0] is None: brush = None else: - brush = fn.mkBrush(*args, **kargs) + brush = fn.mkBrush(*args, **kwargs) if self.opts['fillBrush'] == brush: return self.opts['fillBrush'] = brush self.updateItems(styleUpdate=True) - def setBrush(self, *args, **kargs): + def setBrush(self, *args, **kwargs): """ - See :func:`~pyqtgraph.PlotDataItem.setFillBrush` + An alias to :func:`~pyqtgraph.PlotDataItem.setFillBrush`. + + Parameters + ---------- + *args : tuple + Arguments directed to :func:`~pyqtgraph.mkBrush`. + **kwargs : dict + Arguments directed to :func:`~pyqtgraph.mkBrush`. + + See Also + -------- + :func:`~pyqtgraph.mkBrush` + Function used to construct the :class:`QBrush` instance. """ - return self.setFillBrush(*args, **kargs) + self.setFillBrush(*args, **kwargs) - def setFillLevel(self, level): + def setFillLevel(self, level: float | None): """ - Enables filling the area under the curve towards the value specified by - `level`. `None` disables the filling. + Set the y-axis value to act as a boundary for the fill. + + Parameters + ---------- + level : float or None + The value that the fill from the curve is drawn to. Use ``None`` to disable + the filling. + + See Also + -------- + :class:`pyqtgraph.FillBetweenItem` + See for another :class:`~pyqtgraph.GraphicsItem` that fills in regions. """ if self.opts['fillLevel'] == level: return self.opts['fillLevel'] = level self.updateItems(styleUpdate=True) - def setSymbol(self, symbol): - """ `symbol` can be any string recognized by - :class:`ScatterPlotItem ` or a list that - specifies a symbol for each point. + def setSymbol( + self, + symbol: str | QtGui.QPainterPath | list[str | QtGui.QPainterPath] + ): + """ + Set the symbol used for drawing the points. + + See :func:`pyqtgraph.ScatterPlotItem.setSymbol` for a full list of accepted + arguments. + + Parameters + ---------- + symbol : str or :class:`QPainterPath` or list + Symbol to draw as the points. If of type ``list``, it must be the same + length as the number of points, and every element must be a recognized + string or of type :class:`QPainterPath`. + + See Also + -------- + :func:`~pyqtgraph.ScatterPlotItem.setSymbol` + Method detailing accepted symbols. """ if self.opts['symbol'] == symbol: return self.opts['symbol'] = symbol - #self.scatter.setSymbol(symbol) self.updateItems(styleUpdate=True) - def setSymbolPen(self, *args, **kargs): - """ - Sets the :class:`QtGui.QPen` used to draw symbol outlines. - See :func:`mkPen() `) for arguments. + def setSymbolPen(self, *args, **kwargs): + """ + Set the :class:`QPen` used to draw symbols. + + Parameters + ---------- + *args : tuple + Arguments directed to :func:`~pyqtgraph.mkPen`. + **kwargs : dict + Arguments directed to :func:`~pyqtgraph.mkPen`. + + See Also + -------- + :func:`~pyqtgraph.mkPen` + See for supported arguments. + :func:`~pyqtgraph.mkColor` + See for supported color arguments. """ - pen = fn.mkPen(*args, **kargs) + pen = fn.mkPen(*args, **kwargs) if self.opts['symbolPen'] == pen: return self.opts['symbolPen'] = pen - #self.scatter.setSymbolPen(pen) self.updateItems(styleUpdate=True) - def setSymbolBrush(self, *args, **kargs): + def setSymbolBrush(self, *args, **kwargs): """ - Sets the :class:`QtGui.QBrush` used to fill symbols. - See :func:`mkBrush() `) for arguments. + Set the :class:`QBrush` used to fill symbols. + + Parameters + ---------- + *args : tuple + Arguments directed to :func:`~pyqtgraph.mkBrush`. + **kwargs : dict + Arguments directed to :func:`~pyqtgraph.mkBrush`. + + See Also + -------- + :func:`~pyqtgraph.mkBrush` + See for supported arguments. + :func:`~pyqtgraph.mkColor` + See for supported color arguments. """ - brush = fn.mkBrush(*args, **kargs) + brush = fn.mkBrush(*args, **kwargs) if self.opts['symbolBrush'] == brush: return self.opts['symbolBrush'] = brush #self.scatter.setSymbolBrush(brush) self.updateItems(styleUpdate=True) - def setSymbolSize(self, size): + def setSymbolSize(self, size: int): """ - Sets the symbol size. + Set the symbol size. + + Parameters + ---------- + size : int + The size to set the symbols to. Size is in pixels or data-coordinates + depending on `pxMode` value used. """ if self.opts['symbolSize'] == size: return self.opts['symbolSize'] = size - #self.scatter.setSymbolSize(symbolSize) self.updateItems(styleUpdate=True) - def setDownsampling(self, ds=None, auto=None, method=None): + def setDownsampling( + self, + ds: int | None = None, + auto: bool | None = None, + method: str = 'peak' + ): """ - Sets the downsampling mode of this item. Downsampling reduces the number - of samples drawn to increase performance. - - ============== ================================================================= - **Arguments:** - ds (int) Reduce visible plot samples by this factor. To disable, - set ds=1. - auto (bool) If True, automatically pick *ds* based on visible range - mode 'subsample': Downsample by taking the first of N samples. - This method is fastest and least accurate. - 'mean': Downsample by taking the mean of N samples. - 'peak': Downsample by drawing a saw wave that follows the min - and max of the original data. This method produces the best - visual representation of the data but is slower. - ============== ================================================================= + Set the downsampling mode. + + Downsampling reduces the number of samples drawn to increase performance. + + Parameters + ---------- + ds : int or None, default None + Reduce the visible plot sample by this factor. To disable, set ``ds=1``. + auto : bool or None, default None + If ``True``, automatically pick `ds` based on visible range. + method : { 'subsample', 'mean', 'peak' }, default 'peak' + Specify the method by which to perform the downsampling calculation. + + * `subsample` - Downsample by taking the first of `N` samples. This method + is the fastest, but least accurate. + * `mean` - Downsample by taking the mean of `N` samples. + * `peak` - Downsample by drawing a saw wave that follows the min and max of + the original data. This method produces the best visual representation of + the data but is slower. """ changed = False - if ds is not None: - if self.opts['downsample'] != ds: - changed = True - self.opts['downsample'] = ds + if ds is not None and self.opts['downsample'] != ds: + changed = True + self.opts['downsample'] = ds if auto is not None and self.opts['autoDownsample'] != auto: - self.opts['autoDownsample'] = auto changed = True + self.opts['autoDownsample'] = auto - if method is not None: - if self.opts['downsampleMethod'] != method: - changed = True - self.opts['downsampleMethod'] = method + if method is not None and self.opts['downsampleMethod'] != method: + changed = True + self.opts['downsampleMethod'] = method if changed: - self._datasetMapped = None # invalidata mapped data + self._datasetMapped = None # invalidate mapped data self._datasetDisplay = None # invalidate display data self._adsLastValue = 1 # reset auto-downsample value self.updateItems(styleUpdate=False) - def setClipToView(self, state): + def setClipToView(self, state: bool): """ - ``state=True`` enables clipping the displayed data set to the - visible x-axis range. + Clip the displayed data to the visible range in the x-axis. + + This setting can result in significant performance improvements. + + Parameters + ---------- + state : bool + Enable clipping the displayed data set to the visible x-axis range. """ if self.opts['clipToView'] == state: return @@ -639,69 +1021,99 @@ def setClipToView(self, state): self._datasetDisplay = None # invalidate display data self.updateItems(styleUpdate=False) - def setDynamicRangeLimit(self, limit=1e06, hysteresis=3.): + def setDynamicRangeLimit(self, limit: float | None = 1e06, hysteresis: float = 3.): """ - Limit the off-screen positions of data points at large magnification - This avoids errors with plots not displaying because their visibility is incorrectly determined. - The default setting repositions far-off points to be within Âą10^6 times the viewport height. - - =============== ================================================================ - **Arguments:** - limit (float or None) Any data outside the range of limit * hysteresis - will be constrained to the limit value limit. - All values are relative to the viewport height. - 'None' disables the check for a minimal increase in performance. - Default is 1E+06. - - hysteresis (float) Hysteresis factor that controls how much change - in zoom level (vertical height) is allowed before recalculating - Default is 3.0 - =============== ================================================================ + Limit the off-screen positions of data points at large magnification. + + This avoids errors with plots not displaying because their visibility is + incorrectly determined. The default setting repositions far-off points to be + within Âą10^6 times the viewport height. + + This is intended to work around an upstream Qt issue. + + Parameters + ---------- + limit : float or None, default 1e+06 + Any data outside the range of ``limit * hysteresis`` will be constrained to + the limit value. All values are relative to the viewport height. ``None`` + disables the check for a minimal increase in performance. + hysteresis : float, default 3.0 + Hysteresis factor that controls how much change in zoom level (vertical + height) is allowed before recalculating. + + Notes + ----- + See https://github.com/pyqtgraph/pyqtgraph/issues/1676 for an example + of the issue this method addresses. """ - if hysteresis < 1.0: - hysteresis = 1.0 - self.opts['dynamicRangeHyst'] = hysteresis + hysteresis = max(hysteresis, 1.0) + self.opts['dynamicRangeHyst'] = hysteresis if limit == self.opts['dynamicRangeLimit']: - return # avoid update if there is no change - self.opts['dynamicRangeLimit'] = limit # can be None + return # avoid update if there is no change + self.opts['dynamicRangeLimit'] = limit # can be None self._datasetDisplay = None # invalidate display data - self.updateItems(styleUpdate=False) - def setSkipFiniteCheck(self, skipFiniteCheck): + def setSkipFiniteCheck(self, skipFiniteCheck: bool): """ - When it is known that the plot data passed to ``PlotDataItem`` contains only finite numerical values, - the ``skipFiniteCheck`` property can help speed up plotting. If this flag is set and the data contains - any non-finite values (such as `NaN` or `Inf`), unpredictable behavior will occur. The data might not - be plotted, or there migth be significant performance impact. + Toggle performance option to bypass the finite check. + + This option is intended to improve performance if the user knows that the `x` + and `y` data will not have non-finite values. + + When it is known that the plot data passed to ``PlotDataItem`` contains only + finite numerical values, the ``skipFiniteCheck`` property can help speed up + plotting. If this flag is set and the data contains any non-finite values (such + as `NaN` or `Inf`), unpredictable behavior will occur. The data might not be + plotted, or there might be significant performance impact. - In the default 'auto' connect mode, ``PlotDataItem`` will apply this setting automatically. + In the default ``connect='auto'` mode, ``PlotDataItem`` will apply this setting + automatically. + + Parameters + ---------- + skipFiniteCheck : bool + Skip the :obj:`numpy.isfinite` check for the input arrays. + + See Also + -------- + numpy.isfinite + NumPy function used to identify if there are non-finite values in the `x` + and `y` data. + :func:`~pyqtgraph.arrayToQPath` + Function to create :class:`QPainterPath` which is rendered on the screen + from numpy arrays. """ - self.opts['skipFiniteCheck'] = bool(skipFiniteCheck) + self.opts['skipFiniteCheck'] = skipFiniteCheck - def setData(self, *args, **kargs): + def setData( + self, + *args, + **kwargs + ): """ Clear any data displayed by this item and display new data. - See :func:`__init__() ` for details; it accepts the same arguments. + + Parameters + ---------- + *args : tuple + See :class:`PlotDataItem` description for supported arguments. + **kwargs : dict + See :class:`PlotDataItem` description for supported arguments. + + Raises + ------ + TypeError + Raised when an invalid type was passed in for `x` or `y` data. + + See Also + -------- + :class:`PlotDataItem` + Contains more detailed descriptions for accepted arguments. + :func:`~pyqtgraph.arrayToQPath` + See for how the draw paths are constructed. """ - #self.clear() - if kargs.get("stepMode", None) is True: - warnings.warn( - 'stepMode=True is deprecated and will result in an error after October 2022. Use stepMode="center" instead.', - DeprecationWarning, stacklevel=3 - ) - if 'decimate' in kargs.keys(): - warnings.warn( - 'The decimate keyword has been deprecated. It has no effect and may result in an error in releases after October 2022. ', - DeprecationWarning, stacklevel=2 - ) - - if 'identical' in kargs.keys(): - warnings.warn( - 'The identical keyword has been deprecated. It has no effect may result in an error in releases after October 2022. ', - DeprecationWarning, stacklevel=2 - ) profiler = debug.Profiler() y = None x = None @@ -713,8 +1125,8 @@ def setData(self, *args, **kargs): elif dt == 'listOfValues': y = np.array(data) elif dt == 'Nx2array': - x = data[:,0] - y = data[:,1] + x = data[:, 0] + y = data[:, 1] elif dt == 'recarray' or dt == 'dictOfLists': if 'x' in data: x = np.array(data['x']) @@ -725,9 +1137,11 @@ def setData(self, *args, **kargs): x = np.array([d.get('x',None) for d in data]) if 'y' in data[0]: y = np.array([d.get('y',None) for d in data]) - for k in ['data', 'symbolSize', 'symbolPen', 'symbolBrush', 'symbolShape']: + for k in [ + 'data', 'symbolSize', 'symbolPen', 'symbolBrush', 'symbolShape' + ]: if k in data: - kargs[k] = [d.get(k, None) for d in data] + kwargs[k] = [d.get(k) for d in data] elif dt == 'MetaArray': y = data.view(np.ndarray) x = data.xvals(0).view(np.ndarray) @@ -738,7 +1152,13 @@ def setData(self, *args, **kargs): seq = ('listOfValues', 'MetaArray', 'empty') dtyp = dataType(args[0]), dataType(args[1]) if dtyp[0] not in seq or dtyp[1] not in seq: - raise TypeError('When passing two unnamed arguments, both must be a list or array of values. (got %s, %s)' % (str(type(args[0])), str(type(args[1])))) + raise TypeError( + ( + 'When passing two unnamed arguments, both must be a list or ' + 'array of values. (got %s, %s)' + % (str(type(args[0])), str(type(args[1]))) + ) + ) if not isinstance(args[0], np.ndarray): #x = np.array(args[0]) if dtyp[0] == 'MetaArray': @@ -756,82 +1176,94 @@ def setData(self, *args, **kargs): else: y = args[1].view(np.ndarray) - if 'x' in kargs: - x = kargs['x'] + if 'x' in kwargs: + x = kwargs['x'] if dataType(x) == 'MetaArray': x = x.asarray() - if 'y' in kargs: - y = kargs['y'] + if 'y' in kwargs: + y = kwargs['y'] if dataType(y) == 'MetaArray': y = y.asarray() profiler('interpret data') - ## pull in all style arguments. - ## Use self.opts to fill in anything not present in kargs. + # pull in all style arguments. + # Use self.opts to fill in anything not present in kwargs. - if 'name' in kargs: - self.opts['name'] = kargs['name'] + if 'name' in kwargs: + self.opts['name'] = kwargs['name'] self.setProperty('styleWasChanged', True) - if 'connect' in kargs: - self.opts['connect'] = kargs['connect'] + if 'connect' in kwargs: + self.opts['connect'] = kwargs['connect'] self.setProperty('styleWasChanged', True) - if 'skipFiniteCheck' in kargs: - self.opts['skipFiniteCheck'] = kargs['skipFiniteCheck'] - - ## if symbol pen/brush are given with no previously set symbol, then assume symbol is 'o' - if 'symbol' not in kargs and ('symbolPen' in kargs or 'symbolBrush' in kargs or 'symbolSize' in kargs): - if self.opts['symbol'] is None: - kargs['symbol'] = 'o' + if 'skipFiniteCheck' in kwargs: + self.opts['skipFiniteCheck'] = kwargs['skipFiniteCheck'] + + # if symbol pen/brush are given with no previously set symbol, + # then assume symbol is 'o' + if ( + 'symbol' not in kwargs + and ( + 'symbolPen' in kwargs + or 'symbolBrush' in kwargs + or 'symbolSize' in kwargs + ) and self.opts['symbol'] is None + ): + kwargs['symbol'] = 'o' - if 'brush' in kargs: - kargs['fillBrush'] = kargs['brush'] + if 'brush' in kwargs: + kwargs['fillBrush'] = kwargs['brush'] for k in list(self.opts.keys()): - if k in kargs: - self.opts[k] = kargs[k] + if k in kwargs: + self.opts[k] = kwargs[k] self.setProperty('styleWasChanged', True) #curveArgs = {} #for k in ['pen', 'shadowPen', 'fillLevel', 'brush']: - #if k in kargs: - #self.opts[k] = kargs[k] + #if k in kwargs: + #self.opts[k] = kwargs[k] #curveArgs[k] = self.opts[k] #scatterArgs = {} #for k,v in [('symbolPen','pen'), ('symbolBrush','brush'), ('symbol','symbol')]: - #if k in kargs: - #self.opts[k] = kargs[k] + #if k in kwargs: + #self.opts[k] = kwargs[k] #scatterArgs[v] = self.opts[k] - if y is None or len(y) == 0: # empty data is represented as None + if y is None or len(y) == 0: # empty data is represented as None yData = None - else: # actual data is represented by ndarray + else: # actual data is represented by ndarray if not isinstance(y, np.ndarray): y = np.array(y) yData = y.view(np.ndarray) if x is None: x = np.arange(len(y)) - if x is None or len(x)==0: # empty data is represented as None + if x is None or len(x) == 0: # empty data is represented as None xData = None else: # actual data is represented by ndarray if not isinstance(x, np.ndarray): x = np.array(x) - xData = x.view(np.ndarray) # one last check to make sure there are no MetaArrays getting by + # one last check to make sure there are no MetaArrays getting by + xData = x.view(np.ndarray) if xData is None or yData is None: self._dataset = None else: self._dataset = PlotDataset( xData, yData ) - self._datasetMapped = None # invalidata mapped data , will be generated in getData() / _getDisplayDataset() - self._datasetDisplay = None # invalidate display data, will be generated in getData() / _getDisplayDataset() - self._adsLastValue = 1 # reset auto-downsample value + # invalidate mapped data , will be generated in getData() / _getDisplayDataset() + self._datasetMapped = None + # invalidate display data, will be generated in getData() / _getDisplayDataset() + self._datasetDisplay = None + # reset auto-downsample value + self._adsLastValue = 1 profiler('set data') - self.updateItems( styleUpdate = self.property('styleWasChanged') ) - self.setProperty('styleWasChanged', False) # items have been updated + self.updateItems( styleUpdate=self.property('styleWasChanged') ) + # items have been updated + self.setProperty('styleWasChanged', False) profiler('update items') self.informViewBoundsChanged() @@ -839,20 +1271,32 @@ def setData(self, *args, **kargs): self.sigPlotChanged.emit(self) profiler('emit') - def updateItems(self, styleUpdate=True): - # override styleUpdate request and always enforce update until we have a better solution for + def updateItems(self, styleUpdate: bool = True): + """ + Method that is run after a graphics style was updated. + + Parameters + ---------- + styleUpdate : bool, default True + Indicates if the style was updated. + """ + + # override styleUpdate request and always enforce update until we have a + # better solution for: # - ScatterPlotItem losing per-point style information # - PlotDataItem performing multiple unnecessary setData calls on initialization - styleUpdate=True - + # See: https://github.com/pyqtgraph/pyqtgraph/pull/1653 + if not styleUpdate: + styleUpdate = True + curveArgs = {} scatterArgs = {} - if styleUpdate: # repeat style arguments only when changed + if styleUpdate: # repeat style arguments only when changed for k, v in [ - ('pen','pen'), - ('shadowPen','shadowPen'), - ('fillLevel','fillLevel'), + ('pen', 'pen'), + ('shadowPen', 'shadowPen'), + ('fillLevel', 'fillLevel'), ('fillOutline', 'fillOutline'), ('fillBrush', 'brush'), ('antialias', 'antialias'), @@ -864,9 +1308,9 @@ def updateItems(self, styleUpdate=True): curveArgs[v] = self.opts[k] for k, v in [ - ('symbolPen','pen'), - ('symbolBrush','brush'), - ('symbol','symbol'), + ('symbolPen', 'pen'), + ('symbolBrush', 'brush'), + ('symbol', 'symbol'), ('symbolSize', 'size'), ('data', 'data'), ('pxMode', 'pxMode'), @@ -877,7 +1321,7 @@ def updateItems(self, styleUpdate=True): scatterArgs[v] = self.opts[k] dataset = self._getDisplayDataset() - if dataset is None: # then we have nothing to show + if dataset is None: # then we have nothing to show self.curve.hide() self.scatter.hide() return @@ -885,12 +1329,18 @@ def updateItems(self, styleUpdate=True): x = dataset.x y = dataset.y #scatterArgs['mask'] = self.dataMask - if( - self.opts['pen'] is not None - or (self.opts['fillBrush'] is not None and self.opts['fillLevel'] is not None) - ): # draw if visible... + if ( + self.opts['pen'] is not None + or ( + self.opts['fillBrush'] is not None and + self.opts['fillLevel'] is not None + ) + ): # draw if visible... # auto-switch to indicate non-finite values as interruptions in the curve: - if isinstance(curveArgs['connect'], str) and curveArgs['connect'] == 'auto': # connect can also take a boolean array + if ( + isinstance(curveArgs['connect'], str) and + curveArgs['connect'] == 'auto' + ): # connect can also take a boolean array if dataset.containsNonfinite is False: # all points can be connected, and no further check is needed. curveArgs['connect'] = 'all' @@ -904,43 +1354,56 @@ def updateItems(self, styleUpdate=True): curveArgs['skipFiniteCheck'] = False self.curve.setData(x=x, y=y, **curveArgs) self.curve.show() - else: # ...hide if not. + else: # ...hide if not. self.curve.hide() - if self.opts['symbol'] is not None: # draw if visible... - ## check against `True` too for backwards compatibility - if self.opts.get('stepMode', False) in ("center", True): + if self.opts['symbol'] is not None: # draw if visible... + if self.opts.get('stepMode') == "center": x = 0.5 * (x[:-1] + x[1:]) self.scatter.setData(x=x, y=y, **scatterArgs) self.scatter.show() - else: # ...hide if not. + else: # ...hide if not. self.scatter.hide() - def getOriginalDataset(self): - """ - Returns the original, unmapped data as the tuple (`xData`, `yData`). - """ - dataset = self._dataset - if dataset is None: - return (None, None) - return dataset.x, dataset.y + def getOriginalDataset(self) -> tuple[None, None] | tuple[np.ndarray, np.ndarray]: + """ + Get the numpy data representation of the data provided. + + Returns + ------- + xData : np.ndarray or None + Original representation of x-axis data. + yData : np.ndarray or None + Original representation of y-axis data. + """ + dataset = self._dataset + return (None, None) if dataset is None else (dataset.x, dataset.y) - def _getDisplayDataset(self): + def _getDisplayDataset(self) -> PlotDataset | None: """ - Returns a :class:`~.PlotDataset` object that contains data suitable for display - (after mapping and data reduction) as ``dataset.x`` and ``dataset.y``. - Intended for internal use. + Get data suitable for display as a :class:`PlotDataset`. + + Warnings + -------- + This method is not considered part of the public API. + + Returns + ------- + :class:`PlotDataset` + Data suitable for display (after mapping and data reduction) as + ``dataset.x`` and ``dataset.y``. """ if self._dataset is None: return None # Return cached processed dataset if available and still valid: - if( self._datasetDisplay is not None and + if ( + self._datasetDisplay is not None and not (self.property('xViewRangeWasChanged') and self.opts['clipToView']) and not (self.property('xViewRangeWasChanged') and self.opts['autoDownsample']) and not (self.property('yViewRangeWasChanged') and self.opts['dynamicRangeLimit'] is not None) ): return self._datasetDisplay - + # Apply data mapping functions if mapped dataset is not yet available: if self._datasetMapped is None: x = self._dataset.x @@ -949,25 +1412,29 @@ def _getDisplayDataset(self): y = y.astype(np.uint8) if x.dtype == bool: x = x.astype(np.uint8) - if self.opts['fftMode']: - x,y = self._fourierTransform(x, y) + x, y = self._fourierTransform(x, y) # Ignore the first bin for fft data if we have a logx scale if self.opts['logMode'][0]: - x=x[1:] - y=y[1:] - + x = x[1:] + y = y[1:] if self.opts['derivativeMode']: # plot dV/dt - y = np.diff(self._dataset.y)/np.diff(self._dataset.x) + y = np.diff(self._dataset.y) / np.diff(self._dataset.x) x = x[:-1] if self.opts['phasemapMode']: # plot dV/dt vs V x = self._dataset.y[:-1] - y = np.diff(self._dataset.y)/np.diff(self._dataset.x) + y = np.diff(self._dataset.y) / np.diff(self._dataset.x) - dataset = PlotDataset(x, y, self._dataset.xAllFinite, self._dataset.yAllFinite) + dataset = PlotDataset( + x, + y, + self._dataset.xAllFinite, + self._dataset.yAllFinite + ) if True in self.opts['logMode']: - dataset.applyLogMapping( self.opts['logMode'] ) # Apply log scaling for x and/or y axis + # Apply log scaling for x and/or y-axis + dataset.applyLogMapping( self.opts['logMode'] ) self._datasetMapped = dataset @@ -981,7 +1448,7 @@ def _getDisplayDataset(self): if view is None: view_range = None else: - view_range = view.viewRect() # this is always up-to-date + view_range = view.viewRect() # this is always up-to-date if view_range is None: view_range = self.viewRect() @@ -991,48 +1458,58 @@ def _getDisplayDataset(self): if self.opts['autoDownsample']: # this option presumes that x-values have uniform spacing - if xAllFinite: finite_x = x else: # False: (we checked and found non-finites) # None : (we haven't performed a check for non-finites yet) finite_x = x[np.isfinite(x)] # ignore infinite and nan values - if view_range is not None and len(finite_x) > 1: dx = float(finite_x[-1]-finite_x[0]) / (len(finite_x)-1) if dx != 0.0: width = self.getViewBox().width() if width != 0.0: # autoDownsampleFactor _should_ be > 1.0 - ds_float = max(1.0, abs(view_range.width() / dx / (width * self.opts['autoDownsampleFactor']))) + ds_float = max( + 1.0, + abs( + view_range.width() / + dx / + (width * self.opts['autoDownsampleFactor']) + ) + ) if math.isfinite(ds_float): ds = int(ds_float) - ## downsampling is expensive; delay until after clipping. # use the last computed value if our new value is not too different. # this guards against an infinite cycle where the plot never stabilizes. if math.isclose(ds, self._adsLastValue, rel_tol=0.01): ds = self._adsLastValue self._adsLastValue = ds + # downsampling is expensive; delay until after clipping. if self.opts['clipToView']: if view is None or view.autoRangeEnabled()[0]: - pass # no ViewBox to clip to, or view will autoscale to data range. + pass # no ViewBox to clip to, or view will autoscale to data range. else: # clip-to-view always presumes that x-values are in increasing order if view_range is not None and len(x) > 1: - # find first in-view value (left edge) and first out-of-view value (right edge) - # since we want the curve to go to the edge of the screen, we need to preserve - # one down-sampled point on the left and one of the right, so we extend the interval - x0 = bisect.bisect_left(x, view_range.left()) - ds - x0 = fn.clip_scalar(x0, 0, len(x)) # workaround + # find first in-view value (left edge) and first out-of-view value + # (right edge) since we want the curve to go to the edge of the + # screen, we need to preserve one down-sampled point on the left and + # one of the right, so we extend the interval + + # np.searchsorted performs poorly when the array.dtype does not + # match the type of the value (float) being searched. + # see: https://github.com/pyqtgraph/pyqtgraph/pull/2719 # x0 = np.searchsorted(x, view_range.left()) - ds + x0 = bisect.bisect_left(x, view_range.left()) - ds # x0 = np.clip(x0, 0, len(x)) + x0 = fn.clip_scalar(x0, 0, len(x)) # workaround - x1 = bisect.bisect_left(x, view_range.right()) + ds - x1 = fn.clip_scalar(x1, x0, len(x)) # x1 = np.searchsorted(x, view_range.right()) + ds + x1 = bisect.bisect_left(x, view_range.right()) + ds # x1 = np.clip(x1, 0, len(x)) + x1 = fn.clip_scalar(x1, x0, len(x)) x = x[x0:x1] y = y[x0:x1] @@ -1042,115 +1519,156 @@ def _getDisplayDataset(self): y = y[::ds] elif self.opts['downsampleMethod'] == 'mean': n = len(x) // ds - stx = ds//2 # start of x-values; try to select a somewhat centered point - x = x[stx:stx+n*ds:ds] - y = y[:n*ds].reshape(n,ds).mean(axis=1) + # start of x-values try to select a somewhat centered point + stx = ds // 2 + x = x[stx:stx + n * ds:ds] + y = y[:n * ds].reshape(n, ds).mean(axis=1) elif self.opts['downsampleMethod'] == 'peak': n = len(x) // ds - x1 = np.empty((n,2)) - stx = ds//2 # start of x-values; try to select a somewhat centered point - x1[:] = x[stx:stx+n*ds:ds,np.newaxis] - x = x1.reshape(n*2) - y1 = np.empty((n,2)) - y2 = y[:n*ds].reshape((n, ds)) - y1[:,0] = y2.max(axis=1) - y1[:,1] = y2.min(axis=1) - y = y1.reshape(n*2) - - if self.opts['dynamicRangeLimit'] is not None: - if view_range is not None: - data_range = self._datasetMapped.dataRect() - if data_range is not None: - view_height = view_range.height() - limit = self.opts['dynamicRangeLimit'] - hyst = self.opts['dynamicRangeHyst'] - # never clip data if it fits into +/- (extended) limit * view height - if ( # note that "bottom" is the larger number, and "top" is the smaller one. - view_height > 0 # never clip if the view does not show anything and would cause division by zero - and not data_range.bottom() < view_range.top() # never clip if all data is too small to see - and not data_range.top() > view_range.bottom() # never clip if all data is too large to see - and data_range.height() > 2 * hyst * limit * view_height - ): - cache_is_good = False - # check if cached display data can be reused: - if self._datasetDisplay is not None: # top is minimum value, bottom is maximum value - # how many multiples of the current view height does the clipped plot extend to the top and bottom? - top_exc =-(self._drlLastClip[0]-view_range.bottom()) / view_height - bot_exc = (self._drlLastClip[1]-view_range.top() ) / view_height - # print(top_exc, bot_exc, hyst) - if ( top_exc >= limit / hyst and top_exc <= limit * hyst - and bot_exc >= limit / hyst and bot_exc <= limit * hyst ): - # restore cached values - x = self._datasetDisplay.x - y = self._datasetDisplay.y - cache_is_good = True - if not cache_is_good: - min_val = view_range.bottom() - limit * view_height - max_val = view_range.top() + limit * view_height - # print('alloc:', end='') - # workaround for slowdown from numpy deprecation issues in 1.17 to 1.20+ : - # y = np.clip(y, a_min=min_val, a_max=max_val) - y = fn.clip_array(y, min_val, max_val) - self._drlLastClip = (min_val, max_val) + x1 = np.empty((n, 2)) + # start of x-values; try to select a somewhat centered point + stx = ds // 2 + x1[:] = x[stx:stx + n * ds:ds, np.newaxis] + x = x1.reshape(n * 2) + y1 = np.empty((n, 2)) + y2 = y[:n * ds].reshape((n, ds)) + y1[:, 0] = y2.max(axis=1) + y1[:, 1] = y2.min(axis=1) + y = y1.reshape(n * 2) + + if self.opts['dynamicRangeLimit'] is not None and view_range is not None: + data_range = self._datasetMapped.dataRect() + if data_range is not None: + view_height = view_range.height() + limit = self.opts['dynamicRangeLimit'] + hyst = self.opts['dynamicRangeHyst'] + # never clip data if it fits into +/- (extended) limit * view height + if ( + # note that "bottom" is the larger number, and "top" is the smaller + # one. Never clip if the view does not show anything and would cause + # division by zero + view_height > 0 + # never clip if all data is too small to see + and not data_range.bottom() < view_range.top() + # never clip if all data is too large to see + and not data_range.top() > view_range.bottom() + and data_range.height() > 2 * hyst * limit * view_height + ): + cache_is_good = False + # check if cached display data can be reused: + if self._datasetDisplay is not None: + # top is minimum value, bottom is maximum value + # how many multiples of the current view height does the clipped + # plot extend to the top and bottom? + top_exc = -(self._drlLastClip[0]-view_range.bottom()) / view_height + bot_exc = (self._drlLastClip[1]-view_range.top() ) / view_height + if ( + limit / hyst <= top_exc <= limit * hyst and + limit / hyst <= bot_exc <= limit * hyst + ): + # restore cached values + x = self._datasetDisplay.x + y = self._datasetDisplay.y + cache_is_good = True + if not cache_is_good: + min_val = view_range.bottom() - limit * view_height + max_val = view_range.top() + limit * view_height + y = fn.clip_array(y, min_val, max_val) + self._drlLastClip = (min_val, max_val) self._datasetDisplay = PlotDataset(x, y, xAllFinite, yAllFinite) self.setProperty('xViewRangeWasChanged', False) self.setProperty('yViewRangeWasChanged', False) return self._datasetDisplay - def getData(self): + def getData(self) -> tuple[None, None] | tuple[np.ndarray, np.ndarray]: """ - Returns the displayed data as the tuple (`xData`, `yData`) after mapping and data reduction. + The data being rendered on the screen. + + Returns + ------- + xData : np.ndarray or None + The x-axis data, after mapping and data reduction if present or ``None``. + yData : np.ndarray or None + The y-axis data, after mapping and data reduction if present or ``None``. """ dataset = self._getDisplayDataset() - if dataset is None: - return (None, None) - return dataset.x, dataset.y + return (None, None) if dataset is None else (dataset.x, dataset.y) - # compatbility method for access to dataRect for full dataset: - def dataRect(self): - """ - Returns a bounding rectangle (as :class:`QtCore.QRectF`) for the full set of data. - Will return `None` if there is no data or if all values (x or y) are NaN. + # compatibility method for access to dataRect for full dataset: + def dataRect(self) -> QtCore.QRectF | None: """ - if self._dataset is None: - return None - return self._dataset.dataRect() + The bounding rectangle for the full set of data. - def dataBounds(self, ax, frac=1.0, orthoRange=None): + Returns + ------- + :class:`QRectF` or None + Will return ``None`` if there is no data or if all values (x or y) are + ``NaN``. + """ + return None if self._dataset is None else self._dataset.dataRect() + + def dataBounds( + self, + ax: int, + frac: float = 1.0, + orthoRange: tuple[float, float] | None = None + ) -> tuple[float, float] | tuple[None, None]: """ - Returns the range occupied by the data (along a specific axis) in this item. - This method is called by :class:`ViewBox` when auto-scaling. - - =============== ==================================================================== - **Arguments:** - ax (0 or 1) the axis for which to return this item's data range - frac (float 0.0-1.0) Specifies what fraction of the total data - range to return. By default, the entire range is returned. - This allows the :class:`ViewBox` to ignore large spikes in the data - when auto-scaling. - orthoRange ([min,max] or None) Specifies that only the data within the - given range (orthogonal to *ax*) should me measured when - returning the data range. (For example, a ViewBox might ask - what is the y-range of all data with x-values between min - and max) - =============== ==================================================================== + Get the range occupied by the data (along a specific axis) for this item. + + This method is called by :class:`~pyqtgraph.ViewBox` when auto-scrolling. + + Parameters + ---------- + ax : { 0, 1 } + The axis for which to return this items data range. + * 0 - x-axis + * 1 - y-axis + frac : float, default 1.0 + Specifies the fraction of the total data range to return. By default, the + entire range is returned. This allows the :class:`~pyqtgraph.ViewBox` to + ignore large spikes in the data when auto-scrolling. + orthoRange : tuple of float, float or None, optional, default None + Specify that only the data within the given range (orthogonal to `ax`), + should be measured when returning the data range. For example, a + :class:`~pyqtgraph.ViewBox` might ask what is the y-range of all data with + x-values between the specifies (min, max) range. + + Returns + ------- + min : float or None + The minimum end of the range that the data occupies along the specified + axis. ``None`` if there is no data. + max : float or None + The maximum end of the range that the data occupies along the specified + axis. ``None`` if there is no data. """ - range = [None, None] + bounds: tuple[None, None] | tuple[float, float] = (None, None) if self.curve.isVisible(): - range = self.curve.dataBounds(ax, frac, orthoRange) - elif self.scatter.isVisible(): - r2 = self.scatter.dataBounds(ax, frac, orthoRange) - range = [ - r2[0] if range[0] is None else (range[0] if r2[0] is None else min(r2[0], range[0])), - r2[1] if range[1] is None else (range[1] if r2[1] is None else min(r2[1], range[1])) - ] - return range - - def pixelPadding(self): + bounds = self.curve.dataBounds(ax, frac, orthoRange) + if self.scatter.isVisible(): + bounds2 = self.scatter.dataBounds(ax, frac, orthoRange) + bounds = ( + min( + (i for i in [bounds2[0], bounds[0]] if i is not None), default=None + ), + min( + (i for i in [bounds2[1], bounds[1]] if i is not None), default=None + ) + ) + return bounds + + def pixelPadding(self) -> int: """ - Returns the size in pixels that this item may draw beyond the values returned by dataBounds(). - This method is called by :class:`ViewBox` when auto-scaling. + Get the size (in pixels) that this item may draw beyond the current data. + + Returns + ------- + int + The padding size in pixels that this item may draw beyond the values + returned by :meth:`dataBounds`. This method is called by :class:`ViewBox` + when auto-scaling. """ pad = 0 if self.curve.isVisible(): @@ -1160,23 +1678,33 @@ def pixelPadding(self): return pad def clear(self): - self._dataset = None - self._datasetMapped = None - self._datasetDisplay = None + self._dataset = self._datasetMapped = self._datasetDisplay = None self.curve.clear() self.scatter.clear() - def appendData(self, *args, **kargs): + def appendData(self, *args, **kwargs): pass - def curveClicked(self, curve, ev): + def curveClicked(self, _: PlotCurveItem, ev): + warnings.warn( + ( + "PlotCurveItem.curveClicked is deprecated, and will be removed in a " + "future version of pyqtgraph." + ), DeprecationWarning, stacklevel=3 + ) self.sigClicked.emit(self, ev) - def scatterClicked(self, plt, points, ev): + def scatterClicked(self, _, points, ev): self.sigClicked.emit(self, ev) self.sigPointsClicked.emit(self, points, ev) - def scatterHovered(self, plt, points, ev): + def scatterHovered(self, _, points, ev): + warnings.warn( + ( + "PlotCurveItem.scatterHovered is deprecated, and will be removed in a " + "future version of pyqtgraph." + ), DeprecationWarning, stacklevel=3 + ) self.sigPointsHovered.emit(self, points, ev) # def viewTransformChanged(self): @@ -1193,7 +1721,8 @@ def viewRangeChanged(self, vb=None, ranges=None, changed=None): # if ranges is not None: # print('hor:', ranges[0]) self.setProperty('xViewRangeWasChanged', True) - if( self.opts['clipToView'] + if ( + self.opts['clipToView'] or self.opts['autoDownsample'] ): self._datasetDisplay = None @@ -1208,48 +1737,62 @@ def viewRangeChanged(self, vb=None, ranges=None, changed=None): if update_needed: self.updateItems(styleUpdate=False) - def _fourierTransform(self, x, y): - ## Perform Fourier transform. If x values are not sampled uniformly, - ## then use np.interp to resample before taking fft. + @staticmethod + def _fourierTransform(x, y): + # Perform Fourier transform. If x values are not sampled uniformly, + # then use np.interp to resample before taking fft. dx = np.diff(x) - uniform = not np.any(np.abs(dx-dx[0]) > (abs(dx[0]) / 1000.)) + uniform = not np.any(np.abs(dx - dx[0]) > (abs(dx[0]) / 1000.)) if not uniform: x2 = np.linspace(x[0], x[-1], len(x)) y = np.interp(x2, x, y) x = x2 n = y.size f = np.fft.rfft(y) / n - d = float(x[-1]-x[0]) / (len(x)-1) + d = float(x[-1] - x[0]) / (len(x) - 1) x = np.fft.rfftfreq(n, d) y = np.abs(f) return x, y - -# helper functions: -def dataType(obj): + + +def dataType(obj) -> str: + type_: str if hasattr(obj, '__len__') and len(obj) == 0: - return 'empty' - if isinstance(obj, dict): - return 'dictOfLists' - elif isSequence(obj): + type_ = 'empty' + elif isinstance(obj, dict): + type_ = 'dictOfLists' + elif np.iterable(obj): first = obj[0] - - if (hasattr(obj, 'implements') and obj.implements('MetaArray')): - return 'MetaArray' - elif isinstance(obj, np.ndarray): + if isinstance(obj, np.ndarray): if obj.ndim == 1: - if obj.dtype.names is None: - return 'listOfValues' - else: - return 'recarray' + type_ = 'listOfValues' if obj.dtype.names is None else 'recarray' elif obj.ndim == 2 and obj.dtype.names is None and obj.shape[1] == 2: - return 'Nx2array' + type_ = 'Nx2array' else: - raise ValueError('array shape must be (N,) or (N,2); got %s instead' % str(obj.shape)) + raise ValueError( + f'array shape must be (N,) or (N,2); got {str(obj.shape)} instead' + ) elif isinstance(first, dict): - return 'listOfDicts' + type_ = 'listOfDicts' else: - return 'listOfValues' + type_ = 'listOfValues' + else: + raise ValueError("Cannot identify data-structure.") + return type_ def isSequence(obj): - return hasattr(obj, '__iter__') or isinstance(obj, np.ndarray) or (hasattr(obj, 'implements') and obj.implements('MetaArray')) + warnings.warn( + ( + "isSequence is deprecated and will be removed in a future version of" + "pyqtgraph, use np.iterable(obj) instead." + ), DeprecationWarning, stacklevel=2 + ) + return ( + hasattr(obj, '__iter__') or + isinstance(obj, np.ndarray) or + ( + hasattr(obj, 'implements') and + obj.implements('MetaArray') + ) + ) diff --git a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py index 5c9decb523..deca078457 100644 --- a/pyqtgraph/graphicsItems/PlotItem/PlotItem.py +++ b/pyqtgraph/graphicsItems/PlotItem/PlotItem.py @@ -552,7 +552,7 @@ def addItem(self, item, *args, **kargs): self.legend.addItem(item, name=name) def listDataItems(self): - """Return a list of all data items (:class:`PlotDataItem `, + """Return a list of all data items (:class:`~pyqtgraph.PlotDataItem`, :class:`~pyqtgraph.PlotCurveItem` , :class:`~pyqtgraph.ScatterPlotItem` , etc) contained in this PlotItem.""" return self.dataItems[:] @@ -611,8 +611,7 @@ def clearPlots(self): def plot(self, *args, **kargs): # **Additional arguments:** """ - Add and return a new plot. - See :func:`PlotDataItem.__init__ ` for data arguments + Add and return a new plot. See :class:`PlotDataItem` for data arguments **Additional allowed arguments** diff --git a/pyqtgraph/graphicsItems/ROI.py b/pyqtgraph/graphicsItems/ROI.py index 39fb143298..5774eccc43 100644 --- a/pyqtgraph/graphicsItems/ROI.py +++ b/pyqtgraph/graphicsItems/ROI.py @@ -105,6 +105,10 @@ class ROI(GraphicsObject): an option to remove the ROI. The ROI emits sigRemoveRequested when this menu action is selected. Default is False. + antialias (bool) If True, the ROI will render using AntiAliasing, + this is what is desired in almost all cases, the option is + added for testing purposes. + Default is True ================ =========================================================== @@ -143,7 +147,7 @@ def __init__(self, pos, size=Point(1, 1), angle=0.0, invertible=False, translateSnap=False, rotateSnap=False, parent=None, pen=None, hoverPen=None, handlePen=None, handleHoverPen=None, movable=True, rotatable=True, resizable=True, removable=False, - aspectLocked=False): + aspectLocked=False, antialias=True): GraphicsObject.__init__(self, parent) self.setAcceptedMouseButtons(QtCore.Qt.MouseButton.NoButton) pos = Point(pos) @@ -154,6 +158,7 @@ def __init__(self, pos, size=Point(1, 1), angle=0.0, invertible=False, self.resizable = resizable self.removable = removable self.menu = None + self._antialias = antialias self.freeHandleMoved = False ## keep track of whether free handles have moved since last change signal was emitted. self.mouseHovering = False @@ -611,7 +616,7 @@ def addHandle(self, info, index=None): ## If a Handle was not supplied, create it now if 'item' not in info or info['item'] is None: h = Handle(self.handleSize, typ=info['type'], pen=self.handlePen, - hoverPen=self.handleHoverPen, parent=self) + hoverPen=self.handleHoverPen, parent=self, antialias=self._antialias) info['item'] = h else: h = info['item'] @@ -762,8 +767,8 @@ def _makePen(self): return self.pen def contextMenuEnabled(self): - return self.removable - + return self.removable or self.menu and len(self.menu.children()) > 1 + def raiseContextMenu(self, ev): if not self.contextMenuEnabled(): return @@ -776,13 +781,11 @@ def getMenu(self): if self.menu is None: self.menu = QtWidgets.QMenu() self.menu.setTitle(translate("ROI", "ROI")) - remAct = QtGui.QAction(translate("ROI", "Remove ROI"), self.menu) - remAct.triggered.connect(self.removeClicked) - self.menu.addAction(remAct) - self.menu.remAct = remAct - # ROI menu may be requested when showing the handle context menu, so - # return the menu but disable it if the ROI isn't removable - self.menu.setEnabled(self.contextMenuEnabled()) + if self.removable: + remAct = QtGui.QAction(translate("ROI", "Remove ROI"), self.menu) + remAct.triggered.connect(self.removeClicked) + self.menu.addAction(remAct) + self.menu.remAct = remAct return self.menu def removeClicked(self): @@ -1069,8 +1072,10 @@ def boundingRect(self): def paint(self, p, opt, widget): # Note: don't use self.boundingRect here, because subclasses may need to redefine it. r = QtCore.QRectF(0, 0, self.state['size'][0], self.state['size'][1]).normalized() - - p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) + p.setRenderHint( + QtGui.QPainter.RenderHint.Antialiasing, + self._antialias + ) p.setPen(self.currentPen) p.translate(r.left(), r.top()) p.scale(r.width(), r.height()) @@ -1337,19 +1342,18 @@ class Handle(UIGraphicsItem): sigRemoveRequested = QtCore.Signal(object) # self def __init__(self, radius, typ=None, pen=(200, 200, 220), - hoverPen=(255, 255, 0), parent=None, deletable=False): + hoverPen=(255, 255, 0), parent=None, deletable=False, antialias=True): self.rois = [] self.radius = radius self.typ = typ self.pen = fn.mkPen(pen) self.hoverPen = fn.mkPen(hoverPen) self.currentPen = self.pen - self.pen.setWidth(0) - self.pen.setCosmetic(True) self.isMoving = False self.sides, self.startAng = self.types[typ] self.buildPath() self._shape = None + self._antialias = antialias self.menu = self.buildMenu() UIGraphicsItem.__init__(self, parent=parent) @@ -1470,19 +1474,22 @@ def buildPath(self): self.path = QtGui.QPainterPath() ang = self.startAng dt = 2 * np.pi / self.sides - for i in range(0, self.sides+1): + for i in range(0, self.sides): x = size * cos(ang) y = size * sin(ang) ang += dt if i == 0: self.path.moveTo(x, y) else: - self.path.lineTo(x, y) + self.path.lineTo(x, y) + self.path.closeSubpath() def paint(self, p, opt, widget): - p.setRenderHints(p.RenderHint.Antialiasing, True) + p.setRenderHint( + p.RenderHint.Antialiasing, + self._antialias + ) p.setPen(self.currentPen) - p.drawPath(self.shape()) def shape(self): @@ -1491,7 +1498,9 @@ def shape(self): if s is None: return self.path self._shape = s - self.prepareGeometryChange() ## beware--this can cause the view to adjust, which would immediately invalidate the shape. + # beware--this can cause the view to adjust, + # which would immediately invalidate the shape. + self.prepareGeometryChange() return self._shape def boundingRect(self): @@ -1842,12 +1851,14 @@ def _clearPath(self): def paint(self, p, opt, widget): r = self.boundingRect() - p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) + + p.setRenderHint( + QtGui.QPainter.RenderHint.Antialiasing, + self._antialias + ) p.setPen(self.currentPen) - p.scale(r.width(), r.height())## workaround for GL bug r = QtCore.QRectF(r.x()/r.width(), r.y()/r.height(), 1,1) - p.drawEllipse(r) def getArrayRegion(self, arr, img=None, axes=(0, 1), returnMappedCoords=False, **kwds): @@ -2020,7 +2031,7 @@ def setState(self, state): def addSegment(self, h1, h2, index=None): seg = _PolyLineSegment(handles=(h1, h2), pen=self.pen, hoverPen=self.hoverPen, - parent=self, movable=False) + parent=self, movable=False, antialias=self._antialias) if index is None: self.segments.append(seg) else: @@ -2165,7 +2176,10 @@ def setState(self, state): self.movePoint(self.getHandles()[1], p2) def paint(self, p, *args): - p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) + p.setRenderHint( + QtGui.QPainter.RenderHint.Antialiasing, + self._antialias + ) p.setPen(self.currentPen) h1 = self.endpoints[0].pos() h2 = self.endpoints[1].pos() @@ -2281,9 +2295,11 @@ def shape(self): def paint(self, p, *args): radius = self.getState()['size'][1] - p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) + p.setRenderHint( + QtGui.QPainter.RenderHint.Antialiasing, + self._antialias + ) p.setPen(self.currentPen) - p.drawLine(Point(0, -radius), Point(0, radius)) p.drawLine(Point(-radius, 0), Point(radius, 0)) @@ -2340,7 +2356,10 @@ def __init__(self, pos, size, **args): def paint(self, p, *args): r = self.boundingRect() - p.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing) + p.setRenderHint( + QtGui.QPainter.RenderHint.Antialiasing, + self._antialias + ) p.scale(r.width(), r.height()) p.setPen(self.currentPen) p.drawPolygon(self.poly) diff --git a/pyqtgraph/graphicsItems/ScatterPlotItem.py b/pyqtgraph/graphicsItems/ScatterPlotItem.py index 0a19882b5b..27d768faf9 100644 --- a/pyqtgraph/graphicsItems/ScatterPlotItem.py +++ b/pyqtgraph/graphicsItems/ScatterPlotItem.py @@ -16,7 +16,7 @@ ## Build all symbol paths -name_list = ['o', 's', 't', 't1', 't2', 't3', 'd', '+', 'x', 'p', 'h', 'star', +name_list = ['o', 's', 't', 't1', 't2', 't3', 'd', '+', 'x', 'p', 'h', 'star', '|', '_', 'arrow_up', 'arrow_right', 'arrow_down', 'arrow_left', 'crosshair'] Symbols = OrderedDict([(name, QtGui.QPainterPath()) for name in name_list]) Symbols['o'].addEllipse(QtCore.QRectF(-0.5, -0.5, 1, 1)) @@ -52,6 +52,7 @@ def makeCrosshair(r=0.5, w=1, h=1): (-0.1816, 0.059), (-0.2939, 0.4045), (0, 0.1910), (0.2939, 0.4045), (0.1816, 0.059), (0.4755, -0.1545), (0.1123, -0.1545)], + '|': [(-0.1, 0.5),(0.1, 0.5), (0.1, -0.5), (-0.1, -0.5)], 'arrow_up': [ (-0.125, 0.125), (0, 0), (0.125, 0.125), (0.05, 0.125), (0.05, 0.5), (-0.05, 0.5), (-0.05, 0.125) @@ -69,6 +70,9 @@ def makeCrosshair(r=0.5, w=1, h=1): Symbols['arrow_right'] = tr.map(Symbols['arrow_up']) Symbols['arrow_down'] = tr.map(Symbols['arrow_right']) Symbols['arrow_left'] = tr.map(Symbols['arrow_down']) + +# already rotated 90 degrees from earlier commands +Symbols['_'] = tr.map(Symbols['|']) _DEFAULT_STYLE = {'symbol': None, 'size': -1, 'pen': None, 'brush': None, 'visible': True} @@ -85,7 +89,7 @@ def drawSymbol(painter, symbol, size, pen, brush): painter.drawPath(symbol) -def renderSymbol(symbol, size, pen, brush, device=None): +def renderSymbol(symbol, size, pen, brush, device=None, dpr=1.0): """ Render a symbol specification to QImage. Symbol may be either a QPainterPath or one of the keys in the Symbols dict. @@ -96,13 +100,14 @@ def renderSymbol(symbol, size, pen, brush, device=None): ## Render a spot with the given parameters to a pixmap penPxWidth = max(math.ceil(pen.widthF()), 1) if device is None: - device = QtGui.QImage(int(size+penPxWidth), int(size+penPxWidth), - QtGui.QImage.Format.Format_ARGB32_Premultiplied) + side = int(math.ceil(dpr*(size+penPxWidth))) + device = QtGui.QImage(side, side, QtGui.QImage.Format.Format_ARGB32_Premultiplied) + device.setDevicePixelRatio(dpr) device.fill(QtCore.Qt.GlobalColor.transparent) p = QtGui.QPainter(device) try: p.setRenderHint(p.RenderHint.Antialiasing) - p.translate(device.width()*0.5, device.height()*0.5) + p.translate(device.width()/dpr*0.5, device.height()/dpr*0.5) drawSymbol(p, symbol, size, pen, brush) finally: p.end() @@ -148,14 +153,8 @@ class SymbolAtlas(object): _idGenerator = itertools.count() def __init__(self): - self._data = np.zeros((0, 0, 4), dtype=np.ubyte) # numpy array of atlas image - self._coords = {} - self._pixmap = None - self._maxWidth = 0 - self._totalWidth = 0 - self._totalArea = 0 - self._pos = (0, 0) - self._rowShape = (0, 0) + self._dpr = 1.0 + self.clear() def __getitem__(self, styles): """ @@ -173,6 +172,12 @@ def __getitem__(self, styles): def __len__(self): return len(self._coords) + def devicePixelRatio(self): + return self._dpr + + def setDevicePixelRatio(self, dpr): + self._dpr = dpr + @property def pixmap(self): if self._pixmap is None: @@ -181,7 +186,8 @@ def pixmap(self): @property def maxWidth(self): - return self._maxWidth + # return the max logical width + return self._maxWidth / self._dpr def rebuild(self, styles=None): profiler = debug.Profiler() # noqa: profiler prints on GC @@ -196,7 +202,14 @@ def rebuild(self, styles=None): self._extendFromData(data) def clear(self): - self.__init__() + self._data = np.zeros((0, 0, 4), dtype=np.ubyte) # numpy array of atlas image + self._coords = {} + self._pixmap = None + self._maxWidth = 0 + self._totalWidth = 0 + self._totalArea = 0 + self._pos = (0, 0) + self._rowShape = (0, 0) def diagnostics(self): n = len(self) @@ -233,7 +246,7 @@ def _extend(self, styles): images = [] data = [] for key, style in styles.items(): - img = renderSymbol(*style) + img = renderSymbol(*style, dpr=self._dpr) arr = fn.ndarray_from_qimage(img) images.append(img) # keep these to delay garbage collection data.append((key, arr)) @@ -352,6 +365,8 @@ def __init__(self, *args, **kargs): self.picture = None # QPicture used for rendering when pxmode==False self.fragmentAtlas = SymbolAtlas() + if screen := QtGui.QGuiApplication.primaryScreen(): + self.fragmentAtlas.setDevicePixelRatio(screen.devicePixelRatio()) dtype = [ ('x', float), @@ -656,6 +671,8 @@ def setSymbol(self, symbol, update=True, dataSet=None, mask=None): * 'p' pentagon * 'h' hexagon * 'star' + * '|' vertical line + * '_' horizontal line * 'x' cross * 'arrow_up' * 'arrow_right' @@ -919,7 +936,7 @@ def setExportMode(self, *args, **kwds): self.invalidate() @debug.warnOnException ## raising an exception here causes crash - def paint(self, p, *args): + def paint(self, p, option, widget): profiler = debug.Profiler() cmode = self.opts.get('compositionMode', None) if cmode is not None: @@ -947,6 +964,15 @@ def paint(self, p, *args): if self.opts['useCache'] and self._exportOpts is False: # Draw symbols from pre-rendered atlas + dpr = self.fragmentAtlas.devicePixelRatio() + if widget is not None and (dpr_new := widget.devicePixelRatioF()) != dpr: + # force a re-render if dpr changed + dpr = dpr_new + self.fragmentAtlas.setDevicePixelRatio(dpr) + self.fragmentAtlas.clear() + self.data['sourceRect'] = 0 + self.updateSpots() + # x, y is the center of the target rect xy = pts[:, viewMask].T sr = self.data['sourceRect'][viewMask] @@ -955,7 +981,7 @@ def paint(self, p, *args): frags = self._pixmapFragments.ndarray() frags[:, 0:2] = xy frags[:, 2:6] = np.frombuffer(sr, dtype=int).reshape((-1, 4)) # sx, sy, sw, sh - frags[:, 6:10] = [1.0, 1.0, 0.0, 1.0] # scaleX, scaleY, rotation, opacity + frags[:, 6:10] = [1/dpr, 1/dpr, 0.0, 1.0] # scaleX, scaleY, rotation, opacity profiler('prep') drawargs = self._pixmapFragments.drawargs() diff --git a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py index 6ea6e431d8..87a6843f1b 100644 --- a/pyqtgraph/graphicsItems/ViewBox/ViewBox.py +++ b/pyqtgraph/graphicsItems/ViewBox/ViewBox.py @@ -9,7 +9,7 @@ from ... import functions as fn from ... import getConfigOption from ...Point import Point -from ...Qt import QtCore, QtGui, QtWidgets, isQObjectAlive +from ...Qt import QtCore, QtGui, QtWidgets, isQObjectAlive, QT_LIB from ..GraphicsWidget import GraphicsWidget from ..ItemGroup import ItemGroup @@ -510,11 +510,11 @@ def targetRect(self): print("make qrectf failed:", self.state['targetRange']) raise - def _resetTarget(self): + def _resetTarget(self, force: bool = False): # Reset target range to exactly match current view range. # This is used during mouse interaction to prevent unpredictable # behavior (because the user is unaware of targetRange). - if self.state['aspectLocked'] is False: # (interferes with aspect locking) + if self.state['aspectLocked'] is False or force: # (interferes with aspect locking) self.state['targetRange'] = [self.state['viewRange'][0][:], self.state['viewRange'][1][:]] def _effectiveLimits(self): @@ -1615,7 +1615,9 @@ def updateViewRange(self, forceX=False, forceY=False): if maxRng[target] is not None and diff > maxRng[target] or \ minRng[target] is not None and diff < minRng[target]: # tweak the target range down so we can still pan properly - self.state['targetRange'][ax] = canidateRange[ax] + viewRange[ax] = canidateRange[ax] + self.state['viewRange'][ax] = viewRange[ax] + self._resetTarget(force=True) ax = target # Switch the "fixed" axes if ax == 0: @@ -1629,6 +1631,26 @@ def updateViewRange(self, forceX=False, forceY=False): changed[0] = True viewRange[0] = rangeX + # Ensure, that the new viewRange obeys all the limits + for axis in [0, 1]: + range = viewRange[axis][1] - viewRange[axis][0] + if minRng[axis] is not None and minRng[axis] > range: + viewRange[axis][1] = viewRange[axis][0] + minRng[axis] + self.state["targetRange"][axis] = viewRange[axis] + if maxRng[axis] is not None and maxRng[axis] < range: + viewRange[axis][1] = viewRange[axis][0] + maxRng[axis] + self.state["targetRange"][axis] = viewRange[axis] + if limits[axis][0] is not None and viewRange[axis][0] < limits[axis][0]: + delta = limits[axis][0] - viewRange[axis][0] + viewRange[axis][0] += delta + viewRange[axis][1] += delta + self.state["targetRange"][axis] = viewRange[axis] + if limits[axis][1] is not None and viewRange[axis][1] > limits[axis][1]: + delta = viewRange[axis][1] - limits[axis][1] + viewRange[axis][0] -= delta + viewRange[axis][1] -= delta + self.state["targetRange"][axis] = viewRange[axis] + # Consider only as 'changed' if the differences are larger than floating point inaccuracies, # which regularly appear in magnitude of around 1e-15. Therefore, 1e-9 as factor was chosen # more or less arbitrarily. @@ -1763,6 +1785,15 @@ def quit(): if isQObjectAlive(k) and getConfigOption('crashWarning'): sys.stderr.write('Warning: ViewBox should be closed before application exit.\n') + # PySide >= 6.7 prints a warning if we attempt to disconnect + # a signal that isn't connected. + if ( + QT_LIB == 'PySide6' and + isQObjectAlive(k) and + k.receivers(QtCore.SIGNAL("destroyed()")) == 0 + ): + continue + try: k.destroyed.disconnect() except RuntimeError: ## signal is already disconnected. diff --git a/pyqtgraph/icons/peegee/peegee.svg b/pyqtgraph/icons/peegee/peegee.svg new file mode 100644 index 0000000000..b34df009db --- /dev/null +++ b/pyqtgraph/icons/peegee/peegee.svg @@ -0,0 +1,209 @@ + + + + diff --git a/pyqtgraph/icons/peegee/peegee_128px.png b/pyqtgraph/icons/peegee/peegee_128px.png new file mode 100644 index 0000000000..6826ec3e58 Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_128px.png differ diff --git a/pyqtgraph/icons/peegee/peegee_128px@2x.png b/pyqtgraph/icons/peegee/peegee_128px@2x.png new file mode 100644 index 0000000000..4245c67da2 Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_128px@2x.png differ diff --git a/pyqtgraph/icons/peegee/peegee_192px.png b/pyqtgraph/icons/peegee/peegee_192px.png new file mode 100644 index 0000000000..34bba92b97 Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_192px.png differ diff --git a/pyqtgraph/icons/peegee/peegee_256px.png b/pyqtgraph/icons/peegee/peegee_256px.png new file mode 100644 index 0000000000..4245c67da2 Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_256px.png differ diff --git a/pyqtgraph/icons/peegee/peegee_256px@2x.png b/pyqtgraph/icons/peegee/peegee_256px@2x.png new file mode 100644 index 0000000000..a813f9d09d Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_256px@2x.png differ diff --git a/pyqtgraph/icons/peegee/peegee_512px.png b/pyqtgraph/icons/peegee/peegee_512px.png new file mode 100644 index 0000000000..a813f9d09d Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_512px.png differ diff --git a/pyqtgraph/icons/peegee/peegee_512px@2x.png b/pyqtgraph/icons/peegee/peegee_512px@2x.png new file mode 100644 index 0000000000..a9a92a4b93 Binary files /dev/null and b/pyqtgraph/icons/peegee/peegee_512px@2x.png differ diff --git a/pyqtgraph/parametertree/Parameter.py b/pyqtgraph/parametertree/Parameter.py index 6b7581780e..ea3c8759e5 100644 --- a/pyqtgraph/parametertree/Parameter.py +++ b/pyqtgraph/parametertree/Parameter.py @@ -1,4 +1,5 @@ import re +import warnings import weakref from collections import OrderedDict @@ -11,6 +12,7 @@ _PARAM_ITEM_TYPES = {} + def registerParameterItemType(name, itemCls, parameterCls=None, override=False): """ Similar to :func:`registerParameterType`, but works on ParameterItems. This is useful for Parameters where the @@ -20,7 +22,9 @@ def registerParameterItemType(name, itemCls, parameterCls=None, override=False): """ global _PARAM_ITEM_TYPES if name in _PARAM_ITEM_TYPES and not override: - raise Exception("Parameter item type '%s' already exists (use override=True to replace)" % name) + raise ValueError( + f"Parameter item type '{name}' already exists (use override=True to replace)" + ) parameterCls = parameterCls or Parameter _PARAM_ITEM_TYPES[name] = itemCls @@ -35,14 +39,16 @@ def registerParameterType(name, cls, override=False): """ global PARAM_TYPES if name in PARAM_TYPES and not override: - raise Exception("Parameter type '%s' already exists (use override=True to replace)" % name) + raise ValueError(f"Parameter type '{name}' already exists (use override=True to replace)") PARAM_TYPES[name] = cls PARAM_NAMES[cls] = name + def __reload__(old): PARAM_TYPES.update(old.get('PARAM_TYPES', {})) PARAM_NAMES.update(old.get('PARAM_NAMES', {})) + class Parameter(QtCore.QObject): """ A Parameter is the basic unit of data in a parameter tree. Each parameter has @@ -54,7 +60,7 @@ class Parameter(QtCore.QObject): Note: It is fairly uncommon to use the Parameter class directly; mostly you will use subclasses which provide specialized type and data handling. The static - pethod Parameter.create(...) is an easy way to generate instances of these subclasses. + method Parameter.create(...) is an easy way to generate instances of these subclasses. For more Parameter types, see ParameterTree.parameterTypes module. @@ -86,8 +92,6 @@ class Parameter(QtCore.QObject): ## name, type, limits, etc. ## can also carry UI hints (slider vs spinbox, etc.) - itemClass = None - sigValueChanged = QtCore.Signal(object, object) ## self, value emitted when value is finished being edited sigValueChanging = QtCore.Signal(object, object) ## self, value emitted as value is being edited @@ -134,7 +138,7 @@ def create(**opts): else: cls = PARAM_TYPES[opts['type']] return cls(**opts) - + def __init__(self, **opts): """ Initialize a Parameter object. Although it is rare to directly create a @@ -178,8 +182,6 @@ def __init__(self, **opts): (default=None; added in version 0.9.9) ======================= ========================================================= """ - - QtCore.QObject.__init__(self) self.opts = { @@ -193,36 +195,39 @@ def __init__(self, **opts): 'expanded': True, 'syncExpanded': False, 'title': None, - #'limits': None, ## This is a bad plan--each parameter type may have a different data type for limits. + # The following intentionally excluded; each parameter type may have a different data type for limits. + # 'limits': None, } - value = opts.get('value', None) name = opts.get('name', None) + if not isinstance(name, str): + raise TypeError("Parameter must have a string name specified in opts.") self.opts.update(opts) - self.opts['value'] = None # will be set later. self.opts['name'] = None - + self.childs = [] self.names = {} ## map name:child self.items = weakref.WeakKeyDictionary() ## keeps track of tree items representing this parameter self._parent = None self.treeStateChanges = [] ## cache of tree state changes to be delivered on next emit self.blockTreeChangeEmit = 0 - #self.monitoringChildren = False ## prevent calling monitorChildren more than once - - if not isinstance(name, str): - raise Exception("Parameter must have a string name specified in opts.") self.setName(name) - + self.addChildren(self.opts.pop('children', [])) - + if 'value' in self.opts and 'default' not in self.opts: + warnings.warn( + "Parameter has no default value. Pass a default, or use setDefault(). This will no longer set " + "an implicit default after January 2025.", + DeprecationWarning, + stacklevel=2, + ) + self.opts['default'] = self.opts['value'] + value = self.opts.get('value', self.opts.get('default', None)) + modified = 'value' in self.opts if value is not None: self.setValue(value) + self._modifiedSinceReset = modified - if 'default' not in self.opts: - self.opts['default'] = None - self.setDefault(self.opts['value']) - - ## Connect all state changed signals to the general sigStateChanged + # Connect all state changed signals to the general sigStateChanged self.sigValueChanged.connect(self._emitValueChanged) self.sigChildAdded.connect(self._emitChildAddedChanged) self.sigChildRemoved.connect(self._emitChildRemovedChanged) @@ -233,9 +238,13 @@ def __init__(self, **opts): self.sigOptionsChanged.connect(self._emitOptionsChanged) self.sigContextMenu.connect(self._emitContextMenuChanged) - - #self.watchParam(self) ## emit treechange signals if our own state changes - + @property + def itemClass(self): + """ + The class of ParameterItem to use when displaying this parameter in a ParameterTree. + """ + return ParameterItem + def name(self): """Return the name of this Parameter.""" return self.opts['name'] @@ -257,12 +266,13 @@ def contextMenu(self, name): def setName(self, name): """Attempt to change the name of this parameter; return the actual name. (The parameter may reject the name change or automatically pick a different name)""" - if self.opts['strictNaming']: - if len(name) < 1 or re.search(r'\W', name) or re.match(r'\d', name[0]): - raise Exception("Parameter name '%s' is invalid. (Must contain only alphanumeric and underscore characters and may not start with a number)" % name) + if self.opts['strictNaming'] and (len(name) < 1 or re.search(r'\W', name) or re.match(r'\d', name[0])): + raise ValueError( + f"Parameter name '{name}' is invalid. (Must contain only alphanumeric and underscore characters and " + f"may not start with a number)") parent = self.parent() if parent is not None: - name = parent._renameChild(self, name) ## first ask parent if it's ok to rename + name = parent._renameChild(self, name) # first ask parent if it's ok to rename if self.opts['name'] != name: self.opts['name'] = name self.sigNameChanged.emit(self, name) @@ -285,7 +295,7 @@ def isType(self, typ): global PARAM_TYPES cls = PARAM_TYPES.get(typ, None) if cls is None: - raise Exception("Type name '%s' is not registered." % str(typ)) + raise ValueError(f"Type name '{typ}' is not registered.") return self.__class__ is cls def childPath(self, child): @@ -310,8 +320,9 @@ def setValue(self, value, blockSignal=None): if blockSignal is not None: self.sigValueChanged.disconnect(blockSignal) value = self._interpretValue(value) - if fn.eq(self.opts['value'], value): + if fn.eq(self.opts.get('value', None), value): return value + self._modifiedSinceReset = True self.opts['value'] = value self.sigValueChanged.emit(self, value) # value might change after signal is received by tree item finally: @@ -323,14 +334,27 @@ def setValue(self, value, blockSignal=None): def _interpretValue(self, v): return v + def hasValue(self): + """Return True if this Parameter has a value set.""" + return 'value' in self.opts + def value(self): """ - Return the value of this Parameter. + Return the value of this Parameter. Raises ValueError if no value has been set. """ - return self.opts['value'] + if 'value' not in self.opts: + warnings.warn( + "Parameter has no value set. Pass an initial value or default, or use setValue() or setDefault(). " + "This will be an error after January 2025.", + DeprecationWarning, + stacklevel=2, + ) + return self.opts.get('value') def getValues(self): - """Return a tree of all values that are children of this parameter""" + """ + Return a tree of all values that are children of this parameter. Raises ValueError if any child has no value. + """ vals = OrderedDict() for ch in self: vals[ch.name()] = (ch.value(), ch.getValues()) @@ -350,9 +374,12 @@ def saveState(self, filter=None): global PARAM_NAMES state['type'] = PARAM_NAMES.get(type(self), None) elif filter == 'user': - state = {'value': self.value()} + if self.hasValue(): + state = {'value': self.value()} + else: + state = {} else: - raise ValueError("Unrecognized filter argument: '%s'" % filter) + raise ValueError(f"Unrecognized filter argument: '{filter}'") ch = OrderedDict([(ch.name(), ch.saveState(filter=filter)) for ch in self]) if len(ch) > 0: @@ -435,33 +462,49 @@ def restoreState(self, state, recursive=True, addChildren=True, removeChildren=T finally: if blockSignals: self.unblockTreeChangeSignal() - - - + + def valueModifiedSinceResetToDefault(self): + """Return True if this parameter's value has been changed since the last time + it was reset to its default value.""" + return self._modifiedSinceReset + def defaultValue(self): - """Return the default value for this parameter.""" - return self.opts['default'] - - def setDefault(self, val): - """Set the default value for this parameter.""" - if self.opts['default'] == val: + """Return the default value for this parameter. Raises ValueError if no default.""" + if 'default' not in self.opts: + warnings.warn("Parameter has no default value. This will be a ValueError after January 2025.", + DeprecationWarning, + stacklevel=2) + return self.opts.get('default') + + def setDefault(self, val, updatePristineValues=False): + """Set the default value for this parameter. If updatePristineValues is True, then + any values that haven't been modified since the last time they were reset to default + will be updated to the new default value (default: False).""" + if self.opts.get('default', None) == val: return self.opts['default'] = val + if 'value' not in self.opts or (updatePristineValues and not self.valueModifiedSinceResetToDefault()): + self.setToDefault() + if not self.valueIsDefault(): + self._modifiedSinceReset = True self.sigDefaultChanged.emit(self, val) def setToDefault(self): - """Set this parameter's value to the default.""" - if self.hasDefault(): + """Set this parameter's value to the default. Raises ValueError if no default is set.""" + with self.treeChangeBlocker(): self.setValue(self.defaultValue()) + self._modifiedSinceReset = False def hasDefault(self): """Returns True if this parameter has a default value.""" - return self.opts['default'] is not None + return self.opts.get('default', None) is not None def valueIsDefault(self): """Returns True if this parameter's value is equal to the default value.""" + if not self.hasValue() or not self.hasDefault(): + return False return fn.eq(self.value(), self.defaultValue()) - + def setLimits(self, limits): """Set limits on the acceptable values for this parameter. The format of limits depends on the type of the parameter and @@ -501,7 +544,8 @@ def setOpts(self, **opts): Set any arbitrary options on this parameter. The exact behavior of this function will depend on the parameter type, but most parameters will accept a common set of options: value, name, limits, - default, readonly, removable, renamable, visible, enabled, expanded and syncExpanded. + default, readonly, removable, renamable, visible, enabled, expanded and + syncExpanded. See :func:`Parameter.__init__ ` for more information on default options. @@ -570,7 +614,6 @@ def makeTreeItem(self, depth): itemClass = self.itemClass or _PARAM_ITEM_TYPES.get(self.opts['type'], ParameterItem) return itemClass(self, depth) - def addChild(self, child, autoIncrementName=None, existOk=False): """ Add another parameter to the end of this parameter's child list. @@ -704,14 +747,15 @@ def incrementName(self, name): num += 1 def __iter__(self): - for ch in self.childs: - yield ch + yield from self.childs def __getitem__(self, names): """Get the value of a child parameter. The name may also be a tuple giving the path to a sub-parameter:: value = param[('child', 'grandchild')] + + Raises ValueError if the child value is not set. """ if not isinstance(names, tuple): names = (names,) @@ -739,9 +783,9 @@ def child(self, *names): """ try: param = self.names[names[0]] - except KeyError: - raise KeyError("Parameter %s has no child named %s" % (self.name(), names[0])) - + except KeyError as e: + raise KeyError(f"Parameter {self.name()} has no child named {names[0]}") from e + if len(names) > 1: return param.child(*names[1:]) else: @@ -829,6 +873,7 @@ def emitTreeChanges(self): if len(changes) > 0: self.sigTreeStateChanged.emit(self, changes) + class SignalBlocker(object): def __init__(self, enterFn, exitFn): self.enterFn = enterFn diff --git a/pyqtgraph/parametertree/ParameterSystem.py b/pyqtgraph/parametertree/ParameterSystem.py index c9e60ebe17..728390d0c6 100644 --- a/pyqtgraph/parametertree/ParameterSystem.py +++ b/pyqtgraph/parametertree/ParameterSystem.py @@ -62,24 +62,12 @@ def setSystem(self, sys): def updateSystem(self, param, changes): changes = [ch for ch in changes if ch[0] not in self._ignoreChange] - #resets = [ch[0] for ch in changes if ch[1] == 'setToDefault'] sets = [ch[0] for ch in changes if ch[1] == 'value'] - #for param in resets: - #setattr(self._system, param.name(), None) for param in sets: - #if param in resets: - #continue - - #if param in self._fixParams: - #param.parent().setWritable(param.value()) - #else: if param in self._fixParams: parent = param.parent() - if param.value(): - setattr(self._system, parent.name(), parent.value()) - else: - setattr(self._system, parent.name(), None) + setattr(self._system, parent.name(), parent.value() if parent.hasValue() else None) else: setattr(self._system, param.name(), param.value()) diff --git a/pyqtgraph/parametertree/ParameterTree.py b/pyqtgraph/parametertree/ParameterTree.py index ade9f87427..da5a529336 100644 --- a/pyqtgraph/parametertree/ParameterTree.py +++ b/pyqtgraph/parametertree/ParameterTree.py @@ -1,5 +1,5 @@ from .parameterTypes import GroupParameterItem -from ..Qt import QtCore, QtWidgets, mkQApp +from ..Qt import QtCore, QtWidgets, QtGui, mkQApp from ..widgets.TreeWidget import TreeWidget from .ParameterItem import ParameterItem @@ -21,7 +21,6 @@ def __init__(self, parent=None, showHeader=True): self.setAnimated(False) self.setColumnCount(2) self.setHeaderLabels(["Parameter", "Value"]) - self.setAlternatingRowColors(True) self.paramSet = None self.header().setSectionResizeMode(QtWidgets.QHeaderView.ResizeMode.ResizeToContents) self.setHeaderHidden(not showHeader) @@ -30,9 +29,8 @@ def __init__(self, parent=None, showHeader=True): self.itemCollapsed.connect(self.itemCollapsedEvent) self.lastSel = None self.setRootIsDecorated(False) - - app = mkQApp() - app.paletteChanged.connect(self.updatePalette) + self.setAlternatingRowColors(True) + self._updatePalette(self.palette()) def setParameters(self, param, showTop=True): """ @@ -133,16 +131,56 @@ def contextMenuEvent(self, ev): item = self.currentItem() if hasattr(item, 'contextMenuEvent'): item.contextMenuEvent(ev) - - def updatePalette(self): - """ - called when application palette changes - This should ensure that the color theme of the OS is applied to the GroupParameterItems - should the theme chang while the application is running. - """ - for item in self.listAllItems(): - if isinstance(item, GroupParameterItem): - item.updateDepth(item.depth) + + def _updatePalette(self, palette: QtGui.QPalette) -> None: + app = mkQApp() + # Docs say to use the following methods + # QApplication.instance().styleHints().colorScheme() == QtCore.Qt.ColorScheme.Dark + # but on macOS with Qt 6.7 this is giving opposite results (says color sceme is light + # when it is dark and vice versa). This was not observed in the ExampleApp, but was + # observed with the ParameterTree. We fall back to the "legacy" method of determining + # if the color theme is dark or light from QPalette + windowTextLightness = palette.color(QtGui.QPalette.ColorRole.WindowText).lightness() + windowLightness = palette.color(QtGui.QPalette.ColorRole.Window).lightness() + darkMode = windowTextLightness > windowLightness + app.setProperty('darkMode', darkMode) + + for group in [ + QtGui.QPalette.ColorGroup.Disabled, + QtGui.QPalette.ColorGroup.Active, + QtGui.QPalette.ColorGroup.Inactive + ]: + baseColor = palette.color( + group, + QtGui.QPalette.ColorRole.Base + ) + if app.property("darkMode"): + alternateColor = baseColor.lighter(180) + else: + alternateColor = baseColor.darker(110) + # apparently colors are transparent here by default! + alternateColor.setAlpha(255) + palette.setColor( + group, + QtGui.QPalette.ColorRole.AlternateBase, + alternateColor + ) + self.setPalette(palette) + return None + + def event(self, event: QtCore.QEvent) -> bool: + if event.type() == QtCore.QEvent.Type.FontChange: + for item in self.listAllItems(): + if isinstance(item, GroupParameterItem): + item.updateDepth(item.depth) + elif event.type() == QtCore.QEvent.Type.ApplicationPaletteChange: + app = mkQApp() + self._updatePalette(app.palette()) + elif event.type() == QtCore.QEvent.Type.PaletteChange: + # For Windows to effectively change all the rows we + # need to catch QEvent.Type.PaletteChange event as well + self._updatePalette(self.palette()) + return super().event(event) def itemChangedEvent(self, item, col): if hasattr(item, 'columnChangedEvent'): diff --git a/pyqtgraph/parametertree/interactive.py b/pyqtgraph/parametertree/interactive.py index 05d3eb5939..c31c817a40 100644 --- a/pyqtgraph/parametertree/interactive.py +++ b/pyqtgraph/parametertree/interactive.py @@ -3,9 +3,9 @@ import inspect import pydoc +from .. import functions as fn from . import Parameter from .parameterTypes import ActionGroupParameter -from .. import functions as fn class PARAM_UNSET: @@ -136,7 +136,7 @@ def hookupParameters(self, params=None, clearOld=True): self.parameters[param.name()] = param param.sigValueChanged.connect(self.updateCachedParameterValues) # Populate initial values - self.parameterCache[param.name()] = param.value() + self.parameterCache[param.name()] = param.value() if param.hasValue() else None def removeParameters(self, clearCache=True): """ diff --git a/pyqtgraph/parametertree/parameterTypes/__init__.py b/pyqtgraph/parametertree/parameterTypes/__init__.py index 2fe0336e04..c9515d39d4 100644 --- a/pyqtgraph/parametertree/parameterTypes/__init__.py +++ b/pyqtgraph/parametertree/parameterTypes/__init__.py @@ -1,4 +1,4 @@ -from ..Parameter import registerParameterItemType, registerParameterType +from ..Parameter import registerParameterType from .action import ActionParameter, ActionParameterItem from .actiongroup import ActionGroup, ActionGroupParameter, ActionGroupParameterItem from .basetypes import ( @@ -12,6 +12,7 @@ from .checklist import ChecklistParameter, ChecklistParameterItem from .color import ColorParameter, ColorParameterItem from .colormap import ColorMapParameter, ColorMapParameterItem +from .colormaplut import ColorMapLutParameter, ColorMapLutParameterItem from .file import FileParameter, FileParameterItem from .font import FontParameter, FontParameterItem from .list import ListParameter, ListParameterItem @@ -23,25 +24,25 @@ from .str import StrParameterItem from .text import TextParameter, TextParameterItem -registerParameterItemType('bool', BoolParameterItem, SimpleParameter, override=True) -registerParameterItemType('float', NumericParameterItem, SimpleParameter, override=True) -registerParameterItemType('int', NumericParameterItem, SimpleParameter, override=True) -registerParameterItemType('str', StrParameterItem, SimpleParameter, override=True) - registerParameterType('group', GroupParameter, override=True) # Keep actiongroup private for now, mainly useful for Interactor but not externally registerParameterType('_actiongroup', ActionGroupParameter, override=True) registerParameterType('action', ActionParameter, override=True) +registerParameterType('bool', SimpleParameter, override=True) registerParameterType('calendar', CalendarParameter, override=True) registerParameterType('checklist', ChecklistParameter, override=True) +registerParameterType('cmaplut', ColorMapLutParameter, override=True) registerParameterType('color', ColorParameter, override=True) registerParameterType('colormap', ColorMapParameter, override=True) registerParameterType('file', FileParameter, override=True) +registerParameterType('float', SimpleParameter, override=True) registerParameterType('font', FontParameter, override=True) +registerParameterType('int', SimpleParameter, override=True) registerParameterType('list', ListParameter, override=True) registerParameterType('pen', PenParameter, override=True) registerParameterType('progress', ProgressBarParameter, override=True) # qtenum is a bit specific, hold off on registering for now registerParameterType('slider', SliderParameter, override=True) +registerParameterType('str', SimpleParameter, override=True) registerParameterType('text', TextParameter, override=True) diff --git a/pyqtgraph/parametertree/parameterTypes/basetypes.py b/pyqtgraph/parametertree/parameterTypes/basetypes.py index ba9a27c921..3977acec05 100644 --- a/pyqtgraph/parametertree/parameterTypes/basetypes.py +++ b/pyqtgraph/parametertree/parameterTypes/basetypes.py @@ -2,7 +2,7 @@ from ... import functions as fn from ... import icons -from ...Qt import QtCore, QtGui, QtWidgets, mkQApp +from ...Qt import QtCore, QtWidgets from ..Parameter import Parameter from ..ParameterItem import ParameterItem @@ -17,6 +17,7 @@ class WidgetParameterItem(ParameterItem): This class can be subclassed by overriding makeWidget() to provide a custom widget. """ + def __init__(self, param, depth): ParameterItem.__init__(self, param, depth) @@ -147,11 +148,11 @@ def valueChanged(self, param, val, force=False): self.updateDefaultBtn() def updateDefaultBtn(self): - ## enable/disable default btn self.defaultBtn.setEnabled( - not self.param.valueIsDefault() and self.param.opts['enabled'] and self.param.writable()) + self.param.valueModifiedSinceResetToDefault() + and self.param.opts['enabled'] + and self.param.writable()) - # hide / show self.defaultBtn.setVisible(self.param.hasDefault() and not self.param.readonly()) def updateDisplayLabel(self, value=None): @@ -217,6 +218,7 @@ def treeWidgetChanged(self): def defaultClicked(self): self.param.setToDefault() + self.updateDefaultBtn() def optsChanged(self, param, opts): """Called when any options are changed that are not @@ -269,15 +271,17 @@ class SimpleParameter(Parameter): - 'colormap' """ - def __init__(self, *args, **kargs): - """ - Initialize the parameter. - - This is normally called implicitly through :meth:`Parameter.create`. - The keyword arguments available to :meth:`Parameter.__init__` are - applicable. - """ - Parameter.__init__(self, *args, **kargs) + @property + def itemClass(self): + from .bool import BoolParameterItem + from .numeric import NumericParameterItem + from .str import StrParameterItem + return { + 'bool': BoolParameterItem, + 'int': NumericParameterItem, + 'float': NumericParameterItem, + 'str': StrParameterItem, + }[self.opts['type']] def _interpretValue(self, v): typ = self.opts['type'] @@ -401,7 +405,6 @@ def updateAddList(self): self.addWidget.blockSignals(False) - class GroupParameter(Parameter): """ Group parameters are used mainly as a generic parent item that holds (and groups!) a set diff --git a/pyqtgraph/parametertree/parameterTypes/calendar.py b/pyqtgraph/parametertree/parameterTypes/calendar.py index 48f1fac1c1..ae0b134871 100644 --- a/pyqtgraph/parametertree/parameterTypes/calendar.py +++ b/pyqtgraph/parametertree/parameterTypes/calendar.py @@ -51,6 +51,6 @@ def _interpretValue(self, v): def saveState(self, filter=None): state = super().saveState(filter) fmt = self._interpretFormat() - if state['value'] is not None: + if state.get('value', None) is not None: state['value'] = state['value'].toString(fmt) return state diff --git a/pyqtgraph/parametertree/parameterTypes/checklist.py b/pyqtgraph/parametertree/parameterTypes/checklist.py index 8cf4179737..dad066b1ce 100644 --- a/pyqtgraph/parametertree/parameterTypes/checklist.py +++ b/pyqtgraph/parametertree/parameterTypes/checklist.py @@ -131,12 +131,13 @@ def maybeSigChanged(self, val): # Proxy around radio/bool type so the correct item class gets instantiated class BoolOrRadioParameter(SimpleParameter): - def __init__(self, **kargs): - if kargs.get('type') == 'bool': - self.itemClass = BoolParameterItem + @property + def itemClass(self): + if self.opts.get('type') == 'bool': + return BoolParameterItem else: - self.itemClass = RadioParameterItem - super().__init__(**kargs) + return RadioParameterItem + class ChecklistParameter(GroupParameter): """ @@ -202,7 +203,7 @@ def _onChildChanging(self, child, value): def updateLimits(self, _param, limits): oldOpts = self.names - val = self.opts['value'] + val = self.opts.get('value', None) # Make sure adding and removing children don't cause tree state changes self.blockTreeChangeSignal() self.clearChildren() @@ -231,8 +232,6 @@ def _finishChildChanges(self, paramAndValue): def optsChanged(self, param, opts): if 'exclusive' in opts: - # Force set value to ensure updates - # self.opts['value'] = self._VALUE_UNSET self.updateLimits(None, self.opts.get('limits', [])) if 'delay' in opts: self.valChangingProxy.setDelay(opts['delay']) diff --git a/pyqtgraph/parametertree/parameterTypes/color.py b/pyqtgraph/parametertree/parameterTypes/color.py index bb7f51e8b9..c46b8ab839 100644 --- a/pyqtgraph/parametertree/parameterTypes/color.py +++ b/pyqtgraph/parametertree/parameterTypes/color.py @@ -23,7 +23,10 @@ def _interpretValue(self, v): return fn.mkColor(v) def value(self): - return fn.mkColor(super().value()) + value = super().value() + if value is None: + return None + return fn.mkColor(value) def saveState(self, filter=None): state = super().saveState(filter) diff --git a/pyqtgraph/parametertree/parameterTypes/colormaplut.py b/pyqtgraph/parametertree/parameterTypes/colormaplut.py new file mode 100644 index 0000000000..5cda72f572 --- /dev/null +++ b/pyqtgraph/parametertree/parameterTypes/colormaplut.py @@ -0,0 +1,24 @@ +from ... import colormap +from ...widgets.ColorMapButton import ColorMapButton +from .basetypes import Parameter, WidgetParameterItem + + +class ColorMapLutParameterItem(WidgetParameterItem): + def makeWidget(self): + w = ColorMapButton() + w.sigChanged = w.sigColorMapChanged + w.value = w.colorMap + w.setValue = w.setColorMap + self.hideWidget = False + return w + + +class ColorMapLutParameter(Parameter): + itemClass = ColorMapLutParameterItem + + def _interpretValue(self, v): + if isinstance(v, str): + v = colormap.get(v) + if v is not None and not isinstance(v, colormap.ColorMap): + raise TypeError("Cannot set colormap parameter from object %r" % v) + return v diff --git a/pyqtgraph/parametertree/parameterTypes/file.py b/pyqtgraph/parametertree/parameterTypes/file.py index 53254df793..1de4d43043 100644 --- a/pyqtgraph/parametertree/parameterTypes/file.py +++ b/pyqtgraph/parametertree/parameterTypes/file.py @@ -129,7 +129,7 @@ def value(self): return self._value def _retrieveFileSelection_gui(self): - curVal = self.param.value() + curVal = self.param.value() if self.param.hasValue() else None if isinstance(curVal, list) and len(curVal): # All files should be from the same directory, in principle # Since no mechanism exists for preselecting multiple, the most sensible @@ -148,10 +148,8 @@ def _retrieveFileSelection_gui(self): if opts.get('windowTitle') is None: opts['windowTitle'] = self.param.title() - fname = popupFilePicker(None, **opts) - if not fname: - return - self.param.setValue(fname) + if fname := popupFilePicker(None, **opts): + self.param.setValue(fname) def updateDefaultBtn(self): # Override since a readonly label should still allow reverting to default diff --git a/pyqtgraph/parametertree/parameterTypes/list.py b/pyqtgraph/parametertree/parameterTypes/list.py index 22c80c645a..d9c19795ef 100644 --- a/pyqtgraph/parametertree/parameterTypes/list.py +++ b/pyqtgraph/parametertree/parameterTypes/list.py @@ -24,7 +24,7 @@ def makeWidget(self): w.setValue = self.setValue self.widget = w ## needs to be set before limits are changed self.limitsChanged(self.param, self.param.opts['limits']) - if len(self.forward) > 0: + if len(self.forward) > 0 and self.param.hasValue(): self.setValue(self.param.value()) return w @@ -92,11 +92,6 @@ def __init__(self, **opts): self.forward = OrderedDict() ## {name: value, ...} self.reverse = ([], []) ## ([value, ...], [name, ...]) - # Parameter uses 'limits' option to define the set of allowed values - if 'values' in opts: - warnings.warn('Using "values" to set limits is deprecated. Use "limits" instead.', - DeprecationWarning, stacklevel=2) - opts['limits'] = opts['values'] if opts.get('limits', None) is None: opts['limits'] = [] Parameter.__init__(self, **opts) @@ -107,10 +102,11 @@ def setLimits(self, limits): self.forward, self.reverse = self.mapping(limits) Parameter.setLimits(self, limits) - # 'value in limits' expression will break when reverse contains numpy array - curVal = self.value() - if len(self.reverse[0]) > 0 and not any(fn.eq(curVal, limVal) for limVal in self.reverse[0]): - self.setValue(self.reverse[0][0]) + if self.hasValue(): + # 'value in limits' expression will break when reverse contains numpy array + curVal = self.value() + if len(self.reverse[0]) > 0 and not any(fn.eq(curVal, limVal) for limVal in self.reverse[0]): + self.setValue(self.reverse[0][0]) @staticmethod def mapping(limits): diff --git a/pyqtgraph/parametertree/parameterTypes/numeric.py b/pyqtgraph/parametertree/parameterTypes/numeric.py index 8b10210af2..281ce7f387 100644 --- a/pyqtgraph/parametertree/parameterTypes/numeric.py +++ b/pyqtgraph/parametertree/parameterTypes/numeric.py @@ -27,7 +27,7 @@ def makeWidget(self): for k in defs: if k in opts: defs[k] = opts[k] - if 'limits' in opts: + if opts.get('limits') is not None: defs['min'], defs['max'] = opts['limits'] w = SpinBox() w.setOpts(**defs) diff --git a/pyqtgraph/parametertree/parameterTypes/pen.py b/pyqtgraph/parametertree/parameterTypes/pen.py index 91d2ddad3c..5954768ad5 100644 --- a/pyqtgraph/parametertree/parameterTypes/pen.py +++ b/pyqtgraph/parametertree/parameterTypes/pen.py @@ -1,13 +1,14 @@ import re from contextlib import ExitStack -from . import GroupParameterItem, WidgetParameterItem -from .basetypes import GroupParameter, Parameter, ParameterItem -from .qtenum import QtEnumParameter from ... import functions as fn from ...Qt import QtCore, QtWidgets from ...SignalProxy import SignalProxy from ...widgets.PenPreviewLabel import PenPreviewLabel +from . import GroupParameterItem, WidgetParameterItem +from .basetypes import GroupParameter, Parameter, ParameterItem +from .qtenum import QtEnumParameter + class PenParameterItem(GroupParameterItem): def __init__(self, param, depth): @@ -48,6 +49,12 @@ def updateDefaultBtn(self): ) +def cap_first(s: str): + if not s: + return s + return s[0].upper() + s[1:] + + class PenParameter(GroupParameter): """ Controls the appearance of a QPen value. @@ -82,7 +89,7 @@ def __init__(self, **opts): def _childrenFinishedChanging(self, paramAndValue): self.setValue(self.pen) - def setDefault(self, val): + def setDefault(self, val, **kwargs): pen = self._interpretValue(val) with self.treeChangeBlocker(): # Block changes until all are finalized @@ -92,14 +99,16 @@ def setDefault(self, val): attrName = f'is{opt.title()}' else: attrName = opt - self.child(opt).setDefault(getattr(pen, attrName)()) - out = super().setDefault(val) + self.child(opt).setDefault(getattr(pen, attrName)(), **kwargs) + out = super().setDefault(val, **kwargs) return out def saveState(self, filter=None): state = super().saveState(filter) opts = state.pop('children') state['value'] = tuple(o['value'] for o in opts.values()) + if 'default' not in state: + state['default'] = state['value'] # TODO remove this after January 2025 return state def restoreState(self, state, recursive=True, addChildren=True, removeChildren=True, blockSignals=True): @@ -131,8 +140,7 @@ def applyOptsToPen(self, **opts): def setOpts(self, **opts): # Transform opts into a value - penOpts = self.applyOptsToPen(**opts) - if penOpts: + if self.applyOptsToPen(**opts): self.setValue(self.pen) return super().setOpts(**opts) @@ -163,8 +171,8 @@ def _makeChildren(self, boundPen=None): optsPen = boundPen or fn.mkPen() for p in param: name = p.name() - # Qt naming scheme uses isXXX for booleans - if isinstance(p.value(), bool): + # Qt naming scheme uses isXxx for booleans + if p.type() == 'bool': attrName = f'is{name.title()}' else: attrName = name @@ -177,7 +185,7 @@ def _makeChildren(self, boundPen=None): if boundPen is not None: self.updateFromPen(param, boundPen) for p in param: - setName = f'set{p.name().capitalize()}' + setName = f'set{cap_first(p.name())}' # Instead, set the parameter which will signal the old setter setattr(boundPen, setName, p.setValue) newSetter = self.penPropertySetter @@ -185,7 +193,15 @@ def _makeChildren(self, boundPen=None): if p.type() != 'color': p.sigValueChanging.connect(newSetter) # Force children to emulate self's value instead of being part of a tree like normal - p.sigValueChanged.disconnect(p._emitValueChanged) + try: + p.sigValueChanged.disconnect(p._emitValueChanged) + except RuntimeError: + # workaround https://bugreports.qt.io/projects/PYSIDE/issues/PYSIDE-2487 + # that affects PySide 6.5.3 + # Since the child param was freshly created by us, there can only have been one slot + # connected. So we can just disconnect all the slots without specifying which one. + assert p.receivers(QtCore.SIGNAL("sigValueChanged(PyObject,PyObject)")) == 1 + p.sigValueChanged.disconnect() # Some widgets (e.g. checkbox, combobox) don't emit 'changing' signals, so tie to 'changed' as well p.sigValueChanged.connect(newSetter) @@ -193,7 +209,7 @@ def _makeChildren(self, boundPen=None): def penPropertySetter(self, p, value): boundPen = self.pen - setName = f'set{p.name().capitalize()}' + setName = f'set{cap_first(p.name())}' # boundPen.setName has been monkey-patched # so we get the original setter from the class getattr(boundPen.__class__, setName)(boundPen, value) diff --git a/pyqtgraph/parametertree/parameterTypes/qtenum.py b/pyqtgraph/parametertree/parameterTypes/qtenum.py index fa1b3b07ef..2342098553 100644 --- a/pyqtgraph/parametertree/parameterTypes/qtenum.py +++ b/pyqtgraph/parametertree/parameterTypes/qtenum.py @@ -1,4 +1,5 @@ from enum import Enum + from ...Qt import QT_LIB, QtCore from .list import ListParameter @@ -26,22 +27,22 @@ def setValue(self, value, blockSignal=None): def formattedLimits(self): # Title-cased words without the ending substring for brevity - substringEnd = None mapping = self.enumMap shortestName = min(len(name) for name in mapping) names = list(mapping) cmpName, *names = names - for ii in range(-1, -shortestName-1, -1): - if any(cmpName[ii] != curName[ii] for curName in names): - substringEnd = ii+1 - break - # Special case of 0: Set to none to avoid null string + substringEnd = next( + ( + ii + 1 + for ii in range(-1, -shortestName - 1, -1) + if any(cmpName[ii] != curName[ii] for curName in names) + ), + None, + ) + # Special case of 0: Set to None to avoid null string if substringEnd == 0: substringEnd = None - limits = {} - for kk, vv in self.enumMap.items(): - limits[kk[:substringEnd]] = vv - return limits + return {kk[:substringEnd]: vv for kk, vv in self.enumMap.items()} def saveState(self, filter=None): state = super().saveState(filter) diff --git a/pyqtgraph/util/garbage_collector.py b/pyqtgraph/util/garbage_collector.py index a800d37097..4b5971987a 100644 --- a/pyqtgraph/util/garbage_collector.py +++ b/pyqtgraph/util/garbage_collector.py @@ -25,7 +25,7 @@ def __init__(self, interval=1.0, debug=False): self.threshold = gc.get_threshold() gc.disable() - self.timer.start(interval * 1000) + self.timer.start(int(interval * 1000)) def check(self): #return self.debug_cycles() # uncomment to just debug cycles diff --git a/pyqtgraph/widgets/ColorMapButton.py b/pyqtgraph/widgets/ColorMapButton.py new file mode 100644 index 0000000000..4bad5f96fb --- /dev/null +++ b/pyqtgraph/widgets/ColorMapButton.py @@ -0,0 +1,120 @@ +import numpy as np + +from .ColorMapMenu import ColorMapMenu +from .. import colormap +from .. import functions as fn +from ..Qt import QtCore, QtGui, QtWidgets + +__all__ = ['ColorMapButton'] + + +class ColorMapDisplayMixin: + # Note that this Mixin attempts to be safe for inheritance + # on either the lhs or rhs. To this end: + # 1) the __init__ is safe to be called more than once + # 2) it does not override any main class virtual methods + + def __init__(self, *, orientation): + self.horizontal = orientation == 'horizontal' + self._menu = None + self._setColorMap(None) + + def setMaximumThickness(self, val): + # calls main class methods + Thickness = 'Height' if self.horizontal else 'Width' + getattr(self, f'setMaximum{Thickness}')(val) + + def _setColorMap(self, cmap): + if isinstance(cmap, str): + try: + cmap = colormap.get(cmap) + except FileNotFoundError: + cmap = None + if cmap is None: + cmap = colormap.ColorMap(None, [0.0, 1.0]) + + self._cmap = cmap + self._image = None + + def setColorMap(self, cmap): + # calls main class methods + self._setColorMap(cmap) + self.colorMapChanged() + + def colorMap(self): + return self._cmap + + def getImage(self): + if self._image is None: + lut = self._cmap.getLookupTable(nPts=256, alpha=True) + lut = np.expand_dims(lut, axis=0 if self.horizontal else 1) + qimg = fn.ndarray_to_qimage(lut, QtGui.QImage.Format.Format_RGBA8888) + self._image = qimg if self.horizontal else qimg.mirrored() + return self._image + + def getMenu(self): + if self._menu is None: + self._menu = ColorMapMenu(showColorMapSubMenus=True) + self._menu.sigColorMapTriggered.connect(self.setColorMap) + return self._menu + + def paintColorMap(self, painter, rect): + painter.save() + image = self.getImage() + painter.drawImage(rect, image) + + if not self.horizontal: + painter.translate(rect.center()) + painter.rotate(-90) + painter.translate(-rect.center()) + + text = self.colorMap().name + wpen = QtGui.QPen(QtCore.Qt.GlobalColor.white) + bpen = QtGui.QPen(QtCore.Qt.GlobalColor.black) + # get an estimate of the lightness of the colormap + # from its center element + lightness = image.pixelColor(image.rect().center()).lightnessF() + if lightness >= 0.5: + # light: draw text with dark pen + pens = [wpen, bpen] + else: + # dark: draw text with light pen + pens = [bpen, wpen] + + AF = QtCore.Qt.AlignmentFlag + trect = painter.boundingRect(rect, AF.AlignCenter, text) + # draw a background shadow + painter.setPen(pens[0]) + painter.drawText(trect, 0, text) + # draw the foreground text + painter.setPen(pens[1]) + painter.drawText(trect.adjusted(1,0,1,0), 0, text) + + painter.restore() + + +class ColorMapButton(ColorMapDisplayMixin, QtWidgets.QWidget): + sigColorMapChanged = QtCore.Signal(object) + + def __init__(self): + QtWidgets.QWidget.__init__(self) + ColorMapDisplayMixin.__init__(self, orientation='horizontal') + + def colorMapChanged(self): + cmap = self.colorMap() + self.sigColorMapChanged.emit(cmap) + self.update() + + def paintEvent(self, evt): + painter = QtGui.QPainter(self) + self.paintColorMap(painter, self.contentsRect()) + painter.end() + + def mouseReleaseEvent(self, evt): + if evt.button() != QtCore.Qt.MouseButton.LeftButton: + return + + # position the menu below the widget + pos = self.mapToGlobal(self.pos()) + pos.setY(pos.y() + self.height()) + self.getMenu().popup(pos) diff --git a/pyqtgraph/widgets/ColorMapMenu.py b/pyqtgraph/widgets/ColorMapMenu.py new file mode 100644 index 0000000000..6b91318af8 --- /dev/null +++ b/pyqtgraph/widgets/ColorMapMenu.py @@ -0,0 +1,292 @@ +import collections +import importlib.util +import re + +from .. import colormap +from ..graphicsItems.GradientPresets import Gradients +from ..Qt import QtCore, QtGui, QtWidgets + +__all__ = ['ColorMapMenu'] + + +# from https://matplotlib.org/stable/gallery/color/colormap_reference.html +MATPLOTLIB_CMAPS = [ + ('Perceptually Uniform Sequential', [ + 'viridis', 'plasma', 'inferno', 'magma', 'cividis']), + ('Sequential', [ + 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', + 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', + 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']), + ('Sequential (2)', [ + 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', + 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', + 'hot', 'afmhot', 'gist_heat', 'copper']), + ('Diverging', [ + 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', + 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic']), + ('Cyclic', ['twilight', 'twilight_shifted', 'hsv']), + ('Qualitative', [ + 'Pastel1', 'Pastel2', 'Paired', 'Accent', + 'Dark2', 'Set1', 'Set2', 'Set3', + 'tab10', 'tab20', 'tab20b', 'tab20c']), + ('Miscellaneous', [ + 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', + 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', + 'gist_rainbow', 'rainbow', 'jet', 'turbo', 'nipy_spectral', + 'gist_ncar']) + ] + + +PrivateActionData = collections.namedtuple("ColorMapMenuPrivateActionData", ["name", "source"]) + + +def buildMenuEntryWidget(cmap, text): + lut = cmap.getLookupTable(nPts=32, alpha=True) + qimg = QtGui.QImage(lut, len(lut), 1, QtGui.QImage.Format.Format_RGBA8888) + pixmap = QtGui.QPixmap.fromImage(qimg) + + widget = QtWidgets.QWidget() + layout = QtWidgets.QHBoxLayout(widget) + layout.setContentsMargins(1,1,1,1) + label1 = QtWidgets.QLabel() + label1.setScaledContents(True) + label1.setPixmap(pixmap) + label2 = QtWidgets.QLabel(text) + layout.addWidget(label1, 0) + layout.addWidget(label2, 1) + + return widget + +def buildMenuEntryAction(menu, name, source): + if isinstance(source, colormap.ColorMap): + cmap = source + elif source == 'preset-gradient': + cmap = preset_gradient_to_colormap(name) + else: + cmap = colormap.get(name, source=source) + act = QtWidgets.QWidgetAction(menu) + act.setData(PrivateActionData(name, source)) + act.setDefaultWidget(buildMenuEntryWidget(cmap, name)) + menu.addAction(act) + +def sorted_filenames(names): + pattern = re.compile(r'(\d+)') + key = lambda x: [int(c) if c.isdigit() else c for c in pattern.split(x)] + return sorted(names, key=key) + +def find_mpl_leftovers(): + names = colormap.listMaps(source="matplotlib") + # remove entries registered by colorcet + names = [x for x in names if not x.startswith('cet_')] + # remove the reversed colormaps + names = [x for x in names if not x.endswith('_r')] + # remove entries that are already categorised + known_names = set() + for item in MATPLOTLIB_CMAPS: + known_names.update(item[1]) + names = [x for x in names if x not in known_names] + return names + +def buildCetSubMenu(menu, source, cet_type): + names = colormap.listMaps(source=source) + names = [x for x in names if x.startswith("CET")] + + if cet_type.endswith("Blind"): + names = [x for x in names if x[4:6] == "CB"] + else: + names = [x for x in names if x[4] == cet_type[0] and x[5].isdigit()] + + for name in sorted_filenames(names): + buildMenuEntryAction(menu, name, source) + +def buildUserSubMenu(menu, userList): + for item in userList: + if isinstance(item, colormap.ColorMap): + name, source = item.name, item + elif isinstance(item, str): + name, source = item, None + elif isinstance(item, tuple): + name, source = item + else: + raise ValueError("userList items must be ColorMap, str or tuple") + + buildMenuEntryAction(menu, name, source) + +def preset_gradient_to_colormap(name): + # generate the hsv two gradients using makeHslCycle + if name == 'spectrum': + # steps=30 for 300 degrees gives the same density as + # the default steps=36 for 360 degrees + cmap = colormap.makeHslCycle((0, 300/360), steps=30) + elif name == 'cyclic': + cmap = colormap.makeHslCycle((1, 0)) + else: + cmap = colormap.ColorMap(*zip(*Gradients[name]["ticks"]), name=name) + return cmap + + +class ColorMapMenu(QtWidgets.QMenu): + sigColorMapTriggered = QtCore.Signal(object) + + def __init__(self, *, userList=None, showGradientSubMenu=False, showColorMapSubMenus=False): + """ + Creates a new ColorMapMenu. + + Parameters + ---------- + userList : list of ColorMapSpecifier, optional + Supported values for ColorMapSpecifier are + ``str``, ``(str, str)``, :class:`~pyqtgraph.ColorMap` + + Example: ``["viridis", ("glasbey", "colorcet"), ("rainbow", "matplotlib")]`` + showGradientSubMenu : bool, default=False + Adds legacy gradients in a submenu. + showColorMapSubMenus : bool, default=False + Adds bundled colormaps and external (colorcet, matplotlib) colormaps in submenus. + """ + super().__init__() + + self.setTitle("ColorMaps") + self.triggered.connect(self.onTriggered) + + topmenu = self + act = topmenu.addAction('None') + act.setData(PrivateActionData(None, None)) + + if userList is not None: + buildUserSubMenu(topmenu, userList) + + if any([showGradientSubMenu, showColorMapSubMenus]): + topmenu.addSeparator() + + # render the submenus only if the user actually clicks on it + + if showGradientSubMenu: + submenu = topmenu.addMenu('preset gradient') + submenu.aboutToShow.connect(self.buildGradientSubMenu) + + if not showColorMapSubMenus: + return + + submenu = topmenu.addMenu('local') + submenu.aboutToShow.connect(self.buildLocalSubMenu) + + have_colorcet = importlib.util.find_spec('colorcet') is not None + # arranged in the order listed in https://colorcet.com/ + cet_types = ["Linear", "Divergent", "Rainbow", "Cyclic", "Isoluminant", "Color Blind"] + + # the local cet files are a subset of the colorcet module. + # expose just one of them. + if not have_colorcet: + submenu = topmenu.addMenu('cet (local)') + for cet_type in cet_types: + sub2menu = submenu.addMenu(cet_type) + sub2menu.aboutToShow.connect(self.buildCetLocalSubMenu) + else: + submenu = topmenu.addMenu('cet (external)') + for cet_type in cet_types: + sub2menu = submenu.addMenu(cet_type) + sub2menu.aboutToShow.connect(self.buildCetExternalSubMenu) + + if importlib.util.find_spec('matplotlib') is not None: + submenu = topmenu.addMenu('matplotlib') + # skip 1st entry which is "Perceptually Uniform Sequential" + # since pyqtgraph has those already + for category, _ in MATPLOTLIB_CMAPS[1:]: + sub2menu = submenu.addMenu(category) + sub2menu.aboutToShow.connect(self.buildMplCategorySubMenu) + + if find_mpl_leftovers(): + sub2menu = submenu.addMenu("Others") + sub2menu.aboutToShow.connect(self.buildMplOthersSubMenu) + + if have_colorcet: + submenu = topmenu.addMenu('colorcet') + submenu.aboutToShow.connect(self.buildColorcetSubMenu) + + def onTriggered(self, action): + if not isinstance(data := action.data(), PrivateActionData): + return + cmap = self.actionDataToColorMap(data) + self.sigColorMapTriggered.emit(cmap) + + def buildGradientSubMenu(self): + source = 'preset-gradient' + names = list(Gradients.keys()) + self.buildSubMenu(names, source, sort=False) + + def buildLocalSubMenu(self): + source = None + names = colormap.listMaps(source=source) + names = [x for x in names if not x.startswith('CET')] + names = [x for x in names if not x.startswith('PAL-relaxed')] + self.buildSubMenu(names, source) + + def buildCetLocalSubMenu(self): + # in Qt6 we could have used Qt.ConnectionType.SingleShotConnection + menu = self.sender() + menu.aboutToShow.disconnect() + source = None + cet_type = menu.title() + buildCetSubMenu(menu, source, cet_type) + + def buildCetExternalSubMenu(self): + # in Qt6 we could have used Qt.ConnectionType.SingleShotConnection + menu = self.sender() + menu.aboutToShow.disconnect() + source = 'colorcet' + cet_type = menu.title() + buildCetSubMenu(menu, source, cet_type) + + def buildMplCategorySubMenu(self): + # in Qt6 we could have used Qt.ConnectionType.SingleShotConnection + menu = self.sender() + menu.aboutToShow.disconnect() + source = 'matplotlib' + category = menu.title() + categories = [x[0] for x in MATPLOTLIB_CMAPS] + names = MATPLOTLIB_CMAPS[categories.index(category)][1] + for name in names: + try: + buildMenuEntryAction(menu, name, source) + except ValueError: + # the names are not programmatically discovered, + # so to be safe, we wrap around try except + pass + + def buildMplOthersSubMenu(self): + self.buildSubMenu(find_mpl_leftovers(), "matplotlib") + + def buildColorcetSubMenu(self): + # colorcet colormaps with shorter/simpler aliases + source = 'colorcet' + import colorcet + names = list(colorcet.palette_n.keys()) + self.buildSubMenu(names, source) + + def buildSubMenu(self, names, source, sort=True): + # in Qt6 we could have used Qt.ConnectionType.SingleShotConnection + menu = self.sender() + menu.aboutToShow.disconnect() + + if sort: + names = sorted_filenames(names) + for name in names: + buildMenuEntryAction(menu, name, source) + + @staticmethod + def actionDataToColorMap(data): + name, source = data + if isinstance(source, colormap.ColorMap): + cmap = source + elif name is None: + cmap = colormap.ColorMap(None, [0.0, 1.0]) + elif source == 'preset-gradient': + cmap = preset_gradient_to_colormap(name) + cmap.name = f"{source}:{name}" # for GradientEditorItem + else: + # colormap module maintains a cache keyed by name only. + # thus if a colormap has the same name in two different sources, + # we will end up getting whatever was already cached. + cmap = colormap.get(name, source=source) + return cmap diff --git a/pyqtgraph/widgets/GraphicsView.py b/pyqtgraph/widgets/GraphicsView.py index b1b256a5b6..ede9065532 100644 --- a/pyqtgraph/widgets/GraphicsView.py +++ b/pyqtgraph/widgets/GraphicsView.py @@ -357,7 +357,7 @@ def mouseMoveEvent(self, ev): super().mouseMoveEvent(ev) if not self.mouseEnabled: return - self.sigSceneMouseMoved.emit(self.mapToScene(lpos)) + self.sigSceneMouseMoved.emit(self.mapToScene(lpos.toPoint())) if self.clickAccepted: ## Ignore event if an item in the scene has already claimed it. return @@ -365,7 +365,7 @@ def mouseMoveEvent(self, ev): if ev.buttons() == QtCore.Qt.MouseButton.RightButton: delta = Point(fn.clip_scalar(delta[0], -50, 50), fn.clip_scalar(-delta[1], -50, 50)) scale = 1.01 ** delta - self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos)) + self.scale(scale[0], scale[1], center=self.mapToScene(self.mousePressPos.toPoint())) self.sigDeviceRangeChanged.emit(self, self.range) elif ev.buttons() in [QtCore.Qt.MouseButton.MiddleButton, QtCore.Qt.MouseButton.LeftButton]: ## Allow panning by left or mid button. diff --git a/pyqtgraph/widgets/PlotWidget.py b/pyqtgraph/widgets/PlotWidget.py index 932a30fdef..b3085ab599 100644 --- a/pyqtgraph/widgets/PlotWidget.py +++ b/pyqtgraph/widgets/PlotWidget.py @@ -44,6 +44,9 @@ class PlotWidget(GraphicsView): other methods, use :func:`getPlotItem `. """ def __init__(self, parent=None, background='default', plotItem=None, **kargs): + ## start by instantiating the plotItem attribute in order to avoid recursive + ## calls of PlotWidget.__getattr__ - which access self.plotItem! + self.plotItem = None """When initializing PlotWidget, *parent* and *background* are passed to :func:`GraphicsWidget.__init__() ` and all others are passed @@ -97,6 +100,3 @@ def restoreState(self, state): def getPlotItem(self): """Return the PlotItem contained within.""" return self.plotItem - - - diff --git a/pyqtgraph/widgets/RawImageWidget.py b/pyqtgraph/widgets/RawImageWidget.py index dd3a4272e4..5059ef6918 100644 --- a/pyqtgraph/widgets/RawImageWidget.py +++ b/pyqtgraph/widgets/RawImageWidget.py @@ -4,18 +4,23 @@ Distributed under MIT/X11 license. See license.txt for more information. """ +import importlib +import numpy as np + from .. import functions as fn +from .. import functions_qimage from .. import getConfigOption, getCupy -from ..Qt import QtCore, QtGui, QtWidgets +from ..Qt import QtCore, QtGui, QtWidgets, QT_LIB try: - QOpenGLWidget = QtWidgets.QOpenGLWidget - from OpenGL.GL import * # noqa - + if QT_LIB in ["PyQt5", "PySide2"]: + QtOpenGL = QtGui + QtOpenGLWidgets = QtWidgets + else: + QtOpenGL = importlib.import_module(f"{QT_LIB}.QtOpenGL") + QtOpenGLWidgets = importlib.import_module(f"{QT_LIB}.QtOpenGLWidgets") HAVE_OPENGL = True -except (ImportError, AttributeError): - # Would prefer `except ImportError` here, but some versions of pyopengl generate - # AttributeError upon import +except ModuleNotFoundError: HAVE_OPENGL = False __all__ = ['RawImageWidget'] @@ -54,10 +59,35 @@ def paintEvent(self, ev): if self.opts is None: return if self.image is None: - argb, alpha = fn.makeARGB(self.opts[0], *self.opts[1], **self.opts[2]) - if self._cp and self._cp.get_array_module(argb) == self._cp: - argb = argb.get() # transfer GPU data back to the CPU - self.image = fn.makeQImage(argb, alpha, copy=False, transpose=False) + img = self.opts[0] + xp = self._cp.get_array_module(img) if self._cp else np + + qimage = None + if ( + not self.opts[1] # no positional arguments + and {"levels", "lut"}.issuperset(self.opts[2]) # no kwargs besides levels and lut + ): + transparentLocations = None + if img.dtype.kind == "f" and xp.isnan(img.min()): + nanmask = xp.isnan(img) + if nanmask.ndim == 3: + nanmask = nanmask.any(axis=2) + transparentLocations = nanmask.nonzero() + + qimage = functions_qimage.try_make_qimage( + img, + levels=self.opts[2].get("levels"), + lut=self.opts[2].get("lut"), + transparentLocations=transparentLocations + ) + + if qimage is None: + argb, alpha = fn.makeARGB(self.opts[0], *self.opts[1], **self.opts[2]) + if self._cp and self._cp.get_array_module(argb) == self._cp: + argb = argb.get() # transfer GPU data back to the CPU + qimage = fn.ndarray_to_qimage(argb, QtGui.QImage.Format.Format_ARGB32) + + self.image = qimage self.opts = () # if self.pixmap is None: # self.pixmap = QtGui.QPixmap.fromImage(self.image) @@ -80,7 +110,8 @@ def paintEvent(self, ev): if HAVE_OPENGL: __all__.append('RawImageGLWidget') - class RawImageGLWidget(QOpenGLWidget): + + class RawImageGLWidget(QtOpenGLWidgets.QOpenGLWidget): """ Similar to RawImageWidget, but uses a GL widget to do all drawing. Performance varies between platforms; see examples/VideoSpeedTest for benchmarking. @@ -88,14 +119,16 @@ class RawImageGLWidget(QOpenGLWidget): Checks if setConfigOptions(imageAxisOrder='row-major') was set. """ - def __init__(self, parent=None, scaled=False): - QOpenGLWidget.__init__(self, parent) - self.scaled = scaled + def __init__(self, parent=None, smooth=False): + super().__init__(parent) self.image = None self.uploaded = False - self.smooth = False + self.smooth = smooth self.opts = None + self.m_texture = QtOpenGL.QOpenGLTexture(QtOpenGL.QOpenGLTexture.Target.Target2D) + self.m_blitter = None + def setImage(self, img, *args, **kargs): """ img must be ndarray of shape (x,y), (x,y,3), or (x,y,4). @@ -109,57 +142,71 @@ def setImage(self, img, *args, **kargs): self.update() def initializeGL(self): - self.texture = glGenTextures(1) + ctx = self.context() - def uploadTexture(self): - glEnable(GL_TEXTURE_2D) - glBindTexture(GL_TEXTURE_2D, self.texture) - if self.smooth: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + # in Python, slot will not get called during application termination + ctx.aboutToBeDestroyed.connect(self.cleanup) + + profile = QtOpenGL.QOpenGLVersionProfile() + profile.setVersion(2, 0) + if QT_LIB == 'PySide2': + self.glfn = ctx.functions() + elif QT_LIB == 'PyQt5': + self.glfn = ctx.versionFunctions(profile) else: - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER) - # glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER) - - ## Test texture dimensions first - # shape = self.image.shape - # glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_RGBA, shape[0], shape[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, None) - # if glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH) == 0: - # raise Exception("OpenGL failed to create 2D texture (%dx%d); too large for this hardware." % shape[:2]) + self.glfn = QtOpenGL.QOpenGLVersionFunctionsFactory.get(profile, ctx) + + self.m_blitter = QtOpenGL.QOpenGLTextureBlitter() + self.m_blitter.create() + def cleanup(self): + # explicit call of cleanup() is needed during application termination + self.makeCurrent() + self.m_texture.destroy() + self.uploaded = False + if self.m_blitter is not None: + self.m_blitter.destroy() + self.m_blitter = None + self.doneCurrent() + + def uploadTexture(self): h, w = self.image.shape[:2] - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, self.image) - glDisable(GL_TEXTURE_2D) + + if self.m_texture.isCreated() and (w != self.m_texture.width() or h != self.m_texture.height()): + self.m_texture.destroy() + + if not self.m_texture.isCreated(): + self.m_texture.setFormat(QtOpenGL.QOpenGLTexture.TextureFormat.RGBAFormat) + self.m_texture.setSize(w, h) + self.m_texture.allocateStorage() + + filt = QtOpenGL.QOpenGLTexture.Filter.Linear if self.smooth else QtOpenGL.QOpenGLTexture.Filter.Nearest + self.m_texture.setMinMagFilters(filt, filt) + self.m_texture.setWrapMode(QtOpenGL.QOpenGLTexture.WrapMode.ClampToBorder) + self.m_texture.setData(QtOpenGL.QOpenGLTexture.PixelFormat.RGBA, QtOpenGL.QOpenGLTexture.PixelType.UInt8, self.image) + self.uploaded = True def paintGL(self): - glClear(GL_COLOR_BUFFER_BIT) + GL_COLOR_BUFFER_BIT = 0x4000 + GL_BLEND = 0x0BE3 + GL_SRC_ALPHA = 0x0302 + GL_ONE_MINUS_SRC_ALPHA = 0x0303 + self.glfn.glClearColor(1, 1, 1, 1) + self.glfn.glClear(GL_COLOR_BUFFER_BIT) + self.glfn.glEnable(GL_BLEND) + self.glfn.glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, 1, GL_ONE_MINUS_SRC_ALPHA) if self.image is None: if self.opts is None: return img, args, kwds = self.opts - kwds['useRGBA'] = True - self.image, _ = fn.makeARGB(img, *args, **kwds) + self.image, _ = fn.makeRGBA(img, *args, **kwds) if not self.uploaded: self.uploadTexture() - glEnable(GL_TEXTURE_2D) - glBindTexture(GL_TEXTURE_2D, self.texture) - glColor4f(1, 1, 1, 1) - - glBegin(GL_QUADS) - glTexCoord2f(0, 1) - glVertex3f(-1, -1, 0) - glTexCoord2f(1, 1) - glVertex3f(1, -1, 0) - glTexCoord2f(1, 0) - glVertex3f(1, 1, 0) - glTexCoord2f(0, 0) - glVertex3f(-1, 1, 0) - glEnd() - glDisable(GL_TEXTURE_2D) + target = QtGui.QMatrix4x4() + self.m_blitter.bind() + self.m_blitter.blit(self.m_texture.textureId(), target, QtOpenGL.QOpenGLTextureBlitter.Origin.OriginTopLeft) + self.m_blitter.release() \ No newline at end of file diff --git a/pyqtgraph/widgets/SpinBox.py b/pyqtgraph/widgets/SpinBox.py index e893d0d8de..642c3b32ec 100644 --- a/pyqtgraph/widgets/SpinBox.py +++ b/pyqtgraph/widgets/SpinBox.py @@ -1,5 +1,6 @@ import decimal import re +import warnings from math import isinf, isnan from .. import functions as fn @@ -81,7 +82,8 @@ def __init__(self, parent=None, value=0.0, **kwargs): 'prefix': '', ## string to be prepended to spin box value 'suffix': '', 'siPrefix': False, ## Set to True to display numbers with SI prefix (ie, 100pA instead of 1e-10A) - + 'scaleAtZero': None, + 'delay': 0.3, ## delay sending wheel update signals for 300ms 'delayUntilEditFinished': True, ## do not send signals until text editing has finished @@ -133,6 +135,9 @@ def setOpts(self, **opts): orders of magnitude, such as a Reynolds number, an SI prefix is allowed with no suffix. Default is False. prefix (str) String to be prepended to the spin box value. Default is an empty string. + scaleAtZero (float) If siPrefix is also True, this option then sets the default SI prefix + that a value of 0 will have applied (and thus the default scale of the first + number the user types in after the SpinBox has been zeroed out). step (float) The size of a single step. This is used when clicking the up/ down arrows, when rolling the mouse wheel, or when pressing keyboard arrows while the widget has keyboard focus. Note that @@ -370,7 +375,7 @@ def setValue(self, value=None, update=True, delaySignal=False): changed = not fn.eq(value, prev) # use fn.eq to handle nan if update and (changed or not bounded): - self.updateText(prev=prev) + self.updateText() if changed: self.sigValueChanging.emit(self, float(self.val)) ## change will be emitted in 300ms if there are no subsequent changes. @@ -401,34 +406,35 @@ def stepEnabled(self): return self.StepEnabledFlag.StepUpEnabled | self.StepEnabledFlag.StepDownEnabled def stepBy(self, n): - if isinf(self.val) or isnan(self.val): - return + ## note all steps (arrow buttons, wheel, up/down keys..) emit delayed signals only. + self.setValue(self._stepByValue(n), delaySignal=True) - n = decimal.Decimal(int(n)) ## n must be integral number of steps. - s = [decimal.Decimal(-1), decimal.Decimal(1)][n >= 0] ## determine sign of step + def _stepByValue(self, steps): + if isinf(self.val) or isnan(self.val): + return self.val + steps = int(steps) + sign = [decimal.Decimal(-1), decimal.Decimal(1)][steps >= 0] val = self.val - - for i in range(int(abs(n))): + for i in range(int(abs(steps))): if self.opts['dec']: if val == 0: step = self.opts['minStep'] exp = None else: vs = [decimal.Decimal(-1), decimal.Decimal(1)][val >= 0] - #exp = decimal.Decimal(int(abs(val*(decimal.Decimal('1.01')**(s*vs))).log10())) - fudge = decimal.Decimal('1.01')**(s*vs) ## fudge factor. at some places, the step size depends on the step sign. + ## fudge factor. at some places, the step size depends on the step sign. + fudge = decimal.Decimal('1.01') ** (sign * vs) exp = abs(val * fudge).log10().quantize(1, decimal.ROUND_FLOOR) - step = self.opts['step'] * decimal.Decimal(10)**exp + step = self.opts['step'] * decimal.Decimal(10) ** exp if 'minStep' in self.opts: step = max(step, self.opts['minStep']) - val += s * step - #print "Exp:", exp, "step", step, "val", val + val += sign * step else: - val += s*self.opts['step'] - + val += sign * self.opts['step'] + if 'minStep' in self.opts and abs(val) < self.opts['minStep']: val = decimal.Decimal(0) - self.setValue(val, delaySignal=True) ## note all steps (arrow buttons, wheel, up/down keys..) emit delayed signals only. + return val def valueInRange(self, value): if not isnan(value): @@ -442,11 +448,11 @@ def valueInRange(self, value): return False return True - def updateText(self, prev=None): + def updateText(self, **kwargs): # temporarily disable validation self.skipValidate = True - txt = self.formatText(prev=prev) + txt = self.formatText(**kwargs) # actually set the text self.lineEdit().setText(txt) @@ -455,7 +461,13 @@ def updateText(self, prev=None): # re-enable the validation self.skipValidate = False - def formatText(self, prev=None): + def formatText(self, **kwargs): + if 'prev' in kwargs: + warnings.warn( + "updateText and formatText no longer take prev argument. This will error after January 2025.", + DeprecationWarning, + stacklevel=2 + ) # TODO remove all kwargs handling here and updateText after January 2025 # get the number of decimal places to print decimals = self.opts['decimals'] suffix = self.opts['suffix'] @@ -466,9 +478,11 @@ def formatText(self, prev=None): if self.opts['siPrefix'] is True: # SI prefix was requested, so scale the value accordingly - if self.val == 0 and prev is not None: - # special case: if it's zero use the previous prefix - (s, p) = fn.siScale(prev) + if self.val == 0: + if self.opts['scaleAtZero'] is not None: + (s, p) = fn.siScale(self.opts['scaleAtZero']) + else: + (s, p) = fn.siScale(self._stepByValue(1)) else: (s, p) = fn.siScale(val) parts = {'value': val, 'suffix': suffix, 'decimals': decimals, 'siPrefix': p, 'scaledValue': s*val, 'prefix':prefix} diff --git a/setup.py b/setup.py index d8d6907ba1..0439263826 100644 --- a/setup.py +++ b/setup.py @@ -45,6 +45,7 @@ from setuptools.command import install path = os.path.split(__file__)[0] +sys.path.append(path) import tools.setupHelpers as helpers ## Decide what version string to use in the build @@ -122,11 +123,11 @@ def run(self): 'style': helpers.StyleCommand }, packages=find_namespace_packages(include=['pyqtgraph', 'pyqtgraph.*']), - python_requires=">=3.9", + python_requires=">=3.10", package_dir={"pyqtgraph": "pyqtgraph"}, package_data={ 'pyqtgraph.examples': ['optics/*.gz', 'relativity/presets/*.cfg'], - "pyqtgraph.icons": ["*.svg", "*.png"], + "pyqtgraph.icons": ["**/*.svg", "**/*.png"], "pyqtgraph": [ "colors/maps/*.csv", "colors/maps/*.txt", @@ -134,7 +135,7 @@ def run(self): ], }, install_requires = [ - 'numpy>=1.22.0', + 'numpy>=1.23.0', ], **setupOpts ) diff --git a/tests/exporters/test_csv.py b/tests/exporters/test_csv.py index 05a5a96f3d..0e1edbb594 100644 --- a/tests/exporters/test_csv.py +++ b/tests/exporters/test_csv.py @@ -1,7 +1,6 @@ -""" -CSV export test -""" + import csv +import math import tempfile import numpy as np @@ -11,12 +10,8 @@ app = pg.mkQApp() - -def approxeq(a, b): - return (a-b) <= ((a + b) * 1e-6) - - -def test_CSVExporter(): +@pytest.mark.parametrize('log_mapping', [True, False]) +def test_CSVExporter(log_mapping: bool): plt = pg.PlotWidget() plt.show() y1 = [1,3,2,3,1,6,9,8,4,2] @@ -30,30 +25,27 @@ def test_CSVExporter(): x3 = np.linspace(0, 1.0, len(y3)+1) plt.plot(x=x3, y=y3, stepMode="center") - for log_mapping in (False, True): - if log_mapping: - print('testing original data export in log mapped mode') - else: - print('testing data export in unmapped mode') - plt.setLogMode(x=log_mapping, y=log_mapping) - ex = pg.exporters.CSVExporter(plt.plotItem) - with tempfile.NamedTemporaryFile(mode="w+t", suffix='.csv', encoding="utf-8", delete=False) as tf: - print(" using %s as a temporary file" % tf.name) - ex.export(fileName=tf.name) - lines = [line for line in csv.reader(tf)] - header = lines.pop(0) - assert header == ['myPlot_x', 'myPlot_y', 'x0001', 'y0001', 'x0002', 'y0002'] - - for i, vals in enumerate(lines): - vals = list(map(str.strip, vals)) - assert (i >= len(y1) and vals[0] == '') or approxeq(float(vals[0]), i) - assert (i >= len(y1) and vals[1] == '') or approxeq(float(vals[1]), y1[i]) - - assert (i >= len(x2) and vals[2] == '') or approxeq(float(vals[2]), x2[i]) - assert (i >= len(y2) and vals[3] == '') or approxeq(float(vals[3]), y2[i]) - - assert (i >= len(x3) and vals[4] == '') or approxeq(float(vals[4]), x3[i]) - assert (i >= len(y3) and vals[5] == '') or approxeq(float(vals[5]), y3[i]) + # log mapping is True tests original data export in log mapped mode + plt.setLogMode(x=log_mapping, y=log_mapping) + ex = pg.exporters.CSVExporter(plt.plotItem) + with tempfile.NamedTemporaryFile(mode="w+t", suffix='.csv', encoding="utf-8", delete=False) as tf: + print(f" using {tf.name} as a temporary file") + ex.export(fileName=tf.name) + lines = list(csv.reader(tf)) + header = lines.pop(0) + assert header == ['myPlot_x', 'myPlot_y', 'x0001', 'y0001', 'x0002', 'y0002'] + + for i, vals in enumerate(lines): + vals = list(map(str.strip, vals)) + assert (i >= len(y1) and vals[0] == '') or math.isclose(float(vals[0]), i) + assert (i >= len(y1) and vals[1] == '') or math.isclose(float(vals[1]), y1[i]) + + assert (i >= len(x2) and vals[2] == '') or math.isclose(float(vals[2]), x2[i]) + assert (i >= len(y2) and vals[3] == '') or math.isclose(float(vals[3]), y2[i]) + + assert (i >= len(x3) and vals[4] == '') or math.isclose(float(vals[4]), x3[i]) + assert (i >= len(y3) and vals[5] == '') or math.isclose(float(vals[5]), y3[i]) + def test_CSVExporter_with_ErrorBarItem(): plt = pg.PlotWidget() @@ -71,9 +63,14 @@ def test_CSVExporter_with_ErrorBarItem(): ) plt.addItem(err) ex = pg.exporters.CSVExporter(plt.plotItem) - with tempfile.NamedTemporaryFile(mode="w+t", suffix='.csv', encoding="utf-8", delete=False) as tf: + with tempfile.NamedTemporaryFile( + mode="w+t", + suffix='.csv', + encoding="utf-8", + delete=False + ) as tf: ex.export(fileName=tf.name) - lines = [line for line in csv.reader(tf)] + lines = list(csv.reader(tf)) header = lines.pop(0) diff --git a/tests/exporters/test_exporter_dialog.py b/tests/exporters/test_exporter_dialog.py new file mode 100644 index 0000000000..5af2e1d8a0 --- /dev/null +++ b/tests/exporters/test_exporter_dialog.py @@ -0,0 +1,27 @@ +import pyqtgraph as pg + +from tests.ui_testing import mouseClick + + +app = pg.mkQApp() + + +def test_export_dialog(): + plt = pg.PlotWidget() + y1 = [1,3,2,3,1,6,9,8,4,2] + plt.plot(y=y1) + plt.show() + + # # export dialog doesn't exist + assert plt.scene().exportDialog is None + mouseClick( + plt, + pos=pg.Qt.QtCore.QPointF(plt.mapFromGlobal(plt.geometry().center())), + button=pg.Qt.QtCore.Qt.MouseButton.RightButton + ) + plt.scene().contextMenu[0].trigger() # show dialog + plt.scene().showExportDialog() + assert plt.scene().exportDialog.isVisible() + plt.scene().exportDialog.close() + app.processEvents() + plt.close() diff --git a/tests/exporters/test_image.py b/tests/exporters/test_image.py index 8ef12a26bd..a5a186c955 100644 --- a/tests/exporters/test_image.py +++ b/tests/exporters/test_image.py @@ -9,8 +9,10 @@ def test_ImageExporter_filename_dialog(): - """Tests ImageExporter code path that opens a file dialog. Regression test - for pull request 1133.""" + """ + Tests ImageExporter code path that opens a file dialog. + Regression test for pull request 1133. + """ p = pg.PlotWidget() p.show() exp = ImageExporter(p.getPlotItem()) diff --git a/tests/exporters/test_svg.py b/tests/exporters/test_svg.py index b88f0abd2f..bccd09ba32 100644 --- a/tests/exporters/test_svg.py +++ b/tests/exporters/test_svg.py @@ -16,7 +16,7 @@ def test_plotscene(tmpdir): ex = pg.exporters.SVGExporter(w.scene()) - tf = tmpdir.join("expot.svg") + tf = tmpdir.join("export.svg") ex.export(fileName=tf) # clean up after the test is done w.close() @@ -66,5 +66,5 @@ def test_simple(tmpdir): grp2.addItem(rect3) ex = pg.exporters.SVGExporter(scene) - tf = tmpdir.join("expot.svg") + tf = tmpdir.join("export.svg") ex.export(fileName=tf) diff --git a/tests/graphicsItems/PlotItem/test_PlotItem.py b/tests/graphicsItems/PlotItem/test_PlotItem.py index f0c52d0301..3bcb68e3eb 100644 --- a/tests/graphicsItems/PlotItem/test_PlotItem.py +++ b/tests/graphicsItems/PlotItem/test_PlotItem.py @@ -22,7 +22,7 @@ def is_none_or_scalar(value): sorted_randint(0, 20, 15), *[sorted_randint(0, 20, 15) for _ in range(4)], ], - np.row_stack([sorted_randint(20, 40, 15) for _ in range(6)]), + np.vstack([sorted_randint(20, 40, 15) for _ in range(6)]), ] diff --git a/tests/graphicsItems/test_AxisItem.py b/tests/graphicsItems/test_AxisItem.py index 6e55f039c1..15878339f5 100644 --- a/tests/graphicsItems/test_AxisItem.py +++ b/tests/graphicsItems/test_AxisItem.py @@ -121,32 +121,24 @@ def test_collision(p, axisSpec, tickSpecs, textSpecs): app.processEvents() plot.close() - -def test_AxisItem_label_visibility(): +@pytest.mark.parametrize('orientation,label_kwargs,labelText,labelUnits', [ + ('left', {}, '', '',), + ('left', dict(text='Position', units='mm'), 'Position', 'mm'), + ('left', dict(text=None, units=None), '', ''), + ('left', dict(text='Current', units=None), 'Current', ''), + ('left', dict(text='', units='V'), '', 'V') +]) +def test_AxisItem_label_visibility(orientation, label_kwargs, labelText: str, labelUnits: str): """Test the visibility of the axis item using `setLabel`""" - axis = pg.AxisItem('left') - assert axis.labelText == '' - assert axis.labelUnits == '' - assert not axis.label.isVisible() - axis.setLabel(text='Position', units='mm') - assert axis.labelText == 'Position' - assert axis.labelUnits == 'mm' - assert axis.label.isVisible() - # XXX: `None` is converted to empty strings. - axis.setLabel(text=None, units=None) - assert axis.labelText == '' - assert axis.labelUnits == '' - assert not axis.label.isVisible() - axis.setLabel(text='Current', units=None) - assert axis.labelText == 'Current' - assert axis.labelUnits == '' - assert axis.label.isVisible() - axis.setLabel(text=None, units=None) - assert not axis.label.isVisible() - axis.setLabel(text='', units='V') - assert axis.labelText == '' - assert axis.labelUnits == 'V' - assert axis.label.isVisible() + axis = pg.AxisItem(orientation) + axis.setLabel(**label_kwargs) + assert axis.labelText == labelText + assert axis.labelUnits == labelUnits + assert ( + axis.label.isVisible() + if any(label_kwargs.values()) + else not axis.label.isVisible() + ) @pytest.mark.parametrize( "orientation,x,y,expected", diff --git a/tests/graphicsItems/test_GraphicsItem.py b/tests/graphicsItems/test_GraphicsItem.py index e8c8b2fa2e..c2ef23b0f2 100644 --- a/tests/graphicsItems/test_GraphicsItem.py +++ b/tests/graphicsItems/test_GraphicsItem.py @@ -1,10 +1,7 @@ -import faulthandler import weakref import pyqtgraph as pg -faulthandler.enable() - pg.mkQApp() def test_getViewWidget(): diff --git a/tests/graphicsItems/test_ImageItem.py b/tests/graphicsItems/test_ImageItem.py index f3e245e302..e5d71b011c 100644 --- a/tests/graphicsItems/test_ImageItem.py +++ b/tests/graphicsItems/test_ImageItem.py @@ -86,12 +86,12 @@ def test_ImageItem(transpose=False): app.processEvents() assertImageApproved(w, 'imageitem/init', 'Init image item. View is auto-scaled, image axis 0 marked by 1 line, axis 1 is marked by 2 lines. Origin in bottom-left.') - # ..with colormap + # ... with colormap cmap = pg.ColorMap([0, 0.25, 0.75, 1], [[0, 0, 0, 255], [255, 0, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255]]) img.setLookupTable(cmap.getLookupTable()) assertImageApproved(w, 'imageitem/lut', 'Set image LUT.') - # ..and different levels + # ... and different levels img.setLevels([dmax+9, dmax+13]) assertImageApproved(w, 'imageitem/levels1', 'Levels show only axis lines.') @@ -167,7 +167,7 @@ def test_ImageItem(transpose=False): assertImageApproved(w, 'imageitem/resolution_without_downsampling', 'Resolution test without downsampling.') img.setAutoDownsample(True) - assertImageApproved(w, 'imageitem/resolution_with_downsampling_x', 'Resolution test with downsampling axross x axis.') + assertImageApproved(w, 'imageitem/resolution_with_downsampling_x', 'Resolution test with downsampling across x axis.') assert img._lastDownsample == (4, 1) img.setImage(data.T, levels=[-1, 1]) diff --git a/tests/graphicsItems/test_InfiniteLine.py b/tests/graphicsItems/test_InfiniteLine.py index 2d0690490c..15ee80d9e2 100644 --- a/tests/graphicsItems/test_InfiniteLine.py +++ b/tests/graphicsItems/test_InfiniteLine.py @@ -16,7 +16,7 @@ def test_InfiniteLine(): plt.setYRange(-10, 10) plt.resize(600, 600) - # seemingly arbitrary requirements; might need longer wait time for some platforms.. + # seemingly arbitrary requirements; might need longer wait time for some platforms QtTest.QTest.qWaitForWindowExposed(plt) QtTest.QTest.qWait(100) diff --git a/tests/graphicsItems/test_LegendItem.py b/tests/graphicsItems/test_LegendItem.py index 7cd29f4640..96142daaf4 100644 --- a/tests/graphicsItems/test_LegendItem.py +++ b/tests/graphicsItems/test_LegendItem.py @@ -1,8 +1,8 @@ import pyqtgraph as pg +pg.mkQApp() def test_legend_item_basics(): - pg.mkQApp() legend = pg.LegendItem() diff --git a/tests/graphicsItems/test_LinearRegionItem.py b/tests/graphicsItems/test_LinearRegionItem.py index 677c4d6591..acb2de0653 100644 --- a/tests/graphicsItems/test_LinearRegionItem.py +++ b/tests/graphicsItems/test_LinearRegionItem.py @@ -25,7 +25,7 @@ def test_clip_to_plot_data_item(orientation): # initial bounds for the LRI init_vals = (-1.5, 1.5) - # data for a PlotDataItem to clip to, both inside the inial bounds + # data for a PlotDataItem to clip to, both inside the initial bounds x = np.linspace(-1, 1, 10) y = np.linspace(1, 1.2, 10) diff --git a/tests/graphicsItems/test_NonUniformImage.py b/tests/graphicsItems/test_NonUniformImage.py index a77e575ce2..a472019bdf 100644 --- a/tests/graphicsItems/test_NonUniformImage.py +++ b/tests/graphicsItems/test_NonUniformImage.py @@ -61,15 +61,11 @@ def test_NonUniformImage_lut(): Z = X * Y image = NonUniformImage(x, y, Z, border=fn.mkPen('g')) - viewbox.addItem(image) - - lut = pg.HistogramLUTItem() - window.addItem(lut) - image.setLookupTable(lut, autoLevel=True) + cmap = ColorMap(None, [0.0, 1.0]) + image.setLookupTable(cmap.getLookupTable(nPts=256)) - h = image.getHistogram() - lut.plot.setData(*h) + viewbox.addItem(image) QtTest.QTest.qWaitForWindowExposed(window) QtTest.QTest.qWait(100) @@ -90,7 +86,7 @@ def test_NonUniformImage_colormap(): X, Y = np.meshgrid(x, y, indexing='ij') Z = X * Y - Z[:, 0] = [np.NINF, np.NAN, np.PINF] + Z[:, 0] = [-np.inf, np.nan, np.inf] image = NonUniformImage(x, y, Z, border=fn.mkPen('g')) diff --git a/tests/graphicsItems/test_PlotCurveItem.py b/tests/graphicsItems/test_PlotCurveItem.py index 77873164ac..1266342403 100644 --- a/tests/graphicsItems/test_PlotCurveItem.py +++ b/tests/graphicsItems/test_PlotCurveItem.py @@ -17,7 +17,7 @@ def test_PlotCurveItem(): v.addItem(c) v.autoRange() - # Check auto-range works. Some platform differences may be expected.. + # Check auto-range works. Some platform differences may be expected. checkRange = np.array([[-1.1457564053237301, 16.145756405323731], [-3.076811473165955, 11.076811473165955]]) assert np.allclose(v.viewRange(), checkRange) diff --git a/tests/graphicsItems/test_PlotDataItem.py b/tests/graphicsItems/test_PlotDataItem.py index 1cd9f32d6b..3a190005e1 100644 --- a/tests/graphicsItems/test_PlotDataItem.py +++ b/tests/graphicsItems/test_PlotDataItem.py @@ -185,7 +185,7 @@ def test_clipping(): # test center and expected number of remaining data points for center, num in ((-100.,1), (100.,1), (0.,len(y)) ): # when all elements are off-screen, only one will be kept - # when all elelemts are on-screen, all should be kept + # when all elements are on-screen, all should be kept # and the code should not crash for zero separation w.setXRange( center-50, center+50, padding=0 ) xDisp, yDisp = c.getData() diff --git a/tests/graphicsItems/test_ROI.py b/tests/graphicsItems/test_ROI.py index 89a4f82bcb..362a873e31 100644 --- a/tests/graphicsItems/test_ROI.py +++ b/tests/graphicsItems/test_ROI.py @@ -14,52 +14,55 @@ pg.setConfigOption("mouseRateLimit", 0) -def test_getArrayRegion(transpose=False): - pr = pg.PolyLineROI([[0, 0], [27, 0], [0, 28]], closed=True) - pr.setPos(1, 1) - rois = [ - (pg.ROI([1, 1], [27, 28], pen='y'), 'baseroi'), - (pg.RectROI([1, 1], [27, 28], pen='y'), 'rectroi'), - (pg.EllipseROI([1, 1], [27, 28], pen='y'), 'ellipseroi'), - (pr, 'polylineroi'), +@pytest.mark.parametrize("roi, name", [ + (pg.ROI([1, 1], [27, 28], pen='y', antialias=False), 'baseroi'), + (pg.RectROI([1, 1], [27, 28], pen='y', antialias=False), 'rectroi'), + (pg.EllipseROI([1, 1], [27, 28], pen='y', antialias=False), 'ellipseroi'), + ( + pg.PolyLineROI( + [[0, 0], [27, 0], [0, 28]], + closed=True, + pos=(1, 1), + antialias=False + ),'polylineroi' + ), ] - for roi, name in rois: - # For some ROIs, resize should not be used. - testResize = not isinstance(roi, pg.PolyLineROI) - - origMode = pg.getConfigOption('imageAxisOrder') - try: - if transpose: - pg.setConfigOptions(imageAxisOrder='row-major') - check_getArrayRegion(roi, 'roi/' + name, testResize, - transpose=True) - else: - pg.setConfigOptions(imageAxisOrder='col-major') - check_getArrayRegion(roi, 'roi/' + name, testResize) - finally: - pg.setConfigOptions(imageAxisOrder=origMode) - - -def test_getArrayRegion_axisorder(): - test_getArrayRegion(transpose=True) +) +@pytest.mark.parametrize("transpose", [True, False]) +def test_getArrayRegion(roi, name, transpose): + # For some ROIs, resize should not be used. + testResize = not isinstance(roi, pg.PolyLineROI) + + origMode = pg.getConfigOption('imageAxisOrder') + try: + pg.setConfigOptions( + imageAxisOrder='row-major' if transpose else 'col-major' + ) + check_getArrayRegion( + roi, f"roi/{name}", + testResize, + transpose=transpose + ) + finally: + pg.setConfigOptions(imageAxisOrder=origMode) def check_getArrayRegion(roi, name, testResize=True, transpose=False): - # on windows, edges corner pixels seem to be slightly different from - # other platforms giving a pxCount=2 for a fudge factor - if (isinstance(roi, (pg.ROI, pg.RectROI)) - and platform.system() == "Windows"): - pxCount = 2 + # edges corner pixels seem to be slightly different on windows + if ( + isinstance(roi, (pg.ROI, pg.RectROI)) + and platform.system() == "Windows" + ): + pxCount = 1 else: pxCount = -1 initState = roi.getState() - win = pg.GraphicsView() win.show() resizeWindow(win, 200, 400) - # Don't use Qt's layouts for testing--these generate unpredictable results. - # Instead, place the viewboxes manually + # Don't use Qts' layouts for testing--these generate unpredictable results. + # Instead, manually place the ViewBoxes vb1 = pg.ViewBox() win.scene().addItem(vb1) vb1.setPos(6, 6) @@ -94,12 +97,13 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False): vb1.addItem(roi) if isinstance(roi, pg.RectROI): - if transpose: - assert roi.getAffineSliceParams(data, img1, axes=(1, 2)) == ( - [28.0, 27.0], ((1.0, 0.0), (0.0, 1.0)), (1.0, 1.0)) - else: - assert roi.getAffineSliceParams(data, img1, axes=(1, 2)) == ( - [27.0, 28.0], ((1.0, 0.0), (0.0, 1.0)), (1.0, 1.0)) + first_arg = [28.0, 27.0] if transpose else [27.0, 28.0] + assert roi.getAffineSliceParams( + data, + img1, + axes=(1, 2) + ) == (first_arg, ((1.0, 0.0), (0.0, 1.0)), (1.0, 1.0)) + rgn = roi.getArrayRegion(data, img1, axes=(1, 2)) # assert np.all((rgn == data[:, 1:-2, 1:-2, :]) | (rgn == 0)) @@ -108,8 +112,12 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False): vb2.enableAutoRange(True, True) app.processEvents() - assertImageApproved(win, name + '/roi_getarrayregion', - 'Simple ROI region selection.', pxCount=pxCount) + assertImageApproved( + win, + f'{name}/roi_getarrayregion', + 'Simple ROI region selection.', + pxCount=pxCount + ) with pytest.raises(TypeError): roi.setPos(0, False) @@ -118,44 +126,59 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False): rgn = roi.getArrayRegion(data, img1, axes=(1, 2)) img2.setImage(rgn[0, ..., 0]) app.processEvents() - assertImageApproved(win, name + '/roi_getarrayregion_halfpx', - 'Simple ROI region selection, 0.5 pixel shift.', - pxCount=pxCount) + assertImageApproved( + win, + f'{name}/roi_getarrayregion_halfpx', + 'Simple ROI region selection, 0.5 pixel shift.', + pxCount=pxCount + ) roi.setAngle(45) roi.setPos([3, 0]) rgn = roi.getArrayRegion(data, img1, axes=(1, 2)) img2.setImage(rgn[0, ..., 0]) app.processEvents() - assertImageApproved(win, name + '/roi_getarrayregion_rotate', - 'Simple ROI region selection, rotation.', - pxCount=pxCount) + assertImageApproved( + win, + f'{name}/roi_getarrayregion_rotate', + 'Simple ROI region selection, rotation.', + pxCount=pxCount + ) if testResize: roi.setSize([60, 60]) rgn = roi.getArrayRegion(data, img1, axes=(1, 2)) img2.setImage(rgn[0, ..., 0]) app.processEvents() - assertImageApproved(win, name + '/roi_getarrayregion_resize', - 'Simple ROI region selection, resized.', - pxCount=pxCount) + assertImageApproved( + win, + f'{name}/roi_getarrayregion_resize', + 'Simple ROI region selection, resized.', + pxCount=pxCount + ) img1.setPos(0, img1.height()) img1.setTransform(QtGui.QTransform().scale(1, -1).rotate(20), True) rgn = roi.getArrayRegion(data, img1, axes=(1, 2)) img2.setImage(rgn[0, ..., 0]) app.processEvents() - assertImageApproved(win, name + '/roi_getarrayregion_img_trans', - 'Simple ROI region selection, image transformed.', - pxCount=pxCount) + assertImageApproved( + win, + f'{name}/roi_getarrayregion_img_trans', + 'Simple ROI region selection, image transformed.', + pxCount=pxCount + ) vb1.invertY() rgn = roi.getArrayRegion(data, img1, axes=(1, 2)) img2.setImage(rgn[0, ..., 0]) app.processEvents() - assertImageApproved(win, name + '/roi_getarrayregion_inverty', - 'Simple ROI region selection, view inverted.', - pxCount=pxCount) + assertImageApproved( + win, + f'{name}/roi_getarrayregion_inverty', + 'Simple ROI region selection, view inverted.', + pxCount=pxCount + ) roi.setState(initState) img1.setPos(0, 0) @@ -164,13 +187,13 @@ def check_getArrayRegion(roi, name, testResize=True, transpose=False): img2.setImage(rgn[0, ..., 0]) app.processEvents() assertImageApproved( - win, name + '/roi_getarrayregion_anisotropic', + win, + f'{name}/roi_getarrayregion_anisotropic', 'Simple ROI region selection, image scaled anisotropically.', - pxCount=pxCount) - + pxCount=pxCount + ) # allow the roi to be re-used roi.scene().removeItem(roi) - win.hide() @@ -188,11 +211,15 @@ def test_mouseClickEvent(): vb.addItem(roi) app.processEvents() - mouseClick(plt, roi.mapToScene(pg.Point(2, 2)), - QtCore.Qt.MouseButton.LeftButton) + mouseClick( + plt, + roi.mapToScene(pg.Point(2, 2)), + QtCore.Qt.MouseButton.LeftButton + ) def test_mouseDragEventSnap(): + pg.setConfigOptions(antialias=False) plt = pg.GraphicsView() plt.show() resizeWindow(plt, 200, 200) @@ -205,8 +232,14 @@ def test_mouseDragEventSnap(): # A Rectangular roi with scaleSnap enabled initial_x = 20 initial_y = 20 - roi = pg.RectROI((initial_x, initial_y), (20, 20), scaleSnap=True, - translateSnap=True, snapSize=1.0, movable=True) + roi = pg.RectROI( + (initial_x, initial_y), + (20, 20), + scaleSnap=True, + translateSnap=True, + snapSize=1.0, + movable=True + ) vb.addItem(roi) app.processEvents() @@ -223,28 +256,53 @@ def test_mouseDragEventSnap(): # Only drag in y direction roi_position = roi.mapToView(pg.Point(initial_x, initial_y)) - mouseDrag(plt, roi_position, roi_position + pg.Point(0, 10), - QtCore.Qt.MouseButton.LeftButton) + mouseDrag( + plt, + roi_position, + roi_position + pg.Point(0, 10), + QtCore.Qt.MouseButton.LeftButton + ) assert roi.pos() == pg.Point(initial_x, 19) - mouseDrag(plt, roi_position, roi_position + pg.Point(0, 10), - QtCore.Qt.MouseButton.LeftButton) + mouseDrag( + plt, + roi_position, + roi_position + pg.Point(0, 10), + QtCore.Qt.MouseButton.LeftButton + ) assert roi.pos() == pg.Point(initial_x, 18) # Only drag in x direction - mouseDrag(plt, roi_position, roi_position + pg.Point(10, 0), - QtCore.Qt.MouseButton.LeftButton) + mouseDrag( + plt, + roi_position, + roi_position + pg.Point(10, 0), + QtCore.Qt.MouseButton.LeftButton + ) assert roi.pos() == pg.Point(21, 18) - -def test_PolyLineROI(): - rois = [ - (pg.PolyLineROI([[0, 0], [10, 0], [0, 15]], closed=True, pen=0.3), - 'closed'), - (pg.PolyLineROI([[0, 0], [10, 0], [0, 15]], closed=False, pen=0.3), - 'open') +@pytest.mark.parametrize("roi, name", [ + ( + pg.PolyLineROI( + [[0, 0], [10, 0], [0, 15]], + closed=True, + pen=0.3, + antialias=False + ), + 'closed' + ), + ( + pg.PolyLineROI( + [[0, 0], [10, 0], [0, 15]], + closed=False, + pen=0.3, + antialias=False + ), + 'open' + ) ] - +) +def test_PolyLineROI(roi, name): plt = pg.GraphicsView() plt.show() resizeWindow(plt, 200, 200) @@ -257,89 +315,134 @@ def test_PolyLineROI(): plt.scene().minDragTime = 0 # let us simulate mouse drags very quickly. - # seemingly arbitrary requirements; might need longer wait time for some - # platforms.. + # seemingly arbitrary requirements; might need longer wait time for some platforms. QtTest.QTest.qWaitForWindowExposed(plt) QtTest.QTest.qWait(100) - for r, name in rois: - vb.clear() - vb.addItem(r) - vb.autoRange() - app.processEvents() + vb.clear() + vb.addItem(roi) + vb.autoRange() + app.processEvents() - assertImageApproved(plt, 'roi/polylineroi/' + name + '_init', - 'Init %s polyline.' % name) - initState = r.getState() - assert len(r.getState()['points']) == 3 - - # hover over center - center = r.mapToScene(pg.Point(3, 3)) - mouseMove(plt, center) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_hover_roi', - 'Hover mouse over center of ROI.') - - # drag ROI - mouseDrag(plt, center, center + pg.Point(10, -10), - QtCore.Qt.MouseButton.LeftButton) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_drag_roi', - 'Drag mouse over center of ROI.') - - # hover over handle - pt = r.mapToScene(pg.Point(r.getState()['points'][2])) - mouseMove(plt, pt) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_hover_handle', - 'Hover mouse over handle.') - - # drag handle - mouseDrag(plt, pt, pt + pg.Point(5, 20), - QtCore.Qt.MouseButton.LeftButton) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_drag_handle', - 'Drag mouse over handle.') - - # hover over segment - pt = r.mapToScene((pg.Point(r.getState()['points'][2]) + pg.Point( - r.getState()['points'][1])) * 0.5) - mouseMove(plt, pt + pg.Point(0, 2)) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_hover_segment', - 'Hover mouse over diagonal segment.') - - # click segment - mouseClick(plt, pt, QtCore.Qt.MouseButton.LeftButton) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_click_segment', - 'Click mouse over segment.') - - # drag new handle - mouseMove(plt, pt + pg.Point(10, - -10)) - # pg bug: have to move the mouse off/on again to register hover - mouseDrag(plt, pt, pt + pg.Point(10, -10), - QtCore.Qt.MouseButton.LeftButton) - assertImageApproved(plt, - 'roi/polylineroi/' + name + '_drag_new_handle', - 'Drag mouse over created handle.') - - # clear all points - r.clearPoints() - assertImageApproved(plt, 'roi/polylineroi/' + name + '_clear', - 'All points cleared.') - assert len(r.getState()['points']) == 0 - - # call setPoints - r.setPoints(initState['points']) - assertImageApproved( - plt, - f'roi/polylineroi/{name}_setpoints', - 'Reset points to initial state.', - pxCount=1 if platform.system() == "Darwin" and parse(platform.mac_ver()[0]) >= Version("13.0") else 0 - ) - assert len(r.getState()['points']) == 3 + assertImageApproved( + plt, + f'roi/polylineroi/{name}_init', + f'Init {name} polyline.' + ) + initState = roi.getState() + assert len(roi.getState()['points']) == 3 + + # hover over center + center = roi.mapToScene(pg.Point(3, 3)) + mouseMove(plt, center) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_hover_roi', + 'Hover mouse over center of ROI.' + ) + + # drag ROI + mouseDrag( + plt, + center, center + pg.Point(10, -10), + QtCore.Qt.MouseButton.LeftButton + ) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_drag_roi', + 'Drag mouse over center of ROI.' + ) + + # hover over handle + pt = roi.mapToScene( + pg.Point(roi.getState()['points'][2]) + ) + mouseMove(plt, pt) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_hover_handle', + 'Hover mouse over handle.' + ) + + # drag handle + mouseDrag(plt, + pt, + pt + pg.Point(5, 20), + QtCore.Qt.MouseButton.LeftButton + ) + + assertImageApproved( + plt, + f'roi/polylineroi/{name}_drag_handle', + 'Drag mouse over handle.' + ) + + # hover over segment + pt = roi.mapToScene( + ( + pg.Point(roi.getState()['points'][2]) + + pg.Point(roi.getState()['points'][1]) + ) * 0.5 + ) + + mouseMove(plt, pt + pg.Point(0, 2)) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_hover_segment', + 'Hover mouse over diagonal segment.' + ) + + # click segment + mouseClick(plt, pt, QtCore.Qt.MouseButton.LeftButton) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_click_segment', + 'Click mouse over segment.', + pxCount=3 + ) + + # drag new handle + mouseMove(plt, pt + pg.Point(10, -10)) + # pg bug: have to move the mouse off/on again to register hover + mouseDrag( + plt, + pt, pt + pg.Point(10, -10), + QtCore.Qt.MouseButton.LeftButton + ) + + assertImageApproved( + plt, + f'roi/polylineroi/{name}_drag_new_handle', + 'Drag mouse over created handle.', + pxCount=2 + ) + + # clear all points + roi.clearPoints() + assertImageApproved( + plt, + f'roi/polylineroi/{name}_clear', + 'All points cleared.' + ) + assert len(roi.getState()['points']) == 0 + + # call setPoints + roi.setPoints(initState['points']) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_setpoints', + 'Reset points to initial state.', + ) + assert len(roi.getState()['points']) == 3 - # call setState - r.setState(initState) - assertImageApproved(plt, 'roi/polylineroi/' + name + '_setstate', - 'Reset ROI to initial state.') - assert len(r.getState()['points']) == 3 + # call setState + roi.setState(initState) + assertImageApproved( + plt, + f'roi/polylineroi/{name}_setstate', + 'Reset ROI to initial state.' + ) + assert len(roi.getState()['points']) == 3 plt.hide() @@ -351,6 +454,7 @@ def test_PolyLineROI(): ((-2, 1), (-4, -8)), ]) def test_LineROI_coords(p1, p2): + pg.setConfigOptions(antialias=False) pw = pg.PlotWidget() pw.show() @@ -358,8 +462,10 @@ def test_LineROI_coords(p1, p2): pw.addItem(lineroi) # first two handles are the scale-rotate handles positioned by pos1, pos2 - for expected, (name, scenepos) in zip([p1, p2], - lineroi.getSceneHandlePositions()): + for expected, (_, scenepos) in zip( + [p1, p2], + lineroi.getSceneHandlePositions() + ): got = lineroi.mapSceneToParent(scenepos) assert math.isclose(got.x(), expected[0]) assert math.isclose(got.y(), expected[1]) diff --git a/tests/image_testing.py b/tests/image_testing.py index 2db9b4b67f..363823b186 100644 --- a/tests/image_testing.py +++ b/tests/image_testing.py @@ -153,7 +153,7 @@ def assertImageApproved(image, standardFile, message=None, **kwargs): print(graphstate) if os.getenv('PYQTGRAPH_AUDIT_ALL') == '1': - raise Exception("Image test passed, but auditing due to PYQTGRAPH_AUDIT_ALL evnironment variable.") + raise Exception("Image test passed, but auditing due to PYQTGRAPH_AUDIT_ALL environment variable.") except Exception: if os.getenv('PYQTGRAPH_AUDIT') == '1' or os.getenv('PYQTGRAPH_AUDIT_ALL') == '1': sys.excepthook(*sys.exc_info()) @@ -171,7 +171,7 @@ def assertImageApproved(image, standardFile, message=None, **kwargs): "PYQTGRAPH_AUDIT=1 to add this image." % stdFileName) if os.getenv('CI') is not None: standardFile = os.path.join(os.getenv("SCREENSHOT_DIR", "screenshots"), standardFile) - saveFailedTest(image, stdImage, standardFile) + saveFailedTest(image, stdImage, standardFile, save_comparison=True) print(graphstate) raise @@ -223,7 +223,7 @@ def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50., pxdiff = diff.max(axis=2) # largest value difference per pixel mask = np.abs(pxdiff) >= pxThreshold if pxCount is not None: - assert mask.sum() <= pxCount + assert mask.sum() <= pxCount, f"allowed {pxCount=}, actual was {mask.sum()}" maskedDiff = diff[mask] if maxPxDiff is not None and maskedDiff.size > 0: @@ -237,7 +237,21 @@ def assertImageMatch(im1, im2, minCorr=None, pxThreshold=50., assert corr >= minCorr -def saveFailedTest(data, expect, filename): +def saveFailedTest(data, expect, filename, save_comparison=False): + directory = os.path.dirname(filename) + if not os.path.isdir(directory): + os.makedirs(directory) + base, ext = os.path.splitext(filename) + if ext != ".png": + filename += ".png" + + png = makePng(data) + with open(filename, "wb") as png_file: + png_file.write(png) + + if not save_comparison: + return None + # concatenate data, expect, and diff into a single image ds = data.shape es = expect.shape @@ -253,15 +267,10 @@ def saveFailedTest(data, expect, filename): diff = makeDiffImage(data, expect) img[2:2+diff.shape[0], -diff.shape[1]-2:-2] = diff - png = makePng(data) # change `img` to `data` to save just the failed image - directory = os.path.dirname(filename) - if not os.path.isdir(directory): - os.makedirs(directory) - with open(filename + ".png", "wb") as png_file: + png = makePng(img) + with open(f"{base}_comparison.png", "wb") as png_file: png_file.write(png) - print("\nImage comparison failed. Test result: %s %s Expected result: " - "%s %s" % (data.shape, data.dtype, expect.shape, expect.dtype)) - + return None def makePng(img): """Given an array like (H, W, 4), return a PNG-encoded byte string. @@ -297,7 +306,7 @@ def __init__(self): QtWidgets.QWidget.__init__(self) self.resize(1200, 800) - #self.showFullScreen() + self.setWindowTitle("ImageTester") self.layout = QtWidgets.QGridLayout() self.setLayout(self.layout) @@ -308,33 +317,45 @@ def __init__(self): self.label = QtWidgets.QLabel() self.layout.addWidget(self.label, 1, 0, 1, 2) self.label.setWordWrap(True) - font = QtGui.QFont("monospace", 14, QtGui.QFont.Weight.Bold) + font = QtGui.QFont("monospace", 14) + font.setStyleHint(QtGui.QFont.StyleHint.Monospace) self.label.setFont(font) self.passBtn = QtWidgets.QPushButton('Pass') self.failBtn = QtWidgets.QPushButton('Fail') - self.layout.addWidget(self.passBtn, 2, 0) - self.layout.addWidget(self.failBtn, 2, 1) + self.saveBtn = QtWidgets.QPushButton('Save Test Result Image') + + self.btnBox = QtWidgets.QDialogButtonBox() + self.btnBox.addButton(self.passBtn, QtWidgets.QDialogButtonBox.ButtonRole.YesRole) + self.btnBox.addButton(self.failBtn, QtWidgets.QDialogButtonBox.ButtonRole.NoRole) + self.btnBox.addButton(self.saveBtn, QtWidgets.QDialogButtonBox.ButtonRole.AcceptRole) self.passBtn.clicked.connect(self.passTest) self.failBtn.clicked.connect(self.failTest) - - self.views = (self.view.addViewBox(row=0, col=0), - self.view.addViewBox(row=0, col=1), - self.view.addViewBox(row=0, col=2)) - labelText = ['test output', 'standard', 'diff'] - for i, v in enumerate(self.views): + self.saveBtn.clicked.connect(self.saveImage) + self.layout.addWidget(self.btnBox, 2, 0, 1, -1) + + self.plots = ( + self.view.addPlot(title="Result", row=0, col=0), + self.view.addPlot(title="Baseline", row=0, col=1), + self.view.addPlot(title="Difference", row=0, col=2) + ) + + for plot in self.plots: + plot.hideButtons() + for axis in ['left', 'bottom', 'right', 'top']: + plot.hideAxis(axis) + v = plot.getViewBox() v.setAspectLocked(1) v.invertY() v.image = ImageItem(axisOrder='row-major') v.image.setAutoDownsample(True) v.addItem(v.image) - v.label = TextItem(labelText[i]) v.setBackgroundColor(0.5) - self.views[1].setXLink(self.views[0]) - self.views[1].setYLink(self.views[0]) - self.views[2].setXLink(self.views[0]) - self.views[2].setYLink(self.views[0]) + self.plots[1].setXLink(self.plots[0]) + self.plots[1].setYLink(self.plots[0]) + self.plots[2].setXLink(self.plots[0]) + self.plots[2].setYLink(self.plots[0]) def test(self, im1, im2, message): """Ask the user to decide whether an image test passes or fails. @@ -345,32 +366,42 @@ def test(self, im1, im2, message): then an exception is raised. """ self.show() + message = f"Test Message: {message}" if im2 is None: - message += '\nImage1: %s %s Image2: [no standard]' % (im1.shape, im1.dtype) + message += ( + "\n" + + f"Result: Dimensions={im1.shape}\tDType={im1.dtype}\n" + + "Baseline: [no standard]" + ) im2 = np.zeros((1, 1, 3), dtype=np.ubyte) else: - message += '\nImage1: %s %s Image2: %s %s' % (im1.shape, im1.dtype, im2.shape, im2.dtype) + message += ( + "\n" + + f"Result: Dimensions={im1.shape}\tDType={im1.dtype}\n" + + f"Baseline: Dimensions={im2.shape}\tDType={im2.dtype}" + ) self.label.setText(message) - - self.views[0].image.setImage(im1) - self.views[1].image.setImage(im2) + + self.plots[0].getViewBox().image.setImage(im1) + self.plots[1].getViewBox().image.setImage(im2) diff = makeDiffImage(im1, im2) - self.views[2].image.setImage(diff) - self.views[0].autoRange() + self.plots[2].getViewBox().image.setImage(diff) + self.plots[0].autoRange() while True: QtWidgets.QApplication.processEvents() lastKey = self.lastKey - + self.lastKey = None if lastKey in ('f', 'esc') or not self.isVisible(): - raise Exception("User rejected test result.") + raise ValueError("User rejected test result.") elif lastKey == 'p': break time.sleep(0.03) - for v in self.views: + for plot in self.plots: + v = plot.getViewBox() v.image.setImage(np.zeros((1, 1, 3), dtype=np.ubyte)) def keyPressEvent(self, event): @@ -385,6 +416,24 @@ def passTest(self): def failTest(self): self.lastKey = 'f' + def saveImage(self): + filename, _ = QtWidgets.QFileDialog.getSaveFileName( + self, + "Save Test Image", + filter="Images (*png)", + options=QtWidgets.QFileDialog.Option.ReadOnly + ) + if not filename: + # user cancelled out of the dialog + return None + + _, ext = os.path.splitext(filename) + if ext != ".png": + filename = f"{filename}.png" + result = self.plots[0].getViewBox().image.image + expected = self.plots[1].getViewBox().image.image + saveFailedTest(result, expected, filename, save_comparison=True) + return None def getTestDataDirectory(): dataPath = Path(__file__).absolute().parent / "images" @@ -406,9 +455,9 @@ def scenegraphState(view, name): def itemState(root): state = str(root) + '\n' from pyqtgraph import ViewBox - state += 'bounding rect: ' + str(root.boundingRect()) + '\n' + state += f'bounding rect: {str(root.boundingRect())}' + '\n' if isinstance(root, ViewBox): - state += "view range: " + str(root.viewRange()) + '\n' + state += f"view range: {str(root.viewRange())}" + '\n' state += "transform:\n" + indent(transformStr(root.transform()).strip(), " ") + '\n' for item in root.childItems(): state += indent(itemState(item).strip(), " ") + '\n' diff --git a/tests/images/roi/baseroi/roi_getarrayregion.png b/tests/images/roi/baseroi/roi_getarrayregion.png index 440ebfdc8a..a4031ac459 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion.png and b/tests/images/roi/baseroi/roi_getarrayregion.png differ diff --git a/tests/images/roi/baseroi/roi_getarrayregion_anisotropic.png b/tests/images/roi/baseroi/roi_getarrayregion_anisotropic.png index ad0eaf2c6f..925f5218d6 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion_anisotropic.png and b/tests/images/roi/baseroi/roi_getarrayregion_anisotropic.png differ diff --git a/tests/images/roi/baseroi/roi_getarrayregion_halfpx.png b/tests/images/roi/baseroi/roi_getarrayregion_halfpx.png index e64976aef3..00d34ee94c 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion_halfpx.png and b/tests/images/roi/baseroi/roi_getarrayregion_halfpx.png differ diff --git a/tests/images/roi/baseroi/roi_getarrayregion_img_trans.png b/tests/images/roi/baseroi/roi_getarrayregion_img_trans.png index e59ddec78f..819e607506 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion_img_trans.png and b/tests/images/roi/baseroi/roi_getarrayregion_img_trans.png differ diff --git a/tests/images/roi/baseroi/roi_getarrayregion_inverty.png b/tests/images/roi/baseroi/roi_getarrayregion_inverty.png index a97fd068bd..aee5254aad 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion_inverty.png and b/tests/images/roi/baseroi/roi_getarrayregion_inverty.png differ diff --git a/tests/images/roi/baseroi/roi_getarrayregion_resize.png b/tests/images/roi/baseroi/roi_getarrayregion_resize.png index 5e82196d9a..60a206b947 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion_resize.png and b/tests/images/roi/baseroi/roi_getarrayregion_resize.png differ diff --git a/tests/images/roi/baseroi/roi_getarrayregion_rotate.png b/tests/images/roi/baseroi/roi_getarrayregion_rotate.png index eff9c64fca..7a59908a47 100644 Binary files a/tests/images/roi/baseroi/roi_getarrayregion_rotate.png and b/tests/images/roi/baseroi/roi_getarrayregion_rotate.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion.png b/tests/images/roi/ellipseroi/roi_getarrayregion.png index 8bb1cfc7c3..91a0514ad2 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion.png and b/tests/images/roi/ellipseroi/roi_getarrayregion.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion_anisotropic.png b/tests/images/roi/ellipseroi/roi_getarrayregion_anisotropic.png index 1601298f1a..6a48b12b9d 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion_anisotropic.png and b/tests/images/roi/ellipseroi/roi_getarrayregion_anisotropic.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion_halfpx.png b/tests/images/roi/ellipseroi/roi_getarrayregion_halfpx.png index 88165740a6..36e6c08764 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion_halfpx.png and b/tests/images/roi/ellipseroi/roi_getarrayregion_halfpx.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion_img_trans.png b/tests/images/roi/ellipseroi/roi_getarrayregion_img_trans.png index 9ba008c77b..4ae9888972 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion_img_trans.png and b/tests/images/roi/ellipseroi/roi_getarrayregion_img_trans.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion_inverty.png b/tests/images/roi/ellipseroi/roi_getarrayregion_inverty.png index 2b5b9703b1..9e54fdf37b 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion_inverty.png and b/tests/images/roi/ellipseroi/roi_getarrayregion_inverty.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion_resize.png b/tests/images/roi/ellipseroi/roi_getarrayregion_resize.png index 604d733c75..c1604d48d8 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion_resize.png and b/tests/images/roi/ellipseroi/roi_getarrayregion_resize.png differ diff --git a/tests/images/roi/ellipseroi/roi_getarrayregion_rotate.png b/tests/images/roi/ellipseroi/roi_getarrayregion_rotate.png index 1f806959b3..f090e5cb27 100644 Binary files a/tests/images/roi/ellipseroi/roi_getarrayregion_rotate.png and b/tests/images/roi/ellipseroi/roi_getarrayregion_rotate.png differ diff --git a/tests/images/roi/polylineroi/closed_click_segment.png b/tests/images/roi/polylineroi/closed_click_segment.png index dba7d2cc0c..94c27ff2d7 100644 Binary files a/tests/images/roi/polylineroi/closed_click_segment.png and b/tests/images/roi/polylineroi/closed_click_segment.png differ diff --git a/tests/images/roi/polylineroi/closed_drag_handle.png b/tests/images/roi/polylineroi/closed_drag_handle.png index 4a635d4617..c5cc3f0434 100644 Binary files a/tests/images/roi/polylineroi/closed_drag_handle.png and b/tests/images/roi/polylineroi/closed_drag_handle.png differ diff --git a/tests/images/roi/polylineroi/closed_drag_new_handle.png b/tests/images/roi/polylineroi/closed_drag_new_handle.png index ac08eac376..a1857a76a6 100644 Binary files a/tests/images/roi/polylineroi/closed_drag_new_handle.png and b/tests/images/roi/polylineroi/closed_drag_new_handle.png differ diff --git a/tests/images/roi/polylineroi/closed_drag_roi.png b/tests/images/roi/polylineroi/closed_drag_roi.png index 9094dca28e..5e59a91c98 100644 Binary files a/tests/images/roi/polylineroi/closed_drag_roi.png and b/tests/images/roi/polylineroi/closed_drag_roi.png differ diff --git a/tests/images/roi/polylineroi/closed_hover_handle.png b/tests/images/roi/polylineroi/closed_hover_handle.png index c596eb237e..3b8fe3506e 100644 Binary files a/tests/images/roi/polylineroi/closed_hover_handle.png and b/tests/images/roi/polylineroi/closed_hover_handle.png differ diff --git a/tests/images/roi/polylineroi/closed_hover_roi.png b/tests/images/roi/polylineroi/closed_hover_roi.png index e535773334..ee5bd8bdca 100644 Binary files a/tests/images/roi/polylineroi/closed_hover_roi.png and b/tests/images/roi/polylineroi/closed_hover_roi.png differ diff --git a/tests/images/roi/polylineroi/closed_hover_segment.png b/tests/images/roi/polylineroi/closed_hover_segment.png index ff15e5822e..2fc130442a 100644 Binary files a/tests/images/roi/polylineroi/closed_hover_segment.png and b/tests/images/roi/polylineroi/closed_hover_segment.png differ diff --git a/tests/images/roi/polylineroi/closed_init.png b/tests/images/roi/polylineroi/closed_init.png index e99a6c58d8..f16ffb8509 100644 Binary files a/tests/images/roi/polylineroi/closed_init.png and b/tests/images/roi/polylineroi/closed_init.png differ diff --git a/tests/images/roi/polylineroi/closed_setpoints.png b/tests/images/roi/polylineroi/closed_setpoints.png index 2f31114019..155fa3e1ba 100644 Binary files a/tests/images/roi/polylineroi/closed_setpoints.png and b/tests/images/roi/polylineroi/closed_setpoints.png differ diff --git a/tests/images/roi/polylineroi/closed_setstate.png b/tests/images/roi/polylineroi/closed_setstate.png index e99a6c58d8..f16ffb8509 100644 Binary files a/tests/images/roi/polylineroi/closed_setstate.png and b/tests/images/roi/polylineroi/closed_setstate.png differ diff --git a/tests/images/roi/polylineroi/open_click_segment.png b/tests/images/roi/polylineroi/open_click_segment.png index f99e663a00..f715169c76 100644 Binary files a/tests/images/roi/polylineroi/open_click_segment.png and b/tests/images/roi/polylineroi/open_click_segment.png differ diff --git a/tests/images/roi/polylineroi/open_drag_handle.png b/tests/images/roi/polylineroi/open_drag_handle.png index 50cfeed514..dc0f033bb7 100644 Binary files a/tests/images/roi/polylineroi/open_drag_handle.png and b/tests/images/roi/polylineroi/open_drag_handle.png differ diff --git a/tests/images/roi/polylineroi/open_drag_new_handle.png b/tests/images/roi/polylineroi/open_drag_new_handle.png index f2aad0a708..db223a9605 100644 Binary files a/tests/images/roi/polylineroi/open_drag_new_handle.png and b/tests/images/roi/polylineroi/open_drag_new_handle.png differ diff --git a/tests/images/roi/polylineroi/open_drag_roi.png b/tests/images/roi/polylineroi/open_drag_roi.png index a3fe2d6a5d..12466d02aa 100644 Binary files a/tests/images/roi/polylineroi/open_drag_roi.png and b/tests/images/roi/polylineroi/open_drag_roi.png differ diff --git a/tests/images/roi/polylineroi/open_hover_handle.png b/tests/images/roi/polylineroi/open_hover_handle.png index 93f0f786a8..a2e13ac6a2 100644 Binary files a/tests/images/roi/polylineroi/open_hover_handle.png and b/tests/images/roi/polylineroi/open_hover_handle.png differ diff --git a/tests/images/roi/polylineroi/open_hover_roi.png b/tests/images/roi/polylineroi/open_hover_roi.png index 23edb1967a..4c9851b263 100644 Binary files a/tests/images/roi/polylineroi/open_hover_roi.png and b/tests/images/roi/polylineroi/open_hover_roi.png differ diff --git a/tests/images/roi/polylineroi/open_hover_segment.png b/tests/images/roi/polylineroi/open_hover_segment.png index 53c6df6c53..61a4090676 100644 Binary files a/tests/images/roi/polylineroi/open_hover_segment.png and b/tests/images/roi/polylineroi/open_hover_segment.png differ diff --git a/tests/images/roi/polylineroi/open_init.png b/tests/images/roi/polylineroi/open_init.png index 38cf15d6a4..884f007086 100644 Binary files a/tests/images/roi/polylineroi/open_init.png and b/tests/images/roi/polylineroi/open_init.png differ diff --git a/tests/images/roi/polylineroi/open_setpoints.png b/tests/images/roi/polylineroi/open_setpoints.png index 5c2d59310d..800464864a 100644 Binary files a/tests/images/roi/polylineroi/open_setpoints.png and b/tests/images/roi/polylineroi/open_setpoints.png differ diff --git a/tests/images/roi/polylineroi/open_setstate.png b/tests/images/roi/polylineroi/open_setstate.png index 38cf15d6a4..884f007086 100644 Binary files a/tests/images/roi/polylineroi/open_setstate.png and b/tests/images/roi/polylineroi/open_setstate.png differ diff --git a/tests/images/roi/polylineroi/roi_getarrayregion.png b/tests/images/roi/polylineroi/roi_getarrayregion.png index bbf424e4eb..77e4166db7 100644 Binary files a/tests/images/roi/polylineroi/roi_getarrayregion.png and b/tests/images/roi/polylineroi/roi_getarrayregion.png differ diff --git a/tests/images/roi/polylineroi/roi_getarrayregion_anisotropic.png b/tests/images/roi/polylineroi/roi_getarrayregion_anisotropic.png index 1900907149..650b0f6630 100644 Binary files a/tests/images/roi/polylineroi/roi_getarrayregion_anisotropic.png and b/tests/images/roi/polylineroi/roi_getarrayregion_anisotropic.png differ diff --git a/tests/images/roi/polylineroi/roi_getarrayregion_halfpx.png b/tests/images/roi/polylineroi/roi_getarrayregion_halfpx.png index f5af5fc3c3..1cce4fb857 100644 Binary files a/tests/images/roi/polylineroi/roi_getarrayregion_halfpx.png and b/tests/images/roi/polylineroi/roi_getarrayregion_halfpx.png differ diff --git a/tests/images/roi/polylineroi/roi_getarrayregion_img_trans.png b/tests/images/roi/polylineroi/roi_getarrayregion_img_trans.png index b3cf8a1c66..96e9f8e255 100644 Binary files a/tests/images/roi/polylineroi/roi_getarrayregion_img_trans.png and b/tests/images/roi/polylineroi/roi_getarrayregion_img_trans.png differ diff --git a/tests/images/roi/polylineroi/roi_getarrayregion_inverty.png b/tests/images/roi/polylineroi/roi_getarrayregion_inverty.png index 004662962c..a84029bba5 100644 Binary files a/tests/images/roi/polylineroi/roi_getarrayregion_inverty.png and b/tests/images/roi/polylineroi/roi_getarrayregion_inverty.png differ diff --git a/tests/images/roi/polylineroi/roi_getarrayregion_rotate.png b/tests/images/roi/polylineroi/roi_getarrayregion_rotate.png index 7961c675db..55485217dd 100644 Binary files a/tests/images/roi/polylineroi/roi_getarrayregion_rotate.png and b/tests/images/roi/polylineroi/roi_getarrayregion_rotate.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion.png b/tests/images/roi/rectroi/roi_getarrayregion.png index 13b308e7ae..a29e9db0f4 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion.png and b/tests/images/roi/rectroi/roi_getarrayregion.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion_anisotropic.png b/tests/images/roi/rectroi/roi_getarrayregion_anisotropic.png index 8d0a825fbf..6a14163856 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion_anisotropic.png and b/tests/images/roi/rectroi/roi_getarrayregion_anisotropic.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion_halfpx.png b/tests/images/roi/rectroi/roi_getarrayregion_halfpx.png index 956796d092..312b4943a3 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion_halfpx.png and b/tests/images/roi/rectroi/roi_getarrayregion_halfpx.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion_img_trans.png b/tests/images/roi/rectroi/roi_getarrayregion_img_trans.png index 7a12ba7a99..6bbc4554ee 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion_img_trans.png and b/tests/images/roi/rectroi/roi_getarrayregion_img_trans.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion_inverty.png b/tests/images/roi/rectroi/roi_getarrayregion_inverty.png index 8a801f78f5..83ed514fbf 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion_inverty.png and b/tests/images/roi/rectroi/roi_getarrayregion_inverty.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion_resize.png b/tests/images/roi/rectroi/roi_getarrayregion_resize.png index 881517fe91..a6afd07a31 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion_resize.png and b/tests/images/roi/rectroi/roi_getarrayregion_resize.png differ diff --git a/tests/images/roi/rectroi/roi_getarrayregion_rotate.png b/tests/images/roi/rectroi/roi_getarrayregion_rotate.png index 366e1f9ce1..2f2ebbb6eb 100644 Binary files a/tests/images/roi/rectroi/roi_getarrayregion_rotate.png and b/tests/images/roi/rectroi/roi_getarrayregion_rotate.png differ diff --git a/tests/makeARGB_test_data.py b/tests/makeARGB_test_data.py new file mode 100644 index 0000000000..5fad6f2d25 --- /dev/null +++ b/tests/makeARGB_test_data.py @@ -0,0 +1,4268 @@ +import sys +from typing import Optional, Union + +import numpy as np +import numpy.typing as npt + +from pyqtgraph.functions import makeARGB + + + + +IN_2D_INT8 = np.array([[173, 48, 122, 41], [210, 192, 0, 5], [104, 56, 102, 115], [78, 19, 255, 6]], dtype=np.uint8) +IN_RGB_INT8 = np.array( + [ + [[16, 69, 62], [66, 132, 135], [220, 80, 36], [53, 34, 68]], + [[140, 23, 113], [0, 63, 206], [96, 255, 100], [226, 182, 155]], + [[28, 237, 223], [215, 232, 209], [17, 16, 50], [96, 187, 93]], + [[220, 193, 232], [134, 168, 150], [55, 64, 221], [96, 108, 227]], + ], + dtype=np.uint8, +) +IN_RGBA_INT8 = np.array( + [ + [[151, 252, 73, 107], [28, 221, 35, 0], [87, 122, 126, 114], [47, 59, 24, 200]], + [[189, 246, 242, 255], [123, 255, 29, 14], [201, 208, 133, 32], [118, 203, 141, 245]], + [[133, 131, 248, 81], [4, 84, 99, 40], [40, 167, 119, 150], [13, 158, 108, 21]], + [[156, 221, 166, 250], [77, 188, 13, 166], [0, 1, 185, 25], [83, 35, 103, 120]], + ], + dtype=np.uint8, +) +IN_2D_INT16 = np.array( + [ + [13364, 55041, 40746, 40937], + [57612, 34247, 34132, 0], + [10109, 56950, 41856, 21479], + [14881, 65535, 48079, 11372], + ], + dtype=np.uint16, +) +IN_RGB_INT16 = np.array( + [ + [[55626, 45263, 0], [19468, 39208, 36391], [33255, 8664, 56991], [37588, 31212, 38295]], + [[58933, 16402, 36905], [9928, 23928, 12418], [16461, 47738, 18189], [17004, 39307, 59941]], + [[43717, 49573, 9843], [35967, 3891, 39618], [53542, 58151, 29112], [53667, 4092, 35267]], + [[15957, 21648, 45238], [65535, 47107, 52049], [6342, 34547, 19902], [43386, 37301, 35095]], + ], + dtype=np.uint16, +) +IN_RGBA_INT16 = np.array( + [ + [ + [13060, 40847, 29621, 46719], + [0, 36509, 33525, 56649], + [48328, 23093, 47186, 26801], + [57336, 12247, 30996, 11691], + ], + [ + [4863, 41121, 32045, 25250], + [27779, 65098, 59921, 47771], + [8906, 18280, 5066, 48587], + [65535, 25758, 27250, 17284], + ], + [ + [52005, 65535, 40746, 65535], + [33, 57630, 27750, 42371], + [50176, 35079, 19220, 63662], + [17702, 5506, 36216, 48303], + ], + [ + [61592, 27692, 37436, 7249], + [54653, 39986, 58441, 12819], + [20887, 56588, 32440, 85], + [13457, 14661, 58972, 48779], + ], + ], + dtype=np.uint16, +) +IN_2D_FLOAT = np.array( + [ + [np.inf, 0.53662884, np.nan, 0.8853132], + [0.8496698, 0.88006145, 1.0, 0.06621328], + [0.99158293, 0.8476984, 0.16672458, 0.9887786], + [0.07076367, 0.66354364, 0.8781082, 0.988832], + ], + dtype=np.float32, +) +IN_RGB_FLOAT = np.array( + [ + [ + [0.23317624, 0.39086635, 0.12795302], + [0.40659714, 0.9079258, 0.28431135], + [0.91651599, 0.46082205, 0.16928465], + [0.29368765, 0.97987488, 0.72257988], + ], + [ + [np.nan, 0.72908475, 0.54018012], + [0.91277435, 0.2842577, 0.73481915], + [0.33844504, 0.22060913, 0.9802894], + [0.13995676, 0.34752838, 0.39652277], + ], + [ + [0.85315026, 0.19330797, 0.0], + [0.48584232, 0.04943356, 0.59906953], + [np.inf, 0.32614581, 0.1483722], + [0.37340863, 0.35432855, 0.08973532], + ], + [ + [0.69666134, 0.52481322, 0.49057305], + [0.93366339, 0.1428689, 0.6845513], + [0.27681383, 0.69472673, 0.06750892], + [0.26349886, 0.25841691, 0.86171104], + ], + ] +) +IN_RGBA_FLOAT = np.array( + [ + [ + [0.97383172, 0.62680971, 0.02285016, np.nan], + [0.85295433, 0.93014834, 0.59482999, np.inf], + [0.4017482, 0.79809183, 0.22407464, 0.17327807], + [0.95953263, 0.69535086, 0.28846483, 0.76970823], + ], + [ + [0.11487603, 0.7447609, 0.06767498, 0.98054729], + [0.66071068, 0.73931366, 0.33155686, 0.81827122], + [0.78035892, 0.52920802, 0.5671388, 0.31783899], + [0.81709002, 0.82204682, 0.82584029, 0.49434749], + ], + [ + [0.03142089, 0.8322058, 0.31646922, 0.94636969], + [0.62381573, 0.60052138, 0.50244611, 0.92886007], + [np.nan, np.nan, 0.02940048, 0.52529675], + [0.9786162, 0.54928697, 0.2409731, 0.34705397], + ], + [ + [0.68922233, np.inf, 0.85027734, 0.35388624], + [0.16489042, 0.29860162, 0.09349833, 0.67714667], + [0.25351483, 0.25596098, 0.80461891, 0.99952403], + [0.0, 1.0, 0.58084746, 0.46211944], + ], + ] +) +INPUTS: dict[tuple[npt.DTypeLike, str], np.ndarray] = { + (np.uint8, "2D"): IN_2D_INT8, + (np.uint8, "RGB"): IN_RGB_INT8, + (np.uint8, "RGBA"): IN_RGBA_INT8, + (np.uint16, "2D"): IN_2D_INT16, + (np.uint16, "RGB"): IN_RGB_INT16, + (np.uint16, "RGBA"): IN_RGBA_INT16, + (np.float32, "2D"): IN_2D_FLOAT, + (np.float32, "RGB"): IN_RGB_FLOAT, + (np.float32, "RGBA"): IN_RGBA_FLOAT, +} +LUT8 = np.zeros((255,), dtype=np.uint8) +LUT8[::2] = 255 +LUT16 = np.zeros((65535,), dtype=np.uint8) +LUT16[::3] = 255 +LUTS: dict[npt.DTypeLike, np.ndarray] = { + np.uint8: LUT8, + np.uint16: LUT16, +} +LEVELS = { + "SIMPLE": (0, 1), + "RGB": ((0, 255), (1, 250), (100, 160)), + "RGBA": ((255, 11111), (100, 10000), (0, 255), (127, 255)), +} + +EXPECTED_OUTPUTS: dict[ + tuple[npt.DTypeLike, str, Optional[str], Optional[npt.DTypeLike], Optional[int], bool], + Union[type(Exception), np.ndarray] +] = { + (np.uint8, "2D", None, None, None, True): np.array( + [ + [[173, 173, 173, 255], [48, 48, 48, 255], [122, 122, 122, 255], [41, 41, 41, 255]], + [[210, 210, 210, 255], [192, 192, 192, 255], [0, 0, 0, 255], [5, 5, 5, 255]], + [[104, 104, 104, 255], [56, 56, 56, 255], [102, 102, 102, 255], [115, 115, 115, 255]], + [[78, 78, 78, 255], [19, 19, 19, 255], [255, 255, 255, 255], [6, 6, 6, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, None, None, False): np.array( + [ + [[173, 173, 173, 255], [48, 48, 48, 255], [122, 122, 122, 255], [41, 41, 41, 255]], + [[210, 210, 210, 255], [192, 192, 192, 255], [0, 0, 0, 255], [5, 5, 5, 255]], + [[104, 104, 104, 255], [56, 56, 56, 255], [102, 102, 102, 255], [115, 115, 115, 255]], + [[78, 78, 78, 255], [19, 19, 19, 255], [255, 255, 255, 255], [6, 6, 6, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, None, 232, True): np.array( + [ + [[157, 157, 157, 255], [43, 43, 43, 255], [110, 110, 110, 255], [37, 37, 37, 255]], + [[191, 191, 191, 255], [174, 174, 174, 255], [0, 0, 0, 255], [4, 4, 4, 255]], + [[94, 94, 94, 255], [50, 50, 50, 255], [92, 92, 92, 255], [104, 104, 104, 255]], + [[70, 70, 70, 255], [17, 17, 17, 255], [232, 232, 232, 255], [5, 5, 5, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, None, 232, False): np.array( + [ + [[157, 157, 157, 255], [43, 43, 43, 255], [110, 110, 110, 255], [37, 37, 37, 255]], + [[191, 191, 191, 255], [174, 174, 174, 255], [0, 0, 0, 255], [4, 4, 4, 255]], + [[94, 94, 94, 255], [50, 50, 50, 255], [92, 92, 92, 255], [104, 104, 104, 255]], + [[70, 70, 70, 255], [17, 17, 17, 255], [232, 232, 232, 255], [5, 5, 5, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint8, None, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint8, None, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint8, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint8, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint16, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", None, np.uint16, 13333, False): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGB", None, None, True): Exception, + (np.uint8, "2D", "RGB", None, None, False): Exception, + (np.uint8, "2D", "RGB", None, 232, True): Exception, + (np.uint8, "2D", "RGB", None, 232, False): Exception, + (np.uint8, "2D", "RGB", None, 13333, True): Exception, + (np.uint8, "2D", "RGB", None, 13333, False): Exception, + (np.uint8, "2D", "RGB", np.uint8, None, True): Exception, + (np.uint8, "2D", "RGB", np.uint8, None, False): Exception, + (np.uint8, "2D", "RGB", np.uint8, 232, True): Exception, + (np.uint8, "2D", "RGB", np.uint8, 232, False): Exception, + (np.uint8, "2D", "RGB", np.uint8, 13333, True): Exception, + (np.uint8, "2D", "RGB", np.uint8, 13333, False): Exception, + (np.uint8, "2D", "RGB", np.uint16, None, True): Exception, + (np.uint8, "2D", "RGB", np.uint16, None, False): Exception, + (np.uint8, "2D", "RGB", np.uint16, 232, True): Exception, + (np.uint8, "2D", "RGB", np.uint16, 232, False): Exception, + (np.uint8, "2D", "RGB", np.uint16, 13333, True): Exception, + (np.uint8, "2D", "RGB", np.uint16, 13333, False): Exception, + (np.uint8, "2D", "RGBA", None, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [122, 122, 122, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [102, 102, 102, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", None, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [122, 122, 122, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [102, 102, 102, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", None, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [110, 110, 110, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [92, 92, 92, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [232, 232, 232, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", None, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [110, 110, 110, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [92, 92, 92, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [232, 232, 232, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", None, 13333, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [123, 123, 123, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", None, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [123, 123, 123, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint16, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint16, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint16, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint16, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint16, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "2D", "RGBA", np.uint16, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, None, None, True): np.array( + [ + [[16, 69, 62, 255], [66, 132, 135, 255], [220, 80, 36, 255], [53, 34, 68, 255]], + [[140, 23, 113, 255], [0, 63, 206, 255], [96, 255, 100, 255], [226, 182, 155, 255]], + [[28, 237, 223, 255], [215, 232, 209, 255], [17, 16, 50, 255], [96, 187, 93, 255]], + [[220, 193, 232, 255], [134, 168, 150, 255], [55, 64, 221, 255], [96, 108, 227, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, None, None, False): np.array( + [ + [[62, 69, 16, 255], [135, 132, 66, 255], [36, 80, 220, 255], [68, 34, 53, 255]], + [[113, 23, 140, 255], [206, 63, 0, 255], [100, 255, 96, 255], [155, 182, 226, 255]], + [[223, 237, 28, 255], [209, 232, 215, 255], [50, 16, 17, 255], [93, 187, 96, 255]], + [[232, 193, 220, 255], [150, 168, 134, 255], [221, 64, 55, 255], [227, 108, 96, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, None, 232, True): np.array( + [ + [[14, 62, 56, 255], [60, 120, 122, 255], [200, 72, 32, 255], [48, 30, 61, 255]], + [[127, 20, 102, 255], [0, 57, 187, 255], [87, 232, 90, 255], [205, 165, 141, 255]], + [[25, 215, 202, 255], [195, 211, 190, 255], [15, 14, 45, 255], [87, 170, 84, 255]], + [[200, 175, 211, 255], [121, 152, 136, 255], [50, 58, 201, 255], [87, 98, 206, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, None, 232, False): np.array( + [ + [[56, 62, 14, 255], [122, 120, 60, 255], [32, 72, 200, 255], [61, 30, 48, 255]], + [[102, 20, 127, 255], [187, 57, 0, 255], [90, 232, 87, 255], [141, 165, 205, 255]], + [[202, 215, 25, 255], [190, 211, 195, 255], [45, 14, 15, 255], [84, 170, 87, 255]], + [[211, 175, 200, 255], [136, 152, 121, 255], [201, 58, 50, 255], [206, 98, 87, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint8, None, True): np.array( + [ + [[255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[255, 0, 0, 255], [255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[255, 0, 0, 255], [0, 255, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255]], + [[255, 0, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint8, None, False): np.array( + [ + [[255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[0, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[0, 0, 255, 255], [0, 255, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255]], + [[255, 0, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[0, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 255, 255], [0, 0, 255, 255], [0, 255, 0, 255], [0, 255, 255, 255]], + [[255, 0, 0, 255], [0, 255, 255, 255], [255, 255, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 0, 255], [0, 0, 255, 255], [255, 255, 0, 255], [0, 0, 0, 255]], + [[255, 0, 0, 255], [255, 0, 0, 255], [0, 255, 0, 255], [255, 255, 0, 255]], + [[0, 0, 255, 255], [255, 255, 0, 255], [0, 255, 255, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint16, None, True): np.array( + [ + [[0, 255, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint16, None, False): np.array( + [ + [[0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 0, 255], [0, 255, 0, 255], [255, 255, 0, 255]], + [[0, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255], [0, 255, 255, 255]], + [[0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 255, 255, 255], [0, 255, 0, 255], [0, 255, 255, 255]], + [[255, 0, 0, 255], [0, 255, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255]], + [[0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [255, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255]], + [[255, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 255, 0, 255]], + [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 255, 0, 255]], + [[255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", None, np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 0, 255]], + [[0, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 255, 0, 255]], + [[0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255], [0, 255, 255, 255]], + [[0, 0, 255, 255], [255, 255, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 255, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255]], + [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 0, 0, 255]], + [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", None, None, True): np.array( + [ + [[16, 69, 0, 255], [66, 134, 148, 255], [220, 80, 0, 255], [53, 33, 0, 255]], + [[140, 22, 55, 255], [0, 63, 255, 255], [96, 255, 0, 255], [226, 185, 233, 255]], + [[28, 241, 255, 255], [215, 236, 255, 255], [17, 15, 0, 255], [96, 190, 0, 255]], + [[220, 196, 255, 255], [134, 171, 212, 255], [55, 64, 255, 255], [96, 109, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", None, None, False): np.array( + [ + [[0, 69, 16, 255], [148, 134, 66, 255], [0, 80, 220, 255], [0, 33, 53, 255]], + [[55, 22, 140, 255], [255, 63, 0, 255], [0, 255, 96, 255], [233, 185, 226, 255]], + [[255, 241, 28, 255], [255, 236, 215, 255], [0, 15, 17, 255], [0, 190, 96, 255]], + [[255, 196, 220, 255], [212, 171, 134, 255], [255, 64, 55, 255], [255, 109, 96, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", None, 232, True): np.array( + [ + [[14, 63, 0, 255], [60, 122, 135, 255], [200, 73, 0, 255], [48, 30, 0, 255]], + [[127, 20, 50, 255], [0, 57, 255, 255], [87, 236, 0, 255], [205, 168, 212, 255]], + [[25, 219, 255, 255], [195, 215, 255, 255], [15, 13, 0, 255], [87, 173, 0, 255]], + [[200, 178, 255, 255], [121, 155, 193, 255], [50, 58, 255, 255], [87, 99, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", None, 232, False): np.array( + [ + [[0, 63, 14, 255], [135, 122, 60, 255], [0, 73, 200, 255], [0, 30, 48, 255]], + [[50, 20, 127, 255], [255, 57, 0, 255], [0, 236, 87, 255], [212, 168, 205, 255]], + [[255, 219, 25, 255], [255, 215, 195, 255], [0, 13, 15, 255], [0, 173, 87, 255]], + [[255, 178, 200, 255], [193, 155, 121, 255], [255, 58, 50, 255], [255, 99, 87, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", None, 13333, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", None, 13333, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint8, None, True): np.array( + [ + [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255]], + [[255, 255, 0, 255], [255, 0, 255, 255], [255, 255, 255, 255], [255, 0, 0, 255]], + [[255, 0, 255, 255], [0, 255, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint8, None, False): np.array( + [ + [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 0, 255]], + [[0, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255]], + [[255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint8, 232, True): np.array( + [ + [[255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[0, 255, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint8, 232, False): np.array( + [ + [[255, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[255, 255, 0, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint16, None, True): np.array( + [ + [[0, 0, 255, 255], [255, 0, 0, 255], [0, 0, 255, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255], [0, 255, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [0, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint16, None, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 255, 255], [255, 0, 0, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [0, 255, 255, 255], [255, 0, 255, 255], [0, 255, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [0, 255, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint16, 232, True): np.array( + [ + [[0, 255, 255, 255], [255, 0, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [255, 0, 255, 255], [0, 255, 0, 255]], + [[0, 255, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255]], + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint16, 232, False): np.array( + [ + [[255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [255, 0, 255, 255], [0, 255, 0, 255]], + [[0, 255, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255]], + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint16, 13333, True): np.array( + [ + [[0, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255]], + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGB", np.uint16, 13333, False): np.array( + [ + [[255, 0, 0, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[0, 0, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255], [0, 0, 0, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255]], + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGB", "RGBA", None, None, True): Exception, + (np.uint8, "RGB", "RGBA", None, None, False): Exception, + (np.uint8, "RGB", "RGBA", None, 232, True): Exception, + (np.uint8, "RGB", "RGBA", None, 232, False): Exception, + (np.uint8, "RGB", "RGBA", None, 13333, True): Exception, + (np.uint8, "RGB", "RGBA", None, 13333, False): Exception, + (np.uint8, "RGB", "RGBA", np.uint8, None, True): Exception, + (np.uint8, "RGB", "RGBA", np.uint8, None, False): Exception, + (np.uint8, "RGB", "RGBA", np.uint8, 232, True): Exception, + (np.uint8, "RGB", "RGBA", np.uint8, 232, False): Exception, + (np.uint8, "RGB", "RGBA", np.uint8, 13333, True): Exception, + (np.uint8, "RGB", "RGBA", np.uint8, 13333, False): Exception, + (np.uint8, "RGB", "RGBA", np.uint16, None, True): Exception, + (np.uint8, "RGB", "RGBA", np.uint16, None, False): Exception, + (np.uint8, "RGB", "RGBA", np.uint16, 232, True): Exception, + (np.uint8, "RGB", "RGBA", np.uint16, 232, False): Exception, + (np.uint8, "RGB", "RGBA", np.uint16, 13333, True): Exception, + (np.uint8, "RGB", "RGBA", np.uint16, 13333, False): Exception, + (np.uint8, "RGBA", None, None, None, True): np.array( + [ + [[151, 252, 73, 107], [28, 221, 35, 0], [87, 122, 126, 114], [47, 59, 24, 200]], + [[189, 246, 242, 255], [123, 255, 29, 14], [201, 208, 133, 32], [118, 203, 141, 245]], + [[133, 131, 248, 81], [4, 84, 99, 40], [40, 167, 119, 150], [13, 158, 108, 21]], + [[156, 221, 166, 250], [77, 188, 13, 166], [0, 1, 185, 25], [83, 35, 103, 120]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, None, None, False): np.array( + [ + [[73, 252, 151, 107], [35, 221, 28, 0], [126, 122, 87, 114], [24, 59, 47, 200]], + [[242, 246, 189, 255], [29, 255, 123, 14], [133, 208, 201, 32], [141, 203, 118, 245]], + [[248, 131, 133, 81], [99, 84, 4, 40], [119, 167, 40, 150], [108, 158, 13, 21]], + [[166, 221, 156, 250], [13, 188, 77, 166], [185, 1, 0, 25], [103, 35, 83, 120]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, None, 232, True): np.array( + [ + [[137, 229, 66, 97], [25, 201, 31, 0], [79, 110, 114, 103], [42, 53, 21, 181]], + [[171, 223, 220, 232], [111, 232, 26, 12], [182, 189, 121, 29], [107, 184, 128, 222]], + [[121, 119, 225, 73], [3, 76, 90, 36], [36, 151, 108, 136], [11, 143, 98, 19]], + [[141, 201, 151, 227], [70, 171, 11, 151], [0, 0, 168, 22], [75, 31, 93, 109]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, None, 232, False): np.array( + [ + [[66, 229, 137, 97], [31, 201, 25, 0], [114, 110, 79, 103], [21, 53, 42, 181]], + [[220, 223, 171, 232], [26, 232, 111, 12], [121, 189, 182, 29], [128, 184, 107, 222]], + [[225, 119, 121, 73], [90, 76, 3, 36], [108, 151, 36, 136], [98, 143, 11, 19]], + [[151, 201, 141, 227], [11, 171, 70, 151], [168, 0, 0, 22], [93, 31, 75, 109]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [209, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 52, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 209, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 52, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint8, None, True): np.array( + [ + [[0, 255, 0, 0], [255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255]], + [[0, 255, 255, 255], [0, 255, 0, 255], [0, 255, 0, 255], [255, 0, 0, 0]], + [[0, 0, 255, 0], [255, 255, 0, 255], [255, 0, 0, 255], [0, 255, 255, 0]], + [[255, 0, 255, 255], [0, 255, 0, 255], [255, 0, 0, 0], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint8, None, False): np.array( + [ + [[0, 255, 0, 0], [0, 0, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255]], + [[255, 255, 0, 255], [0, 255, 0, 255], [0, 255, 0, 255], [0, 0, 255, 0]], + [[255, 0, 0, 0], [0, 255, 255, 255], [0, 0, 255, 255], [255, 255, 0, 0]], + [[255, 0, 255, 255], [0, 255, 0, 255], [0, 0, 255, 0], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint8, 232, True): np.array( + [ + [[0, 0, 255, 0], [0, 0, 0, 255], [0, 255, 255, 0], [255, 0, 0, 0]], + [[0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 0, 0], [0, 255, 255, 255]], + [[0, 0, 0, 0], [0, 255, 255, 255], [255, 0, 255, 255], [0, 0, 255, 0]], + [[0, 0, 0, 0], [255, 0, 0, 0], [255, 255, 255, 255], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint8, 232, False): np.array( + [ + [[255, 0, 0, 0], [0, 0, 0, 255], [255, 255, 0, 0], [0, 0, 255, 0]], + [[255, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 0], [255, 255, 0, 255]], + [[0, 0, 0, 0], [255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 255, 0], [255, 255, 255, 255], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint16, None, True): np.array( + [ + [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 0]], + [[255, 255, 0, 0], [255, 0, 0, 0], [255, 0, 0, 0], [0, 0, 255, 0]], + [[0, 0, 0, 255], [0, 255, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255]], + [[255, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint16, None, False): np.array( + [ + [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 0]], + [[0, 255, 255, 0], [0, 0, 255, 0], [0, 0, 255, 0], [255, 0, 0, 0]], + [[0, 0, 0, 255], [255, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint16, 232, True): np.array( + [ + [[0, 0, 255, 0], [0, 255, 0, 255], [0, 0, 255, 0], [255, 0, 255, 0]], + [[255, 0, 0, 0], [255, 0, 0, 255], [0, 255, 0, 0], [0, 0, 0, 255]], + [[0, 0, 255, 0], [255, 0, 255, 255], [255, 0, 255, 0], [0, 0, 0, 0]], + [[255, 255, 0, 0], [0, 255, 0, 0], [255, 255, 255, 0], [255, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint16, 232, False): np.array( + [ + [[255, 0, 0, 0], [0, 255, 0, 255], [255, 0, 0, 0], [255, 0, 255, 0]], + [[0, 0, 255, 0], [0, 0, 255, 255], [0, 255, 0, 0], [0, 0, 0, 255]], + [[255, 0, 0, 0], [255, 0, 255, 255], [255, 0, 255, 0], [0, 0, 0, 0]], + [[0, 255, 255, 0], [0, 255, 0, 0], [255, 255, 255, 0], [255, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint16, 13333, True): np.array( + [ + [[0, 255, 255, 0], [255, 0, 255, 255], [255, 255, 255, 0], [255, 255, 255, 0]], + [[255, 0, 0, 0], [0, 0, 0, 255], [255, 255, 255, 0], [0, 255, 0, 255]], + [[255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], + [[0, 0, 255, 255], [255, 0, 0, 255], [255, 0, 255, 0], [0, 255, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", None, np.uint16, 13333, False): np.array( + [ + [[255, 255, 0, 0], [255, 0, 255, 255], [255, 255, 255, 0], [255, 255, 255, 0]], + [[0, 0, 255, 0], [0, 0, 0, 255], [255, 255, 255, 0], [0, 255, 0, 255]], + [[255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], + [[255, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 0], [255, 255, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 232, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 232, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 0]], + [[255, 255, 0, 255], [255, 255, 0, 0], [255, 0, 0, 0], [0, 0, 255, 0]], + [[0, 0, 0, 255], [0, 255, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255]], + [[255, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 0]], + [[0, 255, 255, 255], [0, 255, 255, 0], [0, 0, 255, 0], [255, 0, 0, 0]], + [[0, 0, 0, 255], [255, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGB", None, None, True): Exception, + (np.uint8, "RGBA", "RGB", None, None, False): Exception, + (np.uint8, "RGBA", "RGB", None, 232, True): Exception, + (np.uint8, "RGBA", "RGB", None, 232, False): Exception, + (np.uint8, "RGBA", "RGB", None, 13333, True): Exception, + (np.uint8, "RGBA", "RGB", None, 13333, False): Exception, + (np.uint8, "RGBA", "RGB", np.uint8, None, True): Exception, + (np.uint8, "RGBA", "RGB", np.uint8, None, False): Exception, + (np.uint8, "RGBA", "RGB", np.uint8, 232, True): Exception, + (np.uint8, "RGBA", "RGB", np.uint8, 232, False): Exception, + (np.uint8, "RGBA", "RGB", np.uint8, 13333, True): Exception, + (np.uint8, "RGBA", "RGB", np.uint8, 13333, False): Exception, + (np.uint8, "RGBA", "RGB", np.uint16, None, True): Exception, + (np.uint8, "RGBA", "RGB", np.uint16, None, False): Exception, + (np.uint8, "RGBA", "RGB", np.uint16, 232, True): Exception, + (np.uint8, "RGBA", "RGB", np.uint16, 232, False): Exception, + (np.uint8, "RGBA", "RGB", np.uint16, 13333, True): Exception, + (np.uint8, "RGBA", "RGB", np.uint16, 13333, False): Exception, + (np.uint8, "RGBA", "RGBA", None, None, True): np.array( + [ + [[0, 3, 73, 0], [0, 3, 35, 0], [0, 0, 126, 0], [0, 0, 24, 145]], + [[0, 3, 242, 255], [0, 3, 29, 0], [0, 2, 133, 0], [0, 2, 141, 235]], + [[0, 0, 248, 0], [0, 0, 99, 0], [0, 1, 119, 45], [0, 1, 108, 0]], + [[0, 3, 166, 245], [0, 2, 13, 77], [0, 0, 185, 0], [0, 0, 103, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", None, None, False): np.array( + [ + [[73, 3, 0, 0], [35, 3, 0, 0], [126, 0, 0, 0], [24, 0, 0, 145]], + [[242, 3, 0, 255], [29, 3, 0, 0], [133, 2, 0, 0], [141, 2, 0, 235]], + [[248, 0, 0, 0], [99, 0, 0, 0], [119, 1, 0, 45], [108, 1, 0, 0]], + [[166, 3, 0, 245], [13, 2, 0, 77], [185, 0, 0, 0], [103, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", None, 232, True): np.array( + [ + [[0, 3, 66, 0], [0, 2, 31, 0], [0, 0, 114, 0], [0, 0, 21, 132]], + [[0, 3, 220, 232], [0, 3, 26, 0], [0, 2, 121, 0], [0, 2, 128, 213]], + [[0, 0, 225, 0], [0, 0, 90, 0], [0, 1, 108, 41], [0, 1, 98, 0]], + [[0, 2, 151, 222], [0, 2, 11, 70], [0, 0, 168, 0], [0, 0, 93, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", None, 232, False): np.array( + [ + [[66, 3, 0, 0], [31, 2, 0, 0], [114, 0, 0, 0], [21, 0, 0, 132]], + [[220, 3, 0, 232], [26, 3, 0, 0], [121, 2, 0, 0], [128, 2, 0, 213]], + [[225, 0, 0, 0], [90, 0, 0, 0], [108, 1, 0, 41], [98, 1, 0, 0]], + [[151, 2, 0, 222], [11, 2, 0, 70], [168, 0, 0, 0], [93, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", None, 13333, True): np.array( + [ + [[0, 204, 255, 0], [0, 162, 255, 0], [0, 29, 255, 0], [0, 0, 255, 255]], + [[0, 196, 255, 255], [0, 208, 255, 0], [0, 145, 255, 0], [0, 138, 255, 255]], + [[0, 41, 255, 0], [0, 0, 255, 0], [0, 90, 255, 255], [0, 78, 255, 0]], + [[0, 162, 255, 255], [0, 118, 255, 255], [0, 0, 255, 0], [0, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", None, 13333, False): np.array( + [ + [[255, 204, 0, 0], [255, 162, 0, 0], [255, 29, 0, 0], [255, 0, 0, 255]], + [[255, 196, 0, 255], [255, 208, 0, 0], [255, 145, 0, 0], [255, 138, 0, 255]], + [[255, 41, 0, 0], [255, 0, 0, 0], [255, 90, 0, 255], [255, 78, 0, 0]], + [[255, 162, 0, 255], [255, 118, 0, 255], [255, 0, 0, 0], [255, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint8, None, True): np.array( + [ + [[255, 0, 0, 255], [255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0]], + [[255, 0, 255, 255], [255, 0, 0, 255], [255, 255, 0, 255], [255, 255, 0, 0]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 0, 0, 0], [255, 0, 255, 255]], + [[255, 0, 255, 0], [255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint8, None, False): np.array( + [ + [[0, 0, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0]], + [[255, 0, 255, 255], [0, 0, 255, 255], [0, 255, 255, 255], [0, 255, 255, 0]], + [[255, 255, 255, 255], [0, 255, 255, 255], [0, 0, 255, 0], [255, 0, 255, 255]], + [[255, 0, 255, 0], [0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint8, 232, True): np.array( + [ + [[255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 0]], + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 0, 255, 0], [255, 0, 255, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint8, 232, False): np.array( + [ + [[255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[255, 0, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 0]], + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 0], [255, 0, 255, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint16, None, True): np.array( + [ + [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [255, 255, 255, 0]], + [[255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 255, 0]], + [[255, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [255, 0, 255, 255]], + [[255, 0, 0, 0], [255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint16, None, False): np.array( + [ + [[0, 0, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 0]], + [[0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 0]], + [[0, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255]], + [[0, 0, 255, 0], [0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint16, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 0, 0], [255, 255, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 0], [255, 0, 0, 255]], + [[255, 0, 0, 255], [255, 0, 0, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint16, 232, False): np.array( + [ + [[255, 255, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 255, 255, 0], [0, 255, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 0], [0, 0, 255, 255]], + [[0, 0, 255, 255], [0, 0, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint16, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 0]], + [[255, 0, 0, 0], [255, 0, 0, 255], [255, 0, 255, 255], [255, 255, 0, 255]], + [[255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint8, "RGBA", "RGBA", np.uint16, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 0]], + [[0, 0, 255, 0], [0, 0, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255]], + [[255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 0], [0, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, None, None, True): np.array( + [ + [[52, 52, 52, 255], [214, 214, 214, 255], [158, 158, 158, 255], [159, 159, 159, 255]], + [[224, 224, 224, 255], [133, 133, 133, 255], [132, 132, 132, 255], [0, 0, 0, 255]], + [[39, 39, 39, 255], [221, 221, 221, 255], [162, 162, 162, 255], [83, 83, 83, 255]], + [[57, 57, 57, 255], [255, 255, 255, 255], [187, 187, 187, 255], [44, 44, 44, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, None, None, False): np.array( + [ + [[52, 52, 52, 255], [214, 214, 214, 255], [158, 158, 158, 255], [159, 159, 159, 255]], + [[224, 224, 224, 255], [133, 133, 133, 255], [132, 132, 132, 255], [0, 0, 0, 255]], + [[39, 39, 39, 255], [221, 221, 221, 255], [162, 162, 162, 255], [83, 83, 83, 255]], + [[57, 57, 57, 255], [255, 255, 255, 255], [187, 187, 187, 255], [44, 44, 44, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, None, 232, True): np.array( + [ + [[47, 47, 47, 255], [194, 194, 194, 255], [144, 144, 144, 255], [144, 144, 144, 255]], + [[203, 203, 203, 255], [121, 121, 121, 255], [120, 120, 120, 255], [0, 0, 0, 255]], + [[35, 35, 35, 255], [201, 201, 201, 255], [148, 148, 148, 255], [76, 76, 76, 255]], + [[52, 52, 52, 255], [232, 232, 232, 255], [170, 170, 170, 255], [40, 40, 40, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, None, 232, False): np.array( + [ + [[47, 47, 47, 255], [194, 194, 194, 255], [144, 144, 144, 255], [144, 144, 144, 255]], + [[203, 203, 203, 255], [121, 121, 121, 255], [120, 120, 120, 255], [0, 0, 0, 255]], + [[35, 35, 35, 255], [201, 201, 201, 255], [148, 148, 148, 255], [76, 76, 76, 255]], + [[52, 52, 52, 255], [232, 232, 232, 255], [170, 170, 170, 255], [40, 40, 40, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint8, 232, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint8, 232, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint16, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", None, np.uint16, 13333, False): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGB", None, None, True): Exception, + (np.uint16, "2D", "RGB", None, None, False): Exception, + (np.uint16, "2D", "RGB", None, 232, True): Exception, + (np.uint16, "2D", "RGB", None, 232, False): Exception, + (np.uint16, "2D", "RGB", None, 13333, True): Exception, + (np.uint16, "2D", "RGB", None, 13333, False): Exception, + (np.uint16, "2D", "RGB", np.uint8, None, True): Exception, + (np.uint16, "2D", "RGB", np.uint8, None, False): Exception, + (np.uint16, "2D", "RGB", np.uint8, 232, True): Exception, + (np.uint16, "2D", "RGB", np.uint8, 232, False): Exception, + (np.uint16, "2D", "RGB", np.uint8, 13333, True): Exception, + (np.uint16, "2D", "RGB", np.uint8, 13333, False): Exception, + (np.uint16, "2D", "RGB", np.uint16, None, True): Exception, + (np.uint16, "2D", "RGB", np.uint16, None, False): Exception, + (np.uint16, "2D", "RGB", np.uint16, 232, True): Exception, + (np.uint16, "2D", "RGB", np.uint16, 232, False): Exception, + (np.uint16, "2D", "RGB", np.uint16, 13333, True): Exception, + (np.uint16, "2D", "RGB", np.uint16, 13333, False): Exception, + (np.uint16, "2D", "RGBA", None, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[231, 231, 231, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[231, 231, 231, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[210, 210, 210, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[210, 210, 210, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "2D", "RGBA", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, None, None, True): np.array( + [ + [[216, 176, 0, 255], [75, 152, 141, 255], [129, 33, 221, 255], [146, 121, 149, 255]], + [[229, 63, 143, 255], [38, 93, 48, 255], [64, 185, 70, 255], [66, 152, 233, 255]], + [[170, 192, 38, 255], [139, 15, 154, 255], [208, 226, 113, 255], [208, 15, 137, 255]], + [[62, 84, 176, 255], [255, 183, 202, 255], [24, 134, 77, 255], [168, 145, 136, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, None, None, False): np.array( + [ + [[0, 176, 216, 255], [141, 152, 75, 255], [221, 33, 129, 255], [149, 121, 146, 255]], + [[143, 63, 229, 255], [48, 93, 38, 255], [70, 185, 64, 255], [233, 152, 66, 255]], + [[38, 192, 170, 255], [154, 15, 139, 255], [113, 226, 208, 255], [137, 15, 208, 255]], + [[176, 84, 62, 255], [202, 183, 255, 255], [77, 134, 24, 255], [136, 145, 168, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, None, 232, True): np.array( + [ + [[196, 160, 0, 255], [68, 138, 128, 255], [117, 30, 201, 255], [133, 110, 135, 255]], + [[208, 58, 130, 255], [35, 84, 43, 255], [58, 168, 64, 255], [60, 139, 212, 255]], + [[154, 175, 34, 255], [127, 13, 140, 255], [189, 205, 103, 255], [189, 14, 124, 255]], + [[56, 76, 160, 255], [232, 166, 184, 255], [22, 122, 70, 255], [153, 132, 124, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, None, 232, False): np.array( + [ + [[0, 160, 196, 255], [128, 138, 68, 255], [201, 30, 117, 255], [135, 110, 133, 255]], + [[130, 58, 208, 255], [43, 84, 35, 255], [64, 168, 58, 255], [212, 139, 60, 255]], + [[34, 175, 154, 255], [140, 13, 127, 255], [103, 205, 189, 255], [124, 14, 189, 255]], + [[160, 76, 56, 255], [184, 166, 232, 255], [70, 122, 22, 255], [124, 132, 153, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, None, 13333, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, None, 13333, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [0, 0, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255]], + [[255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255]], + [[255, 255, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [0, 255, 0, 255]], + [[255, 255, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 255, 255]], + [[255, 0, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [0, 255, 0, 255]], + [[255, 255, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 255, 255]], + [[255, 0, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint16, None, True): np.array( + [ + [[255, 0, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], + [[0, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint16, None, False): np.array( + [ + [[255, 0, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], + [[255, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint16, 232, True): np.array( + [ + [[0, 0, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [0, 255, 0, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint16, 232, False): np.array( + [ + [[255, 0, 0, 255], [0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint16, 13333, True): np.array( + [ + [[0, 0, 255, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], + [[0, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 255]], + [[255, 255, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", None, np.uint16, 13333, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255]], + [[0, 255, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [0, 0, 0, 255]], + [[0, 255, 255, 255], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", None, None, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", None, 232, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", None, 13333, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint16, None, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", None, None, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", None, None, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", None, 232, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", None, 232, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", None, 13333, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", None, 13333, False): np.array( + [ + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint16, None, True): np.array( + [ + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint16, None, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint16, 232, True): np.array( + [ + [[0, 255, 255, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint16, 232, False): np.array( + [ + [[255, 255, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 255, 255, 255], [0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint16, 13333, True): np.array( + [ + [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGB", np.uint16, 13333, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGB", "RGBA", None, None, True): Exception, + (np.uint16, "RGB", "RGBA", None, None, False): Exception, + (np.uint16, "RGB", "RGBA", None, 232, True): Exception, + (np.uint16, "RGB", "RGBA", None, 232, False): Exception, + (np.uint16, "RGB", "RGBA", None, 13333, True): Exception, + (np.uint16, "RGB", "RGBA", None, 13333, False): Exception, + (np.uint16, "RGB", "RGBA", np.uint8, None, True): Exception, + (np.uint16, "RGB", "RGBA", np.uint8, None, False): Exception, + (np.uint16, "RGB", "RGBA", np.uint8, 232, True): Exception, + (np.uint16, "RGB", "RGBA", np.uint8, 232, False): Exception, + (np.uint16, "RGB", "RGBA", np.uint8, 13333, True): Exception, + (np.uint16, "RGB", "RGBA", np.uint8, 13333, False): Exception, + (np.uint16, "RGB", "RGBA", np.uint16, None, True): Exception, + (np.uint16, "RGB", "RGBA", np.uint16, None, False): Exception, + (np.uint16, "RGB", "RGBA", np.uint16, 232, True): Exception, + (np.uint16, "RGB", "RGBA", np.uint16, 232, False): Exception, + (np.uint16, "RGB", "RGBA", np.uint16, 13333, True): Exception, + (np.uint16, "RGB", "RGBA", np.uint16, 13333, False): Exception, + (np.uint16, "RGBA", None, None, None, True): np.array( + [ + [[50, 158, 115, 181], [0, 142, 130, 220], [188, 89, 183, 104], [223, 47, 120, 45]], + [[18, 160, 124, 98], [108, 253, 233, 185], [34, 71, 19, 189], [255, 100, 106, 67]], + [[202, 255, 158, 255], [0, 224, 107, 164], [195, 136, 74, 247], [68, 21, 140, 187]], + [[239, 107, 145, 28], [212, 155, 227, 49], [81, 220, 126, 0], [52, 57, 229, 189]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, None, None, False): np.array( + [ + [[115, 158, 50, 181], [130, 142, 0, 220], [183, 89, 188, 104], [120, 47, 223, 45]], + [[124, 160, 18, 98], [233, 253, 108, 185], [19, 71, 34, 189], [106, 100, 255, 67]], + [[158, 255, 202, 255], [107, 224, 0, 164], [74, 136, 195, 247], [140, 21, 68, 187]], + [[145, 107, 239, 28], [227, 155, 212, 49], [126, 220, 81, 0], [229, 57, 52, 189]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, None, 232, True): np.array( + [ + [[46, 144, 104, 165], [0, 129, 118, 200], [171, 81, 167, 94], [202, 43, 109, 41]], + [[17, 145, 113, 89], [98, 230, 212, 169], [31, 64, 17, 172], [232, 91, 96, 61]], + [[184, 232, 144, 232], [0, 204, 98, 149], [177, 124, 68, 225], [62, 19, 128, 170]], + [[218, 98, 132, 25], [193, 141, 206, 45], [73, 200, 114, 0], [47, 51, 208, 172]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, None, 232, False): np.array( + [ + [[104, 144, 46, 165], [118, 129, 0, 200], [167, 81, 171, 94], [109, 43, 202, 41]], + [[113, 145, 17, 89], [212, 230, 98, 169], [17, 64, 31, 172], [96, 91, 232, 61]], + [[144, 232, 184, 232], [98, 204, 0, 149], [68, 124, 177, 225], [128, 19, 62, 170]], + [[132, 98, 218, 25], [206, 141, 193, 45], [114, 200, 73, 0], [208, 51, 47, 172]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [6, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 17], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 6, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 17], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint8, None, True): np.array( + [ + [[255, 255, 0, 0], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 255, 0]], + [[255, 255, 255, 255], [255, 0, 0, 0], [255, 0, 0, 0], [255, 255, 255, 0]], + [[255, 255, 255, 255], [255, 255, 0, 255], [0, 255, 255, 0], [255, 0, 255, 0]], + [[0, 0, 0, 255], [255, 0, 0, 0], [0, 255, 255, 255], [255, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint8, None, False): np.array( + [ + [[0, 255, 255, 0], [255, 255, 255, 255], [0, 0, 255, 255], [255, 0, 0, 0]], + [[255, 255, 255, 255], [0, 0, 255, 0], [0, 0, 255, 0], [255, 255, 255, 0]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 0, 0], [255, 0, 255, 0]], + [[0, 0, 0, 255], [0, 0, 255, 0], [255, 255, 0, 255], [0, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 0], [255, 0, 255, 255], [0, 0, 0, 255], [255, 0, 0, 0]], + [[0, 0, 0, 0], [255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 0]], + [[255, 255, 255, 255], [255, 255, 255, 0], [0, 255, 255, 0], [255, 0, 255, 255]], + [[255, 255, 255, 0], [0, 0, 255, 0], [0, 255, 255, 255], [0, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 0], [255, 0, 255, 255], [0, 0, 0, 255], [0, 0, 255, 0]], + [[0, 0, 0, 0], [255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 0]], + [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 0, 0], [255, 0, 255, 255]], + [[255, 255, 255, 0], [255, 0, 0, 0], [255, 255, 0, 255], [255, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 0], [255, 0, 255, 255]], + [[255, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 255, 0, 0]], + [[255, 0, 255, 0], [255, 255, 255, 0], [0, 255, 0, 0], [0, 0, 255, 255]], + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 255, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 0], [255, 0, 255, 255]], + [[0, 255, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 255, 0, 0]], + [[255, 0, 255, 0], [255, 255, 255, 0], [0, 255, 0, 0], [255, 0, 0, 255]], + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 255, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint16, 232, True): np.array( + [ + [[0, 255, 0, 255], [255, 255, 0, 0], [255, 255, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0]], + [[0, 0, 255, 0], [255, 255, 0, 0], [255, 0, 0, 255], [0, 0, 0, 0]], + [[0, 0, 255, 0], [0, 255, 0, 255], [0, 0, 255, 255], [0, 255, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint16, 232, False): np.array( + [ + [[0, 255, 0, 255], [0, 255, 255, 0], [0, 255, 255, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0]], + [[255, 0, 0, 0], [0, 255, 255, 0], [0, 0, 255, 255], [0, 0, 0, 0]], + [[255, 0, 0, 0], [0, 255, 0, 255], [255, 0, 0, 255], [0, 255, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint16, 13333, True): np.array( + [ + [[0, 255, 0, 255], [255, 0, 0, 0], [0, 255, 0, 0], [255, 0, 255, 0]], + [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 255, 0], [255, 255, 0, 0], [0, 0, 0, 255], [0, 0, 255, 0]], + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", None, np.uint16, 13333, False): np.array( + [ + [[0, 255, 0, 255], [0, 0, 255, 0], [0, 255, 0, 0], [255, 0, 255, 0]], + [[255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255]], + [[255, 0, 0, 0], [0, 255, 255, 0], [0, 0, 0, 255], [255, 0, 0, 0]], + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGB", None, None, True): Exception, + (np.uint16, "RGBA", "RGB", None, None, False): Exception, + (np.uint16, "RGBA", "RGB", None, 232, True): Exception, + (np.uint16, "RGBA", "RGB", None, 232, False): Exception, + (np.uint16, "RGBA", "RGB", None, 13333, True): Exception, + (np.uint16, "RGBA", "RGB", None, 13333, False): Exception, + (np.uint16, "RGBA", "RGB", np.uint8, None, True): Exception, + (np.uint16, "RGBA", "RGB", np.uint8, None, False): Exception, + (np.uint16, "RGBA", "RGB", np.uint8, 232, True): Exception, + (np.uint16, "RGBA", "RGB", np.uint8, 232, False): Exception, + (np.uint16, "RGBA", "RGB", np.uint8, 13333, True): Exception, + (np.uint16, "RGBA", "RGB", np.uint8, 13333, False): Exception, + (np.uint16, "RGBA", "RGB", np.uint16, None, True): Exception, + (np.uint16, "RGBA", "RGB", np.uint16, None, False): Exception, + (np.uint16, "RGBA", "RGB", np.uint16, 232, True): Exception, + (np.uint16, "RGBA", "RGB", np.uint16, 232, False): Exception, + (np.uint16, "RGBA", "RGB", np.uint16, 13333, True): Exception, + (np.uint16, "RGBA", "RGB", np.uint16, 13333, False): Exception, + (np.uint16, "RGBA", "RGBA", None, None, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[108, 255, 255, 255], [255, 255, 255, 255], [203, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 139, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", None, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 108, 255], [255, 255, 255, 255], [255, 255, 203, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 139, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[98, 255, 255, 255], [255, 255, 255, 255], [184, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 126, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 98, 255], [255, 255, 255, 255], [255, 255, 184, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 126, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint16, 232, True): np.array( + [ + [[255, 255, 255, 0], [255, 0, 255, 0], [0, 0, 255, 0], [0, 0, 255, 0]], + [[0, 0, 255, 0], [255, 0, 255, 0], [0, 255, 0, 0], [255, 0, 255, 0]], + [[0, 255, 0, 0], [255, 0, 0, 0], [0, 255, 0, 0], [255, 255, 255, 0]], + [[0, 0, 255, 0], [0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint16, 232, False): np.array( + [ + [[255, 255, 255, 0], [255, 0, 255, 0], [255, 0, 0, 0], [255, 0, 0, 0]], + [[255, 0, 0, 0], [255, 0, 255, 0], [0, 255, 0, 0], [255, 0, 255, 0]], + [[0, 255, 0, 0], [0, 0, 255, 0], [0, 255, 0, 0], [255, 255, 255, 0]], + [[255, 0, 0, 0], [255, 0, 0, 255], [255, 255, 0, 255], [255, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint16, 13333, True): np.array( + [ + [[255, 255, 0, 0], [255, 0, 0, 0], [0, 255, 0, 0], [0, 255, 0, 0]], + [[0, 255, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [255, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.uint16, "RGBA", "RGBA", np.uint16, 13333, False): np.array( + [ + [[0, 255, 255, 0], [0, 0, 255, 0], [0, 255, 0, 0], [0, 255, 0, 0]], + [[0, 255, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 255, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", None, None, True): np.array( + [ + [[255, 255, 255, 255], [136, 136, 136, 255], [0, 0, 0, 0], [225, 225, 225, 255]], + [[216, 216, 216, 255], [224, 224, 224, 255], [255, 255, 255, 255], [16, 16, 16, 255]], + [[252, 252, 252, 255], [216, 216, 216, 255], [42, 42, 42, 255], [252, 252, 252, 255]], + [[18, 18, 18, 255], [169, 169, 169, 255], [223, 223, 223, 255], [252, 252, 252, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", None, None, False): np.array( + [ + [[255, 255, 255, 255], [136, 136, 136, 255], [0, 0, 0, 0], [225, 225, 225, 255]], + [[216, 216, 216, 255], [224, 224, 224, 255], [255, 255, 255, 255], [16, 16, 16, 255]], + [[252, 252, 252, 255], [216, 216, 216, 255], [42, 42, 42, 255], [252, 252, 252, 255]], + [[18, 18, 18, 255], [169, 169, 169, 255], [223, 223, 223, 255], [252, 252, 252, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [124, 124, 124, 255], [0, 0, 0, 0], [205, 205, 205, 255]], + [[197, 197, 197, 255], [204, 204, 204, 255], [232, 232, 232, 255], [15, 15, 15, 255]], + [[230, 230, 230, 255], [196, 196, 196, 255], [38, 38, 38, 255], [229, 229, 229, 255]], + [[16, 16, 16, 255], [153, 153, 153, 255], [203, 203, 203, 255], [229, 229, 229, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [124, 124, 124, 255], [0, 0, 0, 0], [205, 205, 205, 255]], + [[197, 197, 197, 255], [204, 204, 204, 255], [232, 232, 232, 255], [15, 15, 15, 255]], + [[230, 230, 230, 255], [196, 196, 196, 255], [38, 38, 38, 255], [229, 229, 229, 255]], + [[16, 16, 16, 255], [153, 153, 153, 255], [203, 203, 203, 255], [229, 229, 229, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGB", None, None, True): Exception, + (np.float32, "2D", "RGB", None, None, False): Exception, + (np.float32, "2D", "RGB", None, 232, True): Exception, + (np.float32, "2D", "RGB", None, 232, False): Exception, + (np.float32, "2D", "RGB", None, 13333, True): Exception, + (np.float32, "2D", "RGB", None, 13333, False): Exception, + (np.float32, "2D", "RGB", np.uint8, None, True): Exception, + (np.float32, "2D", "RGB", np.uint8, None, False): Exception, + (np.float32, "2D", "RGB", np.uint8, 232, True): Exception, + (np.float32, "2D", "RGB", np.uint8, 232, False): Exception, + (np.float32, "2D", "RGB", np.uint8, 13333, True): Exception, + (np.float32, "2D", "RGB", np.uint8, 13333, False): Exception, + (np.float32, "2D", "RGB", np.uint16, None, True): Exception, + (np.float32, "2D", "RGB", np.uint16, None, False): Exception, + (np.float32, "2D", "RGB", np.uint16, 232, True): Exception, + (np.float32, "2D", "RGB", np.uint16, 232, False): Exception, + (np.float32, "2D", "RGB", np.uint16, 13333, True): Exception, + (np.float32, "2D", "RGB", np.uint16, 13333, False): Exception, + (np.float32, "2D", "RGBA", None, None, True): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [1, 1, 1, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", None, None, False): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [1, 1, 1, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", None, 232, True): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", None, 232, False): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [52, 52, 52, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [8, 8, 8, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [45, 45, 45, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [52, 52, 52, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [8, 8, 8, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [45, 45, 45, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint16, None, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint16, None, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint16, 232, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint16, 232, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint16, 13333, True): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "2D", "RGBA", np.uint16, 13333, False): np.array( + [ + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", None, None, True): np.array( + [ + [[59, 99, 32, 255], [103, 231, 72, 255], [233, 117, 43, 255], [74, 249, 184, 255]], + [[0, 185, 137, 0], [232, 72, 187, 255], [86, 56, 249, 255], [35, 88, 101, 255]], + [[217, 49, 0, 255], [123, 12, 152, 255], [255, 83, 37, 255], [95, 90, 22, 255]], + [[177, 133, 125, 255], [238, 36, 174, 255], [70, 177, 17, 255], [67, 65, 219, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", None, None, False): np.array( + [ + [[32, 99, 59, 255], [72, 231, 103, 255], [43, 117, 233, 255], [184, 249, 74, 255]], + [[137, 185, 0, 0], [187, 72, 232, 255], [249, 56, 86, 255], [101, 88, 35, 255]], + [[0, 49, 217, 255], [152, 12, 123, 255], [37, 83, 255, 255], [22, 90, 95, 255]], + [[125, 133, 177, 255], [174, 36, 238, 255], [17, 177, 70, 255], [219, 65, 67, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", None, 232, True): np.array( + [ + [[54, 90, 29, 255], [94, 210, 65, 255], [212, 106, 39, 255], [68, 227, 167, 255]], + [[0, 169, 125, 0], [211, 65, 170, 255], [78, 51, 227, 255], [32, 80, 91, 255]], + [[197, 44, 0, 255], [112, 11, 138, 255], [255, 75, 34, 255], [86, 82, 20, 255]], + [[161, 121, 113, 255], [216, 33, 158, 255], [64, 161, 15, 255], [61, 59, 199, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", None, 232, False): np.array( + [ + [[29, 90, 54, 255], [65, 210, 94, 255], [39, 106, 212, 255], [167, 227, 68, 255]], + [[125, 169, 0, 0], [170, 65, 211, 255], [227, 51, 78, 255], [91, 80, 32, 255]], + [[0, 44, 197, 255], [138, 11, 112, 255], [34, 75, 255, 255], [20, 82, 86, 255]], + [[113, 121, 161, 255], [158, 33, 216, 255], [15, 161, 64, 255], [199, 59, 61, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 0, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint8, None, True): np.array( + [ + [[0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[255, 0, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255], [0, 255, 0, 255]], + [[0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint8, None, False): np.array( + [ + [[255, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[0, 0, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 0, 255]], + [[255, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255], [255, 255, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 0, 0, 255]], + [[255, 0, 0, 0], [0, 0, 255, 255], [255, 0, 0, 255], [255, 255, 0, 255]], + [[0, 255, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 0, 255, 255]], + [[0, 0, 255, 0], [255, 0, 0, 255], [0, 0, 255, 255], [0, 255, 255, 255]], + [[255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 255, 255], [255, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 255]], + [[255, 0, 255, 0], [0, 0, 255, 255], [255, 255, 0, 255], [0, 0, 255, 255]], + [[255, 0, 255, 255], [255, 0, 0, 255], [0, 0, 255, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [0, 0, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint16, None, False): np.array( + [ + [[255, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [0, 0, 0, 255]], + [[255, 0, 255, 0], [255, 0, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255]], + [[255, 0, 255, 255], [0, 0, 255, 255], [255, 0, 0, 255], [255, 255, 255, 255]], + [[0, 0, 0, 255], [255, 0, 0, 255], [0, 255, 0, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[255, 255, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[255, 0, 0, 0], [0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255]], + [[0, 0, 255, 255], [0, 0, 255, 255], [0, 255, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 255, 255, 255], [0, 255, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 255, 0], [0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255]], + [[255, 0, 0, 255], [255, 0, 0, 255], [0, 255, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 0, 0, 255]], + [[255, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], + [[0, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 0, 255, 255]], + [[0, 255, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255]], + [[255, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[255, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", None, None, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", None, None, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", None, 232, True): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", None, 232, False): np.array( + [ + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], + [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", None, 13333, True): np.array( + [ + [[12, 0, 0, 255], [21, 0, 0, 255], [47, 0, 0, 255], [15, 0, 0, 255]], + [[0, 0, 0, 0], [47, 0, 0, 255], [17, 0, 0, 255], [7, 0, 0, 255]], + [[44, 0, 0, 255], [25, 0, 0, 255], [255, 0, 0, 255], [19, 0, 0, 255]], + [[36, 0, 0, 255], [48, 0, 0, 255], [14, 0, 0, 255], [13, 0, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", None, 13333, False): np.array( + [ + [[0, 0, 12, 255], [0, 0, 21, 255], [0, 0, 47, 255], [0, 0, 15, 255]], + [[0, 0, 0, 0], [0, 0, 47, 255], [0, 0, 17, 255], [0, 0, 7, 255]], + [[0, 0, 44, 255], [0, 0, 25, 255], [0, 0, 255, 255], [0, 0, 19, 255]], + [[0, 0, 36, 255], [0, 0, 48, 255], [0, 0, 14, 255], [0, 0, 13, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint16, None, True): np.array( + [ + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint16, None, False): np.array( + [ + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint16, 232, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint16, 232, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint16, 13333, True): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGB", np.uint16, 13333, False): np.array( + [ + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGB", "RGBA", None, None, True): Exception, + (np.float32, "RGB", "RGBA", None, None, False): Exception, + (np.float32, "RGB", "RGBA", None, 232, True): Exception, + (np.float32, "RGB", "RGBA", None, 232, False): Exception, + (np.float32, "RGB", "RGBA", None, 13333, True): Exception, + (np.float32, "RGB", "RGBA", None, 13333, False): Exception, + (np.float32, "RGB", "RGBA", np.uint8, None, True): Exception, + (np.float32, "RGB", "RGBA", np.uint8, None, False): Exception, + (np.float32, "RGB", "RGBA", np.uint8, 232, True): Exception, + (np.float32, "RGB", "RGBA", np.uint8, 232, False): Exception, + (np.float32, "RGB", "RGBA", np.uint8, 13333, True): Exception, + (np.float32, "RGB", "RGBA", np.uint8, 13333, False): Exception, + (np.float32, "RGB", "RGBA", np.uint16, None, True): Exception, + (np.float32, "RGB", "RGBA", np.uint16, None, False): Exception, + (np.float32, "RGB", "RGBA", np.uint16, 232, True): Exception, + (np.float32, "RGB", "RGBA", np.uint16, 232, False): Exception, + (np.float32, "RGB", "RGBA", np.uint16, 13333, True): Exception, + (np.float32, "RGB", "RGBA", np.uint16, 13333, False): Exception, + (np.float32, "RGBA", "SIMPLE", None, None, True): np.array( + [ + [[248, 159, 5, 0], [217, 237, 151, 255], [102, 203, 57, 44], [244, 177, 73, 196]], + [[29, 189, 17, 250], [168, 188, 84, 208], [198, 134, 144, 81], [208, 209, 210, 126]], + [[8, 212, 80, 241], [159, 153, 128, 236], [0, 0, 7, 0], [249, 140, 61, 88]], + [[175, 255, 216, 90], [42, 76, 23, 172], [64, 65, 205, 254], [0, 255, 148, 117]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", None, None, False): np.array( + [ + [[5, 159, 248, 0], [151, 237, 217, 255], [57, 203, 102, 44], [73, 177, 244, 196]], + [[17, 189, 29, 250], [84, 188, 168, 208], [144, 134, 198, 81], [210, 209, 208, 126]], + [[80, 212, 8, 241], [128, 153, 159, 236], [7, 0, 0, 0], [61, 140, 249, 88]], + [[216, 255, 175, 90], [23, 76, 42, 172], [205, 65, 64, 254], [148, 255, 0, 117]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", None, 232, True): np.array( + [ + [[225, 145, 5, 0], [197, 215, 138, 255], [93, 185, 51, 40], [222, 161, 66, 178]], + [[26, 172, 15, 227], [153, 171, 76, 189], [181, 122, 131, 73], [189, 190, 191, 114]], + [[7, 193, 73, 219], [144, 139, 116, 215], [0, 0, 6, 0], [227, 127, 55, 80]], + [[159, 255, 197, 82], [38, 69, 21, 157], [58, 59, 186, 231], [0, 232, 134, 107]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", None, 232, False): np.array( + [ + [[5, 145, 225, 0], [138, 215, 197, 255], [51, 185, 93, 40], [66, 161, 222, 178]], + [[15, 172, 26, 227], [76, 171, 153, 189], [131, 122, 181, 73], [191, 190, 189, 114]], + [[73, 193, 7, 219], [116, 139, 144, 215], [6, 0, 0, 0], [55, 127, 227, 80]], + [[197, 255, 159, 82], [21, 69, 38, 157], [186, 59, 58, 231], [134, 232, 0, 107]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", None, 13333, True): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", None, 13333, False): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 0, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint8, None, True): np.array( + [ + [[255, 0, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 0, 255, 255]], + [[255, 255, 255, 0], [0, 0, 255, 255], [255, 255, 0, 0], [0, 255, 0, 255]], + [[0, 255, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255], [255, 255, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint8, None, False): np.array( + [ + [[0, 0, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255]], + [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 0, 255, 255]], + [[255, 255, 255, 0], [255, 0, 0, 255], [0, 255, 255, 0], [0, 255, 0, 255]], + [[255, 255, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255], [255, 255, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint8, 232, True): np.array( + [ + [[0, 0, 0, 0], [0, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[255, 255, 0, 0], [0, 0, 255, 0], [0, 255, 0, 0], [0, 255, 0, 255]], + [[0, 0, 0, 0], [255, 0, 255, 0], [255, 255, 255, 0], [0, 0, 0, 255]], + [[0, 255, 0, 255], [255, 0, 0, 0], [255, 0, 255, 0], [255, 255, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint8, 232, False): np.array( + [ + [[0, 0, 0, 0], [255, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], + [[0, 255, 255, 0], [255, 0, 0, 0], [0, 255, 0, 0], [0, 255, 0, 255]], + [[0, 0, 0, 0], [255, 0, 255, 0], [255, 255, 255, 0], [0, 0, 0, 255]], + [[0, 255, 0, 255], [0, 0, 255, 0], [255, 0, 255, 0], [255, 255, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint8, 13333, True): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint8, 13333, False): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint16, None, True): np.array( + [ + [[0, 0, 255, 0], [0, 255, 255, 0], [255, 255, 0, 255], [0, 0, 0, 255]], + [[0, 255, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255], [255, 0, 0, 255]], + [[0, 0, 255, 0], [255, 0, 0, 0], [255, 255, 255, 0], [0, 255, 255, 0]], + [[255, 0, 255, 0], [255, 0, 0, 255], [255, 0, 0, 0], [255, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint16, None, False): np.array( + [ + [[255, 0, 0, 0], [255, 255, 0, 0], [0, 255, 255, 255], [0, 0, 0, 255]], + [[0, 255, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255], [0, 0, 255, 255]], + [[255, 0, 0, 0], [0, 0, 255, 0], [255, 255, 255, 0], [255, 255, 0, 0]], + [[255, 0, 255, 0], [0, 0, 255, 255], [0, 0, 255, 0], [0, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint16, 232, True): np.array( + [ + [[255, 0, 0, 0], [0, 0, 255, 0], [255, 0, 255, 0], [255, 0, 255, 0]], + [[0, 0, 255, 0], [255, 255, 0, 255], [0, 0, 0, 0], [255, 0, 0, 255]], + [[0, 0, 0, 255], [255, 0, 0, 0], [255, 255, 255, 0], [0, 0, 0, 0]], + [[255, 0, 0, 0], [0, 255, 255, 0], [0, 0, 255, 255], [255, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint16, 232, False): np.array( + [ + [[0, 0, 255, 0], [255, 0, 0, 0], [255, 0, 255, 0], [255, 0, 255, 0]], + [[255, 0, 0, 0], [0, 255, 255, 255], [0, 0, 0, 0], [0, 0, 255, 255]], + [[0, 0, 0, 255], [0, 0, 255, 0], [255, 255, 255, 0], [0, 0, 0, 0]], + [[0, 0, 255, 0], [255, 255, 0, 0], [255, 0, 0, 255], [0, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint16, 13333, True): np.array( + [ + [[255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 255, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 255, 255]], + [[0, 0, 0, 0], [0, 0, 255, 255], [255, 255, 0, 0], [255, 255, 0, 0]], + [[255, 0, 0, 0], [0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "SIMPLE", np.uint16, 13333, False): np.array( + [ + [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 255], [255, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0], [255, 0, 0, 255]], + [[0, 0, 0, 0], [255, 0, 0, 255], [0, 255, 255, 0], [0, 255, 255, 0]], + [[0, 0, 255, 0], [0, 255, 0, 0], [0, 0, 0, 255], [0, 0, 255, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGB", None, None, True): Exception, + (np.float32, "RGBA", "RGB", None, None, False): Exception, + (np.float32, "RGBA", "RGB", None, 232, True): Exception, + (np.float32, "RGBA", "RGB", None, 232, False): Exception, + (np.float32, "RGBA", "RGB", None, 13333, True): Exception, + (np.float32, "RGBA", "RGB", None, 13333, False): Exception, + (np.float32, "RGBA", "RGB", np.uint8, None, True): Exception, + (np.float32, "RGBA", "RGB", np.uint8, None, False): Exception, + (np.float32, "RGBA", "RGB", np.uint8, 232, True): Exception, + (np.float32, "RGBA", "RGB", np.uint8, 232, False): Exception, + (np.float32, "RGBA", "RGB", np.uint8, 13333, True): Exception, + (np.float32, "RGBA", "RGB", np.uint8, 13333, False): Exception, + (np.float32, "RGBA", "RGB", np.uint16, None, True): Exception, + (np.float32, "RGBA", "RGB", np.uint16, None, False): Exception, + (np.float32, "RGBA", "RGB", np.uint16, 232, True): Exception, + (np.float32, "RGBA", "RGB", np.uint16, 232, False): Exception, + (np.float32, "RGBA", "RGB", np.uint16, 13333, True): Exception, + (np.float32, "RGBA", "RGB", np.uint16, 13333, False): Exception, + (np.float32, "RGBA", "RGBA", None, None, True): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", None, None, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", None, 232, True): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", None, 232, False): np.array( + [ + [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", None, 13333, True): np.array( + [ + [[0, 0, 1, 0], [0, 0, 31, 255], [0, 0, 11, 0], [0, 0, 15, 0]], + [[0, 0, 3, 0], [0, 0, 17, 0], [0, 0, 29, 0], [0, 0, 43, 0]], + [[0, 0, 16, 0], [0, 0, 26, 0], [0, 0, 1, 0], [0, 0, 12, 0]], + [[0, 255, 44, 0], [0, 0, 4, 0], [0, 0, 42, 0], [0, 0, 30, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", None, 13333, False): np.array( + [ + [[1, 0, 0, 0], [31, 0, 0, 255], [11, 0, 0, 0], [15, 0, 0, 0]], + [[3, 0, 0, 0], [17, 0, 0, 0], [29, 0, 0, 0], [43, 0, 0, 0]], + [[16, 0, 0, 0], [26, 0, 0, 0], [1, 0, 0, 0], [12, 0, 0, 0]], + [[44, 255, 0, 0], [4, 0, 0, 0], [42, 0, 0, 0], [30, 0, 0, 0]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint8, None, True): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint8, None, False): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint8, 232, True): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint8, 232, False): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint8, 13333, True): np.array( + [ + [[255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint8, 13333, False): np.array( + [ + [[0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 0], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint16, None, True): np.array( + [ + [[255, 255, 0, 0], [255, 255, 0, 0], [255, 255, 255, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 0], [255, 255, 0, 255]], + [[255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint16, None, False): np.array( + [ + [[0, 255, 255, 0], [0, 255, 255, 0], [255, 255, 255, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 0], [0, 255, 255, 255]], + [[0, 0, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint16, 232, True): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint16, 232, False): np.array( + [ + [[255, 255, 255, 0], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], + [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint16, 13333, True): np.array( + [ + [[255, 255, 0, 0], [255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], + [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 0], [255, 255, 255, 255]], + [[255, 0, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), + (np.float32, "RGBA", "RGBA", np.uint16, 13333, False): np.array( + [ + [[0, 255, 255, 0], [0, 255, 255, 0], [0, 255, 255, 255], [255, 255, 255, 255]], + [[255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], + [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 0], [255, 255, 255, 255]], + [[0, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], + ], + dtype=np.uint8, + ), +} + + +def _makeARGB(*args, **kwds): + img, alpha = makeARGB(*args, **kwds) + if kwds.get('useRGBA'): # endian independent + out = img + elif sys.byteorder == 'little': # little-endian ARGB32 to B,G,R,A + out = img + else: # big-endian ARGB32 to B,G,R,A + out = img[..., [3, 2, 1, 0]] + return out, alpha + + +def _do_something_for_every_combo(func): + for dtype in [np.uint8, np.uint16, np.float32]: + for in_fmt in ["2D", "RGB", "RGBA"]: + data = INPUTS[(dtype, in_fmt)] + for levels_name in [None, "SIMPLE", "RGB", "RGBA"]: + levels = LEVELS.get(levels_name, None) + if dtype == np.float32 and levels_name is None: + continue + for lut_type in [None, np.uint8, np.uint16]: + lut = LUTS.get(lut_type, None) + for scale in [None, 232, 13333]: + for use_rgba in [True, False]: + key = (dtype, in_fmt, levels_name, lut_type, scale, use_rgba) + func(data, key, levels, lut, scale, use_rgba) + + +def save_reference(): + """ + This saves the output (or exception type) of running makeARGB for every combo of arguments. The + output isn't fit for immediate inclusion in this file as EXPECTED_OUTPUTS, and needs some replace-all + work. + """ + with open("_unformatted_expected_outputs_", "w") as tmp_file: + + def write_expectation_to_file(data, key, levels, lut, scale, use_rgba): + try: + output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) + except Exception as e: + tmp_file.write(f"{key!r}: {type(e)}\n") + else: + tmp_file.write(f"{key!r}: {output!r},\n") + + _do_something_for_every_combo(write_expectation_to_file) diff --git a/tests/parametertree/test_Parameter.py b/tests/parametertree/test_Parameter.py index 4ede448cdc..309a93c0e2 100644 --- a/tests/parametertree/test_Parameter.py +++ b/tests/parametertree/test_Parameter.py @@ -1,17 +1,17 @@ from functools import wraps import numpy as np -import pyqtgraph as pg import pytest +import pyqtgraph as pg from pyqtgraph import functions as fn from pyqtgraph.parametertree import ( InteractiveFunction, Interactor, - interact, + Parameter, RunOptions, + interact, ) -from pyqtgraph.parametertree import Parameter from pyqtgraph.parametertree.Parameter import PARAM_TYPES from pyqtgraph.parametertree.parameterTypes import GroupParameter as GP from pyqtgraph.Qt import QtGui @@ -19,25 +19,93 @@ pg.mkQApp() def test_parameter_hasdefault(): - opts = {"name": "param", "type": int, "value": 1} + opts = {"name": "param", "type": 'int', "value": 1} # default unspecified - p = Parameter(**opts) + p = Parameter.create(**opts) + # TODO after January 2025, this next line needs to reverse its assertion assert p.hasDefault() - assert p.defaultValue() == opts["value"] - - p.setDefault(2) - assert p.hasDefault() - assert p.defaultValue() == 2 # default specified - p = Parameter(default=0, **opts) + p = Parameter.create(default=0, **opts) assert p.hasDefault() assert p.defaultValue() == 0 # default specified as None - p = Parameter(default=None, **opts) + p = Parameter.create(default=None, **opts) assert not p.hasDefault() + p.setDefault(2) + assert p.hasDefault() + assert p.defaultValue() == 2 + + +def test_parameter_defaults_and_pristineness(): + # init with identical value and default + p = Parameter.create(name="param", type='int', value=1, default=1) + assert p.valueModifiedSinceResetToDefault() is True + # init with different value and default + p = Parameter.create(name="param", type='int', value=1, default=2) + assert p.valueModifiedSinceResetToDefault() is True + # init with value only + p = Parameter.create(name="param", type='int', value=1) + assert p.valueModifiedSinceResetToDefault() is True + # TODO after January 2025, uncomment the following lines + # with pytest.raises(ValueError): + # p.setToDefault() + # init with default only + p = Parameter.create(name="param", type='int', default=1) + assert p.valueModifiedSinceResetToDefault() is False + + # initially value is pristine since only a default was given + assert p.value() == 1 + # update default, and allow the value to track since it is pristine + p.setDefault(2, updatePristineValues=True) + assert p.value() == 2 + assert p.valueModifiedSinceResetToDefault() is False + # update default but do not allow the value to track + p.setDefault(3) # by default, updatePristineValues=False + assert p.value() == 2 + assert p.valueModifiedSinceResetToDefault() is True + # update default again, explicitly requesting updatePristineValues=False + p.setToDefault() + assert p.valueModifiedSinceResetToDefault() is False + p.setDefault(4, updatePristineValues=False) + assert p.value() == 3 + assert p.valueModifiedSinceResetToDefault() is True + # update value directly, causing dirty state + p.setToDefault() + assert p.valueModifiedSinceResetToDefault() is False + p.setValue(5) + assert p.valueModifiedSinceResetToDefault() is True + p.setDefault(6, updatePristineValues=True) + assert p.value() == 5 + assert p.valueModifiedSinceResetToDefault() is True + # test setting value to same as default value does not result in pristine state + p.setToDefault() + assert p.valueModifiedSinceResetToDefault() is False + p.setValue(0) + p.setValue(p.defaultValue()) + assert p.valueModifiedSinceResetToDefault() is True + # test setToDefault + p.setToDefault() + assert p.valueModifiedSinceResetToDefault() is False + assert p.value() == p.defaultValue() + p.setDefault(7, updatePristineValues=True) + assert p.value() == 7 + + # init with neither value nor default + p = Parameter.create(name="param", type='int') + assert p.valueModifiedSinceResetToDefault() is False + # TODO after January 2025, uncomment the following lines + # with pytest.raises(ValueError): + # p.value() + # with pytest.raises(ValueError): + # p.defaultValue() + # with pytest.raises(ValueError): + # p.setToDefault() + p.setDefault(8) + assert p.valueModifiedSinceResetToDefault() is False + assert p.value() == 8 def test_add_child(): diff --git a/tests/parametertree/test_parametertypes.py b/tests/parametertree/test_parametertypes.py index 382ac2e913..975ea50e4d 100644 --- a/tests/parametertree/test_parametertypes.py +++ b/tests/parametertree/test_parametertypes.py @@ -8,16 +8,25 @@ from pyqtgraph.parametertree.parameterTypes import ChecklistParameterItem from pyqtgraph.Qt import QtCore, QtGui +import pytest + app = pg.mkQApp() + def _getWidget(param): return list(param.items.keys())[0].widget +def test_typeless_param(): + p = pt.Parameter.create(name='test', type=None, value=set()) + p.setValue(range(4)) + + def test_opts(): paramSpec = [ dict(name='bool', type='bool', readonly=True), dict(name='color', type='color', readonly=True), + dict(name='float', type='float', limits=None), ] param = pt.Parameter.create(name='params', type='group', children=paramSpec) @@ -93,14 +102,14 @@ def check_param_types(param, types, map_func, init, objs, keys): param.setValue(). keys : list The list of keys indicating the valid objects in *objs*. When - param.setValue() is teasted with each value from *objs*, we expect + param.setValue() is tested with each value from *objs*, we expect an exception to be raised if the associated key is not in *keys*. """ val = param.value() if not isinstance(types, tuple): types = (types,) assert val == init and type(val) in types - + # test valid input types good_inputs = [objs[k] for k in keys if k in objs] good_outputs = map(map_func, good_inputs) @@ -110,7 +119,7 @@ def check_param_types(param, types, map_func, init, objs, keys): if not (eq(val, y) and type(val) in types): raise Exception("Setting parameter %s with value %r should have resulted in %r (types: %r), " "but resulted in %r (type: %r) instead." % (param, x, y, types, val, type(val))) - + # test invalid input types for k,v in objs.items(): if k in keys: @@ -120,12 +129,22 @@ def check_param_types(param, types, map_func, init, objs, keys): except (TypeError, ValueError, OverflowError): continue except Exception as exc: - raise Exception("Setting %s parameter value to %r raised %r." % (param, v, exc)) - + raise Exception( + "Setting %s parameter value to %r raised %r." % (param, v, exc) + ) from exc + raise Exception("Setting %s parameter value to %r should have raised an exception." % (param, v)) - -def test_limits_enforcement(): + +@pytest.mark.parametrize("k,v_in,v_out",[ + ('float', -1, 0), + ('float', 2, 1), + ('int', -1, 0), + ('int', 2, 1), + ('list', 'w', 'x'), + ('dict', 'w', 1) +]) +def test_limits_enforcement(k, v_in, v_out): p = pt.Parameter.create(name='params', type='group', children=[ dict(name='float', type='float', limits=[0, 1]), dict(name='int', type='int', bounds=[0, 1]), @@ -134,14 +153,8 @@ def test_limits_enforcement(): ]) t = pt.ParameterTree() t.setParameters(p) - for k, vin, vout in [('float', -1, 0), - ('float', 2, 1), - ('int', -1, 0), - ('int', 2, 1), - ('list', 'w', 'x'), - ('dict', 'w', 1)]: - p[k] = vin - assert p[k] == vout + p[k] = v_in + assert p[k] == v_out def test_data_race(): @@ -188,7 +201,6 @@ def test_pen_settings(): p["width"] = 10 assert p.pen.width() == 10 - def test_recreate_from_savestate(): from pyqtgraph.examples import _buildParamTypes created = _buildParamTypes.makeAllParamTypes() diff --git a/tests/graphicsItems/test_ImageItemFormat.py b/tests/test_ImageFormat.py similarity index 60% rename from tests/graphicsItems/test_ImageItemFormat.py rename to tests/test_ImageFormat.py index 059e25083a..3f9436d078 100644 --- a/tests/graphicsItems/test_ImageItemFormat.py +++ b/tests/test_ImageFormat.py @@ -4,12 +4,13 @@ from pyqtgraph.Qt import QtGui -def check_format(shape, dtype, levels, lut, expected_format): +rng = np.random.default_rng() + + +def check_format(shape, dtype, levels, lut, expected_format, *, transparentLocations=None): data = np.zeros(shape, dtype=dtype) - item = pg.ImageItem(axisOrder='row-major') - item.setImage(data, autoLevels=False, lut=lut, levels=levels) - item.render() - assert item.qimage.format() == expected_format + qimage = pg.functions_qimage.try_make_qimage(data, levels=levels, lut=lut, transparentLocations=transparentLocations) + assert qimage is not None and qimage.format() == expected_format def test_uint8(): @@ -18,22 +19,22 @@ def test_uint8(): w, h = 192, 108 lo, hi = 50, 200 lut_none = None - lut_mono1 = np.random.randint(256, size=256, dtype=np.uint8) - lut_mono2 = np.random.randint(256, size=(256, 1), dtype=np.uint8) - lut_rgb = np.random.randint(256, size=(256, 3), dtype=np.uint8) - lut_rgba = np.random.randint(256, size=(256, 4), dtype=np.uint8) + lut_mono1 = rng.integers(256, size=256, dtype=np.uint8) + lut_mono2 = rng.integers(256, size=(256, 1), dtype=np.uint8) + lut_rgb = rng.integers(256, size=(256, 3), dtype=np.uint8) + lut_rgba = rng.integers(256, size=(256, 4), dtype=np.uint8) # lut with less than 256 entries - lut_mono1_s = np.random.randint(256, size=255, dtype=np.uint8) - lut_mono2_s = np.random.randint(256, size=(255, 1), dtype=np.uint8) - lut_rgb_s = np.random.randint(256, size=(255, 3), dtype=np.uint8) - lut_rgba_s = np.random.randint(256, size=(255, 4), dtype=np.uint8) + lut_mono1_s = rng.integers(256, size=255, dtype=np.uint8) + lut_mono2_s = rng.integers(256, size=(255, 1), dtype=np.uint8) + lut_rgb_s = rng.integers(256, size=(255, 3), dtype=np.uint8) + lut_rgba_s = rng.integers(256, size=(255, 4), dtype=np.uint8) # lut with more than 256 entries - lut_mono1_l = np.random.randint(256, size=257, dtype=np.uint8) - lut_mono2_l = np.random.randint(256, size=(257, 1), dtype=np.uint8) - lut_rgb_l = np.random.randint(256, size=(257, 3), dtype=np.uint8) - lut_rgba_l = np.random.randint(256, size=(257, 4), dtype=np.uint8) + lut_mono1_l = rng.integers(256, size=257, dtype=np.uint8) + lut_mono2_l = rng.integers(256, size=(257, 1), dtype=np.uint8) + lut_rgb_l = rng.integers(256, size=(257, 3), dtype=np.uint8) + lut_rgba_l = rng.integers(256, size=(257, 4), dtype=np.uint8) levels = None check_format((h, w), dtype, levels, lut_none, Format.Format_Grayscale8) @@ -74,29 +75,25 @@ def test_uint16(): lo, hi = 100, 10000 lut_none = None - lut_mono1 = np.random.randint(256, size=256, dtype=np.uint8) - lut_mono2 = np.random.randint(256, size=(256, 1), dtype=np.uint8) - lut_rgb = np.random.randint(256, size=(256, 3), dtype=np.uint8) - lut_rgba = np.random.randint(256, size=(256, 4), dtype=np.uint8) + lut_mono1 = rng.integers(256, size=256, dtype=np.uint8) + lut_mono2 = rng.integers(256, size=(256, 1), dtype=np.uint8) + lut_rgb = rng.integers(256, size=(256, 3), dtype=np.uint8) + lut_rgba = rng.integers(256, size=(256, 4), dtype=np.uint8) # lut with less than 256 entries - lut_mono1_s = np.random.randint(256, size=255, dtype=np.uint8) - lut_mono2_s = np.random.randint(256, size=(255, 1), dtype=np.uint8) - lut_rgb_s = np.random.randint(256, size=(255, 3), dtype=np.uint8) - lut_rgba_s = np.random.randint(256, size=(255, 4), dtype=np.uint8) + lut_mono1_s = rng.integers(256, size=255, dtype=np.uint8) + lut_mono2_s = rng.integers(256, size=(255, 1), dtype=np.uint8) + lut_rgb_s = rng.integers(256, size=(255, 3), dtype=np.uint8) + lut_rgba_s = rng.integers(256, size=(255, 4), dtype=np.uint8) # lut with more than 256 entries - lut_mono1_l = np.random.randint(256, size=257, dtype=np.uint8) - lut_mono2_l = np.random.randint(256, size=(257, 1), dtype=np.uint8) - lut_rgb_l = np.random.randint(256, size=(257, 3), dtype=np.uint8) - lut_rgba_l = np.random.randint(256, size=(257, 4), dtype=np.uint8) + lut_mono1_l = rng.integers(256, size=257, dtype=np.uint8) + lut_mono2_l = rng.integers(256, size=(257, 1), dtype=np.uint8) + lut_rgb_l = rng.integers(256, size=(257, 3), dtype=np.uint8) + lut_rgba_l = rng.integers(256, size=(257, 4), dtype=np.uint8) levels = None - try: - fmt_gray16 = Format.Format_Grayscale16 - except AttributeError: - fmt_gray16 = Format.Format_ARGB32 - check_format((h, w), dtype, levels, lut_none, fmt_gray16) + check_format((h, w), dtype, levels, lut_none, Format.Format_Grayscale16) check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888) check_format((h, w, 4), dtype, levels, lut_none, Format.Format_RGBA64) @@ -129,28 +126,27 @@ def test_float32(): lo, hi = -1, 1 lut_none = None - lut_mono1 = np.random.randint(256, size=256, dtype=np.uint8) - lut_mono2 = np.random.randint(256, size=(256, 1), dtype=np.uint8) - lut_rgb = np.random.randint(256, size=(256, 3), dtype=np.uint8) - lut_rgba = np.random.randint(256, size=(256, 4), dtype=np.uint8) + lut_mono1 = rng.integers(256, size=256, dtype=np.uint8) + lut_mono2 = rng.integers(256, size=(256, 1), dtype=np.uint8) + lut_rgb = rng.integers(256, size=(256, 3), dtype=np.uint8) + lut_rgba = rng.integers(256, size=(256, 4), dtype=np.uint8) # lut with less than 256 entries - lut_mono1_s = np.random.randint(256, size=255, dtype=np.uint8) - lut_mono2_s = np.random.randint(256, size=(255, 1), dtype=np.uint8) - lut_rgb_s = np.random.randint(256, size=(255, 3), dtype=np.uint8) - lut_rgba_s = np.random.randint(256, size=(255, 4), dtype=np.uint8) + lut_mono1_s = rng.integers(256, size=255, dtype=np.uint8) + lut_mono2_s = rng.integers(256, size=(255, 1), dtype=np.uint8) + lut_rgb_s = rng.integers(256, size=(255, 3), dtype=np.uint8) + lut_rgba_s = rng.integers(256, size=(255, 4), dtype=np.uint8) # lut with more than 256 entries - lut_mono1_l = np.random.randint(256, size=257, dtype=np.uint8) - lut_mono2_l = np.random.randint(256, size=(257, 1), dtype=np.uint8) - lut_rgb_l = np.random.randint(256, size=(257, 3), dtype=np.uint8) - lut_rgba_l = np.random.randint(256, size=(257, 4), dtype=np.uint8) + lut_mono1_l = rng.integers(256, size=257, dtype=np.uint8) + lut_mono2_l = rng.integers(256, size=(257, 1), dtype=np.uint8) + lut_rgb_l = rng.integers(256, size=(257, 3), dtype=np.uint8) + lut_rgba_l = rng.integers(256, size=(257, 4), dtype=np.uint8) levels = [lo, hi] check_format((h, w), dtype, levels, lut_none, Format.Format_Grayscale8) check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGB888) - check_format((h, w, 4), dtype, levels, lut_none, Format.Format_RGBA8888) check_format((h, w), dtype, levels, lut_mono1, Format.Format_Indexed8) check_format((h, w), dtype, levels, lut_mono2, Format.Format_Indexed8) @@ -166,3 +162,17 @@ def test_float32(): check_format((h, w), dtype, levels, lut_mono2_l, Format.Format_Grayscale8) check_format((h, w), dtype, levels, lut_rgb_l, Format.Format_RGBX8888) check_format((h, w), dtype, levels, lut_rgba_l, Format.Format_RGBA8888) + + all_lut_types = [ + lut_none, + lut_mono1, lut_mono2, lut_rgb, lut_rgba, + lut_mono1_s, lut_mono2_s, lut_rgb_s, lut_rgba_s, + lut_mono1_l, lut_mono2_l, lut_rgb_l, lut_rgba_l, + ] + + center = (np.array([h//2]), np.array([w//2])) + + for lut in all_lut_types: + check_format((h, w), dtype, levels, lut, Format.Format_RGBA8888, transparentLocations=center) + + check_format((h, w, 3), dtype, levels, lut_none, Format.Format_RGBA8888, transparentLocations=center) diff --git a/tests/test_canvas_manager_crash.py b/tests/test_canvas_manager_crash.py new file mode 100644 index 0000000000..880d217f4a --- /dev/null +++ b/tests/test_canvas_manager_crash.py @@ -0,0 +1,8 @@ +import subprocess +import sys + + +def test_canvas_manager_singleton_crash() -> None: + """Regression test for #2838.""" + proc = subprocess.run([sys.executable, "-c", "import pyqtgraph.canvas"]) + assert proc.returncode == 0 diff --git a/tests/test_colormap.py b/tests/test_colormap.py index 16372ca6f5..4dcddafccb 100644 --- a/tests/test_colormap.py +++ b/tests/test_colormap.py @@ -1,5 +1,6 @@ import pytest +import numpy as np import pyqtgraph as pg from pyqtgraph.Qt import QtGui @@ -79,3 +80,15 @@ def test_ColorMap_getByIndex(): cm = pg.ColorMap([0.0, 1.0], [(0,0,0), (255,0,0)]) assert cm.getByIndex(0) == QtGui.QColor.fromRgbF(0.0, 0.0, 0.0, 1.0) assert cm.getByIndex(1) == QtGui.QColor.fromRgbF(1.0, 0.0, 0.0, 1.0) + +def test_round_trip(): + # test that colormap survives a round trip. + # note that while both input and output are in BYTE, + # internally the colors are stored as float; thus + # there is a conversion BYTE -> float -> BYTE + nPts = 256 + zebra = np.zeros((nPts, 3), dtype=np.uint8) + zebra[1::2, :] = 255 + cmap = pg.ColorMap(None, zebra) + lut = cmap.getLookupTable(nPts=nPts) + assert np.all(lut == zebra) diff --git a/tests/test_functions.py b/tests/test_functions.py index 426d757348..0ada2890ce 100644 --- a/tests/test_functions.py +++ b/tests/test_functions.py @@ -6,8 +6,8 @@ from numpy.testing import assert_array_almost_equal import pyqtgraph as pg -from pyqtgraph.functions import arrayToQPath, eq -from pyqtgraph.Qt import QtGui +from pyqtgraph.functions import arrayToQPath, eq, SignalBlock +from pyqtgraph.Qt import QtCore, QtGui np.random.seed(12345) @@ -159,7 +159,7 @@ def __eq__(self, x): return False noteq = NotEq() - assert eq(noteq, noteq) # passes because they are the same object + assert eq(noteq, noteq) # passes because they are the same object assert not eq(noteq, NotEq()) @@ -278,12 +278,20 @@ def test_CIELab_reconversion(): def _handle_underflow(dtype, *elements): """Wrapper around path description which converts underflow into proper points""" out = [] + dtype = np.dtype(dtype) + # get the signed integer type of the same width + dtype_int = np.dtype(f'i{dtype.itemsize}') for el in elements: newElement = [el[0]] for ii in range(1, 3): coord = el[ii] - if coord < 0: - coord = np.array(coord, dtype=dtype) + if dtype.kind == 'u' and coord < 0: + # coord is a float with a negative integral value. + # for unsigned integer types, we want negative values to + # wrap-around. to get consistent wrap-around behavior + # across different numpy versions and machine platforms, + # we first convert coord to a signed integer. + coord = np.array(coord, dtype=dtype_int).astype(dtype) newElement.append(float(coord)) out.append(tuple(newElement)) return out @@ -330,7 +338,7 @@ def _handle_underflow(dtype, *elements): ), # NaN types don't coerce to integers, don't test for all types since that doesn't make sense ( - np.arange(5), np.array([0, -1, np.NaN, -3, -4]), 'finite', ( + np.arange(5), np.array([0, -1, np.nan, -3, -4]), 'finite', ( (MoveToElement, 0.0, 0.0), (LineToElement, 1.0, -1.0), (LineToElement, 1.0, -1.0), @@ -339,7 +347,7 @@ def _handle_underflow(dtype, *elements): ) ), ( - np.array([0, 1, np.NaN, 3, 4]), np.arange(0, -5, step=-1), 'finite', ( + np.array([0, 1, np.nan, 3, 4]), np.arange(0, -5, step=-1), 'finite', ( (MoveToElement, 0.0, 0.0), (LineToElement, 1.0, -1.0), (LineToElement, 1.0, -1.0), @@ -409,3 +417,65 @@ def test_ndarray_from_qimage(): def test_colorDistance(): pg.colorDistance([pg.Qt.QtGui.QColor(0,0,0), pg.Qt.QtGui.QColor(255,0,0)]) pg.colorDistance([]) + + +@pytest.mark.parametrize( + "test_input,expected", + [ + (["r"], [255, 0, 0, 255]), + (["g"], [0, 255, 0, 255]), + (["b"], [0, 0, 255, 255]), + (["c"], [0, 255, 255, 255]), + (["m"], [255, 0, 255, 255]), + (["y"], [255, 255, 0, 255]), + (["k"], [0, 0, 0, 255]), + (["w"], [255, 255, 255, 255]), + (["d"], [150, 150, 150, 255]), + (["l"], [200, 200, 200, 255]), + (["s"], [100, 100, 150, 255]), + ([0.75], [191, 191, 191, 255]), + ([11, 22, 33], [11, 22, 33, 255]), + ([11, 22, 33, 44], [11, 22, 33, 44]), + ([(11, 22, 33)], [11, 22, 33, 255]), + ([(11, 22, 33, 44)], [11, 22, 33, 44]), + ([0], [255, 0, 0, 255]), + ([1], [255, 170, 0, 255]), + ([2], [170, 255, 0, 255]), + ([3], [0, 255, 0, 255]), + ([4], [0, 255, 170, 255]), + ([5], [0, 170, 255, 255]), + ([9], [255, 0, 0, 255]), + ([(0, 2)], [255, 0, 0, 255]), + ([(1, 2)], [0, 255, 255, 255]), + ([(2, 2)], [255, 0, 0, 255]), + (["#89a"], [136, 153, 170, 255]), + (["#89ab"], [136, 153, 170, 187]), + (["#4488cc"], [68, 136, 204, 255]), + (["#4488cc00"], [68, 136, 204, 0]), + ([QtGui.QColor(1, 2, 3, 4)], [1, 2, 3, 4]), + (["steelblue"], [70, 130, 180, 255]), + (["lawngreen"], [124, 252, 0, 255]), + ], +) +def test_mkColor(test_input, expected): + qcol: QtGui.QColor = pg.functions.mkColor(*test_input) + assert list(qcol.getRgb()) == expected + +def test_signal_block_unconnected(): + """Test that SignalBlock does not end up connecting an unconnected slot""" + class Sender(QtCore.QObject): + signal = QtCore.Signal() + + class Receiver: + def __init__(self): + self.counter = 0 + + def slot(self): + self.counter += 1 + + sender = Sender() + receiver = Receiver() + with SignalBlock(sender.signal, receiver.slot): + pass + sender.signal.emit() + assert receiver.counter == 0 diff --git a/tests/test_makeARGB.py b/tests/test_makeARGB.py index 3840c8419f..a5c7ef1942 100644 --- a/tests/test_makeARGB.py +++ b/tests/test_makeARGB.py @@ -1,4249 +1,18 @@ import sys -from typing import Any, Dict, Type, Union import numpy as np import pytest -from pyqtgraph import getConfigOption, getCupy, setConfigOption +from pyqtgraph import setConfigOptions from pyqtgraph.functions import makeARGB as real_makeARGB +from .makeARGB_test_data import EXPECTED_OUTPUTS, INPUTS, LEVELS, LUTS + + try: import cupy except ImportError: - cupy = None - -IN_2D_INT8 = np.array([[173, 48, 122, 41], [210, 192, 0, 5], [104, 56, 102, 115], [78, 19, 255, 6]], dtype=np.uint8) -IN_RGB_INT8 = np.array( - [ - [[16, 69, 62], [66, 132, 135], [220, 80, 36], [53, 34, 68]], - [[140, 23, 113], [0, 63, 206], [96, 255, 100], [226, 182, 155]], - [[28, 237, 223], [215, 232, 209], [17, 16, 50], [96, 187, 93]], - [[220, 193, 232], [134, 168, 150], [55, 64, 221], [96, 108, 227]], - ], - dtype=np.uint8, -) -IN_RGBA_INT8 = np.array( - [ - [[151, 252, 73, 107], [28, 221, 35, 0], [87, 122, 126, 114], [47, 59, 24, 200]], - [[189, 246, 242, 255], [123, 255, 29, 14], [201, 208, 133, 32], [118, 203, 141, 245]], - [[133, 131, 248, 81], [4, 84, 99, 40], [40, 167, 119, 150], [13, 158, 108, 21]], - [[156, 221, 166, 250], [77, 188, 13, 166], [0, 1, 185, 25], [83, 35, 103, 120]], - ], - dtype=np.uint8, -) -IN_2D_INT16 = np.array( - [ - [13364, 55041, 40746, 40937], - [57612, 34247, 34132, 0], - [10109, 56950, 41856, 21479], - [14881, 65535, 48079, 11372], - ], - dtype=np.uint16, -) -IN_RGB_INT16 = np.array( - [ - [[55626, 45263, 0], [19468, 39208, 36391], [33255, 8664, 56991], [37588, 31212, 38295]], - [[58933, 16402, 36905], [9928, 23928, 12418], [16461, 47738, 18189], [17004, 39307, 59941]], - [[43717, 49573, 9843], [35967, 3891, 39618], [53542, 58151, 29112], [53667, 4092, 35267]], - [[15957, 21648, 45238], [65535, 47107, 52049], [6342, 34547, 19902], [43386, 37301, 35095]], - ], - dtype=np.uint16, -) -IN_RGBA_INT16 = np.array( - [ - [ - [13060, 40847, 29621, 46719], - [0, 36509, 33525, 56649], - [48328, 23093, 47186, 26801], - [57336, 12247, 30996, 11691], - ], - [ - [4863, 41121, 32045, 25250], - [27779, 65098, 59921, 47771], - [8906, 18280, 5066, 48587], - [65535, 25758, 27250, 17284], - ], - [ - [52005, 65535, 40746, 65535], - [33, 57630, 27750, 42371], - [50176, 35079, 19220, 63662], - [17702, 5506, 36216, 48303], - ], - [ - [61592, 27692, 37436, 7249], - [54653, 39986, 58441, 12819], - [20887, 56588, 32440, 85], - [13457, 14661, 58972, 48779], - ], - ], - dtype=np.uint16, -) -IN_2D_FLOAT = np.array( - [ - [np.inf, 0.53662884, np.nan, 0.8853132], - [0.8496698, 0.88006145, 1.0, 0.06621328], - [0.99158293, 0.8476984, 0.16672458, 0.9887786], - [0.07076367, 0.66354364, 0.8781082, 0.988832], - ], - dtype=np.float32, -) -IN_RGB_FLOAT = np.array( - [ - [ - [0.23317624, 0.39086635, 0.12795302], - [0.40659714, 0.9079258, 0.28431135], - [0.91651599, 0.46082205, 0.16928465], - [0.29368765, 0.97987488, 0.72257988], - ], - [ - [np.nan, 0.72908475, 0.54018012], - [0.91277435, 0.2842577, 0.73481915], - [0.33844504, 0.22060913, 0.9802894], - [0.13995676, 0.34752838, 0.39652277], - ], - [ - [0.85315026, 0.19330797, 0.0], - [0.48584232, 0.04943356, 0.59906953], - [np.inf, 0.32614581, 0.1483722], - [0.37340863, 0.35432855, 0.08973532], - ], - [ - [0.69666134, 0.52481322, 0.49057305], - [0.93366339, 0.1428689, 0.6845513], - [0.27681383, 0.69472673, 0.06750892], - [0.26349886, 0.25841691, 0.86171104], - ], - ] -) -IN_RGBA_FLOAT = np.array( - [ - [ - [0.97383172, 0.62680971, 0.02285016, np.nan], - [0.85295433, 0.93014834, 0.59482999, np.inf], - [0.4017482, 0.79809183, 0.22407464, 0.17327807], - [0.95953263, 0.69535086, 0.28846483, 0.76970823], - ], - [ - [0.11487603, 0.7447609, 0.06767498, 0.98054729], - [0.66071068, 0.73931366, 0.33155686, 0.81827122], - [0.78035892, 0.52920802, 0.5671388, 0.31783899], - [0.81709002, 0.82204682, 0.82584029, 0.49434749], - ], - [ - [0.03142089, 0.8322058, 0.31646922, 0.94636969], - [0.62381573, 0.60052138, 0.50244611, 0.92886007], - [np.nan, np.nan, 0.02940048, 0.52529675], - [0.9786162, 0.54928697, 0.2409731, 0.34705397], - ], - [ - [0.68922233, np.inf, 0.85027734, 0.35388624], - [0.16489042, 0.29860162, 0.09349833, 0.67714667], - [0.25351483, 0.25596098, 0.80461891, 0.99952403], - [0.0, 1.0, 0.58084746, 0.46211944], - ], - ] -) -INPUTS: Dict[Any, np.ndarray] = { - (np.uint8, "2D"): IN_2D_INT8, - (np.uint8, "RGB"): IN_RGB_INT8, - (np.uint8, "RGBA"): IN_RGBA_INT8, - (np.uint16, "2D"): IN_2D_INT16, - (np.uint16, "RGB"): IN_RGB_INT16, - (np.uint16, "RGBA"): IN_RGBA_INT16, - (np.float32, "2D"): IN_2D_FLOAT, - (np.float32, "RGB"): IN_RGB_FLOAT, - (np.float32, "RGBA"): IN_RGBA_FLOAT, -} -LUT8 = np.zeros((255,), dtype=np.uint8) -LUT8[::2] = 255 -LUT16 = np.zeros((65535,), dtype=np.uint8) -LUT16[::3] = 255 -LUTS: Dict[Any, np.ndarray] = { - np.uint8: LUT8, - np.uint16: LUT16, -} -LEVELS = { - "SIMPLE": (0, 1), - "RGB": ((0, 255), (1, 250), (100, 160)), - "RGBA": ((255, 11111), (100, 10000), (0, 255), (127, 255)), -} - -EXPECTED_OUTPUTS: Dict[tuple, Union[Type[Exception], np.ndarray]] = { - (np.uint8, "2D", None, None, None, True): np.array( - [ - [[173, 173, 173, 255], [48, 48, 48, 255], [122, 122, 122, 255], [41, 41, 41, 255]], - [[210, 210, 210, 255], [192, 192, 192, 255], [0, 0, 0, 255], [5, 5, 5, 255]], - [[104, 104, 104, 255], [56, 56, 56, 255], [102, 102, 102, 255], [115, 115, 115, 255]], - [[78, 78, 78, 255], [19, 19, 19, 255], [255, 255, 255, 255], [6, 6, 6, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, None, None, False): np.array( - [ - [[173, 173, 173, 255], [48, 48, 48, 255], [122, 122, 122, 255], [41, 41, 41, 255]], - [[210, 210, 210, 255], [192, 192, 192, 255], [0, 0, 0, 255], [5, 5, 5, 255]], - [[104, 104, 104, 255], [56, 56, 56, 255], [102, 102, 102, 255], [115, 115, 115, 255]], - [[78, 78, 78, 255], [19, 19, 19, 255], [255, 255, 255, 255], [6, 6, 6, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, None, 232, True): np.array( - [ - [[157, 157, 157, 255], [43, 43, 43, 255], [110, 110, 110, 255], [37, 37, 37, 255]], - [[191, 191, 191, 255], [174, 174, 174, 255], [0, 0, 0, 255], [4, 4, 4, 255]], - [[94, 94, 94, 255], [50, 50, 50, 255], [92, 92, 92, 255], [104, 104, 104, 255]], - [[70, 70, 70, 255], [17, 17, 17, 255], [232, 232, 232, 255], [5, 5, 5, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, None, 232, False): np.array( - [ - [[157, 157, 157, 255], [43, 43, 43, 255], [110, 110, 110, 255], [37, 37, 37, 255]], - [[191, 191, 191, 255], [174, 174, 174, 255], [0, 0, 0, 255], [4, 4, 4, 255]], - [[94, 94, 94, 255], [50, 50, 50, 255], [92, 92, 92, 255], [104, 104, 104, 255]], - [[70, 70, 70, 255], [17, 17, 17, 255], [232, 232, 232, 255], [5, 5, 5, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint8, None, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint8, None, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint8, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint8, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint16, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", None, np.uint16, 13333, False): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGB", None, None, True): Exception, - (np.uint8, "2D", "RGB", None, None, False): Exception, - (np.uint8, "2D", "RGB", None, 232, True): Exception, - (np.uint8, "2D", "RGB", None, 232, False): Exception, - (np.uint8, "2D", "RGB", None, 13333, True): Exception, - (np.uint8, "2D", "RGB", None, 13333, False): Exception, - (np.uint8, "2D", "RGB", np.uint8, None, True): Exception, - (np.uint8, "2D", "RGB", np.uint8, None, False): Exception, - (np.uint8, "2D", "RGB", np.uint8, 232, True): Exception, - (np.uint8, "2D", "RGB", np.uint8, 232, False): Exception, - (np.uint8, "2D", "RGB", np.uint8, 13333, True): Exception, - (np.uint8, "2D", "RGB", np.uint8, 13333, False): Exception, - (np.uint8, "2D", "RGB", np.uint16, None, True): Exception, - (np.uint8, "2D", "RGB", np.uint16, None, False): Exception, - (np.uint8, "2D", "RGB", np.uint16, 232, True): Exception, - (np.uint8, "2D", "RGB", np.uint16, 232, False): Exception, - (np.uint8, "2D", "RGB", np.uint16, 13333, True): Exception, - (np.uint8, "2D", "RGB", np.uint16, 13333, False): Exception, - (np.uint8, "2D", "RGBA", None, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [122, 122, 122, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [102, 102, 102, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", None, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [122, 122, 122, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [102, 102, 102, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", None, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [110, 110, 110, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [92, 92, 92, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [232, 232, 232, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", None, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [110, 110, 110, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [2, 2, 2, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [92, 92, 92, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [232, 232, 232, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", None, 13333, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [123, 123, 123, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", None, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [123, 123, 123, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint16, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint16, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint16, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint16, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint16, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "2D", "RGBA", np.uint16, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, None, None, True): np.array( - [ - [[16, 69, 62, 255], [66, 132, 135, 255], [220, 80, 36, 255], [53, 34, 68, 255]], - [[140, 23, 113, 255], [0, 63, 206, 255], [96, 255, 100, 255], [226, 182, 155, 255]], - [[28, 237, 223, 255], [215, 232, 209, 255], [17, 16, 50, 255], [96, 187, 93, 255]], - [[220, 193, 232, 255], [134, 168, 150, 255], [55, 64, 221, 255], [96, 108, 227, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, None, None, False): np.array( - [ - [[62, 69, 16, 255], [135, 132, 66, 255], [36, 80, 220, 255], [68, 34, 53, 255]], - [[113, 23, 140, 255], [206, 63, 0, 255], [100, 255, 96, 255], [155, 182, 226, 255]], - [[223, 237, 28, 255], [209, 232, 215, 255], [50, 16, 17, 255], [93, 187, 96, 255]], - [[232, 193, 220, 255], [150, 168, 134, 255], [221, 64, 55, 255], [227, 108, 96, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, None, 232, True): np.array( - [ - [[14, 62, 56, 255], [60, 120, 122, 255], [200, 72, 32, 255], [48, 30, 61, 255]], - [[127, 20, 102, 255], [0, 57, 187, 255], [87, 232, 90, 255], [205, 165, 141, 255]], - [[25, 215, 202, 255], [195, 211, 190, 255], [15, 14, 45, 255], [87, 170, 84, 255]], - [[200, 175, 211, 255], [121, 152, 136, 255], [50, 58, 201, 255], [87, 98, 206, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, None, 232, False): np.array( - [ - [[56, 62, 14, 255], [122, 120, 60, 255], [32, 72, 200, 255], [61, 30, 48, 255]], - [[102, 20, 127, 255], [187, 57, 0, 255], [90, 232, 87, 255], [141, 165, 205, 255]], - [[202, 215, 25, 255], [190, 211, 195, 255], [45, 14, 15, 255], [84, 170, 87, 255]], - [[211, 175, 200, 255], [136, 152, 121, 255], [201, 58, 50, 255], [206, 98, 87, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint8, None, True): np.array( - [ - [[255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[255, 0, 0, 255], [255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[255, 0, 0, 255], [0, 255, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255]], - [[255, 0, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint8, None, False): np.array( - [ - [[255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[0, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[0, 0, 255, 255], [0, 255, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255]], - [[255, 0, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[0, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 255, 255], [0, 0, 255, 255], [0, 255, 0, 255], [0, 255, 255, 255]], - [[255, 0, 0, 255], [0, 255, 255, 255], [255, 255, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 0, 255], [0, 0, 255, 255], [255, 255, 0, 255], [0, 0, 0, 255]], - [[255, 0, 0, 255], [255, 0, 0, 255], [0, 255, 0, 255], [255, 255, 0, 255]], - [[0, 0, 255, 255], [255, 255, 0, 255], [0, 255, 255, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint16, None, True): np.array( - [ - [[0, 255, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint16, None, False): np.array( - [ - [[0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 0, 255], [0, 255, 0, 255], [255, 255, 0, 255]], - [[0, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255], [0, 255, 255, 255]], - [[0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 255, 255, 255], [0, 255, 0, 255], [0, 255, 255, 255]], - [[255, 0, 0, 255], [0, 255, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255]], - [[0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [255, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255]], - [[255, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 255, 0, 255]], - [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 255, 0, 255]], - [[255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", None, np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 0, 255]], - [[0, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 255, 0, 255]], - [[0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255], [0, 255, 255, 255]], - [[0, 0, 255, 255], [255, 255, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 255, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255]], - [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 0, 0, 255]], - [[0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", None, None, True): np.array( - [ - [[16, 69, 0, 255], [66, 134, 148, 255], [220, 80, 0, 255], [53, 33, 0, 255]], - [[140, 22, 55, 255], [0, 63, 255, 255], [96, 255, 0, 255], [226, 185, 233, 255]], - [[28, 241, 255, 255], [215, 236, 255, 255], [17, 15, 0, 255], [96, 190, 0, 255]], - [[220, 196, 255, 255], [134, 171, 212, 255], [55, 64, 255, 255], [96, 109, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", None, None, False): np.array( - [ - [[0, 69, 16, 255], [148, 134, 66, 255], [0, 80, 220, 255], [0, 33, 53, 255]], - [[55, 22, 140, 255], [255, 63, 0, 255], [0, 255, 96, 255], [233, 185, 226, 255]], - [[255, 241, 28, 255], [255, 236, 215, 255], [0, 15, 17, 255], [0, 190, 96, 255]], - [[255, 196, 220, 255], [212, 171, 134, 255], [255, 64, 55, 255], [255, 109, 96, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", None, 232, True): np.array( - [ - [[14, 63, 0, 255], [60, 122, 135, 255], [200, 73, 0, 255], [48, 30, 0, 255]], - [[127, 20, 50, 255], [0, 57, 255, 255], [87, 236, 0, 255], [205, 168, 212, 255]], - [[25, 219, 255, 255], [195, 215, 255, 255], [15, 13, 0, 255], [87, 173, 0, 255]], - [[200, 178, 255, 255], [121, 155, 193, 255], [50, 58, 255, 255], [87, 99, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", None, 232, False): np.array( - [ - [[0, 63, 14, 255], [135, 122, 60, 255], [0, 73, 200, 255], [0, 30, 48, 255]], - [[50, 20, 127, 255], [255, 57, 0, 255], [0, 236, 87, 255], [212, 168, 205, 255]], - [[255, 219, 25, 255], [255, 215, 195, 255], [0, 13, 15, 255], [0, 173, 87, 255]], - [[255, 178, 200, 255], [193, 155, 121, 255], [255, 58, 50, 255], [255, 99, 87, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", None, 13333, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", None, 13333, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint8, None, True): np.array( - [ - [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255]], - [[255, 255, 0, 255], [255, 0, 255, 255], [255, 255, 255, 255], [255, 0, 0, 255]], - [[255, 0, 255, 255], [0, 255, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint8, None, False): np.array( - [ - [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 0, 255]], - [[0, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255]], - [[255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint8, 232, True): np.array( - [ - [[255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[0, 255, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint8, 232, False): np.array( - [ - [[255, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[255, 255, 0, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint16, None, True): np.array( - [ - [[0, 0, 255, 255], [255, 0, 0, 255], [0, 0, 255, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255], [0, 255, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [0, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint16, None, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 255, 255], [255, 0, 0, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [0, 255, 255, 255], [255, 0, 255, 255], [0, 255, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [0, 255, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint16, 232, True): np.array( - [ - [[0, 255, 255, 255], [255, 0, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [255, 0, 255, 255], [0, 255, 0, 255]], - [[0, 255, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255]], - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint16, 232, False): np.array( - [ - [[255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [255, 0, 255, 255], [0, 255, 0, 255]], - [[0, 255, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255]], - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint16, 13333, True): np.array( - [ - [[0, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255]], - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGB", np.uint16, 13333, False): np.array( - [ - [[255, 0, 0, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[0, 0, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255], [0, 0, 0, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255]], - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGB", "RGBA", None, None, True): Exception, - (np.uint8, "RGB", "RGBA", None, None, False): Exception, - (np.uint8, "RGB", "RGBA", None, 232, True): Exception, - (np.uint8, "RGB", "RGBA", None, 232, False): Exception, - (np.uint8, "RGB", "RGBA", None, 13333, True): Exception, - (np.uint8, "RGB", "RGBA", None, 13333, False): Exception, - (np.uint8, "RGB", "RGBA", np.uint8, None, True): Exception, - (np.uint8, "RGB", "RGBA", np.uint8, None, False): Exception, - (np.uint8, "RGB", "RGBA", np.uint8, 232, True): Exception, - (np.uint8, "RGB", "RGBA", np.uint8, 232, False): Exception, - (np.uint8, "RGB", "RGBA", np.uint8, 13333, True): Exception, - (np.uint8, "RGB", "RGBA", np.uint8, 13333, False): Exception, - (np.uint8, "RGB", "RGBA", np.uint16, None, True): Exception, - (np.uint8, "RGB", "RGBA", np.uint16, None, False): Exception, - (np.uint8, "RGB", "RGBA", np.uint16, 232, True): Exception, - (np.uint8, "RGB", "RGBA", np.uint16, 232, False): Exception, - (np.uint8, "RGB", "RGBA", np.uint16, 13333, True): Exception, - (np.uint8, "RGB", "RGBA", np.uint16, 13333, False): Exception, - (np.uint8, "RGBA", None, None, None, True): np.array( - [ - [[151, 252, 73, 107], [28, 221, 35, 0], [87, 122, 126, 114], [47, 59, 24, 200]], - [[189, 246, 242, 255], [123, 255, 29, 14], [201, 208, 133, 32], [118, 203, 141, 245]], - [[133, 131, 248, 81], [4, 84, 99, 40], [40, 167, 119, 150], [13, 158, 108, 21]], - [[156, 221, 166, 250], [77, 188, 13, 166], [0, 1, 185, 25], [83, 35, 103, 120]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, None, None, False): np.array( - [ - [[73, 252, 151, 107], [35, 221, 28, 0], [126, 122, 87, 114], [24, 59, 47, 200]], - [[242, 246, 189, 255], [29, 255, 123, 14], [133, 208, 201, 32], [141, 203, 118, 245]], - [[248, 131, 133, 81], [99, 84, 4, 40], [119, 167, 40, 150], [108, 158, 13, 21]], - [[166, 221, 156, 250], [13, 188, 77, 166], [185, 1, 0, 25], [103, 35, 83, 120]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, None, 232, True): np.array( - [ - [[137, 229, 66, 97], [25, 201, 31, 0], [79, 110, 114, 103], [42, 53, 21, 181]], - [[171, 223, 220, 232], [111, 232, 26, 12], [182, 189, 121, 29], [107, 184, 128, 222]], - [[121, 119, 225, 73], [3, 76, 90, 36], [36, 151, 108, 136], [11, 143, 98, 19]], - [[141, 201, 151, 227], [70, 171, 11, 151], [0, 0, 168, 22], [75, 31, 93, 109]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, None, 232, False): np.array( - [ - [[66, 229, 137, 97], [31, 201, 25, 0], [114, 110, 79, 103], [21, 53, 42, 181]], - [[220, 223, 171, 232], [26, 232, 111, 12], [121, 189, 182, 29], [128, 184, 107, 222]], - [[225, 119, 121, 73], [90, 76, 3, 36], [108, 151, 36, 136], [98, 143, 11, 19]], - [[151, 201, 141, 227], [11, 171, 70, 151], [168, 0, 0, 22], [93, 31, 75, 109]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [209, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 52, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 209, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 52, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint8, None, True): np.array( - [ - [[0, 255, 0, 0], [255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255]], - [[0, 255, 255, 255], [0, 255, 0, 255], [0, 255, 0, 255], [255, 0, 0, 0]], - [[0, 0, 255, 0], [255, 255, 0, 255], [255, 0, 0, 255], [0, 255, 255, 0]], - [[255, 0, 255, 255], [0, 255, 0, 255], [255, 0, 0, 0], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint8, None, False): np.array( - [ - [[0, 255, 0, 0], [0, 0, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255]], - [[255, 255, 0, 255], [0, 255, 0, 255], [0, 255, 0, 255], [0, 0, 255, 0]], - [[255, 0, 0, 0], [0, 255, 255, 255], [0, 0, 255, 255], [255, 255, 0, 0]], - [[255, 0, 255, 255], [0, 255, 0, 255], [0, 0, 255, 0], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint8, 232, True): np.array( - [ - [[0, 0, 255, 0], [0, 0, 0, 255], [0, 255, 255, 0], [255, 0, 0, 0]], - [[0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 0, 0], [0, 255, 255, 255]], - [[0, 0, 0, 0], [0, 255, 255, 255], [255, 0, 255, 255], [0, 0, 255, 0]], - [[0, 0, 0, 0], [255, 0, 0, 0], [255, 255, 255, 255], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint8, 232, False): np.array( - [ - [[255, 0, 0, 0], [0, 0, 0, 255], [255, 255, 0, 0], [0, 0, 255, 0]], - [[255, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 0], [255, 255, 0, 255]], - [[0, 0, 0, 0], [255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 255, 0], [255, 255, 255, 255], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint16, None, True): np.array( - [ - [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 0]], - [[255, 255, 0, 0], [255, 0, 0, 0], [255, 0, 0, 0], [0, 0, 255, 0]], - [[0, 0, 0, 255], [0, 255, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255]], - [[255, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint16, None, False): np.array( - [ - [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 0]], - [[0, 255, 255, 0], [0, 0, 255, 0], [0, 0, 255, 0], [255, 0, 0, 0]], - [[0, 0, 0, 255], [255, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint16, 232, True): np.array( - [ - [[0, 0, 255, 0], [0, 255, 0, 255], [0, 0, 255, 0], [255, 0, 255, 0]], - [[255, 0, 0, 0], [255, 0, 0, 255], [0, 255, 0, 0], [0, 0, 0, 255]], - [[0, 0, 255, 0], [255, 0, 255, 255], [255, 0, 255, 0], [0, 0, 0, 0]], - [[255, 255, 0, 0], [0, 255, 0, 0], [255, 255, 255, 0], [255, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint16, 232, False): np.array( - [ - [[255, 0, 0, 0], [0, 255, 0, 255], [255, 0, 0, 0], [255, 0, 255, 0]], - [[0, 0, 255, 0], [0, 0, 255, 255], [0, 255, 0, 0], [0, 0, 0, 255]], - [[255, 0, 0, 0], [255, 0, 255, 255], [255, 0, 255, 0], [0, 0, 0, 0]], - [[0, 255, 255, 0], [0, 255, 0, 0], [255, 255, 255, 0], [255, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint16, 13333, True): np.array( - [ - [[0, 255, 255, 0], [255, 0, 255, 255], [255, 255, 255, 0], [255, 255, 255, 0]], - [[255, 0, 0, 0], [0, 0, 0, 255], [255, 255, 255, 0], [0, 255, 0, 255]], - [[255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], - [[0, 0, 255, 255], [255, 0, 0, 255], [255, 0, 255, 0], [0, 255, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", None, np.uint16, 13333, False): np.array( - [ - [[255, 255, 0, 0], [255, 0, 255, 255], [255, 255, 255, 0], [255, 255, 255, 0]], - [[0, 0, 255, 0], [0, 0, 0, 255], [255, 255, 255, 0], [0, 255, 0, 255]], - [[255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], - [[255, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 0], [255, 255, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 232, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 232, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 0]], - [[255, 255, 0, 255], [255, 255, 0, 0], [255, 0, 0, 0], [0, 0, 255, 0]], - [[0, 0, 0, 255], [0, 255, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255]], - [[255, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 0]], - [[0, 255, 255, 255], [0, 255, 255, 0], [0, 0, 255, 0], [255, 0, 0, 0]], - [[0, 0, 0, 255], [255, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGB", None, None, True): Exception, - (np.uint8, "RGBA", "RGB", None, None, False): Exception, - (np.uint8, "RGBA", "RGB", None, 232, True): Exception, - (np.uint8, "RGBA", "RGB", None, 232, False): Exception, - (np.uint8, "RGBA", "RGB", None, 13333, True): Exception, - (np.uint8, "RGBA", "RGB", None, 13333, False): Exception, - (np.uint8, "RGBA", "RGB", np.uint8, None, True): Exception, - (np.uint8, "RGBA", "RGB", np.uint8, None, False): Exception, - (np.uint8, "RGBA", "RGB", np.uint8, 232, True): Exception, - (np.uint8, "RGBA", "RGB", np.uint8, 232, False): Exception, - (np.uint8, "RGBA", "RGB", np.uint8, 13333, True): Exception, - (np.uint8, "RGBA", "RGB", np.uint8, 13333, False): Exception, - (np.uint8, "RGBA", "RGB", np.uint16, None, True): Exception, - (np.uint8, "RGBA", "RGB", np.uint16, None, False): Exception, - (np.uint8, "RGBA", "RGB", np.uint16, 232, True): Exception, - (np.uint8, "RGBA", "RGB", np.uint16, 232, False): Exception, - (np.uint8, "RGBA", "RGB", np.uint16, 13333, True): Exception, - (np.uint8, "RGBA", "RGB", np.uint16, 13333, False): Exception, - (np.uint8, "RGBA", "RGBA", None, None, True): np.array( - [ - [[0, 3, 73, 0], [0, 3, 35, 0], [0, 0, 126, 0], [0, 0, 24, 145]], - [[0, 3, 242, 255], [0, 3, 29, 0], [0, 2, 133, 0], [0, 2, 141, 235]], - [[0, 0, 248, 0], [0, 0, 99, 0], [0, 1, 119, 45], [0, 1, 108, 0]], - [[0, 3, 166, 245], [0, 2, 13, 77], [0, 0, 185, 0], [0, 0, 103, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", None, None, False): np.array( - [ - [[73, 3, 0, 0], [35, 3, 0, 0], [126, 0, 0, 0], [24, 0, 0, 145]], - [[242, 3, 0, 255], [29, 3, 0, 0], [133, 2, 0, 0], [141, 2, 0, 235]], - [[248, 0, 0, 0], [99, 0, 0, 0], [119, 1, 0, 45], [108, 1, 0, 0]], - [[166, 3, 0, 245], [13, 2, 0, 77], [185, 0, 0, 0], [103, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", None, 232, True): np.array( - [ - [[0, 3, 66, 0], [0, 2, 31, 0], [0, 0, 114, 0], [0, 0, 21, 132]], - [[0, 3, 220, 232], [0, 3, 26, 0], [0, 2, 121, 0], [0, 2, 128, 213]], - [[0, 0, 225, 0], [0, 0, 90, 0], [0, 1, 108, 41], [0, 1, 98, 0]], - [[0, 2, 151, 222], [0, 2, 11, 70], [0, 0, 168, 0], [0, 0, 93, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", None, 232, False): np.array( - [ - [[66, 3, 0, 0], [31, 2, 0, 0], [114, 0, 0, 0], [21, 0, 0, 132]], - [[220, 3, 0, 232], [26, 3, 0, 0], [121, 2, 0, 0], [128, 2, 0, 213]], - [[225, 0, 0, 0], [90, 0, 0, 0], [108, 1, 0, 41], [98, 1, 0, 0]], - [[151, 2, 0, 222], [11, 2, 0, 70], [168, 0, 0, 0], [93, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", None, 13333, True): np.array( - [ - [[0, 204, 255, 0], [0, 162, 255, 0], [0, 29, 255, 0], [0, 0, 255, 255]], - [[0, 196, 255, 255], [0, 208, 255, 0], [0, 145, 255, 0], [0, 138, 255, 255]], - [[0, 41, 255, 0], [0, 0, 255, 0], [0, 90, 255, 255], [0, 78, 255, 0]], - [[0, 162, 255, 255], [0, 118, 255, 255], [0, 0, 255, 0], [0, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", None, 13333, False): np.array( - [ - [[255, 204, 0, 0], [255, 162, 0, 0], [255, 29, 0, 0], [255, 0, 0, 255]], - [[255, 196, 0, 255], [255, 208, 0, 0], [255, 145, 0, 0], [255, 138, 0, 255]], - [[255, 41, 0, 0], [255, 0, 0, 0], [255, 90, 0, 255], [255, 78, 0, 0]], - [[255, 162, 0, 255], [255, 118, 0, 255], [255, 0, 0, 0], [255, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint8, None, True): np.array( - [ - [[255, 0, 0, 255], [255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0]], - [[255, 0, 255, 255], [255, 0, 0, 255], [255, 255, 0, 255], [255, 255, 0, 0]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 0, 0, 0], [255, 0, 255, 255]], - [[255, 0, 255, 0], [255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint8, None, False): np.array( - [ - [[0, 0, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0]], - [[255, 0, 255, 255], [0, 0, 255, 255], [0, 255, 255, 255], [0, 255, 255, 0]], - [[255, 255, 255, 255], [0, 255, 255, 255], [0, 0, 255, 0], [255, 0, 255, 255]], - [[255, 0, 255, 0], [0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint8, 232, True): np.array( - [ - [[255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 0]], - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 0, 255, 0], [255, 0, 255, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint8, 232, False): np.array( - [ - [[255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[255, 0, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 0]], - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 0], [255, 0, 255, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint16, None, True): np.array( - [ - [[255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [255, 255, 255, 0]], - [[255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 255, 0]], - [[255, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [255, 0, 255, 255]], - [[255, 0, 0, 0], [255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint16, None, False): np.array( - [ - [[0, 0, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 0]], - [[0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 0]], - [[0, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255]], - [[0, 0, 255, 0], [0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint16, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 0, 0], [255, 255, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 0], [255, 0, 0, 255]], - [[255, 0, 0, 255], [255, 0, 0, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint16, 232, False): np.array( - [ - [[255, 255, 255, 255], [0, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 255, 255, 0], [0, 255, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 0], [0, 0, 255, 255]], - [[0, 0, 255, 255], [0, 0, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint16, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 0]], - [[255, 0, 0, 0], [255, 0, 0, 255], [255, 0, 255, 255], [255, 255, 0, 255]], - [[255, 0, 255, 255], [255, 255, 0, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint8, "RGBA", "RGBA", np.uint16, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 255, 0]], - [[0, 0, 255, 0], [0, 0, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255]], - [[255, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 0], [0, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, None, None, True): np.array( - [ - [[52, 52, 52, 255], [214, 214, 214, 255], [158, 158, 158, 255], [159, 159, 159, 255]], - [[224, 224, 224, 255], [133, 133, 133, 255], [132, 132, 132, 255], [0, 0, 0, 255]], - [[39, 39, 39, 255], [221, 221, 221, 255], [162, 162, 162, 255], [83, 83, 83, 255]], - [[57, 57, 57, 255], [255, 255, 255, 255], [187, 187, 187, 255], [44, 44, 44, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, None, None, False): np.array( - [ - [[52, 52, 52, 255], [214, 214, 214, 255], [158, 158, 158, 255], [159, 159, 159, 255]], - [[224, 224, 224, 255], [133, 133, 133, 255], [132, 132, 132, 255], [0, 0, 0, 255]], - [[39, 39, 39, 255], [221, 221, 221, 255], [162, 162, 162, 255], [83, 83, 83, 255]], - [[57, 57, 57, 255], [255, 255, 255, 255], [187, 187, 187, 255], [44, 44, 44, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, None, 232, True): np.array( - [ - [[47, 47, 47, 255], [194, 194, 194, 255], [144, 144, 144, 255], [144, 144, 144, 255]], - [[203, 203, 203, 255], [121, 121, 121, 255], [120, 120, 120, 255], [0, 0, 0, 255]], - [[35, 35, 35, 255], [201, 201, 201, 255], [148, 148, 148, 255], [76, 76, 76, 255]], - [[52, 52, 52, 255], [232, 232, 232, 255], [170, 170, 170, 255], [40, 40, 40, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, None, 232, False): np.array( - [ - [[47, 47, 47, 255], [194, 194, 194, 255], [144, 144, 144, 255], [144, 144, 144, 255]], - [[203, 203, 203, 255], [121, 121, 121, 255], [120, 120, 120, 255], [0, 0, 0, 255]], - [[35, 35, 35, 255], [201, 201, 201, 255], [148, 148, 148, 255], [76, 76, 76, 255]], - [[52, 52, 52, 255], [232, 232, 232, 255], [170, 170, 170, 255], [40, 40, 40, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint8, 232, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint8, 232, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint16, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", None, np.uint16, 13333, False): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGB", None, None, True): Exception, - (np.uint16, "2D", "RGB", None, None, False): Exception, - (np.uint16, "2D", "RGB", None, 232, True): Exception, - (np.uint16, "2D", "RGB", None, 232, False): Exception, - (np.uint16, "2D", "RGB", None, 13333, True): Exception, - (np.uint16, "2D", "RGB", None, 13333, False): Exception, - (np.uint16, "2D", "RGB", np.uint8, None, True): Exception, - (np.uint16, "2D", "RGB", np.uint8, None, False): Exception, - (np.uint16, "2D", "RGB", np.uint8, 232, True): Exception, - (np.uint16, "2D", "RGB", np.uint8, 232, False): Exception, - (np.uint16, "2D", "RGB", np.uint8, 13333, True): Exception, - (np.uint16, "2D", "RGB", np.uint8, 13333, False): Exception, - (np.uint16, "2D", "RGB", np.uint16, None, True): Exception, - (np.uint16, "2D", "RGB", np.uint16, None, False): Exception, - (np.uint16, "2D", "RGB", np.uint16, 232, True): Exception, - (np.uint16, "2D", "RGB", np.uint16, 232, False): Exception, - (np.uint16, "2D", "RGB", np.uint16, 13333, True): Exception, - (np.uint16, "2D", "RGB", np.uint16, 13333, False): Exception, - (np.uint16, "2D", "RGBA", None, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[231, 231, 231, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[231, 231, 231, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[210, 210, 210, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[210, 210, 210, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "2D", "RGBA", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, None, None, True): np.array( - [ - [[216, 176, 0, 255], [75, 152, 141, 255], [129, 33, 221, 255], [146, 121, 149, 255]], - [[229, 63, 143, 255], [38, 93, 48, 255], [64, 185, 70, 255], [66, 152, 233, 255]], - [[170, 192, 38, 255], [139, 15, 154, 255], [208, 226, 113, 255], [208, 15, 137, 255]], - [[62, 84, 176, 255], [255, 183, 202, 255], [24, 134, 77, 255], [168, 145, 136, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, None, None, False): np.array( - [ - [[0, 176, 216, 255], [141, 152, 75, 255], [221, 33, 129, 255], [149, 121, 146, 255]], - [[143, 63, 229, 255], [48, 93, 38, 255], [70, 185, 64, 255], [233, 152, 66, 255]], - [[38, 192, 170, 255], [154, 15, 139, 255], [113, 226, 208, 255], [137, 15, 208, 255]], - [[176, 84, 62, 255], [202, 183, 255, 255], [77, 134, 24, 255], [136, 145, 168, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, None, 232, True): np.array( - [ - [[196, 160, 0, 255], [68, 138, 128, 255], [117, 30, 201, 255], [133, 110, 135, 255]], - [[208, 58, 130, 255], [35, 84, 43, 255], [58, 168, 64, 255], [60, 139, 212, 255]], - [[154, 175, 34, 255], [127, 13, 140, 255], [189, 205, 103, 255], [189, 14, 124, 255]], - [[56, 76, 160, 255], [232, 166, 184, 255], [22, 122, 70, 255], [153, 132, 124, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, None, 232, False): np.array( - [ - [[0, 160, 196, 255], [128, 138, 68, 255], [201, 30, 117, 255], [135, 110, 133, 255]], - [[130, 58, 208, 255], [43, 84, 35, 255], [64, 168, 58, 255], [212, 139, 60, 255]], - [[34, 175, 154, 255], [140, 13, 127, 255], [103, 205, 189, 255], [124, 14, 189, 255]], - [[160, 76, 56, 255], [184, 166, 232, 255], [70, 122, 22, 255], [124, 132, 153, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, None, 13333, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, None, 13333, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [0, 0, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255]], - [[255, 255, 255, 255], [255, 0, 255, 255], [255, 255, 0, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255]], - [[255, 255, 255, 255], [255, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [0, 255, 0, 255]], - [[255, 255, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 255, 255]], - [[255, 0, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 0, 255], [0, 255, 0, 255]], - [[255, 255, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 255, 255]], - [[255, 0, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint16, None, True): np.array( - [ - [[255, 0, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], - [[0, 0, 255, 255], [255, 255, 255, 255], [0, 0, 255, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint16, None, False): np.array( - [ - [[255, 0, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], - [[255, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint16, 232, True): np.array( - [ - [[0, 0, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [0, 255, 0, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint16, 232, False): np.array( - [ - [[255, 0, 0, 255], [0, 255, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint16, 13333, True): np.array( - [ - [[0, 0, 255, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], - [[0, 255, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 255]], - [[255, 255, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", None, np.uint16, 13333, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255], [255, 0, 255, 255]], - [[0, 255, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [0, 0, 0, 255]], - [[0, 255, 255, 255], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", None, None, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", None, 232, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", None, 13333, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint16, None, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", None, None, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", None, None, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", None, 232, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", None, 232, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", None, 13333, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", None, 13333, False): np.array( - [ - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint16, None, True): np.array( - [ - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint16, None, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint16, 232, True): np.array( - [ - [[0, 255, 255, 255], [255, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 0, 255], [0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint16, 232, False): np.array( - [ - [[255, 255, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 255, 255, 255], [0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint16, 13333, True): np.array( - [ - [[0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGB", np.uint16, 13333, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGB", "RGBA", None, None, True): Exception, - (np.uint16, "RGB", "RGBA", None, None, False): Exception, - (np.uint16, "RGB", "RGBA", None, 232, True): Exception, - (np.uint16, "RGB", "RGBA", None, 232, False): Exception, - (np.uint16, "RGB", "RGBA", None, 13333, True): Exception, - (np.uint16, "RGB", "RGBA", None, 13333, False): Exception, - (np.uint16, "RGB", "RGBA", np.uint8, None, True): Exception, - (np.uint16, "RGB", "RGBA", np.uint8, None, False): Exception, - (np.uint16, "RGB", "RGBA", np.uint8, 232, True): Exception, - (np.uint16, "RGB", "RGBA", np.uint8, 232, False): Exception, - (np.uint16, "RGB", "RGBA", np.uint8, 13333, True): Exception, - (np.uint16, "RGB", "RGBA", np.uint8, 13333, False): Exception, - (np.uint16, "RGB", "RGBA", np.uint16, None, True): Exception, - (np.uint16, "RGB", "RGBA", np.uint16, None, False): Exception, - (np.uint16, "RGB", "RGBA", np.uint16, 232, True): Exception, - (np.uint16, "RGB", "RGBA", np.uint16, 232, False): Exception, - (np.uint16, "RGB", "RGBA", np.uint16, 13333, True): Exception, - (np.uint16, "RGB", "RGBA", np.uint16, 13333, False): Exception, - (np.uint16, "RGBA", None, None, None, True): np.array( - [ - [[50, 158, 115, 181], [0, 142, 130, 220], [188, 89, 183, 104], [223, 47, 120, 45]], - [[18, 160, 124, 98], [108, 253, 233, 185], [34, 71, 19, 189], [255, 100, 106, 67]], - [[202, 255, 158, 255], [0, 224, 107, 164], [195, 136, 74, 247], [68, 21, 140, 187]], - [[239, 107, 145, 28], [212, 155, 227, 49], [81, 220, 126, 0], [52, 57, 229, 189]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, None, None, False): np.array( - [ - [[115, 158, 50, 181], [130, 142, 0, 220], [183, 89, 188, 104], [120, 47, 223, 45]], - [[124, 160, 18, 98], [233, 253, 108, 185], [19, 71, 34, 189], [106, 100, 255, 67]], - [[158, 255, 202, 255], [107, 224, 0, 164], [74, 136, 195, 247], [140, 21, 68, 187]], - [[145, 107, 239, 28], [227, 155, 212, 49], [126, 220, 81, 0], [229, 57, 52, 189]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, None, 232, True): np.array( - [ - [[46, 144, 104, 165], [0, 129, 118, 200], [171, 81, 167, 94], [202, 43, 109, 41]], - [[17, 145, 113, 89], [98, 230, 212, 169], [31, 64, 17, 172], [232, 91, 96, 61]], - [[184, 232, 144, 232], [0, 204, 98, 149], [177, 124, 68, 225], [62, 19, 128, 170]], - [[218, 98, 132, 25], [193, 141, 206, 45], [73, 200, 114, 0], [47, 51, 208, 172]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, None, 232, False): np.array( - [ - [[104, 144, 46, 165], [118, 129, 0, 200], [167, 81, 171, 94], [109, 43, 202, 41]], - [[113, 145, 17, 89], [212, 230, 98, 169], [17, 64, 31, 172], [96, 91, 232, 61]], - [[144, 232, 184, 232], [98, 204, 0, 149], [68, 124, 177, 225], [128, 19, 62, 170]], - [[132, 98, 218, 25], [206, 141, 193, 45], [114, 200, 73, 0], [208, 51, 47, 172]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [6, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 17], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 6, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 17], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint8, None, True): np.array( - [ - [[255, 255, 0, 0], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 255, 0]], - [[255, 255, 255, 255], [255, 0, 0, 0], [255, 0, 0, 0], [255, 255, 255, 0]], - [[255, 255, 255, 255], [255, 255, 0, 255], [0, 255, 255, 0], [255, 0, 255, 0]], - [[0, 0, 0, 255], [255, 0, 0, 0], [0, 255, 255, 255], [255, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint8, None, False): np.array( - [ - [[0, 255, 255, 0], [255, 255, 255, 255], [0, 0, 255, 255], [255, 0, 0, 0]], - [[255, 255, 255, 255], [0, 0, 255, 0], [0, 0, 255, 0], [255, 255, 255, 0]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 0, 0], [255, 0, 255, 0]], - [[0, 0, 0, 255], [0, 0, 255, 0], [255, 255, 0, 255], [0, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 0], [255, 0, 255, 255], [0, 0, 0, 255], [255, 0, 0, 0]], - [[0, 0, 0, 0], [255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 0]], - [[255, 255, 255, 255], [255, 255, 255, 0], [0, 255, 255, 0], [255, 0, 255, 255]], - [[255, 255, 255, 0], [0, 0, 255, 0], [0, 255, 255, 255], [0, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 0], [255, 0, 255, 255], [0, 0, 0, 255], [0, 0, 255, 0]], - [[0, 0, 0, 0], [255, 255, 255, 0], [0, 255, 0, 255], [255, 0, 255, 0]], - [[255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 0, 0], [255, 0, 255, 255]], - [[255, 255, 255, 0], [255, 0, 0, 0], [255, 255, 0, 255], [255, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 0], [255, 0, 255, 255]], - [[255, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 255, 0, 0]], - [[255, 0, 255, 0], [255, 255, 255, 0], [0, 255, 0, 0], [0, 0, 255, 255]], - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 255, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 0], [255, 0, 255, 255]], - [[0, 255, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 255, 0, 0]], - [[255, 0, 255, 0], [255, 255, 255, 0], [0, 255, 0, 0], [255, 0, 0, 255]], - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 255, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint16, 232, True): np.array( - [ - [[0, 255, 0, 255], [255, 255, 0, 0], [255, 255, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0]], - [[0, 0, 255, 0], [255, 255, 0, 0], [255, 0, 0, 255], [0, 0, 0, 0]], - [[0, 0, 255, 0], [0, 255, 0, 255], [0, 0, 255, 255], [0, 255, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint16, 232, False): np.array( - [ - [[0, 255, 0, 255], [0, 255, 255, 0], [0, 255, 255, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0]], - [[255, 0, 0, 0], [0, 255, 255, 0], [0, 0, 255, 255], [0, 0, 0, 0]], - [[255, 0, 0, 0], [0, 255, 0, 255], [255, 0, 0, 255], [0, 255, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint16, 13333, True): np.array( - [ - [[0, 255, 0, 255], [255, 0, 0, 0], [0, 255, 0, 0], [255, 0, 255, 0]], - [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 255, 0], [255, 255, 0, 0], [0, 0, 0, 255], [0, 0, 255, 0]], - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", None, np.uint16, 13333, False): np.array( - [ - [[0, 255, 0, 255], [0, 0, 255, 0], [0, 255, 0, 0], [255, 0, 255, 0]], - [[255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255]], - [[255, 0, 0, 0], [0, 255, 255, 0], [0, 0, 0, 255], [255, 0, 0, 0]], - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGB", None, None, True): Exception, - (np.uint16, "RGBA", "RGB", None, None, False): Exception, - (np.uint16, "RGBA", "RGB", None, 232, True): Exception, - (np.uint16, "RGBA", "RGB", None, 232, False): Exception, - (np.uint16, "RGBA", "RGB", None, 13333, True): Exception, - (np.uint16, "RGBA", "RGB", None, 13333, False): Exception, - (np.uint16, "RGBA", "RGB", np.uint8, None, True): Exception, - (np.uint16, "RGBA", "RGB", np.uint8, None, False): Exception, - (np.uint16, "RGBA", "RGB", np.uint8, 232, True): Exception, - (np.uint16, "RGBA", "RGB", np.uint8, 232, False): Exception, - (np.uint16, "RGBA", "RGB", np.uint8, 13333, True): Exception, - (np.uint16, "RGBA", "RGB", np.uint8, 13333, False): Exception, - (np.uint16, "RGBA", "RGB", np.uint16, None, True): Exception, - (np.uint16, "RGBA", "RGB", np.uint16, None, False): Exception, - (np.uint16, "RGBA", "RGB", np.uint16, 232, True): Exception, - (np.uint16, "RGBA", "RGB", np.uint16, 232, False): Exception, - (np.uint16, "RGBA", "RGB", np.uint16, 13333, True): Exception, - (np.uint16, "RGBA", "RGB", np.uint16, 13333, False): Exception, - (np.uint16, "RGBA", "RGBA", None, None, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[108, 255, 255, 255], [255, 255, 255, 255], [203, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 139, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", None, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 108, 255], [255, 255, 255, 255], [255, 255, 203, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 139, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[98, 255, 255, 255], [255, 255, 255, 255], [184, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 126, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 98, 255], [255, 255, 255, 255], [255, 255, 184, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 126, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint16, 232, True): np.array( - [ - [[255, 255, 255, 0], [255, 0, 255, 0], [0, 0, 255, 0], [0, 0, 255, 0]], - [[0, 0, 255, 0], [255, 0, 255, 0], [0, 255, 0, 0], [255, 0, 255, 0]], - [[0, 255, 0, 0], [255, 0, 0, 0], [0, 255, 0, 0], [255, 255, 255, 0]], - [[0, 0, 255, 0], [0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint16, 232, False): np.array( - [ - [[255, 255, 255, 0], [255, 0, 255, 0], [255, 0, 0, 0], [255, 0, 0, 0]], - [[255, 0, 0, 0], [255, 0, 255, 0], [0, 255, 0, 0], [255, 0, 255, 0]], - [[0, 255, 0, 0], [0, 0, 255, 0], [0, 255, 0, 0], [255, 255, 255, 0]], - [[255, 0, 0, 0], [255, 0, 0, 255], [255, 255, 0, 255], [255, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint16, 13333, True): np.array( - [ - [[255, 255, 0, 0], [255, 0, 0, 0], [0, 255, 0, 0], [0, 255, 0, 0]], - [[0, 255, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [255, 0, 0, 0], [255, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.uint16, "RGBA", "RGBA", np.uint16, 13333, False): np.array( - [ - [[0, 255, 255, 0], [0, 0, 255, 0], [0, 255, 0, 0], [0, 255, 0, 0]], - [[0, 255, 0, 0], [0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 255, 0], [0, 0, 255, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", None, None, True): np.array( - [ - [[255, 255, 255, 255], [136, 136, 136, 255], [0, 0, 0, 0], [225, 225, 225, 255]], - [[216, 216, 216, 255], [224, 224, 224, 255], [255, 255, 255, 255], [16, 16, 16, 255]], - [[252, 252, 252, 255], [216, 216, 216, 255], [42, 42, 42, 255], [252, 252, 252, 255]], - [[18, 18, 18, 255], [169, 169, 169, 255], [223, 223, 223, 255], [252, 252, 252, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", None, None, False): np.array( - [ - [[255, 255, 255, 255], [136, 136, 136, 255], [0, 0, 0, 0], [225, 225, 225, 255]], - [[216, 216, 216, 255], [224, 224, 224, 255], [255, 255, 255, 255], [16, 16, 16, 255]], - [[252, 252, 252, 255], [216, 216, 216, 255], [42, 42, 42, 255], [252, 252, 252, 255]], - [[18, 18, 18, 255], [169, 169, 169, 255], [223, 223, 223, 255], [252, 252, 252, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [124, 124, 124, 255], [0, 0, 0, 0], [205, 205, 205, 255]], - [[197, 197, 197, 255], [204, 204, 204, 255], [232, 232, 232, 255], [15, 15, 15, 255]], - [[230, 230, 230, 255], [196, 196, 196, 255], [38, 38, 38, 255], [229, 229, 229, 255]], - [[16, 16, 16, 255], [153, 153, 153, 255], [203, 203, 203, 255], [229, 229, 229, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [124, 124, 124, 255], [0, 0, 0, 0], [205, 205, 205, 255]], - [[197, 197, 197, 255], [204, 204, 204, 255], [232, 232, 232, 255], [15, 15, 15, 255]], - [[230, 230, 230, 255], [196, 196, 196, 255], [38, 38, 38, 255], [229, 229, 229, 255]], - [[16, 16, 16, 255], [153, 153, 153, 255], [203, 203, 203, 255], [229, 229, 229, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 255, 255, 0], [0, 0, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGB", None, None, True): Exception, - (np.float32, "2D", "RGB", None, None, False): Exception, - (np.float32, "2D", "RGB", None, 232, True): Exception, - (np.float32, "2D", "RGB", None, 232, False): Exception, - (np.float32, "2D", "RGB", None, 13333, True): Exception, - (np.float32, "2D", "RGB", None, 13333, False): Exception, - (np.float32, "2D", "RGB", np.uint8, None, True): Exception, - (np.float32, "2D", "RGB", np.uint8, None, False): Exception, - (np.float32, "2D", "RGB", np.uint8, 232, True): Exception, - (np.float32, "2D", "RGB", np.uint8, 232, False): Exception, - (np.float32, "2D", "RGB", np.uint8, 13333, True): Exception, - (np.float32, "2D", "RGB", np.uint8, 13333, False): Exception, - (np.float32, "2D", "RGB", np.uint16, None, True): Exception, - (np.float32, "2D", "RGB", np.uint16, None, False): Exception, - (np.float32, "2D", "RGB", np.uint16, 232, True): Exception, - (np.float32, "2D", "RGB", np.uint16, 232, False): Exception, - (np.float32, "2D", "RGB", np.uint16, 13333, True): Exception, - (np.float32, "2D", "RGB", np.uint16, 13333, False): Exception, - (np.float32, "2D", "RGBA", None, None, True): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [1, 1, 1, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", None, None, False): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [1, 1, 1, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", None, 232, True): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", None, 232, False): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [52, 52, 52, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [8, 8, 8, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [45, 45, 45, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [52, 52, 52, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [8, 8, 8, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [45, 45, 45, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint16, None, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint16, None, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint16, 232, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint16, 232, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint16, 13333, True): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "2D", "RGBA", np.uint16, 13333, False): np.array( - [ - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", None, None, True): np.array( - [ - [[59, 99, 32, 255], [103, 231, 72, 255], [233, 117, 43, 255], [74, 249, 184, 255]], - [[0, 185, 137, 0], [232, 72, 187, 255], [86, 56, 249, 255], [35, 88, 101, 255]], - [[217, 49, 0, 255], [123, 12, 152, 255], [255, 83, 37, 255], [95, 90, 22, 255]], - [[177, 133, 125, 255], [238, 36, 174, 255], [70, 177, 17, 255], [67, 65, 219, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", None, None, False): np.array( - [ - [[32, 99, 59, 255], [72, 231, 103, 255], [43, 117, 233, 255], [184, 249, 74, 255]], - [[137, 185, 0, 0], [187, 72, 232, 255], [249, 56, 86, 255], [101, 88, 35, 255]], - [[0, 49, 217, 255], [152, 12, 123, 255], [37, 83, 255, 255], [22, 90, 95, 255]], - [[125, 133, 177, 255], [174, 36, 238, 255], [17, 177, 70, 255], [219, 65, 67, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", None, 232, True): np.array( - [ - [[54, 90, 29, 255], [94, 210, 65, 255], [212, 106, 39, 255], [68, 227, 167, 255]], - [[0, 169, 125, 0], [211, 65, 170, 255], [78, 51, 227, 255], [32, 80, 91, 255]], - [[197, 44, 0, 255], [112, 11, 138, 255], [255, 75, 34, 255], [86, 82, 20, 255]], - [[161, 121, 113, 255], [216, 33, 158, 255], [64, 161, 15, 255], [61, 59, 199, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", None, 232, False): np.array( - [ - [[29, 90, 54, 255], [65, 210, 94, 255], [39, 106, 212, 255], [167, 227, 68, 255]], - [[125, 169, 0, 0], [170, 65, 211, 255], [227, 51, 78, 255], [91, 80, 32, 255]], - [[0, 44, 197, 255], [138, 11, 112, 255], [34, 75, 255, 255], [20, 82, 86, 255]], - [[113, 121, 161, 255], [158, 33, 216, 255], [15, 161, 64, 255], [199, 59, 61, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 0, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint8, None, True): np.array( - [ - [[0, 0, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[255, 0, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255], [0, 255, 0, 255]], - [[0, 0, 255, 255], [0, 255, 255, 255], [255, 0, 0, 255], [0, 255, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint8, None, False): np.array( - [ - [[255, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[0, 0, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 0, 255]], - [[255, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255], [255, 255, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 0, 0, 255]], - [[255, 0, 0, 0], [0, 0, 255, 255], [255, 0, 0, 255], [255, 255, 0, 255]], - [[0, 255, 255, 255], [255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 0, 255, 255]], - [[0, 0, 255, 0], [255, 0, 0, 255], [0, 0, 255, 255], [0, 255, 255, 255]], - [[255, 255, 0, 255], [255, 0, 255, 255], [255, 0, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 255, 255], [255, 0, 0, 255], [255, 0, 255, 255], [0, 0, 0, 255]], - [[255, 0, 255, 0], [0, 0, 255, 255], [255, 255, 0, 255], [0, 0, 255, 255]], - [[255, 0, 255, 255], [255, 0, 0, 255], [0, 0, 255, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [0, 0, 255, 255], [0, 255, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint16, None, False): np.array( - [ - [[255, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255], [0, 0, 0, 255]], - [[255, 0, 255, 0], [255, 0, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255]], - [[255, 0, 255, 255], [0, 0, 255, 255], [255, 0, 0, 255], [255, 255, 255, 255]], - [[0, 0, 0, 255], [255, 0, 0, 255], [0, 255, 0, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[255, 255, 0, 255], [0, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[255, 0, 0, 0], [0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 0, 255]], - [[0, 0, 255, 255], [0, 0, 255, 255], [0, 255, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 255, 255, 255], [0, 255, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 255, 0], [0, 0, 0, 255], [0, 255, 255, 255], [0, 0, 0, 255]], - [[255, 0, 0, 255], [255, 0, 0, 255], [0, 255, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 0, 0, 255]], - [[255, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 255, 255]], - [[0, 255, 255, 255], [255, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255], [255, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 0, 255, 255]], - [[0, 255, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255], [255, 0, 255, 255]], - [[255, 255, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[255, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255], [0, 0, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", None, None, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", None, None, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", None, 232, True): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [255, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", None, 232, False): np.array( - [ - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 0, 255]], - [[0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255], [0, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", None, 13333, True): np.array( - [ - [[12, 0, 0, 255], [21, 0, 0, 255], [47, 0, 0, 255], [15, 0, 0, 255]], - [[0, 0, 0, 0], [47, 0, 0, 255], [17, 0, 0, 255], [7, 0, 0, 255]], - [[44, 0, 0, 255], [25, 0, 0, 255], [255, 0, 0, 255], [19, 0, 0, 255]], - [[36, 0, 0, 255], [48, 0, 0, 255], [14, 0, 0, 255], [13, 0, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", None, 13333, False): np.array( - [ - [[0, 0, 12, 255], [0, 0, 21, 255], [0, 0, 47, 255], [0, 0, 15, 255]], - [[0, 0, 0, 0], [0, 0, 47, 255], [0, 0, 17, 255], [0, 0, 7, 255]], - [[0, 0, 44, 255], [0, 0, 25, 255], [0, 0, 255, 255], [0, 0, 19, 255]], - [[0, 0, 36, 255], [0, 0, 48, 255], [0, 0, 14, 255], [0, 0, 13, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint16, None, True): np.array( - [ - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint16, None, False): np.array( - [ - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint16, 232, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint16, 232, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint16, 13333, True): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGB", np.uint16, 13333, False): np.array( - [ - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGB", "RGBA", None, None, True): Exception, - (np.float32, "RGB", "RGBA", None, None, False): Exception, - (np.float32, "RGB", "RGBA", None, 232, True): Exception, - (np.float32, "RGB", "RGBA", None, 232, False): Exception, - (np.float32, "RGB", "RGBA", None, 13333, True): Exception, - (np.float32, "RGB", "RGBA", None, 13333, False): Exception, - (np.float32, "RGB", "RGBA", np.uint8, None, True): Exception, - (np.float32, "RGB", "RGBA", np.uint8, None, False): Exception, - (np.float32, "RGB", "RGBA", np.uint8, 232, True): Exception, - (np.float32, "RGB", "RGBA", np.uint8, 232, False): Exception, - (np.float32, "RGB", "RGBA", np.uint8, 13333, True): Exception, - (np.float32, "RGB", "RGBA", np.uint8, 13333, False): Exception, - (np.float32, "RGB", "RGBA", np.uint16, None, True): Exception, - (np.float32, "RGB", "RGBA", np.uint16, None, False): Exception, - (np.float32, "RGB", "RGBA", np.uint16, 232, True): Exception, - (np.float32, "RGB", "RGBA", np.uint16, 232, False): Exception, - (np.float32, "RGB", "RGBA", np.uint16, 13333, True): Exception, - (np.float32, "RGB", "RGBA", np.uint16, 13333, False): Exception, - (np.float32, "RGBA", "SIMPLE", None, None, True): np.array( - [ - [[248, 159, 5, 0], [217, 237, 151, 255], [102, 203, 57, 44], [244, 177, 73, 196]], - [[29, 189, 17, 250], [168, 188, 84, 208], [198, 134, 144, 81], [208, 209, 210, 126]], - [[8, 212, 80, 241], [159, 153, 128, 236], [0, 0, 7, 0], [249, 140, 61, 88]], - [[175, 255, 216, 90], [42, 76, 23, 172], [64, 65, 205, 254], [0, 255, 148, 117]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", None, None, False): np.array( - [ - [[5, 159, 248, 0], [151, 237, 217, 255], [57, 203, 102, 44], [73, 177, 244, 196]], - [[17, 189, 29, 250], [84, 188, 168, 208], [144, 134, 198, 81], [210, 209, 208, 126]], - [[80, 212, 8, 241], [128, 153, 159, 236], [7, 0, 0, 0], [61, 140, 249, 88]], - [[216, 255, 175, 90], [23, 76, 42, 172], [205, 65, 64, 254], [148, 255, 0, 117]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", None, 232, True): np.array( - [ - [[225, 145, 5, 0], [197, 215, 138, 255], [93, 185, 51, 40], [222, 161, 66, 178]], - [[26, 172, 15, 227], [153, 171, 76, 189], [181, 122, 131, 73], [189, 190, 191, 114]], - [[7, 193, 73, 219], [144, 139, 116, 215], [0, 0, 6, 0], [227, 127, 55, 80]], - [[159, 255, 197, 82], [38, 69, 21, 157], [58, 59, 186, 231], [0, 232, 134, 107]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", None, 232, False): np.array( - [ - [[5, 145, 225, 0], [138, 215, 197, 255], [51, 185, 93, 40], [66, 161, 222, 178]], - [[15, 172, 26, 227], [76, 171, 153, 189], [131, 122, 181, 73], [191, 190, 189, 114]], - [[73, 193, 7, 219], [116, 139, 144, 215], [6, 0, 0, 0], [55, 127, 227, 80]], - [[197, 255, 159, 82], [21, 69, 38, 157], [186, 59, 58, 231], [134, 232, 0, 107]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", None, 13333, True): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 0, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", None, 13333, False): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 0, 0, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint8, None, True): np.array( - [ - [[255, 0, 0, 0], [0, 0, 0, 255], [255, 0, 0, 255], [255, 0, 0, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 0, 255, 255]], - [[255, 255, 255, 0], [0, 0, 255, 255], [255, 255, 0, 0], [0, 255, 0, 255]], - [[0, 255, 255, 255], [255, 255, 0, 255], [255, 0, 0, 255], [255, 255, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint8, None, False): np.array( - [ - [[0, 0, 255, 0], [0, 0, 0, 255], [0, 0, 255, 255], [0, 0, 255, 255]], - [[0, 0, 0, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 0, 255, 255]], - [[255, 255, 255, 0], [255, 0, 0, 255], [0, 255, 255, 0], [0, 255, 0, 255]], - [[255, 255, 0, 255], [0, 255, 255, 255], [0, 0, 255, 255], [255, 255, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint8, 232, True): np.array( - [ - [[0, 0, 0, 0], [0, 0, 255, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[255, 255, 0, 0], [0, 0, 255, 0], [0, 255, 0, 0], [0, 255, 0, 255]], - [[0, 0, 0, 0], [255, 0, 255, 0], [255, 255, 255, 0], [0, 0, 0, 255]], - [[0, 255, 0, 255], [255, 0, 0, 0], [255, 0, 255, 0], [255, 255, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint8, 232, False): np.array( - [ - [[0, 0, 0, 0], [255, 0, 0, 255], [0, 0, 0, 255], [255, 0, 255, 255]], - [[0, 255, 255, 0], [255, 0, 0, 0], [0, 255, 0, 0], [0, 255, 0, 255]], - [[0, 0, 0, 0], [255, 0, 255, 0], [255, 255, 255, 0], [0, 0, 0, 255]], - [[0, 255, 0, 255], [0, 0, 255, 0], [255, 0, 255, 0], [255, 255, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint8, 13333, True): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint8, 13333, False): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint16, None, True): np.array( - [ - [[0, 0, 255, 0], [0, 255, 255, 0], [255, 255, 0, 255], [0, 0, 0, 255]], - [[0, 255, 0, 255], [255, 255, 0, 255], [0, 0, 255, 255], [255, 0, 0, 255]], - [[0, 0, 255, 0], [255, 0, 0, 0], [255, 255, 255, 0], [0, 255, 255, 0]], - [[255, 0, 255, 0], [255, 0, 0, 255], [255, 0, 0, 0], [255, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint16, None, False): np.array( - [ - [[255, 0, 0, 0], [255, 255, 0, 0], [0, 255, 255, 255], [0, 0, 0, 255]], - [[0, 255, 0, 255], [0, 255, 255, 255], [255, 0, 0, 255], [0, 0, 255, 255]], - [[255, 0, 0, 0], [0, 0, 255, 0], [255, 255, 255, 0], [255, 255, 0, 0]], - [[255, 0, 255, 0], [0, 0, 255, 255], [0, 0, 255, 0], [0, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint16, 232, True): np.array( - [ - [[255, 0, 0, 0], [0, 0, 255, 0], [255, 0, 255, 0], [255, 0, 255, 0]], - [[0, 0, 255, 0], [255, 255, 0, 255], [0, 0, 0, 0], [255, 0, 0, 255]], - [[0, 0, 0, 255], [255, 0, 0, 0], [255, 255, 255, 0], [0, 0, 0, 0]], - [[255, 0, 0, 0], [0, 255, 255, 0], [0, 0, 255, 255], [255, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint16, 232, False): np.array( - [ - [[0, 0, 255, 0], [255, 0, 0, 0], [255, 0, 255, 0], [255, 0, 255, 0]], - [[255, 0, 0, 0], [0, 255, 255, 255], [0, 0, 0, 0], [0, 0, 255, 255]], - [[0, 0, 0, 255], [0, 0, 255, 0], [255, 255, 255, 0], [0, 0, 0, 0]], - [[0, 0, 255, 0], [255, 255, 0, 0], [255, 0, 0, 255], [0, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint16, 13333, True): np.array( - [ - [[255, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 255, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [255, 0, 0, 0], [0, 0, 255, 255]], - [[0, 0, 0, 0], [0, 0, 255, 255], [255, 255, 0, 0], [255, 255, 0, 0]], - [[255, 0, 0, 0], [0, 255, 0, 0], [0, 0, 0, 255], [255, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "SIMPLE", np.uint16, 13333, False): np.array( - [ - [[0, 0, 255, 0], [0, 0, 0, 0], [0, 0, 0, 255], [255, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 255, 0], [255, 0, 0, 255]], - [[0, 0, 0, 0], [255, 0, 0, 255], [0, 255, 255, 0], [0, 255, 255, 0]], - [[0, 0, 255, 0], [0, 255, 0, 0], [0, 0, 0, 255], [0, 0, 255, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGB", None, None, True): Exception, - (np.float32, "RGBA", "RGB", None, None, False): Exception, - (np.float32, "RGBA", "RGB", None, 232, True): Exception, - (np.float32, "RGBA", "RGB", None, 232, False): Exception, - (np.float32, "RGBA", "RGB", None, 13333, True): Exception, - (np.float32, "RGBA", "RGB", None, 13333, False): Exception, - (np.float32, "RGBA", "RGB", np.uint8, None, True): Exception, - (np.float32, "RGBA", "RGB", np.uint8, None, False): Exception, - (np.float32, "RGBA", "RGB", np.uint8, 232, True): Exception, - (np.float32, "RGBA", "RGB", np.uint8, 232, False): Exception, - (np.float32, "RGBA", "RGB", np.uint8, 13333, True): Exception, - (np.float32, "RGBA", "RGB", np.uint8, 13333, False): Exception, - (np.float32, "RGBA", "RGB", np.uint16, None, True): Exception, - (np.float32, "RGBA", "RGB", np.uint16, None, False): Exception, - (np.float32, "RGBA", "RGB", np.uint16, 232, True): Exception, - (np.float32, "RGBA", "RGB", np.uint16, 232, False): Exception, - (np.float32, "RGBA", "RGB", np.uint16, 13333, True): Exception, - (np.float32, "RGBA", "RGB", np.uint16, 13333, False): Exception, - (np.float32, "RGBA", "RGBA", None, None, True): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", None, None, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", None, 232, True): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", None, 232, False): np.array( - [ - [[0, 0, 0, 0], [0, 0, 0, 255], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - [[0, 255, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", None, 13333, True): np.array( - [ - [[0, 0, 1, 0], [0, 0, 31, 255], [0, 0, 11, 0], [0, 0, 15, 0]], - [[0, 0, 3, 0], [0, 0, 17, 0], [0, 0, 29, 0], [0, 0, 43, 0]], - [[0, 0, 16, 0], [0, 0, 26, 0], [0, 0, 1, 0], [0, 0, 12, 0]], - [[0, 255, 44, 0], [0, 0, 4, 0], [0, 0, 42, 0], [0, 0, 30, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", None, 13333, False): np.array( - [ - [[1, 0, 0, 0], [31, 0, 0, 255], [11, 0, 0, 0], [15, 0, 0, 0]], - [[3, 0, 0, 0], [17, 0, 0, 0], [29, 0, 0, 0], [43, 0, 0, 0]], - [[16, 0, 0, 0], [26, 0, 0, 0], [1, 0, 0, 0], [12, 0, 0, 0]], - [[44, 255, 0, 0], [4, 0, 0, 0], [42, 0, 0, 0], [30, 0, 0, 0]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint8, None, True): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint8, None, False): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint8, 232, True): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint8, 232, False): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint8, 13333, True): np.array( - [ - [[255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint8, 13333, False): np.array( - [ - [[0, 255, 255, 0], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 0], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint16, None, True): np.array( - [ - [[255, 255, 0, 0], [255, 255, 0, 0], [255, 255, 255, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 0, 0], [255, 255, 0, 255]], - [[255, 0, 0, 255], [255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint16, None, False): np.array( - [ - [[0, 255, 255, 0], [0, 255, 255, 0], [255, 255, 255, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [0, 255, 255, 0], [0, 255, 255, 255]], - [[0, 0, 255, 255], [255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint16, 232, True): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint16, 232, False): np.array( - [ - [[255, 255, 255, 0], [255, 255, 255, 0], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 0], [255, 255, 255, 255]], - [[255, 0, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint16, 13333, True): np.array( - [ - [[255, 255, 0, 0], [255, 255, 0, 0], [255, 255, 0, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 255]], - [[255, 255, 0, 255], [255, 255, 0, 255], [255, 255, 0, 0], [255, 255, 255, 255]], - [[255, 0, 0, 255], [255, 255, 0, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), - (np.float32, "RGBA", "RGBA", np.uint16, 13333, False): np.array( - [ - [[0, 255, 255, 0], [0, 255, 255, 0], [0, 255, 255, 255], [255, 255, 255, 255]], - [[255, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 255]], - [[0, 255, 255, 255], [0, 255, 255, 255], [0, 255, 255, 0], [255, 255, 255, 255]], - [[0, 0, 255, 255], [0, 255, 255, 255], [255, 255, 255, 255], [255, 255, 255, 255]], - ], - dtype=np.uint8, - ), -} - - -def _error_description(output, test_case): - return ( - f"'{test_case['name']}' output does not match expectations\n" - + f"\tExpected:\n{test_case['expected_output']!r}\n\n" - + f"\tReceived:\n{output!r}\n" - ) - - -def _do_something_for_every_combo(func): - for dtype in [np.uint8, np.uint16, np.float32]: - for in_fmt in ["2D", "RGB", "RGBA"]: - data = INPUTS[(dtype, in_fmt)] - for levels_name in [None, "SIMPLE", "RGB", "RGBA"]: - levels = LEVELS.get(levels_name, None) - if dtype == np.float32 and levels_name is None: - continue - for lut_type in [None, np.uint8, np.uint16]: - lut = LUTS.get(lut_type, None) - for scale in [None, 232, 13333]: - for use_rgba in [True, False]: - key = (dtype, in_fmt, levels_name, lut_type, scale, use_rgba) - func(data, key, levels, lut, scale, use_rgba) + pass def _makeARGB(*args, **kwds): @@ -4257,93 +26,190 @@ def _makeARGB(*args, **kwds): return out, alpha -def save_reference(): - """ - This saves the output (or exception type) of running makeARGB for every combo of arguments. The - output isn't fit for immediate inclusion in this file as EXPECTED_OUTPUTS, and needs some replace-all - work. - """ - with open("_unformatted_expected_outputs_", "w") as tmp_file: - - def write_expectation_to_file(data, key, levels, lut, scale, use_rgba): - try: - output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) - except Exception as e: - tmp_file.write(f"{key!r}: {type(e)}\n") - else: - tmp_file.write(f"{key!r}: {output!r},\n") - - _do_something_for_every_combo(write_expectation_to_file) - - -def test_makeARGB_against_generated_references(): - def assert_correct(data, key, levels, lut, scale, use_rgba): - expectation = EXPECTED_OUTPUTS[key] - if isinstance(expectation, type) and issubclass(expectation, Exception): - try: - _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) - except Exception as e: - assert expectation == type(e) - else: - assert False, f"makeARGB({key!r}) was supposed to raise {expectation} but didn't raise anything." - else: - output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) - assert ( - output == expectation - ).all(), f"Incorrect _makeARGB({key!r}) output! Expected:\n{expectation!r}\n Got:\n{output!r}" - - _do_something_for_every_combo(assert_correct) +@pytest.mark.filterwarnings("ignore:invalid value encountered") +@pytest.mark.parametrize('acceleration', [ + pytest.param('numpy'), + pytest.param('cupy', marks=pytest.mark.skipif('cupy' not in sys.modules, reason="CuPy not available")), + ] +) +@pytest.mark.parametrize('dtype', [np.uint8, np.uint16, np.float32]) +@pytest.mark.parametrize('in_fmt', ["2D", "RGB", "RGBA"]) +@pytest.mark.parametrize('level_name', [None, 'SIMPLE', 'RGB', 'RGBA']) +@pytest.mark.parametrize('lut_type', [None, np.uint8, np.uint16]) +@pytest.mark.parametrize('scale', [None, 232, 13333]) +@pytest.mark.parametrize('use_rgba', [True, False]) +def test_makeARGB_against_generated_references(acceleration, dtype, in_fmt, level_name, lut_type, scale, use_rgba): + if acceleration == "cupy": + setConfigOptions(useCupy=True, useNumba=False) + else: + setConfigOptions(useCupy=False, useNumba=False) + + if dtype == np.float32 and level_name is None: + pytest.skip(f"{dtype=} is not compatible with {level_name=}") + + data = INPUTS[(dtype, in_fmt)] + levels = LEVELS.get(level_name, None) + lut = LUTS.get(lut_type, None) + + key = (dtype, in_fmt, level_name, lut_type, scale, use_rgba) + expectation = EXPECTED_OUTPUTS[key] + if isinstance(expectation, type) and issubclass(expectation, Exception): + with pytest.raises(expectation) as exc_info: + _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) + assert exc_info.type is expectation, f"makeARGB({key!r}) was supposed to raise {expectation}" + else: + output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) + assert ( + output == expectation + ).all(), f"Incorrect _makeARGB({key!r}) output! Expected:\n{expectation!r}\n Got:\n{output!r}" + setConfigOptions(useCupy=False, useNumba=False) + + +@pytest.mark.parametrize('makeARGB_args,makeARGB_kwargs', + [ + pytest.param( + [np.zeros((2,), dtype='float')], + dict(), + marks=pytest.mark.xfail( + raises=TypeError, + strict=True, + reason="invalid image shape (ndim=1)" + ) + ), + pytest.param( + [np.zeros((2, 2, 7), dtype='float')], + dict(), + marks=pytest.mark.xfail( + raises=TypeError, + strict=True, + reason="invalid_image_shape (ndim=3)" + ) + ), + pytest.param( + [np.zeros((2, 2, 7), dtype='float')], + dict(), + marks=pytest.mark.xfail( + raises=Exception, + strict=True, + reason="float images require levels arg" + ) + ), + pytest.param( + [np.zeros((2, 2), dtype='float')], + dict(levels=[1]), + marks=pytest.mark.xfail( + raises=Exception, + strict=True, + reason="bad levels arg" + ) + ), + pytest.param( + [np.zeros((2, 2), dtype='float')], + dict(levels=[1, 2, 3]), + marks=pytest.mark.xfail( + raises=Exception, + strict=True, + reason="bad levels arg" + ) + ), + pytest.param( + [np.zeros((2, 2))], + dict(lut=np.zeros((10, 3), dtype='ubyte'), levels=[(0, 1)] * 3), + marks=pytest.mark.xfail( + raises=Exception, + strict=True, + reason="can't mix 3-channel levels and LUT" + ), + ), + pytest.param( + [np.zeros((2, 2, 3), dtype='float')], + dict(levels=[(1, 2)] * 4), + marks=pytest.mark.xfail( + raises=Exception, + strict=True, + reason="multichannel levels must have same number of channels as image" + ) + ), + pytest.param( + [np.zeros((2, 2, 3), dtype='float')], + dict(levels=np.zeros([3, 2, 2])), + marks=pytest.mark.xfail( + raises=Exception, + strict=True, + reason="3d levels not allowed" + ), + ) + ] +) +def test_makeARGB_exceptions(makeARGB_args, makeARGB_kwargs): + _makeARGB(*makeARGB_args, **makeARGB_kwargs) -@pytest.mark.skipif(cupy is None, reason="CuPy unavailable to test") -def test_cupy_makeARGB_against_generated_references(): - prev_setting = getConfigOption("useCupy") - try: - setConfigOption("useCupy", True) +def test_makeARGB_with_nans(): + # NaNs conversion to 0 is undefined in the C-standard + # see: https://github.com/pyqtgraph/pyqtgraph/issues/2969#issuecomment-2014924400 + # see: https://stackoverflow.com/questions/10366485/problems-casting-nan-floats-to-int - cupy = getCupy() + # nans in image + # 2d input image, one pixel is nan + im1 = np.ones((10, 12)) + im1[3, 5] = np.nan + im2, alpha = _makeARGB(im1, levels=(0, 1)) + assert alpha + assert im2[3, 5, 3] == 0 # nan pixel is transparent + assert im2[0, 0, 3] == 255 # doesn't affect other pixels - def assert_cupy_correct(data, key, levels, lut, scale, use_rgba): - data = cupy.asarray(data) - if lut is not None: - lut = cupy.asarray(lut) - expectation = EXPECTED_OUTPUTS[key] - if isinstance(expectation, type) and issubclass(expectation, Exception): - try: - _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) - except Exception as e: - assert expectation == type(e) - else: - assert False, f"makeARGB({key!r}) was supposed to raise {expectation} but didn't raise anything." - else: - expectation = cupy.asarray(expectation) - output, alpha = _makeARGB(data, lut=lut, levels=levels, scale=scale, useRGBA=use_rgba) - assert ( - output == expectation - ).all(), f"Incorrect _makeARGB({key!r}) output! Expected:\n{expectation!r}\n Got:\n{output!r}" + # With masking nans disabled, the nan pixel shouldn't be transparent + im2, alpha = _makeARGB(im1, levels=(0, 1), maskNans=False) + assert im2[3, 5, 3] == 255 # nan pixel is transparent - _do_something_for_every_combo(assert_cupy_correct) - finally: - setConfigOption("useCupy", prev_setting) + # 3d RGB input image, any color channel of a pixel is nan + im1 = np.ones((10, 12, 3)) + im1[3, 5, 1] = np.nan + im2, alpha = _makeARGB(im1, levels=(0, 1)) + assert alpha + assert im2[3, 5, 3] == 0 # nan pixel is transparent + assert im2[0, 0, 3] == 255 # doesn't affect other pixels + # 3d RGBA input image, any color channel of a pixel is nan + im1 = np.ones((10, 12, 4)) + im1[3, 5, 1] = np.nan + im2, alpha = _makeARGB(im1, levels=(0, 1), useRGBA=True) + assert alpha + assert im2[3, 5, 3] == 0 # nan pixel is transparent -@pytest.mark.filterwarnings("ignore:invalid value encountered") -def test_numba_makeARGB_against_generated_references(): - oldcfg_numba = getConfigOption("useNumba") - if not oldcfg_numba: - try: - import numba - except ImportError: - pytest.skip("Numba unavailable to test") - # useCupy needs to be set to False because it takes - # precedence over useNumba in rescaleData - oldcfg_cupy = getConfigOption("useCupy") - setConfigOption("useCupy", False) - setConfigOption("useNumba", not oldcfg_numba) - test_makeARGB_against_generated_references() - setConfigOption("useNumba", oldcfg_numba) - setConfigOption("useCupy", oldcfg_cupy) +def checkArrays(a, b): + # because pytest output is difficult to read for arrays + if not np.all(a == b): + comp = [] + for i in range(a.shape[0]): + if a.shape[1] > 1: + comp.append('[') + for j in range(a.shape[1]): + m = a[i, j] == b[i, j] + comp.append('%d,%d %s %s %s%s' % + (i, j, str(a[i, j]).ljust(15), str(b[i, j]).ljust(15), + m, ' ********' if not np.all(m) else '')) + if a.shape[1] > 1: + comp.append(']') + raise ValueError("arrays do not match:\n%s" % '\n'.join(comp)) + + +def checkImage(img, check, alpha, alphaCheck): + assert img.dtype == np.ubyte + assert alpha is alphaCheck + if alpha is False: + checkArrays(img[..., 3], 255) + + if np.isscalar(check) or check.ndim == 3: + checkArrays(img[..., :3], check) + elif check.ndim == 2: + checkArrays(img[..., :3], check[..., np.newaxis]) + elif check.ndim == 1: + checkArrays(img[..., :3], check[..., np.newaxis, np.newaxis]) + else: + raise ValueError('Invalid check array ndim') def test_makeARGB_with_human_readable_code(): @@ -4358,36 +224,6 @@ def test_makeARGB_with_human_readable_code(): # Need to check that all input values map to the correct output values, especially # at and beyond the edges of the level range. - def checkArrays(a, b): - # because py.test output is difficult to read for arrays - if not np.all(a == b): - comp = [] - for i in range(a.shape[0]): - if a.shape[1] > 1: - comp.append('[') - for j in range(a.shape[1]): - m = a[i, j] == b[i, j] - comp.append('%d,%d %s %s %s%s' % - (i, j, str(a[i, j]).ljust(15), str(b[i, j]).ljust(15), - m, ' ********' if not np.all(m) else '')) - if a.shape[1] > 1: - comp.append(']') - raise Exception("arrays do not match:\n%s" % '\n'.join(comp)) - - def checkImage(img, check, alpha, alphaCheck): - assert img.dtype == np.ubyte - assert alpha is alphaCheck - if alpha is False: - checkArrays(img[..., 3], 255) - - if np.isscalar(check) or check.ndim == 3: - checkArrays(img[..., :3], check) - elif check.ndim == 2: - checkArrays(img[..., :3], check[..., np.newaxis]) - elif check.ndim == 1: - checkArrays(img[..., :3], check[..., np.newaxis, np.newaxis]) - else: - raise Exception('invalid check array ndim') # uint8 data tests @@ -4477,61 +313,3 @@ def checkImage(img, check, alpha, alphaCheck): lut = (np.arange(1280)[::-1] // 10).astype('ubyte') im2, alpha = _makeARGB(im1, lut=lut, levels=(1, 17)) checkImage(im2, np.linspace(127.5, 0, 256).astype('ubyte'), alpha, False) - - # nans in image - - # 2d input image, one pixel is nan - im1 = np.ones((10, 12)) - im1[3, 5] = np.nan - im2, alpha = _makeARGB(im1, levels=(0, 1)) - assert alpha - assert im2[3, 5, 3] == 0 # nan pixel is transparent - assert im2[0, 0, 3] == 255 # doesn't affect other pixels - - # With masking nans disabled, the nan pixel shouldn't be transparent - im2, alpha = _makeARGB(im1, levels=(0, 1), maskNans=False) - assert im2[3, 5, 3] == 255 - - # 3d RGB input image, any color channel of a pixel is nan - im1 = np.ones((10, 12, 3)) - im1[3, 5, 1] = np.nan - im2, alpha = _makeARGB(im1, levels=(0, 1)) - assert alpha - assert im2[3, 5, 3] == 0 # nan pixel is transparent - assert im2[0, 0, 3] == 255 # doesn't affect other pixels - - # 3d RGBA input image, any color channel of a pixel is nan - im1 = np.ones((10, 12, 4)) - im1[3, 5, 1] = np.nan - im2, alpha = _makeARGB(im1, levels=(0, 1), useRGBA=True) - assert alpha - assert im2[3, 5, 3] == 0 # nan pixel is transparent - - # test sanity checks - class AssertExc(object): - def __init__(self, exc=Exception): - self.exc = exc - - def __enter__(self): - return self - - def __exit__(self, *args): - assert args[0] is self.exc, "Should have raised %s (got %s)" % (self.exc, args[0]) - return True - - with AssertExc(TypeError): # invalid image shape - _makeARGB(np.zeros((2,), dtype='float')) - with AssertExc(TypeError): # invalid image shape - _makeARGB(np.zeros((2, 2, 7), dtype='float')) - with AssertExc(): # float images require levels arg - _makeARGB(np.zeros((2, 2), dtype='float')) - with AssertExc(): # bad levels arg - _makeARGB(np.zeros((2, 2), dtype='float'), levels=[1]) - with AssertExc(): # bad levels arg - _makeARGB(np.zeros((2, 2), dtype='float'), levels=[1, 2, 3]) - with AssertExc(): # can't mix 3-channel levels and LUT - _makeARGB(np.zeros((2, 2)), lut=np.zeros((10, 3), dtype='ubyte'), levels=[(0, 1)] * 3) - with AssertExc(): # multichannel levels must have same number of channels as image - _makeARGB(np.zeros((2, 2, 3), dtype='float'), levels=[(1, 2)] * 4) - with AssertExc(): # 3d levels not allowed - _makeARGB(np.zeros((2, 2, 3), dtype='float'), levels=np.zeros([3, 2, 2])) diff --git a/tests/test_pickles.py b/tests/test_pickles.py new file mode 100644 index 0000000000..40e55bf5cc --- /dev/null +++ b/tests/test_pickles.py @@ -0,0 +1,16 @@ +import math +import pickle + +from pyqtgraph import SRTTransform + + +def test_SRTTransform(): + a = SRTTransform({'scale': 2, 'angle': math.pi / 2}) + b = pickle.loads(pickle.dumps(a)) + assert a == b + + +def test_SRTTransform3D(): + a = SRTTransform({'scale': 2, 'angle': math.pi / 2}) + b = pickle.loads(pickle.dumps(a)) + assert a == b diff --git a/tests/test_qpainterpathprivate.py b/tests/test_qpainterpathprivate.py index bfddfea31a..5ce5eef7b7 100644 --- a/tests/test_qpainterpathprivate.py +++ b/tests/test_qpainterpathprivate.py @@ -21,11 +21,6 @@ def test_qpainterpathprivate_read(): assert memory['c'][0] == 0 assert np.all(memory['c'][1:] == 1) - -@pytest.mark.skipif( - not hasattr(QtGui.QPainterPath, 'reserve'), - reason="needs Qt version >= 5.13" -) def test_qpainterpathprivate_write(): x0, y0 = 100, 200 size = 100 diff --git a/tests/test_qt.py b/tests/test_qt.py index 94dc6307f3..ca98bc22c0 100644 --- a/tests/test_qt.py +++ b/tests/test_qt.py @@ -13,12 +13,6 @@ def test_isQObjectAlive(): del o1 assert not pg.Qt.isQObjectAlive(o2) -@pytest.mark.skipif( - pg.Qt.QT_LIB == "PySide2" - and tuple(map(int, pg.Qt.PySide2.__version__.split("."))) >= (5, 14) - and tuple(map(int, pg.Qt.PySide2.__version__.split("."))) < (5, 14, 2, 2), - reason="new PySide2 doesn't have loadUi functionality" -) def test_loadUiType(): path = os.path.dirname(__file__) formClass, baseClass = pg.Qt.loadUiType(os.path.join(path, 'uictest.ui')) diff --git a/tests/test_reload.py b/tests/test_reload.py index ff86a69a00..323511b1f3 100644 --- a/tests/test_reload.py +++ b/tests/test_reload.py @@ -1,9 +1,10 @@ import os +import platform import shutil -import sys import time import pytest +from packaging.version import Version, parse import pyqtgraph as pg @@ -32,9 +33,10 @@ def remove_cache(mod): @pytest.mark.skipif( ( - (pg.Qt.QT_LIB == "PySide2" and pg.Qt.QtVersion.startswith("5.15")) - or (pg.Qt.QT_LIB == "PySide6") - ) and (sys.version_info >= (3, 9)), + pg.Qt.QT_LIB.startswith("PySide") and + parse(pg.Qt.QtVersion) < Version('6.6.0') and # not sure when exactly fixed + platform != 'Darwin' # seems to work on macOS + ), reason="Unknown Issue" ) @pytest.mark.usefixtures("tmp_module") diff --git a/tests/test_signalproxy.py b/tests/test_signalproxy.py index b0bb2764d4..c35a913716 100644 --- a/tests/test_signalproxy.py +++ b/tests/test_signalproxy.py @@ -90,7 +90,6 @@ def test_signal_proxy_no_slot_start(qapp): qapp.processEvents(QtCore.QEventLoop.ProcessEventsFlag.AllEvents, 10) assert receiver.counter == 0 - # Start a connect proxy.connectSlot(receiver.slotReceive) assert proxy.blockSignal is False sender.signalSend.emit() diff --git a/tests/test_stability.py b/tests/test_stability.py index 9a97e224b8..ac9bafd4d6 100644 --- a/tests/test_stability.py +++ b/tests/test_stability.py @@ -8,14 +8,22 @@ """ import gc import sys +import time import weakref from random import randint, seed import pyqtgraph as pg from pyqtgraph.Qt import QtTest +from pyqtgraph.util.garbage_collector import GarbageCollector app = pg.mkQApp() + +def test_garbage_collector(): + GarbageCollector(interval=0.1) + time.sleep(1) + + seed(12345) widgetTypes = [ diff --git a/tests/ui_testing.py b/tests/ui_testing.py index b56141a609..20a738987e 100644 --- a/tests/ui_testing.py +++ b/tests/ui_testing.py @@ -28,7 +28,7 @@ def resizeWindow(win, w, h, timeout=2.0): # We would like to use QTest for this purpose, but it seems to be broken. # See: http://stackoverflow.com/questions/16299779/qt-qgraphicsview-unit-testing-how-to-keep-the-mouse-in-a-pressed-state -def mousePress(widget, pos, button, modifier=None): +def mousePress(widget, pos: QtCore.QPointF, button, modifier=None): if isinstance(widget, QtWidgets.QGraphicsView): widget = widget.viewport() global_pos = QtCore.QPointF(widget.mapToGlobal(pos.toPoint())) @@ -45,7 +45,7 @@ def mousePress(widget, pos, button, modifier=None): QtWidgets.QApplication.sendEvent(widget, event) -def mouseRelease(widget, pos, button, modifier=None): +def mouseRelease(widget, pos: QtCore.QPointF, button, modifier=None): if isinstance(widget, QtWidgets.QGraphicsView): widget = widget.viewport() global_pos = QtCore.QPointF(widget.mapToGlobal(pos.toPoint())) @@ -62,10 +62,9 @@ def mouseRelease(widget, pos, button, modifier=None): QtWidgets.QApplication.sendEvent(widget, event) -def mouseMove(widget, pos, buttons=None, modifier=None): +def mouseMove(widget, pos: QtCore.QPointF, buttons=None, modifier=None): if isinstance(widget, QtWidgets.QGraphicsView): widget = widget.viewport() - global_pos = QtCore.QPointF(widget.mapToGlobal(pos.toPoint())) if modifier is None: modifier = QtCore.Qt.KeyboardModifier.NoModifier @@ -82,14 +81,14 @@ def mouseMove(widget, pos, buttons=None, modifier=None): QtWidgets.QApplication.sendEvent(widget, event) -def mouseDrag(widget, pos1, pos2, button, modifier=None): +def mouseDrag(widget, pos1: QtCore.QPointF, pos2: QtCore.QPointF, button, modifier=None): mouseMove(widget, pos1) mousePress(widget, pos1, button, modifier) mouseMove(widget, pos2, button, modifier) mouseRelease(widget, pos2, button, modifier) -def mouseClick(widget, pos, button, modifier=None): +def mouseClick(widget, pos: QtCore.QPointF, button, modifier=None): mouseMove(widget, pos) mousePress(widget, pos, button, modifier) mouseRelease(widget, pos, button, modifier) diff --git a/tests/widgets/test_histogramlutwidget.py b/tests/widgets/test_histogramlutwidget.py index 4bf1c6ff7a..ba53e0fb24 100644 --- a/tests/widgets/test_histogramlutwidget.py +++ b/tests/widgets/test_histogramlutwidget.py @@ -4,6 +4,8 @@ Tests the creation of a HistogramLUTWidget. """ + +import itertools import numpy as np import pyqtgraph as pg @@ -12,7 +14,7 @@ def testHistogramLUTWidget(): pg.mkQApp() - + win = QtWidgets.QMainWindow() win.show() @@ -33,14 +35,13 @@ def testHistogramLUTWidget(): l.addWidget(w, 0, 1) data = pg.gaussianFilter(np.random.normal(size=(256, 256, 3)), (20, 20, 0)) - for i in range(32): - for j in range(32): - data[i*8, j*8] += .1 + for i, j in itertools.product(range(32), range(32)): + data[i*8, j*8] += .1 img = pg.ImageItem(data) vb.addItem(img) vb.autoRange() w.setImageItem(img) - + QtWidgets.QApplication.processEvents() win.close() diff --git a/tests/widgets/test_matplotlibwidget.py b/tests/widgets/test_matplotlibwidget.py index 31ca2f62b6..565fe9ac80 100644 --- a/tests/widgets/test_matplotlibwidget.py +++ b/tests/widgets/test_matplotlibwidget.py @@ -8,6 +8,7 @@ import numpy as np import pytest +from packaging.version import parse, Version import pyqtgraph as pg from pyqtgraph.Qt import QtWidgets @@ -17,8 +18,8 @@ # see https://github.com/matplotlib/matplotlib/pull/24172 if ( pg.Qt.QT_LIB == "PySide6" - and tuple(map(int, pg.Qt.PySide6.__version__.split("."))) > (6, 4) - and tuple(map(int, version("matplotlib").split("."))) < (3, 6, 2) + and parse(pg.Qt.PySide6.__version__) > Version('6.4') + and parse(version("matplotlib")) < Version('3.6.2') ): pytest.skip( "matplotlib + PySide6 6.4 bug", @@ -43,7 +44,7 @@ def assert_widget_fields(mplw, parent, figsize, dpi): def test_init_with_qwidget_arguments(): """ Ensures providing only the parent argument to the constructor properly - intializes the widget to match the QWidget constructor prototype. + initializes the widget to match the QWidget constructor prototype. """ win = QtWidgets.QMainWindow() @@ -54,7 +55,7 @@ def test_init_with_qwidget_arguments(): def test_init_with_matplotlib_arguments(): """ - Tests the contructor that sets variables associated with Matplotlib and + Tests the constructor that sets variables associated with Matplotlib and abstracts away any details about the underlying QWidget parent class. """ figsize = (1.0, 3.0) diff --git a/tests/widgets/test_spinbox.py b/tests/widgets/test_spinbox.py index 977900a587..0e6036165a 100644 --- a/tests/widgets/test_spinbox.py +++ b/tests/widgets/test_spinbox.py @@ -25,6 +25,10 @@ def test_SpinBox_defaults(): (-2500.3427, '$-2500.34', dict(int=False, format='${value:0.02f}')), (1000, '1 k', dict(siPrefix=True, suffix="")), (1.45e-9, 'i = 1.45e-09 A', dict(int=False, decimals=6, suffix='A', siPrefix=False, prefix='i =')), + (0, '0 mV', dict(suffix='V', siPrefix=True, scaleAtZero=1e-3)), + (0, '0 mV', dict(suffix='V', siPrefix=True, minStep=5e-6, scaleAtZero=1e-3)), + (0, '0 mV', dict(suffix='V', siPrefix=True, step=1e-3)), + (0, '0 mV', dict(suffix='V', dec=True, siPrefix=True, minStep=15e-3)), ]) def test_SpinBox_formatting(value, expected_text, opts): sb = pg.SpinBox(**opts) @@ -33,14 +37,27 @@ def test_SpinBox_formatting(value, expected_text, opts): assert sb.value() == value assert sb.text() == expected_text + +def test_evalFunc(): + sb = pg.SpinBox(evalFunc=lambda s: 100) + + sb.lineEdit().setText('3') + sb.editingFinishedEvent() + assert sb.value() == 100 + + sb.lineEdit().setText('0') + sb.editingFinishedEvent() + assert sb.value() == 100 + + @pytest.mark.parametrize("suffix", ["", "V"]) def test_SpinBox_gui_set_value(suffix): sb = pg.SpinBox(suffix=suffix) - sb.lineEdit().setText('0.1' + suffix) + sb.lineEdit().setText(f'0.1{suffix}') sb.editingFinishedEvent() assert sb.value() == 0.1 - sb.lineEdit().setText('0.1 m' + suffix) + sb.lineEdit().setText(f'0.1 m{suffix}') sb.editingFinishedEvent() assert sb.value() == 0.1e-3 diff --git a/tox.ini b/tox.ini index a8b1314d39..2b8ebdfc40 100644 --- a/tox.ini +++ b/tox.ini @@ -1,15 +1,15 @@ [tox] envlist = ; qt 5.15.x - py{39,310,311}-pyqt5_515 - py{39,310}-pyside2_515 + py{310,311,312}-pyqt5_515 + py{310}-pyside2_515 ; qt 6.2 - py{39,310,311}-pyqt6_62 - py{39,310}-pyside6_62 + py{310,311}-pyqt6_62 + py{310}-pyside6_62 ; qt 6-newest - py{39,310,311}-{pyqt6,pyside6} + py{310,311,312}-{pyqt6,pyside6} [base] deps =