-
Notifications
You must be signed in to change notification settings - Fork 789
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
Update nbconvert to work with Altair/Vega-Lite/Vega output #329
Comments
This sounds like an issue in http://github.com/vega/ipyvega, which is soon going to be replaced by https://github.com/altair-viz/jupyter_vega. @gnestor, do you know whether this will still be an issue in |
It sounds like an issue with the mime type of the figures. In jupyter_vega, we output both a vega mime type that renders the dynamic plot and a state See #216 for status on built-in support Vega/Vega-lite in JupyterLab. Once this is merged, we will do the same for classic Jupyter Notebook. |
We have plans to do a full overhaul of nbconvert's HTML oputput eventually to support arbitrary MIME output based on the new JupyterLab components. But that may still be a ways off as JupyterLab is still pre-1.0. @mpacer @blink1073 @sccolbert @jasongrout |
jupyter nbconvert --execute --to html
does not export figures
@ellisonbg I like this plan! Until then, should renderer extensions still plan on providing an |
Yes, I think so!
…On Wed, Sep 27, 2017 at 1:24 PM, Grant Nestor ***@***.***> wrote:
@ellisonbg <https://github.com/ellisonbg> I like this plan! Until then,
should renderer extensions still plan on providing an image/png or
text/html representation along with the custom MIME representation to
support rendering in nbviewer/on Github?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#329 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AABr0E-GxrmbEI4xz5_RdJHrMR-3n2Vxks5smq8agaJpZM4NfaM3>
.
--
Brian E. Granger
Associate Professor of Physics and Data Science
Cal Poly State University, San Luis Obispo
@ellisonbg on Twitter and GitHub
bgranger@calpoly.edu and ellisonbg@gmail.com
|
@gnestor I have a workaround that just uses Altair to generate charts and runs First set up to use the javascript librariesRun this in a separate cell because the last thing has to be the import json # need it for json.dumps
import altair as alt
from altair.vega import v3
# Create the correct URLs for require.js to find the Javascript libraries
vega_url = 'https://cdn.jsdelivr.net/npm/vega@' + v3.SCHEMA_VERSION
vega_lib_url = 'https://cdn.jsdelivr.net/npm/vega-lib'
vega_lite_url = 'https://cdn.jsdelivr.net/npm/vega-lite@' + alt.SCHEMA_VERSION
vega_embed_url = 'https://cdn.jsdelivr.net/npm/vega-embed@3'
noext = "?noext"
paths = {
'vega': vega_url + noext,
'vega-lib': vega_lib_url + noext,
'vega-lite': vega_lite_url + noext,
'vega-embed': vega_embed_url + noext
}
workaround = """
requirejs.config({{
baseUrl: 'https://cdn.jsdelivr.net/npm/',
paths: {paths}
}});
"""
HTML("".join((
"<script>",
workaround.format(paths=json.dumps(paths)),
"</script>",
"This code block sets up embedded rendering in HTML."
))) Next make a helper function to do the renderingIt is called # Define the function for rendering
def add_autoincrement(render_func):
# Keep track of unique <div/> IDs
cache = {}
def wrapped(chart, id="vega-chart", autoincrement=True):
"""Render an altair chart directly via javascript.
This is a workaround for functioning export to HTML.
(It probably messes up other ways to export.) It will
cache and autoincrement the ID suffixed with a
number (e.g. vega-chart-1) so you don't have to deal
with that.
"""
if autoincrement:
if id in cache:
counter = 1 + cache[id]
cache[id] = counter
else:
cache[id] = 0
actual_id = id if cache[id] == 0 else id + '-' + str(cache[id])
else:
if id not in cache:
cache[id] = 0
actual_id = id
return render_func(chart, id=actual_id)
# Cache will stay defined and keep track of the unique div Ids
return wrapped
@add_autoincrement
def render(chart, id="vega-chart"):
# This below is the javascript to make the chart directly using vegaEmbed
chart_str = """
<div id="{id}"></div><script>
require(["vega-embed"], function(vegaEmbed) {{
const spec = {chart};
vegaEmbed("#{id}", spec, {{defaultStyle: true}}).catch(console.warn);
}});
</script>
"""
return HTML(
chart_str.format(
id=id,
chart=json.dumps(chart) if isinstance(chart, dict) else chart.to_json(indent=None)
)
) Then you can use the
|
@tanyaschlusser This really saved my day. Thank you. |
An alternative is to customise the In short it adds the vega JavaScript libraries to the header, and wraps the specs for each visualisation in a jupyter nbconvert --to html notebook.ipynb --template=altair_interactive.tpl output.html |
Also, this gist ensures unique numbers, although it is slightly hacky to get around the scoped context. Assignment doesn't work, but calling a function on a mutable object works just fine. |
@tanyaschlusser I'm eager to implement your workaround but received a NameError when running the HTML() command: |
@hassenmorad I think you'll want: |
@Alcampopiano That was it. Thanks! |
For some reason I'm just getting a blank output (even w/ the exact example @tanyaschlusser provided). Not sure what I'm missing. Any suggestions? |
@hassenmorad Yes this is was happens in the notebook. Save it as HTML and you'll see the charts and they'll have interactivity. |
Hmm, not sure what I'm doing wrong. I saved the notebook as html via nbviewer but the html file just displays the static notebook. And when I upload it to github it displays it as html code. |
Here is a gist using simple extension of the nbconvert template. Use:
{% extends "full.tpl" %}
{% set altair = {'vis_number': 1} %}
{% block header %}
<script src="https://cdn.jsdelivr.net/npm/vega@3"></script>
<script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite@2"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite@3"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@3"></script>
{{super()}}
{% endblock header %}
{% block data_png scoped %}
{% if 'application/vnd.vegalite.v1+json' in output.data %}
{% elif 'application/vnd.vegalite.v2+json' in output.data %}
{% elif 'application/vnd.vegalite.v3+json' in output.data %}
{% elif 'application/vnd.vega.v2+json' in output.data %}
{% elif 'application/vnd.vega.v3+json' in output.data %}
{% else %}
{{super()}}
{% endif %}
{% endblock data_png %}
{% block data_text scoped %}
{% if 'application/vnd.vegalite.v1+json' in output.data %}
{% elif 'application/vnd.vegalite.v2+json' in output.data %}
{% elif 'application/vnd.vegalite.v3+json' in output.data %}
{% elif 'application/vnd.vega.v2+json' in output.data %}
{% elif 'application/vnd.vega.v3+json' in output.data %}
{% else %}
{{super()}}
{% endif %}
{% endblock data_text %}
{% block data_priority scoped %}
{% for mimetype in (
'application/vnd.vegalite.v1+json',
'application/vnd.vegalite.v2+json',
'application/vnd.vegalite.v3+json',
'application/vnd.vega.v2+json',
'application/vnd.vega.v3+json')
%}
{% if mimetype in output.data %}
{% if altair.update({'vis_number': altair.vis_number+1}) %}{% endif %}
<div id="vis{{cell['execution_count']}}_{{ altair.vis_number }}"></div>
<script type="text/javascript">
var spec = {{ output.data[mimetype] | replace("None","null") | replace("True","true") | replace("False","false") }};
var opt = {"renderer": "canvas", "actions": false};
vegaEmbed("#vis{{cell['execution_count']}}_{{ altair.vis_number }}", spec, opt);
</script>
{% elif loop.index == 1 %}
{{super()}}
{% endif %}
{% endfor %}
{% endblock data_priority %} Live Example: https://knanne.github.io/notebooks/visualize_strava_data_in_python.html#Plots Credit:
Requirements:
Explanations:
|
Hi @knanne, I also had to tweak around the I've published an updated gist with those changes. Feel free to merge them into yours. I've also created a post on it, plus some examples showing how it all fits together. |
Thanks @octavifs your solution worked for me in the end. Unfortunately @tanyaschlusser and @knanne didn't work for me. |
#329 (comment) has been updated with improvements by @octavifs. Working on latest version |
Thanks @knanne -- your template works great @ellisonbg NBConvert currently exports VegaLite plots as static PNG images. Is this something that can be easily realized with NBConvert as well? (but for the whole notebook) |
As of Altair 4.0, the default renderer is HTML-based and should work with nbconvert with interactive charts without any special setup. The I'm going to close this issue; I think the core questions are addressed as of 4.0. |
Not sure what I am doing wrong, but I cannot export an interactive chart. I have tried to do it in All the templates are within the I am running the below command: Thanks |
How about: Please also check that you have the latest versions of Jupyterlab and Nbconvert |
An FYI, the altair visuals were not rendering for me when converting to html with nbconvert as well, but found the issue was simply a button at the top of the display to trust HTML that enabled them to render.
|
Hi,
when exporting q notebook to HTML from the command line, altair does not export figures and they are not embedded in the produced document.
Exporting the notebook from the jupyter web interface works correctly and exports every figures.
Thanks,
Rémi
The text was updated successfully, but these errors were encountered: