matplotlib quiver 畫風速風向

一個箭頭的組成

image

quiver幾個參數的理解


quiver([X, Y], U, V, [C], **kw),其中kw可供選擇的參數有:算法

units:默認值是width, width/heigth:箭頭的寬度是x或者y軸的總長,沒錯,是總長; dots/inches:箭頭的寬度是設置的dpi或者設置的英寸大小,這個影響了width參數,好比說畫布大小設爲plt.figure(figsize=(144, 72), dpi=10),這個畫布佔1440*720px,若是quiver設置units="dots",width=5,表明以10像素爲基礎單位,5倍的寬度也就是畫一個箭頭它的寬度佔50px,那麼數據就須要抽樣畫了,否則會糊在一塊兒;json

x/y/xy:以x,y,或者xy的平方根爲基礎的寬度,若是x軸或者y軸座標設置步長爲1,和畫布像素大小一致,這樣一個像素對應一個x的整數座標值,那麼就能夠控制箭頭杆的寬度了,箭頭杆的基礎長度就是根號2px;ui

width:float型,用來控制箭頭杆的寬度,我只清楚units=dots時寬度的理解,可是對於units=x/y/xy時寬度到底指的是我暫時是按照上面的理解;spa

angle:uv/xy,uv箭頭的縱橫比(axis aspect ratio)爲1,因此若U==V,則繪圖上箭頭的方向與水平軸逆時針呈45度(正向右);xy箭頭從(x,y)指向(x + u,y + v),例如,使用它來繪製漸變場(gradient field)code

headwidth:float型,默認3,用來控制箭頭三角形底邊的半寬,值指的是杆寬的倍數;blog

headlength: float型,默認5,用來控制箭頭斜邊的長度,值指的是杆寬的倍數,好比4.5指的是杆寬的4.5倍;ip

scale:float型,默認爲None,用來控制桿身的長度,值越小,杆身越長,若是爲None,則使用matplotlib自動縮放算法,箭頭長度單scale_units參數指定utf-8

scale_units:若是該值設置爲width/heigth,則scale應該設爲0.000x的範圍差很少纔是想要的結果,若是設置爲inches,則和你的dpi以及scale相關,對於plt.figure(figsize=(144, 72),dpi=10) scale=1,scale_units="inches"和scale=0.1,scale_units="x/xy/不寫"的畫出來的結果是同樣的;it

pivot:tail/mid/middle/tip,默認tail,指的是箭頭中心,其實就是從哪裏畫io

image

樣例圖


image

所有代碼參考


# _*_coding:utf-8_*_
import matplotlib.pyplot as plt
from PIL import Image
import numpy as np
import os
import sys
import json
import h5py

FILLVALUE = -32767

def assigncolor(tardataset, mask, colorbar):
    if tardataset[mask].size > 0:
        if len(colorbar) >= 4:
            tardataset[mask] = colorbar
        else:
            tardataset[mask] = [colorbar[0], colorbar[1], colorbar[2], 255]
    return tardataset[mask]
    
    
def single_drawer(dataset, colorbar, tardataset):
    #特殊值的處理
    nullmask = np.isnan(dataset[:]) | np.isinf(dataset)
    tardataset[nullmask] = [255, 255, 255, 0]
    for index in range(0, len(colorbar)):
        # 獲取須要進行判斷的值
        valuemask = tardataset[:, :] == [-1, -1, -1, -1]
        # 三維轉二維,方便與dataset的mask合併
        valuemask = valuemask[:, :, 0]
        mask = dataset == colorbar[index][0]
        tardataset[valuemask & mask] = assigncolor(tardataset, valuemask & mask, colorbar[index][1])
    return tardataset


def gradient_drawer(dataset, colorbar, tardataset):
    # 特殊值的處理
    nullmask = np.isnan(dataset[:]) | np.isinf(dataset)
    tardataset[nullmask] = [255, 255, 255, 0]
    # 小於最小值
    valuemask = tardataset[:, :] == [-1, -1, -1, -1]
    valuemask = valuemask[:, :, 0]
    mask = dataset <= colorbar[0][0]
    tardataset[valuemask & mask] = assigncolor(tardataset, valuemask & mask, colorbar[0][1])
    for index in range(0, len(colorbar) - 1):
        # 獲取須要進行判斷的值
        valuemask = tardataset[:, :] == [-1, -1, -1, -1]
        if index == 18:
            print(valuemask.shape)
        valuemask = valuemask[:, :, 0]
        mask = (dataset > colorbar[index][0]) & (dataset <= colorbar[index + 1][0])
        tempmask = valuemask & mask
        if tempmask[tempmask == True].size > 0:
            ratio = (1.0 * (dataset[valuemask & mask] - colorbar[index][0]) / (colorbar[index + 1][0] - colorbar[index][0])).reshape(-1, 1)
            colorrange = (np.array(colorbar[index + 1][1] - np.array(colorbar[index][1]))).reshape(1, -1)
            temp = np.dot(ratio, colorrange) + np.array(colorbar[index][1])
            if len(colorbar[index][1]) < 4:
                alphaband = np.ones((temp.shape[0], 1))
                alphaband[::] = 255
                temp = np.column_stack((temp, alphaband))
            tardataset[valuemask & mask] = temp
    # 大於最大值
    valuemask = tardataset[:, :] == [-1, -1, -1, -1]
    valuemask = valuemask[:, :, 0]
    mask = dataset > colorbar[-1][0]
    tardataset[valuemask & mask] = assigncolor(tardataset, valuemask & mask, colorbar[-1][1])
    return tardataset


def drawWindDir(in_file, u_ds, v_ds, dir_file, cb_file):
    # 讀取調色板
    gradient_cb = []
    single_cb = []
    with open(cb_file, "r") as cb_json:
        cb_data = json.load(cb_json)
        gradient_cb = cb_data["gradient"]
        single_cb = cb_data["single"]

    # 讀取風速
    h5py_obj = h5py.File(in_file, 'r')
    u_data = np.array(h5py_obj[u_ds])
    v_data = np.array(h5py_obj[v_ds])
    sws_data = np.array(h5py_obj["SWS"])

    # 獲取寬高
    uh, uw = np.shape(u_data)
    vh, vw = np.shape(v_data)

    # 上下翻轉數據
    u = np.flip(u_data, 0)
    v = np.flip(v_data, 0)

    # 讀取風速有效值範圍
    sws_valid = h5py_obj["SWS"].attrs['valid range']

    # 用風速有效值控制無效值區域提取
    valid_mask = (sws_data >= sws_valid[0]) & (sws_data <= sws_valid[1])

    # 用u,v向量計算風速
    wp = np.empty((uh, uw), dtype=np.float)
    wp[:, :] = FILLVALUE
    wp[valid_mask] = np.sqrt(np.power(u[valid_mask] / 100.0, 2) + np.power(v[valid_mask] / 100.0, 2))

    # 初始化輸出數據集
    tardataset = np.ones((uh, uw, 4), dtype=np.int)
    tardataset[::] = -1

    # 去掉single調色板的值
    tardataset = single_drawer(sws_data, single_cb, tardataset)

    # 根據gradient調色板從新賦值
    result_data = gradient_drawer(sws_data, gradient_cb, tardataset)

    # 輸出風速的底圖
    new_image = Image.fromarray(result_data.astype(np.uint8)).convert('RGBA')
    new_image.save(in_file.replace(".HDF", ".png"), 'png')

    # 風向的xy座標,uv向量,1440,720,去除無效值
    u_valid = valid_mask
    X, Y = np.meshgrid(np.arange(0, uw, 1), np.flipud(np.arange(0, uh, 1)))

    U = u.astype(np.int64)
    V = v.astype(np.int64)
    newU = np.zeros((uh, uw))
    newV = np.zeros((uh, uw))
    newU[u_valid] = U[u_valid] / np.sqrt(np.power(U[u_valid], 2) + np.power(V[u_valid], 2))
    newV[u_valid] = V[u_valid] / np.sqrt(np.power(U[u_valid], 2) + np.power(V[u_valid], 2))

    # 無效值爲nan
    newU[newU == 0] = np.nan
    newV[newV == 0] = np.nan

    # 建立畫布
    fig1 = plt.figure(figsize=(uw, uh), dpi=1)
    ax1 = fig1.add_subplot(111)

    # 去掉座標軸,去掉兩邊空白,控制輸出的xy軸範圍
    plt.axis('off')
    plt.subplots_adjust(top=1, bottom=0, left=0, right=1, hspace=0, wspace=0)
    plt.ylim(0, uh)
    plt.xlim(0, uw)

    # 柵格抽樣
    i = 10
    Q = ax1.quiver(X[::i, ::i], Y[::i, ::i], newU[::i, ::i], newV[::i, ::i], scale=0.1, width=1, units="xy", angles='uv', headwidth=3.5, headlength=4, pivot="mid")
    ax1.scatter(X[::i, ::i], Y[::i, ::i], color='r', s=30)
    plt.show()

    fig1.savefig(dir_file, transparent=True)
    plt.close()

def mergeDirSpd(spd_img, dir_img, out_img):
    backimage = Image.open(spd_img)
    frontimage = Image.open(dir_img)
    # 暫時沒有考慮分辨率不一致狀況
    outimage = Image.alpha_composite(backimage, frontimage)
    outimage.save(out_img)


if __name__ == "__main__":
    in_path = sys.argv[1]
    ds = sys.argv[2]
    cb_file = sys.argv[3]

    if os.path.isdir(in_path):
        for w_root, w_dirs, dir_files in os.walk(in_path):
            for one_file in dir_files:
                if '.HDF' in one_file and "SWS" in one_file:
                    in_file = os.path.join(w_root, one_file)
                    spd_img = in_file.replace(".HDF", ".png")
                    dir_img = in_file.replace(".HDF", "_dir.png")
                    out_img = in_file.replace(".HDF", "_dp.png")
                    u_ds = "wind_vel_u"
                    v_ds = "wind_vel_v"
                    drawWindDir(in_file, u_ds, v_ds, dir_img, cb_file)
                    mergeDirSpd(spd_img, dir_img, out_img)
    elif os.path.isfile(in_path):
        in_file = in_path
        spd_img = in_file.replace(".HDF", ".png")
        dir_img = in_file.replace(".HDF", "_dir.png")
        out_img = in_file.replace(".HDF", "_dp.png")
        u_ds = "dwind_vel_u"
        v_ds = "wind_vel_v"
        drawWindDir(in_file, u_ds, v_ds, dir_img, cb_file)
        mergeDirSpd(spd_img, dir_img, out_img)
相關文章
相關標籤/搜索