<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Andreas Kollegger</title>
    <description>The latest articles on Forem by Andreas Kollegger (@akollegger).</description>
    <link>https://forem.com/akollegger</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F507971%2F2ce12ec0-f640-47fd-a52c-a0ad167cad26.png</url>
      <title>Forem: Andreas Kollegger</title>
      <link>https://forem.com/akollegger</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/akollegger"/>
    <language>en</language>
    <item>
      <title>Observable Graphs</title>
      <dc:creator>Andreas Kollegger</dc:creator>
      <pubDate>Thu, 21 Jan 2021 11:49:41 +0000</pubDate>
      <link>https://forem.com/neo4j/observable-graphs-306o</link>
      <guid>https://forem.com/neo4j/observable-graphs-306o</guid>
      <description>&lt;h3&gt;
  
  
  &lt;em&gt;Create graphs with &lt;a href="https://gram-data.github.io/gram-js/" rel="noopener noreferrer"&gt;&lt;code&gt;gram&lt;/code&gt;&lt;/a&gt; then share them on &lt;a href="https://observablehq.com/" rel="noopener noreferrer"&gt;ObservableHQ&lt;/a&gt;.&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Gram&lt;/code&gt; makes writing graphs as easy as &lt;code&gt;(a)--&amp;gt;(b)&amp;lt;--(c)&lt;/code&gt;. But then what? Well, graphs are eminently visual data structures. Naturally, we should visualize them with &lt;a href="https://d3js.org" rel="noopener noreferrer"&gt;d3.js&lt;/a&gt;. There's a convenient integration called &lt;a href="https://github.com/gram-data/d3-gram" rel="noopener noreferrer"&gt;d3-gram&lt;/a&gt; which we'll exercise on ObservableHQ.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observe as I demonstrate...
&lt;/h2&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;First, we'll create a notebook:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click the &lt;code&gt;New&lt;/code&gt; button in the upper-right corner&lt;/li&gt;
&lt;li&gt;Give it a nice title like &lt;code&gt;# Observable Graph by ABK&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next, import the &lt;code&gt;graphOf&lt;/code&gt; function which parses gram then renders a graph.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new block using the &lt;code&gt;+&lt;/code&gt; button&lt;/li&gt;
&lt;li&gt;Copy/paste the following code&lt;/li&gt;
&lt;li&gt;Hit shift-return or press the play/run button ▶️ to perform the import
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {graphOf} from "@akollegger/graph-input"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now creating a graph visualization is as easy as calling the &lt;code&gt;graphOf&lt;/code&gt; function, passing in a Cypher-like gram pattern. Add a new block try this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abc = graphOf("(a)--&amp;gt;(b)&amp;lt;--(c)");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Neat, right? We can tweak the visualization a little by adding a zoom level and viewbox height:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abc = graphOf("(a)--&amp;gt;(b)&amp;lt;--(c)", {zoom:4, height: 60})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Observe the graph
&lt;/h2&gt;

&lt;p&gt;What is &lt;code&gt;abc&lt;/code&gt;? The &lt;code&gt;graphOf&lt;/code&gt; function returns an &lt;a href="https://observablehq.com/@observablehq/introduction-to-views" rel="noopener noreferrer"&gt;observable view&lt;/a&gt;, an input element with a current value. That's right, you can use the graph visualization like a slider or a text input field. &lt;/p&gt;

&lt;p&gt;Modify the &lt;code&gt;graphOf&lt;/code&gt; block, prepending &lt;code&gt;viewof&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;viewof abc = graphOf("(a)--&amp;gt;(b)&amp;lt;--(c)", {zoom:4, height: 60})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add another block which only contains &lt;code&gt;abc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;abc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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 &lt;code&gt;selected&lt;/code&gt; array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Object {
  nodes: Array(3) [Object, Object, Object]
  links: Array(2) [Object, Object]
  selected: Array(1) [Object]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;selectedNode = abc.selected.length == 0 ? {} : Object.getPrototypeOf(abc.selected[0])
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's better. Now we can add more details to the graph, which will influence the graph visualization and show up in the &lt;code&gt;selectedNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Try this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;viewof abc = graphOf("(a:Person {name:"ABK"})--&amp;gt;(b)&amp;lt;--(c)", {zoom:4, height: 60})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With all this in place, you can create your own graphs by editing the gram string passed into &lt;code&gt;graphOf()&lt;/code&gt;. Or you could add a text field using &lt;a href="https://observablehq.com/@mbostock/form-input" rel="noopener noreferrer"&gt;form-input&lt;/a&gt;. Or load from an attached file or URL. &lt;/p&gt;

&lt;p&gt;For fun, I re-created wikipedia's &lt;a href="https://observablehq.com/@akollegger/gallery-of-named-graphs?collection=@akollegger/gram-for-graphs" rel="noopener noreferrer"&gt;Gallery of Named Graphs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A gram of graphs goes a long way. Have fun! :) &lt;/p&gt;




&lt;p&gt;Footnotes:&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;&lt;a&gt;[1]&lt;/a&gt; &lt;a href="https://observablehq.com/@akollegger/observable-graph-by-abk" rel="noopener noreferrer"&gt;Observable Graph by ABK&lt;/a&gt; The complete notebook described in this post.&lt;br&gt;
&lt;/sup&gt;&lt;br&gt;
&lt;sup&gt;&lt;a&gt;[2]&lt;/a&gt; &lt;a href="https://observablehq.com/collection/@akollegger/gram-for-graphs" rel="noopener noreferrer"&gt;Gram of Graphs&lt;/a&gt; - a collection of ObservableHQ notebooks about gram and graphs&lt;br&gt;
&lt;/sup&gt;&lt;br&gt;
&lt;sup&gt;&lt;a&gt;[2]&lt;/a&gt; &lt;a href="https://observablehq.com/@akollegger/graph-input" rel="noopener noreferrer"&gt;@akollegger/graph-input&lt;/a&gt; - the particular ObservableHQ notebook which provides the utility functions used in this post&lt;br&gt;
&lt;/sup&gt;&lt;/p&gt;

</description>
      <category>observable</category>
      <category>graphs</category>
      <category>d3</category>
      <category>gram</category>
    </item>
    <item>
      <title>Gram: a data graph format</title>
      <dc:creator>Andreas Kollegger</dc:creator>
      <pubDate>Tue, 19 Jan 2021 12:41:21 +0000</pubDate>
      <link>https://forem.com/neo4j/gram-a-data-graph-format-3mi2</link>
      <guid>https://forem.com/neo4j/gram-a-data-graph-format-3mi2</guid>
      <description>&lt;p&gt;Gram is a textual format for data. We have &lt;code&gt;CSV&lt;/code&gt; for tables, &lt;code&gt;JSON&lt;/code&gt; for documents, and &lt;code&gt;gram&lt;/code&gt; for data graphs.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;gram&lt;/code&gt; when &lt;code&gt;[a,b,c]&lt;/code&gt; becomes &lt;code&gt;(a)--&amp;gt;(b)&amp;lt;--(c)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why another data format?
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Anything worth talking about is worth inventing a language for.&lt;/p&gt;

&lt;p&gt;-- probably not &lt;a href="https://en.wikipedia.org/wiki/Ludwig_Wittgenstein" rel="noopener noreferrer"&gt;L. Wittgenstein&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Graphs are a powerful and increasingly popular way to think about and work with data. ISO has established a project to formalize an &lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/GQL_Graph_Query_Language" rel="noopener noreferrer"&gt;international standard Graph Query Language&lt;/a&gt;. ISO GQL will become the "language of graphs".&lt;/p&gt;

&lt;p&gt;But graph technology includes databases, analytics libraries, visualization software, and a host of other tools.&lt;/p&gt;

&lt;p&gt;How do we use these things together? We need a common format to connect tools when performing the usual operations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;import/export data file&lt;/li&gt;
&lt;li&gt;send/receive network transmissions&lt;/li&gt;
&lt;li&gt;copy &amp;amp; paste across applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We all expect these actions to just work. It's frustrating when any of them are not possible. Tools with limited interoperability feel locked-in and isolated. That's not the graph way. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Gram&lt;/code&gt; can make it possible for data graphs to be used in normal everyday work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://xkcd.com/927/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffxtymqcirbyiz3riq652.png" alt="Another standard" width="500" height="283"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Data graphs as information architecture
&lt;/h2&gt;

&lt;p&gt;While there are existing graph formats, &lt;code&gt;gram&lt;/code&gt; is designed to complement the Property Graph Model defined by ISO GQL.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Gram&lt;/code&gt; is interested in information architectures. Data graphs are the means, not the goal. Rather than talking about graphs, &lt;code&gt;gram&lt;/code&gt; speaks in graph to talk about other things.&lt;/p&gt;

&lt;p&gt;Some motivating examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developer.ibm.com/articles/the-class-diagram/#association-class" rel="noopener noreferrer"&gt;Association class&lt;/a&gt;: How do we describe the relationship between two things? Not just that they are connected, but &lt;em&gt;how&lt;/em&gt; they are connected.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Decorator_pattern" rel="noopener noreferrer"&gt;Decorator pattern&lt;/a&gt;: Can multiple applications share data while reserving space for their own use?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/U.S._Route_66" rel="noopener noreferrer"&gt;U.S. Route 66&lt;/a&gt;: How can we represent path membership and also information about the path itself?&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Bill_of_materials" rel="noopener noreferrer"&gt;Bill of materials&lt;/a&gt; with &lt;a href="https://en.wikipedia.org/wiki/Finished_goods" rel="noopener noreferrer"&gt;finished goods&lt;/a&gt;: How do we describe both the plan to build stuff and the stuff that has been built?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Gram&lt;/code&gt; attempts to address these scenarios while being friendly to read and write by adopting a path-based representation. Paths all the way down, or all the way up with path composition.&lt;/p&gt;
&lt;h3&gt;
  
  
  Friendly to read and write
&lt;/h3&gt;

&lt;p&gt;Gram is intuitively simple, inspired by Cypher&lt;sup&gt;1&lt;/sup&gt; path expressions.&lt;/p&gt;

&lt;p&gt;Information starts with a familiar looking data record of nested properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Andreas Kollegger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="na"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Malmö&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sweden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The extra set of parenthesis wrapping the record provides space for an identifier and a set of labels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Andreas Kollegger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Malmö&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sweden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Data records can be composed into information structures using relationships:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;Wrote&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gram: a data graph format&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can complete this scene with another related record:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Putting it all together we could write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;Wrote&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Blog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;Author&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Andreas Kollegger&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;address&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Malmö&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;country&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sweden&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}})&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Gram: a data graph format&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;when&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;date&lt;/span&gt;&lt;span class="s2"&gt;`2021-01-21`&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nice. The first path is readable as a sentence that "a &lt;code&gt;Person&lt;/code&gt; &lt;code&gt;Wrote&lt;/code&gt; a &lt;code&gt;Blog&lt;/code&gt; that was &lt;code&gt;Read&lt;/code&gt; by another &lt;code&gt;Person&lt;/code&gt;." Notice in this rewrite we accumulated information -- all the &lt;code&gt;a&lt;/code&gt;'s are the same record. &lt;/p&gt;

&lt;p&gt;Like writing prose, you don't have to say everything at once. Paths appear in an ordered stream that merges forward into a final result. In fact, because any path or sequence of paths forms a valid result you can time-travel or page through a graph.&lt;/p&gt;

&lt;h1&gt;
  
  
  Use &lt;code&gt;gram&lt;/code&gt; for data graphs
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;Gram&lt;/code&gt; is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;friendly to read and write&lt;/li&gt;
&lt;li&gt;composable, sliceable, pageable and streamable&lt;/li&gt;
&lt;li&gt;vendor-neutral&lt;/li&gt;
&lt;li&gt;a work-in-progress :)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a reference implementation called &lt;a href="https://gram-data.github.io/gram-js/" rel="noopener noreferrer"&gt;gram-js&lt;/a&gt; which is used along with d3.js in a &lt;a href="https://observablehq.com/collection/@akollegger/gram-for-graphs" rel="noopener noreferrer"&gt;collection of ObservableHQ notebooks&lt;/a&gt;. Next up is integration with other Javascript libraries and conversion to/from other formats. &lt;/p&gt;

&lt;p&gt;Check it out and let me know what you think!&lt;/p&gt;




&lt;p&gt;Footnotes:&lt;/p&gt;

&lt;p&gt;&lt;sup&gt;&lt;a&gt;[1]&lt;/a&gt; &lt;a href="https://neo4j.com/developer/cypher/" rel="noopener noreferrer"&gt;Cypher Language&lt;/a&gt; inspired both ISO GQL and &lt;code&gt;gram&lt;/code&gt; with the use of "ASCII art" to draw graph elements. &lt;code&gt;cypher&lt;/code&gt; is a graph database query language.&lt;br&gt;
&lt;/sup&gt;&lt;br&gt;
&lt;sup&gt;&lt;a&gt;[2]&lt;/a&gt; &lt;a href="https://observablehq.com/collection/@akollegger/gram-for-graphs" rel="noopener noreferrer"&gt;Gram of Graphs&lt;/a&gt; - an Observable HQ notebook collection which illustrates how to use &lt;code&gt;gram&lt;/code&gt; and provides handy utilities for visualizing graphs.&lt;br&gt;
&lt;/sup&gt;&lt;br&gt;
&lt;sup&gt;&lt;a&gt;[3]&lt;/a&gt; &lt;a href="https://gram-data.github.io/gram-js/" rel="noopener noreferrer"&gt;gram-js&lt;/a&gt; - the &lt;code&gt;gram&lt;/code&gt; reference implementation, written in TypeScript&lt;br&gt;
&lt;/sup&gt;&lt;/p&gt;

</description>
      <category>gram</category>
      <category>graph</category>
      <category>neo4j</category>
      <category>json</category>
    </item>
    <item>
      <title>Graphs on Tap</title>
      <dc:creator>Andreas Kollegger</dc:creator>
      <pubDate>Thu, 12 Nov 2020 14:02:27 +0000</pubDate>
      <link>https://forem.com/neo4j/graphs-on-tap-5gh6</link>
      <guid>https://forem.com/neo4j/graphs-on-tap-5gh6</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/neo4j-devtools/relate" rel="noopener noreferrer"&gt;Neo4j Relate&lt;/a&gt;  delivers graphs on tap. From the CLI, from your app, or from a local server, you can provision Neo4j databases whenever you'd like to enjoy the clean, refreshing goodness of graphs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Extracted from Neo4j Desktop
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;The best frameworks are in my opinion extracted, not envisioned.&lt;br&gt;
-- &lt;a href="https://dhh.dk/posts/6-why-theres-no-rails-inc" rel="noopener noreferrer"&gt;David Heinemeier Hansson&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Neo4j Desktop is a native application which packages up everything you need for working with the Neo4j DBMS.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Neo4j DBMS download and management&lt;/li&gt;
&lt;li&gt;Neo4j connection management &lt;/li&gt;
&lt;li&gt;tools like &lt;a href="https://neo4j.com/developer/neo4j-browser/" rel="noopener noreferrer"&gt;Neo4j Browser&lt;/a&gt;, &lt;a href="https://neo4j.com/developer/neo4j-bloom/" rel="noopener noreferrer"&gt;Neo4j Bloom&lt;/a&gt; and &lt;a href="https://neo4j.com/labs/etl-tool/" rel="noopener noreferrer"&gt;Neo4j ETL&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Internally, there is a GraphQL API through which tools may discover available databases, provision new ones and negotiate authentication.&lt;/p&gt;

&lt;p&gt;Neo4j Desktop is extensible. New tools can be added, and you can write your own. But it feels like a walled garden.  Peering over the hedge, wouldn't it be nice to easily manage Neo4j from the command line, or from VS Code, or even from within your app? &lt;/p&gt;

&lt;p&gt;Neo4j Relate extracts the core operational library of Neo4j Desktop then packages that into a CLI tool, a web server, or a generic Electron app. Let's take the CLI for a spin.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs5vxa4wcgnsxbiiy90yw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fs5vxa4wcgnsxbiiy90yw.png" alt="CLI, App, Server to Neo4j Relate" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Neo4j at your command
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;Now witness the firepower of this fully armed and operational &lt;del&gt;battle station&lt;/del&gt; CLI&lt;br&gt;
-- &lt;a href="https://www.imdb.com/title/tt0086190/characters/nm0001519#quotes" rel="noopener noreferrer"&gt;The Emperor&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href="https://www.npmjs.com/package/@relate/cli" rel="noopener noreferrer"&gt;&lt;code&gt;@relate/cli&lt;/code&gt;&lt;/a&gt; package installs the &lt;code&gt;relate&lt;/code&gt; command line tool. There &lt;a href="https://github.com/neo4j-devtools/relate/pull/209" rel="noopener noreferrer"&gt;is a PR&lt;/a&gt; which will make the CLI available without requiring node.js. &lt;/p&gt;

&lt;p&gt;For now, try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @relate/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Set up a provisioning environment:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relate &lt;span class="nb"&gt;env&lt;/span&gt;:init &lt;span class="nt"&gt;--name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;graphs-on-tap &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;LOCAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Accept the default settings when prompted. You'll need to provide this semi-secret access code &lt;code&gt;r31473&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Enter the access code you received from applying at https://neo4j.relate.by/invite:r31473
✔ Do you need to &lt;span class="nb"&gt;enable &lt;/span&gt;authentication? &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; · &lt;span class="nb"&gt;false&lt;/span&gt;
✔ Do you need to restrict access to the GraphQL API methods? &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; · &lt;span class="nb"&gt;false&lt;/span&gt;
✔ Are HTTP consumers required to have an API key? &lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt; · &lt;span class="nb"&gt;false
&lt;/span&gt;Creating environment... &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The authentication mentioned above is for the GraphQL API, which we'll explore in a later post.&lt;/p&gt;

&lt;p&gt;Now install a Neo4j DBMS named "hello" into the provisioning environment named "graphs-on-tap". If you drop &lt;code&gt;4.1.3&lt;/code&gt; from the end, you can pick which version to install:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relate dbms:install &lt;span class="nt"&gt;-e&lt;/span&gt; graphs-on-tap &lt;span class="nt"&gt;--name&lt;/span&gt; hello 4.1.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;code&gt;Enter new passphrase:&lt;/code&gt; will set the password for the admin user named "neo4j":&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;✔ Enter new passphrase · 
DOWNLOAD PROGRESS &lt;span class="o"&gt;[&lt;/span&gt;████████████████████████████████████████] 100%
extracting neo4j... &lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;b92ada41] hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Finally, start the DBMS named "hello" within the "graphs-on-tap" environment:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;relate dbms:start &lt;span class="nt"&gt;-e&lt;/span&gt; graphs-on-tap hello
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Neo4j DBMS should start up, then you'll be able to browse to &lt;a href="http://localhost:7474" rel="noopener noreferrer"&gt;http://localhost:7474&lt;/a&gt; to use Neo4j Browser. Use the admin user named &lt;code&gt;neo4j&lt;/code&gt; and the password you set above.&lt;/p&gt;

&lt;p&gt;Convenient, right?&lt;/p&gt;

&lt;p&gt;Try &lt;code&gt;relate --help&lt;/code&gt; to see the other available commands and options. For instance, &lt;code&gt;relate env:use&lt;/code&gt; to set the "current" environment, saving you a little typing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;Neo4j Relate is in alpha, evolving quickly with more capabilities and integrations. Stay tuned and reach out to me with any ideas or questions.  &lt;/p&gt;

&lt;p&gt;In later posts, I'll explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;e2e testing using &lt;code&gt;relate&lt;/code&gt; to do setup &amp;amp; teardown &lt;/li&gt;
&lt;li&gt;hosting Browser, Bloom and other tools &lt;em&gt;without&lt;/em&gt; needing Neo4j Desktop&lt;/li&gt;
&lt;li&gt;spinning up a server to provision DBMSes on demand&lt;/li&gt;
&lt;li&gt;writing &lt;a href="https://nestjs.com" rel="noopener noreferrer"&gt;nest.js&lt;/a&gt; modules to use &lt;code&gt;relate&lt;/code&gt; as an application server&lt;/li&gt;
&lt;/ul&gt;


&lt;h1&gt;
  
  
  Related...
&lt;/h1&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/neo4j-devtools" rel="noopener noreferrer"&gt;
        neo4j-devtools
      &lt;/a&gt; / &lt;a href="https://github.com/neo4j-devtools/relate" rel="noopener noreferrer"&gt;
        relate
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag__link"&gt;
  &lt;a href="/adamcowley" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F343203%2Ff7e5bb09-4711-4663-931b-20b3fdaea225.jpeg" alt="adamcowley"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/adamcowley/building-a-modern-web-application-with-neo4j-and-nestjs-38ih" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Building a Modern Web Application with Neo4j and NestJS&lt;/h2&gt;
      &lt;h3&gt;Adam Cowley ・ Jul 2 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#neo4j&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#typescript&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#nestjs&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;



</description>
      <category>neo4j</category>
      <category>cli</category>
      <category>node</category>
    </item>
  </channel>
</rss>
