Repository navigation
Replies: 23 comments
|
If, as @nspope suggests, we cut the inferred tree sequence into three parts (to the left, centre, and right of the orange zone), we get something like the iterated version within the sweep zone. This implies that indeed, we are porting too much information from adjacent trees (i.e. our ancestral nodes within the swept region are too long, extending into regions of the genome where they shouldn't exist, and we are matching into those regions):
So while Relate probably doesn't tie together nodes enough, tsinfer might tie them together too much? This might also be exacerbated because if there are several equally likely matches during match_ancestors, # alternatively, split up the tree sequence so that internal nodes are broken either side of the
# cutoff values, so that adjacent regions are not dragging the nodes down
cutoffs = sim_ts.sequence_length/2 + np.array([-1, 1]) * 200_000
i_ts = tsinfer.infer(tsinfer.SampleData.from_tree_sequence(sim_ts))
i1_ts = i_ts.keep_intervals([[0, cutoffs[0]]])
i2_ts = i_ts.keep_intervals([[cutoffs[0], cutoffs[1]]])
i3_ts = i_ts.keep_intervals([[cutoffs[1], sim_ts.sequence_length]])
tables = i1_ts.dump_tables()
node_map, site_map = np.arange(i2_ts.num_nodes), np.arange(i2_ts.num_sites)
for n in i2_ts.nodes():
if not n.is_sample():
node_map[n.id] = tables.nodes.append(n)
for e in i2_ts.edges():
tables.edges.append(e.replace(parent=node_map[e.parent], child=node_map[e.child]))
for s in i2_ts.sites():
site_map[s.id] = tables.sites.append(s)
for m in i2_ts.mutations():
tables.mutations.append(m.replace(site=site_map[m.site], node=node_map[m.node]))
node_map, site_map = np.arange(i3_ts.num_nodes), np.arange(i3_ts.num_sites)
for n in i3_ts.nodes():
if not n.is_sample():
node_map[n.id] = tables.nodes.append(n)
for e in i3_ts.edges():
tables.edges.append(e.replace(parent=node_map[e.parent], child=node_map[e.child]))
for s in i3_ts.sites():
site_map[s.id] = tables.sites.append(s)
for m in i3_ts.mutations():
tables.mutations.append(m.replace(site=site_map[m.site], node=node_map[m.node], parent=tskit.NULL))
tables.sort()
tables.build_index()
tables.compute_mutation_parents()
i_all_ts = tables.tree_sequence()
d_split_ts = tsdate.date(
i_all_ts, mutation_rate=mu, population_size=pop_size, method="variational_gamma", max_shape=1000) |
|
I suspect what is going on when we iteratively improve the situation is that we are forcing ancestors within the swept region to adopt slightly more ancestral states in the regions flanking the focal sites, and also, crucially, to make shorter ancestors (the left-and-right building process will terminate earlier, because adjacent site distributions are more often incompatible with with original pattern of variation at the focal site. That explains why you need to take the dates into account when actually building ancestors, not just when matching. Note that Relate might fall into the same trap, because it might use topology to accidentally group edges or nodes between the swept and non-swept regions, when actually they should be separate. |
|
Can you show a tsqc plot of the ancestor haplotype lengths and edges in the inferred ts here @hyanwong? Should help intuition. Does this use truncate ancestors? |
|
Nice. Do you think it's the long old edges that are causing the problem, or more recent ones that are closely associated with the sweep? |
Well, the badly dated nodes are all at a time of ~1.5e2 (log time = 5) and are being wrongly dated as time 1e4 (log time ~ 9), so I think the problem is that some of the medium-length edges in the sweep region are being pushed way back in time (you can see these in the edges plot, in the middle of what should be a blank triangle around (2.5e6, 10), (2.5e6, 8.8), and (2.5e6, 7.5) . As @nspope surmised, this is likely to be because the ancestors associated with these edges are attached via other edges to correctly dated ancient nodes. My suggestion is that when we iteratively refine the ancestor dates, we change the recent ancestral haplotypes in the swept region so that although they might contain high frequency derived variants, they are placed more recently than their frequency suggests. This means that sites which are adjacent to the focal sites will not contain older derived alleles, and so the recent haplotype won't be treated as e.g. a parent of a relatively old haplotype, or an immediate child of an old haplotype. |
|
Edge plot is definitely showing it's picking something up re the sweep. When you look closely there's also these odd curves in there, where the ends of edges seem to form patterns: Nothing to do with the sweep, just an interesting qualitative property of the ARG-Needle edges that shows up in this view. cc @savitakartik - cool to see tsqc working here on Relate and ARG-Needle! |
|
Very interesting to see the patterns in ARGneedle edges, and the edges plot picking up the sweep! Super interesting work, Yan. I really enjoyed reading this thread. |
|
Interesting! Possible explanation for why previous attempts at iteration didn't seem to work? |
|
A major improvement is seen if we use @nspope 's
And here's what it looks like after 6 rounds of iteration:
Edit: here's the edge plot too, e.g. via from matplotlib import pyplot as plt
import numpy as np
from matplotlib import collections as mc
tm = ts.nodes_time[ts.edges_child]
lines = np.array([[ts.edges_left, ts.edges_right], [tm, tm]]).T
lc = mc.LineCollection(lines, linewidths=1)
fig, ax = plt.subplots(figsize=(10, 5))
ax.add_collection(lc)
ax.autoscale()
ax.margins(0)
ax.set_yscale("log")
ax.set_ylabel("Time of edge child (generations)")
ax.set_xlabel("Genome position")
|
|
This looks great -- there's no visible artefacts in the residuals from the sweep |
Not quite as good as using the true site times (see #877 (comment)), and there is a slight band of orange residuals just below 2, but yes, generally excellent. |
|
Interestingly, if we also split the root nodes (see #850) , we initially do better, but then start doing worse on repeated tsinfer/date iteration:: |
|
The iterative process also seems to improve the mismatch between site and branch-length measures of diversity (see tskit-dev/tsdate#366). And a closer match is seen if the |






























Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
We claim that tsinfer, not being particularly model-based, should be robust to selection. We can test this by carrying out a selective sweep and inferring + dating the result.
The plots below show that there are errors in dating around the position of the sweep.
However, if we repeat the analysis with the true tree sequence, as we might hope there are no dating biases.
This implies that we are doing something wrong in
tsinfer. The lower right hand plots imply that the arity of the node below the mutation is seemingly not an issue (@nspope suggested this might be a reason for oddness).Code to recreate these plots is:
All reactions