I'm trying to inset a plot using ggplot2 and annotation_custom (the plot is actually a map that I'm using to replace the legend). However, I'm also using facet_wrap to generate multiple panels, but when used with annotation_custom, this reproduces the plot in each facet. Is there an easy way to insert the plot only once, preferably outside the plotting area?
Here is a brief example:
#Generate fake data
set.seed(9)
df=data.frame(x=rnorm(100),y=rnorm(100),facets=rep(letters[1:2]),
colors=rep(c("red","blue"),each=50))
#Create base plot
p=ggplot(df,aes(x,y,col=colors))+geom_point()+facet_wrap(~facets)
#Create plot to replace legend
legend.plot=ggplotGrob(
ggplot(data=data.frame(colors=c("red","blue"),x=c(1,1),y=c(1,2)),
aes(x,y,shape=colors,col=colors))+geom_point(size=16)+
theme(legend.position="none") )
#Insert plot using annotation_custom
p+annotation_custom(legend.plot)+theme(legend.position="none")
#this puts plot on each facet!
This produces the following plot:
When I would like something more along the lines of:
Any help is appreciated. Thanks!
In the help of annotation_custom() it is said that annotations "are the same in every panel", so it is expected result to have your legend.plot in each facet (panel).
One solution is to add theme(legend.position="none") to your base plot and then use grid.arrange() (library gridExtra) to plot both plots.
library(gridExtra)
p=ggplot(df,aes(x,y,col=colors))+geom_point()+facet_wrap(~facets)+
theme(legend.position="none")
grid.arrange(p,legend.plot,ncol=2,widths=c(3/4,1/4))
Related
I try to plot a graph in R using the ggplot2 package. Let's assume I have the following data:
df1<-data.frame(xpos=c(1,2,3,4),ypos=c(0.222,0.222,0.303,0.285))
Now, I want to plot a simple line graph:
ggplot(data=df1, aes(x=xpos, y=ypos)) +
geom_line()+
geom_point()
Now, when I adjust the y-axis:
+scale_y_continuous("Y rates upd", breaks=seq(0,1,0.2),limits=c(0,1))
The lines get "broken"
That's dependent upon your graphics device that plots are sent to from R. See the same plot below when I instead export it to PDF.
I have a common legend for two ggplot2 graphs which are aligned with grid.arrange() (see code below). However, the legend does not adjust according to graph size, when I export graphs as one pdf.
For a comparison, here is the output of the individual plot:
And after using grid.arrange with the following code:
pdf("Fig1.pdf", onefile=TRUE, paper="a4",width=3.22, height=5)
grid.arrange(Fig1A,Fig1B)
dev.off()
I get this:
The commands for the legend of plot A are:
gglpot2
+theme(legend.key.size=unit(0.5,'lines'))
+theme(legend.key.height=unit(0.25,"cm"))
+theme(legend.key.height=unit(1,"line"))
+theme(legend.text=element_text(size=10))
+theme(legend.position=c(0.85,0.8))
+theme(legend.direction = "vertical")
+guides(fill=guide_legend(title=NULL))
The commands for the legend of plot B are:
+theme(legend.position="")
I tried to solve the issue, according to:
Keep or set the ratio between text labels and size of plot in grid.arrange
which didn’t help, as it is quite similar but not exactly my problem.
https://github.com/baptiste/gridextra/wiki/arranging-ggplot
Here I followed the suggestion:
draw your plots
plot1 <- ggplot(...) # this specifies your first plot
plot2 <- ggplot(...) # this specifies your second plot
plot3 <- ggplot(...) # this specifies your third plot
merge all three plots within one grid (and visualize this)
grid.arrange(plot1, plot2, plot3, nrow=3) #arranges plots within grid
save
g <- arrangeGrob(plot1, plot2, plot3, nrow=3) #generates g
ggsave(file="whatever.pdf", g) #saves g
but I ended up with the same result and worse, as I didn’t have the margins I’d like to have.
https://www.r-bloggers.com/15-questions-all-r-users-have-about-plots/
Printing multiple ggplots into a single pdf, multiple plots per page
didn’t help either, as my problem is not placing the plots on one page, but the ratio of legend size to plot.
Does anyone have a solution?
in the meanwhile I found someone outside this community who was able to help me. The solution is quite simple:
Change the code to
theme(legend.key.size=unit(0.5,'lines'),
legend.key.height=unit(0.32,"cm"),
legend.text=element_text(size=10),
legend.position=c(0.85,0.8),
legend.direction = "vertical")
so basically I removed
theme(legend.key.height=unit(1,"line"))
and
guides(fill=guide_legend(title=NULL))
changed
theme(legend.key.height=unit(0.25,"cm"))
to
theme(legend.key.height=unit(0.32,"cm"))
and that did the job.
I hope this may be usueful for someone else, facing a similar problem.
Best regards!
I am trying to do multipanel plots one panel being a heatmap using layout to place plots. I've been drawing heatmaps with pheatmap which provides a very convenient color scheme among other things.
The code for pheatmap is available here.
When I try using pheatmap in this way it always plots on a new page. I imagine this is because of its use of the grid package? Is there a way I can do this with pheatmap?
Example code to produce a heatmap next to a barplot but which doesn't since the heatmap gets plotted on a new page below:
xlay=layout( matrix(c(2,2,1),nrow=1) )
layout.show(xlay)
barplot(rnorm(8),horiz=T)
pheatmap(matrix(rnorm(80),nrow=8))
Make your bar plot in ggplot
bar <- ggplot()
Assign both the barplots and heatmap to a variable
heat <- pheatmap(matrix(rnorm(80),nrow=8))
then use gridExtra package to make panel plot the heatmap is saved as an object and you can plot it again by assessing the 4th item in the object
grid.arrange(bar, heat[[4]], nrow = 1)
I've been learning ggplot2, and hope to use it for all my R graphing. However, I've yet to find a way to make a contour plot that looks analogous to a conventional contour plot, like what can be obtained using lattice:filled.contour(). For example:
#define data
x<-seq(1,11,1)
y<-seq(1,11,1)
xyz.func<-function(x,y) {-10.4+6.53*x+6.53*y-0.167*x^2-0.167*y^2+0.0500*x*y}
#contour plot using lattice graphics and R Color Brewer
library(lattice) #for filled.contour()
library(RColorBrewer) #for brewer.pal()
z.lattice<-outer(x,y,xyz.func)
filled.contour(x,y,z.lattice,nlevels=6,col=brewer.pal(6,"YlOrRd"))
This gives me a nice contour plot.
Now, let's try the same thing in ggplot2. The best I can come up with, based on everything I've read (particularly Drawing labels on flat section of contour lines in ggplot2) is:
#contour plot using ggplot2
library(ggplot2)
library(reshape2) #for melt()
z.molten<-melt(z.lattice)
names(z.molten) <- c("x", "y", "z")
v<-ggplot(z.molten, aes(x,y,z=z))+
geom_tile(aes(fill=z))+
stat_contour(bins=6,aes(x,y,z=z), color="black", size=0.6)+
scale_fill_gradientn(colours=brewer.pal(6,"YlOrRd"))
v
This graph has the same basic idea as filled.contour(), but the colored tiles don't conform to the contours very well.
I haven't been successful with changing the sizes of the tiles, either.
Any suggestions on how to make ggplot2's output closer to filled.contour()'s output?
The essence of your question, it seems, is how to produce a contour plot in ggplot with discrete filled contours, rather than continuous contours as you would get using the conventional geom_tile(...) approach. Here is one way.
x<-seq(1,11,.03) # note finer grid
y<-seq(1,11,.03)
xyz.func<-function(x,y) {-10.4+6.53*x+6.53*y-0.167*x^2-0.167*y^2+0.0500*x*y}
gg <- expand.grid(x=x,y=y)
gg$z <- with(gg,xyz.func(x,y)) # need long format for ggplot
library(ggplot2)
library(RColorBrewer) #for brewer.pal()
brks <- cut(gg$z,breaks=seq(0,100,len=6))
brks <- gsub(","," - ",brks,fixed=TRUE)
gg$brks <- gsub("\\(|\\]","",brks) # reformat guide labels
ggplot(gg,aes(x,y)) +
geom_tile(aes(fill=brks))+
scale_fill_manual("Z",values=brewer.pal(6,"YlOrRd"))+
scale_x_continuous(expand=c(0,0))+
scale_y_continuous(expand=c(0,0))+
coord_fixed()
The use of, e.g., scale_x_continuos(...) is just to get rid of the extra space ggplot puts around the axis limits; fine for most things but distracting in contour plots. The use of coord_fixed(...) is just to set the aspect ratio to 1:1. These are optional.
I am trying to create a heatmap combined with a barplot, such that at the end of every row is a bar with length relevant to that row. The idea is to combine something like the following two into one:
library(gplots)
data(mtcars)
x <- as.matrix(mtcars[,2:11])
hm<-heatmap(x)
barplot(mtcars[hm$rowInd,"mpg"],horiz=T,names.arg=row.names(mtcars)[hm$rowInd],las=2,cex.names=0.7,col="purple",2)
My question is how to combine the two while making the rows and bars align?
Thanks.
You can't combine the plots because (as per the documentation) heatmap() uses layout and draws the image in the lower right corner of a 2x2 layout. Consequentially, it can not be used in a multi column/row layout, i.e., when par(mfrow = *) or (mfcol = *) has been called.
Your best best would be to use ggplot2 and gridExtra to combine the graphs. For this both the heatmap and bar plot need to be created using ggplot.
You can find a heatmap on ggplot2 tutorial here.
Once you have your two plots combine them using the following commands:
#Create the plots
g1 <- heatmap
g2 <- barplot
#Arrange them in a grid
gg1 <- ggplot_gtable(ggplot_build(g1))
gg2 <- ggplot_gtable(ggplot_build(g2))
grid.arrange(gg1, gg2, ncol=2)