What's the best way to dynamically update variables that aren't displayed on screen?

3

2

One property of Dynamic is that its result has to be displayed and manipulated onscreen for the dynamic updating to take place. What's the best way to dynamically update "hidden" variables that nonetheless depend on and influence onscreen features (which in my case would consist of graphics and controls)?

To be more specific, I'm trying to track some symbol(s) for updates (sort of like Refresh does—or, even better, track a function value on a symbol, e.g. only track x[[3]]), and when the tracked symbol is updated, evaluate a certain expression (usually an assignment)—and have this all running completely in the background of some Dynamic or DynamicModule process.

Where to evaluate the "hidden" expression

  • One way seems to be to make a compound expression, and wrap the whole thing in dynamic, e.g. Dynamic[a=f[x]; <...>; interactiveGraphicMaker[x]].

  • Another seems to be to hide the update in the evaluation function, e.g. Dynamic[interactiveGraphicMaker[x],(a=f[x]; <...>; x=g[#])&]

  • It also seems like I can put a DynamicWrapper around dynamic content, e.g. DynamicWrapper[Dynamic[interactiveGraphic[x]], Dynamic[a=f[x]; <...>]]

  • I also could hide the work of updating itself in my function(s), e.g. expanding interactiveGraphicMaker[x] into interactiveGraphicMaker[x, hiddenvar1, hiddenvar2, ...] all enclosed in a DynamicModule, but I'm worried this would demand re-evaluation of the whole graphics object each time one of them changed, and slow down the computation of interactiveGraphicMaker, as we'd be waiting for all of these update-checks to finish first. If all these tools exist to track symbols, why would I want to evaluate a bunch of conditionals to see if parts of x have changed before evaluating the hidden expressions? It intuitively seems better to do this kind of updating "separately". But maybe this is low-cost, or can be combined effectively with the other options, and I just don't know enough about what's happening to see that!

  • I've seen this question and this question, which suggest setting the FrontEndDynamicExpression option (or using scheduled evaluation, which I don't want to do). And then I suppose I'd set up a dynamic wormhole? But if this is even a good design for performing these background updates (which I don't know), the documentation mentions that

the tricky part in setting up such a wormhole is getting the NotebookInterfaceObject necessary to refer to the parent DynamicModule [...] By using DynamicModuleParent explicitly, it is possible to link up an arbitrary existing DynamicModule, but doing so is tricky, and beyond the scope of this document.

I'm not sure how I would do that, or if a value for FrontEndDynamicExpression would even be accessible as a NotebookInterfaceObject (or which way the "parent" link should even go!). (DynamicModuleParent and NotebookInterfaceObject seem to be undocumented.)


Is one of these options better than the others? Or is there an altogether better way I don't know about?

How to track updates

Another issue with tracking updates is that Refresh used with TrackedSymbols :> (as opposed to TrackedSymbols ->) only works if the following symbols are actually evaluated in the first argument of Refresh. But the documentation recommends against using ->, as the following symbols might get evaluated under some circumstances (but doesn't say what those circumstances are). As a subquestion of "how best to perform update-controlled background assignments", since I'm guessing Refresh will come into play: is it better to just insert an evaluation of the symbol before evaluating the first argument, e.g. Refresh[x; <...>, TrackedSymbols :> {x}], or to try to use Refresh[<...>, TrackedSymbols -> {x}] and hope for the best?

Further, I'd often like to evaluate only certain assignments depending on what exactly was modified—but often these things I'd like to track are parts of my dynamic expressions, not the entire expression. E.g., I'd like to track only the value of x[[3]]. I could imagine doing this a couple of ways:

  • setting up new "indicator" variables that store e.g. the value of x[[3]] by itself, e.g. y=x[[3]], and update whenever x as a whole does; then separately track y to perform the nontrivial evaluation content

  • hiding the nontrivial evaluation content inside a refreshed conditional which tests for updates somehow, e.g. Refresh[If[y==x[[3]], y=x; a=f[x]; <...>], ...] which is refreshed every time x as a whole updates; the only difference here is that there's only one Refresh in play instead of two separate-but-linked ones.

  • putting the work of updating the indicator variables into my functions, e.g. making the function that updates x[[3]] also set the value of the indicator variable y (and having this be the only influence on y)

or something else I haven't thought of.


If anyone has any advice or insight on best practices in performing these kinds of update-controlled background evaluations in a dynamic environment, I'd appreciate it!

thorimur

Posted 2020-08-21T02:07:41.073

Reputation: 1 678

No answers