From 9f679bd8c303fed02860cf5931925e87012a47c9 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Thu, 4 Aug 2022 17:21:25 -0700 Subject: [PATCH 1/3] release prep --- .github/workflows/ci.yml | 1 + CHANGELOG.rst | 41 ++++++++++++++++++++++++++++++++++++++++ changelog/10.feature.rst | 1 - changelog/12.feature.rst | 1 - changelog/16.feature.rst | 1 - changelog/17.feature.rst | 2 -- changelog/23.trivial.rst | 1 - changelog/24.feature.rst | 1 - changelog/26.feature.rst | 2 -- changelog/29.feature.rst | 2 -- changelog/30.trivial.rst | 1 - changelog/34.bugfix.rst | 1 - changelog/37.feature.rst | 1 - changelog/38.feature.rst | 1 - changelog/4.feature.rst | 1 - changelog/52.trivial.rst | 1 - changelog/55.bugfix.rst | 1 - changelog/59.feature.rst | 1 - changelog/69.trivial.rst | 1 - changelog/70.feature.rst | 1 - changelog/73.trivial.rst | 2 -- changelog/79.trivial.rst | 1 - changelog/84.feature.rst | 1 - setup.cfg | 6 +++--- 24 files changed, 45 insertions(+), 28 deletions(-) delete mode 100644 changelog/10.feature.rst delete mode 100644 changelog/12.feature.rst delete mode 100644 changelog/16.feature.rst delete mode 100644 changelog/17.feature.rst delete mode 100644 changelog/23.trivial.rst delete mode 100644 changelog/24.feature.rst delete mode 100644 changelog/26.feature.rst delete mode 100644 changelog/29.feature.rst delete mode 100644 changelog/30.trivial.rst delete mode 100644 changelog/34.bugfix.rst delete mode 100644 changelog/37.feature.rst delete mode 100644 changelog/38.feature.rst delete mode 100644 changelog/4.feature.rst delete mode 100644 changelog/52.trivial.rst delete mode 100644 changelog/55.bugfix.rst delete mode 100644 changelog/59.feature.rst delete mode 100644 changelog/69.trivial.rst delete mode 100644 changelog/70.feature.rst delete mode 100644 changelog/73.trivial.rst delete mode 100644 changelog/79.trivial.rst delete mode 100644 changelog/84.feature.rst diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2214014..b458712 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,7 @@ jobs: coverage: codecov envs: | - macos: py38 + - linux: py310 docs: needs: [core] diff --git a/CHANGELOG.rst b/CHANGELOG.rst index e69de29..137b981 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -0,0 +1,41 @@ +0.1.0 (2022-08-04) +================== + +Features +-------- + +- Creation of :class:`~sunkit_pyvista.plotter.SunpyPlotter` class which allows for plotting of a :class:`~sunpy.map.GenericMap` through pyvista. (`#4 `__) +- Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.set_camera_coordinate` which allows for specifying the initial camera coordinates. (`#10 `__) +- Added :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_field_lines` method which allows for plotting of magnetic field lines from `pfsspy` through pyvista. (`#12 `__) +- Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.set_view_angle` which allows for setting of the camera's width/view angle. (`#16 `__) +- Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_quadrangle` which allows for drawing a quadrangle defined + by coordinates passed to it. (`#17 `__) +- Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter._add_mesh_to_dict` stores each mesh in a dictionary for later access. (`#24 `__) +- :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_map` accepts the keyword ``clip_interval`` as argument, which clips the data + according to the percentile interval bounded by the two numbers. (`#26 `__) +- ``plot_line()`` is renamed to :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_coordinates` + which also allows for a sphere with given ``radius`` to be plotted if a single coordinate is passed to it. (`#29 `__) +- Added :meth:`~sunkit_pyvista.plotter.SunpyPlotter.save` method which allows for saving of plots to a vtm file. (`#37 `__) +- Allows for figure tests to be performed with `pytest`. (`#38 `__) +- Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_limb` which allows for drawing a limb as seen by the map's observer. (`#59 `__) +- Allows user to specify color via a color function to :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_field_lines`. (`#70 `__) +- Added narrative documentation for sunkit-pyvista. (`#84 `__) + + +Bug Fixes +--------- + +- Adds parenthesis to fix check in :meth:`~sunkit_pyvista.plotter.SunpyPlotter.set_view_angle`. (`#34 `__) +- Fixes error while loading color map in :meth:`~sunkit_pyvista.plotter.SunpyPlotter.load`. (`#55 `__) + + +Internal Changes +---------------- + +- Increases test converage for :class:`~sunkit_pyvista.plotter.SunpyPlotter`. (`#23 `__) +- Rearranged existing examples and added an example brightest pixel with :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_coordinates`. (`#30 `__) +- :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_quadrangle` uses a :meth`~pyvista.utilities.Spline` for combining the individual points. (`#52 `__) +- Adds an example using :meth:`~sunpy.coordinates.frames.Helioprojective.assume_spherical_screen`. (`#69 `__) +- Changed the manner that colors or colormaps are saved. + Changed default of meshes to be white. (`#73 `__) +- Removes colorbars when displaying plots. (`#79 `__) diff --git a/changelog/10.feature.rst b/changelog/10.feature.rst deleted file mode 100644 index 511c8be..0000000 --- a/changelog/10.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.set_camera_coordinate` which allows for specifying the initial camera coordinates. diff --git a/changelog/12.feature.rst b/changelog/12.feature.rst deleted file mode 100644 index 46949b7..0000000 --- a/changelog/12.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Added :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_field_lines` method which allows for plotting of magnetic field lines from `pfsspy` through pyvista. diff --git a/changelog/16.feature.rst b/changelog/16.feature.rst deleted file mode 100644 index 16c9e19..0000000 --- a/changelog/16.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.set_view_angle` which allows for setting of the camera's width/view angle. diff --git a/changelog/17.feature.rst b/changelog/17.feature.rst deleted file mode 100644 index 8fac2d1..0000000 --- a/changelog/17.feature.rst +++ /dev/null @@ -1,2 +0,0 @@ -Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_quadrangle` which allows for drawing a quadrangle defined -by coordinates passed to it. diff --git a/changelog/23.trivial.rst b/changelog/23.trivial.rst deleted file mode 100644 index ad174ce..0000000 --- a/changelog/23.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -Increases test converage for :class:`~sunkit_pyvista.plotter.SunpyPlotter`. diff --git a/changelog/24.feature.rst b/changelog/24.feature.rst deleted file mode 100644 index d2c02f9..0000000 --- a/changelog/24.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter._add_mesh_to_dict` stores each mesh in a dictionary for later access. diff --git a/changelog/26.feature.rst b/changelog/26.feature.rst deleted file mode 100644 index dcae5f0..0000000 --- a/changelog/26.feature.rst +++ /dev/null @@ -1,2 +0,0 @@ -:meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_map` accepts the keyword ``clip_interval`` as argument, which clips the data -according to the percentile interval bounded by the two numbers. diff --git a/changelog/29.feature.rst b/changelog/29.feature.rst deleted file mode 100644 index 65583c5..0000000 --- a/changelog/29.feature.rst +++ /dev/null @@ -1,2 +0,0 @@ -``plot_line()`` is renamed to :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_coordinates` -which also allows for a sphere with given ``radius`` to be plotted if a single coordinate is passed to it. diff --git a/changelog/30.trivial.rst b/changelog/30.trivial.rst deleted file mode 100644 index f049377..0000000 --- a/changelog/30.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -Rearranged existing examples and added an example brightest pixel with :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_coordinates`. diff --git a/changelog/34.bugfix.rst b/changelog/34.bugfix.rst deleted file mode 100644 index 033dc4d..0000000 --- a/changelog/34.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Adds parenthesis to fix check in :meth:`~sunkit_pyvista.plotter.SunpyPlotter.set_view_angle`. diff --git a/changelog/37.feature.rst b/changelog/37.feature.rst deleted file mode 100644 index aa02e6b..0000000 --- a/changelog/37.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Added :meth:`~sunkit_pyvista.plotter.SunpyPlotter.save` method which allows for saving of plots to a vtm file. diff --git a/changelog/38.feature.rst b/changelog/38.feature.rst deleted file mode 100644 index 0192384..0000000 --- a/changelog/38.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Allows for figure tests to be performed with `pytest`. diff --git a/changelog/4.feature.rst b/changelog/4.feature.rst deleted file mode 100644 index 0e00011..0000000 --- a/changelog/4.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Creation of :class:`~sunkit_pyvista.plotter.SunpyPlotter` class which allows for plotting of a :class:`~sunpy.map.GenericMap` through pyvista. diff --git a/changelog/52.trivial.rst b/changelog/52.trivial.rst deleted file mode 100644 index d5226ec..0000000 --- a/changelog/52.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -:meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_quadrangle` uses a :meth`~pyvista.utilities.Spline` for combining the individual points. diff --git a/changelog/55.bugfix.rst b/changelog/55.bugfix.rst deleted file mode 100644 index 119bd96..0000000 --- a/changelog/55.bugfix.rst +++ /dev/null @@ -1 +0,0 @@ -Fixes error while loading color map in :meth:`~sunkit_pyvista.plotter.SunpyPlotter.load`. diff --git a/changelog/59.feature.rst b/changelog/59.feature.rst deleted file mode 100644 index a55eabc..0000000 --- a/changelog/59.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Adds :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_limb` which allows for drawing a limb as seen by the map's observer. diff --git a/changelog/69.trivial.rst b/changelog/69.trivial.rst deleted file mode 100644 index 8495f6d..0000000 --- a/changelog/69.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -Adds an example using :meth:`~sunpy.coordinates.frames.Helioprojective.assume_spherical_screen`. diff --git a/changelog/70.feature.rst b/changelog/70.feature.rst deleted file mode 100644 index 921b2c3..0000000 --- a/changelog/70.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Allows user to specify color via a color function to :meth:`~sunkit_pyvista.plotter.SunpyPlotter.plot_field_lines`. diff --git a/changelog/73.trivial.rst b/changelog/73.trivial.rst deleted file mode 100644 index 899de08..0000000 --- a/changelog/73.trivial.rst +++ /dev/null @@ -1,2 +0,0 @@ -Changed the manner that colors or colormaps are saved. -Changed default of meshes to be white. diff --git a/changelog/79.trivial.rst b/changelog/79.trivial.rst deleted file mode 100644 index b81e710..0000000 --- a/changelog/79.trivial.rst +++ /dev/null @@ -1 +0,0 @@ -Removes colorbars when displaying plots. diff --git a/changelog/84.feature.rst b/changelog/84.feature.rst deleted file mode 100644 index 1dde83e..0000000 --- a/changelog/84.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Added narrative documentation for sunkit-pyvista. diff --git a/setup.cfg b/setup.cfg index e063e2d..b0ab448 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,10 +23,11 @@ classifiers = Programming Language :: Python :: 3 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 Topic :: Scientific/Engineering :: Visualization [options] -python_requires = >=3.8, <3.10 +python_requires = >=3.8 zip_safe = False packages = find: include_package_data = True @@ -34,7 +35,7 @@ setup_requires = setuptools_scm install_requires = pfsspy>=0.6.6 - pyvista>0.34.0 + pyvista>0.36.0 sunpy[map]>=4.0.0 [options.extras_require] @@ -47,7 +48,6 @@ docs = pythreejs sphinx sphinx-automodapi - sphinx-automodapi sphinx-changelog streamtracer sunpy-sphinx-theme From 64fc7ee2c8505a86f7a7848780166ca7c5a77fe4 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Thu, 4 Aug 2022 17:26:57 -0700 Subject: [PATCH 2/3] its time to lint --- .pre-commit-config.yaml | 66 ++++------- .readthedocs.yaml | 2 +- docs/conf.py | 81 +++++++------ docs/examples/setup.py | 4 +- examples/3d_functionality.py | 28 +++-- examples/assume_spherical.py | 3 +- examples/field_lines.py | 7 +- setup.py | 13 +- sunkit_pyvista/plotter.py | 165 +++++++++++++++----------- sunkit_pyvista/sample.py | 5 +- sunkit_pyvista/tests/conftest.py | 50 ++++---- sunkit_pyvista/tests/test_plotting.py | 52 ++++---- sunkit_pyvista/tests/test_pyvista.py | 96 ++++++++------- sunkit_pyvista/utils.py | 20 ++-- 14 files changed, 322 insertions(+), 270 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d082bcc..aa053bd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,59 +1,39 @@ repos: -# The warnings/errors we check for here are: - # E901 - SyntaxError or IndentationError - # E902 - IOError - # F822 - undefined name in __all__ - # F823 - local variable name referenced before assignment - # Others are taken care of by autopep8 - - repo: https://github.com/PyCQA/flake8 - rev: 5.0.2 + - repo: https://github.com/myint/docformatter + rev: v1.4 hooks: - - id: flake8 - args: - [ - "--count", - "--select", - "E901,E902,F822,F823", - ] - exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|extern.*|.rst|.md|cm/__init__.py|sunpy/extern|sunpy/visualization/colormaps/color_tables.py)$" + - id: docformatter + args: [--in-place, --pre-summary-newline, --make-summary-multi] - repo: https://github.com/myint/autoflake rev: v1.4 hooks: - id: autoflake - args: - [ - "--in-place", - "--remove-all-unused-imports", - "--remove-unused-variable", - ] - exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|extern.*|.rst|.md|__init__.py|sunpy/extern|docs/conf.py)$" - - repo: https://github.com/PyCQA/isort - rev: 5.10.1 - hooks: + args: ['--in-place', '--remove-all-unused-imports', '--remove-unused-variable'] + exclude: ".*(.fits|.fts|.fit|.txt|tca.*|extern.*|.rst|.md|__init__.py|docs/conf.py)$" + - repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - repo: https://github.com/timothycrosley/isort + rev: 5.10.1 + hooks: - id: isort - args: ["--sp", "setup.cfg"] - exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|extern.*|.rst|.md|cm/__init__.py|sunpy/extern|docs/conf.py)$" - - repo: https://github.com/pre-commit/mirrors-autopep8 - rev: v1.6.0 - hooks: - - id: autopep8 - args: ["--in-place","--max-line-length", "200"] - exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*|extern.*|.rst|.md|cm/__init__.py|sunpy/extern|sunpy/visualization/colormaps/color_tables.py)$" - - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 - hooks: + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: - id: check-ast - id: check-case-conflict - id: trailing-whitespace - exclude: ".*(.fits|.fts|.fit|.header|.txt)$" + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - id: mixed-line-ending + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" + - id: end-of-file-fixer + exclude: ".*(.fits|.fts|.fit|.txt|.csv)$" - id: check-yaml - id: debug-statements - id: check-added-large-files args: ['--enforce-all','--maxkb=1054'] - - id: end-of-file-fixer - exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*)$" - - id: mixed-line-ending - exclude: ".*(.fits|.fts|.fit|.header|.txt|tca.*)$" - ci: autofix_prs: false diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f7017c9..00fa09a 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.9" + python: "3.10" apt_packages: - graphviz diff --git a/docs/conf.py b/docs/conf.py index 3d114a0..9b48227 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -4,6 +4,7 @@ import warnings import numpy as np import pyvista + # Use the sunpy theme from sunpy_sphinx_theme.conf import * from packaging.version import Version @@ -12,71 +13,73 @@ from datetime import datetime # -- Project information ----------------------------------------------------- -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' -os.environ['HIDE_PARFIVE_PROGESS'] = 'True' -project = 'sunkit-pyvista' -author = 'SunPy Community' -copyright = '{}, {}'.format(datetime.now().year, author) +on_rtd = os.environ.get("READTHEDOCS", None) == "True" +os.environ["HIDE_PARFIVE_PROGESS"] = "True" +project = "sunkit-pyvista" +author = "SunPy Community" +copyright = "{}, {}".format(datetime.now().year, author) # The full version, including alpha/beta/rc tags release = __version__ sunkit_pyvista_version = Version(__version__) -is_release = not(sunkit_pyvista_version.is_prerelease or sunkit_pyvista_version.is_devrelease) +is_release = not ( + sunkit_pyvista_version.is_prerelease or sunkit_pyvista_version.is_devrelease +) # -- General configuration --------------------------------------------------- extensions = [ - 'sphinx_automodapi.automodapi', - 'sphinx_automodapi.smart_resolver', - 'sphinx_changelog', - 'sphinx.ext.autodoc', - 'sphinx.ext.coverage', - 'sphinx.ext.doctest', - 'sphinx.ext.inheritance_diagram', - 'sphinx.ext.intersphinx', - 'sphinx.ext.mathjax', - 'sphinx.ext.napoleon', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', + "sphinx_automodapi.automodapi", + "sphinx_automodapi.smart_resolver", + "sphinx_changelog", + "sphinx.ext.autodoc", + "sphinx.ext.coverage", + "sphinx.ext.doctest", + "sphinx.ext.inheritance_diagram", + "sphinx.ext.intersphinx", + "sphinx.ext.mathjax", + "sphinx.ext.napoleon", + "sphinx.ext.todo", + "sphinx.ext.viewcode", "jupyter_sphinx", ] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: -source_suffix = '.rst' +source_suffix = ".rst" # The master toctree document. -master_doc = 'index' +master_doc = "index" # Enable nitpicky mode, which forces links to be non-broken nitpicky = True nitpick_ignore = [ # Prevents sphinx nitpicky mode picking up on optional # (see https://github.com/sphinx-doc/sphinx/issues/6861) - ('py:class', 'optional'), + ("py:class", "optional"), # See https://github.com/numpy/numpy/issues/10039 - ('py:obj', 'numpy.datetime64'), + ("py:obj", "numpy.datetime64"), # There's no specific file or function classes to link to - ('py:class', 'file object'), - ('py:class', 'function'), - ('py:obj', 'function'), - ('py:class', 'any type'), - ('py:class', "Unit('pix')"), - ('py:class', "Unit('deg')"), - ('py:class', "Unit('arcsec')"), - ('py:class', "Unit('%')"), - ('py:class', "Unit('s')"), - ('py:class', "Unit('Angstrom')"), - ('py:class', "Unit('arcsec / pix')"), - ('py:class', "Unit('W / m2')"), - ('py:class', 'array-like'), - ('py:obj', 'parfive'), - ('py:class', 'string'), - ('py:class', 'floats'), + ("py:class", "file object"), + ("py:class", "function"), + ("py:obj", "function"), + ("py:class", "any type"), + ("py:class", "Unit('pix')"), + ("py:class", "Unit('deg')"), + ("py:class", "Unit('arcsec')"), + ("py:class", "Unit('%')"), + ("py:class", "Unit('s')"), + ("py:class", "Unit('Angstrom')"), + ("py:class", "Unit('arcsec / pix')"), + ("py:class", "Unit('W / m2')"), + ("py:class", "array-like"), + ("py:obj", "parfive"), + ("py:class", "string"), + ("py:class", "floats"), ] # -- Options for intersphinx extension --------------------------------------- diff --git a/docs/examples/setup.py b/docs/examples/setup.py index e2d3855..a064ccc 100644 --- a/docs/examples/setup.py +++ b/docs/examples/setup.py @@ -1,6 +1,6 @@ import pyvista -pyvista.global_theme.background = 'white' +pyvista.global_theme.background = "white" pyvista.global_theme.window_size = [600, 600] pyvista.global_theme.antialiasing = True -pyvista.global_theme.jupyter_backend = 'pythreejs' +pyvista.global_theme.jupyter_backend = "pythreejs" diff --git a/examples/3d_functionality.py b/examples/3d_functionality.py index 3f8ec5a..dab94cd 100644 --- a/examples/3d_functionality.py +++ b/examples/3d_functionality.py @@ -23,7 +23,7 @@ # Start by creating a plotter plotter = SunpyPlotter() # Plot a map -plotter.plot_map(low_res_aia_193, clip_interval=(1, 99.9)*u.percent) +plotter.plot_map(low_res_aia_193, clip_interval=(1, 99.9) * u.percent) # Add an arrow to show the solar rotation axis plotter.plot_solar_axis() @@ -34,18 +34,26 @@ pixel_pos = np.argwhere(low_res_aia_193.data == low_res_aia_193.data.max()) * u.pixel hpc_max = low_res_aia_193.pixel_to_world(pixel_pos[:, 1], pixel_pos[:, 0]) -plotter.plot_coordinates(hpc_max, color='blue') +plotter.plot_coordinates(hpc_max, color="blue") # Plot a quadrangle with width of 20 degrees and a height of 60 degrees -bottom_left = SkyCoord(30*u.deg, -10*u.deg, - frame=frames.HeliographicStonyhurst, - obstime=low_res_aia_193.date) -plotter.plot_quadrangle(bottom_left=bottom_left, width=20*u.deg, - height=60*u.deg, color='blue') +bottom_left = SkyCoord( + 30 * u.deg, + -10 * u.deg, + frame=frames.HeliographicStonyhurst, + obstime=low_res_aia_193.date, +) +plotter.plot_quadrangle( + bottom_left=bottom_left, width=20 * u.deg, height=60 * u.deg, color="blue" +) # Set the camera coordinate to view the plot correctly -camera_coord = SkyCoord(30*u.deg, -10*u.deg, 6*R_sun, - frame=frames.HeliographicStonyhurst, - obstime=low_res_aia_193.date) +camera_coord = SkyCoord( + 30 * u.deg, + -10 * u.deg, + 6 * R_sun, + frame=frames.HeliographicStonyhurst, + obstime=low_res_aia_193.date, +) plotter.set_camera_coordinate(camera_coord) plotter.show() diff --git a/examples/assume_spherical.py b/examples/assume_spherical.py index 9909033..e7664c7 100644 --- a/examples/assume_spherical.py +++ b/examples/assume_spherical.py @@ -24,8 +24,7 @@ plotter = SunpyPlotter() # Plot a map setting the `assume_spherical_screen` to False plotter.plot_map( - low_res_aia_193, clip_interval=[1, 99] * u.percent, - assume_spherical_screen=False + low_res_aia_193, clip_interval=[1, 99] * u.percent, assume_spherical_screen=False ) plotter.show() diff --git a/examples/field_lines.py b/examples/field_lines.py index a8d604e..51afc0c 100644 --- a/examples/field_lines.py +++ b/examples/field_lines.py @@ -48,7 +48,7 @@ # Create 5 points spaced between long={0, 180} degrees lon = np.linspace(0, 2 * np.pi, 16, endpoint=False) # Make a 2D grid from these 1D points -lat, lon = np.meshgrid(lat, lon, indexing='ij') +lat, lon = np.meshgrid(lat, lon, indexing="ij") # Create lon, lat and radial coordinate values by using a pfsspy # and trace them using tracer lat, lon = lat.ravel() * u.rad, lon.ravel() * u.rad @@ -56,8 +56,7 @@ tracer = tracing.FortranTracer() input_ = pfsspy.Input(gong_map, nrho, rss) output_ = pfsspy.pfss(input_) -seeds = SkyCoord(lon, lat, radius*R_sun, - frame=gong_map.coordinate_frame) +seeds = SkyCoord(lon, lat, radius * R_sun, frame=gong_map.coordinate_frame) field_lines = tracer.trace(seeds, output_) # We can also specify a color function while plotting the field lines. @@ -68,7 +67,7 @@ def my_fline_color_func(field_line): norm = colors.LogNorm(vmin=1, vmax=1000) - cmap = plt.get_cmap('viridis') + cmap = plt.get_cmap("viridis") return cmap(norm(np.abs(field_line.expansion_factor))) diff --git a/setup.py b/setup.py index 07a384c..be8569a 100755 --- a/setup.py +++ b/setup.py @@ -20,20 +20,21 @@ ################################################################################ # Programmatically generate some extras combos. ################################################################################ -extras = read_configuration("setup.cfg")['options']['extras_require'] +extras = read_configuration("setup.cfg")["options"]["extras_require"] # Dev is everything -extras['dev'] = list(chain(*extras.values())) +extras["dev"] = list(chain(*extras.values())) # All is everything but tests and docs exclude_keys = ("tests", "docs", "dev") ex_extras = dict(filter(lambda i: i[0] not in exclude_keys, extras.items())) # Concatenate all the values together for 'all' -extras['all'] = list(chain.from_iterable(ex_extras.values())) +extras["all"] = list(chain.from_iterable(ex_extras.values())) setup( extras_require=extras, - use_scm_version={'write_to': os.path.join('sunkit_pyvista', 'version.py'), - 'write_to_template': VERSION_TEMPLATE}, - + use_scm_version={ + "write_to": os.path.join("sunkit_pyvista", "version.py"), + "write_to_template": VERSION_TEMPLATE, + }, ) diff --git a/sunkit_pyvista/plotter.py b/sunkit_pyvista/plotter.py index 52b2f62..e97f1d7 100644 --- a/sunkit_pyvista/plotter.py +++ b/sunkit_pyvista/plotter.py @@ -16,7 +16,7 @@ from sunkit_pyvista.utils import get_limb_coordinates -__all__ = ['SunpyPlotter'] +__all__ = ["SunpyPlotter"] class SunpyPlotter: @@ -84,14 +84,14 @@ def _extract_color(self, mesh_kwargs): A tuple containing the (r, g, b) values from the strings passed to it. Deafults to (255, 255, 255) - white. """ - color_string = mesh_kwargs.pop('color', 'white') + color_string = mesh_kwargs.pop("color", "white") color = colors.to_rgb(color_string) return color def _add_mesh_to_dict(self, block_name, mesh): """ - Adds all of the meshes to a `dict` - that stores a reference to the meshes. + Adds all of the meshes to a `dict` that stores a reference to the + meshes. """ if block_name in self.all_meshes: self.all_meshes[block_name].append(mesh) @@ -114,17 +114,21 @@ def _coords_to_xyz(self, coords): of the coordinates. """ coords = coords.transform_to(self.coordinate_frame) - coords.representation_type = 'cartesian' - return np.stack((coords.x.to_value(R_sun), - coords.y.to_value(R_sun), - coords.z.to_value(R_sun)), - axis=-1) + coords.representation_type = "cartesian" + return np.stack( + ( + coords.x.to_value(R_sun), + coords.y.to_value(R_sun), + coords.z.to_value(R_sun), + ), + axis=-1, + ) def _get_clim(self, data, clip_interval): """ Get vmin, vmax of a data slice when clip_interval is specified. """ - percent_limits = clip_interval.to('%').value + percent_limits = clip_interval.to("%").value vmin, vmax = AsymmetricPercentileInterval(*percent_limits).get_limits(data) return [vmin, vmax] @@ -153,8 +157,7 @@ def set_view_angle(self, angle: u.deg): """ view_angle = angle.to_value(u.deg) if not (view_angle > 0 and view_angle <= 180): - raise ValueError("specified view angle must be " - "0 deg < angle <= 180 deg") + raise ValueError("specified view angle must be " "0 deg < angle <= 180 deg") zoom_value = self.camera.view_angle / view_angle self.plotter.camera.zoom(zoom_value) @@ -177,7 +180,8 @@ def _map_to_mesh(self, m, assume_spherical=True): if assume_spherical: context = Helioprojective.assume_spherical_screen( - m.observer_coordinate, only_off_disk=True) + m.observer_coordinate, only_off_disk=True + ) else: context = contextlib.nullcontext() with context: @@ -195,11 +199,15 @@ def _map_to_mesh(self, m, assume_spherical=True): upper_left = vert_indices[:-1, 1:] nfaces = (nx - 1) * (ny - 1) - faces = np.column_stack([np.ones(nfaces).astype(int) * 4, - lower_left.ravel(), - lower_right.ravel(), - upper_right.ravel(), - upper_left.ravel()]) + faces = np.column_stack( + [ + np.ones(nfaces).astype(int) * 4, + lower_left.ravel(), + lower_right.ravel(), + upper_right.ravel(), + upper_left.ravel(), + ] + ) # Remove faces that don't have a finite vertex # this can often happen with off-limb vertices) finite = np.sum(np.isfinite(verts[faces[:, 1], :]), axis=1) == 3 @@ -218,14 +226,13 @@ def _map_to_mesh(self, m, assume_spherical=True): # Remove non-finite vertices verts = verts[vert_mask, :] grid = pv.PolyData(verts, faces.ravel()) - grid['data'] = m.plot_settings['norm'](m.data.ravel()[finite]) + grid["data"] = m.plot_settings["norm"](m.data.ravel()[finite]) return grid @u.quantity_input - def plot_map(self, m, - clip_interval: u.percent = None, - assume_spherical_screen=True, - **kwargs): + def plot_map( + self, m, clip_interval: u.percent = None, assume_spherical_screen=True, **kwargs + ): """ Plot a sunpy map. @@ -246,18 +253,20 @@ def plot_map(self, m, map_mesh = self._map_to_mesh(m, assume_spherical=assume_spherical_screen) if clip_interval is not None: if len(clip_interval) == 2: - clim = self._get_clim(data=map_mesh['data'], - clip_interval=clip_interval) + clim = self._get_clim( + data=map_mesh["data"], clip_interval=clip_interval + ) else: - raise ValueError("Clip percentile interval must be " - "specified as two numbers.") + raise ValueError( + "Clip percentile interval must be " "specified as two numbers." + ) else: clim = [0, 1] cmap = self._get_cmap(kwargs, m) - kwargs.setdefault('show_scalar_bar', False) + kwargs.setdefault("show_scalar_bar", False) self.plotter.add_mesh(map_mesh, cmap=cmap, clim=clim, **kwargs) - map_mesh.add_field_data([cmap], 'cmap') - self._add_mesh_to_dict(block_name='maps', mesh=map_mesh) + map_mesh.add_field_data([cmap], "cmap") + self._add_mesh_to_dict(block_name="maps", mesh=map_mesh) @staticmethod def _get_cmap(kwargs, m): @@ -268,7 +277,7 @@ def _get_cmap(kwargs, m): ------- str """ - cmap = kwargs.pop('cmap', m.plot_settings['cmap']) + cmap = kwargs.pop("cmap", m.plot_settings["cmap"]) return cmap def plot_coordinates(self, coords, radius=0.05, **kwargs): @@ -301,11 +310,11 @@ def plot_coordinates(self, coords, radius=0.05, **kwargs): point_mesh = pv.Spline(points) color = self._extract_color(kwargs) - point_mesh.add_field_data(color, 'color') + point_mesh.add_field_data(color, "color") - kwargs['render_lines_as_tubes'] = kwargs.pop('render_lines_as_tubes', True) + kwargs["render_lines_as_tubes"] = kwargs.pop("render_lines_as_tubes", True) self.plotter.add_mesh(point_mesh, color=color, smooth_shading=True, **kwargs) - self._add_mesh_to_dict(block_name='coordinates', mesh=point_mesh) + self._add_mesh_to_dict(block_name="coordinates", mesh=point_mesh) def plot_solar_axis(self, length=2.5, arrow_kwargs={}, **kwargs): """ @@ -322,21 +331,28 @@ def plot_solar_axis(self, length=2.5, arrow_kwargs={}, **kwargs): **kwargs : Keyword arguments are handed to `pyvista.Plotter.add_mesh`. """ - defaults = {'shaft_radius': 0.01, - 'tip_length': 0.05, - 'tip_radius': 0.02} + defaults = {"shaft_radius": 0.01, "tip_length": 0.05, "tip_radius": 0.02} defaults.update(arrow_kwargs) - arrow_mesh = pv.Arrow(start=(0, 0, -length / 2), - direction=(0, 0, length), - scale='auto', - **defaults) + arrow_mesh = pv.Arrow( + start=(0, 0, -length / 2), + direction=(0, 0, length), + scale="auto", + **defaults, + ) color = self._extract_color(kwargs) - arrow_mesh.add_field_data(color, 'color') + arrow_mesh.add_field_data(color, "color") self.plotter.add_mesh(arrow_mesh, color=color, **kwargs) - self._add_mesh_to_dict(block_name='solar_axis', mesh=arrow_mesh) - - def plot_quadrangle(self, bottom_left, top_right=None, width: u.deg = None, - height: u.deg = None, radius=0.01, **kwargs): + self._add_mesh_to_dict(block_name="solar_axis", mesh=arrow_mesh) + + def plot_quadrangle( + self, + bottom_left, + top_right=None, + width: u.deg = None, + height: u.deg = None, + radius=0.01, + **kwargs, + ): """ Plot a quadrangle. @@ -362,23 +378,29 @@ def plot_quadrangle(self, bottom_left, top_right=None, width: u.deg = None, **kwargs : Keyword arguments are handed to `pyvista.Plotter.add_mesh`. """ bottom_left, top_right = get_rectangle_coordinates( - bottom_left, top_right=top_right, width=width, height=height) + bottom_left, top_right=top_right, width=width, height=height + ) width = Longitude(top_right.spherical.lon - bottom_left.spherical.lon) height = top_right.spherical.lat - bottom_left.spherical.lat - quadrangle_patch = Quadrangle((bottom_left.lon, bottom_left.lat), width, height, resolution=1000) + quadrangle_patch = Quadrangle( + (bottom_left.lon, bottom_left.lat), width, height, resolution=1000 + ) quadrangle_coordinates = quadrangle_patch.get_xy() - c = SkyCoord(quadrangle_coordinates[:, 0]*u.deg, - quadrangle_coordinates[:, 1]*u.deg, frame=bottom_left.frame) + c = SkyCoord( + quadrangle_coordinates[:, 0] * u.deg, + quadrangle_coordinates[:, 1] * u.deg, + frame=bottom_left.frame, + ) c.transform_to(self.coordinate_frame) quad_grid = self._coords_to_xyz(c) quad_block = pv.Spline(quad_grid) - radius = kwargs.get('radius', 0.01) + radius = kwargs.get("radius", 0.01) quad_block = quad_block.tube(radius=radius) color = self._extract_color(kwargs) - quad_block.add_field_data(color, 'color') + quad_block.add_field_data(color, "color") self.plotter.add_mesh(quad_block, color=color, **kwargs) - self._add_mesh_to_dict(block_name='quadrangles', mesh=quad_block) + self._add_mesh_to_dict(block_name="quadrangles", mesh=quad_block) def plot_field_lines(self, field_lines, color_func=None, **kwargs): """ @@ -402,8 +424,11 @@ def color_func(field_line: pfsspy.fieldline.FieldLine) -> color: Keyword arguments are handed to `pyvista.Plotter.add_mesh`. """ if not color_func: + def color_func(field_line): - color = {0: 'black', -1: 'tab:blue', 1: 'tab:red'}.get(field_line.polarity) + color = {0: "black", -1: "tab:blue", 1: "tab:red"}.get( + field_line.polarity + ) return colors.to_rgb(color) field_line_meshes = pv.MultiBlock([]) @@ -420,14 +445,14 @@ def color_func(field_line): opacity = color[3] color = color[:3] - spline.add_field_data([color], 'color') + spline.add_field_data([color], "color") - kwargs['render_lines_as_tubes'] = kwargs.pop('render_lines_as_tubes', True) - kwargs['line_width'] = kwargs.pop('line_width', 5) + kwargs["render_lines_as_tubes"] = kwargs.pop("render_lines_as_tubes", True) + kwargs["line_width"] = kwargs.pop("line_width", 5) self.plotter.add_mesh(spline, color=color, opacity=opacity, **kwargs) field_line_meshes.append(spline) - self._add_mesh_to_dict(block_name='field_lines', mesh=spline) + self._add_mesh_to_dict(block_name="field_lines", mesh=spline) def save(self, filepath, overwrite=False): """ @@ -447,14 +472,15 @@ def save(self, filepath, overwrite=False): >>> plotter = SunpyPlotter() >>> plotter.plot_solar_axis() >>> plotter.save('./filename.vtm') # doctest: +SKIP - """ file_path = Path(filepath) - directory_path = file_path.with_suffix('') + directory_path = file_path.with_suffix("") if not overwrite: if file_path.is_file(): - raise ValueError(f"VTM file '{directory_path.absolute()}' already exists") + raise ValueError( + f"VTM file '{directory_path.absolute()}' already exists" + ) if directory_path.exists(): raise ValueError(f"Directory '{directory_path.absolute()}' already exists") @@ -466,15 +492,15 @@ def save(self, filepath, overwrite=False): def _loop_through_meshes(self, mesh_block): """ - Recursively loop to add nested `~pyvista.core.MultiBlock` to the `pyvsita.Plotter` - along with the color of the mesh. + Recursively loop to add nested `~pyvista.core.MultiBlock` to the + `pyvsita.Plotter` along with the color of the mesh. """ for block in mesh_block: if isinstance(block, pv.MultiBlock): self._loop_through_meshes(block) else: - color = dict(block.field_data).get('color', None) - cmap = dict(block.field_data).get('cmap', [None])[0] + color = dict(block.field_data).get("color", None) + cmap = dict(block.field_data).get("cmap", [None])[0] self.plotter.add_mesh(block, color=color, cmap=cmap) def load(self, filepath): @@ -503,13 +529,14 @@ def plot_limb(self, m, radius=0.02, **kwargs): Defaults to ``0.02`` times the radius of the sun. **kwargs : Keyword arguments are handed to `pyvista.Plotter.add_mesh`. """ - limb_coordinates = get_limb_coordinates(m.observer_coordinate, m.rsun_meters, - resolution=1000) + limb_coordinates = get_limb_coordinates( + m.observer_coordinate, m.rsun_meters, resolution=1000 + ) limb_coordinates.transform_to(self.coordinate_frame) limb_grid = self._coords_to_xyz(limb_coordinates) limb_block = pv.Spline(limb_grid) color = self._extract_color(mesh_kwargs=kwargs) limb_block = limb_block.tube(radius=radius) - limb_block.add_field_data(color, 'color') + limb_block.add_field_data(color, "color") self.plotter.add_mesh(limb_block, color=color, **kwargs) - self._add_mesh_to_dict(block_name='limbs', mesh=limb_block) + self._add_mesh_to_dict(block_name="limbs", mesh=limb_block) diff --git a/sunkit_pyvista/sample.py b/sunkit_pyvista/sample.py index cf6e24a..7490e94 100644 --- a/sunkit_pyvista/sample.py +++ b/sunkit_pyvista/sample.py @@ -1,7 +1,8 @@ import astropy.units as u -import sunpy.data.sample import sunpy.map __all__ = ["low_res_aia_193"] -low_res_aia_193 = sunpy.map.Map(sunpy.data.sample.AIA_193_IMAGE).resample([512, 512] * u.pix) +low_res_aia_193 = sunpy.map.Map( + "https://github.com/sunpy/data/blob/main/sunpy/v1/AIA20110607_063307_0193_lowres.fits?raw=true" +).resample([512, 512] * u.pix) diff --git a/sunkit_pyvista/tests/conftest.py b/sunkit_pyvista/tests/conftest.py index 1825f87..1cd5fd7 100644 --- a/sunkit_pyvista/tests/conftest.py +++ b/sunkit_pyvista/tests/conftest.py @@ -10,11 +10,11 @@ try: pyvista.start_xvfb() except Exception as e: - print('Could not start xvfb server:') + print("Could not start xvfb server:") print(e) -IMAGE_CACHE_DIR = os.path.join(Path(__file__).parent.absolute(), 'image_cache') +IMAGE_CACHE_DIR = os.path.join(Path(__file__).parent.absolute(), "image_cache") if not os.path.isdir(IMAGE_CACHE_DIR): os.mkdir(IMAGE_CACHE_DIR) # Normal image warning/error thresholds (assumes using use_vtk) @@ -25,9 +25,9 @@ @pytest.fixture(scope="session", autouse=True) def get_cmd_opt(pytestconfig): global glb_reset_image_cache, glb_ignore_image_cache, add_image_cache - glb_reset_image_cache = pytestconfig.getoption('reset_image_cache') - glb_ignore_image_cache = pytestconfig.getoption('ignore_image_cache') - add_image_cache = pytestconfig.getoption('add_image_cache') + glb_reset_image_cache = pytestconfig.getoption("reset_image_cache") + glb_ignore_image_cache = pytestconfig.getoption("ignore_image_cache") + add_image_cache = pytestconfig.getoption("add_image_cache") def verify_cache_images(plotter): @@ -44,7 +44,7 @@ def verify_cache_images(plotter): import vtk # Image cache is only valid for VTK9.2 on Linux - if not vtk.__version__ >= '9.2.0' or platform.system() != 'Linux': + if not vtk.__version__ >= "9.2.0" or platform.system() != "Linux": pytest.skip("VTK9.2 on linux required for this test") # since each test must contain a unique name, we can simply @@ -52,9 +52,9 @@ def verify_cache_images(plotter): stack = inspect.stack() test_name = None for item in stack: - if item.function == 'check_gc': + if item.function == "check_gc": return - if item.function[:5] == 'test_': + if item.function[:5] == "test_": test_name = item.function break @@ -62,15 +62,19 @@ def verify_cache_images(plotter): allowed_warning = IMAGE_REGRESSION_WARNING if test_name is None: - raise RuntimeError('Unable to identify calling test function. This function ' - 'should only be used within a pytest environment.') + raise RuntimeError( + "Unable to identify calling test function. This function " + "should only be used within a pytest environment." + ) # cached image name - image_filename = os.path.join(IMAGE_CACHE_DIR, test_name[5:] + '.png') + image_filename = os.path.join(IMAGE_CACHE_DIR, test_name[5:] + ".png") # simply save the last screenshot if it doesn't exist or the cache # is being reset. - if add_image_cache and (glb_reset_image_cache or not os.path.isfile(image_filename)): + if add_image_cache and ( + glb_reset_image_cache or not os.path.isfile(image_filename) + ): print("Image doesn't exist, saving file in image_cache") return plotter.screenshot(image_filename) @@ -80,19 +84,23 @@ def verify_cache_images(plotter): # otherwise, compare with the existing cached image error = pyvista.compare_images(image_filename, plotter) if error > allowed_error: - raise RuntimeError('Exceeded image regression error of ' - f'{IMAGE_REGRESSION_ERROR} with an image error of ' - f'{error}') + raise RuntimeError( + "Exceeded image regression error of " + f"{IMAGE_REGRESSION_ERROR} with an image error of " + f"{error}" + ) if error > allowed_warning: - warnings.warn('Exceeded image regression warning of ' - f'{IMAGE_REGRESSION_WARNING} with an image error of ' - f'{error}') + warnings.warn( + "Exceeded image regression warning of " + f"{IMAGE_REGRESSION_WARNING} with an image error of " + f"{error}" + ) def pytest_addoption(parser): - parser.addoption("--reset_image_cache", action='store_true', default=False) - parser.addoption("--add_image_cache", action='store_true', default=True) - parser.addoption("--ignore_image_cache", action='store_true', default=False) + parser.addoption("--reset_image_cache", action="store_true", default=False) + parser.addoption("--add_image_cache", action="store_true", default=True) + parser.addoption("--ignore_image_cache", action="store_true", default=False) @pytest.fixture diff --git a/sunkit_pyvista/tests/test_plotting.py b/sunkit_pyvista/tests/test_plotting.py index 7e1fbbe..d0db9ff 100644 --- a/sunkit_pyvista/tests/test_plotting.py +++ b/sunkit_pyvista/tests/test_plotting.py @@ -24,7 +24,7 @@ @pytest.fixture def aia171_test_map(): - return smap.Map(test.get_test_filepath('aia_171_level1.fits')) + return smap.Map(test.get_test_filepath("aia_171_level1.fits")) @pytest.fixture @@ -32,29 +32,40 @@ def plotter(): return SunpyPlotter() -def test_plot_map_with_functionality(aia171_test_map, plotter, verify_cache_image, tmp_path): - plotter.plot_map(aia171_test_map, clip_interval=(0, 99)*u.percent) +def test_plot_map_with_functionality( + aia171_test_map, plotter, verify_cache_image, tmp_path +): + plotter.plot_map(aia171_test_map, clip_interval=(0, 99) * u.percent) plotter.plot_solar_axis() - bottom_left = SkyCoord(30*u.deg, -10*u.deg, - frame=frames.HeliographicStonyhurst, - obstime=aia171_test_map.date) - plotter.plot_quadrangle(bottom_left=bottom_left, width=20*u.deg, - height=60*u.deg, color='blue') + bottom_left = SkyCoord( + 30 * u.deg, + -10 * u.deg, + frame=frames.HeliographicStonyhurst, + obstime=aia171_test_map.date, + ) + plotter.plot_quadrangle( + bottom_left=bottom_left, width=20 * u.deg, height=60 * u.deg, color="blue" + ) plotter.plot_limb(aia171_test_map) - line = SkyCoord(lon=[90, 2200, 2200] * u.deg, - lat=[10, 10, 20] * u.deg, - distance=[1, 2, 3] * const.R_sun, - frame='heliocentricinertial') + line = SkyCoord( + lon=[90, 2200, 2200] * u.deg, + lat=[10, 10, 20] * u.deg, + distance=[1, 2, 3] * const.R_sun, + frame="heliocentricinertial", + ) plotter.plot_coordinates(line) - coordinate = SkyCoord(30*u.deg, -10*u.deg, - frame=frames.HeliographicStonyhurst, - obstime=aia171_test_map.date) - plotter.plot_coordinates(coordinate, color='blue') + coordinate = SkyCoord( + 30 * u.deg, + -10 * u.deg, + frame=frames.HeliographicStonyhurst, + obstime=aia171_test_map.date, + ) + plotter.plot_coordinates(coordinate, color="blue") - filepath = (tmp_path / "save_data.vtm") + filepath = tmp_path / "save_data.vtm" plotter.save(filepath=filepath) plotter = SunpyPlotter() @@ -70,19 +81,18 @@ def test_field_lines_figure(aia171_test_map, plotter, verify_cache_image): rss = 2.5 lat = np.linspace(-np.pi / 2, np.pi / 2, 8, endpoint=False) lon = np.linspace(0, 2 * np.pi, 8, endpoint=False) - lat, lon = np.meshgrid(lat, lon, indexing='ij') + lat, lon = np.meshgrid(lat, lon, indexing="ij") lat, lon = lat.ravel() * u.rad, lon.ravel() * u.rad radius = 1.2 tracer = tracing.PythonTracer() input_ = pfsspy.Input(gong_map, nrho, rss) output_ = pfsspy.pfss(input_) - seeds = SkyCoord(lon, lat, radius*const.R_sun, - frame=gong_map.coordinate_frame) + seeds = SkyCoord(lon, lat, radius * const.R_sun, frame=gong_map.coordinate_frame) field_lines = tracer.trace(seeds, output_) def color_function(field_line): norm = colors.LogNorm(vmin=1, vmax=1000) - cmap = plt.get_cmap('magma') + cmap = plt.get_cmap("magma") return cmap(norm(np.abs(field_line.expansion_factor))) plotter.plot_map(aia171_test_map) diff --git a/sunkit_pyvista/tests/test_pyvista.py b/sunkit_pyvista/tests/test_pyvista.py index 501e25d..318ea66 100644 --- a/sunkit_pyvista/tests/test_pyvista.py +++ b/sunkit_pyvista/tests/test_pyvista.py @@ -1,4 +1,3 @@ - import pathlib import matplotlib.pyplot as plt @@ -22,7 +21,7 @@ @pytest.fixture def aia171_test_map(): - return smap.Map(test.get_test_filepath('aia_171_level1.fits')) + return smap.Map(test.get_test_filepath("aia_171_level1.fits")) @pytest.fixture @@ -54,11 +53,12 @@ def test_camera_position(aia171_test_map, plotter): def test_set_view_angle(plotter): - plotter.set_view_angle(45*u.deg) + plotter.set_view_angle(45 * u.deg) assert plotter.camera.view_angle == 45 - with pytest.raises(ValueError, match=r"specified view angle must be " - r"0 deg < angle <= 180 deg"): - plotter.set_view_angle(190*u.deg) + with pytest.raises( + ValueError, match=r"specified view angle must be " r"0 deg < angle <= 180 deg" + ): + plotter.set_view_angle(190 * u.deg) def test_plot_map(aia171_test_map, plotter): @@ -74,64 +74,78 @@ def test_plot_solar_axis(plotter): def test_plot_quadrangle(aia171_test_map, plotter): - bottom_left = SkyCoord(30*u.deg, -10*u.deg, - frame=HeliographicStonyhurst, - obstime=aia171_test_map.date) - plotter.plot_quadrangle(bottom_left=bottom_left, width=20*u.deg, - height=60*u.deg, color='blue') + bottom_left = SkyCoord( + 30 * u.deg, + -10 * u.deg, + frame=HeliographicStonyhurst, + obstime=aia171_test_map.date, + ) + plotter.plot_quadrangle( + bottom_left=bottom_left, width=20 * u.deg, height=60 * u.deg, color="blue" + ) assert plotter.plotter.mesh.n_cells == 22 assert plotter.plotter.mesh.n_points == 80060 def test_plot_coordinates(aia171_test_map, plotter): # Tests the plot for a line - line = SkyCoord(lon=[180, 190, 200] * u.deg, - lat=[0, 10, 20] * u.deg, - distance=[1, 2, 3] * const.R_sun, - frame='heliocentricinertial') + line = SkyCoord( + lon=[180, 190, 200] * u.deg, + lat=[0, 10, 20] * u.deg, + distance=[1, 2, 3] * const.R_sun, + frame="heliocentricinertial", + ) plotter.plot_coordinates(line) assert plotter.plotter.mesh.n_cells == 1 assert plotter.plotter.mesh.n_points == 3 # Tests plotting of a small sphere - sphere = SkyCoord(lon=225*u.deg, - lat=45*u.deg, - distance=1*const.R_sun, - frame='heliocentricinertial') + sphere = SkyCoord( + lon=225 * u.deg, + lat=45 * u.deg, + distance=1 * const.R_sun, + frame="heliocentricinertial", + ) plotter.plot_coordinates(sphere) assert plotter.plotter.mesh.n_cells == 1680 assert plotter.plotter.mesh.n_points == 842 expected_center = [-0.5000000149011612, -0.5, 0.7071067690849304] assert np.allclose(plotter.plotter.mesh.center, expected_center) - pixel_pos = np.argwhere(aia171_test_map.data == aia171_test_map.data.max()) * u.pixel + pixel_pos = ( + np.argwhere(aia171_test_map.data == aia171_test_map.data.max()) * u.pixel + ) hpc_max = aia171_test_map.pixel_to_world(pixel_pos[:, 1], pixel_pos[:, 0]) - plotter.plot_coordinates(hpc_max, color='blue') + plotter.plot_coordinates(hpc_max, color="blue") assert plotter.plotter.mesh.n_cells == 1680 assert plotter.plotter.mesh.n_points == 842 def test_clip_interval(aia171_test_map, plotter): - plotter.plot_map(aia171_test_map, clip_interval=(1, 99)*u.percent) - clim = plotter._get_clim(data=plotter.plotter.mesh['data'], - clip_interval=(1, 99)*u.percent) + plotter.plot_map(aia171_test_map, clip_interval=(1, 99) * u.percent) + clim = plotter._get_clim( + data=plotter.plotter.mesh["data"], clip_interval=(1, 99) * u.percent + ) expected_clim = [0.006716044038535769, 0.8024368512284383] assert np.allclose(clim, expected_clim) expected_clim = [0, 1] - clim = plotter._get_clim(data=plotter.plotter.mesh['data'], - clip_interval=(0, 100)*u.percent) + clim = plotter._get_clim( + data=plotter.plotter.mesh["data"], clip_interval=(0, 100) * u.percent + ) assert np.allclose(clim, expected_clim) - with pytest.raises(ValueError, match=r"Clip percentile interval must be " - r"specified as two numbers."): - plotter.plot_map(aia171_test_map, clip_interval=(1, 50, 99)*u.percent) + with pytest.raises( + ValueError, + match=r"Clip percentile interval must be " r"specified as two numbers.", + ): + plotter.plot_map(aia171_test_map, clip_interval=(1, 50, 99) * u.percent) def test_multi_block(plotter): plotter.plot_solar_axis() - assert plotter.all_meshes['solar_axis'][0].n_cells == 43 - assert plotter.all_meshes['solar_axis'][0].n_points == 101 + assert plotter.all_meshes["solar_axis"][0].n_cells == 43 + assert plotter.all_meshes["solar_axis"][0].n_points == 101 def test_field_lines_and_color_func(aia171_test_map, plotter): @@ -141,22 +155,20 @@ def test_field_lines_and_color_func(aia171_test_map, plotter): rss = 2.5 lat = np.linspace(-np.pi / 2, np.pi / 2, 8, endpoint=False) lon = np.linspace(0, 2 * np.pi, 8, endpoint=False) - lat, lon = np.meshgrid(lat, lon, indexing='ij') + lat, lon = np.meshgrid(lat, lon, indexing="ij") lat, lon = lat.ravel() * u.rad, lon.ravel() * u.rad radius = 1.2 tracer = tracing.PythonTracer() input_ = pfsspy.Input(gong_map, nrho, rss) output_ = pfsspy.pfss(input_) - seeds = SkyCoord(lon, lat, radius*const.R_sun, - frame=gong_map.coordinate_frame) + seeds = SkyCoord(lon, lat, radius * const.R_sun, frame=gong_map.coordinate_frame) field_lines = tracer.trace(seeds, output_) plotter.plot_field_lines(field_lines) - assert isinstance(plotter.all_meshes['field_lines'][0], - pv.PolyData) + assert isinstance(plotter.all_meshes["field_lines"][0], pv.PolyData) def color_func(field_line): norm = colors.LogNorm(vmin=1, vmax=1000) - cmap = plt.get_cmap('viridis') + cmap = plt.get_cmap("viridis") return cmap(norm(np.abs(field_line.expansion_factor))) plotter = SunpyPlotter() @@ -166,7 +178,7 @@ def color_func(field_line): def test_save_and_load(aia171_test_map, plotter, tmp_path): plotter.plot_map(aia171_test_map) - filepath = (tmp_path / "save_data.vtm") + filepath = tmp_path / "save_data.vtm" plotter.save(filepath=filepath) plotter.plotter.clear() @@ -174,13 +186,13 @@ def test_save_and_load(aia171_test_map, plotter, tmp_path): assert plotter.plotter.mesh.n_cells == 16384 assert plotter.plotter.mesh.n_points == 16641 - assert dict(plotter.plotter.mesh.field_data)['cmap'][0] == 'sdoaia171' + assert dict(plotter.plotter.mesh.field_data)["cmap"][0] == "sdoaia171" - with pytest.raises(ValueError, match='VTM file'): + with pytest.raises(ValueError, match="VTM file"): plotter.save(filepath=filepath) - with pytest.raises(ValueError, match='already exists'): + with pytest.raises(ValueError, match="already exists"): pathlib.Path(tmp_path / "save_data_dir").mkdir(parents=True, exist_ok=True) - filepath = (tmp_path / "save_data_dir.vtm") + filepath = tmp_path / "save_data_dir.vtm" plotter.save(filepath=filepath) diff --git a/sunkit_pyvista/utils.py b/sunkit_pyvista/utils.py index 494a7ef..3d001f8 100644 --- a/sunkit_pyvista/utils.py +++ b/sunkit_pyvista/utils.py @@ -22,18 +22,22 @@ def get_limb_coordinates(observer, rsun=constants.radius, resolution=1000): Number of coordinates to return. The coordinates are equally spaced around the limb as seen from the observer. """ - observer = observer.transform_to( - HeliographicStonyhurst(obstime=observer.obstime)) + observer = observer.transform_to(HeliographicStonyhurst(obstime=observer.obstime)) dsun = observer.radius if dsun <= rsun: - raise ValueError('Observer distance must be greater than rsun') + raise ValueError("Observer distance must be greater than rsun") # Create the limb coordinate array using Heliocentric Radial limb_radial_distance = np.sqrt(dsun**2 - rsun**2) limb_hcr_rho = limb_radial_distance * rsun / dsun limb_hcr_z = dsun - np.sqrt(limb_radial_distance**2 - limb_hcr_rho**2) - limb_hcr_psi = np.linspace(0, 2*np.pi, resolution+1)[:-1] << u.rad - limb = SkyCoord(limb_hcr_rho, limb_hcr_psi, limb_hcr_z, - representation_type='cylindrical', - frame='heliocentric', - observer=observer, obstime=observer.obstime) + limb_hcr_psi = np.linspace(0, 2 * np.pi, resolution + 1)[:-1] << u.rad + limb = SkyCoord( + limb_hcr_rho, + limb_hcr_psi, + limb_hcr_z, + representation_type="cylindrical", + frame="heliocentric", + observer=observer, + obstime=observer.obstime, + ) return limb From 827ed748a7d252403b5e381744da7ec29c62a788 Mon Sep 17 00:00:00 2001 From: Nabil Freij Date: Thu, 4 Aug 2022 17:44:25 -0700 Subject: [PATCH 3/3] drop 3.10 again for now --- .github/workflows/ci.yml | 1 - .readthedocs.yaml | 2 +- setup.cfg | 3 +-- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b458712..2214014 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,7 +36,6 @@ jobs: coverage: codecov envs: | - macos: py38 - - linux: py310 docs: needs: [core] diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 00fa09a..f7017c9 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.10" + python: "3.9" apt_packages: - graphviz diff --git a/setup.cfg b/setup.cfg index b0ab448..3e1fc91 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,11 +23,10 @@ classifiers = Programming Language :: Python :: 3 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 - Programming Language :: Python :: 3.10 Topic :: Scientific/Engineering :: Visualization [options] -python_requires = >=3.8 +python_requires = >=3.8, <3.10 zip_safe = False packages = find: include_package_data = True