Search code examples
rggplot2colorbar

How to modify a continous ggplot legend in R


I'm using ggplot to graph the bias of the mean temperature in South America.

In order to graph this, I'm using the following code:

ggplot(bias.df2) +  
  geom_tile(aes(x=x, y=y, fill=pr), alpha=0.8) + 
  scale_fill_viridis(na.value="white") +
  coord_equal() +
  theme(legend.position="bottom") +
  theme(legend.key.width=unit(2, "cm"))+
  scale_color_continuous(limits=c(-10,10),breaks=brkbias)

Which generates the following color bar:

ggplot legend

But I need the color bar to look like this:

Grads legend

I've tried modifying the limits of the colourbar but nothing seems to generate the kind of plot that I need. Would really appreciate any help to solve this.

EDIT: The data I'm using can be found in this csv file.


Solution

  • guide_colorsteps() can be used in combination with the breaks = argument of scale_fill_viridis_c() to print a discrete colorbar with the continuous fill. We can modify the code linked in the comments to add the triangles to that guide. Since you have a horizontal bar, it requires moving and pointing the triangles horizontally instead of vertically.

    library(ggplot2)
    library(gtable)
    library(grid)
    
    bias.df2 <- read.csv("~/Downloads/data.csv")
    
    my_triangle_colorsteps <- function(...) {
      guide <- guide_colorsteps(...)
      class(guide) <- c("my_triangle_colorsteps", class(guide))
      guide
    }
    
    guide_gengrob.my_triangle_colorsteps <- function(...) {
      # First draw normal colorsteps
      guide <- NextMethod()
      # Extract bar / colours
      is_bar <- grep("^bar$", guide$layout$name)
      bar <- guide$grobs[[is_bar]]
      extremes <- c(bar$gp$fill[1], bar$gp$fill[length(bar$gp$fill)])
      # Extract size
      width  <- guide$widths[guide$layout$l[is_bar]]
      height <- guide$heights[guide$layout$t[is_bar]]
      short  <- min(convertUnit(width, "cm",  valueOnly = TRUE),
                    convertUnit(height, "cm", valueOnly = TRUE))
      # Make space for triangles
      guide <- gtable_add_cols(guide, unit(short, "cm"),
                               guide$layout$t[is_bar] - 1)
      guide <- gtable_add_cols(guide, unit(short, "cm"),
                               guide$layout$t[is_bar])
    
      left <- polygonGrob(
        x = unit(c(0, 1, 1), "npc"),
        y = unit(c(0.5, 1, 0), "npc"),
        gp = gpar(fill = extremes[1], col = NA)
      )
      right <- polygonGrob(
        x = unit(c(0, 1, 0), "npc"),
        y = unit(c(0, 0.5, 1), "npc"),
        gp = gpar(fill = extremes[2], col = NA)
      )
      # Add triangles to guide
      guide <- gtable_add_grob(
        guide, left, 
        t = guide$layout$t[is_bar],
        l = guide$layout$l[is_bar] - 1
      )
      guide <- gtable_add_grob(
        guide, right,
        t = guide$layout$t[is_bar],
        l = guide$layout$l[is_bar] + 1
      )
      
      return(guide)
    }
    
    ggplot(bias.df2) +  
      geom_tile(aes(x=x, y=y, fill=pr), alpha=0.8) + 
      scale_fill_viridis_c(na.value="white", limits = c(-10, 10),
                           breaks = c(-10, -7, -4, -1, -.5, .5, 1, 4, 7, 10), 
                           guide = my_triangle_colorsteps(show.limits = TRUE)) +
      coord_equal() +
      theme(legend.position="bottom") +
      theme(legend.key.width=unit(2, "cm"))
    

    Created on 2022-06-01 by the reprex package (v2.0.1)