I have a data frame with a titration curve of pH, function of volume. I would like to put two colored/shadowed horizontal rectangles to show the range of pH of two indicators, methyl orange (3.2
Here is a reproducible exemple :
Volume <- c(1:5)
pH <- c(3,4,9,10,12)
df <- data.frame(Volume,pH)
ggplot(df,aes(x=Volume,y=pH))+geom_line(color="purple")+
geom_rect(aes(ymin=3.2,ymax=4.4,xmin=-Inf,xmax=Inf))+
geom_rect(aes(ymin=8.2,ymax=10,xmin=-Inf,xmax=Inf))+
scale_fill_manual(values = alpha(c("orange", "pink"),alpha = .3))
Which gives me this result :
How can theses rectangles be orange, pink and shadowed ?
Try this:
Volume <- c(1:5)
pH <- c(3,4,9,10,12)
df <- data.frame(Volume,pH)
ggplot(df,aes(x=Volume,y=pH))+geom_line(color="purple")+
geom_rect(aes(ymin=3.2,ymax=4.4,xmin=-Inf,xmax=Inf), fill="orange", alpha=.3)+
geom_rect(aes(ymin=8.2,ymax=10,xmin=-Inf,xmax=Inf), fill="pink", alpha=.3)
When something is not working, it is often a problem of referencing the wrong data or aesthetic in your geom_... calls.
Try to be very explicit when calling your geom.
Below I am creating an explicit data frame for your rectangles. You should explicitly call this data and also add inherit.aes = FALSE, so that it won't try to read the aesthetic from the ggpolt main call.
library(tidyverse)
mydf <- data.frame(Volume = c(1:5), pH = c(3, 4, 9, 10, 12))
ann_rect <- bind_rows(
data.frame(ymin = 3.2, ymax = 4.4, xmin = -Inf, xmax = Inf, fill = "orange"),
data.frame(ymin = 8.2, ymax = 10, xmin = -Inf, xmax = Inf, fill = "pink")
)
ggplot(mydf, aes(x = Volume, y = pH)) +
geom_rect(
inherit.aes = FALSE,
data = ann_rect,
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill)
) +
geom_line(color = "purple") +
scale_fill_identity()
Alternatively, leave the main call empty and explicitly reference the data in each geom call.
ggplot() +
geom_rect(data = ann_rect, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, fill = fill)) +
geom_line(data = mydf, aes(x = Volume, y = pH), color = "purple") +
scale_fill_identity()
Created on 2020-03-19 by the reprex package (v0.3.0)
Related
I'm trying to plot a geom_rect(). Why do I receive an Error in FUN(X[[i]], ...) : object 'Month' not found? If I run df$Month in my console the object is there:
df$Month
#> [1] 2019-01 2019-02 2019-03
#> Levels: 2019-01 2019-02 2019-03
Here's my code block:
library(tidyverse)
df <- tibble(Month = factor(c("2019-01", "2019-02", "2019-03")),
Value = c(4, 9, 7))
ggplot(df, aes(Month, Value, group = 1)) +
geom_line() +
theme_minimal() +
geom_rect(data =
data.frame(xmin = min(as.integer(df$Month)) - 0.5,
xmax = max(as.integer(df$Month)) + 0.5,
ymin = min(df$Value),
ymax = max(df$Value)),
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
alpha = 0.2, fill = "green")
#> Error in FUN(X[[i]], ...) : object 'Month' not found
This works:
ggplot(df, aes(Month, Value, group = 1)) +
geom_line() +
theme_minimal() +
geom_rect(data =
data.frame(xmin = min(as.integer(df$Month)) - 0.5,
xmax = max(as.integer(df$Month)) + 0.5,
ymin = min(df$Value),
ymax = max(df$Value)),
aes(x = NULL,y = NULL,xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
alpha = 0.2, fill = "green")
by unmapping the inherited x/y aesthetics from the top ggplot call. It's understandable that this might be confusing, though, since the description in ?geom_rect sorta kinda implies that geom_rect isn't looking for those aesthetics at all.
You just have an extra step of setting up a dataframe in geom_rect which coincide with data in ggplot. Simply provide your max and min values to geom_rect and it works:
ggplot(df, aes(Month, Value, group = 1)) +
geom_line() +
theme_minimal() +
geom_rect(aes(xmin = min(as.integer(Month)) - 0.5,
xmax = max(as.integer(Month)) + 0.5,
ymin = min(Value),
ymax = max(Value)),
alpha = 0.2/nrow(df), fill = "green")
I was able to return your desired result by calling df in geom_line() after gemo_rect(). However leaving the Month field as is returned the error: Error: Discrete value supplied to continuous scale.
I worked around this by wrapping as.integer() around Month.
ggplot() +
theme_minimal() +
geom_rect(data =
data.frame(xmin = min(as.integer(df$Month)) - 0.5,
xmax = max(as.integer(df$Month)) + 0.5,
ymin = min(df$Value),
ymax = max(df$Value)),
aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
alpha = 0.2, fill = "green") +
geom_line(data = df, aes(as.integer(Month), Value, group = 1))
You might have to clean up your x-axis label but it achieves desired outcome!
This question already has answers here:
Conditionally change panel background with facet_grid?
(2 answers)
Closed 2 years ago.
I am attempting to shade multiple regions of interest on a scatter plot. Based on this answer, I believe I am forced to leave the intial ggplot() call empty, and supplie the geom_rect() calls before the geom_point() call. I have gotten all of this to work. I can not however apply a facet based on data passed to geom_point().
The following correctly plots my data (scatter plot over red and blue regions of different sizes):
ggplot() +
geom_rect(aes(xmin=885, xmax=1544, ymin=-Inf, ymax=Inf), alpha=.2, fill = "red") +
geom_rect(aes(xmin=1858, xmax=2580, ymin=-Inf, ymax=Inf), alpha=.2, fill = "blue") +
geom_point(data=df, aes(x=Position, y=Max_Freq))
However all of the following produce errors as follows:
+ facet_wrap(~Replicate)
#Error in if (empty(data)) { : missing value where TRUE/FALSE needed
+ facet_wrap(data~Replicate)
#Error in combine_vars(data, params$plot_env, rows, drop = params$drop):
# At least one layer must contain all variables used for facetting
+ facet_wrap(data$Replicate)
#Error in data$Replicate : object of type 'closure' is not subsettable
In other graphs when df is supplied in the ggplot() call (ie ggplot(df, aes(x=Position, y=Max_Freq)) the first option correctly facets the data. Admittedly, I am not well versed in R, but it seems like this should have a simple solution.
One approach is to create a data frame with the rect coordinates that will also have the facet variable. Example:
some data:
df <- data.frame(x = rnorm(20),
y = runif(20),
facet = sample(c("A", "B"),
20,
replace = TRUE))
create a data frame with geom_rect coordinates:
rect1 <- data.frame(xmin = -1,
xmax = 1,
ymin = -Inf,
ymax = Inf,
facet = c("A", "B"))
plot it:
ggplot() +
geom_rect(data = rect1 , aes(xmin = xmin,
xmax = xmax,
ymin = ymin,
ymax = ymax),
alpha = 0.2, fill = "blue") +
geom_point(data = df, aes(x = x, y = y))+
facet_wrap(~facet)
This allows for per facet customization of rectangles. Example:
rect2 <- data.frame(xmin = c(-1, 0),
xmax = c(0, 2),
ymin = c(-Inf, 0.25),
ymax = Inf,
facet = c("A", "B"))
ggplot() +
geom_rect(data = rect2 , aes(xmin = xmin,
xmax = xmax,
ymin = ymin,
ymax = ymax,
fill = facet),
alpha = 0.2) +
geom_point(data = df, aes(x = x, y = y))+
facet_wrap(~facet)
or just to plot rectangles in some facets:
rect3 <- data.frame(xmin = -1,
xmax = 0,
ymin = 0.25,
ymax = Inf,
facet = "A")
This is my dataset example:
df <- data.frame(group = rep(c("group1","group2","group3", "group4", "group5", "group6"), each=3),
X = paste(letters[1:18]),
Y = c(1:18))
As you can see, there are three variables, two of them categorical (group and X). I have constructed a line chart using ggplot2 where the X axis is X and Y axis is Y.
I want to shade the background using the group variable, so that 6 different colors must appear.
I tried this code:
ggplot(df, aes(x = X, y = Y)) +
geom_rect(xmin = 0, xmax = 3, ymin = -0.5, ymax = Inf,
fill = 'blue', alpha = 0.05) +
geom_point(size = 2.5)
But geom_rect() only colorize the area between 0 and 3, in the X axis.
I guess I can do it manually by replicating the the geom_rect() so many times as groups I have. But I am sure there must be a more beautiful code using the variable itself. Any idea?
To get shading for the entire graph, geom_rect needs the xmin and xmax locations for all the rectangles, so these need to be provided by mapping xmin and xmax to columns in the data, rather than hard-coding them.
ggplot(df, aes(x = X, y = Y)) +
geom_rect(aes(xmin = X, xmax = dplyr::lead(X), ymin = -0.5, ymax = Inf, fill = group),
alpha = 0.5) +
geom_point(size = 2.5) +
theme_classic()
Here is one way:
df2 <- df %>% mutate(Xn=as.numeric(X))
ggplot(df2) +
geom_rect(aes(xmin=Xn-.5, xmax=Xn+.5, ymin=-Inf, ymax=Inf, fill = group), alpha=0.5, stat="identity") +
geom_point(aes(x = Xn, y = Y), size = 2.5) + scale_x_continuous(breaks=df2$Xn, labels=df2$X)
This will get you close - need to add a couple columns to your data frame. Using dplyr here.
df <- df %>%
group_by(group) %>%
mutate(xmin = sort(X)[1],
xmax = sort(X, decreasing = T)[1])
ggplot(df, aes(x = X, y = Y)) +
geom_point(size = 2.5) +
geom_rect(aes(xmin=xmin, xmax = xmax, fill = group), ymin = -0.5, ymax = Inf,
alpha = 0.05)
Based on the answer https://stackoverflow.com/a/26748780/1172302 and the following data
"Category","Driver","Intensity","Intensity (Numeric)","Intensity (Fraction)","ymin","ymax","Color"
"Ec","Loss","High",2,0.0833333333,0,0.0833333333,"orange"
"Ec","Stress","High",2,0.0833333333,0.0833333333,0.1666666666,"orange"
"Ec","Expectations","High",2,0.0833333333,0.1666666666,0.2499999999,"orange"
"Go","Lack","Very high",3,0.125,0.2499999999,0.3749999999,"red"
"Go","Competition","Very high",3,0.125,0.3749999999,0.4999999999,"red"
"So","Disrespect","Low",1,0.0833333333,0.4999999999,0.5833333332,"yellow"
"So","Harassment","High",2,0.0833333333,0.5833333332,0.6666666665,"orange"
"So","Upheaval","Low",1,0.0833333333,0.6666666665,0.7499999998,"yellow"
"Se","Vulnerability","High",2,0.0833333333,0.7499999998,0.8333333331,"orange"
"Se","Police","Very high",3,0.0833333333,0.8333333331,0.9166666664,"red"
"Se","Presence","Low",1,0.0833333333,0.9166666664,0.9999999997,"yellow"
a pie can be derived via
# prepare data
cd <- read.csv("piedata.csv", header = TRUE, check.names = FALSE )[1:8]
cd[[2]] <- as.character(cd[[2]])
cd[[3]] <- factor(cd[[3]], levels(cd[[3]])[c(2, 1, 3)])
# load library
library(ggplot2)
# plot
ggplot(cd) +
geom_rect( aes ( fill = cd[[2]],
ymax = ymax, ymin = ymin, xmax = 4, xmin = 2)) +
geom_rect( aes ( fill = cd[[1]],
ymax = ymax, ymin = ymin, xmax = 2, xmin = 0)) +
xlim( c(0, 4)) +
theme(aspect.ratio = 1) +
coord_polar(theta="y") + theme_void()
How can I use the colors defined in cd$Color for the segments of the outer circle, define another four custom colors for the inner circle and, finally, avoid having the categories from cd$Category ("Ec", "Go", "So" and "Se") be present in the legend alltogether?
I can't answer all of your questions, but if you extend your data frame with an additional column describing the inner color and rewrite the plot code as followed, it should work
#plot
ggplot(cd) +
geom_rect(aes (fill = cd[[2]],
ymax = ymax, ymin = ymin, xmax = 4, xmin = 2), fill = cd$Color_in) +
geom_rect( aes ( fill = cd[[1]],
ymax = ymax, ymin = ymin, xmax = 2, xmin = 0), fill = cd$Color_out) +
xlim(c(0, 4)) +
theme(aspect.ratio = 1) +
coord_polar(theta="y")+theme_void()
I'm trying to shade a certain area of time series plot using geom_rect.
I used the code below to create the time series plot
library(ggplot2)
set.seed(123)
date <- as.Date(seq(as.Date("2014-01-01"), as.Date("2015-12-31"), by = 1), format="%Y-%m-%d")
a <- runif(730, 3000, 120000)
df <- data.frame(date, a)
ggplot() +
geom_line(data = df, aes(x = date, y = a))
I tried to create the rectangle using geom_rect following the answer to this question
library(lubridate)
rectangle <- data.frame(xmin = decimal_date(as.Date(c("2014-10-01"))),
xmax = decimal_date(as.Date(c("2015-02-01"))),
ymin = -Inf, ymax = Inf)
ggplot() +
geom_line(data = df, aes(x = date, y = a)) +
geom_rect(data = rectangle, aes(xmin=xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = "red", alpha = 0.5)
I got this error
Error: Invalid input: date_trans works with objects of class Date only
Any suggestions how to fix that would be appreciated.
This works:
library(lubridate)
rectangle <- data.frame(xmin = as.Date(c("2014-10-01")),
xmax = as.Date(c("2015-02-01")),
ymin = -Inf, ymax = Inf)
ggplot() +
geom_line(data = df, aes(x = date, y = a)) +
geom_rect(data = rectangle, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax),
fill = "red", alpha = 0.5)
Just remove decimal_date()