最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How to set multiple conditions for color in Altair 5.5 using alt.when().then().otherwise()? - Stack Overflow

programmeradmin1浏览0评论

How can I set multiple conditions for colours of a bar chart? Specifically, I want the color scheme for values < 0 to be "reds", values > 0 to "lightgray" and the "Gold" name to be "goldenrod" color. I am using Altair 5.5.

Here is what I have tried:

np.random.seed(1)
test = pd.DataFrame(
    {
        'Name': ['Cat_A', 'Cat_B', 'Cat_C', 'Cat_D', 'Gold'],
        'Value': np.random.randint(-10,10,5),
    },
).sort_values(by='Value', ascending=False).reset_index(drop=True).reset_index()
test.rename(columns={'index': 'Rank'}, inplace=True)

color = (
    alt.when(alt.datum.Value < 0)           # check if Value < 0
    .then(alt.Color("Rank:O").scale(scheme='reds').legend(None)) # then 'reds'
    #.when(alt.datum.Name == 'Gold')        # check if Name is 'Gold'
    #.then(alt.value('goldenrod'))          # If true, use 'goldenrod'
    .otherwise(alt.value('lightgray'))      # Default color if neither is true
)
alt.Chart(test).mark_bar(tooltip=True).encode(
    x=alt.X('Value:Q').title('Change in Score'),
    y=alt.Y('Name:N', sort=test['Name'].to_list()).title(None),
    color=color
)

I can only get two conditions to work, and not the "goldenrod" color (which I have commented out above in order to get this):

How can I set multiple conditions for colours of a bar chart? Specifically, I want the color scheme for values < 0 to be "reds", values > 0 to "lightgray" and the "Gold" name to be "goldenrod" color. I am using Altair 5.5.

Here is what I have tried:

np.random.seed(1)
test = pd.DataFrame(
    {
        'Name': ['Cat_A', 'Cat_B', 'Cat_C', 'Cat_D', 'Gold'],
        'Value': np.random.randint(-10,10,5),
    },
).sort_values(by='Value', ascending=False).reset_index(drop=True).reset_index()
test.rename(columns={'index': 'Rank'}, inplace=True)

color = (
    alt.when(alt.datum.Value < 0)           # check if Value < 0
    .then(alt.Color("Rank:O").scale(scheme='reds').legend(None)) # then 'reds'
    #.when(alt.datum.Name == 'Gold')        # check if Name is 'Gold'
    #.then(alt.value('goldenrod'))          # If true, use 'goldenrod'
    .otherwise(alt.value('lightgray'))      # Default color if neither is true
)
alt.Chart(test).mark_bar(tooltip=True).encode(
    x=alt.X('Value:Q').title('Change in Score'),
    y=alt.Y('Name:N', sort=test['Name'].to_list()).title(None),
    color=color
)

I can only get two conditions to work, and not the "goldenrod" color (which I have commented out above in order to get this):

Share Improve this question asked Feb 21 at 4:44 footfalconfootfalcon 6417 silver badges18 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

I believe the basic usage of chaining when().then() multiple times is that it implies a priority: i.e. the FIRST when() that is true will take effect.

In the example shown here, "Gold" has a value < 0, and therefore (were it not commented) it would still trigger the first when() and be colored with the Reds scale, and this plot would look the same as it does now.

On the other hand, if name=="Gold" was the first when().then(), I think you would get the result you want.

-- UPDATE --

I'm just coming back to Altair ver 5+, and it seems the new when().then() syntax does not like mixing in alt.Color() encodings, and returns an error for me "TypeError: Chained conditions cannot be mixed with field conditions."

So instead, here's an old school hacky way of doing it. Still works, I tested it this time:

condition1 = alt.condition(alt.datum.Name == 'Gold', alt.value('goldenrod'), alt.Color("Rank:O").scale(scheme='reds').legend(None))
condition2 = alt.condition(alt.datum.Value >= 0, alt.value('lightgray'), alt.Color("Rank:O").scale(scheme='reds').legend(None))
combined_condition = condition1.copy()
combined_condition['condition'] = [condition1['condition'], condition2['condition']]


alt.Chart(test).mark_bar(tooltip=True).encode(
    x=alt.X('Value:Q').title('Change in Score'),
    y=alt.Y('Name:N', sort=test['Name'].to_list()).title(None),
    color=combined_condition
)

Is cobbling together two alt.condition()s elegant? Nope, but I hope this helps. It might break with small variations because I don't know if this hack is intended, but it works for this example.

发布评论

评论列表(0)

  1. 暂无评论