4

Data: Data

Code:

palette = brewer.pal(11,"RdYlGn")    # ColorBrewewr.org spectral palette, 11 colors
ggmap_byscen   = ggplot(wmap_byscen.df[wmap_byscen.df$variable !=c("AVG") &
                                     wmap_byscen.df$ID_1 !=c("0"),], aes(x=long, y=lat, group=group))
ggmap_byscen   = ggmap_byscen + geom_polygon(aes(fill=value)) + facet_wrap(~ variable)
ggmap_byscen   = ggmap_byscen + geom_path(colour="grey50", size=.1)
ggmap_byscen   = ggmap_byscen + geom_text(aes(x=c.long, y=c.lat, label=ID_1),size=5)
ggmap_byscen   = ggmap_byscen + scale_fill_gradientn(name="% Change",colours=palette)
ggmap_byscen   = ggmap_byscen + coord_fixed(xlim = longlimits, ylim = latlimits)
ggmap_byscen   = ggmap_byscen + scale_y_continuous(breaks=seq(-60,90,30), labels=c("60ºS","30ºS","0º","30ºN","60ºN","90ºN"))
ggmap_byscen   = ggmap_byscen + scale_x_continuous(breaks=seq(-180,180,45), labels=c("180ºW","135ºW","90ºW","45ºW","0º","45ºE","90ºE","135ºE","180ºE"))
ggmap_byscen   = ggmap_byscen + labs(x="",y="",title="Average yield impacts across all crops across\nby climate scenarios (% change)")
ggmap_byscen   = ggmap_byscen + theme(plot.title=element_text(size=rel(2), hjust=0.5, vjust=1.5, face="bold"),
                                  legend.text=element_text(size=17),
                                  legend.position="left",legend.text=element_text(size=rel(1.3)),
                                  legend.title=element_text(size=rel(1.4), hjust=0.5, vjust=1),
                                  panel.background = element_rect(fill = "white", colour = "gray95"),
                                  strip.text = element_text(size=18),
                                  axis.text.x = element_text(size=16),
                                  axis.text.y = element_text(size=16))
ggmap_byscen

Result: Map

Question: I am looking to add an additional legend defined by the column "label" in the dataframe to identify the region on the map. Preferably, I'd like the legend to be below the faceted map. I have seen examples where one can add a table entry as a separate plot and then merge the two. I could not figure out how to make it for my case.

Any help would be great, thanks.

iouraich
  • 2,944
  • 5
  • 29
  • 40

1 Answers1

4

As @jlhoward mentioned, longlimits and latlimits are not defined. I, therefore, decided to leave coord_fixed(xlim = longlimits, ylim = latlimits) part from this answer. My workaround works, but I am sure there are better ways to work on this. The challenge was to create another legend in a way it can present the data well. If you use colour in geom_text, you can create another legend, but you end up seeing the alphabet, a in the grey boxes in the legend. So, I decided to use geom_point with alpha = 0 as well as colour in aes. In this way, you have a new legend with ID names, but you do not see any points on the maps. Then, I used annotate to assign the numbers on the maps. Thanks to @jlhoward, I created a small data frame which is necessary for annotate(). If you use the original data frame, R tries to write the texts 4000 times or so. In the theme part, I added legend.key = element_rect(fill = NA) in order to remove grey squares in the legend. I made the height and width of the figure pretty small so that I could post it here. So it does not look that great. But if you specify large numbers, the figure will look better.

library(dplyr)
library(ggplot2)

wmap_byscen.df <- read.csv("mydata.csv", header = T)

mydf <- wmap_byscen.df[wmap_byscen.df$variable != c("AVG") &
        wmap_byscen.df$ID_1 != c("0"),]

### This is for annotate()

mydf2 <- select(mydf, c.long, c.lat, ID_1, ID_name) %>%
         distinct()

### Color setting

palette = brewer.pal(11,"RdYlGn")


ggplot(mydf, aes(x = long, y = lat, group = group)) +
geom_polygon(aes(fill = value)) + 
facet_wrap(~ variable) +
geom_path(colour = "grey50", size = .1) +
geom_point(aes(x = c.long, y = c.lat, color=factor(ID_name, levels=unique(ID_name)), label = ID_1), size = 1, alpha = 0) +
annotate("text", x = mydf2$c.long, y = mydf2$c.lat, label = mydf2$ID_1) +
scale_fill_gradientn(name = "% Change",colours = palette) +
scale_color_discrete(name = "Regions") +
#coord_fixed(xlim = longlimits, ylim = latlimits) +
scale_y_continuous(breaks = seq(-60,90,30), labels = c("60ºS","30ºS","0º","30ºN","60ºN","90ºN")) +
scale_x_continuous(breaks = seq(-180,180,45), labels = c("180ºW","135ºW","90ºW","45ºW","0º","45ºE","90ºE","135ºE","180ºE")) +
labs(x = "",y = "",title = "Average yield impacts across all crops across\nby climate scenarios (% change)") +
theme(plot.title = element_text(size = rel(2), hjust = 0.5, vjust = 1.5, face = "bold"),
      legend.text = element_text(size = 8),
      legend.position = "bottom",
      legend.text = element_text(size = rel(1.3)),
      legend.title = element_text(size = rel(1.4), hjust = 0.5, vjust = 1),
      panel.background = element_rect(fill = "white", colour = "gray95"),
      strip.text = element_text(size = 18),
      axis.text.x = element_text(size = 16),
      axis.text.y = element_text(size = 16),
      legend.key = element_rect(fill = NA)) +
guides(col = guide_legend(nrow = 3, byrow = TRUE)) 

enter image description here

jazzurro
  • 23,179
  • 35
  • 66
  • 76
  • 2
    If you set `alpha=0` in the call to `geom_point(...)` the points disappear and it doesn'l matter what `size=...`. – jlhoward Dec 16 '14 at 16:11
  • Is there a way to control manually the position of each legend? – iouraich Dec 16 '14 at 17:54
  • @jlhoward Thank you very much for your message. That is absolutely right. I totally forgot that when I was trying to solve this question. Let me play with the code today and revise my suggestion. Thank you for your support. – jazzurro Dec 17 '14 at 00:55
  • 2
    Also, when you use `annotate(...)` this way, you are drawing a label *for every row of `mydf`*, so each label is drawn about 4000 times at the same location. This is why this runs so slowly. OP's use of `geom_text(...)` has the same problem. You should really create a separate data frame with just the 16 labels and the coordinates. – jlhoward Dec 17 '14 at 02:52
  • 2
    Finally, note the legend is ordered alphabetically, not numerically (e.g., 1, 10, 11, 12, ... instead of 1, 2, 3, ...) this is because of the way `ggplot` manages factors. You can fix that using `color=factor(ID_name, levels=unique(ID_name))` in the call to `geom_point(aes(...))` and by using `byrow=TRUE` in the call to `guide_legend(...)` at the bottom. – jlhoward Dec 17 '14 at 02:55
  • 1
    @jlhoward Thank you very much for the further notes. Yes, I noticed that the code was so slow, but I did not think why that was happening. As for the order of legend, I just left it since it would be fixed later using factor. But it seems that this operation was more than what I thought. Thank you for the advice. Given all of these, I have some good amount of revise today. :) – jazzurro Dec 17 '14 at 03:06
  • 1
    @iouraich I thought about that. I found a post on SO, but that seems to make things a bit complicated. Have a look of [**this post**](http://stackoverflow.com/questions/13143894/how-do-i-position-two-legends-independently-in-ggplot) – jazzurro Dec 17 '14 at 03:07
  • 1
    @iouraich I revised my answer. This is much faster thanks to jlhoward. – jazzurro Dec 17 '14 at 08:02
  • @iouraich I am not sure if I am reading your message right. But, the legend is taking up space at the bottom, so you definitely have smaller maps. The other thought I have is that you may want to specify width and height in `ggsave` or `png`. Have you specified these? – jazzurro Dec 18 '14 at 02:34
  • @jazzurro I figure it out. It was just a matter of choosing the right image resolution while saving the plot as `png` file. Thank you for your work. It helped a lot. – iouraich Dec 18 '14 at 03:10
  • 1
    @iouraich Ah good to hear that. Your question gave me a good chance to know more about ggplot! – jazzurro Dec 18 '14 at 03:12