I'd love to build in support for Altair plots in jupyter-book (link). However, I can't figure out how to get Altair plots to show up there (when the notebooks are converted to markdown, instead of the display code there, the Vega 2 object output that others have reported is there).
Is there some way to make vega HTML be generated when you convert the notebook, that could then be rendered similar to how ipyleaflet works? (for example, here is an ipyleaflet output converted to markdown w/ nbconvert...it just keeps the raw HTML code). It seemed like the HTML export gets pretty close.
Or, is there a way to get nbconvert to render all the vega plots as high-res PNG when it converts them? From looking at the docs it seems like this would require selenium
You could try using alt.renderers.enable('html') to embed a full HTML representation in the output notebook. This won't work in the live notebook because the notebook loads requirejs, but when you export to HTML the plots should display because exported notebooks do not load requirejs.
Hmm, when I run that I get a NoSuchEntryPoint error. (I'm running altair 2.3)
I didn't see any mention of 'html' on the renderers page...is it written up somewhere?
My mistake... yeah there's no HTML renderer. But if you use alt.renderers.enable('colab') or alt.renderers.enable('kaggle') it does essentially the same thing.
I should add an html renderer as well, because it's more generic.
interesting - do you think it'd be too hacky for a user to create a custom rendering function that output both? E.g. something like
def hacky_render_altair(chart):
alt.renderers.enable('colab')
code_to_render_chart
alt.renderers.enable('jupyterlab/notebook')
code_to_render_chart
The better way to do it would be to construct a renderer that creates a mimebundle that includes both a vegalite mimetype and an HTML mimetype. The renderers are basically thin wrappers of routines that do that; see https://github.com/altair-viz/altair/blob/master/altair/vegalite/v2/display.py
interesting, so I basically need default_renderer + HTMLRenderer...I can try to dig into the code and see if I can make sense of it. It would be great if we could share notebooks w/ altair plots and have them show up w/o needing a jupyter/colab/nteract server
This is a related thing that I worked on a while back, but it stalled: https://github.com/altair-viz/altair/pull/1127
ah nice - yes that is the kind of thing I'm looking for. It's pretty cool that, for example, the ipyleaflet output persists when you export the notebook to either markdown or HTML.
Could it be as simple as taking the current "save to HTML" functionality, but putting the necessary links etc in <script> tags instead of in a <head> tag and embedding that in one big ugly clump of output code?
I haven't looked into how ipyleaflet does this... it seems like the model used by modern jupyter (mimebundles with special frontend extensions to handle them) is fundamentally incompatible with HTML export, unless you also push to the frontend a fully self-contained HTML bundle alongside the custom mimebundle on the off-chance that someone decides to export the notebook... that doesn't seem desirable.
In JupyterLab we do a somewhat hacky thing with vega outputs where we embed image/png outputs in the same mimebundle so that it can be visualized in other frontends:
https://github.com/jupyterlab/jupyterlab/blob/ae3bc129065705b96da79f2d16bef861f7a81c9b/packages/vega4-extension/src/index.ts#L105-L109
So you could get the desired behavior by opening a notebook in JupyterLab and re-saving it. That's not a particularly nice UX, however.
A backburner project of mine has been to try to wire up some of the frontend mimerenderers to nbconvert so that stuff like this could be better driven via a CLI, but you know how backburner projects go...
@Zsailer also mentioned that something like this happens as a part of the sphinx docs build too: https://github.com/altair-viz/altair/blob/master/altair/sphinxext/altairplot.py
The sphinx output is easier, because the chart only has to be displayed in a known HTML environment. Enabling both jupyterlab and HTML export from a single notebook is harder, because Jupyterlab doesn't support arbitrary javascript execution, and HTML exports don't support jupyterlab extensions.
@choldgraf I did some experimenting today to make a vega (and JSON, and VDOM) preprocessor for nbconvert, allowing HTML representations to be embedded in notebooks via a CLI:
https://github.com/ian-r-rose/jupyterlab-nbconvert
hey @ian-r-rose - any chance you've made progress on this one? Some updates from me:
requirejs statements if you use either kaggle or colab renderers. So the plots don't show up by defaultUncaught Error: Mismatched anonymous define() module errorso I'm still trying to figure this one out :-)
Yeah, the whole requirejs vs. no requirejs is a real mess when it comes to trying to support frontend rendering in Jupyter, since libraries must be invoked differently depending on the frontend, and by design IPython doesn't let the backend (where these invocations are produced) reason about the frontend (where these invocations are interpreted).
I think mimebundle rendering was an attempt to streamline that situation, but it's been challenging because it's not fully supported by the classic notebook (which stubbornly refuses to die) and it introduces the added complexity of making output rendering dependent on frontend extensions, which must be kept in sync with their peer dependencies in the backend. Since peer dependencies are not well supported in the Python world, this leads to troubleshooting guides that are essentially gigantic decision trees based on user-visible symptoms of versions of things that the majority of users didn't even know they had installed (https://altair-viz.github.io/user_guide/troubleshooting.html is a good example).
A while back I did some experimentation with a renderer that would work in notebook, jupyterlab, and nbconvert, though I didn't quite get it working: the idea is to embed JS code in a way that works both with and without requirejs (so, e.g. it works in both classic notebook and nbconvert) and also return a mimebundle so that it will render in JupyterLab (which doesn't support custom Javascript outputs at all). It's based on an approach I developed for mpld3 6 years ago, but it was easier back then because JupyterLab wasn't in the mix.
Anyway, no good answers here, except the suggestion that IPython offer some way for the kernel to reason about which frontend is being used, to enable package maintainers to tailor their display functions appropriately and/or give their users more informative error messages.
Yeah that makes sense - frustrating that you can't make assumptions about what JS libraries/frameworks/etc are at your fingertips.
In my case, I'm using nbconvert with a custom HTML template, so I could put whatever dependencies are needed for vega plots to show up into the header. Maybe there'd be value in a page like "if you have control over your own HTML, and want Altair plots embedded in that HTML, here's the best way to do it" (e.g. embedding altair outputs in custom HTML where the altair outputs aren't the only thing in that HTML).
I've found nbconvert does a decent job of grabbing the right mimetype (aka, displaying a PNG) when converting to HTML, but it'd be nice to have nifty HTML plots in there!
One thing you could do is construct your own renderer from the tools that Altair provides internally, such as
from altair.utils.display import HTMLRenderer
my_renderer = HTMLRenderer(mode='vega',
fullhtml=False, requirejs=False,
output_div='altair-viz',
vega_version=alt.VEGA_VERSION,
vegaembed_version=alt.VEGAEMBED_VERSION)
alt.renderers.register('myrenderer', my_renderer)
alt.renderers.enable('myrenderer')
This registers an HTML mimetype with various flavors of HTML output. If you use this in concert with an nbconvert template that provides a matching Javascript environment, the charts will render interactively.
Notes here: the fullhtml=False implies that your template should load the appropriate vega-lite, vega & vega-embed libraries at the top of the page; to see the required invocations, look at the output of fullhtml=True.
whoah cool! ok I will play around with that :-)
Closing the loop on this: #1793 adds an HTML renderer that works in a variety of environments, including notebook, lab, nbviewer, nbconvert, kaggle, colab, and likely others.
Amazing 馃槏 I'll give it a shot
Most helpful comment
@choldgraf I did some experimenting today to make a vega (and JSON, and VDOM) preprocessor for nbconvert, allowing HTML representations to be embedded in notebooks via a CLI:
https://github.com/ian-r-rose/jupyterlab-nbconvert