Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plotly plot not converted to HTML #944

Open
janba opened this issue Jan 25, 2019 · 24 comments
Open

Plotly plot not converted to HTML #944

janba opened this issue Jan 25, 2019 · 24 comments

Comments

@janba
Copy link

janba commented Jan 25, 2019

Dear NBConvert developers
CC @gnestor

If I convert the following notebook to html, the output html file does not contain any graphics output.

import plotly.graph_objs as go
mesh = go.Mesh3d(x=[0,1,0],y=[0,0,1],z=[0,0,0],i=[0],j=[1],k=[2],flatshading=False,color='#333333')
go.FigureWidget([mesh])

However, if I use the old-fashioned:

import plotly.offline as py
import plotly.graph_objs as go
py.init_notebook_mode(connected=False)
mesh = go.Mesh3d(x=[0,1,0],y=[0,0,1],z=[0,0,0],i=[0],j=[1],k=[2],flatshading=False,color='#333333')
py.iplot([mesh])

everything works fine. It does not matter if I export from within Jupyter Lab or if I export from the command line with jupyter nbconvert --execute --to html something.ipynb

My environment is MacOS 10.14.2, running Python 3.7 with
jupyter 1.0.0
jupyter-client 5.2.4
jupyter-console 6.0.0
jupyter-core 4.4.0
jupyterlab 0.35.0
jupyterlab-server 0.2.0

jupyter nbconvert 5.4.0

It seems that nbconvert has not been brought up to speed with the latest Plotly.py, i.e. > 3.0

I would be most grateful if this were fixed :-)

  • Andreas
@gnestor
Copy link

gnestor commented Jan 25, 2019

It's because plotly.offline.iplot and FigureWidget both return outputs of Plotly JSON MIME type:

image

whereas calling py.init_notebook_mode(connected=False) in the classic notebook (this only works in the classic notebook) instructs plotly to output Plotly JSON and HTML output (in the first output, plotly.py actually injects a script element with the contents of plotly.js in it, that's why _Plotly is available in the subsequent cells):

image

We want to discourage the injection of scripts in notebook outputs in JupyterLab so we encourage people to use renderer extensions like plotly-extension. To solve this problem of making rich outputs show up in nbviewer and static nbconvert targets, plotly-extension and others inject a static image into the output:

image

Unfortunately, FigureWidget doesn't inject a static image into the output like plotly-extension does, just a plain text fallback (like most ipywidgets):

image

You can either request that plotly.py offer some sort of fallback output for nbviewer, etc. or render you plotly charts using plotly-extension which ends up looking like your classic notebook code minus the init_notebook_mode:

import plotly.offline as py
import plotly.graph_objs as go
mesh = go.Mesh3d(x=[0,1,0],y=[0,0,1],z=[0,0,0],i=[0],j=[1],k=[2],flatshading=False,color='#333333')
py.iplot([mesh])

@janba
Copy link
Author

janba commented Jan 26, 2019

Right, thanks for the swift reply. Based on your comments, I have introduced a global variable that selects a mode which is either output or interactive. In output mode, the iplot function is used and in interactive mode, it uses the Widgets.

I can see that not having scripts and html injected in the notebook might be a concern, but fallback output is terrible for anyone relying on the HTML as the target format of the notebook. For presentations or students hand-ins it is extremely convenient to be able to bake a notebook where the figures work, but no computation takes place.

Consequently, I really hope that iplot continues to work :)

On a side note, I still need to call init_notebook_mode. This may be a transient issue.

Thanks again

@gnestor
Copy link

gnestor commented Jan 29, 2019

You're welcome. I'm a little unclear about whether you're suggesting that we change the current functionality or not. If you use iplot and have @jupyterlab/plotly-extension installed, then it will save a PNG output that will render when exported to HTML. However, if you use FigureWidget, there is no fallback. It could include a static image output as well or Plotly HTML output. Github's flavor of nbviewer will sanitize and strip out any script tags in outputs, so Plotly HTML outputs will not work on Github.

@janba
Copy link
Author

janba commented Jan 30, 2019

What I would really like is to be able to nbconvert a notebook containing ipywidgets (e.g. plotly figures) to HTML and the widgets still working interactively in the exported HTML.

If I understand correctly, there are two issues:

  1. the scripts needed for running the widgets is part of the jupyter engine and not the notebook so it would not normally be injected in the html output.
  2. Widgets can be interactive, so probably only a subset of their functionality would be exported.

It is not clear to me how this would be overcome.

To my mind, though, this would be great. We create these notebooks that contain interactive content and it is great for handing in student work and for online presentation, but if the interactive content is shorn on export, then it sort of defeats the purpose.

@janba
Copy link
Author

janba commented Jan 30, 2019

Maybe I am really just asking for Dash. if so, excuse my ignorance.

@maartenbreddels
Copy link
Collaborator

What you want is possible, using this PR #900 which is not merged yet. Please test it out if it works for you.

@janba
Copy link
Author

janba commented Jan 30, 2019

Thanks. This seems to bring me much closer, but something is odd. Having downloaded and installed your version of nbconvert, it works beautifully for Plotly plots containing webgl, but not for simple scatter plots?

Also, it seems that I need to do

jupyter nbconvert --to HTML --execute something.ipynb
rather than export to HTML from within Jupyter.

Should it work with any FigureWidget? If so are there known gotchas?

@janba
Copy link
Author

janba commented Jan 31, 2019

@maartenbreddels

A more detailed analysis.

I downloaded the commit as a zip from GitHub and as mentioned, things are fine for my WebGL plots, but if I add a simple scatter plot things go wrong. This is a minimal example:

import plotly.graph_objs as go
from numpy import array

ORIG_PTS = array([
[1.21,2.21],
[0.91,2.84],
[1.81,1.21],
[2.102,-.908],
[2.741,-2.53],
[3.19,-2.31],
[3.938,-1.519],
[4.183,-1.1092],
[5.11,1.44],
[5.92,2.31]])

fig = go.FigureWidget()
fig.layout.xaxis = dict(nticks=20,showgrid=False,range=[-5,5])
fig.layout.yaxis = dict(scaleanchor="x")
fig.add_scatter(x=ORIG_PTS[:,0],y=ORIG_PTS[:,1],mode='markers',name='Points')
fig

This works for me as long as I leave out the fig.add_scatter line. However, adding that line, the plot is omitted from the html file. Below, the output with --debug. It contains no meaningful error messages as far as I can see, but maybe others can see an issue.

/Andreas

Andreas-MBP:Numerics janba$ jupyter nbconvert --debug --to html --execute minimal.ipynb
[NbConvertApp] Searching ['/Users/janba/Teaching/02580/02580-pysrc/Numerics', '/Users/janba/.jupyter', '/opt/local/Library/Frameworks/Python.framework/Versions/3.7/etc/jupyter', '/usr/local/etc/jupyter', '/etc/jupyter'] for config files
[NbConvertApp] Looking for jupyter_config in /etc/jupyter
[NbConvertApp] Looking for jupyter_config in /usr/local/etc/jupyter
[NbConvertApp] Looking for jupyter_config in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/etc/jupyter
[NbConvertApp] Looking for jupyter_config in /Users/janba/.jupyter
[NbConvertApp] Looking for jupyter_config in /Users/janba/Teaching/02580/02580-pysrc/Numerics
[NbConvertApp] Looking for jupyter_nbconvert_config in /etc/jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /usr/local/etc/jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /opt/local/Library/Frameworks/Python.framework/Versions/3.7/etc/jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /Users/janba/.jupyter
[NbConvertApp] Looking for jupyter_nbconvert_config in /Users/janba/Teaching/02580/02580-pysrc/Numerics
[NbConvertApp] Converting notebook minimal.ipynb to html
[NbConvertApp] Notebook name is 'minimal'
[NbConvertApp] Applying preprocessor: TagRemovePreprocessor
[NbConvertApp] Applying preprocessor: RegexRemovePreprocessor
[NbConvertApp] Applying preprocessor: ExecutePreprocessor
[NbConvertApp] Starting kernel: ['/opt/local/Library/Frameworks/Python.framework/Versions/3.7/bin/python3.7', '-m', 'ipykernel_launcher', '-f', '/var/folders/0_/6z0hxc0s31xck3nvym5rnvl40000gn/T/tmp3e2l4x0p.json']
[NbConvertApp] Connecting to: tcp://127.0.0.1:56531
[NbConvertApp] connecting shell channel to tcp://127.0.0.1:56528
[NbConvertApp] Connecting to: tcp://127.0.0.1:56528
[NbConvertApp] connecting iopub channel to tcp://127.0.0.1:56529
[NbConvertApp] Connecting to: tcp://127.0.0.1:56529
[NbConvertApp] connecting stdin channel to tcp://127.0.0.1:56530
[NbConvertApp] Connecting to: tcp://127.0.0.1:56530
[NbConvertApp] connecting heartbeat channel to tcp://127.0.0.1:56532
[NbConvertApp] Executing notebook with kernel: python3
[NbConvertApp] Executing cell:
import plotly.graph_objs as go
from numpy import array

ORIG_PTS = array([
[1.21,2.21],
[0.91,2.84],
[1.81,1.21],
[2.102,-.908],
[2.741,-2.53],
[3.19,-2.31],
[3.938,-1.519],
[4.183,-1.1092],
[5.11,1.44],
[5.92,2.31]])

fig = go.FigureWidget()
fig.layout.xaxis = dict(nticks=20,showgrid=False,range=[-5,5])
fig.layout.yaxis = dict(scaleanchor="x")
fig.add_scatter(x=ORIG_PTS[:,0],y=ORIG_PTS[:,1],mode='markers',name='Points')
fig
[NbConvertApp] output: status
[NbConvertApp] output: execute_input
[NbConvertApp] output: comm_open
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: comm_msg
[NbConvertApp] output: display_data
[NbConvertApp] output: status
[NbConvertApp] Applying preprocessor: coalesce_streams
[NbConvertApp] Applying preprocessor: CSSHTMLHeaderPreprocessor
[NbConvertApp] Applying preprocessor: HighlightMagicsPreprocessor
[NbConvertApp] Attempting to load template full.tpl
[NbConvertApp] template_path: .
[NbConvertApp] Writing 279901 bytes to minimal.html

@gnestor
Copy link

gnestor commented Jan 31, 2019

@maartenbreddels How does this PR work? I see that it involves the widget state, but how does it render widgets when targeting HTML output?

@astrojuanlu
Copy link

Perhaps it's a different issue, but FigureWidget objects disappear when the notebook is converted to slides as well. I tried @maartenbreddels #900 PR and didn't work. I attach the notebook here just in case. cc'ing @jonmmease.

Test.ipynb.zip

@gnestor
Copy link

gnestor commented Feb 21, 2019

One workaround for FigureWidget is to display your widget using plotly.offline.iploy:

import plotly.offline as py
import plotly.graph_objs as go

mesh = go.Mesh3d(x=[0,1,0],y=[0,0,1],z=[0,0,0],i=[0],j=[1],k=[2],flatshading=False,color='#333333')

py.iplot(go.FigureWidget([mesh]))

iplot uses @jupyterlab/plotly-extension to render it which in turn adds a static image to the output, so it will render correctly when exported to HTML, PDF, etc.

@astrojuanlu
Copy link

@gnestor thanks for the workaround, it works.

@pakinja
Copy link

pakinja commented Mar 25, 2019

Hello:
"CC @flying-sheep"
Hello. I have the problem that when I export an IRkernel notebook to html the plotly objects appear in blank, in the notebook they appear normally.
The notebook have the following plot:

ir2

This is the html where the plotly object is in blank, whether I export it from the book or using nbconvert from the console, the result is the same:

ir3

If I save the graph using htmlwidgets::saveWidget(p, "test.html") there is no problem, but exporting the entire book does not work.

Here is some information of my system:

ir1

Thank you in advance for any help.

@gnestor
Copy link

gnestor commented Apr 2, 2019

@pakinja See my workaround above. If the plotly R library doesn't provide an equivalent to the Python library's iplot, that's ok because all it does it return a mime bundle of mime type application/vnd.plotly.v1+json. You can see an example at https://github.com/jupyterlab/jupyter-renderers/tree/master/packages/plotly-extension#usage.

@astrojuanlu
Copy link

Documenting my attempt to understand the situation of this issue with the upcoming Plotly 4.0.0, using the most up-to-date instructions on how to enable Jupyterlab support:

Ignoring plotly.offline for a moment (because it has been superseded by the renderers framework), right now there are three ways (actually just two) of displaying a FigureWidget in a notebook:

a) Letting just fig represent itself,
b) Using plotly.io.show(fig) (pio.show(fig) for brevity)

(Note that fig.show() is the same as (b))

Even without changing the default renderer nor temporally overriding it, as explained in the renderers documentation, both fig and pio.show(fig) will display the widget in the notebook just fine. However, only the second one will do the magic so the figure is preserved after converting the notebook to HTML.

I tested this authoring the notebook on Jupyterlab, which has an option to save widget state automatically and therefore avoids common pitfalls.

@gnestor @jonmmease Am I missing anything here?

@jonmmease
Copy link

Hi @Juanlu001,

Letting the FigureWidget display itself will display the figure through the jupyter widgets display path, while calling .show() on it will display the figure using the renderers display path. So if the .show() approch works for you, then it would probably be a bit less confusing to use regular Figure objects instead of FigureWidget objects.

Also, for docs that will always be viewed online, it might be a good idea to use the notebook_connected renderer so that the plotly.js bundle isn't embedded into every page. Instead it would be loaded from the plotly.js CDN.

@jennykathambi90
Copy link

import plotly.offline as py

autosize =False

py.iplot(fig) instead of fig.show() worked for me.

@littlesweet1129
Copy link

Documenting my attempt to understand the situation of this issue with the upcoming Plotly 4.0.0, using the most up-to-date instructions on how to enable Jupyterlab support:

Ignoring plotly.offline for a moment (because it has been superseded by the renderers framework), right now there are three ways (actually just two) of displaying a FigureWidget in a notebook:

a) Letting just fig represent itself,
b) Using plotly.io.show(fig) (pio.show(fig) for brevity)

(Note that fig.show() is the same as (b))

Even without changing the default renderer nor temporally overriding it, as explained in the renderers documentation, both fig and pio.show(fig) will display the widget in the notebook just fine. However, only the second one will do the magic so the figure is preserved after converting the notebook to HTML.

I tested this authoring the notebook on Jupyterlab, which has an option to save widget state automatically and therefore avoids common pitfalls.

@gnestor @jonmmease Am I missing anything here?

pio.show(fig) still does not show the plot after converting the notebook to HTML, is there anything else you are doing on top of that?

@astrojuanlu
Copy link

A lot has changed in one year, I haven't been hit by this since then. It's a bit difficult to stay up to date with Jupyter, Jupyterlab, widgets and all the other components of the ecosystem :) I think it's easier if folks having this particular issue provide their own debugging information, using the latest version of everything if possible (in particular, using the new Plotly renderers instead of iplot).

@mritzco
Copy link

mritzco commented May 19, 2020

Hi,
I was having the same issue displaying charts after saving as HTML.

What worked for me was to add the correct renderer to the show instruction:

fig.show(renderer="notebook")

There are quite a few renderers, more info in here:
https://plotly.com/python/renderers/#builtin-renderers

@iotanano
Copy link

@pakinja See my workaround above. If the plotly R library doesn't provide an equivalent to the Python library's iplot, that's ok because all it does it return a mime bundle of mime type application/vnd.plotly.v1+json. You can see an example at https://github.com/jupyterlab/jupyter-renderers/tree/master/packages/plotly-extension#usage.

@gnestor thank you for the advice. I had the same situation recently, but the usage link(https://github.com/jupyterlab/jupyter-renderers/tree/master/packages/plotly-extension#usage) no longer exits. Could you please give a new one?

@DrDanRyan
Copy link

Hi, I was having the same issue displaying charts after saving as HTML.

What worked for me was to add the correct renderer to the show instruction:

fig.show(renderer="notebook")

There are quite a few renderers, more info in here: https://plotly.com/python/renderers/#builtin-renderers

This works well, but the resulting file size is very large because plotly gets embedded in the HTML. If you are good with a static image in the HTML you can get it with a lot smaller file size by doing this:

from IPython.display import Image

Image(fig.to_image())

@im-SN
Copy link

im-SN commented Jul 27, 2022

Hi, I am having similar issues when exporting notebooks to html, but using the --TagRemovePreprocessor options of nbconvert. Without the TagRemove option plotly plots show correctly in the html file, but as soon as I have a few cells tagged for removal, all plotly plots show as blank on html.

A full export command would be something like: jupyter nbconvert --to html my_notebook.ipynb --TagRemovePreprocessor.enabled=True --TagRemovePreprocessor.remove_cell_tags="remove-cell"

I have attempted the solutions/workarounds proposed here, but without success. Any extra advice on this matter?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests