This code replicates the problem:
library(ggplot2)
set.seed(0)
df <- data.frame(ID = letters[1:10],
Var = rnorm(10),
"Some_very_long_label_names" = rnorm(10),
"Not_so_long" = rnorm(10),
"Short" = rnorm(10),
"Incredibly_long_label_name_why_oh_why" = rnorm(10),
"Etc" = rnorm(10))
melted_df <- reshape2::melt(df)
p1 <- ggplot(df, aes(ID, Var)) +
geom_bar(stat = "identity") +
theme(axis.title.x = element_blank())
p2 <- ggplot(melted_df, aes(ID, variable)) +
geom_tile(aes(fill = value)) +
guides(fill = FALSE)
cowplot::plot_grid(p1, p2, nrow = 2, align = "v", axis = "n")
If you run that code, it'll yield this plot:
The problem with this plot lies in the positioning of the y-axis title of the first plot. I thought perhaps setting axis = "n" would stop it from aligning to the axis from the second plot, but it didn't.
My desired output would be this plot, which has aligned the graphics but not the axis labels.
You can use the egg package instead
library(ggplot2)
p1 <- ggplot(df, aes(ID, Var)) +
geom_bar(stat = "identity") +
scale_x_discrete(expand = c(0, 0)) +
theme_bw() +
theme(axis.title.x = element_blank())
p2 <- ggplot(melted_df, aes(ID, variable)) +
geom_tile(aes(fill = value)) +
scale_x_discrete(expand = c(0, 0)) +
theme_bw() +
guides(fill = FALSE)
library(egg)
#> Loading required package: gridExtra
ggarrange(p1, p2, nrow = 2)
Created on 2018-09-21 by the reprex package (v0.2.1.9000)
Related
I need to add a legend to my combined ggplot but don't seem to succeed. The data is made up from three different values of which "targeted" and "non targeted" are in one plot and "response" in the other. I would like to add the legend at the bottom of the combined plot.
Thanks in advance
Output of my current code
A <- ggplot(placeholder) +
geom_line(aes(x=date, y= targeted), color='#0072b2', group= 1, size=1.25) +
geom_line(aes(x=date, y= non_targeted), color='#d55e00' , group= 1, size=1.25) +
theme(axis.text.x = element_text(angle = 90)) +
labs(y= "Y1", x = "Date") + theme_classic() +
theme(axis.text.x = element_text(angle = 90))
A
B <- ggplot(media_analysis) +
geom_line(aes(x=date, y= nuisance_reports), color='#f0e442', group= 1, size=1.25) +
theme(axis.text.x = element_text(angle = 90)) +
labs(y= "Y2", x = "Date") + theme_classic() +
theme(axis.text.x = element_text(angle = 90))
B
combined <- plot_grid(A, B,
labels = c("A", "B"),
ncol = 2, nrow = 1)
combined
Easiest is to use facets. This requires minor data wrangling (see comments).
suppressMessages(library(tidyverse))
set.seed(42)
foo <- cbind(data.frame(replicate(3, rnorm(30))), date = ISOdate(1,1,1:30))
# make a data frame which has all the values in one column,
# and all the dates in another
# there needs to be a facetting variable
foo %>%
pivot_longer(starts_with("X")) %>%
## combine X1 and X2 to one category
mutate(new_name = ifelse(grepl("X[1-2]", name), "A", "B")) %>%
## now facet by this new variable
ggplot() +
geom_line(aes(date, value, color = name)) +
facet_wrap(~new_name) +
## place at bottom
theme(legend.position = "bottom")
or combining the plots with patchwork
This will require same name and limits of the guides
library(patchwork)
p1 <-
foo %>%
pivot_longer(matches("X[1-2]")) %>%
ggplot() +
geom_line(aes(date, value, color = name)) +
## now define the same names for your color legend and get the same limits
scale_color_brewer("color", limits = paste0("X", 1:3))
p2 <- foo %>%
ggplot() +
geom_line(aes(date, X3, color = "X3")) +
scale_color_brewer("color", limits = paste0("X", 1:3))
p1 + p2 +
## combine the legends
plot_layout(guides = "collect") +
# add tags
plot_annotation(tag_levels = "A") &
## place at bottom
theme(legend.position = "bottom")
Created on 2022-06-29 by the reprex package (v2.0.1)
I am trying to add the labels A, B, and C to the top left hand corner of each of these graphs. I have tried cowplot::draw_plot_label(), but nothing seems to work. Can anyone help?
These A, B and C labels are not the main title of each plot.
# Packages
library(ggplot2)
library(gridExtra)
library(cowplot)
# 1st plot
p1 <- ggplot(data = new_data %>%
filter(Species =="Sharksucker_Remora")) +
scale_colour_manual(values=c(Sharksucker_Remora="black"), labels = c("Sharksucker Remora")) +
geom_line(mapping = aes(x = Date, y = Proportion, group = Species, colour = Species)) +
xlab("") +
ylab("Proportion") +
theme(legend.position="top") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) + labs(colour = ~italic(M.alfredi)~"Hitchhiker Species:") +
theme(legend.key=element_blank())
# 2nd plot
p2 <- ggplot(data = new_data %>%
filter(Species !="Sharksucker_Remora")) +
geom_line(mapping = aes(x = Date, y = Proportion, group = Species, colour = Species)) +
scale_colour_manual(values=c(Golden_Trevally="goldenrod2", Red_Snapper="firebrick2", Juvenile_Remora="darkolivegreen3"), labels = c("Juvenile Remora", "Golden Trevally", "Red Snapper")) +
xlab("") + ylab("Proportion") + labs(colour = "") + theme(legend.position="top") + theme(legend.key=element_blank()) +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1))
# 3rd plot
p3 <- ggplot(data = new_data_counts) +
geom_bar(mapping = aes(x = Date, y = Count), stat =
'identity') +
xlab("Date (2015-2019)") + ylab("Total"~italic
(M.alfredi)~"Sightings") +
draw_plot_label(label =c("C") + theme(axis.text.x =
element_text(angle = 90, vjust = 0.5, hjust = 1))
# The grid
grid.arrange(p1,p2,p3)
I suggest you use labs(..., tag = ...) and theme(plot.tag = element_text()).
The code show how you can format the main title (here centered with hjust = 0.5) and the tag inside the theme() function. See the reproducible example, below:
# Packages
library(ggplot2)
library(gridExtra)
# library(cowplot) # not necessary here
# Plots
p1 <- ggplot() +
labs(title = "plot 1", tag = "A") +
theme(plot.title = element_text(hjust = 0.5),
plot.tag = element_text())
p2 <- ggplot() +
labs(title = "plot 2", tag = "B") +
theme(plot.title = element_text(hjust = 0.5),
plot.tag = element_text())
grid.arrange(p1, p2)
If you want the tag (A, B, C) to be inside the plotting area, this post suggest to use plot.tag.position = c(x, y). See for example:
p3 <- ggplot() +
labs(title = "plot 3", tag = "C") +
theme(plot.title = element_text(hjust = 0.5),
plot.tag = element_text(),
plot.tag.position = c(0.1, 0.8))
p3
Have you tried the package egg?
https://cran.r-project.org/web/packages/egg/vignettes/Overview.html
library(tidyverse)
library(magrittr)
data <- list()
for(i in 1:6) data[[i]] <- rnorm(100,0,1)
data %<>% bind_cols() %>% setNames(paste0("var",1:6))
p1 <- ggplot(data,aes(x = var1, y = var2)) + geom_point()
p2 <- ggplot(data,aes(x = var3, y = var4)) + geom_point()
p3 <- ggplot(data,aes(x = var5, y = var6)) + geom_point()
egg::ggarrange(p1,p2,p3,ncol = 1,
labels = c("A","B","C"))
Another option is using the patchwork package with plot_annotation which has the tag_levels argument which gives the possibility to add tags like letters or numbers. First a reproducible example with letters:
library(patchwork)
library(ggplot2)
p1 <- ggplot(mtcars) +
geom_point(aes(hp, disp)) +
ggtitle('Plot 1')
p2 <- ggplot(mtcars) +
geom_boxplot(aes(gear, mpg, group = gear)) +
ggtitle('Plot 2')
p1 + p2 & plot_annotation(tag_levels = 'A')
Created on 2022-08-21 with reprex v2.0.2
Another option with numbers where you change the tag_levels to "1" like this:
p1 + p2 & plot_annotation(tag_levels = '1')
Created on 2022-08-21 with reprex v2.0.2
As you can see, the tags have letters or numbers. Check the links above for more information and options.
This question already has answers here:
How to make gap between x and y axis and protruded ticks in ggplot2
(4 answers)
Closed 2 years ago.
I am doing some plots for a project where they need to have a specific look. They will need to have some space between the axes lines and the plot panel.
library(ggplot2)
plot_data <- data.frame(X = 1:10, Y = 1:10)
ggplot() + geom_point(data = plot_data, aes(x = X, y = Y)) +
theme(axis.line = element_line(colour = "black", linetype = "solid"))
What I have
I want to add some distance between the X and Y axis of my plot, but without my axes lines also expanding, like they if I use the expand command.
plot_data <- data.frame(X = 1:10, Y = 1:10)
ggplot() + geom_point(data = plot_data, aes(x = X, y = Y)) +
theme(axis.line = element_line(colour = "black", linetype = "solid"))+
scale_x_continuous(name = "X", limits = c(1, 10), expand = c(0.1,0)) +
scale_y_continuous(name = "Y", limits = c(1, 10), expand = c(0.1,0))
What I can do
Is there a fast and reliable way to do this in R?
What i want
Thank you all in advance !
You could achieve this "capping" of the lines with the lemon package. You may use the following code to achieve this:
library(ggplot2)
library(lemon)
### your code
plot_data <- data.frame(X = 1:10, Y = 1:10)
p <- ggplot() + geom_point(data = plot_data, aes(x = X, y = Y)) +
theme(axis.line = element_line(colour = "black", linetype = "solid"))+
scale_x_continuous(name = "X", limits = c(1, 10), expand = c(0.1,0)) +
scale_y_continuous(name = "Y", limits = c(1, 10), expand = c(0.1,0))
### using the lemon package
p + coord_capped_cart(bottom='right', left='none', gap = 0.15)
### mimic the view of your plot
p2 <- p + coord_capped_cart(bottom='right', left='none', gap = 0.15)
p2 + theme(panel.background = element_rect(fill = "white"))
which yields the following picture:
An other option : Deleting the axis lines and making new ones with geom_segment.
plot_data <- data.frame(X = 1:10, Y = 1:10)
library(ggplot2)
ggplot() + geom_point(data = plot_data, aes(x = X, y = Y)) +
theme(axis.line = element_blank(),panel.background =element_blank())+
geom_segment(aes(x=0,y=1,xend=0,yend=10))+
geom_segment(aes(x=1,y=0,xend=10,yend=0))+
scale_x_discrete(limits=c(1,2,3,4,5, 8,10))+
scale_y_discrete(limits=c(1:10))
Using this SO solution I created a facet with two "empty" plots, with the aim of combining with another group of facet_wrap plots, as shown below. The purpose is to have two y-axis labels for different unit measurements. How can I make the grid layout look like the top image, which produces the arrangement I want, but not the axis labels? This was accomplished with plot_grid with individual plots. My current output does not scale correctly and overlaps the other plots, as seen in the second image, but provides the axis labels.
I have example data below, just copy and run the code to input it.
library(ggplot2)
library(grid)
library(cowplot)
clipboard <- readClipboard()
test.data <- read.table(file = "clipboard", sep = ",", header=TRUE)
test.data1 <- test.data[1:24, ]
test.data2 <- test.data[25:32, ]
testplot1 <- ggplot(test.data1, aes(Station, value)) +
geom_point() +
labs(x = "Stations", y = "Scale A") +
theme(legend.position = "none", legend.title = element_blank()) +
facet_wrap( ~ constituent, ncol = 3, scales = "free_y")
testplot2 <- ggplot(test.data2, aes(Station, value)) +
geom_point() +
labs(x = "Stations", y = "Scale B") +
theme(legend.position = "none", legend.title = element_blank(), axis.title.y = element_text(hjust = 0.2)) +
facet_wrap( ~ constituent, ncol = 1, scales = "free_y")
blankplots <- ggplotGrob(testplot2)
rm_grobs <- blankplots$layout$name %in% c("panel-1-1", "panel-2-1", "strip-t-1-1", "strip-t-1-2")
blankplots$grobs[rm_grobs] <- NULL
blankplots$layout <- blankplots$layout[!rm_grobs, ]
grid.newpage()
emptygrids <- grid.draw(blankplots)
plot_grid(emptygrids, MPLOOplot1)
Example date is below:
Station,constituent,value
A1,A,1
B1,A,1
A1,B,2
B1,B,2
A1,C,3
B1,C,3
A1,D,4
B1,D,4
A1,E,5
B1,E,5
A1,F,6
B1,F,6
A1,G,7
B1,G,7
A1,H,8
B1,H,8
A1,I,9
B1,I,9
A1,J,10
B1,J,10
A1,K,11
B1,K,11
A1,L,1.4
B1,L,1.4
A1,Blank1,NA
B1,Blank1,NA
A1,Blank2,NA
B1,Blank2,NA
A1,XX,0.52
B1,XX,0.52
A1,YY,0.355
B1,YY,0.355
I'm not sure I understand exactly what you're trying to do, so let me know if this is what you had in mind. I wasn't sure what you wanted colour to be mapped to, so I just used constituent for this example.
library(gridExtra)
library(ggplot2)
library(dplyr)
library(cowplot)
theme_set(theme_classic())
testplot1 <- ggplot(test.data1, aes(Station, value, colour=constituent)) +
geom_point() +
labs(x = "Stations", y = "Scale A") +
theme(legend.title = element_blank()) +
facet_wrap( ~ constituent, ncol = 3, scales = "free_y") +
guides(colour=guide_legend(ncol=2))
testplot2 <- ggplot(test.data2 %>% filter(!grepl("Blank", constituent)),
aes(Station, value, colour=constituent)) +
geom_point() +
labs(x = "Stations", y = "Scale B") +
theme(legend.title = element_blank(),
axis.title.y = element_text(hjust = 0.2)) +
facet_wrap( ~ constituent, ncol = 1, scales = "free_y")
leg1 = get_legend(testplot1)
leg2 = get_legend(testplot2)
testplot1 = testplot1 + guides(colour=FALSE)
testplot2 = testplot2 + guides(colour=FALSE)
Now we lay out the plots and legends with grid.arrange. This requires some manual tweaking of the heights and widths.
grid.arrange(
arrangeGrob(
arrangeGrob(nullGrob(), leg2, leg1, nullGrob(), ncol=4, widths=c(1,4,4,1)),
testplot2, ncol=1, heights=c(4.2,5)
),
testplot1, ncol=2, widths=c(1.1,3))
This question already has answers here:
Left align two graph edges (ggplot)
(9 answers)
Closed 9 years ago.
I am a newbie using ggplot2 and I'm trying to plot a scatter plot above a heatmap. Both plots have the same discrete x-axis.
This is the code I'm trying:
library(ggplot2)
library(grid)
library(reshape2)
#data for the scatterplot
df = data.frame(id1 = letters[1:10], C = abs(rnorm(10)))
#scatter plot
p1 <- ggplot(df, aes(x= id1, y = C)) +
geom_point(pch = 19) + theme_bw() +
scale_x_discrete(expand = c(0, 0), breaks = letters[1:10]) +
theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank())
#data for the heatmap
X = data.frame(matrix(rnorm(100), nrow = 10))
names(X) = month.name[1:10]
X = melt(cbind(id1 = letters[1:10], X))
#heatmap
p2 <- ggplot(X,
aes(x = id1, y = variable, fill = value))
p2 <- p2 + geom_tile()
p2 <- p2 + scale_fill_gradientn(colours = c("blue", "white" , "red"))
p2 <- p2 + theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank())
p2 <- p2 + scale_x_discrete(expand = c(0, 0), breaks = letters[1:10])
p2 <- p2 + scale_y_discrete(expand = c(0, 0))
layt <- grid.layout(nrow=2,ncol=1,heights=c(2/8,6/8),default.units=c('null','null'))
vplayout <- function(x,y) {viewport(layout.pos.row = x, layout.pos.col = y)}
grid.newpage()
pushViewport(viewport(layout=layt))
print(p1,vp=vplayout(1,1))
print(p2,vp = vplayout(2,1))
The problem is that the axis are not situated one above the other.
https://mail.google.com/mail/u/0/?ui=2&ik=81975edabc&view=att&th=13ece12a06a3cea2&attid=0.1&disp=emb&realattid=ii_13ece128398baede&zw&atsh=1
Is there any solution? It is possible to reshape the data and make something like facets?
Another option:
grid.draw(gtable:::rbind.gtable(ggplotGrob(p1),
ggplotGrob(p2), size='last'))
(ideally one would want size=max, but it has a bug preventing it to work).
There are a couple of tricks here. The first is that the tick marks get treated differently, even though you have the same discrete axis. When you do expand = c(0,0), on the scatterplot the tick is now aligned with the y axis, while on the heatmap it is in the centre of the category. My method of getting around that is to manually assign the expand value for the scatterplot so that there is a gap of of 1/2 a categorical value. Because there are 10 categorical values, in this case it is 0.05 ((1/10)/2). The points will now align with the centre of each category.
The other side of the problem is because the y labels are different sizes they throw out the rest of the alignment. The solution comes from this question, using ggplot_gtable and grid.arrange from the gridExtra package.
library(gridExtra)
#data for the scatterplot
df = data.frame(id1 = letters[1:10], C = abs(rnorm(10)))
#scatter plot
p1 <- ggplot(df, aes(x= id1, y = C)) +
geom_point(pch = 19) + theme_bw() +
# Change the expand values
scale_x_discrete(expand = c(0.05, 0.05), breaks = letters[1:10]) +
#scale_y_discrete(breaks = NULL) +
theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank())
p1
#data for the heatmap
X = data.frame(matrix(rnorm(100), nrow = 10))
names(X) = month.name[1:10]
X = melt(cbind(id1 = letters[1:10], X))
#heatmap
p2 <- ggplot(X,
aes(x = id1, y = variable, fill = value))
p2 <- p2 + geom_tile()
p2 <- p2 + scale_fill_gradientn(colours = c("blue", "white" , "red"))
p2 <- p2 + theme(legend.position = "none") + theme(axis.title.y = element_blank()) + theme(axis.title.x = element_blank())
p2 <- p2 + scale_x_discrete(expand = c(0, 0), breaks = letters[1:10])
p2 <- p2 + scale_y_discrete(expand = c(0, 0))
#Here's the gtable magic
gp1<- ggplot_gtable(ggplot_build(p1))
gp2<- ggplot_gtable(ggplot_build(p2))
#This identifies the maximum width
maxWidth = unit.pmax(gp1$widths[2:3], gp2$widths[2:3])
#Set each to the maximum width
gp1$widths[2:3] <- maxWidth
gp2$widths[2:3] <- maxWidth
#Put them together
grid.arrange(gp1, gp2)
EDIT - See #baptiste's answer for a more elegant method of alignment of the y axis