1

I have a polygon layer of a region (100% coverage, no overlaps) and a line layer in the same region. I want to calculate for each line to which percentage it crosses certain polygons.

I have seen the question also here How to calculate the percentage of a Line through Polygons? but its 6 years old and the proposed solution is completely manual. Is there maybe a newer, more automatable solution, considering QGIS 3.6 or R?

  • 1
    What have you tried in R already? Have you read your data in? Have you looked at the sf package which can do spatial operations such as intersection and overlay etc? – Spacedman Mar 14 at 8:00
2

Get some sample polygons:

library(sf)
nc = st_read(system.file("shape/nc.shp", package="sf"))

Next I created some lines as a spatial data frame with an ID for each line.

> ld
Simple feature collection with 3 features and 2 fields
geometry type:  LINESTRING
dimension:      XY
bbox:           xmin: -82.45293 ymin: 34.27059 xmax: -77.21339 ymax: 36.51012
epsg (SRID):    4267
proj4string:    +proj=longlat +datum=NAD27 +no_defs
  ID                           geom  
1  1 LINESTRING (-77.30014 36.39...  
2  2 LINESTRING (-82.45293 35.65... 
3  3 LINESTRING (-78.72279 34.27...  

Now add the length of each line to itself as an attribute:

ld$length = st_length(ld$geom)

intersect the lines with the polygons. This returns 15 line features, chopped by the polygons:

ldnc = st_intersection(ld, nc)

These have the ID from the lines, and the attributes from the polygons. Each of these also still has the length from the original source line. So we can compute the percentage this way:

ldnc$lpercent = 100 * (st_length(ldnc)/ldnc$length)

That gets me a data frame of ID of line, NAME of polygon, and percentage of line ID in polygon NAME (as well as all the other attributes). So I can do:

> data.frame(ldnc[,c("ID", "NAME","lpercent")] )
     ID        NAME     lpercent                           geom
1     1 Northampton 100.000000 1 LINESTRING (-77.30014 36.39...
2     2    Guilford   5.218371 1 LINESTRING (-79.75943 35.90...
2.1   2     Iredell   6.464218 1 LINESTRING (-80.96068 35.65...
2.2   2       Burke  12.923325 1 LINESTRING (-81.87066 35.72...
2.3   2    McDowell  11.559291 1 LINESTRING (-82.28688 35.67...
2.4   2    Randolph  13.634564 1 LINESTRING (-79.83549 35.50...
2.5   2       Rowan   4.376041 1 LINESTRING (-80.74295 35.57...
2.6   2     Catawba  12.385203 1 LINESTRING (-81.40348 35.70...
2.7   2    Buncombe   4.613577 1 LINESTRING (-82.45293 35.65...
2.8   2    Cabarrus   8.260595 1 LINESTRING (-80.61847 35.50...
2.9   2  Montgomery  10.887982 1 LINESTRING (-80.07517 35.32...
2.10  2      Stanly   9.676922 1 LINESTRING (-80.41298 35.32...
3     3  Cumberland   8.059165 1 LINESTRING (-78.69006 34.84...
3.1   3      Bladen  61.657953 1 LINESTRING (-78.66501 34.45...
3.2   3    Columbus  30.282891 1 LINESTRING (-78.72279 34.27...

line 1 is all in Northampton, line 2 is all over the place, line 3 is mostly Bladen and Columbus with a bit in Cumberland. I can confirm this by plotting and checking.

4

If you just want an outpout list with the result, I would recommend to use a database e.g. PostgreSQL + PostGIS or Spatialite. There you can do it with a simple statement like this:

select l.nameofline, p.nameofpolygon,
(st_length(ST_Intersection(l.geom,p.geom)) / st_length(l.geom)) * 100 as linepercentage
from lines l
join polygons p on (st_intersects(l.geom,p.geom));

The output would look like this:

Line1    Polygon1   36.0
Line1    Polygon2   64.0
Line2    Polygon1   10.0
Line2    Polygon2   40.0
Line2    Polygon3   50.0

You join the tables "lines" and "polygons" where a line intersects a polygon. For the percentage value the length of the subpart of the line within the specific polygon is divided by the complete length of the origin line and multplied with 100.

  • 2
    The questioner hasn't mentioned PostGIS and this can be done in R using the sf packages. – Spacedman Mar 14 at 7:59
  • looks decent but i dont have any SQL skills, prefer an GIS or R based solution – a.urbanite Mar 15 at 7:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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