Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PyVista for 3D plotting in Python #29

Merged
merged 9 commits into from
Sep 27, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ srf.plot()
<img src="https://raw.githubusercontent.com/GeoStat-Framework/GSTools/master/docs/source/pics/gau_field.png" alt="Random field" width="600px"/>
</p>

A similar example but for a three dimensional field is exported to a [VTK](https://vtk.org/) file, which can be visualized with [ParaView](https://www.paraview.org/).
A similar example but for a three dimensional field is exported to a [VTK](https://vtk.org/) file, which can be visualized with [ParaView](https://www.paraview.org/) or [PyVista](http://docs.pyvista.org) in Python:
banesullivan marked this conversation as resolved.
Show resolved Hide resolved

```python
from gstools import SRF, Gaussian
Expand All @@ -114,7 +114,10 @@ x = y = z = range(100)
model = Gaussian(dim=3, var=0.6, len_scale=20)
srf = SRF(model)
srf((x, y, z), mesh_type='structured')
srf.vtk_export('3d_field')
srf.vtk_export('3d_field') # Save to a VTK file for ParaView

mesh = srf.to_pyvista() # Create a PyVista mesh for plotting in Python
mesh.threshold_percent(0.5).plot()
```

<p align="center">
Expand Down Expand Up @@ -222,21 +225,25 @@ yielding
[kraichnan_link]: https://doi.org/10.1063/1.1692799


## VTK Export
## VTK/PyVista Export

After you have created a field, you may want to save it to file, so we provide
a handy [VTK][vtk_link] export routine:
a handy [VTK][vtk_link] export routine using the `.vtk_export()` or you could
create a VTK/PyVista dataset for use in Python with to `.to_pyvista()` method:

```python
from gstools import SRF, Gaussian
x = y = range(100)
model = Gaussian(dim=2, var=1, len_scale=10)
srf = SRF(model)
srf((x, y), mesh_type='structured')
srf.vtk_export("field")
srf.vtk_export("field") # Saves to a VTK file
mesh = srf.to_pyvista() # Create a VTK/PyVista dataset in memory
mesh.plot()
```

Which gives a RectilinearGrid VTK file ``field.vtr``.
Which gives a RectilinearGrid VTK file ``field.vtr`` or creates a PyVista mesh
in memory for immediate 3D plotting in Python.


## Requirements:
Expand All @@ -248,6 +255,11 @@ Which gives a RectilinearGrid VTK file ``field.vtr``.
- [pyevtk](https://bitbucket.org/pauloh/pyevtk)
- [six](https://github.com/benjaminp/six)

### Optional

- [matplotlib](https://matplotlib.org)
- [pyvista](https://docs.pyvista.org/)


## Contact

Expand Down
14 changes: 12 additions & 2 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ with a :any:`Gaussian` covariance model.

A similar example but for a three dimensional field is exported to a
`VTK <https://vtk.org/>`__ file, which can be visualized with
`ParaView <https://www.paraview.org/>`_.
`ParaView <https://www.paraview.org/>`_ or
`PyVista <http://docs.pyvista.org>`__ in Python:

.. code-block:: python

Expand All @@ -102,7 +103,10 @@ A similar example but for a three dimensional field is exported to a
model = Gaussian(dim=3, var=0.6, len_scale=20)
srf = SRF(model)
srf((x, y, z), mesh_type='structured')
srf.vtk_export('3d_field')
srf.vtk_export('3d_field') # Save to a VTK file for ParaView

mesh = srf.to_pyvista() # Create a PyVista mesh for plotting in Python
mesh.threshold_percent(0.5).plot()

.. image:: https://raw.githubusercontent.com/GeoStat-Framework/GSTools/master/docs/source/pics/3d_gau_field.png
:width: 400px
Expand Down Expand Up @@ -304,6 +308,12 @@ Requirements
- `pyevtk <https://bitbucket.org/pauloh/pyevtk>`_
- `six <https://github.com/benjaminp/six>`_

Optional
~~~~~~~~

- `matplotlib <https://matplotlib.org>`_
- `pyvista <https://docs.pyvista.org>`_


License
=======
Expand Down
7 changes: 7 additions & 0 deletions docs/source/tutorial_01_srf.rst
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,13 @@ Using the field from `previous example <Using an Unstructured Grid_>`__, it can

srf.vtk_export("field")

Or it could visualized immediately in Python using `PyVista <http://docs.pyvista.org>`__:

.. code-block:: python

mesh = srf.to_pyvista("field")
mesh.plot()

The script can be found in :download:`gstools/examples/04_export.py<../../examples/04_export.py>` and
in :download:`gstools/examples/06_unstr_srf_export.py<../../examples/06_unstr_srf_export.py>`

Expand Down
2 changes: 2 additions & 0 deletions examples/06_unstr_srf_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

field = srf((x, y))
srf.vtk_export("field")
# Or create a PyVista dataset
# mesh = srf.to_pyvista()

pt.tricontourf(x, y, field.T)
pt.axes().set_aspect("equal")
Expand Down
6 changes: 6 additions & 0 deletions gstools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,11 @@
.. currentmodule:: gstools.tools

.. autosummary::
to_vtk
vtk_export
to_vtk_structured
vtk_export_structured
to_vtk_unstructured
vtk_export_unstructured

variogram estimation
Expand Down Expand Up @@ -149,7 +152,10 @@

__all__ += [
"SRF",
"to_vtk_structured",
"vtk_export_structured",
"to_vtk_unstructured",
"vtk_export_unstructured",
"to_vtk",
"vtk_export",
]
71 changes: 59 additions & 12 deletions gstools/field/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import numpy as np

from gstools.covmodel.base import CovModel
from gstools.tools.export import vtk_export as vtk_ex
from gstools.tools.export import to_vtk, vtk_export
from gstools.field.tools import _get_select

__all__ = ["Field"]
Expand Down Expand Up @@ -147,16 +147,15 @@ def mesh(
mesh.point_data[name] = field
return out

def vtk_export(
self, filename, field_select="field", fieldname="field"
def _to_vtk_helper(
self, filename=None, field_select="field", fieldname="field"
): # pragma: no cover
"""Export the stored field to vtk.
"""Create a VTK/PyVista grid of the stored field.

This is an internal helper that will handle saving or creating objects

Parameters
----------
filename : :class:`str`
Filename of the file to be saved, including the path. Note that an
ending (.vtr or .vtu) will be added to the name.
banesullivan marked this conversation as resolved.
Show resolved Hide resolved
field_select : :class:`str`, optional
Field that should be stored. Can be:
"field", "raw_field", "krige_field", "err_field" or "krige_var".
Expand All @@ -181,7 +180,10 @@ def vtk_export(
fields = {}
for i in range(self.model.dim):
fields[fieldname + suf[i]] = field[i]
vtk_ex(filename, self.pos, fields, self.mesh_type)
if filename is None:
return to_vtk(self.pos, fields, self.mesh_type)
else:
return vtk_export(filename, self.pos, fields, self.mesh_type)
elif self.value_type == "scalar":
if hasattr(self, field_select):
field = getattr(self, field_select)
Expand All @@ -190,18 +192,63 @@ def vtk_export(
if not (
self.pos is None or field is None or self.mesh_type is None
):
vtk_ex(filename, self.pos, {fieldname: field}, self.mesh_type)
if filename is None:
return to_vtk(self.pos, {fieldname: field}, self.mesh_type)
else:
return vtk_export(filename, self.pos, {fieldname: field}, self.mesh_type)
else:
print(
"Field.vtk_export: No "
+ field_select
+ " stored in the class."
"Field.to_vtk: No " + field_select + " stored in the class."
)
else:
raise ValueError(
"Unknown field value type: {}".format(self.value_type)
)


def to_pyvista(
self, field_select="field", fieldname="field"
): # pragma: no cover
"""Create a VTK/PyVista grid of the stored field.

Parameters
----------
field_select : :class:`str`, optional
Field that should be stored. Can be:
"field", "raw_field", "krige_field", "err_field" or "krige_var".
Default: "field"
fieldname : :class:`str`, optional
Name of the field in the VTK file. Default: "field"
"""
grid = self._to_vtk_helper(filename=None, field_select=field_select,
fieldname=fieldname)
return grid


def vtk_export(
self, filename, field_select="field", fieldname="field"
): # pragma: no cover
"""Export the stored field to vtk.

Parameters
----------
filename : :class:`str`
Filename of the file to be saved, including the path. Note that an
ending (.vtr or .vtu) will be added to the name.
field_select : :class:`str`, optional
Field that should be stored. Can be:
"field", "raw_field", "krige_field", "err_field" or "krige_var".
Default: "field"
fieldname : :class:`str`, optional
Name of the field in the VTK file. Default: "field"
"""
if not isinstance(filename, str):
raise TypeError("Please use a string filename.")
return self._to_vtk_helper(filename=filename,
field_select=field_select,
fieldname=fieldname)


def plot(self, field="field", fig=None, ax=None): # pragma: no cover
"""
Plot the spatial random field.
Expand Down
5 changes: 4 additions & 1 deletion gstools/tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
^^^^^^

.. autosummary::
vtk_export
to_vtk_structured
vtk_export_structured
to_vtk_unstructured
vtk_export_unstructured
to_vtk
vtk_export

Special functions
^^^^^^^^^^^^^^^^^
Expand Down
Loading