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
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
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
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?
You can use a series of joinaggregate and calculate transforms to compute the values you wish to display. You can use the format
text property to adjust the format using a d3-format string, and the align
mark property to adjust the alignment. For example:
import altair as alt
from vega_datasets import data
source = data.iris()[10:130]
colors = ['red', 'orange', 'blue', 'red'] * 30
source['colors'] = colors
sort_order=['blue', 'orange', 'red']
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 = chart.transform_joinaggregate(
count='count()',
groupby=['species', 'colors']
).transform_joinaggregate(
total='count()',
groupby=['species']
).transform_calculate(
fraction='datum.count / datum.total'
).mark_text(
dx=-7, dy=3, align='right'
).encode(
color=alt.ColorValue('white'),
text=alt.Text('fraction:Q', format='.2')
)
chart + text
(Note: I also made the script a bit more concise by sharing the data and encodings between the two charts)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.