【可视化】Python绘制风车玫瑰图动画

2023-10-24 22:59

本文主要是介绍【可视化】Python绘制风车玫瑰图动画,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最终成品

在这里插入图片描述

思路

风车玫瑰图等效于极坐标系下的堆积条形图。

  1. 绘制直角坐标系下的堆积条形图。pyplot本身没有找到堆积条形图的方法,所以使用计算堆积。
  2. 因为极坐系下,x轴会卷积成一个圆,所以需要提前将x轴的刻度转成弧度。
  3. 由于x轴变换了,所以不能直接使用.bar()方法绘图,同时需要将数据构造转成 层级 * 柱数 的样式,分别绘制条形。
  4. 将子图的坐标系改成极坐标系。
  5. 使用FuncAnimation()方法绘制动画。

环境

Python 3.10

引入包

import pandas as pd
import matplotlib.pyplot as plt 
import matplotlib.animation as animation
import numpy as npplt.rcParams["font.sans-serif"] = ["SimHei"]    # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False      # 指定负号等特殊符号兼容

创建测试数据

创建 (16,3) 的数集,对应16个风车柱子,每个柱子分三层。

data = pd.DataFrame(np.random.randint(70, 100, size=(16, 3)),index=[i for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'][:16], columns=["l1", 'l2', 'l3'])data

绘制堆积条形图

pyplot中没有找到堆积条形图的办法,只有 stackplot() 堆积面积图,所以直接用 bar()方法画。
每一层都指定前层的合计值为柱子底部 bottom,实现堆积效果。
因为数据集是随机生成的,所以每张图的柱子高度不一致,勿怪。

fig = plt.figure()
ax = fig.add_subplot()
for i in range(data.shape[1]):plt.bar(x=data.index, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1))

堆积条形图

转极坐标系

在subplot子图中指定 projection=“polar” ,即可使用极坐标系。

fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
for i in range(data.shape[1]):plt.bar(x=data.index, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1))

极坐标下的堆积条形图由于x轴的刻度没有转换成角度,所以外圈的刻度不对,A和G靠太近了。

  1. 将x轴转换成弧度。共16个柱子,每个柱子所在弧度即是 2 π / 16 2\pi/16 2π/16
  2. 缩小桩子的宽度,避免挤到一起。
fig = plt.figure()
ax = fig.add_subplot(projection="polar")        # 指定子图为极坐标系
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]  # 计算X轴的弧度
for i in range(data.shape[1]):plt.bar(x=x, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1))

X轴刻度转成弧度比较接近了,把X轴的角度标签换成数据标签 tick_label=data.index

fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]  # 计算X轴
for i in range(data.shape[1]):plt.bar(x=x, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1), width=np.pi/data.shape[0],   # 调整柱子宽度tick_label=data.index        # 添加标签)

修改标签

修饰文本

调整一下

  1. 把标签加到每个柱子上
  2. 隐藏坐标轴和边框

为啥plt.text()方法一次只能画一条文本?

fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
ax.spines["polar"].set_visible(False)       # 隐藏边框
ax.axes.xaxis.set_visible(False)            # 隐藏X轴
ax.axes.yaxis.set_visible(False)            # 隐藏Y轴
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]   # 计算X轴
for i in range(data.shape[1]):ax.bar(x=x, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1), width=np.pi/data.shape[0],          # 调整柱子宽度tick_label=data.index               # 添加标签)# 添加文本到柱子上
for i in range(data.shape[0]):plt.text(x=x[i],                                         # 文本的X坐标y=data.iloc[i].sum(),                           # 文本的Y坐标s=f"{data.iloc[i].name}: {data.iloc[i].sum()}"  # 文本内容)

添加文本标签
修改文字:

  1. 旋转文字的角度,与柱子方向一致。
  2. 文字与柱太近了,远离一点。
  3. 同时修改对齐方式。O和P有点不齐。
fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
ax.spines["polar"].set_visible(False)       # 隐藏边框
ax.axes.xaxis.set_visible(False)            # 隐藏X轴
ax.axes.yaxis.set_visible(False)            # 隐藏Y轴
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]   # 计算X轴
for i in range(data.shape[1]):ax.bar(x=x, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1), width=np.pi/data.shape[0],          # 调整柱子宽度tick_label=data.index               # 添加标签)# 添加文本到柱子上
for i in range(data.shape[0]):plt.text(x=x[i],                             # 文本的X坐标y=data.iloc[i].sum() * 1.05,        # 文本的Y坐标s=f"{data.iloc[i].name}: {data.iloc[i].sum()}",  # 文本内容rotation= (i * 360)/data.shape[0],  # 旋转角度rotation_mode="anchor",             # 指定旋转模式horizontalalignment="left",         # 水平对齐方式verticalalignment="center"          # 垂直对齐方式)

对齐文本

修饰颜色

修改柱子的颜色, 并添加柱子边框。因为配色无能,所以直接使用了plt的颜色重采样,好东西啊。
思路是先使用 resampled() 方法从调色盘中取 16 * 3 = 48 个颜色,再给每个柱子用不同的颜色。

fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
ax.spines["polar"].set_visible(False)       # 隐藏边框
ax.axes.xaxis.set_visible(False)            # 隐藏X轴
ax.axes.yaxis.set_visible(False)            # 隐藏Y轴
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]   # 计算X轴
color_list = plt.colormaps['inferno'].resampled(48).colors          # 从调色盘中重采样48个颜色,做为柱子的颜色。for i in range(data.shape[1]):ax.bar(x=x, height=data.iloc[:, i], bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1), width=np.pi/data.shape[0],          # 调整柱子宽度tick_label=data.index,              # 添加标签color=color_list[i*16:(i+1)*16],    # 添加颜色edgecolor="k",                      # 指定组间边框颜色linewidth=1,                        # 组间边框宽度)# 添加文本到柱子上
for i in range(data.shape[0]):plt.text(x=x[i],                             # 文本的X坐标y=data.iloc[i].sum() * 1.05,        # 文本的Y坐标s=f"{data.iloc[i].name}: {data.iloc[i].sum()}",  # 文本内容rotation= (i * 360)/data.shape[0],  # 旋转角度rotation_mode="anchor",             # 指定旋转模式horizontalalignment="left",         # 水平对齐方式verticalalignment="center",         # 垂直对齐方式)plt.show()

修饰颜色

制作动画

先作个简单的动画,即按照绘制顺序,逐个实现动画效果:

  1. 创建自定义函数 update() 保存每一帧的绘图方法。
  2. for循环的子句移入动画函数,再调用matplotlib的FuncAnimation()方法。
  3. 第0帧时,先清空画布,再绘制。
  4. 最后一帧时,把文字画上去。
fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
ax.spines["polar"].set_visible(False)       # 隐藏边框
ax.axes.xaxis.set_visible(False)            # 隐藏X轴
ax.axes.yaxis.set_visible(False)            # 隐藏Y轴
ax.set_ylim([0, 300])
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]   # 计算X轴
color_list = plt.colormaps['inferno'].resampled(48).colors# 动画函数
def update(i):if i == 0: ax.cla()ax.set_ylim([0, 300])bar = ax.bar(x=x,height=data.iloc[:, i],bottom=0 if i == 0 else data.iloc[:, 0:i].sum(axis=1), width=np.pi/data.shape[0], color=color_list[i*16:(i+1)*16],edgecolor="k",linewidth=1,)if i == 2:for i in range(data.shape[0]):plt.text(x=x[i],                             # 文本的X坐标y=data.iloc[i].sum() * 1.05,        # 文本的Y坐标s=f"{data.iloc[i].name}: {data.iloc[i].sum()}",  # 文本内容rotation= (i * 360)/data.shape[0],  # 旋转角度rotation_mode="anchor",             # 指定旋转模式horizontalalignment="left",         # 水平对齐方式verticalalignment="center",         # 垂直对齐方式)return bar anim = animation.FuncAnimation(fig=fig,        # 指定画布对象func=update,    # 指定更新方法frames=3,       # 动画帧数,即画几次的意思,和一秒多少帧无关interval=720,   # 每次绘画的间隔时间,单位是毫秒)

动画
一层一层出现的方式有点奇怪,改成分柱子出现的比较好。即每次绘制一行数据柱,绘制16次。


fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
ax.spines["polar"].set_visible(False)       # 隐藏边框
ax.axes.xaxis.set_visible(False)            # 隐藏X轴
ax.axes.yaxis.set_visible(False)            # 隐藏Y轴
ax.set_ylim([0, 300])
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]   # 计算X轴
color_list = plt.colormaps['inferno'].resampled(48).colors
bar = ax.bar(x, [0]*len(x), width=np.pi/data.shape[0])[0]# 动画函数
def update(i):if i == 0: ax.cla()                # 清除画布ax.set_ylim([0, 300])   # 重新建立Y轴范围for j in range(3):          # 分成三层画柱子bar = ax.bar(x = x[i],           # X轴坐标height=data.iloc[i, j].sum(),   # 每层柱子的高度bottom=0 if j==0 else data.iloc[i, 0:j].sum(),  # 每层柱子的底width=np.pi/data.shape[0],      # 柱子宽度color=color_list[j*16 + i],     # 柱子颜色edgecolor="k",                  # 分隔线颜色linewidth=1,                    # 分隔线宽度)plt.text(x=x[i],                             # 标签的X轴坐标,与柱子相同y=data.iloc[i].sum()*1.05,          # 标签的Y轴坐标,比柱子略高一点,避免重叠s=f"{data.iloc[i].name}: {data.iloc[i].sum()}",     # 标签的文本内容rotation= (i * 360)/data.shape[0],  # 旋转角度rotation_mode="anchor",             # 指定旋转模式horizontalalignment="left",         # 水平对齐方式verticalalignment="center",         # 垂直对齐方式)return bar anim = animation.FuncAnimation(fig=fig, func=update, frames=16, interval=720)

分行绘制

结束

附件:完整代码

import pandas as pd
import matplotlib.pyplot as plt 
import matplotlib.animation as animation
import numpy as npplt.rcParams["font.sans-serif"] = ["SimHei"]    # 指定中文字体
plt.rcParams['axes.unicode_minus'] = False      # 指定负号等特殊符号兼容data = pd.DataFrame(np.random.randint(70, 100, size=(16, 3)),index=[i for i in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'][:16], columns=["l1", 'l2', 'l3'])fig = plt.figure()
ax = fig.add_subplot(projection="polar")    # 指定子图为极坐标系
ax.spines["polar"].set_visible(False)       # 隐藏边框
ax.axes.xaxis.set_visible(False)            # 隐藏X轴
ax.axes.yaxis.set_visible(False)            # 隐藏Y轴
ax.set_ylim([0, 300])
x = [(i * np.pi * 2)/data.shape[0] for i in range(data.shape[0])]   # 计算X轴
color_list = plt.colormaps['inferno'].resampled(48).colors
bar = ax.bar(x, [0]*len(x), width=np.pi/data.shape[0])[0]# 动画函数
def update(i):if i == 0: ax.cla()                # 清除画布ax.set_ylim([0, 300])   # 重新建立Y轴范围for j in range(3):          # 分成三层画柱子bar = ax.bar(x = x[i],           # X轴坐标height=data.iloc[i, j].sum(),   # 每层柱子的高度bottom=0 if j==0 else data.iloc[i, 0:j].sum(),  # 每层柱子的底width=np.pi/data.shape[0],      # 柱子宽度color=color_list[j*16 + i],     # 柱子颜色edgecolor="k",                  # 分隔线颜色linewidth=1,                    # 分隔线宽度)plt.text(x=x[i],                             # 标签的X轴坐标,与柱子相同y=data.iloc[i].sum()*1.05,          # 标签的Y轴坐标,比柱子略高一点,避免重叠s=f"{data.iloc[i].name}: {data.iloc[i].sum()}",     # 标签的文本内容rotation= (i * 360)/data.shape[0],  # 旋转角度rotation_mode="anchor",             # 指定旋转模式horizontalalignment="left",         # 水平对齐方式verticalalignment="center",         # 垂直对齐方式)return bar anim = animation.FuncAnimation(fig=fig, func=update, frames=16, interval=720)anim.save("./sample_02.gif")	# 保存到GIF文件

这篇关于【可视化】Python绘制风车玫瑰图动画的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/278345

相关文章

Git可视化管理工具(SourceTree)使用操作大全经典

《Git可视化管理工具(SourceTree)使用操作大全经典》本文详细介绍了SourceTree作为Git可视化管理工具的常用操作,包括连接远程仓库、添加SSH密钥、克隆仓库、设置默认项目目录、代码... 目录前言:连接Gitee or github,获取代码:在SourceTree中添加SSH密钥:Cl

Python开发文字版随机事件游戏的项目实例

《Python开发文字版随机事件游戏的项目实例》随机事件游戏是一种通过生成不可预测的事件来增强游戏体验的类型,在这篇博文中,我们将使用Python开发一款文字版随机事件游戏,通过这个项目,读者不仅能够... 目录项目概述2.1 游戏概念2.2 游戏特色2.3 目标玩家群体技术选择与环境准备3.1 开发环境3

Python中模块graphviz使用入门

《Python中模块graphviz使用入门》graphviz是一个用于创建和操作图形的Python库,本文主要介绍了Python中模块graphviz使用入门,具有一定的参考价值,感兴趣的可以了解一... 目录1.安装2. 基本用法2.1 输出图像格式2.2 图像style设置2.3 属性2.4 子图和聚

Python使用Matplotlib绘制3D曲面图详解

《Python使用Matplotlib绘制3D曲面图详解》:本文主要介绍Python使用Matplotlib绘制3D曲面图,在Python中,使用Matplotlib库绘制3D曲面图可以通过mpl... 目录准备工作绘制简单的 3D 曲面图绘制 3D 曲面图添加线框和透明度控制图形视角Matplotlib

Pandas中统计汇总可视化函数plot()的使用

《Pandas中统计汇总可视化函数plot()的使用》Pandas提供了许多强大的数据处理和分析功能,其中plot()函数就是其可视化功能的一个重要组成部分,本文主要介绍了Pandas中统计汇总可视化... 目录一、plot()函数简介二、plot()函数的基本用法三、plot()函数的参数详解四、使用pl

一文教你Python如何快速精准抓取网页数据

《一文教你Python如何快速精准抓取网页数据》这篇文章主要为大家详细介绍了如何利用Python实现快速精准抓取网页数据,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以了解下... 目录1. 准备工作2. 基础爬虫实现3. 高级功能扩展3.1 抓取文章详情3.2 保存数据到文件4. 完整示例

使用Python实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句