vega-lite
vega-lite copied to clipboard
Composing cartesian and polar coordinates
I was exploring some of the ideas outlined in this comment: https://github.com/vega/vega-lite/issues/408#issuecomment-500184377
I wanted to attempt a basic scatter chart in which each point is represented by a pie chart. Here's my basic attempt (open in editor):
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"category": 1, "value": 4, "x": 1, "y": 2},
{"category": 2, "value": 6, "x": 1, "y": 2},
{"category": 3, "value": 10, "x": 1, "y": 2},
{"category": 4, "value": 3, "x": 1, "y": 2},
{"category": 5, "value": 7, "x": 1, "y": 2},
{"category": 6, "value": 8, "x": 1, "y": 2},
{"category": 1, "value": 4, "x": 2, "y": 1},
{"category": 2, "value": 6, "x": 2, "y": 1},
{"category": 3, "value": 10, "x": 2, "y": 1},
{"category": 4, "value": 3, "x": 2, "y": 1},
{"category": 5, "value": 7, "x": 2, "y": 1},
{"category": 6, "value": 8, "x": 2, "y": 1}
]
},
"mark": {"type": "arc", "radius": 15},
"encoding": {
"x": {"field": "x", "type": "quantitative", "scale": {"domain": [0, 3]}},
"y": {"field": "y", "type": "quantitative", "scale": {"domain": [0, 3]}},
"theta": {"field": "value", "type": "quantitative"},
"color": {"field": "category", "type": "nominal"},
"detail": [{"field": "x"}, {"field": "y"}]
}
}
It's almost what I want, but the extents of each mark are computed from the whole dataset rather than from the in-group values. Is there an easy way to make the arc mark extents respect the grouping implied by the x
and y
encodings?
I like this direction. I don't have a solution but I think what we need is to facet the data by x and y before computing the scale for theta. Maybe this could be done with faceting into layers (which we don't support right now) and/or an addition to resolve.
@jakevdp How about this for a workaround? Obviously, native support in Vega-Lite would still be preferred for the sake of simplicity but I think these intermediate transforms also achieve your goals.
FYI, I changed some of your values so both pies were not identical.
{
"$schema": "https://vega.github.io/schema/vega-lite/v5.json",
"data": {
"values": [
{"category": 1, "value": 4, "x": 1, "y": 2},
{"category": 2, "value": 6, "x": 1, "y": 2},
{"category": 3, "value": 10, "x": 1, "y": 2},
{"category": 4, "value": 3, "x": 1, "y": 2},
{"category": 5, "value": 7, "x": 1, "y": 2},
{"category": 6, "value": 8, "x": 1, "y": 2},
{"category": 1, "value": 14, "x": 2, "y": 1},
{"category": 2, "value": 16, "x": 2, "y": 1},
{"category": 3, "value": 10, "x": 2, "y": 1},
{"category": 4, "value": 3, "x": 2, "y": 1},
{"category": 5, "value": 7, "x": 2, "y": 1},
{"category": 6, "value": 8, "x": 2, "y": 1}
]
},
"transform": [
{
"window": [{"op": "sum", "field": "value", "as": "total"}],
"frame": [null, null],
"groupby": ["x"]
},
{"calculate": "datum.value/datum.total * 100", "as": "percent"},
{
"stack": "percent",
"offset": "normalize",
"as": ["v1", "v2"],
"groupby": ["x"]
},
{"calculate": "datum.v1 * (2*PI)", "as": "t1"},
{"calculate": "datum.v2* (2*PI)", "as": "t2"}
],
"mark": {
"type": "arc",
"radius": 15,
"theta": {"expr": "datum.t1"},
"theta2": {"expr": "datum.t2"}
},
"encoding": {
"x": {"field": "x", "type": "quantitative", "scale": {"domain": [0, 3]}},
"y": {"field": "y", "type": "quantitative", "scale": {"domain": [0, 3]}},
"color": {"field": "category", "type": "nominal"}
}
}
I think @kanitw was thinking about a simpler way to add normalization to Vega-Lite in general and it would be perfect for this application.
Is there a way to get the area of each circle to be proportional to the sum of "value" fields of each slice that makes up that circle in PB-David's approach? I tried
"mark": {
"type": "arc",
"radius": {
"field": "sqrt_total",
"type": "quantitative"
},
with
{"calculate": "sqrt(datum.total)", "as": "sqrt_total"}
in transform
section but it didn't work.
@aslangencer - you don't need a calculate. Just change the radius to this:
"mark": { "type": "arc", "radius": {"expr": "sqrt(datum.total)"}, "theta": {"expr": "datum.t1"}, "theta2": {"expr": "datum.t2"} },