vega / altair

Declarative statistical visualization library for Python
https://altair-viz.github.io/
BSD 3-Clause "New" or "Revised" License
9.25k stars 790 forks source link

`to_html()` isn't rendered in Jupyter Notebook #3435

Open augustebaum opened 3 months ago

augustebaum commented 3 months ago

What happened?

I want to inject an Altair chart in a Jinja template, and so turned to chart.to_html(). While I was experimenting, I found it didn't behave like I expected.

As shown below, the following code prints nothing in a Jupyter notebook:

A = np.array([[50,  0,  0],
             [ 0, 48,  2],
             [ 0,  2, 48]])

data = pd.DataFrame(((i, j, v) for (i, j), v in np.ndenumerate(A)), columns=['i', 'j', 'v'])
chart = alt.Chart(data, title="Confusion matrix").mark_rect().encode(
    x=alt.X("i:O", axis=alt.Axis(orient="top"), title="Predicted class"),
    y=alt.Y('j:O', title="True class"),
    color='v:Q'
).properties(width=400, height=400)

from IPython.display import display, HTML

display(HTML(chart.to_html()))

2024-06-13T17_20_12_screenshot

However, I went digging into the source code and following snippet outputs the chart like I want:

from altair.vegalite.v5.display import html_renderer

display(HTML(html_renderer(chart.to_dict())['text/html']))

Is this behaviour of to_html to be expected?

What would you like to happen instead?

I would expect the snippet to show the chart as if I'd called chart in its own cell, as shown in the screenshot.

Which version of Altair are you using?

5.3.0

joelostblom commented 3 months ago

Thanks for the report @augustebaum . HTML(chart.to_html()) (without display) works for me, but I have to run that cell three times the first time the notebook is opened (as mentioned in more detail here https://github.com/jonmmease/avenger/issues/77#issuecomment-2116340446). I'm not sure why this is the case, but maybe something related to how JupyterLab handles the loading of the javascript/CDNs from Vega that are required to display Altair charts? PR welcome if you think there is anything we can do from Altair's side here, but I would be inclined to think it is on the note / ipython side of things (although I'm far from certain that's the case).

jardelva96 commented 1 month ago

chart.to_html() not displaying as expected in a Jupyter notebook could be related to how JupyterLab handles the loading of the required JavaScript libraries for rendering Altair charts. The behavior you're seeing might be due to the asynchronous nature of loading these libraries, causing the chart to not render immediately. Problem Using display(HTML(chart.to_html())) doesn't immediately show the chart in Jupyter notebooks. However, using html_renderer(chart.to_dict()) works as expected. Explanation When you call chart.to_html(), it generates the HTML necessary to display the chart, but it might not ensure that all the required JavaScript libraries (like Vega and Vega-Lite) are properly loaded and ready to render the chart in the notebook environment. Workaround One workaround that has been suggested is to directly use the html_renderer method from Altair's display module, which seems to handle the loading better in the notebook environment.

sugestion import numpy as np import pandas as pd import altair as alt from IPython.display import display, HTML from altair.vegalite.v5.display import html_renderer

Create the confusion matrix data A = np.array([[50, 0, 0], [0, 48, 2], [0, 2, 48]])

data = pd.DataFrame(((i, j, v) for (i, j), v in np.ndenumerate(A)), columns=['i', 'j', 'v'])

Create the Altair chart chart = alt.Chart(data, title="Confusion matrix").mark_rect().encode( x=alt.X("i:O", axis=alt.Axis(orient="top"), title="Predicted class"), y=alt.Y('j:O', title="True class"), color='v:Q' ).properties(width=400, height=400)

Display the chart using html_renderer display(HTML(html_renderer(chart.to_dict())['text/html']))