Here is my example:
library(ggplot2)
forecast <- c(2,2,1,2,2,3,2,3,3,3,3)
actual <- c(2,2,1,2,2,3,2,3,2,2,1)
my_df <- data.frame(forecast = forecast, actual = actual)
my_df$seq_order <- as.factor(1:NROW(my_df))
my_df <-gather(my_df, "line_type", "value", -seq_order)
ggplot(data=my_df, aes(x=seq_order, y = value,
colour = line_type, group=line_type))+geom_line()+theme(legend.position="bottom")
Here is how it looks:
I would like to have red line to be on top of blue line everywhere where they coincide. I tried scale_color_manual(values = c("forecast" = "red" ,"actual" = "blue")), but it did not work.
Change the factor level order. Don't forget to change the group too.
See this related thread, why I used scales::hue() etc
library(tidyverse)
forecast <- c(2,2,1,2,2,3,2,3,3,3,3)
actual <- c(2,2,1,2,2,3,2,3,2,2,1)
my_df <- data.frame(forecast = forecast, actual = actual, seq_order = 1:11)
my_df <-gather(my_df, line_type, value, -seq_order) %>% mutate(type = factor(line_type, levels = c('forecast','actual')))
ggplot(data=my_df, aes(x=seq_order, y = value,
colour = type, group = type)) +
geom_line()+
theme(legend.position="bottom") +
scale_color_manual(values = rev(scales::hue_pal()(2)))
Created on 2020-03-24 by the reprex package (v0.3.0)
Related
I have a dataset that I am modeling with a gam. Because there are two continuous varaibles in the gam, I have centred and scaled these variables before adding them to the model. Therefore, when I use the built-in features in gratia to show the results, the x values are not the same as the original scale. I'd like to plot the results using the scale of the original data.
An example:
library(tidyverse)
library(mgcv)
library(gratia)
set.seed(42)
df <- data.frame(
doy = sample.int(90, 300, replace = TRUE),
year = sample(c(1980:2020), size = 300, replace = TRUE),
site = c(rep("A", 150), rep("B", 80), rep("C", 70)),
sex = sample(c("F", "M"), size = 300, replace = TRUE),
mass = rnorm(300, mean = 500, sd = 50)) %>%
mutate(doy.s = scale(doy, center = TRUE, scale = TRUE),
year.s = scale(year, center = TRUE, scale = TRUE),
across(c(sex, site), as.factor))
m1 <- gam(mass ~
s(year.s, site, bs = "fs", by = sex, k = 5) +
s(doy.s, site, bs = "fs", by = sex, k = 5) +
s(sex, bs = "re"),
data = df, method = "REML", family = gaussian)
draw(m1)
How do I re-plot the last two panels in this figure to show the relationship between year and mass with ggplot?
You can't do this with gratia::draw automatically (unless I'm mistaken).* But you can use gratia::smooth_estimates to get a dataframe which you can then do whatever you like with.
To answer your specific question: to re-plot the last two panels of the plot you provided, but with year unscaled, you can do the following
# Get a tibble of smooth estimates from the model
sm <- gratia::smooth_estimates(m1)
# Add a new column for the unscaled year
sm <- sm %>% mutate(year = mean(df$year) + (year.s * sd(df$year)))
# Plot the smooth s(year.s,site) for sex=F with year unscaled
pF <- sm %>% filter(smooth == "s(year.s,site):sexF" ) %>%
ggplot(aes(x = year, y = est, color=site)) +
geom_line() +
theme(legend.position = "none") +
labs(y = "Partial effect", title = "s(year.s,site)", subtitle = "By: sex; F")
# Plot the smooth s(year.s,site) for sex=M with year unscaled
pM <- sm %>% filter(smooth == "s(year.s,site):sexM" ) %>%
ggplot(aes(x = year, y = est, color=site)) +
geom_line() +
theme(legend.position = "none") +
labs(y = "Partial effect", title = "s(year.s,site)", subtitle = "By: sex; M")
library(patchwork) # use `patchwork` just for easy side-by-side plots
pF + pM
to get:
EDIT: If you also want to shift result on the y-axis as #GavinSimpson (who is the author and maintainer of gratia) mentioned, you can do this with add_constant, adding this code before plotting above:
sm <- sm %>%
add_constant(coef(m1)["(Intercept)"]) %>%
transform_fun(inv_link(m1))
[You should also in general untransform the smooth by the inverse of the model's link function. In your case this is just the identity, so it is not necessary, but in general it would be. That's what the second step above is doing.]
In your example, this results in:
*As mentioned in the custom-plotting vignette for gratia, the goal of draw not to be fully customizable, but just to be useful default. See there for recommendations about custom plots.
Let's say I'm creating the grouped barplot by something like this:
data <- data.frame(time = factor(1:3), type = LETTERS[1:4], values = runif(24)*10)
ggplot(data, aes(x = type, y = values, fill = time)) +
stat_summary(fun=mean, geom='bar', width=0.55, size = 1, position=position_dodge(0.75))
Inside each type I want to connect all bar tops (meaning to connect 3 bars for A, 3 bars for B, and so on) with the line.
I'd like to get something like that as a result:
Is there a way to do that ?
Thank you!
I changed the code to another logic that I prefer, that is to prepare the data before using ggplot().
Code
library(dplyr)
library(ggplot2)
data <- data.frame(time = factor(1:3), type = LETTERS[1:4], values = runif(24)*10)
pdata <- data %>% group_by(type,time) %>% summarise(values = mean(values,na.rm = TRUE)) %>% ungroup()
pdata %>%
ggplot(aes(x = type, y = values)) +
geom_col(
mapping = aes(fill = time, group = time),
width = 0.55,
size = 1,
position = position_dodge(0.75)
)+
geom_line(
mapping = aes(group = type),
size = 1,
position = position_dodge2(.75)
)
Output
I've seen some other examples (especially using geom_col() and stat_bin()) to add frequency or count numbers on top of bars. I'm trying to get this to work with geom_histogram() where I have a discrete (string), not continuous, x variable.
library(tidyverse)
d <- cars |>
mutate( discrete_var = factor(speed))
ggplot(d, aes(x = discrete_var)) +
geom_histogram(stat = "count") +
stat_bin(binwidth=1, geom='text', color='white', aes(label=..count..),
position=position_stack(vjust = 0.5)) +
Gives me an error because StatBin requires a continuous x variable. Any quick fix ideas?
The error message gives you the answer: ! StatBin requires a continuous x variable: the x variable is discrete.Perhaps you want stat="count"?
So instead of stat_bin() use stat_count()
And for further reference here is a reproducible example:
library(tidyverse)
d <- cars |>
mutate( discrete_var = factor(speed))
ggplot(data = d,
aes(x = discrete_var)) +
geom_histogram(stat = "count") +
stat_count(binwidth = 1,
geom = 'text',
color = 'white',
aes(label = ..count..),
position = position_stack(vjust = 0.5))
I am new to R and trying to add count labels to my boxplots, so the sample size per boxplot shows in the graph.
This is my code:
bp_east_EC <-total %>% filter(year %in% c(1977, 2020, 2021, 1992),
sampletype == "groundwater",
East == 1,
#EB == 1,
#N59 == 1,
variable %in% c("EC_uS")) %>%
ggplot(.,aes(x = as.character(year), y = value, colour = as.factor(year))) +
theme_ipsum() +
ggtitle("Groundwater EC, eastern Curacao") +
theme(plot.title = element_text(hjust = 0.5, size=14)) +
theme(legend.position = "none") +
labs(x="", y="uS/cm") +
geom_jitter(color="grey", size=0.4, alpha=0.9) +
geom_boxplot() +
stat_summary(fun.y=mean, geom="point", shape=23, size=2) #shows mean
I have googled a lot and tried different things (with annotate, with return functions, mtext, etc), but it keeps giving different errors. I think I am such a beginner I cannot figure out how to integrate such suggestions into my own code.
Does anybody have an idea what the best way would be for me to approach this?
I would create a new variable that contained your sample sizes per group and plot that number with geom_label. I've generated an example of how to add count/sample sizes to a boxplot using the iris dataset since your example isn't fully reproducible.
library(tidyverse)
data(iris)
# boxplot with no label
ggplot(iris, aes(x = Species, y = Sepal.Length, fill = Species)) +
geom_boxplot()
# boxplot with label
iris %>%
group_by(Species) %>%
mutate(count = n()) %>%
mutate(mean = mean(Sepal.Length)) %>%
ggplot(aes(x = Species, y = Sepal.Length, fill = Species)) +
geom_boxplot() +
geom_label(aes(label= count , y = mean + 0.75), # <- change this to move label up and down
size = 4, position = position_dodge(width = 0.75)) +
geom_jitter(alpha = 0.35, aes(color = Species)) +
stat_summary(fun = mean, geom = "point", shape = 23, size = 6)
How can I plot observed data and the results of differents models (lm and lme) in the same plot?
I tried the code below, but it only worked for points. I would like to add the data predicted by the inline models of different colors.
#Data
d <- runif(160,0,100)#data
y <- rnorm(16,1,0.05)*x + rnorm(16,0,0.5)#data
df = data.frame(d,y)
#Models
#linear - 1
m1 = lm(y~d, data = df)
summary(m1)
# linear - 2
m2 = lm(y~d+I(d^2), data = df)
summary(m2)
df$Class10<-with(df,ifelse(d<20,"<20",ifelse(d<30,"20-30",
ifelse(d<40,"30-40",ifelse(d<50,"40-50",ifelse(d<60,"50-60",
ifelse(d<70,"60-70",ifelse(d<80,"70-80",ifelse(d<90,"80-90",
ifelse(d>=90,">90","ERROR"))))))))))
# number of classes
length(unique(df$Class10))
# classes
sort(unique(df$Class10))
# observations by class
table(df$Class10)
plot(table(df$Class10))
# b0
m10 = lme(y~d, random=~1|Class10, method="ML" ,data = df)
# b1
m10 = lme(y~d, random=~-1+d|Class10, method="ML" , data = df)
#
m10 = lme(y~d, random=~d|Class10, method="ML" , data = df,
control = lmeControl(niterEM = 5200, msMaxIter = 5200))
#plot points - It works
plot(df$d, df$y)
points(df$d, predict(m1), col="blue")
points(df$d, predict(m10, level=1), col="red")
#curve
plot(df$d, df$y)
curve(predict(m1,newdata=data.frame(d=x)),lwd=2, add=T)
curve(predict(m10,newdata=data.frame(d=x)),lwd=1, add=T)#error
# line
plot(df$d,df$y)
curve(predict(m1,newdata=data.frame(d=x)),lwd=2, add=T)
lines(df$d, predict(m10, level=1),col="green")#error
Is there any way in ggplot2, for example?
Here is a way! I like using broom and broom.mixed to get a complete tibble with predicted values for each model.
library(tidyverse)
library(lme4)
library(broom)
library(broom.mixed)
df <- ChickWeight
lin <- lm(weight ~ Time,df)
mlm <- lmer(weight ~ Time + (1 | Chick),df)
df <- df %>%
mutate(linpred = broom::augment(lin)[,3] %>% pull(),
mlmpred = broom.mixed::augment(mlm)[,4] %>% pull())
ggplot(df,aes(Time,weight,group = Chick)) +
geom_line(alpha = .2) +
geom_line(aes(y = linpred,color = 'Fixed Linear Effect')) +
geom_line(aes(y = mlmpred,color = 'Random Intercepts'), alpha = .4) +
scale_color_manual(values = c('blue','red')) +
labs(color = '') +
theme_minimal()