Let's consider very simple plot and try to name it
library(ggplot2)
plot_1 <- ggplot() + aes(x = 1:10, y = 1:10) + geom_line()
patchwork::wrap_plots(plot_1, plot_1, plot_1, ncol = 1, nrow = 3) + ggtitle("a")
However, this code will only name the very last plot:
Is there any possibility that I can have a name for whole plot and not for only the last one ? i.e. to have a name in the place of black rectangle
you want plot_annotation
library(ggplot2)
library(patchwork)
plot_1 <- ggplot() + aes(x = 1:10, y = 1:10) + geom_line()
wrap_plots(rep(list(plot_1), 4), ncol = 2, nrow = 2) +
plot_annotation(title = "a")&
theme(plot.title = element_text(hjust = .5))
Created on 2021-03-03 by the reprex package (v1.0.0)
Related
I have a code to plot histogram in R that works fine:
fun_hist <- function(c, E, HS, log_EC_50) {
df <- data.frame(log_c = c, response = V({{c}}, {{E}}, {{HS}}, {{log_EC50}}))
ggplot2::ggplot(df, aes( response)) + geom_histogram(binwidth=0.03)
}
I want to correct my histogram so that its bars have a graphic design as in the attached photo.
This looks pretty similar to my eye:
library(ggplot2)
set.seed(1)
df <- data.frame(response = rnorm(25000, 15, 2))
ggplot(df, aes(response)) +
geom_histogram(binwidth = 0.5, color = 'black', fill = "#547fbf") +
xlim(c(0, 24)) +
labs(x = NULL, y = NULL) +
theme_bw(base_size = 16)
Created on 2022-11-03 with reprex v2.0.2
A similar question was asked here, however I cant adapt the answer to my issue.
I am trying to correctly align two legends when using cowplot. For example, if I create some data and a cowplot with two legends like so:
library(cowplot)
library(ggplot2)
# create some data
dat <- NULL
for(i in 1:20){
x <- LETTERS[1:5]
y <- paste0("var", seq(1,5))
dat[[i]] <- expand.grid(X=x, Y=y)
dat[[i]]$Z <- runif(25, 0, 1)
}
# plotting function
plotFun <- function(data){
ggplot(data, aes(X, Y, fill= Z)) +
geom_tile() +
theme(aspect.ratio = 1,
legend.justification = c(0,1),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank()) +
xlab("") + ylab("")
}
# set up to plot on a grid
allPlots <- lapply(dat, plotFun)
allPlotsAlter <- lapply(allPlots, function(x) x + theme(legend.position = "none"))
n <- length(allPlotsAlter)
nRow <- floor(sqrt(n))
plotGrid <- gridExtra::arrangeGrob(grobs=allPlotsAlter, nrow=nRow)
# create a different type of legend
newPlot <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, fill = Species)) +
geom_bar(stat = 'identity') + theme(legend.justification = c(0,1))
# get both legends and combine
legend <- cowplot::get_legend(allPlots[[1]])
legend1 <- cowplot::get_legend(newPlot)
combineLegend <- cowplot::plot_grid(
legend,
legend1,
nrow = 2)
# now make plot
cowplot::plot_grid(plotGrid,
combineLegend,
rel_widths = c(0.9, 0.11),
ncol = 2)
That creates this type of plot:
As you can see, the two legends have quite a bit of vertical space between them and they are not centred with the plot.
Is there a way to align the two legends so they look something like this:
I'm not sure if it is possible using cowplot... or is there a way to maybe use ggplot's annotate to place the legends?
I would probably go for patchwork, as Stefan suggests, but within cowplot you probably need to adjust the legend margins:
theme_margin <- theme(legend.box.margin = margin(100, 10, 100, 10))
legend <- cowplot::get_legend(allPlots[[1]] + theme_margin)
legend1 <- cowplot::get_legend(newPlot + theme_margin)
combineLegend <- cowplot::plot_grid(
legend,
legend1,
nrow = 2)
# now make plot
cowplot::plot_grid(plotGrid,
combineLegend,
rel_widths = c(0.9, 0.11),
ncol = 2)
If switching to another package is an option for you I would suggest to use patchwork to glue your plots together. One feature offered by patchwork is that using plot_spacer you could easily add some empty panels above and below your legends to "move" them to the center and thereby getting rid of the empty space. Depending on your final result or the height of your final plot you probably have to play a bit around with the heights and/or widths arguments:
library(cowplot)
library(ggplot2)
library(patchwork)
set.seed(123)
# create some data
dat <- NULL
for (i in 1:20) {
x <- LETTERS[1:5]
y <- paste0("var", seq(1, 5))
dat[[i]] <- expand.grid(X = x, Y = y)
dat[[i]]$Z <- runif(25, 0, 1)
}
# plotting function
plotFun <- function(data) {
ggplot(data, aes(X, Y, fill = Z)) +
geom_tile() +
theme(
aspect.ratio = 1,
legend.justification = c(0, 1),
axis.text.x = element_blank(),
axis.ticks.x = element_blank(),
axis.text.y = element_blank(),
axis.ticks.y = element_blank()
) +
labs(x = NULL, y = NULL)
}
# set up to plot on a grid
allPlots <- lapply(dat, plotFun)
allPlotsAlter <- lapply(allPlots, function(x) x + theme(legend.position = "none"))
n <- length(allPlotsAlter)
nRow <- floor(sqrt(n))
plotGrid <- wrap_plots(grobs = allPlotsAlter, nrow = nRow)
# create a different type of legend
newPlot <- ggplot(iris, aes(x = Sepal.Length, y = Petal.Length, fill = Species)) +
geom_bar(stat = "identity") +
theme(legend.justification = c(0, 1))
# get both legends and combine
legend <- cowplot::get_legend(allPlots[[1]])
legend1 <- cowplot::get_legend(newPlot)
combineLegend <- plot_spacer() + legend + legend1 + plot_spacer() + plot_layout(ncol = 1, heights = c(.5, 1, 1, .5))
wrap_elements(plotGrid) + combineLegend + plot_layout(widths = c(4, 1))
I'm looking for some help creating a "Canopy Height Model (CHM)-Zmax-curve/line" on my las-plots. I extracted a transect with the lidR package
las_tr <- clip_transect(las, p1, p2, width = 3, xz=T)
And I plotted it with ggplot
ggplot(las_tr#data, aes(X,Z, color = Z)) +
geom_point(size = 0.5) +
coord_equal() +
theme_minimal() +
scale_color_gradientn(colours = height.colors(50)) +
xlim(-80,0) + ylim(0,45) +
labs(title = "2D profile", subtitle= paste(round(x[i]),round(y[i])))
I have this
But I would like something like this
I hope someone can help me.
library(lidR)
library(dplyr)
library(ggplot2)
LASfile <- system.file("extdata", "Megaplot.laz", package="lidR")
las = readLAS(LASfile, select = "xyz")
p1 <- c(684800, y = 5017800)
p2 <- c(684900, y = 5017900)
tr <- clip_transect(las, p1, p2, width = 4, xz = T)
DSM <- tr#data[ , .(Z = max(Z)), by = list(X = plyr::round_any(X, 1))]
ggplot(tr#data) +
aes(X,Z, color = Z) +
geom_point(size = 0.5) +
geom_line(data = DSM, color = "black") +
coord_equal() +
theme_minimal() +
scale_color_gradientn(colours = height.colors(50))
Created on 2021-05-27 by the reprex package (v2.0.0)
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)
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