Visualization
Embedding Altair charts in the web app
Concepts
- Altair is a Python library that produces Vega-Lite chart specifications as JSON
- the JSON describes what to draw, not how to draw it
- the browser uses the Vega-Embed JavaScript library to render the actual pixels
- The server returns the chart specification as JSON from a dedicated route
- the browser requests it separately from the HTML page (typically via HTMX)
- keeps the page fast and the code organized
- Encoding channels map data fields to visual properties
xandyfor position,colorfor hue,tooltipfor hover text- each channel requires a field name and a data type
(
quantitative,nominal,ordinal,temporal)
- A mount point is an empty
<div>with anid; Vega-Embed finds it by ID and renders the chart inside it- the Vega-Embed script must be loaded before the initialization code runs
- PNG export is performed by Vega-Embed in the browser from the rendered chart
- the exported PNG reflects exactly what the user sees, including any interactive state
Altair in a server context
- Altair generates Vega-Lite JSON, not images
- A route that returns the JSON specification for a chart
Embedding Vega-Lite in a page
- Loading the Vega-Embed script
- A
<div>that receives the spec from the server via HTMX and renders it in the browser
A scatter plot of diameter vs. mutation
- Building the Altair chart from query results
- Encoding channels, color, and tooltip
A bar chart of counts by site
- A second chart type
- Switching between charts with Alpine.js tabs
Exporting charts
- Adding a download button that triggers Vega-Embed's PNG export
- What the LLM produces versus what actually works
Check for Understanding
Why does Altair not produce an image file directly, and what does the browser use to render the chart?
Altair produces a Vega-Lite JSON specification—a description of the chart's data, marks, and encodings. Rendering pixels from that specification requires the Vega-Lite runtime, which runs as JavaScript in the browser. The Vega-Embed library loads the spec, runs the renderer, and inserts an SVG or Canvas element into the page. This separation means the chart can be interactive (zoom, pan, tooltip) without any additional server code.
If you change the data in the database and reload the page, what needs to happen for the chart to update?
The page must make a new request to the chart data route, which queries the database and returns an updated Vega-Lite specification. If the chart spec is loaded once on page load and cached in the browser, it will not update automatically. Using HTMX to fetch the spec on demand (e.g., when the user clicks a "Refresh" button or when the page loads) ensures the chart always reflects the current data.
What does an Altair color encoding do, and how would you use it to distinguish mutated from non-mutated snails?
The color encoding maps a data field to the hue of each mark. To distinguish
mutated from non-mutated snails: color=alt.Color("mutated:N") where :N indicates
a nominal (categorical) field. Altair will automatically assign different colors to
True and False values and add a legend. You can customize the color scheme with
alt.Scale(range=["steelblue", "orange"]).
What is Vega-Embed, and where in the HTML must the script tag loading it appear?
Vega-Embed is a JavaScript library that takes a Vega-Lite JSON specification and a
DOM element, renders the chart, and adds interactive features (tooltips, zoom, export
button). The script tag must appear before any JavaScript that calls vegaEmbed();
placing it in the <head> or at the end of <body> both work, but the call to
vegaEmbed() must run after both the script and the mount-point <div> exist in
the DOM.
Exercises
Add a histogram
Ask the LLM to add a histogram of shell diameters to the visualization page. Before accepting the output, decide: how many bins make sense for the range of values in the data? Does the LLM choose a reasonable bin width? If not, adjust the specification and verify the result looks sensible.
Add rich tooltips
Modify the scatter plot so that hovering over a point shows the site name, survey date, diameter, and mutation status in the tooltip. Implement the Altair encoding yourself first using the Altair documentation, then compare with what the LLM produces.
Compare chart types
Display the count of measurements per site as both a bar chart and a dot plot. Ask the LLM which encoding is more effective for this data and why. Evaluate the reasoning: does it match what you would conclude from looking at both charts?
Test the chart route
Write a pytest test that calls the chart data route and checks that the response
body is valid JSON with at least a mark key and a data key (the minimum required
by Vega-Lite). Do not test the exact values—just that the structure is present and
the status code is 200.