@@ -36,9 +36,14 @@ def viz_ts():
3636 ts_small.dump("data/viz_ts_small.trees")
3737
3838 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
3945 ts_small_mutated.dump("data/viz_ts_small_mutated.trees")
4046
41-
4247def viz_root_mut():
4348 """
4449 Taken from the drawing unit tests
@@ -758,7 +763,8 @@ y_ticks = np.delete(y_ticks, np.argwhere(np.ediff1d(y_ticks) <= 0.01))
758763
759764svg = ts.draw_svg(size=(1000, 350), y_axis=True, y_gridlines=True, y_ticks=y_ticks, style=(
760765 ".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)}"
762768 ".y-axis .grid {stroke: #DDDDDD}"
763769 + ".tree :not(.leaf).node > .lab {transform: translate(0,0); text-anchor:middle; fill: white}"
764770 + ".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]))
789795```
790796
791797#### 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.
797804
798805``` {code-cell} ipython3
799806:"tags": ["hide-input"]
@@ -812,6 +819,80 @@ means that there can be sample nodes which are "isolated" in a tree. These are d
812819unconnected to the main topology in one or more trees (e.g. nodes 7 and 8 above).
813820:::
814821
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+
815896#### Animation
816897
817898The classes attached to the SVG also allow elements to be animated. Here's a
0 commit comments