I have two ggplots that I can created like this:
df1 = data.frame(x=1:10, y1=11:20, y2=21:30)
gg1 = ggplot(df1) + geom_point(aes(x=x, y=y1))
gg2 = ggplot(df1) + geom_point(aes(x=x, y=y2))
grid.arrange(gg1, gg2, top=textGrob("Here should be some space above",
gp=gpar(fontsize=18,
fontfamily="Times New Roman")))
Now the output looks like this:
One does not see it here as it is white on white, but I would like to create more space in the output-image above the title. And I'm not really sure on how to do it. Here is described on how to add space between the single plots Margins between plots in grid.arrange , but I did not manage to just add space above the header.
Making use of arrangeGrob you could add some margin on top of your header via a zeroGrob like so:
library(ggplot2)
library(gridExtra)
library(grid)
df1 = data.frame(x=1:10, y1=11:20, y2=21:30)
gg1 = ggplot(df1) + geom_point(aes(x=x, y=y1))
gg2 = ggplot(df1) + geom_point(aes(x=x, y=y2))
title <- textGrob("Here should be some space above",
gp=gpar(fontsize=18, fontfamily="Times New Roman"))
# Add a zeroGrob of height 2cm on top of the title
title <- arrangeGrob(zeroGrob(), title,
widths = unit(1, 'npc'),
heights = unit(c(2, 1), c('cm', 'npc')),
as.table = FALSE)
grid.arrange(gg1, gg2, top = title)
Can you live with another package?
library(patchwork)
plot_spacer()/ (gg1 + ggtitle("there is now space above")) / gg2 + plot_layout(heights = c(.5,1,1))
Or set the title margin in the first plot
gg1 = ggplot(df1) + geom_point(aes(x=x, y=y1)) +
ggtitle("there is now space above") +
theme(plot.title = element_text(margin = margin(t = 1, unit = "in")))
gg1 / gg2
Related
I have 16 plots that I want to arrange together for illustration purposes. Below I show one graph as an example.
The code for creating each plot is next:
P1<- ggplot(Fish_acc_C.D.Mean_bottom_invierno_P16, aes(C.D.Mean_bottom,meanAcc)) +
geom_point(aes(C.D.Mean_bottom,meanAcc, color = C.I.Mean_bottom),show.legend = FALSE) +
scale_colour_gradientn(colours=c("green","black")) +
theme_bw() +
geom_smooth(aes(linetype = "Activity"),fill = "lightblue",color="red", alpha = 0.99) +
ggtitle("Activity ~ Curr Direct Mean bottom WINTER (Hourly data)") +
theme(plot.title = element_text(size=10,hjust = 0.5)) +
geom_smooth(aes(C.D.Mean_bottom, C.I.Mean_bottom * max(range(Fish_acc_C.D.Mean_bottom_invierno_P16$C.I.Mean_bottom)), linetype = "C.I.M.B"), se=FALSE, colour = "blue",show.legend = FALSE) +
scale_y_continuous(sec.axis = sec_axis(trans = ~ . /max(range(Fish_acc_C.D.Mean_bottom_invierno_P16$C.I.Mean_bottom)), name = "C.I.Mean bottom")) +
scale_linetype_manual(values = c(1,1),guide = guide_legend(override.aes = list(colour = c("red", "blue")))) +
coord_cartesian(ylim = c(0, 1.25)) +
theme(legend.justification = c(1,1),
legend.position = c(1,1))
My problem is that when I use grid.arrange() to group them all together, the legends of each plot increase their size with regard to their size in the individual ones. Here an example:
Here I show the code for creating the grid_arrange:
grid.arrange(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16,ncol=4)
Does anyone know how to reduce the size of the legends in the grid_arranged graph in order to see the lines? I thought that maybe I could place the legends in the upper-middle position of the graph, delete the word "linetype" from the legend and display the linetypes in one line (side by side instead of up and down). However I don't know how to do it.
Does anyone have any recommendation?
You can look at the ggarrange function from the ggpubr package.
It allows you to group your plots as you need and have a common legend for all of them, for which you can specify the position.
e.g.
library(ggpubr)
ggarrange(g1, g2, ncol = 2, common.legend = T, legend = 'bottom')
# or
ggarrange(plotlist = my_list, ncol = 2, common.legend = T, legend = 'bottom')
#Dekike then you can extract the legend and put the legend on top/bottom of the main plot.
Here are my psude code
library(ggplot2)
library(cowplot)
P1 <- ggplot() + ... + guides(lineType=guide_legend(ncol=2))
legend_extracted <- get_legend(P1)
P1 <- P1 + theme(legend.position="none")
P2 <- ggplot() + ... + theme(legend.position="none")
...
P16 <- ggplot() + ... + theme(legend.position="none")
main_plot <- grid.arrange(P1,P2,P3,P4,P5,P6,P7,P8,P9,P10,P11,P12,P13,P14,P15,P16,ncol=4)
main_plot_wLegend <- grid.arrange(legend_extracted, main_plot, ncol=1, nrow=2)
Please try and feedback on this!
I want to align Plots with titles with grid.arrange so that the y-Axis of the two plots matches. If one of the plots has a Title that contains a character with a decender (g,j,y,...) and the other doesn't the plots are misaligned.
Is there an option to fix the size of the element e.g. in element_text in the theme to line heights including decenders?
An alternative would be to modify the grid-grobs directly with ggplotGrob but this seems overly complicated.
require(ggplot2)
require(gridExtra)
test <- data.frame(x=1:3, y=1:3)
plot1 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
ggtitle("asdf")
plot2 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
ggtitle("asdfg")
grid.arrange(plot1, plot1, nrow=1)
grid.arrange(plot1, plot2, nrow=1)
Notice the slight difference in the alignment of the top border of the plotting area in the second plot. In the first one both are aligned perfectly.
This hack solves the Problem, but I think it only works for one line titles.
Set the lineheight to 0 and add an empty line to every title:
require(ggplot2)
require(gridExtra)
test <- data.frame(x=1:3, y=1:3)
plot1 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
theme(
plot.title = element_text(lineheight = 0),
) +
ggtitle("asdf\n")
plot2 <- ggplot(test, aes(x=x, y=y)) +
geom_point() +
theme(
plot.title = element_text(lineheight = 0)
) +
ggtitle("asdfg\n")
grid.arrange(plot1, plot1, nrow=1)
grid.arrange(plot1, plot2, nrow=1)
There might be a simple way to do this, but I am not sure what it is. I am trying to make it so that the text in the legend matches up with the color box next to it. I have been trying to do this for a while and have not found a way to use the element_text function to add multiple colors to the legend. I've had no problem making every label the same color, but is there a way to make each legend label a different color?
data<-data.frame(count=c(39,36,19,6), category=c("a","b","c","d"))
data$fraction = data$count / sum(data$count)
data = data[order(data$fraction), ]
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#Create Plot
fill <- c("blue3","cyan3","darkgrey","forestgreen")
library(ggplot2)
p1 = ggplot(data, aes(fill=category, ymax=ymax, ymin=ymin, xmax=4, xmin=3.5)) +
geom_rect(colour="White") +
coord_polar(theta="y") +
scale_fill_manual(values=fill)+
theme_bw()+
geom_label(aes(label=paste(data$fraction*100,"%"),x=4,y=
(ymin+ymax)/2),inherit.aes = F)+
theme(panel.grid=element_blank())+
theme(axis.ticks=element_blank()) +
xlim(c(0, 4)) +
theme(axis.text=element_blank()) +
theme(legend.text=element_text(color=fill,size=12))+
theme(legend.key.size=unit(2,'lines'))+
theme(legend.key=element_rect(size=5))+
labs(title="donut plot")
print(p1)
With a couple of modifications to this answer, match-legend-text-color-in-geom-text-to-symbol, you get what you want. But note, the answer uses grid's editing functions.
# Your data and plot
data<-data.frame(count=c(39,36,19,6), category=c("a","b","c","d"))
data$fraction = data$count / sum(data$count)
data = data[order(data$fraction), ]
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
fill <- c("blue3","cyan3","darkgrey","forestgreen")
library(ggplot2)
p1 = ggplot(data, aes(fill=category, ymax=ymax, ymin=ymin, xmax=4, xmin=3.5)) +
geom_rect(colour="White") +
coord_polar(theta="y") +
scale_fill_manual(values=fill)+
theme_bw()+
geom_label(aes(label=paste(data$fraction*100,"%"),x=4,y=
(ymin+ymax)/2),inherit.aes = F)+
theme(panel.grid=element_blank())+
theme(axis.ticks=element_blank()) +
xlim(c(0, 4)) +
theme(axis.text=element_blank()) +
theme(legend.text=element_text(color=fill,size=12))+
theme(legend.key.size=unit(2,'lines'))+
theme(legend.key=element_rect(size=5))+
labs(title="donut plot")
# Get the ggplot grob
g <- ggplotGrob(p1)
# Check out the grobs
library(grid)
grid.ls(grid.force(g))
Look through the list of grobs. The grobs you want to edit are towards the bottom of the list, in the 'guide-box' set of grobs - with names that begin with "label". There are four grobs:
label-3-3.4-4-4-4
label-4-3.5-4-5-4
label-5-3.6-4-6-4
label-6-3.7-4-7-4
# Get names of 'label' grobs.
names.grobs <- grid.ls(grid.force(g))$name
labels <- names.grobs[which(grepl("^label", names.grobs))]
# Edit the 'label' grobs - change their colours
# Use the `editGrob` function
for(i in seq_along(labels)) {
g <- editGrob(grid.force(g), gPath(labels[i]), grep = TRUE,
gp = gpar(col = fill[i]))
}
# Draw it
grid.newpage()
grid.draw(g)
It's possible to achieve this without editing grobs, by using the ggtext package. Specify the legend text labels as element_markdown and wrap them in <span> tags that use the colors you want.
data<-data.frame(count=c(39,36,19,6), category=c("a","b","c","d"))
data$fraction = data$count / sum(data$count)
data = data[order(data$fraction), ]
data$ymax = cumsum(data$fraction)
data$ymin = c(0, head(data$ymax, n=-1))
fill <- c("blue3","cyan3","darkgrey","forestgreen")
library(ggplot2)
library(ggtext)
ggplot(data, aes(fill=category, ymax=ymax, ymin=ymin, xmax=4, xmin=3.5)) +
geom_rect(colour="White") +
coord_polar(theta="y") +
scale_fill_manual(labels = paste("<span style='color:",
fill,
"'>",
unique(data$category),
"</span>"),
values = fill)+
theme_bw()+
geom_label(aes(label=paste(data$fraction*100,"%"),x=4,y=
(ymin+ymax)/2),inherit.aes = F)+
theme(panel.grid=element_blank())+
theme(axis.ticks=element_blank()) +
xlim(c(0, 4)) +
theme(axis.text=element_blank()) +
theme(legend.text=element_markdown(size=12))+
theme(legend.key.size=unit(2,'lines'))+
theme(legend.key=element_rect(size=5))+
labs(title="donut plot")
I've plotted a heat-map like this:
ggplot(test, aes(start1, start2)) +
geom_tile(aes(fill = logFC), colour = "gray", size=0.05) +
scale_fill_gradientn(colours=c("#0000FF","white","#FF0000"), na.value="#DAD7D3")
This plots the upper triangle of a heatmap. What i'd like to plot is the very same triangle, but having the hypotenuse as the x-axis.
How would I do that?
Edit: Added reproducible example
library(ggplot2)
# dummy data
df1 <- mtcars[, c("gear","carb", "mpg")]
# normal tile plot
gg1 <- ggplot(df1, aes(gear, carb, fill = mpg)) +
geom_tile() +
xlim(c(1, 10)) +
ylim(c(1, 10)) +
theme_void() +
theme(legend.position = "none")
Expected output (rotated manually):
Related post using base plot image():
Visualising and rotating a matrix
Possible solution example code is in LDheatmap package using grid.
Using this solution gets the output clipped at the bottom, so workaround would be to add extra plot margins then use grid::viewport() to rotate:
library(ggplot2) #ggplot2_2.2.1
library(grid)
gg1 <- ggplot(df1, aes(gear, carb, fill = mpg)) +
geom_tile() +
xlim(c(1, 10)) +
ylim(c(1, 10)) +
theme_void() +
# add extra margins
theme(legend.position = "none",
plot.margin = unit(c(1, 1, 1, 1), "cm"))
# then rotate
print(gg1, vp = viewport(angle = 45))
I have been using the plot_grid command from cowplot to arrange my plots. I use the labeling feature, and my plots all look the same in that regard. However, when I 'hv' align some plots that have very different y-axis limits, such as the one below, it appears the height of the plot with shortest range of y is used.
If I just 'v' align the plot it looks better in some respects, but it is hard to resize the plot and have the labels looking good. I'd prefer the plot height not consider the x-axis labels, etc, like above.
Using gtables, I can get the desired width/height (below), but these leaves me without the consistent labels across all the figures in a document. Can I use the 'hv' alignment with cowplot and specify which plot height to use?
library(ggplot2)
library(dplyr)
library(scales)
library(grid)
library(cowplot)
data(iris)
iris <- iris %>% mutate(Petal.Width2 = ifelse(Species == "setosa", Petal.Width * 75, Petal.Width))
p1 <- ggplot(data=iris, aes(x = factor(Species), y=Sepal.Width)) +
geom_bar(stat="identity") +
labs(x = NULL, y = "Plot One") +
scale_y_continuous(labels = percent) +
theme(axis.text.x = element_blank(),
axis.title.y = element_text(vjust=1), plot.margin=unit(c(2,2,0,2),"mm"))
p2 <- ggplot(data=iris, aes(x = factor(Species), y=Petal.Width2)) + geom_bar(stat="identity") +
labs(x = NULL, y = "Plot Two") +
scale_y_continuous(labels = percent) +
theme(axis.text.x = element_blank(),
axis.title.y = element_text(vjust=1), plot.margin=unit(c(0,2,0,2),"mm"))
p3 <- ggplot(data=iris, aes(x = factor(Species), y=Petal.Length*0+.01)) + geom_bar(stat="identity") +
labs(x = "SPECIES", y = "The Third plot") +
scale_y_continuous(labels = percent) +
theme( axis.title.y = element_text(vjust=1, color="blue"), plot.margin=unit(c(0,2,0,2),"mm"),
axis.text.x = element_text(angle = 90, hjust=1, vjust=1,face ="italic", size=10))
plot_grid(p1,p2,p3,ncol=1, align="v", labels=c("A", "B", "C"))
# https://stackoverflow.com/a/27408589/1670053
plots <- list(p1, p2, p3)
grobs = lapply(plots, ggplotGrob)
g = do.call(rbind, c(grobs, size="first"))
g$widths = do.call(unit.pmax, lapply(grobs, "[[", "widths"))
grid.newpage()
grid.draw(g)
it's easy as to add labels,
plots <- list(p1, p2, p3)
grobs = lapply(plots, ggplotGrob)
library(gridExtra)
g = do.call(rbind, grobs) # uses gridExtra::rbind.gtable
panels <- g$layout[g$layout$name=="panel",]
g <- gtable::gtable_add_grob(g, lapply(LETTERS[1:nrow(panels)],
textGrob, vjust=1, y=1,
gp=gpar(fontface=2)),
t=panels$t, l=2)
grid.newpage()
grid.draw(g)