Pick two nodes A and B and click other nodes to observe them (shaded, the set C). The demo lists every path between A and B, ignoring the directions of the links, and says where it is blocked: at a head-to-tail or tail-to-tail node that is observed, or at a head-to-head node that is not observed and has no observed descendant. If every path is blocked, A and B are d-separated by C and A ⊥ B | C holds for every distribution that factorises over the graph. The right-hand panel checks this on one such distribution: the conditional mutual information I(A; B | C) is zero (up to rounding) exactly when the graph says so.
Every node is binary. Except for the fuel gauge (the book's tables) and the five-node graph of Figure 8.22 (tables chosen to make the dependences visible), the tables are random: each probability p(x = 1 | parents) is drawn uniformly from (0.1, 0.9). I is in nats; values below 10−12 are rounding errors, so they count as zero.
code/ch08_graphical_models.py (functions d_separated, trails, markov_blanket, cond_mutual_info, fuel_gauge; Figures 8.15, 8.21, 8.22 and 8.26) and the checks in code/checks_ch08.py (d-separation against brute-force independence tests on random networks).