I have spend a lot of time searching for a solution to this but haven't found a decent one yet.
I have a geodataframe with 2D LineStrings between two points and also 2 different Z-values/coordinates per 2D LineString. I want a direct way to add those z-coordinates to the respected LineString-parts. Is there a good way to accomplish this by use ex shapely.ops.transform?? or any other technique?.
I know I can access the LineString x,y coordinates in several ways, build two 3D points and then create a 3D LineString between these two points using x,y,z coordinates, so I'm not searching for all methods. But I want a more direct way to do this than to first create 3D points and then 3D LineString.
I'm also not looking for how to add the a dedicated z-value to a 2D LineString to create a 3D LineString. I need different Z-coordinates on the different part of the LineStrings.
My code:
import pandas as pd
import geopandas as gpd
from shapely import wkt
df = pd.DataFrame(
{
"ID": [1, 2, 3],
"z1": [133.56, 184.84, 230.53],
"z2": [158.66, 212.68, 241.20],
"geometry": [
"LINESTRING (565035.0499992011 6622605.24012313, 565064.889999201 6622483.90012313)",
"LINESTRING (565084.009999201 6622367.28012313, 565101.339999201 6622257.27012313)",
"LINESTRING (565119.8599992 6622140.37012313, 565144.4599992 6621985.04012313)"]
}
)
print(df)
df["geometry"] = gpd.GeoSeries.from_wkt(df["geometry"])
gdf = gpd.GeoDataFrame(df, geometry="geometry")
gdf = gdf.set_crs('epsg:25832')
print(gdf.crs)
print(gdf.dtypes)
print(gdf['geometry'][0])
print(gdf['geometry'][1])
print(gdf['geometry'][2])
gdf
Result: epsg:25832 ID int64 z1 float64 z2 float64 geometry geometry dtype: object
LINESTRING (565035.0499992011 6622605.24012313, 565064.889999201 6622483.90012313)
LINESTRING (565084.009999201 6622367.28012313, 565101.339999201 6622257.27012313)
LINESTRING (565119.8599992 6622140.37012313, 565144.4599992 6621985.04012313)
I want to add the respected z-coordinates so the output geodataframe geometry becomes:
"geometry": [
"LINESTRING Z(565035.0499992011 6622605.24012313 133.56, 565064.889999201 6622483.90012313 158.66)",
"LINESTRING Z(565084.009999201 6622367.28012313 184.84, 565101.339999201 6622257.27012313 212.68)",
"LINESTRING Z(565119.8599992 6622140.37012313 230.53, 565144.4599992 6621985.04012313 241.20)"]
I appreciate any help with this
Regards Lars
I have tried severel shapely.ops.transform codes but none is solving this issue
Following your transform
's idea, you can do it this way :
from shapely import LineString
from shapely.ops import transform
l3d = [
LineString(
(
transform(lambda x, y, z=z1: (x, y, z), p1),
transform(lambda x, y, z=z2: (x, y, z), p2),
)
)
for p1, p2, z1, z2 in gdf.boundary.explode(index_parts=True)
.unstack()
.join(gdf[["z1", "z2"]])
.to_numpy()
]
gdf.geometry = l3d # is a list of LineString Z objects
Output :
>>> l3d
[
<LINESTRING Z (565035.05 6622605.24 133.56, 565064.89 6622483.9 158.66)>,
<LINESTRING Z (565084.01 6622367.28 184.84, 565101.34 6622257.27 212.68)>,
<LINESTRING Z (565119.86 6622140.37 230.53, 565144.46 6621985.04 241.2)>
]
>>> gdf
ID z1 z2 geometry
0 1 133.56 158.66 LINESTRING Z (565035.050 6622605.240 133.560, ...
1 2 184.84 212.68 LINESTRING Z (565084.010 6622367.280 184.840, ...
2 3 230.53 241.20 LINESTRING Z (565119.860 6622140.370 230.530, ...