如何为条形图添加组标签
- 2024-12-23 08:43:00
- admin 原创
- 71
问题描述:
我想使用 matplotlib 条形图绘制以下形式的数据:
data = {'Room A':
{'Shelf 1':
{'Milk': 10,
'Water': 20},
'Shelf 2':
{'Sugar': 5,
'Honey': 6}
},
'Room B':
{'Shelf 1':
{'Wheat': 4,
'Corn': 7},
'Shelf 2':
{'Chicken': 2,
'Cow': 1}
}
}
条形图应该看起来
条形组应该从 x 轴上的标签可见。有没有办法用 matplotlib 做到这一点?
解决方案 1:
由于我在 matplotlib 中找不到此问题的内置解决方案,因此我编写了自己的代码:
#!/usr/bin/env python
from matplotlib import pyplot as plt
def mk_groups(data):
try:
newdata = data.items()
except:
return
thisgroup = []
groups = []
for key, value in newdata:
newgroups = mk_groups(value)
if newgroups is None:
thisgroup.append((key, value))
else:
thisgroup.append((key, len(newgroups[-1])))
if groups:
groups = [g + n for n, g in zip(newgroups, groups)]
else:
groups = newgroups
return [thisgroup] + groups
def add_line(ax, xpos, ypos):
line = plt.Line2D([xpos, xpos], [ypos + .1, ypos],
transform=ax.transAxes, color='black')
line.set_clip_on(False)
ax.add_line(line)
def label_group_bar(ax, data):
groups = mk_groups(data)
xy = groups.pop()
x, y = zip(*xy)
ly = len(y)
xticks = range(1, ly + 1)
ax.bar(xticks, y, align='center')
ax.set_xticks(xticks)
ax.set_xticklabels(x)
ax.set_xlim(.5, ly + .5)
ax.yaxis.grid(True)
scale = 1. / ly
for pos in xrange(ly + 1): # change xrange to range for python3
add_line(ax, pos * scale, -.1)
ypos = -.2
while groups:
group = groups.pop()
pos = 0
for label, rpos in group:
lxpos = (pos + .5 * rpos) * scale
ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes)
add_line(ax, pos * scale, ypos)
pos += rpos
add_line(ax, pos * scale, ypos)
ypos -= .1
if __name__ == '__main__':
data = {'Room A':
{'Shelf 1':
{'Milk': 10,
'Water': 20},
'Shelf 2':
{'Sugar': 5,
'Honey': 6}
},
'Room B':
{'Shelf 1':
{'Wheat': 4,
'Corn': 7},
'Shelf 2':
{'Chicken': 2,
'Cow': 1}
}
}
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
label_group_bar(ax, data)
fig.subplots_adjust(bottom=0.3)
fig.savefig('label_group_bar_example.png')
该mk_groups
函数接受一个字典(或任何带有 items() 方法的内容,如collections.OrderedDict
),并将其转换为数据格式,然后用于创建图表。它基本上是一个以下形式的列表:
[ [(label, bars_to_span), ...], ..., [(tick_label, bar_value), ...] ]
该add_line
函数在子图中的指定位置(轴坐标)创建一条垂直线。
该label_group_bar
函数采用字典并在子图中创建条形图,并在下方添加标签。示例结果如下所示。
仍然非常感谢更简单或更好的解决方案和建议。
解决方案 2:
我找这个解决方案已经有一段时间了。我修改了一些以使其适用于 pandas 数据表。分享一下才公平。
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
from itertools import groupby
def test_table():
data_table = pd.DataFrame({'Room':['Room A']*4 + ['Room B']*4,
'Shelf':(['Shelf 1']*2 + ['Shelf 2']*2)*2,
'Staple':['Milk','Water','Sugar','Honey','Wheat','Corn','Chicken','Cow'],
'Quantity':[10,20,5,6,4,7,2,1],
'Ordered':np.random.randint(0,10,8)
})
return data_table
def add_line(ax, xpos, ypos):
line = plt.Line2D([xpos, xpos], [ypos + .1, ypos],
transform=ax.transAxes, color='black')
line.set_clip_on(False)
ax.add_line(line)
def label_len(my_index,level):
labels = my_index.get_level_values(level)
return [(k, sum(1 for i in g)) for k,g in groupby(labels)]
def label_group_bar_table(ax, df):
ypos = -.1
scale = 1./df.index.size
for level in range(df.index.nlevels)[::-1]:
pos = 0
for label, rpos in label_len(df.index,level):
lxpos = (pos + .5 * rpos)*scale
ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes)
add_line(ax, pos*scale, ypos)
pos += rpos
add_line(ax, pos*scale , ypos)
ypos -= .1
df = test_table().groupby(['Room','Shelf','Staple']).sum()
fig = plt.figure()
ax = fig.add_subplot(111)
df.plot(kind='bar',stacked=True,ax=fig.gca())
#Below 3 lines remove default labels
labels = ['' for item in ax.get_xticklabels()]
ax.set_xticklabels(labels)
ax.set_xlabel('')
label_group_bar_table(ax, df)
fig.subplots_adjust(bottom=.1*df.index.nlevels)
plt.show()
解决方案 3:
自 Matplotlib v3.1 起,secondary_xaxis方法可用于在不同级别创建额外刻度。以下内容改编自最近添加到 Matplotlib 文档中的此示例。
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
foods = ['Milk', 'Water', 'Sugar', 'Honey', 'Wheat', 'Corn', 'Chicken', 'Cow']
totals = [10, 20, 5, 6, 4, 7, 2, 1]
fig, ax = plt.subplots(layout='constrained')
# Plot the main data.
ax.bar(foods, totals)
ax.grid(axis='y')
ax.yaxis.set_major_locator(mticker.MultipleLocator(5))
ax.tick_params('x', length=0)
ax.set_xlim(-0.5, 7.5)
# Add ticks and labels for the shelves.
shelf_ax = ax.secondary_xaxis(location=0)
shelf_ax.set_xticks([i * 2 + 0.5 for i in range(4)], labels=['Shelf 1', 'Shelf 2'] * 2)
shelf_ax.tick_params('x', length=15)
# Add ticks and labels for the rooms.
room_ax = ax.secondary_xaxis(location=0)
room_ax.set_xticks([1.5, 5.5], labels=['Room A', 'Room B'])
room_ax.tick_params('x', length=25)
# Long ticks with no labels to separate the rooms.
room_sep_ax = ax.secondary_xaxis(location=0)
room_sep_ax.set_xticks([-0.5, 3.5, 7.5], ['', '', ''])
room_sep_ax.tick_params('x', length=40)
plt.show()
相关推荐
热门文章
项目管理软件有哪些?
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
热门标签
云禅道AD