29

I would like to use seaborn bar plot for my data with a color scale according to the values in the Y-axis. For example, from this image, color changes from left to right according to a color palette:

enter image description here

But what I actually wanted is this same color scheme but in "vertical" instead of "horizontal". Is this possible? I've searched and tried to set the hue parameter to the Y-axis but it doesn't seem to work, how can I do it?

2
  • So ... you want all of the bars to have a blue-red colour scale, but with them being coloured blue at the top and gradually changing colour to red at the bottom? Commented Mar 28, 2016 at 21:16
  • 1
    I've edited the question, it's not the color scheme blue-red, but light green to dark green as in the image I've edited. For example, bar C would have the darkest color, and bars with lower values would have a lighter color Commented Mar 28, 2016 at 21:33

5 Answers 5

29

Here a solution:

import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

sns.set(style="whitegrid", color_codes=True)

titanic = sns.load_dataset("titanic")
data = titanic.groupby("deck").size()  # data underlying bar plot in question

pal = sns.color_palette("Greens_d", len(data))
rank = data.argsort().argsort()  # http://stackoverflow.com/a/6266510/1628638
sns.barplot(x=data.index, y=data, palette=np.array(pal[::-1])[rank])

plt.show()

Here the output: bar plot

Note: the code currently assigns different (adjacent) colors to bars with identical height. (Not a problem in the sample plot.) While it would be nicer to use the same color for identical-height bars, the resulting code would likely make the basic idea less clear.

Sign up to request clarification or add additional context in comments.

Comments

13

This solution uses the values as indices into the color palette; so that similar values get similar colors:

import seaborn as sns
import numpy as np


def colors_from_values(values, palette_name):
    # normalize the values to range [0, 1]
    normalized = (values - min(values)) / (max(values) - min(values))
    # convert to indices
    indices = np.round(normalized * (len(values) - 1)).astype(np.int32)
    # use the indices to get the colors
    palette = sns.color_palette(palette_name, len(values))
    return np.array(palette).take(indices, axis=0)


x = np.arange(10)
y = np.random.random(10)
sns.barplot(x, y, palette=colors_from_values(y, "YlOrRd"))

Resulting in:

This

2 Comments

Great solution. This one solves the problem of assigning different (adjacent) colors to bars with identical height.
Thank gods and godnesses! Finally some clean and easy code :-) Thanks!
3

Here a solution:

import seaborn as sns
import numpy as np
import pandas as pd

def colors_from_values(values: pd.Series, palette_name:str, ascending=True):
    '''Returns a seaborn palette reordered by value
    Parameters:
    values: pd.Series
    palette_name:str, Seaborn valid palette name
    ascending: bool, optional color sort order
    '''
    # convert to indices
    values = values.sort_values(ascending=ascending).reset_index()
    indices = values.sort_values(by=values.columns[0]).index
    # use the indices to get the colors
    palette = sns.color_palette(palette_name, len(values))
    return np.array(palette).take(indices, axis=0)

s = pd.Series([123456, 123457, 122345, 95432],
              index=pd.Index([2018, 2019, 2020, 2021], name='Year'))


sns.barplot(x=s.index, y=s.values, palette=colors_from_values(s, "rocket_r"))

Results: Plot

Comments

2

The double usage of the argsort from Ulrich's answer didn't work for me. But this did:

rank = [int((max(array)-elem)*len(df)*0.75/(max(array)+1)) for elem in array] 
pal = sea.color_palette("Reds_r",len(df))

Example seaborn barchart with bar heights according to y values:

mentioned seaborn barchart

2 Comments

@colidyre What is array referring to when setting the rank variable?
@adin this is more a question to molecman - I have only minor edited the answer for readabilty reasons and didn't change the code itself.
-1

The following worked for me

pal = sns.color_palette("YlOrBr", len(df_1))
array = df_1['Count']
rank = [int((max(array)-elem)*len(df_1)*0.75/(max(array)+1)) for elem in array]

sns.barplot(x = df_1.index, y = 'Count', data = df_1, 
palette=np.array(pal[::-1])[rank]);
plt.xticks(rotation = 90)  # rotate the xticks by 90 degree. 
plt.show()

1 Comment

Since this answer does not have any sample data and is not reproducible, it's not very useful.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.