import arcpy as ARCPY
import numpy as NUM
import SSDataObject as SSDO
import scipy as SCIPY
import pandas as PANDA
import pysal as PYSAL

"""
Explanation: Leveraging Open-Source Python Packages for Data Analysis within the ArcGIS Environment (Direct Integration Strategy)
Using NumPy as the common denominator

Could use the ArcPy Data Access Module directly, but there are host of issues/information one must take into account:
How to deal with projections and other environment settings?
How Cursors affect the accounting of features?
How to deal with bad records/bad data and error handling?
How to honor/account for full field object control?
How do I create output features that correspond to my inputs?
Points are easy, what about Polygons and Polylines?




Spatial Statistics Data Object (SSDataObject)
Almost 30 Spatial Statistics Tools written in Python that ${\bf{must}}$  behave like traditional GP Tools
Use SSDataObject and your code should adhere



The Data Analysis Python Modules


PANDAS (Python Data Analysis Library)


SciPy (Scientific Python)


PySAL (Python Spatial Analysis Library)


Basic Imports
End of explanation
"""


inputFC = r'../data/CA_Polygons.shp'
ssdo = SSDO.SSDataObject(inputFC)
for fieldName, fieldObject in ssdo.allFields.iteritems():
    print fieldName, fieldObject.type


"""
Explanation: Initialize Data Object and Query Attribute Fields
End of explanation
"""


ssdo.obtainData(ssdo.oidName, ['GROWTH', 'PCR1970', 'POPDEN70', 'PERCNOHS'])


popInfo = ssdo.fields['POPDEN70']
popData = popInfo.data
print popData[0:5]

"""
Explanation: Select Fields to Read Into NumPy Arrays

The Unique ID Field (Object ID in this example) will keep track of the order of your features
You have no control over Object ID Fields.  It is quick, assures "uniqueness", but can't assume they will not get "scrambled" during copies.
To assure full control I advocate the "Add Field (LONG)" --> "Calculate Field (From Object ID)" workflow.
End of explanation
"""


import numpy.random as RAND
ARCPY.env.overwriteOutput = True
outArray = RAND.normal(0,1, (ssdo.numObs,))
outDict = {}
outField = SSDO.CandidateField('STDNORM', 'DOUBLE', outArray, alias = 'My Standard Normal Result')
outDict[outField.name] = outField


"""
Explanation: Adding Results to Input/Output

Example: Adding a field of random standard normal values to your input/output

Create a Dictionary of Candidate Fields
End of explanation
"""


ssdo.addFields2FC(outDict)


"""
Explanation: Add New Field to Input

Be Carefull!
End of explanation
"""


import os as OS
outputFC = OS.path.abspath(r'../data/testMyOutput.shp')
ssdo.output2NewFC(outputFC, outDict, appendFields = ['GROWTH', 'PERCNOHS'])
del ssdo

"""
Explanation: Copy Features, Selected Attribute Field(s), New Result Field(s) to Output
End of explanation
"""


ssdo = SSDO.SSDataObject(inputFC)
years = NUM.arange(1975, 2015, 5)
fieldNames = ['PCR' + str(i) for i in years]
fieldNamesAll = fieldNames + ['NEW_NAME', 'SOCAL']
ssdo.obtainData("MYID", fieldNamesAll)
ids = [ssdo.order2Master[i] for i in xrange(ssdo.numObs)]
convertDictDF = {}
for fieldName, fieldObject in ssdo.fields.iteritems():
    convertDictDF[fieldName] = fieldObject.data
df = PANDA.DataFrame(convertDictDF, index = ids)
print df[0:5]


"""
Explanation: Getting More Advanced - SciPy and PANDAS
End of explanation
"""


groups = df.groupby('SOCAL')
print groups.mean()

"""
Explanation: Using GroupBy for Conditional Statistics
Example: One Liner for Average Incomes Based on Southern/Non-Southern California
End of explanation
"""


print groups.median()

"""
Explanation: Now the Median...
End of explanation
"""


pcr = df.ix[:,1:9]
rollMeans = NUM.apply_along_axis(PANDA.rolling_mean, 1, pcr, 4)
timeInts = NUM.arange(0, 5)
outArray = NUM.empty((ssdo.numObs, 5), float)
for i in xrange(ssdo.numObs):
    outArray[i] = SCIPY.stats.linregress(timeInts, rollMeans[i,3:])

"""
Explanation: Example: Calculating the Trend of Rolling Means
End of explanation
"""


outputFC = OS.path.abspath(r'../data/testMyRollingMeanInfo.shp')
outFields = [ "SLOPE", "INTERCEPT", "R_SQRAURED", "P_VALUE", "STD_ERR" ]
outDict = {}
for fieldInd, fieldName in enumerate(outFields):
    outDict[fieldName] = SSDO.CandidateField(fieldName, "DOUBLE", outArray[:,fieldInd])
ssdo.output2NewFC(outputFC, outDict, fieldOrder = outFields)
del ssdo

"""
Explanation: Write to Output (Same as Always...)
End of explanation
"""


ssdo = SSDO.SSDataObject(inputFC)
ssdo.obtainData(ssdo.oidName, ['GROWTH', 'POP1970', 'PERCNOHS'])
w = PYSAL.weights.knnW(ssdo.xyCoords, k=5)
X = NUM.empty((ssdo.numObs,2), float)
X[:,0] = ssdo.fields['GROWTH'].data
X[:,1] = ssdo.fields['PERCNOHS'].data
floorVal = 1000000.0
floorVar = ssdo.fields['POP1970'].returnDouble()
maxp = PYSAL.region.Maxp(w, X, floorVal, floor_variable = floorVar)
outArray = NUM.empty((ssdo.numObs,), int)
for regionID, orderIDs in enumerate(maxp.regions):
    outArray[orderIDs] = regionID
    print regionID, orderIDs
    

outputFC = OS.path.abspath(r'../data/testMaxPInfo.shp')
outDict = {}
outDict["REGIONID"] = SSDO.CandidateField("REGIONID", "DOUBLE", outArray)
ssdo.output2NewFC(outputFC, outDict, appendFields = ['GROWTH', 'POP1970', 'PERCNOHS'])
del ssdo

"""
Explanation: Even More Advanced: PySAL
Example: Max(p) Regional Clustering
End of explanation
"""


