<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="https://www.w3.org/2005/Atom">
  <channel>
    <title>Arcpy on Josh Werts</title>
    <link>https://joshwerts.com/tags/arcpy/</link>
    <description>Recent content in Arcpy on Josh Werts</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 16 Jan 2018 13:51:36 -0500</lastBuildDate>
    <atom:link href="https://joshwerts.com/tags/arcpy/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Group by query in a file geodatabase</title>
      <link>https://joshwerts.com/blog/2018/01/16/group-by-query-in-a-file-geodatabase/</link>
      <pubDate>Tue, 16 Jan 2018 13:51:36 -0500</pubDate>
      
      <guid>https://joshwerts.com/blog/2018/01/16/group-by-query-in-a-file-geodatabase/</guid>
      <description>&lt;p&gt;File geodatabase feature classes and tables lack some of the more advanced ability to query that a true relational database supports.  Sometimes these queries can be simulated with arcpy cursors; one good example is a SQL group by query.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Typical SQL&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-sql&#34;&gt;SELECT field, count(*) from table group by field order by count(*) desc;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;In arcpy&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;from collections import Counter

def group_by_count(table_or_fc, fields):
    &amp;quot;&amp;quot;&amp;quot; Returns dictionary containing count of unique items &amp;quot;&amp;quot;&amp;quot;
    counter = Counter()
    with arcpy.da.SearchCursor(table_or_fc, fields) as curs:
        for row in curs:
            # no need to store as a tuple if only 1 field, just store the value
            if len(row) == 1:
                row = row[0]
            counter[row] += 1
    return counter


def group_by_count_formatted(table_or_fc, fields):
    &amp;quot;&amp;quot;&amp;quot; prints out counts of unique values &amp;quot;&amp;quot;&amp;quot;
    counter = group_by_count(table_or_fc, fields)
    # sort yields highest count records first (order by count(*) desc)
    for key, count in sorted(counter.items(), reverse=True, key=lambda item: item[1]):
        print(&amp;quot;{}: {:,}&amp;quot;.format(str(key), count))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Example usage in ArcMap Python console (single field)&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;&amp;gt;&amp;gt;&amp;gt; group_by_count(&#39;junctions&#39;, &#39;ImpedanceType&#39;)
Counter({u&#39;SmallStreet&#39;: 455145, u&#39;LargeStreet&#39;: 28714, u&#39;Stream&#39;: 9375, u&#39;RailRoad&#39;: 1742})

&amp;gt;&amp;gt;&amp;gt; group_by_count_formatted(&#39;junctions&#39;, &#39;ImpedanceType&#39;)
SmallStreet: 455,145
LargeStreet: 28,714
Stream: 9,375
RailRoad: 1,742
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Example usage in ArcMap Python console (multiple fields)&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;&amp;gt;&amp;gt;&amp;gt; group_by_count(&#39;junctions&#39;, [&#39;ImpedanceType&#39;, &#39;InfrastructureType&#39;])
Counter({(&#39;SmallStreet&#39;, &#39;New&#39;): 318834, (&#39;LargeStreet&#39;, &#39;New&#39;): 28710, (&#39;Stream&#39;, &#39;New&#39;): 18379, (&#39;Stream&#39;, &#39;Aerial&#39;): 5806, (&#39;RailRoad&#39;, &#39;New&#39;): 4043, (&#39;Stream&#39;, &#39;Underground&#39;): 3227, (&#39;RailRoad&#39;, &#39;Aerial&#39;): 1035, (&#39;RailRoad&#39;, &#39;Underground&#39;): 668})

&amp;gt;&amp;gt;&amp;gt; group_by_count_formatted(&#39;junctions&#39;, [&#39;ImpedanceType&#39;, &#39;InfrastructureType&#39;])
(&#39;SmallStreet&#39;, &#39;New&#39;): 318,834
(&#39;LargeStreet&#39;, &#39;New&#39;): 28,710
(&#39;Stream&#39;, &#39;New&#39;): 18,379
(&#39;Stream&#39;, &#39;Aerial&#39;): 5,806
(&#39;RailRoad&#39;, &#39;New&#39;): 4,043
(&#39;Stream&#39;, &#39;Underground&#39;): 3,227
(&#39;RailRoad&#39;, &#39;Aerial&#39;): 1,035
(&#39;RailRoad&#39;, &#39;Underground&#39;): 668
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These functions aren&amp;rsquo;t going to be as efficient as a SQL query, but they can be quite useful sometimes for ad-hoc data exploration - especially in the Arcmap/Pro console.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>FeatureClass from JSON</title>
      <link>https://joshwerts.com/blog/2016/10/14/featureclass-from-json/</link>
      <pubDate>Fri, 14 Oct 2016 10:07:44 -0400</pubDate>
      
      <guid>https://joshwerts.com/blog/2016/10/14/featureclass-from-json/</guid>
      <description>&lt;p&gt;I keep forgetting how to do this after several months pass by and it&amp;rsquo;s certainly not obvious&amp;hellip;&lt;/p&gt;

&lt;p&gt;ESRI provides a tool for converting JSON to FeatureClass but it requires reading the JSON from a .json file: &lt;a href=&#34;https://pro.arcgis.com/en/pro-app/tool-reference/conversion/json-to-features.htm&#34;&gt;JSON to Features&lt;/a&gt;.  That extra step of writing out and reading from a file just seems completely unnecessary.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the alternative lesser known and not obvious way to do it:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;valid_featureset_json = \
&amp;quot;&amp;quot;&amp;quot;{
    &amp;quot;displayFieldName&amp;quot;: &amp;quot;&amp;quot;,
    &amp;quot;fieldAliases&amp;quot;: {
        &amp;quot;OBJECTID&amp;quot;: &amp;quot;OBJECTID&amp;quot;,
        &amp;quot;Description&amp;quot;: &amp;quot;Description&amp;quot;
    },
    &amp;quot;geometryType&amp;quot;: &amp;quot;esriGeometryPoint&amp;quot;,
    &amp;quot;spatialReference&amp;quot;: {
        &amp;quot;wkid&amp;quot;: 4326,
        &amp;quot;latestWkid&amp;quot;: 4326
    },
    &amp;quot;fields&amp;quot;: [
        {
            &amp;quot;name&amp;quot;: &amp;quot;OBJECTID&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;esriFieldTypeOID&amp;quot;,
            &amp;quot;alias&amp;quot;: &amp;quot;OBJECTID&amp;quot;
        },
        {
            &amp;quot;name&amp;quot;: &amp;quot;Description&amp;quot;,
            &amp;quot;type&amp;quot;: &amp;quot;esriFieldTypeString&amp;quot;,
            &amp;quot;alias&amp;quot;: &amp;quot;Description&amp;quot;,
            &amp;quot;length&amp;quot;: 50
        }
    ],
    &amp;quot;features&amp;quot;: [
        {
            &amp;quot;attributes&amp;quot;: {
                &amp;quot;OBJECTID&amp;quot;: 1,
                &amp;quot;Description&amp;quot;: &amp;quot;This is a test feature.&amp;quot;
            },
            &amp;quot;geometry&amp;quot;: {
                &amp;quot;x&amp;quot;: -123.80816799999991,
                &amp;quot;y&amp;quot;: 39.40451500000006
            }
        },
        {
            &amp;quot;attributes&amp;quot;: {
                &amp;quot;OBJECTID&amp;quot;: 2,
                &amp;quot;Description&amp;quot;: &amp;quot;This is aanother test feature.&amp;quot;
            },
            &amp;quot;geometry&amp;quot;: {
                &amp;quot;x&amp;quot;: -123.80816839299996,
                &amp;quot;y&amp;quot;: 39.404514814000095
            }
        }
    ]
}&amp;quot;&amp;quot;&amp;quot;

# convert to RecordSet object (should be able to use this most places FeatureSet would be called for)
record_set = arcpy.AsShape(valid_featureset_json, True)

# If you need a FeatureClass, just copy into one
output_fc = r&#39;in_memory\\output_fc&#39;
arcpy.management.CopyFeatures(record_set, output_fc)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And that&amp;rsquo;s it!  No need to write the json to file.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Fun with Python Sets (and arcpy)</title>
      <link>https://joshwerts.com/blog/2016/07/21/fun-with-python-sets-and-arcpy/</link>
      <pubDate>Thu, 21 Jul 2016 17:38:05 -0400</pubDate>
      
      <guid>https://joshwerts.com/blog/2016/07/21/fun-with-python-sets-and-arcpy/</guid>
      <description>&lt;p&gt;I often forget about the Python &lt;code&gt;set&lt;/code&gt;, so this is a fun reminder to myself to keep it in mind.  Here&amp;rsquo;s a neat example of using a set for deleting fields.&lt;/p&gt;

&lt;p&gt;This function deletes all of the fields &lt;em&gt;except&lt;/em&gt; the ones you specify:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def delete_all_fields_except(fc, keep_fields):
    &amp;quot;&amp;quot;&amp;quot; deletes all fields except those specfied as keep_fields &amp;quot;&amp;quot;&amp;quot; 
    # create set of all possible fields but exclude OBJECTID, SHAPE, etc.
    all_fields = set(f.name for f in arcpy.ListFields(fc) if not f.required)

    # get a list of fields in the featureclass but not in the list of fields to keep
    # using set.difference()
    
    delete_fields = list(all_fields.difference(keep_fields))
    
    # delete out all the fields
    arcpy.management.DeleteField(fc, delete_fields)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Usage:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# Assume our feature class has the following fields:
print([f.name for f in arcpy.ListFields(fc)])
# [&#39;OBJECTID&#39;, &#39;Shape&#39;, &#39;field1&#39;, &#39;field2&#39;, &#39;field3&#39;, &#39;field4&#39;, &#39;field5&#39;]

keep_fields = [&#39;field1&#39;, &#39;field3&#39;]
delete_all_fields_except(fc, keep_fields)

print([f.name for f in arcpy.ListFields(fc)])
# [&#39;OBJECTID&#39;, &#39;Shape&#39;, &#39;field1&#39;, &#39;field3&#39;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is pretty simple example and you could obviously accomplish this without using set, but set is more elegant and more efficient (probably doesn&amp;rsquo;t matter much here).  Perhaps I&amp;rsquo;ll update this post with more advanced usage now that this is here to remind me to think about sets!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>arcpy: Efficient Geometry Creation</title>
      <link>https://joshwerts.com/blog/2016/02/04/arcpy-efficient-geometry-creation/</link>
      <pubDate>Thu, 04 Feb 2016 15:10:09 -0500</pubDate>
      
      <guid>https://joshwerts.com/blog/2016/02/04/arcpy-efficient-geometry-creation/</guid>
      <description>

&lt;p&gt;Sometimes every second counts&amp;hellip; and even if it doesn&amp;rsquo;t, it&amp;rsquo;s still interesting to see the quirks of a familiar library.&lt;/p&gt;

&lt;p&gt;It turns out that object creation can be somewhat expensive (especially when you&amp;rsquo;re talking about Python &amp;ndash;&amp;gt; ArcObjects &amp;ndash;&amp;gt; COM).  With arcpy (and underlying ArcObjects), there are some objects which can be reused to gain some efficiency.&lt;/p&gt;

&lt;p&gt;An interesting example is simply creating a polyline from a pair of points.&lt;/p&gt;

&lt;h2 id=&#34;example-creating-a-2-point-polyline:a6ccf97ec21661e841aba6ff978f1848&#34;&gt;Example: Creating a 2 point polyline&lt;/h2&gt;

&lt;h3 id=&#34;simplest-form:a6ccf97ec21661e841aba6ff978f1848&#34;&gt;Simplest form:&lt;/h3&gt;

&lt;p&gt;In its simplest form, you may write:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def create_line_simple(point1_x_and_y, point2_x_and_y, spatial_ref):
    &amp;quot;&amp;quot;&amp;quot; creates polyline from pair of (x,y) tuples &amp;quot;&amp;quot;&amp;quot;
    start_point = arcpy.Point(*point1_x_and_y)
    end_point = arcpy.Point(*point2_x_and_y)
    array = arcpy.Array([start_point, end_point])
    polyline = arcpy.Polyline(array, spatial_ref)
    return polyline

# Usage:
polyline = create_line_simple((-81.60, 36.20), (-81.70, 36.30), arcpy.SpatialReference(4326))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There&amp;rsquo;s nothing wrong with this code.  In fact, if you&amp;rsquo;re only creating a few polylines, stop here.  It&amp;rsquo;s readable and gets the job done.&lt;/p&gt;

&lt;h3 id=&#34;a-little-more-efficient:a6ccf97ec21661e841aba6ff978f1848&#34;&gt;A little more efficient:&lt;/h3&gt;

&lt;p&gt;However, if you&amp;rsquo;re creating thousands of polylines, some time can be saved by reusing arcpy.Point objects.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# modules scoped private variables
_start_point = arcpy.Point()
_end_point = arcpy.Point()

def create_line_reuse_points(point1_x_and_y, point2_x_and_y, spatial_ref):
    &amp;quot;&amp;quot;&amp;quot; creates polyline from pair of (x,y) tuples &amp;quot;&amp;quot;&amp;quot;
    _start_point.X, _start_point.Y = point1_x_and_y
    _end_point.X, _end_point.Y = point2_x_and_y
    array = arcpy.Array([_start_point, _end_point])
    polyline = arcpy.Polyline(array, spatial_ref)
    return polyline
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this case, we&amp;rsquo;re creating 2 module scoped points only once and then setting the X and Y properties on those points.  The arcpy.Polyline constructor reads X and Y from those points, but it doesn&amp;rsquo;t maintain a reference to the points.  Setting properties on the existing objects is a bit more efficient than creating new objects every time and since references aren&amp;rsquo;t maintained to those objects, we&amp;rsquo;re safe from a memory perspective.&lt;/p&gt;

&lt;h3 id=&#34;even-more-efficient:a6ccf97ec21661e841aba6ff978f1848&#34;&gt;Even more efficient:&lt;/h3&gt;

&lt;p&gt;Why not go ahead and reuse the arcpy.Array as well?  Once again, arcpy.Polyline() only reads data from the array and doesn&amp;rsquo;t maintain a reference.  Make sure to removeAll() from array to clean up.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# modules scoped private variables
_start_point = arcpy.Point()
_end_point = arcpy.Point()
_array = arcpy.Array()

def create_line_reuse_points_array(point1_x_and_y, point2_x_and_y, spatial_ref):
    &amp;quot;&amp;quot;&amp;quot; creates polyline from pair of (x,y) tuples &amp;quot;&amp;quot;&amp;quot;
    _start_point.X, _start_point.Y = point1_x_and_y
    _end_point.X, _end_point.Y = point2_x_and_y
    _array.add(_start_point)
    _array.add(_end_point)
    polyline = arcpy.Polyline(_array, spatial_ref)
    _array.removeAll()
    return polyline
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;how-much-more-efficient-is-this-approach:a6ccf97ec21661e841aba6ff978f1848&#34;&gt;How much more efficient is this approach?&lt;/h2&gt;

&lt;p&gt;Here are the results (in seconds) for creating 100,000 polylines with each function (Python 3.4.1 w/ ArcGIS Pro on Core i7-4712HQ):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Create line simple:
0:00:21.071529

Create line reuse points:
0:00:17.813275

Create line reuse points and array:
0:00:16.277035
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Is it a huge difference?  Not really.  But if you have a process that creates a large amount of geometries, it&amp;rsquo;s worth considering reusing a few objects.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the full test script to produce the above results:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import arcpy
from datetime import datetime as dt


def time_me(n):
    &amp;quot;&amp;quot;&amp;quot; decorator to print total time to run function n number of times &amp;quot;&amp;quot;&amp;quot;
    def time_me_decorator(f):
        def wrapper(*args):
            start = dt.now()
            for _ in range(n):
                f(*args)
            print(dt.now() - start)
        return wrapper
    return time_me_decorator


REPETITIONS = 100000

######## Simple Case

@time_me(REPETITIONS)
def create_line_simple(point1_x_and_y, point2_x_and_y, spatial_ref):
    &amp;quot;&amp;quot;&amp;quot; creates polyline from pair of (x,y) tuples &amp;quot;&amp;quot;&amp;quot;
    start_point = arcpy.Point(*point1_x_and_y)
    end_point = arcpy.Point(*point2_x_and_y)
    array = arcpy.Array([start_point, end_point])
    polyline = arcpy.Polyline(array, spatial_ref)
    return polyline


######## Reuses the point objects

# modules scoped private functions
_start_point = arcpy.Point()
_end_point = arcpy.Point()

@time_me(REPETITIONS)
def create_line_reuse_points(point1_x_and_y, point2_x_and_y, spatial_ref):
    &amp;quot;&amp;quot;&amp;quot; creates polyline from pair of (x,y) tuples &amp;quot;&amp;quot;&amp;quot;
    _start_point.X, _start_point.Y = point1_x_and_y
    _end_point.X, _end_point.Y = point2_x_and_y
    array = arcpy.Array([_start_point, _end_point])
    polyline = arcpy.Polyline(array, spatial_ref)
    return polyline


######## Reuses the point and array objects

# modules scoped private functions
_start_point = arcpy.Point()
_end_point = arcpy.Point()
_array = arcpy.Array()

@time_me(REPETITIONS)
def create_line_reuse_points_array(point1_x_and_y, point2_x_and_y, spatial_ref):
    &amp;quot;&amp;quot;&amp;quot; creates polyline from pair of (x,y) tuples &amp;quot;&amp;quot;&amp;quot;
    _start_point.X, _start_point.Y = point1_x_and_y
    _end_point.X, _end_point.Y = point2_x_and_y
    _array.add(_start_point)
    _array.add(_end_point)
    polyline = arcpy.Polyline(_array, spatial_ref)
    _array.removeAll()
    return polyline


# Run our tests
if __name__ == &amp;quot;__main__&amp;quot;:
    WGS_84 = arcpy.SpatialReference(4326)
    POINT1 = (-81.674525, 36.216630)
    POINT2 = (-81.675351, 36.213886)

    print(&amp;quot;Create line simple:&amp;quot;)
    create_line_simple(POINT1, POINT2, WGS_84)
    print(&amp;quot;&amp;quot;)

    print(&amp;quot;Create line reuse points:&amp;quot;)
    create_line_reuse_points(POINT1, POINT2, WGS_84)
    print(&amp;quot;&amp;quot;)

    print(&amp;quot;Create line reuse points and array:&amp;quot;)
    create_line_reuse_points_array(POINT1, POINT2, WGS_84)
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>arcpy.Project in_memory Featureclass</title>
      <link>https://joshwerts.com/blog/2015/09/10/arcpy-dot-project-in-memory-featureclass</link>
      <pubDate>Thu, 10 Sep 2015 00:00:00 +0000</pubDate>
      
      <guid>https://joshwerts.com/blog/2015/09/10/arcpy-dot-project-in-memory-featureclass</guid>
      <description>&lt;p&gt;It&amp;rsquo;s inevitable that you eventually run into this error when scripting with arcpy (arcpy.Project_management):
&lt;a href=&#34;https://help.arcgis.com/en%20/arcgisdesktop/10.0/help/index.html#//00vp0000000m000944.htm&#34;&gt;https://help.arcgis.com/en%20/arcgisdesktop/10.0/help/index.html#//00vp0000000m000944.htm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The standard project tool does not support in_memory workspaces.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the workaround - we just create a new featureclass using the source featureclass as a template and then exploit the spatial_reference parameter of arcpy.da.SearchCursor to project on the fly while inserting into the new featureclass.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;from os.path import split
import arcpy

# create destination feature class using the source as a template to establish schema
# and set destination spatial reference
def project(source_fc, out_projected_fc, spatial_reference):
  &amp;quot;&amp;quot;&amp;quot; projects source_fc to out_projected_fc using cursors (supports in_memory workspace) &amp;quot;&amp;quot;&amp;quot;
  path, name = split(out_projected_fc)
  arcpy.management.CreateFeatureclass(path, name,
                                      arcpy.Describe(source_fc).shapeType,
                                      template=source_fc,
                                      spatial_reference=spatial_reference)

  # specify copy of all fields from source to destination
  fields = [&amp;quot;Shape@&amp;quot;] + [f.name for f in arcpy.ListFields(source_fc) if not f.required]

  # project source geometries on the fly while inserting to destination featureclass
  with arcpy.da.SearchCursor(source_fc, fields, spatial_reference=spatial_reference) as source_curs, \
       arcpy.da.InsertCursor(out_projected_fc, fields) as ins_curs:
      for row in source_curs:
        ins_curs.insertRow(row)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# assume we&#39;ve already created this somewhere
source_fc = r&amp;quot;in_memory/source_fc&amp;quot;

# destination featureclass to be created
out_projected_fc = r&amp;quot;in_memory/projected_source_fc&amp;quot;

# destination projection
web_mercator = arcpy.SpatialReference(102100)

project(source_fc, out_projected_fc, web_mercator)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Edit 2016-02-04:&lt;/strong&gt; Changed to function per suggestion by &lt;a href=&#34;https://github.com/andygarfield&#34;&gt;Andy Garfield&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>arcpy.da Cursors and Readability Part 2</title>
      <link>https://joshwerts.com/blog/2014/12/21/arcpy-dot-da-cursors-and-readability-part-2/</link>
      <pubDate>Sun, 21 Dec 2014 00:00:00 +0000</pubDate>
      
      <guid>https://joshwerts.com/blog/2014/12/21/arcpy-dot-da-cursors-and-readability-part-2/</guid>
      <description>

&lt;p&gt;arcpy.da cursors provide the simplest data structure by default (tuples).  Python generators provide a pretty neat way of customizing these cursors to increase readability.&lt;/p&gt;

&lt;h3 id=&#34;searchcursor:ab62167d7f5279dad4a62ae177204a76&#34;&gt;SearchCursor:&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Return &lt;code&gt;dict&lt;/code&gt; instead of tuple:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def rows_as_dicts(cursor):
  &amp;quot;&amp;quot;&amp;quot; returns rows as dicts (does not maintain field order) &amp;quot;&amp;quot;&amp;quot;
  colnames = cursor.fields
  for row in cursor:
    yield dict(zip(colnames, row))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt; (note the cursor is wrapped with the generator):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;total_cost_by_name = {}
with arcpy.da.SearchCursor(costs_table, [&amp;quot;name&amp;quot;, &amp;quot;unit_cost&amp;quot;, &amp;quot;quantity&amp;quot;]) as curs:
  for row in rows_as_dicts(curs):
    total_cost_by_name[row[&amp;quot;name&amp;quot;]] = row[&amp;quot;unit_cost&amp;quot;] * row[&amp;quot;quantity&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If using with an update cursor, you&amp;rsquo;ll want to use an OrderedDict so the field/value order is maintained.  You&amp;rsquo;ll also need to the use &lt;code&gt;dict.values()&lt;/code&gt; to pass an ordered tuple back into Cursor.updateRow.&lt;/p&gt;

&lt;h3 id=&#34;updatecursor:ab62167d7f5279dad4a62ae177204a76&#34;&gt;UpdateCursor:&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Return &lt;code&gt;collections.OrderedDict&lt;/code&gt; instead of tuple:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import collections
def rows_as_ordered_dicts(cursor):
  &amp;quot;&amp;quot;&amp;quot; returns rows as collections.OrderedDict &amp;quot;&amp;quot;&amp;quot;
  colnames = cursor.fields
  for row in cursor:
    yield collections.OrderedDict(zip(colnames, row))
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Usage&lt;/strong&gt; (updating):&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;with arcpy.da.UpdateCursor(costs_table, [&amp;quot;unit_cost&amp;quot;, &amp;quot;quantity&amp;quot;, &amp;quot;total_cost&amp;quot;]) as curs:
  for row in rows_as_ordered_dicts(curs):
    row[&amp;quot;total_cost&amp;quot;] = row[&amp;quot;unit_cost&amp;quot;] * row[&amp;quot;quantity&amp;quot;]

    # call .values() to convert back to tuple
    # if we didn&#39;t use OrderedDict, the values would be in random order.
    curs.updateRow( row.values() )
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>arcpy.da Cursors and Readability Part 1</title>
      <link>https://joshwerts.com/blog/2014/08/07/arcpy-dot-da-cursors/</link>
      <pubDate>Thu, 07 Aug 2014 00:00:00 +0000</pubDate>
      
      <guid>https://joshwerts.com/blog/2014/08/07/arcpy-dot-da-cursors/</guid>
      <description>

&lt;p&gt;The arcpy.da cursors (ie: arcpy.da.SearchCursor) are far and away better than the regular cursors (ie: arcpy.SearchCursor).  They&amp;rsquo;re more pythonic, incredibly flexible, faster, and allow context management (with).  However, their straight-out-of-the-box-use may be a little hard to read and maintain.&lt;/p&gt;

&lt;h3 id=&#34;fun-with-tuples:dc138d3f5428a0342b5c02b02f9dbdd9&#34;&gt;Fun with Tuples&lt;/h3&gt;

&lt;p&gt;arcpy.da cursors return tuples (instead of objects that feel too much like writing ArcObjects).&lt;/p&gt;

&lt;h4 id=&#34;good:dc138d3f5428a0342b5c02b02f9dbdd9&#34;&gt;Good:&lt;/h4&gt;

&lt;p&gt;It&amp;rsquo;s perfectly valid to use tuple indexes to access the fields:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;total_cost_by_name = {}
with arcpy.da.SearchCursor(costs_table, [&amp;quot;name&amp;quot;, &amp;quot;unit_cost&amp;quot;, &amp;quot;quantity&amp;quot;]) as curs:
    for row in curs:
        total_cost_by_name[row[0]] = row[1] * row[2]
&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id=&#34;better:dc138d3f5428a0342b5c02b02f9dbdd9&#34;&gt;Better:&lt;/h4&gt;

&lt;p&gt;This works fine, but the intent of our calculation is not really clear without some mental mapping.  How about this?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;total_cost_by_name = {}
with arcpy.da.SearchCursor(costs_table, [&amp;quot;name&amp;quot;, &amp;quot;unit_cost&amp;quot;, &amp;quot;quantity&amp;quot;]) as curs:
    for row in curs:
        name = row[0]
        unit_cost = row[1]
        quantity = row[2]

        total_cost_by_name[name] = unit_cost * quantity
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The intent in the calculation is much more clear here, but we&amp;rsquo;ve gained a lot of verbosity that is perhaps unnecessary.&lt;/p&gt;

&lt;h4 id=&#34;best:dc138d3f5428a0342b5c02b02f9dbdd9&#34;&gt;Best:&lt;/h4&gt;

&lt;p&gt;Of course, you could set the variables all on one line &lt;code&gt;name, unit_cost, quantity = row[0], row[1], row[2]&lt;/code&gt;, but even better would be to take advantage of python&amp;rsquo;s tuple unpacking:  &lt;code&gt;name, unit_cost, quantity = row&lt;/code&gt;.  Taking that one step further, why not unpack every tuple as it&amp;rsquo;s iterated over.  Now we have a process that is both concise and highly readable:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;total_cost_by_name = {}
with arcpy.da.SearchCursor(costs_table, [&amp;quot;name&amp;quot;, &amp;quot;unit_cost&amp;quot;, &amp;quot;quantity&amp;quot;]) as curs:
    for name, unit_cost, quantity in curs:
        total_cost_by_name[name] = unit_cost * quantity
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now what if we want to update a total cost field in the featureclass using an UpdateCursor instead?&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;with arcpy.da.UpdateCursor(costs_table, [&amp;quot;unit_cost&amp;quot;, &amp;quot;quantity&amp;quot;, &amp;quot;total_cost&amp;quot;]) as curs:
    for unit_cost, quantity, total_cost in curs:
        total_cost = unit_cost * quantity
        curs.updateRow( (unit_cost, quantity, total_cost) )
&lt;/code&gt;&lt;/pre&gt;
</description>
    </item>
    
    <item>
      <title>arcpy: Reorder Fields</title>
      <link>https://joshwerts.com/blog/2014/04/17/arcpy-reorder-fields/</link>
      <pubDate>Thu, 17 Apr 2014 00:00:00 +0000</pubDate>
      
      <guid>https://joshwerts.com/blog/2014/04/17/arcpy-reorder-fields/</guid>
      <description>&lt;p&gt;Here&amp;rsquo;s another handy function for re-ordering fields in a feature class.  Like the &lt;code&gt;rename_fields&lt;/code&gt; function previously posted, it recreates the existing field mappings and modifies as necessary.  The output is a new feature class with fields in the order specified.&lt;/p&gt;

&lt;p&gt;The only caveat is that required fields always get pushed to the front (so the featureclass will start with OBJECTID, Shape, rest of fields&amp;hellip;).  After required fields are out of the way, the rest of the fields are added in the order specified in the &lt;code&gt;field_order&lt;/code&gt; list.  If any fields are missing, they are added to the end of the feature class.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;import arcpy

def reorder_fields(table, out_table, field_order, add_missing=True):
    &amp;quot;&amp;quot;&amp;quot;
    Reorders fields in input featureclass/table
    :table:         input table (fc, table, layer, etc)
    :out_table:     output table (fc, table, layer, etc)
    :field_order:   order of fields (objectid, shape not necessary)
    :add_missing:   add missing fields to end if True (leave out if False)
    -&amp;gt; path to output table
    &amp;quot;&amp;quot;&amp;quot;
    existing_fields = arcpy.ListFields(table)
    existing_field_names = [field.name for field in existing_fields]

    existing_mapping = arcpy.FieldMappings()
    existing_mapping.addTable(table)

    new_mapping = arcpy.FieldMappings()

    def add_mapping(field_name):
        mapping_index = existing_mapping.findFieldMapIndex(field_name)

        # required fields (OBJECTID, etc) will not be in existing mappings
        # they are added automatically
        if mapping_index != -1:
            field_map = existing_mapping.fieldMappings[mapping_index]
            new_mapping.addFieldMap(field_map)

    # add user fields from field_order
    for field_name in field_order:
        if field_name not in existing_field_names:
            raise Exception(&amp;quot;Field: {0} not in {1}&amp;quot;.format(field_name, table))

        add_mapping(field_name)

    # add missing fields at end
    if add_missing:
        missing_fields = [f for f in existing_field_names if f not in field_order]
        for field_name in missing_fields:
            add_mapping(field_name)

    # use merge with single input just to use new field_mappings
    arcpy.Merge_management(table, out_table, new_mapping)
    return out_table
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;new_field_order = [&amp;quot;field2&amp;quot;, &amp;quot;field3&amp;quot;, &amp;quot;field1&amp;quot;]
reorder_fields(in_fc, out_fc, new_field_order)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;rsquo;ve tested this in 10.1.1+ - it may work in 10.0 as well and should work with any license level.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>arcpy: Rename Fields</title>
      <link>https://joshwerts.com/blog/2014/04/01/arcpy-rename-fields/</link>
      <pubDate>Tue, 01 Apr 2014 07:43:15 -0400</pubDate>
      
      <guid>https://joshwerts.com/blog/2014/04/01/arcpy-rename-fields/</guid>
      <description>&lt;p&gt;In ArcMap 10.2.1, esri finally added a tool to allow renaming of fields (Data Management -&amp;gt; Alter Field).&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://joshwerts.com/img/alter_field_tool.png&#34; alt=&#34;Alter Field&#34; /&gt;&lt;/p&gt;

&lt;p&gt;This works well for a single field, but you may need something different if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you&amp;rsquo;re still on 10.0/10.1,&lt;/li&gt;
&lt;li&gt;you want to rename several fields at once,&lt;/li&gt;
&lt;li&gt;you would prefer not to rename the fields in-place,&lt;/li&gt;
&lt;li&gt;you need to rename fields in a source unsupported by the Alter Field tool (hint: shapefiles).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;rsquo;s a great function for renaming fields (and maintaining their order).  It can be used in the python console.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def rename_fields(table, out_table, new_name_by_old_name):
    &amp;quot;&amp;quot;&amp;quot; Renames specified fields in input feature class/table
    :table:                 input table (fc, table, layer, etc)
    :out_table:             output table (fc, table, layer, etc)
    :new_name_by_old_name:  {&#39;old_field_name&#39;:&#39;new_field_name&#39;,...}
    -&amp;gt;  out_table
    &amp;quot;&amp;quot;&amp;quot;
    existing_field_names = [field.name for field in arcpy.ListFields(table)]

    field_mappings = arcpy.FieldMappings()
    field_mappings.addTable(table)

    for old_field_name, new_field_name in new_name_by_old_name.iteritems():
        if old_field_name not in existing_field_names:
            message = &amp;quot;Field: {0} not in {1}&amp;quot;.format(old_field_name, table)
            raise Exception(message)

        mapping_index = field_mappings.findFieldMapIndex(old_field_name)
        field_map = field_mappings.fieldMappings[mapping_index]
        output_field = field_map.outputField
        output_field.name = new_field_name
        output_field.aliasName = new_field_name
        field_map.outputField = output_field
        field_mappings.replaceFieldMap(mapping_index, field_map)

    # use merge with single input just to use new field_mappings
    arcpy.Merge_management(table, out_table, field_mappings)
    return out_table
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The function accepts the input feature class, path to output, and a dictionary mapping the old names to the new names:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage:&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;# does need need to include all fields, only those you want to rename
new_name_by_old_name = { &#39;old_name_1&#39;:&#39;new_name_1&#39;,
                         &#39;old_name_2&#39;:&#39;new_name_2&#39; }
rename_fields(in_fc, renamed_fc, new_name_by_old_name)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This works by duplicating the arcpy.FieldMappings object from the existing feature class, renaming the fields within the mapping based on the input, and then calling a function that will apply that mapping.  Merge with a single input gets the job done.  Using the field mappings is a nice trick for efficiently managing fields.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>