Python coding for point distance

1837
14
03-31-2014 10:18 AM
MatthewIsbell
New Contributor
I am a bit stuck and hoping someone can help.   I have some python experience, but am getting stuck on the best rout forward for a specific function I am trying to run.

I have two point shapefiles.  The first is a list of polling locations for the county I live, with the precinct number that corresponds to that location.  the second shapefile is a geocode of all the voters in that county.  Each voter has their precinct number in the attribute table.

What I am hoping to do is run a code that will calculate the distance each voter is from their designated polling spot.  I am assuming Ishould use point distance and a combination of an IF or/and FOR loop to run the function when the precinct numbers from the two distinct shapefiles match.  However, I am unsure how to move forward in writing that code.  If anyone has any suggestions, or a better method, the help would be appreciated.

Matthew
Tags (2)
0 Kudos
14 Replies
markdenil
Occasional Contributor III
>> getting an error (message below) regarding the "Point_Tbl" part of the code. <<

Point_tbl should likely be named "Point_tbl.dbf" because it is is to be placed in a directory rather than a geodatabase.
If the destination was a gdb, arc would know that name was for a table..

Yes, Point_tbl is the direct output from PointDistance,
but since you are running PointDistance multiple times in a loop,
(and destroying any existing instance at the start of the loop;
but you had set the environment to overwrite each new output anyway, eh?),
you will want to save the outputs in a dbf compendium of all the outputs.
That is why you append each iteration to distance.dbf.

>>other question<<

By the time MakeFeatureLayer runs, the search cursor is played out: over and done.
The cursor only builds the list of unique precinct ids, then finishes.

There should likely be a
del rows

just before the
for site in sitesList:

in order to kill the cursor dead.

The loop is through sitesList, which is a list of the values from the Pre field of PollingSite,
and not through a cursor.
Don't think of a cursor as a way to run geoprocessing tools on a single row: it is not.

I assume the values in Pre are the link to the values in PrecinctNa in Voters
That is why the where clauses are set up to reference the same value in the differently named fields in each shp/layer.

What you are (or, I guess, I am) doing is:
> make a list of precinct values common to both shp files (by grabbing it from just one)
> loop through that list to:
>>  make where statements appropriate to each shp file
>>  delete all intermediate layers and tables
>>  make a layer from Voters of the voters in precinct A
>>  make a layer of the polling places in precinct A from PollingSite
>>  make a (temporary, on-disk) point distance table of the point distances between
...  the voter points and their polling place(s)
>>  append the results to the final results table.

>>  continue to the end of the list of polling places, then stop


This code does leave the final batch of ephemeral layer files and the final on-disk Point_Tbl.dbf behind...
It is not a polished bit of code, just an illustration
0 Kudos
MattI
by
New Contributor
thank you for the explanations.  I def understand it better now.  I spent last few days going through some tutorials and lessons I found online to better understand python and GIS coding.  seems like this project of mine is much more complex than most tutorials.  i appreciate your help. 

so I am moving the table that should be outputted to a geodatabase.  so i haven't added .dbf,   i did at one point but it still generated the same error

this is my code as it is now. which isn't much changed form before, but has comments next to each function where I explain what is going on.  let me know if it looks like i am mis-understanding any function.  you said there is still some polishing.  not sure where things need to be changed/added.  it looks done, but obviously is not.  (my moderate experience is showing here).  what are the final steps i need to complete.   thank you so much for your help already.

import arcpy
from arcpy import env

env.workspace = "C:\work"
env.overwriteOutput = True

# Local variables:
Voters = "Voters.shp"  # this is the point file for the voter geocode
PollingSite = "Polling.shp"  # this is the point file of the voter sites
distance = "List.gdb\\distance" # output of distance, must be geodatabase

#need to define rows, use SearchCursor
rows = arcpy.SearchCursor(PollingSite)

##  define a feature class
sitesList = []

#run a for loop to go to each row in attribute table.
for row in rows:  #rows is the PollingSite shapefile
    p_precinct = row.Pre #this is the precinct column for PollingSite

    if p_precinct not in sitesList:
        sitesList.append(p_precinct) #adds p_precinct to sitesList, does this for each precinct row

del row #ends the searchcursor loop

for site in sitesList:
    Votewhere = '"PrecinctNa" = %s' % (site) #loops to grab one precinct at a time
    Sitewhere = '"Pre" = %s' % (site) #loops to grab voters of one precinct at a time

    ##deletes the layers that will be created again and again on loop
    if arcpy.Exists("PollPlace_Lyr"):
        arcpy.Delete_management("PollPlace_Lyr")
    if arcpy.Exists("Voter_Lyr"):
        arcpy.Delete_management("Voter_Lyr")
    if arcpy.Exists("Point_Tbl"):
        arcpy.Delete_management("Point_Tbl")

    #make a layer for the voters of one precinct at a time
    arcpy.MakeFeatureLayer_management(Voters, "Voter_Lyr", Votewhere)

    #make a layer for the voting site of one precinct at a time
    arcpy.MakeFeatureLayer_management(
                            PollingSite, "PollPlace_Lyr", Sitewhere)

    #run point distance analysis for each precinct/voter distance
    arcpy.PointDistance_analysis("Voter_Lyr",
                                 "PollPlace_Lyr",
                                 "Point_Tbl")
    
    #append point distance results as they add up
    arcpy.Append_management("Point_Tbl", distance)
0 Kudos
markdenil
Occasional Contributor III
Your Point_Tbl is still just a string ("Point_Tbl"); it needs to be a path to a table.
You should make a variable:
Point_Tbl = "List.gdb\\Point_Tbl"
and then, after that, refer to Point_Tbl instead of "Point_Tbl".

Similarly, I would make the layers variables too:
PollPlace_Lyr = "PollPlace_Lyr"
Voter_Lyr = "Voter_Lyr"

The tool output has to be a real table, with a path.
The layers just float in memory, so thay can get by with just a string name,
But it is just easier and clearer to set all the explicit names to variables.

As I mentioned before, you may want to delete at least the last Point_Tbl at the end of the script.
Otherwise it will be left behind; the temp layers will vaporize with the ending arcpy session.
0 Kudos
MattI
by
New Contributor
thanks, i will work on that. 

one other thing i am wondering about is this part of the code
Votewhere = '"PrecinctNa" = %s' % (site) #loops to grab one precinct at a time
    Sitewhere = '"Pre" = %s' % (site) #loops to grab voters of one precinct at a time


could you explain how it is looping and grabbing one precinct at a time, i get the concept, but am unfamiliary with the %s' % stuff, just want to be sure i understand the logic better for future uses
0 Kudos
markdenil
Occasional Contributor III
The   "%s " % (var)    business is python string formatting.
The %s is a place holder for a string (there are other codes too, but %s is the standby)
the % after the string tells python to do the format substitution
and the strings, numbers or variables in parentheses after the % is the list of values to insert.
You have to have the same number of openings (the %s flags) and values in the list or python gets peeved.

There are other ways to insert variables and do string formatting in python,
but I generally use this as it seems less confusing than some of the others
and it is a whole lot neater than using lots of pluses and quoted spaces and whatnot...

It loops becasue it is in a loop:
for site in sitesList:
    Votewhere = '"PrecinctNa" = %s' % (site) #loops to grab one precinct at a time
    Sitewhere = '"Pre" = %s' % (site) #loops to grab voters of one precinct at a time
each time the loop goes round, site has a different value
0 Kudos