Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Controlling stack-order of an altair area

Tags:

python

altair

I've got a mark_area chart that is stacking in an apparently-nonsensical order. I'd prefer to order the layers with the biggest on the bottom, and decreasing above.

Here is a picture of the graph, labelled with the preferred order:

enter image description here

I tried to make a toy-example:

import random
import altair as alt

seed = {"date": pd.date_range('1/1/2019',periods=20,freq="M"),
        "jack": random.sample(range(100, 500), 20), 
        "roy":random.sample(range(20, 90), 20),
        "bill":random.sample(range(600, 900), 20), 
        }

df = pd.DataFrame.from_dict(seed)
df = df.melt(id_vars="date", var_name="person", value_name="measure")
alt.renderers.enable('notebook')
alt.Chart(df).mark_area().encode(
                        x=alt.X(
                            'date',                        
                        ),
                        y=alt.Y(
                            'measure',
                        ),
                        color='person',                                                                               
                )

This automatically produces the chart like:

enter image description here

I tried to reuse some incantations found elsewhere, but they silently have no effect. There is no difference whether I use 'ascending' or 'descending':

alt.Chart(df).mark_area().encode(
                        x=alt.X(
                            'date',                        
                        ),
                        y=alt.Y(
                            'measure',
                             sort=alt.EncodingSortField(
                                field="measure",
                                op="sum",
                                order="ascending")  
                        ),
                        color='person',                                                                               
                )
like image 250
user3556757 Avatar asked Apr 16 '19 04:04

user3556757


1 Answers

You can use the order channel to control the stack order. For example:

import random
import altair as alt
import pandas as pd

df = pd.DataFrame({
    "date": pd.date_range('1/1/2019',periods=20,freq="M"),
    "jack": random.sample(range(100, 500), 20), 
    "roy":random.sample(range(20, 90), 20),
    "bill":random.sample(range(600, 900), 20), 
})
df = df.melt(id_vars="date", var_name="person", value_name="measure")
alt.Chart(df).mark_area().encode(
    x='date',       
    y='measure',
    color='person',
    order=alt.Order('sum(measure):Q', sort='descending')
)

enter image description here


Edit: if the rank is not consistent, you can use a joinaggregate transform to define a uniform order across the chart. For example:

import random
import altair as alt
import pandas as pd

df = pd.DataFrame({
    "date": pd.date_range('1/1/2019',periods=20,freq="M"),
    "jack": random.sample(range(100, 500), 20), 
    "roy":random.sample(range(20, 200), 20),
    "bill":random.sample(range(600, 900), 20), 
})
df = df.melt(id_vars="date", var_name="person", value_name="measure")

alt.Chart(df).transform_joinaggregate(
    order='sum(measure)',
    groupby=['person']
).mark_area().encode(
    x='date',       
    y='measure',
    color='person',
    order=alt.Order('order:Q', sort='descending')
)

enter image description here

like image 82
jakevdp Avatar answered Oct 17 '22 07:10

jakevdp