自転車エルゴメータによる漸増運動負荷試験

O2Uptake_Power.qmd

Author

Kizen Sasaki

Published

2024 June 07

Modified

2024 July 30

 Figure 1 は自転車エルゴメータによる漸増運動負荷試験による心拍数と酸素摂取量の関係を示す。漸増運動負荷試験は,運動負荷を段階的に増加させながら,酸素摂取量(V̇O2)を測定すること,最大酸素摂取量(V̇O2max)を推定するための試験である。V̇O2maxは、運動能力の指標として広く用いられてい。  

Code
library(tidyverse)
library(ggplot2)

# ダミーデータの作成
# heart_rate <- c(120,135, 145, 160, 173, 180, 190)
#        vo2 <- c(800, 1100, 1300, 1600, 2127, 2400, 2455)

heart_rate <- c(70, 90, 110, 130, 150, 170, 190)
vo2 <- c(892.5, 1275, 1657.5, 2040, 2227.5, 2415, 2745)
time <- c(0, 30, 60, 90, 120, 150, 180, 210)

# データフレームの作成
df_vo2 <- data.frame(heart_rate, vo2)
df_50_vo2max <- data.frame(heart_rate = c(70, 190), vo2 = c(1372.5, 1372.5))

# フォントの設定
font_family <- "Times New Roman"
font_style <- "bold"
my_theme <- theme_bw() +
  theme(
    plot.title = element_text(size = 12, family = font_family, face = font_style, hjust = 0.5),
    axis.title.x = element_text(size = 12, family = font_family, face = font_style),
    axis.title.y = element_text(size = 12, family = font_family, face = font_style, angle = 90, vjust = 0.5),
    axis.text.x = element_text(size = 10, family = font_family, face = font_style),
    axis.text.y = element_text(size = 10, family = font_family, face = font_style),
    legend.title = element_text(size = 10, family = font_family, face = font_style),
    legend.text = element_text(size = 8, family = font_family, face = font_style)
  )

# 一次回帰モデルの作成
model <- lm(vo2 ~ heart_rate, data = df_vo2)

# 50%V̇O2maxと70%V̇O2maxの線が回帰直線と交わる点を計算
intercept <- coef(model)[1]
slope <- coef(model)[2]
fifty_percent_heart_rate <- (1372.5 - intercept) / slope
seventy_percent_heart_rate <- (1921.5 - intercept) / slope

# 回帰式とR^2の文字列を作成
regression_equation <- paste0("bold(italic(y) == ", round(slope, 2), " * italic(x) + ", round(intercept, 3), ")")
r_squared <- paste0("bold(italic(R)^2 == ", round(summary(model)$r.squared, 3), ")")

# プロットの作成
p2 <- ggplot() +
    geom_point(data = df_vo2, aes(x = heart_rate, y = vo2)) +
    scale_y_continuous(expand = c(0, 0), limits = c(0, 2500), breaks = seq(0, 2500, 500)) + # y軸の設定
    # 回帰線のコード
    geom_abline(intercept = intercept, slope = slope, color = "red") +
    geom_segment(aes(x = 70, xend = fifty_percent_heart_rate, y = 1360, yend = 1360), # 50%V̇O2max時 水平線
                 linetype = 2, linewidth = 0.5, color = "grey") +
    geom_segment(aes(x = fifty_percent_heart_rate, xend = fifty_percent_heart_rate, y = 0, yend = 1360), # 50%V̇O2max時 垂直線
                 linetype = 2, linewidth = 0.5, color = "grey") +
  
    geom_segment(aes(x = 70, xend = seventy_percent_heart_rate, y = 1921.5, yend = 1921.5), # 70%V̇O2max時
                 linetype = "dashed", linewidth = 0.5, color = "grey") +
    geom_segment(aes(x = seventy_percent_heart_rate, xend = seventy_percent_heart_rate, y = 0, yend = 1921.5), # 70%V̇O2max時
                 linetype = "dashed", linewidth = 0.5, color = "grey") +
  
    geom_text(aes(x = 83, y = 1450, vjust = 0, label = "50%VO2max"), angle = 0, size = 4) +
    geom_text(aes(x = seventy_percent_heart_rate - 40, y = 1921.5 + 50, vjust = 0, label = "70%VO2max"), angle = 0, size = 4) +
  
    geom_text(aes(x = 150, y = 2650, label = "Max Oxygen Uptake\n2745 mL/min"), 
              angle = 0, hjust = 0, size = 4) +
  
    labs(x = "Heart Rate (bpm)", y = expression(paste(dot(V), O[2], " (mL/min)"))) +
    scale_x_continuous(breaks = seq(70, 190, 20), limits = c(70, 190)) +
    scale_y_continuous(breaks = seq(0, 2500, 500)) +
    my_theme +
    theme(plot.title = element_text(hjust = 0.5),
          axis.title.y = element_text(angle = 90, vjust = 0.5),
          axis.text = element_text(size = 10),
          axis.title = element_text(size = 12)) +
    # annotate("text", x = 75, y = 125, label = "Resting Metabolic Rate", 
    #          angle = 0, vjust = -0.5, size = 4, color = "darkblue") +
    scale_y_continuous(sec.axis = sec_axis(~ . * 180 / 2745, name = NULL, breaks = NULL)) +
    # 回帰式とR^2をグラフ左上に追加
    annotate("text", x = 92, y = 2650, label = regression_equation, size = 4, color = "black", parse = TRUE) +
    annotate("text", x = 85, y = 2450, label = r_squared, size = 4, color = "black", parse = TRUE) +
  # 50%HRと70%HRの交点に大きなXを追加
  annotate("text", x = fifty_percent_heart_rate, y = 1360, label = "X", size = 5, color = "grey") +
  annotate("text", x = seventy_percent_heart_rate, y = 1921.5, label = "X", size = 5, color = "grey")


# p2 <- p2 + # patchworkで結合するときにy軸タイトルとラベルを消す。以外は追加コードいらない
#   theme(
#     axis.title.y = element_blank(),
#     axis.text.y = element_blank(),
#     axis.ticks.y = element_blank()
#   )
p2
Figure 1: Oxygen Uptake and Heart Rate during Cycling Exercise

 Figure 2 は自転車エルゴメータによる漸増運動負荷試験の結果を示す。漸増運動負荷試験は,運動負荷を段階的に増加させながら,酸素摂取量(V̇O2)を測定すること,最大酸素摂取量(V̇O2max)を推定するための試験である。V̇O2maxは、運動能力の指標として広く用いられてい。  

Code
library(tidyverse)
library(ggplot2)
library(patchwork)

# データの作成
work_rate <- c(30, 60, 90, 120, 150, 180, 210)
vo2 <- c(892.5, 1275, 1657.5, 2040, 2227.5, 2415, 2745)
time <- c(0, 30, 60, 90, 120, 150, 180, 210)
power_output <- c(0, 0, 30, 60, 90, 120, 150, 180)
# データフレームの作成
df_vo2 <- data.frame(work_rate, vo2)
df_power <- data.frame(time, power_output)
df_50_vo2max <- data.frame(work_rate = c(0, 210), vo2 = c(1372.5, 1372.5))
# フォントの設定
font_family <- "Times New Roman"
font_style <- "bold"
my_theme <- theme_bw() +
  theme(
    plot.title = element_text(size = 12, family = font_family, face = font_style, hjust = 0.5),
    axis.title.x = element_text(size = 12, family = font_family, face = font_style),
    axis.title.y = element_text(size = 12, family = font_family, face = font_style, angle = 90, vjust = 0.5),
    axis.text.x = element_text(size = 10, family = font_family, face = font_style),
    axis.text.y = element_text(size = 10, family = font_family, face = font_style),
    legend.title = element_text(size = 10, family = font_family, face = font_style),
    legend.text = element_text(size = 8, family = font_family, face = font_style)
  )

# 一次回帰モデルの作成
model <- lm(vo2 ~ work_rate, data = df_vo2)

# 50%V̇O2maxと70%V̇O2maxの線が回帰直線と交わる点を計算
intercept <- coef(model)[1]
slope <- coef(model)[2]
fifty_percent_work_rate <- (1372.5 - intercept) / slope
seventy_percent_work_rate <- (1921.5 - intercept) / slope

# 回帰式とR^2の文字列を作成
regression_equation <- paste0("bold(italic(y) == ", round(slope, 2), " * italic(x) + ", round(intercept, 2), ")")
r_squared <- paste0("bold(italic(R)^2 == ", round(summary(model)$r.squared, 2), ")")

# プロットの作成
p1 <- ggplot() +
    geom_bar(data = df_vo2, 
             aes(x = work_rate, y = vo2 / 10), # 漸増運動負荷Wのスケールに合せるために10で割る不要
             stat = "identity", fill = "skyblue", # color = "darkblue", # nudge=15で30Wからはじまるように
             width = 30, position = position_nudge(x =15)) +        # 棒の隙間30で隙間なし
    scale_y_continuous(expand = c(0, 0), limits = c(0, 2500), breaks = seq(0, 2500, 500)) + # y軸の設定
    geom_point(data = df_vo2, aes(x = work_rate, y = vo2)) +
    # 回帰線のコード
    geom_abline(intercept = intercept, slope = slope, color = "red") +
    #geom_line(data = df_50_vo2max, aes(x = work_rate, y = vo2), linetype = "dashed") +
    geom_segment(aes(x = 0, xend = fifty_percent_work_rate, y = 1360, yend = 1360), # 50%V̇O2max時 水平線
                 linetype = 2, linewidth = 0.5, color = "grey") +
    geom_segment(aes(x = fifty_percent_work_rate, xend = fifty_percent_work_rate, y = 0, yend = 1360), # 50%V̇O2max時 垂直線
                 linetype = 2, linewidth = 0.5, color = "grey") +
  
    geom_segment(aes(x = 0, xend = seventy_percent_work_rate, y = 1921.5, yend = 1921.5), # 70%V̇O2max時
                 linetype = "dashed", linewidth = 0.5, color = "grey") +
    geom_segment(aes(x = seventy_percent_work_rate, xend = seventy_percent_work_rate, y = 0, yend = 1921.5), # 70%V̇O2max時
                 linetype = "dashed", linewidth = 0.5, color = "grey") +
  
    geom_text(aes(x = 30, y = 1400, vjust = 0, label = "50%VO2max"), angle = 0, size = 4) +
    geom_text(aes(x = seventy_percent_work_rate - 65, y = 1921.5 + 50, vjust = 0, label = "70%VO2max"), angle = 0, size = 4) +
  
    geom_text(aes(x = 130, y = 2700, label = "Max Oxygen Uptake\n2745 mL/min"), 
              angle = 0, hjust = 0, size = 4) +
   annotate("text", x = 165, y = 100, label = "Progressive exercise load", color = "white", size = 4) +
    #annotate("text", x = 165, y = - 10, label = "Progressive exercise load", color = "black", size = 4) +
  
    labs(x = "Work Rate (W)", y = expression(paste(dot(V), O[2], " (mL/min)"))) + # , 
         # title = "Oxygen Uptake and Work Rate during Cycling Exercise") +
    scale_x_continuous(breaks = seq(0, 210, 30), limits = c(0, 210)) +
    scale_y_continuous(breaks = seq(0, 2500, 500)) +
    my_theme +
    theme(plot.title = element_text(hjust = 0.5),
          axis.title.y = element_text(angle = 90, vjust = 0.5),
          axis.text = element_text(size = 10),
          axis.title = element_text(size = 12)) +
    annotate("text", x = 30, y = 125, label = "Resting Metabolic Rate", 
             angle = 0, vjust = -0.5, size = 4, color = "darkblue") +
    scale_y_continuous(sec.axis = sec_axis(~ . * 180 / 2745, name = NULL, breaks = NULL)) +
    # 回帰式とR^2をグラフ左上に追加
    annotate("text", x = 39, y = 2650, label = regression_equation, size = 4, color = "black", parse = TRUE) +
    annotate("text", x = 25, y = 2450, label = r_squared, size = 4, color = "black", parse = TRUE) +
    # 50%HRと70%HRの交点に大きなXを追加
  annotate("text", x = fifty_percent_work_rate, y = 1360, label = "X", size = 5, color = "grey") +
  annotate("text", x = seventy_percent_work_rate, y = 1921.5, label = "X", size = 5, color = "grey")
p1
Figure 2: Oxygen Uptake and Work Rate during Cycling Exercise 
Code
library(patchwork)

combined_plot <- p1 + p2
combined_plot
(a) Work Rate
Figure 3: Oxygen Uptake during Progressive Exercise Load Test