Write wowchemy articles with quarto + python + plotly

My recent article about Time series analysis of gas price data is written with Quarto because it contains executable Python code, some of which generates interactive graphs with Plotly. Luckily, Quarto supports the hugo output format, which is great because Wowchemy is the system my blog runs on. When I compiled the quarto article and previewed the post with hugo serve I could not see the plotly graphs produced from:

import plotly.express as px

fig = px.line(...)
fig.show()

For recap, the following happens when compiling a quarto document with python code to (hugo) markdown:

  1. A jupyter instance is started in the background with a Python kernel.
  2. Execute Python code cells in jupyter and write the output to the markdown file.

The output cell output from the above code yields a piece of HTML code with an interactive Plotly chart. The HTML element requires Plotly Javascript, which of course is not loaded. Hugo provides hooks to inject Javascript elements in the header of each page of your website, but this felt too hacky. Some googling later I discovered the Hugo example article Writing technical content in Markdown which shows how to include Plotly graphs in markdown articles. Instead of directly rendering the Plotly graph from the Python cell we need a workaround:

  1. Export every Plotly graph data to json with

    #| eval: false
    fig = px.line(...)
    fig.write_json('your-graph-data.json')
    
  2. Display the plotly graph in the article rendered with Hugo by using the following Hugo shortcode in the markdown file (remove the “\” to make it work)

    {\{< chart data=your-graph-data >}\}
    

This means that every Plotly graph I want to create needs three code cells in the quarto document:

  1. The code for producing the Plotly graph, which exposes the Plotly figure with a variable called fig:

    #| eval: false
    import plotly.express as px
    
    fig = px.line(...)
    fig.show()
    
  2. Code to export the graph data to JSON:

    #| eval: false
    fig.write_json('your-graph-data.json')
    
  3. The hugo shortcode loading the graph data:

    {\{< chart data=your-graph-data.json >}\}
    

To prevent the two code blocks from being executed whenever running quarto render index.qmd I did the following:

  1. Create a boolean flag to indicate when the code should be run
  2. Define a custom function to export the graph only when the flag is set to true.
  3. Place every Plotly graph creating code into its own code cell
  4. Set eval: false for every code cell with Plotly code
#| eval: false
EXPORT_PLOTLY = False
fig = None # Define None to prevent code errors

def export_plotly(fig, filepath: str):
    if EXPORT_PLOTLY:
        fig.write_json(filepath)

And then the code producing Plotly figures, but not executable:

#| eval: false
import plotly.express as px

fig = px.line(...)
fig.show()
#| echo: false
export_plotly(fig, 'your-graph-data.json')
{\{< chart data='your-graph-data' >}\}

In order to apply the solution you need to run the quarto document at least once with

  • every code cell with eval: true, and
  • set EXPORT_PLOTLY = True

to export the relevant graph data to JSON. I also enable cell caching to speed up the compile process:

execute:
  enabled: true
  cache: true
Peter W. Egger
Peter W. Egger
Software Engineer / Data Scientist

Maker culture enthusiast and aspiring data scientist.