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

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)
1 Like

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 Likes

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

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

4 Likes