I am interested in creating a figure akin to the below, which has a separate legend entry for each of four components: two geom_segment and two geom_point, which are grouped according to some facet (corresponding to the color).
Here is a sample dataset, and some initial code.
x <- c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
y <- c(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
z <- c(3, 6, 9, 12, 15, 18, 21, 24, 27, 30)
s <- c(5, 5, 5, 5, 5, 5, 5, 5, 5, 5)
t <- c(10, 10, 10, 10, 10, 10, 10, 10, 10, 10)
n <- c("A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
"B", "B", "B", "B", "B", "B", "B", "B", "B", "B")
df <- cbind(rbind(data.frame(x = x, y = y, s = s), data.frame(x = x, y = z, s = t)), n)
ggplot(data = df, mapping = aes(x = x, y = y, color = n)) +
geom_point() +
scale_color_manual(values = c("blue", "gray64")) +
geom_segment(mapping = aes(x = 0, xend = 10, y = 10, yend = 10), color = "blue", inherit.aes = FALSE) +
geom_segment(mapping = aes(x = 0, xend = 10, y = 20, yend = 20), color = "gray64", inherit.aes = FALSE)
Give this a shot:
library(ggplot2)
ggplot() +
geom_point(data = dplyr::filter(df, n == "A"), mapping = aes(x = x, y = y, shape = "Label A.1"), color = "gray") +
geom_point(data = dplyr::filter(df, n == "B"), mapping = aes(x = x, y = y, shape = "Label B.1"), color = "blue") +
geom_line(data = dplyr::filter(df, n == "A"), mapping = aes(x = x, y = s, color = "Label A.2")) +
geom_line(data = dplyr::filter(df, n == "B"), mapping = aes(x = x, y = s, color = "Label B.2")) +
scale_shape_manual(name = NULL, values = c(19, 19)) +
scale_color_manual(name = NULL, values = c("Label A.2" = "gray", "Label B.2" = "blue")) +
guides(shape = guide_legend(override.aes = list(color = c("Label A.1" = "gray", "Label B.1" = "blue"))))
ggplot2 doesn't seem to like separating legends (I suppose it does make the plot more complicated). In this solution, we add each layer separately, controlling the legend using shape (which we later set to 19, the default filled-in circle) and color aesthetics. In the last line, we make sure the colors of the shape layer are correct (try the code without the last line to see what it does!).
I also don't think "facet" is used correctly in your question. Generally, facets are like subplots.
Related
The question can be described with a MWE as follows:
df <- data.frame(Team = c("A", "B", "C"), Score = c(5, 8, 10))
plot <- ggplot(df, aes(Team, Score)) +
geom_bar(stat = "identity") ## plot the bar chart showing differences between teams
### In the following, I would like to add segmented lines between any two bars.
segments_AB <- data.frame(x0 = c("A", "A", "B"),
y0 = c(5, 9, 9),
x1 = c("A", "B", "B"),
y1 = c(9, 9, 8))
segments_AC <- data.frame(x0 = c("A", "A", "C"),
y0 = c(5, 11, 11),
x1 = c("A", "C", "C"),
y1 = c(11, 11, 10))
plot_segment <- plot + geom_segment(data = segments_AB, aes(x = x0, y = y0, xend = x1, yend = y1), show.legend = F) +
geom_segment(data = segments_AC, aes(x = x0, y = y0, xend = x1, yend = y1), show.legend = F)
plot_segment
Now, the problem is that the two segmented lines overlap on top of bar A which is shown in the following picture:
This is mainly because the horizontal axis is a categorical variable and I cannot shift the line by adding or subtracting some values.
Question: How do I make the AB line and AC line separate from each other?
In addition, I also want to add some text near each segmented line, but I can only add on top of one of the bars as follows:
annotation <- data.frame(
x = c("A", "B"),
y = c(6, 9),
label = c("p = 0.38", "p = 0.02")
)
plot_segment + geom_text(data = annotation, aes(x = x, y = y, label = label), size = 2)
Question: How can I add annotations near the center of the horizontal part of each segmented line?
Thanks a lot for your help!
I have a bar-plot with two different variables.
For one of the factors (gr) I have chosen different ´lintype´ in the plot.
The legend for "gr" shows ´lintype´ but with a dark grey fill, which I think is confusing.
Does anyone know how to remove the fill or change it to white or transparent?
(All tips I have found only change a background to the legend, but does not affect the grey fill)
yval <- c(3, 7, 4, 4, 8, 9, 4, 7, 9, 6, 6, 3)
trt <- rep(c("A", "B", "C"), times=4)
gr <- rep(c(rep(("case"), times = 3), rep(("control"), times = 3)), times = 2)
var <- c(rep(("var1"), times = 6), rep(("var2"), times = 6))
df <- data.frame(yval, device, ccgroup, var)
ggplot(data=df, aes(x=var)) +
geom_bar( color = "black", size = 1, aes(weights = yval, fill = trt, linetype = gr) , position = "dodge")
This can be achieved e.g. via guide_legend which allows you to set the fill color used in the legend. Try this:
library(ggplot2)
yval <- c(3, 7, 4, 4, 8, 9, 4, 7, 9, 6, 6, 3)
trt <- rep(c("A", "B", "C"), times=4)
gr <- rep(c(rep(("case"), times = 3), rep(("control"), times = 3)), times = 2)
var <- c(rep(("var1"), times = 6), rep(("var2"), times = 6))
df <- data.frame(yval, trt, gr, var)
ggplot(data=df, aes(x=var)) +
geom_bar(color = "black", size = 1, aes(weights = yval, fill = trt, linetype = gr) , position = "dodge") +
guides(linetype = guide_legend(override.aes = list(fill = c(NA, NA))))
#> Warning: Ignoring unknown aesthetics: weights
I am actually very amazed to see I cannot quickly find a guide to how to do this. Here is an example:
library(ggplot2)
library(gganimate)
library(data.table)
library(magrittr)
dt <- lapply(seq(10), function(i){
mean = i
label = paste0("T = ", i)
dt = data.table(x = seq(0, 50, length.out = 100))
set(dt, j = "y", value = dt[, dlnorm(x, meanlog = log(mean), sdlog = 0.2)])
set(dt, j = "frameN", value = i)
return(dt)
}) %>% rbindlist
print(dt)
p <- ggplot(dt, aes(x = x, y = y)) +
geom_line() +
scale_x_continuous(name = "x", breaks = c(0, 1)) +
transition_manual(frameN)
animate(p)
I want the breaks and labels of scale_x_continuous to follow my own definitions:
arr_breaks <- c(1, 3, 2, 4, 3, 5, 4, 6, 5, 7)
arr_labels <- paste0(seq(10, 100, 10), " kg")
And then
breaks = arr_breaks[1], labels = arr_labels[1] for frame 1
breaks = arr_breaks[2], labels = arr_labels[2] for frame 2
...
breaks = arr_breaks[10], labels = arr_labels[10] for frame 10
No matter how I do it I got errors. Any idea?
As #z-lin noted, gganimate is not currently set up (to my knowledge) to animate scales with different breaks. The effect could be closely approximated using geoms, and with some more work you could probably make an exact visual match to a changing scale.
breaks_df <- data.frame(
frameN = c(1:10),
arr_breaks = c(1, 3, 2, 4, 3, 5, 4, 6, 5, 7),
arr_labels = paste0(seq(10, 100, 10), " kg")
)
p <- ggplot(dt, aes(x = x, y = y)) +
geom_segment(data = breaks_df, color = "white",
aes(x = arr_breaks, xend = arr_breaks,
y = -Inf, yend = Inf)) +
geom_text(data = breaks_df, vjust = 3, size = 3.5, color = "gray30",
aes(x = arr_breaks, y = 0, label = arr_labels)) +
geom_line() +
scale_x_continuous(name = "x", breaks = c(0)) +
coord_cartesian(clip = "off") +
transition_manual(frameN)
animate(p, width = 600, height = 250)
Continuing on from my previous bspline question
If this is my curve:
data <- tibble (
x = c(10, 15, 17, 17, 20, 22, 22, 23, 25, 25, 27, 29),
y = c(5, 7, 4, 4, 0, 5, 5, 6, 5, 5, 4, 5.5),
g = c("A", "A", "A", "B", "B", "B", "C", "C", "C", "D","D","D"),
pt = c(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1)
)
ggplot(data) +
stat_bspline2(aes(x=x, y=y, color = ..group.., group = g), size = 4, n = 300, geom = "bspline0") +
scale_color_gradientn(colours = c("red", "pink", "green", "white"), guide = F)
How do I add dots to selected points on the curve?
Here's how not to do it:
ggplot(data) +
stat_bspline2(aes(x=x, y=y, color = ..group.., group = g), size = 4, n = 300, geom = "bspline0") +
scale_color_gradientn(colours = c("red", "pink", "green", "white"), guide = F) +
stat_bspline2(data = pt, aes(x = x, y = x, color = ..group.., group = pt), n = 12, geom = "point", size = 9)
)
It isn't perfect, but it works. Add some columns with the positions of the points you want (I'm assuming that if pt = 1, you want the point plotted)
data <- data %>%
mutate(pt_x = ifelse(pt == 1, x, NA),
pt_y = ifelse(pt == 1, y, NA))
ggplot(data) +
stat_bspline2(aes(x=x, y=y, color = ..group.., group = g), size = 4, n = 300, geom = "bspline0") +
scale_color_gradientn(colours = c("red", "pink", "green", "white"), guide = F) +
geom_point(aes(pt_x, pt_y))
I am intrigued by this plot of Albert Cairo.
I can smooth my curve sufficiently with ggforce::bspline
However, now that I don't have a date axis I am unsure as to how to change the color of a spline midway.
Let's assume that the three points represent the years 1990, 1991 and 1992. And someone got elected on July 1, 1990. I would like to change the color of the spline at this point. So the curved line would be red from origin until aprox (12, 5.6) then blue from (12, 5.6) to (17,4)
I am not sure how to accomplish this.
library(ggforce)
library(ggplot2)
data <- tibble (
x = c(10, 15, 17),
y = c(5, 7, 4)
)
ggplot(data) +
stat_bspline2(aes(x = x, y = y), n = 300, geom = "bspline0", color = "red") +
stat_bspline2(aes(x = x, y = y), n = 3, geom = "point", color = "red") +
geom_point(aes(x = x, y = y), color = "grey")
Thinking about what M.A. told me about groups I now have code that can:
Change the color of straight line segments:
# Works for straight lines
ggplot(data, aes(x=x, y=y, colour = g, group = 1)) +
geom_line(size = 3) +
geom_point() +
scale_color_manual(values = c("A" = "red", "B" = "pink", "C" = "green", "D" = "white"))
And the continuous colour of a bspline. But I would like this to be discrete colors only as in the plot above.
# Works with continuous color
ggplot(data, aes(x=x, y=y, colour = g, group = 1)) +
geom_bspline2(size = 4, n = 300) +
scale_color_manual(values = c("A" = "red", "B" = "pink", "C" = "green", "D" = "white"))
Or this error, "Error: Continuous value supplied to discrete scale" with:
ggplot(data) +
stat_bspline2(aes(x = x, y = y, color = ..group.., group = 1), n = 300, geom = "bspline0") +
scale_color_manual(values = c("A" = "red", "B" = "pink", "C" = "green", "D" = "white"))
So I'm wondering how to manually control the color of discrete segments with bspline.
You can do this by grouping:
data <- tibble (
x = c(10, 15, 17, 17, 20, 22),
y = c(5, 7, 4, 4, 0, 5),
g = c("A", "A", "A", "B", "B", "B")
)
ggplot(data) +
stat_bspline2(
aes(x = x, y = y, color = ..group.., group = g),
n = 300, geom = "bspline0") +
scale_colour_gradient(low = "blue", high = "red", guide=FALSE)
Edit:
The error Continuous value supplied to discrete scale is is somewhat confusing here. I don't know if there is an easier way to get what you want but it can be achieved using scale_colour_gradientn(). This function allows to map the group g to a gradient between n colours so you want n to be the number of groups.
For example, consider a larger data set with four groups:
# example data
data <- tibble (
x = c(10, 15, 17, 17, 20, 22, 22, 23, 25, 25, 27, 29),
y = c(5, 7, 4, 4, 0, 5, 5, 6, 5, 5, 4, 5.5),
g = c("A", "A", "A", "B", "B", "B", "C", "C", "C", "D","D","D")
)
You can use a palette like rainbow() and specify the number of colours for the gradient to be 4 since there are four groups A, B, C and D.
# use a colour palette:
ggplot(data) +
stat_bspline2(
aes(x = x, y = y, color = ..group.., group = g),
n = 300, size = 1, geom = "bspline0") +
scale_color_gradientn(colours = rainbow(4),
guide = F
)
For custom colours, you may do the following:
# use custom colors:
ggplot(data, aes(x=x, y=y, color = ..group.., group = g)) +
geom_bspline2(size = 1, n = 300) +
scale_color_gradientn(
colours = c("red", "pink", "green", "white"),
guide = F
)
This uses a gradient between the colours red, pink, green and white. Note that the order of the colours matters as a different order leads to a different gradient and thus a different mapping of the groups.