%pylab inline
from __future__ import print_function
import matplotlib.pylab as plt
plt.style.use('ggplot')
plt.rcParams['figure.figsize'] = 12, 8
import warnings
warnings.filterwarnings("ignore")
from obspy.core import read, UTCDateTime
from obspy import read_inventory, read_events
Funkce read_events
umožňuje načíst eventová metadata uložená v různých formátech do jednotného objektu Catalog
.
Podporované formáty: CMTSOLUTION, FNETMT, GSE2, IMS10BULLETIN, MCHEDR, NDK, NLLOC_HYP, NORDIC, QUAKEML, SC3ML,
SCARDEC, ZMAP.
Načteme soubor easiaa_p_pick.xml
obsahující seznam eventů určených pro pickování teleseismických P vln na stanicích projektu AlpArray-EASI a jeho nejbližšího okolí. Jako zdroj metadat byly použity ISC a NEIC katalogy.
cat = read_events('easiaa_p_pick.xml')
print(cat)
Objekt Catalog
má předdefinováno několik funkcí, základní z nich je plot
pro vykreslení zemětřesných lokací.
plt.rcParams['figure.figsize'] = 12, 8
cat.plot(),
Vybereme jen eventy s magnitudem minimálně 7 a barevně rozlišíme dobu vzniku zemětřesení.
cat.filter('magnitude >= 7').plot(color="date"),
Do obrázku lze začlenit i informaci o poloze stanic, použijeme STATIONXML soubor vytvořený ze stanic ALpArray-EASI. Projekce tentokrát lokální.
cat_eu = cat.filter("latitude >= 30.0", "latitude <= 60.0", "longitude >= -15.0", "longitude <= 30.0")
fig = cat_eu.plot(projection="local", show=False)
inv = read_inventory('XT_all.xml')
inv.plot(fig=fig, label=False, size=50, color_per_network={"XT": "red"}),
Zajímá nás azimutální rozložení eventů. Vybereme prostřední stanici z EASI profilu a napočteme back-azimuty a epicentrální vzdálenosti pro všechny eventy. K tomu poslouží funkce calc_vincenty_inverse
s eliptickou aproximací tvaru Země.
from obspy.geodetics.base import calc_vincenty_inverse, kilometer2degrees
refstat = inv.get_coordinates(seed_id="XT.AAE28.00.HHZ") # souřednice z prostřední stanice v profilu
dists, bazs = [], []
for event in cat:
origin = event.preferred_origin() or event.origins[0] # finta na výběr nejlépe určeného ohniska
[dist_m, az, baz] = calc_vincenty_inverse(origin.latitude, origin.longitude,
refstat['latitude'], refstat['longitude'])
dist = kilometer2degrees(dist_m/1000.)
dists.append(dist); bazs.append(baz)
# vykresli histogramy pro BAZ a EP. DIST
fig = plt.figure(figsize=(14.5,4))
ax1 = fig.add_subplot(1,2,1); ax2 = fig.add_subplot(1,2,2)
ax1.hist(bazs, 36, range=(0,360), facecolor='red', alpha=0.75)
ax2.hist(dists, 30, facecolor='green', alpha=0.75)
ax1.set_xlim(0,360); ax1.set_xticks(range(0,361, 60)); ax2.set_xlim(0,max(dists))
ax1.set_xlabel('back-azimuth [$^\circ$]'); ax2.set_xlabel('epic. distance [$^\circ$]')
beachball
vykreslí ohniskovou koulibeach
to samé, navíc ale s umístěním do mapyMomentový tenzor lze definovat dvěma způsoby:
from obspy.imaging.beachball import beachball
mt1 = [150, 87, 30] # strike, dip, and rake
mt2 = [0.91, -0.89, -0.02, 1.78, -1.55, 0.47] # MOMENT TENSOR:
mt3 = [-2.39, 1.04, 1.35, 0.57, -2.94, -0.94] # M11, M22, M33, M12, M13, M23
beachball(mt1, size=200, linewidth=2, facecolor='b')
beachball(mt2, size=200, linewidth=2, facecolor='r')
beachball(mt3, size=200, linewidth=2, facecolor='g'),
Zatím v ObsPy neexistuje jednoduchý způsob, jak dávkově načíst eventy i s ohniskovými mechanismy. Nejjednoduší řešení je stáhnout si např. z https://www.globalcmt.org celý Harvardský katalog (soubor http://www.ldeo.columbia.edu/~gcmt/projects/CMT/catalog/jan76_dec17.ndk.gz pro období 1976 až 2017) a pomocí jednoduchého skriptu např. v shellu z něj vyfiltrovat požadovanou část.
Funkce read_events
umí načíst eventová metadata i ve formátu ndk
.
cat1 = read_events('GCMT_ALL_30N_50N_000E_030E.ndk')
cat1.plot(projection="local"),
Pro hezčí vykreslení mapy s ohniskovými koulemi jsem převzal a upravil původní skript z https://github.com/qingkaikong/blog/tree/master/15_plot_historical_moment_tensors .
from obspy.imaging.beachball import beach
from mpl_toolkits.basemap import Basemap
from matplotlib.lines import Line2D
def plot_mt(cat, latlons, figsize = (16,24), mt_size = 10, mt_aspect = None,\
pretty = False, resolution='l'):
'''
Plot the historical moment tensor from the query of GCMT
cat - catalog with focal mechanisms (e.g. from GCMT)
latlons - list or tuple form a map domain: lat1, lat2, long1, long2
figsize - tuple of the size of the figure
mt_size - size of the moment tensor on the plot for magnitude 5 (or all, see mt_size_large)
mt_aspect - magnification of large events, magn=8: size = mt_aspect * mt_size
if None, all events have the same size mt_size
pretty - boolean, whether want to plot nice maps
resolution - low or high as you want
'''
llat = float(latlons[0])
ulat = float(latlons[1])
llon = float(latlons[2])
ulon = float(latlons[3])
lats, lons, depths, mts, mags, mt_sizes = [],[],[],[],[],[]
for event in cat:
# jak z objektu Catalog dostat lat, long, depth, magnitude, moment tensor
origin = event.preferred_origin() or event.origins[0]
magnitude = event.preferred_magnitude() or event.magnitudes[0]
focmec = event.preferred_focal_mechanism() or event.focal_mechanisms[0]
tensor = focmec.moment_tensor.tensor
lats.append(origin.latitude)
lons.append(origin.longitude)
mts.append([tensor.m_rr, tensor.m_tt, tensor.m_pp, tensor.m_rt, tensor.m_rp, tensor.m_tp])
depths.append(origin.depth/1000.)
mags.append(magnitude.mag)
if mt_aspect:
# velikost koule úměrná magnitudu
mtsize = max([mt_size * ((mt_aspect-1.)*(magnitude.mag-5.)/3.+1.), mt_size/2.])
mt_sizes.append(mtsize)
else:
mt_sizes.append(mt_size)
plt.figure(figsize=figsize)
m = Basemap(projection='cyl', resolution=resolution,
llcrnrlon=llon,llcrnrlat=llat,urcrnrlon=ulon,urcrnrlat=ulat)
m.drawcoastlines()
m.drawcountries()
if pretty:
m.etopo() # ETOPO podklad
else:
m.drawmapboundary()
m.fillcontinents()
m.drawparallels(np.arange(llat, ulat, (ulat - llat) / 4.0), labels=[1,0,0,0])
m.drawmeridians(np.arange(llon, ulon, (ulon - llon) / 4.0), labels=[0,0,0,1])
ax = plt.gca()
x, y = m(lons, lats)
for i in range(len(mts)):
# barevné rozlišení podle hloubky
if depths[i] <= 50:
color = '#FFA500'
elif depths[i] > 50 and depths[i] <= 100:
color = 'g'
elif depths[i] > 100 and depths[i] <= 200:
color = 'b'
else:
color = 'r'
#note here, if the mrr is zero, then you will have an error
#so, change this to a very small number
if mts[i][0] == 0:
mts[i][0] = 0.001
try:
b = beach(mts[i], xy=(x[i], y[i]),width=mt_sizes[i], linewidth=1, facecolor=color)
except:
pass
b.set_zorder(10)
ax.add_collection(b)
# add the legend
circ1 = Line2D([0], [0], linestyle="none", \
marker="o", alpha=0.6, markersize=10, markerfacecolor="#FFA500")
circ2 = Line2D([0], [0], linestyle="none", \
marker="o", alpha=0.6, markersize=10, markerfacecolor="g")
circ3 = Line2D([0], [0], linestyle="none", \
marker="o", alpha=0.6, markersize=10, markerfacecolor="b")
circ4 = Line2D([0], [0], linestyle="none", \
marker="o", alpha=0.6, markersize=10, markerfacecolor="r")
plt.legend((circ1, circ2, circ3, circ4), \
("depth $\leq$ 50 km", "50 km $<$ depth $\leq$ 100 km", \
"100 km $<$ depth $\leq$ 200 km", "200 km $<$ depth"), \
numpoints=1, loc=3)
plt.show()
return
plot_mt(cat1, latlons=[30,50,0,30], mt_size=0.5, mt_aspect=2, pretty=True),
cat2 = read_events('GCMT_ALL_10S_10N_090W_070W.ndk') # výřez pro SZ Jižní Ameriky
plot_mt(cat2, latlons=[-10,10,-90,-70], figsize = (11,11), mt_size=0.4, mt_aspect=2, pretty=True),
# výřez jen pro AlpArray
#plot_mt(cat1, latlons=[33,42,18,30], mt_size=0.25, mt_aspect=2, pretty=True),