"Introduction to Manipulate" and "Introduction to Dynamic" provide most of the information you need to use the Wolfram Language's interactive features accessible through the functions Manipulate, Dynamic, and DynamicModule. This tutorial gives further details on the workings of Dynamic and DynamicModule and describes advanced features and techniques for achieving maximum performance for complex interactive examples.
Many examples in this tutorial display a single output value and use Pause to simulate slow calculations. In real life, you will instead be doing useful computations and displaying sophisticated graphics or large tables of values.
Module and DynamicModule have similar syntax and in many respects behave similarly, at least at first glance. They are, however, fundamentally different in such areas as when their variables are localized, where the local values are stored, and in what universe the variables are unique.
Module works by replacing all occurrences of its local variables with new, uniquely named variables, constructed so that they do not conflict with any variables in the current session of the Wolfram Language kernel.
Both examples produce seemingly independent sliders that allow separate settings of separate copies of the variable x. The problem with sliders inside Module is that a different kernel session may coincidentally share the same localized variable names. So if this notebook is saved and then reopened sometime later, the sliders may "connect" to variables in some other Module that happen to have the same local variables at that time.
This will not happen with the sliders inside DynamicModule because DynamicModule waits to localize the variables until the object is displayed in the front end and generates local names that are unique to the current session of the front end. Localization happens when DynamicModule is first created as output and then repeats anew each time the file that contains DynamicModule is opened, so there can never be a name conflict among examples generated in different sessions.
Variables generated by Module are purely kernel session variables; when the kernel session ends, the values are irretrievably lost. DynamicModule, on the other hand, generates a structure in the output cell that is responsible for maintaining the values of the variables, allowing them to be saved in files. This is a somewhat subtle concept, best explained by way of two analogies. First, you can think of DynamicModule as a sort of persistent version of Module.
The module in this example evaluates a series of expressions in order, and from one line to the next the values of all the local module variables are preserved (obviously). You can have as many lines as you like in the compound expression, but they all have to be there at the start; once the Module has finished execution, it evaporates along with all its local variables.
DynamicModule, on the other hand, creates an environment in which evaluations of expressions in Dynamic that appear within the body of the DynamicModule are like additional lines in the compound expression in the previous example. From one dynamic update to the next the values of all the variables are preserved, just as if the separate evaluations were separate lines in a compound expression, all within the local variable context created by DynamicModule.
This preservation of variable values extends not just to subsequent dynamic evaluations within the same session, but to all future sessions. Because all the local variable values are stored and preserved in the notebook file, if the notebook is opened in an entirely new session of the Wolfram System, the values will still be there, and dynamic updates will resume just where they left off. DynamicModule is like an indefinitely extendable Module.
Another way to think about the difference between Module and DynamicModule is that while Module localizes its variables for a certain duration of time (while the body of the module is being evaluated), DynamicModule localizes its variables for a certain area of space in the output.
As long as that space of the output remains in existence, the values of the variables defined for it will be preserved, allowing them to be used in subsequent evaluations of Dynamic expressions within the scope (area) of the DynamicModule. Saving the output into a file puts that bit of real estate into hibernation, waiting for the moment when the file is opened again. (In computer science terms, this is sometimes referred to as a freeze‐dried or serialized object.)
The ability of DynamicModule to preserve state across sessions is also a way of extending the notion of editing in a file. Normally when you edit text or expressions in a file, save the file, and reopen it, you expect it to open the way you left it. Editing means changing the contents of a file.
Ordinary kernel variables do not have this property; if you make an assignment to x, then quit and restart the Wolfram System, x does not have that value anymore. There are several reasons for this, not least of which is the question of where the value of x should be saved.
DynamicModule answers this question by defining a specific location (the output cell) where values of specific variables (the local variables) should be preserved. Arbitrary editing operations, like moving a slider, typing in an input field, or dragging a dynamic graphics object, change the values of the local variables. And since these values are automatically preserved when the file is saved, the sliders, and other objects, open exactly where they were left. Thus DynamicModule lets you make any quantity editable in the same way that text and expressions can be edited and saved in notebook files.
Ordinary variables in the Wolfram Language are owned by the kernel. Their values reside in the kernel, and when you ask the Wolfram System to display the value in the front end, a transaction is initiated with the kernel to retrieve the value. The same is true of dynamic output that refers to the values of ordinary variables.
When one slider is moved, the other 499 move in sync with it. This requires 500 separate transactions with the kernel to retrieve the value of x. (The semantics of the Wolfram Language are complex enough that there is no guarantee that evaluating x several times in a row will actually return the same value each time: it would not be possible for the front end to improve efficiency by somehow sharing a single value retrieved from the kernel with all the sliders.)
Variables declared with DynamicModule, on the other hand, are owned by the front end. Their values reside in the front end, and when the front end needs a value, it can be retrieved locally with very little overhead.
If a complex function is applied to such a variable, its value must of course be sent to the kernel. This happens transparently, with each side of the system being kept informed on a just‐in‐time basis of any changes to variable values.
Whether it is better to use a normal kernel variable or a DynamicModule variable in a given situation depends on a number of factors. The most important is the fact that values of all DynamicModule variables are saved in the file when the notebook is saved. If you need a value preserved between sessions, it must be declared in a DynamicModule. On the other hand, a temporary variable holding a large table of numbers, for example, might be a poor choice for a DynamicModule variable as it could greatly increase the size of the file. It is quite reasonable to nest a Module inside a DynamicModule and vice versa, or to partition variables between the front end and kernel.
In many situations the limiting factor in performance is the time needed to retrieve information from the kernel: by making variables local to the front end, speed can sometimes be increased dramatically.
The specification for dynamic output is simple: Dynamic[expr] should always display the value you would get if you evaluated expr now. If a variable value, or some other state of the system, changes, the dynamic output should be updated immediately. Of course, for efficiency, not every dynamic output should be reevaluated every time any variable changes. It is critical that dependencies be tracked so that dynamic outputs are evaluated only when necessary.
The first expression might change its value any time the value of a, b, or c changes, or if any patterns associated with a, b, or c are changed. The second expression depends on a and b (but not c) while a is True and on a and c (but not b) while a is False. If a is neither True nor False, then it depends only on a (because the If statement returns unevaluated).
Figuring out these dependencies a priori is impossible (there are theorems to this effect), so instead the system keeps track of which variables or other trackable entities are actually encountered during the process of evaluating a given expression. Data is then associated with those variable(s) identifying which dynamic expressions need to be notified if the given variable receives a new value.
An important design goal of the system is to allow monitoring of variable values by way of dynamic output referencing them, without imposing any more load than absolutely necessary on the system, especially if the value of the variable is being changed rapidly.
When the loop is started and x is first given a new value, the data associated with it is consulted, and the front end is notified that the dynamic output needs to be updated. The data associated with x is then deleted. Essentially the system forgets all about the dynamic output, and subsequent assignments in the loop incur absolutely no speed penalty because of the existence of a dynamic output monitoring the value of x.
Much later (on a computer time scale; only a fraction of a second on a human time scale) when the screen is next redrawn and the dynamic output containing the reference to x is reevaluated, the connection between the dynamic output and the variable x is noticed again, and the association is reestablished.
By default, dynamic outputs triggered by changes in variable values are updated no faster than twenty times per second (this rate can be changed with the SystemOption "DynamicUpdateInterval"). In the previous example you will typically see the value jump by tens or hundreds of thousands with each update (more the faster your computer is), and the overall speed of the computation is slowed down by only a percent or two, nearly zero if you have a multiprocessor system.
You might expect that having a dynamic output monitoring the value of a symbol that is being changed rapidly in a tight loop would slow that loop down significantly. But the overhead is in fact zero‐order in the rate at which the variable is changed, and in practice is usually minimal.
Dynamic outputs are only updated when they are visible on screen. This optimization allows you to have an open‐ended number of dynamic outputs, all changing constantly, without incurring an open‐ended amount of processor load. Outputs that are scrolled off-screen, above or below the current document position, will be left unexamined until the next time they are scrolled on‐screen, at which point they are updated before being displayed. (Thus the fact that they stopped updating is not normally apparent, unless they have side effects, which is discouraged in general.)
As long as the output is visible on screen, there will be a certain amount of CPU activity any time the mouse is moved, because this particular dynamic output is being redrawn immediately with every movement of the mouse. But if it is scrolled off-screen, the CPU usage will vanish.
Normally, dynamic output is updated whenever the system detects any reason to believe it might need to be (see "Automatic Updates of Dynamic Objects" for details about what this means). Refresh can be used to modify this behavior by specifying explicitly what should or should not trigger updates.
When you move the second (y) slider, nothing happens, but when you move the first slider, the expression is updated to reflect the current value of both variables. You might say that after moving the second slider, the dynamic output is wrong, since it does not reflect the current state of the system. But that is essentially the whole reason for the existence of the Refresh command. It allows you to override the system's mandate to always update dynamic output any time it is potentially out of date.
The setting TrackedSymbols->Automatic can be used to track only those symbols that occur explicitly (lexically) in the expression given in the first argument to Refresh. For example, if you use a function that depends on a global variable that does not occur lexically inside Refresh, changes to the value of the global variable will not cause updating, when normally they would.
Refresh can also be used to cause updates at regular time intervals. It is important to understand that this is not a feature that should be used lightly. It is fundamental to the design of Dynamic that it does not need to update on any fixed schedule, because it simply always updates immediately whenever doing so would be useful. But there are some situations where this either cannot, or just unfortunately does not, happen.
One potentially vexing case is RandomReal. Every time you evaluate RandomReal, you get a different answer, and you might think that Dynamic[RandomReal] should therefore constantly update itself as fast as possible. But this would normally not be useful, and would in fact have negative consequences for a number of algorithms that use randomness internally (e.g., a Monte Carlo integration inside Dynamic should probably not update constantly simply because it will, in fact, give a slightly different answer each time).
For this reason, RandomReal is not "ticklish", in the sense that it does not trigger updates. If you want to see new random numbers, you have to use Refresh to specify how frequently you want the output updated. Another example of non‐ticklish functions are file system operations.
In the unlikely event that the file containing the Classroom Assistant palette changes size, this Dynamic will not be updated. If you want to monitor the size of a file, you need to use Refresh to specify a polling interval. (On sufficiently advanced operating systems it would theoretically be possible for the Wolfram Language to efficiently receive notifications of file system activity, and future versions of the Wolfram Language might in fact update such expressions automatically. As with other Dynamic expressions, automatic correctness is always the goal.)
Finally, several functions you might think would trigger dynamic updates in fact do not: for example, DateList and AbsoluteTime. As with RandomReal, it would cause more trouble than it is worth for these functions to automatically trigger updates, and Refresh can trivially be used to create clock‐like objects. The function Clock is intended specifically as a time‐based function that is ticklish.
In the "Refresh" section examples, Refresh is always the outermost function inside Dynamic. You might almost wonder why its options are not simply options to Dynamic. But in fact it is often important to place Refresh as deeply in the expression as possible, especially if it specifies a time‐based updating interval.
When the checkbox is checked, Refresh is causing frequent updating of the clock, and CPU time is being consumed to keep things up-to-date. When the checkbox is unchecked, however, the Refresh expression is no longer reached by evaluation, the output remains static, and no CPU time is consumed. If Refresh were wrapped around the whole expression inside Dynamic, CPU time would be consumed constantly, even if the clock were not being displayed. The words "No clock" would be constantly refreshed, pointlessly. (This refreshing is not visible; there is no flicker of the screen, but CPU time is being consumed nevertheless.)
Dynamic expressions can be nested, and the system takes great care to update them only when necessary. Particularly when the contents of a Dynamic contain further interactive elements, it is important to keep track of what will stay static and what will update, when a given variable is changed.
The position of the first slider determines the number of sliders underneath it, and each of those sliders in turn is connected to the value of one element of a list of data. Because the number of sliders is variable, and changes dynamically in response to the position of the first slider, the table that generates them needs to be inside Dynamic.
Now any time you click one of the lower sliders, it moves only one step, then stops. The problem is that the data[[i]] expressions in the second column of the grid are creating a dependency in the outer Dynamic on the values in data.
As soon as data changes, the contents of the outer Dynamic, including the slider you are trying to drag, are destroyed and replaced with a nearly identical copy (in which the displayed value of one of the data[[i]] has been changed). In other words, the act of dragging the slider destroys it, preventing any further activity.
Now you can drag any of the sliders and see dynamically updated values. This works because the outer Dynamic now depends only on the value of n, the number of sliders, not on the value of data. (Technically this is because Dynamic is HoldFirst: when it is evaluated, the expression in its first argument is never touched by evaluation, and therefore no dependencies are registered.)
When building large, complex interfaces using multiple levels of nested Dynamic expressions, these are important issues to keep in mind. The Wolfram Language works hard to do exactly the right thing even in the most complex cases. For example, the output of Manipulate consists of a highly complex set of interrelated and nested Dynamic expressions: if the dependency tracking system did not work correctly, Manipulate would not work right.
The Wolfram System consists of two separate processes, the front end and the kernel. These really are separate processes in the computer science sense of the word: two independent threads of execution with separate memory spaces that show up separately in a CPU task monitor.
The front end and kernel communicate with each other through several Wolfram Symbolic Transfer Protocol (WSTP) connections, known as the main link, the preemptive link, and the service link. The main and preemptive links are pathways by which the front end can send evaluation requests to the kernel, and the kernel can respond with results. The service link works in reverse, with the kernel sending requests to the front end.
The main link is used for Shift+Enter evaluations. The front end maintains a queue of pending evaluation requests to send down this link. When you use Shift+Enter on one or more input cells, they are all added to the queue, and then processed one by one. At any one time, the kernel is only aware of a single main link evaluation, the one it is currently working on (if any). In the meantime, the front end remains fully functional; you can type, open and save files, and so on. There is no arbitrary limit on how long a main link evaluation can reasonably take. People routinely do evaluations that take days to complete.
The preemptive link works the same way as the main link in the sense that the front end can send an evaluation to it and get an answer, but it is administered quite differently on both ends. On the front end side, the preemptive link is used to handle normal Dynamic updates. There is no queue; instead, the front end sends one evaluation at a time and waits for the result before continuing with its other work. It is thus important to limit preemptive link evaluations to a couple of seconds at most. During any preemptive link evaluation, the front end is completely locked up, and no typing or other actions are possible.
On the kernel side, evaluation requests coming from the preemptive link are given priority over evaluations from the main link, including the current running main link evaluation (if any). If an evaluation request comes from the preemptive link while the kernel is processing a main link evaluation, the main link evaluation is halted at a safe point (usually within microseconds). The preemptive link evaluation is then run to completion, after which the main link evaluation is restarted and allowed to continue as before. The net effect is similar to, though not the same as, a threading mechanism. Multiple fast preemptive link evaluations can be executed during a single long, slow main link evaluation, giving the impression that the kernel is working on more than one problem at a time.
Preemptive link evaluations can change the values of variables, including those being used by a main link evaluation running at the same time. There is no paradox here, and the interleaving is done in a way that is entirely safe, though it can result in some fairly peculiar behavior until you understand what is going on.
You will not see anything happening (other than the slider moving) but when the second evaluation finishes, you will see that it has recorded 10 different values of x, representing the positions the slider happened to be at during the 10 points at which x was evaluated to build the list.
Dynamic normally uses the preemptive link for its evaluations. Evaluation is synchronous, and the front end locks up until it is finished. This is unavoidable in some cases, but can be suboptimal in others. By setting the option SynchronousUpdating->False, you can tell the front end to use the main link queue, rather than the preemptive link. The front end then displays a gray box placeholder until it receives the response from the kernel.
Clicking the slider will update the display with a delay of between one and ten seconds. Notice that the cell bracket is outlined, just as if the cell were being Shift+Enter evaluated. This is an indication that the evaluation is queued, and that you can continue with other work in the front end while the evaluation is progressing.
Asynchronous updating is useful for displaying full Dynamic subexpressions when it is possible to draw a screen around them and fill in their value later, in much the same way a web browser draws text around an image that is inserted later when it finishes downloading.
Why not always use asynchronous Dynamic expressions? There are several reasons. First, they are queued so that, by definition, they do not operate while another Shift+Enter evaluation is underway. This is not the case for normal (synchronous) updates.
Move the slider around rapidly, and you will end up with a choppy, distorted sine wave, because the value of n changed during the evaluation of the Table command. This is the correct, expected behavior, but it is probably not what you wanted.
This problem does not occur if you use synchronous Dynamic expressions, generally does not happen with DynamicModule local variables, and can be avoided by storing the value of any potentially changing variables into a second variable before starting the asynchronous evaluations.
As a general rule, if you have a Dynamic that is meant to respond interactively to the movements of a slider or other continuous‐action control, it should be able to evaluate in under a second, preferably well under. If the evaluation takes longer than that, you are not going to get satisfactory interactive performance, whether the Dynamic is updating synchronously or asynchronously.
But what if you have an example that simply cannot finish evaluating fast enough, yet you want to be able to make it respond to a slider? One option is to use asynchronous updating and simply accept that you will not get real‐time interactive performance. If that is what you want to do, setting ContinuousAction->False in the slider or other control is a good idea; that way you get only one update after the control is released, avoiding the starting up of potentially lengthy evaluations in the middle of a drag, before you have arrived at the value you want to stop at.
Another, much better solution is to provide a fast‐to‐compute preview of some sort during the interactive control dragging operation, then compute the full, slow output when the control is released. Several features exist specifically to support this.
The first is the function ControlActive, which returns its first argument if a control is currently being dragged, and its second argument if not. Unlike Dynamic, ControlActive is an ordinary function that evaluates in the kernel, returning one or the other of its arguments immediately. It can be embedded inside functions or option values.
The second feature is an option setting SynchronousUpdating->Automatic for Dynamic, which makes the Dynamic synchronous when a control is being dragged, and asynchronous when the control is released. Together, these two features can be used to implement a fast, synchronously updated display to be used while a control is being dragged, along with a slower, asynchronously updated display when it is released.
Of course, in most cases, you will want a preview that is some kind of reduced, thinned out, skeletal, or other elided form of the final display. Then the crude form can be fast enough to give a smooth preview, and the computation of the final version, even if it takes awhile, does not block the front end. In fact, this behavior is so useful that it is the default in Plot3D and other plotting functions.
You may have noticed one subtlety. When the output of either of the above three examples is first placed in the notebook, you see a crudely drawn (control‐active state) version, followed shortly thereafter by a refined (control‐inactive) version. This is intentional: the system is providing a fast preview so you see something rather than just a gray rectangle. The first update is done synchronously, just as if a control were being dragged.
This preview‐evaluation behavior is examined in more detail in the next section.
ImageSizeCache is an option to Dynamic that specifies a rectangular size to be used in displaying a Dynamic whose value has not yet been computed. It is normally not specified in input, but is instead generated automatically by the front end and saved in files along with the Dynamic expression.
The interaction of ControlActive, SynchronousUpdating, and ImageSizeCache is subtle, complex, and very useful. The first two constructs are explained in "ControlActive and SynchronousUpdatingAutomatic". The remaining part is explained here.
Note first that Dynamic expressions with the default value of SynchronousUpdating->True will never have a chance to use the value of their ImageSizeCache option, because they are always computed before being displayed, and, once computed, the actual image size will be used.
On the other hand, Dynamic expressions with SynchronousUpdating->False will be displayed as a gray rectangle while they are being computed for the first time. In that case, the size of the rectangle is determined by the value of the ImageSizeCache option. This allows the surrounding contents of the notebook to be drawn in the right place, so that when the Dynamic finishes updating, there is no unnecessary flicker and shifting around of the contents of the notebook. (Users of HTML will recognize this as the analog of the width and height parameters of the img tag.)
It is generally not necessary to specify the ImageSizeCache option explicitly, because the system will set it automatically as soon as the value of the Dynamic is computed successfully. (The computed result is measured, and the actual size copied into the ImageSizeCache option.) This automatically computed value is preserved if the Dynamic output is saved in a file.
When the input expression is evaluated, a small gray rectangle appears; because this Dynamic has never been evaluated, there is no cache of its proper image size, and a default small size is used.
Three seconds later, the result arrives, and the dynamic output is displayed. At this point an actual size is known, and is copied to the ImageSizeCache option. You can see the value by clicking anywhere in the output cell and choosing Show Expression from the Cell menu. (This shows you the underlying expression representing the cell, exactly as it would appear in the notebook file if you were to save this cell.) Note the presence of an ImageSizeCache option.
Now type a space in some innocuous place in the raw cell expression (to force a reparsing of the cell contents), and choose Show Expression again to reformat the cell. This time you will see a gray rectangle the size of the final output for three seconds, followed by the proper output. This is also what you would see if you opened a notebook containing previously saved, asynchronous dynamic output.
The behavior of the setting SynchronousUpdating->Automatic is similar, but subtly different. As we saw in the examples in "ControlActive and SynchronousUpdatingAutomatic", with the Automatic setting, a synchronous preview‐evaluation is done when the output is first placed, to provide a (hopefully) rapid display of the contents of the Dynamic expression before the slower, asynchronous value is computed. Because the first evaluation is synchronous, no gray rectangle is ever displayed.
But this preview evaluation is done only if the ImageSizeCache option is not present. A Dynamic with SynchronousUpdating->Automatic and an ImageSizeCache option specifying explicit dimensions will not do a synchronous preview evaluation, and will instead display a gray rectangle (of the correct size) pending the result of the first asynchronous evaluation.
This may seem like baffling behavior at first, until you consider the practical effect of it. Generally speaking, Dynamic expressions will always have an ImageSizeCache option (created automatically by the front end) except for the very first time they appear, when they are originally placed as output from an evaluation. Any time they are opened from a file they will have a known, cached size.
In Manipulate, which accounts for the vast majority of dynamic outputs, the default setting is SynchronousUpdating->Automatic and the described behavior lets the output show up cleanly with a preview image in place when it is first generated. When a file containing dozens of Manipulate outputs is opened, you will get a useful behavior that is familiar from web browsers: the text displays immediately, and graphics (and other dynamic content) fill in later as fast as they are able. So you can scroll through a file rapidly, without any delay associated with precomputing potentially many preview images before the first page of the file can be displayed.
If the initial evaluations when the Manipulate output was first placed were not synchronous, there would be flicker and resizing/shifting of the surroundings, because the size would not be known. But when the Manipulate output is opened from a file, the size is known, and the final output can be placed smoothly without flicker.
After evaluating in the kernel, ControlActive can trigger an update of the Dynamic containing it, but in a highly asymmetric fashion, only when it is going from the active to the inactive state. When making a transition in the other direction, from inactive to active, ControlActive does not trigger any update on its own.
The reason for this somewhat unusual behavior is that ControlActive is a completely global concept. It returns the active state if any control anywhere in the Wolfram System is currently being dragged—even controls that have nothing to do with a particular Dynamic that happen to contain a reference to ControlActive. If ControlActive caused updates on its own, then as soon as you clicked any control, all Dynamic expressions containing references to ControlActive (e.g., a default dynamic Plot3D output) would immediately update, which would be entirely pointless. Instead, only those outputs that have some other reason for updating will pick up the current value of ControlActive.
On the other hand, when the control is released, it is desirable to fix up any outputs that were drawn in control-active form, to give them their final polished appearance. Thus, when ControlActive is going into its inactive state, it needs to, on its own, issue updates to any Dynamic expression that may have been drawn in the active state.
Watch carefully what happens when you click the slider. If you click and hold the mouse without moving it, the display will remain Inactive. But as soon as you move it, the display updates to Active. This is happening because x changed, causing the Dynamic as a whole to update, thus picking up the current state of ControlActive.
Now carefully release the mouse button without moving the mouse. Note that the display does revert to Inactive even though x has not changed.
The variables declared in a DynamicModule are localized to a particular rectangular area within one cell in a notebook. There are situations in which it is desirable to extend the scope of such a local variable to other cells or even other windows. For example, you might want to have a button in one cell that opens a dialog box that allows you to modify the value of a variable declared in the same scope as the button that opened the dialog.
This can be done with one of the more surreal constructs in the Wolfram Language, a DynamicModule wormhole. DynamicModule accepts the option DynamicModuleParent, whose value is a NotebookInterfaceObject that refers to another DynamicModule anywhere in the front end. For purposes of variable localization, the DynamicModule with this option will be treated as if it resided inside the one referred to, regardless of where the two actually are (even if they are in separate windows).
The tricky part in setting up such a wormhole is getting the NotebookInterfaceObject necessary to refer to the parent DynamicModule. This reference can be created only after the DynamicModule has been created and placed as output, and it is valid only for the current session.
To make the process easier, and in fact avoid all reference to explicit NotebookInterfaceObjects, DynamicModule also accepts the option InheritScope, which automatically generates the correct value of the DynamicModuleParent option to make the new DynamicModule function as if it were inside the scope of the DynamicModule from which it was created. This is confusing, so an example is in order.
Clicking the + button increments the value of a DynamicModule local variable, which is displayed at the end of the output. To decrement the number you have to click the Make - Palette button, which creates a new (very small) floating palette window containing a - button.
This - button is living in a wormhole created by the InheritScope option of the DynamicModule containing it. Clicking the button decrements the value of a local, private variable in the scope of a distant DynamicModule in another window.
InheritScope can be used only when the code creating the second DynamicModule is executed from inside a button or other dynamic object located within the first 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.