altair icon indicating copy to clipboard operation
altair copied to clipboard

Add a method to always return the long/most verbose version of a chart spec

Open joelostblom opened this issue 4 years ago • 3 comments
trafficstars

To test that the correct chart was created, (e.g. in a student assignment), it would be quite useful it if was possible to convert a chart to the most verbose version of the vega spec. For example, using mark_point() will set chart.mark to 'point', whereas using mark_point(opacity=0.5) will instead set chart.mark to a dictionary and chart.mark.type to "point". For writing tests for autograding, it would be helpful is there was a method that always returned the long dictionary version (and maybe there is and I missed it).

joelostblom avatar Oct 23 '21 19:10 joelostblom

Can you clarify what you mean by "the most verbose"? For example, if you have something like

chart.encode(x='x')

do you want the result to look something like this?

spec = {'encoding': {'x': {'field': 'x', 'type': 'quantitative', 'axis': {}, 'scale': {'bins': {}, ...}, ...}}}

jakevdp avatar Oct 24 '21 13:10 jakevdp

I was mainly thinking about being able to always return a dictionary with the existing properties/keys so that chart.mark would return MarkDef({type: 'point'}) rather than just 'point'. The advantage would be that this would allow me to always check the type key in the dict regardless of whether students just used an empty mark_point() or specified some additional properties such as opacity etc.

I didn't think of that all the empty keys could also be included as you brought up, and I agree that this would actually be the "most verbose" version. I think for my purposes, either of these implementation would be a great help. The more verbose one with all the empty keys would avoid key errors in the tests, but the way our autograding works a key error would result in the same type of test failure as if the key value does not match the expected value, so either one is fine for my purposes here.

joelostblom avatar Oct 24 '21 16:10 joelostblom

Thanks - I think the closest thing to getting this kind of verbose specification would be to do a to_dict/from_dict round-trip. This would wrap each entry in the associated schema class; e.g.

import altair as alt
chart = alt.Chart('data.txt').mark_point().encode(x='x:Q')
print(chart.mark)
# 'point'

chart2 = alt.Chart.from_dict(chart.to_dict())
print(chart2.mark)
# Mark('point')

This doesn't expand Mark('point') to Mark({'type': 'point'}), but I'm not sure there is any way to do this automatically with the information available to Altair: nothing exists in the vega-lite schema to indicate that these two are treated equivalently by the renderer.

jakevdp avatar Oct 24 '21 17:10 jakevdp