Reputation: 7445
How can I show the direction (heading) of observations using ggplot2? Is there a way to adjust shape=17
(triangle) so that it "points" to the next time observations?
Example Code
library(ggplot2)
dat <- data.frame(id = c(1, 1, 2, 2, 3, 3),
time = c(1, 2, 1, 2, 1, 2),
x = c(.1, .2, .3, .4, .5, .6),
y = c(.6, .25, .4, .33, .2, .51))
ggplot(dat, aes(x, y, color=factor(id))) +
geom_point(shape=17) +
# geom_line() +
NULL
Upvotes: 4
Views: 208
Reputation: 29153
Combining ideas from dario's answer, How to scale a 2D vector and keep direction and Arranging arrows between points nicely in ggplot2
library(dplyr)
library(tidyr)
library(ggplot2)
dat %>%
pivot_wider(names_from = time, values_from = c(x, y)) %>%
group_by(id) %>%
mutate(x_v = x_2 - x_1, y_v = y_2 - y_1) %>%
mutate_at(vars("x_v", "y_v"),
list(units =~ (. / sqrt((x_v)^2 + (y_v)^2))/1000)) %>%
ggplot(aes(x=x_1, y=y_1, colour = factor(id))) +
geom_segment(aes(xend = x_1 + x_v_units, yend = y_1 + y_v_units),
show.legend = F,
arrow = arrow(length = unit(.3,"cm"), type="closed", angle = 20)) +
geom_point(data = (dat %>% filter(time == 2)), aes(x, y), shape=15, size=2) +
labs(x="x", y="y", colour="id") +
theme_bw()
Data:
dat <- data.frame(id = c(1, 1, 2, 2, 3, 3),
time = c(1, 2, 1, 2, 1, 2),
x = c(.1, .2, .3, .4, .5, .6),
y = c(.6, .25, .4, .33, .2, .51))
Upvotes: 2
Reputation: 6483
We can use ggplot2::geom_segment
after we reshape the data using
dplyr
and tidyr::pivot_wider
:
dat <- data.frame(id = c(1, 1, 2, 2, 3, 3),
time = c(1, 2, 1, 2, 1, 2),
x = c(.1, .2, .3, .4, .5, .6),
y = c(.6, .25, .4, .33, .2, .51))
library(dplyr)
library(tidyr)
library(ggplot2)
dat %>%
pivot_wider(names_from = time, values_from = c(x, y)) %>%
ggplot(aes(x=x_1, y=y_1, color=factor(id))) +
geom_segment(aes(xend = x_2, yend = y_2),
arrow = arrow(length = unit(.3,"cm"))) +
labs(x="x", y="y", color="id")
but I just want the arrow pointing without lines.
I'm not sure how we should handle the second point for each id (since it has not direction) but if we want to omit them from the plot we can do:
library(dplyr)
library(tidyr)
library(ggplot2)
dat %>%
group_by(id) %>%
arrange(id, time) %>%
mutate(x_2 = x + 0.0001 * (lead(x) - x),
y_2 = y + 0.0001 * (lead(y) - y)) %>%
filter(!is.na(x_2)) %>%
ggplot(aes(x=x, y=y, color=factor(id))) +
geom_segment(aes(xend = x_2, yend = y_2),
arrow = arrow(length = unit(.3,"cm"))) +
labs(x="x", y="y", color="id")
Or if we want the arrows to point to the next measurement, independently of the color we can use the code below (now there is only the last point missing because of no direction):
library(dplyr)
library(tidyr)
library(ggplot2)
dat %>%
arrange(id, time) %>%
mutate(x_2 = x + 0.0001 * (lead(x) - x),
y_2 = y + 0.0001 * (lead(y) - y)) %>%
filter(!is.na(x_2)) %>%
ggplot(aes(x=x, y=y, color=factor(id))) +
geom_segment(aes(xend = x_2, yend = y_2),
arrow = arrow(length = unit(.3,"cm"))) +
labs(x="x", y="y", color="id")
If we want to keep the 'last' measures we could add them in another geom_point
layer...
Upvotes: 3