@@ -942,20 +942,20 @@ def zonal_stats(inShp, inRas, band, bandname, layer=None, stat = 'mean',
942
942
src_offset = _bbox_to_pixel_offsets (rgt , geom )
943
943
944
944
#x, y, xcount, ycount - so if counts are 0, the geom is smaller than
945
- # the pixel, so we can give it a shape of 1x1
945
+ # the pixel, so we can give it a shape of 1xninS
946
946
if src_offset [2 ] == 0 :
947
947
src_offset [2 ] = 1
948
948
if src_offset [3 ] == 0 :
949
949
src_offset [3 ] = 1
950
950
951
951
# This does not seem to be fullproof
952
952
# This is a hacky mess that needs fixed
953
- if poly .Contains (geom ) == False :
954
- #print(src_offset[0],src_offset[1])
955
- #offs.append()
956
- feat = vlyr .GetNextFeature ()
957
- continue
958
- elif src_offset [0 ] > rds .RasterXSize :
953
+ # if poly.Contains(geom) == False: # this isn't working -
954
+ # #print(src_offset[0],src_offset[1])
955
+ # #offs.append()
956
+ # feat = vlyr.GetNextFeature()
957
+ # continue
958
+ if src_offset [0 ] > rds .RasterXSize :
959
959
feat = vlyr .GetNextFeature ()
960
960
continue
961
961
elif src_offset [1 ] > rds .RasterYSize :
@@ -1021,7 +1021,7 @@ def zonal_stats(inShp, inRas, band, bandname, layer=None, stat = 'mean',
1021
1021
)
1022
1022
1023
1023
if stat == 'mode' :
1024
- feature_stats = mode (masked ) [0 ]
1024
+ feature_stats = mode (masked , axis = None )[ 0 ] [0 ]
1025
1025
elif stat == 'min' :
1026
1026
feature_stats = float (masked .min ())
1027
1027
elif stat == 'mean' :
@@ -1055,7 +1055,7 @@ def zonal_stats(inShp, inRas, band, bandname, layer=None, stat = 'mean',
1055
1055
feature_stats = float (cellvol .sum ())
1056
1056
else :
1057
1057
raise ValueError ("Must be one of mode, min, mean, max,"
1058
- "std, sum, count, var, skew, kurt, vol" )
1058
+ "std, sum, count, var, skew, kurt, vol, mode " )
1059
1059
# You can't have the stat of a single value - this is not an ideal
1060
1060
# solution - should be flagged somehow but
1061
1061
if src_array .shape == (1 ,1 ):
@@ -1074,9 +1074,9 @@ def zonal_stats(inShp, inRas, band, bandname, layer=None, stat = 'mean',
1074
1074
1075
1075
vds = None
1076
1076
rds = None
1077
- frame = DataFrame (stats )
1077
+ frame = DataFrame (data = stats , columns = [ stat ] )
1078
1078
1079
- if write_stat != None :
1079
+ if write_stat is None :
1080
1080
return frame , rejects
1081
1081
1082
1082
def zonal_frac (inShp , inRas , band , bandname , layer = None ,
@@ -1151,11 +1151,11 @@ def zonal_frac(inShp, inRas, band, bandname, layer=None,
1151
1151
if write_stat != None :
1152
1152
# if the field exists leave it as ogr is a pain with dropping it
1153
1153
# plus can break the file
1154
- if _fieldexist (vlyr , bandname + '_cls' ) == False :
1155
- vlyr .CreateField (ogr .FieldDefn (bandname + '_cls' , ogr .OFTIntegerList ))
1154
+ # intlist not used see later code #ogr.OFTIntegerList))
1155
+ if _fieldexist (vlyr , bandname + '_cls' ) == False :
1156
+ vlyr .CreateField (ogr .FieldDefn (bandname + '_cls' , ogr .OFTString ))
1156
1157
if _fieldexist (vlyr , bandname + '_cnt' ) == False :
1157
- vlyr .CreateField (ogr .FieldDefn (bandname + '_cnt' , ogr .OFTIntegerList ))
1158
-
1158
+ vlyr .CreateField (ogr .FieldDefn (bandname + '_cnt' , ogr .OFTString ))
1159
1159
1160
1160
mem_drv = ogr .GetDriverByName ('Memory' )
1161
1161
driver = gdal .GetDriverByName ('MEM' )
@@ -1167,8 +1167,17 @@ def zonal_frac(inShp, inRas, band, bandname, layer=None,
1167
1167
rejects = []
1168
1168
1169
1169
#create a poly of raster bbox to test for within raster
1170
+ # this is
1170
1171
poly = rasterext2poly (inRas )
1171
1172
1173
+ # so we can map the field name to an integer when setting the list
1174
+ # (yes I know....)
1175
+ fieldict = {}
1176
+ ldefn = vlyr .GetLayerDefn ()
1177
+ for n in range (ldefn .GetFieldCount ()):
1178
+ fdefn = ldefn .GetFieldDefn (n )
1179
+ fieldict .update ({fdefn .name :n })
1180
+
1172
1181
#TODO FAR too many if statements in this loop.
1173
1182
# This is FAR too slow
1174
1183
@@ -1191,12 +1200,12 @@ def zonal_frac(inShp, inRas, band, bandname, layer=None,
1191
1200
1192
1201
# This does not seem to be fullproof
1193
1202
# This is a hacky mess that needs fixed
1194
- if poly .Contains (geom ) == False :
1195
- #print(src_offset[0],src_offset[1])
1196
- #offs.append()
1197
- feat = vlyr .GetNextFeature ()
1198
- continue
1199
- elif src_offset [0 ] > rds .RasterXSize :
1203
+ # if poly.Contains(geom) == False: - not working rejects legit polygons
1204
+ # #print(src_offset[0],src_offset[1])
1205
+ # #offs.append()
1206
+ # feat = vlyr.GetNextFeature()
1207
+ # continue
1208
+ if src_offset [0 ] > rds .RasterXSize :
1200
1209
feat = vlyr .GetNextFeature ()
1201
1210
continue
1202
1211
elif src_offset [1 ] > rds .RasterYSize :
@@ -1250,29 +1259,42 @@ def zonal_frac(inShp, inRas, band, bandname, layer=None,
1250
1259
gdal .RasterizeLayer (rvds , [1 ], mem_layer , burn_values = [1 ], options = [touch ])
1251
1260
rv_array = rvds .ReadAsArray ()
1252
1261
1253
- # Mask the source data array with our current feature using np mask
1254
-
1255
- #rejects.append(feat.GetField('DN'))
1256
- masked = np .ma .MaskedArray (
1257
- src_array ,
1258
- mask = np .logical_or (
1259
- src_array == nodata_value ,
1260
- np .logical_not (rv_array )
1261
- )
1262
- )
1263
- unique , count = np .unique (masked .data , return_counts = True )
1262
+ # masked array dumped as it causes problems with unique producing non-unique
1263
+ # arrays - also slows it down
1264
+ if src_array .shape == (1 ,1 ):
1265
+ unique = src_array [0 ]
1266
+ count = np .array ([1 ])
1267
+ else :
1268
+ unique , count = np .unique (src_array [rv_array > 0 ], return_counts = True )
1264
1269
1265
- stats .append ([feat .GetFID (), unique , count ])
1270
+ entry = [feat .GetFID (), unique .tolist (), count .tolist ()]
1271
+
1272
+ stats .append (entry )
1266
1273
1267
1274
if write_stat != None :
1268
- # may have to insert into gdf as array
1269
- # TypeError: Feature_SetFieldIntegerList expected 3 arguments, got 4
1270
- # But there are 3 args apart from the self
1271
- feat .SetFieldIntegerList (bandname + '_cls' , 3 , unique .tolist ())
1272
- feat .SetFieldIntegerList (bandname + '_cnt' , 3 , count .tolist ())
1275
+
1276
+ # in this cas tho - the field_integerlist is a property (ie attribute)
1277
+ # so not useful here but maybe later
1278
+ # feat.field_integerlist = '(3:10,20,30)'
1279
+ # feat.field_integer64list = [9876543210]
1280
+ # feat.field_reallist = [123.5,567.0]
1281
+ # feat.field_stringlist = ['abc','def']
1282
+
1283
+ # This VERY slow to write....
1284
+ # It is also parsed as a string in gpd etc anyway so may
1285
+ # it appears like this '(3:10,20,30)' (length: list)
1286
+ # so not very practical for parsing later anyway
1287
+ # as well just write as a string and use eval later
1288
+ # field int idx input data
1289
+ # feat.SetFieldIntegerList(fieldict[bandname+'_cls'], entry[1])
1290
+ # feat.SetFieldIntegerList(fieldict[bandname+'_cnt'], entry[2])
1291
+
1292
+ # This is equally slow to write, but easier to parse
1273
1293
# A hack could be to write a string then use eval(string) to get a list back
1274
- #feat.SetField(bandname+'_cls', str(unique.tolist()))
1275
- #feat.SetField(bandname+'_cnt', str((count.tolist()))
1294
+ ustr = str (unique .tolist ())
1295
+ cntstr = str (count .tolist ())
1296
+ feat .SetField (bandname + '_cls' , ustr )
1297
+ feat .SetField (bandname + '_cnt' , cntstr )
1276
1298
vlyr .SetFeature (feat )
1277
1299
feat = vlyr .GetNextFeature ()
1278
1300
@@ -1281,6 +1303,7 @@ def zonal_frac(inShp, inRas, band, bandname, layer=None,
1281
1303
1282
1304
vds = None
1283
1305
rds = None
1306
+
1284
1307
frame = DataFrame (data = stats , columns = ['fid' , bandname + '_cls' , bandname + '_cnt' ])
1285
1308
1286
1309
if write_stat is None :
0 commit comments