2
$\begingroup$

In this question, I learned how to cascade or nest interdependent Setter and SetterBar controls with numerical Ranges. The puzzle has arisen again, this time with lists containing symbols. This puzzle is not, to me, in any obvious way a duplicate of the prior one.

Consider this miniature database of destination cities:

destinations = {SLC, DEN, OKC, MSY, ABQ};

and this function (as a lookup table) from destination city to pair of nearby source cities:

src[SLC] = {ONT, PHX}; 
src[DEN] = {PHX, DFW}; 
src[OKC] = {DFW, SAT}; 
src[MSY] = {DFW, TPA}; 
src[ABQ] = {DFW, PHX};

My first attempt at nested controls, allowing one to choose a destination city and then choose one of the nearby source cities, produced a surprise:

Manipulate[
 {dest, source},
 {dest, destinations, SetterBar},
 {{source, src[dest][[1]]}, src[dest], SetterBar}]

enter image description here

Notice that, while the pair of sources for each destination are correctly pulled from the src function, there is no default selected item in the lower SetterBar even though I explicitly set it to the first item src[dest][[1]]. The default source seems always to be (inexplicably) the first city in destinations list. The source SetterBar works correctly when I click in it, but its default is never set correctly.

I can work around the problem by mapping through indices:

Manipulate[
 {dest, src[dest][[source]]},
 {dest, destinations, SetterBar},
 {{source, 1}, {1 -> src[dest][[1]], 2 -> src[dest][[2]]}, SetterBar}]

enter image description here

but this is not a robust solution because it requires me to hardcode the list of button labels in a set of rules. What if I wanted three sources for one of the destinations?

$\endgroup$
5
  • 1
    $\begingroup$ Maybe, MapIndexed[#2[[1]] -> # &, src[dest]] in place of {1 -> src[dest][[1]], 2 -> src[dest][[2]]} to cover cases where src[_] can be of any length? $\endgroup$
    – kglr
    Commented Sep 12, 2017 at 13:36
  • 1
    $\begingroup$ This is less about the GUI and more about the code, but: have you considered making src an Association[]? $\endgroup$ Commented Sep 12, 2017 at 13:40
  • $\begingroup$ @klgr that works nicely, with "SetterBar" remaining as the control type (the control type defaults to a slider, which is weird because the domain is discrete, but was explained in the referenced older question as a side effect of an implicit Dynamic). $\endgroup$
    – Reb.Cabin
    Commented Sep 12, 2017 at 15:10
  • $\begingroup$ @J.M. I tried associations. With the original control spec, namely {{source, src[dest][[1]]}, src[dest], SetterBar}, associations produce the same undesirable results as my first proposal. I have long hypothesized that associations are just an alternative syntax for the traditional, single-bracket, pseudo-functional, pattern-matching notation like src[dest], which produces an internal lookup table (almost certainly a hash table). Semantically, I don't know of a difference between an association and the equivalent set of single-bracket definitions like my original definition of src. $\endgroup$
    – Reb.Cabin
    Commented Sep 12, 2017 at 15:18
  • 1
    $\begingroup$ @Reb.Cabin You might want to have a look at this question regarding the use of associations $\endgroup$
    – Lukas Lang
    Commented Sep 12, 2017 at 15:24

3 Answers 3

2
$\begingroup$

You can use the option TrackingFunction

destinations = {SLC, DEN, OKC, MSY, ABQ};
src[SLC] = {ONT, PHX}; 
src[DEN] = {PHX, DFW}; 
src[OKC] = {DFW, SAT}; 
src[MSY] = {DFW, TPA}; 
src[ABQ] = {DFW, PHX};
Manipulate[
 {dest, source},
 {dest, destinations, SetterBar,TrackingFunction->(dest=#;source=src[dest][[1]];&)},
 {source, src[dest], SetterBar}]

EDIT

Here is a new version with the right initialisation :

destinations = {SLC, DEN, OKC, MSY, ABQ};
src[SLC] = {ONT, PHX}; 
src[DEN] = {PHX, DFW}; 
src[OKC] = {DFW, SAT}; 
src[MSY] = {DFW, TPA}; 
src[ABQ] = {DFW, PHX};
Manipulate[
 {dest, source},
 {dest, destinations, SetterBar,TrackingFunction->(dest=#;source=src[#][[1]];&)},
 {source, src[dest], SetterBar},
 Initialization:> (dest=destinations[[1]];source = src[destinations[[1]]][[1]])]
$\endgroup$
2
  • $\begingroup$ This is the option I always forget the name and it's impossible to find the name by consulting the documentation. $\endgroup$
    – andre314
    Commented Sep 12, 2017 at 16:31
  • $\begingroup$ This is close to best because I can use source directly and not src[dest][[source]] in the content of the Manipulate. If you fix a couple of things, I'll mark it as the answer. I had to change the TrackingFunction to TrackingFunction -> (dest = #; source = src[#][[1]]; & and the initial value of source to src[destinations[[1]]][[1]]. $\endgroup$
    – Reb.Cabin
    Commented Sep 12, 2017 at 16:57
2
$\begingroup$

One way of doing it is the following:

Manipulate[{dest, source},
 {dest, destinations, SetterBar},
 {source, (source = src[dest][[1]]; SetterBar[Dynamic[source], src[dest]]) &}
]

This works by manually specifying the control for source. The function that generates the control simply sets source explicitly to the desired default value.

$\endgroup$
1
  • $\begingroup$ This is also a great answer because I can use source instead of src[dest][[source]] in the content of the Manipulate. I prefer andre's TrackingFunction solution because of (subjectively) more obvious semantics. In other words, if I had known about TrackingFunction I probably would have thought of andre's solution before yours, but that's only because I would have been distracting by thinking source is already Dynamic. $\endgroup$
    – Reb.Cabin
    Commented Sep 12, 2017 at 17:01
1
$\begingroup$
Manipulate[{dest, src[dest][[source]]}, 
 {dest, destinations, SetterBar}, 
 {{source, 1}, MapIndexed[#2[[1]] -> # &, src[dest]], SetterBar}]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.