代码中关键问题是bar画图中加入了bottom,柱状叠加画图,这样避免了图的覆盖问题。并且方便用了子函数,在suplot中调中,比用WindroseAxes要方便
'''Author Wudongqiao 2022.10.09'''
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
#-------设置支持中文----------------------#
# import matplotlib as mpl
# mpl.rcParams['font.sans-serif'] = ['SimHei'] #设置简黑字体
# mpl.rcParams['axes.unicode_minus'] = False
#-------自定义坐标轴刻度格式----------------#
from matplotlib.ticker import FuncFormatter
import tkinter.filedialog
path=tkinter.filedialog.askopenfilename()
print('需至少有两列数据,字段名为wd,ws')
df=pd.read_csv(path)[['wd','ws']]
print(df)
'''==================================输出各方位的占比、样本数表==========================='''
wd_labs='N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW'.split(' ')
data=pd.DataFrame(columns=wd_labs,index=['0~2', '2~4', '4~6','6~8','8~inf'])
total_n=len(df)
ws_1,ws_2,ws_3,ws_4,ws_5=[],[],[],[],[]
for i in range(16):
if i == 0:
temp_wd=df[(df['wd'] <=11.25) | (df['wd'] >= 348.75)]
ws_1.append(len(temp_wd[(temp_wd['ws']>=0) & (temp_wd['ws']<2)]))
ws_2.append(len(temp_wd[(temp_wd['ws']>=2) & (temp_wd['ws']<4)]))
ws_3.append(len(temp_wd[(temp_wd['ws']>=4) & (temp_wd['ws']<6)]))
ws_4.append(len(temp_wd[(temp_wd['ws']>=6) & (temp_wd['ws']<8)]))
ws_5.append(len(temp_wd[(temp_wd['ws']>=8)]))
elif i>0:
temp_wd=df[((df['wd'] >= 22.5 * i - 11.25)) & (df['wd'] <= 22.5 * i + 11.25)]
ws_1.append(len(temp_wd[(temp_wd['ws']>=0) & (temp_wd['ws']<2)]))
ws_2.append(len(temp_wd[(temp_wd['ws']>=2) & (temp_wd['ws']<4)]))
ws_3.append(len(temp_wd[(temp_wd['ws']>=4) & (temp_wd['ws']<6)]))
ws_4.append(len(temp_wd[(temp_wd['ws']>=6) & (temp_wd['ws']<8)]))
ws_5.append(len(temp_wd[(temp_wd['ws']>=8)]))
data.loc['0~2']=ws_1
data.loc['2~4']=ws_2
data.loc['4~6']=ws_3
data.loc['6~8']=ws_4
data.loc['8~inf']=ws_5
#转化为百分比数据
data = data /total_n
print(data)
N = 16 # 风速分布为16个方向
theta = np.linspace(0, 2*np.pi, N, endpoint=False) # 获取16个方向的角度值
width = np.pi / N # 绘制扇型的宽度,可以自行调整
labels = list(data.columns) # 自定义坐标标签为 N , NSN, ……
# 开始绘图
plt.figure(figsize=(8,8))
ax = plt.subplot(111, projection='polar')
bottom = [0 for i in range(16)]
for idx in data.index:
# 每一行绘制一个扇形
radii = data.loc[idx] # 每一行数据
ax.bar(theta, radii, width=width, bottom=bottom, label=idx, tick_label=labels)
bottom = bottom + radii
#------------------------------------#
ax.set_theta_zero_location('N') #设置零度方向北
ax.set_theta_direction(-1) # 逆时针方向绘图
#--------自定义yaxis的刻度格式-----------#
plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda s, position: '{:.0f}%'.format(100*s)))
plt.legend() # 将label显示出来, 并调整位置
plt.savefig('风向风速占比玫瑰图.jpg')
plt.show()
def plot_windrose(df,sea,ax):
wd_labs = 'N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW'.split(' ')
data_x=pd.DataFrame(columns=wd_labs,index=['0~2', '2~4', '4~6','6~8','8~inf'])
total_n=len(df)
ws_1,ws_2,ws_3,ws_4,ws_5=[],[],[],[],[]
for i in range(16):
if i == 0:
temp_wd=df[(df['wd'] <=11.25) | (df['wd'] >= 348.75)]
ws_1.append(len(temp_wd[(temp_wd['ws']>=0) & (temp_wd['ws']<2)]))
ws_2.append(len(temp_wd[(temp_wd['ws']>=2) & (temp_wd['ws']<4)]))
ws_3.append(len(temp_wd[(temp_wd['ws']>=4) & (temp_wd['ws']<6)]))
ws_4.append(len(temp_wd[(temp_wd['ws']>=6) & (temp_wd['ws']<8)]))
ws_5.append(len(temp_wd[(temp_wd['ws']>=8)]))
elif i>0:
temp_wd=df[((df['wd'] >= 22.5 * i - 11.25)) & (df['wd'] <= 22.5 * i + 11.25)]
ws_1.append(len(temp_wd[(temp_wd['ws']>=0) & (temp_wd['ws']<2)]))
ws_2.append(len(temp_wd[(temp_wd['ws']>=2) & (temp_wd['ws']<4)]))
ws_3.append(len(temp_wd[(temp_wd['ws']>=4) & (temp_wd['ws']<6)]))
ws_4.append(len(temp_wd[(temp_wd['ws']>=6) & (temp_wd['ws']<8)]))
ws_5.append(len(temp_wd[(temp_wd['ws']>=8)]))
data_x.loc['0~2']=ws_1
data_x.loc['2~4']=ws_2
data_x.loc['4~6']=ws_3
data_x.loc['6~8']=ws_4
data_x.loc['8~inf']=ws_5
#转化为百分比数据
_sum=data_x.apply(np.sum)
data = data_x /total_n
print(data)
N = 16 # 风速分布为16个方向
theta = np.linspace(0, 2*np.pi, N, endpoint=False) # 获取16个方向的角度值
width = np.pi / N # 绘制扇型的宽度,可以自行调整
bottom=[0 for i in range(16)]
for idx in data.index:
# 每一行绘制一个扇形
'''将数据叠加'''
radii = data.loc[idx] # 每一行数据
ax.bar(theta, radii, width=width, bottom=bottom, label=idx, tick_label=labels)
bottom=bottom+radii
#------------------------------------#
ax.set_theta_zero_location('N') #设置零度方向北
ax.set_theta_direction(-1) # 逆时针方向绘图
#--------自定义yaxis的刻度格式-----------#
ax.yaxis.set_major_formatter(FuncFormatter(lambda s, position: '{:.1f}%'.format(100*s)))
ax.set_title(sea)
ax.legend() # 将label显示出来, 并调整位置
另外一种方法用WindroseAxes代码更简单,不过不方便做多图
def windrose(df,sea,ax):
wd=df['wd'].tolist()
ws=df['ws'].tolist()
ax = WindroseAxes.from_ax()
ax.bar(wd, ws, normed=True, opening=0.8, edgecolor='white',bins=np.arange(0,16,2))
#--------自定义yaxis的刻度格式-----------#
ax.yaxis.set_major_formatter(FuncFormatter(lambda s, position: '{:.1f}%'.format(s)))
ax.set_title(sea)
ax.legend() # 将label显示出来, 并调整位置