AJMR-Python-Baird/EWR_Data/EWR_BathyInterpolation.py

285 lines
13 KiB
Python

## Python Script to Process EWR Bathymetry Data
# AJMR: March 2022
import pandas as pd
import geopandas as gp
import matplotlib.pyplot as plt
import contextily as ctx
import numpy as np
from shapely import geometry, ops
#%% Read in and process centerline shapefile
mapbox = 'https://api.mapbox.com/styles/v1/alexander0042/ckemxgtk51fgp19nybfmdcb1e/tiles/256/{z}/{x}/{y}@2x?access_token=pk.eyJ1IjoiYWxleGFuZGVyMDA0MiIsImEiOiJjazVmdG4zbncwMHY4M2VrcThwZGUzZDFhIn0.w6oDHoo1eCeRlSBpwzwVtw'
river_centerline = gp.read_file('//srv-ott3/Projects/12828.101 English Wabigoon River/03_Data/02_Physical/16_Waterline/Centerline_for_Modelling_merge_UTMZ15.shp')
river_centerlineExploded = river_centerline.explode(ignore_index=True)
tempMulti = river_centerlineExploded.iloc[[4, 3, 1, 2], 1]
# Put the sub-line coordinates into a list of sublists
outcoords = [list(i.coords) for i in tempMulti]
# Flatten the list of sublists and use it to make a new line
river_centerline_merge = geometry.LineString([i for sublist in outcoords for i in sublist])
river_centerline_merge_gpd = gp.GeoSeries(river_centerline_merge)
# Interpolate the centerline to every 25 m
distance_delta = 25
distances = np.arange(0, river_centerline_merge.length, distance_delta)
points = [river_centerline_merge.interpolate(distance) for distance in distances] + [river_centerline_merge.boundary[1]]
# multipoint = ops.unary_union(points)
interpolated_centerline = geometry.LineString(points)
# Turn the linestring into a geodataframe and add distance
# river_centerline_merge_gpd2 =\
# gp.GeoDataFrame(geometry=gp.points_from_xy(
# river_centerline_merge.xy[0], river_centerline_merge.xy[1], crs="EPSG:32615"))
#
# river_centerline_merge_gpd2['Distance'] = river_centerline_merge_gpd2.distance(river_centerline_merge_gpd2.shift(1))
# river_centerline_merge_gpd2.loc[0, 'Distance'] = 0
#
# river_centerline_merge_gpd2['RiverKM'] = river_centerline_merge_gpd2['Distance'].cumsum()
# Turn interpolated inestring into a geodataframe and add distance
river_centerline_merge_gpd3 = \
gp.GeoDataFrame(geometry=gp.points_from_xy(
interpolated_centerline.xy[0], interpolated_centerline.xy[1]), crs="EPSG:32615")
river_centerline_merge_gpd3['Distance'] = river_centerline_merge_gpd3.distance(river_centerline_merge_gpd3.shift(1))
river_centerline_merge_gpd3.loc[0, 'Distance'] = 0
river_centerline_merge_gpd3['RiverKM'] = river_centerline_merge_gpd3['Distance'].cumsum()
#%% Read in the processed waterline shapefile
river_edges = gp.read_file('//srv-ott3/Projects/12828.101 English Wabigoon River/03_Data/02_Physical/16_Waterline/WaterlineToLines_Grass_Simple5m_RevB.shp')
# Interpolate the edges to every 10 m
distance_delta = 10
distances = np.arange(0, river_edges.geometry[0].length, distance_delta)
points = [river_edges.geometry[0].interpolate(distance) for distance in distances] + [river_edges.geometry[0].boundary[1]]
# multipoint = ops.unary_union(points)
interpolated_edges = geometry.LineString(points)
# Create geodataframes for south edge
river_edges_south = \
gp.GeoDataFrame(geometry=gp.points_from_xy(
interpolated_edges.xy[0], interpolated_edges.xy[1]), crs="EPSG:32615")
river_edges_south['SouthBoundary'] = river_edges_south['geometry']
# Interpolate the edges to every 10 m North
distances = np.arange(0, river_edges.geometry[1].length, distance_delta)
points = [river_edges.geometry[1].interpolate(distance) for distance in distances] + [river_edges.geometry[1].boundary[1]]
# multipoint = ops.unary_union(points)
interpolated_edges = geometry.LineString(points)
# Create geodataframes for North edge
river_edges_north = \
gp.GeoDataFrame(geometry=gp.points_from_xy(
interpolated_edges.xy[0], interpolated_edges.xy[1]), crs="EPSG:32615")
river_edges_north['NorthBoundary'] = river_edges_north['geometry']
# river_edges_south = \
# gp.GeoDataFrame(geometry=gp.points_from_xy(
# river_edges.loc[0, 'geometry'].xy[0], river_edges.loc[0, 'geometry'].xy[1]), crs="EPSG:32615")
# river_edges_south['SouthBoundary'] = river_edges_south['geometry']
# river_edges_north = \
# gp.GeoDataFrame(geometry=gp.points_from_xy(
# river_edges.loc[1, 'geometry'].xy[0], river_edges.loc[1, 'geometry'].xy[1]), crs="EPSG:32615")
# river_edges_north['NorthBoundary'] = river_edges_north['geometry']
#%% Plot the centerline and the waterline
fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(20, 14))
fig.patch.set_facecolor('white')
axes.set_xlim(350000, 520000)
axes.set_ylim(5510000, 5580000)
axes.set_xlim(505438, 508368)
axes.set_ylim(5518465, 5520152)
ctx.add_basemap(axes, source=mapbox, crs='EPSG:32615')
# river_centerlineExploded.loc[[0], 'geometry'].plot(ax=axes, color='tab:blue')
# river_centerlineExploded.loc[[1], 'geometry'].plot(ax=axes, color='tab:orange')
# river_centerlineExploded.loc[[2], 'geometry'].plot(ax=axes, color='tab:green')
# river_centerlineExploded.loc[[3], 'geometry'].plot(ax=axes, color='tab:red')
# river_centerlineExploded.loc[[4], 'geometry'].plot(ax=axes, color='tab:purple')
river_edges.loc[[0], 'geometry'].plot(ax=axes, color='tab:red', linestyle='-')
river_edges.loc[[1], 'geometry'].plot(ax=axes, color='tab:orange', linestyle='-')
#
# river_centerline_merge_gpd.plot(ax=axes, marker='s')
#
# river_centerline_merge_gpd2.plot(ax=axes, column='RiverKM', marker='o')
#
river_centerline_merge_gpd3.plot(ax=axes, column='RiverKM', marker='^')
plt.show()
#%% Find the closest point on the centerline to the North and South waterlines
river_centerline_Bounds = river_centerline_merge_gpd3.sjoin_nearest(river_edges_south, how='left', distance_col='South_Distance')
# Remove Index Right Column
river_centerline_Bounds = river_centerline_Bounds.drop(['index_right'], axis=1)
river_centerline_Bounds = river_centerline_Bounds.sjoin_nearest(river_edges_north, how='left', distance_col='North_Distance')
river_centerline_Bounds = river_centerline_Bounds.drop(['index_right'], axis=1)
#%% Add points to cenetrline gdf at 10,10,90% of the distance between the two waterline points through the centerline
# Take x and y for south distances from centerline
for t_percent in range(10, 100, 10):
transect_name = 'transectSouth_' + str(t_percent)
river_centerline_Bounds[transect_name] = gp.points_from_xy((river_centerline_Bounds.geometry.x -
river_centerline_Bounds['SouthBoundary'].x) * t_percent * 0.01 + river_centerline_Bounds['SouthBoundary'].x,
(river_centerline_Bounds.geometry.y -
river_centerline_Bounds['SouthBoundary'].y) * t_percent * 0.01 + river_centerline_Bounds['SouthBoundary'].y,
crs="EPSG:32615")
# Take x and y for north distances from centerline
for t_percent in range(10, 100, 10):
transect_name = 'transectNorth_' + str(t_percent)
river_centerline_Bounds[transect_name] = gp.points_from_xy((river_centerline_Bounds.geometry.x -
river_centerline_Bounds['NorthBoundary'].x) * t_percent * 0.01 + river_centerline_Bounds['NorthBoundary'].x,
(river_centerline_Bounds.geometry.y -
river_centerline_Bounds['NorthBoundary'].y) * t_percent * 0.01 + river_centerline_Bounds['NorthBoundary'].y,
crs="EPSG:32615")
#%% Plotting Check
fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(20, 14))
fig.patch.set_facecolor('white')
axes.set_xlim(505438, 508368)
axes.set_ylim(5518465, 5520152)
ctx.add_basemap(axes, source=mapbox, crs='EPSG:32615')
for t_percent in range(10, 100, 10):
transect_name = 'transectSouth_' + str(t_percent)
river_centerline_Bounds.loc[1:500, transect_name].plot(ax=axes)
transect_name = 'transectNorth_' + str(t_percent)
river_centerline_Bounds.loc[1:500, transect_name].plot(ax=axes)
river_edges.loc[[0], 'geometry'].plot(ax=axes, color='k', linestyle='-')
river_edges.loc[[1], 'geometry'].plot(ax=axes, color='k', linestyle='-')
river_centerline_merge_gpd.plot(ax=axes, color='k')
river_centerline_merge_gpd3.plot(ax=axes, column='RiverKM', marker='^', color='k')
plt.show()
#%% Read in bathymetry observations
bathy_obs = pd.read_csv('//oak-inundation/D/12828.101 EWR_Delft3FM_MTB/Bathy/combined_ZeroRemoved_RevC.xyz',
delim_whitespace=True, header=None, names=['x', 'y', 'z'])
# Create geodataframe
bathy_obs_gdf = gp.GeoDataFrame(bathy_obs, geometry=gp.points_from_xy(
bathy_obs.x, bathy_obs.y), crs="EPSG:32615")
bathy_obs_gdf = bathy_obs_gdf.drop(['x', 'y'], axis=1)
#%% Find the closest point (to a 50 m max) on the transects to observations
river_transect_bathy = dict()
# Does not include 0% or 100%
for t_percent in range(10, 100, 10):
# Set geometry to specific transectfor merge
transect_name = 'transectSouth_' + str(t_percent)
transect_merge_tmp = river_centerline_Bounds.loc[:, ['RiverKM', transect_name]]
transect_merge_tmp.set_geometry(transect_name, inplace=True)
# Create buffered polygons around transect lines
transect_buffer = geometry.LineString(transect_merge_tmp.geometry).buffer(2.5, resolution=8)
transect_buffer_gdf = gp.GeoDataFrame(geometry=[transect_buffer], crs="EPSG:32615")
# Find observations within buffered polygons
bathy_obs_gdf_tmp = bathy_obs_gdf.sjoin(transect_buffer_gdf, how='inner', predicate='within')
bathy_obs_gdf_tmp = bathy_obs_gdf_tmp.drop(['index_right'], axis=1)
river_transect_bathy[transect_name] = transect_merge_tmp.sjoin_nearest(bathy_obs_gdf_tmp, how='left', max_distance=50)
river_transect_bathy[transect_name] = river_transect_bathy[transect_name].drop(['index_right'], axis=1)
bathy_obs_gdf_tmp = []
# # Rename bathy column and drop index
# river_centerline_Bounds.rename(columns={'z': transect_name + '_z'}, inplace=True)
# river_centerline_Bounds = river_centerline_Bounds.drop(['index_right'], axis=1)
# Repeat for North transect
transect_name = 'transectNorth_' + str(t_percent)
transect_merge_tmp = river_centerline_Bounds.loc[:, ['RiverKM', transect_name]]
transect_merge_tmp.set_geometry(transect_name, inplace=True)
transect_buffer = geometry.LineString(transect_merge_tmp.geometry).buffer(2.5, resolution=8)
transect_buffer_gdf = gp.GeoDataFrame(geometry=[transect_buffer], crs="EPSG:32615")
bathy_obs_gdf_tmp = bathy_obs_gdf.sjoin(transect_buffer_gdf, how='inner', predicate='within')
bathy_obs_gdf_tmp = bathy_obs_gdf_tmp.drop(['index_right'], axis=1)
river_transect_bathy[transect_name] = transect_merge_tmp.sjoin_nearest(bathy_obs_gdf_tmp, how='left', max_distance=50)
river_transect_bathy[transect_name] = river_transect_bathy[transect_name].drop(['index_right'], axis=1)
bathy_obs_gdf_tmp = []
# # Rename bathy column and drop index
# river_centerline_Bounds.rename(columns={'z': transect_name + '_z'}, inplace=True)
# river_centerline_Bounds = river_centerline_Bounds.drop(['index_right'], axis=1)
print(t_percent)
#%% Plotting Check
fig, axes = plt.subplots(nrows=1, ncols=1, figsize=(20, 14))
fig.patch.set_facecolor('white')
axes.set_xlim(505438, 508368)
axes.set_ylim(5518465, 5520152)
ctx.add_basemap(axes, source=mapbox, crs='EPSG:32615')
bathy_obs_gdf.loc[:, :].plot(ax=axes, column='z', vmin=320, vmax=350, marker='^')
for t_percent in range(10, 100, 10):
transect_name = 'transectSouth_' + str(t_percent)
river_transect_bathy[transect_name].loc[1:500, :].plot(ax=axes, column='z', vmin=320, vmax=350)
transect_name = 'transectNorth_' + str(t_percent)
river_transect_bathy[transect_name].loc[1:500, :].plot(ax=axes, column='z', vmin=320, vmax=350)
plt.show()
#%% Merge the lines to 1D profile and save as csv
bathy_FileName = 'C:/Users/arey/files/Projects/Grassy Narrows/Bathymetry/AJMR_Interpolated_bathy_25m.xyz'
shape_FileName = 'C:/Users/arey/files/Projects/Grassy Narrows/Bathymetry/'
# bathy_FileName = '//oak-inundation/D/12828.101 EWR_Delft3FM_MTB/Bathy/AJMR_Interpolated_bathy_10m.xyz'
for t_percent in range(10, 100, 10):
transect_name = 'transectSouth_' + str(t_percent)
# Convert to numpy array
bathyNP = np.vstack((river_transect_bathy[transect_name].geometry.x.values,
river_transect_bathy[transect_name].geometry.y.values,
river_transect_bathy[transect_name].z.values))
# Transpose
bathyNP = bathyNP.T
# Save using pandas
pd.DataFrame(bathyNP[~np.isnan(bathyNP[:, 2]), :]).to_csv(bathy_FileName, sep=' ', header=False, index=False, mode='a')
# Write to shape
# river_transect_bathy[transect_name].to_file(shape_FileName + transect_name + '.shp')
# Repeat for North transect
transect_name = 'transectNorth_' + str(t_percent)
bathyNP = np.vstack((river_transect_bathy[transect_name].geometry.x.values,
river_transect_bathy[transect_name].geometry.y.values,
river_transect_bathy[transect_name].z.values))
bathyNP = bathyNP.T
pd.DataFrame(bathyNP[~np.isnan(bathyNP[:, 2]), :]).to_csv(bathy_FileName, sep=' ', header=False, index=False, mode='a')
# river_transect_bathy[transect_name].to_file(shape_FileName + transect_name)