0

I'm quite new to R and am trying to create a map of my country with points overlayed on it (representing cities, with points sized by population). I've already created the map with geom_sf() using lat, long boundaries, and have stored it as map.

This is an example of the code I'm trying to replicate, where cities is a df with columns state, pop, lat and long (with no missing values):

map <- map +
  geom_point(aes(x = cities$long[1], y = cities$lat[1], size = cities$pop[1])) +
  geom_point(aes(x = cities$long[2], y = cities$lat[2], size = cities$pop[2])) +
  geom_point(aes(x = cities$long[3], y = cities$lat[3], size = cities$pop[3])) +
  geom_point(aes(x = cities$long[4], y = cities$lat[4], size = cities$pop[4])) +
  geom_point(aes(x = cities$long[5], y = cities$lat[5], size = cities$pop[5]))

This is the loop that I thought would work, but it seems to be overwriting the geom_point with each iteration as my map just ends up with the last point. When I output a map with each iteration, it just shows the most recent point.

or(i in 1:nrow(cities)){
  if(!is.na(cities$lat[i]) && !is.na(cities$long[i])){
    map <- map +
      geom_point(aes(x = cities$long[i], y = cities$lat[i], size = cities$pop[i]))
  }
}

I hope that I've provided enough info - please let me know if I haven't. Thank you!

  • any chance of a [mcve] ... ? – Ben Bolker May 30 '20 at 04:08
  • As a new R user, maybe these two concepts will help: (1) with ggplot, you provide the data frame in the `data` argument, and provide only the column names (that is, `long` rather than `cities$long`) inside `aes`. (2) R is "vectorized". You usually don't need a for loop (see [chapter 3](https://www.burns-stat.com/pages/Tutor/R_inferno.pdf)). Instead, you provide the whole vector of values (e.g., `long`, `lat`, and `pop` are vectors of values) and the function, `geom_point` in this case, operates on all the values with a single call to the function. – eipi10 May 30 '20 at 04:37
  • Regarding why you get only the last point with a for loop, see [here](https://stackoverflow.com/a/26246791/496488). – eipi10 May 30 '20 at 04:44
  • 1
    @eipi10 Thank you! I see where I've gone wrong and appreciate the link with the explanation of lazy evaluation. Certainly wasn't something I was aware of. The intro to chapter 3 made me laugh: "This is speaking R with a C accent—a strong accent." I feel exposed. Also, good to know about minimal reproducible examples for next time. Thanks again. – StillLearningBeGentle May 30 '20 at 08:18

1 Answers1

1

There's no need to do this in a loop.

Can't reproduce without your data, but assuming that your cities object looks like:

cities <- data.frame(name = .., 
                     pop = .., 
                     lat = ..., 
                     long = ...)

and given that your base map is a geom_sf object, this is all the code you'd need.

cities_spatial <- cities %>% 
  st_as_sf(coords = c("lat","long"), crs = 4326)

map <- map +
  geom_sf(data = cities_spatial, aes(size = pop))

The option crs = 4326 is to ensure that your data is projected in WGS84 which is standard for lat/long coordinates. If your base map map is projected with a different projection you may need to adjust it to match your lat/long data as well, using sf::st_transform(...)

dshkol
  • 1,208
  • 7
  • 23