You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Random.sample为broken bar设置hatch图案填充失效问题排查

分段水平条形图(broken barh)图案填充不显示的问题解决

我希望为每个分段水平条形图(broken barh)从预定义集合中随机选取不同的图案填充(hatch),但代码中使用facecolors=random.sample(colors, k=bc)能正常设置随机颜色,使用hatch=random.sample(hatches, k=bc)时图案却不显示。以下是完整代码:

import matplotlib.pyplot as plt
import pandas as pd
import random

result = pd.DataFrame([['Bill', 1972, 1974],
                       ['Bill', 1976, 1978],
                       ['Bill', 1967, 1971],
                       ['Danny', 1969, 1975],
                       ['Danny', 1976, 1977],
                       ['James', 1971, 1972],
                       ['Marshall', 1967, 1975]],
                      columns=['Person', 'Year_start', 'Year_left']).\
    sort_values(['Year_start', 'Year_left'], ascending=[True, True]).\
    reset_index(drop=True)

fig, ax = plt.subplots()

height = 0.5
names = []
colors = ['tab:blue', 'tab:green', 'tab:red', 'yellow', 'brown', 'black', 'tab:orange', 'aquamarine']
hatches = ['/', 'o', '+', '-', '*', 'O', 'x', 'X', '|']

bc = result.groupby('Person')['Person'].count().max()
# this is broken barh's max count in this dataframe that will be used further in loop (in order to avoid using constants)
print(bc)

for y, (name, g) in enumerate(result.groupby('Person', sort=False)):
    ax.broken_barh(list(zip(g['Year_start'],
                            g['Year_left'] - g['Year_start'])),
                   (y - height / 2, height),
                   facecolors=random.sample(colors, k=bc),
                   hatch=random.sample(hatches, k=bc)
                   )
    names.append(name)
ax.set_ylim(0 - height, len(names) - 1 + height)
ax.set_xlim(result['Year_start'].min() - 1, result['Year_left'].max() + 1)
ax.set_yticks(range(len(names)), names)
ax.set_yticklabels(names)

print(result)

ax.grid(True)
plt.show()

问题原因

Matplotlib的broken_barh方法中,hatch参数不支持传入列表为每个分段单独设置图案,它只能接受单个字符串作为全局图案,这和支持列表格式的facecolors参数逻辑不同。直接传入列表会被方法忽略,导致图案无法显示。

解决方法

需要手动为每个分段的条形图单独设置hatch,有两种可行实现方式:

方式1:逐个绘制分段并指定hatch

循环遍历每个人员的分段数据,单独调用broken_barh绘制每个分段,同时为其分配随机hatch:

import matplotlib.pyplot as plt
import pandas as pd
import random

result = pd.DataFrame([['Bill', 1972, 1974],
                       ['Bill', 1976, 1978],
                       ['Bill', 1967, 1971],
                       ['Danny', 1969, 1975],
                       ['Danny', 1976, 1977],
                       ['James', 1971, 1972],
                       ['Marshall', 1967, 1975]],
                      columns=['Person', 'Year_start', 'Year_left']).\
    sort_values(['Year_start', 'Year_left'], ascending=[True, True]).\
    reset_index(drop=True)

fig, ax = plt.subplots()

height = 0.5
names = []
colors = ['tab:blue', 'tab:green', 'tab:red', 'yellow', 'brown', 'black', 'tab:orange', 'aquamarine']
hatches = ['/', 'o', '+', '-', '*', 'O', 'x', 'X', '|']

for y, (name, g) in enumerate(result.groupby('Person', sort=False)):
    # 为当前人员的每个分段随机选取颜色和hatch
    seg_colors = random.sample(colors, k=len(g))
    seg_hatches = random.sample(hatches, k=len(g))
    
    # 逐个绘制分段条形图
    for start, duration, color, hatch in zip(g['Year_start'], 
                                             g['Year_left'] - g['Year_start'],
                                             seg_colors, seg_hatches):
        ax.broken_barh([(start, duration)], 
                       (y - height / 2, height),
                       facecolors=color,
                       hatch=hatch)
    names.append(name)

ax.set_ylim(0 - height, len(names) - 1 + height)
ax.set_xlim(result['Year_start'].min() - 1, result['Year_left'].max() + 1)
ax.set_yticks(range(len(names)), names)

ax.grid(True)
plt.show()

方式2:获取补丁对象后批量设置hatch

先绘制所有分段,再获取返回的补丁(Patch)对象,逐个为其设置hatch:

# 仅修改循环部分,其余代码不变
for y, (name, g) in enumerate(result.groupby('Person', sort=False)):
    # 绘制当前人员的所有分段,获取补丁对象
    bars = ax.broken_barh(list(zip(g['Year_start'],
                                   g['Year_left'] - g['Year_start'])),
                          (y - height / 2, height),
                          facecolors=random.sample(colors, k=len(g)))
    # 为每个分段分配随机hatch
    seg_hatches = random.sample(hatches, k=len(g))
    for bar, hatch in zip(bars, seg_hatches):
        bar.set_hatch(hatch)
    names.append(name)

关键说明

  • 两种方法都确保每个分段能单独分配随机hatch;
  • 注意random.sample的k值要与当前人员的分段数一致,而非全局最大值bc,避免出现资源浪费或不足的情况;
  • 修改后即可实现每个分段条形图使用不同的随机图案填充,效果与颜色的随机分配逻辑一致。

内容的提问来源于stack exchange,提问作者muted_buddy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 17:17:56