Inserting a Table Under the Legend in a Ggplot2 Histogram

Inserting a table under the legend in a ggplot2 histogram

Dickoa's answer is very neat. Mine gives you more control over the elements.

my_hist <- ggplot(diamonds, aes(clarity, fill=cut)) + geom_bar()

#create inset table
my_table <- tableGrob(head(diamonds)[,1:3], gpar.coretext = gpar(fontsize=8), gpar.coltext=gpar(fontsize=8), gpar.rowtext=gpar(fontsize=8))

#Extract Legend
g_legend <- function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)}

legend <- g_legend(my_hist)

#Create the viewports, push them, draw and go up
grid.newpage()
vp1 <- viewport(width = 0.75, height = 1, x = 0.375, y = .5)
vpleg <- viewport(width = 0.25, height = 0.5, x = 0.85, y = 0.75)
subvp <- viewport(width = 0.3, height = 0.3, x = 0.85, y = 0.25)
print(my_hist + opts(legend.position = "none"), vp = vp1)
upViewport(0)
pushViewport(vpleg)
grid.draw(legend)
#Make the new viewport active and draw
upViewport(0)
pushViewport(subvp)
grid.draw(my_table)

Sample Image

Inserting a table under the legend in a ggplot2

The other solution is correct. I guess you get an error because you don't set the legend variable. So arrangeGrob is called with the R function legend as argument. You should define legend as:

g_legend <- function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
return(legend)
}
legend <- g_legend(p)

I slightly modify the other answer, to better rearrange grobs by setting widths argument:

pp <- arrangeGrob(p + theme(legend.position = "none"), 
widths=c(3/4, 1/4),
arrangeGrob( legend,leg.df.grob), ncol = 2)

Sample Image

Add percentage in the right side of the histogram with legend

You can create a custom legend (actually another ggplot plot) and add both using patchwork and also do some customization to make it good.

library(tidyverse)
library(patchwork)

df <- data.frame(
Age = c(18, 19, 20, 21, 23, 24, 25),
n = c(2500L, 1200L, 4500L, 800L, 120L, 50L, 100L)
)

pc_data <- data.frame(
stringsAsFactors = FALSE,
Age = c("18-19", "20-21", "23-24", "25+"),
success = c(80, 60, 50, 20)
)


p1 <- ggplot(df, aes(x=Age, y=n)) +
geom_bar(stat="identity") +
scale_y_continuous(labels = function(x) format(x, scientific = FALSE)) +
scale_x_continuous(labels = 18:25, breaks = 18:25) +
labs(y = NULL) +
theme_bw() +
theme(
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank()
)

p2 <- pc_data %>%
mutate(
Age = fct_rev(factor(Age)),
label_pos = success - (success/2)
) %>%
ggplot(aes(Age, success)) +
geom_col(fill = colorspace::lighten("gray"), width = 0.7) +
coord_flip() +
labs( x = NULL, y = NULL,
title = "Success rate\nof Age") +
geom_text(aes(Age, label_pos, label = paste0(success, "%")),
size = 4) +
theme_classic() +
theme(
axis.line = element_blank(),
axis.text.y = element_text(size = 9, angle = 90, hjust = 0.5),
axis.ticks = element_blank(),
axis.text.x = element_blank(),
plot.title = element_text(color = colorspace::lighten("black", amount = 0.5))
)

layout <- "
AAAA##
AAAABB
"

p1 + p2 + plot_layout(design = layout, heights = c(1, 30)) +
plot_annotation(
title = "Student Body by Age at ETH in the assesment year"
)


plot_with_custom_legend

Add additional text below the legend (R + ggplot)

This is one possible approach:

library(gridExtra)
library(grid)

p <- ggplot(data = msleep, aes(x = log(bodywt), y = sleep_total)) +
geom_point(aes(color = vore)) +
theme(legend.position="bottom", plot.margin = unit(c(1,1,3,1),"lines")) +
annotation_custom(grob = textGrob("Extra text. Read all about it"),
xmin = 2, xmax = 2, ymin = -4.5, ymax = -4.55)


gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name=="panel"] <- "off"
grid.draw(gt)

Sample Image

How to plot just the legends in ggplot2?

Here are 2 approaches:

Set Up Plot

library(ggplot2) 
library(grid)
library(gridExtra)

my_hist <- ggplot(diamonds, aes(clarity, fill = cut)) +
geom_bar()

Cowplot approach

# Using the cowplot package
legend <- cowplot::get_legend(my_hist)

grid.newpage()
grid.draw(legend)

Sample Image

Home grown approach

Shamelessly stolen from: Inserting a table under the legend in a ggplot2 histogram

## Function to extract legend
g_legend <- function(a.gplot){
tmp <- ggplot_gtable(ggplot_build(a.gplot))
leg <- which(sapply(tmp$grobs, function(x) x$name) == "guide-box")
legend <- tmp$grobs[[leg]]
legend
}

legend <- g_legend(my_hist)

grid.newpage()
grid.draw(legend)

Created on 2018-05-31 by the reprex package (v0.2.0).

Modify Legend using ggplot2 in R

Maybe something like this...

dat = data.frame(x=rnorm(1000))  
ggplot(dat,aes(x=x)) +
geom_histogram(aes(y=..density..,fill="Histogram"),binwidth=0.5) +
stat_function(fun = dnorm, aes(colour= "Density")) +
scale_x_continuous('x', limits = c(-4, 4)) +
opts(title = "Histogram with Overlay") +
scale_fill_manual(name="",value="blue") +
scale_colour_manual(name="",value="red") +
scale_y_continuous('Frequency')+
opts(legend.key=theme_rect(fill="white",colour="white"))+
opts(legend.background = theme_blank())

Note: Since version 0.9.2 opts has been replaced by theme. So for example, the last two lines above would be:

theme(legend.key = element_rect(fill = "white",colour = "white")) + 
theme(legend.background = element_blank())

ggplot Adding manual legend to plot without modifying the dataset

If you want to have a legend then you have to map on aesthetics. Otherwise scale_color/fill_manual will have no effect:

vec <- c(rep(1, 100), rep(2, 100), rep(3, 80), rep(4, 70), rep(5, 60))
tbl <- data.frame(value = vec)

mean_vec <- mean(vec)

cols <- c(
"Frequency" = "grey",
"mean" = "blue"
)

library(ggplot2)

ggplot(tbl) +
aes(x = value) +
geom_histogram(aes(fill = "Frequency"), binwidth = 1) +
geom_vline(aes(color = "mean", xintercept = mean_vec), size = 1) +
theme_minimal() +
scale_color_manual(values = "blue") +
scale_fill_manual(name = "Test", values = "grey")

Sample Image



Related Topics



Leave a reply



Submit