Related
I have a data frame with three groups (group1, group2, group3). I would like to show the p-value of their mean comparisons in ggplot2 which I can do however, the values are stacked ontop of one another making it difficult to see what is being compared. When I try to adjust where the p-values are located using the y_position() function, the boxplots collapse (I think because the y-axis is log10) but the p-values are no longer stacked ontop of one another. How can I keep the boxplots from collapsing and keep the p-values displayed so that you can see what is being compared?
Example data
library(ggplot2)
library(dplyr)
library(ggsignif)
df <- data.frame(matrix(ncol = 2, nrow = 30))
colnames(df)[1:2] <- c("group", "value")
df$group <- rep(c("group1","group2","group3"), each = 10)
df[1:10,2] <- rexp(10, 1/10)
df[11:20,2] <- rexp(10, 1/100)
df[21:30,2] <- rexp(10, 1/900)
# Need to say what should be compared for p-value determination
my_comparisons <- list(c("group1", "group2"),
c("group1", "group3"),
c("group2", "group3"))
Boxplots showing the distribution of value for each group however the p-values are ontop of one another so you cannot compare among groups.
df %>%
mutate(group = factor(group, levels = c("group3","group2","group1"))) %>%
ggplot(aes(x = group, y = value)) +
geom_signif(comparisons = my_comparisons,
map_signif_level = function(x) paste("p =", scales::pvalue(x))) +
scale_y_log10() +
geom_boxplot(outlier.colour="white", outlier.fill = "white", outlier.shape = 1, outlier.size = 0) +
geom_jitter(shape=1, position=position_jitter(0.2), color = "black", fill = "white", size = 2) +
labs(x = "",
y = "value") +
theme_bw() +
theme(axis.text.x = element_text(size = 16, color = "black"),
axis.text.y = element_text(size = 16, color = "black"),
axis.title = element_text(size = 16, color = "black"),
axis.title.x = element_text(vjust = -0.5),
panel.grid = element_blank(),
panel.background = element_blank())
Adjusting the y_position() of where the p-values should display but this collapses the y-axis. I have tried several values within y_position.
df %>%
mutate(group = factor(group, levels = c("group3","group2","group1"))) %>%
ggplot(aes(x = group, y = value)) +
geom_signif(y_position = c(2000,1800,1600),
comparisons = my_comparisons,
map_signif_level = function(x) paste("p =", scales::pvalue(x))) +
scale_y_log10() +
geom_boxplot(outlier.colour="white", outlier.fill = "white", outlier.shape = 1, outlier.size = 0) +
geom_jitter(shape=1, position=position_jitter(0.2), color = "black", fill = "white", size = 2) +
labs(x = "",
y = "value") +
theme_bw() +
theme(axis.text.x = element_text(size = 16, color = "black"),
axis.text.y = element_text(size = 16, color = "black"),
axis.title = element_text(size = 16, color = "black"),
axis.title.x = element_text(vjust = -0.5),
panel.grid = element_blank(),
panel.background = element_blank())
For some reason this parameter ignores the axis transformation. You therefore need to use the log10 values of the desired positions:
df %>%
mutate(group = factor(group, levels = c("group3","group2","group1"))) %>%
ggplot(aes(x = group, y = value)) +
geom_signif(comparisons = my_comparisons,
y_position = log10(c(5000, 10000, 25000)),
map_signif_level = function(x) paste("p =", scales::pvalue(x))) +
scale_y_log10() +
geom_boxplot(outlier.colour="white", outlier.fill = "white",
-outlier.shape = 1, outlier.size = 0) +
geom_jitter(shape=1, position=position_jitter(0.2), color = "black",
fill = "white", size = 2) +
labs(x = "",
y = "value") +
theme_bw() +
theme(axis.text.x = element_text(size = 16, color = "black"),
axis.text.y = element_text(size = 16, color = "black"),
axis.title = element_text(size = 16, color = "black"),
axis.title.x = element_text(vjust = -0.5),
panel.grid = element_blank(),
panel.background = element_blank())
I would like to plot geom_text() in a facet_wrap with scale = free.
I tried to use geom_blank() or, set each height on each graph, but it was not successful.
Would you possibly tell me how to plot geom_text() in the right bottom in each figure.
z_cor <- fit01_varsize2 %>%
filter(!variable1 == "intercept") %>%
group_by(variable1) %>%
# mutate(height = max(value_with) + .3 * sd(value_with)) %>%
ggplot(aes(x = value_without, y = value_with))+
geom_point(aes(color = value), shape = 1)+
# geom_blank(aes(x = 1, y = 1)) +
geom_text(
data = data.frame(variable1 = c("Agricultural_land", "Artificial_land", "Precipitation", "Protected_area",
"RiverLake", "Seashore", "Temperature", "Volcanic_area", "Wasteland"),
label = c("TRUE:FALSE = 694:316", "TRUE:FALSE = 698:312", "TRUE:FALSE = 733:277", "TRUE:FALSE = 864:146",
"TRUE:FALSE = 721:289", "TRUE:FALSE = 739:271", "TRUE:FALSE = 657:353", "TRUE:FALSE = 748:262", "TRUE:FALSE = 707:303")),
aes(x = 0.1, y = 0.1, label = label))+
geom_abline(intercept = 0, slope = 1, linetype = "dashed") +
scale_color_manual(values = c("TRUE" = "salmon", "FALSE" = "steelblue"))+
# geom_smooth(method = "lm",colour= "deepskyblue3")+
# ggpubr::stat_cor(method="pearson", label.y.npc="top", label.x.npc = "center")+
facet_wrap(.~variable1, scales = "free")+
theme(strip.text.x = element_text(size = 20),
axis.title=element_text(size=16),
axis.line = element_line(colour="grey40"),
axis.title.y = element_blank(),
axis.title.x = element_blank(),
legend.position = "bottom",
panel.background = element_rect(fill = "transparent",
colour = "transparent",
size = 0.5, linetype = "solid"),
plot.background = element_rect(fill = "transparent",
colour = "transparent"),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()
)
[![enter image description here][1]][1]
By setting the aes(x, y) parameters to positive or negative Inf inside geom_text, we can have text labels on the lower right bottom of each facet. The extra hjust and vjust adjust the position of the label so that they would be in the panel.
Here I use the diamonds dataset as an example, and the data for geom_text is called diamonds_label.
library(ggplot2)
diamonds_label <- data.frame(clarity = unique(diamonds$clarity), label = LETTERS[1:8])
ggplot(diamonds, aes(x, y)) +
geom_point() +
facet_wrap(.~clarity, scale = "free") +
geom_text(data = diamonds_label, aes(Inf, -Inf, label = label),
col = "red",
hjust = 1,
vjust = -1)
Created on 2022-05-10 by the reprex package (v2.0.1)
I have a 100% stacked bar chart that displays 3 types of variable. I've set a example db so I could create a graph more easily.
I've already adjust the chart with the colors and information I need. But I'm not being able to independently position the labels. Here's the current code and output.
Code:
(empilhado<-ggplot(dfm, aes(y = Year, x = abs(value), fill = variable)) +
scale_x_continuous(sec.axis = sec_axis(trans = ~.*1, name="Trab."), expand=expansion(mult=c(0,0.05)))+
geom_col(data = rotulo, aes(y = Year, x=abs(trabalho), fill=NULL), width = .7, colour="black", lwd=0.1, position = "fill", orientation = "y") +
geom_label(data = rotulo, aes(y= Year, x = abs(trabalho), fill=NULL, label=paste(format(round(trabalho, digits=0), nsmall=0, decimal.mark=",", big.mark="."),
format(round(aprovado, digits=0), nsmall=0, decimal.mark=",", big.mark="."))
), color="black", size=4, position = position_fill(vjust=1.06)) +
geom_col(width = .7, colour="black", lwd=0.1, position = "fill", orientation = "y") +
geom_text(aes(label=format(round(value, digits=0), nsmall=0, decimal.mark=",", big.mark=".")),
size=4, color="white", position = position_fill(vjust=0.5)) +
theme(panel.grid.major = element_line(colour = "gray90",size=0.75), panel.grid.minor = element_line(colour = "gray90",size=0.75),
legend.position="top", axis.text.x = element_blank(), axis.ticks.x = element_blank(),
axis.title.x = element_blank(), panel.background = element_blank())+
scale_fill_manual(values = c("#000000","tomato","blue"))
Output:
How is it now? Position_fill(vjust=0.5), so all the labels are centered inside its respective bar.
What I want? To be able to set the position of the 'Marionete' label on the left(like a vjust=0 would do), keep the 'Pedido' label as is (in the center of the 'Pedido' stacked bar) and place the 'Fatura' label on the right (like a vjust=1 would do).
Thanks in advance!
One option to achieve your desired result would be to compute/set the positions for each label and the horizontal alignment manually instead of making use of position="fill":
Making use of some random mock data:
library(ggplot2)
library(dplyr)
dfm <- dfm %>%
group_by(Year) %>%
arrange(desc(variable)) %>%
mutate(
pct = value / sum(value),
x_label = case_when(
variable == "Marionete" ~ 0,
variable == "Pedido" ~ .5 * (cumsum(pct) + lag(cumsum(pct))),
TRUE ~ 1
),
hjust = case_when(
variable == "Marionete" ~ 0,
variable == "Pedido" ~ .5,
TRUE ~ 1
)
)
ggplot(dfm, aes(y = Year, x = abs(value), fill = variable)) +
scale_x_continuous(sec.axis = sec_axis(trans = ~ . * 1, name = "Trab."), expand = expansion(mult = c(0, 0.05))) +
geom_col(width = .7, colour = "black", lwd = 0.1, position = "fill", orientation = "y") +
geom_text(aes(x = x_label, label = format(round(value, digits = 0), nsmall = 0, decimal.mark = ",", big.mark = "."), hjust = hjust),
size = 4, color = "white"
) +
theme(
panel.grid.major = element_line(colour = "gray90", size = 0.75), panel.grid.minor = element_line(colour = "gray90", size = 0.75),
legend.position = "top", axis.text.x = element_blank(), axis.ticks.x = element_blank(),
axis.title.x = element_blank(), panel.background = element_blank()
) +
scale_fill_manual(values = c("#000000", "tomato", "blue"))
DATA
set.seed(123)
dfm <- data.frame(
Year = rep(c(2006:2016), each = 3),
value = sample(1:100, 3 * 11, replace = TRUE),
variable = c("Fatura", "Pedido", "Marionete")
)
dfm$variable <- factor(dfm$variable, levels = c("Fatura", "Pedido", "Marionete"))
dfm$Year <- factor(dfm$Year)
I used ggpubr::ggarrange to create a multiple plot with a shared y- and x axis. The only issue that I am having is that the first plot, which does have the y axis is smaller than the other 3 plots which brings the whole figure out of proportion.
I am therefore looking for a solution to display only one y lab without bringing the first plot out of proportion to the other 3 plots. Help is highly appreciated as I have been searching for a solution to this problem since quiet some time already.
My approach so far was to remove the y lab from plot (p) 2,3,4 and leave it on p1.
This is my code:
library(ggplot2)
library(ggpubr)
library(dplyr)
p1 <- ggplot(arrange(ploughed1, Horizont), aes(Ferment, RAI_II, fill = factor(Horizont, levels=c("4","3","2","1"))))+
geom_bar(stat = "identity", position = "dodge")+
scale_fill_manual(values = c("#FF9933", "#CC6600","#663300","#000000"))+
guides(fill = guide_legend(reverse = TRUE))+
labs(fill="Horizon")+
ylim(0,200)+
theme_bw()+
facet_wrap(~compost)+
theme(strip.text = element_text(size = 7),
panel.spacing = unit(0.2, "lines"))+
geom_col(position = position_stack(reverse = TRUE))+
labs(x="Ferment", y = "RAI_II=Rooting*Scheme*Active", title = "P- ")
p2 <- ggplot(arrange(ploughed2, Horizont), aes(Ferment, RAI_II, fill = factor(Horizont, levels=c("4","3","2","1"))))+
geom_bar(stat = "identity", position = "dodge")+
scale_fill_manual(values = c("#FF9933", "#CC6600","#663300","#000000"))+
guides(fill = guide_legend(reverse = TRUE))+
labs(fill="Horizon")+
ylim(0,200)+
theme_bw()+
theme(axis.text.y = element_blank(),
panel.spacing = unit(0.2, "lines"),
strip.text = element_text(size = 7))+
facet_wrap(~compost)+
geom_col(position = position_stack(reverse = TRUE))+
labs(x="Ferment", title = "P+ ")+
rremove("ylab")
p3 <- ggplot(arrange(reduced1, Horizont), aes(Ferment, RAI_II, fill = factor(Horizont, levels=c("4","3","2","1"))))+
geom_bar(stat = "identity", position = "dodge")+
scale_fill_manual(values = c("#FF9933", "#CC6600","#663300","#000000"))+
guides(fill = guide_legend(reverse = TRUE))+
labs(fill="Horizon")+
ylim(0,200)+
theme_bw()+
theme(axis.text.y = element_blank(),
panel.spacing = unit(0.2, "lines"),
strip.text = element_text(size = 7))+
facet_wrap(~compost)+
geom_col(position = position_stack(reverse = TRUE))+
labs(x="Ferment", title = "RT- ")+
rremove("ylab")
p4 <- ggplot(arrange(reduced2, Horizont), aes(Ferment, RAI_II, fill = factor(Horizont, levels=c("4","3","2","1"))))+
geom_bar(stat = "identity", position = "dodge")+
scale_fill_manual(values = c("#FF9933", "#CC6600","#663300","#000000"))+
guides(fill = guide_legend(reverse = TRUE))+
labs(fill="Horizon")+
ylim(0,200)+
theme_bw()+
theme(axis.text.y = element_blank(),
panel.spacing = unit(0.2, "lines"),
strip.text = element_text(size = 7))+
facet_wrap(~compost)+
geom_col(position = position_stack(reverse = TRUE))+
labs(x="Ferment", title = "RT+ ")+
rremove("ylab")
ggarrange(p1, p2, p3, p4, nrow=1, common.legend = TRUE)
Output .png
Output image: 1
I also tried to solve it in the ggarrange function, without removing the y lab and text in p2,p3 and p4, which had the same result.
ggarrange(p1, p2+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ), p3+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ), p4+
theme(axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank() ) , nrow=1, common.legend = TRUE)
If other packages are an option for you, I would suggest to make use of patchwork. Using some convenience functions to reduce the duplicated code and some random example data to mimic your real data:
library(ggplot2)
library(patchwork)
library(dplyr)
ploughed1 <- data.frame(
Horizont = rep(1:4, 4),
RAI_II = runif(16, 10, 50),
Ferment = rep(c("-", "+"), each = 8),
compost = rep(c("- Compost", "+ Compost"), each = 4)
)
plot_fun <- function(x, title) {
ggplot(arrange(x, Horizont), aes(Ferment, RAI_II, fill = factor(Horizont, levels = c("4", "3", "2", "1")))) +
geom_bar(stat = "identity", position = "dodge") +
scale_fill_manual(values = c("#FF9933", "#CC6600", "#663300", "#000000")) +
guides(fill = guide_legend(reverse = TRUE)) +
ylim(0, 200) +
theme_bw() +
facet_wrap(~compost) +
theme(
strip.text = element_text(size = 7),
panel.spacing = unit(0.2, "lines")
) +
geom_col(position = position_stack(reverse = TRUE)) +
labs(x = "Ferment", y = "RAI_II=Rooting*Scheme*Active", fill = "Horizon", title = title)
}
remove_y <- theme(
axis.text.y = element_blank(),
axis.ticks.y = element_blank(),
axis.title.y = element_blank()
)
p <- list(
plot_fun(ploughed1, "P-"),
plot_fun(ploughed1, "P+") + remove_y,
plot_fun(ploughed1, "RT-") + remove_y,
plot_fun(ploughed1, "RT+") + remove_y
)
wrap_plots(p, nrow = 1) + plot_layout(guides = "collect")
Compared to patchwork where all facets are of the same width in each plot making use of ggpubr:ggarrange squeezes the facets in the first plot because of the y scale:
ggpubr::ggarrange(plotlist = p, nrow = 1, common.legend = TRUE)
I am trying to make a horizontal bar chart in ggplot2 where the bars are of equal width and with text labels centered on the bars. There are two groups on the y axis -- one with 2 bars, and one with three.
There are a lot of similar questions on SO that address both of these issues, but I haven't been able to fix one without breaking the other. Here's my data:
## data
df <- tibble(var1 = c("a", "b", "b", "c", "c"),
var2 = c("x", "y", "x", "y", "x"),
proportion = c(100, 33.3, 66.7, 66.7, 33.3)) %>%
mutate(var1 = factor(var1, levels = var1_order))
var1_order <- c("a", "c", "b")
Here's an example where the widths are good, but the labels of the y group are off:
## labels bad
df %>%
ggplot(aes(x = proportion, y = var2, fill = var1,
label = paste0(round(proportion, 1), "%"))) +
geom_col(position = position_dodge2(preserve = "single", padding = 0), width = .9) +
geom_text(size = 3, position = position_dodge2(width = 0.9), hjust = -.5,
color = "black", aes(group = var1)) +
scale_fill_manual(name = "", values = c("#093D6E","#5D8AA8", "#00918B",
"#F8AF54", "#CD9575")) +
labs(x = NULL) +
theme(axis.ticks = element_blank(),
axis.title.y = element_blank(),
axis.line=element_blank(),
axis.text.x = element_blank(),
panel.background = element_blank(),
strip.text = element_text(size = 7, face = "bold")) +
scale_x_continuous(expand = c(.2, .2)) +
guides(fill = guide_legend(reverse = TRUE))
And here's an example where the labels are good but the widths are now off:
## col widths bad
df %>%
ggplot(aes(x = proportion, y = var2, fill = var1,
label = paste0(round(proportion, 1), "%"))) +
geom_col(position = position_dodge(width = 0.9)) +
geom_text(size = 3, position = position_dodge(width = 0.9), hjust = -.5,
color = "black", aes(group = var1)) +
scale_fill_manual(name = "", values = c("#093D6E","#5D8AA8", "#00918B",
"#F8AF54", "#CD9575")) +
labs(x = NULL) +
theme(axis.ticks = element_blank(),
axis.title.y = element_blank(),
axis.line=element_blank(),
axis.text.x = element_blank(),
panel.background = element_blank(),
strip.text = element_text(size = 7, face = "bold")) +
scale_x_continuous(expand = c(.2, .2)) +
guides(fill = guide_legend(reverse = TRUE))
Note that this will be part of a parameterized report, so it needs to be capable of dealing with different numbers of var1 and var2 groups. Thanks!
Try this approach. You can use position_dodge2() to keep uniform bars. Here the code:
library(ggplot2)
#Code
df %>%
ggplot(aes(x = proportion, y = var2, fill = var1,
label = paste0(round(proportion, 1), "%"))) +
geom_col(position = position_dodge2(preserve = 'single',width = 0.9)) +
geom_text(size = 3, position = position_dodge2(preserve = 'single',width = 0.9), hjust = -.5,
color = "black", aes(group = var1)) +
scale_fill_manual(name = "", values = c("#093D6E","#5D8AA8", "#00918B",
"#F8AF54", "#CD9575")) +
labs(x = NULL) +
theme(axis.ticks = element_blank(),
axis.title.y = element_blank(),
axis.line=element_blank(),
axis.text.x = element_blank(),
panel.background = element_blank(),
strip.text = element_text(size = 7, face = "bold")) +
scale_x_continuous(expand = c(.2, .2)) +
guides(fill = guide_legend(reverse = TRUE))
Output: