This question already has answers here:
Changing facet label to math formula in ggplot2
(5 answers)
Closed 9 years ago.
I have a dataset from which I would like to plot small multiples, specifically in a 2-by-2 array, like this:
mydf <- data.frame(letter = factor(rep(c("A", "B", "C", "D"), each = 20)), x = rnorm(80), y = rnorm(80))
ggplot(mydf, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point() + facet_wrap(~ letter, ncol = 2)
However, I want each facet label to include an expression, such as
expression(paste("A or ", alpha))
I can make this happen using facet_grid() via
f_names <- list('A' = expression(paste("A or ", alpha)), 'B' = expression(paste("B or ", beta)), 'C' = expression(paste("C or ", gamma)), 'D' = expression(paste("D or ", delta)))
f_labeller <- function(variable, value){return(f_names[value])}
ggplot(mydf, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point() + facet_grid(~ letter, labeller = f_labeller)
But then I lose the 2-by-2 array. How can I rename the facet_wrap() facet labels with an expression? Or, how can I solve this by recreating the 2-by-2 array using facet_grid(), but only faceting by a single variable?
(This question builds off of the parenthetical note in #baptiste's answer to this previous question.)
Thanks!
In order to do what I asked, first load this labeller function from #Roland first appearing here:
facet_wrap_labeller <- function(gg.plot,labels=NULL) {
#works with R 3.0.1 and ggplot2 0.9.3.1
require(gridExtra)
g <- ggplotGrob(gg.plot)
gg <- g$grobs
strips <- grep("strip_t", names(gg))
for(ii in seq_along(labels)) {
modgrob <- getGrob(gg[[strips[ii]]], "strip.text",
grep=TRUE, global=TRUE)
gg[[strips[ii]]]$children[[modgrob$name]] <- editGrob(modgrob,label=labels[ii])
}
g$grobs <- gg
class(g) = c("arrange", "ggplot",class(g))
g
}
Then save the original ggplot() object:
myplot <- ggplot(mydf, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point() + facet_wrap(~ letter, ncol = 2)
Then call facet_wrap_labeller() and feed the expression labels as an argument:
facet_wrap_labeller(myplot, labels = c(expression(paste("A or ", alpha)), expression(beta), expression(gamma), expression(delta)))
The expressions should now appear as the facet_wrap() labels.
Related
df <- data.frame(y = rt(26, df = 5), name = letters)
p <- ggplot(df, aes(sample = y))
p + stat_qq() + stat_qq_line()
The above produced the plot as expected.
But now I need labels at each point, so:
df <- data.frame(y = rt(26, df = 5), name = letters)
p <- ggplot(df, aes(sample = y))
p + stat_qq() + stat_qq_line() + geom_text(label = letters)
But it complains that geom_text needs x and y aes.
how do I fix it?
I found out how to compute the y.
But don't know how to compute the x.
You can use ggplot_build() to get the coordinates of points in your plot. In your case these are found in data[[1]].
The default labels appear right on top of the points. Spacing is adjusted using the variable offset... seems to look good.
library(ggplot2)
df <- data.frame(y = rt(26, df = 5), name = letters)
myplot <- ggplot(df, aes(sample = y)) +
stat_qq() +
stat_qq_line()
x.pnts <- ggplot_build(myplot)$data[[1]]$x
y.pnts <- ggplot_build(myplot)$data[[1]]$y
offset <- (max(y.pnts) - min(y.pnts)) / 20
myplot +
geom_text(label = df$name,
x = x.pnts,
y = y.pnts + offset)
(x-posted to community.rstudio.com)
I'm wondering if it's possible to change the axis text in ggplot2 programatically or if there is some native way to do this in ggplot2. In this reprex, the idea is that I want to bold the axis text of a variable y that has an absolute value of x over 1.5. I can add it in manually via theme(), and that works fine:
library(ggplot2)
library(dplyr)
library(forcats)
set.seed(2939)
df <- data.frame(x = rnorm(15), y = paste0("y", 1:15), group = rep(1:3, 5))
df <- mutate(df, big_number = abs(x) > 1.5, face = ifelse(big_number, "bold",
"plain"))
p <- ggplot(df, aes(x = x, y = fct_inorder(y), col = big_number)) + geom_point() +
theme(axis.text.y = element_text(face = df$face))
p
Plot 1 with no facets
But if I facet it by group, y gets reordered and ggplot2 has no idea how face is connected to df and thus y, so it just bolds in the same order as the first plot.
p + facet_grid(group ~ .)
Plot 2 with facets
And it's worse if I use a different scale for each.
p + facet_grid(group ~ ., scales = "free")
Plot 3 with facets and different scales
What do you think? Is there a general way to handle this that would work consistently here?
Idea: Don't change theme, change y-axis labels. Create a call for every y with if/else condition and parse it with parse.
Not the most elegant solution (using for loop), but works (need loop as bquote doesn't work with ifelse). I always get confused when trying to work with multiple expressions (more on that here).
Code:
# Create data
library(tidyverse)
set.seed(2939)
df <- data.frame(x = rnorm(15), y = paste0("y", 1:15), group = rep(1:3, 5)) %>%
mutate(yF = fct_inorder(y),
big_number = abs(x) > 1.5)
# Expressions for y-axis
# ifelse doesn't work
# ifelse(df$big_number, bquote(bold(1)), bquote(plain(2)))
yExp <- c() # Ignore terrible way of concatenating
for(i in 1:nrow(df)) {
if (df$big_number[i]) {
yExp <- c(yExp, bquote(bold(.(as.character(df$yF[i])))))
} else {
yExp <- c(yExp, bquote(plain(.(as.character(df$yF[i])))))
}
}
# Plot with facets
ggplot(df, aes(x, yF, col = big_number)) +
geom_point() +
scale_y_discrete(breaks = levels(df$yF),
labels = parse(text = yExp)) +
facet_grid(group ~ ., scales = "free")
Result:
Inspired by #PoGibas, I also used a function in scale_y_discrete(), which works, too.
bold_labels <- function(breaks) {
big_nums <- filter(df, y %in% breaks) %>%
pull(big_number)
labels <- purrr::map2(
breaks, big_nums,
~ if (.y) bquote(bold(.(.x))) else bquote(plain(.(.x)))
)
parse(text = labels)
}
ggplot(df, aes(x, fct_inorder(y), col = big_number)) +
geom_point() +
scale_y_discrete(labels = bold_labels) +
facet_grid(group ~ ., scales = "free")
This question already has answers here:
Storing ggplot objects in a list from within loop in R
(4 answers)
Closed 5 years ago.
I have really strange problem... I'm trying to create plots in a loop and put them to the list and after that drew them all on one page. when I do it:
for (i in 1:ncol(df)){
plot[[i]] <- ggplot(df, aes(x = df[,i], y=(..count..)/sum(..count..))) +
geom_bar(fill="#003366") +
labs(title = dfcolnames[i], x = "Variable Values", y = "Frequency")
}
return(multiplot(plotlist=plot, cols = 2))
I get 3 this same plots, but when I do it without for loop:
plot[[1]] <- ggplot(df, aes(x = df[,1], y=(..count..)/sum(..count..))) + geom_bar(fill="#003366") + labs(title = dfcolnames[1], x = "Variable Values", y = "Frequency")
plot[[2]] <- ggplot(df, aes(x = df[,2], y=(..count..)/sum(..count..))) + geom_bar(fill="#003366") + labs(title = dfcolnames[2], x = "Variable Values", y = "Frequency")
plot[[3]] <- ggplot(df, aes(x = df[,3], y=(..count..)/sum(..count..))) + geom_bar(fill="#003366") + labs(title = dfcolnames[3], x = "Variable Values", y = "Frequency")
return(multiplot(plotlist=plot, cols = 2))
I get correct plots (three different). I don't understand what is going on.... Any ideas?
The problem is that aes() performs lazy evaluation. The values you pass to aes() are only resolved when you actually draw the plot. You really should only be passing symbol names to aes(). This is because after the loop ends, i will be fixed at it's last value from the loop and you'll just get the same plot three times.
You could instead use aes_string and loop over the column names
plot <- lapply(names(df), function(colname) {
ggplot(df, aes_string(x = colname, y="(..count..)/sum(..count..)")) +
geom_bar(fill="#003366") +
labs(title = colname, x = "Variable Values", y = "Frequency")
})
Tested with
set.seed(10)
df <- data.frame(a=rpois(100, 5), b=rpois(100, 7), c=rpois(100, 3))
This question already has answers here:
Changing facet label to math formula in ggplot2
(5 answers)
Closed 9 years ago.
I have a dataset from which I would like to plot small multiples, specifically in a 2-by-2 array, like this:
mydf <- data.frame(letter = factor(rep(c("A", "B", "C", "D"), each = 20)), x = rnorm(80), y = rnorm(80))
ggplot(mydf, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point() + facet_wrap(~ letter, ncol = 2)
However, I want each facet label to include an expression, such as
expression(paste("A or ", alpha))
I can make this happen using facet_grid() via
f_names <- list('A' = expression(paste("A or ", alpha)), 'B' = expression(paste("B or ", beta)), 'C' = expression(paste("C or ", gamma)), 'D' = expression(paste("D or ", delta)))
f_labeller <- function(variable, value){return(f_names[value])}
ggplot(mydf, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point() + facet_grid(~ letter, labeller = f_labeller)
But then I lose the 2-by-2 array. How can I rename the facet_wrap() facet labels with an expression? Or, how can I solve this by recreating the 2-by-2 array using facet_grid(), but only faceting by a single variable?
(This question builds off of the parenthetical note in #baptiste's answer to this previous question.)
Thanks!
In order to do what I asked, first load this labeller function from #Roland first appearing here:
facet_wrap_labeller <- function(gg.plot,labels=NULL) {
#works with R 3.0.1 and ggplot2 0.9.3.1
require(gridExtra)
g <- ggplotGrob(gg.plot)
gg <- g$grobs
strips <- grep("strip_t", names(gg))
for(ii in seq_along(labels)) {
modgrob <- getGrob(gg[[strips[ii]]], "strip.text",
grep=TRUE, global=TRUE)
gg[[strips[ii]]]$children[[modgrob$name]] <- editGrob(modgrob,label=labels[ii])
}
g$grobs <- gg
class(g) = c("arrange", "ggplot",class(g))
g
}
Then save the original ggplot() object:
myplot <- ggplot(mydf, aes(x = x, y = y)) + geom_smooth(method = "lm") + geom_point() + facet_wrap(~ letter, ncol = 2)
Then call facet_wrap_labeller() and feed the expression labels as an argument:
facet_wrap_labeller(myplot, labels = c(expression(paste("A or ", alpha)), expression(beta), expression(gamma), expression(delta)))
The expressions should now appear as the facet_wrap() labels.
Can I use subscripts in ggplot2 legends? I see this question on greek letters in legends and elsewhere, but I can't figure out how to adapt it.
I thought that using expression(), which works in axis labels, would do the trick. But my attempt below fails. Thanks!
library(ggplot2)
temp <- data.frame(a = rep(1:4, each = 100), b = rnorm(4 * 100), c = 1 + rnorm(4 * 100))
names(temp)[2:3] <- c("expression(b[1])", "expression(c[1])")
temp.m <- melt(temp, id.vars = "a")
ggplot(temp.m, aes(x = value, linetype = variable)) + geom_density() + facet_wrap(~ a)
The following should work (remove your line with names(temp) <-...):
ggplot(temp.m, aes(x = value, linetype = variable)) +
geom_density() + facet_wrap(~ a) +
scale_linetype_discrete(breaks=levels(temp.m$variable),
labels=c(expression(b[1]), expression(c[1])))
See help(scale_linetype_discrete) for available customization (e.g. legend title via name=).
If you want to incorporate Greek symbols etc. into the major tick labels, use an unevaluated expression.
For a bar graph, i did the following:
library(ggplot2)
data <- data.frame(names=tolower(LETTERS[1:4]),mean_p=runif(4))
p <- ggplot(data,aes(x=names,y=mean_p))
p <- p + geom_bar(colour="black",fill="white")
p <- p + xlab("expressions") + scale_y_continuous(expression(paste("Wacky Data")))
p <- p + scale_x_discrete(labels=c(a=expression(paste(Delta^2)),
b=expression(paste(q^n)),
c=expression(log(z)),
d=expression(paste(omega / (x + 13)^2))))
p