How can I insert annotations outside the plot?
I want to add a note on top of the first bar to signal that it continues e.g. up to 1000. If I use annotate, the note won't go outside the plot. (Note that I am using coord_cartesian to limit the y axis to 100.)
Here is my code.
plot <- ggplot() +
geom_crossbar(data=GHG, aes(x=Study, y=Avg, ymin=Min, ymax=Max),
fill="white", width=0.3) +
coord_cartesian(ylim=c(0, 100), clip="off") +
labs(x="", y="g CO2-eq.") +
annotate("text", x=1, y=150, label=c("150"), vjust=-1) +
theme(legend.position = "bottom",
axis.text.x = element_text(angle=0, vjust=1, hjust=0.5),
panel.grid.major.x= element_blank(),
panel.grid.minor = element_blank(),
plot.margin = unit(c(1,3,1,1),"lines"))
And here is the chart:
One strategy is to use a secondary axis and the labels to annotate your bar.
This is a bit tricky, because only continuous scales can have a secondary axis.
I used the following data.frame for test purpose:
GHG <- data.frame(Avg = c(50, 37, 62), Min = c(10, 25, 25), Max = c(1000, 50, 80), Study = c("A", "B", "C"))
The code:
ggplot() +
geom_crossbar(data=GHG, aes(x=as.numeric(Study), y=Avg, ymin=Min, ymax=Max),
fill="white", width=0.3) +
coord_cartesian(ylim=c(0, 100), clip = "on") +
scale_x_continuous(position = "top",
breaks = 1:length(unique(GHG$Study)),
labels = c(1000, rep("", length(unique(GHG$Study)) - 1)),
sec.axis = sec_axis(~.,
breaks = 1:length(unique(GHG$Study)),
labels = rep("", length(unique(GHG$Study))))) +
labs(x="", y="g CO2-eq.") +
theme(legend.position = "bottom",
axis.text.x = element_text(angle=0, vjust=1, hjust=0.5),
panel.grid.major.x= element_blank(),
panel.grid.minor = element_blank(),
plot.margin = unit(c(1,3,1,1),"lines"),
axis.ticks.x.top = element_blank(),
axis.text.x.top = element_text(size = 14, color = "black", margin = margin(b = 5)))
Details:
The aes is slightly changed to allow for continuous scale: aes(x=as.numeric(Study), y=Avg, ymin=Min, ymax=Max)
In coord_cartesian(ylim=c(0, 100), clip = "on"): clip is set to on to clip the part of the bars that goes out of the plot area.
Add and configure the continuous scale for X on top: scale_x_continuous(position = "top",
Manually add breaks for each value of Study: breaks = 1:length(unique(GHG$Study)),
Label the first break with the text you want to add, the rest of the breaks has no text: labels = c("text", rep("", length(unique(GHG$Study)) - 1)),
Add a secondary axis to keep the ticks at the bottom. If you don't want them, this is not necessary: sec.axis = sec_axis(~.,
Manually set the breaks for the continuous scale: breaks = 1:length(unique(GHG$Study)),
And add blank labels to reproduce your example: labels = rep("", length(unique(GHG$Study))))) +
In the theme method, remove the ticks for the top axis: axis.ticks.x.top = element_blank(),
And finally customize the font, color and everything for the top label: axis.text.x.top = element_text(size = 14, color = "black", margin = margin(b = 5)))
Related
I have a plot whose margins are slightly askew and need to be removed. So there should be no empty grey along the bottom or at the left and right of the plot. The dots should go right against the axis's. I think part of the problems may be my last two annotation lines. I tried adding + theme(plot.margins = unit(c(0.1,0.1,0.1,0.1), "cm")) in the last line that defines my plot but this just returns an error:
Error: Theme element `plot.margins` is not defined in the element hierarchy.
`
pvalplot<-function(var, maintitle) {
pvalall<-as.data.frame(c(t(var)))
pvalall$Sample_Size<-c((1:(5*162)),(1:(11*162)),(1:(3*162)),(1:(5*162)),(1:(13*162)),(1:(3*162)),(1:(5*162)))
pvalall$Domain<-c(rep("Physical",5*162),rep("Perinatal",11*162),rep("Developmental",3*162),
rep("Lifestyle-Life Events",5*162),rep("Parental-Family",13*162),rep("School",3*162),
rep("Neighborhood",5*162))
pvalall$Domain <- factor(pvalall$Domain,
levels = c("Physical", "Perinatal", "Developmental",
"Lifestyle-Life Events", "Parental-Family",
"School","Neighborhood"))
pvalall[,1]<-ifelse(pvalall[,1]<1e-20,1e-20,pvalall[,1])
names(pvalall)[1]<-"P-Values"
pvalexp.labels= rep("",45*162)
for (i in c(1:45)){
j=i*162-81
pvalexp.labels[j]=rownames(var)[i]
} #makes list of empyt labels that w
p<-ggplot(pvalall,aes(x = 1:nrow(pvalall), y = -log10(pvalall[,1])))+
geom_point(aes(color = Domain,size=5),
alpha = 0.7, size=1)
p+ylab(expression(atop(" -log10(P-Values)")))+
ylim(0,20)+
xlab(element_blank())+
theme(legend.title=element_blank())+
scale_x_continuous( breaks=c(1:45)*162-81, labels = rownames(var))+
theme_classic()+
theme(axis.title.x = element_blank())+
theme(axis.ticks.x = element_blank())+
theme(axis.title.y = element_text(size = 25))+
theme(text = element_text(size=25))+
theme(legend.title=element_blank())+
theme(legend.position=c(0.8,0.7))+
geom_abline(slope=0,intercept=-log10(c(var)[astsa::FDR(c(var))]),linetype = "dashed")+
geom_abline(slope=0,intercept=5.2,linetype = "dashed")+
ggtitle(maintitle)+
theme(plot.title = element_text(hjust = 0.5))+
theme(
legend.box.background = element_rect(),
legend.box.margin = margin(6, 6, 6, 6))+
theme_update(axis.text.x = element_text(angle = 35, size = 6.5, vjust = 1, hjust=1, color = "black")) +
annotate("text", label = expression(paste("FDR P-value","=0.05")),size=5, x=1000,y=-log10(c(var)[astsa::FDR(c(var))])-0.5, color="black",parse=TRUE)+
annotate("text", label = expression(paste("Bonferroni P-value","=0.05")),size=5, x=1200,y=5.7, color="black",parse=TRUE)
}#end of plotting
You can insert a line
scale_y_continuous(expand = c(0, 0)) +
in your plot command chain.
I am trying to plot a 2y-axes plot; on the left, the actual values, and on the right, the % values. In addition to this, I need to apply coord_trans on the left y-axis for a better visualization of small values. However, when I do it, the labels on the right do not show up.
Here the data (example)
Here the code
DAXIS <- ggplot(x1, aes(hour, value_T, colour=season, linetype = variable)) +
geom_line(size = 1) +
scale_linetype_manual(c("var"), values=c("solid", "dashed", "dotted"))+ # here to change one name
geom_point(aes(shape = season), size = 1)+
labs(x = "hour", y = "T") +
scale_x_continuous(breaks = c(0, 6, 12, 18, 23), labels= c(0, 6, 12, 18, 24))+
scale_y_continuous("T",
sec.axis = sec_axis(~./2.341598, name = " [%] ",
breaks=c(0.2135294, 0.4270588, 0.6405882, 0.8541176,1),
labels = function(b) { paste0(round(b * 100, 0), "%")}))+
#coord_trans(y = "log10", breaks=c(0.5,1,1.5,1.903738), labels = c(0.5,1,1.5,1.9))+ # attemp 1
#coord_trans(y = "log10")+ # attemp 2
scale_color_aaas()+
theme_bw()+
theme(legend.direction = "horizontal", legend.position = "bottom", legend.key = element_blank(),
legend.background = element_rect(fill = "white", colour = "gray30")) +
theme(legend.position="bottom",
text=element_text(size=18),
axis.text.x = element_text(size=15),
axis.text.y = element_text(size=15))
DAXIS
Here the output without coord_trans
Here the output with coord_trans
Any help is very much appreciated
I am using R and ggplot2 to do some plots for publishing purposes. I have come across this plot and I would like to replicate it using ggplot2. However, I have never seen a plot like this made using ggplot2.
Can it be done with ggplot2? What about the text below the bars? I guess these will have to be hard coded in the ggplot2 codes. And how do you align those text?
This gets fairly close:
# Generate sample data (I'm too lazy to type out the full labels)
df <- data.frame(
perc = c(60, 36, 44, 41, 42, 57, 34, 52),
type = rep(c("blue", "green"), 4),
label = rep(c(
"Individual reports created as needed",
"Regular reports on single topics",
"Analytics using data integrated from multiple systems",
"Business unit-specific dashboards and visuals"), each = 2))
library(ggplot2)
ggplot(df, aes(1, perc, fill = type)) +
geom_col(position = "dodge2") +
scale_fill_manual(values = c("turquoise4", "forestgreen"), guide = FALSE) +
facet_wrap(~ label, ncol = 1, strip.position = "bottom") +
geom_text(
aes(y = 1, label = sprintf("%i%%", perc)),
colour = "white",
position = position_dodge(width = .9),
hjust = 0,
fontface = "bold") +
coord_flip(expand = F) +
theme_minimal() +
theme(
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
strip.text = element_text(angle = 0, hjust = 0, face = "bold"))
A few explanations:
We use dodged bars and matching dodged labels with position = "dodge2" (note that this requires ggplot_ggplot2_3.0.0, otherwise use position = position_dodge(width = 1.0)) and position = position_dodge(width = 0.9), respectively.
We use facet_wrap and force a one-column layout; strip labels are moved to the bottom.
We rotate the entire plot with coord_flip(expand = F), where expand = F ensures that left aligned (hjust = 0) facet strip texts align with 0.
Finally we tweak the theme to increase the overall aesthetic similarity.
You can try using the data from the other answer. Differences are: we use scales::percent to draw percents. We use ggpubr::theme_transparent() theme to tweak as less as possible.
df$perc <- c(.60, .36, .44, .41, .42, .57, .34, .52)
ggplot(df, aes(label, perc, label=scales::percent(round(perc,2)),fill= factor(type))) +
geom_col(position = position_dodge(0.9), show.legend = F) +
geom_text(aes(y=0), position = position_dodge(0.9), size=5, hjust=-0.1, color="white", fontface="bold") +
scale_y_continuous("",labels = scales::percent) +
coord_flip(expand = F) +
facet_wrap(~label,scales = "free", strip.position = "bottom", ncol = 1) +
ggpubr::theme_transparent() +
xlab("") +
theme(strip.background = element_blank(),
strip.text = element_text(size = 12, face = "bold",hjust=0))
Maybe using facet wrap and adjusting the style?
dat <- data.frame(perc = c(60, 20, 90, 30), col = rep(c("gr1", "gr2"), 2),
text = c(rep("text1", 2), rep("text2", 2)))
ggplot(dat, aes(y = perc, x = col, fill = col)) +
geom_bar(stat = "identity", position = "dodge") +
coord_flip() +
facet_wrap(~text, strip.position = "bottom", ncol = 1)
I have been trying to shift my legend title across to be centered over the legend contents using the guide function. I've been trying to use the following code:
guides(colour=guide_legend(title.hjust = 20))
I thought of trying to make a reproducable example, but I think the reason it's not working has something to do with the above line not matching the rest of my code specifically. So here is the rest of the code I'm using in my plot:
NH4.cum <- ggplot(data=NH4_by_Date, aes(x=date, y=avg.NH4, group = CO2, colour=CO2)) +
geom_line(aes(linetype=CO2), size=1) + #line options
geom_point(size=3) + #point symbol sizes
#scale_shape_manual(values = c(1, 16)) + #manually choose symbols
theme_bw()+
theme(axis.text.x=element_text(colour="white"), #change x axis labels to white.
axis.title=element_text(size=12),
axis.title.x = element_text(color="white"), #Change x axis label colour to white
panel.border = element_blank(), #remove box boarder
axis.line.x = element_line(color="black", size = 0.5), #add x axis line
axis.line.y = element_line(color="black", size = 0.5), #add y axis line
legend.key = element_blank(), #remove grey box from around legend
legend.position = c(0.9, 0.6))+ #change legend position
geom_vline(xintercept=c(1.4,7.5), linetype="dotted", color="black")+ #put in dotted lines for season boundaries
scale_color_manual(values = c("#FF6600", "green4", "#0099FF"),
name=expression(CO[2]~concentration~(ppm))) + #manually define line colour
scale_linetype_manual(guide="none", values=c("solid", "solid", "solid")) + #manually define line types
scale_shape_manual(values = c(16, 16, 16)) + #manually choose symbols
guides(colour=guide_legend(title.hjust = 20))+
scale_y_continuous(expand = c(0, 0), limits = c(0,2200), breaks=seq(0,2200,200))+ #change x axis to intercept y axis at 0
xlab("Date")+
ylab(expression(Membrane~available~NH[4]^{" +"}~-N~(~mu~g~resin^{-1}~14~day^{-1})))+
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())+
geom_errorbar(aes(ymin = avg.NH4 - se.NH4, #set y error bars
ymax = avg.NH4 + se.NH4),
width=0.1)
I have tried doing the following instead with no luck:
guides(fill=guide_legend(title.hjust=20)
I have also adjusted the hjust value from values between -2 to 20 just to see if that made a difference but it didn't.
I'll try to attach a picture of the graph so far so you can see what I'm talking about.
I've looked through all the questions I can on stack overflow and to the best of my knowledge this is not a duplicate as it's specific to a coding error of my own somewhere.
Thank-you in advance!!
The obvious approach e.g.
theme(legend.title = element_text(hjust = .5))
didn't work for me. I wonder if it is related to this open issue in ggplot2. In any case, one manual approach would be to remove the legend title, and position a new one manually:
ggplot(mtcars, aes(x = wt, y = mpg, colour = factor(cyl))) +
geom_point() +
stat_smooth(se = FALSE) +
theme_bw() +
theme(legend.position = c(.85, .6),
legend.title = element_blank(),
legend.background = element_rect(fill = alpha("white", 0)),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank()) +
annotate("text", x = 5, y = 27, size = 3,
label = "CO[2]~concentration~(ppm)", parse = TRUE)
Output:
Using ggplot, I would like represent a graph tile with panel, but with same height tile for each panel.
I have this graph :
dataSta <- list(sites=rep(paste("S", 1:31),each=12), month=rep(1:12,31), value=round(runif(31*12, min=0, max=3000)), panel=c(rep("Group 1",16*12),rep("Group 2", 12*12), rep("Group 3", 3*12)))
library(ggplot2)
library(grid)
base_size <- 9
windows()
ggplot(data.frame(dataSta), aes(factor(month), sites)) +
geom_tile(aes(fill = value), colour = "black")+
facet_wrap(~panel, scale="free_y", nrow=3)+
theme_grey(base_size = base_size) +
labs(x = "",y = "") +
scale_x_discrete(expand = c(0, 0)) +
scale_y_discrete(expand = c(0, 0)) +
theme(legend.title = element_blank(),
axis.ticks = element_blank(),
axis.text.x = element_text(size = base_size *0.8, hjust = 0),
panel.margin = unit(0,"lines"),
strip.text = element_text(colour="red3", size=10, face=2))
But height of tiles is different between panel. I try to use facet_grid :
windows()
ggplot(data.frame(dataSta), aes(factor(month), sites)) +
geom_tile(aes(fill = value), colour = "black")+
facet_grid(panel~., scales="free_y", space="free")+
theme_grey(base_size = base_size) +
labs(x = "",y = "") +
scale_x_discrete(expand = c(0, 0)) +
scale_y_discrete(expand = c(0, 0)) +
theme(legend.title = element_blank(),
axis.ticks = element_blank(),
axis.text.x = element_text(size = base_size *0.8, hjust = 0),
panel.margin = unit(0,"lines"),
strip.text = element_text(colour="red3", size=10, face=2))
The problem with height of tiles is resolved, but labels of panel (Group 1 ... Group 3) are not on top of panel. Is it possible to change position of panel labels with facet_grid ? or combine facet_grid and facet_wrap ?
Thanks for your help, and sorry for my English !
You can look at what ggplot contains before plotting, and rescale the panels accordingly.
g <- ggplot_build(p)
## find out how many y-breaks are in each panel
## to infer the number of tiles
vtiles <- sapply(lapply(g$panel$ranges, "[[", "y.major"), length)
## convert the plot to a gtable object
gt <- ggplot_gtable(g)
## find out which items in the layout correspond to the panels
## we refer to the "t" (top) index of the layout
panels <- gt$layout$t[grepl("panel", gt$layout$name)]
## replace the default panel heights (1null) with relative sizes
## null units scale relative to each other, so we scale with the number of tiles
gt$heights[panels] <-lapply(vtiles, unit, "null")
## draw on a clean slate
library(grid)
grid.newpage()
grid.draw(gt)
It took me some time to find easier solution which is actually part of the facet_grid where you can set the space = "free_y". More info at recent question.
The ggforce package has a neat little function for this called facet_col. It requires no messing around with the grid package!
All you have to do is replace the call to facet_grid with the appropriate facet_col alternative:
library(ggplot2)
library(ggforce)
dataSta <- list(sites=rep(paste("S", 1:31),each=12),
month=rep(1:12,31), value=round(runif(31*12, min=0, max=3000)),
panel=c(rep("Group 1",16*12),rep("Group 2", 12*12), rep("Group 3", 3*12)))
base_size <- 9
ggplot(data.frame(dataSta), aes(factor(month), sites)) +
geom_tile(aes(fill = value), colour = "black") +
# Here's the line to alter:
facet_col(vars(panel), , scales = "free_y", space = "free") +
theme_grey(base_size = base_size) +
labs(x = "",y = "") +
scale_x_discrete(expand = c(0, 0)) +
scale_y_discrete(expand = c(0, 0)) +
theme(legend.title = element_blank(),
axis.ticks = element_blank(),
axis.text.x = element_text(size = base_size *0.8, hjust = 0),
panel.spacing = unit(0,"lines"),
strip.text = element_text(colour="red3", size=10, face=2))