## ----include = FALSE---------------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ## ----setup, message=FALSE----------------------------------------------------- library(stdbscan) library(readr) library(ggplot2) library(plotly) ## ----------------------------------------------------------------------------- head(geolife_traj) ## ----fig.wigeolife_trajh=7, fig.height=7-------------------------------------- ggplot() + geom_path(data = geolife_traj, aes(x, y)) + labs(x = "", y = "", title = "GPS track analyzed in this vignette", caption = "Data: GeoLife GPS Trajectories (Microsoft, 2012). Author: Antoine Le Doeuff, 2026", ) + coord_equal() + theme_minimal() + theme(plot.title = element_text(size = 16, face = "bold")) ## ----------------------------------------------------------------------------- geolife_traj$date_time <- as.POSIXct( paste(geolife_traj$date, geolife_traj$time), format = "%Y-%m-%d %H:%M:%S", tz = "GMT" ) # Sort data by time if needed geolife_traj <- geolife_traj[order(geolife_traj$date_time), ] # Convert to cumulative time geolife_traj$t <- as.numeric( geolife_traj$date_time - min(geolife_traj$date_time) ) # Convert to matrix data <- cbind(geolife_traj$x, geolife_traj$y, geolife_traj$t) ## ----fig.height=8------------------------------------------------------------- (res <- st_dbscan( data = data, eps_spatial = 3, # meters eps_temporal = 30, # seconds min_pts = 3, # extra arguments splitRule = "STD", search = "kdtree", approx = 1 )) ## ----fig.wigeolife_trajh=7, fig.height=7-------------------------------------- # Put the cluster in the input data geolife_traj$clust <- as.factor(res$cluster) # Extract stops and movements geolife_traj_mvt <- geolife_traj[geolife_traj$clust == "0", ] geolife_traj_stop <- geolife_traj[geolife_traj$clust != "0", ] # Plot ggplot() + geom_path(data = geolife_traj_mvt, aes(x, y)) + geom_point(data = geolife_traj_stop, aes(x, y, color = clust), size = 4) + labs(x = "", y = "", color = "stop ID", title = "ST-DBSCAN stop identification", subtitle = "eps_spatial = 3 m, eps_temporal = 30 s and min_pts = 3", caption = "Data: GeoLife GPS Trajectories (Microsoft, 2012). Author: Antoine Le Doeuff, 2026", ) + scale_color_manual(values = MetBrewer::met.brewer("Isfahan2", 5)) + coord_equal() + theme_minimal() + theme( legend.position = "bottom", plot.title = element_text(size = 16, face = "bold"), ) ## ----warning=FALSE, message=FALSE--------------------------------------------- # Zoom on stop 4 geolife_traj_f <- geolife_traj[ geolife_traj$x > 441060 & geolife_traj$x < 441100, ] geolife_traj_f <- geolife_traj_f[ geolife_traj_f$y > 4428780 & geolife_traj_f$y < 4428820, ] # Extract stop geolife_traj_f_stop <- geolife_traj_f[geolife_traj_f$clust != "0", ] # Plotly figure fig <- plot_ly( data = geolife_traj_f, x = ~x, y = ~y, z = ~t, type = "scatter3d", mode = "lines+markers", line = list(wigeolife_trajh = 4, color = "grey"), marker = list(size = 3, color = "grey") ) fig |> add_markers( x = ~geolife_traj_f_stop$x, y = ~geolife_traj_f_stop$y, z = ~geolife_traj_f_stop$t, marker = list(size = 4, color = 'red'), name = 'Stop' ) |> layout( scene = list( xaxis = list(title = "x"), yaxis = list(title = "y"), zaxis = list(title = "t") ) )