Why do geom_sf() with dotted lines look so messy?

ggplot2
spatial

#1

Sorry, I don't come up with the good issue title..., but I wonder why these lines have uneven widths. Is this expected? Or am I doing something wrong?

library(ggplot2)

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

ggplot(nc) +
  geom_sf(linetype = "dotted", size = 1.5) +
  theme_minimal()


ggplot(nc) +
  geom_sf(linetype = "dashed", size = 1.5) +
  theme_minimal()


# This seems rather OK
plot(nc$geometry, lty = 3, lwd = 3)

Created on 2018-06-04 by the reprex package (v0.2.0).

Session info
devtools::session_info()
#> ─ Session info ──────────────────────────────────────────────────────────
#>  setting  value                       
#>  version  R version 3.5.0 (2018-04-23)
#>  os       Windows 10 x64              
#>  system   x86_64, mingw32             
#>  ui       RTerm                       
#>  language (EN)                        
#>  collate  Japanese_Japan.932          
#>  tz       Asia/Tokyo                  
#>  date     2018-06-04                  
#> 
#> ─ Packages ──────────────────────────────────────────────────────────────
#>  package     * version     date       source                            
#>  assertthat    0.2.0       2017-04-11 CRAN (R 3.5.0)                    
#>  backports     1.1.2       2017-12-13 CRAN (R 3.5.0)                    
#>  bindr         0.1.1       2018-03-13 CRAN (R 3.5.0)                    
#>  bindrcpp      0.2.2       2018-03-29 CRAN (R 3.5.0)                    
#>  callr         2.0.4       2018-05-15 CRAN (R 3.5.0)                    
#>  class         7.3-14      2015-08-30 CRAN (R 3.5.0)                    
#>  classInt      0.2-3       2018-04-16 CRAN (R 3.5.0)                    
#>  cli           1.0.0       2017-11-05 CRAN (R 3.5.0)                    
#>  clisymbols    1.2.0       2017-05-21 CRAN (R 3.5.0)                    
#>  colorspace    1.3-2       2016-12-14 CRAN (R 3.5.0)                    
#>  crayon        1.3.4       2017-09-16 CRAN (R 3.5.0)                    
#>  curl          3.2         2018-03-28 CRAN (R 3.5.0)                    
#>  DBI           1.0.0       2018-05-02 CRAN (R 3.5.0)                    
#>  debugme       1.1.0       2017-10-22 CRAN (R 3.5.0)                    
#>  desc          1.2.0       2018-05-01 CRAN (R 3.5.0)                    
#>  devtools      1.13.5.9000 2018-05-17 Github (r-lib/devtools@13ee56b)   
#>  digest        0.6.15      2018-01-28 CRAN (R 3.5.0)                    
#>  e1071         1.6-8       2017-02-02 CRAN (R 3.5.0)                    
#>  evaluate      0.10.1      2017-06-24 CRAN (R 3.5.0)                    
#>  ggplot2     * 2.2.1.9000  2018-06-04 Github (tidyverse/ggplot2@cc48035)
#>  glue          1.2.0       2017-10-29 CRAN (R 3.5.0)                    
#>  gtable        0.2.0       2016-02-26 CRAN (R 3.5.0)                    
#>  htmltools     0.3.6       2017-04-28 CRAN (R 3.5.0)                    
#>  httr          1.3.1       2017-08-20 CRAN (R 3.5.0)                    
#>  knitr         1.20.2      2018-05-10 local                             
#>  lazyeval      0.2.1       2017-10-29 CRAN (R 3.5.0)                    
#>  magrittr      1.5         2014-11-22 CRAN (R 3.5.0)                    
#>  memoise       1.1.0       2017-04-21 CRAN (R 3.5.0)                    
#>  mime          0.5         2016-07-07 CRAN (R 3.5.0)                    
#>  munsell       0.4.3       2016-02-13 CRAN (R 3.5.0)                    
#>  pillar        1.2.3       2018-05-25 CRAN (R 3.5.0)                    
#>  pkgbuild      1.0.0       2018-05-17 Github (r-lib/pkgbuild@0457039)   
#>  pkgconfig     2.0.1       2017-03-21 CRAN (R 3.5.0)                    
#>  pkgload       1.0.0       2018-05-17 Github (r-lib/pkgload@35efedd)    
#>  plyr          1.8.4       2016-06-08 CRAN (R 3.5.0)                    
#>  processx      3.1.0       2018-05-15 CRAN (R 3.5.0)                    
#>  R6            2.2.2       2017-06-17 CRAN (R 3.5.0)                    
#>  Rcpp          0.12.17     2018-05-18 CRAN (R 3.5.0)                    
#>  rlang         0.2.1       2018-05-30 CRAN (R 3.5.0)                    
#>  rmarkdown     1.9         2018-03-01 CRAN (R 3.5.0)                    
#>  rprojroot     1.3-2       2018-01-03 CRAN (R 3.5.0)                    
#>  scales        0.5.0.9000  2018-06-04 Github (hadley/scales@d767915)    
#>  sessioninfo   1.0.0       2017-06-21 CRAN (R 3.5.0)                    
#>  sf            0.6-3       2018-05-17 CRAN (R 3.5.0)                    
#>  spData        0.2.8.3     2018-03-25 CRAN (R 3.5.0)                    
#>  stringi       1.2.2       2018-05-02 CRAN (R 3.5.0)                    
#>  stringr       1.3.1       2018-05-10 CRAN (R 3.5.0)                    
#>  testthat      2.0.0       2017-12-13 CRAN (R 3.5.0)                    
#>  tibble        1.4.2       2018-01-22 CRAN (R 3.5.0)                    
#>  udunits2      0.13        2016-11-17 CRAN (R 3.5.0)                    
#>  units         0.5-1       2018-01-08 CRAN (R 3.5.0)                    
#>  usethis       1.3.0       2018-02-24 CRAN (R 3.5.0)                    
#>  withr         2.1.2       2018-05-29 Github (jimhester/withr@70d6321)  
#>  xml2          1.2.0       2018-01-24 CRAN (R 3.5.0)                    
#>  yaml          2.1.19      2018-05-01 CRAN (R 3.5.0)

#2

I'm not sure why the "standard" line types display poorly, especially the "dotted" one. However, you can use linetype codes to get more control over how the lines look.

ggplot(nc) +
  geom_sf(linetype = "11", size = 1.5) +
  theme_minimal()

ggplot(nc) +
  geom_sf(linetype = "21", size = 1.5) +
  theme_minimal()


#3

Wow, thanks!! I didn't know this way of specification.


#4

Now I think I've figured out the problem. There are at least two problem on my code:

Problem 1) Lines are under other polygon fills

The lines and fills of polygons are drawn geometry by geometry, so it's natural that we can't see the underlying lines.
I should have drawn them independently:

library(ggplot2)
library(patchwork)

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

p1 <- ggplot(nc) +
  geom_sf(linetype = "dotted", size = 1.5) +
  theme_minimal()

p2 <- ggplot(nc) +
  # draw polygon fills
  geom_sf(colour = "transparent") +
  # draw polygon lines
  geom_sf(fill = "transparent", linetype = "dotted", size = 1.5) +
  theme_minimal()

p1 / p2

Problem 2) Lines are overwrapped

The boundaries between polygons are drawn multiple times. I should have extract the boundaries and merge them beforehand (Are there easier way to do this...?):

library(sf)

nc_12 <- tibble::rownames_to_column(nc[1:2,], "id")

nc_12_merged <- nc_12 %>%
  st_boundary() %>%
  st_union() %>%
  st_line_merge() %>%
  st_sf()

p1 <- ggplot(nc_12) +
  geom_sf(aes(colour = id), fill = "transparent", linetype = "dotted", size = 4) +
  theme_minimal()

p2 <-  ggplot(nc_12_merged) +
  geom_sf(colour = "black", fill = "transparent", linetype = "dotted", size = 4) +
  theme_minimal()

p1 / p2