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"))
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"))
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) )
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
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))
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)
# 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;
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
Extracting Orthogonal Polynomial Coefficients from R's Poly() Function
Change Color Median Line Ggplot Geom_Boxplot()
Fixing Variance Values in Lme4
Update Rows of Data Frame in R
How to Speed Up or Vectorize a for Loop
R Corpus Is Messing Up My Utf-8 Encoded Text
Setting Individual Y Axis Limits with Facet Wrap Not with Scales Free_Y
Remove Numbers at the Beginning and End of a String
Replace Nas in One Variable with Values from Another Variable
How to Start Ggplot2 Geom_Bar from Different Origin
Intersecting Points and Polygons in R
Package Domc Not Available for R Version 3.0.0 Warning in Install.Packages
Passing Arguments into Multiple Match_Fun Functions in R Fuzzyjoin::Fuzzy_Join
Filling Bars in Barplot with Textiles in Ggplot2
User Defined Colour Palette in R and Ggpairs
Replace Missing Values with a Value from Another Column
Why Doesn't Comparison Between Numeric and Character Variables Give a Warning