python风玫瑰图,解决叠加问题

代码中关键问题是bar画图中加入了bottom,柱状叠加画图,这样避免了图的覆盖问题。并且方便用了子函数,在suplot中调中,比用WindroseAxes要方便
python风玫瑰图,解决叠加问题_第1张图片

'''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) # 自定义坐标标签为 NNSN, ……
# 开始绘图
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()

可以一次作几张图
python风玫瑰图,解决叠加问题_第2张图片
作为子程序方便以后调用

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显示出来, 并调整位置

你可能感兴趣的:(地面气象数据,python,风玫瑰,matplotlib)