Ggplot2 Add a Legend for Several Stat_Functions

Using legend with stat_function in ggplot2

Put colour= inside the aes() and then provide name for particular line as is should appear in legend. Legend is made for aesthetics that are only inside aes() call.

ggplot(my.df, aes(x=x)) +
stat_function(fun = MyFun, n = 1000, args = list(p = 10), aes(colour = "line1")) +
stat_function(fun = MyFun, n = 1000, args = list(p = 3), aes(colour = "line2")) +
stat_function(fun = MyFun, n = 1000, args = list(p = 2), aes(colour = "line3")) +
stat_function(fun = MyFun, n = 1000, args = list(p = 1), aes(colour = "line4")) +
scale_colour_manual("Lgend title", values = c("red", "blue", "green", "orange"))

Sample Image

ggplot2 add a legend for several stat_functions

Try this:

ggplot(NULL, aes(x=x, colour = g)) +
stat_function(data = data.frame(x = 1:5, g = factor(1)), fun = myfun1) +
stat_function(data = data.frame(x = 1:5, g = factor(2)), fun = myfun2) +
scale_colour_manual(values = c("red", "green"), labels = c("quadratic", "cubic"))

Sample Image

Adding a legend to ggplot when using stat_function

Try:

set.seed(1)
lambda = .2
n = 40
sim = 10000
newvar = rnorm(sim, mean = 1/lambda, sd=sqrt(lambda^-2/n) )
means = replicate(sim, expr = mean(rexp(n,lambda)))
ddf = data.frame(means, newvar)
mm = melt(ddf)
ggplot(mm) +geom_density( aes(value, group=variable, color=variable) )

Sample Image

How to create legend by line type and colour in stat_function

I've reduced the number of stats plotted to make it easier to see what's going on.

As the legends are the same for both graphs you only need one set of scale_x_manual.

Both linetype and colour need to be in the call to aes to appear in the legend.

To merge the two legends give both legends (colour and linetype) the same name in the call to labs.

You may find you need to define additional linetypes as the standard set comprises 6.

library(gamlss)
library(ggplot2)
library(cowplot)

xlower= 50
xupper= 183

plot1<-ggplot(data.frame(x = c(xlower , xupper)), aes(x = x)) +
xlim(c(xlower , xupper)) +
stat_function(fun = dNO, args =list(mu= 85.433,sigma=2.208), aes(colour = "Observed", linetype="Observed"))+
stat_function(fun = dSN2, args =list(mu= 97.847,sigma=2.896,nu=5.882,log=FALSE), aes(colour = "CMCC.ESM2", linetype = "CMCC.ESM2"))+
stat_function(fun = dNO, args =list(mu= 107.372,sigma=2.232), aes(colour = "TaiESM1", linetype = "TaiESM1"))+
labs(x = "Monthly average Precipitation (mm)", y = "PDF") +
theme(plot.title = element_text(hjust = 0.5),
axis.title.x = element_text(face="plain", colour="black", size = 12),
axis.title.y = element_text(face="plain", colour="black", size = 12),
legend.title = element_text(face="plain", size = 10),
legend.position = "none")

plot2<- ggplot(data.frame(x = c(xlower , xupper)), aes(x = x)) +
xlim(c(xlower , xupper)) +
stat_function(fun = pNO, args =list(mu= 85.433,sigma=2.208), aes(colour = "Observed", linetype="Observed"))+
stat_function(fun = pSN2, args =list(mu= 97.847,sigma=2.896,nu=5.882,log=FALSE), aes(colour = "CMCC.ESM2", linetype = "CMCC.ESM2"))+
stat_function(fun = dNO, args =list(mu= 107.372,sigma=2.232), aes(colour = "TaiESM1", linetype = "TaiESM1"))+
scale_color_manual(breaks = c("Observed", "CMCC.ESM2", "TaiESM1"),
values = c("Black","green", "magenta4"))+
scale_linetype_manual(breaks = c("Observed", "CMCC.ESM2", "TaiESM1"),
values = c("solid", "dashed", "longdash"))+
labs(x = "Monthly average Precipitation (mm)",
y = "CDF",
colour = "Data types",
linetype = "Data types") +
theme(plot.title = element_text(hjust = 0.5),
axis.title.x = element_text(face="plain", colour="black", size = 12),
axis.title.y = element_text(face="plain", colour="black", size = 12),
legend.title = element_text(face="plain", size = 10),
legend.position = "right")

p<- plot_grid(plot1, plot2, labels = "")
p

Sample Image

Created on 2021-11-30 by the reprex package (v2.0.1)

Combine legend for several stat_function lines and raw data points

Here's a (slightly ugly) possibility:

ggplot(data, aes(x = X, y = Y, colour = "Data")) +
geom_point() +
geom_line(aes(linetype = "Data"), alpha = 0) +
stat_function(fun = f1, aes(colour = "Function A", linetype = "Function A")) +
stat_function(fun = f2, aes(colour = "Function B", linetype = "Function B")) +
stat_function(fun = m, aes(colour = "Model", linetype = "model")) +
scale_linetype_manual(values = c("blank", "dashed", "dashed", "solid"),
guide = FALSE) +
scale_colour_manual(values = c("black", "red", "red", "red"),
guide = guide_legend(override.aes = list(
linetype = c("blank", "dashed", "dashed", "solid"),
size = c(2, 0, 0, 0)),
title = NULL))

Sample Image

I created a blank dummy line for the "Data" points (geom_line [...] alpha = 0); moved linetype to inside aes, removed linetype legend (scale_linetype_manual [...] guide = FALSE); changed linetype and point size in the legend using guide_legend(override.aes.

stat_function and legends: create plot with two separate colour legends mapped to different variables

When looking at previous examples of stat_function and legend on SO, I got the impression that it is not very easy to make the two live happily together without some hard-coding of each curve generated by stat_summary (I would be happy to find that I am wrong). See e.g. here, here, and here. In the last answer @baptiste wrote: "you'll be better off building a data.frame before plotting". That's what I try in my answer: I pre-calculated data using the function, and then use geom_line instead of stat_summary in the plot.

# load relevant packages
library(ggplot2)
library(reshape2)
library(RColorBrewer)
library(gridExtra)
library(gtable)
library(plyr)

# create base data
df <- data.frame(A = rnorm(1000, sd = 0.25),
B = rnorm(1000, sd = 0.25),
C = rnorm(1000, sd = 0.25))
melt.df <- melt(df)
melt.df$ypos <- as.numeric(melt.df$variable)

# plot points only, to get a colour legend for points
p1 <- ggplot(data = melt.df, aes(x = value, y = ypos, colour = variable)) +
geom_point(position = "jitter", alpha = 0.2, size = 2) +
xlim(-1, 1) + ylim(-5, 5) +
guides(colour =
guide_legend("Type", override.aes = list(alpha = 1, size = 4)))

p1

# grab colour legend for points
legend_points <- gtable_filter(ggplot_gtable(ggplot_build(p1)), "guide-box")

# grab colours for points. To be used in final plot
point_cols <- unique(ggplot_build(p1)[["data"]][[1]]$colour)

# create data for lines
# define function for lines
fun.bar <- function(x, param = 4) {
return(((x + 1) ^ (1 - param)) / (1 - param))
}

# parameters for lines
pars = c(1.7, 2:8)

# for each value of parameters and x (i.e. x = melt.df$value),
# calculate ypos for lines
df2 <- ldply(.data = pars, .fun = function(pars){
ypos = fun.bar(melt.df$value, pars)
data.frame(pars = pars, value = melt.df$value, ypos)
})

# colour palette for lines
line_cols <- brewer.pal(length(pars), "Set1")

# plot lines only, to get a colour legends for lines
# please note that when using ylim:
# "Observations not in this range will be dropped completely and not passed to any other layers"
# thus the warnings
p2 <- ggplot(data = df2,
aes(x = value, y = ypos, group = pars, colour = as.factor(pars))) +
geom_line() +
xlim(-1, 1) + ylim(-5, 5) +
scale_colour_manual(name = "Param", values = line_cols, labels = as.character(pars))

p2

# grab colour legend for lines
legend_lines <- gtable_filter(ggplot_gtable(ggplot_build(p2)), "guide-box")

# plot both points and lines with legend suppressed
p3 <- ggplot(data = melt.df, aes(x = value, y = ypos)) +
geom_point(aes(colour = variable),
position = "jitter", alpha = 0.2, size = 2) +
geom_line(data = df2, aes(group = pars, colour = as.factor(pars))) +
xlim(-1, 1) + ylim(-5, 5) +
theme(legend.position = "none") +
scale_colour_manual(values = c(line_cols, point_cols))
# the colours in 'scale_colour_manual' are added in the order they appear in the legend
# line colour (2, 3) appear before point cols (A, B, C)
# slightly hard-coded
# see alternative below

p3

# arrange plot and legends for points and lines with viewports
# define plotting regions (viewports)
# some hard-coding of positions
grid.newpage()
vp_plot <- viewport(x = 0.45, y = 0.5,
width = 0.9, height = 1)

vp_legend_points <- viewport(x = 0.91, y = 0.7,
width = 0.1, height = 0.25)

vp_legend_lines <- viewport(x = 0.93, y = 0.35,
width = 0.1, height = 0.75)

# add plot
print(p3, vp = vp_plot)

# add legend for points
upViewport(0)
pushViewport(vp_legend_points)
grid.draw(legend_points)

# add legend for lines
upViewport(0)
pushViewport(vp_legend_lines)
grid.draw(legend_lines)

Sample Image

# A second alternative, with greater control over the colours
# First, plot both points and lines with colour legend suppressed
# let ggplot choose the colours
p3 <- ggplot(data = melt.df, aes(x = value, y = ypos)) +
geom_point(aes(colour = variable),
position = "jitter", alpha = 0.2, size = 2) +
geom_line(data = df2, aes(group = pars, colour = as.factor(pars))) +
xlim(-1, 1) + ylim(-5, 5) +
theme(legend.position = "none")

p3

# build p3 for rendering
# get a list of data frames (one for each layer) that can be manipulated
pp3 <- ggplot_build(p3)

# grab the whole vector of point colours from plot p1
point_cols_vec <- ggplot_build(p1)[["data"]][[1]]$colour

# grab the whole vector of line colours from plot p2
line_cols_vec <- ggplot_build(p2)[["data"]][[1]]$colour

# replace 'colour' values for points, with the colours from plot p1
# points are in the first layer -> first element in the 'data' list
pp3[["data"]][[1]]$colour <- point_cols_vec

# replace 'colour' values for lines, with the colours from plot p2
# lines are in the second layer -> second element in the 'data' list
pp3[["data"]][[2]]$colour <- line_cols_vec

# build a plot grob from the data generated by ggplot_build
# to be used in grid.draw below
grob3 <- ggplot_gtable(pp3)

# arrange plot and the two legends with viewports
# define plotting regions (viewports)
vp_plot <- viewport(x = 0.45, y = 0.5,
width = 0.9, height = 1)

vp_legend_points <- viewport(x = 0.91, y = 0.7,
width = 0.1, height = 0.25)

vp_legend_lines <- viewport(x = 0.92, y = 0.35,
width = 0.1, height = 0.75)

grid.newpage()

pushViewport(vp_plot)
grid.draw(grob3)

upViewport(0)
pushViewport(vp_legend_points)
grid.draw(legend_points)

upViewport(0)
pushViewport(vp_legend_lines)
grid.draw(legend_lines)

How to change colour and add legend on Laplacian plot?

I don't have the package rmutil thus I couldn't draw your function; you can easily apply this method for yours;

library(ggplot2)
plot <- ggplot() +
geom_function(fun = function(x) sin(x),aes(color='Sinus')) +
expand_limits(x=c(-10,10)) +
geom_function(fun = function(x) cos(x),aes(color='Cosinus')) +
expand_limits(x=c(-10,10)) +
xlab("Noise Range") +
ylab("Probability") +
scale_color_manual(name='Functions',values = c(Sinus='pink',Cosinus='purple'))

fields;
Sample Image

Plotting multiple functions and adding legends for them in ggplot2

Partial answer:

ggplot(data.frame(x=c(-0.25, 0.25)), aes(x=x)) + 
geom_path(aes(colour="red"), stat="function", fun=log1plusx)+
geom_path(aes(colour="blue"), stat="function", fun=self) +
scale_colour_identity("Function", guide="legend",
labels = c("log1plusx", "self"),
breaks = c("red", "blue"))

Though in my opinion you'll be better off building a data.frame before plotting.

ggplot2: Getting a color legend to appear using stat_function() in a for loop

The help on stat_function has an example for showing two functions in the same plot. It also adds stat_function twice and specifies explicit colours and no automatic legend is generated:

f <- ggplot(data.frame(x = c(0, 10)), aes(x))
f + stat_function(fun = sin, colour = "red") +
stat_function(fun = cos, colour = "blue")

Thus, I suspect that plotting several functions with a legend is not within the scope of stat_function.

Following krlmlr's remark you could create a data set as follows:

x <- seq(0,1,0.01)
names(clusterDf)[4]<-"lam"
fun_data <- lapply(1:nrow(clusterDf),function(i) {
args <- clusterDf[i,-1]
data.frame(cluster=clusterDf$cluster[i],
x=x,
y=do.call(plotMixMdlComps,c(list(x=x),args))
)
}) %>% bind_rows

This can now be plotted directly with ggplot:

ggplot(fun_data,aes(x=x,y=y,colour=as.factor(cluster))) + geom_line(lwd=1.5)

This lets ggplot pick the colours for you. If you want to use the colours that you specified (which are, in your situation, identical to those that ggplot picks), you can add scale_colour_manual(values=cols) to the plot.

Edit:

Alternatively, you could also create the plot data using mdply from the plyr package:

library(plyr)
x <- seq(0,1,0.01)
names(clusterDf)[4]<-"lam"
fun_data <- mdply(clusterDf,function(cluster,mu,sigma,lam) {
data.frame(cluster=cluster,
x=x,
y=plotMixMdlComps(x,mu,sigma,lam)
)
}) %>% bind_rows


Related Topics



Leave a reply



Submit