视界:Magic可视化的下一步将何去何从?

目录

本文翻译自 ECMWF 的一篇通讯文章,介绍 ECMWF 开发可视化工具库 Magics/Magics++ 的历史,并介绍 Magics 未来将如何整合进 ECMWF 新的开源项目中。

What next for Magics visualisation?

by Sylvie Lamy-Thépaut, Stephan Siemen, James Varndell

in ECMWF Newsletter Number 177 - Autumn 2023 (Published in October 2023)

https://www.ecmwf.int/en/newsletter/177/computing/what-next-magics-visualisation

以下正文部分使用 ChatGPT 和文心一言翻译自原文,并根据笔者理解略有修改。

正文

Magics(Meteorological Applications Graphics Integrated System)是 ECMWF 专门为数据可视化而设计的软件库,自 1985 年首次发布以来,已经发生了重大变化。 本文旨在提供 Magics 的发展历史,并强调 Magics 如何不断适应科学家的需求,特别是在生成高质量天气图、有效处理不断增加的数据分辨率以及采用新标准和技术方面。 文章最后探讨了当前的挑战,并介绍了 Magics 将如何发展成为 ECMWF 雄心勃勃的新开源项目 earthkit 的可视化组件。

1980s:将彩色引入天气图

可视化天气预报和观测数据对于理解开发和运行预报模式所涉及的大量数据至关重要。 因此,ECMWF 从一开始就投资建立良好的可视化设施,以使科学家和用户能够处理和开发预报模式并分析其结果:使用预报数据的二维地图和使用其他数据的图形。 在 20 世纪 80 年代,这主要意味着印刷地图,因为计算机屏幕大多分辨率太低,无法显示大型和复杂的地图。 Magics 开发的一个重点是广泛使用颜色,以在地图上叠加不同的参数。

从一开始,开发人员就意识到需要创建一个易于扩展的解决方案,预见到用户的需求和要求会不断增加。 然而,在 80 年代初,扩展用户界面(API)通常涉及向子程序添加参数。 认识到维护这种方法存在的困难,Magics 团队有意决定采取替代策略。 他们选择保持简洁的子程序列表,同时提供大量的参数集。 这个设计选择使用户能够有效定制他们的绘图,简化了文档编制过程。

Magics 首次生成的图是 metgram,它帮助用户查看特定位置关键气象变量的演变。 当时,开源解决方案并不可行。 相反,成员国资助了 ECMWF 软件的开发以支持他们的日常工作。 Magics 本身依赖于 CONICON,这是一个需要付费许可的等值线包。 尽管当时数据分辨率较低,但这种算法对于生成平滑线条是必要的。 Magics 是最早能够可视化用于格点预报和观测的 WMO 标准格式数据的软件包之一(即 GRIB 和 BUFR)。 图1显示了 Magics 提供的早期输出的示例。

图1 1986 年 Magics 生成的地图,显示了根据 850 百帕温度对 30 米风箭头进行着色的能力。这张地图由 Magics 的首位开发者 Jens Daabeck 提供。图片来自原文

1993年,Magics 成为 ECMWF 研发人员使用的工作站 Metview 的图形核心。 科学家们首次能够在屏幕上迅速可视化数据,放大特定区域,交互式选择线条以执行进一步的操作,比如可视化剖面图,以及查看光标下方的要素场值。

2000s 早期:适应网络和 Python

在 2000 年代早期,与天气图创建相关的关键技术发生了变化。 模式分辨率迅速提高,Metview 的使用更加广泛,网络和大屏幕取代了打印机成为展示地图的主要媒介(有关使用打印地图和计算机屏幕的示例,请参见图2)。 与此同时,用户将数据分析和可视化工作从 Fortran 转移到 Python 和网络服务。 由于 Magics 主要是用 Fortran 编写的,并且越来越难以维护,因此决定将 Magics 重写为 C++,并提供额外的接口以创建绘图,包括 C、Python、XML 和 JSON。 为了平稳过渡,决定确保与先前 API 的向后兼容性,并保留由一组全面的参数集增强的有限数量的操作例程的概念。 作为临时名称,“Magics++” 被采用,以与早期版本区分开来。 CONICON 被放弃,改用一个可自由使用的算法,这为开源开发之路敞开了大门,使 Magics 在 2005 年成为最早采用开源 Apache 许可协议分发的 ECMWF 软件包之一。

图2:制作天气图的媒介变化。直到 2000 年代初,打印地图是处理预报数据的主要方式,正如左侧照片所示,这是 2000 年代初 ECMWF MetOps 房间的照片。如右侧 2018 年 ECMWF Weather Room 的照片所示,现在交互式屏幕设置已完全取代了打印地图。

重写为 Magics 提供了集成附加功能的可能性,例如支持 NetCDF 和 ODB(ECMWF 自己用来处理观测数据的格式)、包括政治边界以及实现热力图。 此外,引入了新的图形格式,如 PNG、PDF 或 SVG。 Magics 首次使用外部开源库 cairo 来生成这些不同的格式。 实现了一个新的 Python 接口,与当时用户偏爱的 Metview 宏语言的理念保持一致。 图3 显示了 Metview 显示的天气图示例。

图3:使用 Magics 进行预报分析的 Metview 能力示例,显示 2012 年飓风桑迪。图片来自原文

新版本成为 ecCharts 的图形核心,这是一个用于天气预报数据的高度交互式网络应用,于 2010 年开发。 这一次,用户可以直接在网络浏览器内以本机分辨率放大和平移最新预报。 如今,ecCharts 为超过 250 个参数提供按需可视化,即每天超过 2TB 的预报数据。 为了实现这一点,进行了大规模的优化工作,并创建了大量样式。 随后,这个样式库被移植回到 Magics,实现基于元数据自动选择适当的可视化。 这个自动样式功能在 SkinnyWMS 中广泛使用,SkinnyWMS 是 Open Geospatial Consortium(OGC)Web Map Service 标准的轻量级实现。 这个轻量级实现可以识别 GRIB 或 NetCDF 数据,并允许用户快速可视化、放大和平移他们的数据。 当在 JupyterLab 环境中工作时,这个功能尤其有价值。

2020s:新挑战

然而,局势已经发生了变化,如今 Magics 面临新的挑战。 气象学已经扩展到涵盖更广泛的社群,包括气候和海洋学等领域。 为了促进这个更大社群内的合作和交流,需要缩短学习曲线,以便能够创建复杂的可视化,并转向更符合 Pythonic 的方法。 为了满足这些不断发展的需求,下一代 Magics 将通过提供一个直观的界面来满足这些需求,使新手能够更无缝、更有效地与社群的其他成员互动。

为了实现这一目标,新的 Magics 将成为 ECMWF 领导的激动人心的新开源项目 earthkit 的可视化组件。 作为 Metview 的继任者,earthkit 将通过简化数据访问、分析和可视化,提供强大和方便的 Python 工具,以加速天气和气候科学工作流。 该项目的地理空间可视化组件 earthkit-maps 将通过新的 Python API 提供 Magics 的广泛功能,而其后端将基于像 matplotlib 和 Plotly 等广泛采用的开源包构建。 这一朝着被广泛采用工具的方向转变,将确保在数据可视化生态系统中的兼容性和集成的便捷性。

与当前版本的 Magics 一样,earthkit-maps 的目标是提供广泛的功能,方便可视化气象和气候数据。

在保持速度和高质量之间微妙平衡的同时,earthkit-maps 将继续提供高效的渲染,而不会损害视觉输出。 为了实现这一目标,earthkit-maps 将利用 MIR (ECMWF Meteorological Interpolation and Regridding package),使其能够选择最合适的插值技术。 这种方法有效地减小了数据大小,同时保留了必要的细节,从而优化了可视化效果。 默认情况下,地理区域将适应数据的特定领域,从 Magics 导入的自动样式机制将根据数据特征选择最合适的可视化技术。 这将确保可视化既有意义又信息丰富。 earthkit-maps 将继续提供各种便捷功能,如基于元数据的自动标题、布局和标签,同时还提供了全面的用户自由度,以便轻松自定义可视化。

基于成熟的软件包,过渡到 earthkit-maps 对 Python 用户而言将是平稳的。 同时,我们将为现有的 Magics 和 Metview 用户提供支持,以方便他们的迁移过程。 为了协助过渡,我们将创建专门的 Jupyter 笔记本,重现 Magics 和 Metview 示例库。 这些笔记本将作为实际示例,展示 earthkit-maps 的能力。 此外,我们将制定全面的指南,为希望迁移到 earthkit-maps 的 Magics 和 Metview 用户提供逐步说明。 这些指南将概述必要的步骤,突出关键的区别和改进,并帮助用户充分发挥 earthkit-maps 的潜力。 图4 和图5 分别提供了使用当前版本的 Magics 和 earthkit-maps 生成天气图的示例代码。

YEARS = {
    1993: "Normal conditions",
    1997: "El Nino",
    1998: "La Nina",
}

# getting forecast from CDS

import cdsapi

c = cdsapi.Client()

file_name = "sst_era5_month.grib"

c.retrieve(
    "reanalysis-era5-single-levels-monthly-means",
    {
        "product_type": "monthly_averaged_reanalysis",
        "variable": "sea_surface_temperature",
        "year": list(YEARS),
        "month": [12],
        "day": "01",
        "time": "00:00",
        "area": [90, -180, -90, 180],
        "grid": [0.25, 0.25],
        "format": "grib",
    },
    file_name,
)
import metview as mv

YEARS = {
    1993: "Normal conditions",
    1997: "El Nino",
    1998: "La Nina",
}

file_name = "sst_era5_month.grib"

# read data from file
data = mv.read(file_name)

# define coastlines
coast = mv.mcoast(
    map_coastline_land_shade="on",
    map_coastline_land_shade_colour="charcoal"
)

# define the view: geographical area: [-20, 100, 20, -60]
view = mv.geoview(
    map_area_definition="corners",
    area=[-20, 100, 20, -60],
    coastlines=coast
)

# define a 3x1 layout
page_0 = mv.plot_page(
    top=0, bottom=30, left=5, right=95, view=view,
)
page_1 = mv.plot_page(
    top=33, bottom=63, left=5, right=95, view=view,
)
page_2 = mv.plot_page(
    top=66, bottom=96, left=5, right=95, view=view,
)
dw = mv.plot_superpage(
    pages=[page_0, page_1, page_2]
)

# define the style
style = mv.mcont(
    legent="on",
    contour="off",
    contour_level_selection_type="interval",
    contour_max_level=32,
    contour_min_level=15,
    contour_interval=1,
    contour_label="off",
    contour_shade="on",
    contour_shade_colour_method="palette",
    contour_shade_method="area_fill",
    contour_shade_palette_name="colorbrewer_Spectral_17",
)

# define title
titles = []
short_name = "<grib_info key='shortName' />"
data_info = "<grib_info key='valid-date' format=‘%Y %b' />"
for conditions in YEARS.values():
    titles.append(mv.mtext(
        text_lines=f"{conditions} - ERA5 {short_name} monthly mean: {data_info}",
        text_font_size=0.35,
    ))

# generate plot and save the result in a pdf file.
mv.setoutput(mv.pdf_output(output_name="sst_era5_elnino_map"))
mv.plot(
    dw[0], data[0], style, titles[0],
    dw[1], data[1], style, titles[1],
    dw[2], data[2], style, titles[2],
)

图4 使用当前版本的 Magics 生成三张地图,显示 1993 年 12 月、1997 年 12 月和 1998 年 12 月在热带太平洋地区的海表温度(SST),数据来自 ECMWF 的 ERA5 再分析。图片来自原文

import earthkit

YEARS = {
    1993: "Normal conditions",
    1997: "El Nino",
    1998: "La Nina",
}

# getting forecast data from CDS
data = earthkit.data.from_source(
    "cds",
    "reanalysis-era5-single-levels-monthly-means",
    {
        "product_type": "monthly_averaged_reanalysis",
        "variable": "sea_surface_temperature",
        "year": list(YEARS),
        "month": "12",
        "day": "01",
        "time": "00:00",
        "area": [90, -180, -90, 180],
        "grid": [0.25, 0.25],
    },
)

print(data)

# define the plot, the geographical area and a 3 rows layout
chart = earthkit.maps.Chart(
    domain=[100, 300, -20, 20],
    rows=3,
)

# define the style
style = earthkit.maps.styles.Contour(
    colors="Spectral_r",
    levels=range(15, 33),
    units="celsius",
)

# generate plot
chart.plot(data, style=style)

# add the coastlines
chart.land(color="#555", zorder=10)
chart.gridlines(
    xlocs=range(-180, 180, 20),
    ylocs=range(-20, 20, 10)
)

# add the title
for subplot, conditions in zip(chart, YEARS.values()):
    subplot.title(f"{conditions} - ERA5 SST monthly mean: {{time:%B %Y}}")

# add the legend
chart.legend(location="bottom", ticks=range(15, 33))

# generate the plot and save the result in a pdf file.
chart.save("era5-el-nino.pdf")
chart.show()

图5 使用未来的 earthkit-maps 包生成三张地图,显示与图 4 中相同范围的热带太平洋地区的海表温度(SST)月平均值。图片来自原文

结论

Magics 从早期作为一个具有独特参数化方法的可扩展工具发展而来,已经克服了与数据分辨率和许可相关的挑战,现在面临着在容纳更大社群的新挑战,同时确保平稳的学习曲线和与其他开源软件包的兼容性。 通过持续关注易用性自动数据理解,earthkit-maps 将成为数据可视化领域的一个有力工具。 目前,它正在开发的 beta 阶段,计划于 2024 年发布。

注意:正文部分结束,以下部分为译者添加

讨论

无论从 NCAR 的 NCL [1] 还是从本文 ECMWF 的 Magics++ 来看,气象可视化工具正在经历从编译型语言过渡到脚本语言 Python 的趋势。 笔者不负责任地推测,可能因为随着老一代程序员的退休,熟悉编译型语言的人才越来越难招,维护老工具的成本逐渐提高,而新一代程序员对 Python 更为熟悉,所以只能被迫转向用 Python 开发新的工具。

从 Python 项目的架构上来看,NCAR 和 ECMWF 都采用多项目组合的方式来替代原有单一工具。

NCAR 开发 GeoCAT 系列软件包:

ECMWF 开发 earthkit 系列软件包:

同样 nmcdev 也开发了 nmc_met 系列软件包:

与分散多软件包对应的另外一种形式是单一集成软件包,将所有功能整合到同一个包中。 比如 unidata 的 MetPy [2],dtcenter 的 METPlus ,Met Office 的 iris。 nmcdev 也有两个整合的工具包:

  • metdig:天气学诊断分析工具(仅部分 IO 功能依赖 nmc_met_io 库)
  • meteva:全流程检验程序库(全内置)[3]

笔者参考 geocat、earthkit、nmc_met 等系列软件包的设计,计划开发 cedarkit 工具集,并正在探索适合合作开发开源(或内部开源)项目的工作方式。 计划开发的项目包括:

  • cedarkit-data (暂定):数据,依赖以下项目
    • reki:数据准备
    • cmadaas-client (暂定 nuwe-cmadaas-python):CMADaaS MUSIC 接口客户端,数据源
    • godas-client (暂定):GODAS 客户端 (CEMC 格点数据库),数据源,内部开源 (暂定)
  • cedarkit-comp:计算
  • cedarkit-maps:绘图
  • cedarkit-maps-examples:绘图示例,内部开源 (未来计划开源)

以上项目均在开发或筹备开发阶段,欢迎大家试用。 希望能借助 2024 年业务系统升级切换的机会将单位内部使用的部分 NCL 绘图脚本替换为 Python 绘图包。

参考

原文链接:

What next for Magics visualisation?

项目链接:

ecmwf/earthkit-maps

ecmwf/earthkit-data

参考文献:

[1] The Future of NCL and the Pivot to Python. 2020-11-11. https://www.ncl.ucar.edu/Document/Pivot_to_Python/

[2] May R M, Goebbert K H, Thielen J E, et al. MetPy: A meteorological Python library for data analysis and visualization[J]. Bulletin of the American Meteorological Society, 2022, 103(10): E2273-E2284.

[3] 刘凑华, 代刊, 林建, 等. 天气预报全流程检验评估程序库的设计与实现[J]. 气象, 2023, 49(3): 351-364.