4
votes

I'm trying to use Seaborn to present a 1d dataframe as a horizontal bar graph. I would like to shade the bars using the coolwarm palette to reflect their magnitude and direction.

In other words, I'm hoping to generate something like the second example shown here (this is from the Seaborn site), but I want to orient it horizontally:

enter image description here

I've succeeded in turning the graph sideways, but I can't seem to make the palette apply along the horizontal axis as well. My code:

import pandas as pd, seaborn as sns

sns.set()
df = pd.DataFrame([7,-5,-2,1.5,-3],
                  index=['question 1','question 2','question 3','question 4','question 5'],
                  columns=['t'])
sns.barplot(data=    df,
            x=       't', 
            y=       df.index,
            palette= 'coolwarm') 

The output:

output

I'd like it to go from blue to red as you move from left to right (instead of top to bottom).

3

3 Answers

4
votes

Seaborn does not perform any true colormapping. So if that is desiered, one would need to do it externally. In the following, each bar gets its color from a colormap according to its magnitude.

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

sns.set()
df = pd.DataFrame([7,-5,-2,1.5,-3],
                  index=['question 1','question 2','question 3','question 4','question 5'],
                  columns=['t'])

absmax = np.abs(df["t"].values).max()
norm = plt.Normalize(-absmax, absmax)
cmap = plt.get_cmap("coolwarm")
colors = cmap(norm(df["t"].values))
plt.barh("index", "t", data=df.reset_index(), color=colors)

plt.colorbar(plt.cm.ScalarMappable(norm, cmap))

plt.gca().invert_yaxis()
plt.tight_layout()
plt.show()

enter image description here

3
votes

If you don't mind having the questions in order of increasing value, you can do the following:

df2 = df.sort_values('t')

sns.barplot(data=df2,
            x='t',
            y=df2.index
            palette='coolwarm_r')

Which should yield:

enter image description here

If you want to leave your questions in their original order, you can specify a custom palette (list of RGBA values) for sns.barplot using the palette kwarg:

val_order = df['t'].rank(method='max').astype(int) # rank ordered values in column 't'
val_index = val_order - 1 # convert for use as a list index
colors = sns.color_palette('coolwarm_r', len(df.index)) # list of N colors spaced along coolwarm
palette = [colors[x] for x in val_index] # re-order colors with increasing value of 't'

sns.barplot(data=df, x='t', y=df.index, palette=palette)

Yielding:

enter image description here

After making the images I realized I accidentally used coolwarm_r instead of coolwarm. Adding the _r suffix will use a reversed colormap. Oh well.

1
votes

This is going to be an extremely late reply, however...

The easiest way would be to set the hue argument as the column you wish to set as an axis for coloring:

sns.barplot(data=df,x='t',y=df.index,palette='coolwarm', hue='t', dodge=False)

It's crucial to set dodge to True since you'll get extremely thin, line-like boxes otherwise.

And you'll get this kind of output:

Output