Skip to content

Commit c6ca191

Browse files
authored
Merge pull request #5 from DIG-Kaust/visual
Added basic data visualization routines
2 parents 8f72c16 + 65bb6a9 commit c6ca191

File tree

4 files changed

+708
-0
lines changed

4 files changed

+708
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ The following notebooks are provided:
2626
- :orange_book: ``acoustic/Modelling_filtering.ipynb``: notebook comparing modelling with a filtered wavelet and filtering of original data computed with unfiltered wavelet;
2727
- :orange_book: ``acoustic/Gradient_comparison.ipynb``: notebook comparing gradients from different objective functions;
2828
- :orange_book: ``acoustic/Gradient_decoupled.ipynb``: notebook comparing gradient computations with mixed computational graphs including a Torch Module (useful to embed NNs in FWI);
29+
- :orange_book: ``acoustic/Data_visualization.ipynb``: notebook showcasing different visualization routines;
2930
- :orange_book: ``acoustic/AcousticVel_L2_1stage.ipynb``: notebook performing acoustic FWI parametrized in velocity with entire data;
3031
- :orange_book: ``acoustic/AcousticVel_L2_1stagewrapper.ipynb``: notebook performing acoustic FWI parametrized in velocity with entire data using AcousticFWI wrapper;
3132
- :orange_book: ``acoustic/AcousticVel_L2torch_1stage.ipynb``: notebook performing acoustic FWI parametrized in velocity with entire data using Torch AD-based objective function;

devitofwi/visual/__init__.py

Whitespace-only changes.

devitofwi/visual/data.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
__all__ = ["display_multiple_gathers",
2+
"display_sidebyside",
3+
]
4+
5+
import numpy as np
6+
import matplotlib.pyplot as plt
7+
8+
9+
def display_multiple_gathers(data, ishots=None, irecs=None,
10+
srcs=None, recs=None, t=None,
11+
figsize=(15, 5), vlims=None, vclip=1.,
12+
cmap='gray', interpolation=None,
13+
titles=None):
14+
"""Display multiple gathers
15+
16+
Display multiple shot or receiver gathers side by side.
17+
18+
Parameters
19+
----------
20+
data : :obj:`numpy.ndarray`
21+
Data of size `ns x nt x nr`
22+
ishots : :obj:`tuple`, optional
23+
Indices of shots to display
24+
(set to `None` to display receiver gathers)
25+
irecs : :obj:`tuple`, optional
26+
Indices of receivers to display
27+
srcs : :obj:`numpy.ndarray`, optional
28+
Source axis of size `ns`
29+
recs : :obj:`numpy.ndarray`, optional
30+
Receiver axis of size `nr`
31+
t : :obj:`numpy.ndarray`, optional
32+
Time axis of size `nt`
33+
figsize : :obj:`tuple`, optional
34+
Figure size
35+
vlims : :obj:`tuple`, optional
36+
Colorbar limits
37+
vclip : :obj:`tuple`, optional
38+
Colorbar clipping to be applied on top of `vlims`
39+
cmap : :obj:`str`, optional
40+
Colormap
41+
interpolation : :obj:`str`, optional
42+
Interpolation in plotting
43+
titles : :obj:`tuple`, optional
44+
Titles to use for the different panels
45+
46+
Returns
47+
-------
48+
fig : :obj:`matplotlib.figure.Figure`
49+
Figure handle
50+
axs : :obj:`list`
51+
Axes handles
52+
53+
"""
54+
# Choose whether to display shot of receiver gathers
55+
xlabel = 'Recs [m]'
56+
titleprefix = 'Shot'
57+
if ishots is None:
58+
data = data.transpose(2, 1, 0)
59+
recs = srcs
60+
ishots = irecs
61+
xlabel = 'Shots [m]'
62+
titleprefix = 'Rec'
63+
64+
# Define axes
65+
recs = (0, data.shape[1]) if recs is None else recs
66+
t = (0, data.shape[2]) if t is None else t
67+
68+
# Define vlims
69+
if vlims is None:
70+
vlims = (-np.abs(data.ravel()).max(), np.abs(data.ravel()).max())
71+
72+
# Display
73+
fig, axs = plt.subplots(1, len(ishots), sharey=True, figsize=figsize)
74+
for ax, ishot in zip(axs, ishots):
75+
ax.imshow(data[ishot], cmap=cmap,
76+
vmin=vclip * vlims[0], vmax=vclip * vlims[1],
77+
extent=(recs[0], recs[-1], t[-1], t[0]),
78+
interpolation=interpolation)
79+
ax.axis('tight')
80+
ax.set_xlabel(xlabel)
81+
ax.set_title(f'{titleprefix} {ishot}' if titles is None else titles[ishot])
82+
axs[0].set_ylabel('Time [s]')
83+
fig.tight_layout()
84+
return fig, axs
85+
86+
87+
def display_sidebyside(data, data1, ishot, srcs, recs, t=None,
88+
figsize=(15, 5), vlims=None, vclip=1.,
89+
cmap='gray', titles=None):
90+
"""Display multiple gathers
91+
92+
Display multiple shot or receiver gathers side by side.
93+
94+
Parameters
95+
----------
96+
data : :obj:`numpy.ndarray`
97+
Data of size `ns x nt x nr`
98+
data : :obj:`numpy.ndarray`
99+
Second data of size `ns x nt x nr`
100+
ishot : :obj:`int`
101+
Index of shot to display
102+
srcs : :obj:`numpy.ndarray`
103+
Source array
104+
recs : :obj:`numpy.ndarray`
105+
Receiver array
106+
t : :obj:`numpy.ndarray`, optional
107+
Time axis of size `nt`
108+
figsize : :obj:`tuple`, optional
109+
Figure size
110+
vlims : :obj:`tuple`, optional
111+
Colorbar limits
112+
vclip : :obj:`tuple`, optional
113+
Colorbar clipping to be applied on top of `vlims`
114+
cmap : :obj:`str`, optional
115+
Colormap
116+
titles : :obj:`tuple`, optional
117+
Titles to use for `data` and `data1`
118+
119+
Returns
120+
-------
121+
fig : :obj:`matplotlib.figure.Figure`
122+
Figure handle
123+
axs : :obj:`list`
124+
Axes handles
125+
126+
"""
127+
# Extract shot gathers
128+
data = data[ishot]
129+
data1 = data1[ishot]
130+
131+
# Define data to display
132+
izerooff = np.argmin(np.abs(srcs[ishot] - recs))
133+
if izerooff > len(recs) // 2:
134+
data = data[:, ::-1]
135+
data1 = data1[:, ::-1]
136+
recs = recs[::-1]
137+
izerooff = len(recs) - izerooff
138+
139+
# Define axes
140+
off = np.abs(srcs[ishot] - recs)
141+
t = (0, data.shape[2]) if t is None else t
142+
143+
# Define vlims
144+
if vlims is None:
145+
vlims = (-np.abs(data.ravel()).max(), np.abs(data.ravel()).max())
146+
147+
# Define titles
148+
titles = (None, None) if titles is None else titles
149+
150+
# Display
151+
fig, axs = plt.subplots(1, 3, figsize=figsize, sharey=True, gridspec_kw=dict(wspace=0))
152+
axs[0].imshow(data[:, izerooff:][:, ::-1], cmap=cmap, vmin=vclip * vlims[0], vmax=vclip * vlims[1],
153+
extent=(off[-1], off[izerooff], t[-1], t[0]))
154+
axs[1].imshow(data1[:, izerooff:], cmap=cmap, vmin=vclip * vlims[0], vmax=vclip * vlims[1],
155+
extent=(off[izerooff], off[-1], t[-1], t[0]))
156+
axs[2].imshow(data[:, izerooff:][:, ::-1], cmap=cmap, vmin=vclip * vlims[0], vmax=vclip * vlims[1],
157+
extent=(off[-1], off[izerooff], t[-1], t[0]))
158+
axs[0].set_title(titles[0])
159+
axs[1].set_title(titles[1])
160+
axs[2].set_title(titles[0])
161+
for ax in axs:
162+
ax.axis('tight')
163+
ax.set_xlabel('Offset [m]')
164+
axs[0].set_ylabel('Time [s]')
165+
return fig, ax

notebooks/acoustic/Data_visualization.ipynb

Lines changed: 542 additions & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)