Interactive 3-D Visualization


In [1]:
# Importing GemPy
import gempy as gp

# Embedding matplotlib figures in the notebooks
%matplotlib inline

# Importing auxiliary libraries
import numpy as np
import matplotlib.pyplot as plt

Loading an example geomodel


In [2]:
data_path = 'https://raw.githubusercontent.com/cgre-aachen/gempy_data/master/'

geo_model = gp.create_data('viz_3d',
                           [0, 2000, 0, 2000, 0, 1600],
                           [50, 50, 50],
                           path_o=data_path + "data/input_data/lisa_models/foliations" + str(7) + ".csv",
                           path_i=data_path + "data/input_data/lisa_models/interfaces" + str(7) + ".csv"
                           )

gp.map_stack_to_surfaces(
    geo_model,
    {"Fault_1": 'Fault_1', "Fault_2": 'Fault_2',
     "Strat_Series": ('Sandstone', 'Siltstone', 'Shale', 'Sandstone_2', 'Schist', 'Gneiss')}
)

geo_model.set_is_fault(['Fault_1', 'Fault_2'])
geo_model.set_topography()

gp.set_interpolator(geo_model)
gp.compute_model(geo_model, compute_mesh=True)


Active grids: ['regular']
i:\pycharmprojects\gempy\gempy\core\data_modules\geometric_data.py:533: UserWarning: If pole_vector and orientation are passed pole_vector is used/
  warnings.warn('If pole_vector and orientation are passed pole_vector is used/')
Fault colors changed. If you do not like this behavior, set change_color to False.
[1280. 1600.]
Active grids: ['regular' 'topography']
Setting kriging parameters to their default values.
Compiling theano function...
Level of Optimization:  fast_compile
Device:  cpu
Precision:  float64
Number of faults:  2
Compilation Done!
Kriging values: 
                        values
range                 3249.62
$C_o$                  251429
drift equations  [3, 3, 3, 3]
Out[2]:
Lithology ids 
  [9. 9. 9. ... 3. 3. 3.] 

Basic plotting API

Data plot


In [3]:
gp.plot_3d(geo_model, show_surfaces=False, notebook=True)


Out[3]:
<gempy.plot.vista.GemPyToVista at 0x1cb1200d6d8>

Geomodel plot


In [4]:
gp.plot_3d(geo_model, notebook=True)


Out[4]:
<gempy.plot.vista.GemPyToVista at 0x1cb1200d3c8>

Interactive plot

Passing the notebook=False keyword argument will run the pyvista visualization in an external window, allowing for interactivity:


In [5]:
gp.plot_3d(geo_model, notebook=False)


Out[5]:
<gempy.plot.vista.GemPyToVista at 0x1cb38f683c8>

Granular 3-D Visualization

Plotting surfaces


In [6]:
geo_model.surfaces


Out[6]:
surface series order_surfaces color id
0 Fault_1 Fault_1 1 #527682 1
1 Fault_2 Fault_2 1 #527682 2
7 Sandstone Strat_Series 1 #4878d0 3
6 Siltstone Strat_Series 2 #5DA629 4
5 Shale Strat_Series 3 #ff3f20 5
4 Sandstone_2 Strat_Series 4 #443988 6
3 Schist Strat_Series 5 #728f02 7
2 Gneiss Strat_Series 6 #ffbe00 8
8 basement Basement 1 #ee854a 9

In [17]:
gpv = gp.plot_3d(geo_model, show_data=False, show_results=False, plotter_type='background')

In [18]:
# Plotting all surfaces...
gpv.plot_surfaces()


Out[18]:
{'Fault_1': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6DC8,
 'Fault_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6CA8,
 'Sandstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6A68,
 'Siltstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6EE8,
 'Shale': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12108,
 'Sandstone_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12D68,
 'Schist': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12E28,
 'Gneiss': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12EE8}

In [19]:
# ... masked by topography
gpv.plot_topography()


Out[19]:
(vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12888

In [20]:
# Just few surfaces
gpv.plot_surfaces(['Siltstone', 'Gneiss'])


Out[20]:
{'Fault_1': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6DC8,
 'Fault_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6CA8,
 'Sandstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6A68,
 'Siltstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B125E8,
 'Shale': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12108,
 'Sandstone_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12D68,
 'Schist': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12E28,
 'Gneiss': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12768,
 'topography': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12888,
 'topography_cont': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB3B3A3108}

Plotting individual surfaces


In [21]:
gpv.plot_surfaces(["Fault_1"])
gpv.plot_surfaces(["Shale"], clear=False)


Out[21]:
{'Fault_1': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12F48,
 'Fault_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6CA8,
 'Sandstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6A68,
 'Siltstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B125E8,
 'Shale': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39AE6AC8,
 'Sandstone_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12D68,
 'Schist': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12E28,
 'Gneiss': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12768,
 'topography': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB39B12888,
 'topography_cont': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB3B3A3108}

Plotting input data


In [22]:
gpv.plot_surface_points()
gpv.plot_orientations()


Out[22]:
(vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB3B3A36A8

In [23]:
mesh = gpv.surface_points_mesh
mesh


Out[23]:
HeaderData Arrays
PolyDataInformation
N Cells22
N Points22
X Bounds2.500e+02, 1.750e+03
Y Bounds5.000e+02, 1.500e+03
Z Bounds3.000e+02, 1.500e+03
N Arrays1
NameFieldTypeN CompMinMax
idPointsint3211.000e+008.000e+00

In [24]:
mesh.points[:, -1]


Out[24]:
pyvista_ndarray([ 500.,  500.,  500.,  500., 1500., 1200., 1500., 1300.,
                 1300., 1100., 1200., 1200., 1000.,  900.,  900.,  700.,
                  700.,  700.,  500.,  300.,  500.,  500.])

In [25]:
mesh.n_arrays


Out[25]:
1

Plot structured grids


In [26]:
gpv.plot_structured_grid("scalar", series = 'Strat_Series')


Out[26]:
[UnstructuredGrid (0x1cb3b3a3b28)
   N Cells:	105205
   N Points:	112868
   X Bounds:	2.000e+01, 1.980e+03
   Y Bounds:	2.000e+01, 1.980e+03
   Z Bounds:	1.600e+01, 1.584e+03
   N Arrays:	4,
 'viridis']

Interactive Block with cross sections


In [4]:
gp.plot.plot_interactive_3d(geo_model, show_topography=True)


here
Out[4]:
<gempy.plot.vista.GemPyToVista at 0x2cc32d17908>

Interactive Plotting: Drag and drop

GemPy supports interactive plotting, meaning that you can drag & drop the input data and GemPy will update the geomodel live. This does not work in the static notebook plotter, but instead you have to pass the notebook=False argument to open an interactive plotting window. When running the next cell you can freely move the surface points (spheres) and orientations (arrows) of the Shale horizon and see how it updates the model.

Note: Everytime you move a data point, GemPy will recompute the geomodel. This works best whe running GemPy on a dedicated graphics card (GPU).


In [29]:
gpv = gp.plot_3d(geo_model, show_data=False, show_results=False, plotter_type='background')
gpv.plot_surface_points()
gpv.plot_orientations()
gpv.plot_surfaces()


Out[29]:
{'Fault_1': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C3A8,
 'Fault_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB60C04E88,
 'Sandstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C4C8,
 'Siltstone': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C588,
 'Shale': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C648,
 'Sandstone_2': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C708,
 'Schist': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C7C8,
 'Gneiss': (vtkRenderingOpenGL2Python.vtkOpenGLActor)000001CB5D86C888}

In [30]:
gpv.toggle_live_updating()


Out[30]:
True

Now if you move the data the model updates!

To go back to static models:


In [31]:
gpv.toggle_live_updating()


Out[31]:
False

Interactive Plotting: Programatically

If the model is in live_updating model. It is also possible to change the model by passing the plotting object to the typical methods:


In [32]:
gpv.live_updating = True
gpv.plot_surface_points()
gpv.plot_orientations()


Out[32]:
{0: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871408,
 1: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871468,
 15: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D8714C8,
 16: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871528,
 17: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871588,
 18: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D8715E8,
 10: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871648,
 11: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D8716A8,
 12: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871708,
 13: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871768,
 14: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D8717C8,
 5: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871828,
 6: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871888,
 7: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D8718E8,
 8: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871948,
 9: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D8719A8,
 2: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871A08,
 3: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871A68,
 4: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871AC8,
 19: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871B28,
 20: (vtkInteractionWidgetsPython.vtkPlaneWidget)000001CB5D871B88}

In [33]:
geo_model.modify_surface_points(0, X=-100, plot_object=gpv)


Out[33]:
X Y Z smooth surface
0 -100.0 1500.0 500.0 0.000002 Fault_1
1 750.0 500.0 500.0 0.000002 Fault_1
2 1250.0 1500.0 500.0 0.000002 Fault_2
3 1250.0 1500.0 500.0 0.000002 Fault_2
18 250.0 1000.0 1500.0 0.000002 Sandstone
19 1000.0 1000.0 1200.0 0.000002 Sandstone
20 1750.0 1000.0 1500.0 0.000002 Sandstone
15 250.0 1000.0 1300.0 0.000002 Siltstone
16 1750.0 1000.0 1300.0 0.000002 Siltstone
17 1000.0 1000.0 1100.0 0.000002 Siltstone
12 1750.0 1000.0 1200.0 0.000002 Shale
14 250.0 1000.0 1200.0 0.000002 Shale
21 1000.0 1000.0 1000.0 0.000002 Shale
9 250.0 1000.0 900.0 0.000002 Sandstone_2
10 1750.0 1000.0 900.0 0.000002 Sandstone_2
11 1000.0 1000.0 700.0 0.000002 Sandstone_2
6 250.0 1000.0 700.0 0.000002 Schist
7 1750.0 1000.0 700.0 0.000002 Schist
8 1000.0 1000.0 500.0 0.000002 Schist
4 1000.0 1000.0 300.0 0.000002 Gneiss
5 250.0 1000.0 500.0 0.000002 Gneiss
13 1750.0 1000.0 500.0 0.000002 Gneiss

In [34]:
geo_model.add_surface_points(-200, 1500, 600, 'Schist', plot_object=gpv)


Out[34]:
X Y Z smooth surface
0 -100.0 1500.0 500.0 0.000002 Fault_1
1 750.0 500.0 500.0 0.000002 Fault_1
2 1250.0 1500.0 500.0 0.000002 Fault_2
3 1250.0 1500.0 500.0 0.000002 Fault_2
18 250.0 1000.0 1500.0 0.000002 Sandstone
19 1000.0 1000.0 1200.0 0.000002 Sandstone
20 1750.0 1000.0 1500.0 0.000002 Sandstone
15 250.0 1000.0 1300.0 0.000002 Siltstone
16 1750.0 1000.0 1300.0 0.000002 Siltstone
17 1000.0 1000.0 1100.0 0.000002 Siltstone
12 1750.0 1000.0 1200.0 0.000002 Shale
14 250.0 1000.0 1200.0 0.000002 Shale
21 1000.0 1000.0 1000.0 0.000002 Shale
9 250.0 1000.0 900.0 0.000002 Sandstone_2
10 1750.0 1000.0 900.0 0.000002 Sandstone_2
11 1000.0 1000.0 700.0 0.000002 Sandstone_2
6 250.0 1000.0 700.0 0.000002 Schist
7 1750.0 1000.0 700.0 0.000002 Schist
8 1000.0 1000.0 500.0 0.000002 Schist
22 -200.0 1500.0 600.0 0.000001 Schist
4 1000.0 1000.0 300.0 0.000002 Gneiss
5 250.0 1000.0 500.0 0.000002 Gneiss
13 1750.0 1000.0 500.0 0.000002 Gneiss

In [35]:
geo_model.delete_surface_points(22, plot_object=gpv)


Out[35]:
X Y Z smooth surface
0 -100.0 1500.0 500.0 0.000002 Fault_1
1 750.0 500.0 500.0 0.000002 Fault_1
2 1250.0 1500.0 500.0 0.000002 Fault_2
3 1250.0 1500.0 500.0 0.000002 Fault_2
18 250.0 1000.0 1500.0 0.000002 Sandstone
19 1000.0 1000.0 1200.0 0.000002 Sandstone
20 1750.0 1000.0 1500.0 0.000002 Sandstone
15 250.0 1000.0 1300.0 0.000002 Siltstone
16 1750.0 1000.0 1300.0 0.000002 Siltstone
17 1000.0 1000.0 1100.0 0.000002 Siltstone
12 1750.0 1000.0 1200.0 0.000002 Shale
14 250.0 1000.0 1200.0 0.000002 Shale
21 1000.0 1000.0 1000.0 0.000002 Shale
9 250.0 1000.0 900.0 0.000002 Sandstone_2
10 1750.0 1000.0 900.0 0.000002 Sandstone_2
11 1000.0 1000.0 700.0 0.000002 Sandstone_2
6 250.0 1000.0 700.0 0.000002 Schist
7 1750.0 1000.0 700.0 0.000002 Schist
8 1000.0 1000.0 500.0 0.000002 Schist
4 1000.0 1000.0 300.0 0.000002 Gneiss
5 250.0 1000.0 500.0 0.000002 Gneiss
13 1750.0 1000.0 500.0 0.000002 Gneiss