如何用Python绘制棒棒糖图案
作者:麦兜 更新时间:2025-07-07 21:04:01 阅读 845
什么是棒棒糖图?
棒棒糖图功能上与条形图基本相同,都可以进行数据间的对比观察和分析。
BUT,从视觉上观察,它由一条从坐标轴锚定的线段和一个在末尾标记该值的圆点组成。
如果我们要处理大量的数值并且高数值的比例偏高,比如在80-90%范围内。此时我们可以通常认为棒棒糖图比普通条形图更加有用的,因为棒棒糖图上面突出的高大线段在视觉上具有侵略性和增强效果。
棒棒糖图的样式和数据格式
棒棒糖图的5条使用建议
为了避免因坐标轴尺度使用不合理而发现信息传达扭曲,建议数据坐标轴须以0为起点,不能截断部分坐标轴显示,这个要求与条形图要求基本一致。为了充分考虑读者体验,当坐标轴标签的名称过长时,一般采用横向水平呈现 (时间轴除外)为了更加符合人眼的阅读习惯,建议将数据优先按大小排序,从而让解读信息变得更加舒服。为了更加清爽的视觉感受,建议使用有意义的颜色(避免每个数据条使用一种颜色)与普通条形图相比,棒棒糖图更加吸引人的注意力和眼球。为了避免由于末端以圆形为中心点,造成精确度不如条形图的直边,圆形大小不宜过大!棒棒糖图的具体绘制过程
下面我们就利用Python代码来实现,同时给出几种常见的美化方案
准备工作
## 初始字体设置,设置好可避免很多麻烦
plt.rcParams['font.sans-serif']=['Source Han Sans CN'] # 显示中文不乱码,思源黑体
plt.rcParams['font.size'] = 22 # 设置图表全局字体大小,后期某个元素的字体大小可以自行调整
plt.rcParams['axes.unicode_minus'] = False # 显示负数不乱码
## 初始化图表大小
plt.rcParams['figure.figsize'] = (20.0, 8.0) # 设置figure_size尺寸
## 初始化图表分辨率质量
plt.rcParams['savefig.dpi'] = 300 # 设置图表保存时的像素分辨率
plt.rcParams['figure.dpi'] = 300 # 设置图表绘制时的像素分辨率
## 图表的颜色自定义
colors = ['#dc2624', '#2b4750', '#45a0a2', '#e87a59',
'#7dcaa9', '#649E7D', '#dc8018', '#C89F91',
'#6c6d6c', '#4f6268', '#c7cccf']
plt.rcParams['axes.prop_cycle'] = plt.cycler( color=colors)
path = 'D:\\系列文章\\'
# 自定义文件路径,可以自行设定
os.chdir(path)
# 设置为该路径为工作路径,一般存放数据源文件设置图表样式和文件路径
Sales_data = pd.read_excel('虚拟演示案例数据.xlsx',
sheet_name='销售数据表')
Sales_data_sum = Sales_data.groupby(['门店城市'])['购买数量'].sum().reset_index()
Sales_data_sum读取模拟数据集
# 第一种方法,直接使用stem方法,此法可以设置X轴的数据标签样式
# plt.stem('门店城市','购买数量',data=Sales_data_sum[:10])
# 第二种方法,简略后的stem方法,此法X轴没有数据标签,自动赋值数字序列
# plt.stem('购买数量',data=Sales_data_sum[:10])
# 第三种方法,此法与第一种方法效果类似,写法略微麻烦
# (markerline, stemlines, baseline) = plt.stem('门店城市','购买数量',data=Sales_data_sum[:10])
# plt.setp(baseline, visible=False)
# 第四种方法,此法使用vlines方法,先画线条,再画圆点,组合完成。优点是可以分别不同图形的颜色和大小。
# 首先画出不同高度的线段来表达数据大小
plt.vlines(x='门店城市', # 设置X轴的数据标签
ymin=0,
ymax='购买数量', # 设置线段的长度,从0开始
data=Sales_data_sum[:10]) # 设置数据来源,这里选择了前10个城市数据作为参考展示
# 其次画出某个线段的顶点坐标,设置圆点大小
plt.plot('门店城市', #
'购买数量', "o",markersize=12,
data=Sales_data_sum[:10])
plt.ylim(0,) # 设置Y轴起点位置
plt.title("城市门店销量对比", loc='left')
plt.xlabel('不同城市')
plt.ylabel('购买数量')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()画出基础的棒棒糖图
其中涉及四种方法,都可以实现。前两种可以快速出图,后两种相对自定义化程度高一些。
# 第一种方法,直接使用stem方法,此法可以设置X轴的数据标签样式
# plt.stem('门店城市','购买数量',data=Sales_data_sum[:10])
# 第二种方法,简略后的stem方法,此法X轴没有数据标签,自动赋值数字序列
# plt.stem('购买数量',data=Sales_data_sum[:10])
# 第三种方法,此法与第一种方法效果类似,写法略微麻烦
# (markerline, stemlines, baseline) = plt.stem('门店城市','购买数量',data=Sales_data_sum[:10])
# plt.setp(baseline, visible=False)
# 第四种方法,此法使用vlines方法,先画线条,再画圆点,组合完成。优点是可以分别不同图形的颜色和大小。
# 首先画出不同高度的线段来表达数据大小
plt.vlines(x='门店城市', # 设置X轴的数据标签
ymin=0,
ymax='购买数量', # 设置线段的长度,从0开始
data=Sales_data_sum[:10]) # 设置数据来源,这里选择了前10个城市数据作为参考展示
# 其次画出某个线段的顶点坐标,设置圆点大小
plt.plot('门店城市', #
'购买数量', "o",markersize=12,
data=Sales_data_sum[:10])
plt.ylim(0,) # 设置Y轴起点位置
plt.title("城市门店销量对比", loc='left')
plt.xlabel('不同城市')
plt.ylabel('购买数量')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()优化一:加入数据排序让图表更具洞察力
# 只需画图前,先进行一下数据排序即可!
Ordered_data_sum = Sales_data_sum[:10].sort_values(by='购买数量',ascending=False)
# 第一种方法,直接使用stem方法,此法可以设置X轴的数据标签样式
# plt.stem('门店城市','购买数量',data=Ordered_data_sum)
# 第二种方法,简略后的stem方法,此法X轴没有数据标签,自动赋值数字序列
# plt.stem('购买数量',data=Ordered_data_sum)
# 第三种方法,此法与第一种方法效果类似,写法略微麻烦
# (markerline, stemlines, baseline) = plt.stem('门店城市','购买数量',data=Ordered_data_sum)
# plt.setp(baseline, visible=False)
# 第四种方法,此法使用vlines方法,先画线条,再画圆点,组合完成。优点是可以分别不同图形的颜色和大小。
# 首先画出不同高度的线段来表达数据大小
plt.vlines(x='门店城市',
ymin=0,
ymax='购买数量',
data=Ordered_data_sum)
# 其次画出某个线段的顶点坐标,设置圆点大小
plt.plot('门店城市',
'购买数量', "o",markersize=12,
data=Ordered_data_sum)
plt.title("城市门店销量对比", loc='left')
plt.xlabel('不同城市')
plt.ylabel('购买数量')
plt.ylim(0,) # 设置Y轴起点位置
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()优化二:采用横向图表设计,更符合人眼阅读习惯
# 只需画图前,先进行一下数据排序即可!
Ordered_data_sum = Sales_data_sum[:10].sort_values(by='购买数量',ascending=True)
# 此处使用 hlines方法即可实现横向效果
# 首先画出不同高度的线段来表达数据大小
plt.hlines(y='门店城市',
xmin=0,
xmax='购买数量',
data=Ordered_data_sum)
# 其次画出某个线段的顶点坐标,设置圆点大小
plt.plot('购买数量',
'门店城市',
"o",
markersize=12,
data=Ordered_data_sum)
plt.xlim(0,) # 设置X轴起点位置
plt.title("城市门店销量对比", loc='left')
plt.ylabel('不同城市')
plt.xlabel('购买数量')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()优化三:利用颜色来突出显示某个数据
# 只需画图前,先进行一下数据排序即可!
Ordered_data_sum = Sales_data_sum[:10].sort_values(by='购买数量',ascending=True)
# 加入颜色和大小筛选条件,当为中山市时显示不同的颜色和大小!
color_data_sum = np.where(Ordered_data_sum['门店城市']=='中山市',colors[0],colors[1])
size_data_sum = np.where(Ordered_data_sum['门店城市']=='中山市',300,100)
# 此处使用 hlines方法即可实现横向效果
plt.hlines(y='门店城市',
xmin=0,
xmax='购买数量',
color=color_data_sum, # 利用条件筛选来画线段,当出现满足条件的则显示强调颜色
data=Ordered_data_sum)
plt.scatter('购买数量',
'门店城市',
s=size_data_sum, # 利用条件筛选来画圆点,当出现满足条件的则显示强调大小
color=color_data_sum, # 利用条件筛选来画线段,当出现满足条件的则显示强调颜色
data=Ordered_data_sum)
plt.xlim(0,) # 设置X轴起点位置
plt.title("城市门店销量对比", loc='left')
plt.ylabel('不同城市')
plt.xlabel('购买数量')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()优化四:利用形状标记来突出显示某个数据
# 只需画图前,先进行一下数据排序即可!
Ordered_data_sum = Sales_data_sum[:10].sort_values(by='购买数量',ascending=True)
# 加入颜色和大小筛选条件,当为中山市时显示不同的颜色和大小!
color_data_sum = np.where(Ordered_data_sum['门店城市']=='中山市',colors[0],colors[1])
size_data_sum = np.where(Ordered_data_sum['门店城市']=='中山市',300,100)
# 此处使用 hlines方法即可实现横向效果
plt.hlines(y='门店城市',
xmin=0,
xmax='购买数量',
color=color_data_sum, # 利用条件筛选来画线段,当出现满足条件的则显示强调颜色
data=Ordered_data_sum)
plt.scatter('购买数量',
'门店城市',
s=size_data_sum, # 利用条件筛选来画圆点,当出现满足条件的则显示强调大小
color=color_data_sum, # 利用条件筛选来画线段,当出现满足条件的则显示强调颜色
marker = 'D',
data=Ordered_data_sum)
plt.xlim(0,) # 设置X轴起点位置
plt.title("城市门店销量对比", loc='left')
plt.ylabel('不同城市')
plt.xlabel('购买数量')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()优化五:利用变化折线来突出趋势
# 只需画图前,先进行一下数据排序即可!
Ordered_data_sum = Sales_data_sum[:10].sort_values(by='购买数量',ascending=True)
# 此处使用 hlines方法即可实现横向效果
# 首先画出不同高度的线段来表达数据大小
plt.hlines(y='门店城市',
xmin=0,
xmax='购买数量',
data=Ordered_data_sum)
# 其次画出某个线段的顶点坐标,设置圆点大小
plt.plot('购买数量',
'门店城市',
marker="o", # 使用marker标记可实现顶点连续效果
markersize=12,
data=Ordered_data_sum)
plt.xlim(0,) # 设置X轴起点位置
plt.title("城市门店销量对比", loc='left')
plt.ylabel('不同城市')
plt.xlabel('购买数量')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()优化六:比较突出两组数据的变化差异跨度
# 只需画图前,先进行一下数据排序即可!
Ordered_data_sum = Sales_data_sum[:10].sort_values(by='购买数量',ascending=True)
# 方便演示,随机生成一组数据作为下月的销量数值!
Ordered_data_sum['下月预计购买量'] = Ordered_data_sum['购买数量']- np.random.randint(0,1000,10)
# 加入颜色和大小筛选条件,当为中山市时显示不同的颜色和大小!
color_data_sum = np.where(Ordered_data_sum['门店城市']=='中山市',colors[2],colors[1]) # 第一组颜色以及筛选条件
color_data_sum2 = np.where(Ordered_data_sum['门店城市']=='中山市',colors[2],colors[3]) # 第二组颜色以及筛选条件
size_data_sum = np.where(Ordered_data_sum['门店城市']=='中山市',300,100) # 圆点大小的筛选条件
# 此处使用 hlines方法即可实现横向效果
plt.hlines(y='门店城市',
xmin='购买数量',
xmax='下月预计购买量',
color=colors[10], # 直接设置线段的颜色
data=Ordered_data_sum)
plt.scatter('购买数量',
'门店城市',
s=size_data_sum, # 利用条件筛选来画圆点,当出现满足条件的则显示强调大小
color=color_data_sum, # 利用条件筛选来画线段,当出现满足条件的则显示强调颜色
# marker = 'D',
data=Ordered_data_sum)
plt.scatter('下月预计购买量',
'门店城市',
s=size_data_sum, # 利用条件筛选来画圆点,当出现满足条件的则显示强调大小
color=color_data_sum2, # 利用条件筛选来画线段,当出现满足条件的则显示强调颜色
# marker = 'D',
data=Ordered_data_sum)
# plt.xlim(0,) # 设置X轴起点位置,此处比较差异可以存在负增长的情况,因此暂时没有设置刻度线由0开始
plt.title("城市门店销量对比", loc='left')
plt.ylabel('不同城市')
plt.xlabel('2个月的购买数量比较')
sns.despine() # 默认无参数状态,就是删除上方和右方的边框,matplotlib貌似做不到
plt.show()写在最后
任何图表都不是万能通用的,棒棒糖图也存在缺点:
棒棒糖末端的圆心标记了该值,但是该中心的位置很难判断,与条形的直边相比,它不精确同时顶端的圆点半径,已经超出了它所代表的值,因此可能造成视觉不准确。与棒棒糖图类似的图表还有哑铃图,它可以通过突出显示差异来表现两个值之间的跨度间隔。
OK,今天先到这里了,以上为本文全部内容,如果觉得喜欢,请动动小手转发和关注一下我们。
我是老海,来自数据炼金术师
声明:本文由"麦兜"发布,不代表"破站"立场,转载联系作者并注明出处:https://www.848586.cn/204573.html
