r-spatialecology/landscapemetrics

Issues with circles

Closed this issue · 3 comments

Hi,

I suggested a solution (#164) for a problem I haven't described yet (but had discussed it with @mhesselbarth). But here, we go:

Consider the following code:

library(landscapemetrics)

# T-shaped patch with 7 cells horizontal and 6 cells vertical, patch size: 12 cells
mat1 <- matrix(data = c(NA,5,NA,NA,NA,NA,NA,
                        NA,5,NA,NA,NA,NA,NA,
                        NA,5,NA,NA,NA,NA,NA,
                        NA,5, 5, 5, 5, 5, 5,
                        NA,5,NA,NA,NA,NA,NA,
                        NA,5,NA,NA,NA,NA,NA,
                        NA,5,NA,NA,NA,NA,NA), nrow = 7, ncol = 7)
r <- raster::raster(mat1)
raster::extent(r) <- c(0, 7, 0, 7)
landscapetools::show_landscape(r)

lsm_p_area(r)$value * 10000
#> [1] 12
get_circumscribingcircle(r)
#> # A tibble: 1 x 3
#>   layer    id  dist
#>   <int> <dbl> <dbl>
#> 1     1     5  7.21

Created on 2020-02-08 by the reprex package (v0.3.0)

The issue is that the diameter of the smallest circumscribing circle is not 7.21, but rather just a bit more than 8 (blue line):

circle

The current algorithm simply looks for the two points that are furthest apart and takes the distance as the diameter of the circle (green line). This, however, is not necessarily the smallest circumscribing circle of the patch - as shown in the example.

@mhesselbarth compared the results of our current algorithm to FRAGSTATS, and they seem to do the same calculation:

library(landscapemetrics)
library(raster)
#> Loading required package: sp
library(tidyverse)

mat <- matrix(data = NA, nrow = 13, ncol = 13)

mat[4:9, 7] <- 1
mat[4, 4:10] <- 1

ras <- raster::raster(mat, xmn = 0, xmx = 13, ymn = 0, ymx = 13)

radius <- (7.211103 / 2) # 7.211103

plot(ras)
plot(rasterToPolygons(ras), add = TRUE)
points(matrix(data = c(6.5, 7.5), ncol = 2, byrow = TRUE),
       col = "red")

lines(x = c(6.5, 6.5), y = c(7.5 - radius, 7.5 + radius), col = "green")
lines(x = c(6.5 - radius, 6.5 + radius), y = c(7.5, 7.5), col = "green")

circ <- construct_buffer(coords = matrix(c(6.5, 7.5), 1, 2),
                         shape = "circle", size = radius)

plot(circ, add = TRUE)

pull(lsm_p_circle(ras), value)
#> [1] 0.7061755

# FRAGSTATS
# 0.7062

Created on 2020-02-08 by the reprex package (v0.3.0)

The other issue I'd like to address is that for patches that consist of only one cell lsm_p_circle returns zero:

library(landscapemetrics)

# A 1-cell patch
mat1 <- matrix(data = c(NA,NA,NA,
                        NA, 5,NA,
                        NA,NA,NA), nrow = 3, ncol = 3)
r <- raster::raster(mat1)
raster::extent(r) <- c(0, 3, 0, 3)
landscapetools::show_landscape(r)

lsm_p_area(r)$value * 10000
#> [1] 1
lsm_p_circle(r)
#> # A tibble: 1 x 6
#>   layer level class    id metric value
#>   <int> <chr> <int> <int> <chr>  <dbl>
#> 1     1 patch     5     1 circle     0

Created on 2020-02-08 by the reprex package (v0.3.0)

This just doesn't make sense to me. A single-cell patch has a clear size and also a circle can be drawn around it.

Great work @bitbacchus and @mhesselbarth. I would suggest adding some explanation of the changes (including some of the figures showed above) to https://r-spatialecology.github.io/landscapemetrics/articles/articles/comparing_tools.html,

I already started doing so :)

Done. Pls re-open if needed.