Plotly: Interactive Graphs in Hugo

When I was hosting a WordPress blog on Bluehost, I used the Visualizer plugin to display tables and graphs for my dividend income update. Both WordPress and the Visualizer plugin are updated frequently and as a result, both are automatically updated by Bluehost. That’s one of the benefits of hosting with these companies. Security vulnerabilities are discovered all the time and timely updates ensure that your website stays safe. The downside is that sometimes the Visualizer plugin doesn’t work. This happened numerous times and I ended up creating graphs in Excel and taking a screenshot. As frustrating as those incidences have been, what I liked about the Visualizer plugin was that it displayed an interactive graph. You can hover your mouse over bar graphs to display the value. It looked nice. So when I was looking around for alternatives to Bluehost hosting or WordPress alternatives, I was looking to mimic the same functionality.

When I was researching Hugo, I found a third-party Javascript library called Plotly that not only provides the same functionality but can do much more. With all things WordPress, the Visualizer plugin is limited to using data stored in a database. Plotly allows you to use data stored in files, but also lets you use remote data as long as it’s accessible through the Internet and formatted in a way that Plotly understands. It can also display many different types of graphs. Though my use case only requires basic functionality.

Let’s dive into how to integrate Plotly into Hugo!

Including Javascript Libraries

Plotly is available through Javascript libraries. In HTML, Javascript libraries are referenced in the head section. Most if not all Hugo themes allow users to add custom HTML to the head section by overriding a partial. You have to look through your theme’s head partial, which is usually found in the layouts/partials folder.

I use the hugo-clarity theme, which allows users to include custom HTML in layouts/partials/hooks/head-end.html. I found that by inspecting the code in layouts/_default/baseof.html (Github):

20  <head>
21    {{- partial "head" . }}
22    {{- partial "hooks/head-end" . }}
23  </head>

Another example using the hugo-theme-stack theme, users can include custom HTML in layouts/partials/head/custom.html. I found that by inspecting the code in layouts/partials/head/head.html (Github):

25{{- template "_internal/google_analytics.html" . -}}
26{{- partial "head/custom.html" . -}}

Going back to the hugo-clarity theme, I added the following content to a new layout/partials/hooks/head-end.html file in my site’s GitHub repository:

1{{ if .Params.plotly }}
2<script src="https://d3js.org/d3.v7.min.js"></script>
3<script src="https://cdn.plot.ly/plotly-2.24.2.min.js"></script>
4{{ end }}

This says that if the Hugo page has the parameter plotly: true, then include these Javascript libraries. Otherwise, don’t include these Javascript libraries.

If you’re looking to upgrade to the latest versions, here are the available versions of these libraries:

Enabling Plotly on a Page

To enable Plotly on a Hugo page, I added the parameter option in my default archetype. In archetypes/default.md, I added:

1plotly: true

Whenever I create a new post, this option is included and I can decide whether to include Plotly or not based on the content.

Plotly Data Files

I store my Plotly data in my site’s GitHub repository in the static/data folder. The static folder is available to every Hugo page, so you usually store things like site graphics there. There is also a top-level data folder, but the files in that folder are only available when Hugo pages are built, but not when they’re deployed. You can review Hugo’s directory structure.

My data files are stored in JSON format. This is a simplified example of what a Plotly data file looks like for one of my bar graphs:

 1{
 2  "data": [
 3    {
 4      "type": "bar",
 5      "name": "2022",
 6      "x": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
 7      "y": [2412, 778, 4272, 1251, 1077, 5875, 1383, 1306, 4590, 1741, 1358, 5523]
 8    },
 9    {
10      "type": "bar",
11      "name": "2023",
12      "x": ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13      "y": [2652, 1861, 4753, 2106, 2310, 7951, 0, 0, 0, 0, 0, 0]
14    }
15  ],
16  "layout": {
17    "barmode": "group",
18    "title": "Passive Income",
19    "yaxis": {
20      "tickprefix": "$",
21      "tickformat": ","
22    },
23    "legend": {
24      "orientation": "h",
25      "xanchor": "center",
26      "x": 0.5
27    }
28  }
29}

Each year represents a set of data, which is called trace in Plotly. You can find the configuration options for bar traces here. The data file also includes layout options. I group my traces, provide a title for the graph, and provide display options for the y-axis and legend. You can find the layout configuration options here.

This is what the bar graph looks like:

Here is an example of a Plotly data file for a pie chart:

 1{
 2    "data": [
 3      {
 4        "type": "pie",
 5        "values": [50, 30, 20],
 6        "labels": ["Domestic", "International", "Bonds"],
 7        "hoverinfo": "label+percent"
 8      }
 9    ],
10    "layout": {
11      "title": "Asset Allocation"
12    }
13  }

This is what the pie chart looks like:

Displaying a Graph

In order to display the Plotly graph, we need to write a Hugo shortcode. Shortcodes let you run custom code that generates HTML. I created a new plotly shortcode located in layouts/shortcodes/plotly.html in my site’s GitHub repository. The contents of the shortcode are:

1{{- $json := .Get "json" }}
2{{- $height := .Get "height" | default "200px" }}
3<div id="{{ $json }}" class="plotly" style="height: {{ $height }};"></div>
4<script>
5  d3.json({{ $json }}).then(function (fig) {
6      Plotly.newPlot({{ $json }}, fig.data, fig.layout, { responsive: true, displayModeBar: false });
7  });
8</script>

In my post, I simply use the shortcode with a link to my Plotly data file:

1{{< plotly json="/data/bar.json" height="500px" >}}

Conclusion

I have been very happy with Plotly so far. When I post my dividend income update each month, all I have to do is copy and update the JSON files, then include a shortcode on my post. It doesn’t get simpler than that.