[fastpages] Plotly plot doesn't load, JS error in browser

I’m almost ready for a PR to covid19dashboard for an inflection-sensitive chart like https://youtu.be/54XLXg4fYsc but I used Plotly and when I render a post with fastpages following the contribution instructions, there’s a JavaScript error in the browser and the chart itself doesn’t display. Is Plotly unsupported, or am I doing it wrong?

Here’s the error, seemingly complaining of an undefined ‘require’ symbol, perhaps RequireJS?:

The full notebook is here, in case that helps: https://github.com/computableai/covid19-dashboard/blob/inflection-detection/_notebooks/2020-03-30-where-are-we-winning.ipynb

Thanks!
-Daniel

1 Like

Funny, I have just been grappling with Plotly :slight_smile: What I had to do is:

from IPython.display import HTML
HTML(fig.to_html())

And then it displayed in the blog.

4 Likes

Thanks I had no idea how to make plotly work this is useful

1 Like

Thank you for replying! That worked for fastpages-generated page. However, in the notebook itself, I get this in the browser console:

VM127:6 Uncaught ReferenceError: Plotly is not defined
at <anonymous>:6:21
at m (jquery.min.js:2)
at Re (jquery.min.js:2)
at w.fn.init.append (jquery.min.js:2)
at OutputArea._safe_append (outputarea.js:457)
at OutputArea.append_execute_result (outputarea.js:494)
at OutputArea.append_output (outputarea.js:326)
at OutputArea.handle_output (outputarea.js:257)
at output (codecell.js:395)
at Kernel._handle_output_message (kernel.js:1196)

Does that happen to you? Should I perhaps just add control flow code to do fig.show() when I’m in an interactive notebook, but HTML(fig.to_html()) otherwise?

Oddly, the control flow option didn’t actually work… It seems I need to have run HTML(fig.to_html()) to get a blank plot in the notebook for fastpages to produce a working plot.

OK, I’ve got a workaround. The first cell shows in the notebook, but #hide prevents it from being rendered by fastpages and throwing errors in the browser. The second cell renders as empty in the actual notebook, throwing silent errors and displaying a blank plot, but not actually causing any harm.

I’ve had really spotty luck getting plotly to work. If anyone comes up with a coherent solution would love to know. I’ve also struggled with this over and over again

Yeah, I’ll try to make time to keep messing with it later today. This solution works, but it isn’t terribly clean. Plotly is pretty powerful, but far harder to deploy than I expected.

I really needed this particular visualization to be both interactive and animated (because the x-axis isn’t time), and I went through several libraries before I finally got it to work in Plotly.

Funny story: The Plotly Express solution was one line long, but not animated such that the entire history of each trace was displayed. Getting that to work added ~124 lines.

1 Like

For Plotly in jupyter locally you need some widget, at least if you are running Jupyter Lab: I wrote a summary (from my recollection of how I got it working)

I think there might be some additional steps, and I don’t know what you need to do if you are running classic Jupyter notebook.

Doing fig.show() or having fig as the last statement in the cell renders the image for me in the notebook, but I need the HTML(fig.to_html()) for it to render in the published blog.

@binnisb left a comment for you on your blog – would love to incorporate some instructions into the official fastpages docs, if you have time to flesh out your writeup a bit (if not, no worries - just wanted to throw that out there).

1 Like

Hey, sorry for being slow right now. I’ve gotten involved in 3D printing for a local hospital, so I’m a little behind on other things I had going. I haven’t had time yet to find a cleaner solution to plotting in both the notebook and Plotly, but I can certainly write up what I’ve got sometime in the next week.

In the latest version 2.1.20, I find plotly dosen’t compatibility with jemoji plugin(Jekyll build failed), and rss link doesn’t work well. Anyone meet the same problem?

1 Like

I also faced the same problem as yours.

Plot.ly is not officially supported by fastpages. I have had trouble with plot.ly because of the various CSS and other collisions.

Hey folks! For some reason – and I have no idea why – the thing that makes plotly work with both fastpages and with nbdev-generated documentation
(e.g. see the interactive 3D plotly scatter plot that works on my new mrspuff/viz documentation page) is to download a copy of the ipynb file from Google Colab.

So, literally, just upload your notebook file to Colab, run it, then download it from Colab, move that into your _notebooks directory and git commit it, push it, and …watch the magic happen!

2 Likes

Hi! I had the same issue, and HTML(fig.to_html()) does not work for me (plotly 4.14.3, classical notebook). Jekyll just fails to generate the html page (Error: error parsing fragment (1)).

However going through Colab worked as @drscotthawley mentioned. I’ve inspected the notebooks before/after to understand, and it turns out that plotly has different renderers. It usually defaults to plotly_mimetype+notebook, but it is set to a special colab renderer when used there. Interestingly that renderer generates code that loads plotly.js from a CDN instead of embedding it into the notebook, and then jekyll is much happier with that 30k input instead of 3MB of plotly code.

So the first solution that worked for me was to change the default renderer to colab locally too with a cell at the top:

import plotly.io as pio
pio.renderers.default = 'colab'

The problem with that is that we don’t get any output in a classical local notebook. However I found that setting the renderer to only notebook or notebook_connected (to use a CDN) makes Jekyll happy too as the guilty code was generated by plotly_mimetype. But then the generated HTML raised errors about require being undefined, so I had to add code to load require.js.

This is my current final top-cell that makes it work both in the local notebook and in the generated HTML:

# hide_input
# This cell is required for the export to HTML to work.
import plotly.io as pio
# Default is plotly_mimetype+notebook, but jekyll fails to parse plotly_mimetype.
pio.renderers.default = 'notebook_connected'
# Uncomment below to avoid using a CDN for plotly.js
# pio.renderers.default = 'notebook'

# Inject the missing require.js dependency.
from IPython.display import display, HTML
js = '<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script>'
display(HTML(js))

Hope this helps!

1 Like

Thanks for sharing this! Congratulations on figuring this out!

I’ll add one semi-related similar note: to get Bokeh plots to work, I had to import JQuery via a CDN. But I inserted JavaScript code into a Markdown cell; it did not occur to me to use HTML() to do this. I like your method because then the code is explicitly shown in the notebook, whereas by my method, you only see the JavaScript when you double-click on the Markdown cell. (Otherwise it’s invisible).

Interesting that when I run your from within Colab it breaks everything, and the output cells in the generated blog are all blank. Maybe the idea was that one would only run that in regular-jupyter.

In that case, how about a general purpose code group like…

#hide_input 
def on_colab():   # cf https://stackoverflow.com/questions/53581278/test-if-notebook-is-running-on-google-colab
    """Returns true if code is being executed on Colab, false otherwise"""
    try:
        return 'google.colab' in str(get_ipython())
    except NameError:    # no get_ipython, so definitely not on Colab
        return False 

if not on_colab():  # Nick Burrus' code for normal-Juptyer use with plotly:
    import plotly.io as pio
    pio.renderers.default = 'notebook_connected'
    from IPython.display import display, HTML
    js = '<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script>'
    display(HTML(js))

…yeah? For me, this seems to produce working (blog) results regardless of whether the .ipynb file was generated by Colab or regular-Jupyter.

Making libraries with Colab isn’t supported in nbdev because they use different delimiters and such

Oh wow. Interesting. Because the (nbdev-powered) library I’ve been writing is specifically intended for making things work nicely on Colab.

(I’ll be teaching 20 students this fall and we’ll be using Colab for everything. Paperspace Gradient had bugs that I got tired of.)