@@ -36,9 +36,14 @@ def viz_ts():
36
36
ts_small.dump("data/viz_ts_small.trees")
37
37
38
38
ts_small_mutated = msprime.sim_mutations(ts_small, rate=1e-7, random_seed=342)
39
+ # 3rd tree should have first site with 2 muts
40
+ first_site_tree_2 = next(ts_small_mutated.at_index(2).sites())
41
+ assert len(first_site_tree_2.mutations) == 2
42
+ # mutation 8 should be above node 16 in the 1st tree
43
+ assert ts_small_mutated.site(8).mutations[0].id == 8
44
+ assert ts_small_mutated.site(8).mutations[0].node == 16
39
45
ts_small_mutated.dump("data/viz_ts_small_mutated.trees")
40
46
41
-
42
47
def viz_root_mut():
43
48
"""
44
49
Taken from the drawing unit tests
@@ -758,7 +763,8 @@ y_ticks = np.delete(y_ticks, np.argwhere(np.ediff1d(y_ticks) <= 0.01))
758
763
759
764
svg = ts.draw_svg(size=(1000, 350), y_axis=True, y_gridlines=True, y_ticks=y_ticks, style=(
760
765
".tree .lab {font-family: sans-serif}"
761
- ".x-axis .tick .lab {text-anchor: start; transform: rotate(90deg) translate(8px)}"
766
+ # Normal X axis tick labels have dominant baseline: hanging, but it needs centring when rotated
767
+ ".x-axis .tick .lab {text-anchor: start; dominant-baseline: central; transform: rotate(90deg)}"
762
768
".y-axis .grid {stroke: #DDDDDD}"
763
769
+ ".tree :not(.leaf).node > .lab {transform: translate(0,0); text-anchor:middle; fill: white}"
764
770
+ ".tree :not(.leaf).node > .sym {transform: scale(3.5)}"
@@ -789,11 +795,12 @@ SVG(ts.draw_svg(style=css_string, time_scale="rank", x_lim=[0, 30]))
789
795
```
790
796
791
797
#### Leaf, sample & isolated nodes
792
- By default, sample nodes are square and non-sample nodes circular. However, neither need
793
- to be at time 0. Moreover, leaves need not be samples, and samples need not be leaves.
794
- Here we change the previous tree sequence to make some leaves non-samples and some samples
795
- internal nodes. To highlight the change, we have plotted sample nodes in green, and
796
- leaf nodes (if not samples) in blue.
798
+ By default, sample nodes are square and non-sample nodes circular (at the moment this
799
+ can't easily be changed). However, neither need to be at specific times: sample nodes can
800
+ be at times other than 0, and nonsample nodes can be at time 0. Moreover, leaves need not
801
+ be samples, and samples need not be leaves. Here we change the previous tree sequence to
802
+ make some leaves non-samples and some samples internal nodes. To highlight the change,
803
+ we have plotted sample nodes in green, and leaf nodes (if not samples) in blue.
797
804
798
805
``` {code-cell} ipython3
799
806
:"tags": ["hide-input"]
@@ -812,6 +819,80 @@ means that there can be sample nodes which are "isolated" in a tree. These are d
812
819
unconnected to the main topology in one or more trees (e.g. nodes 7 and 8 above).
813
820
:::
814
821
822
+ #### Tick labels and gridlines
823
+
824
+ Y tick labels can be specified explicitly, which allows time scales to be plotted
825
+ e.g. in years even if the tree sequence ticks in generations. The grid lines associated
826
+ with each y tick can also be changed or even hidden individually using the CSS
827
+ [ nth-child pseudo-selector] ( https://www.w3.org/TR/2018/REC-selectors-3-20181106/#nth-child-pseudo ) ,
828
+ where tickmarks are indexed from the bottom. This is used in
829
+ the {ref}` sec_msprime_introgression ` tutorial to show lines behind the trees at specific,
830
+ important times. Below we show a slightly simpler example than in that tutorial,
831
+ keeping node and mutation symbols in black, but colouring gridlines instead:
832
+
833
+ ``` {code-cell} ipython3
834
+ :"tags": ["hide-input"]
835
+ # Function from the introgression tutorial - see there for justification
836
+ import msprime
837
+ time_units = 1000 / 25 # Conversion factor for kya to generations
838
+
839
+ def run_simulation(sequence_length, random_seed=None):
840
+ demography = msprime.Demography()
841
+ # The same size for all populations; highly unrealistic!
842
+ Ne = 10**4
843
+ demography.add_population(name="Africa", initial_size=Ne)
844
+ demography.add_population(name="Eurasia", initial_size=Ne)
845
+ demography.add_population(name="Neanderthal", initial_size=Ne)
846
+
847
+ # 2% introgression 50 kya
848
+ demography.add_mass_migration(
849
+ time=50 * time_units, source='Eurasia', dest='Neanderthal', proportion=0.02)
850
+ # Eurasian 'merges' backwards in time into Africa population, 70 kya
851
+ demography.add_mass_migration(
852
+ time=70 * time_units, source='Eurasia', dest='Africa', proportion=1)
853
+ # Neanderthal 'merges' backwards in time into African population, 300 kya
854
+ demography.add_mass_migration(
855
+ time=300 * time_units, source='Neanderthal', dest='Africa', proportion=1)
856
+
857
+ ts = msprime.sim_ancestry(
858
+ recombination_rate=1e-8,
859
+ sequence_length=sequence_length,
860
+ samples=[
861
+ msprime.SampleSet(1, ploidy=1, population='Africa'),
862
+ msprime.SampleSet(1, ploidy=1, population='Eurasia'),
863
+ # Neanderthal sample taken 30 kya
864
+ msprime.SampleSet(1, ploidy=1, time=30 * time_units, population='Neanderthal'),
865
+ ],
866
+ demography = demography,
867
+ record_migrations=True, # Needed for tracking segments.
868
+ random_seed=random_seed,
869
+ )
870
+ return ts
871
+
872
+ ts = run_simulation(20 * 10**6, 1)
873
+
874
+ css = ".y-axis .tick .lab {font-size: 85%}" # Multi-line labels unimplemented: use smaller font
875
+ css += ".y-axis .tick .grid {stroke: lightgrey}" # Default gridline type
876
+ css += ".y-axis .ticks .tick:nth-child(3) .grid {stroke-dasharray: 4}" # 3rd line from bottom
877
+ css += ".y-axis .ticks .tick:nth-child(3) .grid {stroke: magenta}" # also 3rd line from bottom
878
+ css += ".y-axis .ticks .tick:nth-child(4) .grid {stroke: blue}" # 4th line from bottom
879
+ css += ".y-axis .ticks .tick:nth-child(5) .grid {stroke: darkgrey}" # 5th line from bottom
880
+ y_ticks = {0: "0", 30: "30", 50: "Introgress", 70: "Eur origin", 300: "Nea origin", 1000: "1000"}
881
+ y_ticks = {y * time_units: lab for y, lab in y_ticks.items()}
882
+ SVG(ts.draw_svg(
883
+ size=(1200, 500),
884
+ x_lim=(0, 25_000),
885
+ time_scale="log_time",
886
+ node_labels = {0: "Afr", 1: "Eur", 2: "Neand"},
887
+ y_axis=True,
888
+ y_label="Time (kya)",
889
+ x_label="Genomic position (bp)",
890
+ y_ticks=y_ticks,
891
+ y_gridlines=True,
892
+ style=css))
893
+ ```
894
+
895
+
815
896
#### Animation
816
897
817
898
The classes attached to the SVG also allow elements to be animated. Here's a
0 commit comments