# Decreasing polygon size based on percentage using ArcPy?

I would like to decrease the size of polygons by percentage and not by distance in order to implement this into ModelBuilder to loop over a number of polygons. To my knowledge this tool is available in QGIS but not in ArcGIS. The scale function does not do the trick in my case.

Does someone know how it is done?

Or may be stumbled over the same problem and could tell how he solved it or has a Python code for implementing into the ModelBuilder?

• It´s the Plugin: Buffer by Percentage plugins.qgis.org/plugins/BufferByPercentage Mar 30, 2015 at 11:23
• @Daniel It works nice! Mar 30, 2015 at 12:22
• Can't you just calculate your "percentage" in a field and use that for your buffer ? You have the option to use a field instead of a distance with ArcGIS. Mar 30, 2015 at 13:45
• @jbchurchill Agreed, that would work if he has a field that represents the average distance of vertices to the centroid of each polygon. Mar 30, 2015 at 14:05
• Looking at bufferbypercentage.py, the secant method used by the module is generally how this sort of thing can be done. If you want to lean something new, consider rewriting the module to fit the tools you are using. Mar 31, 2015 at 0:23

I by mistake gave that answer to an old thread. So copied it here. Trying to find the thread I found this ESRI code for field calculator that iterate to find the right buffer for each polygon. Code attached in the end, and there is a link to the page.

Note that this answer is un-related to the code below (but I worked to hard to make it, so I leave it here it might be helpful after all):

I can only suggest a simple method that will give an approximate on average; yet if you are looking for the exact percentage reduction of area this would not work - but might guide your thoughts towards a coding solution. This method is based, like others have suggested, on negative input to the buffer tool. However it also involves adjustment to the the distance field inputs based on the "shape" of each polygon.

I suggest to use the compactness of the polygons to adjust the "reduction coefficient". More on compactness here.

To start with, I assume that your polygons are quite regular in shape, i.e. complete pseudo geometric shapes. Otherwise this might not work.

I started with this layer:

I computed the compactness using this formula:

``````4*3.14*[SHAPE_Area]/( [SHAPE_Length]^2)
``````

Than, aiming for a-20% reduction in area, I computed the "new radius" (assuming a perfect circle) and adjusted the result using the compactness coefficient by multiplication. That is since a perfect circle's compactness index will be 1 (fully compact) and then the index decreases when the shpae is less compact. Thus a smaller "radius" is needed to get the same area.

The formula I used is:

``````-(0.2*Sqr ([SHAPE_Area])/3.14)* [Compact]
``````

My results are presented in a scatter plot (between the new and original area) and summary statistics of the ratios between the new area to the original (hoping to get 0.8). Some deviation can be seen, yet I didn't lookup too carfully for their causes. It might be that few adjustments to the "compactness coefficient" will give better results.

And the stats:

Code from ESRI forum (VB):

``````' ---- You may need to adjust these values ----
``````

Const PCNT_RED As Double = 20 Const PCNT_TOL As Double = 0.001 ' --------------------------------------------- Const NUM_FMT = "0.0##############" Dim dMinArea As Double Dim dMaxArea As Double Dim dMinDis As Double Dim dMaxDis As Double Dim dBufDis As Double Dim pEnv As IEnvelope Dim pPoly As IPolygon Dim dPolyArea As Double Dim pTopOp As ITopologicalOperator Dim pBuffer As IPolygon Dim pArea As IArea Dim dBufArea As Double

``````    ' Get a ref to the polygon
Set pPoly = [Shape]
Set pTopOp = pPoly
pTopOp.Simplify

' Calc valid area range
Set pArea = pPoly
dPolyArea = pArea.Area
dMinArea = dPolyArea * (1 - (PCNT_RED + PCNT_TOL) / 100)
dMaxArea = dPolyArea * (1 - (PCNT_RED - PCNT_TOL) / 100)

' Calc min/max/initial bufferdis
Set pEnv = pPoly.Envelope
With pEnv
If .Width > .Height Then
dMaxDis = .Width / 2
Else
dMaxDis = .Height / 2
End If
End With
dMinDis = -dMaxDis
dBufDis = (dMinDis + dMaxDis) / 2

' Get the buffer
Set pBuffer = pTopOp.Buffer(dBufDis)
' Iterate through adjusting the buffer until we get a value
' within our agreed range or until we get as close as possible
Do While Format(dMinDis, NUM_FMT) <> Format(dMaxDis, NUM_FMT)

' Check buffered area is within valid range
Set pArea = pBuffer
dBufArea = pArea.Area
If dBufArea >= dMinArea And dBufArea <= dMaxArea Then Exit Do

' Check if we have a negative area
If dBufArea < 0 Then
' We have, so just use the original polygon
Set pBuffer = pPoly
Exit Do
End If

If dBufArea < dMinArea Then
dMinDis = dBufDis
Else
dMaxDis = dBufDis
End If
dBufDis = (dMinDis + dMaxDis) / 2

' Generate the buffer from adjusted distance
Set pBuffer = pTopOp.Buffer(dBufDis)

Loop

' Use pBuffer in box below Advanced Window
``````