Tải bản đầy đủ - 0 (trang)
ArcPy Cursors – Search, Insert, and Update

ArcPy Cursors – Search, Insert, and Update

Tải bản đầy đủ - 0trang

Chapter5.ArcPyCursors–Search,

Insert,andUpdate

NowthatweunderstandhowtointeractwithArcToolboxtoolsusingArcPy,andwehave

alsocoveredusingPythontocreatefunctionsandimportmodules,wehaveabasic

understandingofhowtoimproveGISworkflowsusingPython.Inthischapterwewill

coverdatacursorsandtheDataAccessmodule,introducedin10.1.Thesedataaccess

cursorsareavastimprovementonthecursorsusedinthearcgisscriptingmodule(the

precursortoArcPy)andinearlierversionsofArcPy.Notonlycanthecursorssearchdata,

aswehaveseen,buttheycanupdatedatausingtheUpdateCursorsandcanaddnewrows

ofdatausingtheInsertCursor.

Datacursorsareusedtoaccessdatarecordscontainedwithindatatables,usingarowby

rowiterativeapproach.Theconceptwasborrowedfromrelationaldatabases,wheredata

cursorsareusedtoextractdatafromtablesreturnedfromaSQLexpression.Cursorsare

usedtosearchfordata,butalsotoupdatedataortoaddnewdata.

WhenwediscusscreatingdatasearchesusingArcPycursors,wearenotjusttalkingabout

attributeinformation.Thenewdataaccessmodelcursorscaninteractdirectlywiththe

shapefield,andwhencombinedwithArcPyGeometryobjects,canperformgeospatial

functionsandreplacetheneedtopassdatatoArcToolboxtools.Dataaccesscursors

representthemostusefulinnovationyetintherealmofPythonautomationforGIS.

Inthischapterwewillcover:

UsingSearchCursorstoaccessattributeandspatialdata

UsingUpdateCursorstoadjustvalueswithinrows

Usinginsertcursorstoaddnewdatatoadataset

UsingcursorsandtheArcPyGeometryobjecttypestoperformgeospatialanalysesin

memory



Thedataaccessmodule

IntroducedwiththereleaseofArcGIS10.1,thenewdataaccessmoduleknownas

arcpy.dahasmadedatainteractioneasier,andfaster,thanallowedbypreviousdata

cursors.Byallowingfordirectaccesstotheshapefieldinavarietyofforms(shape

object,Xvalues,Yvalues,centroid,area,length,andmore),andavarietyofformats

(JavaScriptObjectNotation(JSON),KeyholeMarkupLanguage(KML),WellKnown

Binary(WKB),Well-KnownText(WKT)),thedataaccessmodulegreatlyincreasesthe

abilityofaGISanalysttoextractandcontrolshapefielddata.

Thedataaccesscursorsacceptanumberofrequiredandoptionalparameters.The

requiredparametersarethepathtothefeatureclassasastring(oravariablerepresenting

thepath)andthefieldstobereturned.Ifallfieldsaredesired,usingtheasterisknotation

andprovidealistwithanasteriskasastringasthefield’sparameter([*]).Ifonlyafew

fieldsarerequired,providethosefieldsasstringfieldnames(forexample[“NAME”,

“DATE”]).

Theotherparametersareoptionalbutareveryimportant,forbothsearchandUpdate

Cursors.AwhereclauseintheformofaSQLexpressioncanbeprovidednext;thisclause

willlimitthenumberofrowsreturnedfromthedataset(asdemonstratedbytheSQL

expressioninthescriptsinthelastchapter).TheSQLexpressionsusedbythesearchand

updatecursorsarenotcompleteSQLexpressions,astheSELECTorUPDATEcommandsare

providedautomaticallybythechoiceofcursor.OnlythewhereclauseoftheSQL

expressionisrequiredforthisparameter.

AspatialreferencecanbeprovidednextintheArcPySpatialReferenceformat;thisisnot

necessaryifthedataisinthecorrectformatbutcanbeusedtotransformdataintoanother

projectiononthefly.Thereisnowaytospecifythespatialtransformationused,however.

ThethirdoptionalparameterisaBoolean(orTrue/False)valuethatdeclareswhetherdata

shouldbereturnedinexplodedpoints(thatis,alistoftheindividualvertices)orinthe

originalgeometryformat.Thefinaloptionalparameterisanotherlistthatcanbeusedto

organizethedatareturnedbythecursor;thislistwouldincludeSQLkeywordssuchas

DISTINCT,ORBERBY,orGROUPBY.However,thisfinalparameterisonlyavailable

whenworkingwithageodatabase.

Let’stakealookatusingarcpy.da.SearchCursorforshapefieldinteractions.Ifwe

neededtoproduceaspreadsheetlistingallbusstopsalongaparticularroute,andinclude

thelocationofthedatainanX/Yformat,wecouldusetheAddXYtoolfromthe

ArcToolbox.However,thishastheeffectofaddingtwonewfieldstoourdata,whichis

notalwaysallowed,especiallywhenthedataisstoredinenterprisegeodatabaseswith

fixedschemas.Instead,we’llusetheSHAPE@XYtokenbuiltintothedataaccessmodule

toeasilyextractthedataandpassittothecreateCSV()functionfromChapter4,Complex

ArcPyScriptsandGeneralizingFunctions,alongwiththeSQLexpressionlimitingresults

tothestopsofinterest:

csvname="C:\Projects\Output\StationLocations.csv"

headers='BusLineName','BusStopID','X','Y'



createCSV(headers,csvname,'wb')

sql="(NAME='71IB'ANDBUS_SIGNAG='FerryPlaza')OR(NAME='71OB'

ANDBUS_SIGNAG='48thAvenue')"

witharcpy.da.SearchCursor(Bus_Stops,['NAME','STOPID','SHAPE@XY'],sql)

ascursor:

forrowincursor:

linename=row[0]

stopid=row[1]

locationX=row[2][0]

locationY=row[2][1]

locationY=row[2][1]

data=linename,stopid,locationX,locationY

createCSV(data,csvname)



Notethateachrowofdataisreturnedasatuple;thismakessenseastheSearchCursor

doesnotallowanydatamanipulationandtuplesareimmutableassoonastheyare

created.Incontrast,datareturnedfromUpdateCursorsisinlistformat,aslistscanbe

updated.Bothcanbeaccessedusingtheindexingasshownpreviously.

Eachrowreturnedbythecursorisatuplewiththreeobjects:thenameofthebusstop,the

busstopID,andfinallyanothertuplecontainingtheX/Ylocationofthestop.Theobjects

inthetuple,containedinthevariablerow,areaccessibleusingindexing:thebusstop

nameisatindex0,theIDisatindex1,andthelocationtupleisatindex2.

Withinthelocationtuple,theXvalueisatindex0andtheYvalueisatindex1;this

makesiteasytoaccessthedatainthelocationtuplebypassingavalueasshowninthe

following:

locationX=row[2][0]



Theabilitytoaddlistsandtuplesandevendictionariestoanotherlistortupleor

dictionaryisastrongcomponentofPython,makingdataaccesslogicalanddata

organizationeasy.

However,thespreadsheetreturnedfromthepreviouscodehasafewissues:thelocationis

returnedinthenativeprojectionofthefeatureclass(inthiscase,aStatePlaneprojection),

andtherearerowsofdatathatarerepeated.Itwouldbemuchmorehelpfulifwecould

providelatitudeandlongitudevaluesinthespreadsheetandtheduplicatevalueswere

removed.Let’susetheoptionalspatialreferenceparameterandalisttosortthedata

beforewepassittothecreateCSV()function:

spatialReference=arcpy.SpatialReference(4326)

sql="(NAME='71IB'ANDBUS_SIGNAG='FerryPlaza')OR(NAME='71OB'

ANDBUS_SIGNAG='48thAvenue')"

dataList=[]

witharcpy.da.SearchCursor(Bus_Stops,['NAME','STOPID','SHAPE@XY'],sql,

spatialReference)ascursor:

forrowincursor:

linename=row[0]

stopid=row[1]

locationX=row[2][0]

locationY=row[2][1]

data=linename,stopid,locationX,locationY



ifdatanotindataList:

dataList.append(data)

csvname="C:\Projects\Output\StationLocations.csv"

headers='BusLineName','BusStopID','X','Y'

createCSV(headers,csvname,'wb')

fordataindataList:



Thespatialreferenceiscreatedbypassingacoderepresentingthedesiredprojection

system.InthiscasethecodefortheWGS1984LatitudeandLongitudegeographicsystem

is4326andispassedtothearcpy.SpatialReference()methodtocreateaspatial

referenceobjectthatcanbepassedtotheSearchCursor.Also,theifconditionalisused

tofilterthedata,acceptingonlyonelistperstopintothelistcalleddataList.Thisnew

versionofthecodewillproduceaCSVfilewiththedesireddata.ThisCSVcouldthenbe

convertedintoaKMLwiththeserviceprovidedbywww.convertcsv.com/csv-to-kml.htm,

orevenbetter,usingPython.UsestringformattingandloopstoinsertthedataintoprebuiltKMLstrings.



Attributefieldinteractions

Apartfromtheshapefieldinteractions,anotherimprovementofferedbythedataaccess

modulecursorsistheabilitytocallthefieldsinafeatureclassbyusingalist,asdiscussed

previously.Earlierdatacursorsrequiredtheuseofalessefficientgetvaluefunctioncall,

orrequiredthefieldstobecalledasiftheyweremethodsavailabletothefunction.The

newmethodallowsforallfieldstobecalledbypassinganasterisk,avaluablemethodto

accessfieldsinfeatureclassesthathavenotbeeninspectedpreviously.

OneofthemorevaluableimprovementsistheabilitytoaccesstheUniqueIDfield

withoutneedingtoknowwhetherthedatasetisafeatureclassorashapefile.Because

shapefileshadafeatureIDorFID,andfeatureclasseshadanobjectID,itwasharderto

programaScripttooltoaccesstheuniqueIDfield.Dataaccessmodulecursorsallowfor

theuseoftheOID@stringtorequesttheuniqueIDfromeithertypeofinput.Thismakes

theneedtoknowthetypeofuniqueIDirrelevant.

Asdemonstratedpreviously,otherattributefieldsarerequestedbyastringinalist.The

fieldnamesmustmatchthetruenameofthefield;aliasnamescannotbepassedtothe

cursor.Thefieldscanbeinthelistinanyorderdesired,andwillbereturnedintheorder

requested.Onlytherequiredfieldshavetobeincludedinthelist.

Hereisademonstrationofrequestingfieldinformation:

sql="OBJECTID=1"

witharcpy.da.SearchCursor(Bus_Stops,

['STOPID','NAME','OID@'],

sql)ascursor:

forrowincursor:



Ifthefieldsinthefieldslistwereadjusted,thedataintheresultingrowwouldreflectthe

adjustment.Also,allofthemembersofthetuplereturnedbythecursorareaccessibleby

zero-basedindexing.



Updatecursors

Updatecursorsareusedtoadjustdatawithinexistingrowsofdata.Updatesbecomevery

importantwhencalculatingdataorconvertingnullvaluestoanon-nullvalue.Combined

withspecificSQLexpressions,datacanbetargetedforupdatingwithnewlycollectedor

calculatedvalues.

NotethatrunningcodecontaininganUpdateCursorwillchange,orupdate,thedataon

whichitoperates.Itisagoodideatomakeacopyofthedatatotestoutthecodebefore

runningitontheoriginaldata.

AlldataaccessmoduleSearchCursorparametersdiscussedpreviouslyarevalidfor

UpdateCursors.ThemaindifferenceisthatdatarowsreturnedbyUpdateCursorsare

returnedaslists.Becauselistsaremutable,theycanbeadjustedusingalistvalue

assignment.

Asanexample,let’simaginethatthebusline71willberenamedtothe75.Bothinbound

andoutboundlineswillbeaffected,soaSQLexpressionmustbeincludedtogetallrows

ofdataassociatedwiththeline.Oncethedatacursoriscreated,therowsreturnedmust

havethenameadjusted,addedbackintothelist,andtheUpdatecursor’supdateRow

methodmustbeinvoked.Hereishowthisscenariowouldlookincode:

sql="NAMELIKE'71%'"

witharcpy.da.UpdateCursor(Bus_Stops,['NAME'],sql),)ascursor:

forrowincursor:

lineName=row[0]

newName=lineName.replace('71','75')

row[0]=newName



TheSQLexpressionwillreturnallrowsofdatawithanamestartingwith71;thiswill

include71IBand71OB.NotethattheSQLexpressionmustbeenclosedindouble

quotes,astheattributevalueneedstobeinsinglequotes.

Foreachrowofdata,thenameatpositionzerointherowreturnedisassignedtothe

variablelineName.Thisvariable,astring,usesthereplace()methodtoreplacethe

characters71withthecharacters75.Thiscouldalsojustbereplacing1with5butI

wantedtobeexplicitastowhatisbeingreplaced.

Oncethenewstringhasbeengenerated,itisassignedtothevariablenewName.This

variableisthenaddedtothelistreturnedbythecursorusinglistassignment;thiswill

replacethedatavaluethatinitiallyoccupiedthezeropositioninthelist.Oncetherow

valuehasbeenassigned,itisthenpassedtothecursor’supdateRow()method.This

methodacceptstherowandupdatesthevalueinthefeatureclassforthatparticularrow.



Updatingtheshapefield

Foreachrow,allvaluesincludedinthelistreturnedbythecursorareavailableforupdate,

excepttheuniqueID(whilenoexceptionwillbethrown,theUIDvalueswillnotbe

updated).Eventheshapefieldcanbeadjusted,withafewcaveats.Themaincaveatisthat

theupdatedshapefieldmustbethesamegeometrytypeastheoriginalrow,apointcanbe

replacedwithapoint,alinewithaline,andapolygonwithanotherpolygon.



Adjustingapointlocation

Ifabusstopwasmoveddownthestreetfromitscurrentposition,itwouldneedtobe

updatedusinganUpdateCursor.ThisoperationwillrequireanewlocationinanX/Y

format,preferablyinthesameprojectionasthefeatureclasstoavoidanylossoflocation

fidelityinaspatialtransformation.Therearetwomethodsavailabletousforcreatinga

newpointlocation,dependingonthemethodusedtoaccessthedata.Thefirstmethodis

usedwhenthelocationdataisrequestedusingtheSHAPE@tokens,andrequirestheuseof

anArcPyGeometrytype,inthiscasethePointtype.TheArcPyGeometrytypesare

discussedindetailinthenextchapter.

sql='OBJECTID<5'

witharcpy.da.UpdateCursor(Bus_Stops,['OID@','SHAPE@'],sql)ascursor:

forrowincursor:

row[1]=arcpy.Point(5999783.78657,2088532.563956)



BypassinganXandYvaluetotheArcPyPointGeometry,aPointshapeobjectiscreated

andpassedtothecursorintheupdatedlistreturnedbythecursor.Assigninganew

locationtotheshapefieldinatuple,thenusingthecursor’supdateRow()methodallows

theshapefieldvaluetobeadjustedtothenewlocation.Becausethefirstfourbusstops

areatthesamelocation,theyareallmovedtothenewlocation.

Thesecondmethodappliestoallotherformsofshapefieldinteractions,includingthe

SHAPE@XY,SHAPE@JSON,SHAPE@KML,SHAPE@WKT,andSHAPE@WKBtokens.Theseareupdated

bypassingthenewlocationintheformatrequestedbacktothecursorandupdatingthe

list:

sql='OBJECTID<5'

witharcpy.da.UpdateCursor(Bus_Stops,['OID@','SHAPE@XY'],sql)ascursor:

forrowincursor:

row[1]=(5999783.786500007,2088532.5639999956)



HereisthesamecodeusingtheSHAPE@JSONkeywordandaJSONrepresentationofthe

data:

sql='OBJECTID<5'

witharcpy.da.UpdateCursor(Bus_Stops,['OID@','SHAPE@JSON'],sql)as

cursor:

forrowincursor:

printrow

row[1]=u'{"x":5999783.7865000069,"y":2088532.5639999956,

"spatialReference":{"wkid":102643}}'



Aslongasthekeyword,thedataformat,andthegeometrytypematch,thelocationis

updatedtothenewcoordinates.Thekeywordmethodisveryusefulwhenupdatingpoints,

however,theSHAPE@XYkeyworddoesnotworkwithlinesorpolygonsasthelocation

returnedrepresentsthecentroidoftherequestedgeometry.



DeletingarowusinganUpdateCursor

Ifweneedtoremovearowofdata,theUpdateCursorhasadeleteRowmethodthatworks

toremovetherow.Notethatthiswillcompletelyremovethedatarow,makingit

unrecoverable.Thismethoddoesnotrequireaparametertobepassedtoit;instead,itwill

removethecurrentrow:

sql='OBJECTID<2'

Bus_Stops=r'C:\Projects\PacktDB.gdb\Bus_Stops'

witharcpy.da.UpdateCursor(Bus_Stops,

['OID@',

'SHAPE@XY'],sql)ascursor:

forrowincursor:



UsinganInsertCursor

Nowthatwehaveagrasponhowtoupdateexistingdata,let’sinvestigateusingInsert

Cursorstocreatenewdataandaddittoafeatureclass.Themethodsinvolvedarevery

similartousingotherdataaccesscursors,exceptthatwedonotneedtocreateaniterable

cursortoextractrowsofdata;instead,wewillcreateacursorthatwillhavethespecial

insertRowmethodthatiscapableofaddingdatatothefeatureclassrowbyrow.

TheInsertCursorcanbecalledusingthesamewith..assyntaxbutgenerallyitiscreated

asavariableintheflowofthescript.



Note

Notethatonlyonecursorcanbeinvokedatatime;anexception(aPythonerror)willbe

generatedwhencreatingtwoinsert(orupdate)cursorswithoutfirstremovingtheinitial

cursorusingthePythondelkeywordtoremovethecursorvariablefrommemory.Thisis

whythewith..assyntaxispreferredbymany.

Thedataaccessmodule’sInsertCursorrequiressomeofthesameparametersastheother

cursors.Thefeatureclasstobewrittentoandthelistoffieldsthatwillhavedatainserted

(thisincludestheshapefield)arerequired.Thespatialreferencewillnotbeusedasthe

newshapedatamustbeinthesamespatialreferenceasthefeatureclass.NoSQL

expressionisallowedforanInsertCursor.

Thedatatobeaddedtothefeatureclasswillbeintheformofatupleoralist,inthesame

orderasthefieldsthatarelistedinthefieldslistparameter.Onlyfieldsofinterestneedto

beincludedinthelistoffields,meaningnoteveryfieldneedsavalueinthelisttobe

added.Whenaddinganewrowofdatatoafeatureclass,theuniqueIDwillautomatically

begenerated,makingitunnecessarytoexplicitlyincludetheuniqueID(intheformofthe

OID@keyword)inthelistoffieldstobeadded.

Let’sexplorecodethatcouldbeusedtogenerateanewbusstop.We’llwritetoatest

datasetcalledTestBusStops.WeareonlyinterestedintheNameandStopIDfields,so

thosefieldsalongwiththeshapefield(whichisinaStatePlaneprojectionsystem)willbe

includedinthedatalisttobeadded:

Bus_Stops=r'C:\Projects\PacktDB.gdb\TestBusStops'

insertCursor=arcpy.da.InsertCursor(Bus_Stops,['SHAPE@',

'NAME','STOPID'])

coordinatePair=(6001672.5869999975,2091447.0435000062)

newPoint=arcpy.Point(*coordinatePair)

dataList=[newPoint,'NewStop1',112121]

insertCursor.insertRow(dataList)

delinsertCursor



Ifthereisaniterablelistofdatatobeinsertedintothefeatureclass,createtheInsert

Cursorvariablebeforeenteringtheiteration,anddeletetheInsertCursorvariableoncethe

datahasbeeniteratedthrough,orusethewith..asmethodtoautomaticallydeletetheInsert

Cursorvariablewhentheiterationiscomplete:

Bus_Stops=r'C:\Projects\PacktDB.gdb\TestBusStops'



listOfLists=[[(6002672.58675,2092447.04362),'NewStop2',112122],

[(6003672.58675,2093447.04362),'NewStop3',112123],

[(6004672.58675,2094447.04362),'NewStop4',112124]

]



witharcpy.da.InsertCursor(Bus_Stops,

['SHAPE@',

'NAME',

'STOPID'])asiCursor:

fordataListinlistOfLists:

newPoint=arcpy.Point(*dataList[0])

dataList[0]=newPoint



Asalist,thelistOfListsvariableisiterable.EachlistwithinitisconsideredasdataList

intheiteration,andthefirstvalueindataList(thecoordinatepair)ispassedtothe

arcpy.Point()functiontocreateaPointobject.Thearcpy.Point()functionrequires

twoparameters,XandY;theseareextractedfromthecoordinatepairtupleusingthe

asterisk,which‘explodes’thetupleandpassesthevaluesitcontainstothefunction.The

PointobjectisthenaddedbackintodataListusinganindex-basedlistassignment,

whichwouldnotbeavailabletousifthedataListvariablewasatuple(wewouldinstead

havetocreateanewlistandaddinthePointobjectandtheotherdatavalues).



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

ArcPy Cursors – Search, Insert, and Update

Tải bản đầy đủ ngay(0 tr)

×