0

I use geom_segment() from ggplot2 package in R, where the data attribute is a vector with two elements. The segment is an arrow. I want to hide the segment if one of the elements of the data vector equals 0. Is there a way to only plot the segment if a certain condition is true?

If an example is needed to understand what I mean, please let me know. My current use case is quite complex and requires some preparation to be shown here.

EDIT: Here's my reduced but working example, taken from this post and extended a little bit. I want the arrows not to show up when exposure_time is 0.

# load necessary libraries
library(ggplot2)
library(sf)

# load csv data
photo_positions <- readr::read_csv("photos_hamburg2.csv") |>
  sf::st_as_sf(coords=c('X', 'Y'))

# transform degrees to radians for orientation values
photo_positions[['orientation_rad']] = photo_positions[['orientation']] * pi / 180

# define a length_factor
length_factor <- .2
  
# test plot
ggplot(data = photo_positions) +
  
  # extract coordinates
  stat_sf_coordinates() +
  
  # draw arrows with orientation and length from attributes
  geom_segment(
    stat = "sf_coordinates",
    mapping = aes(
      geometry = geometry,
      x = after_stat(x), 
      y = after_stat(y),
      xend = after_stat(x) + photo_positions[['exposure_time']] * length_factor * sin(photo_positions[['orientation_rad']]),
      yend = after_stat(y) + photo_positions[['exposure_time']] * length_factor * cos(photo_positions[['orientation_rad']])
    ),
    arrow = arrow(),
    size = 2,
    color = "turquoise"
  ) +
  
  # draw circle markers
  geom_sf(stat = "sf_coordinates", mapping = aes(geometry = geometry, x = after_stat(x), y = after_stat(y)), size = 4, shape = 21, fill = "white") +
  
  # axis labels
  xlab("Longitude") + ylab("Latitude") +
  
  #map title
  ggtitle("Photos in Hamburg")

Not very realistic, but hopefully showing what I want to achieve. In my real use case I work with wind speeds and wind directions for different locations, but it was too complicated to reduce it to a suitable example.

CSV data used:

X,Y,name,orientation,exposure_time
9.991293,53.55456,"Alster view 2",59,0.004
9.992967,53.550898,"Rathaus view 2",219,0.008
9.995563,53.556932,"Alster view 1",201,0
9.992591,53.551986,"Rathaus view 1",177,0
9.995724,53.552775,"Alster view 3",338,0.016

Screenshot of the result (including arrows to be hidden)

winnewoerp
  • 161
  • 6
  • 1
    Yes a [minimal reproducible example](https://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example) is (always) required, please. – neilfws Oct 21 '22 at 00:14
  • You can assign the plot to a variable, i.e. `p <- ggplot(data, aes(x=x1)) + geom_point()` then if a condition met add the desired element: `if(condition) {p <- p + geom_segment())}` and finally `print(p)`. Please share an example to make it possible to give an answer to you. – Ric Oct 21 '22 at 00:15
  • Using a manual color scale and setting the color when the element == 0 to NA should do the trick. – Dan Slone Oct 21 '22 at 03:02
  • "the data attribute is a vector with two elements" seems to use `attribute`, `vector` and `elements` differently than I expected, so an example would be very helpful. Maybe you're saying the data argument is a data frame with two variables? – Jon Spring Oct 21 '22 at 03:10
  • Does `data` hold xy coordinates and you are drawing arrows from the origin and you want to skip zero-length segments? – Jon Spring Oct 21 '22 at 03:11
  • Thanks for the comments. I added a working example to show how I currently solve it and what I have not solved yet. – winnewoerp Oct 21 '22 at 06:01
  • @JonSpring: Yes, that's what I want, exclude zero-length segments. Do you have any hints for me and is my example helpful? – winnewoerp Oct 21 '22 at 18:45
  • `photo_positions <- photo_positions[photo_positions$'exposure_time' > 0,]` or `photo_positions <- subset(photo_positions, 'exposure_time' > 0)`would limit the `photo_positions` data frame to rows with positive non-zero exposure time. – Jon Spring Oct 21 '22 at 18:52
  • Thank you! That will work. I don't know why, but for some reason I had not thought of the solution to reduce the data frame _before_ the `ggplot()` operations. – winnewoerp Oct 22 '22 at 00:36

1 Answers1

0

Here's the solution with photo_positions <- photo_positions[photo_positions$'exposure_time' > 0,] from Jon Spring's comment included, based on the same CSV data as provided with the question.

# load necessary libraries
library(ggplot2)
library(sf)

# load csv data
photo_positions <- readr::read_csv("photos_hamburg2.csv") |>
  sf::st_as_sf(coords=c('X', 'Y'))

# remove rows with zero values for exposure time data
photo_positions <- photo_positions[photo_positions$'exposure_time' > 0,]

# transform degrees to radians for orientation values
photo_positions[['orientation_rad']] = photo_positions[['orientation']] * pi / 180

# define a length_factor
length_factor <- .2
  
# test plot
ggplot(data = photo_positions) +
  
  # extract coordinates
  stat_sf_coordinates() +
  
  # draw arrows with orientation and length from attributes
  geom_segment(
    stat = "sf_coordinates",
    mapping = aes(
      geometry = geometry,
      x = after_stat(x), 
      y = after_stat(y),
      xend = after_stat(x) + photo_positions[['exposure_time']] * length_factor * sin(photo_positions[['orientation_rad']]),
      yend = after_stat(y) + photo_positions[['exposure_time']] * length_factor * cos(photo_positions[['orientation_rad']])
    ),
    arrow = arrow(),
    size = 2,
    color = "turquoise"
  ) +
  
  # draw circle markers
  geom_sf(stat = "sf_coordinates", mapping = aes(geometry = geometry, x = after_stat(x), y = after_stat(y)), size = 4, shape = 21, fill = "white") +
  
  # axis labels
  xlab("Longitude") + ylab("Latitude") +
  
  #map title
  ggtitle("Photos in Hamburg")
winnewoerp
  • 161
  • 6