@jim In addition to Meredydd’s solution, I’ve been using Vega-Lite via its Python API Altair.
With this approach, I can write the code for the chart using Python instead of JSON. Altair produces the corresponding JSON needed for Vega-Lite. The JSON is plugged into some html, and the html is displayed in an iframe.
Client code
media=anvil.server.call('make_chart')
self.i_frame_1.url=media.get_url(True)
Server code
make chart with Altair
@anvil.server.callable
def make_chart():
source = pd.DataFrame({
'a': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I'],
'b': [28, 55, 43, 91, 81, 53, 19, 87, 52]
})
c=alt.Chart(source).mark_bar().encode(
x='a',
y='b'
)
grab the JSON and stick it into some html
altair_spec = c.to_json().replace('\n', '')
html = """
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vega@4"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite@3.0.0-rc8"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@3"></script>
</head>
<body>
<div id="vis"></div>
<script type="text/javascript">
var spec = {json_spec};
var embed_opt = {{"mode": "vega-lite", "renderer": "svg"}};
function showError(el, error){{
el.innerHTML = ('<div class="error">'
+ '<p>JavaScript Error: ' + error.message + '</p>'
+ "<p>This usually means there's a typo in your chart specification. "
+ "See the javascript console for the full traceback.</p>"
+ '</div>');
throw error;
}}
const el = document.getElementById('vis');
vegaEmbed("#vis", spec, embed_opt)
.catch(error => showError(el, error));
</script>
</body>
</html>
""".format(json_spec=altair_spec)
return the html as media
media = anvil.BlobMedia(content_type='text/html', content=html)
return media
An example app (note that you will need the iframe component)
https://anvil.works/build#clone:EKTF2GOLLOTSWKOS=ZIHI6PZRUKESB6GVB4GYV6OJ