Dividing a polygon into a given number of equal areas with arcpy

I was recently searching the Internet trying to find any tool that would let me split an arbitrary polygon inside a geodatabase feature class into multiple polygons of equal area. ArcGIS does provide this functionality as a part of the parcel fabric functionality. Unfortunately, there is a lot of work involved in setting up the parcel fabric and there is a lot to learn before you will be able to divide your parcels. So I was looking for a simpler solution that would work directly with the geometry of a polygon.

However, I was not able to find any solution that would work and most helpful posts on the forums were pointing either at parcel fabrics or providing some ideas on the implementation of the workflow using multiple geoprocessing tools and some custom code. I found a nice ArcGIS custom script tool called Polygon Bisector which

computes a line that bisects, or divides in half, a polygon area along a line of constant latitude or longitude.

So, this would work great if you need to split a polygon creating a number that follows the exponent of two (2, 4, 8, 16, 32 and so forth). This is because after dividing a polygon into two polygons of equal area (now you have 2 polygons), you could divide each of them into two parts again (now you have 4 polygons), and so on. Since I want to be able to divide a polygon into an arbitrary number of areas, I had to write my own tool.

I have solved this problem this way. Say I want to have the polygon of area 1000 sq. m. divided into 5 equal areas:

  1. Get an extent of a polygon.
  2. Construct a polyline using the vertices of the polygon’s extent with a tiny shift of coordinates.
  3. Cut the polygon into two halves using this line.
  4. Find what is the area of the smallest polygon.
  5. If the area is smaller than the 200 sq. m. (that is, fifth part of the polygon), the shift the line again and re-run steps 2-4.
  6. If the area is 200 sq. m. or larger, than leave this part and keep working with the polygon that is left essentially running through the steps 2-5.
  7. When the original polygon has been successfully divided into equal areas, they are inserted into a new feature class along with the source polygon attributes.

The illustration of the cutting lines with the extent polygon is below.

extent_figure

This approach has several disadvantages, though.
First, if your polygon is very large and you want the parts of the polygon to have the same area with the minimal difference, the tool execution will take a lot of time as you will need to shift the cutting lines a few centimeters, cut the polygon into halves, and evaluate the result.
Second, you can only choose between the North-South or West-East direction of the cutting lines. You won’t be able to specify the angle yourself.

However, this tool works great for the target use I kept in mind when writing it. Using 0.5 meters as the step for moving the cutting line, the difference between the largest and the smallest sub-polygons was just around 1%. Running the same code for the same polygon with the shift value set to 0.05 meters (5 cm), I have observed the difference value to be around 0.1%.

The illustration of the polygon subdivision is below (West-East to the left, North-South to the right).

divide_polys_figure

The code is available at the GitHub Gist as usual. Run this code inside the Python window in ArcMap while having a single polygon selected.

 

 

Advertisements

Generate HTML report about Esri geodatabase using Python

Many GIS administrators and analysts maintain an inventory of all the data and metadata associated with a corporate Esri geodatabase. Most of the users have written short Python scripts that reads properties of geodatabase items and prints them to a text file or an Excel sheet.

A non-supported product called ArcGIS Diagrammer was able to generate HTML reports about your geodatabase reporting information about its domains, feature classes, tables and so much more. However, since version ArcGIS 10.3, the support for the tools was dropped, so if you want to use it now you need either to have ArcGIS Desktop 10.2 installed or have a bunch of .dll files from the ArcObjects .NET SDK 10.2 stored on your machine. This makes using ArcGIS Diagrammer cumbersome.

Anyways, ArcGIS Diagrammer wasn’t good enough for my needs because I have always wanted to work with an interactive representation (where I could sort columns, filter irrelevant information, and create printable views). Being frustrated with the need to hack own scripts for this, I’ve decided to write an own Python package that would report information about Esri geodatabase in an interactive HTML page.

Spending some evenings now and then, and that’s it – the package is in beta now, ready to install and use! Make sure to get it from its GitHub repository: registrant. This is how a sample report could look like; below is an animated example just to give you a feeling of what it would be like to work with the report.

report_sample

I would love to hear from users whether it’s useful and what other information and features such a report should have. You can submit an issue on the registrant‘s GitHub page or just leave a comment to this post.

 

Network Analyst and ArcPy: finding k-alternate path

Using ArcGIS Network Analyst extension, it is possible to find out the best route between a pair of points (best is defined in terms of the impedance — it can the shortest or the fastest route, for instance). However, you might like having multiple alternatives to the best route which one usually refers to as the K shortest paths.

The K shortest path routing algorithm is

an extension algorithm of the shortest path routing algorithm in a given network.

When solving a route between a pair of points, Network Analyst finds only a single route that is considered to be the best. That is, one cannot get a number of routes while solving a Route layer. However, this is something many of you have seen when routing using Google Maps or HERE, for instance.

I got curious and have started searching for this algorithm implementation using ArcGIS Network Analyst. I’ve found a very useful Esri forums post by a former Esri Network Analyst product engineer Michael Rice who wrote that

At the ArcGIS 10 release, you can approximate a k-shortest paths solver using the enhanced barrier features. Additionally, for line and polygon barriers, instead of just restricting the parts of the network that are covered by their geometry, you can opt to simply scale the costs of the parts of the network covered by the geometry.

Therefore, to approximate k-shortest paths, you can do the following:

1. Solve the route to get the best path
2. Take the current best path and load it as a polyline barrier with a scale factor of x
3. Repeat

Note that by scaling the polyline barrier instead of restricting it, this will allow
the next path to reuse some of the same edges along the previous path if necessary, but at a higher cost than in previous paths. Also note that when multiple line barriers apply to the same edge, the final scale factor for the cost of that edge becomes the product of their individual scale factors. For example, if there are two line barriers applied to some edge with scale factors x and y, respectively, the scaled cost of traversing that edge will be x*y*originalEdgeCost.

This means that the more an edge is reused across different paths, the less likely it will be to be used in any subsequent paths as the process discussed above continues to iterate.

This approach will technically not guarantee a true k-shortest path solve, so we must
be careful not to incorrectly label it as such. As I said previously, it is merely an
approximation for this concept. A more appropriate name might be to call this a
k-alternate path approach (as opposed to shortest). The alternate paths you get will
ultimately depend on the scale factors you use.

I’ve written a Python add-in that given a number of alternative routes to find, will generate a new feature layer with a number of routes solved. I have used the workflow Michael described loading a solved route as a polyline barrier for all subsequent solve operations. You can use this code when you want to generate multiple alternate routes. This is how it looks in ArcMap.

2017-04-27 15_12_00-Routing.mxd - ArcMap

The Python code to be used to make the add-in:

Call ArcGIS Pro .NET SDK class library from Python

As some of you may already know, it is possible to interact with ArcObjects COM libraries using Python with the help of comtypes module. This means a whole lot for any GIS analyst who at some point may hit the limitations of arcpy package and will need to do something using ArcObjects which provide a fine-grained API into the ArcGIS components.

If you switch to ArcGIS Pro, though, you won’t be able to run your old ArcObjects code that, for instance, will hide or show map grids (graticules) in map layout before exporting the map (this is not supported with arcpy). Even though ArcGIS Pro is shipped with arcpy, its functionality is not any richer than of ArcGIS Desktop based arcpy (at least for now).

However, because ArcGIS Pro comes with .NET SDK, it becomes relevant to learn how to access .NET .dll files and access the methods of classes available within the class libraries. I’ve tested to use pythonnet module and it worked great to access a class library authored with Visual Studio 2015 and Visual C#.

In order to make calls to .dll files compiled based on .NET code (in my case, it’s C#) using Python, you would need to install a Python package called pythonnet. Learn more at Calling a C# library from python.

However, accessing the ArcGIS Pro .NET libraries isn’t that easy as there are many dependent references involved. There is support for embedding the core functionality of ArcGIS Pro (such as accessing the geodatabase data, iterating features with cursors, constructing geometries etc.), however, one is supposed to access this functionality either using a console application or a WPF application.

There is a Python module called subprocess that would let you get the result of console app execution as a string which you could load into a Python data structure to use later, however, this is not a very elegant way to proceed. You basically author your console apps and then use Python to call those apps supplying the input arguments. This is probably the easiest way to get your .NET code executed from Python, though, as you have everything you need already installed.

An alternative approach is to compile a class library using x64 platform in Visual Studio and then access it from 64 bit Python (your ArcGIS Desktop x86 Python won’t work). Read more about accessing the core of .NET SDK at ProConcepts CoreHost.

Here are the steps involved. Please mind that this can get messy with all those Python modules installations, so you might like spinning a virtual machine or at least a virtualenv for this.

  1. Build your class library in Visual Studio for x64 platform.
  2. Install pythonnet for x64.
  3. Install pywin32 for x64.
  4. Copy two .dll files from:
    ​C:\Python27\ArcGISx6410.4\Lib\site-packages\pywin32_system32 to C:\Python27\ArcGISx6410.4\Lib\site-packages\win32\lib
  5. You should be able to run the code in the snippet below.

 

ArcGIS Pro vs ArcGIS Desktop: geoprocessing tools

Both ArcGIS Desktop and ArcGIS Pro have a suite of toolboxes with hundreds of geoprocessing tools available. However, there are still quite a few tools that are available only in ArcMap and have not been ported to Pro. You can find the list of those tools at the Help page Tools that are not available in ArcGIS Pro.

However, what not so many people may know is that there are actually quite a few tools that are available exclusively in ArcGIS Pro. They have never existed in ArcMap in other words. They may or may not become a core part of the ArcGIS Desktop ArcToolbox. I have seen that many of the tools added to ArcGIS Pro 1.3 have been added to ArcGIS Desktop 10.5. A good part of them is specific to Pro, however, and would not make sense in ArcMap, such as Consolidate Project or Package Project tools. However, there are some tools that are applicable to both environments as they operate on geodatabase, for instance, Alter Domain, or with a network dataset, for instance, Create Network Dataset From Template.

To be able to find out what tools are available in ArcGIS Pro and not available in ArcGIS Desktop, I’ve written a tiny Python script that reads all the toolboxes available in the both installations and then compares them. You would need to run the code for Pro and Desktop Python installations, of course.

As I need to call Python installed in Pro and Desktop, I prefer to use a .bat file for this:

"C:\Python27\ArcGIS10.4\python.exe" "C:\GIS\Temp\ToolLister.py" "Desktop"
"C:\Program Files\ArcGIS\Pro\bin\Python\Scripts\propy.bat" "C:\GIS\Temp\ToolLister.py" "Pro"

After calling this .bat file, you will get two .json files each containing the tools available in these two environments.

Please note that I have run this code for ArcGIS Desktop 10.4 and ArcGIS Pro 1.4.

The code for your reference (ToolLister.py):

The list of tools present in Pro that are not in Desktop

ArcGIS Pro does have some new toolsets we never had in Desktop.

Standard Feature Analysis

The Standard Feature Analysis toolbox contains tools for performing spatial analysis on feature data in your portal.

Raster Analysis

The Raster Analysis toolbox contains a set of powerful tools for performing raster analysis on data in your portal. By distributing the processing between multiple server nodes, you can efficiently process large datasets in less time than ever before.

GeoAnalytics Tools

The GeoAnalytics Tools toolbox contains a set of powerful tools for performing spatial analysis on big data. GeoAnalytics Tools are powered by your ArcGIS GeoAnalytics Server. ArcGIS GeoAnalytics Server distributes the analysis between multiple server nodes. By using distributed processing, you can process large datasets in less time.

And here are the new tools in existing toolboxes:

Geostatistical Analyst Tools
  • EBKRegressionPrediction_ga
  • GALayerToRasters_ga
Editing Tools
  • AlignFeatures_edit (since Desktop 10.5 only)
  • CalculateTransformationErrors_edit (since Desktop 10.5 only)
Analysis Tools
  • EnrichLayer_analysis
  • PairwiseIntersect_analysis
  • SummarizeWithin_analysis
  • PairwiseDissolve_analysis
  • SummarizeNearby_analysis
  • PairwiseBuffer_analysis
  • SplitByAttributes_analysis
  • GraphicBuffer_analysis
Spatial Analyst Tools
  • LocateRegions_sa (since Desktop 10.5 only)
  • RemoveRasterSegmentTilingArtifacts_sa (since Desktop 10.5 only)
3D Analyst Tools
  • ClassifyLasBuilding_3d (since Desktop 10.5 only)
  • TileLas_3d (since Desktop 10.5 only)
Conversion Tools
  • AddRasterToGeoPackage_conversion (since Desktop 10.5 only)
Data Management Tools (some of the tools may be available since Desktop 10.5)
  • AlterDomain_management
  • AddRelate_management
  • RemoveRelate_management
  • CreateMobileMapPackage_management
  • CreateVectorTileIndex_management
  • CreateVectorTilePackage_management
  • MosaicDatasetToMobileMosaicDataset_management
  • CreateSceneLayerPackage_management
  • EnableCOGO_management
  • DisableCOGO_management
  • BuildStereoModel_management
  • InterpolateFromPointCloud_management
  • ComputeCameraModel_management
  • GeneratePointCloud_management
  • ComputeMosaicCandidates_management
Space Time Pattern Mining Tools
  • LocalOutlierAnalysis_stpm
Network Analyst Tools
  • CreateNetworkDatasetFromTemplate_na
  • CreateTemplateFromNetworkDataset_na

Hope you will find this list useful. If your main workflows are still ArcGIS Desktop based (which I believe they are for most of us), keep in mind that you can call ArcGIS Pro Python 3.5 installation to take advantage of those new geoprocessing tools if you have both Pro and Desktop installed. Take a look at this Help page Python in ArcGIS Pro. To learn more about calling Windows applications from Python, take a look at the built-in subprocess module.

Arcpy: Get route distance and travel time between stops in an ArcMap Network Analysis layer

If you are a user of ArcGIS Network Analyst extension, this post is for you. I am pretty sure many analysts solving routes between multiple stops would like to get some additional information about the solved stops. The route feature created after the solve does contain the information on the total route travel time as well as its distance. However, there is no information about the distance between individual stops in the route.

In other words, if your route has 10 stops, what if you would like to quickly get the distance value from the stop2 to stop7? If you have set up the accumulators in the Route solver properties, you will get those accumulators attributes in the Stops sub layer. This means you will be able to do the calculation manually because you would know that from the route start point, it took 5 minutes to get to stop2 and 18 minutes to get to stop7, so the travel time between the stop2 and stop7 is 13 minutes (18 min minus 5 min).

To avoid doing those tedious calculations, I’ve written a tiny code snippet with arcpy that you can wrap into an ArcGIS Python add-in. After installing the add-in, you will be able to select two arbitrary route stops and after calling the code, a message window will show you the distance and travel time between the stops. This code is supposed to be wrapped into a Python add-in, but can also be executed as a standalone script tool with minor modifications. This code assumes that the route has been already solved and there are accumulators associated with the route solver.

If you would like to customize this tool making it more flexible by reading the accumulators and getting their types and units, take a look at the RouteSolverProperties arcpy object as well as the network dataset Describe object properties.

This is how this code runs in ArcMap with the Python add-in installed:

distance_between_route_stops

The code:

ArcPy: Batch export of attachments from geodatabase feature class with custom naming

If you have worked with attachments within an ArGIS geodatabase, you might have needed to take the attachments out of the geodatabase to use in another system or to process them separately. Unfortunately, there is no geoprocessing tool that would allow you to export all attachments to files, however this workflow is supported with arcpy and Python. There is a KB article at Esri site that shows the code necessary to export attachments of a feature class into an output folder.

This workflow is based, however, on using the attributes from the attachments table – %featureclassname%__ATTACH. But what if you would like to export the attachments naming output files using attributes of the source feature that has attachments associated with it? In this case, you would need to find out what feature every attachment is associated to (this is exposed via a relationship class) and then use this value to name the output file. To get all the information needed regarding the relationship class properties a Describe object for the relationship class can be used. Of course when exporting the attachments and naming output files using a source feature attribute, you have to make sure it is unique, otherwise the later exported attachment files will overwrite the previous ones.

This tool will handle Unicode characters in the attribute field you would like to use for naming output files, so it will work for users working in various locales, however, there is no validation for the output file name in terms of operating system restrictions on legal file names, but its easy to fix, for instance, using regex.

The code that will do this with some extra comments to help you follow along: