How to Add Annotations Below the X Axis in Ggplot2

How can I add annotations below the x axis in ggplot2?

With ggplot2 version 3.0.0, you won't need gtable to turn clipping off in Stibu's answer. Use coord_cartesian() to achieve the same thing:

library(gridExtra)
df1 %>% ggplot(aes(x , y )) + geom_bar(stat = "identity")+
scale_y_continuous(labels = percent)+
theme(plot.margin = unit(c(1,1,2,1), "lines")) +
annotation_custom(text_high,xmin=1,xmax=1,ymin=-0.07,ymax=-0.07) +
annotation_custom(text_low,xmin=5,xmax=5,ymin=-0.07,ymax=-0.07)+
coord_cartesian(ylim=c(0,0.35), clip="off")

Annotate below a ggplot2 graph

In my answer, I have changed a couple things:
1 - I changed the name of your data to "df", as "data" can cause confusion between objects and arguments.
2 - I removed the extra panel space around the main data plot, so that the annotation wasn't so far away.

require(ggplot2)
require(grid)
require(gridExtra)

# make the data
df <- data.frame(y = -log10(runif(100)), x = 1:100)

p <- ggplot(data=df, aes(x, y)) + geom_point()

# remove this line of code:
# p <- p + theme(plot.margin=unit(c(1, 1, 5, 1), "lines"))

# set up the plot theme for the annotation
blank_axes_and_thin_margin <- theme(axis.text = element_text(color="white"),
axis.title = element_text(color="white"),
axis.ticks = element_blank(),
panel.grid = element_blank(),
panel.border = element_blank(),
plot.margin=unit(c(0, 2, 0,2),"mm"))

# define the position of the arrow (you would change this part)
arrow_start <- min(df$x)
arrow_end <- mean(c(min(df$x), max(df$x)))
arrow_height <- 1

# here's the rectangle with the arrow
t2 <- ggplot(df, aes(x,y))+
theme_bw()+
geom_rect(aes(xmin=min(x), xmax = max(x)),
ymin=0, ymax=4,fill="gray50")+
coord_cartesian(ylim=c(0,4))+
annotate(geom="text", label="Gene1",
x=20, y=2, size=6, color="black")+
geom_segment(x=arrow_start, xend=arrow_end,
y=arrow_height, yend=arrow_height,
color="black", arrow=arrow(ends="both"))+
blank_axes_and_thin_margin
t2

# arrange the graphic objects here
# I use arrangeGrob because it allows you to use ggsave(), unlike grid.arrange
plot_both <- arrangeGrob(p, t2, nrow=2, heights=unit(c(0.75,0.25), "null"))
plot_both

# ta-da !

Sample Image

ggplot2 annotate on y-axis (outside of plot)

Set the breaks and labels accordingly. Try this:

library(ggplot2)

set.seed(57)
discharge <- data.frame(date = seq(as.Date("2011-01-01"), as.Date("2011-12-31"), by="days"),
discharge = rexp(365))

ggplot(discharge) +
geom_line(aes(x = date, y = discharge)) +
geom_hline(yintercept = 5.5, linetype= "dashed", color = "red") +
scale_y_continuous(breaks = c(0, 2, 4, 5.5, 6),
labels = c(0, 2, 4, "High", 6))

Sample Image

Created on 2020-03-08 by the reprex package (v0.3.0)

Secondary x-axis labels for sample size with ggplot2 on R

I have a solution that might help. I was unable to grab the data you shared, I created my own dummy dataset as follows:

set.seed(12345)
library(lubridate)

df <- data.frame(
dates=as.Date('2020-03-01')+days(0:9),
y_vals=rnorm(10, 50,7),
n=100
)

First, the basic plot:

library(scales)
library(ggrepel)
p.basic <- ggplot(df, aes(dates, y_vals)) +
geom_line() +
geom_point(size=2.5, shape=15) +
geom_text_repel(
aes(label=paste0(round(y_vals, 1), '%')),
size=3, direction='y', force=7) +
ylim(0,100) +
scale_x_date(breaks=date_breaks('day'), labels=date_format('%b %d')) +
theme_bw()

Sample Image

Note that my code is a bit different than your own. Text labels are pushed away via the ggrepel package. I'm also using some functions from scales to fix and set formatting of the date axis (note also lubridate is the package used to create the dates in the dummy dataset above). Otherwise, pretty standard ggplot stuff there.

For the text outside the axis, the best way to do this is through a custom annotation, where you have to setup the grob. The approach here is as follows:

  • Move the axis "down" to allow room for the extra text. We do that via setting a margin on top of the axis title.

  • Turn off clipping via coord_cartesian(clip='off'). This is needed in order to see the annotations outside of the plot by allowing things to be drawn outside the plot area.

  • Loop through the values of df$n, to create a separate annotation_custom object added to the plot via a for loop.

Here's the code:

p <- p.basic +
theme(axis.title.x = element_text(margin=margin(50,0,0,0))) +
coord_cartesian(clip='off')

for (i in 1:length(df$n)) {
p <- p + annotation_custom(
textGrob(
label=paste0('n=',df$n[i]), rot=90, gp=gpar(fontsize=9)),
xmin=df$dates[i], xmax=df$dates[i], ymin=-25, ymax=-15
)
}
p

Sample Image

Advanced Options for more Fun

Two more things to add: Annotations (like callouts for specific points + text), and the lines below the plot in between the axis label stuff.

For lines below the axis: You can add breaks= to other axes fairly easily via scale_... and the breaks= parameter; however, for a date axis, it's... complicated. This is why we will just add lines using the same method as above for the text below the axis. The idea here is to break the axis into sub.div segments in the code below, which is based on how many discrete values are in your x axis. I could do this in-line a few times... but it's fun to create the variable first:

sub.div <- 1/length(df$n)

Then, I use that to create the lines by annotating individually the lines along the step sub.div*i using a for loop again:

for (i in 1:(length(df$n)-1)) {
p <- p + annotation_custom(
linesGrob(
x=unit(c(sub.div*i,sub.div*i), 'npc'),
y=unit(c(0,-0.2), 'npc') # length of the line below axis
)
)
}

Sample Image

I realize I don't have the lines on the ends here, but you can probably see how it would be easy to add that by modifying the method above.

Annotations (with arrows, why not?): There are lots of ways to do annotations. Some are covered here using the annotate() function. As well as here. You can use annotate() if you wish, but in this example, I'm just going to use geom_label for the text labels and geom_curve to make some curvy arrows.

You can manually pass individual aes() values through the call to both functions for each annotation. For example, geom_text(aes(x=as.Date('2020-03-01'), y=55,..., but if you have a few in your dataset, it would be advisable to set the annotations based on information within the dataframe itself. I'll do that here first, where we will label two of the points:

df$notes <- c('','','','Wow!','','','OMG!!!','','','')

You can use the value of df$notes to indicate which of the points are getting labeled, and also take advantage of the mapping of x and y values within the same dataset.

Then you just need to add the two geoms to your plot, modifying as you wish to fit your own aesthetics.

p <- p + geom_curve(
data=df[which(df$notes!=''),],
mapping=aes(x=dates+0.5, xend=dates, y=y_vals+20, yend=y_vals+2),
color='red', curvature = 0.5,
arrow=arrow(length=unit(5,'pt'))
) +
geom_label(
data=df[which(df$notes!=''),],
aes(y=y_vals+20, label=notes),
size=4, color='red', hjust=0
)

Sample Image

Final thing: Horizontal Lines One final thing that I noticed in your code before, but forgot to point out is that to make your horizontal lines, just use geom_hline. It's much easier. Also, you can do it in two calls to geom_hline pretty easily (and even in just one call if you care to pass a dataframe to the function):

p <- p + geom_hline(yintercept = 50, size=2, color='gray30') +
geom_hline(yintercept = c(25,75), linetype=2, color='gray30')

Just note that it's advisable to add these two geom_hline calls before geom_line or geom_point in the original p.basic plot so they are behind everything else.

Sample Image

Add boxes with descriptive annotations to y-axis in ggplot2

One approach to achieve this is by using patchwork. You can set up the annotations of the y-axis as a second ggplot and glue it to your main plot using patchwork. Try this:

library(ggplot2)
library(patchwork)
library(dplyr)

p1 <- tibble(x = 1:10, y = 1:10) %>%
ggplot(aes(x, y)) +
geom_point() +
scale_y_reverse(breaks = seq(1, 10)) +
labs(y = NULL)

p2 <- tibble(ymin = c(0, 4), ymax = c(4, 10), fill = c("bad", "good")) %>%
ggplot() +
geom_rect(aes(xmin = 0, xmax = 1, ymin = ymin, ymax = ymax, fill = fill)) +
geom_text(aes(x = .5, y = (ymin + ymax) / 2, label = fill), angle = 90) +
scale_y_reverse(breaks = seq(1, 10), expand = expansion(mult = c(0, 0))) +
scale_x_continuous(breaks = c(0), expand = expansion(mult = c(0, 0))) +
guides(fill = FALSE) +
theme_void()

p2 + p1 + plot_layout(widths = c(1, 9))

Sample Image

Created on 2020-05-28 by the reprex package (v0.3.0)

How to add a line under ggplot axis text

You can make annotations outside the plot area by using coord_cartesian(xlim, ylim, clip="off") and then using annotate() with the appropriate geom. Depending on your aesthetic for grouping, you can put lines at the base of the plot area or below the axis labels.

library(ggplot2)

df <- data.frame(x=seq(1,10), y=seq(1,10))

ggplot(df, aes(x,y)) +
geom_point() +
coord_cartesian(xlim=c(0,10), ylim=c(0,10), clip="off") +
annotate("segment", x = 2, xend = 4, y = -1, yend = -1) +
annotate("segment", x = 5, xend = 7, y = -0.5, yend = -0.5)

Sample Image

How to customize x-axis with annotation_custom in ggplot2

Your ymin and ymax are outside the range of the y-axis. It should be in the range where you want to place the new labels.

Try this

#create a basic plot
p <- ggplot(mtcars, aes(mpg, wt)) +
facet_grid(.~cyl) +
geom_point() + theme(axis.title.x = element_text(margin=margin(50,0,0,0)), axis.text.x = element_blank()) +
coord_cartesian(clip = "off")

#Add annotations
for (i in 1:length(unique(dfwow$mpg_grob))){
p <- p + annotation_custom(
textGrob(label = paste0('n=',dfwow$mpg_grob[i]),
rot = 90,
gp = gpar(fontsize = 8)),
xmin = dfwow$mpg_axis[i],
xmax = dfwow$mpg_axis[i],
ymin = .8,
ymax = 1.5
)
}
p

output

Add annotation to axis text for ggcorrplot

The exact look you are going for is not achievable directly within ggplot. You can do it by adding shapes manually using grid, but I note that you feel this is not really an option.

One logically equivalent and similar look could be achieved with facets, though that requires fiddling with the output of ggcorrplot:

p <- ggcorrplot::ggcorrplot(cor.vals)

p$data$facets_y <- factor(rep(labels.samples, length = nrow(p$data)), c("normal", "drug"))
p$data$facets_x <- rep(labels.samples, each = length(labels.samples))
p$coordinates <- coord_cartesian()

p + facet_grid(facets_x~facets_y, scales = "free", switch = "both") +
theme(panel.spacing = unit(-0.02, "npc"),
axis.ticks.y.left = element_blank(),
strip.background = element_rect(color = c("black")))

Sample Image



Related Topics



Leave a reply



Submit