Observable Graphs
Tags: observable, graphs, d3, gram
Published: 2021-01-21 11:49:41

### _Create graphs with [`gram`](https://gram-data.github.io/gram-js/) then share them on [ObservableHQ](https://observablehq.com/)._

`Gram` makes writing graphs as easy as `(a)-->(b)<--(c)`. But then what? Well, graphs are eminently visual data structures. Naturally, we should visualize them with [d3.js](https://d3js.org). There's a convenient integration called [d3-gram](https://github.com/gram-data/d3-gram) which we'll exercise on ObservableHQ.

## Observe as I demonstrate...

To follow along you'll need to login or create an account on ObservableHQ. Conveniently, you can use github, google or twitter to sign in. 

First, we'll create a notebook:

1. Click the `New` button in the upper-right corner
2. Give it a nice title like `# Observable Graph by ABK`

Next, import the `graphOf` function which parses gram then renders a graph.

1. Create a new block using the `+` button
2. Copy/paste the following code
3. Hit shift-return or press the play/run button :arrow_forward: to perform the import

```
import {graphOf} from "@akollegger/graph-input"
```

Now creating a graph visualization is as easy as calling the `graphOf` function, passing in a Cypher-like gram pattern. Add a new block try this:

```
abc = graphOf("(a)-->(b)<--(c)");
```

Neat, right? We can tweak the visualization a little by adding a zoom level and viewbox height:

```
abc = graphOf("(a)-->(b)<--(c)", {zoom:4, height: 60})
```

## Observe the graph

What is `abc`? The `graphOf` function returns an [observable view](https://observablehq.com/@observablehq/introduction-to-views), an input element with a current value. That's right, you can use the graph visualization like a slider or a text input field. 

Modify the `graphOf` block, prepending `viewof`:

```
viewof abc = graphOf("(a)-->(b)<--(c)", {zoom:4, height: 60})
```

Add another block which only contains `abc`:

```
abc
```

When you run that block, notice the result is an object. That's the current value of the input element. It contains an array of all nodes, an array of links, and an array of the current selection. Shift-clicking the graph adds multiple nodes to the `selected` array.

```
Object {
  nodes: Array(3) [Object, Object, Object]
  links: Array(2) [Object, Object]
  selected: Array(1) [Object]
}
```

The array elements are objects that mix d3-js properties for things like x,y coordinates along with the original graph data. Let's add another block to focus on the graph data: 


```
selectedNode = abc.selected.length == 0 ? {} : Object.getPrototypeOf(abc.selected[0])
```

That's better. Now we can add more details to the graph, which will influence the graph visualization and show up in the `selectedNode`.

Try this:
```
viewof abc = graphOf("(a:Person {name:"ABK"})-->(b)<--(c)", {zoom:4, height: 60})
```

With all this in place, you can create your own graphs by editing the gram string passed into `graphOf()`. Or you could add a text field using [form-input](https://observablehq.com/@mbostock/form-input). Or load from an attached file or URL. 

For fun, I re-created wikipedia's [Gallery of Named Graphs](https://observablehq.com/@akollegger/gallery-of-named-graphs?collection=@akollegger/gram-for-graphs).


A gram of graphs goes a long way. Have fun! :) 

---
Footnotes:

<sup><a name="observable-graph">[1]</a> [Observable Graph by ABK](https://observablehq.com/@akollegger/observable-graph-by-abk) The complete notebook described in this post.
</sup>
<sup><a name="gram-collection">[2]</a> [Gram of Graphs](https://observablehq.com/collection/@akollegger/gram-for-graphs) - a collection of ObservableHQ notebooks about gram and graphs
</sup>
<sup><a name="gram-input">[2]</a> [@akollegger/graph-input](https://observablehq.com/@akollegger/graph-input) - the particular ObservableHQ notebook which provides the utility functions used in this post
</sup>