25
votes

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?

Thanks in advance.

4
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?Akshat Mahajan
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 colorMrPedru22

4 Answers

25
votes

Here a solution:

import numpy as np, matplotlib.pyplot as plt, 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.

9
votes

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
votes

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

1
votes

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