Skip to main content

dynamic - Trouble using If[] within TabView Manipulate control



If I place an If in the "body" of a Manipulate as in:


Manipulate[tick;
Dynamic@If [ s1 == 1,
{"m1 ", Manipulator[Dynamic[m1, (m1 = #; tick = Not[tick]) &], {1, 4}], " ", Dynamic[m1]},
{"m2 ", Manipulator[Dynamic[m2, (m2 = #; tick = Not[tick]) &], {0, 1}], " ", Dynamic[m2]}
]
, TabView[{ "1" -> Grid[tabNumber = t1;(*Dynamic@*){ }],
"2" -> Grid[tabNumber = t2; {
{"s1 ", SetterBar[Dynamic[s1, (s1 = #; tick = Not[tick]) &], Range[2]], " ", Dynamic[s1]}
}]

}, Dynamic@tabNumber]
, {{tick, False}, None} , {{tabNumber, 1}, None}
, {{t1, 1}, None} , {{t2, 2}, None} , {{m1, 1}, None} , {{m2, 1}, None} , {{s1, 1}, None}
, TrackedSymbols :> {tick}, ControlPlacement -> Left
]

Then the selection of the s1 SetterBar control switches the m1/m2 control in the Manipulate display without any trouble:


If within Manipulate


I'd like to have this condition within the TabView control, something like:


Manipulate[tick;

Dynamic@If[tabNumber == t1, Plot[x^2, {x, 0, 1}],
Plot[1 - x^2, {x, 0, 1}]]
, TabView[{
"1" ->(*Dynamic@*)Grid[tabNumber = t1;(*Dynamic@*){
(*Dynamic@*)If [ s1 == 1,
{"m1 ", Manipulator[ Dynamic[m1, (m1 = #; tick = Not[tick]) &], {1, 4}], " ", Dynamic[m1]},
{"m2 ", Manipulator[ Dynamic[m2, (m2 = #; tick = Not[tick]) &], {0, 1}], " ", Dynamic[m2]}
]
}],
"2" -> Grid[tabNumber = t2; {

{"s1 ", SetterBar[Dynamic[s1, (s1 = #; tick = Not[tick]) &], Range[2]], " ", Dynamic[s1]}
}]
}, Dynamic@tabNumber]
, {{tick, False}, None} , {{tabNumber, 1}, None}
, {{t1, 1}, None} , {{t2, 2}, None} , {{m1, 1}, None} , {{m2, 1}, None} , {{s1, 1}, None}
, TrackedSymbols :> {tick}, ControlPlacement -> Left
]

However, instead of one of the two desired controls showing up within the Tab, this producesGrid[...]` text instead:


Grid text in TabView



Is there a way to get the If condition in the Tab definition to evaluate before the TabView? I have tried all the variations of Dynamic@ that I can think of, but they didn't help.



Answer



I figured it out with the help of Dynamically choosing which Manipulate controls to use . That answer used Control@, which doesn't seem to be required here. However, it also pushes the If, up out of the control. That appears to be the trick:


Manipulate[tick;
Dynamic@If[tabNumber == t1, Plot[x^2, {x, 0, 1}],
Plot[1 - x^2, {x, 0, 1}]]
, Dynamic@If[ s1 == 1, tv[ t1gs1 ], tv[ t1gs2 ] ]
, {{tick, False}, None} , {{tabNumber, 1}, None}
, {{t1, 1}, None} , {{t2, 2}, None} , {{m1, 1}, None} , {{m2, 1}, None} , {{s1, 1}, None}


, TrackedSymbols :> {tick}, ControlPlacement -> Left

, Initialization :>
{
t1gs1 := {{"m1 ", Manipulator[Dynamic[m1, (m1 = #; tick = Not[tick]) &], {1, 4}], " ", Dynamic[m1]}} ;
t1gs2 := { {"m2 ", Manipulator[Dynamic[m2, (m2 = #; tick = Not[tick]) &], {0, 1}], " ", Dynamic[m2]} } ;

tv[pred_] := TabView[{
"1" -> Grid[tabNumber = t1; pred ],
"2" -> Grid[tabNumber = t2; { {"s1 ", SetterBar[Dynamic[s1, (s1 = #; tick = Not[tick]) &], Range[2]], " ", Dynamic[s1]} } ]

}, Dynamic@tabNumber] ;
}
]

I also had to introduce some helper functions for the TabView contents to avoid a whole lot of duplication.


EDIT: another way that works, without requiring global symbols that can be problematic, is to fix the bracing, ensuring that any If statements are entirely constrained within those braces. An example of that, structurally a bit different than above, is:


Manipulate[tick;
Switch[tabNumber, tab1, Plot[x^2, {x, 0, 1}], tab2, Plot[1 - x^2, {x, 0, 1}], _, Plot[Sin[v x] E^(-x), {x, 0, 1}]],
TabView[{
"1" -> Column[{Row[{"1 selected"}]}],

"2" -> Column[{Row[{"2 selected"}]}],
"3" -> Grid[{
{Row[{"3 selected"}]},
{Dynamic@If[s1 == 1, "",
Manipulator[Dynamic[v, (v = #; tick = Not[tick]) &], {1, 10}
, ImageSize -> Tiny, ContinuousAction -> False,
AppearanceElements -> {(*"InputField"*)}]]}
}]}
, Dynamic[tabNumber, (tabNumber = #; tick = Not[tick]) &]
]

, {{tick, False}, None} , {{s1, 1}, {1, 2}} , {{v, 1}, None}
, {{tabNumber, 1}, None}, {{tab1, 1}, None}, {{tab2, 2}, None}, {{tab3, 3}, None}
, TrackedSymbols :> {tick}
, ControlPlacement -> Left
]

This method also uses the second argument of Dynamic to collect tabNumber, which doesn't have side effects that interfere with SaveDefinitions.


Comments

Popular posts from this blog

mathematical optimization - Minimizing using indices, error: Part::pkspec1: The expression cannot be used as a part specification

I want to use Minimize where the variables to minimize are indices pointing into an array. Here a MWE that hopefully shows what my problem is. vars = u@# & /@ Range[3]; cons = Flatten@ { Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; Minimize[{Total@((vec1[[#]] - vec2[[u[#]]])^2 & /@ Range[1, 3]), cons}, vars, Integers] The error I get: Part::pkspec1: The expression u[1] cannot be used as a part specification. >> Answer Ok, it seems that one can get around Mathematica trying to evaluate vec2[[u[1]]] too early by using the function Indexed[vec2,u[1]] . The working MWE would then look like the following: vars = u@# & /@ Range[3]; cons = Flatten@{ Table[(u[j] != #) & /@ vars[[j + 1 ;; -1]], {j, 1, 3 - 1}], 1 vec1 = {1, 2, 3}; vec2 = {1, 2, 3}; NMinimize[ {Total@((vec1[[#]] - Indexed[vec2, u[#]])^2 & /@ R...

functions - Get leading series expansion term?

Given a function f[x] , I would like to have a function leadingSeries that returns just the leading term in the series around x=0 . For example: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x)] x and leadingSeries[(1/x + 2 + (1 - 1/x^3)/4)/(4 + x)] -(1/(16 x^3)) Is there such a function in Mathematica? Or maybe one can implement it efficiently? EDIT I finally went with the following implementation, based on Carl Woll 's answer: lds[ex_,x_]:=( (ex/.x->(x+O[x]^2))/.SeriesData[U_,Z_,L_List,Mi_,Ma_,De_]:>SeriesData[U,Z,{L[[1]]},Mi,Mi+1,De]//Quiet//Normal) The advantage is, that this one also properly works with functions whose leading term is a constant: lds[Exp[x],x] 1 Answer Update 1 Updated to eliminate SeriesData and to not return additional terms Perhaps you could use: leadingSeries[expr_, x_] := Normal[expr /. x->(x+O[x]^2) /. a_List :> Take[a, 1]] Then for your examples: leadingSeries[(1/x + 2)/(4 + 1/x^2 + x), x] leadingSeries[Exp[x], x] leadingSeries[(1/x + 2 + (1 - 1/x...

What is and isn't a valid variable specification for Manipulate?

I have an expression whose terms have arguments (representing subscripts), like this: myExpr = A[0] + V[1,T] I would like to put it inside a Manipulate to see its value as I move around the parameters. (The goal is eventually to plot it wrt one of the variables inside.) However, Mathematica complains when I set V[1,T] as a manipulated variable: Manipulate[Evaluate[myExpr], {A[0], 0, 1}, {V[1, T], 0, 1}] (*Manipulate::vsform: Manipulate argument {V[1,T],0,1} does not have the correct form for a variable specification. >> *) As a workaround, if I get rid of the symbol T inside the argument, it works fine: Manipulate[ Evaluate[myExpr /. T -> 15], {A[0], 0, 1}, {V[1, 15], 0, 1}] Why this behavior? Can anyone point me to the documentation that says what counts as a valid variable? And is there a way to get Manpiulate to accept an expression with a symbolic argument as a variable? Investigations I've done so far: I tried using variableQ from this answer , but it says V[1...