LoopStructural 1.0.4__zip
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of LoopStructural might be problematic. Click here for more details.
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/__init__.py +33 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/__init__.py +12 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/__pycache__/_base.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/_base.py +65 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/claudius.csv +21049 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/claudiusbb.txt +2 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/duplex.csv +126 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/duplexbb.txt +2 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/intrusion.csv +1017 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/intrusionbb.txt +2 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/onefoldbb.txt +2 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/onefolddata.csv +2226 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/refolded_bb.txt +2 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/datasets/data/refolded_fold.csv +2126 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__init__.py +31 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/discrete_fold_interpolator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/discrete_interpolator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/finite_difference_interpolator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/geological_interpolator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/operator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/piecewiselinear_interpolator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/structured_grid.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/structured_tetra.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/__pycache__/surfe_wrapper.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/__init__.py +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/dsi_helper.c +27782 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/cython/dsi_helper.cp37-win_amd64.pyd +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/discrete_fold_interpolator.py +171 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/discrete_interpolator.py +551 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/finite_difference_interpolator.py +342 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/geological_interpolator.py +190 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/operator.py +60 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/piecewiselinear_interpolator.py +348 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/structured_grid.py +466 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/structured_tetra.py +638 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/interpolators/surfe_wrapper.py +117 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/__init__.py +46 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__init__.py +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/__pycache__/geological_model.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/core/geological_model.py +1351 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__init__.py +3 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_function.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_function_feature.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/__pycache__/fault_segment.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_function.py +187 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_function_feature.py +75 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fault/fault_segment.py +270 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__init__.py +7 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/cross_product_geological_feature.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/geological_feature.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/geological_feature_builder.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/region_feature.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/structural_frame.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/structural_frame_builder.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/__pycache__/unconformity_feature.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/cross_product_geological_feature.py +77 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/geological_feature.py +286 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/geological_feature_builder.py +329 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/region_feature.py +34 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/structural_frame.py +116 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/structural_frame_builder.py +179 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/features/unconformity_feature.py +69 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__init__.py +8 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold_rotation_angle.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/fold_rotation_angle_feature.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/foldframe.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/__pycache__/svariogram.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/fold.py +135 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/fold_rotation_angle.py +132 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/fold_rotation_angle_feature.py +57 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/foldframe.py +192 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/modelling/fold/svariogram.py +179 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__init__.py +14 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/exceptions.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/helper.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/map2loop.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/__pycache__/utils.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/exceptions.py +9 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/helper.py +378 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/map2loop.py +314 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/utils/utils.py +120 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__init__.py +19 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/map_viewer.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/model_plotter.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/model_visualisation.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/rotation_angle_plotter.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/__pycache__/sphinx_scraper.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/map_viewer.py +307 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/model_plotter.py +16 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/model_visualisation.py +1012 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/rotation_angle_plotter.py +82 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural/visualisation/sphinx_scraper.py +34 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural-1.0.4-py3.7.egg-info/PKG-INFO +10 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural-1.0.4-py3.7.egg-info/SOURCES.txt +60 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural-1.0.4-py3.7.egg-info/dependency_links.txt +1 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural-1.0.4-py3.7.egg-info/requires.txt +8 -0
- Miniconda/envs/loop/Lib/site-packages/LoopStructural-1.0.4-py3.7.egg-info/top_level.txt +2 -0
- Miniconda/envs/loop/Lib/site-packages/tests/__init__.py +0 -0
- Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/__init__.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_faults.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_fold.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_interpolator.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/tests/__pycache__/test_refolded.cpython-37.pyc +0 -0
- Miniconda/envs/loop/Lib/site-packages/tests/test_faults.py +17 -0
- Miniconda/envs/loop/Lib/site-packages/tests/test_fold.py +57 -0
- Miniconda/envs/loop/Lib/site-packages/tests/test_interpolator.py +88 -0
- Miniconda/envs/loop/Lib/site-packages/tests/test_refolded.py +22 -0
|
@@ -0,0 +1,1012 @@
|
|
|
1
|
+
"""
|
|
2
|
+
A wrapper for lavavu
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import logging
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
try:
|
|
10
|
+
import lavavu
|
|
11
|
+
from lavavu.vutils import is_notebook
|
|
12
|
+
except ImportError:
|
|
13
|
+
logger.error("Please install lavavu: pip install lavavu")
|
|
14
|
+
import numpy as np
|
|
15
|
+
from skimage.measure import marching_cubes_lewiner as marching_cubes
|
|
16
|
+
|
|
17
|
+
from LoopStructural.utils.helper import create_surface, get_vectors, create_box
|
|
18
|
+
|
|
19
|
+
# adapted/copied from pyvista for sphinx scraper
|
|
20
|
+
_OPEN_VIEWERS = {}
|
|
21
|
+
|
|
22
|
+
def close_all():
|
|
23
|
+
_OPEN_VIEWERS.clear()
|
|
24
|
+
return True
|
|
25
|
+
# for key, v in _OPEN_VIEWERS.items():
|
|
26
|
+
# if not v._closed:
|
|
27
|
+
# v.close()
|
|
28
|
+
# v.deep_clean()
|
|
29
|
+
# _OPEN_VIEWERS.clear()
|
|
30
|
+
# return True
|
|
31
|
+
##
|
|
32
|
+
class LavaVuModelViewer:
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
Short description
|
|
36
|
+
|
|
37
|
+
"""
|
|
38
|
+
def __init__(self, model=None, bounding_box=None, nsteps=None, vertical_exaggeration=1., **kwargs):
|
|
39
|
+
"""
|
|
40
|
+
A wrapper to plot LoopStructural object with lavavu
|
|
41
|
+
|
|
42
|
+
Parameters
|
|
43
|
+
----------
|
|
44
|
+
**kwargs : lavavu viewer kwargs
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
objects : dictionary of objects that have been plotted
|
|
48
|
+
"""
|
|
49
|
+
# copied from pyvista
|
|
50
|
+
if lavavu is None:
|
|
51
|
+
logger.error("Lavavu isn't installed: pip install lavavu")
|
|
52
|
+
return
|
|
53
|
+
self._id_name = "{}-{}".format(str(hex(id(self))), len(_OPEN_VIEWERS))
|
|
54
|
+
_OPEN_VIEWERS[self._id_name] = self
|
|
55
|
+
#
|
|
56
|
+
self.lv = lavavu.Viewer(**kwargs)
|
|
57
|
+
self.lv['orthographic'] = True
|
|
58
|
+
self.lv.modelscale([1,1,vertical_exaggeration])
|
|
59
|
+
self.objects = {}
|
|
60
|
+
self.bounding_box = bounding_box
|
|
61
|
+
self.nsteps = nsteps
|
|
62
|
+
if model is not None:
|
|
63
|
+
self.bounding_box = model.bounding_box
|
|
64
|
+
self.nsteps = model.nsteps
|
|
65
|
+
logger.debug("Using bounding box from model")
|
|
66
|
+
if self.bounding_box is None or self.nsteps is None:
|
|
67
|
+
logger.error("Plot area has not been defined.")
|
|
68
|
+
self.bounding_box = np.array(self.bounding_box)
|
|
69
|
+
self.nsteps = np.array(self.nsteps)
|
|
70
|
+
self._model = model
|
|
71
|
+
# prerotate to a nice view
|
|
72
|
+
# self.lv.rotate([-57.657936096191406, -13.939384460449219, -6.758780479431152])
|
|
73
|
+
def close(self):
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def model(self):
|
|
78
|
+
return self._model
|
|
79
|
+
|
|
80
|
+
@model.setter
|
|
81
|
+
def model(self, model):
|
|
82
|
+
if model is not None:
|
|
83
|
+
self.bounding_box = np.array(model.bounding_box)
|
|
84
|
+
self.nsteps = np.array(model.nsteps)
|
|
85
|
+
self._model = model
|
|
86
|
+
self._nelements = self.nsteps[0]*self.nsteps[1]*self.nsteps[2]
|
|
87
|
+
logger.debug("Using bounding box from model")
|
|
88
|
+
@property
|
|
89
|
+
def nelements(self):
|
|
90
|
+
"""The number of elements to use for evaluating the isosurface
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
nelements : int
|
|
95
|
+
number of elements to use for isosurfacing
|
|
96
|
+
"""
|
|
97
|
+
return self._nelements
|
|
98
|
+
|
|
99
|
+
@nelements.setter
|
|
100
|
+
def nelements(self, nelements : int):
|
|
101
|
+
"""Setter for nelements, automatically caculates the number of equally sized elements
|
|
102
|
+
to isosurface. Better than specifying step distance manually
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
nelements : int
|
|
107
|
+
[description]
|
|
108
|
+
"""
|
|
109
|
+
box_vol = (self.bounding_box[1, 0]-self.bounding_box[0, 0]) * (self.bounding_box[1, 1]-self.bounding_box[0, 1]) * (self.bounding_box[1, 2]-self.bounding_box[0, 2])
|
|
110
|
+
ele_vol = box_vol / nelements
|
|
111
|
+
# calculate the step vector of a regular cube
|
|
112
|
+
step_vector = np.zeros(3)
|
|
113
|
+
step_vector[:] = ele_vol ** (1. / 3.)
|
|
114
|
+
# step_vector /= np.array([1,1,2])
|
|
115
|
+
# number of steps is the length of the box / step vector
|
|
116
|
+
nsteps = np.ceil((self.bounding_box[1, :] - self.bounding_box[0, :]) / step_vector).astype(int)
|
|
117
|
+
self.nsteps = nsteps
|
|
118
|
+
logger.info("Using grid with dimensions {} {} {}".format(nsteps[0],nsteps[1],nsteps[2]))
|
|
119
|
+
|
|
120
|
+
def deep_clean(self):
|
|
121
|
+
"""[summary]
|
|
122
|
+
|
|
123
|
+
[extended_summary]
|
|
124
|
+
"""
|
|
125
|
+
self.lv.clear()
|
|
126
|
+
self.lv.cleardata()
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
def add_section(self, geological_feature=None, axis='x', value=None, **kwargs):
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
Plot a section/map thru the model and paint with a geological feature
|
|
133
|
+
|
|
134
|
+
Parameters
|
|
135
|
+
----------
|
|
136
|
+
geological_feature : Geological feature
|
|
137
|
+
The feature to paint the section with
|
|
138
|
+
axis : string
|
|
139
|
+
which axis, x,y,z
|
|
140
|
+
value : float
|
|
141
|
+
Where to make the section
|
|
142
|
+
kwargs
|
|
143
|
+
additional kwargs passes to lavavu for colourmaps etc
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
if axis == 'x':
|
|
151
|
+
tri, yy, zz = create_surface(self.bounding_box[:, [1, 2]], self.nsteps[[1, 2]])
|
|
152
|
+
xx = np.zeros(zz.shape)
|
|
153
|
+
if value is None:
|
|
154
|
+
xx[:] = np.nanmean(self.bounding_box[:, 0])
|
|
155
|
+
else:
|
|
156
|
+
xx[:] = value
|
|
157
|
+
if axis == 'y':
|
|
158
|
+
tri, xx, zz = create_surface(self.bounding_box[:, [0, 2]], self.nsteps[[0, 2]])
|
|
159
|
+
yy = np.zeros(xx.shape)
|
|
160
|
+
if value is None:
|
|
161
|
+
yy[:] = np.nanmean(self.bounding_box[:, 1])
|
|
162
|
+
else:
|
|
163
|
+
yy[:] = value
|
|
164
|
+
if axis == 'z':
|
|
165
|
+
tri, xx, yy = create_surface(self.bounding_box[:, 0:2], self.nsteps[0:2])
|
|
166
|
+
zz = np.zeros(xx.shape)
|
|
167
|
+
if value is None:
|
|
168
|
+
zz[:] = np.nanmean(self.bounding_box[:, 2])
|
|
169
|
+
else:
|
|
170
|
+
zz[:] = value
|
|
171
|
+
name = kwargs.get('name', axis + '_slice')
|
|
172
|
+
colour = kwargs.get('colour', 'red')
|
|
173
|
+
|
|
174
|
+
# create an array to evaluate the feature on for the section
|
|
175
|
+
points = np.zeros((len(xx), 3)) #
|
|
176
|
+
points[:, 0] = xx
|
|
177
|
+
points[:, 1] = yy
|
|
178
|
+
points[:, 2] = zz
|
|
179
|
+
|
|
180
|
+
surf = self.lv.triangles(name)
|
|
181
|
+
surf.vertices(self.model.rescale(points))
|
|
182
|
+
surf.indices(tri)
|
|
183
|
+
logger.info("Adding %s section at %f" % (axis, value))
|
|
184
|
+
if geological_feature is None:
|
|
185
|
+
surf.colours(colour)
|
|
186
|
+
if geological_feature is not None:
|
|
187
|
+
if 'norm' in kwargs:
|
|
188
|
+
surf.values(np.linalg.norm(
|
|
189
|
+
geological_feature.evaluate_gradient(points), axis=1),
|
|
190
|
+
geological_feature.name)
|
|
191
|
+
else:
|
|
192
|
+
surf.values(geological_feature.evaluate_value(points),
|
|
193
|
+
geological_feature.name)
|
|
194
|
+
surf["colourby"] = geological_feature.name
|
|
195
|
+
cmap = lavavu.cubehelix(100)
|
|
196
|
+
if 'cmap' in kwargs:
|
|
197
|
+
cmap = kwargs['cmap']
|
|
198
|
+
logger.info("Colouring section with %s min: %f, max: %f" % (
|
|
199
|
+
geological_feature.name, geological_feature.min(), geological_feature.max()))
|
|
200
|
+
surf.colourmap(cmap, range=[geological_feature.min(), geological_feature.max()])
|
|
201
|
+
|
|
202
|
+
def add_isosurface(self, geological_feature, value = None, isovalue=None,
|
|
203
|
+
paint_with=None, slices=None, colour='red', nslices=None,
|
|
204
|
+
cmap=None, filename=None, names=None, colours=None,**kwargs):
|
|
205
|
+
""" Plot the surface of a geological feature
|
|
206
|
+
|
|
207
|
+
[extended_summary]
|
|
208
|
+
|
|
209
|
+
Parameters
|
|
210
|
+
----------
|
|
211
|
+
geological_feature : GeologicalFeature
|
|
212
|
+
[description]
|
|
213
|
+
value : float, optional
|
|
214
|
+
|
|
215
|
+
isovalue : [type], optional
|
|
216
|
+
[description], by default None
|
|
217
|
+
paint_with : [type], optional
|
|
218
|
+
[description], by default None
|
|
219
|
+
slices : [type], optional
|
|
220
|
+
[description], by default None
|
|
221
|
+
colour : [type], optional
|
|
222
|
+
[description], by default None
|
|
223
|
+
nslices : [type], optional
|
|
224
|
+
[description], by default None
|
|
225
|
+
cmap : [type], optional
|
|
226
|
+
[description], by default None
|
|
227
|
+
filename: string, optional
|
|
228
|
+
filename for exporting
|
|
229
|
+
names: list, optional
|
|
230
|
+
list of names same length as slices
|
|
231
|
+
colours: list, optional
|
|
232
|
+
list of colours same length as slices
|
|
233
|
+
|
|
234
|
+
Returns
|
|
235
|
+
-------
|
|
236
|
+
[type]
|
|
237
|
+
[description]
|
|
238
|
+
"""
|
|
239
|
+
|
|
240
|
+
# update the feature to make sure its current
|
|
241
|
+
if 'update' in kwargs:
|
|
242
|
+
geological_feature.update()
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# do isosurfacing of support using marching tetras/cubes
|
|
246
|
+
x = np.linspace(self.bounding_box[0, 0], self.bounding_box[1, 0], self.nsteps[0])
|
|
247
|
+
y = np.linspace(self.bounding_box[0, 1], self.bounding_box[1, 1], self.nsteps[1])
|
|
248
|
+
z = np.linspace(self.bounding_box[1, 2], self.bounding_box[0, 2], self.nsteps[2])
|
|
249
|
+
xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
|
|
250
|
+
points = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
|
|
251
|
+
val = geological_feature.evaluate_value(points)
|
|
252
|
+
# get the stats to check what we are plotting
|
|
253
|
+
mean_property_val = np.nanmean(val)#geological_feature.mean()
|
|
254
|
+
min_property_val = np.nanmin(val)#geological_feature.min()
|
|
255
|
+
max_property_val = np.nanmax(val)#geological_feature.max()
|
|
256
|
+
# set default parameters
|
|
257
|
+
slices_ = [mean_property_val]
|
|
258
|
+
painter = None
|
|
259
|
+
voxet = None
|
|
260
|
+
tris = None
|
|
261
|
+
nodes = None
|
|
262
|
+
# parse kwargs for parameters
|
|
263
|
+
if isovalue is not None:
|
|
264
|
+
slices_ = [isovalue]
|
|
265
|
+
if value is not None:
|
|
266
|
+
slices_ = [value]
|
|
267
|
+
if slices is not None:
|
|
268
|
+
slices_ = slices
|
|
269
|
+
if nslices is not None:
|
|
270
|
+
var = max_property_val - min_property_val
|
|
271
|
+
# buffer slices by 5%
|
|
272
|
+
slices_ = np.linspace(min_property_val + var * 0.05,
|
|
273
|
+
max_property_val - var * 0.05,
|
|
274
|
+
nslices)
|
|
275
|
+
|
|
276
|
+
if paint_with is not None:
|
|
277
|
+
painter = paint_with
|
|
278
|
+
|
|
279
|
+
region = kwargs.get('region', None)
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
if region is not None:
|
|
283
|
+
val[~region(np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T)] = np.nan
|
|
284
|
+
step_vector = np.array([x[1] - x[0], y[1] - y[0], z[1] - z[0]])
|
|
285
|
+
for i, isovalue in enumerate(slices_):
|
|
286
|
+
logger.info("Creating isosurface of %s at %f" % (geological_feature.name, isovalue))
|
|
287
|
+
|
|
288
|
+
if isovalue > np.nanmax(val) or isovalue < np.nanmin(val):
|
|
289
|
+
logger.warning("Isovalue doesn't exist inside bounding box")
|
|
290
|
+
continue # return np.zeros((3, 1)).astype(int), np.zeros((3, 1))
|
|
291
|
+
try:
|
|
292
|
+
verts, faces, normals, values = marching_cubes(
|
|
293
|
+
val.reshape(self.nsteps, order='C'),
|
|
294
|
+
isovalue,
|
|
295
|
+
spacing=step_vector)
|
|
296
|
+
verts += np.array([self.bounding_box[0, 0], self.bounding_box[0, 1], self.bounding_box[1, 2]])
|
|
297
|
+
self.model.rescale(verts)
|
|
298
|
+
|
|
299
|
+
except ValueError:
|
|
300
|
+
logger.warning("no surface to mesh, skipping")
|
|
301
|
+
continue
|
|
302
|
+
|
|
303
|
+
name = geological_feature.name
|
|
304
|
+
name = kwargs.get('name', name)
|
|
305
|
+
name += '_iso_%f' % isovalue
|
|
306
|
+
if names is not None and len(names) == len(slices_):
|
|
307
|
+
name = names[i]
|
|
308
|
+
if name in self.lv.objects:
|
|
309
|
+
ii = 0
|
|
310
|
+
newname = name+"_{}".format(ii)
|
|
311
|
+
while newname in self.lv.objects:
|
|
312
|
+
ii+=1
|
|
313
|
+
newname = name+"_{}".format(ii)
|
|
314
|
+
name = newname
|
|
315
|
+
|
|
316
|
+
if colours is not None and len(colours) == len(slices_):
|
|
317
|
+
colour=colours[i]
|
|
318
|
+
if filename is not None:
|
|
319
|
+
svalues = None
|
|
320
|
+
# svalues[:] = np.nan
|
|
321
|
+
try:
|
|
322
|
+
import meshio
|
|
323
|
+
meshio.write_points_cells(filename.format(name),
|
|
324
|
+
verts,
|
|
325
|
+
[("triangle", faces)]
|
|
326
|
+
)
|
|
327
|
+
except ImportError:
|
|
328
|
+
logger.error("Could not save surfaces, meshio is not installed")
|
|
329
|
+
|
|
330
|
+
surf = self.lv.triangles(name)
|
|
331
|
+
surf.vertices(verts)
|
|
332
|
+
surf.indices(faces)
|
|
333
|
+
if painter is None:
|
|
334
|
+
surf.colours(colour)
|
|
335
|
+
if painter is not None:
|
|
336
|
+
# add a property to the surface nodes for visualisation
|
|
337
|
+
# calculate the mode value, just to get the most common value
|
|
338
|
+
surfaceval = np.zeros(verts.shape[0])
|
|
339
|
+
surfaceval[:] = painter.evaluate_value(self.model.scale(verts))
|
|
340
|
+
if painter.name is geological_feature.name:
|
|
341
|
+
logger.info("Setting surface value to %f"%isovalue)
|
|
342
|
+
surfaceval[:] = isovalue
|
|
343
|
+
surf.values(surfaceval, painter.name)
|
|
344
|
+
surf["colourby"] = painter.name
|
|
345
|
+
vmin = kwargs.get('vmin', min_property_val)
|
|
346
|
+
vmax = kwargs.get('vmax', max_property_val)
|
|
347
|
+
surf.colourmap(cmap, range=(vmin, vmax)) # nodes.shape[0]))
|
|
348
|
+
|
|
349
|
+
def add_scalar_field(self, geological_feature, **kwargs):
|
|
350
|
+
"""
|
|
351
|
+
|
|
352
|
+
Parameters
|
|
353
|
+
----------
|
|
354
|
+
geological_feature : GeologicalFeature
|
|
355
|
+
the geological feature to colour the scalar field by
|
|
356
|
+
kwargs
|
|
357
|
+
kwargs for lavavu
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
|
|
362
|
+
"""
|
|
363
|
+
name = kwargs.get('name', geological_feature.name + '_scalar_field')
|
|
364
|
+
points, tri = create_box(self.bounding_box,self.nsteps)
|
|
365
|
+
|
|
366
|
+
surf = self.lv.triangles(name)
|
|
367
|
+
surf.vertices(self.model.rescale(points))
|
|
368
|
+
surf.indices(tri)
|
|
369
|
+
val =geological_feature.evaluate_value(self.model.scale(points))
|
|
370
|
+
surf.values(val, geological_feature.name)
|
|
371
|
+
surf["colourby"] = geological_feature.name
|
|
372
|
+
cmap = kwargs.get('cmap',lavavu.cubehelix(100))
|
|
373
|
+
|
|
374
|
+
logger.info("Adding scalar field of %s to viewer. Min: %f, max: %f" % (geological_feature.name,
|
|
375
|
+
geological_feature.min(),
|
|
376
|
+
geological_feature.max()))
|
|
377
|
+
vmin = kwargs.get('vmin', np.nanmin(val))
|
|
378
|
+
vmax = kwargs.get('vmax', np.nanmax(val))
|
|
379
|
+
surf.colourmap(cmap, range=(vmin, vmax))
|
|
380
|
+
|
|
381
|
+
def add_model(self, cmap = None, **kwargs):
|
|
382
|
+
"""Add a block model painted by stratigraphic id to the viewer
|
|
383
|
+
|
|
384
|
+
Calls self.model.evaluate_model() for a cube surrounding the model.
|
|
385
|
+
|
|
386
|
+
Parameters
|
|
387
|
+
----------
|
|
388
|
+
cmap : matplotlib cmap, optional
|
|
389
|
+
colourmap name or object from mpl
|
|
390
|
+
|
|
391
|
+
Notes
|
|
392
|
+
------
|
|
393
|
+
It is sensible to increase the viewer step sizes before running this function to
|
|
394
|
+
increase the resolution of the model as its not possible to interpolate a discrete
|
|
395
|
+
colourmap and this causes the model to look like a lego block.
|
|
396
|
+
You can update the model resolution by changing the attribute nsteps
|
|
397
|
+
>>> viewer.nsteps = np.array([100,100,100])
|
|
398
|
+
|
|
399
|
+
"""
|
|
400
|
+
import matplotlib.colors as colors
|
|
401
|
+
from matplotlib import cm
|
|
402
|
+
|
|
403
|
+
name = kwargs.get('name', 'geological_model')
|
|
404
|
+
points, tri = create_box(self.bounding_box, self.nsteps)
|
|
405
|
+
|
|
406
|
+
surf = self.lv.triangles(name)
|
|
407
|
+
surf.vertices(self.model.rescale(points))
|
|
408
|
+
surf.indices(tri)
|
|
409
|
+
val = self.model.evaluate_model(points,scale=True)
|
|
410
|
+
surf.values(val, 'model')
|
|
411
|
+
surf["colourby"] = 'model'
|
|
412
|
+
|
|
413
|
+
if cmap is None:
|
|
414
|
+
import matplotlib.colors as colors
|
|
415
|
+
colours = []
|
|
416
|
+
boundaries = []
|
|
417
|
+
data = []
|
|
418
|
+
for g in self.model.stratigraphic_column.keys():
|
|
419
|
+
for u, v in self.model.stratigraphic_column[g].items():
|
|
420
|
+
data.append((v['id'],v['colour']))
|
|
421
|
+
colours.append(v['colour'])
|
|
422
|
+
boundaries.append(v['id'])#print(u,v)
|
|
423
|
+
cmap = colors.ListedColormap(colours).colors
|
|
424
|
+
# else:
|
|
425
|
+
# cmap = cm.get_cmap(cmap,n_units)
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
# logger.info("Adding scalar field of %s to viewer. Min: %f, max: %f" % (geological_feature.name,
|
|
429
|
+
# geological_feature.min(),
|
|
430
|
+
# geological_feature.max()))
|
|
431
|
+
vmin = kwargs.get('vmin', np.nanmin(val))
|
|
432
|
+
vmax = kwargs.get('vmax', np.nanmax(val))
|
|
433
|
+
surf.colourmap(cmap, range=(vmin, vmax))
|
|
434
|
+
|
|
435
|
+
def add_fault_displacements(self, cmap = 'rainbow', **kwargs):
|
|
436
|
+
"""Add a block model painted by the fault displacement magnitude
|
|
437
|
+
|
|
438
|
+
Calls fault.displacementfeature.evaluate_value(points) for all faults
|
|
439
|
+
|
|
440
|
+
Parameters
|
|
441
|
+
----------
|
|
442
|
+
cmap : matplotlib cmap, optional
|
|
443
|
+
colourmap name or object from mpl
|
|
444
|
+
|
|
445
|
+
Notes
|
|
446
|
+
------
|
|
447
|
+
It is sensible to increase the viewer step sizes before running this function to
|
|
448
|
+
increase the resolution of the model as its not possible to interpolate a discrete
|
|
449
|
+
colourmap and this causes the model to look like a lego block.
|
|
450
|
+
You can update the model resolution by changing the attribute nsteps
|
|
451
|
+
>>> viewer.nsteps = np.array([100,100,100])
|
|
452
|
+
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
name = kwargs.get('name', 'fault_displacements')
|
|
456
|
+
points, tri = create_box(self.bounding_box, self.nsteps)
|
|
457
|
+
|
|
458
|
+
surf = self.lv.triangles(name)
|
|
459
|
+
surf.vertices(self.model.rescale(points))
|
|
460
|
+
surf.indices(tri)
|
|
461
|
+
vals = self.model.evaluate_fault_displacements(points)
|
|
462
|
+
surf.values(vals, 'displacement')
|
|
463
|
+
surf["colourby"] = 'displacement'
|
|
464
|
+
|
|
465
|
+
vmin = kwargs.get('vmin', np.nanmin(vals))
|
|
466
|
+
vmax = kwargs.get('vmax', np.nanmax(vals))
|
|
467
|
+
surf.colourmap(cmap, range=(vmin, vmax))
|
|
468
|
+
|
|
469
|
+
def add_model_surfaces(self, faults = True, cmap=None, **kwargs):
|
|
470
|
+
"""Add surfaces for all of the interfaces in the model
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
Parameters
|
|
474
|
+
----------
|
|
475
|
+
faults : bool, optional
|
|
476
|
+
whether to draw faults, by default True
|
|
477
|
+
cmap : string
|
|
478
|
+
matplotlib cmap
|
|
479
|
+
Notes
|
|
480
|
+
------
|
|
481
|
+
Other parameters are passed to self.add_isosurface()
|
|
482
|
+
|
|
483
|
+
"""
|
|
484
|
+
from matplotlib import cm
|
|
485
|
+
from matplotlib import colors
|
|
486
|
+
n_units = 0 #count how many discrete colours
|
|
487
|
+
for g in self.model.stratigraphic_column.keys():
|
|
488
|
+
for u in self.model.stratigraphic_column[g].keys():
|
|
489
|
+
n_units+=1
|
|
490
|
+
if cmap is None:
|
|
491
|
+
import matplotlib.colors as colors
|
|
492
|
+
colours = []
|
|
493
|
+
boundaries = []
|
|
494
|
+
data = []
|
|
495
|
+
for g in self.model.stratigraphic_column.keys():
|
|
496
|
+
for u, v in self.model.stratigraphic_column[g].items():
|
|
497
|
+
data.append((v['id'],v['colour']))
|
|
498
|
+
colours.append(v['colour'])
|
|
499
|
+
boundaries.append(v['id'])
|
|
500
|
+
cmap = colors.ListedColormap(colours)
|
|
501
|
+
else:
|
|
502
|
+
cmap = cm.get_cmap(cmap,n_units)
|
|
503
|
+
ci = 0
|
|
504
|
+
cmap_colours = colors.to_rgba_array(cmap.colors)
|
|
505
|
+
for g in self.model.stratigraphic_column.keys():
|
|
506
|
+
if g in self.model.feature_name_index:
|
|
507
|
+
feature = self.model.features[self.model.feature_name_index[g]]
|
|
508
|
+
names = []
|
|
509
|
+
values = []
|
|
510
|
+
colours = []
|
|
511
|
+
for u, vals in self.model.stratigraphic_column[g].items():
|
|
512
|
+
names.append(u)
|
|
513
|
+
values.append(vals['min'])
|
|
514
|
+
colours.append(cmap_colours[ci,:])
|
|
515
|
+
ci+=1
|
|
516
|
+
self.add_isosurface(feature, slices=values,names=names,colours=colours,**kwargs)
|
|
517
|
+
|
|
518
|
+
if faults:
|
|
519
|
+
for f in self.model.features:
|
|
520
|
+
if f.type == 'fault':
|
|
521
|
+
def mask(x):
|
|
522
|
+
val = f.displacementfeature.evaluate_value(x)
|
|
523
|
+
val[np.isnan(val)] = 0
|
|
524
|
+
maskv = np.zeros(val.shape).astype(bool)
|
|
525
|
+
maskv[np.abs(val) > 0.001] = 1
|
|
526
|
+
return maskv
|
|
527
|
+
self.add_isosurface(f,isovalue=0,region=mask,**kwargs)
|
|
528
|
+
|
|
529
|
+
# def add_model_data(self, cmap='tab20',**kwargs):
|
|
530
|
+
# from matplotlib import cm
|
|
531
|
+
# n_units = 0 #count how many discrete colours
|
|
532
|
+
# for g in self.model.stratigraphic_column.keys():
|
|
533
|
+
# for u in self.model.stratigraphic_column[g].keys():
|
|
534
|
+
# n_units+=1
|
|
535
|
+
# tab = cm.get_cmap(cmap,n_units)
|
|
536
|
+
# ci = 0
|
|
537
|
+
|
|
538
|
+
# for g in self.model.stratigraphic_column.keys():
|
|
539
|
+
# if g in self.model.feature_name_index:
|
|
540
|
+
# feature = self.model.features[self.model.feature_name_index[g]]
|
|
541
|
+
# for u, vals in self.model.stratigraphic_column[g].items():
|
|
542
|
+
# self.add_isosurface(feature, isovalue=vals['max'],name=u,colour=tab.colors[ci,:],**kwargs)
|
|
543
|
+
# ci+=1
|
|
544
|
+
# if faults:
|
|
545
|
+
# for f in self.model.features:
|
|
546
|
+
# if f.type == 'fault':
|
|
547
|
+
# self.add_isosurface(f,isovalue=0,**kwargs)
|
|
548
|
+
|
|
549
|
+
def add_vector_field(self, geological_feature, **kwargs):
|
|
550
|
+
"""
|
|
551
|
+
|
|
552
|
+
Plot the gradient of a geological feature at given locations
|
|
553
|
+
|
|
554
|
+
Parameters
|
|
555
|
+
----------
|
|
556
|
+
geological_feature : Geological Feature to evaluate gradient
|
|
557
|
+
locations : ((N,3)) array of evaluation locations
|
|
558
|
+
kwargs : kwargs for lavavu vector
|
|
559
|
+
|
|
560
|
+
Returns
|
|
561
|
+
-------
|
|
562
|
+
|
|
563
|
+
"""
|
|
564
|
+
logger.info("Adding vector field for %s " % (geological_feature.name))
|
|
565
|
+
locations = kwargs.get('locations', None)
|
|
566
|
+
if locations is None:
|
|
567
|
+
x = np.linspace(self.bounding_box[0, 0], self.bounding_box[1, 0], self.nsteps[0])
|
|
568
|
+
y = np.linspace(self.bounding_box[0, 1], self.bounding_box[1, 1], self.nsteps[1])
|
|
569
|
+
z = np.linspace(self.bounding_box[1, 2], self.bounding_box[0, 2], self.nsteps[2])
|
|
570
|
+
xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
|
|
571
|
+
locations = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
|
|
572
|
+
vector = geological_feature.evaluate_gradient(locations)
|
|
573
|
+
# normalise
|
|
574
|
+
mask = ~np.any(np.isnan(vector), axis=1)
|
|
575
|
+
vector[mask, :] /= np.linalg.norm(vector[mask, :], axis=1)[:, None]
|
|
576
|
+
vectorfield = self.lv.vectors(geological_feature.name + "_grad",
|
|
577
|
+
**kwargs)
|
|
578
|
+
vectorfield.vertices(self.model.rescale(locations[mask, :],inplace=False))
|
|
579
|
+
vectorfield.vectors(vector[mask, :])
|
|
580
|
+
return
|
|
581
|
+
|
|
582
|
+
def add_data(self, feature, **kwargs):
|
|
583
|
+
"""
|
|
584
|
+
|
|
585
|
+
Plot the data linked to the feature, can choose whether to plot all data types
|
|
586
|
+
using value and grad kwargs
|
|
587
|
+
|
|
588
|
+
Parameters
|
|
589
|
+
----------
|
|
590
|
+
feature
|
|
591
|
+
kwargs
|
|
592
|
+
|
|
593
|
+
Returns
|
|
594
|
+
-------
|
|
595
|
+
|
|
596
|
+
"""
|
|
597
|
+
name = feature.name
|
|
598
|
+
add_grad = True
|
|
599
|
+
add_value = True
|
|
600
|
+
add_tang = True
|
|
601
|
+
add_interface = True
|
|
602
|
+
if 'name' in kwargs:
|
|
603
|
+
name = kwargs['name']
|
|
604
|
+
del kwargs['name']
|
|
605
|
+
if 'grad' in kwargs:
|
|
606
|
+
add_grad = kwargs['grad']
|
|
607
|
+
if 'value' in kwargs:
|
|
608
|
+
add_value = kwargs['value']
|
|
609
|
+
if 'tang' in kwargs:
|
|
610
|
+
add_tang = kwargs['tang']
|
|
611
|
+
if 'interface' in kwargs:
|
|
612
|
+
add_interface = kwargs['interface']
|
|
613
|
+
grad = feature.builder.get_gradient_constraints()
|
|
614
|
+
norm = feature.builder.get_norm_constraints()
|
|
615
|
+
value = feature.builder.get_value_constraints()
|
|
616
|
+
tang = feature.builder.get_tangent_constraints()
|
|
617
|
+
interface = feature.builder.get_interface_constraints()
|
|
618
|
+
|
|
619
|
+
if grad.shape[0] > 0 and add_grad:
|
|
620
|
+
self.add_vector_data(self.model.rescale(grad[:, :3],inplace=False), grad[:, 3:6], name + "_grad_cp",
|
|
621
|
+
**kwargs)
|
|
622
|
+
|
|
623
|
+
if norm.shape[0] > 0 and add_grad:
|
|
624
|
+
self.add_vector_data(self.model.rescale(norm[:, :3],inplace=False), norm[:, 3:6], name + "_norm_cp",
|
|
625
|
+
**kwargs)
|
|
626
|
+
if value.shape[0] > 0 and add_value:
|
|
627
|
+
kwargs['range'] = [feature.min(), feature.max()]
|
|
628
|
+
self.add_value_data(self.model.rescale(value[:, :3],inplace=False), value[:, 3], name + "_value_cp",
|
|
629
|
+
**kwargs)
|
|
630
|
+
if tang.shape[0] > 0 and add_tang:
|
|
631
|
+
self.add_vector_data(self.model.rescale(tang[:, :3],inplace=False), tang[:, 3:6], name + "_tang_cp",
|
|
632
|
+
**kwargs)
|
|
633
|
+
if interface.shape[0] > 0 and add_interface:
|
|
634
|
+
self.add_points(self.model.rescale(interface[:,:3],inplace=False), name + "_interface_cp")
|
|
635
|
+
|
|
636
|
+
def add_points(self, points, name, **kwargs):
|
|
637
|
+
"""
|
|
638
|
+
|
|
639
|
+
Plot points location in the lavavu viewer
|
|
640
|
+
|
|
641
|
+
Parameters
|
|
642
|
+
----------
|
|
643
|
+
points : numpy array of the points locations
|
|
644
|
+
name : string name of the object for lavavu
|
|
645
|
+
**kwargs : lavavu points kwargs
|
|
646
|
+
|
|
647
|
+
Returns
|
|
648
|
+
-------
|
|
649
|
+
|
|
650
|
+
"""
|
|
651
|
+
p = self.lv.points(name, **kwargs)
|
|
652
|
+
p.vertices(points)
|
|
653
|
+
|
|
654
|
+
def add_vector_data(self, position, vector, name, **kwargs):
|
|
655
|
+
"""
|
|
656
|
+
|
|
657
|
+
Plot point data with a vector component into the lavavu viewer
|
|
658
|
+
|
|
659
|
+
Parameters
|
|
660
|
+
----------
|
|
661
|
+
position : numpy array N,3 for xyz locations
|
|
662
|
+
vector : numpy array of vector N,3
|
|
663
|
+
name : string name for the object in lavavu
|
|
664
|
+
kwargs to pass to lavavu
|
|
665
|
+
|
|
666
|
+
Returns
|
|
667
|
+
-------
|
|
668
|
+
|
|
669
|
+
"""
|
|
670
|
+
if 'colour' not in kwargs:
|
|
671
|
+
kwargs['colour'] = 'black'
|
|
672
|
+
# normalise
|
|
673
|
+
if position.shape[0] > 0:
|
|
674
|
+
vector /= np.linalg.norm(vector, axis=1)[:, None]
|
|
675
|
+
vectorfield = self.lv.vectors(name, **kwargs)
|
|
676
|
+
vectorfield.vertices(position)
|
|
677
|
+
vectorfield.vectors(vector)
|
|
678
|
+
return
|
|
679
|
+
|
|
680
|
+
def add_value_data(self, position, value, name, **kwargs):
|
|
681
|
+
"""
|
|
682
|
+
|
|
683
|
+
Plot points data with a value component
|
|
684
|
+
|
|
685
|
+
Parameters
|
|
686
|
+
----------
|
|
687
|
+
position : numpy array N,3 for xyz locations
|
|
688
|
+
value : N array of values
|
|
689
|
+
name : string name of the object for lavavu
|
|
690
|
+
kwargs : kwargs to pass to lavavu
|
|
691
|
+
|
|
692
|
+
Returns
|
|
693
|
+
-------
|
|
694
|
+
|
|
695
|
+
"""
|
|
696
|
+
if "pointtype" not in kwargs:
|
|
697
|
+
kwargs["pointtype"] = "sphere"
|
|
698
|
+
if "pointsize" not in kwargs:
|
|
699
|
+
kwargs["pointsize"] = 4
|
|
700
|
+
# set the colour map to diverge unless user decides otherwise
|
|
701
|
+
cmap = kwargs.get('cmap', "spot")
|
|
702
|
+
p = self.lv.points(name, **kwargs)
|
|
703
|
+
p.vertices(position)
|
|
704
|
+
p.values(value, "v")
|
|
705
|
+
p["colourby"] = "v"
|
|
706
|
+
|
|
707
|
+
if 'vmin' in kwargs and 'vmax' in kwargs:
|
|
708
|
+
logger.info('vmin {} and vmax {}'.format(kwargs['vmin'],kwargs['vmax']))
|
|
709
|
+
p.colourmap(cmap, range=(kwargs['vmin'],kwargs['vmax']))
|
|
710
|
+
else:
|
|
711
|
+
p.colourmap(cmap)
|
|
712
|
+
|
|
713
|
+
def add_fold(self, fold, **kwargs):
|
|
714
|
+
"""
|
|
715
|
+
Draw the vector components of the fold at the locations
|
|
716
|
+
|
|
717
|
+
Parameters
|
|
718
|
+
----------
|
|
719
|
+
fold - fold object
|
|
720
|
+
locations - numpy array of xyz
|
|
721
|
+
|
|
722
|
+
Returns
|
|
723
|
+
-------
|
|
724
|
+
|
|
725
|
+
"""
|
|
726
|
+
locations = kwargs.get('locations', None)
|
|
727
|
+
if locations is None:
|
|
728
|
+
x = np.linspace(self.bounding_box[0, 0], self.bounding_box[1, 0], self.nsteps[0])
|
|
729
|
+
y = np.linspace(self.bounding_box[0, 1], self.bounding_box[1, 1], self.nsteps[1])
|
|
730
|
+
z = np.linspace(self.bounding_box[1, 2], self.bounding_box[0, 2], self.nsteps[2])
|
|
731
|
+
xx, yy, zz = np.meshgrid(x, y, z, indexing='ij')
|
|
732
|
+
locations = np.array([xx.flatten(), yy.flatten(), zz.flatten()]).T
|
|
733
|
+
r2r, fold_axis, dgz = fold.get_deformed_orientation(locations)
|
|
734
|
+
locations = self.model.rescale(locations,inplace=False)
|
|
735
|
+
self.add_vector_data(locations, r2r, fold.name + '_direction', colour='red')
|
|
736
|
+
self.add_vector_data(locations, fold_axis, fold.name + '_axis', colour='black')
|
|
737
|
+
self.add_vector_data(locations, dgz, fold.name + '_norm', colour='green')
|
|
738
|
+
|
|
739
|
+
def interactive(self, popout=False):
|
|
740
|
+
"""
|
|
741
|
+
Runs the lavavu viewer as either a jupyter notebook
|
|
742
|
+
inline interactive viewer or as a separate window
|
|
743
|
+
|
|
744
|
+
Returns
|
|
745
|
+
-------
|
|
746
|
+
|
|
747
|
+
"""
|
|
748
|
+
if is_notebook() and popout is False:
|
|
749
|
+
self.lv.control.Panel()
|
|
750
|
+
self.lv.control.ObjectList()
|
|
751
|
+
self.lv.control.show()
|
|
752
|
+
if not is_notebook() or popout:
|
|
753
|
+
self.lv.control.Panel()
|
|
754
|
+
self.lv.control.ObjectList()
|
|
755
|
+
self.lv.interactive()
|
|
756
|
+
|
|
757
|
+
def add_support_box(self,geological_feature, paint=False, **kwargs):
|
|
758
|
+
name = kwargs.get('name', geological_feature.name + '_support')
|
|
759
|
+
box = np.vstack([geological_feature.interpolator.support.origin,geological_feature.interpolator.support.maximum])
|
|
760
|
+
points, tri = create_box(box,self.nsteps)
|
|
761
|
+
|
|
762
|
+
surf = self.lv.triangles(name)
|
|
763
|
+
surf.vertices(self.model.rescale(points))
|
|
764
|
+
surf.indices(tri)
|
|
765
|
+
if paint:
|
|
766
|
+
val =geological_feature.evaluate_value(self.model.scale(points))
|
|
767
|
+
surf.values(val, geological_feature.name)
|
|
768
|
+
surf["colourby"] = geological_feature.name
|
|
769
|
+
cmap = kwargs.get('cmap',lavavu.cubehelix(100))
|
|
770
|
+
|
|
771
|
+
logger.info("Adding scalar field of %s to viewer. Min: %f, max: %f" % (geological_feature.name,
|
|
772
|
+
geological_feature.min(),
|
|
773
|
+
geological_feature.max()))
|
|
774
|
+
vmin = kwargs.get('vmin', np.nanmin(val))
|
|
775
|
+
vmax = kwargs.get('vmax', np.nanmax(val))
|
|
776
|
+
surf.colourmap(cmap, range=(vmin, vmax))
|
|
777
|
+
def set_zscale(self,zscale):
|
|
778
|
+
""" Set the vertical scale for lavavu
|
|
779
|
+
|
|
780
|
+
just a simple wrapper for lavavu modelscale([xscale,yscale,zscale])
|
|
781
|
+
|
|
782
|
+
Parameters
|
|
783
|
+
----------
|
|
784
|
+
zscale : float
|
|
785
|
+
vertical scale
|
|
786
|
+
"""
|
|
787
|
+
self.lv.modelscale([1,1,zscale])
|
|
788
|
+
|
|
789
|
+
def set_viewer_rotation(self, rotation):
|
|
790
|
+
"""
|
|
791
|
+
Set the viewer rotation given a list of rotations x,y,z
|
|
792
|
+
|
|
793
|
+
Parameters
|
|
794
|
+
----------
|
|
795
|
+
rotation numpy array of 3 rotation
|
|
796
|
+
|
|
797
|
+
Returns
|
|
798
|
+
-------
|
|
799
|
+
|
|
800
|
+
"""
|
|
801
|
+
self.lv.rotate(rotation)
|
|
802
|
+
|
|
803
|
+
def save(self, fname, **kwargs):
|
|
804
|
+
"""
|
|
805
|
+
Calls lavavu.Viewer.image to save the viewer current state as an image
|
|
806
|
+
|
|
807
|
+
Parameters
|
|
808
|
+
----------
|
|
809
|
+
fname - file name string including relative path
|
|
810
|
+
kwargs - optional kwargs to give to lavavu e.g. transparent, resolution
|
|
811
|
+
|
|
812
|
+
Returns
|
|
813
|
+
-------
|
|
814
|
+
|
|
815
|
+
"""
|
|
816
|
+
self.lv.image(fname, **kwargs)
|
|
817
|
+
|
|
818
|
+
def display(self, fname=None, **kwargs):
|
|
819
|
+
"""
|
|
820
|
+
Calls the lv object display function. Shows a static image of the viewer inline.
|
|
821
|
+
|
|
822
|
+
Returns
|
|
823
|
+
-------
|
|
824
|
+
|
|
825
|
+
"""
|
|
826
|
+
if fname:
|
|
827
|
+
self.lv.image(fname, **kwargs)
|
|
828
|
+
|
|
829
|
+
self.lv.display()
|
|
830
|
+
|
|
831
|
+
def image(self, name, **kwargs):
|
|
832
|
+
"""
|
|
833
|
+
Calls the lv object image function to save the display state
|
|
834
|
+
|
|
835
|
+
Parameters
|
|
836
|
+
----------
|
|
837
|
+
name : string
|
|
838
|
+
name of the image file to save
|
|
839
|
+
kwargs
|
|
840
|
+
|
|
841
|
+
Returns
|
|
842
|
+
-------
|
|
843
|
+
|
|
844
|
+
"""
|
|
845
|
+
self.lv.image(name)
|
|
846
|
+
|
|
847
|
+
def image_array(self, **kwargs):
|
|
848
|
+
"""Return the current viewer image image data as a numpy array
|
|
849
|
+
|
|
850
|
+
Returns
|
|
851
|
+
-------
|
|
852
|
+
image : np.array
|
|
853
|
+
image as a numpy array
|
|
854
|
+
"""
|
|
855
|
+
return self.lv.rawimage(**kwargs).data
|
|
856
|
+
|
|
857
|
+
def rotatex(self, r):
|
|
858
|
+
"""
|
|
859
|
+
Rotate the viewer in the x plane
|
|
860
|
+
|
|
861
|
+
Parameters
|
|
862
|
+
----------
|
|
863
|
+
r : double
|
|
864
|
+
degrees to rotate, can be +ve or -ve
|
|
865
|
+
|
|
866
|
+
Returns
|
|
867
|
+
-------
|
|
868
|
+
|
|
869
|
+
"""
|
|
870
|
+
self.lv.rotatex(r)
|
|
871
|
+
|
|
872
|
+
def rotatey(self, r):
|
|
873
|
+
"""
|
|
874
|
+
Rotate the viewer in the Y plane
|
|
875
|
+
|
|
876
|
+
Parameters
|
|
877
|
+
----------
|
|
878
|
+
r : double
|
|
879
|
+
degrees to rotate, can be +ve or -ve
|
|
880
|
+
|
|
881
|
+
Returns
|
|
882
|
+
-------
|
|
883
|
+
|
|
884
|
+
"""
|
|
885
|
+
self.lv.rotatey(r)
|
|
886
|
+
|
|
887
|
+
def rotatez(self, r):
|
|
888
|
+
"""
|
|
889
|
+
Rotate the viewer in the z plane
|
|
890
|
+
|
|
891
|
+
Parameters
|
|
892
|
+
----------
|
|
893
|
+
r : double
|
|
894
|
+
degrees to rotate, can be +ve or -ve
|
|
895
|
+
|
|
896
|
+
Returns
|
|
897
|
+
-------
|
|
898
|
+
|
|
899
|
+
"""
|
|
900
|
+
self.lv.rotatez(r)
|
|
901
|
+
|
|
902
|
+
def rotate(self, r):
|
|
903
|
+
"""
|
|
904
|
+
Rotate by a vector of rotation angles
|
|
905
|
+
|
|
906
|
+
Parameters
|
|
907
|
+
----------
|
|
908
|
+
r : list/numpy array
|
|
909
|
+
a vector of rotations
|
|
910
|
+
|
|
911
|
+
Returns
|
|
912
|
+
-------
|
|
913
|
+
|
|
914
|
+
"""
|
|
915
|
+
self.lv.rotate(r)
|
|
916
|
+
|
|
917
|
+
@property
|
|
918
|
+
def rotation(self):
|
|
919
|
+
"""Accessor for the viewer rotation
|
|
920
|
+
Returns
|
|
921
|
+
-------
|
|
922
|
+
list
|
|
923
|
+
x,y,z rotations
|
|
924
|
+
"""
|
|
925
|
+
return self.lv['xyzrotate']
|
|
926
|
+
|
|
927
|
+
@rotation.setter
|
|
928
|
+
def rotation(self,xyz):
|
|
929
|
+
"""Set the rotation of the viewer
|
|
930
|
+
|
|
931
|
+
Parameters
|
|
932
|
+
----------
|
|
933
|
+
xyz : list like
|
|
934
|
+
x y z rotations
|
|
935
|
+
"""
|
|
936
|
+
self.lv.rotation(xyz)
|
|
937
|
+
|
|
938
|
+
@property
|
|
939
|
+
def border(self):
|
|
940
|
+
"""The width of the border around the model area
|
|
941
|
+
|
|
942
|
+
Returns
|
|
943
|
+
-------
|
|
944
|
+
border : double
|
|
945
|
+
[description]
|
|
946
|
+
"""
|
|
947
|
+
return self.lv['border']
|
|
948
|
+
|
|
949
|
+
@border.setter
|
|
950
|
+
def border(self, border):
|
|
951
|
+
"""Setter for the border
|
|
952
|
+
|
|
953
|
+
Parameters
|
|
954
|
+
----------
|
|
955
|
+
border : double
|
|
956
|
+
set the thickness of the border around objects
|
|
957
|
+
"""
|
|
958
|
+
self.lv['border'] = border
|
|
959
|
+
|
|
960
|
+
def clear(self):
|
|
961
|
+
"""Remove all objects from the viewer
|
|
962
|
+
"""
|
|
963
|
+
self.lv.clear()
|
|
964
|
+
|
|
965
|
+
@property
|
|
966
|
+
def xmin(self):
|
|
967
|
+
return self.lv['xmin']
|
|
968
|
+
|
|
969
|
+
@xmin.setter
|
|
970
|
+
def xmin(self, xmin):
|
|
971
|
+
self.lv['xmin'] = xmin
|
|
972
|
+
|
|
973
|
+
@property
|
|
974
|
+
def xmax(self):
|
|
975
|
+
return self.lv['xmax']
|
|
976
|
+
|
|
977
|
+
@xmax.setter
|
|
978
|
+
def xmax(self, xmax):
|
|
979
|
+
self.lv['xmax'] = xmax
|
|
980
|
+
|
|
981
|
+
@property
|
|
982
|
+
def ymin(self):
|
|
983
|
+
return self.lv['ymin']
|
|
984
|
+
|
|
985
|
+
@ymin.setter
|
|
986
|
+
def ymin(self, ymin):
|
|
987
|
+
self.lv['ymin'] = ymin
|
|
988
|
+
|
|
989
|
+
@property
|
|
990
|
+
def ymax(self):
|
|
991
|
+
return self.lv['ymax']
|
|
992
|
+
|
|
993
|
+
@ymax.setter
|
|
994
|
+
def ymax(self, ymax):
|
|
995
|
+
self.lv['ymax'] = ymax
|
|
996
|
+
|
|
997
|
+
@property
|
|
998
|
+
def zmin(self):
|
|
999
|
+
return self.lv['zmax']
|
|
1000
|
+
|
|
1001
|
+
@zmin.setter
|
|
1002
|
+
def zmin(self, zmin):
|
|
1003
|
+
self.lv['zmin'] = zmin
|
|
1004
|
+
|
|
1005
|
+
@property
|
|
1006
|
+
def zmax(self):
|
|
1007
|
+
return self.lv['zmax']
|
|
1008
|
+
|
|
1009
|
+
@zmax.setter
|
|
1010
|
+
def zmax(self, zmax):
|
|
1011
|
+
self.lv['zmax'] = zmax
|
|
1012
|
+
|