median calculation tool

05-03-2016 11:02 AM
New Contributor II

Currently working on a Median calculation tool. This tool is similar to the one I posted on a previous post involving selecting a city and zooming into it. In this case, we have to type in a country name, where the tool will then select all the cities in that country, sort the POP_RANK of the cities in that country, and calculate the median POP_RANK for that country. I was able to complete the select and zoom aspect but I am not entirely sure how to create a list/search cursor which will allow us to input a calculation. Is there a specific way I should approach this?  Any and all help is appreciated!! Thank you

import arcpy

from arcpy import mapping

#sets the workspace

mxd = arcpy.mapping.MapDocument("CURRENT")

df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]

fc = ("N:/data2016/Lab13/cities.shp")

cities = arcpy.mapping.ListLayers(mxd, "Cities")[0]

cities.showLabels = True

def countryList():

    country = arcpy.GetParameterAsText(0)

    country_Layer = arcpy.MakeFeatureLayer_management(fc, "country_lyr")

    arcpy.SelectLayerByAttribute_management(cities, "NEW_SELECTION", "CNTRY_NAME = '{}' ".format(country))




0 Kudos
9 Replies
MVP Esteemed Contributor

SearchCursor—Help | ArcGIS for Desktop example 2 shows how to ge the unique values.. if you leave out the set(...) bit, you have all the values, which then you can then use a python sort, get the len(gth) and if len is divisible by 2 (mod), just take the average of the middle 2 (from len/2 and len/2 +1) otherwise if len is odd, just take the middle one.

alternately that field can be read and converted to a numpy array for which there are median methods for data with and without nodata values.

MVP Esteemed Contributor

forgot the code link

and your chance to join a cause to free statistical tools Free Frequency ... join the cause

MVP Esteemed Contributor

If you install ArcGIS Pro, you will be using python 3.4 which comes with the Statistics module, which has 4 variants of the median which covers most useable situations 9.7. statistics — Mathematical statistics functions — Python 3.4.4 documentation

0 Kudos
MVP Esteemed Contributor

Does anyone in the 'global reach' section have any further ideas? or should I mark this 'assumed answered'

0 Kudos
MVP Frequent Contributor

There was a median calculation tool posted here somewhere by Caleb Mackey.

But no joy with search. So here it is again.

Written By Caleb Mackey
Calculates Median Statistics
import arcpy, os, sys, traceback
# env settings
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = False
def GetMedian(in_list):
    sorted_list = sorted(in_list)
    median = int(round(len(sorted_list) / 2))
    if len(sorted_list)%2==0:
        med_val = float(sorted_list[median-1]
                        + sorted_list[median]) / 2
        med_val = sorted_list[median]
    return med_val
def GetMedianValues(source_fc, new_table, case_field, value_field):
    ''' Generates a table with Median Values, summarized by case_field. If the
        goal is to get the median for the entire table, use a case field that has
        the same value for all records.
        source_fc - input feature class to compute median statistics for
        new_table - output table
        case_field - similar to dissolve field, computes stats based on unique values in this field
        value_field - field that contains the actual values for statistics; must be numeric
    # Get unique value list for query
    print 'starting cursor'
    with arcpy.da.SearchCursor(source_fc, [case_field]) as rows:
        un_vals = list(set(r[0] for r in rows))
    lyr = arcpy.MakeFeatureLayer_management(source_fc,'source_layer')
    values = {}
    # Get Median UseValue for each station name
    for st in un_vals:
        query = '"{0}" = \'{1}\''.format(case_field, st)
        arcpy.SelectLayerByAttribute_management(lyr, 'NEW_SELECTION', query)
        use_vals = []
        with arcpy.da.SearchCursor(lyr, [value_field]) as rows:
            for row in rows:
                if row[0] != None:
        if len(use_vals) > 0:
            median = GetMedian(use_vals)
            values[st] = [median, len(use_vals)]
    # Create new Summary Statistics table with median
    if arcpy.Exists(new_table):
    # Get field names and types
    for field in arcpy.ListFields(source_fc):
        if in [case_field, value_field]:
            ftype = field.type
            name =
            length = field.length
            pres = field.precision
            scale = field.scale
            if name == value_field:
                if new_table.endswith('.dbf'):
                    name = 'MED_' + value_field[:6]
                    name = 'MED_' + value_field
                value_field2 = name
    # Add frequency field
    # Insert rows
    with arcpy.da.InsertCursor(new_table, [case_field, value_field2, 'FREQUENCY']) as rows:
        for k,v in sorted(values.iteritems()):
            rows.insertRow((k, v[0], v[1]))
    # report results
    print 'Created %s' %os.path.basename(new_table)
    arcpy.AddMessage('Created %s' %os.path.basename(new_table))
    # .dbf's are automatically given a 'Field1' field...Clean this up
        if new_table.endswith('.dbf'):
            arcpy.DeleteField_management(new_table, 'Field1')
    print 'Done'
if __name__ == '__main__':
##    # testing
##    source_fc = r'C:\Testing\Test.gdb\CSR_by_TWP'
####    new_table = r'C:\Testing\Test.gdb\Median_CSR' #gdb test
##    new_table = r'C:\Testing\Median_CSR.dbf'  #dbf test
##    case_field = 'NAME'
##    value_field = 'AVE_CSR'
    # Script tool params
    source_fc = arcpy.GetParameterAsText(0)
    new_table = arcpy.GetParameterAsText(1)
    case_field = arcpy.GetParameterAsText(2)
    value_field = arcpy.GetParameterAsText(3)
    GetMedianValues(source_fc, new_table, case_field, value_field)
MVP Esteemed Contributor

so if using recent versions of python, it would still be easier to use the builtins

>>> import statistics

>>> a = [1,2,3]

>>> statistics.median(a)


>>> b = [1,2,3,4]

>>> statistics.median(b)



>>> dir(statistics)

['Decimal', 'Fraction', 'StatisticsError', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_check_type', '_counts', '_decimal_to_ratio', '_exact_ratio', '_ss', '_sum', 'collections', 'math', 'mean', 'median', 'median_grouped', 'median_high', 'median_low', 'mode', 'pstdev', 'pvariance', 'stdev', 'variance']


MVP Frequent Contributor

Of course Dan,

But I am running 10.3.1 (soon moving to 10.4).

Haven't got anywhere near Pro yet. Need to buy a deep blue before I do.

0 Kudos
MVP Esteemed Contributor

I have been using python 3.4 since arcmap 10.2... it is a matter of setup

0 Kudos
MVP Esteemed Contributor

I think we have it wrapped up with this one, in case it is a network question