Ggplot with more than two legends - r

I have a data.frame which I'd like to scatter plot using ggplot.
The data have 3 factors whose levels I'd like to show in the legend, although the color of the points will only be according to one of these factors (df$group below).
Here's what I have so far:
set.seed(1)
df <- data.frame(x=rnorm(100),y=rnorm(100),
group=LETTERS[sample(5,100,replace=T)],
type=letters[sample(3,100,replace=T)],
background=sample(4,100,replace=T),stringsAsFactors=F)
df$group <- factor(df$group,LETTERS[1:5])
df$type <- factor(df$type,;etters[1:3])
df$background <- factor(df$background,c(1:4))
I manually specify colors:
require(RColorBrewer)
require(scales)
all.colors <- hcl(h=seq(0,(12-1)/(12),length=12)*360,c=100,l=65,fixup=TRUE)
group.colors <- all.colors[1:5]
type.colors <- all.colors[6:8]
background.colors <- all.colors[9:12]
This is what I have for showing the 3 factors in the legend (df$group and df$type):
require(ggplot2)
ggplot(df,aes(x=x,y=y,colour=group,fill=type,alpha=background))+geom_point(cex=2,shape=1,stroke=1)+
theme_bw()+theme(strip.background=element_blank())+scale_color_manual(drop=FALSE,values=group.colors,name="group")+
guides(fill=guide_legend(override.aes=list(colour=type.colors,pch=0)))
So my question is how to get background.colors appear in the legend under "background" rather than the gray scale colors chosen by default that currently appear there.

ggplot(df,aes(x=x, y=y, colour=group, fill=type, alpha=background))+
geom_point(cex=2, shape=1, stroke=1) +
theme_bw() +
theme(strip.background=element_blank()) +
scale_color_manual(drop=FALSE, values=group.colors, name="group") +
guides(fill=guide_legend(override.aes=list(colour=type.colors,pch=0)),
alpha=guide_legend(override.aes=list(colour=background.colors,pch=0)))

Related

How do I add a separate legend for each variable in geom_tile?

I would like to have a separate scale bar for each variable.
I have measurements taken throughout the water column for which the means have been calculated into 50cm bins. I would like to use geom_tile to show the variation of each variable in each bin throughout the water column, so the plot has the variable (categorical) on the x-axis, the depth on the y-axis and a different colour scale for each variable representing the value. I am able to do this for one variable using
ggplot(data, aes(x=var, y=depth, fill=value, color=value)) +
geom_tile(size=0.6)+ theme_classic()+scale_y_continuous(limits = c(0,11), expand = c(0, 0))
But if I put all variables onto one plot, the legend is scaled to the min and max of all values so the variation between bins is lost.
To provide a reproducible example, I have used the mtcars, and I have included alpha = which, of course, doesn't help much because the scale of each variable is so different
data("mtcars")
# STACKS DATA
library(reshape2)
dat2b <- melt(mtcars, id.vars=1:2)
dat2b
ggplot(dat2b) +
geom_tile(aes(x=variable , y=cyl, fill=variable, alpha = value))
Which produces
Is there a way I can add a scale bar for each variable on the plot?
This question is similar to others (e.g. here and here), but they do not use a categorical variable on the x-axis, so I have not been able to modify them to produce the desired plot.
Here is a mock-up of the plot I have in mind using just four of the variables, except I would have all legends horizontal at the bottom of the plot using theme(legend.position="bottom")
Hope this helps:
The function myfun was originally posted by Duck here: R ggplot heatmap with multiple rows having separate legends on the same graph
library(purrr)
library(ggplot2)
library(patchwork)
data("mtcars")
# STACKS DATA
library(reshape2)
dat2b <- melt(mtcars, id.vars=1:2)
dat2b
#Split into list
List <- split(dat2b,dat2b$variable)
#Function for plots
myfun <- function(x)
{
G <- ggplot(x, aes(x=variable, y=cyl, fill = value)) +
geom_tile() +
theme(legend.direction = "vertical", legend.position="bottom")
return(G)
}
#Apply
List2 <- lapply(List,myfun)
#Plot
reduce(List2, `+`)+plot_annotation(title = 'My plot')
patchwork::wrap_plots(List2)

Specify colour to a stacked area graph

I would like to change specific colours (oder than rainbow default) to each column "Sector" in the code below
I've read that geom_area doesn't allow changes in colour? if so is there another way to plot this graph without using ggplot2 package?
Sector <- rep(c("S01","S02","S03","S04","S05","S06","S07"),times=7)
Year <- as.numeric(rep(c("1950","1960","1970","1980","1990","2000","2010"),each=7))
Value <- runif(49, 10, 100)
data <- data.frame(Sector,Year,Value)
data
ggplot(data, aes(x=Year, y=Value, fill=Sector)) +
geom_area(stat="identity")
There are a lot of ways to change the color scale in ggplot.
Here's a way where you can specify exactly which colors you want:
Sector <- rep(c("S01","S02","S03","S04","S05","S06","S07"),times=7)
Year <- as.numeric(rep(c("1950","1960","1970","1980","1990","2000","2010"),each=7))
Value <- runif(49, 10, 100)
data <- data.frame(Sector,Year,Value)
data
ggplot(data, aes(x=Year, y=Value, fill=Sector)) + geom_area(stat="identity") +
scale_fill_manual(values = c("black","blue","gray","orange","tan","purple","darkgray"))

Raster map with discrete color scale for negative and positive values R

I have two dataframes which I will like to map. The dfs have the same xy coordinates and I need a single colorbar with a visible discrete color scale for both dfs like the one shown here. I would like the colors in the colorkey to match the self-defined breaks. a more general solution that can be applied outside this example is much appreciated
The RdYIBu color palette from the RcolorBrewer package is what I am after.
My code so far:
library(rasterVis)
ras1 <- raster(nrow=10,ncol=10)
set.seed(1)
ras1[] <- rchisq(df=10,n=10*10)
ras2=ras1*(-1)/2
s <- stack(ras1,ras2)
Uniques <- cellStats(s,stat=unique)
Uniques.max <- max(Uniques)
Uniques.min <- min(Uniques)
my.at <- round(seq(ceiling(Uniques.max), floor(Uniques.min), length.out= 10),0)
myColorkey <- list(at=my.at, labels=list(at=my.at))
levelplot(s, at=my.at, colorkey=myColorkey,par.settings=RdBuTheme())
How can I set the values in the colorkey to match values on the map as shown on the sample map above? Note that the number of colors in the colorkey should be the same number shown on the map.
Many thanks for your help. Your suggestions will help me to develop many such maps.
Thanks.
The following should get you going. With the ggplot2 documentation and the many online examples,you should be able to tweak the aesthetics to get it to look exactly as you want without any troubles.Cheers.
#Order breaks from lowest to highest
my_at <- sort(my_at)
#Get desired core colours from brewer
cols0 <- brewer.pal(n=length(my_at), name="RdYlBu")
#Derive desired break/legend colours from gradient of selected brewer palette
cols1 <- colorRampPalette(cols0, space="rgb")(length(my_at))
#Convert raster to dataframe
df <- as.data.frame(s, xy=T)
names(df) <- c("x", "y", "Epoch1", "Epoch2")
#Melt n-band raster to long format
dfm <- melt(df, id.vars=c("x", "y"), variable.name="epoch", value.name="value")
#Construct continuous raster plot without legend
#Note usage of argument `values` in `scale_fill_gradientn` -
#-since your legend breaks are not equi-spaced!!!
#Also note usage of coord_equal()
a <- ggplot(data=dfm, aes(x=x, y=y)) + geom_raster(aes(fill=value)) + coord_equal()+
facet_wrap(facets=~epoch, ncol=1) + theme_bw() +
scale_x_continuous(expand=c(0,0))+
scale_y_continuous(expand=c(0,0))+
scale_fill_gradientn(colours=cols1,
values=rescale(my_at),
limits=range(dfm$value),
breaks=my_at) +
theme(legend.position="none", panel.grid=element_blank())
#Make dummy plot discrete legend whose colour breaks go along `cols1`
df_leg <- data.frame(x=1:length(my_at), y=length(my_at):1, value=my_at)
gg_leg <- ggplot(data=df_leg, aes(x=x, y=y)) + geom_raster(aes(fill=factor(value))) +
scale_fill_manual(breaks=my_at, values=cols1,
guide=guide_legend(title="",
label.position="bottom")) +
theme(legend.position="bottom")
#Extract discrete legend from dummy plot
tmp <- ggplot_gtable(ggplot_build(gg_leg))
leg <- which(sapply(tmp$grobs, function(x) x$name)=="guide-box")
legend <- tmp$grobs[[leg]]
#Combine continuous plot of your rasters with the discrete legend
grid.arrange(a, legend, ncol=1, heights=c(4, 0.8))

Change label keys and title on a density curve plot with ggplot2

I have a density plot with this code:
p <- ggplot(data=paddling, aes(frequency, color=type, fill=type))
p <- p + geom_density(alpha=0.2)
p <- p + scale_x_continuous(limits=c(0, 1000),name='Frequency (Hz)')
I would like to change the legend keys and legend title. I tried using:
p <- p + scale_fill_discrete(name='Paddling type',labels=c("Hands only", "Hands and feet"))
But it just added another legend on top of the other one:
Any help would be greatly appreciated! Thank you!!
What you were doing was halfway there. As you have two aestethics in use (fill and color), both of these need a legend. So, if you change legend title and labels for fill, the legend for color doesn't change and gets plotted as is. As such, the solution is to add a 'scale_color_discrete':
#generate data
set.seed(123)
n=1000
paddling <- data.frame(frequency=runif(n,0,n),
type=sample(c("hand_only","with_feet"),n,T))
#plot
p <- ggplot(data=paddling, aes(frequency, color=type, fill=type)) +
geom_density(alpha=0.2)+
scale_x_continuous(limits=c(0, 1000),name='Frequency (Hz)') +
scale_fill_discrete(name='Paddling type',labels=c("Hands only", "Hands and feet"))+
scale_color_discrete(name='Paddling type',labels=c("Hands only", "Hands and feet"))
p
This can be a bit cumbersome if you have a lot of mappings, levels. This is another approach: change the data (both column name and factor levels)
#note the backticks needed for space
paddling$`Paddling type` <- paddling$type
levels(paddling$`Paddling type`)
levels(paddling$`Paddling type`) <- c("Hands only","Hands and feet")
p2 <- p <- ggplot(data=paddling, aes(frequency, color=`Paddling type`, fill=`Paddling type`)) +
geom_density(alpha=0.2)+
scale_x_continuous(limits=c(0, 1000),name='Frequency (Hz)')

bar and line plot in one chart with a legend under ggplot2

I would like put a bar and a line plot of two separate but related series on the same chart with a legend (the bar plot is of quarterly growth the line plot is of annual growth).
I currently do it with a data.frame in wide format and code like this:
p <- ggplot() +
geom_bar(df, aes(x=Date, y=quarterly), colour='blue') +
geom_line(df, aes(x=Date, y=annual), colour='red')
but I cannot work out how to add a legend, which has a red line labeled 'Annual Growth'; and a blue square labeled 'Quarterly Growth'.
Alternatively, I cannot work out how to have differnt geoms for different series with a long-form data.frame.
UPDATE:
The following example code gets me part of the way towards a solution, but with a really ugly duplicate legend. Still looking for a complete solution ... This approach is based on putting the data in long form and then plotting subsets of the data ...
library(ggplot2)
library(reshape)
library(plyr)
library(scales)
### --- make a fake data set
x <- rep(as.Date('2012-01-01'), 24) + (1:24)*30
ybar <- 1:24
yline <- ybar + 1
df <- data.frame(x=x, ybar=ybar, yline=yline)
molten <- melt(df, id.vars='x', measure.vars=c('ybar', 'yline'))
molten$line <- ifelse(molten$variable=='yline', TRUE, FALSE)
molten$bar <- ifelse(molten$variable=='ybar', TRUE, FALSE)
### --- subset the data set
df.line <- subset(molten, line==TRUE)
df.bar <- subset(molten, bar==TRUE)
### --- plot it
p <- ggplot() +
geom_bar(data=df.bar, mapping=aes(x=x, y=value, fill=variable, colour=variable),
stat='identity', position='dodge') +
geom_line(data=df.line, mapping=aes(x=x, y=value, colour=variable)) +
opts(title="Test Plot", legend.position="right")
ggsave(p, width=5, height=3, filename='plot.png', dpi=150)
And an example plot ...
By use of the subset argument to geoms.
> x=1:10;df=data.frame(x=x,y=x+1,z=x+2)
> ggplot(melt(df),
aes(x,value,color=variable,fill=variable))+
geom_bar(subset=.(variable=="y"),stat="identity")+
geom_line(subset=.(variable=="z"))

Resources