优秀的编程知识分享平台

网站首页 > 技术文章 正文

数据可视化-子弹图(Bullet Chart)

nanyue 2024-10-14 11:32:07 技术文章 7 ℃

子弹图(Bullet Chart)是一种用于绩效评估和目标比较的图表,它结合了条形图和温度计图的特点,旨在替代传统的仪表板图表,如仪表盘(Gauge Charts),因为后者通常过于复杂且信息量不足。本篇是使用Python进行演示,如果需要Excel或者PowerBI实现的,可以参考《Excel子弹图Bullet》《PowerBI_子弹图bullet》


【子弹图的组成部分】

性能条(Performance Bar):这是子弹图的主要部分,通常表示实际的绩效或完成情况。颜色通常为深色,以便与背景和比较条区分开来;

比较条(Comparative Bar or Marker):这些可以是水平线或小条,表示目标值或标准值。它们帮助用户快速比较实际绩效与目标或标准;

定性范围(Qualitative Ranges):这些通常是背景中的不同颜色区域,表示绩效的不同等级或范围。例如,绿色可能表示“优秀”,黄色表示“良好”,红色表示“需要改进”;

刻度标记(Scale Marks):这些是图表上的刻度线,表示量化的度量标准,帮助用户理解绩效条和比较条的具体数值。

【子弹图的优势】

简洁性:子弹图设计简洁,信息密度高,能够在小空间内传达大量信息;

直观性:通过颜色和形状的组合,用户可以快速理解绩效的当前状态和与目标的比较;

多功能性:适用于多种类型的数据和绩效评估,无论是销售目标、生产效率还是其他任何可以量化的指标。

【子弹图的缺点】

复杂性:对于不熟悉此图表类型的用户,初次阅读可能会感到困惑;

颜色依赖:如果颜色选择不当,可能会影响图表的可读性,特别是对于色盲用户;

数据限制:适用于展示少量关键绩效指标,数据量过多时效果不佳。

【应用场景】

子弹图广泛应用于商业智能、绩效管理和报告制作中。例如,销售经理可以使用子弹图来展示销售团队的销售业绩与目标的比较,或者生产经理可以用它来监控生产线的效率。

【案例演示】

我们就是用几个酒类的目标和完成情况来举例,数据格式很简单,就几个值,准备工作如下↓

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import matplotlib.pyplot as plt
sns.set_style("white", {'axes.grid': False})
plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号
# 数据
data = [
    {'实际值': 120, '目标值': 100, '范围': [60, 80, 100], '类别': '白酒'},
    {'实际值': 65, '目标值': 80, '范围': [50, 70, 80], '类别': '啤酒'},
    {'实际值': 90, '目标值': 95, '范围': [70, 85, 95], '类别': '葡萄酒'}
]


然后就直接绘制图形了↓

fig, ax = plt.subplots(figsize=(10, 5))
# 绘制每组数据的子弹图
for i, d in enumerate(data):
    actual_value = d['实际值']
    target_value = d['目标值']
    ranges = d['范围']
    label = d['类别']
    range_colors = ['#ff9999', '#ffcc99', '#99ff99']  # 使用更美观的颜色
    # 绘制定性范围
    for j, (start, color) in enumerate(zip([0] + ranges[:-1], range_colors)):
        ax.barh(i, ranges[j] - start, left=start, height=0.5, color=color, edgecolor='white')
    # 绘制性能条
    ax.barh(i, actual_value, height=0.25, color='#3d7abf', edgecolor='white')
    ax.plot([target_value, target_value], [i - 0.4, i + 0.4], color='red', linewidth=2)
# 设置轴的限制和标签
ax.set_xlim(0, 120)
ax.set_yticks(range(len(data)))
ax.set_yticklabels([d['类别'] for d in data], fontsize=15)
ax.set_xlabel('目标和完成率', fontsize=12)
# 添加标题
ax.set_title('seaborn子弹图绘制', fontsize=18)
# 移除不必要的边框
sns.despine(left=True, bottom=True)
# 显示图表
plt.show()


  • 使用plt.subplots()创建一个图形和轴对象。
  • 使用ax.barh()方法绘制水平条形图,表示定性范围。
  • 使用ax.barh()方法绘制实际绩效的水平条。
  • 使用ax.axvline()方法绘制垂直线,表示目标值。
  • 设置x轴的范围和标签,隐藏y轴的刻度。
  • 使用ax.set_title()方法添加图表标题。
  • 使用plt.show()方法显示图表。


然后可以使用ax.text方法,把标签值加上。为了区分,我们使用红色字体为目标值↓

fig, ax = plt.subplots(figsize=(10, 5))
# 绘制每组数据的子弹图
for i, d in enumerate(data):
    actual_value = d['实际值']
    target_value = d['目标值']
    ranges = d['范围']
    label = d['类别']
    range_colors = ['#ff9999', '#ffcc99', '#99ff99']  # 使用更美观的颜色
    # 绘制定性范围
    for j, (start, color) in enumerate(zip([0] + ranges[:-1], range_colors)):
        ax.barh(i, ranges[j] - start, left=start, height=0.5, color=color, edgecolor='white')
    # 绘制性能条
    ax.barh(i, actual_value, height=0.25, color='#3d7abf', edgecolor='white')
    ax.plot([target_value, target_value], [i - 0.4, i + 0.4], color='red', linewidth=2)
    ax.text(actual_value + 1, i, f'{actual_value}', va='center', fontsize=12, color='black')
    ax.text(target_value + 1, i, f'{target_value}', va='center', fontsize=11, color='red')
# 设置轴的限制和标签
ax.set_xlim(0, 120)
ax.set_yticks(range(len(data)))
ax.set_yticklabels([d['类别'] for d in data], fontsize=15)
ax.set_xlabel('目标和完成率', fontsize=12)
# 添加标题
ax.set_title('seaborn子弹图绘制', fontsize=18)
# 移除不必要的边框
sns.despine(left=True, bottom=True)
# 显示图表
plt.show()

最后如果数据维度太多,我们也可以通过纵向的方式来进行展示,代码和结果如下↓

data = [
    {'实际值': 120, '目标值': 100, '范围': [60, 80, 100], '类别': '白酒'},
    {'实际值': 65, '目标值': 80, '范围': [50, 70, 80], '类别': '啤酒'},
    {'实际值': 90, '目标值': 95, '范围': [70, 85, 95], '类别': '葡萄酒'},
    {'实际值': 86, '目标值': 100, '范围': [60, 80, 100], '类别': '威士忌'},
    {'实际值': 95, '目标值': 80, '范围': [50, 70, 80], '类别': '清酒'},
    {'实际值': 102, '目标值': 95, '范围': [70, 85, 95], '类别': '白兰地'}
]
# 创建图形和轴
fig, ax = plt.subplots(figsize=(6, 10))


# 绘制每组数据的子弹图
for i, d in enumerate(data):
    actual_value = d['实际值']
    target_value = d['目标值']
    ranges = d['范围']
    label = d['类别']
    range_colors = ['#ff9999', '#ffcc99', '#99ff99']
    for j, (start, color) in enumerate(zip([0] + ranges[:-1], range_colors)):
        ax.bar(i, ranges[j] - start, bottom=start, width=0.5, color=color, edgecolor='white')
    ax.bar(i, actual_value, bottom=0, width=0.25, color='#3d7abf', edgecolor='white')
    ax.plot([i, i], [target_value, target_value], color='#999999', linestyle='--', linewidth=2)
    ax.plot([i - 0.3, i + 0.3], [target_value, target_value], color='red', linewidth=2)
    ax.text(i, actual_value, f'{actual_value}', ha='center', fontsize=14, color='black')
    ax.text(i, target_value, f'{target_value}', ha='center', fontsize=12, color='red')
    
ax.set_ylim(0, 120)
ax.set_xticks(range(len(data)))
ax.set_xticklabels([d['类别'] for d in data], rotation=45, ha='right', fontsize=15)
ax.set_ylabel('目标和完成率%', fontsize=12)
ax.set_title('垂直分布的子弹图', fontsize=18)
sns.despine(left=True, bottom=True)
plt.tight_layout()
plt.show()

链接是我使用PowerBI整合的历史文章,按类型分类,可以根据需求查询:Microsoft Power BI↓

https://app.powerbi.com/view?r=eyJrIjoiNjI2NWQ3NjktYjU0ZC00ZWZhLTgzMDgtMGI4ZTk1ZDlkODM3IiwidCI6IjI3NDQ3MWQ0LTM4ZDQtNDVlZS1hMmJkLWU1NTVhOTBkYzM4NiJ9

End

Tags:

最近发表
标签列表