I am trying to annotate a ggplot histogram with a shaded rectangle, and am trying to figure out if there is a way to pass an argument to ymax that will dynamically scale the rectangle to the ymax of the plotting area.
I can achieve the desired effect by hard coding the ymax value of the annotate() to be greater than the plot ymax then 'cropping' back the plot using coord_cartesian() shown in the example below. However, this requires me to know a priori what the max of the histogram will be, which of course will change if I adjust binwidth. There is some way to scale ymax dynamically?
ggplot(
data = mtcars,
aes(
x=mpg
)
)+
geom_histogram(
binwidth = 3,
fill = "gray63"
)+
annotate(
"rect",
xmin = 21,
xmax = 22,
ymin = 0,
ymax = 10, #hardcode ymax to be > plot ymax
fill = "gray18",
alpha = 0.5
)+
theme_bw()
coord_cartesian(
ylim = c(0,8) #crop back to plot ymax
)
Many position arguments can accept Inf or -Inf, setting them to whatever is the highest/lowest value currently shown. That's set by the plot limits, not necessarily the data. You can then drop the coord_cartesian bit, because you don't need to hard-code the limits any more.
library(ggplot2)
ggplot(mtcars, aes(x = mpg)) +
geom_histogram(binwidth = 3, fill = "gray63") +
annotate("rect", xmin = 21, xmax = 22, ymin = 0, ymax = Inf, fill = "gray18", alpha = 0.5)
If, for whatever reason, you needed the plot to show a higher limit, you can see that Inf will then adjust accordingly:
ggplot(mtcars, aes(x = mpg)) +
geom_histogram(binwidth = 3, fill = "gray63") +
annotate("rect", xmin = 21, xmax = 22, ymin = 0, ymax = Inf, fill = "gray18", alpha = 0.5) +
ylim(0, 12)
Related
I have created a scatterplot using ggplot2 in RStudio with the function annotate("rect".... to add a layer of colours based on another variable. I have been trying to add a legend for SO long by googling and trying different methods found on this site and others, including using geom_rect function but I cannot seem to get it to work fully. Please can anyone help me add a legend purely based on the shaded areas. See my plot:
This is my script so far:
ggplot(prpc_data,aes(x=age,y=total_proprioception))+
annotate("rect",xmin = 2, xmax = 9, ymin = -Inf, ymax = Inf, colour="blue", fill="blue",alpha = 0.15)+
annotate("rect",xmin=6,xmax=12,ymin=-Inf,ymax=Inf,colour="hotpink",fill="hotpink",alpha=0.15)+
annotate("rect",xmin=8,xmax=16,ymin=-Inf,ymax=Inf,colour="yellow",fill="yellow",alpha=0.2)+
geom_point(shape=21,size=2,colour="black",fill="cadetblue3")+
geom_smooth(method="loess",se=FALSE,colour="cadetblue")+
labs(x="Age (years)",y="Mean proprioception score (0-4)")+
coord_cartesian(ylim=c(0,4),xlim=c(2,16))+
scale_y_continuous(breaks=seq(0,4,0.5))+
scale_x_continuous(breaks=seq(2,16,2))+
theme_bw()
I would be very grateful for any help
Instead of adding rectangles using annotate, you can use geom_rect and map its fill aesthetic to whatever labels you want. To do this you can create a little rect_df that you pass to geom_rect, and use scale_fill_manual to give the rectangles the fill colours you want:
rect_df <- data.frame(xmin = c(2, 6, 8), xmax = c(9, 12, 16),
labs = c("Range1", "Range2", "Range3"))
ggplot(prpc_data, aes(age, total_proprioception)) +
geom_rect(aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf, fill = labs),
alpha = 0.2, data = rect_df, inherit.aes = FALSE) +
geom_point(shape = 21, size = 2, colour = "black", fill = "cadetblue3") +
geom_smooth(method = "loess", se = FALSE, colour = "cadetblue") +
labs(x = "Age (years)", y = "Mean proprioception score (0-4)") +
coord_cartesian(ylim = c(0, 4), xlim = c(2, 16)) +
scale_fill_manual(values = c("blue", "hotpink", "yellow")) +
scale_y_continuous(breaks = seq(0, 4, 0.5)) +
scale_x_continuous(breaks = seq(2, 16, 2)) +
theme_bw()
Data used to emulate OP plot
set.seed(1)
prpc_data <- data.frame(age = runif(50, 0, 16))
prpc_data$total_proprioception <- rnorm(50, prpc_data$age, prpc_data$age/4)^2/200
Annotation layers in ggplot2 are typically used for one-off labels, notes, and symbols, and don't usually relate to a legend. The easiest way to get a legend for some shaded areas would be to make those a normal geom_* layer with aethestics mapped to variables.
Below, I give the geom_rect layer its own data frame, and specific inherit.aes = FALSE so that that layer ignores the global aes(wt, mpg) assignment. Since the fill of those rectangles are mapped to the category, a legend is automatically created.
ggplot(mtcars, aes(wt, mpg)) +
geom_rect(data = data.frame(zone = factor(c("low", "mid", "high"),
levels = c("low", "mid", "high")),
start = c(0,3,4),
end = c(3,4,6)),
inherit.aes = FALSE,
aes(xmin = start, xmax = end, ymin = 0, ymax = Inf, fill = zone),
alpha = 0.1) +
geom_point()
I have a scatter plot:
ex<- ggplot(rdr, aes(x = hb, y = iv, color = pt))+ geom_point() +
ylim(-20,20) +
xlim(-20,20) +
annotate(geom = "rect", xmin = -10, xmax = 10, ymin = -10, ymax = 10,
fill = "gray100", colour = "black", alpha = 0.5) +
annotate( geom = "rect", xmin = -10, xmax = 10, ymin = -15, ymax = -10, fill = "palegreen", color = "blue", alpha =0.5)
I want to count how many points are in each of the rectangles. And depending on the color of the point, I want to give them values. ex: blue(0), green(1).
How can I do this?
If you know the range for each variable in advance (which it seems like you do based on the xmin / ymin args you have), then I would do annotation first.
You don't have a scatterplot, you have data you are representing as a scatterplot, and you want to annotate the points so that they display as different colors on the scatterplot.
library(dplyr)
library(ggplot2)
data(mtcars)
mtcars2 = mtcars %>%
mutate(good = case_when(
# this is the annotation step
between(hp, 100, 150) & between(mpg, 15, 20) ~ 1,
# this says everything else gets this value
TRUE ~ 0
))
# we need as.factor to get different colors displayed
ggplot(mtcars2, aes(x = mpg, y = hp, color = as.factor(good))) + geom_point()
I made a faceted graph using ggplot, and then tried to use the function annotate to create a grey highlighted area in one specific panel of the plot only.
I tried to adapt the labeling method from this question, but I couldn't get it to work:
How to add annotation on each facet
Here is a reproducible example:
ggplot(iris, aes(x = Sepal.Length))+
geom_point(aes(y = Petal.Length))+
facet_grid(Species~.)+
annotate(geom = 'rect', xmin = 6, xmax = 6.5, ymin= 0, ymax= Inf,
fill = 'grey20', alpha = 0.2)
output:
I want the grey highlight to appear on only the versicolor facet, not every facet.
EDIT
As the user #user11362344 has proposed, i test his indication to use geom_rect(), and add to the code in the place of annotate() and WORKED VERY WELL!:
ggplot(data_2, aes(x = Sepal.Length))+
geom_point(aes(y = Petal.Length))+
facet_grid(Species~.)+
geom_rect(data=data.frame(Species='versicolor'), inherit.aes=F,
xmin = 6, xmax = 6.5, ymin = 0, ymax = Inf, fill = 'grey20', alpha = 0.2)
output:
Thanks everyone for the help! And specially thanks for #user11362344!
geom_rect(data=data.frame(Species='versicolor'), inherit.aes=FALSE,
xmin = 6, xmax = 6.5, ymin= 0, ymax= Inf,
fill = 'grey20', alpha = 0.2)
This question already has answers here:
geom_rect and alpha - does this work with hard coded values?
(4 answers)
Closed 2 years ago.
I recently upgraded to R version 3.2.3 and also to ggplot version 2.0.0.
Trying to upgrade some old code to the newer versions I encountered a weird behaviour with ggplot2 and its transparency settings.
Now my question is, is this a bug or a feature (if so, can someone enlighten me as to why its good to have it this way)? The result I want to have is (obviously) plot 2.
Say I plot a line and lay a rectangle with transparency over it like this:
library(ggplot2)
plot_data <- data.frame(x = 1:100, y = rnorm(100))
# Plot 1
ggplot(data = plot_data, aes(x = x, y = y)) +
geom_line() +
geom_rect(aes(xmin = 20, xmax = 50, ymin = -Inf, ymax = Inf), fill = "red",
alpha = 0.1) + ggtitle("Plot 1")
# Plot 2
ggplot() +
geom_line(data = plot_data, aes(x = x, y = y)) +
geom_rect(aes(xmin = 20, xmax = 50, ymin = -Inf, ymax = Inf), fill = "red",
alpha = 0.1) + ggtitle("Plot 2")
To my understanding plot 1 and 2 should be identical. However, I get the following plots:
Plot 1:
and plot 2:
Additionally, if I play around with the alpha-values (for example setting them to 0.01, I get the two following plots:
and
I believe that calling geom_rect without a data parameter will effectively draw an individual rectangle for each row of the data.frame which is why the alpha is "working", but not quite as expected. I have not been able to replicate and get to parity/agreement between the methods, but as you noted, I think it is doing something along the lines of drawing either 100 individual rectangles, or 30 (the width of the rectangles; from 20 to 50) which is why alpha = 0.1 / 100 and alpha = 0.1 / 30 gets you closer, but not quite matching.
Regardless, I would probably use annotate, as that better describes the behavior/result you are trying to achieve without issues and works, as expected, in both cases -- annotations will draw a single instance per geom:
ggplot(data = plot_data, aes(x = x, y = y)) +
# geom_rect(aes(xmin = 20, xmax = 50, ymin = -Inf, ymax = Inf, alpha = 0.1, fill = "red")) +
annotate("rect", xmin = 20, xmax = 50, ymin = -Inf, ymax = Inf, alpha = 0.1, fill = "red") +
geom_line() +
ggtitle("Plot 1")
ggplot() +
geom_line(data = plot_data, aes(x = x, y = y)) +
# geom_rect(aes(xmin = 20, xmax = 50, ymin = -Inf, ymax = Inf), fill = "red", alpha = 0.1) +
annotate("rect", xmin = 20, xmax = 50, ymin = -Inf, ymax = Inf, fill = "red", alpha = 0.1) +
ggtitle("Plot 2")
I'm using ggplot, and am trying to add a ribbon in the form of a simple rectangle to a barplot I have. The idea is to show a cutoff below a certain value.
The barplot is fine but I can't quite get the ribbon right - I'd like it displayed a little wider but it seems to be limited to the width of the barplot data.
I tried using xmin and xmax but that doesn't increase the width of the shaded area.
Is there a way of explicitly controlling the width of geom_ribbon?
# Where df is a data frame containing the data to plot
library(cowplot)
ggplot(df, aes(x=treatments, y=propNotEliminated)) +
geom_ribbon(aes(xmin=0, xmax=21, ymin=0, ymax=20)) + # the xmin and xmax don't do what I'd expect
geom_bar(stat="identity", fill="white", colour="black", size=1) +
theme_cowplot()
Why not use geom_rect?
ggplot(mtcars, aes(factor(cyl))) +
geom_bar() +
geom_rect(xmin = 0, xmax = Inf, ymin = 0, ymax = 1, fill = "blue") +
geom_rect(xmin = 1, xmax = 3, ymin = 1, ymax = 2, fill = "red") +
geom_rect(xmin = 1 - 0.5, xmax = 3 + 0.5, ymin = 2, ymax = 3, fill = "green")
After you're satisfied with the placement, put geom_bar last.