I've been working on a map showing lines running across Europe. Each line is coming from a GPX file, parsed in like so:

spdf <- readOGR("data/file.gpx", layer = "track_points")

Now, if I plot the map using plot(), I can simplify each of these lines without any issue:

spdf_simple <- gSimplify(spdf, tol = 0.1)

However, in this particular instance I am using ggplot2 and need to keep a dataframe structure, as I'm doing some filtering (see below):

# load each file
for (file in list.files('data/') {
    # parse each file
    track_points <- readOGR(paste("data/", file, sep = ""), layer = "track_points")
    track_points@data$time_clean <- ymd_hms(track_points@data$time)

    # we need to preserve @data to filter the time value later on
    df1 <- data.frame(track_points@data)
    df2 <- data.frame(track_points@coords)
    df <- bind_cols(df1, df2)

    # filter out all records that happened after FINISH time
    df.filter <- df %>%
      filter(time_clean < FINISH) %>% 
      select(time, coords.x1, coords.x2) %>%
      mutate(group = file)
    colnames(df.filter) <- c('time', 'lon', 'lat', 'group')

    paths <- rbind(paths, df.filter)

Subsequently I can plot my paths like so:

ggplot() +
    geom_path(data = paths, aes(lon, lat, group = group))

Now the result of gSimplify is a sp::SpatialPoints object which doesn't preserve what's in @data.

I'd like to simplify these paths, although I'm at a loss as to where to do it in ggplot world.

  • If I read a GPX with layer="track_points" and then plot it with plot(spdf) I gt points, not a track. Then running gSimplify on points doesn't actually do any simplification - it returns the points without the attributes. Maybe you need to read the tracks layer?
    – Spacedman
    Commented Nov 18, 2018 at 16:58

1 Answer 1


It might be easier to do this using the sf package.

First read in the GPS track points and I'll assign some time points to each point because my demo GPX doesn't have time stamps:

> library(sf)
> pts = st_read("./uni2track.gpx","track_points", quiet=TRUE)
> dim(pts)
[1] 13 27
> pts$time = Sys.time() + (1:nrow(pts)*73)
> pts$time
 [1] "2018-11-18 17:21:28 GMT" "2018-11-18 17:22:41 GMT"
 [3] "2018-11-18 17:23:54 GMT" "2018-11-18 17:25:07 GMT"
 [5] "2018-11-18 17:26:20 GMT"  (etc, 13 time points)

If I do plot(pts) I see points, not a track. To make a track, I need to combine the points to multipoint, and then cast that to a LINESTRING:

> track = st_cast(st_combine(pts),"LINESTRING")
> track
Geometry set for 1 feature 
geometry type:  LINESTRING
dimension:      XY
bbox:           xmin: -2.788547 ymin: 54.0087 xmax: -2.784867 ymax: 54.01289
epsg (SRID):    4326
proj4string:    +proj=longlat +datum=WGS84 +no_defs
LINESTRING (-2.785507 54.00952, -2.785587 54.01...

Now that's a single row (feature) representing a track. Plotting it shows a line. The attributes at each point are gone, but don't worry we'll get them back shortly.

Now we simplify the LINESTRING track feature:

> track_simple = st_simplify(track, dTolerance=0.001)

track_simple now has five points. To find out which points they are in the original data, use st_intersection:

> track_simple_pts = st_intersection(pts, track_simple)

And then I can get the attributes at each point in track_simple as:

> track_simple_pts$time
[1] "2018-11-18 17:21:28 GMT" "2018-11-18 17:26:20 GMT"
[3] "2018-11-18 17:31:12 GMT" "2018-11-18 17:34:51 GMT"
[5] "2018-11-18 17:36:04 GMT"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.