Gradient legend in base
Asked Answered
P

5

34

Earlier I asked about creating a gradient of n values in base graphics (LINK). Now I'd like to create a gradient legend that goes with it. My ideal would be something like ggplot2's gradient legends:

enter image description here

Here's some code similar to what I'm working with:

colfunc <- colorRampPalette(c("red", "blue"))
plot(1:20, 1:20, pch = 19, cex=2, col = colfunc(20))

enter image description here

Paramorph answered 13/11, 2012 at 3:26 Comment(4)
color.legend in plotrix seems to be something to look intoSerieswound
I would look at how image.plot in the package fields does it.Chelsiechelsy
@Serieswound color.legend it's very unpractical because you have to fiddle around a lot as it needs 4 coordinate points. I like it but haven't found a way to use it quickly.Demisec
Did you check function gradientLegend in package plotfunctions? rdrr.io/cran/plotfunctions/man/gradientLegend.htmlDemimondaine
C
40

Here is an example of how to build a legend from first principles using rasterImage from grDevices and layout to split the screen

layout(matrix(1:2,ncol=2), width = c(2,1),height = c(1,1))
plot(1:20, 1:20, pch = 19, cex=2, col = colfunc(20))

legend_image <- as.raster(matrix(colfunc(20), ncol=1))
plot(c(0,2),c(0,1),type = 'n', axes = F,xlab = '', ylab = '', main = 'legend title')
text(x=1.5, y = seq(0,1,l=5), labels = seq(0,1,l=5))
rasterImage(legend_image, 0, 0, 1,1)

enter image description here

Chelsiechelsy answered 13/11, 2012 at 4:5 Comment(2)
Any tips on how to inset the legend inside the figure?Rodmun
@Rodmun Yes, see answer.Sallie
D
24

Late to the party, but here is a base version presenting a legend using discrete cutoffs. Thought it might be useful for future searchers.

layout(matrix(1:2,nrow=1),widths=c(0.8,0.2))
colfunc <- colorRampPalette(c("white","black"))

par(mar=c(5.1,4.1,4.1,2.1))
plot(1:10,ann=FALSE,type="n")
grid()
points(1:10,col=colfunc(10),pch=19,cex=1.5)

xl <- 1
yb <- 1
xr <- 1.5
yt <- 2

par(mar=c(5.1,0.5,4.1,0.5))
plot(NA,type="n",ann=FALSE,xlim=c(1,2),ylim=c(1,2),xaxt="n",yaxt="n",bty="n")
rect(
     xl,
     head(seq(yb,yt,(yt-yb)/10),-1),
     xr,
     tail(seq(yb,yt,(yt-yb)/10),-1),
     col=colfunc(10)
    )

mtext(1:10,side=2,at=tail(seq(yb,yt,(yt-yb)/10),-1)-0.05,las=2,cex=0.7)

And an example image:

enter image description here

Dardani answered 15/11, 2012 at 0:19 Comment(2)
Much appreciated. This was an excellent starting point to build a general legend adder. As always, it was much simpler having been shown the way.Antisthenes
Thank you for this! Note that you don't need to use layout to fake two plots, you can use par(new=TRUE) [the nomenclature of which I've never understood!] to put the legend inside the existing plot.Enterprising
G
8

The following creates a gradient color bar with three pinpoints without any plot beforehand and no alien package is needed. Hope it is useful:

plot.new()
lgd_ = rep(NA, 11)
lgd_[c(1,6,11)] = c(1,6,11)
legend(x = 0.5, y = 0.5,
       legend = lgd_,
       fill = colorRampPalette(colors = c('black','red3','grey96'))(11),
       border = NA,
       y.intersp = 0.5,
       cex = 2, text.font = 2)
Gulosity answered 1/10, 2019 at 16:54 Comment(0)
S
5

As a refinement of @mnel's great answer, inspired from another great answer of @Josh O'Brien, here comes a way to display the gradient legend inside the plot.

colfunc <- colorRampPalette(c("red", "blue"))
legend_image <- as.raster(matrix(colfunc(20), ncol=1))

## layer 1, base plot
plot(1:20, 1:20, pch=19, cex=2, col=colfunc(20), main='
     Awesome gradient legend inside')

## layer 2, legend inside
op <- par(  ## set and store par
  fig=c(grconvertX(c(0, 10), from="user", to="ndc"),    ## set figure region
        grconvertY(c(4, 20.5), from="user", to="ndc")), 
  mar=c(1, 1, 1, 9.5),                                  ## set margins
  new=TRUE)                                ## set new for overplot w/ next plot

plot.window(c(0, 2), c(0, 1))                               ## ini plot2
rasterImage(legend_image, 0, 0, 1, 1)                       ## the gradient
lbsq <- seq.int(0, 1, l=5)                                  ## seq. for labels
axis(4, at=lbsq, pos=1, labels=F, col=0, col.ticks=1, tck=-.1)  ## axis ticks
mtext(lbsq, 4, -.5, at=lbsq, las=2, cex=.6)                    ## tick labels
mtext('diff', 3, -.125, cex=.6, adj=.1, font=2)          ## legend title

par(op)  ## reset par

enter image description here

Sallie answered 29/12, 2021 at 17:6 Comment(0)
F
0

If you don't mind installing a (lightweight) package, then you can do this automatically with tinyplot (link). It is available from CRAN.

x = 1:20
z = 1:20

library(tinyplot)

plt(x, by = z, pch = 19, cex = 2)

The default palette is (an adjusted version of) viridis. But any of the various colour palettes from palette.pals() and hcl.pals() are supported via simple keyword strings.

plt(x, by = z, pch = 19, cex = 2, palette = "agsunset")

If you prefer a formula syntax, then simply denote the group variable after |. (Here we use a one-sided formula, but only because there's no "y" variable.)

plt(~ x | z, pch = 19, cex = 2, palette = "agsunset")

P.S. Special thanks to @mnel, whose answer above provided the foundation for how tinyplot implements this kind of gradient plot internally.

Flexion answered 22/6 at 4:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.