整体的思路是使用contourf
函数实现污染玫瑰图,具体步骤如下:
- 读取数据
- 处理数据
- 数据网格化
- 绘制污染玫瑰图
最终效果如下:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
获取数据
这里我使用的是完整的数据,其中没有nan(缺失值)。我建议在绘图之前如果有缺失或异常数据需要认真处理。这里我们主要展示绘图部分
数据获取地址
file = r'../data/20年2月污染气象参数.xls'
data = pd.read_excel(file, usecols=['时间', '风速(m/s)', '风向(deg)', 'PM2.5'], index_col=0).iloc[:115, :]
data
风向(deg) | 风速(m/s) | PM2.5 | |
---|---|---|---|
时间 | |||
2020-02-01 00:00 | 229.9 | 1.3 | 106 |
2020-02-01 01:00 | 239.3 | 1.1 | 110 |
2020-02-01 02:00 | 243.2 | 0.7 | 98 |
2020-02-01 03:00 | 292.7 | 0.4 | 77 |
2020-02-01 04:00 | 288.2 | 0.5 | 85 |
... | ... | ... | ... |
2020-02-05 14:00 | 75.9 | 4.3 | 9 |
2020-02-05 15:00 | 73.3 | 4.3 | 12 |
2020-02-05 16:00 | 79.1 | 4.5 | 1 |
2020-02-05 17:00 | 74.2 | 4.4 | 8 |
2020-02-05 18:00 | 77.7 | 4.3 | 4 |
115 rows × 3 columns
处理数据
- 将风向数据转化为弧度数据
data['风向(deg)'] = np.radians(data['风向(deg)'])
- 处理风速风向分类的单位
v = data['风速(m/s)']
# 风速按16等分分类
speed = np.linspace(v.min(), v.max(), endpoint=True, num=16)
# 风向按32等分分类
deg = np.linspace(0, 2*np.pi, endpoint=True, num=32)
生成网格数据
def maker(s, sequence):
'''
将划分网格内的数据按较小值划分
'''
for i, val in enumerate(sequence):
if s <= sequence[i+1]:
return val
d = data['风向(deg)']
data['风速(m/s)'] = v.apply(maker, sequence=speed)
data['风向(deg)'] = d.apply(maker, sequence=deg)
data.head()
风向(deg) | 风速(m/s) | PM2.5 | |
---|---|---|---|
时间 | |||
2020-02-01 00:00 | 3.850985 | 1.14 | 106 |
2020-02-01 01:00 | 4.053668 | 0.86 | 110 |
2020-02-01 02:00 | 4.053668 | 0.58 | 98 |
2020-02-01 03:00 | 5.067085 | 0.30 | 77 |
2020-02-01 04:00 | 4.864402 | 0.30 | 85 |
- 使用mean方法对PM2.5数据进行栅格化分类
# 由于整体PM2.5数据有标记,所以需要将2.5数据处理成float类型
data['PM2.5'] = data['PM2.5'].astype(float)
dt = data.pivot_table(values='PM2.5', index='风速(m/s)', columns='风向(deg)', aggfunc=np.mean)
# 补齐网格并对于缺失的网格用0值填充,这样绘图的效果好一些
dt.fillna(0, inplace=True)
dt = dt.reindex(index=speed, columns=deg, fill_value=0)
dt.head(6)
风向(deg) | 0.000000 | 0.202683 | 0.405367 | 0.608050 | 0.810734 | 1.013417 | 1.216100 | 1.418784 | 1.621467 | 1.824151 | ... | 4.459035 | 4.661718 | 4.864402 | 5.067085 | 5.269768 | 5.472452 | 5.675135 | 5.877819 | 6.080502 | 6.283185 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
风速(m/s) | |||||||||||||||||||||
0.30 | 62.0 | 61.0 | 78.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 85.0 | 77.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
0.58 | 82.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 65.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 93.5 | 0.0 |
0.86 | 65.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1.14 | 0.0 | 89.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 66.0 | 30.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1.42 | 0.0 | 0.0 | 0.0 | 0.0 | 37.0 | 0.0 | 0.0 | 0.0 | 91.5 | 24.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
1.70 | 67.0 | 114.0 | 0.0 | 78.0 | 0.0 | 36.0 | 21.0 | 0.0 | 32.0 | 0.0 | ... | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
6 rows × 32 columns
绘制污染玫瑰图
meshgrid()
将网格数据生成绘制数据
theta, r = np.meshgrid(deg, speed)
- 使用
contourf()
绘制污染玫瑰图
ax = plt.subplot(projection='polar')
ax.set_theta_zero_location("N")
ax.set_theta_direction('clockwise')
pos = ax.contourf(theta, r, dt.to_numpy(), cmap='jet')
plt.colorbar(pos, ax=ax)
plt.show()