Home > database >  Color lines by zones
Color lines by zones

Time:11-21

I´m trying to plot a heart beat for 24 hours, I have data for every second. The problem I´m running through is that when I plot the data and assign to each beat the "intensity zone", I get a straight line in the graph (check the blue line between 4:00 and 10:00) instead of just the color for that data. Also, I´m getting a line for NA values, and although I have added na.rm=TRUE it still shows in the graph.

enter image description here

Here's the code and the enter image description here

As tjebo noted, there is still some overlap in the lines. I understand, though, that there is a specific aesthetic you are looking to achieve, and I'd like a cigar. If we go back to your original solution, geom_line() didn't work because it creates a continuous line for each factor, in this case the Intensity. I suggested you use geom_segment(). With this, you define the start and end points and can determine the color of the line. The problem here is that the points fall into one zone or another, but the lines may cross over the zone/intensities. That is why my early graph had overlaps. If you think it is appropriate, you need to add more points to your data to account for when the thresholds are crossed. Essentially, it adds two new points that are just at and over the threshold. So I've done that in the code below and have gotten you closer. The problem I didn't solve for are the cases when a zone is skipped, for example, it goes from zone 1/sedentary to zone 3/moderate. So you'll note there appear some small overlaps. That could be worked out, but will leave that to you.

library(tidyverse)
library(hms)
library(dplyr)
library(lubridate)
library(ggplot2)


#Import dataset#

graph <-read.csv("graph.csv", sep=";", na.strings = "?")
graph$HR <- as.numeric(as.character(graph$HR))
graph$Zone <- as.numeric(as.character(graph$Zone))
graph$Time =as.POSIXct(graph$Time,format="%H:%M:%S")

#graph$Time = as_hms(graph$Time)  This throws off scale_x_datetime() so didn't use

#remove NA values
graph <- graph[complete.cases(graph),]

#understand zones
graph %>%
    group_by(Zone) %>%
    summarise(min = min(HR), max = max(HR))


#create Heart Rate Theshold values
thresholds <- tibble("Zone" = c(1, 2, 3, 4), "HRT" = c(78, 97, 116, Inf))
graph <- merge(thresholds, graph, by = "Zone")

graph <- graph[order(graph$Time),]




#generate new data points for instances the Zone is crossed
#note we introduce a new time point that is between the two original times
new_points <- tibble()
    
for(r in 1:(nrow(graph)-1)){
    if(graph[r,"Zone"] == graph[r 1, "Zone"]){
        next
    } else if(graph[r,"Zone"] < graph[r 1, "Zone"]) {
        new <- tibble(Zone = c(graph[r,"Zone"], graph[r 1, "Zone"]),
                    Time = c(graph[r,"Time"]   0.5, graph[r 1, "Time"] - 0.4),
                    HR = c(graph[r, "HRT"], graph[r, "HRT"]   1),
                    Intensity = c(graph[r,"Intensity"], graph[r 1, "Intensity"]))
    } else if(graph[r,"Zone"] > graph[r 1, "Zone"]) {
        new <- tibble(Zone = c(graph[r,"Zone"], graph[r 1, "Zone"]),
                      Time = c(graph[r,"Time"]   0.5, graph[r 1, "Time"] - 0.4),
                      HR = c(graph[r 1, "HRT"]  1 , graph[r 1, "HRT"]),
                      Intensity = c(graph[r,"Intensity"], graph[r 1, "Intensity"]))
    }
    new_points <- rbind(new_points, new)
}

new_points <- merge(thresholds, new_points, by = "Zone")

#merge and reorder
graph <- rbind(graph, new_points)
graph <- graph[order(graph$Time),]

#create end points for segments
graph$time_end <- lead(graph$Time, n=1)
graph$HR_end <- lead(graph$HR, n = 1)


####Creating figure####

graph$intensity<-factor(graph$Intensity, 
                        levels =c("Sedentary", "Light", "Moderate", "Vigorous"))

ggplot(graph, aes(x = Time, y = HR))  
    geom_segment(aes(xend = time_end,  yend = HR_end, color = intensity))  
    labs(x = "Time", y = "Heart Rate (bpm)") 
    scale_color_discrete("Intensity:", labels = c("Sedentary", "Light",
                                                  "Moderate", "Vigorous"))  
    theme(legend.title = element_text(#family = "Playfair",
                                      color = "chocolate",
                                      size = 10, face = 2)) 
    theme(panel.grid = element_blank())  
    geom_rug(show.legend = FALSE, aes(color = intensity)) 
    scale_x_datetime(date_breaks = "4 hours", date_labels = "%H:%M") 
    ylim(c(0,160)) 
    scale_y_continuous(breaks = seq(0, 160, by =40))

enter image description here

CodePudding user response:

May I suggest a different (and easier!) visualisation - just color the background :)

library(tidyverse)

hf <- data.frame(heartrate = rnorm(100), time= 1:100)
zones <- data.frame(xmin = -Inf, xmax = Inf, ymin = c(-Inf, -1, 1), ymax = c(-1, 1, Inf), 
                    zones = fct_inorder(c("low", "moderate", "high")))

ggplot(hf, aes(time, heartrate, group = 1 ))  
  geom_rect(data = zones, aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax, 
                              fill = zones), inherit.aes = FALSE)  
  geom_line()  
  scale_fill_brewer()

Created on 2021-11-20 by the reprex package (v2.0.1)

  • Related