-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathusgs_stations_json_csv.py
More file actions
152 lines (124 loc) · 5.08 KB
/
Copy pathusgs_stations_json_csv.py
File metadata and controls
152 lines (124 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import pandas as pd
def read_usgs_json(json_path):
'''
Read USGS stations.json file and extract stations recorded values and
their associated uncertainty.
'''
# Read file using pandas
with open(json_path) as f:
sj = json.load(f)
stations = pd.json_normalize(sj, 'features')
stations['eventid'] = sj['metadata']['eventid']
# Rename columns
stations.columns = [col.replace('properties.','') for col in stations.columns]
# Extract lon and lat
stations[['lon', 'lat']] = pd.DataFrame(
stations['geometry.coordinates'].to_list())
# Get values for available IMTs (PGA and SA)
# ==========================================
# The "channels/amplitudes" dictionary contains the values recorded at
# the seismic stations. The values could report the 3 components, in such
# cases, take the componet with maximum PGA (and in absence of PGA, the
# first IM reported).
channels = pd.DataFrame(stations.channels.to_list())
vals = pd.Series([], dtype = 'object')
for row, rec_station in channels.iterrows():
rec_station.dropna(inplace=True)
# Iterate over different columns. Each colum can be a component
data = []
pgas = []
for _, chan in rec_station.items():
try:
if chan["name"].endswith("Z") or chan["name"].endswith("U"):
continue
# print(chan["name"])
df = pd.DataFrame(chan["amplitudes"])
if 'pga' in df.name.unique():
pga = df.loc[df['name']=='pga','value'].values[0]
else:
pga = df['value'][0]
if pga is None or pga == "null":
continue
elif isinstance(pga, str):
pga = float(pga)
pgas.append(pga)
data.append(chan["amplitudes"])
except TypeError:
print('boh')
# get values for maximum component
if pgas:
max_componet = pgas.index(max(pgas))
vals[row] = data[max_componet]
else:
vals[row] = None
# The "pgm_from_mmi" dictionary contains the values estimated from MMI.
# Combine both dictionaries to extract the values.
# They are generally mutually exclusive (if mixed, the priority is given
# to the station recorded data).
try:
# Some events might not have macroseismic data, then skip them
vals = vals.combine_first(stations['pgm_from_mmi']).apply(pd.Series)
except Exception as e:
print(e, 'not available in json')
vals = vals.apply(pd.Series)
# Arrange columns since the data can include mixed positions for the IMTs
values = pd.DataFrame()
for col in vals.columns:
df = vals[col].apply(pd.Series)
df.set_index(['name'], append=True, inplace=True)
df.drop(columns=['flag', 'units'], inplace=True)
if 0 in df.columns:
df.drop(columns=[0], inplace=True)
df = df.unstack('name')
df.dropna(axis=1, how='all', inplace=True)
df.columns = [col[1]+'_'+col[0] for col in df.columns.values]
for col in df.columns:
if col in values:
# Colum already exist. Combine values in unique column
values[col] = values[col].combine_first(df[col])
else:
values = pd.concat([values, df[col]], axis=1)
values.sort_index(axis=1, inplace=True)
# Add recording to main DataFrame
stations = pd.concat([stations, values], axis=1)
return stations
def json_to_ecd(stations):
'''
Adjust USGS format to match the ECD (Earthquake Consequence Database)
format
'''
# Adjust column names to match format
stations.columns = stations.columns.str.upper()
stations.rename(columns={
'CODE': 'STATION_ID',
'NAME': 'STATION_NAME',
'LON': 'LONGITUDE',
'LAT': 'LATITUDE',
'INTENSITY': 'MMI_VALUE',
'INTENSITY_STDDEV': 'MMI_STDDEV',
}, inplace=True)
# Identify columns for IMTs:
imts = []
for col in stations.columns:
if 'DISTANCE_STDDEV' == col:
continue
elif '_VALUE' in col or '_LN_SIGMA' in col or '_STDDEV' in col:
imts.append(col)
# Identify relevant columns
cols = ['STATION_ID', 'STATION_NAME', 'LONGITUDE', 'LATITUDE',
'STATION_TYPE', 'VS30'] + imts
df = stations[cols].copy()
# Add missing columns
df.loc[:, 'VS30_TYPE'] = 'inferred'
df.loc[:, 'REFERENCES']= 'Stations_USGS'
# Adjust PGA and SA untis to [g]. USGS uses [% g]
adj_cols = [item for item in imts
if '_VALUE' in item and
'PGV' not in item and
'MMI' not in item]
df.loc[:, adj_cols] = round(df.loc[:, adj_cols].
apply(pd.to_numeric, errors='coerce') / 100, 6)
return df