共计 5847 个字符,预计需要花费 15 分钟才能阅读完成。
一个箭头的组成
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, 那么数据就须要抽样画了,不然会糊在一起;
x/y/xy:以 x,y, 或者 xy 的平方根为根底的宽度,如果 x 轴或者 y 轴坐标设置步长为 1,和画布像素大小统一,这样一个像素对应一个 x 的整数坐标值,那么就能够管制箭头杆的宽度了,箭头杆的根底长度就是根号 2px;
width:float 型,用来管制箭头杆的宽度,我只分明 units=dots 时宽度的了解,然而对于 units=x/y/xy 时宽度到底指的是我临时是依照下面的了解;
angle:uv/xy,uv 箭头的纵横比(axis aspect ratio)为 1,所以若 U ==V,则绘图上箭头的方向与程度轴逆时针呈 45 度(正向右);xy 箭头从(x,y)指向(x + u,y + v), 例如,应用它来绘制突变场 (gradient field)
headwidth:float 型,默认 3,用来管制箭头三角形底边的半宽,值指的是杆宽的倍数;
headlength:float 型,默认 5,用来管制箭头斜边的长度,值指的是杆宽的倍数,比方 4.5 指的是杆宽的 4.5 倍;
scale:float 型, 默认为 None, 用来控制杆身的长度,值越小,杆身越长, 如果为 None, 则应用 matplotlib 主动缩放算法,箭头长度单 scale_units 参数指定
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/ 不写" 的画进去的后果是一样的;
pivot:tail/mid/middle/tip,默认 tail, 指的是箭头核心,其实就是从哪里画
样例图
全副代码参考
# _*_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) |