2

Using Esri Desktop Advanced 10.2.2 is it possible to create an attribute based on a classification method, i.e. Jenks? To elaborate - if you use the symbology tab in a layers properties, you can set a classification method that displays the class breaks, but I want to also do some statistical analysis based on those class breaks. Previously, I have done this by performing the classification using the layer properties and then using the class breaks to do a SQL and manually editing a attribute field with the class number. This works, but is labor intensive. Is there a progamatic way to do this?

  • What exactly is the query that you are performing? This type of workflow should be able to be accomplished in ModelBuilder, but it's hard to tell without seeing your data or intended resulting attribute. – Chris Strother Jan 8 '15 at 16:09
  • Hi Chris - I don't know if model builder can do it - I could not find a tool which will perform a Classification. The data has 28,000 records, and is mainly demographic. For example, I want to classify the population density into 8 classes, using Jenks - then create an attibute that tells me what class each record is in. – BretW Jan 8 '15 at 16:11
5

You can calculate natural break values using the PySAL library, then Reclassify or use those values as you choose.

import arcpy, pysal
from pysal.esda.mapclassify import Natural_Breaks as nb
myArray = arcpy.RasterToNumPyArray(<PATH TO RASTER HERE>)
breaks = nb(myArray.ravel(),k=<NUMBER OF CLASSES HERE>,initial=20)
  • Well played - It's easy for us to forget the wealth of modules found outside of ArcGIS. +1 for real. – Jim Jan 8 '15 at 17:28
  • Agreed. Honestly, it was pretty random that I knew this function. – phloem Jan 8 '15 at 17:51
  • +12 I never knew this function. Nice. – If you do not know- just GIS Jan 8 '15 at 17:58
0

I believe there is a more programmatic way, however it only automates the steps you have already described. I don't readily know of a more efficient way to automate for this effect.

First, my gut reaction says to use arcpy.mapping to grab a reference to your target layer object, access the layer.symbology object and then extract the layer.symbology.classBreakValues list. Once we have the list of class break values for your Jenks classification, we'd have to go back and use an arcpy.da.UpdateCursor() to assign category values to your data conditionally, based on the classification bounds found in the layer.symbology.classBreakValues list. These category values would be placed in a new field, maybe called "BreakClass." Then, when all of your records have a value for "BreakClass" we could move on with further statistical analysis, grouping-by our "BreakClass" labels. The following assumes ArcGIS 10.2.2 and that the data we are working with is local to your machine, on-disk.

This also assumes we are working with only 3 jenks classes. I'm having some trouble figuring out a generalized way to push the classifier bounds over the data using an arbitrary number of class breaks - maybe need to def a function for this - comments welcome! Thinking overall it may look something like this - Good Luck:

import arcpy

target_jenks_layer = arcpy.mapping.Layer("C:\\path\\to\\the\\layer\\file")

# for example, where the target layer support symbology and uses graduated colors...
if target_jenks_layer.supports("SYMBOLOGY"):
    if target_jenks_layer.symbologyType == "GRADUATED_COLORS":
        jenks_breaks_list = target_jenks_layer.symbology.classBreakValues
        jenks_labels_list = target_jenks_layer.symbology.classBreakLabels
        for break_value in jenks_breaks_list:
            print(break_value)
    # elif target_jenks_layer.symbologyType == "GRADUATED_SYMBOLS........etc

# add the field to the data which will hold the "BreakClass" labels
if target_jenks_layer.supports("DATASOURCE"):
    arcpy.AddField_management(target_jenks_layer.dataSource, "BreakClass", "TEXT")

# start classifying the data using the breaks values as conditional bounds
cursor = arcpy.da.UpdateCursor(target_jenks_layer.dataSource, 
                              [target_jenks_layer.symbology.valueField, "BreakClass"])

for row in cursor:
    test_value = row[0]
    if test_value > jenks_breaks_list[0] and test_value <= jenks_breaks_list[1]:
        row[1] = jenks_labels_list[0]
        cursor.updateRow(row)
    elif test_value > jenks_breaks_list[1] and test_value <= jenks_breaks_list[2]:
        row[1] = jenks_labels_list[1]
        cursor.updateRow(row)
    elif test_value > jenks_breaks_list[2] and test_value <= jenks_breaks_list[3]:
        row[1] = jenks_labels_list[2]
        cursor.updateRow(row)

del row
del cursor
print('Finished applying break labels to dataset')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.