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?

  • 2
    It´s the Plugin: Buffer by Percentage plugins.qgis.org/plugins/BufferByPercentage
    – Daniel
    Mar 30, 2015 at 11:23
  • 1
    @Daniel It works nice!
    – xunilk
    Mar 30, 2015 at 12:22
  • 1
    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
  • 1
    @jbchurchill Agreed, that would work if he has a field that represents the average distance of vertices to the centroid of each polygon.
    – GeoJohn
    Mar 30, 2015 at 14:05
  • 3
    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.
    – Mike T
    Mar 31, 2015 at 0:23

1 Answer 1


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: StartWith

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: 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

    ' 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
            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

        ' Readjust buffer distance
        If dBufArea < dMinArea Then
            dMinDis = dBufDis
            dMaxDis = dBufDis
        End If
        dBufDis = (dMinDis + dMaxDis) / 2

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


    ' Use pBuffer in box below Advanced Window

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.