Let’s set up a minimal spatial simulation using slimr. We will use it to demonstrate making animation of results in gganimate

library(slimr)
library(gganimate)
N <- 100

## minimal spatial sim
spat_sim <- slim_script(
  
  slim_block(initialize(), {
    initializeSLiMOptions(dimensionality = "xy")
    initializeMutationRate(1e-7)
    initializeMutationType("m1", 0.5, "f", 0.0)
    initializeGenomicElementType("g1", m1, 1.0)
    initializeGenomicElement(g1, 0, 100000 - 1)
    initializeRecombinationRate(1e-8)
  }),
  
  slim_block(1, early(), {
    sim.addSubpop("p1", !!N)
    sim.addSubpop("p2", !!N)
    p1.setSpatialBounds(c(0, 0, 1, 1))
    p2.setSpatialBounds(c(0, 0, 1, 1))
    p1.individuals.setSpatialPosition(p1.pointUniform(!!N))
    p2.individuals.setSpatialPosition(p2.pointUniform(!!N))
  }),
  
  slim_block(1, 1000, late(), {
    inds = sim.subpopulations.individuals
    location = inds.spatialPosition
    ## move around a bit
    inds.setSpatialPosition(p1.pointReflected(sim.subpopulations.individuals.spatialPosition +
                                                rnorm(inds.size() * 2, 0, 0.01)))
    slimr_output_full()
  }),
  
  slim_block(modifyChild(), {
    
    child.setSpatialPosition(parent1.spatialPosition)
    return(T)
    
  })
  
)

spat_sim
<slimr_script[4]>
block_init:initialize() {
    initializeSLiMOptions(dimensionality = "xy");
    initializeMutationRate(1e-07);
    initializeMutationType("m1", 0.5, "f", 0);
    initializeGenomicElementType("g1", m1, 1);
    initializeGenomicElement(g1, 0, 1e+05 - 1);
    initializeRecombinationRate(1e-08);
}

block_2:1 early() {
    sim.addSubpop("p1", 100);
    sim.addSubpop("p2", 100);
    p1.setSpatialBounds(c(0, 0, 1, 1));
    p2.setSpatialBounds(c(0, 0, 1, 1));
    p1.individuals.setSpatialPosition(p1.pointUniform(100));
    p2.individuals.setSpatialPosition(p2.pointUniform(100));
}

block_3:1:1000 late() {
    inds = sim.subpopulations.individuals;
    location = inds.spatialPosition;
    inds.setSpatialPosition(p1.pointReflected(sim.subpopulations.individuals.spatialPosition + rnorm(inds.size() * 2, 0, 0.01)));
    {sim.outputFull() -> full_output}
}

block_4:1:1000 modifyChild() {
    child.setSpatialPosition(parent1.spatialPosition);
    return(T);
}

Run that simulation with slim_run.

spat_run <- slim_run(spat_sim)


Simulation finished with exit status: 0

Success!

Now we can easily extract coordinates:

coords <- slim_extract_full(spat_run$output_data, "coordinates")
coords
# A tibble: 200,000 x 10
   generation unique_ind_id pop_id ind_id sex   gen_id_1 gen_id_2     x     y
        <int> <chr>         <chr>  <chr>  <chr> <chr>    <chr>    <dbl> <dbl>
 1          1 p1:i0         p1     i0     H     p1:0     p1:1     0.799 0.373
 2          1 p1:i1         p1     i1     H     p1:2     p1:3     0.185 0.100
 3          1 p1:i2         p1     i2     H     p1:4     p1:5     0.230 0.636
 4          1 p1:i3         p1     i3     H     p1:6     p1:7     0.565 0.838
 5          1 p1:i4         p1     i4     H     p1:8     p1:9     0.234 0.954
 6          1 p1:i5         p1     i5     H     p1:10    p1:11    0.771 0.391
 7          1 p1:i6         p1     i6     H     p1:12    p1:13    0.616 0.794
 8          1 p1:i7         p1     i7     H     p1:14    p1:15    0.246 0.235
 9          1 p1:i8         p1     i8     H     p1:16    p1:17    0.113 0.207
10          1 p1:i9         p1     i9     H     p1:18    p1:19    0.756 0.233
# ... with 199,990 more rows, and 1 more variable: z <dbl>

Animate it!

anim <- ggplot(coords, aes(x, y)) +
  geom_point(aes(colour = pop_id)) +
  scale_fill_viridis_c() +
  coord_equal() +
  transition_time(generation) +
  shadow_wake(wake_length = 0.01,
              alpha = 0.5) +
  theme_minimal()

animate(anim, nframes = 1000, fps = 30)