Home > Net >  Nested bar plots with three y axis using seaborn package
Nested bar plots with three y axis using seaborn package

Time:04-30

Using the python seaborn package I was trying to plot the nested bar graphs with three different y-axes as shown in the below figure:

enter image description here

And the code that I have used is :

import matplotlib.pyplot as plt
from matplotlib import rc
import numpy as np
import seaborn as sns
#plt.style.use(['science'])

rc('font', **{'family': 'serif', 'serif': ['Computer Modern']})
rc('text', usetex=True)

HV = [388, 438]
YS = [1070, 1200]
UTS = [1150, 1400]
Z = [15, 12.5]

x = [1, 2]
fig, ax1 = plt.subplots(figsize=(5, 5.5))

colors=sns.color_palette("rocket",4)


ax1 = sns.barplot(x[0],YS[0],color="blue")
ax1 = sns.barplot(x[0],color="blue")

ax1 = sns.barplot(x[1],YS[1],color="blue")
ax1 = sns.barplot(x[1],UTS[1],color="blue")

ax2 = ax1.twinx()
ax2 = sns.barplot(x[0], HV[0],color="green")
ax2 = sns.barplot(x[1], HV[1],color="green")

ax3 = ax1.twinx()
ax3 = sns.barplot(x[0],Z[0],color="red")
ax3 = sns.barplot(x[1],Z[1],color="red")
#ax3.spines['right'].set_position(('outward',60))
ax3.spines['right'].set_position(('axes',1.15))

ax1.set_ylabel("First",color="blue")
ax2.set_ylabel("Second",color="green")
ax3.set_ylabel("Third",color="red")

ax1.tick_params(axis='y',colors="blue")
ax2.tick_params(axis='y',colors="green")
ax3.tick_params(axis='y',colors="red")

ax2.spines['right'].set_color("green")  
ax3.spines['right'].set_color("red")
ax3.spines['left'].set_color("blue")

plt.show()

And I'm getting the following error:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/seaborn/utils.py", line 531, in categorical_order
    order = values.cat.categories
AttributeError: 'int' object has no attribute 'cat'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/seaborn/utils.py", line 534, in categorical_order
    order = values.unique()
AttributeError: 'int' object has no attribute 'unique'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/sspenkulinti/these/thesis_E185_fatigue/test_matrix/E185_properties_AB_HT.py", line 21, in <module>
    ax1 = sns.barplot(x[0],YS[0],color="blue")
  File "/usr/lib/python3/dist-packages/seaborn/categorical.py", line 3147, in barplot
    plotter = _BarPlotter(x, y, hue, data, order, hue_order,
  File "/usr/lib/python3/dist-packages/seaborn/categorical.py", line 1614, in __init__
    self.establish_variables(x, y, hue, data, orient,
  File "/usr/lib/python3/dist-packages/seaborn/categorical.py", line 200, in establish_variables
    group_names = categorical_order(groups, order)
  File "/usr/lib/python3/dist-packages/seaborn/utils.py", line 536, in categorical_order
    order = pd.unique(values)
  File "/usr/lib/python3/dist-packages/pandas/core/algorithms.py", line 395, in unique
    values = _ensure_arraylike(values)
  File "/usr/lib/python3/dist-packages/pandas/core/algorithms.py", line 204, in _ensure_arraylike
    inferred = lib.infer_dtype(values, skipna=False)
  File "pandas/_libs/lib.pyx", line 1251, in pandas._libs.lib.infer_dtype
TypeError: 'int' object is not iterable

CodePudding user response:

The error is because you can't call sns.barplot with a single number as first parameter. The x-values need to be a list.

To get want you want using seaborn, the data needs to be presented as if it comes from a dataframe. hue_order is needed to preserve enough space for each of the bars, even when nothing is plotted there.

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

HV = [388, 438]
YS = [1070, 1200]
UTS = [1150, 1400]
Z = [15, 12.5]

x = ["As built", "200ºC-850ºC"]
names = ['YS', 'UTS', 'HV', 'Z']
fig, ax1 = plt.subplots(figsize=(9, 5.5))

colors = sns.color_palette("tab10", len(names))

sns.barplot(x=x   x, y=YS   UTS, hue=[names[0]] * len(x)   [names[1]] * len(x),
            hue_order=names, palette=colors, alpha=0.7, ax=ax1)
# ax1 will already contain the full legend, the third handle needs to
# be updated to show the hatching
ax1.legend_.legendHandles[2].set_hatch('///')

ax2 = ax1.twinx()
sns.barplot(x=x, y=HV, hue=[names[2]] * len(x), hue_order=names, palette=colors, hatch='//', alpha=0.7, ax=ax2)
ax2.legend_.remove() # seaborn automatically creates a new legend

ax3 = ax1.twinx()
sns.barplot(x=x, y=Z, hue=[names[3]] * len(x), hue_order=names, palette=colors, alpha=0.7, ax=ax3)
ax3.legend_.remove()

ax3.spines['right'].set_position(('axes', 1.15))

ax1.set_ylabel("First", color=colors[0])
ax2.set_ylabel("Second", color=colors[2])
ax3.set_ylabel("Third", color=colors[3])

ax1.tick_params(axis='y', colors=colors[0])
ax2.tick_params(axis='y', colors=colors[2])
ax3.tick_params(axis='y', colors=colors[3])

ax2.spines['right'].set_color(colors[2])
ax3.spines['right'].set_color(colors[3])

plt.tight_layout()
plt.show()

nested sns.barplot with twinx axes

  • Related