气象数据NC、grb2解析成矢量json、CMIS、MICPS及图片应用到webgis

news2024/11/24 14:33:21

一、基础概念

气象数据通常以多种格式存储和交换,以适应不同的应用需求和处理工具。以下是一些常见的气象数据格式及其转换方法的概述:

常见气象数据格式

1. NetCDF(Network Common Data Form):一种自描述、自包含的数据格式,广泛用于存储气象和气候模型输出、观测数据等。NetCDF支持多维度数组、属性和变量,便于跨平台共享。

2. GRIB(GRIdded Binary):主要用于气象预报产品,包括GRIB1和GRIB2两种版本。它以高效的方式存储大量的气象格点数据,如温度、风速等,是气象预报中心之间交换数据的标准格式。

3. HDF(Hierarchical Data Format):类似于NetCDF,支持复杂的数据结构,适用于大规模科学数据集的存储和分发。HDF4和HDF5是两个主要版本。

4. CSV(Comma-Separated Values):简单的文本格式,易于阅读和处理,常用于数据交换,但缺乏自描述性,不包含元数据。

5. GeoTIFF:一种地理空间图像格式,用于存储栅格数据,如卫星图像或气象地图,包含地理坐标信息。

6. BUFR(Binary Universal Form for the Representation of Meteorological Data):国际气象组织推荐的一种二进制编码格式,特别适用于气象观测数据的交换。

数据格式转换方法

1. 使用专业软件:

•Panoply:NASA开发的免费软件,可以打开、查看和转换NetCDF、HDF、GRIB等格式数据。•NCAR Command Language (NCL):提供丰富的脚本语言功能,用于处理NetCDF、GRIB等气象数据。

•GDAL/OGR:开源地理空间库,提供了广泛的格式转换能力,支持NetCDF、HDF、GeoTIFF等格式的转换。

2. 编程语言库:

•Python: 利用netCDF4, pygrib, h5py等库进行数据读写和格式转换。xarray库提供了更高级的数据结构,方便处理NetCDF和GRIB数据。

•MATLAB:内置了对NetCDF、HDF的读写支持,也可通过第三方工具箱处理其他格式。

•R语言:使用ncdf4、raster、rgdal等包处理NetCDF、GRIB、GeoTIFF等格式。

3. 在线转换工具:

虽然不如上述方法灵活,但存在一些在线工具,允许用户上传文件并转换为不同格式,不过这类工具在处理大型气象数据集时可能受限。进行数据格式转换时,需注意保留数据的完整性和准确性,特别是元数据信息,以确保转换后的数据在后续分析中仍然有效。

二、实践应用

关键代码实现

package com.netcdf.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.*;

import static com.netcdf.util.NcUtil.*;

@Controller
@RequestMapping(value = "/ReadGridNc")

public class ReadGridNcData {



    //http://localhost:8087/NetcdfServer/ReadGridNc/getNcData?FilePath=20210708_2021070804.nc&FilterBound=&valField=UGRD_10maboveground
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getNcData", method = RequestMethod.GET)
    public @ResponseBody
    Map GetNcData(String FilePath,String FilterBound,String valField) {
        Map map = AnalysisNC(FilePath, FilterBound,valField,1);
        return map;
    }

    //http://localhost:8087/NetcdfServer/ReadGridNc/GetNcWindData?FilePath=2023042323.grb2
    /**
     *
     * @param FilePath
     * @return
     */
    @RequestMapping(value = "/GetNcWindData", method = RequestMethod.GET)
    public @ResponseBody
    JSONArray GetNcWindData(String FilePath) {
        String map = AnalysisNcWind(FilePath);
        return JSON.parseArray(map);
    }

    //http://localhost:8088/NetcdfServer/ReadGridNc/getNcDataSurface?FilePath=2022090212.nc&FilterBound=&valField=PRES_surface&intvRanges=0,100000,10005,100010,100015&boundPath=1&isIDW=true&isClip=false
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getNcDataSurface", method = RequestMethod.GET)
    public @ResponseBody
    String GetNcDataSurface(String FilePath,String FilterBound,String valField,String intvRanges,String boundPath,boolean isIDW,boolean isClip) {
        String[] Ranges=intvRanges.substring(0,intvRanges.length()).split(",");
        double[] dataInterval = new double[Ranges.length];
        for(int i=0;i<Ranges.length;i++){
            dataInterval[i]=Double.valueOf(Ranges[i]);
            if( i == 1 && dataInterval[i] == 0.0){
                dataInterval[i] = 0.0001;
            }
        }
        Map map = AnalysisNC(FilePath, FilterBound,valField,1);
        if(map!=null) {
            String strGeojson = nc2EquiSurface(map, dataInterval,isClip,boundPath,isIDW);
            return strGeojson;
        }
        return "";
    }

    //http://localhost:8088/NetcdfServer/ReadGridNc/getNcDataSurface1?FilePath=wrf_ll.nc&FilterBound=&valField=RH2M&intvRanges=0,100000,10005,100010,100015&boundPath=1&isIDW=true&isClip=false
    //http://localhost:8088/NetcdfServer/ReadGridNc/getNcDataSurface1?FilePath=wrf_ll.nc&FilterBound=&valField=RH2M&intvRanges=0,70,75,80,85,90,95&boundPath=1&isIDW=false&isClip=false
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getNcDataSurface1", method = RequestMethod.GET)
    public @ResponseBody
    String GetNcDataSurface1(String FilePath,String FilterBound,String valField,String intvRanges,String boundPath,boolean isIDW,boolean isClip) {
        String[] Ranges=intvRanges.substring(0,intvRanges.length()).split(",");
        double[] dataInterval = new double[Ranges.length];
        for(int i=0;i<Ranges.length;i++){
            dataInterval[i]=Double.valueOf(Ranges[i]);
            if( i == 1 && dataInterval[i] == 0.0){
                dataInterval[i] = 0.0001;
            }
        }
        Map map = AnalysisNC1(FilePath, FilterBound,valField,3);
//        Map map = AnalysisNC1(FilePath, FilterBound,valField);
        if(map!=null) {
            String strGeojson = nc2EquiSurface1(map, dataInterval,isClip,boundPath,isIDW);
            return strGeojson;
        }
        return "";
    }

    //http://localhost:8088/NetcdfServer/ReadGridNc/getNcDataMICPS?FilePath=wrf_ll.nc&FilterBound=&valField=RH2M&intvRanges=0,70,75,80,85,90,95&boundPath=1&isIDW=false&isClip=false
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getNcDataMICPS", method = RequestMethod.GET)
    public @ResponseBody
    String GetNcDataMICPS(String FilePath,String FilterBound,String valField,String intvRanges,String boundPath,boolean isIDW,boolean isClip) {
        String[] Ranges=intvRanges.substring(0,intvRanges.length()).split(",");
        double[] dataInterval = new double[Ranges.length];
        for(int i=0;i<Ranges.length;i++){
            dataInterval[i]=Double.valueOf(Ranges[i]);
            if( i == 1 && dataInterval[i] == 0.0){
                dataInterval[i] = 0.0001;
            }
        }
        Map map = AnalysisNC1(FilePath, FilterBound,valField,1);
//        Map map = AnalysisNC1(FilePath, FilterBound,valField);
        if(map!=null) {
            StringBuilder strGeojson = new StringBuilder();
            strGeojson.append("diamond 4 2022年4月1日GFS地面相对湿度3小时预报\n" +
                    "    2022    4    1    0   3   2   0.5  -0.5 \n" +
                    "    96.5 106.5 29.5 20.5 \n" +
                    "    1001 901 5 -50 50 1 0\n");
            strGeojson.append(map.get("val").toString().replace("[","").replace("]","").replaceAll(","," "));

            return strGeojson.toString();
        }
        return "";
    }

    //http://localhost:8088/NetcdfServer/ReadGridNc/getNcDataCMISS?FilePath=wrf_ll.nc&FilterBound=&valField=RH2M&intvRanges=0,70,75,80,85,90,95&boundPath=1&isIDW=false&isClip=false
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getNcDataCMISS", method = RequestMethod.GET)
    public @ResponseBody
    String GetNcDataCMISS(String FilePath,String FilterBound,String valField,String intvRanges,String boundPath,boolean isIDW,boolean isClip) {
        String[] Ranges=intvRanges.substring(0,intvRanges.length()).split(",");
        double[] dataInterval = new double[Ranges.length];
        for(int i=0;i<Ranges.length;i++){
            dataInterval[i]=Double.valueOf(Ranges[i]);
            if( i == 1 && dataInterval[i] == 0.0){
                dataInterval[i] = 0.0001;
            }
        }
        Map map = AnalysisNC1(FilePath, FilterBound,valField,1);
//        Map map = AnalysisNC1(FilePath, FilterBound,valField);
        if(map!=null) {
            StringBuilder strGeojson = new StringBuilder();
            strGeojson.append("{\"returnCode\":\"0\",\"returnMessage\":\"Query Succeed\",\"startLat\":29.5,\"startLon\":96.5,\"endLat\":20.5,\"endLon\":106.5,\"latCount\":901,\"lonCount\":1001,\"latStep\":-0.01,\"lonStep\":0.01,\"requestParams\":\"minlat=20.5&time=20190810000000&fcstele=VVP&datacode=NAFP_FOR_FTM_HIGH_JAP_NEHE&maxlat=29.5&fcstlevel=850&maxlon=106.5&validtime=0&minlon=96.5\",\"requestTime\":\"2019-08-20 08:02:24\",\"responseTime\":\"2019-08-20 08:02:24\",\"takeTime\":\"0.022\",\"fieldNames\":\"湿度\",\"fieldUnits\":\"Pa*s^-1\",\"DS\":[");
            strGeojson.append(map.get("val").toString());
            strGeojson.append("]}");

            return strGeojson.toString();
        }
        return "";
    }


    //http://localhost:8088/NetcdfServer/ReadGridNc/getNcDataSurfaceWind?FilePath=2024050914.nc&FilterBound=&intvRanges=0,2,4,6,8,10&boundPath=1&isIDW=true&isClip=false
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getNcDataSurfaceWind", method = RequestMethod.GET)
    public @ResponseBody
    String GetNcDataSurfaceWind(String FilePath,String FilterBound,String valField,String intvRanges,String boundPath,boolean isIDW,boolean isClip) {
        String[] Ranges=intvRanges.substring(0,intvRanges.length()).split(",");
        double[] dataInterval = new double[Ranges.length];
        for(int i=0;i<Ranges.length;i++){
            dataInterval[i]=Double.valueOf(Ranges[i]);
            if( i == 1 && dataInterval[i] == 0.0){
                dataInterval[i] = 0.0001;
            }
        }
        //导出图片
        AnalysisNCWindyToPng(FilePath, FilterBound,"UGRD_10maboveground","VGRD_10maboveground");
//        Map map = AnalysisNCWindy(FilePath, FilterBound,"UGRD_10maboveground","VGRD_10maboveground");


//        if(map!=null) {
//            String strGeojson = nc2EquiSurface(map, dataInterval,isClip,boundPath,isIDW);
//            return strGeojson;
//        }
        return "nc";
    }
    //http://localhost:8088/NetcdfServer/ReadGridNc/getGribDataSurfaceWind?FilePath=2024050914.grb2&FilterBound=&intvRanges=0,1,2,3,4,5,6,7,8,9,10,11,12&boundPath=1&isIDW=true&isClip=false
    /**
     *
     * @param FilePath
     * @param FilterBound
     * @param valField
     * @return
     */
    @RequestMapping(value = "/getGribDataSurfaceWind", method = RequestMethod.GET)
    public @ResponseBody
    String GetGribDataSurfaceWind(String FilePath,String FilterBound,String valField,String intvRanges,String boundPath,boolean isIDW,boolean isClip) {
        String[] Ranges=intvRanges.substring(0,intvRanges.length()).split(",");
        double[] dataInterval = new double[Ranges.length];
        for(int i=0;i<Ranges.length;i++){
            dataInterval[i]=Double.valueOf(Ranges[i]);
            if( i == 1 && dataInterval[i] == 0.0){
                dataInterval[i] = 0.0001;
            }
        }
        //导出图片
//        AnalysisNCWindyToPng(FilePath, FilterBound,"UGRD_10maboveground","VGRD_10maboveground");
        AnalysisGribWindyToPng(FilePath, FilterBound,"u-component_of_wind_height_above_ground","v-component_of_wind_height_above_ground");


        return "grib";
    }


}
<!DOCTYPE html>
<html>
<head>

    <title>Layers Control Tutorial - Leaflet</title>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" crossorigin=""/>
    <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" crossorigin=""></script>


    <style>
        html, body {
            height: 100%;
            margin: 0;
        }
        #map {
            width: 1000px;
            height: 700px;
        }
    </style>


</head>
<body>

<div id='map'></div>

<script>

    var grayscaleLayer= L.tileLayer('http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}', {id: 'map11',maxZoom: 16,minZoom: 4});

    var map = L.map('map', {
        minZoom: 5,
        maxZoom: 12,
        center: [21, 100],
        zoom: 10,
        zoomDelta: 0.5,//点击+-按钮的放缩刻度尺度,默认值1
        zoomSnap: 0.5,//地图能放缩的zoom的最小刻度尺度,默认值1
        fullscreenControl: false,//全屏控件,不显示
        zoomControl: false,//放大缩小控件,不显示
        attributionControl: false//右下角属性控件,不显示
    });
    map.addLayer(grayscaleLayer);


    var imageBounds = [[20.5, 96.5], [29.41, 106.5]];//图片的经纬度范围,西南角点,东北角点(纬度、经度)
    var imageUrl='pixel_art.png';//图片的地址
    var imageLayer =L.imageOverlay(imageUrl, imageBounds,{opacity:0.8});//opacity是透明度
    map.addLayer(imageLayer);

    //如果imageLayer已经创建,后续只需要切换url即可
    if(imageLayer!=null)
    {
        imageLayer.setUrl(imageUrl);
    }
</script>

</body>
</html>

转换成图片成果

示例调用实现

转换成矢量json成果

转换成MICPS成果

转换成CMIS成果

 前端可视效果

成果应用展示

参照windy配置可视化实现

 如果对您有所帮助,请点赞打赏支持!

技术合作交流qq:2401315930

最后分享一下地图下载器设计及下载地址:

链接:https://pan.baidu.com/s/1RZX7JpTpxES-G7GiaVUxOw 
提取码:61cn

地图下载器代码结构设计及功能实现_地图下载管理器解析-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1830368.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SD卡、MicroSD卡与SD NAND的全面对比分析

在当今多样化的存储设备市场中&#xff0c;SD卡、MicroSD卡和SD NAND因其不同的特性和应用场景而广受欢迎。这三种存储解决方案各有千秋&#xff0c;为消费者提供了丰富的选择。以下是MK米客方德SD卡、MicroSD卡和SD NAND全面的对比分析&#xff1a;

springboot“漫画之家”系统 LW+PPT+源码

3 系统分析 链接&#xff1a;https://pan.baidu.com/s/1ihILTui-XEFdC15mcOB0vA?pwdewry 提取码&#xff1a;ewry 3.1系统可行性分析 3.1.1经济可行性 由于本系统是作为毕业设计系统&#xff0c;且系统本身存在一些技术层面的缺陷&#xff0c;并不能直接用于商业用途&#xf…

英伟达发布开源模型Nemotron-4 340B

&#x1f680; 英伟达发布开源模型Nemotron-4 340B 摘要&#xff1a;英伟达最新发布的开源模型Nemotron-4 340B&#xff0c;可能彻底改变大语言模型&#xff08;LLM&#xff09;训练方式。该模型支持多种自然语言和编程语言&#xff0c;使用9万亿个token训练&#xff0c;高达9…

python数据分析-心脏瓣膜手术风险分析与预测

一、研究背景和意义 人的心脏有四个瓣膜&#xff0c;主动脉银、二尖、肺动脉和三尖源 不管是那一个膜发生了病变&#xff0c;都会导致心脏内的血流受到影响&#xff0c;这就是通常所说的心脏期膜病&#xff0c;很多是需要通过手术的方式进行改善的。随着人口老龄化的加剧,&…

Aeron:Multi-Destination-Cast

Multi-Destination-Cast&#xff08;MDC&#xff09;是一种功能&#xff0c;允许 Aeron 从单个 Publication 同时向多个目的地传送数据。Multiple-Destination-Cast是 Aeron 的一项高级功能&#xff0c;本指南将介绍如何开发一个简单示例的基本知识。 一、MDC Publications 注&…

机器学习中的监督学习介绍

In this post well go into the concept of supervised learning, the requirements for machines to learn, and the process of learning and enhancing prediction accuracy. 在这篇文章中&#xff0c;我们将深入探讨监督学习的概念、机器学习的要求以及学习和提高预测准确…

Proxmox VE (PVE) 教学 (3) | 在 Proxmox VE 中安装与配置 OpenWrt

大家好,很长时间没有更新这个系列了。最近正在开发新项目,刚刚想起来我是不是还有一个什么专栏没更新。 本期的网络配置背景同于前两期的描述( 详见https://www.hestudio.net/category/proxmox-ve/ ),这一期只是对网络配置的扩展,也就是安装软路由,实现网络配置的更多功…

计算机网络:1概述

概述 因特网 网络、互连网&#xff08;互联网&#xff09;与因特网的区别与关系 若干节点和链路互连形成网络&#xff0c;若干网络通过路由器互连形成互连网&#xff0c;世界上最大的互连网是互联网&#xff08;因特网Internet&#xff09;。 因特网发展的三个阶段 因特网…

【挑战100天首通《谷粒商城》】-【第一天】【10 番外篇】 解决docker 仓库无法访问 + MobaXterm连接VirtualBox虚拟机

文章目录 课程介绍 1、解决docker 仓库无法访问 2、 MobaXterm连接VirtualBox虚拟机 Stage 1&#xff1a;下载MobaXterm选择适合你的版本 Stage 2&#xff1a;vagrant ssh 连接&#xff0c;开启ssh访问 Stage 2-1&#xff1a;su获取root账号权限,输入密码&#xff08;默认vagra…

C语言笔记第15篇:文件操作

1、为什么使用文件&#xff1f; 如果没有文件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运行程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据进行持久化…

Java 集合框架:LinkedList 的介绍、使用、原理与源码解析

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 014 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

【漏洞复现】畅捷通T+ App_Code.ashx 远程命令执行漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

什么是加密算法,有什么不同类型?

加密算法是一种数学函数或程序&#xff0c;它能够将原始的、可读的数据&#xff08;也称为“明文”&#xff09;转换为一种不可读的代码形式&#xff08;称为“密文”&#xff09;。这种转换是通过特定的算法和密钥来实现的&#xff0c;目的是保护数据的机密性和完整性&#xf…

HTML表单深度解析:构建互动的网页界面

表单是HTML中用于收集用户输入信息的重要元素&#xff0c;是网页与用户交互的关键组件。以下是一个典型的HTML表单示例&#xff0c;我们将会详细解析其中的各个元素及属性含义。 <form action"https://xx.xxx.xx/search" target"_self" method"ge…

CDN简介

CDN 的基本概念 CDN&#xff08;Content Delivery Network&#xff09;&#xff0c;即内容分发网络。 CDN是一种分布式网络架构&#xff1a;它由分布在不同地理位置的服务器组成网络&#xff0c;这些服务器协同工作以提供内容服务。 内容分发的核心目标 确保用户能够快速、可…

WordPress管理员后台登录地址修改教程,WordPress admin登录地址文件修改方法

我们使用WordPress时&#xff0c;管理员后台登录默认地址为“域名/wp-login.php”或“域名/wp-admin”&#xff0c;为了安全&#xff0c;一般会把此地址改掉&#xff0c;防止有人恶意来攻击咱的WordPress&#xff0c;今天出个WordPress后台登录地址修改教程&#xff0c;修改之后…

[oeasy]python0021_宝剑镶宝石_爱之石中剑_批量替换_特殊字符_特殊颜色

继续运行 &#x1f94b; 回忆上次内容 上次 运行了 game.py分析了 game.py也大致读懂了 game.py 这个 程序 可以进一步 进行修改吗&#xff1f;&#xff1f; 添加爱心 可以 把这个 ❤ 选中并复制 再粘贴到 虚拟机右侧的 剪贴板 然后 回到 游戏程序 进行修改和粘贴 按方向键h…

2024广州光亚展参展记录

参展总结 智控面板外观设计百家齐放&#xff0c;但始终逃不出几大设计元素的组合&#xff08;各种尺寸的屏、不同规则的按键切分、不同材质的面板材质&#xff09;&#xff1b;互联互通的趋势明显&#xff0c;接入米家、小度、涂鸦、HomeKit平台成为众多厂商的首选&#xff1b;…

JavaFX BorderPane布局

BorderPane布局顶部&#xff0c;底部&#xff0c;左&#xff0c;右或中心区域中的子节点。每个区域只能有一个节点。BorderPane的顶部和底部区域允许可调整大小的节点占用所有可用宽度。 左边界区域和右边界区域占据顶部和底部边界之间的可用垂直空间。 默认情况下&#xff0c…

一二三应用开发平台应用开发示例(3)——生成库表及后端代码

生成库表 前端页面的配置&#xff0c;也就是视图功能&#xff0c;我们先放一放&#xff0c;来看看生成库表和后端代码。 关闭实体配置界面&#xff0c;回到实体列表&#xff0c;勾选“文件夹”实体&#xff0c;点击“生成库表”&#xff0c;并确定。 系统提示成功后&#xff…