Related
I made a plot with points connected with a line. In this plot I want to draw a vertical line from a point on the x-axis to the intersection with the plot line.And at the intersection, I want to draw a horizontal line to the Y-axis. I have searched several websites, forums and tutorials, but I still can't do it. Any help?
library(ggplot2)
X <- 1:5
Y <- c(2, 6, 4, 7, 12)
DF <- data.frame(X, Y)
ggplot(data = DF,
aes(x = X,
y = Y)) +
geom_point() +
geom_line() +
geom_vline(xintercept = 4.5,
linetype = 2)
Result so far:
Example of desired result:
Already commented by #Eric but also sort of answered by #akrun in link, by applyng the apply function to the function of #akrun you can also plot all the points of the DF, something like this would work for you:
library(ggplot2)
X <- 1:5
Y <- c(2, 6, 4, 7, 12)
DF <- data.frame(X, Y)
draw_guides<- function(x, y) {
list(geom_segment(aes(x = -Inf, xend = x, y = y, yend = y), linetype = "dashed"),
geom_segment(aes(x = x, xend = x, y = y, yend = -Inf), linetype = "dashed"))
}
ggplot(data = DF,
aes(x = X,
y = Y)) +
geom_point() +
geom_line() +
apply(DF, 1, function(y) draw_guides(y[1], y[2]))
As already mentioned by #Eric in his comment geom_segment is the way to go to achieve your desired result. Moreover, you have to manually compute the y value where the segments should cut the geom_line which could be achieved using approx. As quick approach may look like so:
library(ggplot2)
X <- 1:5
Y <- c(2, 6, 4, 7, 12)
DF <- data.frame(X, Y)
# vertical line
vsegment <- function(x, X, Y) {
geom_segment(aes(x = x, xend = x, y = -Inf, yend = approx(X, Y, x)$y),
linetype = 2)
}
# horizontal line
hsegment <- function(x, X, Y) {
geom_segment(aes(x = -Inf, xend = x, y = approx(X, Y, x)$y, yend = approx(X, Y, x)$y),
linetype = 2)
}
ggplot(data = DF,
aes(x = X,
y = Y)) +
geom_point() +
geom_line() +
vsegment(4.5, X, Y) +
hsegment(4.5, X, Y)
You can use geom_path() as well for this
X <- 1:5
Y <- c(2, 6, 4, 7, 12)
DF <- data.frame(X, Y)
ggplot(data = DF, aes(x = X, y = Y)) +
geom_point() +
geom_line() +
geom_path(data = data.frame(x = c(-Inf, 4.5, 4.5), y = c(approx(X, Y, 4.5)$y, approx(X, Y, 4.5)$y, -Inf)), aes(x, y), color = "red", linetype = 2)
If you want it more flexible for more intercepts you can use this function.
Note the ... part, so you can pass the geom_path arguments along, like color, linetype, size, etc. It supports an intercept based on the x value or based on the y value.
my_intercept <- function(x, y, ...) {
if (!missing(x)) dt <- data.frame(x = c(-Inf, x, x), y = c(approx(X, Y, x)$y, approx(X, Y, x)$y, -Inf))
if (!missing(y)) dt <- data.frame(x = c(-Inf, approx(Y, X, y)$y, approx(Y, X, y)$y), y = c(y, y, -Inf))
geom_path(data = dt, aes(x, y), ...)
}
ggplot(data = DF, aes(x = X, y = Y)) +
geom_point() +
geom_line() +
my_intercept(x = 4.5, color = "blue", linetype = 2) +
my_intercept(y = 5, color = "red", linetype = 4)
I want the vertical lines to not go beyond the curve line after they intersect
Example data:
x <- 1:50
dat <- data.frame(x = x, y = 1 - exp(-x/43)^4)
ggplot(dat, aes(x = x, y = y)) +
geom_line() +
geom_vline(xintercept = c(10, 20, 30),
lty = "dashed")
Use geom_segment instead:
ggplot(dat, aes(x = x, y = y)) +
geom_line() +
geom_segment(aes(x = x, xend = x, y = min(dat$y), yend = y),
data = dat[ dat$x %in% c(10, 20, 30), ],
lty = "dashed")
I'm trying to create a boxplot using ggplot2 with :
X as a continuous variable
Colors for different groups
Here is an example :
x <- sample(c(1,2,5),300,replace = TRUE)
y <- sapply(x,function(mu) rnorm(1,mean = mu))
color <- sample(c("color 1","color 2"),300,replace = TRUE)
data <- data.frame(x, y, color)
I can either have colors and x as a factor :
ggplot(data = data) + geom_boxplot(aes(x = factor(x),y = y,col = color))
or x as a continuous variable and no colors :
ggplot(data = data) + geom_boxplot(aes(x = x,y = y,group = x))
But not both.
Does somebody know how to do this ?
Thanks
I think you need one more column for group, which is the combination of color and x. For example, how about simply paste()ing them?
set.seed(1)
x <- sample(c(1,2,5),300,replace = TRUE)
y <- sapply(x,function(mu) rnorm(1,mean = mu))
color <- sample(c("color 1","color 2"),300,replace = TRUE)
data <- data.frame(x, y, color)
library(ggplot2)
ggplot(data = data) +
geom_boxplot(aes(x = x, y = y, col = color, group = paste(color, x)))
You can use scales to change the x-axis scale.
library(ggplot2)
library(scales)
x <- sample(c(1,2,5),300,replace = TRUE)
y <- sapply(x,function(mu) rnorm(1,mean = mu))
color <- sample(c("color 1","color 2"),300,replace = TRUE)
data <- data.frame(x, y, color)
ggplot(data = data) + geom_boxplot(aes(x = factor(x),y = y,col = color)) + scale_x_discrete(limit = c('1','2','3','4','5'))
Hack for dynamic limits:
min = min(data$x)
max = max(data$x)
limits <- as.character(seq(min:max))
ggplot(data = data) + geom_boxplot(aes(x = factor(x),y = y,col = color)) + scale_x_discrete(limit = limits)
You could misuse the fill aesthetic:
ggplot(data = data) +
geom_boxplot(aes(x = x, y = y, col = color, fill = factor(x))) +
scale_fill_manual(values = rep(NA, 3), guide = "none")
How to adjust the height of each geom_line depending on the facet group (y-lims differ depending on the group, see image below)?
I tried to build a custom data.frame which contains heights for each condition but this is not accepted by geom_line.
I have this little working example:
carData <- mtcars
carData$cyl <- factor(carData$cyl)
maxval <- max(carData$mpg)
maxval <- maxval * 1.1
lowval <- maxval - maxval * 0.02
txtval <- maxval * 1.04
llev <- "4"
rlev <- "6"
lpos <- which(levels(carData$cyl) == llev)
rpos <- which(levels(carData$cyl) == rlev)
mpos <- (lpos + rpos) / 2
df1 <- data.frame(a = c(lpos,lpos,rpos,rpos), b = c(lowval, maxval, maxval, lowval))
p <- ggplot(carData, aes(cyl, mpg))
p <- p + geom_boxplot()
p <- p + geom_line(data = df1, aes(x = a, y = b)) + annotate("text", x = mpos, y = txtval, label = "3.0")
p <- p + facet_wrap( ~ gear,ncol=2,scales="free")
You need to capture the variable you are using to facet with, in your summary data.frame. We could capture group wise maxima and use them for the y positions of the geom_segment() and geom_text:
library(tidyverse)
# get the max for each gear facet
df2 <- carData %>% group_by(gear) %>%
summarise(ypos = max(mpg)*1.1) %>%
mutate(x = lpos, xend = rpos) # use your factor level locators
p <- ggplot(carData, aes(cyl, mpg)) +
geom_boxplot() +
geom_segment(data = df2, aes(y = ypos, yend = ypos, x = x, xend = xend)) +
geom_text(data = df2, aes(y = ypos*1.02, x = mean(c(x, xend))), label = "3.0") +
facet_wrap( ~ gear,ncol=2, scales="free")
# if you want the end ticks
p + geom_segment(data = df2, aes(y = ypos, yend = ypos * .99, x = x, xend = x)) +
geom_segment(data = df2, aes(y = ypos, yend = ypos *.99, x = xend, xend = xend))
I want to produce a scatter plot and mean value with error bars. My code is as follows. When I add the geom_errorbar(), there is an error message:
Error in FUN(X[[i]], ...) : object 'value' not found
Z <- c(.1,.5,1.)
T <- seq(1:10)
ZT <- expand.grid(Z,T)
colnames(ZT) <- c("Z","T")
n <- nrow(ZT)
nrep <- 100
rmat <- replicate(nrep, rnorm(n))
ave <- apply(rmat,1,mean)
var <- apply(rmat,1,var)
se <- sqrt(var)/sqrt(nrep)
rmat.summary <- as.data.frame(cbind(ZT,ave,se))
colnames(rmat.summary) <- c("Z","T","ave","se")
library(reshape)
library(ggplot2)
rmat <- as.data.frame(cbind(ZT,rmat))
rmat <- melt(as.data.frame(rmat),id=c(1,2))
ggplot(rmat, aes(x = T, y = value)) + geom_point() + geom_line(data =
rmat.summary, aes(x = T, y = ave)) + facet_wrap( ~ Z)
ggplot(rmat, aes(x = T, y = value)) + geom_point() + geom_line(data =
rmat.summary, aes(x = T, y = ave)) +
geom_errorbar(data = rmat.summary, aes(ymin = ave - se, ymax = ave + se))
+ facet_wrap( ~ Z)
So can anybody please help me to correct this error? Thanks in advance!
This should work:
ggplot() +
geom_point(data = rmat, aes(x = T, y = value)) +
geom_line(data = rmat.summary, aes(x = T, y = ave)) +
geom_errorbar(data = rmat.summary, aes(x = T, y = ave, ymin = ave - se, ymax = ave + se)) +
facet_wrap( ~ Z)
But I think you have to play around with ymin and ymax.