Is there a way to flip the facet label using small_multiple from the dotwhisker package to have the facet labels on the left-handside and coefficient estimate on the right-hand side? I've seen the solutions to this when using ggplot and facet_wrap or facet_grid, but those aren't working with small_multiple since it does the faceting without those arguments. For simplicity, I'll be using the Dot-and-Whisker Plot Vignette that uses small_multiple as the example.
code used to generate plot:
# Generate a tidy data frame of regression results from six models
m <- list()
ordered_vars <- c("wt", "cyl", "disp", "hp", "gear", "am")
m[[1]] <- lm(mpg ~ wt, data = mtcars)
m123456_df <- m[[1]] %>%
tidy() %>%
by_2sd(mtcars) %>%
mutate(model = "Model 1")
for (i in 2:6) {
m[[i]] <- update(m[[i-1]], paste(". ~ . +", ordered_vars[i]))
m123456_df <- rbind(m123456_df, m[[i]] %>%
tidy() %>%
by_2sd(mtcars) %>%
mutate(model = paste("Model", i)))
}
# Relabel predictors (they will appear as facet labels)
m123456_df <- m123456_df %>%
relabel_predictors(c("(Intercept)" = "Intercept",
wt = "Weight",
cyl = "Cylinders",
disp = "Displacement",
hp = "Horsepower",
gear = "Gears",
am = "Manual"))
# Generate a 'small multiple' plot
small_multiple(m123456_df) +
theme_bw() + ylab("Coefficient Estimate") +
geom_hline(yintercept = 0, colour = "grey60", linetype = 2) +
ggtitle("Predicting Mileage") +
theme(plot.title = element_text(face = "bold"),
legend.position = "none",
axis.text.x = element_text(angle = 60, hjust = 1))
Ideally, I would have the flipped version of this plot with labels on the left and estimates on the right.
This could be achieved by overwriting facet_grid and the scale_y as you would do in a normal ggplot like so:
facet_grid(term~., switch = "y", scales="free_y")
scale_y_continuous(position = "right")
library(dotwhisker)
library(dplyr)
library(broom)
# Generate a 'small multiple' plot
small_multiple(m123456_df) +
theme_bw() + ylab("Coefficient Estimate") +
geom_hline(yintercept = 0, colour = "grey60", linetype = 2) +
facet_grid(term~., switch = "y", scales="free_y") +
scale_y_continuous(position = "right") +
ggtitle("Predicting Mileage") +
theme(plot.title = element_text(face = "bold"),
legend.position = "none",
axis.text.x = element_text(angle = 60, hjust = 1))
Related
I am trying to use superscript in geom_text. But I am unable to do that. I am using the following code
library(caret)
library(tidyverse)
summ <- iris %>%
group_by(Species) %>%
summarise(R = cor(Sepal.Length, Petal.Length, use="pairwise.complete.obs"),
RMSE = RMSE(Sepal.Length, Petal.Length)) %>%
mutate_if(is.numeric, round, digits=2)
p <- ggplot(data=iris, aes(x = Sepal.Length, y = Petal.Length)) +
geom_point(color="blue",alpha = 1/3) +
facet_wrap(Species ~ ., scales="free") +
geom_smooth(method=lm, fill="black", formula = y ~ x) +
xlab("Sepal Length") +
ylab("Petal Length") + theme_bw() +
theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank())
# Here we create our annotations data frame.
df.annotations <- data.frame()
# R
df.annotations <- rbind(df.annotations,
cbind(as.character(summ$Species),
paste("R", summ$R,
sep = " = ")))
# RMSE
df.annotations <- rbind(df.annotations,
cbind(as.character(summ$Species),
paste("RMSE", summ$RMSE,
sep = " = ")))
# This here is important, especially naming the first column
# Species
colnames(df.annotations) <- c("Species", "label")
vertical_adjustment = ifelse(grepl("\\bR\\b",df.annotations$label), 1.5, 3)
p + geom_text(data = df.annotations, aes(x=-Inf, y=+Inf, label=label),
hjust = -0.1, vjust = vertical_adjustment, size=3.5)
My expected output is
How can I add the unit for RMSE after the value and superscript 2 after R i.e. R^2? You can also see that there is a slight shift in the alignment of RMSE with respect to R. How can I make them into the same line?
This could be achieved like so:
Set parse=TRUE in geom_text
Make use of ?plotmath to add superscripts to your labels
# Here we create our annotations data frame.
df.annotations <- data.frame(
Species = rep(summ$Species, 2),
label = c(
paste0("~R^{2} == ", summ$R),
paste0("~RMSE == ", summ$RMSE, "~m^{3} ~m^{-3}")
)
)
vertical_adjustment = ifelse(grepl("\\bR\\b", df.annotations$label), 1.5, 3)
p + geom_text(data = df.annotations, aes(x=-Inf, y=+Inf, label=label),
hjust = 0, vjust = vertical_adjustment, size=3.5, parse = TRUE)
Another approach is to use the ggtext package, which enables markdown formatting in ggplot text objects. I find this syntax much easier to use than R's plotmath, especially for things like italics and color:
df.annotations <- data.frame(
Species = rep(summ$Species, 2),
label = c(
paste0("R<sup>2</sup> = ", summ$R),
paste0("RMSE = ", summ$RMSE, "m<sup>3</sup> m<sup>-3</sup>")
)
)
vertical_adjustment = ifelse(grepl("\\bR\\b", df.annotations$label), 1.5, 2.5)
p + geom_richtext(data = df.annotations, aes(x=-Inf, y=+Inf, label=label),
hjust = 0, vjust = vertical_adjustment, size=3.5, label.size = 0)
I have an example code below. I have built a figure with ggplot and it is almost there, but I would like to add an additional curve across all facets from y. The final output should look like the image attached. I'm not sure how I would do this.
x <- iris[-1:-3]
bw <- 1
nbin <- 100
y <- head(iris, 50)[2]
ggplot(x, aes(x = Petal.Width)) +
geom_density(aes(y = bw *..count.., fill = Species), size = 1, alpha = 0.4) +
facet_wrap(~Species)+
scale_x_continuous(labels = scales::math_format(10^.x), limits = c(0, 5), expand = c(0,0)) +
scale_y_continuous(expand = c(0,0), limits = c(0, NA)) +
annotation_logticks(sides = "b", short=unit(-1,"mm"), mid=unit(-2,"mm"), long=unit(-3,"mm")) +
coord_cartesian(clip='off') + theme(panel.background = element_blank(),
panel.border = element_rect(colour = "black", fill=NA))
Does this do what you are looking to achieve?
I'm sure there are better ways; basically I've generated three versions of the y data and shuffled the grouping variables to allow ggplot's facet_wrap and fill to manage the appearance.
It would be great if there is way to make one set of data appear in all facets without this repetition.
library(ggplot2)
library(dplyr)
library(tidyr)
x1 <-
x %>%
mutate(var = "Petal width") %>%
rename(val = Petal.Width)
df <-
y %>%
mutate(var = "Sepal width",
spp1 = "setosa",
spp2 = "versicolor",
spp3 = "virginica") %>%
pivot_longer(cols = starts_with("spp"), names_to = "temp", values_to = "Species") %>%
select(-temp) %>%
rename(val = Sepal.Width )%>%
bind_rows(x1) %>%
mutate(g1 = case_when(var == "Sepal width" ~ "all species: sepal width",
TRUE ~ paste0(Species, ": petal width")))
ggplot(df, aes(x = val)) +
geom_density(aes(y = bw *..count.., fill = g1), size = 1, alpha = 0.4) +
facet_wrap(~Species)+
scale_x_continuous(labels = scales::math_format(10^.x), limits = c(0, 5), expand = c(0,0)) +
scale_y_continuous(expand = c(0,0), limits = c(0, NA)) +
annotation_logticks(sides = "b", short=unit(-1,"mm"), mid=unit(-2,"mm"), long=unit(-3,"mm")) +
coord_cartesian(clip='off') + theme(panel.background = element_blank(),
panel.border = element_rect(colour = "black", fill=NA))
Created on 2020-07-01 by the reprex package (v0.3.0)
For some reason I am getting two legends in my dot-whisker plot.
Plot produced by the below code:
The data are available here.
#first importing data
Q2a<-read.table("~/Q2a.txt", header=T)
# Optionally, read in data directly from figshare.
# Q2a <- read.table("https://ndownloader.figshare.com/files/13283882?private_link=ace5b44bc12394a7c46d", header=TRUE)
library(dplyr)
#splitting into female and male
F2female<-Q2a %>%
filter(sex=="F")
F2male<-Q2a %>%
filter(sex=="M")
library(lme4)
#Female models
ab_f2_f_LBS = lmer(LBS ~ ft + grid + (1|byear), data = subset(F2female))
ab_f2_f_surv = glmer.nb(age ~ ft + grid + (1|byear), data = subset(F2female), control=glmerControl(tol=1e-6,optimizer="bobyqa",optCtrl=list(maxfun=1e19)))
#Male models
ab_f2_m_LBS = lmer(LBS ~ ft + grid + (1|byear), data = subset(F2male))
ab_f2_m_surv = glmer.nb(age ~ ft + grid + (1|byear), data = subset(F2male), control=glmerControl(tol=1e-6,optimizer="bobyqa",optCtrl=list(maxfun=1e19)))
I only plot two of the variables (ft2 and gridSU) from each model.
ab_f2_f_LBS <- tidy(ab_f2_f_LBS) %>% filter(!grepl('sd_Observation.Residual', term)) %>% filter(!grepl('byear', group)) %>% mutate(model = "ab_f2_f_LBS")
ab_f2_m_LBS <- tidy(ab_f2_m_LBS) %>% filter(!grepl('sd_Observation.Residual', term)) %>% filter(!grepl('byear', group)) %>% mutate(model = "ab_f2_m_LBS")
ab_f2_f_surv <- tidy(ab_f2_f_surv)%>% filter(!grepl('sd_Observation.Residual', term)) %>% filter(!grepl('byear', group)) %>% mutate(model = "ab_f2_f_surv")
ab_f2_m_surv <- tidy(ab_f2_m_surv) %>% filter(!grepl('sd_Observation.Residual', term)) %>% filter(!grepl('byear', group)) %>% mutate(model = "ab_f2_m_surv")
tidy_mods <- bind_rows(ab_f2_f_LBS, ab_f2_m_LBS, ab_f2_f_surv, ab_f2_m_surv)
I am then ready to make a dot-whisker plot.
#required packages
library(dotwhisker)
library(broom)
dwplot(tidy_mods,
vline = geom_vline(xintercept = 0, colour = "black", linetype = 2),
conf.int=TRUE,
dodge_size=0.2, #space between the CI's
dot_args = list(aes(shape = model), size = 3), #changes shape of points and the size of the points
style="dotwhisker") %>% # plot line at zero _behind_ coefs
relabel_predictors(c(DamDisFate2= "Immigrant mothers",
gridSU = "Grid (SU)")) +
theme_classic() +
xlab("Coefficient estimate (+/- CI)") +
ylab("") +
scale_color_manual(values=c("#000000", "#666666", "#999999", "#CCCCCC"),
labels = c("Daughter LBS", "Son LBS", "Daughter longevity", "Son longevity"),
name = "First generation models, maternity known") +
theme(axis.title=element_text(size=15),
axis.text.x = element_text(size=15),
axis.text.y = element_text(size=15, angle=90, hjust=.5),
legend.position = c(0.7, 0.7),
legend.justification = c(0, 0),
legend.title=element_text(size=15),
legend.text=element_text(size=13),
legend.key = element_rect(size = 0),
legend.key.size = unit(0.5, "cm"))+
guides(colour = guide_legend(override.aes=list(shape=c(16,17,15,3)))) #changes shape of points in legend
I am encountering this problem:
As is obvious from the plot, I have two legends. One that is unmodified and one that is modified.
I can't find any short cut within the theme() function and the dwplot() package doesn't offer any solutions either.
How can I suppress the unmodified legend (bottom one) and only keep my modified legend (top one)?
Assuming this function uses ggplot, try adding shape="none" to your guides():
guides(colour = guide_legend(override.aes=list(shape=c(16,17,15,3))), shape="none")
I am trying to use facet_wrap to plot indvidual plots.
library(lme4)
library(dplyr)
library(tibble)
# Convert to tibble for better printing. Convert factors to strings
sleepstudy <- sleepstudy %>%
as_tibble() %>%
mutate(Subject = as.character(Subject))
xlab <- "Days of sleep deprivation"
ylab <- "Average reaction time (ms)"
ggplot(df_sleep) +
aes(x = Days, y = Reaction) +
stat_smooth(method = "lm", se = FALSE) +
# Put the points on top of lines
geom_point() +
facet_wrap("Subject") +
labs(x = xlab, y = ylab) +
theme(axis.text=element_text(size=0.02),
axis.title=element_text(size=0.02,face="bold"),
plot.title = element_text(size=0.02)) +
theme(strip.text.x = element_text(size = 8),
strip.background = element_rect(fill="lightblue", colour="black",size=0.2)) +
theme(strip.text.x = element_text(margin = margin(0.02, 0, 0.02, 0, "cm")))
What I want to do is to only visualise selected Subject using facet_wrap? At the moment,
it is plotting plots of all the Subject. How do I plot only for say subject 308`` and352`?
Thanks
You just want to filter your data before plotting
library(lme4)
library(dplyr)
library(tibble)
library(ggplot2)
# Convert to tibble for better printing. Convert factors to strings
sleepstudy <- sleepstudy %>%
as_tibble() %>%
mutate(Subject = as.character(Subject))
xlab <- "Days of sleep deprivation"
ylab <- "Average reaction time (ms)"
sleepstudy %>%
filter(Subject %in% c("308", "352")) %>%
ggplot(.) +
aes(x = Days, y = Reaction) +
stat_smooth(method = "lm", se = FALSE) +
# Put the points on top of lines
geom_point() +
facet_wrap("Subject") +
labs(x = xlab, y = ylab) +
theme(axis.text=element_text(size=0.02),
axis.title=element_text(size=0.02,face="bold"),
plot.title = element_text(size=0.02)) +
theme(strip.text.x = element_text(size = 8),
strip.background = element_rect(fill="lightblue", colour="black",size=0.2)) +
theme(strip.text.x = element_text(margin = margin(0.02, 0, 0.02, 0, "cm")))
I perform a regression with reg <- lm(...) and get some coefficents I can access with reg$coefficients.
It's of type Named num and contains all the coefficients with their values.
Named num [1:11] 505.085 -0.251 -0.286 -0.22 -0.801 ...
- attr(*, "names")= chr [1:11] "(Intercept)" "year" "monthDez" "monthFeb" ...
I want to show these on my graph created with ggplot. My current approach was to use the subtitle for this:
labs(subtitle=paste(toString(names(reg$coefficients)), "\n",
paste(reg$coefficients, collapse = " ")))
But it's not aligned correctly (name directly over the value etc.)
Has someone an idea?
My current plot looks like this:
base <- ggplot(deliveries, aes(Date)) +
geom_line(aes(y = SalesVolume, colour = "SalesVolume"))+
ggtitle("Sales Volume By Time") +
xlab("Time") +
ylab("Sales Volume") +
labs(subtitle=paste(toString(names(reg$coefficients)), "\n", paste(reg$coefficients, collapse = " ")))
print(base + scale_x_date(labels = date_format("%b %y"), breaks = date_breaks("2 months")))
In this graph a forecast is displayed, so I want to see the regression coefficients there as well.
Would it work to make two separate plots and arrange them onto a grid?
library(ggplot2)
library(broom)
library(dplyr)
library(tidyr)
data_plot <-
ggplot(data = mtcars,
mapping = aes(x = qsec,
y = mpg,
colour = factor(gear))) +
geom_point()
fit <- lm(mpg ~ qsec + wt + factor(gear),
data = mtcars)
# Make a data frame with the contents of the model.
reg_data <-
tidy(fit) %>%
mutate(y = nrow(.):1 - 1) %>%
gather(estimate, value,
estimate:p.value) %>%
mutate(estimate = factor(estimate,
c("term", "estimate", "std.error",
"statistic", "p.value")))
# Make a plot displaying the table.
reg_plot <-
ggplot(data = reg_data,
mapping = aes(x = estimate,
y = y)) +
geom_text(mapping = aes(label = round(value, 2))) +
scale_y_continuous(breaks = unique(reg_data[["y"]]),
labels = unique(reg_data[["term"]])) +
scale_x_discrete(position = "top") +
xlab("") +
ylab("") +
theme(panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
panel.background = element_blank(),
axis.line = element_blank())
# Arrange the two plots
gridExtra::grid.arrange(data_plot + theme(plot.margin = grid::unit(c(1,1,0,.5), "lines")),
reg_plot + theme(plot.margin = grid::unit(c(0,0,1,0), "lines")),
clip = FALSE,
nrow = 2,
ncol = 1,
heights = grid::unit(c(.70, .5),
c("null", "null")))
In my limited experience with ggplot2, annotate() could be used to add some annotations to a plot created with ggplot(), but I am not sure if the code below works for what you want
reg <- lm(data = mtcars, mpg ~ wt)
pred <- predict(reg)
newdata <- data.frame(mtcars, pred)
par <- summary(reg)$coefficients[,1] # extract model parameters
par.f <- format(par, digits = 2) # set the decimal digits of parameters
ggplot(mtcars, aes(x = wt, y = mpg)) +
geom_point() +
geom_line(data = newdata, aes(x = wt, y = pred)) +
annotate("text", x = c(2, 2.5), y = 18, label = names(reg$coefficients)) +
annotate("text", x = c(2, 2.5), y = 16.5, label = par.f) # make them aligned by set x and y in annotate()
enter image description here