# get data
= sf::st_read("https://github.com/GretaTimaite/pedestrian_simulation/releases/download/data/gcs_frames.geojson")
frames_sf
# our geometry column is in pixels rather than meters, so let's convert it to metres
= frames_sf |>
frames_sf_m ::mutate(geometry = geometry / 14)
dplyr
## now we'll create a list of dataframes for each agent
# first, let's find out the number of unique agents as this will be the number of dataframes in the list
= frames_sf_m |> dplyr::pull(ID) |> unique() |> sort()
unique_ids
# create an empty list to store DFs
= list()
agent_list # create a loop
for (i in 1:length(unique_ids)){
= frames_sf_m |> # iterate through frames_sf
agent_list[[i]] ::filter(ID %in% unique_ids[i]) # filter frames_sf by a unique ID
dplyr
}
## sanity check
identical(agent_list[[30]],
|> dplyr::filter(ID %in% unique_ids[30]))
frames_sf_m # >TRUE
## Now we will create a matrix of distances for each frame of a given agent.
# It will be used later in a function to extract the distances sequentially (from frame 1 to frame 2 to frame 3, etc)
= list()
distance_matrix_list # system.time( # to measure how long it takes to run
for (i in 1:length(agent_list)){
= sf::st_distance(agent_list[[i]])
distance_matrix_list[[i]]
}# )
# create a function that accepts a list of matrices
= function(list_matrix = list()){ # accepts lists
dist_function = list() # empty list to store new lists
dist_list for (i in 1:length(list_matrix)){ # reiteration over the length of a list
= i # initialisation of a matrix row
k = k + 1 # initialisation of a matrix column, it needs to be + 1 compared to the row as otherwise we will get distance equal to 0
j # (there's no distance traveled from, e.g. frame 2 to frame 2)
if (j <= ncol(list_matrix)){ # columns should not exceed the number of columns of a matrix (looping (out of bounds) error might be given otherwise)
= list_matrix[k,j] # for each `i` list extract matrix values at row k and column j
dist_list[[i]]
}else {
break # break if j is above number of columns of a matrix
}
}return(dist_list)
}
# an empty list for distance vectors
= list()
distance_list # loop over `distance_matrix_list` and apply a `dist_function()`
# system.time( # to measure how long it takes to run
for (i in 1:length(distance_matrix_list)){
= distance_matrix_list[[i]] |>
distance_list[[i]] dist_function() |> # apply the new function
unlist() |>
as.data.frame() # create a dataframe (will be useful in later steps)
colnames(distance_list[[i]]) = "dist" # rename a column
}# )
# NOTE: each list is shorter by 1 element compared to the original input list because of initialisation starting at 1, thus capturing the distance between frame 1 and 2.
# In other words, the function omits the starting point at which an agent.
## testing
# here we'll check that the function works as it should.
5]][1] # agent 5's traveled distance from frame 1 to 2
distance_list[[#> [1] 0.1474067
# finding distance manually
::st_distance(agent_list[[5]][1,3], # frame 1 of agent 5
sf5]][2,3]) # frame 2 of agent 5
agent_list[[#> [1,] 0.1474067
5]][2,1] # second row in matrix 1 ([1,1] would return 0 as there's the distance from frame 1 to frame 1 equals to 0) of agent 5.
distance_matrix_list[[#> [1] 0.1474067
## it's time to join distance_list to agents_list
# NOTE: our lists are of unequal row lengths, hence we will have to do two intermediate steps
# first let's create a list to store joined lists
= list()
agent_dist_list # a list to store values of a shorter (intermediate) list of dataframes
= list()
dist_list_new # create a loop
# first we will create an intermediate list of dataframes
for (i in 1:length(agent_list)){
= rbind(data.frame("dist" = 0),
dist_list_new[[i]] # adding a new row on top of the dataframes in the distance_list,
distance_list[[i]]) # so their length matches the length of DFs in the agent_list
= cbind(agent_list[[i]],
agent_dist_list[[i]] # joining dataframes by column
dist_list_new[[i]])
}
# check
1]]
agent_dist_list[[# looks good, we have 220 rows and the first one has a distance column equal to 0 (ie starting point)
# let's save agent_dist_list for future uses as .dat file
save(agent_dist_list,
file = "agent_dist_list.dat")
saveRDS(agent_dist_list,
file = "agent_dist_list.rds")
= readRDS("agent_dist_list.rds") dist_list
6 Speed
This chapter demonstrates how to derive agent speed per frame (which later can be aggregated into seconds, if needed) from either GCS or JPS data.
The idea is the following: measure the distance an agent travelled from frame 1 to frame 2. This will be indicative of how much an agent moved in one frame (0.04 sec)
It produces a new dataset with a new “dist” column which is equivalent to agent’s speed per frame. The output of this is used to plot fundamental diagrams (speed~density).
Potential enhancements:
- write a function that allows to specify interval at which to estimate travelled distance. For example, it could be for every frame (ie from frame 1 to frame 2) or every 25 frames (ie from frame 1 to frame 25). The second would simplify the trajectory but not much detail should be lost.
7 GCS Speed
# lists into a single df
= readRDS("agent_dist_list.rds")
gcs_dist_list
= as.data.frame(do.call(rbind, gcs_dist_list))
gcs_dist_sf
= gcs_dist_sf |>
gcs_dist_df ::mutate(x_coord = unlist(purrr::map(gcs_dist_sf$geometry,1)),
dplyry_coord = unlist(purrr::map(gcs_dist_sf$geometry,2))) |>
::select(-geometry)
dplyr
# save as csv
# write.csv(jps_dist_df,
# "jps_dist_df")
8 JPS Speed
# get data
= read.table("/Users/gretatimaite/Desktop/pedestrian_simulation/final_results/8_frame/1/traj.txt",
jps col.names = c("ID", "FR", "X", "Y", "Z", "A", "B", "ANGLE", "COLOR"))
= jps |>
jps_sf ::st_as_sf(coords = c("X", "Y"))
sf
## now we'll create a list of dataframes for each agent
# first, let's find out the number of unique agents as this will be the number of dataframes in the list
= jps_sf |> dplyr::pull(ID) |> unique() |> sort()
unique_ids
# create an empty list to store DFs
= list()
agent_list # create a loop
for (i in 1:length(unique_ids)){
= jps_sf |> # iterate through frames_sf
agent_list[[i]] ::filter(ID %in% unique_ids[i]) # filter frames_sf by a unique ID
dplyr
}
## sanity check
identical(agent_list[[30]],
|> dplyr::filter(ID %in% unique_ids[30]))
jps_sf # >TRUE
## Now we will create a matrix of distances for each frame of a given agent.
# It will be used later in a function to extract the distances sequentially (from frame 1 to frame 2 to frame 3, etc)
= list()
distance_matrix_list # system.time( # to measure how long it takes to run
for (i in 1:length(agent_list)){
= sf::st_distance(agent_list[[i]])
distance_matrix_list[[i]]
}# )
# create a function that accepts a list of matrices
= function(list_matrix = list()){ # accepts lists
dist_function = list() # empty list to store new lists
dist_list for (i in 1:length(list_matrix)){ # reiteration over the length of a list
= i # initialisation of a matrix row
k = k + 1 # initialisation of a matrix column, it needs to be + 1 compared to the row as otherwise we will get distance equal to 0
j # (there's no distance traveled from, e.g. frame 2 to frame 2)
if (j <= ncol(list_matrix)){ # columns should not exceed the number of columns of a matrix (looping (out of bounds) error might be given otherwise)
= list_matrix[k,j] # for each `i` list extract matrix values at row k and column j
dist_list[[i]]
}else {
break # break if j is above number of columns of a matrix
}
}return(dist_list)
}
# an empty list for distance vectors
= list()
distance_list # loop over `distance_matrix_list` and apply a `dist_function()`
# system.time( # to measure how long it takes to run
for (i in 1:length(distance_matrix_list)){
= distance_matrix_list[[i]] |>
distance_list[[i]] dist_function() |> # apply the new function
unlist() |>
as.data.frame() # create a dataframe (will be useful in later steps)
colnames(distance_list[[i]]) = "dist" # rename a column
}# )
# NOTE: each list is shorter by 1 element compared to the original input list because of initialisation starting at 1, thus capturing the distance between frame 1 and 2.
# In other words, the function omits the starting point at which an agent.
## testing
# here we'll check that the function works as it should.
5]][1] # agent 5's traveled distance from frame 1 to 2
distance_list[[#> [1] 0.1474067
# finding distance manually
::st_distance(agent_list[[5]][1,3], # frame 1 of agent 5
sf5]][2,3]) # frame 2 of agent 5
agent_list[[#> [1,] 0.1474067
5]][2,1] # second row in matrix 1 ([1,1] would return 0 as there's the distance from frame 1 to frame 1 equals to 0) of agent 5.
distance_matrix_list[[#> [1] 0.1474067
## it's time to join distance_list to agents_list
# NOTE: our lists are of unequal row lengths, hence we will have to do two intermediate steps
# first let's create a list to store joined lists
= list()
jps_dist_list # a list to store values of a shorter (intermediate) list of dataframes
= list()
jps_list_new # create a loop
# first we will create an intermediate list of dataframes
for (i in 1:length(agent_list)){
= rbind(data.frame("dist" = 0),
jps_list_new[[i]] # adding a new row on top of the dataframes in the distance_list,
distance_list[[i]]) # so their length matches the length of DFs in the agent_list
= cbind(agent_list[[i]],
jps_dist_list[[i]] # joining dataframes by column
jps_list_new[[i]])
}
# check
1]]
jps_dist_list[[
# save as RDS
saveRDS(jps_dist_list,
file = "jps_dist_list.rds")
# lists into a single df
= as.data.frame(do.call(rbind, jps_dist_list))
jps_dist_sf
= jps_dist_sf |>
jps_dist_df ::mutate(x_coord = unlist(purrr::map(jps_dist_sf$geometry,1)),
dplyry_coord = unlist(purrr::map(jps_dist_sf$geometry,2))) |>
::select(-geometry)
dplyr
# save as csv
# write.csv(jps_dist_df,
# "jps_dist_df")