Skip to content

Commit e452dfb

Browse files
yvonnefroehlichmichaelgrundseisman
authored
Add a tutorial for plotting focal mechanisms (beachballs) (#2550)
Co-authored-by: Michael Grund <[email protected]> Co-authored-by: Dongdong Tian <[email protected]>
1 parent ee2f5f6 commit e452dfb

File tree

1 file changed

+327
-0
lines changed

1 file changed

+327
-0
lines changed
Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
"""
2+
Plotting focal mechanisms
3+
=========================
4+
5+
Focal mechanisms can be plotted as beachballs with the :meth:`pygmt.Figure.meca` method.
6+
7+
The focal mechanism data or parameters can be provided as various input types: ASCII
8+
file, :class:`numpy.array`, dictionary, or :class:`pandas.Dataframe`. Different
9+
conventions to define the focal mechanism are supported: Aki and Richards (``"aki"``),
10+
global CMT (``"gcmt"``), moment tensor (``"mt"``), partial focal mechanism
11+
(``"partial"``), and, principal axis (``"principal_axis"``). Please refer to the table
12+
in the documentation of :meth:`pygmt.Figure.meca` regarding how to set up the input data
13+
in respect to the chosen input type and convention (i.e., the expected column order,
14+
keys, or column names). In this tutorial we focus on how to adjust the display of the
15+
beachballs.
16+
"""
17+
18+
# %%
19+
import pandas as pd
20+
import pygmt
21+
22+
# Set up arguments for basemap
23+
region = [-5, 5, -5, 5]
24+
projection = "X10c/4c"
25+
frame = ["af", "+ggray90"]
26+
27+
28+
# %%
29+
# Setting up the focal mechanism data
30+
# -----------------------------------
31+
#
32+
# We store focal mechanism parameters for two single events in dictionaries using the
33+
# moment tensor and Aki and Richards conventions:
34+
35+
# moment tensor convention
36+
mt_single = {
37+
"mrr": 4.71,
38+
"mtt": 0.0381,
39+
"mff": -4.74,
40+
"mrt": 0.399,
41+
"mrf": -0.805,
42+
"mtf": -1.23,
43+
"exponent": 24,
44+
}
45+
# Aki and Richards convention
46+
aki_single = {"strike": 318, "dip": 89, "rake": -179, "magnitude": 7.75}
47+
48+
49+
# %%
50+
# Plotting a single beachball
51+
# ---------------------------
52+
#
53+
# Required parameters are ``spec`` and ``scale`` as well as ``longitude``, ``latitude``
54+
# (event location), and depth (if these values are not included in the argument passed
55+
# to ``spec``). Additionally, the ``convention`` parameter is required if ``spec`` is
56+
# an 1-D or 2-D numpy array; for the input types dictionary and ``pandas.Dataframe``,
57+
# the focal mechanism convention is automatically determined from dictionary keys or
58+
# :class:`pandas.DataFrame` column names. The ``scale`` parameter controls the radius
59+
# of the beachball. By default, the value defines the size for a magnitude of 5 (i.e.,
60+
# a scalar seismic moment of :math:`M_0 = 4.0 \times 10^{23}` dyn cm) and the beachball
61+
# size is proportional to the magnitude. Append ``"+l"`` to force the radius to be
62+
# proportional to the seismic moment.
63+
64+
fig = pygmt.Figure()
65+
fig.basemap(region=region, projection=projection, frame=frame)
66+
67+
fig.meca(spec=mt_single, scale="1c", longitude=0, latitude=0, depth=0)
68+
69+
fig.show()
70+
71+
72+
# %%
73+
# Plotting the components of a seismic moment tensor
74+
# --------------------------------------------------
75+
#
76+
# A moment tensor can be decomposed into isotropic and deviatoric parts. The deviatoric
77+
# part can be further decomposed into multiple parts (e.g., a double couple (DC) and a
78+
# compensated linear vector dipole (CLVD)). Use the ``component`` parameter to specify
79+
# the component you want to plot.
80+
81+
fig = pygmt.Figure()
82+
fig.basemap(region=region, projection=projection, frame=frame)
83+
84+
for component, longitude in zip(["full", "dc", "deviatoric"], [-2, 0, 2], strict=True):
85+
fig.meca(
86+
spec=mt_single,
87+
scale="1c",
88+
longitude=longitude,
89+
latitude=0,
90+
depth=0,
91+
component=component,
92+
)
93+
94+
fig.show()
95+
96+
97+
# %%
98+
# Filling the quadrants
99+
# ---------------------
100+
#
101+
# Use the parameters ``compressionfill`` and ``extensionfill`` to fill the quadrants
102+
# with different colors or patterns. Regarding patterns see the gallery example
103+
# :doc:`Bit and hachure patterns </gallery/symbols/patterns>` and the Technical
104+
# Reference :doc:`Bit and hachure patterns </techref/patterns>`.
105+
106+
fig = pygmt.Figure()
107+
fig.basemap(region=region, projection=projection, frame=frame)
108+
109+
fig.meca(
110+
spec=mt_single,
111+
scale="1c",
112+
longitude=-2,
113+
latitude=0,
114+
depth=0,
115+
compressionfill="darkorange",
116+
extensionfill="cornsilk",
117+
)
118+
119+
fig.meca(
120+
spec=mt_single,
121+
scale="1c",
122+
longitude=2,
123+
latitude=0,
124+
depth=0,
125+
compressionfill="p8",
126+
extensionfill="p31",
127+
outline=True,
128+
)
129+
130+
fig.show()
131+
132+
133+
# %%
134+
# Adjusting the outlines
135+
# ----------------------
136+
#
137+
# Use the parameters ``pen`` and ``outline`` for adjusting the circumference of the
138+
# beachball or all lines (i.e, circumference and both nodal planes).
139+
140+
fig = pygmt.Figure()
141+
fig.basemap(region=region, projection=projection, frame=frame)
142+
143+
fig.meca(
144+
spec=aki_single,
145+
scale="1c",
146+
longitude=-2,
147+
latitude=0,
148+
depth=0,
149+
# Use a 1-point thick, darkorange and solid line
150+
pen="1p,darkorange",
151+
)
152+
153+
fig.meca(
154+
spec=aki_single,
155+
scale="1c",
156+
longitude=2,
157+
latitude=0,
158+
depth=0,
159+
outline="1p,darkorange",
160+
)
161+
162+
fig.show()
163+
164+
165+
# %%
166+
# Highlighting the nodal planes
167+
# -----------------------------
168+
#
169+
# Use the parameter ``nodal`` to highlight specific nodal planes. ``"0"`` refers to
170+
# both, ``"1"`` to the first, and ``"2"`` to the second nodal plane(s). Only the
171+
# circumference and the specified nodal plane(s) are plotted, i.e. the quadrants
172+
# remain unfilled (transparent). We can make use of the stacking concept of (Py)GMT,
173+
# and use ``nodal`` in combination with the ``outline``, ``compressionfill`` /
174+
# ``extensionfill`` and ``pen`` parameters.
175+
176+
fig = pygmt.Figure()
177+
fig.basemap(region=region, projection=projection, frame=frame)
178+
179+
fig.meca(
180+
spec=aki_single,
181+
scale="1c",
182+
longitude=-2,
183+
latitude=0,
184+
depth=0,
185+
nodal="0/1p,black",
186+
)
187+
188+
# Plot the same beachball three times with different settings:
189+
# (i) Fill the compressive quadrants
190+
# (ii) Plot the first nodal plane and the circumference in darkorange
191+
# (iii) Plot the circumfence in black on top; use "-" to not fill the quadrants
192+
for kwargs in [
193+
{"compressionfill": "lightorange"},
194+
{"nodal": "1/1p,darkorange"},
195+
{"compressionfill": "-", "extensionfill": "-", "pen": "1p,gray30"},
196+
]:
197+
fig.meca(
198+
spec=aki_single,
199+
scale="1c",
200+
longitude=0,
201+
latitude=0,
202+
depth=0,
203+
**kwargs,
204+
)
205+
fig.show()
206+
207+
208+
# %%
209+
# Adding offset from event location
210+
# ---------------------------------
211+
#
212+
# Specify the optional parameters ``plot_longitude`` and ``plot_latitude``. If ``spec``
213+
# is an ASCII file with columns for ``plot_longitude`` and ``plot_latitude``, the
214+
# ``offset`` parameter has to be set to ``True``. Besides just drawing a line between
215+
# the beachball and the event location, a small circle can be plotted at the event
216+
# location by appending **+s** and the descired circle diameter. The connecting line as
217+
# well as the outline of the circle are plotted with the setting of pen, or can be
218+
# adjusted separately. The fill of the small circle corresponds to the fill of the
219+
# compressive quadrantes.
220+
221+
fig = pygmt.Figure()
222+
fig.basemap(region=region, projection=projection, frame=frame)
223+
224+
fig.meca(
225+
spec=aki_single,
226+
scale="1c",
227+
longitude=-1,
228+
latitude=0,
229+
depth=0,
230+
plot_longitude=-3,
231+
plot_latitude=2,
232+
)
233+
234+
fig.meca(
235+
spec=aki_single,
236+
scale="1c",
237+
longitude=3,
238+
latitude=0,
239+
depth=0,
240+
plot_longitude=1,
241+
plot_latitude=2,
242+
offset="+p1p,darkorange+s0.25c",
243+
compressionfill="lightorange",
244+
)
245+
246+
fig.show()
247+
248+
249+
# %%
250+
# Plotting multiple beachballs
251+
# ----------------------------
252+
#
253+
# Now we want to plot multiple beachballs with one call of :meth:`pygmt.Figure.meca`. We
254+
# use data of four earthquakes taken from USGS. For each focal mechanism parameter a
255+
# list with a length corresponding to the number of events has to be given.
256+
257+
# Set up a pandas.DataFrame with multiple focal mechanism parameters.
258+
aki_multiple = pd.DataFrame(
259+
{
260+
"strike": [255, 173, 295, 318],
261+
"dip": [70, 68, 79, 89],
262+
"rake": [20, 83, -177, -179],
263+
"magnitude": [7.0, 5.8, 6.0, 7.8],
264+
"longitude": [-72.53, -79.61, 69.46, 37.01],
265+
"latitude": [18.44, 0.90, 33.02, 37.23],
266+
"depth": [13, 19, 4, 10],
267+
"plot_longitude": [-70, -110, 100, 0],
268+
"plot_latitude": [40, 10, 50, 55],
269+
"event_name": [
270+
"Haiti - 2010/01/12",
271+
"Esmeraldas - 2022/03/27",
272+
"Afghanistan - 2022/06/21",
273+
"Syria/Turkey - 2023/02/06",
274+
],
275+
}
276+
)
277+
278+
279+
# %%
280+
# Adding a label
281+
# --------------
282+
#
283+
# Use the optional parameter ``event_name`` to add a label near the beachball, e.g.,
284+
# event name or event date and time. Change the font of the label text by appending
285+
# **+f** and the desired font (size,name,color) to the argument passed to the ``scale``
286+
# parameter. Additionally, the location of the label relative to the beachball [Default
287+
# is ``"TC"``, i.e., Top Center] can be changed by appending **+j** and an offset can
288+
# be applied by appending **+o** with values for *dx*\ /*dy*. Add a colored [Default is
289+
# white] box behind the label via the label ``labelbox``. Force a fixed size of the
290+
# beachball by appending **+m** to the argument passed to the ``scale`` parameter.
291+
292+
fig = pygmt.Figure()
293+
fig.coast(region="d", projection="N10c", land="lightgray", frame=True)
294+
295+
fig.meca(spec=aki_multiple, scale="0.4c+m+f5p", labelbox="white@30", offset="+s0.1c")
296+
297+
fig.show()
298+
299+
300+
# %%
301+
# Using size-coding and color-coding
302+
# ----------------------------------
303+
#
304+
# The beachball can be sized and colored by the quantities given as ``magnitude`` and
305+
# ``depth``, e.g., by moment magnitude or hypocentral depth, respectively. Use the
306+
# parameter ``cmap`` to pass the descired colormap. Now, the fills of the small circles
307+
# indicating the event locations are given by the colormap.
308+
309+
fig = pygmt.Figure()
310+
fig.coast(region="d", projection="N10c", land="lightgray", frame=True)
311+
312+
# Set up colormap and colorbar for hypocentral depth
313+
pygmt.makecpt(cmap="lajolla", series=[0, 20])
314+
fig.colorbar(frame=["x+lhypocentral depth", "y+lkm"])
315+
316+
fig.meca(
317+
spec=aki_multiple,
318+
scale="0.4c+f5p",
319+
offset="0.2p,gray30+s0.1c",
320+
labelbox="white@30",
321+
cmap=True,
322+
outline="0.2p,gray30",
323+
)
324+
325+
fig.show()
326+
327+
# sphinx_gallery_thumbnail_number = 8

0 commit comments

Comments
 (0)