I am trying to change the color of a line in a line graph based on the Y axis value.
My specific application: I am visualizing wind speed and direction. Ideally I'd do this with a rose plot, but I am comparing it to other data that is presented in line graphs. I currently have wind direction in degrees, but it is understandably difficult to quickly interpret. I would like to classify the line into 8 differently-colored categories based on cardinal directions (N, NE, E, SE, S, SW, W, NW) so it's easier to understand the wind direction. Nevermind the potentially overwhelming number of colors in the figure, I just want to give this a shot as what I currently have is quite difficult to interpret.
I am very rusty in R and am not equipped with the proper terminology to search, nor do I have a good idea of where to start.
Is this possible? Would it require breaking up the series into many different line segments?
A solution in R or even Excel would be appreciated.
Edit: Here is an example of what the data looks like
# random wind speed and direction over 24 hours, hourly
set.seed(123)
date_time <- seq.POSIXt(ISOdate(2023,1,20, hour = 00), ISOdate(2023, 1, 20, hour = 23), "hour")
wind_speed <- runif(24, 0, 20)
wind_direction <- runif(24, 0, 359)
df_wind <- data.frame(date_time, wind_speed, wind_direction)
The idea of a discrete-time x-axis makes this a bit challenging because, for instance, the wind direction may change across all directions over the course of each unit of time. That would make a blended colored line - or even a segmented colored line - quite confusing to look at.
One alternative option would be to put bands representing the the directions in the background, for instance:
The code to recreate this plot is below, which uses rect
and adjustcolor
to create the transparent bands. I also created a named vector directs
to simplify the direction categories.
## Identify directions
directs <- setNames(seq(0, 315, by = 45),
c("North", "North-east", "East",
"South-east", "South", "South-west",
"West", "North-west"))
# Initiate blank plot
plot(df_wind$date_time, df_wind$wind_direction, type = "n",
bty = "n", xlab = "Time", ylab = "Direction",
ylim = c(0, 360))
# Plot bands and text
rect(xleft = min(df_wind$date_time), xright = max(df_wind$date_time),
ybottom = directs, ytop = c(directs[-1], 360),
col = adjustcolor(1:8, alpha.f = 0.2), border = NA)
text(names(directs), pos = 4,
x = min(df_wind$date_time), y = directs + 22.5, col = 1:8)
text(names(directs), pos = 2,
x = max(df_wind$date_time), y = directs + 22.5, col = 1:8)
# Plot lines over bands
lines(df_wind$date_time, df_wind$wind_direction)
Another option is to plot the colors of the points, not the lines, like this:
For this I created a new variable in the dataset df_wind$direction
:
df_wind <- dplyr::mutate(df_wind, direction = dplyr::case_when(
wind_direction <= 45 ~ "North",
wind_direction > 45 & wind_direction <= 90 ~ "North-east",
wind_direction > 90 & wind_direction <= 135 ~ "East",
wind_direction > 135 & wind_direction <= 180 ~ "South-east",
wind_direction > 180 & wind_direction <= 225 ~ "South",
wind_direction > 225 & wind_direction <= 270 ~ "South-west",
wind_direction > 270 & wind_direction <= 315 ~ "West",
wind_direction > 315 ~ "North-west"
))
dirs <- names(directs)
plot(df_wind$date_time, df_wind$wind_direction, type = "l",
bty = "n", xlab = "Time", ylab = "Direction",
ylim = c(0, 360))
for(i in seq_along(unique(df_wind$direction))){
points(df_wind$date_time[df_wind$direction == dirs[i]],
df_wind$wind_direction[df_wind$direction == dirs[i]],
pch = 21, bg = i)
}
legend("topright", dirs, pch = 21, pt.bg = 1:8, bty = "n", ncol = 2)
Or why not both?
plot(df_wind$date_time, df_wind$wind_direction, type = "l",
bty = "n", xlab = "Time", ylab = "Direction",
ylim = c(0, 360))
rect(xleft = min(df_wind$date_time), xright = max(df_wind$date_time),
ybottom = directs, ytop = c(directs[-1], 360),
col = adjustcolor(1:8, alpha.f = 0.2), border = NA)
for(i in seq_along(unique(df_wind$direction))){
points(df_wind$date_time[df_wind$direction == dirs[i]],
df_wind$wind_direction[df_wind$direction == dirs[i]],
pch = 21, bg = i)
}
legend("topright", dirs, pch = 21, pt.bg = 1:8, bty = "n", ncol = 2)
Lastly, you could color the lines (and add colored dots - to remove them just take out the points
loop) based on the more recent position, as described in your comment, but again you can see the confusion.
plot(df_wind$date_time, df_wind$wind_direction, type = "n",
bty = "n", xlab = "Time", ylab = "Direction",
ylim = c(0, 360))
for(i in 1:nrow(df_wind)){
if(i != nrow(df_wind)){
lines(df_wind$date_time[i:(i + 1)], df_wind$wind_direction[i:(i + 1)],
col = grep(df_wind$direction[i+1], names(directs)))
}
for(i in seq_along(unique(df_wind$direction))){
points(df_wind$date_time[df_wind$direction == dirs[i]],
df_wind$wind_direction[df_wind$direction == dirs[i]],
pch = 21, bg = i)
}
}