Friday 9 July 2021

How to put fraction labels in normalized bar chart in Altair?

import altair as alt
from vega_datasets import data

# get iris dataset and take 120 observations from it
source = data.iris()[10:130]
# add one more feature to dataset
colors = ['red', 'orange', 'blue', 'red'] * 30
source['colors'] = colors

chart = alt.Chart(source).mark_bar().encode(
    alt.Y('species:N', sort='x'),
    alt.X('count():Q', stack='zero'),
    color=alt.Color('colors', sort=colors), 
    order="colors",
    
)

text = alt.Chart(source).mark_text(dx=-7, dy=3, color='white')\
    .encode(
    alt.Y("species:N", sort='x'),
    alt.X('count():Q', stack="zero"),
    order="colors",
    text=alt.Text('count():Q')
    )

chart + text

Result is bar chart with labels showing count for each 'color' feature

Now I want to normalize this chart and labels should represent fraction of a whole.

import altair as alt
from vega_datasets import data

source = data.iris()[10:130]
colors = ['red', 'orange', 'blue', 'red'] * 30
source['colors'] = colors


chart = alt.Chart(source).mark_bar().encode(
    alt.Y('species:N', sort='x'),
    alt.X('count():Q', stack='normalize'),
    color=alt.Color('colors', sort=colors), 
    order="colors",
    
)

text = alt.Chart(source).mark_text(dx=-7, dy=3, color='white')\
    .encode(
    alt.Y("species:N", sort='x'),
    alt.X('count():Q', stack="normalize"),
    order="colors",
    text=alt.Text('count():Q')
    )

chart + text

Normalized bar chart

So in this example instead of 8, 7, 15 for 1st bar I want to see 0.27, 0.23, 0.5 (rounded to 2 digits after comma). How can I achieve this?

update This is how I managed to progress:

import altair as alt
from vega_datasets import data

source = data.iris()[10:130]
colors = ['red', 'orange', 'blue', 'red'] * 30
sort_order=['blue', 'orange', 'red']
source['colors'] = colors

chart = alt.Chart(source).mark_bar().encode(
    alt.Y('species:N', sort='x'),
    alt.X('count():Q', stack='normalize'),
    color=alt.Color('colors', sort=sort_order), 
    order = 'colors'
)

text = alt.Chart(source).transform_aggregate(count='count()', groupby=['species', 'colors'])\
    .transform_joinaggregate(total='sum(count)', groupby=["species"])\
    .transform_calculate(frac=alt.datum.count / alt.datum.total)\
    .mark_text(align='right', dx=-7, dy=3, color='white')\
    .encode(
    alt.Y("species:N", sort='x'),
    alt.X('count():Q', stack="normalize"),
    text=alt.Text('frac:Q', format='.0%'),
    order = 'colors'
    )

chart + text

enter image description here

But labels are not aligned correctly (I need them to be just at the end of each color, just how in first two pictures). Any ideas how to fix it?



from How to put fraction labels in normalized bar chart in Altair?

No comments:

Post a Comment