0

I have a dataset that looks like the following:

library(tidyverse)
library(sf)
library(giscoR)

temp <- data.frame(Country = c("United States", "Brazil", "Mexico", "Canada", "Argentina", "Chile",
                               "Peru", "Guatemala", 'Ecuador', "United Kingdom"),
                   Count = c(3000000, 300000, 250000, 135000, 100000, 99000, 98000, 47000, 40000, 39000))

and I'm able to successfully generate a map using the following code:

all_countries <- gisco_get_countries()
symbol_pos <- st_centroid(all_countries, of_largest_polygon = TRUE)
temp2 <- temp %>%
  left_join(symbol_pos, by=c("Country" = "NAME_ENGL")) %>%
  arrange(desc(Count))

ggplot() +
  geom_sf(data = all_countries, fill = "white") +
  geom_sf(data = temp2, pch = 21, mapping = aes(size = Count, geometry = geometry, fill = Count)) +  
  scale_size( range = c(1, 20), guide = guide_legend(direction = "horizontal", nrow = 1, label.position = "bottom")) +
  scale_fill_gradientn(colours = hcl.colors(10, "Blues 3", rev = TRUE, alpha = 0.9)) +
  guides(fill = guide_legend(title = "")) +
  theme_void() +
  theme(legend.position = "bottom")

My main issue is that the US number is so much larger than everything else that all other points are much smaller and basically white. I'd really like a visualization where I can have a layer with the same exact code, but removing the US observation, and then another layer with the US observation but in Red with a size roughly the same as the next biggest. Brazil. So it would look like the following (but with a red circle on US)

tempNoUS <- temp2 %>%
filter(Country != "United States")
ggplot() +
  geom_sf(data = all_countries, fill = "white") +
  geom_sf(data = tempNoUS, pch = 21, mapping = aes(size = Count, geometry = geometry, fill = Count)) +
  scale_size( range = c(1, 20), guide = guide_legend(direction = "horizontal", nrow = 1, label.position = "bottom")) +
  scale_fill_gradientn(colours = hcl.colors(10, "Blues 3", rev = TRUE, alpha = 0.9)) +
  guides(fill = guide_legend(title = "")) +
  theme_void() +
  theme(legend.position = "bottom")

I looked at library(ggnewscale) to see if I could add the following lines as part of my testing:

+   new_scale("color") +
  geom_sf(data =temp2 %>% filter(Country == "United States"), pch = 21, mapping = aes(size = Count, geometry = geometry, fill = Count))

and it didnt seem to really do anything.

To summarize, I'd like two geom_sf() layers, one for non-US countries with a scale_fill_gradientn of Blue3, and then the other layer just for the US with a fill of Red.

Jacob
  • 406
  • 3
  • 19
  • 2
    You've specified `new_scale("color")` but you've used `fill` to create the colour, I think what you might want to add is `new_scale("fill")`? – nrennie Feb 27 '23 at 18:43
  • Can you include examples of your data - where do `all_countries` come from? – nrennie Feb 27 '23 at 18:47
  • I updated the question to include the ```all_countries``` line. and I changed ```color``` to ```fill``` and that works! Although Im not able to change the size so right now its a tiny red circle. This may be enough for me to go on for now though. – Jacob Feb 27 '23 at 18:56
  • You can probably do something similar with `new_scale("size")`? – nrennie Feb 27 '23 at 19:06
  • Actually, as I experiment more I realize the color isn't doing what I thought it was doing. The ONLY color that's showing up is red, so I can't change it. ```new_scale("size")``` isn't doing anything either. – Jacob Feb 27 '23 at 19:33

1 Answers1

1

Is this what you're looking for?

ggplot() +
  geom_sf(data = all_countries, fill = "white") +
  geom_sf(data = tempNoUS, pch = 21, mapping = aes(size = Count, geometry = geometry, fill = Count)) +
  scale_size(range = c(1, 20), guide = guide_legend(direction = "horizontal", nrow = 1, label.position = "bottom")) +
  scale_fill_gradientn(colours = hcl.colors(10, "Blues 3", rev = TRUE, alpha = 0.9)) +
  guides(fill = guide_legend(title = "")) +
  new_scale("fill") +
  new_scale("size") +
  geom_sf(data =temp2 %>% 
            filter(Country == "United States"), pch = 21, 
          mapping = aes(size = Count, geometry = geometry, fill = Count)) +
  scale_fill_gradientn(colours = c("red")) +
  scale_size(range = c(1, 20)) +
  theme_void() +
  theme(legend.position = "right")

You might need to play around with legend sizes, scale limits to get exactly what you want. It does also sound as though doing something like a log transform on the count might b appropriate and then you wouldn't need to split the data.

enter image description here

nrennie
  • 1,877
  • 1
  • 4
  • 14