Giter Site home page Giter Site logo

bjlittle / geovista Goto Github PK

View Code? Open in Web Editor NEW
154.0 11.0 23.0 5.95 MB

Cartographic rendering and mesh analytics powered by PyVista

Home Page: https://geovista.readthedocs.io/

License: BSD 3-Clause "New" or "Revised" License

Python 100.00%
cartography mesh ugrid vtk earth-science rectilinear curvilinear unstructured grid python

geovista's Introduction

Cartographic rendering and mesh analytics powered by PyVista

โš™๏ธ CI ci-citation ci-locks ci-manifest ci-tests ci-wheels pre-commit
๐Ÿ’ฌ Community Contributor Covenant GH Discussions X (formerly Twitter) Follow YouTube Channel Subscribers All Contributors Mentioned in Awesome Open Geoscience
๐Ÿ“š Docs Documentation Status
๐Ÿ“ˆ Health codecov
โœจ Meta Ruff NEP29 license - bds-3-clause conda platform
๐Ÿ“ฆ Package DOI conda-forge pypi pypi - python version
๐Ÿงฐ Repo commits-since contributors release
๐Ÿ›ก๏ธ Status scitools

Rediscover Your Data

smc-timeseries.mov

GeoVista is built on the shoulders of giants, namely PyVista and VTK, thus allowing it to easily leverage the power of the GPU.

As a result, it offers a paradigm shift in rendering performance and interactive user experience, as demonstrated by this realtime, time-series animation of WAVEWATCH IIIยฎ third-generation wave model (WAVE-height, WATer depth and Current Hindcasting) data developed at NOAA/NCEP.

The animation shows a time-series of Sea Surface Wave Significant Height data located on the cell faces of a quasi-unstructured Spherical Multi-Cell (SMC) grid.

Bring your data alive with GeoVista! ๐Ÿš€

Tempted? Keen to know more? Well, let's begin ...

Motivation

The goal of GeoVista is simple; to complement PyVista with a convenient cartographic capability.

In this regard, from a design perspective we aim to keep GeoVista as pure to PyVista as possible i.e., minimise specialisation as far as practically possible in order to maximise native compatibility within the PyVista and VTK ecosystems.

We intend GeoVista to be a cartographic gateway into the powerful world of PyVista, and all that it offers.

GeoVista is intentionally agnostic to packages such as geopandas, iris, xarray et al, which specialise in preparing your spatial data for visualisation. Rather, we delegate that responsibility and choice of tool to you the user, as we want GeoVista to remain as flexible and open-ended as possible to the entire Scientific Python community.

Simply put, "GeoVista is to PyVista", as "Cartopy is to Matplotlib". Well, that's the aspiration.

Installation

GeoVista is available on both conda-forge and PyPI.

We recommend using conda to install GeoVista ๐Ÿ‘

Conda

GeoVista is available on conda-forge, and can be easily installed with conda:

conda install -c conda-forge geovista

For more information see our conda-forge feedstock and prefix.dev dashboard.

Pip

GeoVista is also available on PyPI:

pip install geovista

Checkout out our PyPI Download Stats, if you like that kinda thing.

Quick Start

GeoVista comes with various pre-canned resources to help get you started on your visualisation journey.

Resources

GeoVista makes use of various resources, such as rasters, VTK meshes, Natural Earth features, and sample model data.

If you want to download and cache all registered GeoVista resources to make them available offline, simply:

geovista download --all

Alternatively, just leave GeoVista to download resources on-the-fly, as and when she needs them.

To view the list of registered resources, simply:

geovista download --list

Want to know more?

geovista download --help

Plotting Examples

Let's explore a sample of various oceanographic and atmospheric model data using GeoVista.

WAVEWATCH III

First, let's render a WAVEWATCH III (WW3) unstructured triangular mesh, with 10m Natural Earth coastlines, a 1:50m Natural Earth Cross-Blended Hypsometric Tints base layer, and the gorgeous perceptually uniform cmocean balance diverging colormap.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import ww3_global_tri
import geovista.theme

# Load the sample data.
sample = ww3_global_tri()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons, sample.lats, connectivity=sample.connectivity, data=sample.data
)

# Plot the mesh.
p = gv.GeoPlotter()
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, show_edges=True, scalar_bar_args=sargs)
p.add_base_layer(texture=gv.natural_earth_hypsometric())
p.add_coastlines()
p.add_graticule()
p.view_xy(negative=True)
p.add_axes()
p.show()

Finite Volume Community Ocean Model

Now, let's visualise the bathymetry of the Plymouth Sound and Tamar River from an FVCOM unstructured mesh, as kindly provided by the Plymouth Marine Laboratory using the lush cmocean deep colormap.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import fvcom_tamar
import geovista.theme

# Load the sample data.
sample = fvcom_tamar()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons,
    sample.lats,
    connectivity=sample.connectivity,
    data=sample.face,
    name="face",
)

# Warp the mesh nodes by the bathymetry.
mesh.point_data["node"] = sample.node
mesh.compute_normals(cell_normals=False, point_normals=True, inplace=True)
mesh.warp_by_scalar(scalars="node", inplace=True, factor=2e-5)

# Plot the mesh.
p = gv.GeoPlotter()
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, cmap="deep", scalar_bar_args=sargs)
p.add_axes()
p.show()

CF UGRID

Local Area Model

Initial projection support is available within GeoVista for Cylindrical and Pseudo-Cylindrical projections. As GeoVista matures and stabilises, we'll aim to complement this capability with other classes of projections, such as Azimuthal and Conic.

In the meantime, let's showcase our basic projection support with some high-resolution unstructured Local Area Model (LAM) data reprojected to Mollweide using a PROJ string, with 10m Natural Earth coastlines and a 1:50m Natural Earth Cross-Blended Hypsometric Tints base layer.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import lam_pacific
import geovista.theme

# Load the sample data.
sample = lam_pacific()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons,
    sample.lats,
    connectivity=sample.connectivity,
    data=sample.data,
)

# Plot the mesh on a mollweide projection using a Proj string.
p = gv.GeoPlotter(crs="+proj=moll")
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, scalar_bar_args=sargs)
p.add_base_layer(texture=gv.natural_earth_hypsometric())
p.add_coastlines()
p.add_graticule()
p.add_axes()
p.view_xy()
p.show()

Using the same unstructured LAM data, reproject to Equidistant Cylindrical but this time using a Cartopy Plate Carrรฉe CRS, also with 10m Natural Earth coastlines and a 1:50m Natural Earth Cross-Blended Hypsometric Tints base layer.

๐Ÿ—’ click for code
import cartopy.crs as ccrs

import geovista as gv
from geovista.pantry.data import lam_pacific
import geovista.theme

# Load the sample data.
sample = lam_pacific()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons,
    sample.lats,
    connectivity=sample.connectivity,
    data=sample.data,
)

# Plot the mesh on a Plate Carrรฉe projection using a cartopy CRS.
p = gv.GeoPlotter(crs=ccrs.PlateCarree(central_longitude=180))
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, scalar_bar_args=sargs)
p.add_base_layer(texture=gv.natural_earth_hypsometric())
p.add_coastlines()
p.add_graticule()
p.add_axes()
p.view_xy()
p.show()

LFRic Cube-Sphere

Now render a Met Office LFRic C48 cube-sphere unstructured mesh of Sea Surface Temperature data on a Robinson projection using an ESRI SRID, with 10m Natural Earth coastlines and a cmocean thermal colormap.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import lfric_sst
import geovista.theme

# Load the sample data.
sample = lfric_sst()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons,
    sample.lats,
    connectivity=sample.connectivity,
    data=sample.data,
)

# Plot the mesh on a Robinson projection using an ESRI spatial reference identifier.
p = gv.GeoPlotter(crs="ESRI:54030")
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, cmap="thermal", show_edges=True, scalar_bar_args=sargs)
p.add_coastlines()
p.view_xy()
p.add_axes()
p.show()

NEMO ORCA2

So far we've demonstrated GeoVista's ability to cope with unstructured data. Now let's plot a curvilinear mesh using Nucleus for European Modelling of the Ocean (NEMO) ORCA2 Sea Water Potential Temperature data, with 10m Natural Earth coastlines and a 1:50m Natural Earth I base layer.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import nemo_orca2
import geovista.theme

# Load sample data.
sample = nemo_orca2()

# Create the mesh from the sample data.
mesh = gv.Transform.from_2d(sample.lons, sample.lats, data=sample.data)

# Remove cells from the mesh with NaN values.
mesh = mesh.threshold()

# Plot the mesh.
p = gv.GeoPlotter()
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, show_edges=True, scalar_bar_args=sargs)
p.add_base_layer(texture=gv.natural_earth_1())
p.add_coastlines()
p.view_xy()
p.add_axes()
p.show()

OISST AVHRR

Now let's render a NOAA/NCEI Optimum Interpolation SST (OISST) Advanced Very High Resolution Radiometer (AVHRR) rectilinear mesh, with 10m Natural Earth coastlines and a NASA Blue Marble base layer.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import oisst_avhrr_sst
import geovista.theme

# Load sample data.
sample = oisst_avhrr_sst()

# Create the mesh from the sample data.
mesh = gv.Transform.from_1d(sample.lons, sample.lats, data=sample.data)

# Remove cells from the mesh with NaN values.
mesh = mesh.threshold()

# Plot the mesh.
p = gv.GeoPlotter()
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, scalar_bar_args=sargs)
p.add_base_layer(texture=gv.blue_marble())
p.add_coastlines()
p.view_xz()
p.add_axes()
p.show()

DYNAMICO

Finally, to demonstrate support for non-traditional cell geometries i.e., not triangles or quadrilaterals, we plot the unstructured mesh from the DYNAMICO project. This model uses hexagonal and pentagonal cells, and is a new dynamical core for LMD-Z, the atmospheric General Circulation Model (GCM) part of the IPSL-CM Earth System Model. The render also contains 10m Natural Earth coastlines.

๐Ÿ—’ click for code
import geovista as gv
from geovista.pantry.data import dynamico
import geovista.theme

# Load sample data.
sample = dynamico()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(sample.lons, sample.lats, data=sample.data)

# Plot the mesh.
p = gv.GeoPlotter()
sargs = {"title": f"{sample.name} / {sample.units}"}
p.add_mesh(mesh, scalar_bar_args=sargs)
p.add_coastlines()
p.add_axes()
p.show()

Further Examples

"Please, sir, I want some more", Charles Dickens, Oliver Twist, 1838.

Certainly, our pleasure! From the command line, simply:

geovista examples --run all --verbose

Want to know more?

geovista examples --help

๐Ÿฌ Candy Store

We've opened the doors to the ๐Ÿฌ Candy Store.

A community space where you can openly share and promote how you're using GeoVista for your work, research or pleasure!

Showcase your most awesome GeoVista eye candy with undiluted pride and tell us more about your work.

We'd ๐Ÿ’š to hear from you!

Documentation

The documentation is built by Sphinx and hosted on Read the Docs.

Ecosystem

Whilst you're here, why not hop on over to the pyvista-xarray project and check it out!

It's aiming to provide xarray DataArray accessors for PyVista to visualize datasets in 3D for the xarray community, and will be building on top of GeoVista ๐ŸŽ‰

Support

Need help? ๐Ÿ˜ข

Why not check out our existing GitHub issues. See something similar? Well, give it a ๐Ÿ‘ to raise its priority and feel free to chip in on the conversation. Otherwise, don't hesitate to create a new GitHub issue instead.

However, if you'd rather have a natter, then head on over to our GitHub Discussions. That's definitely the place to wax lyrical all things GeoVista!

License

GeoVista is distributed under the terms of the BSD-3-Clause license.

Star History

Star History Chart

Graphics and Lead Scientist: Ed Hawkins, National Centre for Atmospheric Science, University of Reading.

Data: Berkeley Earth, NOAA, UK Met Office, MeteoSwiss, DWD, SMHI, UoR, Meteo France & ZAMG.

#ShowYourStripes is distributed under a Creative Commons Attribution 4.0 International License creative-commons-by

geovista's People

Contributors

allcontributors[bot] avatar andrewcoughtrie avatar banesullivan avatar bjlittle avatar dependabot[bot] avatar esadek-mo avatar geovista-ci[bot] avatar github-actions[bot] avatar hgwright avatar pp-mo avatar pre-commit-ci[bot] avatar richardscottoz avatar stephenworsley avatar tkknight avatar tkoyama010 avatar trexfeathers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

geovista's Issues

Geovista 0.2.0 with Conda install can't be launched as CLI app on Windows

๐Ÿ› Bug Report

Cannot run the Geovista CLI script on WIndows - not with the Conda prompt or from Conda Powershell

How to Reproduce

Create a Conda environment on WIndows with Geovista 0.2.0 then from any standard Windows shell attempt to run the Geovista script

Expected Behaviour

I expected the Geovista CLI to execute

Screenshots

Here is a screenshot of the standard Conda command line attempt:

image

Here is a screenshot of the Conda Powershell which attempts to find a Windows application to open the command line shell script:

image

Environment

  • OS & Version: Windows 11 Pro Version 10.0.22621 Build 22621
  • GeoVista Version: 0.2.0 (installed from conda-forge)

Additional Context

Click to expand this section...

On Windows most Conda packages that have a CLI script appear to have a corresponding executable file for running that script from command line. I'm afraid I don't know how those executables are created but that appears to be the standard way to launch a Python CLI script. See screenshot below:

image

I don't think this bash like shell script will work on Windows (it probably would if I ran from WSL but I don't want to resort to that).

Lock-file update PR's don't trigger PR checks

๐Ÿ› Bug Report

The lock-file update GitHub Action uses peter-evans/create-pull-request, which suffers from the known GHA restriction that prevents GHA's generating further GHA's - documented here. This means that the main PR checks do not get run on pull requests proposing dependency updates.

The PR checks are an important benefit of the dependency lock-file PR concept, so we should either:

  • Explore Peter Evans' various documented solutions.
  • Seek an alternative GHA for raising PR's that doesn't have this limitation.

Warnings when rendering on a server not running x server

๐Ÿ› Bug Report

(This can wait until after xmas! ๐ŸŽ…)

Data renders incorrectly on a jupyter notebook when run from a headless server.

Warnings are displayed that PyVista may segfault, and data appears to render incorrectly in threejs viewer.

This system does not appear to be running an xserver.
PyVista will likely segfault when rendering.

Try starting a virtual frame buffer with xvfb, or using
  ``pyvista.start_xvfb()``

  warnings.warn('\n'

I cannot use the provided suggested code as I do not have sudo rights to install additional packages

Input:

pyvista.start_xvfb()

Output:

---------------------------------------------------------------------------
OSError                                   Traceback (most recent call last)
/var/tmp/ipykernel_96063/1929267992.py in <module>
----> 1 pyvista.start_xvfb()

~/.conda/envs/geovista-dev/lib/python3.10/site-packages/pyvista/utilities/xvfb.py in start_xvfb(wait, window_size)
     45 
     46     if os.system('which Xvfb > /dev/null'):
---> 47         raise OSError(XVFB_INSTALL_NOTES)
     48 
     49     # use current default window size

OSError: Please install Xvfb with:

Debian
$ sudo apt install libgl1-mesa-glx xvfb

CentOS / RHL
$ sudo yum install libgl1-mesa-glx xvfb

How To Reproduce

Steps to reproduce the behaviour:

  1. Run ipython notebook server on a headless linux machine
  2. Run the attached notebook Geovista-Render.zip.

The screenshots below are what is shown in the three.js panel in the browser window in the notebook.

Screenshots

image

geovista-render.mp4

Remove VTK dependency to let PyVista manage it

Many users need to install custom builds/variants of VTK and the current constraints on VTK here are too restrictive. PyVista already points to VTK as a dependency, so pointing to PyVista here should be sufficient. This will give users more flexibility when needing to install VTK under different constraints.

No module named 'geovista.pantry'

I get a ModuleNotFoundError: No module named 'geovista.pantry'

I have installed anaconda 2020.11
and I get a geovista at 0.1.dev1 release
after a classic conda install -c conda-forge geovista

Did I miss something ?

Dependabot automerge system

๐Ÿ“ฐ Custom Issue

We are losing time on the Dependabot merge. These are PRs that are fine to be automated.

Allow an additional dimension for data in geovista.Transform.from_1d etc.

โœจ Feature Request

At present, the data array passed to geovista.Transform.from_1d is required to either be an array with (M, N) points, or MxN points. This proposal is to permit an extra dimension, so the data can also have shape (M, N, P) or (MxN, P).

Motivation

One motivation for this change is to allow meshes to be created that represent RGB image values rather than scalar data. Use cases include, for example, plotting of limited-area satellite imagery on the globe.

For example, an RGB image of shape data(nx, ny, 3) and co-ordinate arrays x(nx) and y(ny) could be transformed to a mesh with

mesh = gv.Transform.from_1d(x, y, data)

creating mesh["point_data"] with shape (npoint, 3)
It could then be added as an RGB image to a plot with

plotter.add_mesh(mesh, rgb=True)

Additional Context

Click to expand this section...
Please provide additional verbose information here e.g., references, screenshots, listings etc

Unable to run examples with geovista

๐Ÿ› Bug Report

I am completely unfamiliar with GeoVista and have never used it but I was interested in making a PR with the changes here:
#447 (comment)

However, after installing geovista to a clean, new environment, I am unable to run any of the examples from #447 (comment)

How to Reproduce

pip install geovista
geovista examples --run from_unstructured__tri_hammer

This will result in an import error:

Traceback (most recent call last):
  File "/venv/bin/geovista", line 5, in <module>
    from geovista.cli import main
  File "/venv/lib/python3.12/site-packages/geovista/__init__.py", line 31, in <module>
    from .core import slice_cells, slice_lines  # noqa: F401
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/venv/lib/python3.12/site-packages/geovista/core.py", line 40, in <module>
    from .search import find_cell_neighbours
  File "/venv/lib/python3.12/site-packages/geovista/search.py", line 16, in <module>
    from pykdtree.kdtree import KDTree as pyKDTree
ImportError: dlopen(/venv/lib/python3.12/site-packages/pykdtree/kdtree.cpython-312-darwin.so, 0x0002): symbol not found in flat namespace '___kmpc_for_static_fini'

Perhaps there is a problem with pykdtree for macOS? Or maybe an issue installing with pip instead of conda?

Expected Behaviour

Some sort of output is successfully generated, likely an image.

Environment

Please share the report generated by either of the following CLI commands:

--------------------------------------------------------------------------------
  Date: Sat Jan 06

                 OS : Darwin
             CPU(s) : 8
            Machine : arm64
       Architecture : 64bit
        Environment : Python

  Python 3.12.1 (v3.12.1:2305ca5144, Dec  7 2023, 17:23:38) [Clang 13.0.0
  (clang-1300.0.29.30)]

           geovista : 0.4.0
            cartopy : 0.22.0
              click : 8.1.7
click-default-group : 1.2.4
            cmocean : 3.0.3
            netCDF4 : 1.6.5
              numpy : 1.26.3
       platformdirs : 4.1.0
              pooch : 1.8.0
           pykdtree : 1.3.10
             pyproj : 3.6.1
            pyvista : 0.43.1
           colorcet : Module not found
             sphinx : Module not found
  sphinx-copybutton : Module not found
     jupyter-sphinx : Module not found
pydata-sphinx-theme : Module not found
            codecov : Module not found
         pre-commit : Module not found
             pytest : Module not found
         pytest-cov : Module not found
        pytest-mock : Module not found

Citation

๐Ÿ“ฐ Custom Issue

Hi @bjlittle! I am close to submitting a paper in which one of the figures is made using GeoVista - so naturally I would like give you credit. How would you prefer me to cite GeoVista?

Cheers!

slow geovista import time

๐Ÿ“ฐ Custom Issue

Importing geovista takes a noticably long time, roughly between 2-3 seconds ๐Ÿ˜ข

This is avoidable and should be addressed now before it bloats even further.

Import Cost Analysis

A sample cumulative import geovista time is 2,672,083 us.

Biggest 3rd party offenders include:

package us
pyvista 1,036,055
vtk 338,938
pyproj 232,517
numpy 232,559
cartopy.io.shapereader 136,778

Subsequently, the biggest geovista offenders include:

package us
geovista.bridge 2,279,034
geovista.geometry 141,871

The major costs of geovista.bridge:

  • geovista.common takes 742,282 usecs, due to:
    • vtk 338,938 us
    • pyvista.plotting 392,392 us
  • pyvista, pyproj and numpy

The major cost of geovista.geometry is cartopy.io.shapereader.

Click to expand for full details...
$ python -X importtime -c "import geovista"

import time: self [us] | cumulative | imported package
import time:       353 |        353 |   _io
import time:        76 |         76 |   marshal
import time:       528 |        528 |   posix
import time:       465 |       1421 | _frozen_importlib_external
import time:       161 |        161 |   time
import time:       141 |        302 | zipimport
import time:       156 |        156 |     _codecs
import time:       302 |        457 |   codecs
import time:      1751 |       1751 |   encodings.aliases
import time:      2290 |       4497 | encodings
import time:       864 |        864 | encodings.utf_8
import time:       174 |        174 | _signal
import time:        73 |         73 |     _abc
import time:       183 |        255 |   abc
import time:       211 |        466 | io
import time:        54 |         54 |       _stat
import time:        62 |        116 |     stat
import time:       796 |        796 |     _collections_abc
import time:        39 |         39 |       genericpath
import time:        86 |        125 |     posixpath
import time:       358 |       1394 |   os
import time:        81 |         81 |   _sitebuiltins
import time:      1045 |       1045 |   encodings.ascii
import time:      2492 |       2492 |   _distutils_hack
import time:      1518 |       1518 |   types
import time:      1406 |       1406 |       warnings
import time:      1755 |       3160 |     importlib
import time:      1501 |       1501 |     importlib._abc
import time:       284 |       4944 |   importlib.util
import time:        55 |         55 |   importlib.machinery
import time:       481 |        481 |   sitecustomize
import time:        85 |         85 |   usercustomize
import time:      5077 |      17166 | site
import time:      1649 |       1649 |   __future__
import time:       267 |        267 |           _operator
import time:      1952 |       2219 |         operator
import time:       230 |        230 |             itertools
import time:       886 |        886 |             keyword
import time:      1236 |       1236 |             reprlib
import time:       177 |        177 |             _collections
import time:      3162 |       5689 |           collections
import time:       118 |        118 |           _functools
import time:      1990 |       7796 |         functools
import time:      4499 |      14512 |       enum
import time:       155 |        155 |         _sre
import time:      1959 |       1959 |           re._constants
import time:      1780 |       3739 |         re._parser
import time:      1178 |       1178 |         re._casefix
import time:      2136 |       7206 |       re._compiler
import time:      1072 |       1072 |       copyreg
import time:      3135 |      25924 |     re
import time:      1399 |       1399 |       collections.abc
import time:       934 |        934 |           token
import time:        52 |         52 |           _tokenize
import time:      1746 |       2731 |         tokenize
import time:       845 |       3575 |       linecache
import time:      1824 |       1824 |       textwrap
import time:      1200 |       1200 |       contextlib
import time:      2678 |      10675 |     traceback
import time:       827 |        827 |       _weakrefset
import time:      1288 |       2114 |     weakref
import time:        50 |         50 |       _string
import time:      1379 |       1429 |     string
import time:      1594 |       1594 |     threading
import time:        51 |         51 |     atexit
import time:      5224 |      47008 |   logging
import time:        72 |         72 |       _typing
import time:      3567 |       3638 |     typing
import time:      1456 |       1456 |           numpy._utils._convertions
import time:      1061 |       2516 |         numpy._utils
import time:      3884 |       6400 |       numpy._globals
import time:      1293 |       1293 |       numpy.exceptions
import time:      1124 |       1124 |       numpy.version
import time:        68 |         68 |         numpy._distributor_init_local
import time:      1075 |       1142 |       numpy._distributor_init
import time:      1291 |       1291 |                 numpy._utils._inspect
import time:      1022 |       1022 |                     _datetime
import time:       903 |       1925 |                   datetime
import time:      1236 |       1236 |                   numpy.core._exceptions
import time:      1141 |       1141 |                   numpy.dtypes
import time:     12573 |      16873 |                 numpy.core._multiarray_umath
import time:      1282 |      19445 |               numpy.core.overrides
import time:      1936 |      21381 |             numpy.core.multiarray
import time:      1120 |       1120 |             numpy.core.umath
import time:      1431 |       1431 |               numbers
import time:       988 |        988 |               numpy.core._string_helpers
import time:       786 |        786 |                       fnmatch
import time:       111 |        111 |                         _winapi
import time:        75 |         75 |                         nt
import time:        69 |         69 |                         nt
import time:        66 |         66 |                         nt
import time:        65 |         65 |                         nt
import time:        73 |         73 |                         nt
import time:        66 |         66 |                         nt
import time:       113 |        634 |                       ntpath
import time:        74 |         74 |                       errno
import time:      1728 |       1728 |                         urllib
import time:       833 |        833 |                         math
import time:      1875 |       1875 |                         ipaddress
import time:      2417 |       6852 |                       urllib.parse
import time:      1592 |       9936 |                     pathlib
import time:       109 |        109 |                     pickle5
import time:       990 |        990 |                         _struct
import time:       741 |       1730 |                       struct
import time:       897 |        897 |                       _compat_pickle
import time:       841 |        841 |                       _pickle
import time:      2025 |       5492 |                     pickle
import time:      1416 |      16952 |                   numpy.compat.py3k
import time:      1488 |      18440 |                 numpy.compat
import time:      1030 |       1030 |                 numpy.core._dtype
import time:      1142 |      20611 |               numpy.core._type_aliases
import time:      1005 |      24033 |             numpy.core.numerictypes
import time:       683 |        683 |                         _contextvars
import time:       664 |       1346 |                       contextvars
import time:       958 |       2304 |                     numpy.core._ufunc_config
import time:      1055 |       3359 |                   numpy.core._methods
import time:      1496 |       4854 |                 numpy.core.fromnumeric
import time:       963 |       5816 |               numpy.core.shape_base
import time:      1831 |       1831 |               numpy.core.arrayprint
import time:       937 |        937 |               numpy.core._asarray
import time:      2547 |      11129 |             numpy.core.numeric
import time:      1617 |       1617 |             numpy.core.defchararray
import time:      1370 |       1370 |             numpy.core.records
import time:      1004 |       1004 |             numpy.core.memmap
import time:       805 |        805 |             numpy.core.function_base
import time:      1000 |       1000 |             numpy.core._machar
import time:      1219 |       1219 |             numpy.core.getlimits
import time:      1025 |       1025 |             numpy.core.einsumfunc
import time:      1051 |       1051 |               numpy.core._multiarray_tests
import time:      2057 |       3107 |             numpy.core._add_newdocs
import time:      1166 |       1166 |             numpy.core._add_newdocs_scalars
import time:       952 |        952 |             numpy.core._dtype_ctypes
import time:       154 |        154 |                 _ast
import time:      2045 |       2199 |               ast
import time:      1970 |       1970 |                 _ctypes
import time:      1494 |       1494 |                 ctypes._endian
import time:      2170 |       5633 |               ctypes
import time:      1563 |       9395 |             numpy.core._internal
import time:      1063 |       1063 |             numpy._pytesttester
import time:      1894 |      83271 |           numpy.core
import time:        49 |      83320 |         numpy.core._multiarray_umath
import time:      1262 |      84581 |       numpy.__config__
import time:      1547 |       1547 |         numpy.lib.mixins
import time:       925 |        925 |             numpy.lib.ufunclike
import time:      1191 |       2115 |           numpy.lib.type_check
import time:      1189 |       3304 |         numpy.lib.scimath
import time:       915 |        915 |                     numpy.lib.stride_tricks
import time:      1429 |       2343 |                   numpy.lib.twodim_base
import time:      2552 |       2552 |                   numpy.linalg._umath_linalg
import time:      1230 |       1230 |                     numpy._typing._nested_sequence
import time:      1021 |       1021 |                     numpy._typing._nbit
import time:      1676 |       1676 |                     numpy._typing._char_codes
import time:      1418 |       1418 |                     numpy._typing._scalars
import time:      1071 |       1071 |                     numpy._typing._shape
import time:      2303 |       2303 |                     numpy._typing._dtype_like
import time:      2473 |       2473 |                     numpy._typing._array_like
import time:      1632 |      12822 |                   numpy._typing
import time:      2634 |      20350 |                 numpy.linalg.linalg
import time:      1733 |      22082 |               numpy.linalg
import time:      1532 |      23614 |             numpy.matrixlib.defmatrix
import time:      1596 |      25210 |           numpy.matrixlib
import time:      1360 |       1360 |             numpy.lib.histograms
import time:      2147 |       3507 |           numpy.lib.function_base
import time:      1332 |      30047 |         numpy.lib.index_tricks
import time:      2182 |       2182 |         numpy.lib.nanfunctions
import time:      1311 |       1311 |         numpy.lib.shape_base
import time:      1447 |       1447 |         numpy.lib.polynomial
import time:       122 |        122 |             _wmi
import time:      1403 |       1525 |           platform
import time:      1641 |       3166 |         numpy.lib.utils
import time:      1251 |       1251 |         numpy.lib.arraysetops
import time:      1153 |       1153 |           numpy.lib.format
import time:      1159 |       1159 |           numpy.lib._datasource
import time:      1402 |       1402 |           numpy.lib._iotools
import time:      1581 |       5293 |         numpy.lib.npyio
import time:      1275 |       1275 |         numpy.lib.arrayterator
import time:      1018 |       1018 |         numpy.lib.arraypad
import time:       963 |        963 |         numpy.lib._version
import time:      1713 |      54511 |       numpy.lib
import time:       927 |        927 |           numpy.fft._pocketfft_internal
import time:      1649 |       2576 |         numpy.fft._pocketfft
import time:      1110 |       1110 |         numpy.fft.helper
import time:      1706 |       5391 |       numpy.fft
import time:      1364 |       1364 |           numpy.polynomial.polyutils
import time:      1413 |       1413 |           numpy.polynomial._polybase
import time:      1531 |       4306 |         numpy.polynomial.polynomial
import time:      1548 |       1548 |         numpy.polynomial.chebyshev
import time:      1460 |       1460 |         numpy.polynomial.legendre
import time:      1358 |       1358 |         numpy.polynomial.hermite
import time:      1330 |       1330 |         numpy.polynomial.hermite_e
import time:      1254 |       1254 |         numpy.polynomial.laguerre
import time:      1848 |      13102 |       numpy.polynomial
import time:       361 |        361 |                 backports_abc
import time:      3342 |       3702 |               numpy.random._common
import time:      2859 |       2859 |                   binascii
import time:      1863 |       4722 |                 base64
import time:      6766 |       6766 |                   _hashlib
import time:      1135 |       1135 |                     _blake2
import time:      1370 |       2505 |                   hashlib
import time:      1586 |      10856 |                 hmac
import time:      1202 |       1202 |                     _bisect
import time:       921 |       2123 |                   bisect
import time:      1008 |       1008 |                   _random
import time:       946 |        946 |                   _sha2
import time:      1388 |       5463 |                 random
import time:      1473 |      22512 |               secrets
import time:      3150 |      29363 |             numpy.random.bit_generator
import time:      1611 |       1611 |             numpy.random._bounded_integers
import time:      1168 |       1168 |             numpy.random._mt19937
import time:      2738 |      34878 |           numpy.random.mtrand
import time:      1307 |       1307 |           numpy.random._philox
import time:      1672 |       1672 |           numpy.random._pcg64
import time:      1352 |       1352 |           numpy.random._sfc64
import time:      1629 |       1629 |           numpy.random._generator
import time:      2204 |      43039 |         numpy.random._pickle
import time:      1989 |      45027 |       numpy.random
import time:      1521 |       1521 |       numpy.ctypeslib
import time:       958 |        958 |                 _opcode
import time:      1368 |       2325 |               opcode
import time:      1728 |       4053 |             dis
import time:      3225 |       7277 |           inspect
import time:      4568 |      11845 |         numpy.ma.core
import time:      1947 |       1947 |         numpy.ma.extras
import time:      1359 |      15150 |       numpy.ma
import time:      3322 |     232559 |     numpy
import time:      1463 |       1463 |                     zlib
import time:      1319 |       1319 |                       _compression
import time:      2952 |       2952 |                       _bz2
import time:      1348 |       5618 |                     bz2
import time:      2928 |       2928 |                       _lzma
import time:      2263 |       5190 |                     lzma
import time:      6251 |      18521 |                   shutil
import time:      3791 |      22312 |                 tempfile
import time:      2589 |       2589 |                 importlib.resources.abc
import time:      2374 |       2374 |                 importlib.resources._adapters
import time:      2909 |      30182 |               importlib.resources._common
import time:      1584 |       1584 |               importlib.resources._legacy
import time:      2459 |      34225 |             importlib.resources
import time:      1713 |      35937 |           certifi.core
import time:      1491 |      37428 |         certifi
import time:      1272 |       1272 |           array
import time:      1945 |       1945 |             pyproj._compat
import time:       854 |        854 |                     _json
import time:      1507 |       2360 |                   json.scanner
import time:      1951 |       4311 |                 json.decoder
import time:      1656 |       1656 |                 json.encoder
import time:      1934 |       7900 |               json
import time:      1667 |       9567 |             pyproj.utils
import time:      1663 |      13174 |           pyproj._datadir
import time:     39959 |      54404 |         pyproj._network
import time:      1473 |      93304 |       pyproj.network
import time:      1147 |       1147 |             _csv
import time:      1285 |       2431 |           csv
import time:      1783 |       1783 |           email
import time:      1638 |       1638 |               zipfile._path.glob
import time:      2624 |       4262 |             zipfile._path
import time:      2575 |       6836 |           zipfile
import time:      1229 |       1229 |               quopri
import time:      1267 |       1267 |                   _socket
import time:       834 |        834 |                     select
import time:      1467 |       2300 |                   selectors
import time:      2301 |       5868 |                 socket
import time:       103 |        103 |                       _locale
import time:      1625 |       1727 |                     locale
import time:      1772 |       3498 |                   calendar
import time:      1430 |       4927 |                 email._parseaddr
import time:      1320 |       1320 |                   email.base64mime
import time:      1998 |       1998 |                   email.quoprimime
import time:      2325 |       2325 |                   email.errors
import time:      1485 |       1485 |                   email.encoders
import time:      1550 |       8678 |                 email.charset
import time:      1874 |      21345 |               email.utils
import time:      3309 |       3309 |                 email.header
import time:      2067 |       5375 |               email._policybase
import time:      2386 |       2386 |               email._encoded_words
import time:      1696 |       1696 |               email.iterators
import time:      3010 |      35038 |             email.message
import time:      1520 |       1520 |               importlib.metadata._functools
import time:      1709 |       3228 |             importlib.metadata._text
import time:      1885 |      40150 |           importlib.metadata._adapters
import time:      2061 |       2061 |           importlib.metadata._meta
import time:      1607 |       1607 |           importlib.metadata._collections
import time:      1559 |       1559 |           importlib.metadata._itertools
import time:      1934 |       1934 |           importlib.abc
import time:      4081 |      62439 |         importlib.metadata
import time:      1436 |      63874 |       pyproj._show_versions
import time:       999 |        999 |               copy
import time:      1703 |       2701 |             dataclasses
import time:      2620 |       5321 |           pyproj.aoi
import time:      2204 |       2204 |           pyproj.crs.datum
import time:      4021 |       4021 |             pyproj.enums
import time:      2081 |       6102 |           pyproj.crs.enums
import time:      1319 |       1319 |           pyproj.exceptions
import time:      1805 |       1805 |             pyproj._geod
import time:      1162 |       1162 |             pyproj.list
import time:      1791 |       4756 |           pyproj.geod
import time:      2430 |      22130 |         pyproj._crs
import time:      1777 |       1777 |             pyproj.crs.coordinate_operation
import time:      1457 |       3233 |           pyproj.crs._cf1x8
import time:      1367 |       1367 |           pyproj.crs.coordinate_system
import time:      3383 |       7983 |         pyproj.crs.crs
import time:      1770 |      31882 |       pyproj.crs
import time:      1902 |       1902 |       pyproj.database
import time:      2063 |       2063 |         pyproj._transformer
import time:      1189 |       1189 |           pyproj.datadir
import time:      2773 |       2773 |                 http
import time:      1614 |       1614 |                   email.feedparser
import time:      1048 |       2662 |                 email.parser
import time:      1959 |       1959 |                   _ssl
import time:      3460 |       5419 |                 ssl
import time:      2631 |      13483 |               http.client
import time:      1107 |       1107 |                 urllib.response
import time:      1304 |       2410 |               urllib.error
import time:      2788 |      18680 |             urllib.request
import time:      1380 |       1380 |             pyproj._sync
import time:      1253 |      21312 |           pyproj.sync
import time:      4144 |      26645 |         pyproj.transformer
import time:      1535 |      30242 |       pyproj.proj
import time:     11314 |     232517 |     pyproj
import time:      1563 |       1563 |       pyvista._plot
import time:       736 |        736 |       pyvista._version
import time:      1496 |       1496 |             vtkmodules
import time:     14741 |      16237 |           vtkmodules.vtkCommonCore
import time:      2635 |       2635 |               vtkmodules.vtkCommonMath
import time:      2506 |       2506 |               vtkmodules.vtkCommonTransforms
import time:     15911 |      21051 |             vtkmodules.vtkCommonDataModel
import time:      3001 |       3001 |             vtkmodules.vtkCommonExecutionModel
import time:      1679 |       1679 |             vtkmodules.vtkCommonMisc
import time:     23278 |      49008 |           vtkmodules.vtkFiltersCore
import time:      1807 |       1807 |             vtkmodules.numpy_interface
import time:      1704 |       1704 |             vtkmodules.util
import time:      1114 |       1114 |               vtkmodules.util.vtkConstants
import time:      1498 |       2612 |             vtkmodules.util.numpy_support
import time:      4880 |      11001 |           vtkmodules.numpy_interface.dataset_adapter
import time:      2572 |       2572 |             vtkmodules.vtkFiltersPython
import time:      1383 |       3954 |           vtkmodules.util.vtkAlgorithm
import time:      3055 |       3055 |           vtkmodules.vtkCommonComputationalGeometry
import time:      6294 |       6294 |             vtkmodules.vtkFiltersGeneral
import time:     34463 |      40756 |           vtkmodules.vtkFiltersExtraction
import time:      6724 |       6724 |           vtkmodules.vtkFiltersFlowPaths
import time:      1935 |       1935 |           vtkmodules.vtkFiltersGeometry
import time:     10162 |      10162 |           vtkmodules.vtkFiltersHybrid
import time:      2536 |       2536 |           vtkmodules.vtkFiltersModeling
import time:      2604 |       2604 |             vtkmodules.vtkFiltersSources
import time:      1411 |       1411 |             vtkmodules.vtkFiltersTexture
import time:      1791 |       1791 |             vtkmodules.vtkParallelCore
import time:      5761 |      11567 |           vtkmodules.vtkFiltersParallel
import time:     11448 |      11448 |           vtkmodules.vtkFiltersParallelDIY2
import time:      4096 |       4096 |           vtkmodules.vtkFiltersPoints
import time:      1907 |       1907 |           vtkmodules.vtkFiltersStatistics
import time:      5012 |       5012 |           vtkmodules.vtkFiltersVerdict
import time:      1987 |       1987 |             vtkmodules.vtkIOCore
import time:      2418 |       2418 |             vtkmodules.vtkIOLegacy
import time:     10357 |      14761 |           vtkmodules.vtkIOGeometry
import time:      1587 |       1587 |               vtkmodules.vtkIOXMLParser
import time:      2755 |       4341 |             vtkmodules.vtkIOXML
import time:     15992 |      20333 |           vtkmodules.vtkIOInfovis
import time:      2574 |       2574 |           vtkmodules.vtkIOPLY
import time:      5205 |       5205 |           vtkmodules.vtkImagingCore
import time:      4776 |       4776 |           vtkmodules.vtkImagingGeneral
import time:      4647 |       4647 |           vtkmodules.vtkImagingHybrid
import time:      3572 |       3572 |           vtkmodules.vtkImagingMorphological
import time:      7333 |       7333 |               vtkmodules.vtkRenderingCore
import time:      2389 |       9721 |             vtkmodules.vtkRenderingContext2D
import time:      4527 |      14248 |           vtkmodules.vtkPythonContext2D
import time:      2898 |       2898 |           vtkmodules.vtkImagingFourier
import time:      1741 |     254140 |         pyvista.core._vtk_core
import time:      1594 |       1594 |               numpy._typing._add_docstring
import time:      1350 |       2944 |             numpy.typing
import time:      1505 |       4448 |           pyvista.core._typing_core
import time:      1632 |       1632 |           pyvista.core.celltype
import time:      1096 |       1096 |                 pyvista.core.errors
import time:      1755 |       1755 |                       pyvista.core.utilities.arrays
import time:       949 |        949 |                       pyvista.core.utilities.cells
import time:      1082 |       1082 |                           pyvista.core.utilities.transformations
import time:      1354 |       1354 |                               signal
import time:       822 |       2176 |                             pyvista.core.utilities.observers
import time:       897 |       3072 |                           pyvista.core.utilities.fileio
import time:       969 |       5122 |                         pyvista.core.utilities.helpers
import time:       848 |       5969 |                       pyvista.core.utilities.features
import time:      2736 |       2736 |                           vtkmodules.vtkRenderingFreeType
import time:      1124 |       1124 |                           pyvista.core.utilities.misc
import time:      1296 |       5155 |                         pyvista.core.utilities.geometric_sources
import time:      1400 |       6554 |                       pyvista.core.utilities.geometric_objects
import time:      1065 |       1065 |                       pyvista.core.utilities.parametric_objects
import time:       881 |        881 |                       pyvista.core.utilities.points
import time:      2242 |       2242 |                           xml
import time:      2173 |       4414 |                         xml.etree
import time:      1648 |       1648 |                           xml.etree.ElementPath
import time:      1481 |       1481 |                             pyexpat
import time:      1140 |       2620 |                           _elementtree
import time:      2376 |       6642 |                         xml.etree.ElementTree
import time:      3374 |      14429 |                       pyvista.core.utilities.reader
import time:      1705 |      33304 |                     pyvista.core.utilities
import time:        33 |      33336 |                   pyvista.core.utilities.arrays
import time:      1011 |      34346 |                 pyvista.core.pyvista_ndarray
import time:      1462 |      36903 |               pyvista.core.datasetattributes
import time:      1095 |      37997 |             pyvista.core.dataobject
import time:      2317 |       2317 |                       pprint
import time:      1594 |       1594 |                         fcntl
import time:       333 |        333 |                         msvcrt
import time:      1572 |       1572 |                         _posixsubprocess
import time:      2906 |       6403 |                       subprocess
import time:      1806 |       1806 |                         packaging
import time:      1589 |       1589 |                         packaging._structures
import time:      6292 |       9686 |                       packaging.version
import time:      1859 |       1859 |                         matplotlib._api.deprecation
import time:      2702 |       4560 |                       matplotlib._api
import time:      1108 |       1108 |                       matplotlib._version
import time:      1422 |       1422 |                         gzip
import time:      1344 |       1344 |                         shlex
import time:      1443 |       1443 |                         matplotlib._c_internal_utils
import time:      2920 |       7128 |                       matplotlib.cbook
import time:      1666 |       1666 |                       matplotlib._docstring
import time:      2042 |       2042 |                             PIL._version
import time:      2407 |       4449 |                           PIL
import time:      2001 |       2001 |                                   xml.parsers
import time:      1506 |       3507 |                                 xml.parsers.expat
import time:      1673 |       5179 |                               defusedxml.common
import time:      1971 |       7149 |                             defusedxml
import time:         8 |          8 |                               _elementtree
import time:      3161 |       3169 |                             defusedxml.ElementTree
import time:      9647 |       9647 |                             PIL.ExifTags
import time:      2098 |       2098 |                             PIL.ImageMode
import time:      2779 |       2779 |                             PIL.TiffTags
import time:      1264 |       1264 |                             PIL._binary
import time:      1110 |       1110 |                               PIL._typing
import time:      1417 |       2526 |                             PIL._util
import time:      8957 |       8957 |                             PIL._imaging
import time:      1678 |       1678 |                                 cffi.lock
import time:      2099 |       2099 |                                 cffi.error
import time:      6122 |       6122 |                                 cffi.model
import time:      3363 |      13260 |                               cffi.api
import time:      2636 |      15896 |                             cffi
import time:      6209 |      59688 |                           PIL.Image
import time:      1878 |       1878 |                             PIL.ImageChops
import time:      1521 |       1521 |                               PIL._deprecate
import time:      2508 |       4028 |                             PIL.ImageFile
import time:      2149 |       2149 |                               PIL.GimpGradientFile
import time:      1665 |       1665 |                               PIL.GimpPaletteFile
import time:      2204 |       2204 |                               PIL.ImageColor
import time:      1648 |       1648 |                               PIL.PaletteFile
import time:      1962 |       9626 |                             PIL.ImagePalette
import time:      1934 |       1934 |                             PIL.ImageSequence
import time:      5371 |      22835 |                           PIL.PngImagePlugin
import time:      3681 |       3681 |                           matplotlib._cm
import time:      2027 |       2027 |                                 matplotlib._path
import time:      2064 |       2064 |                                   matplotlib.bezier
import time:      2261 |       4325 |                                 matplotlib.path
import time:      6028 |      12379 |                               matplotlib.transforms
import time:      5009 |      17387 |                             matplotlib.ticker
import time:      3544 |      20930 |                           matplotlib.scale
import time:      2049 |       2049 |                           matplotlib._color_data
import time:      3639 |     117270 |                         matplotlib.colors
import time:      2014 |       2014 |                             pyparsing.util
import time:      3052 |       3052 |                               pyparsing.unicode
import time:      8158 |      11209 |                             pyparsing.exceptions
import time:      9669 |       9669 |                             pyparsing.actions
import time:      1510 |       1510 |                               pyparsing.results
import time:     12981 |      14491 |                             pyparsing.core
import time:      2614 |       2614 |                                   html.entities
import time:      1802 |       4416 |                                 html
import time:        36 |       4451 |                               html.entities
import time:      4107 |       8558 |                             pyparsing.helpers
import time:      1353 |       1353 |                             pyparsing.testing
import time:      4976 |       4976 |                             pyparsing.common
import time:      2496 |      54763 |                           pyparsing
import time:      1539 |      56301 |                         matplotlib._fontconfig_pattern
import time:      1563 |       1563 |                         matplotlib._enums
import time:      1905 |       1905 |                         cycler
import time:      2480 |     179517 |                       matplotlib.rcsetup
import time:      1450 |       1450 |                       matplotlib.ft2font
import time:      1388 |       1388 |                       dateutil._version
import time:      1818 |       1818 |                         kiwisolver.exceptions
import time:      2605 |       4423 |                       kiwisolver._cext
import time:     20513 |      20513 |                         matplotlib._cm_listed
import time:      6271 |      26783 |                       matplotlib.cm
import time:     23581 |     270005 |                     matplotlib
import time:      3984 |       3984 |                         matplotlib.artist
import time:      1273 |       1273 |                         matplotlib.hatch
import time:      2041 |       2041 |                           matplotlib.markers
import time:      6989 |       9030 |                         matplotlib.lines
import time:     23032 |      37317 |                       matplotlib.collections
import time:      1900 |       1900 |                               _uuid
import time:      1317 |       3217 |                             uuid
import time:      1133 |       1133 |                             matplotlib._pylab_helpers
import time:      2168 |       6517 |                           matplotlib.backend_tools
import time:      1718 |       1718 |                                 matplotlib._mathtext_data
import time:      1482 |       3199 |                               matplotlib._afm
import time:      6998 |      10196 |                             matplotlib.font_manager
import time:     42357 |      42357 |                             matplotlib.patches
import time:      1798 |       1798 |                               matplotlib._text_helpers
import time:      2487 |       2487 |                               matplotlib.dviread
import time:       992 |        992 |                                   unicodedata
import time:      4505 |       5496 |                                 matplotlib._mathtext
import time:      1084 |       6580 |                               matplotlib.mathtext
import time:      1566 |       1566 |                               matplotlib.texmanager
import time:      1422 |      13851 |                             matplotlib.textpath
import time:      7671 |      74074 |                           matplotlib.text
import time:      1252 |       1252 |                           matplotlib._tight_bbox
import time:      3493 |       3493 |                           matplotlib.widgets
import time:      1538 |       1538 |                           matplotlib.backend_managers
import time:      1168 |       1168 |                               matplotlib._layoutgrid
import time:      1419 |       2586 |                             matplotlib._constrained_layout
import time:      1333 |       1333 |                             matplotlib._tight_layout
import time:      1201 |       5120 |                           matplotlib.layout_engine
import time:      3287 |      95277 |                         matplotlib.backend_bases
import time:     10509 |     105785 |                       matplotlib.contour
import time:      5582 |       5582 |                       matplotlib.spines
import time:      2849 |     151532 |                     matplotlib.colorbar
import time:      1236 |       1236 |                       matplotlib._image
import time:      7872 |       9107 |                     matplotlib.image
import time:     34761 |      34761 |                       matplotlib.style.core
import time:      1795 |      36556 |                     matplotlib.style
import time:      1572 |       1572 |                       matplotlib._blocking_input
import time:     21528 |      21528 |                             matplotlib.offsetbox
import time:      1873 |       1873 |                                   _decimal
import time:      1094 |       2967 |                                 decimal
import time:      1570 |       4537 |                               matplotlib.units
import time:     12075 |      16611 |                             matplotlib.axis
import time:      1750 |       1750 |                             matplotlib.gridspec
import time:      4679 |       4679 |                             matplotlib.table
import time:      7873 |      52438 |                           matplotlib.axes._base
import time:      3012 |       3012 |                                   six
import time:      1024 |       1024 |                                     dateutil._common
import time:      1098 |       2121 |                                   dateutil.relativedelta
import time:        53 |         53 |                                       six.moves
import time:       978 |        978 |                                       dateutil.tz._common
import time:      1120 |       1120 |                                       dateutil.tz._factories
import time:        40 |         40 |                                         six.moves.winreg
import time:      1048 |       1088 |                                       dateutil.tz.win
import time:      1887 |       5124 |                                     dateutil.tz.tz
import time:      1341 |       6464 |                                   dateutil.tz
import time:      2423 |      14020 |                                 dateutil.parser._parser
import time:      1492 |       1492 |                                 dateutil.parser.isoparser
import time:      1740 |      17251 |                               dateutil.parser
import time:      1286 |      18536 |                             matplotlib.category
import time:      1124 |       1124 |                                   _heapq
import time:       977 |       2101 |                                 heapq
import time:      1774 |       3875 |                               dateutil.rrule
import time:      1910 |       5784 |                             matplotlib.dates
import time:      1063 |       1063 |                               matplotlib.container
import time:      1282 |       1282 |                               matplotlib.legend_handler
import time:      5667 |       8011 |                             matplotlib.legend
import time:      1260 |       1260 |                             matplotlib.mlab
import time:      5747 |       5747 |                             matplotlib.quiver
import time:      1045 |       1045 |                             matplotlib.stackplot
import time:      1254 |       1254 |                             matplotlib.streamplot
import time:      1491 |       1491 |                               matplotlib.tri._triangulation
import time:      2494 |       2494 |                               matplotlib.tri._tricontour
import time:      1301 |       1301 |                               matplotlib.tri._trifinder
import time:      1290 |       1290 |                                 matplotlib.tri._tritools
import time:      1671 |       2961 |                               matplotlib.tri._triinterpolate
import time:      1099 |       1099 |                               matplotlib.tri._tripcolor
import time:      1019 |       1019 |                               matplotlib.tri._triplot
import time:      1110 |       1110 |                               matplotlib.tri._trirefine
import time:      1876 |      13347 |                             matplotlib.tri
import time:      3742 |       3742 |                             matplotlib.axes._secondary_axes
import time:     16177 |      74899 |                           matplotlib.axes._axes
import time:      2149 |     129485 |                         matplotlib.axes
import time:     16665 |      16665 |                         matplotlib.projections.geo
import time:     18736 |      18736 |                         matplotlib.projections.polar
import time:       768 |        768 |                           mpl_toolkits
import time:      2421 |       2421 |                               mpl_toolkits.mplot3d.proj3d
import time:     24751 |      27171 |                             mpl_toolkits.mplot3d.art3d
import time:      8079 |       8079 |                             mpl_toolkits.mplot3d.axis3d
import time:     11441 |      46690 |                           mpl_toolkits.mplot3d.axes3d
import time:      3366 |      50824 |                         mpl_toolkits.mplot3d
import time:      2675 |     218384 |                       matplotlib.projections
import time:      8476 |     228431 |                     matplotlib.figure
import time:      3121 |     698749 |                   matplotlib.pyplot
import time:      2267 |     701016 |                 pyvista.core.filters.data_set
import time:      1428 |     702444 |               pyvista.core.filters.composite
import time:      1309 |       1309 |               pyvista.core.filters.image_data
import time:      1648 |       1648 |               pyvista.core.filters.poly_data
import time:      1231 |       1231 |               pyvista.core.filters.rectilinear_grid
import time:      2785 |       2785 |               pyvista.core.filters.structured_grid
import time:       900 |        900 |               pyvista.core.filters.unstructured_grid
import time:      1825 |     712139 |             pyvista.core.filters
import time:      1650 |     751785 |           pyvista.core.dataset
import time:      1184 |     759048 |         pyvista.core.cell
import time:      1589 |       1589 |         pyvista.core.composite
import time:      1106 |       1106 |         pyvista.core.grid
import time:       980 |        980 |         pyvista.core.objects
import time:      1938 |       1938 |         pyvista.core.pointset
import time:       889 |        889 |         pyvista.core.wrappers
import time:      1215 |    1020901 |       pyvista.core
import time:       965 |        965 |       pyvista.jupyter
import time:      1027 |       1027 |             sysconfig
import time:      1471 |       2497 |           scooby.knowledge
import time:      1694 |       1694 |           scooby.report
import time:      1406 |       1406 |           scooby.tracker
import time:      1187 |       1187 |           scooby.version
import time:      2126 |       8908 |         scooby
import time:      1320 |      10227 |       pyvista.report
import time:      1665 |    1036055 |     pyvista
import time:      1041 |       1041 |       pkgutil
import time:      5824 |       5824 |           vtkmodules.vtkChartsCore
import time:      1483 |       1483 |           vtkmodules.vtkCommonColor
import time:     23745 |      23745 |           vtkmodules.vtkInteractionWidgets
import time:      3473 |       3473 |           vtkmodules.vtkRenderingAnnotation
import time:      3619 |       3619 |           vtkmodules.vtkRenderingLabel
import time:      4141 |       4141 |           vtkmodules.vtkRenderingUI
import time:      4185 |       4185 |           vtkmodules.vtkRenderingVolume
import time:      1925 |       1925 |             vtkmodules.vtkViewsCore
import time:      3844 |       5769 |           vtkmodules.vtkViewsContext2D
import time:      1744 |       1744 |                 vtkmodules.vtkRenderingHyperTreeGrid
import time:      7007 |       8751 |               vtkmodules.vtkRenderingOpenGL2
import time:     20466 |      29216 |             vtkmodules.vtkRenderingContextOpenGL2
import time:      1517 |       1517 |               vtkmodules.vtkImagingMath
import time:      4627 |       6143 |             vtkmodules.vtkRenderingVolumeOpenGL2
import time:      1510 |      36868 |           pyvista.plotting._vtk_gl
import time:      2039 |      91143 |         pyvista.plotting._vtk
import time:      4749 |       4749 |             pyvista.plotting._typing
import time:     14393 |      19141 |           pyvista.plotting.colors
import time:      3338 |       3338 |           pyvista.plotting.opts
import time:      1909 |      24388 |         pyvista.plotting._property
import time:      2434 |       2434 |               pyvista.plotting.tools
import time:      2713 |       5147 |             pyvista.plotting.lookup_table
import time:      2653 |       2653 |                 pyvista.plotting.utilities.algorithms
import time:      1458 |       1458 |                 pyvista.plotting.utilities.cubemap
import time:      1421 |       1421 |                 pyvista.plotting.utilities.gl_checks
import time:      1629 |       1629 |                 pyvista.plotting.utilities.regression
import time:      1343 |       1343 |                 pyvista.plotting.utilities.sphinx_gallery
import time:      1519 |       1519 |                 pyvista.plotting.utilities.xvfb
import time:      1554 |      11573 |               pyvista.plotting.utilities
import time:        40 |      11612 |             pyvista.plotting.utilities.algorithms
import time:      3225 |      19984 |           pyvista.plotting.mapper
import time:      1559 |       1559 |           pyvista.plotting.prop3d
import time:      1987 |      23528 |         pyvista.plotting.actor
import time:      1946 |       1946 |         pyvista.plotting.actor_properties
import time:      2371 |       2371 |           pyvista.plotting.axes_actor
import time:      1383 |       3754 |         pyvista.plotting.axes
import time:      1805 |       1805 |               xml.dom.domreg
import time:      2217 |       4022 |             xml.dom
import time:      1013 |       1013 |             xml.dom.minicompat
import time:      1064 |       1064 |               xml.dom.NodeFilter
import time:      1315 |       2378 |             xml.dom.xmlbuilder
import time:      2580 |       9992 |           xml.dom.minidom
import time:       948 |        948 |           pyvista.plotting.helpers
import time:      1445 |      12383 |         pyvista.plotting.camera
import time:      1811 |       1811 |             matplotlib.backends
import time:      1247 |       1247 |             matplotlib.backends._backend_agg
import time:      1876 |       4933 |           matplotlib.backends.backend_agg
import time:      4168 |       9101 |         pyvista.plotting.charts
import time:      1472 |       1472 |         pyvista.plotting.composite_mapper
import time:      1193 |       1193 |         pyvista.plotting.cube_axes_actor
import time:      1207 |       1207 |         pyvista.plotting.errors
import time:      1473 |       1473 |         pyvista.plotting.lights
import time:      1708 |       1708 |         pyvista.plotting.picking
import time:      1086 |       1086 |           pyvista.plotting._plotting
import time:      1382 |       1382 |           pyvista.plotting.render_window_interactor
import time:      1117 |       1117 |             pyvista.plotting.render_passes
import time:      1922 |       3039 |           pyvista.plotting.renderer
import time:      1185 |       1185 |             pyvista.plotting.background_renderer
import time:      1286 |       2470 |           pyvista.plotting.renderers
import time:      1049 |       1049 |           pyvista.plotting.scalar_bars
import time:      3553 |       3553 |             pyvista.plotting.themes
import time:      2043 |       5595 |           pyvista.plotting.text
import time:      1504 |       1504 |           pyvista.plotting.texture
import time:      1212 |       1212 |           pyvista.plotting.volume
import time:      1303 |       1303 |           pyvista.plotting.volume_property
import time:      1341 |       1341 |             pyvista.plotting.affine_widget
import time:      1816 |       3157 |           pyvista.plotting.widgets
import time:      2807 |      24598 |         pyvista.plotting.plotter
import time:      2659 |       2659 |           colorcet.version
import time:    129077 |     131735 |         colorcet
import time:      1381 |       1381 |             cmocean.tools
import time:     52770 |      54151 |           cmocean.cm
import time:      2158 |       2158 |           cmocean.data
import time:      1344 |      57651 |         cmocean
import time:      5119 |     392392 |       pyvista.plotting
import time:     15911 |      15911 |         vtkmodules.vtkWebCore
import time:      3703 |       3703 |         vtkmodules.vtkIOImage
import time:      1864 |       1864 |         vtkmodules.vtkRenderingSceneGraph
import time:      1631 |       1631 |         vtkmodules.vtkRenderingVtkJS
import time:      2836 |       2836 |         vtkmodules.vtkIOExport
import time:      1970 |       1970 |         vtkmodules.vtkWebGLExporter
import time:      2032 |       2032 |         vtkmodules.vtkInteractionStyle
import time:      7620 |       7620 |         vtkmodules.vtkViewsInfovis
import time:      3375 |       3375 |         vtkmodules.vtkTestingRendering
import time:     16353 |      16353 |         vtkmodules.vtkRenderingQt
import time:      3801 |       3801 |         vtkmodules.vtkRenderingMatplotlib
import time:      2707 |       2707 |         vtkmodules.vtkRenderingLOD
import time:      3283 |       3283 |         vtkmodules.vtkRenderingLICOpenGL2
import time:      2602 |       2602 |         vtkmodules.vtkRenderingImage
import time:      7284 |       7284 |         vtkmodules.vtkIOXdmf2
import time:      2564 |       2564 |         vtkmodules.vtkIOVeraOut
import time:      2566 |       2566 |         vtkmodules.vtkIOTecplotTable
import time:      3058 |       3058 |         vtkmodules.vtkIOSegY
import time:     11073 |      11073 |         vtkmodules.vtkIOXdmf3
import time:      4711 |       4711 |         vtkmodules.vtkIOParallelXML
import time:      2841 |       2841 |         vtkmodules.vtkIOMovie
import time:      5393 |       5393 |         vtkmodules.vtkIOOggTheora
import time:     15499 |      15499 |         vtkmodules.vtkIONetCDF
import time:      3460 |       3460 |         vtkmodules.vtkIOMotionFX
import time:      4084 |       4084 |         vtkmodules.vtkIOParallel
import time:      3755 |       3755 |         vtkmodules.vtkIOMINC
import time:      2604 |       2604 |         vtkmodules.vtkIOLSDyna
import time:      3207 |       3207 |         vtkmodules.vtkIOImport
import time:      8157 |       8157 |         vtkmodules.vtkIOIOSS
import time:      2414 |       2414 |         vtkmodules.vtkIOVideo
import time:     49184 |      49184 |         vtkmodules.vtkIOFFMPEG
import time:      4913 |       4913 |         vtkmodules.vtkIOExportPDF
import time:      3469 |       3469 |         vtkmodules.vtkRenderingGL2PSOpenGL2
import time:      5608 |       5608 |         vtkmodules.vtkIOExportGL2PS
import time:      5979 |       5979 |         vtkmodules.vtkIOExodus
import time:      3740 |       3740 |         vtkmodules.vtkIOEnSight
import time:      2877 |       2877 |         vtkmodules.vtkIOCityGML
import time:      3129 |       3129 |         vtkmodules.vtkIOChemistry
import time:      5457 |       5457 |         vtkmodules.vtkIOCesium3DTiles
import time:      3867 |       3867 |         vtkmodules.vtkIOCONVERGECFD
import time:      4354 |       4354 |         vtkmodules.vtkIOHDF
import time:      4239 |       4239 |         vtkmodules.vtkIOCGNSReader
import time:      3145 |       3145 |         vtkmodules.vtkIOAsynchronous
import time:      5886 |       5886 |         vtkmodules.vtkIOAMR
import time:      5014 |       5014 |         vtkmodules.vtkInteractionImage
import time:      5100 |       5100 |         vtkmodules.vtkImagingStencil
import time:      4724 |       4724 |         vtkmodules.vtkImagingStatistics
import time:      5365 |       5365 |         vtkmodules.vtkIOSQL
import time:      2915 |       2915 |         vtkmodules.vtkImagingSources
import time:      5672 |       5672 |         vtkmodules.vtkInfovisCore
import time:      3607 |       3607 |         vtkmodules.vtkGeovisCore
import time:      3853 |       3853 |         vtkmodules.vtkInfovisLayout
import time:      1734 |       1734 |         vtkmodules.vtkImagingColor
import time:      3996 |       3996 |         vtkmodules.vtkFiltersTopology
import time:      2664 |       2664 |         vtkmodules.vtkFiltersSelection
import time:      2955 |       2955 |         vtkmodules.vtkFiltersSMP
import time:      3746 |       3746 |         vtkmodules.vtkFiltersProgrammable
import time:      2325 |       2325 |         vtkmodules.vtkFiltersImaging
import time:      3506 |       3506 |         vtkmodules.vtkFiltersParallelImaging
import time:      1512 |       1512 |         vtkmodules.vtkCommonSystem
import time:      3107 |       3107 |         vtkmodules.vtkFiltersGeneric
import time:      1552 |       1552 |         vtkmodules.vtkFiltersAMR
import time:      1601 |       1601 |         vtkmodules.vtkDomainsChemistry
import time:      2790 |       2790 |         vtkmodules.vtkDomainsChemistryOpenGL2
import time:      1858 |       1858 |         vtkmodules.vtkFiltersHyperTree
import time:      2688 |       2688 |         vtkmodules.vtkCommonPython
import time:      1521 |       1521 |         vtkmodules.util.misc
import time:      1822 |       1822 |         vtkmodules.util.vtkVariant
import time:      5143 |     338938 |       vtk
import time:      9913 |     742282 |     geovista.common
import time:      8179 |       8179 |     geovista.crs
import time:      6424 |       6424 |     geovista.transform
import time:     17384 |    2279034 |   geovista.bridge
import time:       602 |        602 |           xxhash
import time:      1888 |       2490 |         pooch.hashes
import time:      3133 |       3133 |             platformdirs.api
import time:      1413 |       1413 |             platformdirs.version
import time:      4139 |       4139 |               configparser
import time:      1751 |       5890 |             platformdirs.unix
import time:      2674 |      13109 |           platformdirs
import time:      1515 |      14624 |         pooch.utils
import time:      1844 |       1844 |           ftplib
import time:       137 |        137 |           tqdm
import time:        96 |         96 |           paramiko
import time:      1821 |       3896 |         pooch.downloaders
import time:      2191 |      23200 |       pooch.core
import time:        83 |         83 |           pwd
import time:      1277 |       1277 |           grp
import time:      2170 |       3529 |         tarfile
import time:      1335 |       4863 |       pooch.processors
import time:       980 |        980 |       pooch._version
import time:      1186 |      30227 |     pooch
import time:       219 |        219 |       geovista.siteconfig
import time:       133 |        133 |       geovistaconfig
import time:      4778 |       5128 |     geovista.config
import time:      1099 |       1099 |         importlib.resources._itertools
import time:      1415 |       2514 |       importlib.resources.readers
import time:       977 |       3490 |     importlib.readers
import time:      9539 |      48383 |   geovista.cache
import time:      9545 |       9545 |     geovista.filters
import time:      2264 |       2264 |         pykdtree
import time:      3804 |       6068 |       pykdtree.kdtree
import time:     13424 |      19491 |     geovista.search
import time:     21874 |      50910 |   geovista.core
import time:     24814 |      24814 |   geovista.geodesic
import time:      2178 |       2178 |           cartopy._version
import time:       183 |        183 |           cartopy.siteconfig
import time:       288 |        288 |           cartopy_userconfig
import time:      8455 |       8455 |                 shapely.lib
import time:      1550 |       1550 |                 shapely.errors
import time:      1377 |       1377 |                     shapely._geos
import time:      1826 |       3203 |                   shapely._geometry_helpers
import time:      1183 |       1183 |                   shapely._enum
import time:      1501 |       1501 |                   shapely.decorators
import time:      3085 |       8971 |                 shapely._geometry
import time:      1409 |       1409 |                       shapely.coordinates
import time:      1431 |       1431 |                       shapely.predicates
import time:      1327 |       4166 |                     shapely._ragged_array
import time:      1513 |       5678 |                   shapely.io
import time:      1423 |       7101 |                 shapely.creation
import time:      2003 |       2003 |                     shapely.algorithms
import time:      1242 |       1242 |                     shapely.affinity
import time:      2323 |       5567 |                   shapely.algorithms._oriented_envelope
import time:     42814 |      48381 |                 shapely.constructive
import time:      1272 |       1272 |                 shapely.measurement
import time:      1215 |       1215 |                 shapely.set_operations
import time:      1209 |       1209 |                 shapely.linear
import time:      1031 |       1031 |                         shapely.coords
import time:      1882 |       2913 |                       shapely.geometry.base
import time:      1178 |       1178 |                       shapely.geometry.collection
import time:      1291 |       1291 |                           shapely.geometry.point
import time:      1207 |       2498 |                         shapely.geometry.linestring
import time:      1299 |       1299 |                         shapely.geometry.multilinestring
import time:      1328 |       1328 |                         shapely.geometry.multipoint
import time:      1205 |       1205 |                             shapely.algorithms.cga
import time:      1534 |       2739 |                           shapely.geometry.polygon
import time:      1460 |       4198 |                         shapely.geometry.multipolygon
import time:      1165 |      10486 |                       shapely.geometry.geo
import time:      1832 |      16408 |                     shapely.geometry
import time:        26 |      16433 |                   shapely.geometry.base
import time:      1700 |      18133 |                 shapely.strtree
import time:      1322 |       1322 |                 shapely._version
import time:      2742 |     100346 |               shapely
import time:        78 |     100423 |             shapely.geometry
import time:      1319 |       1319 |             shapely.prepared
import time:      2106 |       2106 |             cartopy.trace
import time:     12417 |     116264 |           cartopy.crs
import time:      3516 |       3516 |               cartopy.io
import time:      2024 |       2024 |               shapefile
import time:       155 |        155 |               fiona
import time:      2627 |       8320 |             cartopy.io.shapereader
import time:      6293 |      14612 |           cartopy.feature
import time:      3141 |     136665 |         cartopy
import time:        39 |     136703 |       cartopy.io
import time:        76 |     136778 |     cartopy.io.shapereader
import time:      5094 |     141871 |   geovista.geometry
import time:      7500 |       7500 |     geovista.gridlines
import time:      4167 |       4167 |     geovista.raster
import time:       133 |        133 |             backports_abc
import time:      1630 |       1630 |                 gettext
import time:      1031 |       2661 |               getopt
import time:      1473 |       4133 |             netCDF4.utils
import time:       150 |        150 |                 backports_abc
import time:      1508 |       1508 |                 cftime._strptime
import time:      3799 |       5455 |               cftime._cftime
import time:      1894 |       7349 |             cftime
import time:      1102 |       1102 |             glob
import time:      5229 |      17943 |           netCDF4._netCDF4
import time:      1695 |      19638 |         netCDF4
import time:     11862 |      31500 |       geovista.pantry
import time:      7190 |      38689 |     geovista.samples
import time:     11537 |      61893 |   geovista.geoplotter
import time:      5204 |       5204 |   geovista.report
import time:      4212 |       4212 |   geovista._version
import time:      7110 |    2672083 | geovista

Environment

----------------------------------------------------------------------------------------
  Date: Wed Jan 17 23:15:55 2024 GMT

                  OS : Linux
              CPU(s) : 4
             Machine : x86_64
        Architecture : 64bit
         Environment : Python
          GPU Vendor : VMware, Inc.
        GPU Renderer : llvmpipe (LLVM 7.0, 256 bits)
         GPU Version : 3.3 (Core Profile) Mesa 18.3.4

  Python 3.12.1 | packaged by conda-forge | (main, Dec 23 2023, 08:03:24) [GCC 12.3.0]

             cartopy : 0.22.0
               click : 8.1.7
 click-default-group : 1.2.4
             cmocean : 3.0.3
            colorcet : 3.0.1
            geovista : 0.5.0.dev169
          matplotlib : 3.8.2
             netcdf4 : 1.6.5
               numpy : 1.26.3
        platformdirs : 4.1.0
               pooch : 1.8.0
            pykdtree : 1.3.10
              pyproj : 3.6.1
             pyvista : 0.43.1
              scooby : 0.9.2
                 vtk : 9.2.6
             IPython : 8.20.0
         fastparquet : 2023.10.1
jupyter_server_proxy : 4.1.0
        nest_asyncio : 1.5.8
              pandas : 2.1.4
               trame : 3.5.1
        trame_client : 2.14.2
        trame_server : 2.15.0
           trame_vtk : 2.6.3
----------------------------------------------------------------------------------------

Remove hard dependency on PyVistaQt

PyVistaQt is currently a hard requirement of this package. It should be opt-in as it is an incredibly heavy dependency stack and most users (well me at least) want to use this in Jupyter and avoid Qt

Odd behaviour with longitude extents at or near 180 degrees

๐Ÿ› Bug Report

I'm experimenting with geovista with a view to understanding the capabilities with splitting and recombining data. I started with very coarse slicing up of global UGrid data, and got unexpected results with longitude ranges of 180 degrees, or just below 180 degress.

How to Reproduce

This example is adapted from the iris docs: https://scitools-iris.readthedocs.io/en/latest/further_topics/ugrid/operations.html#region-extraction

from geovista import Transform
from geovista.geodesic import BBox
from iris import load_cube
from iris.experimental.ugrid import Mesh, PARSE_UGRID_ON_LOAD

from iris.tests import get_data_path
file_path = get_data_path(
    [
        "NetCDF",
        "unstructured_grid",
        "lfric_ngvat_2D_72t_face_half_levels_main_conv_rain.nc",
    ]
)

with PARSE_UGRID_ON_LOAD.context():
    global_cube = load_cube(file_path, "conv_rain")
print(global_cube)

lons, lats = global_cube.mesh.node_coords
face_node = global_cube.mesh.face_node_connectivity
indices = face_node.indices_by_location()
global_polydata = Transform.from_unstructured(
    lons.points, lats.points, indices, start_index=face_node.start_index
)

# Unexpected behaviour - returns 0 cells
region = BBox(lons=[0, 180, 180, 0], lats=[-25, -25, 45, 45])
region_polydata = region.enclosed(global_polydata, preference="center")
print(f"180 degree longitude: {region_polydata.n_cells}")

# Very unexpected behaviour - returns 39 cells
region = BBox(lons=[0, 179.9, 179.9, 0], lats=[-25, -25, 45, 45])
region_polydata = region.enclosed(global_polydata, preference="center")
print(f"179.9 degree longitude: {region_polydata.n_cells}")

Expected Behaviour

Either an Error if this isn't something sensible to be asking for, or:

# Expected behaviour - returns 402 cells
region = BBox(lons=[0, 179, 179, 0], lats=[-25, -25, 45, 45])
region_polydata = region.enclosed(global_polydata, preference="center")
print(f"179 degree longitude: {region_polydata.n_cells}")

Environment

  • OS & Version: RHEL7
  • GeoVista Version: 0.1.4

Investigate ICON segmentation fault

๐Ÿ› Bug Report

Investigate the segmentation fault generated with projecting ICON example data.

e.g., in geovista.examples.from_unstructured__icon configure the plotter as:

plotter = gv.GeoPlotter(crs="+proj=eqc")

Most other stock projections result in the same hard fault.

drop tox-run-command

๐Ÿ“ฐ Custom Issue

The tox-run-command used by the wheels-ci GHA appears to be unsupported and does not support tox 4.x

Drop usage of tox-run-command asap and release the temporary tox<4 pin introduced.

offset or drawn order for add_coastlines

I cannot see coastlines from the example code:

import geovista as gv
from geovista.pantry import lfric_sst
import geovista.theme

# Load the sample data.
sample = lfric_sst()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons,
    sample.lats,
    connectivity=sample.connectivity,
    data=sample.data,
)

# Plot the mesh on a Robinson projection using an ESRI spatial reference identifier.
plotter = gv.GeoPlotter(crs="ESRI:54030")
sargs = {"title": f"{sample.name} / {sample.units}"}
plotter.add_mesh(mesh, cmap="thermal", show_edges=True, scalar_bar_args=sargs)
plotter.add_coastlines(resolution="50m", color="white")
plotter.view_xy()
plotter.add_axes()
plotter.show()

Using cartopy projections sometimes results in garbled plots

๐Ÿ› Bug Report

I'm very grateful for geovista supporting cartopy projections, but the interface seems to contain a few bugs ๐Ÿ˜ƒ

One bug leads to the data not displayed correctly for some values of the central_longitude parameter in the Plate Carree projection. For example, the plot looks OK for central_longitude=0 or 90 or 180, but not for 45, 135, etc. (see screenshots below). This is likely related to the arcsin issue, because I sometimes see that error too.

I also noticed that some of the projections are not displayed correctly, such as Mercator.

How to Reproduce

Click to expand this section... Data source: LFRic C48 simulation.
import cartopy.crs as ccrs
import geovista as gv
import iris
from geovista.pantry import capitalise
from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD

fname = "lfric_diag.nc"
with PARSE_UGRID_ON_LOAD.context():
    my_cube = iris.util.squeeze(iris.load_cube(fname, "toa_upward_longwave_flux"))
face_node = my_cube.mesh.face_node_connectivity
lons, lats = my_cube.mesh.node_coords
indices = face_node.indices_by_location()
mesh0 = gv.Transform.from_unstructured(
    lons.points,
    lats.points,
    indices,
    data=my_cube.data,
    start_index=face_node.start_index,
)

file_prefix = __file__.lower().replace(".py", "")

# Point no. 1: central longitude causes the mesh to display incorrectly
for cen_lon in [0, 45, 90, 135, 180]:
    mesh = mesh0.copy()
    plotter = gv.GeoPlotter(
        off_screen=True, crs=ccrs.PlateCarree(central_longitude=cen_lon), border=True
    )
    sargs = dict(title=f"{capitalise(my_cube.name())} / {my_cube.units}")
    plotter.add_title(f"LFRic C48\nPlateCarree(central_longitude={cen_lon})")
    plotter.add_mesh(
        mesh, cmap="thermal", show_edges=True, edge_color="grey", scalar_bar_args=sargs
    )
    # plotter.add_base_layer(texture=gv.natural_earth_1())
    # plotter.add_coastlines(resolution="10m", color="white")
    plotter.view_xy()
    # plotter.add_axes()
    plotter.camera.zoom(1.5)
    plotter.show(screenshot=f"{file_prefix}__platecarree_cen_lon{cen_lon}.png")

Expected Behaviour

Robust and valid plots.

Screenshots

Point no. 1: central longitude causes the mesh to display incorrectly
geovista-issue125__platecarree_cen_lon0
geovista-issue125__platecarree_cen_lon45
geovista-issue125__platecarree_cen_lon90
geovista-issue125__platecarree_cen_lon135
geovista-issue125__platecarree_cen_lon180

Environment

  • OS & Version: Ubuntu 22.04.1 LTS 64-bit
  • GeoVista Version: 0.1a1.dev460

Hexadron grid

I like to display a mesh of hexaedron cells with geovista to have all projections available.

Here is the mesh I can create and display with pyvista.

import numpy as np
import xarray as xr
import pyvista as pv

ds = xr.open_dataset("https://thredds-su.ipsl.fr/thredds/dodsC/ipsl_thredds/brocksce/ICO/ICO.79.1jour.native.1_19790101_19790101_1D_inca_ges.nc")

blon = ds['bounds_lon'].to_numpy()
blat = ds['bounds_lat'].to_numpy()
nvertex = blon.shape[-1]

blon = blon.reshape(-1, nvertex)
blat = blat.reshape(-1, nvertex)

arr = ds['bounds_lon'].to_numpy()
blon = arr.reshape(-1, arr.shape[-1])
arr = ds['bounds_lat'].to_numpy()
blat = arr.reshape(-1, arr.shape[-1])

deg2rad = np.pi/180.
x = np.cos(blat*deg2rad)*np.cos(blon*deg2rad)
y = np.cos(blat*deg2rad)*np.sin(blon*deg2rad)
z = np.sin(blat*deg2rad)

points = np.stack((x,y,z), axis=2).reshape(x.size, 3)
faces = np.arange(x.shape[0] * nvertex).reshape(x.shape[0], nvertex)
faces = np.insert(faces, 0, nvertex, axis=1)

points = np.stack((x,y,z), axis=2).reshape(x.size, 3)
faces = np.arange(x.shape[0] * nvertex).reshape(x.shape[0], nvertex)
faces = np.insert(faces, 0, nvertex, axis=1)

mesh = pv.PolyData(points, faces)

pl = pv.Plotter()
pl.add_mesh(mesh, show_edges=True)
pl.show()

screenshot

Now if I use geovista with this mesh that is in my understanding the same object as what gv.Transform.from_unstructured returns I do not get the expected projected mesh.

plotter = gv.GeoPlotter(crs="ESRI:54030")
plotter.add_mesh(mesh, show_edges=True)
plotter.view_xy()
plotter.add_axes()
plotter.show()

What do I have missed ?

Projected GeoPlotters permanently modify PolyData instances

๐Ÿ› Bug Report

When repeatedly plotting a PolyData instance with different projections, certain sequences appear to change the PolyData's properties at certain points, affecting subsequent plotting attempts. I haven't been able to tell what these changes are, but the evidence is in the plots themselves.

This behaviour is not seen if I plot a new shallow (or deep) copy of the PolyData, hence the speculation that this bug is caused by PolyData modifications.

How To Reproduce

Expand for code
from geovista import Transform
from geovista.geoplotter import GeoPlotter
from geovista import theme
from iris import load_cube
from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
from iris.tests import get_data_path
import pyvista as pv

file_path = get_data_path(["NetCDF", "unstructured_grid", "lfric_surface_mean.nc"])

with PARSE_UGRID_ON_LOAD.context():
    my_cube = load_cube(file_path, "zh")

face_node = my_cube.mesh.face_node_connectivity
lons, lats = my_cube.mesh.node_coords
indices = face_node.indices_by_location()
my_polydata = Transform.from_unstructured(
    lons.points,
    lats.points,
    indices,
    data=my_cube.data[0],
    start_index=face_node.start_index,
    name=my_cube.name(),
)

pv.global_theme.font.color = (0.5,) * 3

globe_plotter = GeoPlotter()
globe_plotter_2 = GeoPlotter()
moll_plotter = GeoPlotter(crs="+proj=moll")
moll_plotter_90 = GeoPlotter(crs="+proj=moll +lon_0=90")

for ix, plotter in enumerate([globe_plotter, moll_plotter, moll_plotter_90, globe_plotter_2]):
    plotter.add_mesh(my_polydata, show_edges=True)
    print(my_polydata.cell_arrays)
    plotter.camera_position = "xy"
    plotter.show(screenshot=f"{ix}.png")

Expected behaviour

Environment

  • OS & Version - Linux RHEL7
  • GeoVista Version - 0.1a1.dev323+dirty

What I realised GeoVista could achieve when creating the tutorial

โœจ Feature Request

Motivation

This is the memo of what I realised GeoVista could achieve when creating the tutorial.

  1. Wind of the earth. Arrow vectors with glyphs are used to represent wind movement.
    https://scitools.org.uk/cartopy/docs/v0.15/matplotlib/advanced_plotting.html#vector-plotting
    https://unidata.github.io/MetPy/latest/index.html
  2. Quake magnitude of the earth. A glyph-based sphere is used to represent magnitude. The ground should be translucent to show under the ground.

Additional Context

Support for vector visualisation

โœจ Feature Request

Hi again ๐Ÿ˜„

Are there any functions/methods in geovista that make it easier to transform vector-representing data, such as wind components, and visualise them on a sphere (ideally on an unstructured grid too)?

Motivation

As I mentioned in another issue (#15), I would like to visualise output of LFRic on a sphere, including the 3 standard wind components.

A while ago I wrote a simple function to convert u, v, w-cubes from the UM output to a pyvista mesh, so I was wondering if geovista would provide the same functionality.

Thanks in advance.

Resolve example issues with pyvista 0.42.2

๐Ÿ› Bug Report

Only noticed as part of manual post-testing of geovista 0.4.0 in a new environment with the latest version of pyvista 0.42.2, that there are issues with some projection examples, namely:

from_2d__orca_moll

image

from_unstructured__fesom_fouc

image

from_unstructured__icon_eqc

image

from_unstructured__icosahedral_poly

image

from_unstructured__tri_hammer

image

How to Reproduce

geovista examples --run from_2d__orca_moll
geovista examples --run from_unstructured__fesom_fouc
geovista examples --run from_unstructured__icon_eqc
geovista examples --run from_unstructured__icosahedral_poly
geovista examples --run from_unstructured__tri_hammer

Environment

Please share the report generated by either of the following CLI commands:

scooby --report geovista

or

python -c "import geovista; print(geovista.Report())"
----------------------------------------------------------------------------------------
  Date: Tue Sep 19 00:36:48 2023 BST

                 OS : Linux
             CPU(s) : 4
            Machine : x86_64
       Architecture : 64bit
        Environment : Python
         GPU Vendor : VMware, Inc.
       GPU Renderer : llvmpipe (LLVM 7.0, 256 bits)
        GPU Version : 3.3 (Core Profile) Mesa 18.3.4

  Python 3.11.5 | packaged by conda-forge | (main, Aug 27 2023, 03:34:09) [GCC 12.3.0]

            cartopy : 0.22.0
              click : 8.1.7
click-default-group : 1.2.4
            cmocean : v3.0.3
           colorcet : 3.0.1
           geovista : 0.4.0
         matplotlib : 3.7.2
            netcdf4 : 1.6.4
              numpy : 1.26.0
       platformdirs : 3.10.0
              pooch : v1.7.0
           pykdtree : 1.3.7.post0
             pyproj : 3.6.0
            pyvista : 0.42.2
             scooby : 0.7.2
                vtk : 9.2.6
        fastparquet : 2023.8.0
             pandas : 2.1.0
----------------------------------------------------------------------------------------

Transfer repository ownership to SciTools

๐Ÿ“ฐ Custom Issue

It's early days for geovista, which has just been born ๐Ÿฅณ

The current plan is to bootstrap geovista here with an minimal stable core under ownership of https://github.com/bjlittle, before then transferring ownership of the repository to the https://github.com/SciTools organisation.

At the moment SciTools is slowly undergoing re-licensing from LGPL to BSD 3-Clause, and a refresh of its CLA. After this work is completed, and when geovista is "ready" it will be migrated to SciTools to live alongside its more mature and well-behaved sister cartopy.

More importantly, once geovista is under SciTools ownership, it can then be maintained by its awesome team of core developers ๐Ÿ˜„

API for face areas within bounded region(s)

โœจ Feature Request

Some API to assist in calculating how much area of each face lies within 1 or more regions. The regions must support latitude bounding, and ideally great-circle bounding too (allowing lon-lat 'quads', as well as lat bands).

The returned area 'weights' are intended to be used downstream by any package that calculates weighted statistics (e.g. NumPy, xarray, Iris, iris-esmf-regrid) - to generate a statistic (e.g. mean) for that region's data.

Motivation

Calculating statistics for great-circle-bounded regions using ESMF (or iris-esmf-regrid) is accurate, performant and intuitive. But ESMF must approximate a latitude line using a series of great circles, which is either innaccurate (few circles) or resource intensive (many circles). PyVista can represent latitudes completely fine since they are just X-Y planes, so is a valuable tool for calculating area weights (the 'prepare' step), even if iris-esmf-regrid is still best for the weighted statistic calculation itself (the 'perform' step).

Additional context

How much convenience the API should offer is debatable. Here is the spectrum:

  1. A function that takes in a PolyData + bounds information, spits out area array(s).
  2. Some easy means of users trimming and clipping to the desired shapes, with documented examples of how this can be applied to the area weight problem.
  3. No API at all - the code below demonstrates that this is already possible without too many lines, providing the user knows what they are doing. Many detailed examples should be included in the documentation.

Traditional SciTools development would likely have gone with option 1. But we have started to glimpse the benefits of more generic solutions, which can help a wider community of users and with less maintenance. This approach only works with increased user support, in the form of careful documentation, plenty of examples, and being responsive to questions - it's more work (on both sides) when working with beginners, but produces a more knowledgeable and independent user base over time.

Expand this for an example based on an Iris Cube
from dask import array as da
from geovista import Transform
from geovista.common import GV_CELL_IDS, to_xyz
from iris.cube import Cube
from iris.experimental.ugrid import Mesh
import numpy as np
from pyvista import PolyData
from scipy import sparse

# What VTK/PyVista calls the area array produced by compute_cell_sizes.
VTK_AREAS = "Area"


def unstructured_cube_latitude_weights(
    cube: Cube, lat_sequence: np.typing.ArrayLike,
) -> sparse.csr_array:
    """
    Given an unstructured :class:`~iris.cube.Cube`, calculate how much area of each face lies within 1 or more latitude bands.

    Parameters
    ----------
    cube
        The :class:`~iris.cube.Cube` to be collapsed. The
        :attr:`~iris.cube.Cube.mesh` attribute must be a
        :class:`~iris.experimental.ugrid.mesh.Mesh` (i.e. not `None`).
    lat_sequence
        A 1D array of latitude bounds. Must have length >= 2 - to construct at
        least 1 latitude band (using a lower and upper bound).

    Returns
    -------
        A sparse array of areas, shape: (n lat bands, n cube faces)

    """
    if not isinstance(cube.mesh, Mesh):
        message = (
            f"Input cube must have an associated Mesh as cube.mesh, got: {cube.mesh} ."
        )
        raise ValueError(message)
    if lat_sequence.ndim != 1 or len(lat_sequence) < 2:
        message = f"Expected 1D lat_sequence array of length >=2, got shape: {lat_sequence.shape} ."
        raise ValueError(message)

    def z_band_areas(z_lo: float, z_hi: float, polydata: PolyData) -> sparse.csr_array:
        """
        Calculate the areas of :class:`~pyvista.Polydata` cells that exist between Z bounds.

        Parameters
        ----------
        z_lo, z_hi
            The lower and upper Z bounds.
        polydata
            The :class:`~pyvista.Polydata` containing the cells to analyse.

        Returns
        -------
            A sparse array of areas, which maps to the original array of faces.

        """
        n_cells = polydata.n_cells

        # Threshold to produce any cells that overlap with the Z band.
        polydata = polydata.threshold(z_lo, "z_max")
        polydata = polydata.threshold(z_hi, "z_min", invert=True)
        # Clip cells that are only partially in the Z band.
        clip_args_lo = [(0, 0, -1), (0, 0, z_lo)]
        clip_args_hi = [(0, 0, 1), (0, 0, z_hi)]
        for clip_args in [clip_args_lo, clip_args_hi]:
            polydata = polydata.clip(*clip_args)

        # length=True for edge-based data?
        polydata = polydata.compute_cell_sizes(length=False, volume=False)

        # Duplicates ID's - where original cells have been triangulated - are
        #  summed implicitly by the sparse array - producing 1 area for each
        #  original cell.
        return sparse.csr_array(
            (polydata[VTK_AREAS], ([0] * polydata.n_cells, polydata[GV_CELL_IDS])),
            shape=(1, n_cells),
        )

    # Get a Polydata from cube.mesh.
    lons, lats = cube.mesh.node_coords
    face_node = cube.mesh.face_node_connectivity
    indices = face_node.indices_by_location(face_node.core_indices())
    mesh_polydata = Transform.from_unstructured(
        lons.core_points(),
        lats.core_points(),
        indices,
        start_index=face_node.start_index,
    )
    # An an array of ID's to the polydata cells.
    mesh_polydata.cell_data[GV_CELL_IDS] = da.arange(mesh_polydata.n_cells)
    # Add z mins and maxes to the polydata cells - for PyVista thresholding.
    #  How do do this with pure PyVista? Array operations on the cell
    #   points/bounds arrays are clunky, and iteratively using the
    #   equivalent methods for individual cell ID's is very slow.
    lat_coord = cube.coord("latitude")
    for metric in ("min", "max"):
        meth = getattr(np, metric)
        lat_metric = meth(lat_coord.core_bounds(), axis=1)
        mesh_polydata.cell_data[f"z_{metric}"] = to_xyz(0, lat_metric, stacked=False)[
            -1
        ]

    # Get the areas that are within the latitude bands.
    # First convert lat_bounds into 'PyVista language'.
    z_sequence = to_xyz(0, lat_sequence, stacked=False)[-1]
    z_bounds = np.stack([z_sequence[:-1], z_sequence[1:]], axis=1)
    # Use GeoVista to get a sparse matrix of the areas of all faces within
    #  each latitude band.
    areas_matrix = sparse.vstack(
        [z_band_areas(z_lower, z_upper, mesh_polydata) for z_lower, z_upper in z_bounds]
    )
    return areas_matrix

Core dumped when using plotter.show()

๐Ÿ“ฐ Custom Issue

Hello everyone,

I am able to load all the examples and produce the plots, but any time I tried to show them or save them my kernel died.
It happens running the script either on a jupyter notebook or with Python command.
Do you have any suggestions?

Thank you

`get_coastlines(geocentric=False)` latitude lines

Non-geocentric coastlines currently include several continuous latitude lines:

image

This functionality is not yet used in any other part of GeoVista so I suggest removing it from the get_coastlines() API until the latitude lines can be removed.

Projected LFRic cubesphere C12 produces invalid arcsin error

๐Ÿ› Bug Report

Plotting a C12 LFRic cubesphere on a planar projection produces the error:

...geovista/common.py:299: RuntimeWarning: invalid value encountered in arcsin
  lats = np.degrees(np.arcsin(xyz[:, 2] / radius))

This is accompanied by an invalid looking plot with Mollweide, although not with Plate Carree.

I have not seen this behaviour with C72 cubespheres. Might be worth some experiments at other resolutions.

How To Reproduce

Expand for code
import geovista
from geovista import Transform
from geovista.geoplotter import GeoPlotter
from iris import load_cube
from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
from iris.tests import get_data_path

print(geovista.__version__)

file_path = get_data_path(
    [
        "NetCDF",
        "unstructured_grid",
        "lfric_ngvat_2D_1t_face_half_levels_main_conv_rain.nc",
    ]
)

with PARSE_UGRID_ON_LOAD.context():
    my_cube = load_cube(file_path, "conv_rain")

face_node = my_cube.mesh.face_node_connectivity
lons, lats = my_cube.mesh.node_coords
indices = face_node.indices_by_location()
my_polydata = Transform.from_unstructured(
    lons.points, lats.points, indices, start_index=face_node.start_index,
)

for proj in ("moll", "eqc"):
    my_plotter = GeoPlotter(crs=f"+proj={proj}")
    my_plotter.add_mesh(my_polydata, show_edges=True)
    my_plotter.camera_position = "xy"
    my_plotter.show(screenshot=f"{proj}.png")

Expected behaviour

No error raised, and valid plots produced, given this will become a widely used format.

Screenshots

Expand for screenshots

moll
eqc

Environment

  • OS & Version - Linux RHEL7
  • GeoVista Version - 0.1a1.dev313

Python 3.11 support

โœจ Feature Request

Feel free to ignore this for now as this is a very minor issue, but it would be great to remove the Python version cap at 3.10. Or is there a specific reason you've capped it for now?

Motivation

Keeping up with the pace of Python ๐Ÿ

Additional Context

I actually tried geovista in a py-3.11 environment, and it seemed to work. I haven't done any extensive testing though.

Automated decimation for plotting?

โœจ Feature Request

An automatic feature that would intervene during plotting (so presumably part of GeoPlotter?) to reduce the resolution of a PolyData that would otherwise blow memory / cause excessive lag. I imagine the threshold for this would be configurable. There could perhaps be a layer of automation to account for the amount of compute resource actually available.

More sophisticated implementation might involve a visualisation API that encourages and helps users to either limit their region size or limit their resolution. At the very least a User Guide article on the subject.

Motivation

GeoVista's intended use cases will often involve visualising a data set that has global scale, but high enough resolution to closely examine local phenomena. From experience this is often beyond resource limitations when visualising. If the user is viewing global data, then they don't need such high resolution. If the user is viewing smaller regions, then they don't need to view the whole globe.

I see this as a GeoVista feature, rather than PyVista, since it is a particularly common problem with globe-based data sets, and some of the potential solutions could also take advantage of this (e.g. measuring resolution and region size in km).

Additional Context

Could use PyVista's own decimation, or something more sophisticated such as pyvista/pyvista-support#17.

Unpin tox<4

๐Ÿ“ฐ Custom Issue

Unfortunately we've had to pin tox<4 in the GHAs due to our use of the tox-conda plugin not being fully compatible with tox 4.x.

However, there is movement on this, see tox-dev/tox-conda#156

Require to unpin tox in the .github/workflows:

  • ci-locks.yml
  • ci-tests.yml
  • ci-wheels.yml

geovista.pantry.meshes are broken

๐Ÿ› Bug Report

> python -c "from geovista.pantry.meshes import dynamico; print(dynamico())"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/net/home/h05/itwl/projects/git/geovista/src/geovista/pantry/meshes.py", line 171, in dynamico
    sample = geovista.pantry.data.dynamico()
             ^^^^^^^^^^^^^^^^^^^^
AttributeError: module 'geovista.pantry' has no attribute 'data'

Introduced by #645.

Expected Behaviour

> python -c "from geovista.pantry.meshes import dynamico; print(dynamico())"
PolyData (0x7ff598f29720)
  N Cells:    16002
  N Points:   96012
  N Strips:   0
  X Bounds:   -1.000e+00, 1.000e+00
  Y Bounds:   -9.998e-01, 9.998e-01
  Z Bounds:   -9.999e-01, 9.999e-01
  N Arrays:   4

Environment

----------------------------------------------------------------------------------------
  Date: Fri Jan 26 01:29:00 2024 GMT

                  OS : Linux
              CPU(s) : 4
             Machine : x86_64
        Architecture : 64bit
         Environment : Python
          GPU Vendor : VMware, Inc.
        GPU Renderer : llvmpipe (LLVM 7.0, 256 bits)
         GPU Version : 3.3 (Core Profile) Mesa 18.3.4

  Python 3.12.1 | packaged by conda-forge | (main, Dec 23 2023, 08:03:24) [GCC 12.3.0]

             cartopy : 0.22.0
               click : 8.1.7
 click-default-group : 1.2.4
             cmocean : 3.0.3
            colorcet : 3.0.1
            geovista : 0.5.0.dev169
          matplotlib : 3.8.2
             netcdf4 : 1.6.5
               numpy : 1.26.3
        platformdirs : 4.1.0
               pooch : 1.8.0
            pykdtree : 1.3.10
              pyproj : 3.6.1
             pyvista : 0.43.1
              scooby : 0.9.2
                 vtk : 9.2.6
             IPython : 8.20.0
         fastparquet : 2023.10.1
jupyter_server_proxy : 4.1.0
        nest_asyncio : 1.5.8
              pandas : 2.1.4
               trame : 3.5.1
        trame_client : 2.14.2
        trame_server : 2.15.0
           trame_vtk : 2.6.3
----------------------------------------------------------------------------------------

Can't install geovista in dev mode due to scm-versioning

๐Ÿ› Bug Report

Pip install from current head:

$ pip install -e .
[...]
      return _bump_dev(version) or _bump_regex(version)
    File "/var/tmp/pip-build-env-65a6ky4h/overlay/lib/python3.10/site-packages/setuptools_scm/version.py", line 210, in _bump_dev
      raise ValueError(
  ValueError: choosing custom numbers for the `.devX` distance is not supported.
   The 0.1.dev1 can't be bumped
  Please drop the tag or create a new supported one

This seems to be due to the v0.1.dev1 tag and this line:
https://github.com/pypa/setuptools_scm/blob/4da6a5ac0efa68a2c92270112551c86b7ace12f5/src/setuptools_scm/version.py#L209-L215

How To Avoid

Locally, run:

$ tag -d v0.1.dev1
$ pip install -e .

PyPI release is empty

๐Ÿ› Bug Report

The PyPI release contains only __init__.py and _version.py. Additionally, the changed versioning scheme from .dev to a0 seems not to work as intended since .dev is considered newer than a0. Perhaps a 0.2 release is possible?

JOSS Paper Submission

๐Ÿ“š Documentation

At SciPy2023, we found that many researchers needed GeoVista. We propose to submit this project to JOSS so that researchers will have no trouble using GeoVista as a reference in the future.

The Journal of Open Source Software is a developer friendly, open access journal for research software packages.

Feel free to ๐Ÿ‘ this issue if you want to see this happen (@bjlittle)

  • Update the CITATION.cff with the JOSS citation when it lands

Dynamically load interactive examples in documentation

๐Ÿ› Bug Report

Some of the documentation examples in the gallery are taking a bit of time to load for me and might make the examples unresponsive for people with low bandwidth.

How to Reproduce

Load an example page like https://geovista.readthedocs.io/en/latest/generated/gallery/spatial_index/uber_h3.html and notice the ~45MB scene being immediately downloaded.

Expected Behaviour

The scene could load dynamically upon request. PyVista's image scraper implements this for you! I thought it was the default, but maybe it was turned off here or a dependency is missing? Or perhaps this is new to 0.43.1 and the version of PyVista just needs to be bumped to get these tabs?

@bjlittle, was the choice to make all examples dynamic by default intentional?

What I'm thinking these scenes should look like:

Screen.Recording.2023-12-26.at.5.24.43.PM.mov

Sphinx docs and example gallery?

๐Ÿ“š Documentation

Would you be interested in placing all of the examples into a sphinx gallery much like PyVistaโ€™s gallery? If so, I have some time for random side stuff right now and might be able to set this up for you.

Iโ€™m stoked to see this package and want to help you show off what it can do with PyVista!

Support for unstructured grid with a vertical dimension

โœจ Feature Request

Firstly, thanks very much for creating this library, I'm excited to use it in my research!

Secondly, would it be possible to generalise geovista.Transform.from_unstructured() for it to take in arrays with more than 2 dimensions, i.e. vertical levels (and possibly time)?

Motivation

I am trying to visualise LFRic output (happy to eventually contribute to the gallery by the way), and while the from_unstructured() method works great for 2D arrays, I would like to plot something w.r.t. model height. Currently there's no obvious way to do this as that function accepts only longitudes and latitudes, throwing an error if I pass a full 3D array as data.

This is probably related to the "isosurfaces support" to-do item.

Update scalars on existing mesh

๐Ÿ“ฐ Custom Issue

I recently produced this and am wondering if I could improve performance with these sorts of high resolution climate outputs.
The movie shows two 'animated' features:
a) evolving scalars (time dependent velocity and salinity fields) with time
b) A camera move

I wrote the model out in a fashing like this (pseudocode):

import geovista as gv

ds = load_xarray_dataset
frames = range(n)
camera_path = define_camera_path(frames)

p = gv.GeoPlotter()
p.open_movie(f'something.mp4')

for frame in frames:
    # select timestep
    da = ds.sel(time=frame).YOUR_VARIABLE
    
   # create new mesh for each timestep (point a)
    mesh = gv.Transform.from_2d(da.lon, da.lat, data=da.data)
    mesh = mesh.threshold()
    actor = p.add_mesh(mesh)
    
   # Animate camera position (point b)
    p.camera_position = camera_path.points[frame,:]

    # write movie frame and remove actor
    p.write_frame()
    p.remove_actor(actor)

p.close()

This seems super inefficent to me. I actually do not need to redraw the mesh, but instead the whole point a) is currently a change in the scalar values. I saw that there is a possibility to update just the scalars in pyvista. I wonder if there is an internal/external function that would allow me to 'map' my n dimensional array of scalar data with geovista to be in the proper format to use pyvista.Plotter.update_scalars() instead of removing/rebuilding the mesh.

Use of EPSG codes like EPSG:4326

Is an EPSG code acceptable as CRS parameter ?

I have been able to use the PROJ.4 String but not the EPSG code.

import geovista as gv
from geovista.pantry import lfric_sst
import geovista.theme

# Load the sample data.
sample = lfric_sst()

# Create the mesh from the sample data.
mesh = gv.Transform.from_unstructured(
    sample.lons,
    sample.lats,
    connectivity=sample.connectivity,
    data=sample.data
)

# Plot the mesh on a Robinson projection using an ESRI spatial reference identifier.
plotter = gv.GeoPlotter(crs="+proj=longlat")
sargs = {"title": f"{sample.name} / {sample.units}"}
plotter.add_mesh(mesh, cmap="thermal", show_edges=True, scalar_bar_args=sargs)
plotter.view_xy()
plotter.add_axes()
plotter.show()

works but I was expecting to use:
plotter = gv.GeoPlotter(crs="EPSG:4326")

Refactoring of move vtk to PyVista

๐Ÿ“ฐ Custom Issue

I found a place in the existing code where it can be done in PyVista but is expressed in vtk.
@bjlittle Are you fine changing it to PyVista representation?

# We need to add `check_mesh` option in PyVista
remeshed: pv.PolyData = poly1.intersection(
    poly2, check_mesh=check, split_first=True, split_second=False
)

# https://vtk.org/doc/nightly/html/classvtkIntersectionPolyDataFilter.html
alg = _vtk.vtkIntersectionPolyDataFilter()
alg.SetInputDataObject(0, poly0)
alg.SetInputDataObject(1, poly1)
# BoundaryPoints (points) mask array
alg.SetComputeIntersectionPointArray(True)
# BadTriangle and FreeEdge (cells) mask arrays
alg.SetCheckMesh(check)
alg.SetSplitFirstOutput(True)
alg.SetSplitSecondOutput(False)
alg.Update()
remeshed: pv.PolyData = _get_output(alg, oport=1)

Graticule labels not rendered with super-sample anti-aliasing enabled

๐Ÿ› Bug Report

Enabling anti-aliasing type ssaa results in no labels being rendered for the meridians and parallels of a graticule e.g.,

Disabled

import geovista
import geovista.theme

plotter = geovista.GeoPlotter()
plotter.add_coastlines()
plotter.add_base_layer(texture=geovista.natural_earth_1())
plotter.add_graticule()
plotter.camera.zoom(1.5)
plotter.disable_anti_aliasing()
plotter.show()

aa-disables

FXAA - Fast Approximate Anti-Aliasing

import geovista
import geovista.theme

plotter = geovista.GeoPlotter()
plotter.add_coastlines()
plotter.add_base_layer(texture=geovista.natural_earth_1())
plotter.add_graticule()
plotter.camera.zoom(1.5)
plotter.enable_anti_aliasing(aa_type="fxaa")
plotter.show()

aa-fxaa

MSAA - Multi-Sample Anti-Aliasing

import geovista
import geovista.theme

plotter = geovista.GeoPlotter()
plotter.add_coastlines()
plotter.add_base_layer(texture=geovista.natural_earth_1())
plotter.add_graticule()
plotter.camera.zoom(1.5)
plotter.enable_anti_aliasing(aa_type="msaa", multi_samples=8)
plotter.show()

aa-msaa

SSAA - Super-Sample Anti-Aliasing

import geovista
import geovista.theme

plotter = geovista.GeoPlotter()
plotter.add_coastlines()
plotter.add_base_layer(texture=geovista.natural_earth_1())
plotter.add_graticule()
plotter.camera.zoom(1.5)
plotter.enable_anti_aliasing(aa_type="ssaa")
plotter.show()

aa-ssaa

Environment

Please share the report generated by either of the following CLI commands:

scooby --report geovista

or

python -c "import geovista; print(geovista.Report())"
----------------------------------------------------------------------------------------
  Date: Fri Sep 01 13:13:39 2023 BST

                 OS : Linux
             CPU(s) : 4
            Machine : x86_64
       Architecture : 64bit
                RAM : 7.7 GiB
        Environment : Python
        File system : ext4
         GPU Vendor : Intel Open Source Technology Center
       GPU Renderer : Mesa DRI Intel(R) HD Graphics 4000 (IVB GT2)
        GPU Version : 4.2 (Core Profile) Mesa 20.0.8

  Python 3.11.4 | packaged by conda-forge | (main, Jun 10 2023, 18:08:17) [GCC 12.2.0]

            cartopy : 0.21.1
              click : 8.1.5
click-default-group : 1.2.2
            cmocean : v3.0.3
           colorcet : 3.0.1
           geovista : 0.4.0.dev9+dirty
         matplotlib : 3.7.2
            netcdf4 : 1.6.4
              numpy : 1.25.1
       platformdirs : 3.9.0
              pooch : v1.7.0
           pykdtree : 1.3.7.post0
             pyproj : 3.6.0
            pyvista : 0.40.1
             scooby : 0.7.2
                vtk : 9.2.6
            IPython : 8.14.0
        fastparquet : 2023.7.0
       nest_asyncio : 1.5.6
             pandas : 2.0.3
              scipy : 1.11.1
----------------------------------------------------------------------------------------

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.