1

I would like to make pie graph with ggplot and sf package. I have very simple data and un think there is simple method to do. All my data are pourcent :

data <- data.frame(Territory = c(1, 2, 3, 4, 5), 
                      Pins = c(25, 45, 45, 60, 75),
                      oak = c(45, 50, 45, 20, 15), 
                      land = c(30, 5, 10, 20, 10), 
                      sum = c(100, 100, 100, 100, 100))

And my graph code :

read_sf("territories.shp") %>%
  left_join(data, by = "Territory") %>%
  ggplot() +
  geom_sf(aes(fill = Pins), color = "black") + theme_bw() +
  xlab("") + ylab("") +
  scale_fill_distiller(palette = "Spectral") +
  geom_sf_text(aes(label = Territory), colour = "coral4", size = 4) 

In my shapefile I have information about n° of territory, so I didn't need to put longitude and latitude information. When I used geom_sf_text, labels are placed in the center of each sub-part of map, and and this is where I would like to put my pies.

Do you know a simple method to help me please?

thanks !

thomas leon
  • 153
  • 11
  • I don't think you can do this with the current plotting tools. You could perhaps achieve a similar message with a faceted chloroplethor a [bivariate color scale](https://slu-opengis.github.io/biscale/index.html)... – Nate Jun 08 '19 at 01:00
  • 1
    The answer [here](https://stackoverflow.com/a/44125392/8449629) may be relevant. – Z.Lin Jun 08 '19 at 04:13
  • Thank you for your comment. May be biscale can be a good alternative to the pie graph on map, but I need to understand how to work with it. About the second comment, there is an idea here. But, it would then be necessary to overlay this graphs with the map. – thomas leon Jun 08 '19 at 08:27
  • geom_sf_text(aes(label = Territory), colour = "coral4", size = 4) understand the center of each sub_map of my map. We can't just add pie like this label ? Or may-be extract the information of the position of this label to join this with the n° of territory ? I look for alternative way to do this graph without using large code like here [https://stackoverflow.com/questions/10368180/plotting-pie-graphs-on-map-in-ggplot]. Thx ! – thomas leon Jun 08 '19 at 08:34

1 Answers1

4

I don't know how much shorter this code is than the answers in the thread you linked but it at least uses the sf package. Here is one alternative using the cowplot package. I treated the pie charts like inset plots following: https://www.r-spatial.org/r/2018/10/25/ggplot2-sf-3.html

library(sf)
library(tidyr)
library(dplyr)
library(ggplot2)
library(cowplot)


states        <- sf::st_as_sf(maps::map("state", plot = FALSE, fill = TRUE))
state_coords <- st_coordinates(st_centroid(states)) %>%
  data.frame(stringsAsFactors = FALSE) %>%
  mutate(ID = states$ID) %>%
  mutate(X = (abs(abs(X) - abs(st_bbox(states)$xmin)) /
      as.numeric(abs(st_bbox(states)$xmin) - abs(st_bbox(states)$xmax))) - 0.5,
        Y = abs(abs(abs(Y) - abs(st_bbox(states)$ymin)) /
         as.numeric(abs(st_bbox(states)$ymin) - abs(st_bbox(states)$ymax))
        ))

dt     <- data.frame(Territory = c(1, 2, 3, 4, 5),
                   ID = c("california", "wyoming", "new york",
                          "kansas", "georgia"),
                   pins = c(25, 45, 45, 60, 75),
                   oak = c(45, 50, 45, 20, 15),
                   land = c(30, 5, 10, 20, 10))
res <- tidyr::gather(dt, key = "key", value = "value", -Territory, -ID) %>%
  left_join(state_coords)

make_pie <- function(dt, title = NA, legend.position = 0){
  if(is.na(title)){
    title <- unique(dt$ID)
  }
  ggplot() +
    geom_bar(data = dt,
             aes(x = "", y = value, fill = key),
             stat = "identity", width = 1) +
    coord_polar("y") +
    theme_void() +
    theme(legend.position = legend.position) +
    ggtitle(title)
}

terr1 <- make_pie(dplyr::filter(res, Territory == 1))
terr2 <- make_pie(dplyr::filter(res, Territory == 2))
terr3 <- make_pie(dplyr::filter(res, Territory == 3))
terr4 <- make_pie(dplyr::filter(res, Territory == 4))
terr5 <- make_pie(dplyr::filter(res, Territory == 5))

(gg_states <- ggplot(data = states) +
  geom_sf() +
    scale_x_continuous(expand = c(0, 0)) +
    scale_y_continuous(expand = c(0, 0 )) +
  theme(legend.position = 0,
        plot.margin = unit(c(0,0,0,0), "cm"))
    )

leg <- get_legend(make_pie(res, "", legend.position = "left"))

draw_plot_loc <- function(plot, dt){
  draw_plot(plot, x = dt$X[1], y = dt$Y[1],
            height = 0.2)
}

(all <-
ggdraw(gg_states) +
  draw_plot_loc(terr1, dplyr::filter(res, Territory == 1)) +
  draw_plot_loc(terr2, dplyr::filter(res, Territory == 2)) +
  draw_plot_loc(terr3, dplyr::filter(res, Territory == 3)) +
  draw_plot_loc(terr4, dplyr::filter(res, Territory == 4)) +
  draw_plot_loc(terr5, dplyr::filter(res, Territory == 5))
  )

cowplot::plot_grid(all, leg, rel_widths = c(1, 0.1))

enter image description here

I got most of the way there brute forcing the calculation between geographic coordinates and the draw_plot 0-1 grid but it's not perfect.

jsta
  • 3,216
  • 25
  • 35
  • Thank you for your code. I didn't use `states <- sf::st_as_sf(maps::map("state", plot = FALSE, fill = TRUE))` and I change `gg_map <- read_sf(".shp") %>% left_join(data, by = "Territory") %>% ggplot() + geom_sf() + theme(legend.position = 0)` , and it's work. But, the positioning of the pie are manual. It is possible to put this pie automatically in the right place plz ? In my real data I have 30 slots. geom_sf_text put automatically label at the center of sub_part of my map, without giving it X and Y coordinate. It is possible to make pie by Territory and place them in the centroid? thx ! – thomas leon Jun 08 '19 at 14:16
  • I did not notice that both environments are floating. is it possible to fix the layers? The manual solution proposed in the first edit could be interesting to manually adjust the center calculated by the funciton of the top, like the function annotate `("point", x =, y =) but (put the pie, x =, y =)`. The coordinate of my sf map are like 44.5°N; 3.6°E, and the centroid fonction returns x=0.07743768; y=0.20812172. thx ! – thomas leon Jun 12 '19 at 13:26
  • Can we imagine use the package cartography to resolve my problem ? – thomas leon Jun 20 '19 at 15:44