Hi Stu,
The problem, in a nutshell, is mutation across cells: your current notebook relies on mutating values implicitly defined by other cells. Whenever possible, you want to avoid mutation across cells in Observable because it makes it harder to understand dataflow, as when you click the “New polynomial” button to change the value of coeffs.
The corresponding fix to fold any cell that mutates another cell’s value into that other cell. So, updatePoints should be folded into the chart cell, and so should drag (since it calls updatePoints).
Here’s the fix applied to your notebook, and you click Merge if you like:
https://observablehq.com/compare/4448d1c5c41cba46@444...9a199a51e6d7214d@452
Here’s a relevant passage from the recent Learn D3 tutorial:
A subtle consideration when working with data in Observable is whether to put code in a single cell or separate cells. A good rule of thumb is that a cell should either define a named value to be referenced by other cells (such as data above), or it should display something informative to the reader (such as this prose, the chart above, or cells which inspect the data).
A critical implication of this rule is that you should avoid implicit dependencies between cells: only depend on what you can name.
Why? A notebook’s dataflow is built from its cell references. If a cell doesn’t have a name, it cannot be referenced and cells that implicitly depend on its effect may run before it. (Cells run in topological order, not top-to-bottom.) Implicit dependencies lead to nondeterministic behavior
during development, and possible errors
when the notebook is reloaded!
For example, if one cell defines an array and a second cell modifies it in-place, other cells may see the array before or after the mutation. To avoid this nondeterminism, make the dependency explicit by giving the second cell a name and copying the array using Array.from or array.map. Or combine the two cells so that only the already-modified array is visible to other cells.