众所周知,Python 的应用是非常广泛的,今天我们就通过 matplotlib 库学习下如何制作精美的子弹图

1什么是子弹图

一个子弹图约定俗成的定义

子弹图使用长度/高度、位置和颜色对数据进行编码,以显示与目标和性能带相比的实际情况

我们先来看下子弹图大概长什么样子

子弹图具有单一的主要度量(例如,当前年初至今的收入),将该度量与一个或多个其他度量进行比较以丰富其含义(例如,与目标相比),并将其显示在性能的定性范围的背景,例如差、满意和好。定性范围显示为单一色调的不同强度,使色盲者可以辨别它们,并将仪表板上的颜色使用限制在最低限度

好了,差不多这就是子弹图的应用场景和绘制标准了,下面我们就开始制作吧

2构建图表

思路大致是,可以使用堆叠条形图来表示各种范围,并使用另一个较小的条形图来表示值,最后,用一条垂直线标记目标

可以看出,我们需要多个组件图层,使用 matplotlib 来实现会比较方便

import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.ticker import FuncFormatter%matplotlib inline

这里我们还导入了 Seaborn,是因为 Seaborn 有一些非常有用的工具来管理调色板,利用这种功能比尝试以其他方式复制它更容易

我们需要生成调色板的主要原因是我们很可能希望为各种定性范围生成视觉上吸引人的配色方案,直接使用 seaborn 来完成会方便很多

在下面的例子中,我们可以使用 palplot 便利函数来显示 5 种绿色色调的调色板

sns.palplot(sns.light_palette("green", 5))

sns.palplot(sns.light_palette("purple",8, reverse=True))

以相反的顺序制作 8 种不同深浅的紫色

我们现在知道了如何设置调色板,接下来让我们使用 Matplotlib 根据上面列出的原则创建一个简单的子弹图

首先,定义我们想要绘制的值

limits = [80, 100, 150]
data_to_plot = ("Example 1", 105, 120)

这个将创建 3 个范围:0-80、81-100、101-150 和一个值为 105 和目标线为 120 的“示例”线 接下来,构建一个蓝色调色板:

palette = sns.color_palette("Blues_r", len(limits))

接下来是构建范围的堆积条形图:

fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.set_yticks([1])
ax.set_yticklabels([data_to_plot[0]])prev_limit = 0
for idx, lim in enumerate(limits):ax.barh([1], lim-prev_limit, left=prev_limit, height=15, color=palette[idx])prev_limit = lim

然后我们可以添加一个较小的条形图来表示 105 的值:

ax.barh([1], data_to_plot[1], color='black', height=5)

已经初见雏形了

最后一步是使用 axvline 添加目标标记:

ax.axvline(data_to_plot[2], color="gray", ymin=0.10, ymax=0.9)

上面我就完成了子弹图的简单制作,但是我们所有的测试数值都是写死的,下面我们编写一个可以填写任意数值的代码

3最终代码

def bulletgraph(data=None, limits=None, labels=None, axis_label=None, title=None,size=(5, 3), palette=None, formatter=None, target_color="gray",bar_color="black", label_color="gray"):# Determine the max value for adjusting the bar height# Dividing by 10 seems to work pretty wellh = limits[-1] / 10# Use the green palette as a sensible defaultif palette is None:palette = sns.light_palette("green", len(limits), reverse=False)# Must be able to handle one or many data sets via multiple subplotsif len(data) == 1:fig, ax = plt.subplots(figsize=size, sharex=True)else:fig, axarr = plt.subplots(len(data), figsize=size, sharex=True)# Add each bullet graph bar to a subplotfor idx, item in enumerate(data):# Get the axis from the array of axes returned when the plot is createdif len(data) > 1:ax = axarr[idx]# Formatting to get rid of extra marking clutterax.set_aspect('equal')ax.set_yticklabels([item[0]])ax.set_yticks([1])ax.spines['bottom'].set_visible(False)ax.spines['top'].set_visible(False)ax.spines['right'].set_visible(False)ax.spines['left'].set_visible(False)prev_limit = 0for idx2, lim in enumerate(limits):# Draw the barax.barh([1], lim - prev_limit, left=prev_limit, height=h,color=palette[idx2])prev_limit = limrects = ax.patches# The last item in the list is the value we're measuring# Draw the value we're measuringax.barh([1], item[1], height=(h / 3), color=bar_color)# Need the ymin and max in order to make sure the target marker# fitsymin, ymax = ax.get_ylim()ax.vlines(item[2], ymin * .9, ymax * .9, linewidth=1.5, color=target_color)# Now make some labelsif labels is not None:for rect, label in zip(rects, labels):height = rect.get_height()ax.text(rect.get_x() + rect.get_width() / 2,-height * .4,label,ha='center',va='bottom',color=label_color)if formatter:ax.xaxis.set_major_formatter(formatter)if axis_label:ax.set_xlabel(axis_label)if title:fig.suptitle(title, fontsize=14)fig.subplots_adjust(hspace=0)

代码虽然看起来有点长,但是其实都是上面步骤的叠加,都比较简单,就不再重复说明了

我们直接调用一下看看效果

data_to_plot2 = [("张三", 105, 120),("李四", 99, 110),("王五", 109, 125),("赵六", 135, 123),("钱七", 45, 105)]bulletgraph(data_to_plot2, limits=[20, 60, 100, 160],labels=["Poor", "OK", "Good", "Excellent"], size=(8,5),axis_label="Performance Measure", label_color="black",bar_color="#252525", target_color='#f7f7f7',title="销售代表表现")

我们还可以进行一些优化,格式化 x 轴以便更一致地显示信息

在下面这个例子中,我们可以衡量一家假设公司的营销预算绩效

def money(x, pos):'The two args are the value and tick position'return "${:,.0f}".format(x)money_fmt = FuncFormatter(money)
data_to_plot3 = [("HR", 50000, 60000),("Marketing", 75000, 65000),("Sales", 125000, 80000),("R&D", 195000, 115000)]
palette = sns.light_palette("grey", 3, reverse=False)
bulletgraph(data_to_plot3, limits=[50000, 125000, 200000],labels=["Below", "On Target", "Above"], size=(10,5),axis_label="Annual Budget", label_color="black",bar_color="#252525", target_color='#f7f7f7', palette=palette,title="营销渠道预算绩效",formatter=money_fmt)

看起来效果都不错哦,怎么样,一起跟着做起来吧!

END

推荐阅读牛逼!Python常用数据类型的基本操作(长文系列第①篇)
牛逼!Python的判断、循环和各种表达式(长文系列第②篇)牛逼!Python函数和文件操作(长文系列第③篇)牛逼!Python错误、异常和模块(长文系列第④篇)

用 Python 制作子弹图也这么简单,爱了~相关推荐

  1. 爱了爱了!用 Python 制作子弹图也这么简单!

    众所周知,Python 的应用是非常广泛的,今天我们就通过 matplotlib 库学习下如何制作精美的子弹图 1什么是子弹图 一个子弹图约定俗成的定义 子弹图使用长度/高度.位置和颜色对数据进行编码 ...

  2. python多张图片合并拼接,python制作sprite图、雪碧图

    python多张图片合并拼接,python制作sprite图.雪碧图 整理图片集 找两个文件夹,yangying和zhaoliying,分别放上照片8张,共16张照片. 创建sprite.py # 多 ...

  3. python图像识别生成矢量图_使用python制作矢量图

    Get一个使用python制作矢量图的新技能: 前言: Matplotlib远比我们想象的强大,而这只是众多python强大的包中的一个,不愧是群英荟萃. 绘图后端我们一般是看不见的,matplotl ...

  4. [从零开始]用python制作识图翻译器·二

    AlsoEasy-RecognitionTranslator 需求分析 系统分析 功能拆解 工程语言选择 技术可行性分析 具体实现 需求分析   见上篇[从零开始]用python制作识图翻译器·一 上 ...

  5. 甘特图制作_使用excel制作甘特图其实很简单,仅需4步搞定,项目进度一目了然...

    Hello,今天跟大家分享下如何在excel中制作甘特图.甘特图能直观的表现出任务的进度,以及各个项目之间的关联性 如果说你的项目众多,可以使用更专业的Project来制作甘特图,使用Project制 ...

  6. [从零开始]用python制作识图翻译器·一

    AlsoEasy-RecognitionTranslator 前言 需求分析 应用场景 需求提取 需求补充 竞品分析 QQ识图 百度翻译 UU翻译器 小结 功能实现 前言   这是我的毕设作品.当时玩 ...

  7. 利用Python制作动图演示坐标变换理论

    利用Python制作动图演示坐标变换理论 永磁同步电机是一个非线性.强耦合的物理系统,因而不便直接进行控制.后有研究人员创造性的提出了坐标变换理论(后逐渐成为矢量控制的一个部分),让永磁同步电机得以转 ...

  8. 基于Bokeh库,手把手教你制作“子弹图“和“瀑布图“!

    首先,让我们进行导入并使 Bokeh 的输出显示在我们的笔记本中: from bokeh.io import show, output_notebook from bokeh.palettes imp ...

  9. 一张图片能加特效,还能加背景音乐?Python制作雪景图

    本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 以下文章来源于Python技术 ,作者派森酱 前言 这几天很多地方陆续出现了降雪的天气,对于年内的 ...

最新文章

  1. MOS晶体管小信号放大电路
  2. Java 多线程:synchronized 关键字用法(修饰类,方法,静态方法,代码块)
  3. 使用jQuery的hover事件在IE中不停闪动的解决方法
  4. 全国计算机一级d类考试内容,全国计算机一级考试WPS office复习题及答案2017
  5. uac2.0驱动_关闭Vista中令人讨厌的HP驱动程序UAC弹出更新检查
  6. 刘朋:程序员如何练就领导力
  7. ECMAScript 6规范总结(长文慎入)
  8. WPF 禁止在文本框中输入数字
  9. 剑指offer——5.替换空格
  10. Confluence 6 让一个空间可以公众访问
  11. 计算机网络2020秋--第四次测验
  12. Robot Freamwork 安装配置文档
  13. Node.js模块化开发(非常详细,满满的干货)
  14. java stax_XML编程总结(五)——使用StAX接口操作xml
  15. 编程零基础,如何学 Python ?
  16. IIS6同一IP部署多域名证书(部署指南)
  17. JAR包的JDK版本查看与设置
  18. 【cpu如何超频及cpu超频作用】
  19. 某试卷由26道题c语言,c语言模拟试题
  20. Typora安装 Pandoc实现导出功能

热门文章

  1. spyder编辑器报ModuleNotFoundError: No module named ‘pymongo‘,明明已经安装上了pymongo扩展
  2. 非科班的java程序员该如何补充计算机基础知识,需要看哪些书?
  3. 聊一聊双十一背后的技术 - 不一样的秒杀技术, 裸秒
  4. 最新版本sublime text3注册码
  5. arcgis for android离线编辑,操作方法:直接从 Android 或 iOS 设备访问 Collector for ArcGIS 中的离线编辑内容...
  6. 前端须知的 Cookie 知识小结
  7. PHP被忽视的编码规范
  8. java中的方法 net.中的函数_.Net转Java.01.从Main(main)函数说起
  9. linux 分区_Linux文件系统、逻辑分区、物理分区
  10. cad 打开硬件加速卡_为什么我能用CAD“飙车”?因为我用了这些加速秘笈