# R_scripts | 2021-12-19 | # ============ 2021_12_02_plot_my_run.R ==== # # This is a test routine to plot Activity exported from # GoldenCheetah. It is a proof of concept, okeish... plot_my_run <- function(GoldenCheetah_json_file){ #source("def_colours.R") library(sf) library(osmdata) library(ggplot2) library(magrittr) # I love the pipe %>% library(jsonlite) # Read the running file library(scales) # For the function scales::ordinal() run_file <- GoldenCheetah_json_file result <- fromJSON(run_file) ## ----ride import----------------------------- ride <- result$RIDE$SAMPLES ## ----ride data------------------------------- ## Date & Time ride_start <- as.POSIXct(result$RIDE$STARTTIME) ride_start_day <- format(ride_start, format="%B %d (%Y)") ride_start_hour <- format(ride_start, format="%H:%M") # Temperature ride_mean_t <- paste0(round(mean(ride$TEMP, na.rm = TRUE), 2), "°C") # IDs ride_athtlete <- result$RIDE$TAGS$Athlete ride_sport <- result$RIDE$TAGS$Sport ## ----ride into spatial data------------------ ride <- ride[ride$LAT>0 & ride$LON>0,] # Filter missing data ride <- st_as_sf(ride, coords=c("LON","LAT")) st_crs(ride) = 4326 ## -------------------------------------------- # Every 10min (kept a record, but not used in the plot) e10m <- c(seq(1, max(ride$SECS),600)) e10m_distance <- ride[ride$SECS %in% e10m,"KM"] e10m_distance$LABEL <- paste0( round(e10m_distance$KM, 1), "km in ", round(e10m/60,0), "min") # Every 10k seq_km <- 1:max(ride$KM) seq_km_ordi <- scales::ordinal(seq_km) # Match every (rounded) kilometre and pek <- ride[round(ride$KM,1) %in% seq_km, ] # Delete duplicate (take first of km) pek <- pek[!duplicated(round(pek$KM,1)),] pek$LABEL <- paste0( seq_km_ordi, " k pace\n ", round(c(pek$SECS[1]/60, diff(pek$SECS)/60), 1),"min/km") ## ----from points to line--------------------- # Make it a line ride_line <- st_sf(st_sfc(st_linestring(st_coordinates(ride)))) st_crs(ride_line) = 4326 ## -------------------------------------------- ride_distance <- st_length(ride_line) ride_distancek <- paste0(round(ride_distance/1000, 2), "km") ride_average_speed <- paste0(round( (ride_distance/1000) / (max(ride$SECS)/3600),2), "km/h") ## ----calculate bbox-------------------------- ride_box <- st_bbox(ride_line) # I created a function, it is a task I already did earlier expand_box <- function(bbox_obj, percentage) { to_x <- diff(bbox_obj[c("xmin","xmax")])*percentage to_y <- diff(bbox_obj[c("ymin","ymax")])*percentage bbox_obj[c("xmin")] <- bbox_obj[c("xmin")] - to_x bbox_obj[c("xmax")] <- bbox_obj[c("xmax")] + to_x bbox_obj[c("ymin")] <- bbox_obj[c("ymin")] - to_y bbox_obj[c("ymax")] <- bbox_obj[c("ymax")] + to_y return(bbox_obj) } ride_box <- expand_box(ride_box, 0.15) ## ----osmdata intro--------------------------- query_box <- ride_box %>% opq(bbox = .) q <- query_box %>% osmdata_sf () ## ----osmdata layering------------------------ cull_osm <- function(osm_subset){ Filter(function(x)!all(is.na(x)), osm_subset) } boundaries <- q$osm_multipolygons %>% subset(type=="boundary") %>% cull_osm farmlands <- q$osm_polygons %>% subset(landuse=="farmland") %>% cull_osm meadows <- q$osm_polygons %>% subset(landuse %in% c("meadow","grass","recreation_ground"))%>% cull_osm residentials <- q$osm_polygons %>% subset(landuse %in% c("residential","allotments")) %>% cull_osm industrials <- q$osm_polygons %>% subset(landuse %in% c("industrial","commercial")) %>% cull_osm leisure <- q$osm_polygons %>% subset(!is.na(leisure))%>% cull_osm buildings <- q$osm_polygons %>% subset(!is.na(building)) %>% cull_osm naturals <- q$osm_polygons %>% subset(!is.na(natural)) %>% cull_osm waterways <- q$osm_lines %>% subset(!is.na(waterway))%>% cull_osm routes <-q$osm_multilines %>% subset(type=="route") %>% cull_osm highways <- q$osm_lines %>% subset(highway %in% c("tertiary","residential","service")) %>% cull_osm footways <- q$osm_lines %>% subset(highway %in% c("footway","bridleway", "track","path")) %>% cull_osm railways <- q$osm_lines %>% subset(railway %in% c("rail")) %>% cull_osm names <- q$osm_points %>% subset(!is.na(place)) %>% cull_osm ## ----finalmap-------------------------------- ggmap_random_meadow_run <- ggplot(data=result$RIDE$SAMPLE) + geom_sf(data = boundaries, fill = yellow_endive, color = "transparent", alpha = 0.3) + geom_sf(data = industrials, fill = grey_slate, color = "transparent", alpha = 0.4) + geom_sf(data = residentials, fill = grey_conglomerate, color = "transparent", alpha = 0.4) + geom_sf(data = meadows, fill = green_meadow, color = "transparent", alpha = 0.4) + geom_sf(data = farmlands, fill = brown_farmland, color = "transparent", alpha = 0.4) + geom_sf(data = leisure, fill = green_leisure, color = "transparent", alpha = 0.4) + geom_sf(data = buildings, fill = "black", color = "black", alpha = 0.7) + geom_sf(data = highways, color = grey_highway, alpha = 0.7, size = 1) + geom_sf(data = waterways, colour = blue_waterway, alpha = 0.75, size = 0.6) + geom_sf(data = footways, colour = orange_baseball, size = 0.7, lty = "twodash", alpha = 0.6) + geom_sf(data = naturals, fill = green_nature, alpha = 0.2, size = 0) + geom_sf(data = railways, colour = brown_rail, alpha = 0.99, size = 1.2) + geom_sf(data = railways, colour = brown_split_rail, alpha = 0.91, size = 1, lty = "dotdash") + geom_sf_label(data = names, aes(label = name), alpha = 0.7, hjust = 0.0, vjust = 0, fill = "black", col = "white", size = 2.9) + xlim(st_bbox(ride_box)[c(1,3)]) + ylim(st_bbox(ride_box)[c(2,4)]) ## ----finalmap_rided, dpi=200, warning=FALSE---- ggmap_random_meadow_run + geom_sf(data = ride_line, colour = "black", size = 1.8, alpha = 0.9) + geom_sf(data = ride_line, colour = yellow_ride, size = 1.5, alpha = 1) + #geom_sf(data = e10m_distance, # colour = yellow_ride, # fill = orange_baseball, # size=5.6, pch=21, alpha=0.9) + # geom_sf_text(data=e10m_distance, aes(label=KM)) + geom_sf_label(data = pek, aes(label = LABEL), fill = yellow_brown_palette(nrow(pek)), size = 2.9, alpha = 0.9, hjust = -0.1, vjust = 1) + geom_sf(data = pek, colour = "black", fill = bleu_de_france, size = 1.8, pch = 21, alpha = 0.8) + geom_sf_label(data = ride[1,], aes(label = "Start"), fill = "#ffcccc", alpha = 0.9) + labs(title = paste("Map of the", (ride_sport), "Enjoyed", ride_start_day), subtitle = paste("Started at", ride_start_hour, "for a distance of", ride_distancek, "by", ride_mean_t), caption = paste("Data: OpenStreetMap","/", "Software:", "R+osmdata+sf+ggplot2", "/", paste("Author:", ride_athtlete)) ) + geom_text(data=data.frame(), aes(label = paste0("Average speed:", ride_average_speed), x = Inf, y = -Inf), hjust = 1.01, vjust = -0.2) + ylab("") + xlab("")+ theme_minimal() + theme(axis.text = element_text(angle = 45, vjust = 0.5, hjust = 1, colour = "grey"), axis.title.x = element_text(angle = 0, vjust = 0.5, colour = "grey"), axis.title.y = element_text(angle = 0, vjust = 0.5, colour = "grey"), ### Background plot.background = element_rect(fill = "#f8f8f8", colour = "#f9f9f9"), panel.background = element_rect(fill = white_paper, colour = white_paper_border, size = 0.5, linetype = "solid"), panel.grid.major = element_line(size = 0.1, linetype = 'dashed', colour = white_paper_border), panel.grid.minor = element_line(size = 0.25, linetype = 'solid', colour = "black") ) } # bye-bye....................|