Skip to content

Commit 41e3028

Browse files
committed
Add function to convert prism to vedo grids
Add method to the prism layer to convert the full prism layer to a vedo grid.
1 parent 42dd445 commit 41e3028

File tree

7 files changed

+151
-8
lines changed

7 files changed

+151
-8
lines changed

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ Visualization
127127
:toctree: generated/
128128

129129
visualization.prism_to_pyvista
130+
visualization.prism_to_vedo
130131

131132
Utilities
132133
---------

env/requirements-docs.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ ensaio>=0.5.*
1313
netcdf4
1414
matplotlib
1515
pyvista
16+
vedo
1617
vtk>=9
1718
pygmt
1819
gmt

environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ dependencies:
2121
- pyvista
2222
- vtk
2323
- numba-progress
24+
- vedo
2425
# Testing requirements
2526
- pytest
2627
- pytest-cov

harmonica/_forward/prism_layer.py

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import verde as vd
1414
import xarray as xr
1515

16-
from ..visualization import prism_to_pyvista
16+
from ..visualization import prism_to_pyvista, prism_to_vedo
1717
from .prism_gravity import prism_gravity
1818

1919

@@ -482,7 +482,7 @@ def get_prism(self, indices):
482482

483483
def to_pyvista(self, drop_null_prisms=True):
484484
"""
485-
Return a pyvista UnstructuredGrid to plot the PrismLayer
485+
Return a :class:`pyvista.UnstructuredGrid` to plot the prism layer.
486486
487487
Parameters
488488
----------
@@ -495,10 +495,58 @@ def to_pyvista(self, drop_null_prisms=True):
495495
496496
Returns
497497
-------
498-
pv_grid : :class:`pyvista.UnstructuredGrid`
498+
pyvista.UnstructuredGrid
499499
:class:`pyvista.UnstructuredGrid` containing each prism of the
500500
layer as a hexahedron along with their properties.
501501
"""
502+
return self._to_vtk_object(backend="pyvista", drop_null_prisms=drop_null_prisms)
503+
504+
def to_vedo(self, drop_null_prisms=True):
505+
"""
506+
Return a :class:`vedo.UnstructuredGrid` to plot the prism layer.
507+
508+
Parameters
509+
----------
510+
drop_null_prisms : bool (optional)
511+
If True, prisms with zero volume or with any :class:`numpy.nan` as
512+
their top or bottom boundaries won't be included in the
513+
:class:`vedo.UnstructuredGrid`.
514+
If False, every prism in the layer will be included.
515+
Default True.
516+
517+
Returns
518+
-------
519+
vedo.UnstructuredGrid
520+
:class:`vedo.UnstructuredGrid` containing each prism of the
521+
layer as a hexahedron along with their properties.
522+
"""
523+
return self._to_vtk_object(backend="vedo", drop_null_prisms=drop_null_prisms)
524+
525+
def _to_vtk_object(self, backend: str, drop_null_prisms=True):
526+
"""
527+
Return a pyvista or vedo UnstructuredGrid to plot the prism layer.
528+
Return a pyvista UnstructuredGrid to plot the PrismLayer
529+
530+
Parameters
531+
----------
532+
backend : {"pyvista", "vedo"}
533+
Choose which type of UnstructuredGrid to return.
534+
drop_null_prisms : bool (optional)
535+
If True, prisms with zero volume or with any :class:`numpy.nan` as
536+
their top or bottom boundaries won't be included in the
537+
``UnstructuredGrid``.
538+
If False, every prism in the layer will be included.
539+
Default True.
540+
541+
Returns
542+
-------
543+
pyvista.UnstructuredGrid or vedo.UnstructuredGrid
544+
``UnstructuredGrid`` containing each prism of the layer as
545+
a hexahedron along with their properties.
546+
"""
547+
if backend not in ("vedo", "pyvista"):
548+
msg = f"Invalid backend '{backend}'."
549+
raise ValueError(msg)
502550
prisms = self._to_prisms()
503551
null_prisms = np.zeros_like(prisms[:, 0], dtype=bool)
504552
if drop_null_prisms:
@@ -514,7 +562,8 @@ def to_pyvista(self, drop_null_prisms=True):
514562
]
515563
for data_var in self._obj.data_vars
516564
}
517-
return prism_to_pyvista(prisms, properties=properties)
565+
func = prism_to_pyvista if backend == "pyvista" else prism_to_vedo
566+
return func(prisms, properties=properties)
518567

519568

520569
def _discard_thin_prisms(

harmonica/visualization/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
#
55
# This code is part of the Fatiando a Terra project (https://www.fatiando.org)
66
#
7-
from ._prism import prism_to_pyvista
7+
from ._prism import prism_to_pyvista, prism_to_vedo

harmonica/visualization/_prism.py

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,108 @@
55
# This code is part of the Fatiando a Terra project (https://www.fatiando.org)
66
#
77
"""
8-
Functions for visualizing prisms through pyvista
8+
Functions for visualizing prisms in 3D.
99
"""
1010
import numpy as np
1111

1212
try:
1313
import pyvista
1414
except ImportError:
1515
pyvista = None
16-
else:
16+
17+
try:
18+
import vedo
19+
except ImportError:
20+
vedo = None
21+
22+
if pyvista is not None or vedo is not None:
1723
import vtk
1824

1925

26+
def prism_to_vedo(prisms, properties=None):
27+
"""
28+
Create a :class:`vedo.UnstructuredGrid` out of prisms.
29+
30+
Builds a :class:`vedo.UnstructuredGrid` out of a set of prisms that
31+
could be used to plot a 3D representation through :mod:`vedo`.
32+
33+
Parameters
34+
----------
35+
prisms : list or 2d-array
36+
List or 2d-array with the boundaries of the prisms.
37+
Each row contains the boundaries of each prism in the following order:
38+
``west``, ``east``, ``south``, ``north``, ``bottom``, ``top``.
39+
properties : dict or None (optional)
40+
Dictionary with the physical properties of the prisms.
41+
Each key should be a string and its corresponding value a 1D array.
42+
If None, no celldata will be added to the
43+
:class:`vedo.UnstructuredGrid`.
44+
Default to None.
45+
46+
Returns
47+
-------
48+
vedo.UnstructuredGrid
49+
:class:`vedo.UnstructuredGrid` that represents the prisms with their
50+
properties (if any).
51+
52+
Examples
53+
--------
54+
Define a set of prisms and their densities:
55+
56+
>>> prisms = [
57+
... [0, 4, 0, 5, -10, 0],
58+
... [0, 4, 7, 9, -12, -3],
59+
... [6, 9, 2, 6, -7, 3],
60+
... ]
61+
>>> densities = [2900, 3000, 2670]
62+
63+
Generate a :class:`vedo.UnstructuredGrid` out of them:
64+
65+
>>> import harmonica as hm
66+
>>> vedo_grid = hm.visualization.prism_to_vedo(
67+
... prisms, properties={"density": densities}
68+
... )
69+
>>> print(vedo_grid) # doctest: +SKIP
70+
vedo.grids.UnstructuredGrid at (0x56070a0af5b0)
71+
nr. of verts : 24
72+
nr. of cells : 3
73+
cell types : ['HEXAHEDRON']
74+
size : average=6.64122, diagonal=19.6723
75+
center of mass: (3.83333, 4.83333, -4.83333)
76+
bounds : x=(0, 9.00), y=(0, 9.00), z=(-12.0, 3.00)
77+
celldata * : "density" (int64), ndim=1, range=(2.67e+3, 3.00e+3)
78+
"""
79+
# Check if vedo are installed
80+
if vedo is None:
81+
raise ImportError(
82+
"Missing optional dependency 'vedo' required for building vedo grids."
83+
)
84+
# Get prisms and number of prisms
85+
prisms = np.atleast_2d(prisms)
86+
n_prisms = prisms.shape[0]
87+
# Get the vertices of the prisms
88+
vertices = _prisms_boundaries_to_vertices(prisms)
89+
# Generate the cells for the hexahedrons
90+
cells = np.arange(n_prisms * 8).reshape([n_prisms, 8])
91+
# Define celltypes
92+
celltypes = [vtk.VTK_HEXAHEDRON for _ in range(n_prisms)]
93+
# Build the UnstructuredGrid
94+
grid = vedo.UnstructuredGrid([vertices, cells, celltypes])
95+
# Add properties to the grid
96+
if properties is not None:
97+
for name, prop in properties.items():
98+
# Check if the property is given as 1d array
99+
property = np.atleast_1d(prop)
100+
if property.ndim > 1:
101+
raise ValueError(
102+
f"Multidimensional array found in '{name}' property. "
103+
+ "Please, pass prism properties as 1d arrays."
104+
)
105+
# Assign the property to the cell_data
106+
grid.celldata[name] = property
107+
return grid
108+
109+
20110
def prism_to_pyvista(prisms, properties=None):
21111
"""
22112
Create a :class:`pyvista.UnstructuredGrid` out of prisms

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ dependencies = [
4747
"Source Code" = "https://github.com/fatiando/harmonica"
4848

4949
[project.optional-dependencies]
50-
visualizations = ["pyvista>=0.27", "vtk>=9"]
50+
pyvista = ["pyvista>=0.27", "vtk>=9"]
5151
numba_progress = ["numba_progress"]
52+
vedo = ["vedo"]
5253

5354
[build-system]
5455
requires = ["setuptools>=61", "wheel", "setuptools_scm[toml]>=8.0.3"]

0 commit comments

Comments
 (0)