I have three columns (other than OID FID) in my shapefiles for river. And I want to update "from node" and "to node column"
Before update
from node to node gridcode
2 3 8
3 2 9
7 2 5
After update, I want "node column" to be same as "grid code" column, so I used field calculator in ArcGIS (from node = gridcode). My "from node" column has been changed to gridcode but not sure how to update "to node" column (that depends on values in “from node” column)
Below is the final result I want:
from node to node gridcode
8 9 8
9 8 9
5 8 5
Half of the code is working import arcpy, os, sys from arcpy import env fc=r"C:/Users/wis/Desktop/python/fe/fea_c.shp" # instantiate empty dictionary #'FROM_NODE','GRID_CODE','TO_NODE' name of columns in my attribute table
node_values = {} # build dictionary of values with arcpy.da.SearchCursor(fc, ['FROM_NODE','GRID_CODE']) as cursor: for row in cursor: old_node = row[0] new_node= row[1] node_values[FROM_NODE] = new_node with arcpy.da.UpdateCursor(fc, ['FROM_NODE','TO_NODE','GRID_CODE']) as cursor: for row in cursor: # set fromnode to gridcode value row[0] = row[2] # set tonode to new equivalent node to_node = row[1]# I get an error here new_to_node = node_values[TO_NODE] row[1] = new_to_node cursor.updateRow(row)
The error is because row[1] or "to node" does not have all numbers that are in "from node" or "grid code" Because some values will repeat in t"no node" because one river can be connected to more than one rivers. However no repetition in "gridcode" and "from node" Any suggestions
perhaps you could post or show a full example of the data you are working with since only portions of your example make sense
Dan Patterson i attached shapefile. You can familiar with watershed delineation so i guess i can give you some background why am i am doing this. I used swat model to delineate my watershed but because of low elevation, I am getting unwanted streams too (i tried burning original streams, arc hydro and different threshold value).Still I need to make some changes that involve removing some sub basins/streams , merging others. Because swat does not except any subbasin that does not have any stream draining into it. So if i remove unwated streams, i need to merge some subbasins. When i remove some streams it means that gridcode and from node will not be in consecutive order. Since swat model only accept watershed and streams that have consecutive gridcode for streams. So If I change gridcode, then it will also change from node and to node connection for streams. Long story 🙂 so i am trying to use arcpy to update my from node and to node when i change gridcode.
gridcode should be same as from node and then no node will also change accordingly
What about using a dictionary to convert you node data to the grid number?
# dictionary mapping {From_Node : GridCode]
conv = {2:8,3:9,7:5}
....
New_From_Node=conv[From_Node]
New_To_Node=conv[[To_Node]
....
You can even programically build your dictionary
yes that's what i did in the above code.
node_values = {} is dictionary but code gets an error when I try to change no node. It works fine for grid code and from node.
Sorry I got lost in the Nodes when reading your question!
Is there a value for the to_node you are trying to match? With the sample data you gave new_to_node = node_values[1] would fail or error because there is no lookup for it?
Do you have a default grid code for the missing node values.... if you do you could do a node_values.get(to_node,mydefaultvalue)
There is a lot of good stuff here when you have a key with no value.... Initializing a dictionary in python with a key value and no corresponding values - Stack Overflow
"to_node" depends on "from node".I just want to update "to_node". if i change "from node " lets say from node =3 has been changed to 2 then all 3's in "to node" should also changed to 2. Yes the reason I am getting error is because some values in "to_node" are occurring twice, because tributaries can drain into more than one river/streams. Repitition is ok. As long as values are being updated.But no repetition in "grid code" and "from node"
I think you're building your dictionary incorrectly. Right now, it's setting the key "FROM_NODE" to the variable new_node which is row[1].
Should it be something like this?
node_values = {}
with arcpy.da.SearchCursor(fc, ['FROM_NODE','GRID_CODE']) as cursor:
for row in cursor:
old_node = row[0]
new_node= row[1]
node_values[old_node] = new_node
If not, print your dictionary so we can see the contents.
>>> node_values My dictionary. for first part (search cursor)
{1: 1, 3: 2, 4: 5, 5: 3, 6: 4, 7: 6, 8: 8, 9: 7, 10: 12, 11: 9, 12: 10, 13: 11, 14: 13, 15: 14, 16: 19, 17: 24, 18: 15, 19: 16, 20: 17, 21: 18, 22: 20, 23: 21, 25: 22, 26: 23, 27: 26, 28: 29, 29: 25, 30: 27, 31: 33, 32: 28, 33: 32, 34: 30, 35: 31, 37: 35, 38: 34, 39: 37, 40: 36, 42: 38, 43: 39, 44: 40}
yes the code for search cursor part is correct. I matched it with attribute table(in attached shaped file).because i am updating my "from code" based on "grid code". Next step is to update "to node" but i am getting error there (update cursor part), because to_node does not have all values that "from node" has and that's how it should be. code should not care about matching it should just update "to node".
I just ran the code below:
def main():
import arcpy
fc = r'C:\GeoNet\UpdateNodes\shp\fea_c.shp'
node_values = {r[0]: r[1] for r in arcpy.da.SearchCursor(fc, ['FROM_NODE','GRID_CODE'])}
with arcpy.da.UpdateCursor(fc, ['FROM_NODE','TO_NODE','GRID_CODE']) as cursor:
for row in cursor:
row[0] = row[2] # set tonode to new equivalent node
to_node = row[1] # I get an error here
if to_node in node_values:
new_to_node = node_values[to_node]
row[1] = new_to_node
else:
print to_node, " not in dictionary"
cursor.updateRow(row)
if __name__ == '__main__':
main()
and it updated, but there are as you mentioned some case that do not have value in the dictionary:
2 not in dictionary
24 not in dictionary
36 not in dictionary
41 not in dictionary