气ython风雨 发表于 2024-3-28 20:27:21

重磅!Python台风路径还能这样画

本帖最后由 气ython风雨 于 2024-4-30 12:34 编辑

读者来信,想优化一版台风路径绘制
在检索了半天终于找到一个库,tcmarkers。

可以与matplotlib相配合绘制出台风图标,说白了就是提供个marker的矢量文件。Python,很强大吧。

原程序
In :
import os
import pandas as pd
import numpy as np
from pathlib import Path
from typing import List
from typing import Union
from typing import Tuple
from matplotlib.collections import LineCollection
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter
from cartopy.mpl.ticker import LatitudeFormatter
import cartopy.feature as cfeat
import cmaps
def reader(
    typhoon_txt: os.PathLike, code: Union
) -> Tuple, pd.DataFrame]:
    typhoon_txt = Path(typhoon_txt)
    if isinstance(code, int):
      code = "{:04}".format(code)
    with open(typhoon_txt, "r") as txt_handle:
      while True:
            header = txt_handle.readline().split()
            if not header:
                raise ValueError(f"没有在文件里找到编号为{code}的台风")
            if header.strip() == code:
                break
            ))]
      data_path = pd.read_table(
            txt_handle,
            sep=r"\s+",
            header=None,
            names=["TIME", "I", "LAT", "LONG", "PRES", "WND", "OWD"],
            nrows=int(header),
            dtype={
                "I": np.int,
                "LAT": np.float32,
                "LONG": np.float32,
                "PRES": np.float32,
                "WND": np.float32,
                "OWD": np.float32,
            },
            parse_dates=True,
            date_parser=lambda x: pd.to_datetime(x, format=f"%Y%m%d%H"),
            index_col="TIME",
      )
      data_path["LAT"] = data_path["LAT"] / 10
      data_path["LONG"] = data_path["LONG"] / 10
      return header, data_path

head, dat = reader(r"/home/mw/project/CH2014BST(1).txt",'1409')
#print(dat)
lat = dat.LAT
lon = dat.LONG
level = dat.I
pressure = dat.PRES
#创建Figure
fig = plt.figure(figsize=(15, 12), dpi = 150)
#绘制台风路径
ax2 = fig.add_subplot(1,2,2, projection=ccrs.PlateCarree())
#设置ax2的范围
ax2.set_extent()
#为ax1添加海岸线
ax2.coastlines()
ax2.add_feature(cfeat.LAND, alpha = 0.2) #添加大陆特征
ax2.add_feature(cfeat.OCEAN, alpha = 0.5)
#为ax2添加地理经纬度标签及刻度
ax2.set_xticks(np.arange(80,170,10), crs=ccrs.PlateCarree())
ax2.set_yticks(np.arange(0,50,10), crs=ccrs.PlateCarree())
lon_formatter = LongitudeFormatter()
lat_formatter = LatitudeFormatter()
ax2.xaxis.set_major_formatter(lon_formatter)
ax2.yaxis.set_major_formatter(lat_formatter)
# ax2.xaxis.set_major_formatter(cticker.LongitudeFormatter())
# ax2.yaxis.set_major_formatter(cticker.LatitudeFormatter())
#将经纬度数据点存入同一数组
points = np.array().T.reshape(-1, 1, 2)
segments = np.concatenate(, points], axis=1)
#设置色标的标准化范围(即将Z维度的数据对应为颜色数组)
#norm = plt.Normalize(0, 80)   #中心风速的色标
norm = plt.Normalize(0, 6)#台风等级的色标
#设置颜色线条
lc = LineCollection(segments, cmap=cmaps.radar, norm=norm,transform=ccrs.PlateCarree())      
#lc.set_array(dat.WND[:-1])#颜色用中心风速表示
lc.set_array(level[:-1])#颜色用台风等级表示

#绘制线条
line = ax2.add_collection(lc)   
fig.colorbar(lc,ax=ax2,fraction=0.04)




原数据
In :
dat



库安装与官方示例
In :

!pip install tcmarkers -i <a href="https://pypi.mirrors.ustc.edu.cn/simple/" target="_blank">https://pypi.mirrors.ustc.edu.cn/simple/</a>

Looking in indexes: https://pypi.mirrors.ustc.edu.cn/simple/
Collecting tcmarkers
Downloading https://mirrors.bfsu.edu.cn/pypi/web/packages/c7/6e/04ba09ea27742c7d448d65dd521f84cf772cbf455e0eb14b5368837011bf/tcmarkers-0.0.3-py3-none-any.whl (6.9 kB)
Requirement already satisfied: numpy in /opt/conda/lib/python3.7/site-packages (from tcmarkers) (1.21.2)
Requirement already satisfied: matplotlib in /opt/conda/lib/python3.7/site-packages (from tcmarkers) (3.5.0)
Requirement already satisfied: kiwisolver>=1.0.1 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (1.2.0)
Requirement already satisfied: pyparsing>=2.2.1 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (2.4.7)
Requirement already satisfied: packaging>=20.0 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (20.4)
Requirement already satisfied: python-dateutil>=2.7 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (2.8.1)
Requirement already satisfied: cycler>=0.10 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (0.10.0)
Requirement already satisfied: fonttools>=4.22.0 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (4.28.2)
Requirement already satisfied: setuptools-scm>=4 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (6.3.2)
Requirement already satisfied: pillow>=6.2.0 in /opt/conda/lib/python3.7/site-packages (from matplotlib->tcmarkers) (7.2.0)
Requirement already satisfied: six in /opt/conda/lib/python3.7/site-packages (from packaging>=20.0->matplotlib->tcmarkers) (1.15.0)
Requirement already satisfied: setuptools in /opt/conda/lib/python3.7/site-packages (from setuptools-scm>=4->matplotlib->tcmarkers) (49.3.0.post20200809)
Requirement already satisfied: tomli>=1.0.0 in /opt/conda/lib/python3.7/site-packages (from setuptools-scm>=4->matplotlib->tcmarkers) (1.2.2)
Installing collected packages: tcmarkers
Successfully installed tcmarkers-0.0.3

In :
import matplotlib.pyplot as plt
import tcmarkers

fig = plt.figure()
ax = fig.add_subplot(111)

# 设置符号的参数
marker_kwargs = {'markersize': 25, 'color': 'r', 'markeredgecolor': 'r'}

# 绘制台风符号

ax.plot(0, 0.25, marker=tcmarkers.TS, **marker_kwargs)
ax.plot(0.25, 0.20, marker=tcmarkers.SH_TS, **marker_kwargs)


# 显示图形
plt.show()


In :import matplotlib.pyplot as plt
import tcmarkers


fig = plt.figure()
ax = fig.add_subplot(111)

for i, vmax in enumerate():
    ax.plot(i, 2, marker=tcmarkers.tc_marker(vmax), color='r', markeredgecolor='r', markersize=10)
    # pass latitude and SH storms returned for lat < 0
    ax.plot(i, 1, marker=tcmarkers.tc_marker(vmax, -30), color='r', markeredgecolor='r', markersize=10
fig.show()


优化1.0版
将风速表示台风强度修改为等级显示
线段至上加绘台风图标

In :
import os
import pandas as pd
import numpy as np
from pathlib import Path
from typing import List
from typing import Union
from typing import Tuple
from matplotlib.collections import LineCollection
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter
from cartopy.mpl.ticker import LatitudeFormatter
import cartopy.feature as cfeat
import tcmarkers
def reader(
    typhoon_txt: os.PathLike, code: Union
) -> Tuple, pd.DataFrame]:
    typhoon_txt = Path(typhoon_txt)
    if isinstance(code, int):
      code = "{:04}".format(code)
    with open(typhoon_txt, "r") as txt_handle:
      while True:
            header = txt_handle.readline().split()
            if not header:
                raise ValueError(f"没有在文件里找到编号为{code}的台风")
            if header.strip() == code:
                break
            ))]
      data_path = pd.read_table(
            txt_handle,
            sep=r"\s+",
            header=None,
            names=["TIME", "I", "LAT", "LONG", "PRES", "WND", "OWD"],
            nrows=int(header),
            dtype={
                "I": np.int,
                "LAT": np.float32,
                "LONG": np.float32,
                "PRES": np.float32,
                "WND": np.float32,
                "OWD": np.float32,
            },
            parse_dates=True,
            date_parser=lambda x: pd.to_datetime(x, format=f"%Y%m%d%H"),
            index_col="TIME",
      )
      data_path["LAT"] = data_path["LAT"] / 10
      data_path["LONG"] = data_path["LONG"] / 10
      return header, data_path

head, dat = reader(r"/home/mw/project/CH2014BST(1).txt",'1409')
#print(dat)
lat = dat.LAT
lon = dat.LONG
level = dat.I
pressure = dat.PRES
#创建Figure
fig = plt.figure(figsize=(15, 12), dpi = 150)
#绘制台风路径
ax2 = fig.add_subplot(1,2,2, projection=ccrs.PlateCarree())
#设置ax2的范围
ax2.set_extent()
#为ax1添加海岸线
ax2.coastlines()
ax2.add_feature(cfeat.LAND, alpha = 0.2) #添加大陆特征
ax2.add_feature(cfeat.OCEAN, alpha = 0.5)
#为ax2添加地理经纬度标签及刻度
ax2.set_xticks(np.arange(80,170,10), crs=ccrs.PlateCarree())
ax2.set_yticks(np.arange(0,50,10), crs=ccrs.PlateCarree())
lon_formatter = LongitudeFormatter()
lat_formatter = LatitudeFormatter()
ax2.xaxis.set_major_formatter(lon_formatter)
ax2.yaxis.set_major_formatter(lat_formatter)
# ax2.xaxis.set_major_formatter(cticker.LongitudeFormatter())
# ax2.yaxis.set_major_formatter(cticker.LatitudeFormatter())
#将经纬度数据点存入同一数组
points = np.array().T.reshape(-1, 1, 2)
segments = np.concatenate(, points], axis=1)
#设置色标的标准化范围(即将Z维度的数据对应为颜色数组)
#norm = plt.Normalize(0, 80)   #中心风速的色标
norm = plt.Normalize(1, 6)#台风等级的色标
# #设置颜色线条
colors = ['#FFFF00', '#6495ED', '#3CB371', '#FFA500','#FF00FF', '#DC143C']
cmap = plt.cm.colors.ListedColormap(colors)
lc = LineCollection(segments, cmap=cmap, norm=norm,transform=ccrs.PlateCarree())      
#lc.set_array(dat.WND[:-1])#颜色用中心风速表示
lc.set_array(level[:-1])#颜色用台风等级表示
# #绘制线条
line = ax2.add_collection(lc)   
fig.colorbar(lc,ax=ax2,fraction=0.04)
# 绘制图标
for lon_i, lat_i, level in zip(lon, lat, level):
    # 根据风力等级设置图标颜色
    if level == 1:
      color = colors
    elif level == 2:
      color = colors
    elif level == 3:
      color = colors
    elif level == 4:
      color = colors
    elif level == 5:
      color = colors
    elif level == 6:
      color = colors
    # 绘制台风图标
    ax2.plot(lon_i, lat_i, marker=tcmarkers.TS, markersize=3, color=color)


优化2.0
对线段显示进行调整,并增加图例
import os
import pandas as pd
import numpy as np
from pathlib import Path
from typing import List
from typing import Union
from typing import Tuple
from matplotlib.collections import LineCollection
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter
from cartopy.mpl.ticker import LatitudeFormatter
import cartopy.feature as cfeat
import tcmarkers
def reader(
    typhoon_txt: os.PathLike, code: Union
) -> Tuple, pd.DataFrame]:
    typhoon_txt = Path(typhoon_txt)
    if isinstance(code, int):
      code = "{:04}".format(code)
    with open(typhoon_txt, "r") as txt_handle:
      while True:
            header = txt_handle.readline().split()
            if not header:
                raise ValueError(f"没有在文件里找到编号为{code}的台风")
            if header.strip() == code:
                break
            ))]
      data_path = pd.read_table(
            txt_handle,
            sep=r"\s+",
            header=None,
            names=["TIME", "I", "LAT", "LONG", "PRES", "WND", "OWD"],
            nrows=int(header),
            dtype={
                "I": np.int,
                "LAT": np.float32,
                "LONG": np.float32,
                "PRES": np.float32,
                "WND": np.float32,
                "OWD": np.float32,
            },
            parse_dates=True,
            date_parser=lambda x: pd.to_datetime(x, format=f"%Y%m%d%H"),
            index_col="TIME",
      )
      data_path["LAT"] = data_path["LAT"] / 10
      data_path["LONG"] = data_path["LONG"] / 10
      return header, data_path

head, dat = reader(r"/home/mw/project/CH2014BST(1).txt",'1409')

lat = dat.LAT
lon = dat.LONG
level = dat.I
pressure = dat.PRES

# 创建Figure
fig = plt.figure(figsize=(15, 12), dpi = 150)

# 绘制台风路径
ax2 = fig.add_subplot(1,2,2, projection=ccrs.PlateCarree())
ax2.set_extent()
ax2.coastlines()
ax2.add_feature(cfeat.LAND, alpha = 0.2)
ax2.add_feature(cfeat.OCEAN, alpha = 0.5)
ax2.set_xticks(np.arange(80,170,10), crs=ccrs.PlateCarree())
ax2.set_yticks(np.arange(0,50,10), crs=ccrs.PlateCarree())

lon_formatter = LongitudeFormatter()
lat_formatter = LatitudeFormatter()
ax2.xaxis.set_major_formatter(lon_formatter)
ax2.yaxis.set_major_formatter(lat_formatter)

points = np.array().T.reshape(-1, 1, 2)
segments = np.concatenate(, points], axis=1)

norm = plt.Normalize(1, 6)
colors = ['#FFFF00', '#6495ED', '#3CB371', '#FFA500','#FF00FF', '#DC143C']
cmap = plt.cm.colors.ListedColormap(colors)
lc = LineCollection(segments, cmap=cmap, norm=norm, transform=ccrs.PlateCarree())
lc.set_linewidth(0.5)      
lc.set_array(level[:-1])
line = ax2.add_collection(lc)   

# 创建图例
legend_elements = []
for i, color in enumerate(colors):
    legend_elements.append(Line2D(, , marker=tcmarkers.TS,color=color, markersize=5))
   
# 添加图例到图表中
ax2.legend(legend_elements, ['Level 1', 'Level 2', 'Level 3', 'Level 4', 'Level 5', 'Level 6'], loc='lower left')

fig.colorbar(lc, ax=ax2, fraction=0.04)

for lon_i, lat_i, level in zip(lon, lat, level):
    if level == 1:
      color = colors
    elif level == 2:
      color = colors
    elif level == 3:
      color = colors
    elif level == 4:
      color = colors
    elif level == 5:
      color = colors
    elif level == 6:
      color = colors
    ax2.plot(lon_i, lat_i, marker=tcmarkers.TS, markersize=3, color=color)
   
plt.show()
/opt/conda/lib/python3.7/site-packages/ipykernel_launcher.py:38: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations


优化3.0
参考

https://www.heywhale.com/mw/project/5f48b64f5c4b5d00363819bd

替换背景图
增加台风变级时间及箭头



3.0版本的代码还请前往和鲸社区在线运行查看

重磅!Python台风路径还能这样画

文章来源于微信公众号:气ython风雨


FrankJScott 发表于 2024-8-29 00:17:36

Awesome ASIAN2BET Website

In reply to the people talking about pola bonanza xmas hari ini, live rtp tangan judi, slot rtp live hari ini, rtp live olympus, rtp live egp88, bonus138 rtp live, rtp live lido88, rtp live arena369, omega89 live, rtp stars77 hari ini,I highly suggest this helpful hints for RTP ASIAN2BET tips or rtp live pragmatic play, rtp pedro4d, rtp live slot tergacor, idn rtp, pola rtp pragmatic, rtp live egp88, rtp ibc88, rtp live sikat88, rtp bonanza hari ini, rtp live safari88, not to mention this website on RTP ASIAN2BET url on top of rtp live bosswin168, slot online terbaru pragmatic play indonesia, rtp anekaslot99, rtp jam gacor pragmatic hari ini, rtp slot pragmatic mlm ini, rtp 4d slot hari ini, rtp dan jam gacor hari ini, rtp pjslot168, rtp live liga788, rtp live rp369, on top of this check this out about ASIAN2BET url which is also great. Also, have a look at this cool RTP ASIAN2BET info not to mention slotpulsa live, slot rtp gacor, rtp live fixbet88, rtp live slot367, rtp live metro4d, rtp live mpo777, rtp slot hari ini pragmatic play, viral4d rtp live, rtp live gacor77, rtp live pragmatic88, on top of this excellent RTP ASIAN2BET blog with rtp live planet88, rtp tertinggi slot pragmatic hari ini, rtp hepi8, prada188 live, link rtp slot hari ini, https warungslot live, autowin88 rtp live, rtp olympus hari ini, rtp zenwin88, rtp live slot pragmatic play hari ini,for good measure. Check more @ Awesome ASIAN2BET Tips cab878d
页: [1]
查看完整版本: 重磅!Python台风路径还能这样画