# Data join only works when data is in separate cell?

**URL:** <https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763>\
**Category:** Help\
**Created:** [January 21, 2020, 2:07am UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763 "2020-01-21T02:07:48Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jimmcnulty41](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jimmcnulty41/32/2600_2.png) [@jimmcnulty41](https://talk.observablehq.com/u/jimmcnulty41)\
**Post date:** [January 21, 2020, 2:07am UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763/1 "2020-01-21T02:07:48Z")

</div>

I’m working on building my understanding of d3, and right now, I’m specifically having trouble with understanding some behavior of selections (especially with respect to stuff here in observable).

In this notebook, I try to define my data in the same cell where I join that data to a selection, but it doesn’t work, and I’m not sure why.

> **[A New Mystery](https://observablehq.com/@jimmcnulty41/a-new-mystery)**
>
> An Observable notebook by James McNulty.

---

<div class="post-metadata">

**Author:** ![yurivish](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/yurivish/32/198_2.png) [@yurivish](https://talk.observablehq.com/u/yurivish)\
**Post date:** [January 21, 2020, 2:13am UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763/2 "2020-01-21T02:13:21Z")

</div>

> **[A New Mystery / Yuri Vishnevsky / Observable](https://observablehq.com/d/302ba7eb46a49793)**
>
> The magic notebook for visualization.

You need to do the data-join after the data has changed.

---

<div class="post-metadata">

**Author:** ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)\
**Post date:** [January 21, 2020, 3:38am UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763/3 "2020-01-21T03:38:52Z")

</div>

It’s due to Observable’s built-in reactivity (the dataflow runtime). It’s described here:

> **[Observable’s not JavaScript](https://observablehq.com/@observablehq/observables-not-javascript)**
>
> An Observable notebook by Observable.

  

> **[How Observable Runs](https://observablehq.com/@observablehq/how-observable-runs)**
>
> An Observable notebook by Observable.

The second example works because the entire chart is discarded and recreated from scratch when its data changes (because the data is defined as a generator cell, and the chart cell references it).

In contrast the first example mutates the data (by pushing onto the array), but that data is a local variable, and cells only run (react) in response to _other cells_, not local variables.

---

<div class="post-metadata">

**Author:** ![jimmcnulty41](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jimmcnulty41/32/2600_2.png) [@jimmcnulty41](https://talk.observablehq.com/u/jimmcnulty41)\
**Post date:** [January 22, 2020, 6:03am UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763/4 "2020-01-22T06:03:04Z")

</div>

Ah! Thank you both for the help!

After struggling a bit longer, I realized that I was thinking about the data join incorrectly. I had thought that a joined selection watched for changes to the data, and updated the DOM accordingly.

I think where I got confused was with the [d3-force example](https://observablehq.com/@d3/force-directed-graph). Specifically, I lost track of which d3 APIs maintain immutability. Next time I live this life, I’ll have to try learning d3 selection before I jump on d3-force.

I’m curious about how the organization of the d3-force example would have to be modified in the face of changing data, and I plan on updating this topic with a version of the notebook that explores that.

---

<div class="post-metadata">

**Author:** ![bgchen](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/bgchen/32/784_2.png) [@bgchen](https://talk.observablehq.com/u/bgchen)\
**Post date:** [January 22, 2020, 3:28pm UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763/5 "2020-01-22T15:28:17Z")

</div>

> [@jimmcnulty41](#):
>
> I’m curious about how the organization of the d3-force example would have to be modified in the face of changing data, and I plan on updating this topic with a version of the notebook that explores that.

Potentially helpful: here’s a notebook I wrote (based on [this block](https://bl.ocks.org/HarryStevens/bc938c8d45008d99faed47039fbe5d49) by Harry Stevens) when I was learning d3 and Observable

> **["Force Update Pattern" in Observable](https://observablehq.com/@bryangingechen/force-update-pattern-in-observable)**
>
> A port of Harry Stevens's block. The original \\\`README.md\\\` says: An attempt to replicate Mike's General Update Pattern, III with a force layout. The update has four parts: (1) Join, (2) Exit, (3) Update, (4) Enter. See also: Voronoi Update Pattern...

---

<div class="post-metadata">

**Author:** ![mbostock](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mbostock/32/9_2.png) [@mbostock](https://talk.observablehq.com/u/mbostock)\
**Post date:** [January 22, 2020, 3:39pm UTC](https://talk.observablehq.com/t/data-join-only-works-when-data-is-in-separate-cell/2763/6 "2020-01-22T15:39:09Z")

</div>

Using d3.forceSimulation does present some additional concerns: the simulation starts a timer that runs for 300 ticks by default (5 seconds), and the simulation mutates the passed-in nodes and links (to assign the _x_ and _y_ positions, and also optionally reassigning the _link_.source and _link_.target if specified by id rather than object reference).

This is why the example you linked makes a shallow copy of the nodes and links using Object.copy, and uses the [invalidation promise](https://observablehq.com/@observablehq/invalidation) to stop the simulation.

Hence, that example is designed to be “pure” in the sense that if the data changes, it creates a new simulation and discards the old simulation (and all its effects). That is the cleanest approach in Observable. It’s the easiest to reason about because there’s no hidden state that’s affecting the behavior of cells.

If you want to do animated transitions or incremental updates without discarding the old state, you’ll need to opt-in to some additional complexity. There are a variety of ways of doing that, but the one that I recommend is exposing an update function as in these examples:

> **[Sortable Bar Chart](https://observablehq.com/@d3/sortable-bar-chart)**
>
> An Observable notebook by D3.

  

> **[Bar Chart Race with Scrubber](https://observablehq.com/@mbostock/bar-chart-race-with-scrubber)**
>
> An Observable notebook by Mike Bostock.

The skeleton of that approach has two parts. Your chart cell (or whatever cell you want to be responsible for the state…) exposes an update method:

```auto
chart = {
  const svg = d3.create("svg");

  return Object.assign(svg.node(), {
    update(data) {
      // Animate here! 💃
    }
  });
}

```

And then a cell that calls _chart_.update whenever the data (or whatever other state) changes:

```auto
chart.update(data)

```

If you have more than one thing you want to change, you can have multiple update methods with different names that take different arguments. (The “update” name is just a convention and isn’t required.)

The principle here is that the code that mutates state should live in the same cell that defines the state.

(Also: I would avoid using Observable’s `this`! I now consider `this` an antipattern because it’s too dangerous. With animated transitions or incremental updates you typically only expect one thing to change, such as _data_ here; with _this_, the old value is preserved regardless of what changes, making it much easier to write buggy code. For example—and sorry to pick on @bgchen, it’s not your fault, it’s mine for designing `this`—if you resize the window in @bgchen’s example the SVG element does not resize as expected because it ignores changes to _width_.)
