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:
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 created a vector of ordered names and tried to replace each panel title with the ordered one (e.g., Jessie with 1. Jessie, Marion with 2.Marion, etc.). But, I am getting NAs for each panel title instead. Any hints what is going wrong.
With the NAs
With the labeller commented out
list.top.35.names.ordered <- data.frame( cbind(order = c(1:35),list.top.35.names)) %>%
unite( name.new, c("order" ,"list.top.35.names"), sep = ".")
list.top.35.names.ordered <- list.top.35.names.ordered$name.new[1:35]
str(list.top.35.names.ordered)
chr [1:35] "1.Jessie" "2.Marion" "3.Jackie" "4.Alva" "5.Trinidad" "6.Ollie" ...
data.babyname.all %>%
ggplot( mapping = aes(x = year, y = perc, fill = sex)) +
geom_density(stat = "identity", position = "stack" , show.legend = F ) +
facet_wrap(~name, ncol= 7, nrow =5, labeller= as_labeller(list.top.35.names.ordered)) +
scale_fill_manual(values = c('#E1AEA1','#9ABACF')) +
geom_point(data = most.unisex.year.and.value, mapping = aes(x = year, y = perc),
size = 3,
fill = "white",
color = "black",
shape = 21) +
scale_y_continuous(breaks = c(0,.50,1), labels= c("0%", "50%","%100")) +
scale_x_continuous(breaks = c(1940, 1960, 1980,2000), labels= c('1940', "'60","'80",'2000')) +
geom_text(mapping = aes(x =x , y = y , label = label), check_overlap = F, na.rm = T, position = position_dodge(width=.9), size=3) +
theme_minimal() + #set theme
theme(
text = element_text(size = 10),
axis.title.x = element_blank(),
axis.title.y = element_blank(),
panel.grid = element_blank(),
panel.border = element_blank(),
plot.background = element_blank(),
axis.ticks.x = element_line(color = "black"),
axis.ticks.length =unit(.2,'cm'),
strip.text = element_text(size = 10, margin = margin(l=10, b = .1)))
How to modify the "New infected", "Mortality" and "TDR level" text characteristics? I want to make it bigger and in bold. How to modify the "Scen1", "Scen2" and "Scen3" text?
I already looked into the R documentation but didn't find an answer in the particular case where barplot are used with "dodge".
Here is the code:
myd<- data.frame( var1 = rep(c("Newly infected","Mortality","TDR level"),each=3),
samp = rep(c("Scen1","Scen2","Scen3"),3),
V3 = c(3.5,2,NA,8,2,NA,4,5,NA)/1.5, V2 = c(3.5,2,NA,8,3,NA,4,4.3,NA), V1 = c(1.5,0.2,5,5,3,0.2,4,-5,2) )
# rshaping data to long form for ggplot2
library(reshape2)
meltd<- melt(myd, id.vars=1:2)
#meltd<- meltd[-which(is.na(meltd$value)),]
ggplot(meltd, aes(x = var1, y = value, fill = variable, label = paste0(round(value * 100, 1), "%"))) +
geom_bar(stat = "identity", position = position_dodge(width = 0.6), width = 0.5) +
facet_grid(samp ~ ., switch = "y", scales = "free_y", space = "free") +
coord_flip() +
scale_fill_manual("legend",values = c("V3" = "orange", "V2" = "red", "V1" = "blue", "Baseline" = "black")) +
geom_text(aes(y = value + 0.4 * sign(value)), position = position_dodge(width = 0.6)) +
theme_bw() +
theme(
legend.position = "none",
strip.placement = "outside",
#axis.title.x = element_blank(),
axis.title.y = element_blank(),
axis.text.y = element_text(colour="black"),
strip.text.y = element_text(size = 12, colour = "black"))+
ylab("Relative change (in %)")
Here is the plot:
You're pretty much there, I just added face, and size arguments:
axis.text.y = element_text(colour="black", face='bold',size=12),
strip.text.y = element_text(size = 12, colour = "black", face='bold'))+
ylab("Relative change (in %)")
Or to change the size of the value labels add size to geom_text:
geom_text(aes(y = value + 0.4 * sign(value)),
position = position_dodge(width = 0.6), size=6)
Full code:
ggplot(meltd, aes(x = var1, y = value, fill = variable, label = paste0(round(value * 100, 1), "%"))) +
geom_bar(stat = "identity", position = position_dodge(width = 0.6), width = 0.5) +
facet_grid(samp ~ ., switch = "y", scales = "free_y", space = "free") +
coord_flip() +
scale_fill_manual("legend",values = c("V3" = "orange", "V2" = "red", "V1" = "blue", "Baseline" = "black")) +
geom_text(aes(y = value + 0.4 * sign(value)), position = position_dodge(width = 0.6), size=6)+
theme_bw() +
theme(
legend.position = "none",
strip.placement = "outside",
#axis.title.x = element_blank(),
axis.title.y = element_blank(),
# added face and size arguments
axis.text.y = element_text(colour="black", face='bold',size=12),
strip.text.y = element_text(size = 12, colour = "black", face='bold'))+
ylab("Relative change (in %)")