Skip to content

Commit cf8321e

Browse files
refactor: handling of string fields
1 parent d4a1d7d commit cf8321e

1 file changed

Lines changed: 55 additions & 9 deletions

File tree

m2l/main/vectorLayerWrapper.py

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,68 @@
2323

2424

2525

26+
# def qgsLayerToGeoDataFrame(layer) -> gpd.GeoDataFrame:
27+
# if layer is None:
28+
# return None
29+
# features = layer.getFeatures()
30+
# fields = layer.fields()
31+
# data = {'geometry': []}
32+
# for f in fields:
33+
# data[f.name()] = []
34+
# for feature in features:
35+
# geom = feature.geometry()
36+
# if geom.isEmpty():
37+
# continue
38+
# data['geometry'].append(geom)
39+
# for f in fields:
40+
# data[f.name()].append(feature[f.name()])
41+
# return gpd.GeoDataFrame(data, crs=layer.crs().authid())
42+
2643
def qgsLayerToGeoDataFrame(layer) -> gpd.GeoDataFrame:
44+
"""
45+
Convert a QgsVectorLayer to a GeoDataFrame with:
46+
- Shapely geometries
47+
- Pandas nullable string dtype for QGIS string fields
48+
"""
2749
if layer is None:
2850
return None
29-
features = layer.getFeatures()
51+
3052
fields = layer.fields()
31-
data = {'geometry': []}
32-
for f in fields:
33-
data[f.name()] = []
34-
for feature in features:
35-
geom = feature.geometry()
53+
string_field_names = {
54+
f.name() for f in fields
55+
if f.type() in (QVariant.String,) # extend here if you use other text types
56+
}
57+
58+
rows = []
59+
for feat in layer.getFeatures():
60+
geom = feat.geometry()
3661
if geom.isEmpty():
3762
continue
38-
data['geometry'].append(geom)
63+
64+
row = {"geometry": wkb_loads(geom.asWkb())}
3965
for f in fields:
40-
data[f.name()].append(feature[f.name()])
41-
return gpd.GeoDataFrame(data, crs=layer.crs().authid())
66+
val = feat[f.name()]
67+
# Normalize None in string cols to pandas.NA so StringDtype works cleanly
68+
if f.name() in string_field_names:
69+
row[f.name()] = pd.NA if val is None else str(val)
70+
else:
71+
row[f.name()] = val
72+
rows.append(row)
73+
74+
if not rows:
75+
# Empty GeoDataFrame with correct schema & crs
76+
gdf = gpd.GeoDataFrame(columns=["geometry"] + [f.name() for f in fields],
77+
geometry="geometry",
78+
crs=layer.crs().authid())
79+
else:
80+
gdf = gpd.GeoDataFrame(rows, geometry="geometry", crs=layer.crs().authid())
81+
82+
# Enforce pandas' nullable string dtype on QGIS string fields
83+
for name in string_field_names:
84+
if name in gdf.columns:
85+
gdf[name] = gdf[name].astype("string")
86+
87+
return gdf
4288

4389

4490
def qgsLayerToDataFrame(layer, dtm) -> pd.DataFrame:

0 commit comments

Comments
 (0)