I am trying to mimic the Standard Deviational Ellipse tool from ArcGIS through Open Source Python avenues. The formula is here.
At the moment I am failing to get the correct X and Y axis lengths for the ellipse, the first step in the formula.
When I run the tool in ArcGIS the values are 4607.796039, 7816.667667 but I get 3948.758414, 5057.00957766.
Here's my code so far...
from osgeo import ogr
from shapely.geometry import MultiLineString
from shapely import wkt
import numpy as np
import sys, math
## set the driver for the data
driver = ogr.GetDriverByName("FileGDB")
## path to the FileGDB
gdb = r"C:\Users\******\Documents\ArcGIS\Default.gdb"
## ope the GDB in write mode (1)
ds = driver.Open(gdb, 1)
input_lyr_name = "Birmingham_Burglaries_2016"
output_fc = input_lyr_name + "_standard_ellipse"
## reference the layer using the layers name
if input_lyr_name in [ds.GetLayerByIndex(lyr_name).GetName() for lyr_name in range(ds.GetLayerCount())]:
lyr = ds.GetLayerByName(input_lyr_name)
print "{0} found in {1}".format(input_lyr_name, gdb)
if output_fc in [ds.GetLayerByIndex(lyr_name).GetName() for lyr_name in range(ds.GetLayerCount())]:
ds.DeleteLayer(output_fc)
print "Deleting: {0}".format(output_fc)
## for each point in the layer
## get the x and y value
## and place in an array
try:
first_feat = lyr.GetFeature(1)
if first_feat.geometry().GetGeometryName() in ["POINT", "MULTIPOINT", "POLYGON", "MULTIPOLYGON"]:
xy_arr = np.ndarray((len(lyr), 2), dtype=np.float)
for i, pt in enumerate(lyr):
ft_geom = pt.geometry()
xy_arr[i] = (ft_geom.Centroid().GetX(), ft_geom.Centroid().GetY())
## for lines we get the midpoint of a line
elif first_feat.geometry().GetGeometryName() in ["LINESTRING", "MULTILINESTRING"]:
xy_arr = np.ndarray((len(lyr), 2), dtype=np.float)
for i, ln in enumerate(lyr):
line_geom = ln.geometry().ExportToWkt()
shapely_line = MultiLineString(wkt.loads(line_geom))
midpoint = shapely_line.interpolate(shapely_line.length/2)
xy_arr[i] = (midpoint.x, midpoint.y)
except Exception:
print "Unknown geometry for {}".format(input_lyr_name)
sys.exit()
## the mean center (average x and average y coordinate)
avg_x, avg_y = np.mean(xy_arr, axis=0)
print "Mean Center: {0}, {1}".format(avg_x, avg_y)
sum_of_sq_diff_x = 0.0
sum_of_sq_diff_y = 0.0
for x, y in xy_arr:
# (x - xmean)squared
diff_x = math.pow(x - avg_x, 2)
# (y - ymean)squared
diff_y = math.pow(y - avg_y, 2)
# sum the differences sqaured from above
sum_of_sq_diff_x += diff_x
sum_of_sq_diff_y += diff_y
# x axis length
sum_of_results_x = (sum_of_sq_diff_x/lyr.GetFeatureCount())
standard_distance_x = math.sqrt(sum_of_results_x)
# y axis length
sum_of_results_y = (sum_of_sq_diff_y/lyr.GetFeatureCount())
standard_distance_y = math.sqrt(sum_of_results_y)
print standard_distance_x, standard_distance_y