Generating a color legend with shifted labels using ggplot2
Asked Answered
W

3

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))

Weksler answered 7/11, 2014 at 13:23 Comment(4)
Please don't edit your question so it becomes a new question. This may invalidate answers already supplied.Fatalism
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.Weksler
Spacing between legend elements is controlled by the legend.margin theme element.Cooking
@Biran If I'm not mistaken, that's the space added around the legend, not between the single legend elements.Weksler
F
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

Fatalism answered 7/11, 2014 at 13:40 Comment(1)
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.Weksler
P
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

Perloff answered 24/5, 2018 at 15:3 Comment(1)
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.Weksler
G
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.

Geez answered 7/11, 2014 at 14:9 Comment(1)
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.Weksler

© 2022 - 2024 — McMap. All rights reserved.