Convex hull on horizontal and vertical error bars - r

I have a ggplot with means and both horizontal and vertical error bars, and I'd like to add a convex hull that encompasses all the error bars - like so:
I have tried with stat_chull from ggpubr but am not sure how to specify the aesthetics when there is a xmin, xmax, ymin and ymax for the error bars of each point. Below is how I coded the plot specifying the stat_chull aes as the X and Y means as an example - I know this is incorrect but I think I am on the right track?
ggplot()+
geom_point(data = df, aes(MeanX,MeanY)) +
geom_errorbar(data = df,
mapping = aes(x = MeanX,
ymin = MeanY - SdY,
ymax = MeanY + SdY),
width = 0, inherit.aes = FALSE)+
geom_errorbarh(data = df,
mapping = aes(y = MeanY,
xmin = MeanX - SdX,
xmax = MeanX + SdX),
height = 0, inherit.aes = FALSE)+
stat_chull(data = df, aes(MeanX,MeanY))+
theme_classic()
This gives the following plot:
I have also tried geom_polygon and got garbage.
Here is a the data:
df<-structure(list(Source = structure(1:5, .Label = c("A", "B", "C", "D",
"E"), class = "factor"), MeanX = c(-18.7066666666667,
-15.8769230769231, -16.8620689655172, -15.72, -17.4333333333333
), SdX = c(1.61072554509115, 0.409201849758959, 1.04811067886951,
0.74057035077327, 1.15902257671425), MeanY = c(9.93666666666667,
14.3230769230769, 9.22758620689655, 11.1, 13.7333333333333),
SdY = c(1.03005970142791, 0.539116085686704, 0.504990221704281,
0.757187779440037, 1.05039675043925)), row.names = c(NA,
-5L), class = "data.frame")
Any help is greatly appreciated!

Does the following work for you?
library(dplyr)
df %>%
mutate(ymin = MeanY - SdY,
ymax = MeanY + SdY,
xmin = MeanX - SdX,
xmax = MeanX + SdX) %>%
ggplot(aes(x = MeanX, y = MeanY))+
geom_point() +
geom_errorbar(aes(ymin = ymin, ymax = ymax),
width = 0)+
geom_errorbarh(aes(xmin = xmin, xmax = xmax),
height = 0)+
stat_chull(data = . %>%
summarise(x = c(MeanX, MeanX, MeanX, xmin, xmax),
y = c(MeanY, ymin, ymax, MeanY, MeanY)),
aes(x = x, y = y),
geom = "polygon", colour = "black", fill = NA)+
theme_classic()

Related

How to remove border colour of geom_rect_pattern from {ggpattern}?

I want to plot two rectangles with internal gradients beside each other using ggpattern::geom_rect_pattern(pattern = "gradient") without a border around each rectangle.
Example:
library(tidyverse)
library(ggpattern)
tibble(
id = c("a", "b"),
xmin = c(-1, -1),
xmax = c(1, 1),
ymin = c(-1, 0),
ymax = c(0, 1)
) |>
ggplot() +
geom_rect_pattern(
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, pattern_fill2 = id),
pattern_fill = "white", pattern = "gradient", pattern_orientation = "horizontal"
) +
theme_classic() +
coord_fixed(xlim = c(-1.1,1.1), ylim = c(-1.1,1.1), ratio = 1)
Which produces:
My issue is how do I remove the border around the rectangles?
Setting colour = "white" in geom_rect_pattern() will work to remove the outer border, but will introduce an internal border which is undesirable for my figure:
Setting colour = NA and/or pattern_colour = NA produces the same plot as the first
.
Is there an aesthetic I am missing here?
There seems to be a gray-filled rectGrob under the gradient fill on the finished plot, and you can just see the edges of it. If you set fill = NA this disappears.
library(tidyverse)
library(ggpattern)
tibble(
id = c("a", "b"),
xmin = c(-1, -1),
xmax = c(1, 1),
ymin = c(-1, 0),
ymax = c(0, 1)
) |>
ggplot() +
geom_rect_pattern(
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, pattern_fill2 = id),
pattern_fill = "white", pattern = "gradient", fill = NA,
pattern_orientation = "horizontal",
) +
theme_classic() +
coord_fixed(xlim = c(-1.1,1.1), ylim = c(-1.1,1.1), ratio = 1)

Distinguish theme (background) color for negative and positive values in geom_boxplot

For data of this type:
set.seed(123)
df <- data.frame(
Q = c(rep("q_pol",10), rep("q_wh",10)),
slope = c(rnorm(10,-0.5), rnorm(10, 0.5)),
Recipient = rep(c("A", "B"),10)
)
how can I color the theme (or background) of these boxplots in two different colors: the upper half for values > 0, say, "lightblue" and the lower half for values < 0, say, "darkblue":
library(ggplot2)
ggplot(df,
aes(x = Q, y = slope, color = Recipient)) +
geom_boxplot(notch = TRUE)
One option would be to add different filled backgrounds using geom_rect:
library(ggplot2)
ggplot(df,
aes(x = Q, y = slope, color = Recipient)) +
geom_rect(data = data.frame(
xmin = c(-Inf, -Inf),
xmax = c(Inf, Inf),
ymin = c(-Inf, 0),
ymax = c(0, Inf),
fill = c("darkblue", "lightblue")
), aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill), inherit.aes = FALSE, alpha = .5) +
scale_fill_manual(values = c("darkblue" = "darkblue", "lightblue" = "lightblue"), guide = "none") +
geom_boxplot(notch = TRUE)

ggplot2 geom_errorbar with different linetype but with solid whiskers

I am making errorbar plot with different linetype
library(ggplot2)
library(plyr)
# Create dataset:
DF <- data.frame(
group = rep(c("a", "b", "c", "d"),each=10),
Ydata = c(seq(1,10,1),seq(5,50,5),seq(20,11,-1),seq(0.3,3,0.3)),
Xdata = c(seq(1,10,1),seq(5,50,5),seq(20,11,-1),seq(0.3,3,0.3)))
# Summarise data:
subDF <- ddply(DF, .(group), summarise,
X = mean(Xdata), Y = mean(Ydata),
X_sd = sd(Xdata, na.rm = T), Y_sd = sd(Ydata))
# Plot data with error bars:
ggplot(subDF, aes(x = X, y = Y,linetype = group)) +
geom_errorbar(aes(x = X,
ymin = (Y-Y_sd),
ymax = (Y+Y_sd)),
width = 1, size = 0.5) +
geom_point(cex = 3) +
scale_linetype_manual(values = c("solid","twodash","longdash","longdash"))
This give me the following plot, but I want the end whiskers to be solid. Anyone could help?
One option to achieve your desired result would be to switch to geom_linerange and add the whiskers via geom_segment like so:
library(ggplot2)
width <- .3
# Plot data with error bars:
ggplot(subDF, aes(x = X, y = Y, linetype = group)) +
geom_segment(aes(
x = X - width, xend = X + width,
y = Y - Y_sd, yend = Y - Y_sd
),
size = 0.5, linetype = "solid"
) +
geom_segment(aes(
x = X - width, xend = X + width,
y = Y + Y_sd, yend = Y + Y_sd
),
size = 0.5, linetype = "solid"
) +
geom_linerange(aes(
x = X,
ymin = (Y - Y_sd),
ymax = (Y + Y_sd)
),
size = 0.5
) +
geom_point(cex = 3) +
scale_linetype_manual(values = c("solid", "twodash", "longdash", "longdash"))

How to add areas under a geom_line?

I want to display on the same graph a geom_line and the state (which is in a vector).
The data for example:
Timestamp;Value;State
20190618;1.2;UP
20190619;1.0;DOWN
20190620;1.1;UP
...
This is an example of what i'd like to obtain:
I know how to geom_line, i've already try to use geom_area but none of these try succeed.
Any help ? :-)
library(tidyverse)
ggplot(df) +
geom_rect(aes(xmin = Timestamp, xmax = lead(Timestamp),
ymin = 0, ymax = Inf,
fill = State), alpha = 0.2) +
geom_step(aes(Timestamp, Value))
# based on your data, after converting into table with Timestamp as a date
df <- structure(list(Timestamp = structure(c(18065, 18066, 18067), class = "Date"),
Value = c(1.2, 1, 1.1), State = c("UP", "DOWN", "UP")),
class = "data.frame", row.names = c(NA, -3L))
Is this what you are looking for (alternative to geom_rect)?
Prepare example data
x <- 1:5
y <- c(4,1,6,2,2)
plot.df <- data.frame(Timestamp=x, Value=y)
Code for the plot:
library(ggplot2)
ggplot(plot.df, aes(x=Timestamp,y=Value)) +
annotate("rect", xmin = 1, xmax = 2, ymin = -Inf, ymax = Inf,
alpha = .2, fill = "green") +
annotate("rect", xmin = 2, xmax = 3, ymin = -Inf, ymax = Inf,
alpha = .2, fill = "red") +
annotate("rect", xmin = 3, xmax = 4, ymin = -Inf, ymax = Inf,
alpha = .2, fill = "green") +
geom_step(direction = "h") +
theme_classic()

How to use ggplot in a loop with computed parameters?

I am trying to produce a variable number of rectangles (layers) in a ggplot of a zoo object. I would like to do this in a loop since I do not know ahead of time how many rectangles I will need. Here is a toy example.
library("zoo")
library("ggplot2")
set.seed(1)
y <- runif(50, min = 1, max = 2)
start <- as.numeric(as.Date("2018-01-01"))
x <- as.Date(start:(start + 49))
x.zoo <- zoo(y, order.by = x)
## Fill areas
bars <- data.frame(start = c(x[5], x[20], x[35]),
end = c(x[10], x[25], x[40]))
I can plot these manually with this code:
## Plot manually
print(autoplot.zoo(x.zoo, facets = NULL) +
geom_rect(aes(xmin = bars[1,1],
xmax = bars[1,2], ymin = -Inf, ymax = Inf),
fill = "pink", alpha = 0.01) +
geom_rect(aes(xmin = bars[2,1],
xmax = bars[2,2], ymin = -Inf, ymax = Inf),
fill = "pink", alpha = 0.01) +
geom_rect(aes(xmin = bars[3,1],
xmax = bars[3,2], ymin = -Inf, ymax = Inf),
fill = "pink", alpha = 0.01))
This gives me this desired image:
I tried using the loop below but it only plots the last bar. How do I do this??
## This didn't work but illustrates what I am trying to do
p = autoplot.zoo(x.zoo, facets = NULL)
for(i in 1:3) {
p = p + geom_rect(aes(xmin = bars[i,1],
xmax = bars[i,2], ymin = -Inf, ymax = Inf),
fill = "pink", alpha = 0.01)
}
print(p)
You don't need a loop. geom_rect is vectorised
autoplot.zoo(x.zoo, facets = NULL) +
geom_rect(aes(xmin = start, xmax = end, ymin = -Inf, ymax = Inf), data = bars, fill = "pink", alpha = 0.4, inherit.aes = FALSE)
One way to avoid the for loop is to convert x.zoo into a data.frame and map the data to geom_line. This way, you can map the bars data to geom_rect separately.
dat <- data.frame(index = index(x.zoo), data.frame(x.zoo))
ggplot() +
geom_rect(data = bars, aes(xmin = start, xmax = end, ymin =-Inf, ymax = Inf), fill = 'pink', alpha = .5) +
geom_line(data=dat, aes(x = index, y = x.zoo))

Resources