[Bjonnh.net]# _

# Articles/

Nice cytoscape graphs in hugo posts.


categories computer hack tags graph hugo

A friend of mine Pierre Grangé-Praderas needed to make a webpage with graphs. So I decided to play with Cytoscape and Hugo and see if I could integrate them together.

Cytoscape.js is a really nice and efficient library to handle, display and manipulate graphs in JavaScript.

Update 2020/11/16: Added the pies to please scorfi. For that I also added a parameter to have a style file.

Demo (playable)

Data file

The data file reside in the article directory (name of the article without md). Here called graph.json.

[
  { "data": { "id": "a", "label": "A", "foo": 3, "bar": 5, "baz": 2 } },
  { "data": { "id": "b", "label": "B", "foo": 3, "bar": 5, "baz": 20 } },
  { "data": { "id": "c", "label": "C", "foo": 3, "bar": 50, "baz": 2 } },
  {
    "data": {
                "id": "ab",
                "source": "a",
                "target": "b"
            }
  },
  {
    "data": {
                "id": "bc",
                "source": "b",
                "target": "c"
            }
  },
  {
    "data": {
                "id": "ca",
                "source": "c",
                "target": "a"
            }
  },
  {
    "data": {
                "id": "ac",
                "source": "a",
                "target": "c"
            }
  }
]

Shortcode in page

That you insert in the page using the shortcode:

{{<cytoscape id="bacd" file="graph.json" style="style.json" height="200">}}

Shortcode definition (in your theme)

<button onClick="document.getElementById('cyto-{{ .Get "id" }}').cy.reset();">Reset</button>
<button onClick="document.getElementById('cyto-{{ .Get "id" }}').cy.layout({name: 'cose'}).run();">Layout the nodes</button>
<div class="cytoshort" id="cyto-{{ .Get "id" }}">
</div>

<script>
  document.addEventListener("DOMContentLoaded", () => {
      
  var element = document.getElementById("cyto-{{ .Get "id" }}");
  element.style.height = 'calc({{ .Get "height" }}px)'
  element.cy = cytoscape({
      container: element,
      elements: {{ getJSON (printf "content/%s%s/%s" (.Page.Dir) (.Page.File.BaseFileName) (.Get "file")) }},      
      style: {{ getJSON (printf "content/%s%s/%s" (.Page.Dir) (.Page.File.BaseFileName) (.Get "style")) }},
   });

  });

</script>

Of course your page will need to have cytoscapeOn = true in its header. That’s a trick I use to limit the amount of javascript loaded on each page (I use Mermaid on other pages and it doesn’t have to be loaded everytime).

{{ if eq .Params.cytoscapeOn true }}

  <script src="https://cdn.jsdelivr.net/npm/cytoscape@3.17.0/dist/cytoscape.min.js">
  </script>

{{ end }}

There is a minimal css needed as well

You need to give a size to the div, this is usually done with some css.

.cytoshort {
  width: 800px;
  height: 600px;
}