import arcpy
import pandas as pd
from math import radians, cos, sin, asin, sqrt
from sklearn.cluster import DBSCAN
from scipy.spatial.distance import pdist, squareform
import matplotlib.pyplot as plt
import numpy as np
if __name__ == "__main__":
arcpy.env.overwriteOutput = True
in_file = arcpy.GetParameterAsText(0)
output = arcpy.GetParameterAsText(1)
epsilon = float(arcpy.GetParameterAsText(2))
min_sample = int(arcpy.GetParameterAsText(3))
#Convert the feature class to a pandas DataFrame
array = arcpy.da.FeatureClassToNumPyArray(in_file, ["SHAPE@X", "SHAPE@Y"])
df = pd.DataFrame(array)
#Extract the X and Y coordinates from the DataFrame
coords = df[["SHAPE@X", "SHAPE@Y"]].values
#Get the spatial reference of the input feature class
describe = arcpy.Describe(in_file)
#create spatial object
SR = describe.spatialReference
#Create a spatial reference object
SR = arcpy.SpatialReference(SR.FactoryCode)
def haversine(lonlat1, lonlat20) :
# convert decimal degrees to radians
lat1, lon1 = lonlat1
lat2, lon2 = lonlat2
lon1, lat1, lon2, lat2 = map(radians, [lon1, lat1, lon2, lat2])
# haversine formula
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat/2)**2 + cos(lat1) * cos(lat2) * sin(dlon/2)**2
b = 2 * asin(sqrt(a))
r = 6371 # Radius of earth in kilometers. Use 3956 for miles
return (b * r) * 1000
distance_meter = squareform(pdist(coords, (lambda u,v: haversine(u,v))))
arcpy.AddMessage(epsilon)
arcpy.AddMessage(min_sample)
#Function DBSCAN
db = DBSCAN(eps=epsilon, min_samples=min_sample, metric='precomputed').fit(distance_meter)
y_db = db.fit_predict(distance_meter)
#visualization of db_scan
plt.scatter(distance_meter[:,0],distance_meter[:,1],c= db.labels_)
plt.xlabel("X")
plt.ylabel("Y")
plt.title("Grafik Data compound DBscan")
plt.show
print("Jumlah Kluster:{}".format(len(set(db.labels_[np.where(db.labels_!=-1)]))))
print(db.labels_)
labels = db.labels_
#Export feature class
arcpy.env.overwriteOutput = True
out = arcpy.da.NumPyArrayToFeatureClass(array, output, ["SHAPE@X", "SHAPE@Y"],spatial_reference=SR)
#Add field cluster into feature class output
cluster = arcpy.AddField_management(output,"CLUSTER","Short")
with arcpy.da.UpdateCursor(output,["CLUSTER"]) as cusor:
for i, row in enumerate(cusor) :
row[0] = labels[i]
cusor.updateRow (row)