Tuesday, June 26, 2012

Introduction to the Update Cursor (arcpy.da) at 10.1

The UpdateCursor creates a read-write access to records returned from a feature class or table.
Returns an iterator of lists. The order of values in the list matches the order of fields specified by the field_names argument.  UpdateCursor objects can be iterated using a for loop and it supports with statements. Using a with statement will ensure that the database locks are removed.

You can use both an insert and update cursor at the same time if an edit session is opened.


from arcpy import da
fc = r"c:\temp\samples.gdb\nests"
fields = ('BirdPop', 'Rank')

with da.UpdateCursor(fc, fields) as cursor:
    for row in cursor:
        if (row[0] >= 0 and row[0] <= 10):
            row[1] = 1
        elif (row[0] > 10 and row[0] <= 20):
            row[1] = 2
        elif (row[0] > 20 and row[0]<= 30):
            row[1] = 3
        elif (row[0] > 20):
            row[1] = 4

In this simple example, you see that you can use conditional statements to change values within the 'with' statement.


Friday, June 22, 2012

ArcGIS API for Silveright 3.0 Released

I like Silverlight as a programming language, and now the ArcGIS API for Silveright is released.  You can check out the announcement here.


Wednesday, June 20, 2012

Working with BLOB data at 10.1 (arcpy.da)

Reading and writing BLOB data has always been an issue previous to 10.1, but now it's not a problem.  A reader pointed out that fact the other day, so I thought why not point this out to everyone.
From the help (source: resourcebeta.arcgis.com):
A BLOB is data stored as a long sequence of binary numbers. ArcGIS stores annotation and dimensions as BLOBs, and items such as images, multimedia, or bits of code can be stored in this type of field. You can use a cursor to load or view the contents of a BLOB field.
In Python, BLOB fields can accept strings, bytearray, and memoryviews. When reading BLOB fields, a memoryview object is returned.
So what does this mean to you.  We'll it's time to store those documents, pictures from vacation, and videos with geo tags in a spatial database.

Writing Blobs :
from arcpy import da

myFile = open(r"c:\temp\image.jpg",'rb').read()

with da.InsertCursor(r"c:\temp\demo.gdb\table",['blobFieldname','fileName']) as cursor:

Reading Blobs:

from arcpy import da
import os
with da.SearchCursor(r"c:\temp\demo.gdb\table",['blobFieldname','fileName']) as cursor:
   for row in cursor:
      binaryRep = row[0]
      fileName = row[1]
      # save to disk
      open(r"c:\saveFolder" + os.sep + fileName, 'wb').write(binaryRep.tobytes())
      del row
      del binaryRep
      del fileName

Writing and reading Blob fields involves using the python built in open().  This function can open up files in various modes, but ensure that the method used are the binary modes 'rb' (read binary) and 'wb' (write binary), or else this process will not work.  You can essentially open up any file as a Blob, so stick whatever you want in there, but realize that this can balloon the size of your database up greatly.  It does however open up a whole new host of ways of transporting file based data.  Off the top of my head, I can image how this could improve data transport for local parallel processing methods of spatial and non-spatial data.


Tuesday, June 19, 2012

SearchCursor (arcpy.da) 10.1 Continued

The new cursor objects contain a very helpful property called fields.  This property returns a tuple of field names defined in the field_names argument.  This means that if you pass "*" for all fields you can then get the associated field to the associated value.

Remember, cursor objects will ignore BLOB and Raster fields.

import arcpy
from arcpy import da
fc = r"c:\temp\demo_polygon.shp"
with da.SearchCursor(fc,"*") as rows:
   for field in rows.fields:
      print field

So in this example, the cursor will print all the fields being accessed.  It will also show the type of Shape field is being returned.  If all fields is used ("*"), then the SHAPE@XY property returned by default.


Monday, June 18, 2012

10.1 SearchCursor (arcpy.da)

The Search Cursor object creates read-only access to the records in a feature class or table.  It will return an iterator of tuples.  The order of values matches the order of fields mentioned by the field_names argument.

When comparing the old search cursor to the new search cursor, functionally they are basically the same, except the data access module is better, stronger, and faster. It's like the Six Million Dollar Man of upgrades in ArcPy.

Looking at the inputs:
SearchCursor (in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})

The two biggest differences between arcpy.SearchCursor and arcpy.da.SearchCursor, is the field_names is required, and the optional parameter explode_to_points.

Paramter field_names can be "*", which means all fields, but it does exclude BLOB and raster fields.  This is required because you should only be returning what you need.  The other interesting aspect of the is the way you can obtain geometry and other field information using the @.

  • SHAPE@XY —A tuple of the feature's centroid x,y coordinates
  • SHAPE@TRUECENTROID —A tuple of the feature's true centroid x,y coordinates
  • SHAPE@X —A double of the feature's x-coordinate
  • SHAPE@Y —A double of the feature's y-coordinate
  • SHAPE@Z —A double of the feature's z-coordinate
  • SHAPE@M —A double of the feature's m-value
  • SHAPE@ —A geometry object for the feature
  • SHAPE@AREA —A double of the feature's area
  • SHAPE@LENGTH —A double of the feature's length
  • OID@ —The value of the ObjectID field

The parameter explode_to_points is a boolean value.  If you specify the value to true, it will explode multi-geometry values into there own rows.  This means if you have a 5 multipoint geometry object, it will have 5 rows instead of 1.

Example: Basic Use
import arcpy
fc = r"c:\temp\wells.shp"
fields = ["WELL_ID","TYPE","SHAPE@XY"]
with arcpy.da.SearchCursor(fc,fields) as cursor:
   for row in cursor:
      print "{0}, {1}, {2}".format(row[0],row[1],row[2])

So here we have just a simple read-only example where the user will pass in a feature class and the fields needed to query.  It will print the information out on the screen.  Notice the usage of the with statement.  This is great because it automatically cleans up the cursor object.  This means no more del statements and help reduce the number of cursor locks on data.


Friday, June 15, 2012

Introducing the Data Access Module (arcpy.da) at 10.1

The data access module also known as arcpy.da is used to manipulate and search data.  It allows control of an edit session, faster and better cursor support, function to convert to and from numpy arrays, and supports versioning, replicas, domains, and subtypes work flows.

The data access module has the following functions:

  • ExtendTable - Joins the content of a numpy array based on a common attribute field.  This is like a table join but more flexible.
  • FeatureClassToNumPyArray - this convert a feature class to a numpy structured array
  • ListDomains - Lists the attribute domains in a geodatabase
  • ListReplicas - Lists replicas in a work space
  • ListSubtypes - returns a dictionary of subtypes for a table or feature class
  • ListVersions - list the versions in the work space
  • NumPyToFeatureClass - converts a numpy array to a point feature class
  • NumPyToTable - converts a numpy array to a table
  • TableToNumPyArray - converts a table to numpy array

The data access classes:

  • Domain - the domain object properties that describes an attribute domain
  • Editor - editor class allows use of edit sessions and operations to manage database transactions.  This means rollbacks, and better error handling!
  • InsertCursor - adds new rows to a table or feature class
  • Replica - contains properties of a replica
  • SearchCursor - read only access to a table or feature class
  • UpdateCursor - allows read/write access to a table or feature class.  This is what you use to update or delete a row.
  • Version - contains properties that describe a version.

I plan on detailing these items in future posts.

Thursday, June 14, 2012

Random Number Generator (arcpy.env)

This is a tool that creates a random number based on a seed number and an algorithm selection.
Inputs are as follows:
  1. Seed—The seed is an integer value and is used to initiate the random number generator. The default value is 0.
  2. Random Generator Type—The random generator algorithm.

    • ACM599—ACM collected algorithm 599. This is the default.
    • MERSENNE_TWISTER—Mersenne Twister mt19937.
    • STANDARD_C—Standard C Rand

So to create a random number generation environmental variable you can do it two ways:

Option 1:

from arcpy import env
env.randomGenerator = "4 MERSENNE_TWISTER"

Option 2:

from arcpy import env
env.randomGenerator = arcpy.CreateRandomValueGenerator(4, "MERSENNE_TWISTER")

To produce a random number, the easiest way is to use the arcpy.CalculateValue() and get the results from that tool.

import arcpy
arcpy.env.randomGenerator = "4 MERSENNE_TWISTER"
result = arcpy.CalculateValue_management("arcgis.rand('normal 0.0 10.0')")
randomValue = float(result.getOutput(0))
print randomValue

The code should print a random number.

It should be noted that this environmental variable will effect any tool that uses random values.


Wednesday, June 13, 2012

env.ScratchGDB (ArcPy 10.1)

A new environmental parameter as 10.1 is env.scratchGDB.  This environmental parameter is guarantees to have a temporary scratch file geodatabase for your writing pleasure.  This means no more checking to see if a user created a file geodatabase for doing some work.
I personally think this is great.  It takes a common task and puts it into core.  Bravo ArcPy Development Team!
From this help:
Its primary purpose is for use by scripts and models as geoprocessing services, with the added focus of only pointing to a known geodatabase. When ArcGIS for Server executes a geoprocessing task, the scratch GDB is always available to write output to. This environment is also useful in authoring scripts and models for use on the desktop. Writing output to the scratch GDB will make your tool portable, because this location will always be available or created at execution time.

Some notes on the env.scratchGDB:

  1. Scratch GDB will exist if called and user will have write access to the file geodatabase
  2. Scratch GDB is read-only.  You can only change the location of the scratch GDB by changing the env.scratchWorkspace 
  3. If the env.scratchWorkspace is not set, then it defaults to the user's temporary directory

>>> import arcpy

>>> from arcpy import env
>>> env.scratchWorkspace = r"c:\temp"
>>> print env.scratchGDB


Tuesday, June 12, 2012

Introducing env.scratchFolder (ArcGIS 10.1)

The scratch folder is a new environmental variable that is used for the development of both published and non-published scripts.  It will point to a known folder that exists, which is very nice because at 10.0, env.scratchWorkspace or env.workspace could always be set to None or even worse set to a file geodatabase.
From the online help:
"The Scratch Folder is the location of a folder you can use to write file-based data, such as shapefiles, text files, and layer files. It is a read-only environment that is managed by ArcGIS. 
The Scratch Folder environment complements the scratch workspace environment. Its primary purpose is for use by scripts and models as geoprocessing services, with the added focus of pointing only to a known folder. When ArcGIS for Server executes a geoprocessing task, the Scratch Folder is always available to write output to. This environment is also useful in authoring scripts and models for use on the desktop. Writing output to the Scratch Folder will make your tool portable, because this location will always be available or created at execution time."
 Some important notes about env.scratchFolder:

  1. It will always exists
  2. It's read only property
  3. It will always be folder even if your scratch workspace is set to a file geodatabase
  4. If there is no Scratch Workspace set in your map document, or you're working in an environment where the Scratch Workspace has not been explicitly set, the Scratch Folder defaults to the current user's temporary files directory. This directory is typically at C:\Users\\AppData\Local\Temp on Windows 7 or C:\Documents and Settings\\Localsystem\Temp on Windows XP.

>>> import arcpy
>>> from arcpy import env
>>> env.scratchWorkspace = r"c:\temp\myfgdb.gdb"
>>> print env.scratchFolder


Monday, June 11, 2012

Using SQL to Get n number of Rows

When you query spatial data in ArcMap/Catalog/Python, etc.. you cannot limit the row search by default and you can only specify the where part of the sql statement: "SELECT * from < DATASET > WHERE" and then you can specify TYPE = '1'.

Let's assume you want to just get back n number of rows.  If you are using SDE, you could use ArcSDESQLExecute's methods to perform your sql, but you could also use a sub-query. 

Take your default statement that ArcMap allows you to perform on a layer: 

     "Select * from wgs.temp where "

Since we want to just get back n number of rows, use the OBJECTID field as a reference and the 'in' function:

    "Select * from wgs.temp where OBJECT in (select OBJECTID  from wgs.temp where rownum <= 5)"

This will return 5 rows in the data set.  If you want 10, 15, of n number of rows, replace the 5 with whatever value you want.  You can apply this to update and search cursors on SDE data only.


Thursday, June 7, 2012

Monday, June 4, 2012

Creating a Single Directory or Multiple Directories

When automating processes, you should be very aware of system directory structures and the directory structure that your processes need to function properly.

The OS module has a collection of directory tools to make or remove directories as well as checking if they exist or not.

The standard make a directory function is the os.mkdir()

>>> import os
>>> directories = r"c:\temp3\level1"
>>> os.mkdir(directories)

The other folder creation tool I find very helpful is the os.makedirs(), which will generate a several folders at once.

>>> import os
>>> directories = r"c:\temp3\level1\level2\level3\level4"
>>> os.makedirs(directories)