Loon: An Interactive Statistical Visualization Toolkit

Introduction

All of loon's plots can be linked so that some of their n-dimensional states are synchronized. For a linked scatterplot, the states that are synchronized by default (i.e. linked states) are the color, size, selected and active states. Two or more plots are linked if they share the same string in their linkingGroup state.

loon's standard linking model is fairly flexible and the user can choose

We allow only one-to-one synchronization. For example, selecting a point and have it's k nearest neighbors automatically selected in the same display is not possible. Also, it is not possible with the standard linking mechanism to have one selected point in display A result in selecting multiple points in display B. For cases where the standard model is not sufficient it is possible to implement custom linking rules with state bindings.

Loon's Standard Linking Model

The standard linking model depends on the two states linkingGroup and linkingKey.

Displays are linked if their linkingGroup state contains the same string.

For example, for

source iris.tcl
set p1 [plot -x $SepalWidth -y $PetalWidth -linkingGroup iris]
set p2 [plot -x $PetalLength -y $PetalWidth -linkingGroup iris]
set p3 [plot -x $SepalLength -y $PetalLength -linkingGroup none]
set h [histogram -x $SepalLength -linkingGroup iris]

the plots p1, p2, and h are linked to each other and p3 is not linked to any other display.

The states of a plot that are linked can be queried with

$p1 getLinkedStates

Usually the linked states are color, selected, active and size, if they exist for the particular plot. Histograms, for example, have no size state. Note that between displays only states with the same state name can be linked. To set the (n-dimensional!) linked states use

$p1 setLinkedStates {color active}

If display A is linked with display B then

Hence, for the above example where n=150 (i.e. the number of data points) when selecting the i'th point in p1 then loon will set the selected state for the i'th point in p2 and h to TRUE, for any i in {1,...,150}. If a further display gets created with linkingGroup iris but a different value for n, say n=4, then only the first for elements of that plot get synchronized between that display and p1, p2, and h. For example, for

set p4 [plot -x {1 2 3 4} -y {1 2 3 4} -linkingGroup iris]

any change in p4 for any of the linked states will only affect the first 4 elements in p1, p2 and h. Or vice versa, only the states of the first for elements in p1, p2 and h will ever have an effect on p4.

It is possible to change the mapping of which elements should be synchronized between displays. The n dimensional linkingKey state controls which elements get synchronized between the linked displays. That is for two linked displays A and B

By default, the linkingKey contains an n dimensional vector with 0,1,...,n-1.

Switching linkingGroup and linkingKey

Both, the linkingGroup state and the linkingKey state can be changed at run time. Changing the p2 in the above example to have linkingGroup contain the iris2 string, you can run

$p2 configure -linkingGroup iris2

now only p1 and h are linked.

If a plot's, say display A, linkingGroup is changed to a linking group that already has linked members, say display B, C, and D, then one must specify whether the initial synchronization of the linked states should be a push, i.e. A > B, C, D, or a pull, i.e. A < B, C, D. This is done with the sync argument:

$p2 configure -linkingGroup iris2 -sync pull

The sync argument must also be used if the linkingKey state gets changed of a plot that has linked displays. For example, to link the points in p4 with the last 4 points in the iris data use

$p4 configure -linkingKey {146 147 148 149} -sync push

Note that using the default linkingKey results in the fastest linking.

Custom Linking with State Bindings

If more flexible linking rules are needed, one can implement state bindings.

For example, for the following displays pa and pb

set pa [plot -x {1 2 3 4 5 6 7} -y {1 2 3 4 5 6 7} -title A]
set pb [plot -x {1 2 3 4 5} -y {1 2 3 4 5} -title B]

Assume the linking:

many to one is combined by a logical OR

many to one is combined by a logical OR

proc any {booleans} {
    return [expr [join $booleans ||]]
}

proc pa2pb {pa pb} {
    set sa [$pa cget -selected]
    set sb [$pb cget -selected]
    $pb configure -selected [list\
        [any [lrange $sa 0 2]]\
        [lindex $sa 3]\
        [any [lrange $sa 4 5]]\
        [lindex $sa 6]\
        [lindex $sb 4]]
}

proc pb2pa {pa pb} {
    set sb [$pb cget -selected]
    $pa configure -selected [concat\
        [lrepeat 3 [lindex $sb 0]]\
        [lindex $sb 1]\
        [lrepeat 2 [lindex $sb 2]]\
        [lindex $sb 3]]
}

$pa bind state selected "pa2pb $pa $pb"
$pb bind state selected "pb2pa $pa $pb"

This will not end in an endless loop of evaluating state bindings as after the sequence pa2pb - pb2pa - pa2pb or the pb2pa - pa2pb - pb2pa the system will be in equilibrium with respect to these functions. Remember that state bindings do not get evaluated if a configure call does not effectively change the state. If, however, the custom linking does not result in an equilibrium after the first change, then you may need to add a further variable, say busy, to avoid multiple iterations -- or an infinite loop--. Assume the linking

directions are indicated by arrows

directions are indicated by arrows

set pa2 [plot -x {1 2 3 4 5 6 7} -y {1 2 3 4 5 6 7} -title "A 2"]
set pb2 [plot -x {1 2 3 4 5} -y {1 2 3 4 5} -title "B 2"]

set busy FALSE

proc a2b {pa2 pb2} {
    if {!$::busy} {
        set ::busy TRUE
        $pb2 configure\
            -selected [expr ![lindex [$pa2 cget -selected] 0]]\
            -which_n 0
        set ::busy FALSE
    }
}

proc b2a {pa2 pb2} {
    if {!$::busy} {
        set ::busy TRUE
        $pa2 configure\
            -selected [expr ![lindex [$pb2 cget -selected] 0]]\
            -which_n 0
        set ::busy FALSE
    }
}

$pa2 bind state selected "a2b $pa2 $pb2"
$pb2 bind state selected "b2a $pa2 $pb2"

Without the variable busy this would end in an infinite loop one the selected state gets changed of either display.