3

I usually plot maps using GrADS, and usually I use a color legend that in the plot will look like this:

I would like to do the same using ggplot2 in R. If using simply:

g <- g + scale_fill_brewer(palette="Greens", na.value="NA", name=legendtitle)
#g is the previously saved plot with some simple options, prepared with cut()

The output is of course this:

So I'd like to be able to do two things:

  1. Shift the labels so they are between the colors, note indicating the interval above (note: renaming the labels is not the problem, shifting them is)
  2. Last label should be arrow-like, to indicate that entries above the maximum (10 in the example) are indicated in the darkest color (dark green in the example).

EDIT: Using help from the answer below, I've come to this: enter image description here

Part 1. of my question is almost solved, even if it does not look perfect. I'd really like to get rid of the white space between the colors, any idea? Part 2... I have no idea whatsoever.

My code snippet uses:
theme(legend.position="bottom", legend.key.width = unit(1, "cm"), legend.key.height = unit(0.3, "cm")) + guides(fill=guide_legend(label.position = "bottom", label.hjust = 1.2))

Community
  • 1
  • 1
AF7
  • 3,160
  • 28
  • 63
  • Please don't edit your question so it becomes a new question. This may invalidate answers already supplied. – Andrie Nov 07 '14 at 14:28
  • I honestly don't see how I'd have done that. To me, the question looks the same as before, only more specific (thanks to the edits) in the way to archive the goal, which is to clone the first legend above, generated with GrADS. – AF7 Nov 07 '14 at 14:37
  • 1
    Spacing between legend elements is controlled by the `legend.margin` theme element. – Brian Diggs Nov 07 '14 at 16:07
  • @Biran If I'm not mistaken, that's the space added around the legend, not between the single legend elements. – AF7 Nov 08 '14 at 17:48

3 Answers3

4

Here is something to get you started.

The idea is that you use cut() to create the cut points, but specify the labels in the way you desire.

By putting the legend at the bottom of the plot, ggplot automatically puts the legend labels "in between" the values.

library(ggplot2)

dat <- data.frame(x=0:100, y=runif(101, 0, 10), z=seq(0, 12, len=101))

dat$col <- cut(
  dat$z, 
  breaks=c(0, 2, 4, 6, 8, 10, Inf), 
  labels=c(2, 4, 6, 8, 10, "-->")
)

ggplot(dat, aes(x, y, col=col)) + 
  geom_point(size=10) + 
  scale_colour_brewer("", palette="Greens") +
  theme(legend.position="bottom")

enter image description here

Andrie
  • 176,377
  • 47
  • 447
  • 496
  • Good suggestions, thanks. I updated my question with what I've come up with thanks to your answer. I'm not satisfied with the color legend yet, tho. If you have any more suggestion, they'd be greatly appreciated. – AF7 Nov 07 '14 at 14:26
2

As you did'nt provide the geom that you want to use in the end, I modified the answer of Andrie a little bit. I included a rectangle geom (e.g. geom_col) to fill the complete legend boxes. The bars are turned off using suitable alpha values of 0:1.

# data  
set.seed(1324)
dat <- data.frame(x=0:100, y=runif(101, 0, 10), z=seq(0, 12, len=101))
# add discrete values
dat$col <- cut(include.lowest = T,
  dat$z, 
  breaks=c(0, 2, 4, 6, 8, 10, Inf), 
  labels=c(2, 4, 6, 8, 10, "-->")
)
# the plot
ggplot(dat, aes(x,y,fill=col)) + 
  geom_point(aes(col=col),size=8, show.legend = F) +   
  geom_col(alpha=0)+
  scale_fill_brewer("", palette = "Greens")+
  scale_colour_brewer("", palette="Greens")+
  scale_alpha_discrete(range=c(0,1))+
  guides(fill = guide_legend(nrow=1, override.aes = list(alpha = 1), 
                                     label.position="bottom",
                                     label.hjust = .5)) +
  theme(legend.position="bottom",
        legend.key.width = unit(3, "cm"), 
        legend.key.height = unit(1, "cm"))

enter image description here

Roman
  • 17,008
  • 3
  • 36
  • 49
  • Thanks for the answer, but I don't see how this is better than my edit in the question, from nov 2014. Ideally one wants: a) labels between color boxes (can be done but requires fiddling with the `hjust` values, and they are never perfect) and b) no spacing between color boxes. – AF7 May 25 '18 at 09:53
1

The first part of the question can be solved with a continuous color scale. So in addition to your discrete scale, just add a continuous color scale (you may have to relabel it). Then you can put the discrete scale at the top or bottom and you should be set. Here's a reproducible example:

require(scales)
nlvls <- nlevels(diamonds$cut)
ggplot(diamonds, aes(x = price, fill = cut)) +
  geom_histogram(position = "dodge", binwidth = 1000) +
  scale_fill_brewer(palette="Greens", na.value="NA", guide='none') +
  theme(legend.position = 'bottom') +
  geom_line(aes(x=price, y=0, color=as.numeric(cut)), linetype=0) +
  scale_color_continuous(name = 'cont. scale',
                         low = brewer_pal(pal = "Greens")(nlvls)[1], 
                         high = brewer_pal(pal = "Greens")(nlvls)[nlvls])

enter image description here For the arrows, I have absolutely no idea how you would do this with ggplot2. You can probably hack something together with grid, but it may be more trouble than it's worth.

shadow
  • 21,823
  • 4
  • 63
  • 77
  • Using a continuous color scale would be confusing in my case. It's not just a bar plot but a 2D world map, so I need the levels to be well defined to allow for easy confrontation with other maps. – AF7 Nov 07 '14 at 14:24