Skip to content

Commit c408ff3

Browse files
authored
added burst plotting script (#45)
* added burst plotting to multiple formats script
1 parent 5989526 commit c408ff3

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed

src/s1reader/utils/plot_bursts.py

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import argparse
2+
import glob
3+
from importlib import import_module
4+
import os
5+
import sys
6+
7+
named_libs = [('fiona', 'fiona'), ('geopandas', 'gpd'), ('pandas', 'pd')]
8+
9+
for (name, short) in named_libs:
10+
try:
11+
lib = import_module(name)
12+
except:
13+
print(sys.exc_info())
14+
else:
15+
globals()[short] = lib
16+
17+
from osgeo import osr
18+
from shapely.geometry import Polygon
19+
from shapely import wkt
20+
21+
from s1reader.s1_orbit import get_orbit_file_from_list
22+
from s1reader.s1_reader import load_bursts
23+
24+
25+
def command_line_parser():
26+
'''
27+
Command line parser
28+
'''
29+
parser = argparse.ArgumentParser(description="""
30+
Create a burst map for a single slc""",
31+
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
32+
parser.add_argument('-s', '--slc', type=str, action='store',
33+
dest='slc',
34+
help="slc to map")
35+
parser.add_argument('-d', '--orbit-dir', type=str, dest='orbit_dir',
36+
help="Directory containing orbit files")
37+
parser.add_argument('-x', '--x-spacing', type=float, default=5,
38+
dest='x_spacing',
39+
help='Spacing of the geogrid in x direction')
40+
parser.add_argument('-y', '--y-spacing', type=float, default=10,
41+
dest='y_spacing',
42+
help='Spacing of the geogrid in y direction')
43+
parser.add_argument('-e', '--epsg', type=int, dest='epsg',
44+
help='EPSG for output coordinates')
45+
parser.add_argument('-o', '--output', type=str, default='burst_map.gpkg',
46+
dest='output',
47+
help='Base filename for all output burst map products')
48+
return parser.parse_args()
49+
50+
51+
def burst_map(slc, orbit_dir, x_spacing,
52+
y_spacing, epsg,
53+
output_filename):
54+
"""
55+
Create a CSV of SLC metadata and plot bursts
56+
Parameters:
57+
slc: str
58+
Path to SLC file
59+
orbit_dir: str
60+
Path to directory containing orbit files
61+
x_spacing: float
62+
Spacing of the geogrid in the x direction
63+
y_spacing: float
64+
Spacing to the geogrid in the y direction
65+
epsg: int
66+
EPSG code for the output coodrdinates
67+
output_filename: str
68+
Filename used for the output CSV, shp, html, and kml files
69+
70+
Returns:
71+
output_filename.csv, output_filename.shp, output_filename.html, output_filename.kml
72+
"""
73+
74+
# Initialize dictionary that will contain all the info for geocoding
75+
burst_map = {'burst_id':[], 'length': [], 'width': [],
76+
'spacing_x': [], 'spacing_y':[], 'min_x': [],
77+
'max_x': [], 'min_y': [], 'max_y': [], 'first_valid_line': [],
78+
'last_valid_line':[], 'first_valid_sample':[], 'last_valid_sample':[],
79+
'border':[]}
80+
i_subswath = [1, 2, 3]
81+
pol = 'vv'
82+
orbit_list = glob.glob(f'{orbit_dir}/*EOF')
83+
orbit_path = get_orbit_file_from_list(slc, orbit_list)
84+
85+
for subswath in i_subswath:
86+
ref_bursts = load_bursts(slc, orbit_path, subswath, pol)
87+
for burst in ref_bursts:
88+
burst_map['burst_id'].append(burst.burst_id)
89+
burst_map['length'].append(burst.shape[0])
90+
burst_map['width'].append(burst.shape[1])
91+
burst_map['spacing_x'].append(x_spacing)
92+
burst_map['spacing_y'].append(y_spacing)
93+
burst_map['first_valid_line'].append(burst.first_valid_line)
94+
burst_map['last_valid_line'].append(burst.last_valid_line)
95+
burst_map['first_valid_sample'].append(burst.first_valid_sample)
96+
burst_map['last_valid_sample'].append(burst.last_valid_sample)
97+
98+
poly = burst.border[0]
99+
# Give some margin to the polygon
100+
margin = 0.001
101+
poly = poly.buffer(margin)
102+
burst_map['border'].append(Polygon(poly.exterior.coords).wkt)
103+
104+
# Transform coordinates from lat/long to EPSG
105+
llh = osr.SpatialReference()
106+
llh.ImportFromEPSG(4326)
107+
tgt = osr.SpatialReference()
108+
109+
tgt_x, tgt_y = [], []
110+
x, y = poly.exterior.coords.xy
111+
tgt.ImportFromEPSG(int(epsg))
112+
trans = osr.CoordinateTransformation(llh, tgt)
113+
for lx, ly in zip(x, y):
114+
dummy_y, dummy_x, dummy_z = trans.TransformPoint(ly, lx, 0)
115+
tgt_x.append(dummy_x)
116+
tgt_y.append(dummy_y)
117+
118+
if epsg == 4326:
119+
x_min = x_spacing * (min(tgt_x) / x_spacing)
120+
y_min = y_spacing * (min(tgt_y) / y_spacing)
121+
x_max = x_spacing * (max(tgt_x) / x_spacing)
122+
y_max = y_spacing * (max(tgt_y) / y_spacing)
123+
else:
124+
x_min = x_spacing * round(min(tgt_x) / x_spacing)
125+
y_min = y_spacing * round(min(tgt_y) / y_spacing)
126+
x_max = x_spacing * round(max(tgt_x) / x_spacing)
127+
y_max = y_spacing * round(max(tgt_y) / y_spacing)
128+
129+
# Allocate coordinates inside the dictionary
130+
burst_map['min_x'].append(x_min)
131+
burst_map['min_y'].append(y_min)
132+
burst_map['max_x'].append(x_max)
133+
burst_map['max_y'].append(y_max)
134+
135+
# Save generated burst map as csv
136+
data = pd.DataFrame.from_dict(burst_map)
137+
data.to_csv(f'{output_filename}.csv')
138+
139+
# Create GeoDataFrame to plot bursts on a map
140+
df = data
141+
df['border'] = df['border'].apply(wkt.loads)
142+
gdf = gpd.GeoDataFrame(df, crs='epsg:4326')
143+
gdf = gdf.rename(columns={'border': 'geometry'}).set_geometry('geometry')
144+
145+
# Save the GeoDataFrame as a shapefile (some people may prefer the format)
146+
gdf.to_file(f'{output_filename}.shp')
147+
148+
# Save the GeoDataFrame as a kml
149+
kml_path = f'{output_filename}.kml'
150+
if os.path.isfile(kml_path):
151+
os.remove(kml_path)
152+
153+
fiona.supported_drivers['KML'] = 'rw'
154+
gdf.to_file(f'{output_filename}.kml', driver='KML')
155+
156+
157+
# Plot bursts on an interactive map
158+
m = gdf.explore(
159+
column="burst_id", # make choropleth based on "Burst ID" column
160+
tooltip="burst_id", # show "Burst ID" value in tooltip (on hover)
161+
popup=True, # show all values in popup (on click)
162+
tiles="CartoDB positron", # use "CartoDB positron" tiles
163+
cmap="Set1", # use "Set1" matplotlib colormap
164+
style_kwds=dict(color="black") # use black outline
165+
)
166+
167+
m.save(f'{output_filename}.html')
168+
169+
170+
if __name__ == '__main__':
171+
cmd = command_line_parser()
172+
burst_map(cmd.slc, cmd.orbit_dir,
173+
cmd.x_spacing, cmd.y_spacing,
174+
cmd.epsg, cmd.output)

0 commit comments

Comments
 (0)