Skip to content

Spatial equivalent of GNN #7

@hyanwong

Description

@hyanwong

I discussed with @percyfal some ideas of how to plot a GNN equivalent when we don't have a set of defined subpopulations. One possibility is to look at the nearest neighbours and to summarize their x/y locations, perhaps using an average location and some sort of variance.

Here's a SLiM script we could use for testing (try running it in the SLiM GUI: needs the world_map_540x217.png file from the SLiM docs):

// Keywords: continuous space, continuous spatial landscape, spatial map, reprising boundaries

initialize() {
	initializeSLiMOptions(dimensionality="xy");
	initializeTreeSeq();
	initializeMutationRate(1e-7);
	initializeMutationType("m1", 0.5, "f", 0.0);
	initializeGenomicElementType("g1", m1, 1.0);
	initializeGenomicElement(g1, 0, 99999);
	initializeRecombinationRate(1e-8);
	
	// spatial competition
	initializeInteractionType(1, "xy", reciprocal=T, maxDistance=30.0);
	i1.setInteractionFunction("n", 5.0, 10.0);
	
	// spatial mate choice
	initializeInteractionType(2, "xy", reciprocal=T, maxDistance=30.0);
	i2.setInteractionFunction("n", 1.0, 10.0);
}
1 late() {
	sim.addSubpop("p1", 1000);
	
	p1.setSpatialBounds(c(0.0, 0.0, 539.0, 216.0));
	
	// this file is in the recipe archive at http://benhaller.com/slim/SLiM_Recipes.zip
	mapImage = Image("~/Downloads/SLiM_Recipes/world_map_540x217.png");
	p1.defineSpatialMap("world", "xy", 1.0 - mapImage.floatK,
		valueRange=c(0.0, 1.0), colors=c("#0000CC", "#55FF22"));
	
	// start near a specific map location
	for (ind in p1.individuals) {
		ind.x = rnorm(1, 300.0, 1.0);
		ind.y = rnorm(1, 100.0, 1.0);
	}
}
1: late() {
	i1.evaluate();
	inds = sim.subpopulations.individuals;
	competition = i1.totalOfNeighborStrengths(inds) / size(inds);
	competition = pmin(competition, 0.99);
	inds.fitnessScaling = 1.0 - competition;
}
first() {
	i2.evaluate();
}
mateChoice() {
	return i2.strength(individual);
}
modifyChild() {
	do pos = parent1.spatialPosition + rnorm(2, 0, 0.5);
	while (!p1.pointInBounds(pos));
	
	// prevent dispersal into water
	if (p1.spatialMapValue("world", pos) == 0.0)
		return F;
	
	child.setSpatialPosition(pos);
	return T;
}
3000 late() {
	sim.treeSeqOutput("~/Downloads/SLiM_Recipes/spatial.trees");
}

And here's a rough, non-efficient, way of plotting out the spatial GNN (lots could be improved, and I think there's a bug, but putting it down here for reference):

import tskit
import numpy as np
import matplotlib.pyplot as plt

ts = tskit.load("/Users/Yan/Downloads/SLiM_Recipes/spatial.trees")

GNN_x = np.zeros(ts.num_samples)
GNN_y = np.zeros(ts.num_samples)
for u in ts.samples():
    loc = ts.individual(ts.node(u).individual).location
    GNN_x[u] = loc[0]
    GNN_y[u] = loc[1]

GNN_u = np.zeros(ts.num_samples)
GNN_v = np.zeros(ts.num_samples)

for tree in ts.trees():
    for u in ts.samples():
        x = 0
        y = 0
        n = 0
        focal_node = tree.parent(u)
        for s in tree.samples(focal_node):
            if s != u:
                loc = ts.individual(ts.node(s).individual).location
                n += 1
                x += GNN_x[u] - loc[0]
                y += GNN_y[u] - loc[1]
        GNN_u[u] += x * tree.span
        GNN_v[u] += y * tree.span
GNN_u /= ts.sequence_length
GNN_v /= ts.sequence_length

fig, ax = plt.subplots(figsize=(20, 15))
q = ax.quiver(GNN_x, GNN_y, GNN_u, GNN_v, units='xy')

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions