From 20f692fd7b9d770efdee27f0e38fc3e7b9e6d0a5 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 09:59:01 +0200 Subject: [PATCH 1/8] Copier update --- .copier-answers.yml | 2 +- .github/workflows/copier.yml | 25 ---------------- .github/workflows/docs.yml | 2 +- .pre-commit-config.yaml | 29 +++++------------- docs/conf.py | 6 ++-- docs/developer/coding-conventions.md | 2 +- pyproject.toml | 44 ++++++++++++++++++++++------ setup.cfg | 4 --- src/plopp/__init__.py | 3 +- tox.ini | 4 +-- 10 files changed, 52 insertions(+), 69 deletions(-) delete mode 100644 .github/workflows/copier.yml delete mode 100644 setup.cfg diff --git a/.copier-answers.yml b/.copier-answers.yml index f4b591ca..c5bc5088 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: d91bf92 +_commit: 78693de _src_path: https://github.com/scipp/copier_template.git description: Visualization library for Scipp max_python: '3.12' diff --git a/.github/workflows/copier.yml b/.github/workflows/copier.yml deleted file mode 100644 index b1fe6ce4..00000000 --- a/.github/workflows/copier.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: Copier template sync - -on: - workflow_dispatch: - schedule: - - cron: '0 1 * * 1' - -jobs: - update: - name: Sync with copier template - runs-on: 'ubuntu-latest' - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.X' - - run: pip install copier - - run: copier update --skip-answered --vcs-ref=HEAD --conflict=rej - - name: Create Pull Request - uses: peter-evans/create-pull-request@v6 - with: - title: '[CRON] Sync with copier template' - body: | - This PR updates the project to the latest version of scipp's [copier-template](https://github.com/scipp/copier_template). - Remember to check for any conflicts and resolve them. diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ab1be29a..7e5a7bc6 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -65,7 +65,7 @@ jobs: name: docs_html path: html/ - - uses: JamesIves/github-pages-deploy-action@v4.5.0 + - uses: JamesIves/github-pages-deploy-action@v4.6.0 if: ${{ inputs.publish }} with: branch: gh-pages diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 19830db7..4442b1b9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,15 +13,6 @@ repos: - id: trailing-whitespace args: [ --markdown-linebreak-ext=md ] exclude: '\.svg' - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - name: isort (python) - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.11.0 - hooks: - - id: black - repo: https://github.com/kynan/nbstripout rev: 0.6.0 hooks: @@ -29,18 +20,14 @@ repos: types: [ "jupyter" ] args: [ "--drop-empty-cells", "--extra-keys 'metadata.language_info.version cell.metadata.jp-MarkdownHeadingCollapsed cell.metadata.pycharm'" ] - - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - types: ["python"] - additional_dependencies: ["flake8-bugbear==23.9.16"] - - repo: https://github.com/pycqa/bandit - rev: 1.7.5 - hooks: - - id: bandit - additional_dependencies: ["bandit[toml]"] - args: ["-c", "pyproject.toml"] + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.4.3 + hooks: + - id: ruff + args: [ --fix ] + types_or: [ python, pyi, jupyter ] + - id: ruff-format + types_or: [ python, pyi ] - repo: https://github.com/codespell-project/codespell rev: v2.2.6 hooks: diff --git a/docs/conf.py b/docs/conf.py index e12e3256..34033c1a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,9 +9,9 @@ sys.path.insert(0, os.path.abspath('.')) # General information about the project. -project = u'Plopp' -copyright = u'2024 Scipp contributors' -author = u'Scipp contributors' +project = 'Plopp' +copyright = '2024 Scipp contributors' +author = 'Scipp contributors' html_show_sourcelink = True diff --git a/docs/developer/coding-conventions.md b/docs/developer/coding-conventions.md index b23c0eb4..4fafc18d 100644 --- a/docs/developer/coding-conventions.md +++ b/docs/developer/coding-conventions.md @@ -2,7 +2,7 @@ ## Code formatting -There are no explicit code formatting conventions since we use `black` to enforce a format. +There are no explicit code formatting conventions since we use `ruff` to enforce a format. ## Docstring format diff --git a/pyproject.toml b/pyproject.toml index e1b43a18..36fa5f12 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -67,17 +67,43 @@ filterwarnings = [ 'ignore:Cut3dTool is deprecated::', ] -[tool.bandit] -# Excluding tests because bandit doesn't like `assert`. -exclude_dirs = ["docs/conf.py", "tests"] +[tool.ruff] +line-length = 88 +extend-include = ["*.ipynb"] +extend-exclude = [ + ".*", "__pycache__", "build", "dist", "install", +] + +[tool.ruff.lint] +# See https://docs.astral.sh/ruff/rules/ +select = ["B", "C4", "DTZ", "E", "F", "G", "I", "PERF", "PGH", "PT", "PYI", "RUF", "S", "T20", "W"] +ignore = [ + # Conflict with ruff format, see + # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "COM812", "COM819", "D206", "D300", "E111", "E114", "E117", "ISC001", "ISC002", "Q000", "Q001", "Q002", "Q003", "W191", +] +fixable = ["I001", "B010"] +isort.known-first-party = ["plopp"] +pydocstyle.convention = "numpy" -[tool.black] -skip-string-normalization = true +[tool.ruff.lint.per-file-ignores] +# those files have an increased risk of relying on import order +"__init__.py" = ["I"] +"tests/*" = [ + "S101", # asserts are fine in tests + "B018", # 'useless expressions' are ok because some tests just check for exceptions +] +"*.ipynb" = [ + "E501", # longer lines are sometimes more readable + "F403", # *-imports used with domain types + "F405", # linter may fail to find names because of *-imports + "I", # we don't collect imports at the top + "S101", # asserts are used for demonstration and are safe in notebooks + "T201", # printing is ok for demonstration purposes +] -[tool.isort] -skip_gitignore = true -profile = "black" -known_first_party = ["plopp"] +[tool.ruff.format] +quote-style = "preserve" [tool.mypy] strict = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 1ba190c5..00000000 --- a/setup.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[flake8] -# See https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#line-length -max-line-length = 88 -extend-ignore = E203 diff --git a/src/plopp/__init__.py b/src/plopp/__init__.py index 56ce5bd5..dc85914b 100644 --- a/src/plopp/__init__.py +++ b/src/plopp/__init__.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2024 Scipp contributors (https://github.com/scipp) - -# flake8: noqa E402 +# ruff: noqa: E402, F401 import importlib.metadata diff --git a/tox.ini b/tox.ini index 057204e9..58113030 100644 --- a/tox.ini +++ b/tox.ini @@ -20,7 +20,7 @@ commands = pytest tests/backends/plotly [testenv:nightly] deps = -r requirements/nightly.txt -commands = pytest +commands = pytest {posargs} [testenv:unpinned] description = Test with unpinned dependencies, as a user would install now. @@ -29,7 +29,7 @@ deps = -r requirements/base.in -r requirements/optional.in plopp -commands = pytest +commands = pytest {posargs} [testenv:docs] description = invoke sphinx-build to build the HTML docs From e9b2af0bafaba905ab7beaa722e1f27744986898 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 10:17:28 +0200 Subject: [PATCH 2/8] Make ruff happy --- docs/gallery/interactive-masking.ipynb | 29 +++-- docs/gallery/masking-a-range.ipynb | 4 +- docs/gallery/peeling-layers.ipynb | 6 +- docs/gallery/polar-plots.ipynb | 8 +- docs/gallery/rectangle-selection.ipynb | 34 ++++-- docs/gallery/tiled-random-samples.ipynb | 22 ++-- docs/gallery/updating-scatter.ipynb | 15 ++- .../customization/custom-interfaces.ipynb | 4 +- docs/user-guide/customization/subplots.ipynb | 1 - docs/user-guide/plot-types/image-plot.ipynb | 4 +- .../plot-types/inspector-plot.ipynb | 4 +- docs/user-guide/plot-types/scatter-plot.ipynb | 3 +- pyproject.toml | 1 + src/plopp/backends/common.py | 2 +- src/plopp/backends/manager.py | 38 ++++-- src/plopp/backends/matplotlib/canvas.py | 20 ++-- src/plopp/backends/plotly/canvas.py | 10 +- src/plopp/backends/pythreejs/outline.py | 6 +- src/plopp/backends/pythreejs/point_cloud.py | 4 +- src/plopp/core/graph.py | 4 +- src/plopp/core/limits.py | 2 +- src/plopp/core/node.py | 2 +- src/plopp/core/typing.py | 111 ++++++------------ src/plopp/core/utils.py | 12 +- src/plopp/data/factory.py | 2 +- src/plopp/graphics/camera.py | 6 +- src/plopp/graphics/colormapper.py | 2 +- src/plopp/graphics/lineview.py | 2 +- src/plopp/graphics/scatterview.py | 2 +- src/plopp/plotting/common.py | 2 +- src/plopp/plotting/inspector.py | 4 +- src/plopp/plotting/plot.py | 2 +- src/plopp/plotting/scatter.py | 8 +- src/plopp/plotting/scatter3d.py | 10 +- src/plopp/plotting/slicer.py | 12 +- src/plopp/widgets/box.py | 8 +- src/plopp/widgets/clip3d.py | 2 +- src/plopp/widgets/linesave.py | 4 +- src/plopp/widgets/slice.py | 20 ++-- src/plopp/widgets/toolbar.py | 2 +- src/plopp/widgets/tools.py | 8 +- tests/backends/matplotlib/mpl_canvas_test.py | 2 +- tests/backends/matplotlib/mpl_figure_test.py | 7 +- .../backends/matplotlib/mpl_imageview_test.py | 4 +- .../matplotlib/mpl_interactive_test.py | 14 ++- tests/backends/matplotlib/mpl_utils_test.py | 8 +- tests/backends/plotly/conftest.py | 2 +- tests/backends/plotly/plotly_canvas_test.py | 2 +- tests/conftest.py | 8 +- tests/graphics/colormapper_test.py | 2 +- tests/graphics/imageview_test.py | 6 +- tests/graphics/lineview_test.py | 14 +-- tests/graphics/scatter3dview_test.py | 4 +- tests/graphics/scatterview_test.py | 4 +- tests/plotting/common_test.py | 2 +- tests/plotting/inspector_test.py | 24 ++-- tests/plotting/plot_1d_test.py | 4 +- tests/plotting/plot_2d_test.py | 2 +- tests/plotting/scatter3d_test.py | 6 +- tests/plotting/slicer_test.py | 48 +++++--- tests/plotting/superplot_test.py | 18 ++- tests/plotting/xyplot_test.py | 4 +- 62 files changed, 352 insertions(+), 275 deletions(-) diff --git a/docs/gallery/interactive-masking.ipynb b/docs/gallery/interactive-masking.ipynb index 485ac7ee..574e887c 100644 --- a/docs/gallery/interactive-masking.ipynb +++ b/docs/gallery/interactive-masking.ipynb @@ -26,8 +26,7 @@ "source": [ "%matplotlib widget\n", "import plopp as pp\n", - "import scipp as sc\n", - "import numpy as np" + "import scipp as sc" ] }, { @@ -170,8 +169,6 @@ }, "outputs": [], "source": [ - "from plopp.widgets import Box\n", - "\n", "data_node = pp.Node(da)\n", "\n", "\n", @@ -195,7 +192,7 @@ { "cell_type": "code", "execution_count": null, - "id": "fcf38064-eafe-407e-818c-e3516bd33195", + "id": "a5cbc934-8409-4e1c-8033-08a5388cb8ed", "metadata": { "editable": true, "nbsphinx": "hidden", @@ -211,8 +208,23 @@ "r._tool.click(50, 200)\n", "r._tool.click(200, 250)\n", "r._tool.click(30, 50)\n", - "r._tool.click(250, 170)\n", - "\n", + "r._tool.click(250, 170)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fcbbae45-4c37-49b7-9ca8-7161ba0d59f5", + "metadata": { + "editable": true, + "nbsphinx": "hidden", + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ "from ipywidgets import HBox\n", "\n", "fig.children = [\n", @@ -320,7 +332,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.10.14" } }, "nbformat": 4, diff --git a/docs/gallery/masking-a-range.ipynb b/docs/gallery/masking-a-range.ipynb index e5ea4c02..39ff0222 100644 --- a/docs/gallery/masking-a-range.ipynb +++ b/docs/gallery/masking-a-range.ipynb @@ -34,7 +34,6 @@ "%matplotlib widget\n", "import plopp as pp\n", "import scipp as sc\n", - "import numpy as np\n", "import ipywidgets as ipw" ] }, @@ -180,7 +179,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.10.14" } }, "nbformat": 4, diff --git a/docs/gallery/peeling-layers.ipynb b/docs/gallery/peeling-layers.ipynb index 9d2b9251..cc5e9afd 100644 --- a/docs/gallery/peeling-layers.ipynb +++ b/docs/gallery/peeling-layers.ipynb @@ -32,8 +32,7 @@ "outputs": [], "source": [ "import plopp as pp\n", - "import scipp as sc\n", - "import numpy as np" + "import scipp as sc" ] }, { @@ -129,7 +128,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.10.14" } }, "nbformat": 4, diff --git a/docs/gallery/polar-plots.ipynb b/docs/gallery/polar-plots.ipynb index 71be967f..95c05da3 100644 --- a/docs/gallery/polar-plots.ipynb +++ b/docs/gallery/polar-plots.ipynb @@ -48,7 +48,7 @@ "\n", "# Make the plot and tweak the axes\n", "p = pp.plot(da, ax=ax)\n", - "ax.set_xlim(0, 2*np.pi)\n", + "ax.set_xlim(0, 2 * np.pi)\n", "ax.grid(True)\n", "p" ] @@ -147,8 +147,10 @@ "phi = np.radians(np.linspace(0, 90, N))\n", "da = sc.DataArray(\n", " data=sc.array(dims=['phi', 'theta'], values=r, unit='m'),\n", - " coords={'theta': sc.array(dims=['theta'], values=theta, unit='rad'),\n", - " 'phi': sc.array(dims=['phi'], values=phi, unit='rad')},\n", + " coords={\n", + " 'theta': sc.array(dims=['theta'], values=theta, unit='rad'),\n", + " 'phi': sc.array(dims=['phi'], values=phi, unit='rad'),\n", + " },\n", ")\n", "\n", "# Make axes\n", diff --git a/docs/gallery/rectangle-selection.ipynb b/docs/gallery/rectangle-selection.ipynb index c1182f1f..503dd2aa 100644 --- a/docs/gallery/rectangle-selection.ipynb +++ b/docs/gallery/rectangle-selection.ipynb @@ -27,8 +27,7 @@ "source": [ "%matplotlib widget\n", "import plopp as pp\n", - "import scipp as sc\n", - "import numpy as np" + "import scipp as sc" ] }, { @@ -161,9 +160,14 @@ { "cell_type": "code", "execution_count": null, - "id": "4b0f4619-6d13-4acf-867e-36ae9f234040", + "id": "e077370d-941a-4910-b13a-02c5041b6297", "metadata": { - "nbsphinx": "hidden" + "editable": true, + "nbsphinx": "hidden", + "slideshow": { + "slide_type": "" + }, + "tags": [] }, "outputs": [], "source": [ @@ -172,8 +176,23 @@ "r._tool.click(50, 200)\n", "r._tool.click(200, 250)\n", "r._tool.click(30, 50)\n", - "r._tool.click(250, 170)\n", - "\n", + "r._tool.click(250, 170)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a84b4009-0eae-4512-bc78-ab7012841d3f", + "metadata": { + "editable": true, + "nbsphinx": "hidden", + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ "from ipywidgets import HBox\n", "\n", "f1 = box[0]\n", @@ -245,7 +264,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.10.14" } }, "nbformat": 4, diff --git a/docs/gallery/tiled-random-samples.ipynb b/docs/gallery/tiled-random-samples.ipynb index a68c0716..35c3db0d 100644 --- a/docs/gallery/tiled-random-samples.ipynb +++ b/docs/gallery/tiled-random-samples.ipynb @@ -49,21 +49,26 @@ " np.random.wald: {'mean': [1], 'scale': [16, 32, 64]},\n", " np.random.weibull: {'a': [2, 4, 8, 16]},\n", " np.random.f: {'dfnum': [100], 'dfden': [100]},\n", - " np.random.rayleigh: {'scale': [2, 3, 4]}\n", + " np.random.rayleigh: {'scale': [2, 3, 4]},\n", "}\n", "\n", + "\n", "def generate_kwargs(arguments_map: dict[str, list]) -> Generator[dict, None, None]:\n", " from itertools import product\n", "\n", - " key_arg_pairs = [[(key, val) for val in values] for key, values in arguments_map.items()]\n", + " key_arg_pairs = [\n", + " [(key, val) for val in values] for key, values in arguments_map.items()\n", + " ]\n", " for arguments in product(*key_arg_pairs):\n", " yield {str(args[0]): args[1] for args in arguments}\n", "\n", + "\n", "def key_arg_name(key: str, arg) -> str:\n", " return \": \".join([key, str(arg)])\n", "\n", + "\n", "def keys_args_name(**kwargs) -> str:\n", - " return \",\".join([key_arg_name(key, arg) for key, arg in kwargs.items()])\n" + " return \",\".join([key_arg_name(key, arg) for key, arg in kwargs.items()])" ] }, { @@ -75,18 +80,19 @@ "# Collect samples\n", "def sample_and_hist(pdf: Callable, size: int, **kwargs):\n", " samples = sc.array(dims=['event'], values=pdf(size=size, **kwargs), unit='1')\n", - " \n", - " return samples.hist(event=10)/len(samples)\n", "\n", - "plots = dict()\n", + " return samples.hist(event=10) / len(samples)\n", + "\n", + "\n", + "plots = {}\n", "\n", "for pdf, arguments_map in pdf_maps.items():\n", " hists = {\n", " keys_args_name(**kwargs): sample_and_hist(pdf, size=10_000, **kwargs)\n", - " for kwargs in generate_kwargs(arguments_map) \n", + " for kwargs in generate_kwargs(arguments_map)\n", " }\n", " plot = pp.plot(hists, title=f\"{pdf.__name__} distribution\", alpha=0.8, linewidth=4)\n", - " plots[pdf.__name__] = plot\n" + " plots[pdf.__name__] = plot" ] }, { diff --git a/docs/gallery/updating-scatter.ipynb b/docs/gallery/updating-scatter.ipynb index e6ead346..0e4be7ea 100644 --- a/docs/gallery/updating-scatter.ipynb +++ b/docs/gallery/updating-scatter.ipynb @@ -20,23 +20,30 @@ "import plopp as pp\n", "import scipp as sc\n", "import ipywidgets as ipw\n", + "\n", "%matplotlib widget\n", "\n", "a = pp.Node(pp.data.scatter())\n", "b = pp.Node(pp.data.scatter(seed=2) * 10.0)\n", "\n", - "slider = ipw.FloatSlider(min=0, max=60, value=30,\n", - " description='Position of orange group',\n", - " style={'description_width': 'initial'},\n", - " layout={'width': '500px'})\n", + "slider = ipw.FloatSlider(\n", + " min=0,\n", + " max=60,\n", + " value=30,\n", + " description='Position of orange group',\n", + " style={'description_width': 'initial'},\n", + " layout={'width': '500px'},\n", + ")\n", "slider_node = pp.widget_node(slider)\n", "\n", + "\n", "@pp.node\n", "def move(da, x):\n", " out = da.copy(deep=False)\n", " out.coords['x'] = da.coords['x'] + sc.scalar(x, unit=da.coords['x'].unit)\n", " return out\n", "\n", + "\n", "move_node = move(da=b, x=slider_node)\n", "\n", "f = pp.scatter({'a': a, 'b': move_node}, cbar=False)\n", diff --git a/docs/user-guide/customization/custom-interfaces.ipynb b/docs/user-guide/customization/custom-interfaces.ipynb index 401ab3c1..72663534 100644 --- a/docs/user-guide/customization/custom-interfaces.ipynb +++ b/docs/user-guide/customization/custom-interfaces.ipynb @@ -398,7 +398,9 @@ "metadata": {}, "outputs": [], "source": [ - "da.masks['close_to_300'] = abs(da.data - sc.scalar(300.0, unit='K')) < sc.scalar(1.0, unit='K')\n", + "da.masks['close_to_300'] = abs(da.data - sc.scalar(300.0, unit='K')) < sc.scalar(\n", + " 1.0, unit='K'\n", + ")\n", "da.masks['large_x'] = da.coords['x'] > sc.scalar(150.0, unit='m')\n", "da" ] diff --git a/docs/user-guide/customization/subplots.ipynb b/docs/user-guide/customization/subplots.ipynb index 168bcf30..dd7c4d79 100644 --- a/docs/user-guide/customization/subplots.ipynb +++ b/docs/user-guide/customization/subplots.ipynb @@ -114,7 +114,6 @@ "source": [ "%matplotlib inline\n", "import plopp as pp\n", - "import matplotlib.pyplot as plt\n", "\n", "da = pp.data.data3d()" ] diff --git a/docs/user-guide/plot-types/image-plot.ipynb b/docs/user-guide/plot-types/image-plot.ipynb index 7f2ad5c4..890b672d 100644 --- a/docs/user-guide/plot-types/image-plot.ipynb +++ b/docs/user-guide/plot-types/image-plot.ipynb @@ -184,7 +184,9 @@ "metadata": {}, "outputs": [], "source": [ - "da.masks['yband'] = abs(da.coords['y'] - sc.scalar(20, unit='m')) < sc.scalar(5, unit='m')\n", + "da.masks['yband'] = abs(da.coords['y'] - sc.scalar(20, unit='m')) < sc.scalar(\n", + " 5, unit='m'\n", + ")\n", "da.plot()" ] }, diff --git a/docs/user-guide/plot-types/inspector-plot.ipynb b/docs/user-guide/plot-types/inspector-plot.ipynb index 80b62e79..6f6c421e 100644 --- a/docs/user-guide/plot-types/inspector-plot.ipynb +++ b/docs/user-guide/plot-types/inspector-plot.ipynb @@ -58,7 +58,7 @@ "tool = p.children[0].toolbar['inspect']\n", "tool.value = True\n", "\n", - "for i in range(N):\n", + "for _ in range(N):\n", " x, y = 40 * np.random.random(2)\n", " tool._tool.click(x, y)\n", "\n", @@ -132,7 +132,7 @@ "source": [ "tool = p.children[0].toolbar['inspect']\n", "tool.value = True\n", - "for i in range(N):\n", + "for _ in range(N):\n", " x, y = 40 * np.random.random(2)\n", " tool._tool.click(x, y)\n", "update(p)" diff --git a/docs/user-guide/plot-types/scatter-plot.ipynb b/docs/user-guide/plot-types/scatter-plot.ipynb index ea93677b..4a31ed69 100644 --- a/docs/user-guide/plot-types/scatter-plot.ipynb +++ b/docs/user-guide/plot-types/scatter-plot.ipynb @@ -119,8 +119,7 @@ "metadata": {}, "outputs": [], "source": [ - "pp.scatter({'a': a, 'b': b},\n", - " color={'a': 'k', 'b': 'g'})" + "pp.scatter({'a': a, 'b': b}, color={'a': 'k', 'b': 'g'})" ] }, { diff --git a/pyproject.toml b/pyproject.toml index 36fa5f12..6616903e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -95,6 +95,7 @@ pydocstyle.convention = "numpy" ] "*.ipynb" = [ "E501", # longer lines are sometimes more readable + "E741", # the fonts in Jupyter and Sphinx makes these chars distinguishable "F403", # *-imports used with domain types "F405", # linter may fail to find names because of *-imports "I", # we don't collect imports at the top diff --git a/src/plopp/backends/common.py b/src/plopp/backends/common.py index 5300b4fc..052f228d 100644 --- a/src/plopp/backends/common.py +++ b/src/plopp/backends/common.py @@ -68,7 +68,7 @@ def axis_bounds( Whether to pad the limits. """ values = fix_empty_range(find_limits(x, scale=scale, pad=pad)) - bounds = {k: v for k, v in zip(keys, (val.value for val in values))} + bounds = dict(zip(keys, (val.value for val in values))) return bounds diff --git a/src/plopp/backends/manager.py b/src/plopp/backends/manager.py index b3d62c96..e40f0d97 100644 --- a/src/plopp/backends/manager.py +++ b/src/plopp/backends/manager.py @@ -56,35 +56,45 @@ def canvas2d(self, *args, **kwargs): try: _canvas2d = self._backends['2d'].canvas2d except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for canvas2d.') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for canvas2d.' + ) from None return _canvas2d(*args, **kwargs) def canvas3d(self, *args, **kwargs): try: _canvas3d = self._backends['3d'].canvas3d except AttributeError: - raise ValueError(f'Unsupported backend \'{self["3d"]}\' for canvas3d.') + raise ValueError( + f'Unsupported backend \'{self["3d"]}\' for canvas3d.' + ) from None return _canvas3d(*args, **kwargs) def line(self, *args, **kwargs): try: _line = self._backends['2d'].line except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for line (1D).') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for line (1D).' + ) from None return _line(*args, **kwargs) def image(self, *args, **kwargs): try: _image = self._backends['2d'].image except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for image (2D).') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for image (2D).' + ) from None return _image(*args, **kwargs) def scatter(self, *args, **kwargs): try: _scatter = self._backends['2d'].scatter except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for scatter.') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for scatter.' + ) from None return _scatter(*args, **kwargs) def point_cloud(self, *args, **kwargs): @@ -93,33 +103,41 @@ def point_cloud(self, *args, **kwargs): except AttributeError: raise ValueError( f'Unsupported backend \'{self["3d"]}\' for point_cloud (3D).' - ) + ) from None return _point_cloud(*args, **kwargs) def figure1d(self, *args, **kwargs): try: _figure1d = self._backends['2d'].figure1d except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for figure1d.') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for figure1d.' + ) from None return _figure1d(*args, **kwargs) def figure2d(self, *args, **kwargs): try: _figure2d = self._backends['2d'].figure2d except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for figure2d.') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for figure2d.' + ) from None return _figure2d(*args, **kwargs) def figure3d(self, *args, **kwargs): try: _figure3d = self._backends['3d'].figure3d except AttributeError: - raise ValueError(f'Unsupported backend \'{self["3d"]}\' for figure3d.') + raise ValueError( + f'Unsupported backend \'{self["3d"]}\' for figure3d.' + ) from None return _figure3d(*args, **kwargs) def tiled(self, *args, **kwargs): try: _tiled = self._backends['2d'].tiled except AttributeError: - raise ValueError(f'Unsupported backend \'{self["2d"]}\' for tiled.') + raise ValueError( + f'Unsupported backend \'{self["2d"]}\' for tiled.' + ) from None return _tiled(*args, **kwargs) diff --git a/src/plopp/backends/matplotlib/canvas.py b/src/plopp/backends/matplotlib/canvas.py index c2a6e5bf..d4e1dbfa 100644 --- a/src/plopp/backends/matplotlib/canvas.py +++ b/src/plopp/backends/matplotlib/canvas.py @@ -19,15 +19,13 @@ def _to_floats(x: np.ndarray) -> np.ndarray: return mdates.date2num(x) if np.issubdtype(x.dtype, np.datetime64) else x -def _none_if_not_finite(x: Union[float, int, None]) -> Union[float, int, None]: +def _none_if_not_finite(x: Union[float, None]) -> Union[float, int, None]: if x is None: return None return x if np.isfinite(x) else None -def _cursor_value_to_variable( - x: Union[float, int], dtype: sc.DType, unit: str -) -> sc.Variable: +def _cursor_value_to_variable(x: float, dtype: sc.DType, unit: str) -> sc.Variable: if dtype == sc.DType.datetime64: # Annoying chain of conversion but matplotlib has its own way of converting # dates to numbers (number of days since epoch), and num2date returns a python @@ -38,7 +36,7 @@ def _cursor_value_to_variable( return sc.scalar(x, unit=unit) -def _cursor_formatter(x: Union[float, int], dtype: sc.DType, unit: str) -> str: +def _cursor_formatter(x: float, dtype: sc.DType, unit: str) -> str: if dtype == sc.DType.datetime64: return mdates.num2date(x).replace(tzinfo=None).isoformat() return scalar_to_string(sc.scalar(x, unit=unit)) @@ -90,10 +88,10 @@ def __init__( ax: plt.Axes = None, cax: plt.Axes = None, figsize: Optional[Tuple[float, float]] = None, - title: str = None, + title: Optional[str] = None, grid: bool = False, - vmin: Union[sc.Variable, int, float] = None, - vmax: Union[sc.Variable, int, float] = None, + vmin: Union[sc.Variable, float] = None, + vmax: Union[sc.Variable, float] = None, autoscale: Literal['auto', 'grow'] = 'auto', aspect: Literal['auto', 'equal'] = 'auto', cbar: bool = False, @@ -218,9 +216,9 @@ def autoscale(self): line_y = sc.DataArray( data=sc.array( dims=['x', 'y'], - values=np.array([s for (s, l) in zip(segments, lengths) if l])[ - ..., 1 - ], + values=np.array( + [s for (s, length) in zip(segments, lengths) if length] + )[..., 1], ), masks={'mask': line_mask}, ) diff --git a/src/plopp/backends/plotly/canvas.py b/src/plopp/backends/plotly/canvas.py index e7f9d8ef..ae88fffd 100644 --- a/src/plopp/backends/plotly/canvas.py +++ b/src/plopp/backends/plotly/canvas.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Literal, Tuple, Union +from typing import Literal, Optional, Tuple, Union import numpy as np import scipp as sc @@ -38,10 +38,10 @@ class Canvas: def __init__( self, - figsize: Tuple[float, float] = None, - title: str = None, - vmin: Union[sc.Variable, int, float] = None, - vmax: Union[sc.Variable, int, float] = None, + figsize: Optional[Tuple[float, float]] = None, + title: Optional[str] = None, + vmin: Union[sc.Variable, float] = None, + vmax: Union[sc.Variable, float] = None, autoscale: Literal['auto', 'grow'] = 'auto', **ignored, ): diff --git a/src/plopp/backends/pythreejs/outline.py b/src/plopp/backends/pythreejs/outline.py index 764fdaaf..0c2c2ad7 100644 --- a/src/plopp/backends/pythreejs/outline.py +++ b/src/plopp/backends/pythreejs/outline.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import List, Tuple +from typing import List, Optional, Tuple import numpy as np import pythreejs as p3 @@ -77,7 +77,9 @@ class Outline(p3.Group): """ def __init__( - self, limits: Tuple[Variable, Variable, Variable], tick_size: float = None + self, + limits: Tuple[Variable, Variable, Variable], + tick_size: Optional[float] = None, ): center = [var.mean().value for var in limits] if tick_size is None: diff --git a/src/plopp/backends/pythreejs/point_cloud.py b/src/plopp/backends/pythreejs/point_cloud.py index 73df0eee..ce617fec 100644 --- a/src/plopp/backends/pythreejs/point_cloud.py +++ b/src/plopp/backends/pythreejs/point_cloud.py @@ -44,7 +44,7 @@ def __init__( y: str, z: str, data: sc.DataArray, - pixel_size: Union[sc.Variable, float, int] = 1, + pixel_size: Union[sc.Variable, float] = 1, opacity: float = 1, ): """ @@ -61,7 +61,7 @@ def __init__( self._pixel_size = pixel_size if hasattr(self._pixel_size, 'unit'): - if len(set([self._data.coords[dim].unit for dim in [x, y, z]])) > 1: + if len({self._data.coords[dim].unit for dim in [x, y, z]}) > 1: raise ValueError( f'The supplied pixel_size has unit {self._pixel_size.unit}, but ' 'the spatial coordinates do not all have the same units. In this ' diff --git a/src/plopp/core/graph.py b/src/plopp/core/graph.py index d87d7175..7f259ee7 100644 --- a/src/plopp/core/graph.py +++ b/src/plopp/core/graph.py @@ -17,7 +17,7 @@ def _make_graphviz_digraph(*args, **kwargs): "Failed to import `graphviz`. " "Use `pip install graphviz` (requires installed `graphviz` executable) or " "`conda install -c conda-forge python-graphviz`." - ) + ) from None return Digraph(*args, **kwargs) @@ -119,7 +119,7 @@ def show_graph(entry: Union[Node, View], **kwargs): labels = {} # If input is a View, get the underlying node if hasattr(entry, 'graph_nodes'): - entry = list(entry.graph_nodes.values())[0] + entry = next(iter(entry.graph_nodes.values())) _walk_graph( start=entry, nodes=nodes, diff --git a/src/plopp/core/limits.py b/src/plopp/core/limits.py index 2cca4b13..ff315ec6 100644 --- a/src/plopp/core/limits.py +++ b/src/plopp/core/limits.py @@ -69,7 +69,7 @@ def find_limits( def fix_empty_range( - lims: Tuple[sc.Variable, sc.Variable] + lims: Tuple[sc.Variable, sc.Variable], ) -> Tuple[sc.Variable, sc.Variable]: """ Range correction in case xmin == xmax diff --git a/src/plopp/core/node.py b/src/plopp/core/node.py index 8b613a68..721b486a 100644 --- a/src/plopp/core/node.py +++ b/src/plopp/core/node.py @@ -66,7 +66,7 @@ def __init__(self, func: Any, *parents: Any, **kwparents: Any) -> None: fname = getattr(self.func, "__name__", str(self.func)) self.name = f'{fname}({args_string})' else: - val_str = f'={repr(func)}' if isinstance(func, (int, float, str)) else "" + val_str = f'={func!r}' if isinstance(func, (int, float, str)) else "" self.name = f'Input <{type(func).__name__}{val_str}>' # Attempt to set children after setting name in case error message is needed diff --git a/src/plopp/core/typing.py b/src/plopp/core/typing.py index d81d1f18..a1a6ec9e 100644 --- a/src/plopp/core/typing.py +++ b/src/plopp/core/typing.py @@ -28,147 +28,110 @@ class VisibleDeprecationWarning(UserWarning): class CanvasLike(Protocol): - def autoscale(self) -> None: - ... + def autoscale(self) -> None: ... - def draw(self) -> None: - ... + def draw(self) -> None: ... - def save(self) -> None: - ... + def save(self) -> None: ... @property - def empty(self) -> bool: - ... + def empty(self) -> bool: ... @property - def title(self) -> str: - ... + def title(self) -> str: ... @title.setter - def title(self, title: str) -> None: - ... + def title(self, title: str) -> None: ... @property - def xlabel(self) -> str: - ... + def xlabel(self) -> str: ... @xlabel.setter - def xlabel(self, xlabel: str) -> None: - ... + def xlabel(self, xlabel: str) -> None: ... @property - def ylabel(self) -> str: - ... + def ylabel(self) -> str: ... @ylabel.setter - def ylabel(self, ylabel: str) -> None: - ... + def ylabel(self, ylabel: str) -> None: ... @property - def xscale(self) -> str: - ... + def xscale(self) -> str: ... @xscale.setter - def xscale(self, xscale: str) -> None: - ... + def xscale(self, xscale: str) -> None: ... @property - def yscale(self) -> str: - ... + def yscale(self) -> str: ... @yscale.setter - def yscale(self, yscale: str) -> None: - ... + def yscale(self, yscale: str) -> None: ... @property - def xmin(self) -> float: - ... + def xmin(self) -> float: ... @xmin.setter - def xmin(self, xmin: float) -> None: - ... + def xmin(self, xmin: float) -> None: ... @property - def xmax(self) -> float: - ... + def xmax(self) -> float: ... @xmax.setter - def xmax(self, xmax: float) -> None: - ... + def xmax(self, xmax: float) -> None: ... @property - def ymin(self) -> float: - ... + def ymin(self) -> float: ... @ymin.setter - def ymin(self, ymin: float) -> None: - ... + def ymin(self, ymin: float) -> None: ... @property - def ymax(self) -> float: - ... + def ymax(self) -> float: ... @ymax.setter - def ymax(self, ymax: float) -> None: - ... + def ymax(self, ymax: float) -> None: ... @property - def xrange(self) -> Tuple[float, float]: - ... + def xrange(self) -> Tuple[float, float]: ... @xrange.setter - def xrange(self, xrange: Tuple[float, float]) -> None: - ... + def xrange(self, xrange: Tuple[float, float]) -> None: ... @property - def yrange(self) -> Tuple[float, float]: - ... + def yrange(self) -> Tuple[float, float]: ... @yrange.setter - def yrange(self, yrange: Tuple[float, float]) -> None: - ... + def yrange(self, yrange: Tuple[float, float]) -> None: ... - def logx(self) -> None: - ... + def logx(self) -> None: ... - def logy(self) -> None: - ... + def logy(self) -> None: ... class ArtistLike(Protocol): - def update(self, new_values: sc.DataArray) -> None: - ... + def update(self, new_values: sc.DataArray) -> None: ... class FigureLike(Protocol): @property - def canvas(self) -> CanvasLike: - ... + def canvas(self) -> CanvasLike: ... @property - def artists(self) -> Dict[str, ArtistLike]: - ... + def artists(self) -> Dict[str, ArtistLike]: ... @property - def graph_nodes(self) -> Dict[str, Node]: - ... + def graph_nodes(self) -> Dict[str, Node]: ... @property - def id(self) -> str: - ... + def id(self) -> str: ... - def save(self, filename: str, **kwargs) -> None: - ... + def save(self, filename: str, **kwargs) -> None: ... - def update(self, *args, **kwargs) -> None: - ... + def update(self, *args, **kwargs) -> None: ... - def notify_view(self, *args, **kwargs) -> None: - ... + def notify_view(self, *args, **kwargs) -> None: ... - def copy(self, **kwargs) -> FigureLike: - ... + def copy(self, **kwargs) -> FigureLike: ... __all__ = [ diff --git a/src/plopp/core/utils.py b/src/plopp/core/utils.py index 50333222..c0da83b7 100644 --- a/src/plopp/core/utils.py +++ b/src/plopp/core/utils.py @@ -8,7 +8,9 @@ import scipp as sc -def coord_as_bin_edges(da: sc.DataArray, key: str, dim: str = None) -> sc.Variable: +def coord_as_bin_edges( + da: sc.DataArray, key: str, dim: Optional[str] = None +) -> sc.Variable: """ If coordinate ``key`` in DataArray ``da`` is already bin edges, return it unchanged. If it is midpoints, return as bin edges. @@ -70,7 +72,7 @@ def repeat(x: sc.Variable, dim: str, n: int) -> sc.Variable: def maybe_number_to_variable( - x: Union[int, float, sc.Variable], unit: Optional[str] = None + x: Union[float, sc.Variable], unit: Optional[str] = None ) -> sc.Variable: """ If the input is a raw number, convert to a variable. @@ -92,7 +94,7 @@ def maybe_number_to_variable( def maybe_variable_to_number( - x: Union[int, float, sc.Variable], unit=None + x: Union[float, sc.Variable], unit=None ) -> Union[int, float]: """ If the input is a variable, return its value. @@ -113,7 +115,7 @@ def maybe_variable_to_number( return x -def name_with_unit(var: sc.Variable, name: str = None) -> str: +def name_with_unit(var: sc.Variable, name: Optional[str] = None) -> str: """ Make a string from a variable dimension and its unit. The variable dimension can be overridden by specifying the ``name`` directly. @@ -136,7 +138,7 @@ def name_with_unit(var: sc.Variable, name: str = None) -> str: return text -def value_to_string(val: Union[int, float], precision: int = 3) -> str: +def value_to_string(val: Union[float], precision: int = 3) -> str: """ Convert a number to a human readable string. diff --git a/src/plopp/data/factory.py b/src/plopp/data/factory.py index a7faa87f..54704ad8 100644 --- a/src/plopp/data/factory.py +++ b/src/plopp/data/factory.py @@ -139,7 +139,7 @@ def data_array( return sc.DataArray(data=data, coords=coord_dict, masks=mask_dict) -def dataset(entries: List[str] = None, **kwargs) -> sc.Dataset: +def dataset(entries: Optional[List[str]] = None, **kwargs) -> sc.Dataset: """ Generate a sample ``Dataset``. See :func:`data_array` for more options. diff --git a/src/plopp/graphics/camera.py b/src/plopp/graphics/camera.py index 3b18c5d6..41ed3f4b 100644 --- a/src/plopp/graphics/camera.py +++ b/src/plopp/graphics/camera.py @@ -10,7 +10,7 @@ def _vector_to_tuple( - vector: Union[sc.Variable, Sequence[sc.Variable], Sequence[float]] + vector: Union[sc.Variable, Sequence[sc.Variable], Sequence[float]], ) -> Tuple[Union[sc.Variable, float], ...]: if isinstance(vector, sc.Variable): return (vector.fields.x, vector.fields.y, vector.fields.z) @@ -95,13 +95,13 @@ def set_units(self, xunit: str, yunit: str, zunit: str): The unit of the z axis. """ self._parsed_contents = {} - for key in set(self._raw_contents) & set(('position', 'look_at')): + for key in set(self._raw_contents) & {'position', 'look_at'}: self._parsed_contents[key] = tuple( maybe_variable_to_number(x, unit=u) for x, u in zip(self._raw_contents[key], [xunit, yunit, zunit]) ) - for key in set(self._raw_contents) & set(('near', 'far')): + for key in set(self._raw_contents) & {'near', 'far'}: if isinstance(self._raw_contents[key], sc.Variable): if not (xunit == yunit == zunit): raise sc.UnitError( diff --git a/src/plopp/graphics/colormapper.py b/src/plopp/graphics/colormapper.py index b6779003..236fea7e 100644 --- a/src/plopp/graphics/colormapper.py +++ b/src/plopp/graphics/colormapper.py @@ -18,7 +18,7 @@ from ..core.utils import maybe_variable_to_number, merge_masks -def _get_cmap(name: str, nan_color: str = None) -> Colormap: +def _get_cmap(name: str, nan_color: Optional[str] = None) -> Colormap: """ Get a colormap object from a colormap name. diff --git a/src/plopp/graphics/lineview.py b/src/plopp/graphics/lineview.py index 6c729c01..0e25a3a9 100644 --- a/src/plopp/graphics/lineview.py +++ b/src/plopp/graphics/lineview.py @@ -77,7 +77,7 @@ def __init__( aspect: Literal['auto', 'equal'] = 'auto', grid: bool = False, title: Optional[str] = None, - figsize: Tuple[float, float] = None, + figsize: Optional[Tuple[float, float]] = None, format: Optional[Literal['svg', 'png']] = None, legend: Union[bool, Tuple[float, float]] = True, **kwargs, diff --git a/src/plopp/graphics/scatterview.py b/src/plopp/graphics/scatterview.py index 948ef474..0c64a9ed 100644 --- a/src/plopp/graphics/scatterview.py +++ b/src/plopp/graphics/scatterview.py @@ -29,7 +29,7 @@ def __init__( aspect: Literal['auto', 'equal'] = 'auto', grid: bool = False, title: Optional[str] = None, - figsize: Tuple[float, float] = None, + figsize: Optional[Tuple[float, float]] = None, format: Optional[Literal['svg', 'png']] = None, legend: Union[bool, Tuple[float, float]] = True, cmap: str = 'viridis', diff --git a/src/plopp/plotting/common.py b/src/plopp/plotting/common.py index ac23def2..ef65ac82 100644 --- a/src/plopp/plotting/common.py +++ b/src/plopp/plotting/common.py @@ -155,7 +155,7 @@ def check_allowed_dtypes(da: sc.DataArray): def _all_dims_sorted(var, order='ascending'): - return all([sc.allsorted(var, dim, order=order) for dim in var.dims]) + return all(sc.allsorted(var, dim, order=order) for dim in var.dims) def preprocess( diff --git a/src/plopp/plotting/inspector.py b/src/plopp/plotting/inspector.py index ccc65e4c..0ed5ae7d 100644 --- a/src/plopp/plotting/inspector.py +++ b/src/plopp/plotting/inspector.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Dict, Literal +from typing import Dict, Literal, Optional import scipp as sc @@ -36,7 +36,7 @@ def _slice_xy(da: sc.DataArray, xy: Dict[str, Dict[str, int]]) -> sc.DataArray: def inspector( obj: Plottable, - dim: str = None, + dim: Optional[str] = None, *, operation: Literal['sum', 'mean', 'min', 'max'] = 'sum', orientation: Literal['horizontal', 'vertical'] = 'horizontal', diff --git a/src/plopp/plotting/plot.py b/src/plopp/plotting/plot.py index 84940753..7f588361 100644 --- a/src/plopp/plotting/plot.py +++ b/src/plopp/plotting/plot.py @@ -18,7 +18,7 @@ def plot( cbar: bool = True, coords: Optional[List[str]] = None, errorbars: bool = True, - figsize: Tuple[float, float] = None, + figsize: Optional[Tuple[float, float]] = None, grid: bool = False, ignore_size: bool = False, mask_color: str = 'black', diff --git a/src/plopp/plotting/scatter.py b/src/plopp/plotting/scatter.py index 3f4dea09..08dec240 100644 --- a/src/plopp/plotting/scatter.py +++ b/src/plopp/plotting/scatter.py @@ -39,11 +39,11 @@ def scatter( x: str = 'x', y: str = 'y', size: Optional[Union[str, float]] = None, - figsize: Tuple[float, float] = None, + figsize: Optional[Tuple[float, float]] = None, norm: Literal['linear', 'log'] = 'linear', - title: str = None, - vmin: Union[sc.Variable, int, float] = None, - vmax: Union[sc.Variable, int, float] = None, + title: Optional[str] = None, + vmin: Union[sc.Variable, float] = None, + vmax: Union[sc.Variable, float] = None, cbar: bool = False, cmap: str = 'viridis', **kwargs, diff --git a/src/plopp/plotting/scatter3d.py b/src/plopp/plotting/scatter3d.py index f82b9593..e11e6abb 100644 --- a/src/plopp/plotting/scatter3d.py +++ b/src/plopp/plotting/scatter3d.py @@ -42,12 +42,12 @@ def scatter3d( x: str = 'x', y: str = 'y', z: str = 'z', - pos: str = None, + pos: Optional[str] = None, figsize: Tuple[int, int] = (600, 400), norm: Literal['linear', 'log'] = 'linear', - title: str = None, - vmin: Union[sc.Variable, int, float] = None, - vmax: Union[sc.Variable, int, float] = None, + title: Optional[str] = None, + vmin: Union[sc.Variable, float] = None, + vmax: Union[sc.Variable, float] = None, cmap: str = 'viridis', camera: Optional[Camera] = None, **kwargs, @@ -102,7 +102,7 @@ def scatter3d( raise ValueError( 'Keyword "ax" detected. Embedding 3D scatter plots inside Matplotlib axes ' 'is not supported. See ' - 'https://scipp.github.io/plopp/customization/subplots.html#FAQ:-subplots-with-3D-scatter-plots' # noqa: E501 + 'https://scipp.github.io/plopp/customization/subplots.html#FAQ:-subplots-with-3D-scatter-plots' ) nodes = input_to_nodes( diff --git a/src/plopp/plotting/slicer.py b/src/plopp/plotting/slicer.py index 42c7df8d..97e24a18 100644 --- a/src/plopp/plotting/slicer.py +++ b/src/plopp/plotting/slicer.py @@ -61,11 +61,11 @@ def __init__( self, obj: PlottableMulti, *, - keep: List[str] = None, + keep: Optional[List[str]] = None, autoscale: Literal['auto', 'grow', 'fixed'] = 'auto', coords: Optional[List[str]] = None, - vmin: Union[VariableLike, int, float] = None, - vmax: Union[VariableLike, int, float] = None, + vmin: Union[VariableLike, float] = None, + vmax: Union[VariableLike, float] = None, **kwargs, ): nodes = input_to_nodes( @@ -145,11 +145,11 @@ def __init__( def slicer( obj: PlottableMulti, *, - keep: List[str] = None, + keep: Optional[List[str]] = None, autoscale: Literal['auto', 'grow', 'fixed'] = 'auto', coords: Optional[List[str]] = None, - vmin: Union[VariableLike, int, float] = None, - vmax: Union[VariableLike, int, float] = None, + vmin: Union[VariableLike, float] = None, + vmax: Union[VariableLike, float] = None, **kwargs, ) -> FigureLike: """ diff --git a/src/plopp/widgets/box.py b/src/plopp/widgets/box.py index 22e62a18..bdadcc3e 100644 --- a/src/plopp/widgets/box.py +++ b/src/plopp/widgets/box.py @@ -16,7 +16,7 @@ def add(self, obj: Widget): """ Append a widget to the list of children. """ - self.children = list(self.children) + [obj] + self.children = [*self.children, obj] def remove(self, obj: Widget): """ @@ -66,7 +66,7 @@ class Box(VBar): """ def __init__(self, widgets): - children = [] - for view in widgets: - children.append(HBar(view) if isinstance(view, (list, tuple)) else view) + children = [ + HBar(view) if isinstance(view, (list, tuple)) else view for view in widgets + ] super().__init__(children) diff --git a/src/plopp/widgets/clip3d.py b/src/plopp/widgets/clip3d.py index e92ef2b4..74f7ed22 100644 --- a/src/plopp/widgets/clip3d.py +++ b/src/plopp/widgets/clip3d.py @@ -306,7 +306,7 @@ def _add_cut(self, direction: Literal['x', 'y', 'z']): ) self._view.canvas.add(cut.outlines) self.cuts.append(cut) - self.tabs.children = list(self.tabs.children) + [cut] + self.tabs.children = [*self.tabs.children, cut] self.tabs.selected_index = len(self.cuts) - 1 self.update_controls() self.update_state() diff --git a/src/plopp/widgets/linesave.py b/src/plopp/widgets/linesave.py index c94c64eb..6d1fb674 100644 --- a/src/plopp/widgets/linesave.py +++ b/src/plopp/widgets/linesave.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from functools import partial -from typing import Any, Dict +from typing import Any, Dict, Optional import ipywidgets as ipw from matplotlib.colors import to_hex @@ -40,7 +40,7 @@ def __init__(self, data_node: Node, slider_node: Node, fig: View): def _update_container(self): self.container.children = [line['tool'] for line in self._lines.values()] - def save_line(self, change: Dict[str, Any] = None): + def save_line(self, change: Optional[Dict[str, Any]] = None): from ..widgets import ColorTool data = self._data_node.request_data() diff --git a/src/plopp/widgets/slice.py b/src/plopp/widgets/slice.py index 63aa71ee..b4f46fae 100644 --- a/src/plopp/widgets/slice.py +++ b/src/plopp/widgets/slice.py @@ -26,16 +26,16 @@ def __init__(self, da: sc.DataArray, dims: List[str], range: bool): if dim in da.coords else sc.arange(dim, da.sizes[dim], unit=None) ) - widget_args = dict( - step=1, - description=dim, - min=0, - max=da.sizes[dim] - 1, - continuous_update=True, - readout=False, - layout={"width": "200px"}, - style={'description_width': 'initial'}, - ) + widget_args = { + 'step': 1, + 'description': dim, + 'min': 0, + 'max': da.sizes[dim] - 1, + 'continuous_update': True, + 'readout': False, + 'layout': {"width": "200px"}, + 'style': {'description_width': 'initial'}, + } if range: slider = ipw.IntRangeSlider(**widget_args) else: diff --git a/src/plopp/widgets/toolbar.py b/src/plopp/widgets/toolbar.py index ebe599a7..6f3f40dc 100644 --- a/src/plopp/widgets/toolbar.py +++ b/src/plopp/widgets/toolbar.py @@ -19,7 +19,7 @@ class Toolbar(VBox): Dictionary of tools to populate the toolbar. """ - def __init__(self, tools: Dict[str, Any] = None): + def __init__(self, tools: Optional[Dict[str, Any]] = None): self.tools = {} if tools is not None: for key, tool in tools.items(): diff --git a/src/plopp/widgets/tools.py b/src/plopp/widgets/tools.py index 6118d204..667a7904 100644 --- a/src/plopp/widgets/tools.py +++ b/src/plopp/widgets/tools.py @@ -21,7 +21,7 @@ class ButtonTool(ipw.Button): All other kwargs are forwarded to ipywidgets.Button. """ - def __init__(self, callback: Callable = None, **kwargs): + def __init__(self, callback: Callable | None = None, **kwargs): super().__init__(**{**BUTTON_LAYOUT, **kwargs}) self.callback = callback self.on_click(self) @@ -109,8 +109,8 @@ def __init__( callback: Callable, options: List[str], icons: Optional[List[str]] = None, - tooltips: List[str] = None, - descriptions: List[str] = None, + tooltips: Optional[List[str]] = None, + descriptions: Optional[List[str]] = None, value: Optional[str] = None, **kwargs, ): @@ -196,7 +196,7 @@ class PanZoomTool(MultiToggleTool): Set the initially selected button. No button selected if ``None``. """ - def __init__(self, callback: Callable, value: bool = None, **kwargs): + def __init__(self, callback: Callable, value: Optional[bool] = None, **kwargs): self._callback = callback super().__init__( callback=self._panzoom, diff --git a/tests/backends/matplotlib/mpl_canvas_test.py b/tests/backends/matplotlib/mpl_canvas_test.py index 37d080b0..5d4d3071 100644 --- a/tests/backends/matplotlib/mpl_canvas_test.py +++ b/tests/backends/matplotlib/mpl_canvas_test.py @@ -52,5 +52,5 @@ def test_save_to_disk(ext): def test_save_to_disk_with_bad_extension_raises(): canvas = Canvas() - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='txt'): canvas.save(filename='plopp_fig.txt') diff --git a/tests/backends/matplotlib/mpl_figure_test.py b/tests/backends/matplotlib/mpl_figure_test.py index e824b317..0ed422a2 100644 --- a/tests/backends/matplotlib/mpl_figure_test.py +++ b/tests/backends/matplotlib/mpl_figure_test.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import numpy as np +import pytest import scipp as sc from plopp.backends.matplotlib import MatplotlibBackend @@ -17,7 +18,8 @@ def test_create_static_fig1d(): assert isinstance(fig, StaticFig) -def test_create_interactive_fig1d(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_create_interactive_fig1d(): b = MatplotlibBackend() fig = b.figure1d(View=LineView) assert isinstance(fig, InteractiveFig) @@ -29,7 +31,8 @@ def test_create_static_fig2d(): assert isinstance(fig, StaticFig) -def test_create_interactive_fig2d(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_create_interactive_fig2d(): b = MatplotlibBackend() fig = b.figure2d(View=ImageView) assert isinstance(fig, InteractiveFig) diff --git a/tests/backends/matplotlib/mpl_imageview_test.py b/tests/backends/matplotlib/mpl_imageview_test.py index 9eaa03b3..83e093b3 100644 --- a/tests/backends/matplotlib/mpl_imageview_test.py +++ b/tests/backends/matplotlib/mpl_imageview_test.py @@ -75,10 +75,10 @@ def test_with_strings_as_bin_edges_other_coord_is_bin_centers(): def test_kwargs_are_forwarded_to_artist(): da = data_array(ndim=2) fig = ImageView(Node(da), rasterized=True) - artist = list(fig.artists.values())[0] + [artist] = fig.artists.values() assert artist._mesh.get_rasterized() fig = ImageView(Node(da), rasterized=False) - artist = list(fig.artists.values())[0] + [artist] = fig.artists.values() assert not artist._mesh.get_rasterized() diff --git a/tests/backends/matplotlib/mpl_interactive_test.py b/tests/backends/matplotlib/mpl_interactive_test.py index 61d38f34..c7d84e5b 100644 --- a/tests/backends/matplotlib/mpl_interactive_test.py +++ b/tests/backends/matplotlib/mpl_interactive_test.py @@ -1,6 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +import pytest + from plopp import Node from plopp.backends.matplotlib.interactive import InteractiveFig from plopp.data.testing import data_array @@ -8,26 +10,30 @@ from plopp.graphics.lineview import LineView -def test_logx_1d_toolbar_button(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_logx_1d_toolbar_button(): da = data_array(ndim=1) fig = InteractiveFig(LineView, Node(da), scale={'xx': 'log'}) assert fig.toolbar['logx'].value -def test_logy_1d_toolbar_button(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_logy_1d_toolbar_button(): da = data_array(ndim=1) fig = InteractiveFig(LineView, Node(da), norm='log') assert fig.toolbar['logy'].value -def test_logxy_2d_toolbar_buttons(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_logxy_2d_toolbar_buttons(): da = data_array(ndim=2) fig = InteractiveFig(ImageView, Node(da), scale={'xx': 'log', 'yy': 'log'}) assert fig.toolbar['logx'].value assert fig.toolbar['logy'].value -def test_log_norm_2d_toolbar_button(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_log_norm_2d_toolbar_button(): da = data_array(ndim=2) fig = InteractiveFig(ImageView, Node(da), norm='log') assert fig.toolbar['lognorm'].value diff --git a/tests/backends/matplotlib/mpl_utils_test.py b/tests/backends/matplotlib/mpl_utils_test.py index 6e508148..c4e61f68 100644 --- a/tests/backends/matplotlib/mpl_utils_test.py +++ b/tests/backends/matplotlib/mpl_utils_test.py @@ -1,6 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +import pytest + from plopp import Node from plopp.backends.matplotlib.interactive import InteractiveFig from plopp.backends.matplotlib.static import StaticFig @@ -42,9 +44,11 @@ def test_copy_static_keeps_kwargs(): do_test_copy_keeps_kwargs(StaticFig) -def test_copy_interactive(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_copy_interactive(): do_test_copy(InteractiveFig) -def test_copy_interactive_keeps_kwargs(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_copy_interactive_keeps_kwargs(): do_test_copy_keeps_kwargs(InteractiveFig) diff --git a/tests/backends/plotly/conftest.py b/tests/backends/plotly/conftest.py index 8d82a1a3..2e5e092f 100644 --- a/tests/backends/plotly/conftest.py +++ b/tests/backends/plotly/conftest.py @@ -7,7 +7,7 @@ @pytest.fixture(autouse=True, scope='module') -def use_plotly(): +def _use_plotly(): pp.backends['2d'] = 'plotly' yield pp.backends.reset() diff --git a/tests/backends/plotly/plotly_canvas_test.py b/tests/backends/plotly/plotly_canvas_test.py index d210c856..b1f163da 100644 --- a/tests/backends/plotly/plotly_canvas_test.py +++ b/tests/backends/plotly/plotly_canvas_test.py @@ -44,5 +44,5 @@ def test_save_to_disk(ext): def test_save_to_disk_with_bad_extension_raises(): canvas = Canvas() - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='txt'): canvas.save(filename='plopp_fig.txt') diff --git a/tests/conftest.py b/tests/conftest.py index a31bf161..89ee62c5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -7,13 +7,13 @@ @pytest.fixture(autouse=True) -def reset_mpl_defaults(): +def _reset_mpl_defaults(): matplotlib.rcdefaults() matplotlib.use('Agg') @pytest.fixture(autouse=True) -def close_figures(): +def _close_figures(): """ Force closing all figures after each test case. Otherwise, the figures consume a lot of memory and matplotlib complains. @@ -23,8 +23,8 @@ def close_figures(): plt.close(fig) -@pytest.fixture -def use_ipympl(): +@pytest.fixture() +def _use_ipympl(): matplotlib.use('module://ipympl.backend_nbagg') diff --git a/tests/graphics/colormapper_test.py b/tests/graphics/colormapper_test.py index bfe7f1de..3f4b390f 100644 --- a/tests/graphics/colormapper_test.py +++ b/tests/graphics/colormapper_test.py @@ -180,7 +180,7 @@ def test_rgba(): da = data_array(ndim=2, unit='K') mapper = ColorMapper() colors = mapper.rgba(da) - assert colors.shape == da.data.shape + (4,) + assert colors.shape == (*da.data.shape, 4) def test_rgba_with_masks(): diff --git a/tests/graphics/imageview_test.py b/tests/graphics/imageview_test.py index b81b7a9e..26320b4d 100644 --- a/tests/graphics/imageview_test.py +++ b/tests/graphics/imageview_test.py @@ -35,14 +35,14 @@ def test_create_with_node(): da = data_array(ndim=2) fig = ImageView(Node(da)) assert len(fig.artists) == 1 - assert sc.identical(list(fig.artists.values())[0]._data, da) + assert sc.identical(next(iter(fig.artists.values()))._data, da) def test_create_with_bin_edges(): da = data_array(ndim=2, binedges=True) fig = ImageView(Node(da)) assert len(fig.artists) == 1 - assert sc.identical(list(fig.artists.values())[0]._data, da) + assert sc.identical(next(iter(fig.artists.values()))._data, da) def test_create_with_only_one_bin_edge_coord(): @@ -50,7 +50,7 @@ def test_create_with_only_one_bin_edge_coord(): da.coords['xx'] = sc.midpoints(da.coords['xx']) fig = ImageView(Node(da)) assert len(fig.artists) == 1 - assert sc.identical(list(fig.artists.values())[0]._data, da) + assert sc.identical(next(iter(fig.artists.values()))._data, da) def test_log_norm(): diff --git a/tests/graphics/lineview_test.py b/tests/graphics/lineview_test.py index 9381cb6d..22789e32 100644 --- a/tests/graphics/lineview_test.py +++ b/tests/graphics/lineview_test.py @@ -35,7 +35,7 @@ def test_create_with_node(): da = data_array(ndim=1) fig = LineView(Node(da)) assert len(fig.artists) == 1 - line = list(fig.artists.values())[0] + [line] = fig.artists.values() assert sc.identical(line._data, da) assert line._error is None @@ -44,10 +44,10 @@ def test_with_errorbars(): da = data_array(ndim=1, variances=True) fig = LineView(Node(da)) assert len(fig.artists) == 1 - line = list(fig.artists.values())[0] + [line] = fig.artists.values() assert line._error is not None fig = LineView(Node(da), errorbars=False) - line = list(fig.artists.values())[0] + [line] = fig.artists.values() assert line._error is None @@ -55,7 +55,7 @@ def test_with_binedges(): da = data_array(ndim=1, binedges=True) fig = LineView(Node(da)) assert len(fig.artists) == 1 - line = list(fig.artists.values())[0] + [line] = fig.artists.values() assert sc.identical(line._data, da) xdata = line._line.get_xdata() assert np.allclose(xdata, da.coords['xx'].values) @@ -73,7 +73,7 @@ def test_update_grows_limits(): da = data_array(ndim=1) fig = LineView(Node(da)) old_lims = fig.canvas.yrange - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() fig.update({key: da * 2.5}) new_lims = fig.canvas.yrange assert new_lims[0] < old_lims[0] @@ -84,7 +84,7 @@ def test_update_does_shrink_limits_if_auto_mode(): da = data_array(ndim=1) fig = LineView(Node(da), autoscale='auto') old_lims = fig.canvas.yrange - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() const = 0.5 fig.update({key: da * const}) new_lims = fig.canvas.yrange @@ -96,7 +96,7 @@ def test_update_does_not_shrink_limits_if_grow_mode(): da = data_array(ndim=1) fig = LineView(Node(da), autoscale='grow') old_lims = fig.canvas.yrange - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() fig.update({key: da * 0.5}) new_lims = fig.canvas.yrange assert new_lims[0] == old_lims[0] diff --git a/tests/graphics/scatter3dview_test.py b/tests/graphics/scatter3dview_test.py index 3848bbe6..b6202f73 100644 --- a/tests/graphics/scatter3dview_test.py +++ b/tests/graphics/scatter3dview_test.py @@ -13,7 +13,7 @@ def test_creation(): da = scatter() fig = Scatter3dView(Node(da), x='x', y='y', z='z') assert len(fig.artists) == 1 - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() assert sc.identical(fig.artists[key]._data, da) @@ -21,7 +21,7 @@ def test_update(): da = scatter() fig = Scatter3dView(Node(da), x='x', y='y', z='z') assert len(fig.artists) == 1 - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() fig.update({key: da * 3.3}) assert sc.identical(fig.artists[key]._data, da * 3.3) diff --git a/tests/graphics/scatterview_test.py b/tests/graphics/scatterview_test.py index b045f54d..d4270b0b 100644 --- a/tests/graphics/scatterview_test.py +++ b/tests/graphics/scatterview_test.py @@ -13,7 +13,7 @@ def test_creation(): da = scatter_data() fig = ScatterView(Node(da), x='x', y='y') assert len(fig.artists) == 1 - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() assert sc.identical(fig.artists[key]._data, da) @@ -21,7 +21,7 @@ def test_update(): da = scatter_data() fig = ScatterView(Node(da), x='x', y='y') assert len(fig.artists) == 1 - key = list(fig.artists.keys())[0] + [key] = fig.artists.keys() fig.update({key: da * 3.3}) assert sc.identical(fig.artists[key]._data, da * 3.3) diff --git a/tests/plotting/common_test.py b/tests/plotting/common_test.py index 4cb605af..6bb9407e 100644 --- a/tests/plotting/common_test.py +++ b/tests/plotting/common_test.py @@ -60,7 +60,7 @@ def test_preprocess_no_warning_if_dtype_cannot_be_sorted(): ) def test_preprocess_raises_for_unsupported_dtype(dtype_and_shape): dtype, shape = dtype_and_shape - x = np.random.random(shape + (5,)) + x = np.random.random((*shape, 5)) values = x / np.broadcast_to( np.linalg.norm(x, axis=tuple(range(len(shape)))), x.shape ) diff --git a/tests/plotting/inspector_test.py b/tests/plotting/inspector_test.py index 370e2205..ee436398 100644 --- a/tests/plotting/inspector_test.py +++ b/tests/plotting/inspector_test.py @@ -6,23 +6,27 @@ import plopp as pp -def test_creation(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_creation(): da = pp.data.data3d() pp.inspector(da) -def test_from_node(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_from_node(): da = pp.data.data3d() pp.inspector(pp.Node(da)) -def test_multiple_inputs_raises(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_multiple_inputs_raises(): da = pp.data.data3d() with pytest.raises(TypeError, match='Cannot convert input of type'): pp.inspector({'a': da, 'b': 2.3 * da}) -def test_bad_number_of_dims_raises(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_bad_number_of_dims_raises(): with pytest.raises( ValueError, match='The inspector plot currently only works with three-dimensional data', @@ -35,13 +39,15 @@ def test_bad_number_of_dims_raises(use_ipympl): pp.inspector(pp.data.data_array(ndim=4)) -def test_raises_ValueError_when_given_binned_data(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_raises_ValueError_when_given_binned_data(): da = sc.data.table_xyz(100).bin(x=10, y=20, z=30) with pytest.raises(ValueError, match='Cannot plot binned data'): pp.inspector(da, orientation='vertical') -def test_line_creation(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_line_creation(): da = pp.data.data3d() ip = pp.inspector(da) fig2d = ip[0][0] @@ -57,7 +63,8 @@ def test_line_creation(use_ipympl): assert len(fig1d.artists) == 2 -def test_line_removal(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_line_removal(): da = pp.data.data3d() ip = pp.inspector(da) fig2d = ip[0][0] @@ -76,7 +83,8 @@ def test_line_removal(use_ipympl): assert len(fig1d.artists) == 0 -def test_operation(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_operation(): da = pp.data.data3d() ip_sum = pp.inspector(da, operation='sum') ip_mean = pp.inspector(da, operation='mean') diff --git a/tests/plotting/plot_1d_test.py b/tests/plotting/plot_1d_test.py index 902a0af7..b3d3f6ca 100644 --- a/tests/plotting/plot_1d_test.py +++ b/tests/plotting/plot_1d_test.py @@ -220,7 +220,7 @@ def test_save_to_disk_1d(ext): def test_save_to_disk_with_bad_extension_raises(): da = data_array(ndim=1) fig = pp.plot(da) - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='txt'): fig.save(filename='plopp_fig1d.txt') @@ -263,7 +263,7 @@ def test_plot_pandas_series(): s = pd.Series(np.arange(100.0), name='MyDataSeries') p = pp.plot(s) assert p.canvas.dims['x'] == 'row' - assert list(p._view.artists.values())[0].label == 'MyDataSeries' + assert next(iter(p._view.artists.values())).label == 'MyDataSeries' def test_plot_pandas_dataframe(): diff --git a/tests/plotting/plot_2d_test.py b/tests/plotting/plot_2d_test.py index 9b0789a2..4fef69c1 100644 --- a/tests/plotting/plot_2d_test.py +++ b/tests/plotting/plot_2d_test.py @@ -94,7 +94,7 @@ def test_save_to_disk_2d(ext): def test_save_to_disk_with_bad_extension_raises(): da = data_array(ndim=2) fig = pp.plot(da) - with pytest.raises(ValueError): + with pytest.raises(ValueError, match='txt'): fig.save(filename='plopp_fig2d.txt') diff --git a/tests/plotting/scatter3d_test.py b/tests/plotting/scatter3d_test.py index 78668f8b..dca0aaa2 100644 --- a/tests/plotting/scatter3d_test.py +++ b/tests/plotting/scatter3d_test.py @@ -34,7 +34,7 @@ def test_scatter3d_dimensions_are_flattened(): coords={'position': sc.spatial.as_vectors(x, y, 0.0 * sc.units.m)}, ) p = pp.scatter3d(da, pos="position") - assert list(p.artists.values())[0].data.ndim == 1 + assert next(iter(p.artists.values())).data.ndim == 1 nz = 12 z = sc.linspace(dim='z', start=-10.0, stop=10.0, num=nz, unit='m') da = sc.DataArray( @@ -42,7 +42,7 @@ def test_scatter3d_dimensions_are_flattened(): coords={'position': sc.spatial.as_vectors(x, y, z)}, ) p = pp.scatter3d(da, pos="position") - assert list(p.artists.values())[0].data.ndim == 1 + assert next(iter(p.artists.values())).data.ndim == 1 def test_scatter3d_can_plot_scalar_data(): @@ -50,7 +50,7 @@ def test_scatter3d_can_plot_scalar_data(): data=sc.scalar(1.2), coords={'position': sc.vector(value=[1, 2, 3])} ) p = pp.scatter3d(da, pos='position') - assert list(p.artists.values())[0].data.ndim == 1 + assert next(iter(p.artists.values())).data.ndim == 1 def test_raises_ValueError_when_given_binned_data(): diff --git a/tests/plotting/slicer_test.py b/tests/plotting/slicer_test.py index 676bae9b..643da996 100644 --- a/tests/plotting/slicer_test.py +++ b/tests/plotting/slicer_test.py @@ -9,7 +9,8 @@ from plopp.plotting.slicer import Slicer -def test_creation_keep_two_dims(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_creation_keep_two_dims(): da = data_array(ndim=3) sl = Slicer(da, keep=['xx', 'yy']) assert sl.slider.value == {'zz': 0} @@ -17,7 +18,8 @@ def test_creation_keep_two_dims(use_ipympl): assert sc.identical(sl.slice_nodes[0].request_data(), da['zz', 0]) -def test_creation_keep_one_dim(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_creation_keep_one_dim(): da = data_array(ndim=3) sl = Slicer(da, keep=['xx']) assert sl.slider.value == {'zz': 0, 'yy': 0} @@ -26,7 +28,8 @@ def test_creation_keep_one_dim(use_ipympl): assert sc.identical(sl.slice_nodes[0].request_data(), da['yy', 0]['zz', 0]) -def test_update_keep_two_dims(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_update_keep_two_dims(): da = data_array(ndim=3) sl = Slicer(da, keep=['xx', 'yy']) assert sl.slider.value == {'zz': 0} @@ -36,7 +39,8 @@ def test_update_keep_two_dims(use_ipympl): assert sc.identical(sl.slice_nodes[0].request_data(), da['zz', 5]) -def test_update_keep_one_dim(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_update_keep_one_dim(): da = data_array(ndim=3) sl = Slicer(da, keep=['xx']) assert sl.slider.value == {'zz': 0, 'yy': 0} @@ -49,7 +53,8 @@ def test_update_keep_one_dim(use_ipympl): assert sc.identical(sl.slice_nodes[0].request_data(), da['yy', 5]['zz', 8]) -def test_with_dataset(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_with_dataset(): ds = dataset(ndim=2) sl = Slicer(ds, keep=['xx']) nodes = list(sl.figure.graph_nodes.values()) @@ -58,7 +63,8 @@ def test_with_dataset(use_ipympl): assert sc.identical(nodes[1].request_data(), ds['b']['yy', 5]) -def test_with_data_group(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_with_data_group(): da = data_array(ndim=2) dg = sc.DataGroup(a=da, b=da * 2.5) sl = Slicer(dg, keep=['xx']) @@ -68,7 +74,8 @@ def test_with_data_group(use_ipympl): assert sc.identical(nodes[1].request_data(), dg['b']['yy', 5]) -def test_with_dict_of_data_arrays(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_with_dict_of_data_arrays(): a = data_array(ndim=2) b = data_array(ndim=2) * 2.5 sl = Slicer({'a': a, 'b': b}, keep=['xx']) @@ -78,20 +85,23 @@ def test_with_dict_of_data_arrays(use_ipympl): assert sc.identical(nodes[1].request_data(), b['yy', 5]) -def test_with_data_arrays_same_shape_different_coord(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_with_data_arrays_same_shape_different_coord(): a = data_array(ndim=2) b = data_array(ndim=2) * 2.5 b.coords['xx'] *= 1.5 Slicer({'a': a, 'b': b}, keep=['xx']) -def test_with_data_arrays_different_shape_along_keep_dim(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_with_data_arrays_different_shape_along_keep_dim(): a = data_array(ndim=2) b = data_array(ndim=2) * 2.5 Slicer({'a': a, 'b': b['xx', :10]}, keep=['xx']) -def test_with_data_arrays_different_shape_along_non_keep_dim_raises(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_with_data_arrays_different_shape_along_non_keep_dim_raises(): a = data_array(ndim=2) b = data_array(ndim=2) * 2.5 with pytest.raises( @@ -100,19 +110,22 @@ def test_with_data_arrays_different_shape_along_non_keep_dim_raises(use_ipympl): Slicer({'a': a, 'b': b['yy', :10]}, keep=['xx']) -def test_raises_ValueError_when_given_binned_data(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_raises_ValueError_when_given_binned_data(): da = sc.data.table_xyz(100).bin(x=10, y=20) with pytest.raises(ValueError, match='Cannot plot binned data'): Slicer(da, keep=['xx']) +@pytest.mark.usefixtures('_use_ipympl') @pytest.mark.parametrize('ndim', [2, 3]) -def test_from_node(use_ipympl, ndim): +def test_from_node(ndim): da = data_array(ndim=ndim) Slicer(Node(da)) -def test_mixing_raw_data_and_nodes(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_mixing_raw_data_and_nodes(): a = data_array(ndim=2) b = 6.7 * a Slicer({'a': Node(a), 'b': Node(b)}) @@ -120,7 +133,8 @@ def test_mixing_raw_data_and_nodes(use_ipympl): Slicer({'a': Node(a), 'b': b}) -def test_raises_when_requested_keep_dims_do_not_exist(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_raises_when_requested_keep_dims_do_not_exist(): da = data_array(ndim=3) with pytest.raises( ValueError, match='Slicer plot: one or more of the requested dims to be kept' @@ -128,7 +142,8 @@ def test_raises_when_requested_keep_dims_do_not_exist(use_ipympl): Slicer(da, keep=['time']) -def test_raises_when_number_of_keep_dims_requested_is_bad(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_raises_when_number_of_keep_dims_requested_is_bad(): da = data_array(ndim=4) with pytest.raises( ValueError, match='Slicer plot: the number of dims to be kept must be 1 or 2' @@ -140,7 +155,8 @@ def test_raises_when_number_of_keep_dims_requested_is_bad(use_ipympl): Slicer(da, keep=[]) -def test_autoscale_fixed(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_autoscale_fixed(): da = sc.DataArray( data=sc.arange('x', 5 * 10 * 20).fold(dim='x', sizes={'z': 20, 'y': 10, 'x': 5}) ) diff --git a/tests/plotting/superplot_test.py b/tests/plotting/superplot_test.py index fada2ae2..0deeaf03 100644 --- a/tests/plotting/superplot_test.py +++ b/tests/plotting/superplot_test.py @@ -8,18 +8,21 @@ from plopp.plotting.superplot import superplot -def test_creation(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_creation(): da = data_array(ndim=2) sp = superplot(da, keep='xx') assert len(sp.right_bar[0]._lines) == 0 -def test_from_node(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_from_node(): da = data_array(ndim=2) superplot(Node(da)) -def test_save_line(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_save_line(): da = data_array(ndim=2) sp = superplot(da, keep='xx') tool = sp.right_bar[0] @@ -39,7 +42,8 @@ def test_save_line(use_ipympl): assert len(tool.container.children) == 2 -def test_remove_line(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_remove_line(): da = data_array(ndim=2) sp = superplot(da, keep='xx') tool = sp.right_bar[0] @@ -66,7 +70,8 @@ def test_remove_line(use_ipympl): assert len(tool.container.children) == 1 -def test_change_line_color(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_change_line_color(): da = data_array(ndim=2) sp = superplot(da, keep='xx') tool = sp.right_bar[0] @@ -76,7 +81,8 @@ def test_change_line_color(use_ipympl): assert tool._lines[line_id]['line'].color == '#000000' -def test_raises_ValueError_when_given_binned_data(use_ipympl): +@pytest.mark.usefixtures('_use_ipympl') +def test_raises_ValueError_when_given_binned_data(): da = sc.data.table_xyz(100).bin(x=10, y=20) with pytest.raises(ValueError, match='Cannot plot binned data'): superplot(da, keep='x') diff --git a/tests/plotting/xyplot_test.py b/tests/plotting/xyplot_test.py index 65cb3a8b..e28f4cdd 100644 --- a/tests/plotting/xyplot_test.py +++ b/tests/plotting/xyplot_test.py @@ -59,7 +59,7 @@ def test_xyplot_variable_kwargs(): y = sc.arange('time', 100.0, 120.0, unit='K') fig = pp.xyplot(x, y, color='red', vmin=102.0, vmax=115.0) assert np.allclose(fig.canvas.yrange, [102.0, 115.0]) - line = list(fig.artists.values())[0] + [line] = fig.artists.values() assert line.color == 'red' @@ -67,7 +67,7 @@ def test_xyplot_bin_edges(): x = sc.arange('time', 21.0, unit='s') y = sc.arange('time', 100.0, 120.0, unit='K') fig = pp.xyplot(x, y) - line = list(fig.artists.values())[0] + [line] = fig.artists.values() assert len(line._line.get_xdata()) == 21 From 766dea2af341f67b59d6b57f68b112a0bdbd77b4 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 10:43:58 +0200 Subject: [PATCH 3/8] Drop Python 3.9 --- .copier-answers.yml | 2 +- .github/workflows/python-version-ci | 2 +- conda/meta.yaml | 3 ++- docs/developer/getting-started.md | 2 +- pyproject.toml | 3 +-- tox.ini | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.copier-answers.yml b/.copier-answers.yml index c5bc5088..caf97485 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -3,7 +3,7 @@ _commit: 78693de _src_path: https://github.com/scipp/copier_template.git description: Visualization library for Scipp max_python: '3.12' -min_python: '3.9' +min_python: '3.10' namespace_package: '' nightly_deps: scipp orgname: scipp diff --git a/.github/workflows/python-version-ci b/.github/workflows/python-version-ci index bd28b9c5..c8cfe395 100644 --- a/.github/workflows/python-version-ci +++ b/.github/workflows/python-version-ci @@ -1 +1 @@ -3.9 +3.10 diff --git a/conda/meta.yaml b/conda/meta.yaml index bae3b67b..5723e2a9 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -19,7 +19,8 @@ requirements: - setuptools - setuptools_scm run: - - python>=3.9 + - python>=3.10 + {% for package in dependencies %} - {% if package == "graphviz" %}python-graphviz{% else %}{{ package }}{% endif %} {% endfor %} diff --git a/docs/developer/getting-started.md b/docs/developer/getting-started.md index 046d5978..a196f562 100644 --- a/docs/developer/getting-started.md +++ b/docs/developer/getting-started.md @@ -40,7 +40,7 @@ Alternatively, if you want a different workflow, take a look at ``tox.ini`` or ` Run the tests using ```sh -tox -e py39 +tox -e py310 ``` (or just `tox` if you want to run all environments). diff --git a/pyproject.toml b/pyproject.toml index 6616903e..cab79c7d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,14 +18,13 @@ classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Scientific/Engineering", "Typing :: Typed", ] -requires-python = ">=3.9" +requires-python = ">=3.10" # IMPORTANT: # Run 'tox -e deps' after making changes here. This will update requirement files. diff --git a/tox.ini b/tox.ini index 58113030..b83a0854 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,5 @@ [tox] -envlist = py39 +envlist = py310 isolated_build = true [testenv] From 695be663ceb6a2232e59c6624abb9253809a08e3 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 10:51:23 +0200 Subject: [PATCH 4/8] Apply pyupgrade fixes --- docs/gallery/tiled-random-samples.ipynb | 2 +- requirements/make_base.py | 3 +-- src/plopp/backends/common.py | 14 +++++------ src/plopp/backends/matplotlib/canvas.py | 22 ++++++++-------- src/plopp/backends/matplotlib/image.py | 3 +-- src/plopp/backends/matplotlib/line.py | 3 +-- src/plopp/backends/matplotlib/scatter.py | 3 +-- src/plopp/backends/matplotlib/tiled.py | 12 ++++----- src/plopp/backends/matplotlib/utils.py | 6 ++--- src/plopp/backends/plotly/canvas.py | 18 ++++++------- src/plopp/backends/plotly/line.py | 3 +-- src/plopp/backends/pythreejs/canvas.py | 18 ++++++------- src/plopp/backends/pythreejs/outline.py | 17 ++++++------- src/plopp/backends/pythreejs/point_cloud.py | 5 ++-- src/plopp/core/graph.py | 3 +-- src/plopp/core/helpers.py | 3 ++- src/plopp/core/limits.py | 8 +++--- src/plopp/core/node.py | 22 ++++++++-------- src/plopp/core/typing.py | 18 ++++++------- src/plopp/core/utils.py | 23 +++++++---------- src/plopp/core/view.py | 4 +-- src/plopp/data/factory.py | 11 ++++---- src/plopp/graphics/camera.py | 28 +++++++++------------ src/plopp/graphics/colormapper.py | 14 +++++------ src/plopp/graphics/imageview.py | 14 +++++------ src/plopp/graphics/lineview.py | 16 ++++++------ src/plopp/graphics/scatter3dview.py | 14 +++++------ src/plopp/graphics/scatterview.py | 18 ++++++------- src/plopp/plotting/common.py | 15 +++++------ src/plopp/plotting/inspector.py | 6 ++--- src/plopp/plotting/plot.py | 16 ++++++------ src/plopp/plotting/scatter.py | 16 ++++++------ src/plopp/plotting/scatter3d.py | 18 ++++++------- src/plopp/plotting/slicer.py | 18 ++++++------- src/plopp/plotting/superplot.py | 3 +-- src/plopp/plotting/xyplot.py | 5 ++-- src/plopp/utils.py | 2 +- src/plopp/widgets/box.py | 2 +- src/plopp/widgets/checkboxes.py | 6 ++--- src/plopp/widgets/clip3d.py | 19 +++++++------- src/plopp/widgets/cut3d.py | 10 ++++---- src/plopp/widgets/debounce.py | 2 +- src/plopp/widgets/drawing.py | 5 ++-- src/plopp/widgets/linesave.py | 8 +++--- src/plopp/widgets/slice.py | 15 +++++------ src/plopp/widgets/toolbar.py | 8 +++--- src/plopp/widgets/tools.py | 16 ++++++------ 47 files changed, 250 insertions(+), 265 deletions(-) diff --git a/docs/gallery/tiled-random-samples.ipynb b/docs/gallery/tiled-random-samples.ipynb index 35c3db0d..83e43e73 100644 --- a/docs/gallery/tiled-random-samples.ipynb +++ b/docs/gallery/tiled-random-samples.ipynb @@ -18,7 +18,7 @@ "import numpy as np\n", "import scipp as sc\n", "import plopp as pp\n", - "from typing import Callable, Generator" + "from collections.abc import Callable, Generator" ] }, { diff --git a/requirements/make_base.py b/requirements/make_base.py index 1e1f48e3..68a17e84 100644 --- a/requirements/make_base.py +++ b/requirements/make_base.py @@ -1,7 +1,6 @@ import sys from argparse import ArgumentParser from pathlib import Path -from typing import List import tomli @@ -20,7 +19,7 @@ """ -def write_dependencies(dependency_name: str, dependencies: List[str]) -> None: +def write_dependencies(dependency_name: str, dependencies: list[str]) -> None: path = Path(f"{dependency_name}.in") if path.exists(): sections = path.read_text().split(CUSTOM_AUTO_SEPARATOR) diff --git a/src/plopp/backends/common.py b/src/plopp/backends/common.py index 052f228d..0a23e103 100644 --- a/src/plopp/backends/common.py +++ b/src/plopp/backends/common.py @@ -4,7 +4,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Dict, Literal, Optional, Tuple +from typing import Literal import numpy as np import scipp as sc @@ -27,10 +27,10 @@ class BoundingBox: A bounding box in 2D space. """ - xmin: Optional[float] = None - xmax: Optional[float] = None - ymin: Optional[float] = None - ymax: Optional[float] = None + xmin: float | None = None + xmax: float | None = None + ymin: float | None = None + ymax: float | None = None def union(self, other: BoundingBox) -> BoundingBox: """ @@ -46,11 +46,11 @@ def union(self, other: BoundingBox) -> BoundingBox: def axis_bounds( - keys: Tuple[str, str], + keys: tuple[str, str], x: sc.DataArray, scale: Literal['linear', 'log'], pad=False, -) -> Dict[str, float]: +) -> dict[str, float]: """ Find sensible limits for an axis, depending on linear or log scale. diff --git a/src/plopp/backends/matplotlib/canvas.py b/src/plopp/backends/matplotlib/canvas.py index d4e1dbfa..accce25b 100644 --- a/src/plopp/backends/matplotlib/canvas.py +++ b/src/plopp/backends/matplotlib/canvas.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Literal, Optional, Tuple, Union +from typing import Literal import matplotlib.pyplot as plt import numpy as np @@ -19,7 +19,7 @@ def _to_floats(x: np.ndarray) -> np.ndarray: return mdates.date2num(x) if np.issubdtype(x.dtype, np.datetime64) else x -def _none_if_not_finite(x: Union[float, None]) -> Union[float, int, None]: +def _none_if_not_finite(x: float | None) -> float | int | None: if x is None: return None return x if np.isfinite(x) else None @@ -87,15 +87,15 @@ def __init__( self, ax: plt.Axes = None, cax: plt.Axes = None, - figsize: Optional[Tuple[float, float]] = None, - title: Optional[str] = None, + figsize: tuple[float, float] | None = None, + title: str | None = None, grid: bool = False, - vmin: Union[sc.Variable, float] = None, - vmax: Union[sc.Variable, float] = None, + vmin: sc.Variable | float = None, + vmax: sc.Variable | float = None, autoscale: Literal['auto', 'grow'] = 'auto', aspect: Literal['auto', 'equal'] = 'auto', cbar: bool = False, - legend: Union[bool, Tuple[float, float]] = True, + legend: bool | tuple[float, float] = True, **ignored, ): # Note on the `**ignored`` keyword arguments: the figure which owns the canvas @@ -431,14 +431,14 @@ def xmax(self, value: float): self.ax.set_xlim(self.xmin, value) @property - def xrange(self) -> Tuple[float, float]: + def xrange(self) -> tuple[float, float]: """ Get or set the range/limits of the x-axis. """ return self.ax.get_xlim() @xrange.setter - def xrange(self, value: Tuple[float, float]): + def xrange(self, value: tuple[float, float]): self.ax.set_xlim(value) @property @@ -464,14 +464,14 @@ def ymax(self, value: float): self.ax.set_ylim(self.ymin, value) @property - def yrange(self) -> Tuple[float, float]: + def yrange(self) -> tuple[float, float]: """ Get or set the range/limits of the y-axis. """ return self.ax.get_ylim() @yrange.setter - def yrange(self, value: Tuple[float, float]): + def yrange(self, value: tuple[float, float]): self.ax.set_ylim(value) @property diff --git a/src/plopp/backends/matplotlib/image.py b/src/plopp/backends/matplotlib/image.py index 7aed9697..007c694d 100644 --- a/src/plopp/backends/matplotlib/image.py +++ b/src/plopp/backends/matplotlib/image.py @@ -2,7 +2,6 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import uuid -from typing import Tuple import numpy as np import scipp as sc @@ -183,7 +182,7 @@ def update(self, new_values: sc.DataArray): self._data_with_bin_edges.data = new_values.data def format_coord( - self, xslice: Tuple[str, sc.Variable], yslice: Tuple[str, sc.Variable] + self, xslice: tuple[str, sc.Variable], yslice: tuple[str, sc.Variable] ) -> str: """ Format the coordinates of the mouse pointer to show the value of the diff --git a/src/plopp/backends/matplotlib/line.py b/src/plopp/backends/matplotlib/line.py index ee3d5fcc..388db7a9 100644 --- a/src/plopp/backends/matplotlib/line.py +++ b/src/plopp/backends/matplotlib/line.py @@ -2,7 +2,6 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import uuid -from typing import Dict import numpy as np import scipp as sc @@ -69,7 +68,7 @@ def __init__(self, canvas: Canvas, data: sc.DataArray, number: int = 0, **kwargs def _make_line( self, - data: Dict, + data: dict, number: int, errorbars: bool = True, mask_color: str = 'black', diff --git a/src/plopp/backends/matplotlib/scatter.py b/src/plopp/backends/matplotlib/scatter.py index e7bd2c48..d6efc495 100644 --- a/src/plopp/backends/matplotlib/scatter.py +++ b/src/plopp/backends/matplotlib/scatter.py @@ -2,7 +2,6 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import uuid -from typing import Optional import numpy as np import scipp as sc @@ -22,7 +21,7 @@ def __init__( data: sc.DataArray, x: str = 'x', y: str = 'y', - size: Optional[str] = None, + size: str | None = None, number: int = 0, mask_color: str = 'black', cbar: bool = False, diff --git a/src/plopp/backends/matplotlib/tiled.py b/src/plopp/backends/matplotlib/tiled.py index 1bab7189..9a9e474a 100644 --- a/src/plopp/backends/matplotlib/tiled.py +++ b/src/plopp/backends/matplotlib/tiled.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Any, Optional, Tuple, Union +from typing import Any import numpy as np from matplotlib import gridspec @@ -67,7 +67,7 @@ def __init__( self, nrows: int, ncols: int, - figsize: Optional[Tuple[float, float]] = None, + figsize: tuple[float, float] | None = None, **kwargs: Any, ) -> None: self.nrows = nrows @@ -88,7 +88,7 @@ def __init__( def __setitem__( self, - inds: Union[int, slice, Tuple[int, int], Tuple[slice, slice]], + inds: int | slice | tuple[int, int] | tuple[slice, slice], view: FigureLike, ) -> None: new_view = copy_figure(view, ax=self.fig.add_subplot(self.gs[inds])) @@ -96,7 +96,7 @@ def __setitem__( self._history.append((inds, new_view)) def __getitem__( - self, inds: Union[int, slice, Tuple[int, int], Tuple[slice, slice]] + self, inds: int | slice | tuple[int, int] | tuple[slice, slice] ) -> FigureLike: return self.views[inds] @@ -161,7 +161,7 @@ def __truediv__(self, other: Tiled) -> Tiled: return out -def hstack(left: Union[Tiled, FigureLike], right: Union[Tiled, FigureLike]) -> Tiled: +def hstack(left: Tiled | FigureLike, right: Tiled | FigureLike) -> Tiled: """ Display two views side by side. @@ -189,7 +189,7 @@ def hstack(left: Union[Tiled, FigureLike], right: Union[Tiled, FigureLike]) -> T return t + right -def vstack(top: Union[Tiled, FigureLike], bottom: Union[Tiled, FigureLike]) -> Tiled: +def vstack(top: Tiled | FigureLike, bottom: Tiled | FigureLike) -> Tiled: """ Display two views on top of each other. diff --git a/src/plopp/backends/matplotlib/utils.py b/src/plopp/backends/matplotlib/utils.py index f4abd6c9..cc8b737b 100644 --- a/src/plopp/backends/matplotlib/utils.py +++ b/src/plopp/backends/matplotlib/utils.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from io import BytesIO -from typing import Literal, Tuple, Union +from typing import Literal import matplotlib as mpl from matplotlib.pyplot import Figure, _get_backend_mod @@ -56,12 +56,12 @@ def make_figure(*args, **kwargs) -> Figure: return manager.canvas.figure -def make_legend(leg: Union[bool, Tuple[float, float]]): +def make_legend(leg: bool | tuple[float, float]): """ Create a dict of arguments to be used in the legend creation. """ leg_args = {} - if isinstance(leg, (list, tuple)): + if isinstance(leg, list | tuple): leg_args = {'loc': leg} elif not isinstance(leg, bool): raise TypeError(f"Legend must be a bool, tuple, or a list, not {type(leg)}") diff --git a/src/plopp/backends/plotly/canvas.py b/src/plopp/backends/plotly/canvas.py index ae88fffd..993a8cb3 100644 --- a/src/plopp/backends/plotly/canvas.py +++ b/src/plopp/backends/plotly/canvas.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Literal, Optional, Tuple, Union +from typing import Literal import numpy as np import scipp as sc @@ -38,10 +38,10 @@ class Canvas: def __init__( self, - figsize: Optional[Tuple[float, float]] = None, - title: Optional[str] = None, - vmin: Union[sc.Variable, float] = None, - vmax: Union[sc.Variable, float] = None, + figsize: tuple[float, float] | None = None, + title: str | None = None, + vmin: sc.Variable | float = None, + vmax: sc.Variable | float = None, autoscale: Literal['auto', 'grow'] = 'auto', **ignored, ): @@ -258,14 +258,14 @@ def xmax(self, value: float): self.fig.layout.xaxis.range = [self.xmin, value] @property - def xrange(self) -> Tuple[float, float]: + def xrange(self) -> tuple[float, float]: """ Get or set the range/limits of the x-axis. """ return self.fig.layout.xaxis.range @xrange.setter - def xrange(self, value: Tuple[float, float]): + def xrange(self, value: tuple[float, float]): self.fig.layout.xaxis.range = value @property @@ -291,14 +291,14 @@ def ymax(self, value: float): self.fig.layout.yaxis.range = [self.ymin, value] @property - def yrange(self) -> Tuple[float, float]: + def yrange(self) -> tuple[float, float]: """ Get or set the range/limits of the y-axis. """ return self.fig.layout.yaxis.range @yrange.setter - def yrange(self, value: Tuple[float, float]): + def yrange(self, value: tuple[float, float]): self.fig.layout.yaxis.range = value def reset_mode(self): diff --git a/src/plopp/backends/plotly/line.py b/src/plopp/backends/plotly/line.py index 30df85b4..debfd535 100644 --- a/src/plopp/backends/plotly/line.py +++ b/src/plopp/backends/plotly/line.py @@ -2,7 +2,6 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import uuid -from typing import Dict import numpy as np import scipp as sc @@ -63,7 +62,7 @@ def __init__(self, canvas: Canvas, data: sc.DataArray, number: int = 0, **kwargs def _make_line( self, - data: Dict, + data: dict, number: int, errorbars: bool = True, mask_color: str = 'black', diff --git a/src/plopp/backends/pythreejs/canvas.py b/src/plopp/backends/pythreejs/canvas.py index f48fe7bd..4c4e8ea7 100644 --- a/src/plopp/backends/pythreejs/canvas.py +++ b/src/plopp/backends/pythreejs/canvas.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from copy import copy -from typing import Any, Optional, Tuple +from typing import Any import ipywidgets as ipw import numpy as np @@ -32,9 +32,9 @@ class Canvas: def __init__( self, - figsize: Tuple[int, int] = (600, 400), - title: Optional[str] = None, - camera: Optional[Camera] = None, + figsize: tuple[int, int] = (600, 400), + title: str | None = None, + camera: Camera | None = None, ): import pythreejs as p3 @@ -85,7 +85,7 @@ def set_axes(self, dims, units, dtypes): self.dims = dims self.dtypes = dtypes - def make_outline(self, limits: Tuple[sc.Variable, sc.Variable, sc.Variable]): + def make_outline(self, limits: tuple[sc.Variable, sc.Variable, sc.Variable]): """ Create an outline box with ticklabels, given a range in the XYZ directions. """ @@ -98,7 +98,7 @@ def make_outline(self, limits: Tuple[sc.Variable, sc.Variable, sc.Variable]): self._update_camera(limits=limits) self.axes_3d.scale = [self.camera.far] * 3 - def _update_camera(self, limits: Tuple[sc.Variable, sc.Variable, sc.Variable]): + def _update_camera(self, limits: tuple[sc.Variable, sc.Variable, sc.Variable]): """ Update the camera position when a new object is added to the canvas. The camera will look at the mean position of all the objects, and its position @@ -185,7 +185,7 @@ def camera_z_normal(self): """ self._camera_normal(position=self.camera_backup["z_normal"].copy(), ind=2) - def _camera_normal(self, position: Tuple[float, float, float], ind: int): + def _camera_normal(self, position: tuple[float, float, float], ind: int): """ Move camera to requested normal, and flip if current position is equal to the requested position. @@ -196,8 +196,8 @@ def _camera_normal(self, position: Tuple[float, float, float], ind: int): def move_camera( self, - position: Tuple[float, float, float], - look_at: Optional[Tuple[float, float, float]] = None, + position: tuple[float, float, float], + look_at: tuple[float, float, float] | None = None, ): """ Move the camera to the supplied position. diff --git a/src/plopp/backends/pythreejs/outline.py b/src/plopp/backends/pythreejs/outline.py index 0c2c2ad7..3f59afb1 100644 --- a/src/plopp/backends/pythreejs/outline.py +++ b/src/plopp/backends/pythreejs/outline.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import List, Optional, Tuple import numpy as np import pythreejs as p3 @@ -19,7 +18,7 @@ def _get_delta(x: Variable, axis: int) -> float: def _get_offsets( - limits: Tuple[Variable, Variable, Variable], axis: int, ind: int + limits: tuple[Variable, Variable, Variable], axis: int, ind: int ) -> np.ndarray: """ Compute offsets for 3 dimensions, along the edges of the box. @@ -29,7 +28,7 @@ def _get_offsets( return offsets -def _make_geometry(limits: Tuple[Variable, Variable, Variable]) -> p3.EdgesGeometry: +def _make_geometry(limits: tuple[Variable, Variable, Variable]) -> p3.EdgesGeometry: """ Make a geometry to represent the edges of a cubic box. """ @@ -44,7 +43,7 @@ def _make_geometry(limits: Tuple[Variable, Variable, Variable]) -> p3.EdgesGeome def _make_sprite( string: str, - position: Tuple[float, float, float], + position: tuple[float, float, float], color: str = "black", size: float = 1.0, ) -> p3.Sprite: @@ -78,8 +77,8 @@ class Outline(p3.Group): def __init__( self, - limits: Tuple[Variable, Variable, Variable], - tick_size: Optional[float] = None, + limits: tuple[Variable, Variable, Variable], + tick_size: float | None = None, ): center = [var.mean().value for var in limits] if tick_size is None: @@ -101,7 +100,7 @@ def __init__( self.add(obj) def _make_ticks( - self, limits: Tuple[Variable, Variable, Variable], tick_size: float + self, limits: tuple[Variable, Variable, Variable], tick_size: float ) -> p3.Group: """ Create tick labels on outline edges @@ -125,8 +124,8 @@ def _make_ticks( def _make_labels( self, - limits: Tuple[Variable, Variable, Variable], - center: List[float], + limits: tuple[Variable, Variable, Variable], + center: list[float], tick_size: float, ) -> p3.Group: """ diff --git a/src/plopp/backends/pythreejs/point_cloud.py b/src/plopp/backends/pythreejs/point_cloud.py index ce617fec..c12b201d 100644 --- a/src/plopp/backends/pythreejs/point_cloud.py +++ b/src/plopp/backends/pythreejs/point_cloud.py @@ -2,7 +2,6 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import uuid -from typing import Tuple, Union import numpy as np import scipp as sc @@ -44,7 +43,7 @@ def __init__( y: str, z: str, data: sc.DataArray, - pixel_size: Union[sc.Variable, float] = 1, + pixel_size: sc.Variable | float = 1, opacity: float = 1, ): """ @@ -126,7 +125,7 @@ def update(self, new_values): _check_ndim(new_values) self._data = new_values - def get_limits(self) -> Tuple[sc.Variable, sc.Variable, sc.Variable]: + def get_limits(self) -> tuple[sc.Variable, sc.Variable, sc.Variable]: """ Get the spatial extent of all the points in the cloud. """ diff --git a/src/plopp/core/graph.py b/src/plopp/core/graph.py index 7f259ee7..4ab74a85 100644 --- a/src/plopp/core/graph.py +++ b/src/plopp/core/graph.py @@ -3,7 +3,6 @@ from html import escape from itertools import chain -from typing import Union from .node import Node from .view import View @@ -94,7 +93,7 @@ def _make_graph(dot, nodes, edges, labels, views): return dot -def show_graph(entry: Union[Node, View], **kwargs): +def show_graph(entry: Node | View, **kwargs): """ Display the connected nodes and views as a graph. diff --git a/src/plopp/core/helpers.py b/src/plopp/core/helpers.py index f85e1c61..34cc5510 100644 --- a/src/plopp/core/helpers.py +++ b/src/plopp/core/helpers.py @@ -1,7 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Any, Callable +from collections.abc import Callable +from typing import Any from .node import Node diff --git a/src/plopp/core/limits.py b/src/plopp/core/limits.py index ff315ec6..0919d45b 100644 --- a/src/plopp/core/limits.py +++ b/src/plopp/core/limits.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Literal, Tuple +from typing import Literal import numpy as np import scipp as sc @@ -13,7 +13,7 @@ def find_limits( x: sc.DataArray, scale: Literal['linear', 'log'] = 'linear', pad: bool = False, -) -> Tuple[sc.Variable, sc.Variable]: +) -> tuple[sc.Variable, sc.Variable]: """ Find sensible limits, depending on linear or log scale. If there are no finite values in the array, raise an error. @@ -69,8 +69,8 @@ def find_limits( def fix_empty_range( - lims: Tuple[sc.Variable, sc.Variable], -) -> Tuple[sc.Variable, sc.Variable]: + lims: tuple[sc.Variable, sc.Variable], +) -> tuple[sc.Variable, sc.Variable]: """ Range correction in case xmin == xmax """ diff --git a/src/plopp/core/node.py b/src/plopp/core/node.py index 721b486a..e15bdefe 100644 --- a/src/plopp/core/node.py +++ b/src/plopp/core/node.py @@ -5,12 +5,12 @@ import uuid from itertools import chain -from typing import Any, List, Union +from typing import Any from .view import View -def _no_replace_append(container: List[Node], item: Node, kind: str) -> None: +def _no_replace_append(container: list[Node], item: Node, kind: str) -> None: """ Append ``item`` to ``container`` if it is not already in it. """ @@ -66,7 +66,7 @@ def __init__(self, func: Any, *parents: Any, **kwparents: Any) -> None: fname = getattr(self.func, "__name__", str(self.func)) self.name = f'{fname}({args_string})' else: - val_str = f'={func!r}' if isinstance(func, (int, float, str)) else "" + val_str = f'={func!r}' if isinstance(func, int | float | str) else "" self.name = f'Input <{type(func).__name__}{val_str}>' # Attempt to set children after setting name in case error message is needed @@ -186,26 +186,26 @@ def notify_views(self, message: Any) -> None: def __repr__(self) -> str: return f"Node(name={self.name})" - def __add__(self, other: Union[Node, Any]) -> Node: + def __add__(self, other: Node | Any) -> Node: return Node(lambda x, y: x + y, self, other) - def __radd__(self, other: Union[Node, Any]) -> Node: + def __radd__(self, other: Node | Any) -> Node: return Node(lambda x, y: x + y, other, self) - def __sub__(self, other: Union[Node, Any]) -> Node: + def __sub__(self, other: Node | Any) -> Node: return Node(lambda x, y: x - y, self, other) - def __rsub__(self, other: Union[Node, Any]) -> Node: + def __rsub__(self, other: Node | Any) -> Node: return Node(lambda x, y: x - y, other, self) - def __mul__(self, other: Union[Node, Any]) -> Node: + def __mul__(self, other: Node | Any) -> Node: return Node(lambda x, y: x * y, self, other) - def __rmul__(self, other: Union[Node, Any]) -> Node: + def __rmul__(self, other: Node | Any) -> Node: return Node(lambda x, y: x * y, other, self) - def __truediv__(self, other: Union[Node, Any]) -> Node: + def __truediv__(self, other: Node | Any) -> Node: return Node(lambda x, y: x / y, self, other) - def __rtruediv__(self, other: Union[Node, Any]) -> Node: + def __rtruediv__(self, other: Node | Any) -> Node: return Node(lambda x, y: x / y, other, self) diff --git a/src/plopp/core/typing.py b/src/plopp/core/typing.py index a1a6ec9e..d61f65f1 100644 --- a/src/plopp/core/typing.py +++ b/src/plopp/core/typing.py @@ -3,7 +3,7 @@ from __future__ import annotations -from typing import Dict, Protocol, Tuple, Union +from typing import Protocol import scipp as sc from numpy import ndarray @@ -22,9 +22,9 @@ class VisibleDeprecationWarning(UserWarning): VisibleDeprecationWarning.__module__ = 'plopp' -Plottable = Union[VariableLike, ndarray, Node] +Plottable = VariableLike | ndarray | Node -PlottableMulti = Union[Plottable, Dict[str, Plottable]] +PlottableMulti = Plottable | dict[str, Plottable] class CanvasLike(Protocol): @@ -92,16 +92,16 @@ def ymax(self) -> float: ... def ymax(self, ymax: float) -> None: ... @property - def xrange(self) -> Tuple[float, float]: ... + def xrange(self) -> tuple[float, float]: ... @xrange.setter - def xrange(self, xrange: Tuple[float, float]) -> None: ... + def xrange(self, xrange: tuple[float, float]) -> None: ... @property - def yrange(self) -> Tuple[float, float]: ... + def yrange(self) -> tuple[float, float]: ... @yrange.setter - def yrange(self, yrange: Tuple[float, float]) -> None: ... + def yrange(self, yrange: tuple[float, float]) -> None: ... def logx(self) -> None: ... @@ -117,10 +117,10 @@ class FigureLike(Protocol): def canvas(self) -> CanvasLike: ... @property - def artists(self) -> Dict[str, ArtistLike]: ... + def artists(self) -> dict[str, ArtistLike]: ... @property - def graph_nodes(self) -> Dict[str, Node]: ... + def graph_nodes(self) -> dict[str, Node]: ... @property def id(self) -> str: ... diff --git a/src/plopp/core/utils.py b/src/plopp/core/utils.py index c0da83b7..052ce674 100644 --- a/src/plopp/core/utils.py +++ b/src/plopp/core/utils.py @@ -3,13 +3,12 @@ import uuid from functools import reduce -from typing import Dict, Optional, Union import scipp as sc def coord_as_bin_edges( - da: sc.DataArray, key: str, dim: Optional[str] = None + da: sc.DataArray, key: str, dim: str | None = None ) -> sc.Variable: """ If coordinate ``key`` in DataArray ``da`` is already bin edges, return it unchanged. @@ -72,7 +71,7 @@ def repeat(x: sc.Variable, dim: str, n: int) -> sc.Variable: def maybe_number_to_variable( - x: Union[float, sc.Variable], unit: Optional[str] = None + x: float | sc.Variable, unit: str | None = None ) -> sc.Variable: """ If the input is a raw number, convert to a variable. @@ -88,14 +87,12 @@ def maybe_number_to_variable( """ return ( sc.scalar(x, unit=unit) - if isinstance(x, (int, float)) + if isinstance(x, int | float) else (x.to(unit=unit) if unit is not None else x) ) -def maybe_variable_to_number( - x: Union[float, sc.Variable], unit=None -) -> Union[int, float]: +def maybe_variable_to_number(x: float | sc.Variable, unit=None) -> int | float: """ If the input is a variable, return its value. If a unit is requested, perform the conversion to that unit first. @@ -115,7 +112,7 @@ def maybe_variable_to_number( return x -def name_with_unit(var: sc.Variable, name: Optional[str] = None) -> str: +def name_with_unit(var: sc.Variable, name: str | None = None) -> str: """ Make a string from a variable dimension and its unit. The variable dimension can be overridden by specifying the ``name`` directly. @@ -138,7 +135,7 @@ def name_with_unit(var: sc.Variable, name: Optional[str] = None) -> str: return text -def value_to_string(val: Union[float], precision: int = 3) -> str: +def value_to_string(val: float, precision: int = 3) -> str: """ Convert a number to a human readable string. @@ -156,7 +153,7 @@ def value_to_string(val: Union[float], precision: int = 3) -> str: ): text = "{val:.{prec}e}".format(val=val, prec=precision) else: - text = "{}".format(val) + text = str(val) if len(text) > precision + 2 + (text[0] == '-'): text = "{val:.{prec}f}".format(val=val, prec=precision) return text @@ -179,7 +176,7 @@ def scalar_to_string(var: sc.Variable, precision: int = 3) -> str: return out -def merge_masks(masks: Dict[str, sc.Variable]) -> sc.Variable: +def merge_masks(masks: dict[str, sc.Variable]) -> sc.Variable: """ Combine all masks into a single one using the OR operation. @@ -209,9 +206,7 @@ def coord_element_to_string(x: sc.Variable) -> str: return out -def make_compatible( - x: sc.Variable, *, unit: Union[str, None], dim: Optional[str] = None -): +def make_compatible(x: sc.Variable, *, unit: str | None, dim: str | None = None): """ Raise exception if the dimensions of the supplied variable do not contain the requested dimension. diff --git a/src/plopp/core/view.py b/src/plopp/core/view.py index 3191bc64..ecb751d2 100644 --- a/src/plopp/core/view.py +++ b/src/plopp/core/view.py @@ -4,7 +4,7 @@ import uuid from abc import abstractmethod -from typing import TYPE_CHECKING, Any, Dict +from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from .node import Node @@ -37,7 +37,7 @@ def id(self) -> str: """ return self._id - def notify_view(self, message: Dict[str, Any]) -> None: + def notify_view(self, message: dict[str, Any]) -> None: """ When a notification is received, request data from the corresponding parent node and update the relevant artist. diff --git a/src/plopp/data/factory.py b/src/plopp/data/factory.py index 54704ad8..cf7cd665 100644 --- a/src/plopp/data/factory.py +++ b/src/plopp/data/factory.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import List, Optional import numpy as np import scipp as sc @@ -14,8 +13,8 @@ def variable( variances: bool = False, dtype: str = 'float64', unit: str = 'm/s', - dims: Optional[List[str]] = None, - dim_list: List[str] = default_dim_list, + dims: list[str] | None = None, + dim_list: list[str] = default_dim_list, ) -> sc.Variable: """ Generate a sample ``Variable`` containing data based on a sine function. @@ -61,8 +60,8 @@ def data_array( ragged: bool = False, dtype: str = 'float64', unit: str = 'm/s', - dims: Optional[List[str]] = None, - dim_list: List[str] = default_dim_list, + dims: list[str] | None = None, + dim_list: list[str] = default_dim_list, ) -> sc.DataArray: """ Generate a sample ``DataArray`` containing data based on a sine function, with @@ -139,7 +138,7 @@ def data_array( return sc.DataArray(data=data, coords=coord_dict, masks=mask_dict) -def dataset(entries: Optional[List[str]] = None, **kwargs) -> sc.Dataset: +def dataset(entries: list[str] | None = None, **kwargs) -> sc.Dataset: """ Generate a sample ``Dataset``. See :func:`data_array` for more options. diff --git a/src/plopp/graphics/camera.py b/src/plopp/graphics/camera.py index 41ed3f4b..6899eaa6 100644 --- a/src/plopp/graphics/camera.py +++ b/src/plopp/graphics/camera.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from collections.abc import Sequence -from typing import Any, Optional, Tuple, Union +from typing import Any import scipp as sc @@ -10,8 +10,8 @@ def _vector_to_tuple( - vector: Union[sc.Variable, Sequence[sc.Variable], Sequence[float]], -) -> Tuple[Union[sc.Variable, float], ...]: + vector: sc.Variable | Sequence[sc.Variable] | Sequence[float], +) -> tuple[sc.Variable | float, ...]: if isinstance(vector, sc.Variable): return (vector.fields.x, vector.fields.y, vector.fields.z) else: @@ -41,14 +41,10 @@ class Camera: def __init__( self, - position: Optional[ - Union[sc.Variable, Sequence[sc.Variable], Sequence[float]] - ] = None, - look_at: Optional[ - Union[sc.Variable, Sequence[sc.Variable], Sequence[float]] - ] = None, - near: Optional[Union[sc.Variable, float]] = None, - far: Optional[Union[sc.Variable, float]] = None, + position: sc.Variable | Sequence[sc.Variable] | Sequence[float] | None = None, + look_at: sc.Variable | Sequence[sc.Variable] | Sequence[float] | None = None, + near: sc.Variable | float | None = None, + far: sc.Variable | float | None = None, ): self._parsed_contents = None self._raw_contents = {} @@ -61,7 +57,7 @@ def __init__( if far is not None: self._raw_contents['far'] = far - def get(self, key: str, default: Optional[Any] = None) -> Any: + def get(self, key: str, default: Any | None = None) -> Any: """ Attribute getter. If units have been set, the value will be converted to the specified units. @@ -119,7 +115,7 @@ def has_units(self) -> bool: return self._parsed_contents is not None @property - def position(self) -> Union[Tuple[float, float, float], None]: + def position(self) -> tuple[float, float, float] | None: """ The position of the camera. If camera units have been set, the position returned will be converted to the specified units. @@ -127,7 +123,7 @@ def position(self) -> Union[Tuple[float, float, float], None]: self.get('position') @property - def look_at(self) -> Union[Tuple[float, float, float], None]: + def look_at(self) -> tuple[float, float, float] | None: """ The point the camera is looking at. If camera units have been set, the position returned will be converted to the specified units. @@ -135,7 +131,7 @@ def look_at(self) -> Union[Tuple[float, float, float], None]: self.get('look_at') @property - def near(self) -> Union[float, None]: + def near(self) -> float | None: """ The distance to the near clipping plane (how close to the camera objects can be before they disappear). @@ -143,7 +139,7 @@ def near(self) -> Union[float, None]: self.get('near') @property - def far(self) -> Union[float, None]: + def far(self) -> float | None: """ The distance to the far clipping plane (how far from the camera objects can be before they disappear). diff --git a/src/plopp/graphics/colormapper.py b/src/plopp/graphics/colormapper.py index 236fea7e..73159246 100644 --- a/src/plopp/graphics/colormapper.py +++ b/src/plopp/graphics/colormapper.py @@ -4,7 +4,7 @@ from collections.abc import Iterable from copy import copy from functools import reduce -from typing import Any, Literal, Optional, Tuple, Union +from typing import Any, Literal import matplotlib as mpl import matplotlib.pyplot as plt @@ -18,7 +18,7 @@ from ..core.utils import maybe_variable_to_number, merge_masks -def _get_cmap(name: str, nan_color: Optional[str] = None) -> Colormap: +def _get_cmap(name: str, nan_color: str | None = None) -> Colormap: """ Get a colormap object from a colormap name. @@ -93,16 +93,16 @@ class ColorMapper: def __init__( self, - canvas: Optional[Any] = None, + canvas: Any | None = None, cbar: bool = True, cmap: str = 'viridis', mask_cmap: str = 'gray', norm: Literal['linear', 'log'] = 'linear', autoscale: Literal['auto', 'grow'] = 'auto', - vmin: Optional[Union[sc.Variable, int, float]] = None, - vmax: Optional[Union[sc.Variable, int, float]] = None, - nan_color: Optional[str] = None, - figsize: Optional[Tuple[float, float]] = None, + vmin: sc.Variable | int | float | None = None, + vmax: sc.Variable | int | float | None = None, + nan_color: str | None = None, + figsize: tuple[float, float] | None = None, ): self.cax = canvas.cax if canvas is not None else None self.cmap = _get_cmap(cmap, nan_color=nan_color) diff --git a/src/plopp/graphics/imageview.py b/src/plopp/graphics/imageview.py index 751a31f8..412d2e97 100644 --- a/src/plopp/graphics/imageview.py +++ b/src/plopp/graphics/imageview.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Dict, Literal, Optional, Tuple, Union +from typing import Literal import scipp as sc @@ -73,16 +73,16 @@ def __init__( cmap: str = 'viridis', mask_cmap: str = 'gray', norm: Literal['linear', 'log'] = 'linear', - vmin: Optional[Union[sc.Variable, int, float]] = None, - vmax: Optional[Union[sc.Variable, int, float]] = None, + vmin: sc.Variable | int | float | None = None, + vmax: sc.Variable | int | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', - scale: Optional[Dict[str, str]] = None, + scale: dict[str, str] | None = None, aspect: Literal['auto', 'equal'] = 'auto', grid: bool = False, cbar: bool = True, - title: Optional[str] = None, - figsize: Optional[Tuple[float, float]] = None, - format: Optional[Literal['svg', 'png']] = None, + title: str | None = None, + figsize: tuple[float, float] | None = None, + format: Literal['svg', 'png'] | None = None, **kwargs, ): super().__init__(*nodes) diff --git a/src/plopp/graphics/lineview.py b/src/plopp/graphics/lineview.py index 0e25a3a9..07e74b8e 100644 --- a/src/plopp/graphics/lineview.py +++ b/src/plopp/graphics/lineview.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Dict, Literal, Optional, Tuple, Union +from typing import Literal import scipp as sc @@ -68,18 +68,18 @@ def __init__( self, *nodes, norm: Literal['linear', 'log'] = 'linear', - vmin: Optional[Union[sc.Variable, int, float]] = None, - vmax: Optional[Union[sc.Variable, int, float]] = None, + vmin: sc.Variable | int | float | None = None, + vmax: sc.Variable | int | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', - scale: Optional[Dict[str, str]] = None, + scale: dict[str, str] | None = None, errorbars: bool = True, mask_color: str = 'black', aspect: Literal['auto', 'equal'] = 'auto', grid: bool = False, - title: Optional[str] = None, - figsize: Optional[Tuple[float, float]] = None, - format: Optional[Literal['svg', 'png']] = None, - legend: Union[bool, Tuple[float, float]] = True, + title: str | None = None, + figsize: tuple[float, float] | None = None, + format: Literal['svg', 'png'] | None = None, + legend: bool | tuple[float, float] = True, **kwargs, ): super().__init__(*nodes) diff --git a/src/plopp/graphics/scatter3dview.py b/src/plopp/graphics/scatter3dview.py index 1329c79e..0a41cd4b 100644 --- a/src/plopp/graphics/scatter3dview.py +++ b/src/plopp/graphics/scatter3dview.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Literal, Optional, Tuple, Union +from typing import Literal import scipp as sc @@ -63,11 +63,11 @@ def __init__( cmap: str = 'viridis', mask_cmap: str = 'gray', norm: Literal['linear', 'log'] = 'linear', - vmin: Optional[Union[sc.Variable, int, float]] = None, - vmax: Optional[Union[sc.Variable, int, float]] = None, - figsize: Tuple[int, int] = (600, 400), - title: Optional[str] = None, - camera: Optional[Camera] = None, + vmin: sc.Variable | int | float | None = None, + vmax: sc.Variable | int | float | None = None, + figsize: tuple[int, int] = (600, 400), + title: str | None = None, + camera: Camera | None = None, **kwargs, ): super().__init__(*nodes) @@ -132,7 +132,7 @@ def update(self, *args, **kwargs): self.artists[key].update(new_values=new_values) self.colormapper.update(**new) - def get_limits(self) -> Tuple[sc.Variable, sc.Variable, sc.Variable]: + def get_limits(self) -> tuple[sc.Variable, sc.Variable, sc.Variable]: """ Get global limits for all the point clouds in the scene. """ diff --git a/src/plopp/graphics/scatterview.py b/src/plopp/graphics/scatterview.py index 0c64a9ed..8e7074ea 100644 --- a/src/plopp/graphics/scatterview.py +++ b/src/plopp/graphics/scatterview.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2024 Scipp contributors (https://github.com/scipp) -from typing import Dict, Literal, Optional, Tuple, Union +from typing import Literal import scipp as sc @@ -19,19 +19,19 @@ def __init__( *nodes, x: str = 'x', y: str = 'y', - size: Optional[str] = None, + size: str | None = None, norm: Literal['linear', 'log'] = 'linear', - vmin: Optional[Union[sc.Variable, int, float]] = None, - vmax: Optional[Union[sc.Variable, int, float]] = None, + vmin: sc.Variable | int | float | None = None, + vmax: sc.Variable | int | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', - scale: Optional[Dict[str, str]] = None, + scale: dict[str, str] | None = None, mask_color: str = 'black', aspect: Literal['auto', 'equal'] = 'auto', grid: bool = False, - title: Optional[str] = None, - figsize: Optional[Tuple[float, float]] = None, - format: Optional[Literal['svg', 'png']] = None, - legend: Union[bool, Tuple[float, float]] = True, + title: str | None = None, + figsize: tuple[float, float] | None = None, + format: Literal['svg', 'png'] | None = None, + legend: bool | tuple[float, float] = True, cmap: str = 'viridis', mask_cmap: str = 'gray', cbar: bool = False, diff --git a/src/plopp/plotting/common.py b/src/plopp/plotting/common.py index ef65ac82..d7b9b649 100644 --- a/src/plopp/plotting/common.py +++ b/src/plopp/plotting/common.py @@ -2,7 +2,8 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) import warnings -from typing import Any, Callable, List, Optional, Union +from collections.abc import Callable +from typing import Any import numpy as np import scipp as sc @@ -46,7 +47,7 @@ def from_compatible_lib(obj: Any) -> Any: return obj -def _maybe_to_variable(obj: Union[Plottable, list]) -> Plottable: +def _maybe_to_variable(obj: Plottable | list) -> Plottable: """ Attempt to convert the input to a Variable. If the input is either a list or a numpy array, it will be converted. @@ -78,7 +79,7 @@ def to_variable(obj) -> sc.Variable: def to_data_array( - obj: Union[Plottable, list], + obj: Plottable | list, ) -> sc.DataArray: """ Convert an input to a DataArray, potentially adding fake coordinates if they are @@ -159,10 +160,10 @@ def _all_dims_sorted(var, order='ascending'): def preprocess( - obj: Union[Plottable, list], - name: Optional[str] = None, + obj: Plottable | list, + name: str | None = None, ignore_size: bool = False, - coords: Optional[List[str]] = None, + coords: list[str] | None = None, ) -> sc.DataArray: """ Pre-process input data for plotting. @@ -219,7 +220,7 @@ def preprocess( return out -def input_to_nodes(obj: PlottableMulti, processor: Callable) -> List[Node]: +def input_to_nodes(obj: PlottableMulti, processor: Callable) -> list[Node]: """ Convert an input or dict of inputs to a list of nodes that provide pre-processed data. diff --git a/src/plopp/plotting/inspector.py b/src/plopp/plotting/inspector.py index 0ed5ae7d..9d0433e0 100644 --- a/src/plopp/plotting/inspector.py +++ b/src/plopp/plotting/inspector.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Dict, Literal, Optional +from typing import Literal import scipp as sc @@ -28,7 +28,7 @@ def _apply_op(da: sc.DataArray, op: str, dim: str) -> sc.DataArray: return out -def _slice_xy(da: sc.DataArray, xy: Dict[str, Dict[str, int]]) -> sc.DataArray: +def _slice_xy(da: sc.DataArray, xy: dict[str, dict[str, int]]) -> sc.DataArray: x = xy['x'] y = xy['y'] return da[y['dim'], y['value']][x['dim'], x['value']] @@ -36,7 +36,7 @@ def _slice_xy(da: sc.DataArray, xy: Dict[str, Dict[str, int]]) -> sc.DataArray: def inspector( obj: Plottable, - dim: Optional[str] = None, + dim: str | None = None, *, operation: Literal['sum', 'mean', 'min', 'max'] = 'sum', orientation: Literal['horizontal', 'vertical'] = 'horizontal', diff --git a/src/plopp/plotting/plot.py b/src/plopp/plotting/plot.py index 7f588361..b326b516 100644 --- a/src/plopp/plotting/plot.py +++ b/src/plopp/plotting/plot.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from functools import partial -from typing import Dict, List, Literal, Optional, Tuple, Union +from typing import Literal from scipp import Variable @@ -16,19 +16,19 @@ def plot( *, aspect: Literal['auto', 'equal'] = 'auto', cbar: bool = True, - coords: Optional[List[str]] = None, + coords: list[str] | None = None, errorbars: bool = True, - figsize: Optional[Tuple[float, float]] = None, + figsize: tuple[float, float] | None = None, grid: bool = False, ignore_size: bool = False, mask_color: str = 'black', norm: Literal['linear', 'log'] = 'linear', - scale: Optional[Dict[str, str]] = None, - title: Optional[str] = None, - vmin: Optional[Union[Variable, int, float]] = None, - vmax: Optional[Union[Variable, int, float]] = None, + scale: dict[str, str] | None = None, + title: str | None = None, + vmin: Variable | int | float | None = None, + vmax: Variable | int | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', - legend: Union[bool, Tuple[float, float]] = True, + legend: bool | tuple[float, float] = True, **kwargs, ) -> FigureLike: """Plot a Scipp object. diff --git a/src/plopp/plotting/scatter.py b/src/plopp/plotting/scatter.py index 08dec240..b507ef26 100644 --- a/src/plopp/plotting/scatter.py +++ b/src/plopp/plotting/scatter.py @@ -3,7 +3,7 @@ import uuid from functools import partial -from typing import Literal, Optional, Tuple, Union +from typing import Literal import scipp as sc @@ -15,8 +15,8 @@ def _preprocess_scatter( obj: PlottableMulti, x: str, y: str, - size: Optional[str], - name: Optional[str] = None, + size: str | None, + name: str | None = None, ): da = from_compatible_lib(obj) check_not_binned(da) @@ -38,12 +38,12 @@ def scatter( *, x: str = 'x', y: str = 'y', - size: Optional[Union[str, float]] = None, - figsize: Optional[Tuple[float, float]] = None, + size: str | float | None = None, + figsize: tuple[float, float] | None = None, norm: Literal['linear', 'log'] = 'linear', - title: Optional[str] = None, - vmin: Union[sc.Variable, float] = None, - vmax: Union[sc.Variable, float] = None, + title: str | None = None, + vmin: sc.Variable | float = None, + vmax: sc.Variable | float = None, cbar: bool = False, cmap: str = 'viridis', **kwargs, diff --git a/src/plopp/plotting/scatter3d.py b/src/plopp/plotting/scatter3d.py index e11e6abb..1dbdb3f1 100644 --- a/src/plopp/plotting/scatter3d.py +++ b/src/plopp/plotting/scatter3d.py @@ -3,7 +3,7 @@ import uuid from functools import partial -from typing import Literal, Optional, Tuple, Union +from typing import Literal import scipp as sc @@ -17,8 +17,8 @@ def _preprocess_scatter( x: str, y: str, z: str, - pos: Optional[str], - name: Optional[str] = None, + pos: str | None, + name: str | None = None, ) -> sc.DataArray: da = from_compatible_lib(obj) check_not_binned(da) @@ -42,14 +42,14 @@ def scatter3d( x: str = 'x', y: str = 'y', z: str = 'z', - pos: Optional[str] = None, - figsize: Tuple[int, int] = (600, 400), + pos: str | None = None, + figsize: tuple[int, int] = (600, 400), norm: Literal['linear', 'log'] = 'linear', - title: Optional[str] = None, - vmin: Union[sc.Variable, float] = None, - vmax: Union[sc.Variable, float] = None, + title: str | None = None, + vmin: sc.Variable | float = None, + vmax: sc.Variable | float = None, cmap: str = 'viridis', - camera: Optional[Camera] = None, + camera: Camera | None = None, **kwargs, ) -> FigureLike: """Make a three-dimensional scatter plot. diff --git a/src/plopp/plotting/slicer.py b/src/plopp/plotting/slicer.py index 97e24a18..2cd60a59 100644 --- a/src/plopp/plotting/slicer.py +++ b/src/plopp/plotting/slicer.py @@ -4,7 +4,7 @@ import warnings from functools import partial, reduce from itertools import groupby -from typing import List, Literal, Optional, Union +from typing import Literal from scipp.typing import VariableLike @@ -61,11 +61,11 @@ def __init__( self, obj: PlottableMulti, *, - keep: Optional[List[str]] = None, + keep: list[str] | None = None, autoscale: Literal['auto', 'grow', 'fixed'] = 'auto', - coords: Optional[List[str]] = None, - vmin: Union[VariableLike, float] = None, - vmax: Union[VariableLike, float] = None, + coords: list[str] | None = None, + vmin: VariableLike | float = None, + vmax: VariableLike | float = None, **kwargs, ): nodes = input_to_nodes( @@ -145,11 +145,11 @@ def __init__( def slicer( obj: PlottableMulti, *, - keep: Optional[List[str]] = None, + keep: list[str] | None = None, autoscale: Literal['auto', 'grow', 'fixed'] = 'auto', - coords: Optional[List[str]] = None, - vmin: Union[VariableLike, float] = None, - vmax: Union[VariableLike, float] = None, + coords: list[str] | None = None, + vmin: VariableLike | float = None, + vmax: VariableLike | float = None, **kwargs, ) -> FigureLike: """ diff --git a/src/plopp/plotting/superplot.py b/src/plopp/plotting/superplot.py index 3812bb12..dc59a6d2 100644 --- a/src/plopp/plotting/superplot.py +++ b/src/plopp/plotting/superplot.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Optional from ..core.typing import FigureLike, Plottable from .common import require_interactive_backend @@ -10,7 +9,7 @@ def superplot( obj: Plottable, - keep: Optional[str] = None, + keep: str | None = None, **kwargs, ) -> FigureLike: """ diff --git a/src/plopp/plotting/xyplot.py b/src/plopp/plotting/xyplot.py index 8d47de4b..9fcb2c4f 100644 --- a/src/plopp/plotting/xyplot.py +++ b/src/plopp/plotting/xyplot.py @@ -1,7 +1,6 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Union import scipp as sc from numpy import ndarray @@ -28,8 +27,8 @@ def _make_data_array(x: sc.Variable, y: sc.Variable) -> sc.DataArray: def xyplot( - x: Union[sc.Variable, ndarray, list, Node], - y: Union[sc.Variable, ndarray, list, Node], + x: sc.Variable | ndarray | list | Node, + y: sc.Variable | ndarray | list | Node, **kwargs, ) -> FigureLike: """ diff --git a/src/plopp/utils.py b/src/plopp/utils.py index 9a842ade..4002d7ce 100644 --- a/src/plopp/utils.py +++ b/src/plopp/utils.py @@ -3,7 +3,7 @@ import functools import warnings -from typing import Callable +from collections.abc import Callable from .core.typing import VisibleDeprecationWarning diff --git a/src/plopp/widgets/box.py b/src/plopp/widgets/box.py index bdadcc3e..e1de01c1 100644 --- a/src/plopp/widgets/box.py +++ b/src/plopp/widgets/box.py @@ -67,6 +67,6 @@ class Box(VBar): def __init__(self, widgets): children = [ - HBar(view) if isinstance(view, (list, tuple)) else view for view in widgets + HBar(view) if isinstance(view, list | tuple) else view for view in widgets ] super().__init__(children) diff --git a/src/plopp/widgets/checkboxes.py b/src/plopp/widgets/checkboxes.py index d6f1c5bb..7b548401 100644 --- a/src/plopp/widgets/checkboxes.py +++ b/src/plopp/widgets/checkboxes.py @@ -1,8 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +from collections.abc import Callable from html import escape -from typing import Callable, Dict, List import ipywidgets as ipw @@ -21,7 +21,7 @@ class Checkboxes(ipw.HBox): Default value to set all the checkboxes to. """ - def __init__(self, entries: List[str], description: str = "", value: bool = True): + def __init__(self, entries: list[str], description: str = "", value: bool = True): self.checkboxes = {} self._lock = False self.description = ipw.Label(value=description) @@ -61,7 +61,7 @@ def _plopp_observe_(self, callback: Callable, **kwargs): chbx.observe(callback, **kwargs) @property - def value(self) -> Dict[str, bool]: + def value(self) -> dict[str, bool]: """ Returns a dict containing one entry per checkbox, giving the checkbox's value. """ diff --git a/src/plopp/widgets/clip3d.py b/src/plopp/widgets/clip3d.py index 74f7ed22..677936f6 100644 --- a/src/plopp/widgets/clip3d.py +++ b/src/plopp/widgets/clip3d.py @@ -2,8 +2,9 @@ # Copyright (c) 2024 Scipp contributors (https://github.com/scipp) import uuid +from collections.abc import Callable from functools import partial, reduce -from typing import Any, Callable, Dict, List, Literal, Tuple +from typing import Any, Literal import ipywidgets as ipw import numpy as np @@ -16,7 +17,7 @@ from .style import BUTTON_LAYOUT -def _xor(x: List[sc.Variable]) -> sc.Variable: +def _xor(x: list[sc.Variable]) -> sc.Variable: dim = uuid.uuid4().hex return sc.concat(x, dim).sum(dim) == sc.scalar(1, unit=None) @@ -28,7 +29,7 @@ def _xor(x: List[sc.Variable]) -> sc.Variable: } -def select(da: sc.DataArray, s: Tuple[str, sc.Variable]) -> sc.DataArray: +def select(da: sc.DataArray, s: tuple[str, sc.Variable]) -> sc.DataArray: return da[s] @@ -58,7 +59,7 @@ class Clip3dTool(ipw.HBox): def __init__( self, - limits: Tuple[sc.Variable, sc.Variable, sc.Variable], + limits: tuple[sc.Variable, sc.Variable, sc.Variable], direction: Literal['x', 'y', 'z'], update: Callable, color: str = 'red', @@ -156,14 +157,14 @@ def toggle_border(self, value: bool): # the cut, the border visibility is in sync with the parent button. self._border_visible = value - def move(self, value: Dict[str, Any]): + def move(self, value: dict[str, Any]): """ Move the outline of the cut according to new position given by the slider. """ # Early return if relative difference between new and old value is small. # This also prevents flickering of an existing cut when a new cut is added. if ( - np.abs((np.array(value['new']) - np.array(value['old']))).max() + np.abs(np.array(value['new']) - np.array(value['old'])).max() < 0.01 * self.slider.step ): return @@ -333,7 +334,7 @@ def update_controls(self): opacity = self.opacity.value if at_least_one_cut else 1.0 self._set_opacity({'new': opacity}) - def _set_opacity(self, change: Dict[str, Any]): + def _set_opacity(self, change: dict[str, Any]): """ Set the opacity of the original point clouds in the figure, not the cuts. """ @@ -345,14 +346,14 @@ def toggle_visibility(self): """ self.layout.display = None if self.layout.display == 'none' else 'none' - def toggle_border_visibility(self, change: Dict[str, Any]): + def toggle_border_visibility(self, change: dict[str, Any]): """ Toggle the visibility of the borders of the cuts. """ for cut in self.cuts: cut.toggle_border(change['new']) - def change_operation(self, change: Dict[str, Any]): + def change_operation(self, change: dict[str, Any]): """ Change the operation to combine multiple cuts. """ diff --git a/src/plopp/widgets/cut3d.py b/src/plopp/widgets/cut3d.py index 994b0c73..0750ce6d 100644 --- a/src/plopp/widgets/cut3d.py +++ b/src/plopp/widgets/cut3d.py @@ -3,7 +3,7 @@ from functools import partial -from typing import Any, Dict, Literal, Tuple +from typing import Any, Literal import ipywidgets as ipw import numpy as np @@ -50,7 +50,7 @@ class Cut3dTool(ipw.HBox): def __init__( self, view: View, - limits: Tuple[sc.Variable, sc.Variable, sc.Variable], + limits: tuple[sc.Variable, sc.Variable, sc.Variable], direction: Literal['x', 'y', 'z'], value: bool = False, color: str = 'red', @@ -135,7 +135,7 @@ def __init__( ] ) - def toggle(self, change: Dict[str, Any]): + def toggle(self, change: dict[str, Any]): """ Toggle the tool on and off. """ @@ -147,7 +147,7 @@ def toggle(self, change: Dict[str, Any]): else: self._remove_cut() - def move(self, value: Dict[str, Any]): + def move(self, value: dict[str, Any]): """ Move the outline of the cut according to new position given by the slider. """ @@ -307,7 +307,7 @@ def _toggle_opacity(self, _): opacity = self.opacity.value if active_cut else 1.0 self._set_opacity({'new': opacity}) - def _set_opacity(self, change: Dict[str, Any]): + def _set_opacity(self, change: dict[str, Any]): """ Set the opacity of the original point clouds in the figure, not the cuts. """ diff --git a/src/plopp/widgets/debounce.py b/src/plopp/widgets/debounce.py index 2d54ea25..77ed5de2 100644 --- a/src/plopp/widgets/debounce.py +++ b/src/plopp/widgets/debounce.py @@ -2,7 +2,7 @@ # Copyright (c) 2024 Scipp contributors (https://github.com/scipp) import asyncio -from typing import Callable +from collections.abc import Callable class Timer: diff --git a/src/plopp/widgets/drawing.py b/src/plopp/widgets/drawing.py index 9ff0b2d3..adbf20d5 100644 --- a/src/plopp/widgets/drawing.py +++ b/src/plopp/widgets/drawing.py @@ -1,8 +1,9 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +from collections.abc import Callable from functools import partial -from typing import Any, Callable, Union +from typing import Any import scipp as sc @@ -51,7 +52,7 @@ def __init__( input_node: Node, tool: Any, func: Callable, - destination: Union[FigureLike, Node], + destination: FigureLike | Node, get_artist_info: Callable, value: bool = False, **kwargs, diff --git a/src/plopp/widgets/linesave.py b/src/plopp/widgets/linesave.py index 6d1fb674..e3727833 100644 --- a/src/plopp/widgets/linesave.py +++ b/src/plopp/widgets/linesave.py @@ -2,7 +2,7 @@ # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) from functools import partial -from typing import Any, Dict, Optional +from typing import Any import ipywidgets as ipw from matplotlib.colors import to_hex @@ -40,7 +40,7 @@ def __init__(self, data_node: Node, slider_node: Node, fig: View): def _update_container(self): self.container.children = [line['tool'] for line in self._lines.values()] - def save_line(self, change: Optional[Dict[str, Any]] = None): + def save_line(self, change: dict[str, Any] | None = None): from ..widgets import ColorTool data = self._data_node.request_data() @@ -62,10 +62,10 @@ def save_line(self, change: Optional[Dict[str, Any]] = None): ) tool.button.on_click(partial(self.remove_line, line_id=line_id)) - def change_line_color(self, change: Dict[str, Any], line_id: str): + def change_line_color(self, change: dict[str, Any], line_id: str): self._lines[line_id]['line'].color = change['new'] - def remove_line(self, change: Dict[str, Any], line_id: str): + def remove_line(self, change: dict[str, Any], line_id: str): self._lines[line_id]['line'].remove() self._lines[line_id]['node'].remove() del self._lines[line_id] diff --git a/src/plopp/widgets/slice.py b/src/plopp/widgets/slice.py index b4f46fae..4d0fe96b 100644 --- a/src/plopp/widgets/slice.py +++ b/src/plopp/widgets/slice.py @@ -1,7 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Any, Callable, Dict, List, Union +from collections.abc import Callable +from typing import Any import ipywidgets as ipw import scipp as sc @@ -12,7 +13,7 @@ class _BaseSliceWidget(VBar): - def __init__(self, da: sc.DataArray, dims: List[str], range: bool): + def __init__(self, da: sc.DataArray, dims: list[str], range: bool): if isinstance(dims, str): dims = [dims] self._slider_dims = dims @@ -60,7 +61,7 @@ def __init__(self, da: sc.DataArray, dims: List[str], range: bool): super().__init__(children) - def _update_label(self, change: Dict[str, Any]): + def _update_label(self, change: dict[str, Any]): """ Update the readout label with the coordinate value, instead of the integer readout index. @@ -78,7 +79,7 @@ def _plopp_observe_(self, callback: Callable, **kwargs): self.controls[dim]['slider'].observe(callback, **kwargs) @property - def value(self) -> Dict[str, Union[int, tuple[int]]]: + def value(self) -> dict[str, int | tuple[int]]: """ The widget value, as a dict containing the dims as keys and the slider indices as values. @@ -101,7 +102,7 @@ class SliceWidget(_BaseSliceWidget): The dimensions to make sliders for. """ - def __init__(self, da: sc.DataArray, dims: List[str]): + def __init__(self, da: sc.DataArray, dims: list[str]): super().__init__(da, dims, range=False) @@ -122,12 +123,12 @@ class RangeSliceWidget(_BaseSliceWidget): The dimensions to make sliders for. """ - def __init__(self, da: sc.DataArray, dims: List[str]): + def __init__(self, da: sc.DataArray, dims: list[str]): super().__init__(da, dims, range=True) @node -def slice_dims(data_array: sc.DataArray, slices: Dict[str, slice]) -> sc.DataArray: +def slice_dims(data_array: sc.DataArray, slices: dict[str, slice]) -> sc.DataArray: """ Slice the data according to input slices. diff --git a/src/plopp/widgets/toolbar.py b/src/plopp/widgets/toolbar.py index 6f3f40dc..1fafd754 100644 --- a/src/plopp/widgets/toolbar.py +++ b/src/plopp/widgets/toolbar.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) -from typing import Any, Dict, Optional +from typing import Any from ipywidgets import VBox @@ -19,7 +19,7 @@ class Toolbar(VBox): Dictionary of tools to populate the toolbar. """ - def __init__(self, tools: Optional[Dict[str, Any]] = None): + def __init__(self, tools: dict[str, Any] | None = None): self.tools = {} if tools is not None: for key, tool in tools.items(): @@ -49,7 +49,7 @@ def _update_children(self): def make_toolbar_canvas2d( - canvas: Any, colormapper: Optional[ColorMapper] = None + canvas: Any, colormapper: ColorMapper | None = None ) -> Toolbar: """ Create a toolbar for a 2D canvas. @@ -78,7 +78,7 @@ def make_toolbar_canvas2d( def make_toolbar_canvas3d( - canvas: Any, colormapper: Optional[ColorMapper] = None + canvas: Any, colormapper: ColorMapper | None = None ) -> Toolbar: """ Create a toolbar for a 3D canvas. diff --git a/src/plopp/widgets/tools.py b/src/plopp/widgets/tools.py index 667a7904..8ccb383f 100644 --- a/src/plopp/widgets/tools.py +++ b/src/plopp/widgets/tools.py @@ -1,8 +1,8 @@ # SPDX-License-Identifier: BSD-3-Clause # Copyright (c) 2023 Scipp contributors (https://github.com/scipp) +from collections.abc import Callable from functools import partial -from typing import Callable, List, Optional, Union import ipywidgets as ipw @@ -107,11 +107,11 @@ class MultiToggleTool(ipw.VBox): def __init__( self, callback: Callable, - options: List[str], - icons: Optional[List[str]] = None, - tooltips: Optional[List[str]] = None, - descriptions: Optional[List[str]] = None, - value: Optional[str] = None, + options: list[str], + icons: list[str] | None = None, + tooltips: list[str] | None = None, + descriptions: list[str] | None = None, + value: str | None = None, **kwargs, ): self.callback = callback @@ -143,7 +143,7 @@ def __call__(self, change: dict): self.callback() @property - def value(self) -> Union[str, None]: + def value(self) -> str | None: for b in self._buttons.values(): if b.value: return b._option @@ -196,7 +196,7 @@ class PanZoomTool(MultiToggleTool): Set the initially selected button. No button selected if ``None``. """ - def __init__(self, callback: Callable, value: Optional[bool] = None, **kwargs): + def __init__(self, callback: Callable, value: bool | None = None, **kwargs): self._callback = callback super().__init__( callback=self._panzoom, From 72ef15797fb99f6bec2c275f66ffb7b77285be78 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 10:57:40 +0200 Subject: [PATCH 5/8] Make ruff happy again w py310 --- docs/user-guide/getting-started/numpy-pandas-xarray.ipynb | 5 +++-- src/plopp/backends/common.py | 2 +- src/plopp/backends/matplotlib/canvas.py | 6 +++++- src/plopp/core/utils.py | 2 +- src/plopp/data/examples.py | 2 +- src/plopp/data/factory.py | 2 +- src/plopp/graphics/camera.py | 4 +++- src/plopp/graphics/colormapper.py | 4 ++-- src/plopp/graphics/imageview.py | 4 ++-- src/plopp/graphics/lineview.py | 4 ++-- src/plopp/graphics/scatter3dview.py | 4 ++-- src/plopp/graphics/scatterview.py | 4 ++-- src/plopp/plotting/plot.py | 4 ++-- src/plopp/widgets/clip3d.py | 4 ++-- 14 files changed, 29 insertions(+), 22 deletions(-) diff --git a/docs/user-guide/getting-started/numpy-pandas-xarray.ipynb b/docs/user-guide/getting-started/numpy-pandas-xarray.ipynb index f4e083c1..ebab9d08 100644 --- a/docs/user-guide/getting-started/numpy-pandas-xarray.ipynb +++ b/docs/user-guide/getting-started/numpy-pandas-xarray.ipynb @@ -254,7 +254,7 @@ "lon = [265, 235, 281]\n", "lat = [42, 32, 23]\n", "\n", - "for x, y in zip(lon, lat):\n", + "for x, y in zip(lon, lat, strict=True):\n", " tool._tool.click(x, y)\n", "\n", "\n", @@ -304,7 +304,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.10.14" } }, "nbformat": 4, diff --git a/src/plopp/backends/common.py b/src/plopp/backends/common.py index 0a23e103..a3ec1a48 100644 --- a/src/plopp/backends/common.py +++ b/src/plopp/backends/common.py @@ -68,7 +68,7 @@ def axis_bounds( Whether to pad the limits. """ values = fix_empty_range(find_limits(x, scale=scale, pad=pad)) - bounds = dict(zip(keys, (val.value for val in values))) + bounds = dict(zip(keys, (val.value for val in values), strict=True)) return bounds diff --git a/src/plopp/backends/matplotlib/canvas.py b/src/plopp/backends/matplotlib/canvas.py index accce25b..4413f10f 100644 --- a/src/plopp/backends/matplotlib/canvas.py +++ b/src/plopp/backends/matplotlib/canvas.py @@ -217,7 +217,11 @@ def autoscale(self): data=sc.array( dims=['x', 'y'], values=np.array( - [s for (s, length) in zip(segments, lengths) if length] + [ + s + for (s, length) in zip(segments, lengths, strict=True) + if length + ] )[..., 1], ), masks={'mask': line_mask}, diff --git a/src/plopp/core/utils.py b/src/plopp/core/utils.py index 052ce674..f340bab5 100644 --- a/src/plopp/core/utils.py +++ b/src/plopp/core/utils.py @@ -92,7 +92,7 @@ def maybe_number_to_variable( ) -def maybe_variable_to_number(x: float | sc.Variable, unit=None) -> int | float: +def maybe_variable_to_number(x: float | sc.Variable, unit=None) -> float: """ If the input is a variable, return its value. If a unit is requested, perform the conversion to that unit first. diff --git a/src/plopp/data/examples.py b/src/plopp/data/examples.py index 47f8bd35..a143cf1c 100644 --- a/src/plopp/data/examples.py +++ b/src/plopp/data/examples.py @@ -71,7 +71,7 @@ def three_bands(npeaks=200, per_peak=500, spread=30.0): xcenters = rng.uniform(0, nx, size=npeaks) ycenters = rng.choice([ny / 4, ny / 2, 3 * ny / 4], size=npeaks) spreads = rng.uniform(0, spread, size=npeaks) - for i, (xc, yc, sp) in enumerate(zip(xcenters, ycenters, spreads)): + for i, (xc, yc, sp) in enumerate(zip(xcenters, ycenters, spreads, strict=True)): xy = np.random.normal(loc=(xc, yc), scale=sp, size=[per_peak, 2]) x[i, :] = xy[:, 0] y[i, :] = xy[:, 1] diff --git a/src/plopp/data/factory.py b/src/plopp/data/factory.py index cf7cd665..863613aa 100644 --- a/src/plopp/data/factory.py +++ b/src/plopp/data/factory.py @@ -93,7 +93,7 @@ def data_array( List of dimension labels to use if no ``dims`` are provided. """ - coord_units = dict(zip(dim_list, ['m', 'm', 'm', 's', 'K'])) + coord_units = dict(zip(dim_list, ['m', 'm', 'm', 's', 'K'], strict=True)) data = variable( ndim=ndim, diff --git a/src/plopp/graphics/camera.py b/src/plopp/graphics/camera.py index 6899eaa6..8bc481a4 100644 --- a/src/plopp/graphics/camera.py +++ b/src/plopp/graphics/camera.py @@ -94,7 +94,9 @@ def set_units(self, xunit: str, yunit: str, zunit: str): for key in set(self._raw_contents) & {'position', 'look_at'}: self._parsed_contents[key] = tuple( maybe_variable_to_number(x, unit=u) - for x, u in zip(self._raw_contents[key], [xunit, yunit, zunit]) + for x, u in zip( + self._raw_contents[key], [xunit, yunit, zunit], strict=True + ) ) for key in set(self._raw_contents) & {'near', 'far'}: diff --git a/src/plopp/graphics/colormapper.py b/src/plopp/graphics/colormapper.py index 73159246..96294427 100644 --- a/src/plopp/graphics/colormapper.py +++ b/src/plopp/graphics/colormapper.py @@ -99,8 +99,8 @@ def __init__( mask_cmap: str = 'gray', norm: Literal['linear', 'log'] = 'linear', autoscale: Literal['auto', 'grow'] = 'auto', - vmin: sc.Variable | int | float | None = None, - vmax: sc.Variable | int | float | None = None, + vmin: sc.Variable | float | None = None, + vmax: sc.Variable | float | None = None, nan_color: str | None = None, figsize: tuple[float, float] | None = None, ): diff --git a/src/plopp/graphics/imageview.py b/src/plopp/graphics/imageview.py index 412d2e97..2e66ddb2 100644 --- a/src/plopp/graphics/imageview.py +++ b/src/plopp/graphics/imageview.py @@ -73,8 +73,8 @@ def __init__( cmap: str = 'viridis', mask_cmap: str = 'gray', norm: Literal['linear', 'log'] = 'linear', - vmin: sc.Variable | int | float | None = None, - vmax: sc.Variable | int | float | None = None, + vmin: sc.Variable | float | None = None, + vmax: sc.Variable | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', scale: dict[str, str] | None = None, aspect: Literal['auto', 'equal'] = 'auto', diff --git a/src/plopp/graphics/lineview.py b/src/plopp/graphics/lineview.py index 07e74b8e..5c73d00a 100644 --- a/src/plopp/graphics/lineview.py +++ b/src/plopp/graphics/lineview.py @@ -68,8 +68,8 @@ def __init__( self, *nodes, norm: Literal['linear', 'log'] = 'linear', - vmin: sc.Variable | int | float | None = None, - vmax: sc.Variable | int | float | None = None, + vmin: sc.Variable | float | None = None, + vmax: sc.Variable | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', scale: dict[str, str] | None = None, errorbars: bool = True, diff --git a/src/plopp/graphics/scatter3dview.py b/src/plopp/graphics/scatter3dview.py index 0a41cd4b..0b3b2680 100644 --- a/src/plopp/graphics/scatter3dview.py +++ b/src/plopp/graphics/scatter3dview.py @@ -63,8 +63,8 @@ def __init__( cmap: str = 'viridis', mask_cmap: str = 'gray', norm: Literal['linear', 'log'] = 'linear', - vmin: sc.Variable | int | float | None = None, - vmax: sc.Variable | int | float | None = None, + vmin: sc.Variable | float | None = None, + vmax: sc.Variable | float | None = None, figsize: tuple[int, int] = (600, 400), title: str | None = None, camera: Camera | None = None, diff --git a/src/plopp/graphics/scatterview.py b/src/plopp/graphics/scatterview.py index 8e7074ea..ba01c845 100644 --- a/src/plopp/graphics/scatterview.py +++ b/src/plopp/graphics/scatterview.py @@ -21,8 +21,8 @@ def __init__( y: str = 'y', size: str | None = None, norm: Literal['linear', 'log'] = 'linear', - vmin: sc.Variable | int | float | None = None, - vmax: sc.Variable | int | float | None = None, + vmin: sc.Variable | float | None = None, + vmax: sc.Variable | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', scale: dict[str, str] | None = None, mask_color: str = 'black', diff --git a/src/plopp/plotting/plot.py b/src/plopp/plotting/plot.py index b326b516..5fc4d8e6 100644 --- a/src/plopp/plotting/plot.py +++ b/src/plopp/plotting/plot.py @@ -25,8 +25,8 @@ def plot( norm: Literal['linear', 'log'] = 'linear', scale: dict[str, str] | None = None, title: str | None = None, - vmin: Variable | int | float | None = None, - vmax: Variable | int | float | None = None, + vmin: Variable | float | None = None, + vmax: Variable | float | None = None, autoscale: Literal['auto', 'grow'] = 'auto', legend: bool | tuple[float, float] = True, **kwargs, diff --git a/src/plopp/widgets/clip3d.py b/src/plopp/widgets/clip3d.py index 677936f6..6ad7d353 100644 --- a/src/plopp/widgets/clip3d.py +++ b/src/plopp/widgets/clip3d.py @@ -122,7 +122,7 @@ def __init__( layout={'width': '16px', 'padding': '0px'}, ) - for outline, val in zip(self.outlines, self.slider.value): + for outline, val in zip(self.outlines, self.slider.value, strict=True): pos = list(center) pos[axis] = val outline.position = pos @@ -168,7 +168,7 @@ def move(self, value: dict[str, Any]): < 0.01 * self.slider.step ): return - for outline, val in zip(self.outlines, value['new']): + for outline, val in zip(self.outlines, value['new'], strict=True): pos = list(outline.position) axis = 'xyz'.index(self._direction) pos[axis] = val From a4fe3fbec2e8528da47647a3a84d307efca287c8 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 15:29:40 +0200 Subject: [PATCH 6/8] Merge hidden cells --- docs/gallery/interactive-masking.ipynb | 23 ++++--------------- docs/gallery/rectangle-selection.ipynb | 31 +++++++++----------------- 2 files changed, 15 insertions(+), 39 deletions(-) diff --git a/docs/gallery/interactive-masking.ipynb b/docs/gallery/interactive-masking.ipynb index 574e887c..4cc29bdb 100644 --- a/docs/gallery/interactive-masking.ipynb +++ b/docs/gallery/interactive-masking.ipynb @@ -192,7 +192,7 @@ { "cell_type": "code", "execution_count": null, - "id": "a5cbc934-8409-4e1c-8033-08a5388cb8ed", + "id": "c3c1343d-845b-4a1f-9f28-978837169aa1", "metadata": { "editable": true, "nbsphinx": "hidden", @@ -203,29 +203,14 @@ }, "outputs": [], "source": [ + "from ipywidgets import HBox\n", + "\n", "r.value = True\n", "\n", "r._tool.click(50, 200)\n", "r._tool.click(200, 250)\n", "r._tool.click(30, 50)\n", - "r._tool.click(250, 170)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fcbbae45-4c37-49b7-9ca8-7161ba0d59f5", - "metadata": { - "editable": true, - "nbsphinx": "hidden", - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "from ipywidgets import HBox\n", + "r._tool.click(250, 170)\n", "\n", "fig.children = [\n", " fig.top_bar,\n", diff --git a/docs/gallery/rectangle-selection.ipynb b/docs/gallery/rectangle-selection.ipynb index 503dd2aa..5c6bd4ad 100644 --- a/docs/gallery/rectangle-selection.ipynb +++ b/docs/gallery/rectangle-selection.ipynb @@ -3,7 +3,13 @@ { "cell_type": "markdown", "id": "da024b16-3a9d-4761-983b-ecb94ef192ad", - "metadata": {}, + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, "source": [ "# Rectangle selection\n", "\n", @@ -160,7 +166,7 @@ { "cell_type": "code", "execution_count": null, - "id": "e077370d-941a-4910-b13a-02c5041b6297", + "id": "8a372fcb-ffdf-47af-84b3-588926391e8d", "metadata": { "editable": true, "nbsphinx": "hidden", @@ -171,29 +177,14 @@ }, "outputs": [], "source": [ + "from ipywidgets import HBox\n", + "\n", "r.value = True\n", "\n", "r._tool.click(50, 200)\n", "r._tool.click(200, 250)\n", "r._tool.click(30, 50)\n", - "r._tool.click(250, 170)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a84b4009-0eae-4512-bc78-ab7012841d3f", - "metadata": { - "editable": true, - "nbsphinx": "hidden", - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "from ipywidgets import HBox\n", + "r._tool.click(250, 170)\n", "\n", "f1 = box[0]\n", "f1.children = [\n", From 8d5060d76ddb1a3bfb185088a8812637771c7295 Mon Sep 17 00:00:00 2001 From: Jan-Lukas Wynen Date: Fri, 17 May 2024 15:35:25 +0200 Subject: [PATCH 7/8] Update dependencies --- requirements/base.in | 4 ++- requirements/base.txt | 16 ++++----- requirements/basetest.txt | 8 ++--- requirements/ci.txt | 20 +++++------ requirements/constraints.txt | 43 ++-------------------- requirements/dev.txt | 56 ++++++++++++++--------------- requirements/docs.txt | 60 +++++++++++++++---------------- requirements/mypy.txt | 4 +-- requirements/nightly.in | 2 +- requirements/nightly.txt | 4 +-- requirements/noplotly.txt | 32 +++++++---------- requirements/optional.txt | 69 +++++++++++++++++------------------- requirements/static.txt | 10 +++--- requirements/wheels.txt | 6 ++-- 14 files changed, 142 insertions(+), 192 deletions(-) diff --git a/requirements/base.in b/requirements/base.in index a08edf9b..b27b4d31 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -1,7 +1,9 @@ -c constraints.in +# Scipp is listed here because we need it for development +# but the package does not declare a dependency on Scipp. +scipp # Anything above "--- END OF CUSTOM SECTION ---" # will not be touched by ``make_base.py`` # --- END OF CUSTOM SECTION --- # The following was generated by 'tox -e deps', DO NOT EDIT MANUALLY! matplotlib>=3.5 -scipp diff --git a/requirements/base.txt b/requirements/base.txt index b9d2b592..452bc76f 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,28 +5,28 @@ # # pip-compile-multi # -contourpy==1.2.0 +contourpy==1.2.1 # via matplotlib cycler==0.12.1 # via matplotlib -fonttools==4.47.2 +fonttools==4.51.0 # via matplotlib kiwisolver==1.4.5 # via matplotlib -matplotlib==3.8.2 +matplotlib==3.9.0 # via -r base.in -numpy==1.26.3 +numpy==1.26.4 # via # contourpy # matplotlib # scipp -packaging==23.2 +packaging==24.0 # via matplotlib -pillow==10.2.0 +pillow==10.3.0 # via matplotlib -pyparsing==3.1.1 +pyparsing==3.1.2 # via matplotlib -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via matplotlib scipp==24.2.0 # via -r base.in diff --git a/requirements/basetest.txt b/requirements/basetest.txt index 3a058ef2..b80ba202 100644 --- a/requirements/basetest.txt +++ b/requirements/basetest.txt @@ -5,15 +5,15 @@ # # pip-compile-multi # -exceptiongroup==1.2.0 +exceptiongroup==1.2.1 # via pytest iniconfig==2.0.0 # via pytest -packaging==23.2 +packaging==24.0 # via pytest -pluggy==1.4.0 +pluggy==1.5.0 # via pytest -pytest==8.0.0 +pytest==8.2.0 # via -r basetest.in tomli==2.0.1 # via pytest diff --git a/requirements/ci.txt b/requirements/ci.txt index d6f215e2..56406a04 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -5,7 +5,7 @@ # # pip-compile-multi # -cachetools==5.3.2 +cachetools==5.3.3 # via tox certifi==2024.2.2 # via requests @@ -17,26 +17,26 @@ colorama==0.4.6 # via tox distlib==0.3.8 # via virtualenv -filelock==3.13.1 +filelock==3.14.0 # via # tox # virtualenv gitdb==4.0.11 # via gitpython -gitpython==3.1.41 +gitpython==3.1.43 # via -r ci.in -idna==3.6 +idna==3.7 # via requests -packaging==23.2 +packaging==24.0 # via # -r ci.in # pyproject-api # tox -platformdirs==4.2.0 +platformdirs==4.2.2 # via # tox # virtualenv -pluggy==1.4.0 +pluggy==1.5.0 # via tox pyproject-api==1.6.1 # via tox @@ -48,9 +48,9 @@ tomli==2.0.1 # via # pyproject-api # tox -tox==4.12.1 +tox==4.15.0 # via -r ci.in -urllib3==2.2.0 +urllib3==2.2.1 # via requests -virtualenv==20.25.0 +virtualenv==20.26.2 # via tox diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 941639f3..c24fd27f 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -1,47 +1,8 @@ -# SHA1:e834d540057a673dbbdf8add99b78a7a53d08425 +# SHA1:da39a3ee5e6b4b0d3255bfef95601890afd80709 # # This file is autogenerated by pip-compile-multi # To update, run: # # pip-compile-multi # -asttokens==2.4.1 - # via stack-data -backcall==0.2.0 - # via ipython -decorator==5.1.1 - # via ipython -executing==2.0.1 - # via stack-data -ipython==8.9.0 - # via -r constraints.in -jedi==0.19.1 - # via ipython -matplotlib-inline==0.1.6 - # via ipython -parso==0.8.3 - # via jedi -pexpect==4.9.0 - # via ipython -pickleshare==0.7.5 - # via ipython -prompt-toolkit==3.0.36 - # via - # -r constraints.in - # ipython -ptyprocess==0.7.0 - # via pexpect -pure-eval==0.2.2 - # via stack-data -pygments==2.17.2 - # via ipython -six==1.16.0 - # via asttokens -stack-data==0.6.3 - # via ipython -traitlets==5.14.1 - # via - # ipython - # matplotlib-inline -wcwidth==0.2.13 - # via prompt-toolkit + diff --git a/requirements/dev.txt b/requirements/dev.txt index 0a579f56..8101e28e 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -14,7 +14,7 @@ -r wheels.txt annotated-types==0.6.0 # via pydantic -anyio==4.2.0 +anyio==4.3.0 # via # httpx # jupyter-server @@ -32,9 +32,9 @@ click==8.1.7 # via # pip-compile-multi # pip-tools -copier==9.1.1 +copier==9.2.0 # via -r dev.in -dunamai==1.19.0 +dunamai==1.21.1 # via copier fqdn==1.5.1 # via jsonschema @@ -42,40 +42,40 @@ funcy==2.0 # via copier h11==0.14.0 # via httpcore -httpcore==1.0.2 +httpcore==1.0.5 # via httpx -httpx==0.26.0 +httpx==0.27.0 # via jupyterlab isoduration==20.11.0 # via jsonschema jinja2-ansible-filters==1.3.2 # via copier -json5==0.9.14 +json5==0.9.25 # via jupyterlab-server jsonpointer==2.4 # via jsonschema -jsonschema[format-nongpl]==4.21.1 +jsonschema[format-nongpl]==4.22.0 # via # jupyter-events # jupyterlab-server # nbformat -jupyter-events==0.9.0 +jupyter-events==0.10.0 # via jupyter-server -jupyter-lsp==2.2.2 +jupyter-lsp==2.2.5 # via jupyterlab -jupyter-server==2.12.5 +jupyter-server==2.14.0 # via # jupyter-lsp # jupyterlab # jupyterlab-server # notebook-shim -jupyter-server-terminals==0.5.2 +jupyter-server-terminals==0.5.3 # via jupyter-server -jupyterlab==4.1.0 +jupyterlab==4.2.0 # via -r dev.in -jupyterlab-server==2.25.2 +jupyterlab-server==2.27.1 # via jupyterlab -notebook-shim==0.2.3 +notebook-shim==0.2.4 # via jupyterlab overrides==7.7.0 # via jupyter-server @@ -83,23 +83,21 @@ pathspec==0.12.1 # via copier pip-compile-multi==2.6.3 # via -r dev.in -pip-tools==7.3.0 +pip-tools==7.4.1 # via pip-compile-multi -plumbum==1.8.2 +plumbum==1.8.3 # via copier -prometheus-client==0.19.0 +prometheus-client==0.20.0 # via jupyter-server -pycparser==2.21 +pycparser==2.22 # via cffi -pydantic==2.6.0 +pydantic==2.7.1 # via copier -pydantic-core==2.16.1 +pydantic-core==2.18.2 # via pydantic python-json-logger==2.0.7 # via jupyter-events -pyyaml-include==1.3.2 - # via copier -questionary==2.0.1 +questionary==1.10.0 # via copier rfc3339-validator==0.1.4 # via @@ -109,27 +107,27 @@ rfc3986-validator==0.1.1 # via # jsonschema # jupyter-events -send2trash==1.8.2 +send2trash==1.8.3 # via jupyter-server -sniffio==1.3.0 +sniffio==1.3.1 # via # anyio # httpx -terminado==0.18.0 +terminado==0.18.1 # via # jupyter-server # jupyter-server-terminals toposort==1.10 # via pip-compile-multi -types-python-dateutil==2.8.19.20240106 +types-python-dateutil==2.9.0.20240316 # via arrow uri-template==1.3.0 # via jsonschema webcolors==1.13 # via jsonschema -websocket-client==1.7.0 +websocket-client==1.8.0 # via jupyter-server -wheel==0.42.0 +wheel==0.43.0 # via pip-tools # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/docs.txt b/requirements/docs.txt index cfa3e738..1dc91aad 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -7,7 +7,7 @@ # -r base.txt -r optional.txt -accessible-pygments==0.0.4 +accessible-pygments==0.0.5 # via pydata-sphinx-theme alabaster==0.7.16 # via sphinx @@ -15,7 +15,7 @@ attrs==23.2.0 # via # jsonschema # referencing -babel==2.14.0 +babel==2.15.0 # via # pydata-sphinx-theme # sphinx @@ -29,11 +29,11 @@ certifi==2024.2.2 # via requests charset-normalizer==3.3.2 # via requests -debugpy==1.8.0 +debugpy==1.8.1 # via ipykernel defusedxml==0.7.1 # via nbconvert -docutils==0.20.1 +docutils==0.21.2 # via # myst-parser # nbsphinx @@ -43,31 +43,31 @@ fastjsonschema==2.19.1 # via nbformat gitdb==4.0.11 # via gitpython -gitpython==3.1.41 +gitpython==3.1.43 # via -r docs.in -h5py==3.10.0 +h5py==3.11.0 # via -r docs.in -idna==3.6 +idna==3.7 # via requests imagesize==1.4.1 # via sphinx -ipykernel==6.29.0 +ipykernel==6.29.4 # via -r docs.in -jinja2==3.1.3 +jinja2==3.1.4 # via # myst-parser # nbconvert # nbsphinx # sphinx -jsonschema==4.21.1 +jsonschema==4.22.0 # via nbformat jsonschema-specifications==2023.12.1 # via jsonschema -jupyter-client==8.6.0 +jupyter-client==8.6.1 # via # ipykernel # nbclient -jupyter-core==5.7.1 +jupyter-core==5.7.2 # via # ipykernel # jupyter-client @@ -84,34 +84,34 @@ markupsafe==2.1.5 # via # jinja2 # nbconvert -mdit-py-plugins==0.4.0 +mdit-py-plugins==0.4.1 # via myst-parser mdurl==0.1.2 # via markdown-it-py mistune==3.0.2 # via nbconvert -myst-parser==2.0.0 +myst-parser==3.0.1 # via -r docs.in -nbclient==0.9.0 +nbclient==0.10.0 # via nbconvert -nbconvert==7.14.2 +nbconvert==7.16.4 # via nbsphinx -nbformat==5.9.2 +nbformat==5.10.4 # via # nbclient # nbconvert # nbsphinx -nbsphinx==0.9.3 +nbsphinx==0.9.4 # via -r docs.in nest-asyncio==1.6.0 # via ipykernel pandocfilters==1.5.1 # via nbconvert -platformdirs==4.2.0 +platformdirs==4.2.2 # via # jupyter-core # pooch -pooch==1.8.0 +pooch==1.8.1 # via -r docs.in psutil==5.9.8 # via ipykernel @@ -119,11 +119,11 @@ pydata-sphinx-theme==0.15.2 # via -r docs.in pyyaml==6.0.1 # via myst-parser -pyzmq==25.1.2 +pyzmq==26.0.3 # via # ipykernel # jupyter-client -referencing==0.33.0 +referencing==0.35.1 # via # jsonschema # jsonschema-specifications @@ -132,7 +132,7 @@ requests==2.31.0 # -r docs.in # pooch # sphinx -rpds-py==0.17.1 +rpds-py==0.18.1 # via # jsonschema # referencing @@ -142,7 +142,7 @@ snowballstemmer==2.2.0 # via sphinx soupsieve==2.5 # via beautifulsoup4 -sphinx==7.2.6 +sphinx==7.3.7 # via # -r docs.in # myst-parser @@ -152,13 +152,13 @@ sphinx==7.2.6 # sphinx-copybutton # sphinx-design # sphinx-gallery -sphinx-autodoc-typehints==1.25.3 +sphinx-autodoc-typehints==2.1.0 # via -r docs.in sphinx-copybutton==0.5.2 # via -r docs.in sphinx-design==0.5.0 # via -r docs.in -sphinx-gallery==0.15.0 +sphinx-gallery==0.16.0 # via -r docs.in sphinxcontrib-applehelp==1.0.8 # via sphinx @@ -172,15 +172,15 @@ sphinxcontrib-qthelp==1.0.7 # via sphinx sphinxcontrib-serializinghtml==1.1.10 # via sphinx -tinycss2==1.2.1 +tinycss2==1.3.0 # via nbconvert +tomli==2.0.1 + # via sphinx tornado==6.4 # via # ipykernel # jupyter-client -typing-extensions==4.9.0 - # via pydata-sphinx-theme -urllib3==2.2.0 +urllib3==2.2.1 # via requests webencodings==0.5.1 # via diff --git a/requirements/mypy.txt b/requirements/mypy.txt index ac285686..c4b5fb0b 100644 --- a/requirements/mypy.txt +++ b/requirements/mypy.txt @@ -6,9 +6,7 @@ # pip-compile-multi # -r test.txt -mypy==1.8.0 +mypy==1.10.0 # via -r mypy.in mypy-extensions==1.0.0 # via mypy -typing-extensions==4.9.0 - # via mypy diff --git a/requirements/nightly.in b/requirements/nightly.in index 8cdc74fb..52aa898a 100644 --- a/requirements/nightly.in +++ b/requirements/nightly.in @@ -3,4 +3,4 @@ # --- END OF CUSTOM SECTION --- # The following was generated by 'tox -e deps', DO NOT EDIT MANUALLY! matplotlib>=3.5 -https://github.com/scipp/scipp/releases/download/nightly/scipp-nightly-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +https://github.com/scipp/scipp/releases/download/nightly/scipp-nightly-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl diff --git a/requirements/nightly.txt b/requirements/nightly.txt index e1889973..2c1f5298 100644 --- a/requirements/nightly.txt +++ b/requirements/nightly.txt @@ -1,4 +1,4 @@ -# SHA1:426b95d017ee66a28d0053d8aa2a7de55be693e6 +# SHA1:28901c205d4c1ba1a0f3f55702a4cd26dd766b59 # # This file is autogenerated by pip-compile-multi # To update, run: @@ -7,5 +7,5 @@ # -r basetest.txt -r optional.txt -scipp @ https://github.com/scipp/scipp/releases/download/nightly/scipp-nightly-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl +scipp @ https://github.com/scipp/scipp/releases/download/nightly/scipp-nightly-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl # via -r nightly.in diff --git a/requirements/noplotly.txt b/requirements/noplotly.txt index b9922ac6..e2d45c8e 100644 --- a/requirements/noplotly.txt +++ b/requirements/noplotly.txt @@ -9,51 +9,45 @@ -r basetest.txt asttokens==2.4.1 # via stack-data -backcall==0.2.0 - # via ipython -comm==0.2.1 +comm==0.2.2 # via ipywidgets decorator==5.1.1 # via ipython executing==2.0.1 # via stack-data -ipython==8.9.0 - # via - # -c constraints.in - # ipywidgets -ipywidgets==8.1.1 +ipython==8.24.0 + # via ipywidgets +ipywidgets==8.1.2 # via -r noplotly.in jedi==0.19.1 # via ipython -jupyterlab-widgets==3.0.9 +jupyterlab-widgets==3.0.10 # via ipywidgets -matplotlib-inline==0.1.6 +matplotlib-inline==0.1.7 # via ipython -parso==0.8.3 +parso==0.8.4 # via jedi pexpect==4.9.0 # via ipython -pickleshare==0.7.5 +prompt-toolkit==3.0.43 # via ipython -prompt-toolkit==3.0.36 - # via - # -c constraints.in - # ipython ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data -pygments==2.17.2 +pygments==2.18.0 # via ipython stack-data==0.6.3 # via ipython -traitlets==5.14.1 +traitlets==5.14.3 # via # comm # ipython # ipywidgets # matplotlib-inline +typing-extensions==4.11.0 + # via ipython wcwidth==0.2.13 # via prompt-toolkit -widgetsnbextension==4.0.9 +widgetsnbextension==4.0.10 # via ipywidgets diff --git a/requirements/optional.txt b/requirements/optional.txt index ba55be68..227d4e1e 100644 --- a/requirements/optional.txt +++ b/requirements/optional.txt @@ -7,55 +7,54 @@ # asttokens==2.4.1 # via stack-data -backcall==0.2.0 - # via ipython -comm==0.2.1 +comm==0.2.2 # via ipywidgets -contourpy==1.2.0 +contourpy==1.2.1 # via matplotlib cycler==0.12.1 # via matplotlib decorator==5.1.1 # via ipython +exceptiongroup==1.2.1 + # via ipython executing==2.0.1 # via stack-data -fonttools==4.47.2 +fonttools==4.51.0 # via matplotlib -graphviz==0.20.1 +graphviz==0.20.3 # via -r optional.in ipydatawidgets==4.3.5 # via pythreejs -ipympl==0.9.3 +ipympl==0.9.4 # via -r optional.in -ipython==8.9.0 +ipython==8.24.0 # via - # -c constraints.in # ipympl # ipywidgets ipython-genutils==0.2.0 # via ipympl -ipywidgets==8.1.1 +ipywidgets==8.1.2 # via # ipydatawidgets # ipympl # pythreejs jedi==0.19.1 # via ipython -jupyterlab-widgets==3.0.9 +jupyterlab-widgets==3.0.10 # via ipywidgets kaleido==0.2.1 # via -r optional.in kiwisolver==1.4.5 # via matplotlib -matplotlib==3.8.2 +matplotlib==3.9.0 # via # ipympl # mpltoolbox -matplotlib-inline==0.1.6 +matplotlib-inline==0.1.7 # via ipython -mpltoolbox==23.9.0 +mpltoolbox==24.5.0 # via -r optional.in -numpy==1.26.3 +numpy==1.26.4 # via # contourpy # ipydatawidgets @@ -67,42 +66,38 @@ numpy==1.26.3 # pythreejs # scipy # xarray -packaging==23.2 +packaging==24.0 # via # matplotlib # plotly # xarray -pandas==2.2.0 +pandas==2.2.2 # via # -r optional.in # xarray -parso==0.8.3 +parso==0.8.4 # via jedi pexpect==4.9.0 # via ipython -pickleshare==0.7.5 - # via ipython -pillow==10.2.0 +pillow==10.3.0 # via # ipympl # matplotlib -plotly==5.18.0 +plotly==5.22.0 # via -r optional.in -prompt-toolkit==3.0.36 - # via - # -c constraints.in - # ipython +prompt-toolkit==3.0.43 + # via ipython ptyprocess==0.7.0 # via pexpect pure-eval==0.2.2 # via stack-data -pyarrow==15.0.0 +pyarrow==16.1.0 # via -r optional.in -pygments==2.17.2 +pygments==2.18.0 # via ipython -pyparsing==3.1.1 +pyparsing==3.1.2 # via matplotlib -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via # matplotlib # pandas @@ -110,7 +105,7 @@ pythreejs==2.4.2 # via -r optional.in pytz==2024.1 # via pandas -scipy==1.12.0 +scipy==1.13.0 # via -r optional.in six==1.16.0 # via @@ -118,9 +113,9 @@ six==1.16.0 # python-dateutil stack-data==0.6.3 # via ipython -tenacity==8.2.3 +tenacity==8.3.0 # via plotly -traitlets==5.14.1 +traitlets==5.14.3 # via # comm # ipympl @@ -131,11 +126,13 @@ traitlets==5.14.1 # traittypes traittypes==0.2.1 # via ipydatawidgets -tzdata==2023.4 +typing-extensions==4.11.0 + # via ipython +tzdata==2024.1 # via pandas wcwidth==0.2.13 # via prompt-toolkit -widgetsnbextension==4.0.9 +widgetsnbextension==4.0.10 # via ipywidgets -xarray==2024.1.1 +xarray==2024.5.0 # via -r optional.in diff --git a/requirements/static.txt b/requirements/static.txt index 53c7664c..7f416fba 100644 --- a/requirements/static.txt +++ b/requirements/static.txt @@ -9,19 +9,19 @@ cfgv==3.4.0 # via pre-commit distlib==0.3.8 # via virtualenv -filelock==3.13.1 +filelock==3.14.0 # via virtualenv -identify==2.5.33 +identify==2.5.36 # via pre-commit nodeenv==1.8.0 # via pre-commit -platformdirs==4.2.0 +platformdirs==4.2.2 # via virtualenv -pre-commit==3.6.0 +pre-commit==3.7.1 # via -r static.in pyyaml==6.0.1 # via pre-commit -virtualenv==20.25.0 +virtualenv==20.26.2 # via pre-commit # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/wheels.txt b/requirements/wheels.txt index 4935673c..d1a95de4 100644 --- a/requirements/wheels.txt +++ b/requirements/wheels.txt @@ -5,11 +5,11 @@ # # pip-compile-multi # -build==1.0.3 +build==1.2.1 # via -r wheels.in -packaging==23.2 +packaging==24.0 # via build -pyproject-hooks==1.0.0 +pyproject-hooks==1.1.0 # via build tomli==2.0.1 # via build From 3feae9b4f84d6a167059da41ee8d680f27d9a584 Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Tue, 21 May 2024 22:15:53 +0200 Subject: [PATCH 8/8] check for both ipympl and widget in backend string as this seems to have changed in latest version of matplotlib/ipympl --- src/plopp/backends/matplotlib/utils.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plopp/backends/matplotlib/utils.py b/src/plopp/backends/matplotlib/utils.py index cc8b737b..7b08109f 100644 --- a/src/plopp/backends/matplotlib/utils.py +++ b/src/plopp/backends/matplotlib/utils.py @@ -29,9 +29,11 @@ def fig_to_bytes(fig: Figure, form: Literal['png', 'svg'] = 'png') -> bytes: def is_interactive_backend() -> bool: """ - Return `True` if the current backend used by Matplotlib is the widget backend. + Return ``True`` if the current backend used by Matplotlib is the widget/ipympl + backend. """ - return 'ipympl' in mpl.get_backend() + backend = mpl.get_backend() + return any(x in backend for x in ("ipympl", "widget")) def make_figure(*args, **kwargs) -> Figure: