This vignette walks through the key functions and features of the adapter package, and provides worked examples that demonstrate the use of adapter in a proper analysis setting.
Make sure that adapter is installed. For installation instructions, please read the vignette, "Getting started".
Once installed, load adapter to make use of it:
library(adapter)
You will almost always begin by reading in the simulation log file data. This is best done by having the data stored in a specific directory structure. For more information about how to structure data or how to handle cases when the data is not structured this way, please read the vignette, "Reading log files".
Assuming the log files are structured appropriately, read the data into R using read_or_load()
as demonstrated below.
WARNING: reading the data can take a long time.
d <- read_or_load()
path_to_user_data <- system.file("extdata", "eg_user_list", package = "adapter") d <- read_or_load("saved/saved_user_list.rds", path_to_user_data)
By using read_or_load()
, you will read in the data as a list object in a convenient way. Important checks of the data coding are made (e.g., that there is only one driver and one or no drone operators per team, and that there aren't any duplicate unique ids). Other useful preparation and variable calculations occur automatically. The data will also be saved as a properly formatted .RDS object, meaning you can call read_or_load()
in the future and quickly reload the file without waiting for all the data to be read again.
read_or_load()
provides an interactive guide by default. If you've used this function before to read in the data and save it as an RDS, you can save some time by providing the function with a path to the saved RDS file. This will avoid the interactive guide and load the data automatically. For example:
d <- read_or_load("path/to/saved/rds_file.rds")
For more detailed information about this, please read the vignette, "Reading log files".
It is important to understand the structure of the list of user data returned by read_all()
.
It is a list
is.list(d)
Each element contains information about a single user/participant
cat("Data is available for", length(d), "participants:", names(d))
Information for each participant is a list
sapply(d, is.list)
Each participant list contains three data frames
user_1 <- d[[1]] cat("Each user contains", length(user_1), "data frames:", names(user_1), "\n\n") sapply(user_1, is.data.frame)
These three data frames each contain different information:
session
contains session-level information like the user id and time the game startedevents
contains timestamped logs of discrete events, like collisions, or the start/end of events.streams
contains timestamped logs of variables collected every frame like the accelerator value.For more information, please read the vignette, "Reading log files".
adapter provides a number of functions to support working with the data. This section will demonstrate their uses.
The adapter functions follow the philosophy of, and are best used in conjunction with, packages in the tidyverse. From here, we will be using tidyverse functions, which can be loaded as follows:
# install.packages("tidyverse") # Install if needed library(tidyverse)
It is recommended that tidyverse be loaded in your scripts.
# Quietly Set theme theme_set(theme_minimal())
You'll often want to separate data belonging to participants who were drivers or, less commonly, who were drone operators. Two functions are provided to handle these tasks: get_drivers()
and get_drones()
. Both functions take a list of user data and return a list in the same structure, but only with participants of the particular role.
For example:
drivers <- get_drivers(d) drones <- get_drones(d) cat("There were", length(drivers), "drivers (", names(drivers), ") and", length(drones), "drone operator(s) (", names(drones), ")")
It's often the case that you will want to get a single data frame that contains the information for all participants (e.g., session
or streams
). adapter provides the function bind_tbl()
to support this. To use it, you must specify your list of user data and the name of which data frame you want to bind (without quotes). For example:
bind_tbl(d, session)
This section contains examples of working with the sim data to accomplish various tasks.
This example demonstrates how to plot the routes taken by each driver, overlaid with the intended route. This is useful for explaining how the laps worked, as well as for identifying deviations from the intended route.
Mapping the intended routes is made simple because adapter comes with a data object containing information about the waypoints
for each lap:
waypoints
Each row of this tibble contains the lap number, and x and z coordinates of a waypoint (intended turn) in the simulation. You can read more detailed information on the help page by running ?waypoints
. With the added knowledge that laps always started and ended at the same point (approximately x = 600, z = 200), the intended route can be plotted using waypoints
as follows:
ggplot(waypoints, aes(x = x, y = z)) + # Draw route path between waypoints geom_path(colour = "grey", size = 3, lineend = "round", alpha = .7) + # Draw arrow indicating beginning of each lap annotate("segment", x = 600, xend = 600, y = 200, yend = 300, color = "black", alpha = .5, arrow = arrow(type = "closed", angle = 30, length = unit(.1, "inches"))) + # Split routes across facets facet_wrap(~ lap, nrow = 1) + # Ensure x and y scales are equally spaced coord_equal() + # Provide title information ggtitle("Drivers' planned routes on each city lap")
The following challenge is to extract driver's actual routes The information can be obtained using bind_tbl()
in combination with get_drivers()
and dplyr and tidyr functions (in tidyverse):
# Get drivers' position information at each frame # - `position` is a 3-element vector of the x,y,z coordinates driver_positions <- d %>% get_drivers() %>% bind_tbl(streams) %>% select(uid, lap, time, position) driver_positions # Extract the x and z coordinates at each frame driver_positions <- driver_positions %>% mutate(x = map_dbl(position, ~ .[1]), z = map_dbl(position, ~ .[3])) # Make sure to order by time, per driver, so path is plotted correctly driver_positions <- driver_positions %>% arrange(uid, time) driver_positions # Plot these paths ggplot(driver_positions, aes(x = x, y = z)) + geom_path(aes(color = uid), alpha = .4) + facet_wrap(~ lap, nrow = 1) + coord_equal() + ggtitle("Drivers' routes on each city lap")
Here's an example combining these plots (seeing all drivers as the same colour):
ggplot(waypoints, aes(x = x, y = z)) + # Draw waypoint-defined route geom_path(colour = "grey", size = 3, lineend = "round", alpha = .7) + annotate("segment", x = 600, xend = 600, y = 200, yend = 300, color = "black", alpha = .5, arrow = arrow(type = "closed", angle = 30, length = unit(.1, "inches"))) + # Overlay drivers' routes geom_path(data = driver_positions, aes(group = uid), alpha = .2, color = "dodgerblue") + # Plot-general aspects facet_wrap(~ lap, nrow = 1) + coord_equal() + ggtitle("Overlay of drivers' routes on each city lap", subtitle = "Grey line shows intended route\nAll laps start and end at x = 600, z = 200")
This demonstrates a method for counting the number of drivers and drone operators:
# Bind the session tibbles sessions <- bind_tbl(d, session) # Print numbers of drivers and drones sessions %>% count(role)
Here's an example of using bind_tbl()
in combination with get_drivers()
and dplyr functions (in tidyverse) to count the number of collisions each driver had:
# Get events for all drivers driver_events <- d %>% get_drivers() %>% bind_tbl(events) # Count number collisions per driver driver_events %>% group_by(uid) %>% summarise(n_collisions = sum(event == "collision"))
This example demonstrates a method for calculating variance in the steering wheel use during the black ice event, for each lap, for each driver.
# Get streams tibble for all drivers streams <- d %>% get_drivers() %>% bind_tbl(streams) # Refine to variables of interest streams <- streams %>% select(uid, lap, time, input_horizontal, ice) # Filter to only keep rows when drivers were on black ice streams <- streams %>% filter(ice) streams # Summarise to compute variance of brake during each black ice event (per lap) steer_on_ice <- streams %>% group_by(uid, lap) %>% summarise(steer_var = var(input_horizontal)) steer_on_ice # Plot the results ggplot(steer_on_ice, aes(x = lap, y = steer_var)) + geom_path(aes(color = uid)) + geom_point(size = 4) + labs(x = "Lap number", y = "Steering Variance") + ggtitle("Drivers' steering variance during the black ice event")
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.