In ggplot2 I would like to have control over multiple position dodges within variables and factors in a barplot or crossbar plot. For example:
data = data.frame(Var=c("a","a","a","a","b","b","b","b"),
Val=c(0.5,0.4,0.1,0.0,-0.1,-0.3,-0.0,0.1),
g1=c(1,2,3,4,5,6,7,8),
g2=c(1,2,3,4,1,2,3,4),
g3=c(1,2,1,2,1,2,1,2))
q = ggplot(data,aes(Var,Val,ymin = Val-0.15,
ymax=Val+0.15,
group=g1,
colour=factor(g2),
fill=factor(g2),
linetype=factor(g3),))
q + geom_crossbar(width=0.5,fatten=2,size=0.5,position=position_dodge(width=0.51)) +
coord_flip() +
theme_bw() +
scale_fill_manual(values=c("#00000090","#00000090","#00000050","#00000050")) +
scale_colour_manual(values=c("#000000","#00000070","#000000","#00000070"))
In the example above, I would like to be able to slightly separate the darker bars from the lighter bars, while keeping each bar set together. Can I implement multiple position dodges in order to accomplish this? Any help would be appreciated.
I propose using facet_grid to simulate the nested dodging that you want. To do that, I created a new factor g4 that groups the light gray and dark gray bars.
library(ggplot2)
dat = data.frame(Var=c("a","a","a","a","b","b","b","b"),
Val=c(0.5,0.4,0.1,0.0,-0.1,-0.3,-0.0,0.1),
g1=c(1,2,3,4,5,6,7,8),
g2=c(1,2,3,4,1,2,3,4),
g3=c(1,2,1,2,1,2,1,2))
dat$g4 = c(1, 1, 2, 2, 1, 1, 2, 2) # New grouping factor
fill_values = c("#00000090","#00000090","#00000050","#00000050")
colour_values = c("#000000","#00000070","#000000","#00000070")
#---------------------------------------------------------------------------
fig1 = ggplot(dat, aes(x=Var, y=Val, ymin=Val - 0.15, ymax=Val + 0.15,
colour=factor(g2), fill=factor(g2), linetype=factor(g3))) +
geom_crossbar(width=0.5, fatten=2, size=0.5,
position=position_dodge(width=0.51)) +
coord_flip() +
theme_bw() +
scale_fill_manual(values=fill_values) +
scale_colour_manual(values=colour_values) +
opts(title="Figure 1: Original Version")
png("fig1.png", height=600, width=600)
print(fig1)
dev.off()
#---------------------------------------------------------------------------
fig2 = ggplot(dat, aes(x=factor(g4), y=Val, ymin=Val - 0.15,ymax=Val + 0.15,
colour=factor(g2), fill=factor(g2), linetype=factor(g3))) +
geom_crossbar(width=0.7, fatten=2, size=0.5,
position=position_dodge()) +
coord_flip() +
theme_bw() +
scale_fill_manual(values=fill_values) +
scale_colour_manual(values=colour_values) +
facet_grid(Var ~ .) +
opts(title="Figure 2: Proposed Solution")
png("fig2.png", height=600, width=600)
print(fig2)
dev.off()
Updated code and plot
Here's an approach that separates the light grey from the dark grey in the one panel. It involves subsetting the data so that in two calls to geom_crossbar, the light grey corssbars are positioned in the first call, then the dark grey crossbars are positionned in the second call. I've added another grouping variable to the data frame to allow the subsetting of the data.
library(ggplot2)
data = data.frame(Var=c("a","a","a","a","b","b","b","b"),
Val=c(0.5,0.4,0.1,0.0,-0.1,-0.3,-0.0,0.1),
g1=c(1,2,3,4,5,6,7,8),
g2=c(1,2,3,4,1,2,3,4),
g3=c(1,2,1,2,1,2,1,2))
data$g4 = c(1,1,2,2,1,1,2,2)
q = ggplot(data, aes(Var,Val,ymin = Val-0.15,
ymax=Val+0.15, group=g1, colour=factor(g2),
fill=factor(g2), linetype=factor(g3)))
# Position the light grey crossbars
q = q + geom_crossbar(data = subset(data, data$g4 == 1),
aes(as.numeric(Var) - .12, Val, ymin = Val-0.15, ymax = Val + 0.15),
width = 0.2, fatten = 1.25, size = 0.65, position = position_dodge(width = 0.2))
library(grid)
# position the dark grey crossbars, and tidy up
q + geom_crossbar(data = subset(data, data$g4 == 2),
aes(as.numeric(Var) + .12, Val, ymin = Val-0.15, ymax = Val + 0.15),
width = 0.2, fatten = 1.25, size = 0.65, position = position_dodge(width = 0.2)) +
scale_x_continuous(breaks = c(1, 2), labels = c("a", "b"), expand = c(.2, 0)) +
scale_fill_manual(values = c("#00000057", "#00000057", "#00000020", "#00000020")) +
scale_colour_manual(values = c("#000000", "#00000070", "#000000", "#00000070")) +
coord_flip() + theme_bw() +
theme(legend.key.size = unit(1.5, "cm"))
Related
I have previously asked a similar question, which was "how to add OR and CI 95% as text into a forest plot".
In that previous question, I got my codes from a third question by someone named stupidwolf.
I used his codes to get a forest plot, BUT without OR and CI as text. This is the codes I used from stupidwolf, which worked for me.
library('ggplot2')
Outcome_order <- c('Outcome C', 'Outcome A', 'Outcome B', 'Outcome D')
#this is the first dataset you have
df1 <- data.frame(Outcome=c("Outcome A", "Outcome B", "Outcome C", "Outcome D"),
OR=c(1.50, 2.60, 1.70, 1.30),
Lower=c(1.00, 0.98, 0.60, 1.20),
Upper=c(2.00, 3.01, 1.80, 2.20))
# add a group column
df1$group <- "X"
# create a second dataset, similar format to first
df2 <- df1
# different group
df2$group <- "Y"
# and we adjust the values a bit, so it will look different in the plot
df2[,c("OR","Lower","Upper")] <- df2[,c("OR","Lower","Upper")] +0.5
# combine the two datasets
df = rbind(df1,df2)
# you can do the factoring here
df$Outcome = factor (df$Outcome, level=Outcome_order)
#define colours for dots and bars
dotCOLS = c("#a6d8f0","#f9b282")
barCOLS = c("#008fd5","#de6b35")
p <- ggplot(df, aes(x=Outcome, y=OR, ymin=Lower, ymax=Upper,col=group,fill=group)) +
#specify position here
geom_linerange(size=5,position=position_dodge(width = 0.5)) +
geom_hline(yintercept=1, lty=2) +
#specify position here too
geom_point(size=3, shape=21, colour="white", stroke = 0.5,position=position_dodge(width = 0.5)) +
scale_fill_manual(values=barCOLS)+
scale_color_manual(values=dotCOLS)+
scale_x_discrete(name="(Post)operative outcomes") +
scale_y_continuous(name="Odds ratio", limits = c(0.5, 5)) +
coord_flip() +
theme_minimal()
Then I asked in my previous question, if someone could help me with adding the OR and CI as text on the forest plot, which Allan Cameron helped me with.
This almost solved my problem.
So what I did was this, as he suggested me to do and it worked for me as well:
ggplot(df, aes(x = Outcome, y = OR, ymin = Lower, ymax = Upper,
col = group, fill = group)) +
geom_linerange(linewidth = 5, position = position_dodge(width = 0.5)) +
geom_hline(yintercept = 1, lty = 2) +
geom_point(size = 3, shape = 21, colour = "white", stroke = 0.5,
position = position_dodge(width = 0.5)) +
geom_text(aes(y = 3.75, group = group,
label = paste0("OR ", round(OR, 2), ", (", round(Lower, 2),
" - ", round(Upper, 2), ")")), hjust = 0,
position = position_dodge(width = 0.5), color = "black") +
scale_fill_manual(values = barCOLS) +
scale_color_manual(values = dotCOLS) +
scale_x_discrete(name = "(Post)operative outcomes") +
scale_y_continuous(name = "Odds ratio", limits = c(0.5, 5)) +
coord_flip() +
theme_minimal()
And I get this forest plot
As you can see on the forest plot the OR and CI text is inside the plot area. So I have following questions that I hope someone can help me to fix:
How to add one title "OR" above all the OR values instead of it is written for each OR value?
How can I plot the OR and CI text outside the plot, like on the side to the right. Because on my real plot I have very long CI unfortunately, so I can't avoid the text merging with the horizontal CI lines. If I start moving the OR text by changing the y = 3.75 position more to the right, then the OR and 95%CI text starts to disappear (half of it), because it gets pushed out of the plot. So I was thinking if I could plot it outside the plot, then it will solve the issue maybe? But how?
This is the link to my previous question if necessary: How to add OR and 95% CI as text into a forest plot?
Using the patchwork package.
library(ggplot2)
library(patchwork)
p1 <- ggplot(df, aes(x = Outcome, y = OR, ymin = Lower, ymax = Upper,
col = group, fill = group)) +
geom_linerange(size = 5, position = position_dodge(width = 0.5)) +
geom_hline(yintercept = 1, lty = 2) +
geom_point(size = 3, shape = 21, colour = "white", stroke = 0.5,
position = position_dodge(width = 0.5)) +
scale_fill_manual(values = barCOLS) +
scale_color_manual(values = dotCOLS) +
scale_x_discrete(name = "(Post)operative outcomes") +
scale_y_continuous(name = "Odds ratio", limits = c(0.5, 5)) +
coord_flip() +
theme_minimal()
p2 <- ggplot(df, aes(x = Outcome, y = 1.25, ymin = Lower, ymax = Upper)) +
geom_text(aes(group = group,
label = paste0(round(OR, 2), ", (", round(Lower, 2),
" - ", round(Upper, 2), ")")),
position = position_dodge(width = 0.5), color = "black") +
labs(title = "OR") +
coord_flip() +
theme_void()
p1 + p2
I'd like to draw bar plot like this but in dual Y axis
(https://i.stack.imgur.com/ldMx0.jpg)
the first three indexs range from 0 to 1,
so I want the left y-axis (corresponding to NSE, KGE, VE) to range from 0 to 1,
and the right y-axis (corresponding to PBIAS) to range from -15 to 5.
the following is my data and code:
library("ggplot2")
## data
data <- data.frame(
value=c(0.82,0.87,0.65,-3.39,0.75,0.82,0.63,1.14,0.85,0.87,0.67,-7.03),
sd=c(0.003,0.047,0.006,4.8,0.003,0.028,0.006,4.77,0.004,0.057,0.014,4.85),
index=c("NSE","KGE","VE","PBIAS","NSE","KGE","VE","PBIAS","NSE","KGE","VE","PBIAS"),
period=c("all","all","all","all","calibration","calibration","calibration","calibration","validation","validation","validation","validation")
)
## fix index sequence
data$index <- factor(data$index, levels = c('NSE','KGE','VE',"PBIAS"))
data$period <- factor(data$period, levels = c('all','calibration', 'validation'))
## bar plot
ggplot(data, aes(x=index, y=value, fill=period))+
geom_bar(position="dodge", stat="identity")+
geom_errorbar(aes(ymin=value-sd, ymax=value+sd),
position = position_dodge(0.9), width=0.2 ,alpha=0.5, size=1)+
theme_bw()
I try to scale and shift the second y-axis,
but PBIAS bar plot was removed because of out of scale limit as follow:
(https://i.stack.imgur.com/n6Jfm.jpg)
the following is my code with dual y axis:
## bar plot (scale and shift the second y-axis with slope/intercept in 20/-15)
ggplot(data, aes(x=index, y=value, fill=period))+
geom_bar(position="dodge", stat="identity")+
geom_errorbar(aes(ymin=value-sd, ymax=value+sd),
position = position_dodge(0.9), width=0.2 ,alpha=0.5, size=1)+
theme_bw()+
scale_y_continuous(limits = c(0,1), name = "value", sec.axis = sec_axis(~ 20*.- 15, name="value"))
Any advice for move bar_plot or other solution?
Taking a different approach, instead of using a dual axis one option would be to make two separate plots and glue them together using patchwork. IMHO that is much easier than fiddling around with the rescaling the data (that's the step you missed, i.e. if you want to have a secondary axis you also have to rescale the data) and makes it clearer that the indices are measured on a different scale:
library(ggplot2)
library(patchwork)
data$facet <- data$index %in% "PBIAS"
plot_fun <- function(.data) {
ggplot(.data, aes(x = index, y = value, fill = period)) +
geom_bar(position = "dodge", stat = "identity") +
geom_errorbar(aes(ymin = value - sd, ymax = value + sd),
position = position_dodge(0.9), width = 0.2, alpha = 0.5, size = 1
) +
theme_bw()
}
p1 <- subset(data, !facet) |> plot_fun() + scale_y_continuous(limits = c(0, 1))
p2 <- subset(data, facet) |> plot_fun() + scale_y_continuous(limits = c(-15, 15), position = "right")
p1 + p2 +
plot_layout(guides = "collect", width = c(3, 1))
A second but similar option would be to use ggh4x which via ggh4x::facetted_pos_scales allows to set the limits for facet panels individually. One drawback, the panels have the same width. (I failed in making this approach work with facet_grid and space="free")
library(ggplot2)
library(ggh4x)
data$facet <- data$index %in% "PBIAS"
ggplot(data, aes(x = index, y = value, fill = period)) +
geom_bar(position = "dodge", stat = "identity") +
geom_errorbar(aes(ymin = value - sd, ymax = value + sd),
position = position_dodge(0.9), width = 0.2, alpha = 0.5, size = 1
) +
facet_wrap(~facet, scales = "free") +
facetted_pos_scales(
y = list(
facet ~ scale_y_continuous(limits = c(-15, 15), position = "right"),
!facet ~ scale_y_continuous(limits = c(0, 1), position = "left")
)
) +
theme_bw() +
theme(strip.text.x = element_blank())
I used geom_text to put some text inside bar area, but I found that sometimes the text run off the bar area, see below. I want to make the text becomes a substring of the original text in the form that, substring = original_text[i:], where i is chosen automatically such that the substring can fit into the bar area. For example: if "ABCDEFGHIJKIFG" is too long to fit into the bar area, the text inside the bar are would be "JKIFG" for all bars.
Graph Image
Initiate Dataframe
ordering <- c(1,2,1,2)
year <- c(2000,2000,2001,2001)
value <- c(1,10,2,10)
label <- c('ABCDEFGHIJKIFG','ABCDEFGHIJKIFG','ABCDEFGHIJKIFG','ABCDEFGHIJKIFG')
df <- data.frame("ordering" = ordering, "year" = year,'value' = value,'label' = label)
Plot Graph
library(ggstance)
library(ggplot2)
library(gganimate)
ggplot(df, aes(y = ordering, x = value)) +
geom_barh(stat = "identity") +
geom_text(aes(x = 0, label = paste(label, " ")), vjust = 0.2, hjust = 0,color='red') +
transition_states(year, transition_length = 2, state_length = 0) +
view_follow(fixed_y = TRUE)
Here's a bit of a hack I thought up: if you make the plot background a fixed colour, you can plot a bar over the top of the text to cover it up. It's not perfect but it does keep the text from showing outside the bar:
max_val = max(df$value)
ggplot(df, aes(y = ordering, x = value)) +
geom_barh(stat = "identity") +
geom_text(aes(x = 0, label = label), vjust = 0.2, hjust = 0,color='red') +
geom_rect(aes(xmin = value, xmax=max_val, ymin = ordering - 0.2, ymax = ordering + 0.2),
fill = "#aaaaaa") +
transition_states(year, transition_length = 2, state_length = 0) +
view_follow(fixed_y = TRUE) +
theme(panel.background = element_rect(fill = "#aaaaaa"),
panel.grid = element_blank())
EDIT: After a bit more thinking, I came up with a version of this that gets closer to your original intent by having the label stick to the right hand side of the bar, and having the label disappear on the left hand side:
ggplot(df, aes(y = ordering, x = value)) +
geom_barh(stat = "identity") +
geom_text(aes(x = value, label = label), vjust = 0.2, hjust = 1, color='red') +
geom_rect(aes(xmin = -2, xmax=0, ymin = ordering - 0.2, ymax = ordering + 0.2),
fill = "grey92") +
transition_states(year, transition_length = 2, state_length = 0) +
# Manually setting limits, not ideal
coord_cartesian(xlim = c(0, 10)) +
theme(panel.background = element_rect(fill = "grey92"))
I have a graph made in ggplot that looks like this:
I wish to have the numeric labels at each of the bars to be grounded/glued to the x axis where y <= 0.
This is the code to generate the graph as such:
ggplot(data=df) +
geom_bar(aes(x=row, y=numofpics, fill = crop, group = 1), stat='identity') +
geom_point(data=df, aes(x = df$row, y=df$numofparcels*50, group = 2), alpha = 0.25) +
geom_line(data=df, aes(x = df$row, y=df$numofparcels*50, group = 2), alpha = 0.25) +
geom_text(aes(x=row, y=numofpics, label=bbch)) +
geom_hline(yintercept=300, linetype="dashed", color = "red", size=1) +
scale_y_continuous(sec.axis= sec_axis(~./50, name="Number of Parcels")) +
scale_x_discrete(name = c(),breaks = unique(df$crop), labels = as.character(unique(df$crop)))+
labs(x=c(), y="Number of Pictures")
I've tried vjust and experimenting with position_nudge for the geom_text element, but every solution I can find changes the position of each element of the geom_text respective to its current position. As such everything I try results in situation like this one:
How can I make ggplot ground the text to the bottom of the x axis where y <= 0, possibly with the possibility to also introduce a angle = 45?
Link to dataframe = https://drive.google.com/file/d/1b-5AfBECap3TZjlpLhl1m3v74Lept2em/view?usp=sharing
As I said in the comments, just set the y-coordinate of the text to 0 or below, and specify the angle : geom_text(aes(x=row, y=-100, label=bbch), angle=45)
I'm behind a proxy server that blocks connections to google drive so I can't access your data. I'm not able to test this, but I would introduce a new label field in my dataset that sets y to be 0 if y<0:
df <- df %>%
mutate(labelField = if_else(numofpics<0, 0, numofpics)
I would then use this label field in my geom_text call:
geom_text(aes(x=row, y=labelField, label=bbch), angle = 45)
Hope that helps.
You can simply define the y-value in geom_text (e.g. -50)
ggplot(data=df) +
geom_bar(aes(x=row, y=numofpics, fill = crop, group = 1), stat='identity') +
geom_point(data=df, aes(x = df$row, y=df$numofparcels*50, group = 2), alpha = 0.25) +
geom_line(data=df, aes(x = df$row, y=df$numofparcels*50, group = 2), alpha = 0.25) +
geom_text(aes(x=row, y=-50, label=bbch)) +
geom_hline(yintercept=300, linetype="dashed", color = "red", size=1) +
scale_y_continuous(sec.axis= sec_axis(~./50, name="Number of Parcels")) +
scale_x_discrete(name = c(),breaks = unique(df$crop), labels =
as.character(unique(df$crop)))+
labs(x=c(), y="Number of Pictures")
I am creating a grouped boxplot with a scatterplot overlay using ggplot2. I would like to group each scatterplot datapoint with the grouped boxplot that it corresponds to.
However, I'd also like the scatterplot points to be different symbols. I seem to be able to get my scatterplot points to group with my grouped boxplots OR get my scatterplot points to be different symbols... but not both simultaneously. Below is some example code to illustrate what's happening:
library(scales)
library(ggplot2)
# Generates Data frame to plot
Gene <- c(rep("GeneA",24),rep("GeneB",24),rep("GeneC",24),rep("GeneD",24),rep("GeneE",24))
Clone <- c(rep(c("D1","D2","D3","D4","D5","D6"),20))
variable <- c(rep(c(rep("Day10",6),rep("Day20",6),rep("Day30",6),rep("Day40",6)),5))
value <- c(rnorm(24, mean = 0.5, sd = 0.5),rnorm(24, mean = 10, sd = 8),rnorm(24, mean = 1000, sd = 900),
rnorm(24, mean = 25000, sd = 9000), rnorm(24, mean = 8000, sd = 3000))
value <- sqrt(value*value)
Tdata <- cbind(Gene, Clone, variable)
Tdata <- data.frame(Tdata)
Tdata <- cbind(Tdata,value)
# Creates the Plot of All Data
# The below code groups the data exactly how I'd like but the scatter plot points are all the same shape
# and I'd like them to each have different shapes.
ln_clr <- "black"
bk_clr <- "white"
point_shapes <- c(0,15,1,16,2,17)
blue_cols <- c("#EFF2FB","#81BEF7","#0174DF","#0000FF","#0404B4")
lp1 <- ggplot(Tdata, aes(x=variable, y=value, fill=Gene)) +
stat_boxplot(geom ='errorbar', position = position_dodge(width = .83), width = 0.25,
size = 0.7, coef = 4) +
geom_boxplot( coef=1, outlier.shape = NA, position = position_dodge(width = .83), lwd = 0.3,
alpha = 1, colour = ln_clr) +
geom_point(position = position_jitterdodge(dodge.width = 0.83), size = 1.8, alpha = 0.7,
pch=15)
lp1 + scale_fill_manual(values = blue_cols) + labs(y = "Fold Change") +
expand_limits(y=c(0.01,10^5)) +
scale_y_log10(expand = c(0, 0), breaks = c(0.01,1,100,10000,100000),
labels = trans_format("log10", math_format(10^.x)))
ggsave("Scatter Grouped-Wrong Symbols.png")
#*************************************************************************************************************************************
# The below code doesn't group the scatterplot data how I'd like but the points each have different shapes
lp2 <- ggplot(Tdata, aes(x=variable, y=value, fill=Gene)) +
stat_boxplot(geom ='errorbar', position = position_dodge(width = .83), width = 0.25,
size = 0.7, coef = 4) +
geom_boxplot( coef=1, outlier.shape = NA, position = position_dodge(width = .83), lwd = 0.3,
alpha = 1, colour = ln_clr) +
geom_point(position = position_jitterdodge(dodge.width = 0.83), size = 1.8, alpha = 0.7,
aes(shape=Clone))
lp2 + scale_fill_manual(values = blue_cols) + labs(y = "Fold Change") +
expand_limits(y=c(0.01,10^5)) +
scale_y_log10(expand = c(0, 0), breaks = c(0.01,1,100,10000,100000),
labels = trans_format("log10", math_format(10^.x)))
ggsave("Scatter Ungrouped-Right Symbols.png")
If anyone has any suggestions I'd really appreciate it.
Thank you
Nathan
To get the boxplots to appear, the shape aesthetic needs to be inside geom_point, rather than in the main call to ggplot. The reason for this is that when the shape aesthetic is in the main ggplot call, it applies to all the geoms, including geom_boxplot. However, applying a shape=Clone aesthetic causes geom_boxplot to create a separate boxplot for each level of Clone. Since there's only one row of data for each combination of variable and Clone, no boxplot is produced.
That the shape aesthetic affects geom_boxplot seems counterintuitive to me, but maybe there's a reason for it that I'm not aware of. In any case, moving the shape aesthetic into geom_point solves the problem by applying the shape aesthetic only to geom_point.
Then, to get the points to appear with the correct boxplot, we need to group by Gene. I also added theme_classic to make it easier to see the plot (although it's still very busy):
ggplot(Tdata, aes(x=variable, y=value, fill=Gene)) +
stat_boxplot(geom ='errorbar', width=0.25, size=0.7, coef=4, position=position_dodge(0.85)) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3, alpha=1, colour=ln_clr, position=position_dodge(0.85)) +
geom_point(position=position_jitterdodge(dodge.width=0.85), size=1.8, alpha=0.7,
aes(shape=Clone, group=Gene)) +
scale_fill_manual(values=blue_cols) + labs(y="Fold Change") +
expand_limits(y=c(0.01,10^5)) +
scale_y_log10(expand=c(0, 0), breaks=10^(-2:5),
labels=trans_format("log10", math_format(10^.x))) +
theme_classic()
I think the plot would be easier to understand if you use faceting for Gene and the x-axis for variable. Putting time on the x-axis seems more intuitive, while using facetting frees up the color aesthetic for the points. With six different clones, it's still difficult (for me at least) to differentiate the point markers, but this looks cleaner to me than the previous version.
library(dplyr)
ggplot(Tdata %>% mutate(Gene=gsub("Gene","Gene ", Gene)),
aes(x=gsub("Day","",variable), y=value)) +
stat_boxplot(geom='errorbar', width=0.25, size=0.7, coef=4) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3, alpha=1, colour=ln_clr, width=0.5) +
geom_point(aes(fill=Clone), position=position_jitter(0.2), size=1.5, alpha=0.7, shape=21) +
theme_classic() +
facet_grid(. ~ Gene) +
labs(y = "Fold Change", x="Day") +
expand_limits(y=c(0.01,10^5)) +
scale_y_log10(expand=c(0, 0), breaks=10^(-2:5),
labels=trans_format("log10", math_format(10^.x)))
If you really need to keep the points, maybe it would be better to separate the boxplots and points with some manual dodging:
set.seed(10)
ggplot(Tdata %>% mutate(Day=as.numeric(substr(variable,4,5)),
Gene = gsub("Gene","Gene ", Gene)),
aes(x=Day - 2, y=value, group=Day)) +
stat_boxplot(geom ='errorbar', width=0.5, size=0.5, coef=4) +
geom_boxplot(coef=1, outlier.shape=NA, lwd=0.3, alpha=1, width=4) +
geom_point(aes(x=Day + 2, fill=Clone), size=1.5, alpha=0.7, shape=21,
position=position_jitter(width=1, height=0)) +
theme_classic() +
facet_grid(. ~ Gene) +
labs(y="Fold Change", x="Day") +
expand_limits(y=c(0.01,10^5)) +
scale_y_log10(expand=c(0, 0), breaks=10^(-2:5),
labels=trans_format("log10", math_format(10^.x)))
One more thing: For future reference, you can simplify your data creation code:
Gene = rep(paste0("Gene",LETTERS[1:5]), each=24)
Clone = rep(paste0("D",1:6), 20)
variable = rep(rep(paste0("Day", seq(10,40,10)), each=6), 5)
value = rnorm(24*5, mean=rep(c(0.5,10,1000,25000,8000), each=24),
sd=rep(c(0.5,8,900,9000,3000), each=24))
Tdata = data.frame(Gene, Clone, variable, value)