Merge remote-tracking branch 'origin/feat/trajectories-and-alternative-gui' into feat/trajectories-and-alternative-gui
This commit is contained in:
300
src/main.Rmd
300
src/main.Rmd
@@ -10,7 +10,7 @@ date: "`r Sys.Date()`"
|
|||||||
knitr::opts_chunk$set(echo = TRUE)
|
knitr::opts_chunk$set(echo = TRUE)
|
||||||
```
|
```
|
||||||
|
|
||||||
```{r preamble, message=FALSE}
|
```{r preamble, message=FALSE, include=FALSE}
|
||||||
# Load Libraries
|
# Load Libraries
|
||||||
library(dplyr)
|
library(dplyr)
|
||||||
library(lubridate)
|
library(lubridate)
|
||||||
@@ -24,17 +24,15 @@ library(trajr)
|
|||||||
library(shiny)
|
library(shiny)
|
||||||
```
|
```
|
||||||
|
|
||||||
# Download flights
|
```{r opensky, include=FALSE}
|
||||||
```{r opensky}
|
# Openskies API Functions
|
||||||
|
|
||||||
time_now <- Sys.time()
|
time_now <- Sys.time()
|
||||||
creds <- getCredentials(
|
creds <- getCredentials(
|
||||||
client_id = Sys.getenv('OPENSKY_CLIENT_ID'),
|
client_id = Sys.getenv('OPENSKY_CLIENT_ID'),
|
||||||
client_secret = Sys.getenv('OPENSKY_CLIENT_SECRET'))
|
client_secret = Sys.getenv('OPENSKY_CLIENT_SECRET'))
|
||||||
|
|
||||||
# get departures from Frankfurt airport
|
# Get flights for a specific aircraft from OpenSky API
|
||||||
departures <- getAirportDepartures(airport = "EDDF", startTime = time_now - hours(1), endTime = time_now, credentials = creds )
|
|
||||||
|
|
||||||
getFlights <- function(icao, time, creds){
|
getFlights <- function(icao, time, creds){
|
||||||
flights <-getAircraftFlights(icao, startTime = time - days(1), endTime = time, credentials = creds )
|
flights <-getAircraftFlights(icao, startTime = time - days(1), endTime = time, credentials = creds )
|
||||||
return(flights)
|
return(flights)
|
||||||
@@ -56,8 +54,9 @@ getAircraftTrack <- function(icao, time, creds) {
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Trajectory Conversion Functions
|
```{r trajectory-functions, include=FALSE}
|
||||||
```{r trajectory-functions}
|
# Trajectory Conversion Functions
|
||||||
|
|
||||||
# Convert route to distance in meters
|
# Convert route to distance in meters
|
||||||
getRouteDistance <- function(route_df) {
|
getRouteDistance <- function(route_df) {
|
||||||
lat_ref <- route_df$lat[1]
|
lat_ref <- route_df$lat[1]
|
||||||
@@ -166,25 +165,11 @@ calculate_trajectory_params <- function(icao, departure_time, creds) {
|
|||||||
return(NULL)
|
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, include=FALSE}
|
||||||
```{r stat-functions}
|
# Statistical Helper Functions
|
||||||
|
|
||||||
# Get parameter names and labels for trajectory statistics
|
# Get parameter names and labels for trajectory statistics
|
||||||
getTrajectoryParams <- function() {
|
getTrajectoryParams <- function() {
|
||||||
list(
|
list(
|
||||||
@@ -220,8 +205,9 @@ calculateStatsSummary <- function(trajectory_stats_df) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Visualization Functions
|
```{r viz-functions, include=FALSE}
|
||||||
```{r viz-functions}
|
# Visualization Functions
|
||||||
|
|
||||||
# Create boxplots for trajectory statistics
|
# Create boxplots for trajectory statistics
|
||||||
createBoxplots <- function(trajectory_stats_df) {
|
createBoxplots <- function(trajectory_stats_df) {
|
||||||
p <- getTrajectoryParams()
|
p <- getTrajectoryParams()
|
||||||
@@ -323,51 +309,247 @@ generateInterpretation <- function(trajectory_stats_df) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# Example Usage (Demo)
|
# Example Usage (Documentation)
|
||||||
```{r demo, eval=FALSE}
|
|
||||||
# This section shows how to use the functions above
|
|
||||||
# Set eval=TRUE to run this demo
|
|
||||||
|
|
||||||
# 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(
|
creds <- getCredentials(
|
||||||
client_id = Sys.getenv('OPENSKY_CLIENT_ID'),
|
client_id = Sys.getenv("OPENSKY_CLIENT_ID"),
|
||||||
client_secret = Sys.getenv('OPENSKY_CLIENT_SECRET')
|
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()
|
time_now <- Sys.time()
|
||||||
departures <- getAirportDepartures(
|
departures <- getAirportDepartures(
|
||||||
airport = "EDDF",
|
airport = "EDDF",
|
||||||
startTime = time_now - hours(1),
|
startTime = time_now - hours(2),
|
||||||
endTime = time_now,
|
endTime = time_now - hours(1),
|
||||||
credentials = creds
|
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) {
|
if (length(departures) > 0) {
|
||||||
icao <- departures[[1]][["ICAO24"]]
|
for (i in seq_along(departures)) {
|
||||||
dep_time <- departures[[1]][["departure_time"]]
|
icao <- departures[[i]][["ICAO24"]]
|
||||||
|
dep_time <- departures[[i]][["departure_time"]]
|
||||||
route_df <- getAircraftTrack(icao, dep_time, creds)
|
route_df <- getAircraftTrack(icao, dep_time, creds)
|
||||||
|
if (!is.null(route_df) && nrow(route_df) >= 3) {
|
||||||
if (!is.null(route_df)) {
|
cat("Successfully retrieved track for aircraft:", icao, "\n")
|
||||||
# Plot route
|
cat("Number of track points:", nrow(route_df), "\n")
|
||||||
plot(route_df$lon, route_df$lat, type = "o", pch = 20, col = "blue",
|
break
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
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")
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user