diff --git a/src/main.Rmd b/src/main.Rmd index 18d15e5..c7c7a96 100644 --- a/src/main.Rmd +++ b/src/main.Rmd @@ -10,7 +10,7 @@ date: "`r Sys.Date()`" knitr::opts_chunk$set(echo = TRUE) ``` -```{r preamble, message=FALSE} +```{r preamble, message=FALSE, include=FALSE} # Load Libraries library(dplyr) library(lubridate) @@ -24,17 +24,15 @@ library(trajr) library(shiny) ``` -# Download flights -```{r opensky} +```{r opensky, include=FALSE} +# Openskies API Functions time_now <- Sys.time() creds <- getCredentials( client_id = Sys.getenv('OPENSKY_CLIENT_ID'), client_secret = Sys.getenv('OPENSKY_CLIENT_SECRET')) -# get departures from Frankfurt airport -departures <- getAirportDepartures(airport = "EDDF", startTime = time_now - hours(1), endTime = time_now, credentials = creds ) - +# Get flights for a specific aircraft from OpenSky API getFlights <- function(icao, time, creds){ flights <-getAircraftFlights(icao, startTime = time - days(1), endTime = time, credentials = creds ) return(flights) @@ -56,8 +54,9 @@ getAircraftTrack <- function(icao, time, creds) { ``` -## Trajectory Conversion Functions -```{r trajectory-functions} +```{r trajectory-functions, include=FALSE} +# Trajectory Conversion Functions + # Convert route to distance in meters getRouteDistance <- function(route_df) { lat_ref <- route_df$lat[1] @@ -166,25 +165,11 @@ calculate_trajectory_params <- function(icao, departure_time, creds) { return(NULL) }) } - -getAircraftTrajectories <- function(icao, time, creds, days = 5){ - tracks <- list() - for (i in 0: (days-1)) { - flights <- getFlights(icao,time - days(i),creds) - for (f in flights){ - track <- calculate_trajectory_params(icao, f[["departure_time"]], creds) - if (!is.null(track)){ - tracks[[length(tracks)+1]] <- track - } - Sys.sleep(0.5) # API courtesy - } - } - return(tracks) -} ``` -## Statistical Helper Functions -```{r stat-functions} +```{r stat-functions, include=FALSE} +# Statistical Helper Functions + # Get parameter names and labels for trajectory statistics getTrajectoryParams <- function() { list( @@ -220,8 +205,9 @@ calculateStatsSummary <- function(trajectory_stats_df) { } ``` -## Visualization Functions -```{r viz-functions} +```{r viz-functions, include=FALSE} +# Visualization Functions + # Create boxplots for trajectory statistics createBoxplots <- function(trajectory_stats_df) { p <- getTrajectoryParams() @@ -323,51 +309,247 @@ generateInterpretation <- function(trajectory_stats_df) { } ``` -# Example Usage (Demo) -```{r demo, eval=FALSE} -# This section shows how to use the functions above -# Set eval=TRUE to run this demo +# Example Usage (Documentation) -# Get credentials +This section demonstrates how to use all functions defined above. Each step is explained and executed with real flight data from Frankfurt Airport (EDDF). + +## Step 1: Load Credentials + +The `getCredentials()` function loads API credentials from environment variables. + +```{r} creds <- getCredentials( - client_id = Sys.getenv('OPENSKY_CLIENT_ID'), - client_secret = Sys.getenv('OPENSKY_CLIENT_SECRET') + client_id = Sys.getenv("OPENSKY_CLIENT_ID"), + client_secret = Sys.getenv("OPENSKY_CLIENT_SECRET") ) -# Get departures from Frankfurt airport +``` + +## Step 2: Fetch Airport Departures + +Use `getAirportDepartures()` to get recent departures from Frankfurt Airport. + +```{r demo-departures} time_now <- Sys.time() departures <- getAirportDepartures( airport = "EDDF", - startTime = time_now - hours(1), - endTime = time_now, + startTime = time_now - hours(2), + endTime = time_now - hours(1), credentials = creds ) +cat("Found", length(departures), "departures from Frankfurt Airport (EDDF)\n") +``` + +## Step 3: Retrieve Flight Track + +The `getAircraftTrack()` function fetches detailed track data for a specific aircraft. We use the first available departure. + +```{r demo-track} +route_df <- NULL +icao <- "N/A" -# Get first departure's track if (length(departures) > 0) { - icao <- departures[[1]][["ICAO24"]] - dep_time <- departures[[1]][["departure_time"]] - - route_df <- getAircraftTrack(icao, dep_time, creds) - - if (!is.null(route_df)) { - # Plot route - plot(route_df$lon, route_df$lat, type = "o", pch = 20, col = "blue", - main = paste("Geographic route of", icao), - xlab = "Longitude", ylab = "Latitude") - - # Plot altitude - plot(route_df$time, route_df$alt, type = "l", col = "red", lwd = 2, - main = paste("Altitude profile of", icao), - xlab = "Time (Unix)", ylab = "Height (Meter)") - - # Get summary - print(calculateTrajectoryStats(route_df, icao)) - - # Plot trajectory - trj <- getTrajFromRoute(route_df) - plot(trj, main = paste("Trajectory of", icao)) + for (i in seq_along(departures)) { + icao <- departures[[i]][["ICAO24"]] + dep_time <- departures[[i]][["departure_time"]] + route_df <- getAircraftTrack(icao, dep_time, creds) + if (!is.null(route_df) && nrow(route_df) >= 3) { + cat("Successfully retrieved track for aircraft:", icao, "\n") + cat("Number of track points:", nrow(route_df), "\n") + break + } + Sys.sleep(1) } } + +if (is.null(route_df)) { + cat("No valid track data found\n") +} +``` + +## Step 4: Visualize Geographic Route + +Plot the flight path on a simple lat/lon coordinate system. + +```{r demo-route-plot, fig.width=7, fig.height=5} +if (!is.null(route_df)) { + plot(route_df$lon, route_df$lat, type = "o", pch = 20, col = "blue", + main = paste("Geographic Route of Aircraft", icao), + xlab = "Longitude", ylab = "Latitude") + points(route_df$lon[1], route_df$lat[1], pch = 17, col = "green", cex = 2) + points(route_df$lon[nrow(route_df)], route_df$lat[nrow(route_df)], pch = 15, col = "red", cex = 2) + legend("topright", legend = c("Start", "End", "Path"), pch = c(17, 15, 20), col = c("green", "red", "blue")) +} else { + cat("No route data available for plotting\n") +} +``` + +## Step 5: Visualize Altitude Profile + +Plot the altitude over time to see climb, cruise, and descent phases. + +```{r demo-altitude-plot, fig.width=7, fig.height=4} +if (!is.null(route_df)) { + time_minutes <- (route_df$time - route_df$time[1]) / 60 + plot(time_minutes, route_df$alt, type = "l", col = "red", lwd = 2, + main = paste("Altitude Profile of Aircraft", icao), + xlab = "Time (minutes)", ylab = "Altitude (meters)") + grid() +} else { + cat("No route data available for altitude plot\n") +} +``` + +## Step 6: Convert to Trajectory Object + +The `getTrajFromRoute()` function converts the route into a trajr trajectory object for analysis. + +```{r demo-trajectory-plot, fig.width=7, fig.height=5} +if (!is.null(route_df)) { + trj <- getTrajFromRoute(route_df) + plot(trj, main = paste("Trajectory of Aircraft", icao)) + cat("Trajectory created with", nrow(trj), "points\n") +} else { + cat("No route data available for trajectory conversion\n") +} +``` + +## Step 7: Calculate Trajectory Statistics (Single Flight) + +The `calculateTrajectoryStats()` function computes key metrics. Use `format = "table"` for a readable display. + +```{r demo-stats-table} +if (!is.null(route_df)) { + stats_table <- calculateTrajectoryStats(route_df, icao = icao, format = "table") + knitr::kable(stats_table, caption = paste("Trajectory Statistics for", icao)) +} else { + cat("No route data available for statistics\n") +} +``` + +## Step 8: Analyze Multiple Flights + +Retrieve track data for up to 5 departures to enable statistical comparison. + +```{r demo-multiple-tracks} +flight_data <- list() +successful_flights <- 0 + +if (length(departures) > 0) { + max_attempts <- min(10, length(departures)) # Try up to 10 departures to get 5 valid tracks + + for (i in seq_len(max_attempts)) { + icao_temp <- departures[[i]][["ICAO24"]] + dep_time_temp <- departures[[i]][["departure_time"]] + + route_df_temp <- getAircraftTrack(icao_temp, dep_time_temp, creds) + + if (!is.null(route_df_temp) && nrow(route_df_temp) >= 3) { + stats <- calculateTrajectoryStats(route_df_temp, icao = icao_temp, format = "row") + if (!is.null(stats)) { + flight_data[[length(flight_data) + 1]] <- stats + successful_flights <- successful_flights + 1 + cat("Flight", successful_flights, "- ICAO:", icao_temp, "- Points:", nrow(route_df_temp), "\n") + } + } + + if (successful_flights >= 5) break + } + + if (length(flight_data) > 0) { + all_flights_stats <- do.call(rbind, flight_data) + cat("\nTotal flights analyzed:", nrow(all_flights_stats), "\n") + } else { + all_flights_stats <- NULL + cat("No valid flight tracks found\n") + } +} else { + all_flights_stats <- NULL + cat("No departures available\n") +} +``` + +## Step 9: Display All Flight Statistics + +Show the raw statistics for all analyzed flights. + +```{r demo-all-stats-table} +if (!is.null(all_flights_stats)) { + display_stats <- all_flights_stats + display_stats$diffusion_distance_km <- round(display_stats$diffusion_distance_km, 2) + display_stats$path_length_km <- round(display_stats$path_length_km, 2) + display_stats$straightness <- round(display_stats$straightness, 4) + display_stats$duration_min <- round(display_stats$duration_min, 1) + display_stats$mean_velocity_kmh <- round(display_stats$mean_velocity_kmh, 1) + display_stats$fractal_dimension <- round(display_stats$fractal_dimension, 4) + + knitr::kable(display_stats, caption = "Statistics for All Analyzed Flights", + col.names = c("ICAO24", "Distance (km)", "Path (km)", + "Straightness", "Duration (min)", "Velocity (km/h)", "Fractal Dim")) +} else { + cat("No flight data available\n") +} +``` + +## Step 10: Summary Statistics + +The `calculateStatsSummary()` function generates descriptive statistics across multiple flights. + +```{r demo-summary-stats} +if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 2) { + summary_stats <- calculateStatsSummary(all_flights_stats) + knitr::kable(summary_stats, caption = "Summary Statistics Across All Flights") +} else { + cat("Need at least 2 flights for summary statistics\n") +} +``` + +## Step 11: Boxplots + +The `createBoxplots()` function visualizes the distribution of each trajectory parameter. + +```{r demo-boxplots, fig.width=10, fig.height=8} +if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 2) { + createBoxplots(all_flights_stats) +} else { + cat("Need at least 2 flights for boxplots\n") +} +``` + +## Step 12: Density Plots + +The `createDensityPlots()` function shows the probability distribution of each parameter. + +```{r demo-density, fig.width=10, fig.height=8} +if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 3) { + createDensityPlots(all_flights_stats) +} else { + cat("Need at least 3 flights for density plots\n") +} +``` + +## Step 13: Histograms + +The `createHistograms()` function displays histograms with density overlays. + +```{r demo-histograms, fig.width=10, fig.height=8} +if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 3) { + createHistograms(all_flights_stats) +} else { + cat("Need at least 3 flights for histograms\n") +} +``` + +## Step 14: Interpretation + +The `generateInterpretation()` function provides a text-based analysis of the trajectory statistics. + +```{r demo-interpretation} +if (!is.null(all_flights_stats) && nrow(all_flights_stats) >= 2) { + interpretation <- generateInterpretation(all_flights_stats) + cat(interpretation) +} else { + cat("Need at least 2 flights for interpretation\n") +} ```