How fill geom_ribbon with different colour in R? - r

I am trying to use different fill for geom_ribbon according to the x-values (For Temp = 0-20 one fill, 20-30.1 another fill and > 30.1 another fill). I am using the following code
library(tidyverse)
bounds2 <- df %>%
mutate(ymax = pmax(Growth.rate, slope),
ymin = pmin(Growth.rate, slope),
x_bins = cut(Temp, breaks = c(0,20,30.1,max(Temp)+5)))
ggplot(df, aes(x = Temp, y = Growth.rate)) +
geom_line(colour = "blue") +
geom_line(aes(y = slope), colour = "red") +
scale_y_continuous(sec.axis = sec_axis(~ .^1, name = "slope")) +
geom_ribbon(data = bounds2, aes(Temp, ymin = ymin, ymax = ymax, fill = x_bins),
alpha = 0.4)
It is returning me following output
As you can see from the output some regions are remaining empty. Now how can I fill those parts in the curve?
Here is the data
df = structure(list(Temp = c(10, 13, 17, 20, 25, 28, 30, 32, 35, 38
), Growth.rate = c(0, 0.02, 0.19, 0.39, 0.79, 0.96, 1, 0.95,
0.65, 0), slope = c(0, 0.02, 0.16, 0.2, 0.39, 0.1, 0.03, -0.04,
-0.29, -0.65)), row.names = c(NA, 10L), class = "data.frame")

Here's a solution that involves interpolating new points at the boundaries between the areas. I used approx to get the values of ymin and ymax at Temp=30.1 and added this to the plotting dataset.
Then, instead of using cut just once as you did I use it twice, once with lower bounds included in each set then once with upper bounds included. Then I reshape the data long, and de-duplicate the rows I don't need.
If you zoom in enough you can see that the boundary is at 30.1 not at 30.
bounds2 <- df %>%
mutate(ymax = pmax(Growth.rate, slope),
ymin = pmin(Growth.rate, slope))
bounds2 <- bounds2 |>
add_case(Temp=30.1,
ymax=approx(bounds2$Temp,bounds2$ymax,xout = 30.1)$y,
ymin=approx(bounds2$Temp,bounds2$ymin,xout = 30.1)$y) |>
mutate(x_bins2 = cut(Temp, breaks = c(0,20,30.1,max(Temp)+5),right=FALSE, labels=c("0-20","20-30.1","30.1-max")),
x_bins = cut(Temp, breaks = c(0,20,30.1,max(Temp)+5), labels=c("0-20","20-30.1","30.1-max"))) |>
tidyr::pivot_longer(cols=c(x_bins2, x_bins), names_to = NULL, values_to = "xb") |>
distinct()
ggplot(df, aes(x = Temp, y = Growth.rate)) +
geom_line(colour = "blue") +
geom_line(aes(y = slope), colour = "red") +
scale_y_continuous(sec.axis = sec_axis(~ .^1, name = "slope")) +
geom_ribbon(data = bounds2, aes(Temp, ymin = ymin, ymax = ymax, fill = xb),
alpha = 0.4)

The idea is here but the code I show can be much improved at the step ### Dupplicate the 2 last x_bins from each category and move them into the next
### Libraries
library(tidyverse)
df <- structure(list(Temp = c(10, 13, 17, 20, 25, 28, 30, 32, 35, 38
), Growth.rate = c(0, 0.02, 0.19, 0.39, 0.79, 0.96, 1, 0.95,
0.65, 0), slope = c(0, 0.02, 0.16, 0.2, 0.39, 0.1, 0.03, -0.04,
-0.29, -0.65)), row.names = c(NA, 10L), class = "data.frame")
### Preprocessing
bounds2 <- df %>%
mutate(ymax = pmax(Growth.rate, slope),
ymin = pmin(Growth.rate, slope),
x_bins = cut(Temp, breaks = c(0, 20, 30.1, max(Temp)+5)))
### Dupplicate the 2 last x_bins from each category and move them into the next category
bounds2 <- rbind(bounds2, bounds2[c(4, 7), ])
bounds2$x_bins[c(11, 12)] <- bounds2[c(5, 8), ]$x_bins
### Plot
ggplot(df, aes(x = Temp, y = Growth.rate)) +
geom_line(colour = "blue") +
geom_line(aes(y = slope), colour = "red") +
scale_y_continuous(sec.axis = sec_axis(~ .^1, name = "slope")) +
geom_ribbon(data = bounds2, aes(Temp, ymin = ymin, ymax = ymax, fill = x_bins),
alpha = 0.4)

Related

How to add a new (custom) variable to a ggplot legend

I've run a number of models with two estimated parameters per model with five groups and two treatments. I'm trying to graph the confidence intervals of these estimates in a large panel plot. Since, I've simulated these data sets I would like to be able to include a dashed line for the "true value" of the parameter which I set at the beginning of the exercise for reference so we can see how well the confidence interval of the model estimates includes the true value. I can do this just fine but I'd like to include another line in the legend that shows "dashed black line" = True Value.
Here's an example of the code. The first set of code works and does not include the dashed black line in the legend.
group = c("group1", "group2", "group3", "group4", "group5")
treatment = c("treatment1", "treatment2")
estimates = c("estim1", "estim2")
parameters = c("param1", "param2")
means = c(0, 0, 5, 0, -5, 0, 0, 7, -5, 10, -5, 0, 0, 0, 0, 0, -5, 0, 0, 10)
UL = c(.5, .5, 5.5, .5, -4.5, 0.5, 0.5, 7.5, -4.5, 10.5, -4.5, .5, .5, .5, .5, .5, -4.5, .5, .5, 10.5)
LL = c(-.5, -.5, 4.5, -.5, -5.5, -.5, -.5, 6.5, -4.5, 9.5, -4.5, -.5, -.5, -.5, -.5, -.5, -4.5, -.5, -.5, 9.5)
values = c(.2, -.2, 5.2, -.3, -4.7, -.1, -.2, 6.9, -5.3, 10.1, -4.4, 0.1, 0.2, 0.3, 0.1, -0.1, -4.9, -.2, -.2, 9.9)
df = data.frame(
group = rep(rep(group, each = 2), 2),
treatment = rep(treatment, each = 10),
estimates = rep(estimates, 10),
LL = LL,
means = means,
UL = UL,
parameters = rep(parameters, 10),
values = values
)
ggplot(data = df, aes(x = as.factor(estimates), y = means, color = estimates))+
geom_point()+
geom_errorbar(aes(ymin = LL, ymax = UL), width=.1, position = position_dodge(0.1))+
geom_segment(x = rep(c(.6, 1.6), 10), xend = rep(c(1.4, 2.4), 10),
y = values, yend = values, col = "black",
linetype = 3)+
scale_x_discrete(labels = c(expression(beta[1]), expression(beta[2])))+
xlab("Beta coefficient type")+ylab("Confidence Interval of Estimate")+
ggtitle("Coefficient Estimates")+
facet_grid(row = vars(treatment), col = vars(group))+
scale_color_manual(name = "Symbols",
values = c("estim1" = "#F8766D", "estim2" = "#00BFC4"),
labels = c(expression(beta[1]),
expression(beta[2])))
scale_shape_manual(values = c("b1" = 16,
"b2" = 16)+
scale_linetype_manual(values = c("b1" = 1,
"b2" = 1))
The second set of code, does not work but is my best attempt as to what maybe I should do to try to get the dashed black line in the legend.
ggplot(data = df, aes(x = as.factor(estimates), y = means, color = estimates))+
geom_point()+
geom_errorbar(aes(ymin = LL, ymax = UL), width=.1, position = position_dodge(0.1))+
geom_segment(x = rep(c(.6, 1.6), 10), xend = rep(c(1.4, 2.4), 10),
y = values, yend = values, col = "black",
linetype = 3)+
scale_x_discrete(labels = c(expression(beta[1]), expression(beta[2])))+
xlab("Beta coefficient type")+ylab("Confidence Interval of Estimate")+
ggtitle("Coefficient Estimates")+
facet_grid(row = vars(treatment), col = vars(group))+
scale_color_manual(name = "Symbols",
values = c("estim1" = "#F8766D", "estim2" = "#00BFC4"),
#"" = "#00000"),
labels = c(expression(beta[1]),
expression(beta[2])))#,
#"True Value"))#+
scale_shape_manual(values = c("b1" = 16,
"b2" = 16,
"" = 0))+
scale_linetype_manual(values = c("b1" = 1,
"b2" = 1,
"b3" = 3))
I've also thought that maybe I could include try to relevel the df$estimates column to include three levels (the existing) "estim1", "estim2" and a dummy "True Value" level with no observations but I'm worried that this would just add an empty "True Value" tick to each of my 12 plots on the x-axis sublabels.
Thanks for you help.
Map the linetype of your geom_segment to a string called "True value" inside aes, then add a scale_linetype_manual call. This will create a separate legend entry that matches the appearance of your segment and has the correct label.
ggplot(data = df, aes(x = as.factor(estimates), y = means, color = estimates)) +
geom_point() +
geom_errorbar(aes(ymin = LL, ymax = UL), width=.1,
position = position_dodge(0.1)) +
geom_segment(x = rep(c(.6, 1.6), 10), xend = rep(c(1.4, 2.4), 10),
y = values, yend = values, col = "black",
aes(linetype = "True value")) +
scale_x_discrete(labels = c(expression(beta[1]), expression(beta[2]))) +
xlab("Beta coefficient type")+ylab("Confidence Interval of Estimate") +
ggtitle("Coefficient Estimates") +
facet_grid(row = vars(treatment), col = vars(group)) +
scale_color_manual(name = "Symbols",
values = c("estim1" = "#F8766D", "estim2" = "#00BFC4"),
labels = c(expression(beta[1]),
expression(beta[2]))) +
scale_linetype_manual(values = 3, name = NULL)

Forcing specific plot symbols for points in R ggplot2

I am trying to specify manually, the shape of data points in r ggplot2 but can't seem to get it to work. Below is a sample example
p.est<- c(1.65, 1.55, 0.70, 1.61, 1.25)
lcl<-c(1.25, 1.10, 0.50, 1.20, 1.02)
ucl<-c(2.20, 2.05, 0.90, 2.20, 1.50)
toy.data <- tibble(zc = zc, p.est = p.est, p.lcl = p.lcl, p.ucl = p.ucl)
Assume I want two types of plot symbols for the five points, I use scale_shape_manual() in ggplot2 but it doesn't seem to work. Below is my sample code and the resulting plot attached. I'm trying to modify so the plot symbols for the points correspond to 5 which is a diamond and 16 which is a circle.
ggplot(toy.data, aes(zc, p.est, ymin = p.lcl, ymax = p.ucl)) +
scale_shape_manual(values = c(5, 16, 5, 5, 16))+
geom_pointrange(position = position_dodge(width = 0.1))+
geom_hline(yintercept = 1)+
ylim(0.5, 2.5)
You can add shape = factor(p.est). Otherwise scale_shape doesn't apply to anything.
zc <- c(1,2,3,4,5)
p.est <- c(1.65, 1.55, 0.70, 1.61, 1.25)
p.lcl <-c(1.25, 1.10, 0.50, 1.20, 1.02)
p.ucl <-c(2.20, 2.05, 0.90, 2.20, 1.50)
toy.data <- tibble(zc = zc,
p.est = p.est,
p.lcl = p.lcl,
p.ucl = p.ucl)
ggplot(toy.data, aes(zc, p.est, ymin = p.lcl, ymax = p.ucl, shape = factor(p.est))) +
scale_shape_manual(values = c(5, 16, 5, 5, 16)) +
geom_pointrange(position = position_dodge(width = 0.1)) +
geom_hline(yintercept = 1) +
ylim(0.5, 2.5)
EDITED Follow up question
toy.data <- tibble(zc = zc,
p.est = p.est,
p.est.x = c("A","B","A","A","B"),
p.lcl = p.lcl,
p.ucl = p.ucl)
ggplot(toy.data, aes(zc, p.est, ymin = p.lcl, ymax = p.ucl, shape = p.est.x)) +
scale_shape_manual(values = c(5, 16)) +
geom_pointrange(position = position_dodge(width = 0.1)) +
geom_hline(yintercept = 1) +
ylim(0.5, 2.5)

r ggplot2: fill area under curves with geom_step

I'm trying to fill area under each step function using ggplot2 and geom_step. Here's an example dataset:
time = c(0, 5, 8, 11, 14, 18, 20, 0, 3, 7, 13, 19, 20, 0, 4, 9, 15, 18)
prob = c(1, 0.95, 0.80, 0.62, 0.30, 0.03, 0, 1, 0.92, 0.75, 0.57, 0.21, 0, 1, 0.80, 0.64, 0.43, 0)
group = c(1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3)
df = data.frame(time, prob, group)
Here's the codes i've tried:
plot1 = ggplot(df, aes(x = time, y = prob, group = group, fill = group)) +
geom_step()+
geom_ribbon(data = df, aes(ymin = 0, ymax = prob))
The problem is that, after fill the area, only group 1 has the step line, and the area filling is not following the step function.
You may use geom_rect instead of geom_ribbon.
df %>%
mutate(group = as.factor(group)) %>%
ggplot(aes(x = time, y = prob, group = group, fill = group)) +
geom_step()+
geom_rect(aes(xmin = time, xmax = lead(time),
ymin = 0, ymax = prob), alpha = 0.4)

ggplotly with geom_rect not displaying geom_bar

I have a ggplot where I would like to have a striped background of grey and white. I have achieved this using geom_rect, as can be seen below:
ggplot(growth.mon, aes(x = Month, y = Rate)) +
geom_rect(ymin = 0.3, ymax = 0.4,
xmin = 0, xmax = 1000000, fill = '#fbfcfc') +
geom_rect(ymin = 0.2, ymax = 0.3,
xmin = 0, xmax = 1000000, fill = '#f5f6f9')+
geom_rect(ymin = 0.1, ymax = 0.2,
xmin = 0, xmax = 1000000, fill = '#fbfcfc')+
geom_rect(ymin = 0, ymax = 0.1,
xmin = 0, xmax = 1000000, fill = '#f5f6f9')+
geom_rect(ymin = -0.1, ymax = 0,
xmin = 0, xmax = 1000000, fill = '#fbfcfc')+
geom_rect(ymin = -0.2, ymax = -0.1,
xmin = 0, xmax = 1000000, fill = '#f5f6f9')+
geom_rect(ymin = -0.3, ymax = -0.2,
xmin = 0, xmax = 1000000, fill = '#fbfcfc')+
geom_bar(stat = "identity", aes(fill = as.factor(1)), show.legend = FALSE)+
geom_line(aes(y = rollMean, colour = "#7f5ba2"), size = 1.1, show.legend = FALSE)+
scale_fill_manual(values = c("#0095db"))+
scale_colour_manual(values = c("#7f5ba2"))+
scale_y_continuous(NULL, labels = percent_format())+
scale_x_date(date_breaks = "1 month", date_labels = "%b %Y")+
theme(axis.text.x=element_text(angle=60, hjust=1))+
theme(legend.position = "none")
This creates this:
Now I am developing a shiny app and I would like this plot to be interactive rather than static, so I use ggplotly like so:
ggplotly(gg_growth)
However, the chart ends up removing the bars like this:
Can someone tell me what went wrong and how to fix this, please? Thank you.
Data:
dates <- seq(as.Date("2017-02-01"), length = 36, by = "1 month") - 1
sales_mon17 <- c(1503, 1563, 1434.5,1807, 1843.7, 1664, 1285, 1188, 1513, 1997,1718.2, 2191)
sales_mon18 <- c(1919, 1886, 1995, 1930, 1898, 2122, 1818, 1908, 1974, 2074, 1700, 2303)
sales_mon19 <- c(2319, 2424, 2353, 2474, 2500, 2538, 2444, 2219, 1908, 2404, 2288, 3079.7)
monthly_revenue <- data.frame(Month = dates, Revenue = c(sales_mon17, sales_mon18, sales_mon19))
growth.mon <- diff(monthly_revenue$Revenue) / lag(monthly_revenue$Revenue)[-1]
growth.mon <- data.frame(Month = monthly_revenue$Month[-1], Rate = growth.mon)
growth.mon$rollMean <- c(NA, NA, rollmean(growth.mon$Rate, 3))

ggplot2 v2.21.9 sec.axis in polar plot

I am currently trying to add a secondary axis using the recently introduced function sec.axis in ggplot2. This function works well with scatter/bar plots, but not for polar plot: In the following code, the name for the second y-axis appears, but not the axis.
Is there any workaround or option, that I have not figured out?
require(ggplot2)
set.seed(40);
Location <- data.frame(Winkel = round(runif(1000, 0, 24), 0))
Location$BAD <- Location$Winkel %in% c(seq(7, 18))
Abschnitte <- c(0:24)
polar <- data.frame(Winkel2 = c(1.5, 2.34, 1.2, 3.45, 1.67, 2.61, 1.11, 13.2),
value = c(0.1, 0.03, 0.02, 0.015, 0.01, 0.04, 0.09, 0.06))
ggplot(Location, aes(x = Winkel, fill = BAD, y = (..count..)/sum(..count..))) +
geom_histogram(breaks = seq(0,24), colour = "black") +
coord_polar(start = 0) + theme_minimal() +
scale_fill_brewer(type = "seq", palette = 3) +
ylab("Percentual allocation time") +
ggtitle("") +
scale_x_continuous("", limits = c(0, 24), breaks = Abschnitte, labels = Abschnitte) +
scale_y_continuous(labels = scales::percent,
sec.axis = sec_axis(~.*5, name = "mean direction")) +
geom_segment(data = polar, aes(x = Winkel2, y = 0, xend = Winkel2, yend = value, fill = NA),
arrow = arrow(angle = 30, type = "closed", length = unit(0.3, "cm")))
As #henrik mentioned in the comments, this is a bug. It's been patched and is available if you use the development version from GitHub (i.e., devtools::install_github("tidyverse/ggplot2")).
Here's the example after the patch:
require(ggplot2)
#> Loading required package: ggplot2
set.seed(40);
Location <- data.frame(Winkel = round(runif(1000, 0, 24), 0))
Location$BAD <- Location$Winkel %in% c(seq(7, 18))
Abschnitte <- c(0:24)
polar <- data.frame(Winkel2 = c(1.5, 2.34, 1.2, 3.45, 1.67, 2.61, 1.11, 13.2),
value = c(0.1, 0.03, 0.02, 0.015, 0.01, 0.04, 0.09, 0.06))
ggplot(Location, aes(x = Winkel, fill = BAD, y = (..count..)/sum(..count..))) +
geom_histogram(breaks = seq(0,24), colour = "black") +
coord_polar(start = 0) + theme_minimal() +
scale_fill_brewer(type = "seq", palette = 3) +
ylab("Percentual allocation time") +
ggtitle("") +
scale_x_continuous("", limits = c(0, 24), breaks = Abschnitte, labels = Abschnitte) +
scale_y_continuous(labels = scales::percent,
sec.axis = sec_axis(~.*5, name = "mean direction")) +
geom_segment(data = polar, aes(x = Winkel2, y = 0, xend = Winkel2, yend = value, fill = NA),
arrow = arrow(angle = 30, type = "closed", length = unit(0.3, "cm")))
#> Warning: Ignoring unknown aesthetics: fill

Resources