25

Is there an option in QGIS to fill holes in polygons automatically by setting parameters e.g. maximum area, distance between borderlines?

I want to delete/fill holes that a very "thin"/small.

4

6 Answers 6

30

For QGIS 3

The "Delete Holes" tool combines both of the above functionalities. You can optionally specify a maximum area of hole to delete. If left as 0.0, the tool will delete all holes of any size.

For QGIS 2

There are a couple of tools available from the Processing Toolbox:

  • Fill holes tool which you can specify the maximum area.
  • Delete holes tool which would be applied to the whole input layer.

Using QGIS 2.10.1-Pisa with Processing version 2.10.2.

3
  • 1
    Just to check, the max area parameter, that is the maximum size of a hole to be filled? So in a metre UTM project, if the max was 10,000, that would mean the largest hole to be filled would be a hectare and any larger than that would remain?
    – BillW
    Commented Dec 27, 2016 at 21:17
  • 1
    @BillW - Yes, I believe that is exactly what it does :)
    – Joseph
    Commented Jan 4, 2017 at 10:32
  • Thanks, "Delete holes" is really straightforward, and worked for me. In QGIS 3.10, "Fill holes" doesn't seem to be available, but "Delete holes" matches the description given above for "Fill holes".
    – EcologyTom
    Commented Jun 29, 2021 at 12:42
20

I faced the same problem as yours with this shapefile, having many gaps between polygons.

Original file with gaps

In order to solve the problem, You could use a slight modification of tshiffle's method:

  1. First, perform the difference between your file and a polygon covering its whole extent.

Extent_polygon

Difference_tool

This action will create a new shapefile consisting in only one polygon, so you have to explode it into single parts. For that, you could use Vector/Geometry Tools/Multipart to singleparts tool.

Difference_result

Multi_to_single

After that, delete the external entity. Now you have, in a new shapefile, several polygons covering the gaps of your original coverage.

gaps_covered

  1. Perform a Union between the initial data and the single parts. Use the SAGA tool, because default QGIS option creates duplicates into the database.

Union

  1. All the gaps will now appear as empty records in the database (for the example 72 rows). Sort your table using an area field and take the value from the smallest polygon in the original file. For this case, 0.13645 hectares.

database

  1. Finally, use the "Eliminate sliver polygons" tool, with the settings shown in the image.

enter image description here

  1. The final result does not have any gaps.

enter image description here

3
  • Could you add more information regarding the choice of parameters? What is the "value"? The QGIS documentation page is very short on details. Very elegant reply, pity the initial user has not accepted any of the answers!
    – kl-higgins
    Commented Jan 5, 2018 at 20:59
  • 1
    'Value' is the magnitude that you use for the comparison. In the example the used field 'area' was set in hectares, so 0.1 means: eliminate polygons smaller or equal than 0.1 hectares.
    – gtapko
    Commented Jan 12, 2018 at 13:27
  • gtapko, can you please provide further details about phase 3? i can't understand it, thanks
    – newGIS
    Commented Aug 19, 2019 at 23:56
8

There may be more elegant solutions out there, but this has always worked for me.

1) Create "hole-filling" polygons. To do this draw a giant polygon larger than the original and use the "difference" tool. If you drew a much larger polygon you'll have all the "hole-filling" polygons plus a single larger polygon that goes around the original shape. Delete that large polygon, keeping the "hole-filling" polygons.

2) Merge the "hole-filling" polygons with the original shapefile. If you only want to fill holes that fit a certain criteria (ie under X number of square kilometers) you can filter for that here.

3) Dissolve the newly merged polygon on a common field.

2
  • Not clear about step 3, how some one will find the common field?
    – iRfAn
    Commented Sep 28, 2015 at 16:10
  • At this step the common field can be anything, the goal is to simply dissolve the boundaries between the polygons. You could use an existing field or just add one.
    – tshiffle
    Commented Sep 29, 2015 at 17:32
5

In python / shapely, this can fill in your polygon:

import shapely
from shapely.geometry import Polygon
filled_shape = Polygon(shape_with_holes.exterior)
1
  • I have been looking for solution in shapely. This one works well! Thanks Commented Jan 29, 2021 at 9:30
2

I've seen some explanations following the same path as gtapko and tshiffle's, but none worked for me because the invalid geometries made the difference tool disfunctional. So, I came up with a solution of my own which is not 100% automated, but it's manageable. Probably someone already figured this, but I'll take my chances:

1) Create an ID on the original, damaged layer

Creating an ID attribute is simple, but so is my solution, so I'll go over it.

First, you have to open your attribute table and then go to the Field Calculator, which is a button pretty much like an abacus. There, you will be given the option to create a new field or update an existing one. On the picture above I'm creating a new one called "ID". The formula is right at the end of the picture. (Sorry for having my QGIS set up in a different language. Since the design and the formulas are exactly the same throughout the language versions, I don't think it will get in our way here.)

2) Convert the polygons to lines

This step is located on the Vector > Geometry section the the menu. Your converted shape should look like this:

Right after converting the polygons to line, you will have to do the exact opposite, which is...

3) Convert lines to polygons

The options are right next to each other. Again, let's not mind the language barrier here.

4) Rejoice The reason you did steps 2 and 3 is because now you're sure those lines will be considered as polygons, which means they now have their own line on the Attribute Table. If you check it out, it will look like this:

The first one is ALWAYS the entire polygon (trust me, I've deleted a couple hundred lines today...) and the rest are the loose lines in the middle. You can enable editing and get ready for action. If you decide to try this, two things that you should keep in mind are: organize your table ID-wise, this way you're sure you're not missing anything and use shift to select clusters of data, just like any other program.

I'm aware this is not the crème de la crème of QGIS problem-solving, but if you're facing a situation where the tools are not working because of the invalid geometry these line create (I even tried dissolving by the ID, but it didn't work), then this might be a way out.

2
  • 1
    Could you update your images? Links are broken!
    – Simbamangu
    Commented Nov 3, 2017 at 6:34
  • Hey. I'm sorry, but apparently Photobucket hijacked my images, I lost access to them. I already opened a ticket and I'm trying to regain access. I'll get back to you whenever possible.
    – Eric Lino
    Commented Nov 12, 2017 at 15:18
2

It is also possible to solve the same task using the "Geometry by expression" with a corresponding expression.

To fill all holes in polygon features :

make_polygon(
    array_first(
        geometries_to_array(
            order_parts(
                boundary($geometry),
                'area(make_polygon(boundary($geometry)))',
                False
                )
            )
        )
    )

Input:
input

Output:
output1

To fill only holes with a certain area in polygon features :

if(
    num_interior_rings($geometry) = 0,
    $geometry,
    coalesce(
        sym_difference(
            collect_geometries(
            array_foreach(
                array_filter(
                    array_foreach(
                        generate_series(1, num_interior_rings($geometry), 1),
                        interior_ring_n($geometry, @element)
                        ),
                    area(make_polygon(@element)) > 300 -- specify the maximum area
                    ),
                make_polygon(@element)
                )
            ),
            $geometry),
        $geometry
        )
    )

Input:
input

Features with holes in which an area is more than 300 will be filled.

Output:
output2

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.