1

Given the following data:

library(tidyverse)
library(sf)
df <- structure(list(geometry = c("LINESTRING (-85.76 38.34, -85.72 38.38)", 
                                  "LINESTRING (-85.46 38.76, -85.42 38.76)", 
                                  "LINESTRING (-85.89 38.31, -85.89 38.31)"
), var1 = c(4, 5, 6
), var2 = c(1, 2, 3
)), row.names = c(NA, -3L), class = c("tbl_df", "tbl", "data.frame"
))
df
df_sf <- sf::st_as_sf( df, wkt = "geometry" )
# Simple feature collection with 3 features and 2 fields
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: -85.89 ymin: 38.31 xmax: -85.42 ymax: 38.76
# CRS:            NA
# # A tibble: 3 x 3
#                       geometry  var1  var2
#                   <LINESTRING> <dbl> <dbl>
# 1 (-85.76 38.34, -85.72 38.38)     4     1
# 2 (-85.46 38.76, -85.42 38.76)     5     2
# 3 (-85.89 38.31, -85.89 38.31)     6     3

We can use plot to plot the data including the LINESTRING that has two points at the same location (row = 3):

plot(st_geometry(df_sf), lwd = 10)

giving:

enter image description here

but when we plot it using ggplot the point is dropped:

ggplot() +
  geom_sf(data = df_sf, lwd = 8)

enter image description here

Without manually extracting locations that only contain a point, is there a quick way to tell ggplot to plot these? I can see that these points are technically not a line as theres no distance between them but plot is able to pick them up. This question seems related but slightly different, my LINESTRINGs are already created.

thanks

1

2 Answers 2

2

This is one of those situations where the headdesk emoji might come in handy:

ggplot() +
  geom_sf(data = df_sf, lwd = 8, lineend = "round")

plot

From the package's vignette on aesthetic specs, the default lineend is "butt", which stops precisely at the end point of a line (so a line of 0 length won't have anything to show), while the "round" alternative extends beyond the end point:

illustration

TL;DR: The 0-length linestring wasn't dropped. We just couldn't see it.

Sign up to request clarification or add additional context in comments.

1 Comment

exactly what I was looking for, makes you think that round should be the default for this particular reason, thanks anyway!
1

I think that you can solve that problem if you modify the LINESTRING geometries whose length is equal to 0 and cast them as POINTS. For example:

# packages
library(ggplot2)
library(sf)
#> Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

# data
df <- structure(
  list(
    geometry = c(
      "LINESTRING (-85.76 38.34, -85.72 38.38)",
      "LINESTRING (-85.46 38.76, -85.42 38.76)", 
      "LINESTRING (-85.89 38.31, -85.89 38.31)"
      ), 
    var1 = c(4, 5, 6), 
    var2 = c(1, 2, 3)
    ), 
  row.names = c(NA, -3L), 
  class = c("tbl_df", "tbl", "data.frame")
)
df_sf <- st_as_sf( df, wkt = "geometry" )

# Rebuild the geometry column in such a way that the zero-length LINESTRINGS are
# actually POINTS:
new_df_sf_geometry <- st_geometry(df_sf)
idx <- which(st_length(new_df_sf_geometry) == 0)
for (i in idx) {
  new_df_sf_geometry[i] <- unique(st_cast(new_df_sf_geometry[i], "POINT"))
}

# This is the result
new_df_sf_geometry
#> Geometry set for 3 features 
#> geometry type:  GEOMETRY
#> dimension:      XY
#> bbox:           xmin: -85.89 ymin: 38.31 xmax: -85.42 ymax: 38.76
#> CRS:            NA
#> LINESTRING (-85.76 38.34, -85.72 38.38)
#> LINESTRING (-85.46 38.76, -85.42 38.76)
#> POINT (-85.89 38.31)

# Replace the geometry
st_geometry(df_sf) <- new_df_sf_geometry

# Plot
ggplot(df_sf) + 
  geom_sf(size = 3)

Created on 2020-05-25 by the reprex package (v0.3.0)

If you need, you can also adopt more sophisticated approaches than a for-loop such as purrr::map_if.

3 Comments

thanks but I was looking for something that didn't go down this route (I would have thought there would be an option to specify plot points). I think it makes more sense for this to be the default like plot? The user would need to know beforehand that there is LINSTRING data of length 0 within their dataset which I feel is presumptuous!
Hi! I'm sorry but I cannot help you further since I don't understand the internals of ggplot2 or geom_sf. Maybe you can create a new issue on their github page.
the solution i was after is above...you may be interested

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.