## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 10, fig.height = 7, out.width = "100%", dpi = 150 ) library(Athlytics) library(ggplot2) ## ----eval=FALSE--------------------------------------------------------------- # # Stable release from CRAN # install.packages("Athlytics") ## ----eval=FALSE--------------------------------------------------------------- # library(Athlytics) # library(dplyr) # For data manipulation # # # Load your activities # export_path <- "path/to/export_12345678.zip" # activities <- load_local_activities(export_path) # # # View the first few rows # head(activities) ## ----eval=FALSE--------------------------------------------------------------- # # How many activities do you have? # nrow(activities) # # Example output: [1] 847 # # # What sports are in your data? # table(activities$type) # # Example output: # # Ride Run Swim # # 312 498 37 # # # Date range # range(activities$date, na.rm = TRUE) # # Example output: [1] "2018-01-05" "2024-12-20" # # # Key columns in the dataset # names(activities) ## ----eval=FALSE--------------------------------------------------------------- # # Summary statistics # summary(activities |> select(distance, moving_time, average_heartrate)) # # # Check for missing heart rate data # sum(!is.na(activities$average_heartrate)) / nrow(activities) * 100 # # Shows % of activities with HR data # # # Activities without HR data # activities |> # filter(is.na(average_heartrate)) |> # count(type) ## ----eval=FALSE--------------------------------------------------------------- # # Only running activities # runs <- activities |> # filter(type == "Run") # # # Recent activities (last 6 months) # recent <- activities |> # filter(date >= Sys.Date() - 180) # # # Runs with heart rate data from 2024 # runs_2024_hr <- activities |> # filter( # type == "Run", # !is.na(average_heartrate), # lubridate::year(date) == 2024 # ) # # # Long runs only (> 15 km) # long_runs <- activities |> # filter(type == "Run", distance > 15000) ## ----eval=FALSE--------------------------------------------------------------- # # Calculate ACWR for all running activities # acwr_data <- calculate_acwr( # activities_data = runs, # activity_type = "Run", # Filter by activity type # load_metric = "duration_mins", # Can also be "distance_km" or "hrss" # acute_period = 7, # 7-day rolling average # chronic_period = 28 # 28-day rolling average # ) # # # View results # head(acwr_data) ## ----eval=FALSE--------------------------------------------------------------- # # Basic plot # plot_acwr(acwr_data) # # # With ACWR zones highlighted (recommended) # plot_acwr(acwr_data, highlight_zones = TRUE) ## ----acwr-demo, fig.cap="ACWR visualization using sample data"---------------- # Load built-in sample data data("sample_acwr", package = "Athlytics") # Plot ACWR with ACWR zones plot_acwr(sample_acwr, highlight_zones = TRUE) ## ----eval=FALSE--------------------------------------------------------------- # # Identify high-ACWR periods # high_acwr <- acwr_data |> # filter(acwr_smooth > 1.5) |> # select(date, atl, ctl, acwr_smooth) # # print(high_acwr) # # # Check recent trend # recent_acwr <- acwr_data |> # filter(date >= Sys.Date() - 60) |> # arrange(desc(date)) # # head(recent_acwr, 10) ## ----eval=FALSE--------------------------------------------------------------- # # Calculate using HRSS (heart rate stress score) # acwr_hrss <- calculate_acwr( # activities_data = runs, # activity_type = "Run", # load_metric = "hrss", # user_max_hr = 190, # user_resting_hr = 50 # ) ## ----eval=FALSE--------------------------------------------------------------- # # For running (Speed/HR) # ef_runs <- calculate_ef( # activities_data = runs, # activity_type = "Run", # ef_metric = "speed_hr", # Speed (m/s) / HR # export_dir = export_path # Optional; enables stream-based steady-state EF # ) # # # For cycling (Power/HR) # rides <- activities |> filter(type == "Ride") # ef_cycling <- calculate_ef( # activities_data = rides, # activity_type = "Ride", # ef_metric = "power_hr", # Power divided by HR # export_dir = export_path # Optional; enables stream-based steady-state EF # ) # # # View results # head(ef_runs) ## ----eval=FALSE--------------------------------------------------------------- # # Basic plot # plot_ef(ef_runs) # # # With smoothing line to see trend (recommended) # plot_ef(ef_runs, add_trend_line = TRUE) # # # Smooth per activity type (separate trend lines for each discipline) # # Note: requires data with multiple activity types (e.g., Run + Ride) # ef_multi <- calculate_ef( # activities_data = activities, # ef_metric = "speed_hr", # export_dir = export_path # ) # plot_ef(ef_multi, add_trend_line = TRUE, smooth_per_activity_type = TRUE) ## ----ef-demo, fig.cap="Efficiency Factor trend using sample data"------------- # Load built-in sample data (contains Run + Ride activities) data("sample_ef", package = "Athlytics") # Plot EF with trend line plot_ef(sample_ef, add_trend_line = TRUE) ## ----ef-smooth-demo, fig.cap="EF with per-discipline smoothing"--------------- # Smooth per activity type to compare trends across disciplines plot_ef(sample_ef, add_trend_line = TRUE, smooth_per_activity_type = TRUE) ## ----eval=FALSE--------------------------------------------------------------- # # Calculate monthly average EF # library(lubridate) # # ef_monthly <- ef_runs |> # mutate(month = floor_date(date, "month")) |> # group_by(month) |> # summarise( # mean_ef = mean(ef_value, na.rm = TRUE), # n_activities = n() # ) |> # arrange(desc(month)) # # print(ef_monthly) # # # Compare first vs last 3 months # recent_ef <- ef_runs |> # filter(date >= Sys.Date() - 90) |> # pull(ef_value) # baseline_ef <- ef_runs |> # filter(date < Sys.Date() - 90, date >= Sys.Date() - 180) |> # pull(ef_value) # # cat(sprintf( # "Recent EF: %.2f\nBaseline EF: %.2f\nChange: %.1f%%\n", # mean(recent_ef, na.rm = TRUE), # mean(baseline_ef, na.rm = TRUE), # (mean(recent_ef, na.rm = TRUE) / mean(baseline_ef, na.rm = TRUE) - 1) * 100 # )) ## ----eval=FALSE--------------------------------------------------------------- # # For running # decoupling_runs <- calculate_decoupling( # activities_data = runs, # export_dir = export_path, # activity_type = "Run", # decouple_metric = "speed_hr", # min_duration_mins = 60 # Only analyze runs ≥ 60 minutes # ) # # # For cycling # decoupling_rides <- calculate_decoupling( # activities_data = rides, # export_dir = export_path, # activity_type = "Ride", # decouple_metric = "power_hr", # min_duration_mins = 90 # Longer threshold for cycling # ) # # # View results # head(decoupling_runs) ## ----eval=FALSE--------------------------------------------------------------- # # Basic plot # plot_decoupling(data = decoupling_runs) # # # With trend line # plot_decoupling(data = decoupling_runs, add_trend_line = TRUE) ## ----decoupling-demo, fig.cap="Cardiovascular decoupling using sample data"---- # Load built-in sample data data("sample_decoupling", package = "Athlytics") # Plot decoupling trend plot_decoupling(data = sample_decoupling) ## ----eval=FALSE--------------------------------------------------------------- # # Recent decoupling average # recent_decouple <- decoupling_runs |> # filter(date >= Sys.Date() - 60) |> # summarise(avg_decouple = mean(decoupling, na.rm = TRUE)) # # if (recent_decouple$avg_decouple < 5) { # cat("Excellent aerobic base! Ready for higher intensity.\n") # } else if (recent_decouple$avg_decouple < 10) { # cat("Good base, continue building aerobic foundation.\n") # } else { # cat("High decoupling—focus on more easy, long runs.\n") # } ## ----eval=FALSE--------------------------------------------------------------- # # Compare decoupling over time # library(ggplot2) # # decoupling_runs |> # ggplot(aes(x = date, y = decoupling)) + # geom_point(alpha = 0.6) + # geom_smooth(method = "loess", se = TRUE) + # geom_hline(yintercept = 5, linetype = "dashed", color = "green") + # geom_hline(yintercept = 10, linetype = "dashed", color = "orange") + # labs( # title = "Decoupling Trend Over Time", # subtitle = "Lower values = better aerobic endurance", # x = "Date", y = "Decoupling (%)" # ) + # theme_minimal() ## ----eval=FALSE--------------------------------------------------------------- # # Extract personal bests # pbs <- calculate_pbs( # activities_data = runs, # export_dir = export_path, # activity_type = "Run" # ) # # # View all PRs # print(pbs) ## ----eval=FALSE--------------------------------------------------------------- # # Plot PR progression # plot_pbs(pbs) # # # Filter to specific distance # pbs_5k <- pbs |> filter(distance_label == "5k") # print(pbs_5k) ## ----pbs-demo, fig.cap="Personal bests progression using sample data", fig.width=10, fig.height=7---- # Load built-in sample data data("sample_pbs", package = "Athlytics") # Plot PB progression plot_pbs(data = sample_pbs) ## ----eval=FALSE--------------------------------------------------------------- # # Calculate exposure # exposure <- calculate_exposure( # activities_data = runs, # activity_type = "Run", # load_metric = "duration_mins" # ) # # # Plot with ACWR zones # plot_exposure(data = exposure, risk_zones = TRUE) ## ----exposure-demo, fig.cap="Load exposure analysis using sample data"-------- # Load built-in sample data data("sample_exposure", package = "Athlytics") # Plot exposure plot_exposure(data = sample_exposure) ## ----eval=FALSE--------------------------------------------------------------- # library(Athlytics) # library(dplyr) # library(ggplot2) # # # ---- 1. Load and Filter Data ---- # export_path <- "my_strava_export.zip" # activities <- load_local_activities(export_path) # # # Focus on running activities with HR data # runs <- activities |> # filter(type == "Run", !is.na(average_heartrate)) # # cat(sprintf("Loaded %d running activities with HR data\n", nrow(runs))) # # # ---- 2. Training Load Monitoring ---- # acwr_data <- calculate_acwr( # activities_data = runs, # activity_type = "Run", # load_metric = "duration_mins" # ) # # # Check current training status # current_acwr <- acwr_data |> # filter(date >= Sys.Date() - 30) |> # tail(1) |> # pull(acwr_smooth) # # cat(sprintf("Current ACWR: %.2f\n", current_acwr)) # # # Visualize # p1 <- plot_acwr(acwr_data, highlight_zones = TRUE) + # labs(title = "6-Month Training Load Progression") # print(p1) # # # ---- 3. Aerobic Fitness Tracking ---- # ef_data <- calculate_ef( # activities_data = runs, # activity_type = "Run", # ef_metric = "speed_hr", # export_dir = export_path # ) # # # Calculate fitness trend # ef_trend <- ef_data |> # mutate(month = lubridate::floor_date(date, "month")) |> # group_by(month) |> # summarise(mean_ef = mean(ef_value, na.rm = TRUE)) # # p2 <- plot_ef(ef_data, add_trend_line = TRUE) + # labs(title = "Aerobic Efficiency Trend") # print(p2) # # # ---- 4. Endurance Assessment ---- # # Only for long runs (> 60 min) # decoupling_data <- calculate_decoupling( # activities_data = runs, # export_dir = export_path, # activity_type = "Run", # min_duration_mins = 60 # ) # # avg_decouple <- mean(decoupling_data$decoupling, na.rm = TRUE) # cat(sprintf( # "Average decoupling: %.1f%% (%s aerobic base)\n", # avg_decouple, # ifelse(avg_decouple < 5, "excellent", # ifelse(avg_decouple < 10, "good", "needs work") # ) # )) # # p3 <- plot_decoupling(data = decoupling_data) + # labs(title = "Cardiovascular Drift in Long Runs") # print(p3) # # # ---- 5. Export Results ---- # # Save plots # ggsave("acwr_analysis.png", plot = p1, width = 10, height = 6, dpi = 300) # ggsave("ef_trend.png", plot = p2, width = 10, height = 6, dpi = 300) # ggsave("decoupling.png", plot = p3, width = 10, height = 6, dpi = 300) # # # Export data for further analysis # write.csv(acwr_data, "acwr_results.csv", row.names = FALSE) # write.csv(ef_data, "ef_results.csv", row.names = FALSE) # write.csv(decoupling_data, "decoupling_results.csv", row.names = FALSE) # # cat("\nAnalysis complete! Results saved.\n") ## ----eval=FALSE--------------------------------------------------------------- # # Check activity types in your data # table(activities$type) # # # Check for HR data availability # sum(!is.na(activities$average_heartrate)) # # # Verify date range # range(activities$date, na.rm = TRUE) # # # Use an explicit activity type that appears in the table above # test <- calculate_acwr( # activities_data = activities, # activity_type = "Run", # load_metric = "duration_mins" # ) ## ----eval=FALSE--------------------------------------------------------------- # # How much data do you have? # date_span <- as.numeric(max(activities$date) - min(activities$date)) # cat(sprintf("Your data spans %d days\n", date_span)) # # # If < 28 days, you need more data or use shorter periods ## ----eval=FALSE--------------------------------------------------------------- # # Filter before calculating # runs_with_hr <- runs |> filter(!is.na(average_heartrate)) # ef_data <- calculate_ef(runs_with_hr, ef_metric = "speed_hr") ## ----eval=FALSE--------------------------------------------------------------- # # Check if data exists # nrow(acwr_data) # summary(acwr_data$acwr_smooth) # # # Try basic R plot first # plot(acwr_data$date, acwr_data$acwr_smooth, type = "l") ## ----------------------------------------------------------------------------- sessionInfo()