I have an interactive plot in altair
/vega
where I can select points and I see a pie chart with the ratio of the colors of the selected points.
import altair as alt
import numpy as np
import polars as pl
selection = alt.selection_interval(encodings=["x"])
base = (
alt.Chart(
pl.DataFrame(
{
"x": list(np.random.rand(100)),
"y": list(np.random.rand(100)),
"class": list(np.random.choice(["A", "B"], 100)),
}
)
)
.mark_point(filled=True)
.encode(
color=alt.condition(
selection, alt.Color("class:N"), alt.value("lightgray")
),
)
.add_params(selection)
)
alt.hconcat(
base.encode(x="x:Q", y="y:Q"),
(
base.transform_filter(selection)
.mark_arc()
.encode(theta="count()", color="class:N")
),
)
Now I'd like to add two more charts that show the ratio of selected / unselected points for each color. I.e. one pie chart that is orange / gray and one pie chart that is blue / gray with ratios depending on the number of selected points.
I tried to use the selection like this
(
base.mark_arc().encode(
theta="count()",
color=alt.condition(
selection, alt.Color("class:N"), alt.value("gray")
),
row="class:N",
)
),
But it's not what I want:
What's the best way to add the pie charts I want?
There might be an easier way to do this, but the following works:
alt.hconcat(
base.encode(x="x:Q", y="y:Q"),
(
base.mark_arc(theta=4)
.transform_joinaggregate(class_total='count()', groupby=['class'])
.transform_filter(selection)
# Including class_total in the groupby just so that column is not dropped since we need it in the calculate
.transform_aggregate(count_after_filter='count()', groupby=['class', 'class_total'])
.transform_calculate(proportion_selected=alt.datum.count_after_filter / alt.datum.class_total)
.encode(
# Setting the domain to reflect that we computed a proportion
theta=alt.Theta('proportion_selected:Q').scale(domain=(0, 1)),
row='class',
color='class'
# tooltip='proportion_selected:Q'
)
)
)
Together with your initial chart, this could make for an interesting gallery example if you want to create a PR.
For a grey background, I think you would have to layer with a completely filled in grey chart, similar to this layered histogram here https://altair-viz.github.io/gallery/interval_selection_map_quakes.html (should just be alt.Chart().mark_arc(color='lightgrey')