Overall, I am looking for a way to prevent the evaluation of the body of Manipulate
until the controls meet a certain condition.
For example, consider the following.
Manipulate[
(*big code*),
{{x, Null}, {1, 2}, PopupMenu},
{{y, Null}, {3, 4}, PopupMenu},
TrackedSymbols :> True]
(* big code*)
depends on x
and y
and is not just one function, but large, computationally expensive code containing variable assignments and functions. Because the body of Manipulate
is computationally expensive, I of course, do not want it to run if either x
is Null or y
is Null.
I tried using If
and SynchronousUpdating -> True
as below.
Manipulate[
If[x == Null || y == Null, {x, y}, #] &@(* big code*),
{{x, Null}, {1, 2}, PopupMenu},
{{y, Null}, {3, 4}, PopupMenu},
TrackedSymbols :> True, SynchronousUpdating -> True]
However, something is fishy here. First, when running the code for the first time, x
and y
are both Null, so the code should run very fast. I get the correct output, but the code is slow, which makes me think (* big code*)
is still being read when it shouldn't be. Second, if I then change x
while keeping y
in its default Null value, I get the correct output, but once again, the code runs slowly. Finally, when I make both x
and y
not Null, the output is garbled.
I feel there should be a better way of doing what I want anyway. Any thoughts?
I just want the body of Manipulate
to be touched in no way until the controls meet a certain condition.
Update
Doing all of what @lericr mentioned in the comments solves this problem.
expensiveFunct
to only fire on numbers? Something likeexpensiveFunct[x_?NumericQ, y_?NumericQ] := <expensive code>; expensiveFunct[___] := $Failed
$\endgroup$If
is a special form. It holds its arguments (after the initial predicate) unevaluated. But you're applying a functional form (If[...,...,#]&
), so thebig code
stuff is being evaluated. You need to put thebig code
stuff inside theIf
. Another problem is you're using==
withNull
, which I don't think will ever evaluate to a boolean unless the left hand side isNull
. So, you either need to use===
or you need to add a fourth argument to yourIf
. $\endgroup$a = 1; If[a == 1, 1, Pause[2]] // AbsoluteTiming
witha = 1; If[a == 1, 1, #] &[Pause[2]] // AbsoluteTiming
. HoweverIf[a == 1, 1, #; 2] &[Unevaluated[Pause[2]]] // AbsoluteTiming
leads to the same result as placing thePause
inside theIf
$\endgroup$