我正在尝试创建一个条形图,其中每个条形的上限和下限可以高于或低于零。因此,盒子应该根据数据“浮动”。我还尝试使用pandas.plot
函数,因为它使我的生活在实际应用程序中变得更加轻松。
我设计的解决方案是一个可怕的难题,并且只能部分起作用。基本上,我运行的是两个重叠的不同条形图,其中一个条形为白色以在必要时“隐藏”主条形。我正在使用mask
来标记哪些条应该是哪种颜色。如您所见,这在下面的“伦敦”和“巴黎”示例中可以正常运行,但是在“东京”中却无法正常工作,因为绿色条位于白色条的“前面”。
我可以通过一些我可以想到的方式手动修复此问题,但这会使本来就笨拙的解决方案更加糟糕。我敢肯定,有一种更好的方法让我不够聪明以至于无法想到!
这是情节,下面是完整代码。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df_data = {'Category':['London', 'Paris', 'New York', 'Tokyo'],
'Upper':[10, 5, 0, -5],
'Lower':[5, -5, -10, -10]}
df = pd.DataFrame(data = df_data)
#Color corrector
u_mask = df['Upper'] < 0
d_mask = df['Lower'] < 0
n = len(df)
uca = ['darkgreen' for i in range(n)]
uca = np.array(uca)
uc = uca.copy()
uc[u_mask] = 'white'
dca = ['white' for i in range(n)]
dca = np.array(dca, dtype=uca.dtype)
dc = dca.copy()
dc[d_mask] = 'darkgreen'
(df.plot(kind='bar', y='Upper', x='Category',
color=uc, legend=False))
ax = plt.gca()
(df.plot(kind='bar', y='Lower', x='Category',
color=dc, legend=False, ax=ax))
plt.axhline(0, color='black')
x_axis = ax.xaxis
x_axis.label.set_visible(False)
plt.subplots_adjust(left=0.1,right=0.90,bottom=0.2,top=0.90)
plt.show()
答案 0 :(得分:2)
要通过熊猫创建图,可以创建一个额外的高度列。并使用df.plot(..., y=df['Height'], bottom=df['Lower'])
:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
df_data = {'Category': ['London', 'Paris', 'New York', 'Tokyo'],
'Upper': [10, 5, 0, -5],
'Lower': [5, -5, -10, -10]}
df = pd.DataFrame(data=df_data)
df['Height'] = df['Upper'] - df['Lower']
ax = df.plot(kind='bar', y='Height', x='Category', bottom=df['Lower'],
color='darkgreen', legend=False)
ax.axhline(0, color='black')
plt.tight_layout()
plt.show()
PS:请注意,熊猫条状图迫使下部的ylim呈“粘性”。当所有值均为正值且竖线牢固地立在y=0
上时,这是理想的行为。但是,当同时涉及正值和负值时,这种行为会分散注意力。
要去除粘性:
ax.use_sticky_edges = False # df.plot() makes the lower ylim sticky
ax.autoscale(enable=True, axis='y')
答案 1 :(得分:0)
plt.bar
有一个bottom
参数。您只需要计算高度。这是一个非常简单的示例:
upper = [10, 5, 0, -5]
lower = [5, -5, -10, -10]
height = [upper[i] - lower[i] for i in range(len(upper))]
data = [1,2,3]
plt.bar(range(len(lower)),height, bottom=lower)
plt.show()