具有两个y轴的Seaborn条形图

时间:2018-08-16 17:15:17

标签: python-3.x pandas matplotlib seaborn

考虑以下熊猫DataFrame:

          labels  values_a  values_b  values_x  values_y
  0       date1      1         3        150       170
  1       date2      2         6        200       180

使用Seaborn进行绘制很容易(请参见下面的示例代码)。但是,由于values_a / values_b与values_x / values_y之间存在很大差异,values_a和values_b的条形不容易看到(实际上,以上给出的数据集只是一个示例,在我的实际数据集中,差异甚至更大)。因此,我想使用两个y轴,即,一个y轴用于values_a / values_b,一个y轴用于values_x / values_y。我尝试使用plt.twinx()获得第二条轴,但不幸的是,即使至少有两个具有正确缩放比例的y轴,该图也仅显示了value_x和values_y的两个条形。 :)您是否知道如何解决该问题,并为每个标签获得四个条形,而values_a / values_b条形与左侧y轴相关,而values_x / values_y条形与右侧y轴相关?

谢谢!

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

columns = ["labels", "values_a", "values_b", "values_x", "values_y"]
test_data = pd.DataFrame.from_records([("date1", 1, 3, 150, 170),\
                                       ("date2", 2, 6, 200, 180)],\
                                       columns=columns)

# working example but with unreadable values_a and values_b
test_data_melted = pd.melt(test_data, id_vars=columns[0],\
                           var_name="source", value_name="value_numbers")
g = sns.barplot(x=columns[0], y="value_numbers", hue="source",\
                data=test_data_melted)
plt.show()

# values_a and values_b are not displayed
values1_melted = pd.melt(test_data, id_vars=columns[0],\
                         value_vars=["values_a", "values_b"],\
                         var_name="source1", value_name="value_numbers1")
values2_melted = pd.melt(test_data, id_vars=columns[0],\
                         value_vars=["values_x", "values_y"],\
                         var_name="source2", value_name="value_numbers2")
g1 = sns.barplot(x=columns[0], y="value_numbers1", hue="source1",\
                 data=values1_melted)
ax2 = plt.twinx()
g2 = sns.barplot(x=columns[0], y="value_numbers2", hue="source2",\
                 data=values2_melted, ax=ax2)
plt.show()

Working example values_a/values_b missing

1 个答案:

答案 0 :(得分:4)

这可能最适合于多个子图,但是如果您确实是在单个图上进行设置,则可以在绘制之前缩放数据,创建另一个轴,然后修改刻度值。

样本数据

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

columns = ["labels", "values_a", "values_b", "values_x", "values_y"]
test_data = pd.DataFrame.from_records([("date1", 1, 3, 150, 170),\
                                       ("date2", 2, 6, 200, 180)],\
                                       columns=columns)

test_data_melted = pd.melt(test_data, id_vars=columns[0],\
                           var_name="source", value_name="value_numbers")

代码:

# Scale the data, just a simple example of how you might determine the scaling
mask = test_data_melted.source.isin(['values_a', 'values_b'])
scale = int(test_data_melted[~mask].value_numbers.mean()
            /test_data_melted[mask].value_numbers.mean())
test_data_melted.loc[mask, 'value_numbers'] = test_data_melted.loc[mask, 'value_numbers']*scale

# Plot
fig, ax1 = plt.subplots()
g = sns.barplot(x=columns[0], y="value_numbers", hue="source",\
                data=test_data_melted, ax=ax1)

# Create a second y-axis with the scaled ticks
ax1.set_ylabel('X and Y')
ax2 = ax1.twinx()

# Ensure ticks occur at the same positions, then modify labels
ax2.set_ylim(ax1.get_ylim())
ax2.set_yticklabels(np.round(ax1.get_yticks()/scale,1))
ax2.set_ylabel('A and B')

plt.show()

enter image description here