当前位置: 首页 > news >正文

JAVA读取netCdf文件并绘制热力图

读取netCdf的依赖

		<dependency><groupId>ucar</groupId><artifactId>netcdfAll</artifactId><version>5.5.3</version><scope>system</scope><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>spi</artifactId></exclusion></exclusions><systemPath>${basedir}/libs/netcdfAll-5.5.3.jar</systemPath></dependency>

读取文件入库

import cn.iscas.eneity.*;
import cn.iscas.picture.HeatPictureGenerator;
import cn.iscas.util.DateAddition;
import cn.iscas.util.GzipCompressUtil;
import cn.iscas.util.LogUtil;
import cn.iscas.util.PropertiesUtil;
import com.google.common.collect.ImmutableList;
import com.iscas.datasong.client.DataSongClient;
import com.iscas.datasong.client.DataSongHttpClient;
import com.iscas.datasong.client.domain.DataSongSearchResult;
import com.iscas.datasong.lib.common.DataSongException;
import com.iscas.datasong.lib.request.SearchDataRequest;
import com.iscas.datasong.lib.request.search.builder.ConditionBuilder;
import com.iscas.datasong.lib.request.search.condition.search.TermSearchCondition;
import com.iscas.datasong.lib.util.DataSongJsonUtils;
import ucar.nc2.NetcdfFile;
import ucar.nc2.Variable;
import java.io.IOException;
import java.util.*;public static void salinitySaveDataSong(String fileName) throws IOException, DataSongException {NetcdfFile file = NetcdfFile.open(fileName);Map map = new HashMap<>();ImmutableList<Variable> variables = file.getVariables();for (Variable var : variables) {String varName = var.getFullName();Object o = var.read().copyToNDJavaArray();map.put(varName, o);}List<Salinity> salinityList = new ArrayList<>();int[] time = (int[]) map.get("time");float[] lev = (float[]) map.get("lev");float[][][][] ss = (float[][][][]) map.get("ss");float[] lat = (float[]) map.get("lat");float[] lon = (float[]) map.get("lon");for (int i = 0; i < time.length; i++) {for (int j = 0; j < lev.length; j++) {Salinity salinity = new Salinity();salinity.setTime(DateAddition.addDays365(time[i]));salinity.setLev(lev[j]);salinity.setLat(Arrays.toString(lat));salinity.setLon(Arrays.toString(lon));salinity.setNetCdfPath(fileName);//压缩数据String compress = GzipCompressUtil.compress(DataSongJsonUtils.toJson(ss[i][j]));salinity.setSs(compress);salinityList.add(salinity);}}DataSongClient dataSongClient = DataSongHttpClient.getInstance(dataSongIp, dataSongPort);dataSongClient.setDatabaseName(dataSongDatabase);dataSongClient.getDataService().batchSaveData(salinityList).toString();LogUtil.debug(fileName + "入库解析完成");}

读取入库数据

public static void salinityGeneratorPicture(String netCdfPath) throws DataSongException {DataSongClient dataSongClient = DataSongHttpClient.getInstance(dataSongIp,dataSongPort);dataSongClient.setDatabaseName(dataSongDatabase);TermSearchCondition levTermSearchCondition = ConditionBuilder.termCondition("netCdfPath", netCdfPath);SearchDataRequest searchDataRequest = new SearchDataRequest();searchDataRequest.setSearch(levTermSearchCondition);DataSongSearchResult<Salinity> salinityDataSongSearchResult = dataSongClient.getDataService().searchData(Salinity.class, searchDataRequest);List<Salinity> items = salinityDataSongSearchResult.getItems();String ss = "";String lat = "";String lon = "";String pictureName = "";for (Salinity salinity : items) {salinity.setSs(GzipCompressUtil.decompress(salinity.getSs()));ss = salinity.getSs();lat = salinity.getLat();lon = salinity.getLon();pictureName = "salinity" + "_" + salinity.getTime() + "_" + Float.valueOf(salinity.getLev()).intValue();float[] latitudes = DataSongJsonUtils.fromJson(lat, float[].class);float[] longitudes = DataSongJsonUtils.fromJson(lon, float[].class);double[][] values = DataSongJsonUtils.fromJson(ss, double[][].class);//画图String pictureFile = HeatPictureGenerator.pictureGenerator(pictureName, latitudes, longitudes, values);if (pictureFile != null) {salinity.setPicturePath(pictureFile);//写入生成的图片位置dataSongClient.getDataService().updateData(salinity);salinity.setSs("");LogUtil.debug("记录一条"+salinity);}}}

绘制热力图

import javax.imageio.ImageIO;
import cn.iscas.util.LogUtil;
import cn.iscas.util.PropertiesUtil;
import com.iscas.datasong.lib.common.DataSongException;
import java.awt.*;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
/*** 生成热力图(tiff,png格式)* 示例的经度、纬度和对应的值** @param latitudes  float[] longitudes = {100.0f, 200.0f, 300.0f, 400.0f, 500.0f};* @param longitudes float[] latitudes = {100.0f, 150.0f, 200.0f, 250.0f, 300.0f};* @param values     double[][] values = {*                   {0.2, 0.4, 0.6, 0.8, 1.0},*                   {0.3, 0.5, 0.7, 0.9, 1.1},*                   {0.4, 0.6, 0.8, 1.0, 1.2},*                   {0.5, 0.7, 0.9, 1.1, 1.3},*                   {0.6, 0.8, 1.0, 1.2, 1.4}*                   };*/public static String pictureGenerator(String pictureName, float[] latitudes, float[] longitudes, double[][] values) {// 定义图像宽高
//        int width = 1600;
//        int height = 1300;int messageHeight = 100;int width = 1486;int height = 910 + messageHeight;// 创建BufferedImage对象BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 获取Graphics2D对象以便绘制Graphics2D g2d = image.createGraphics();// 设置背景颜色为白色g2d.setColor(Color.WHITE);g2d.fillRect(0, 0, width, height);// 找到最小值和最大值double minValue = Double.MAX_VALUE;double maxValue = Double.MIN_VALUE;for (int i = 0; i < latitudes.length; i++) {for (int j = 0; j < longitudes.length; j++) {if (values[i][j] != 1.0E35 && !Double.isNaN(values[i][j]) && !Double.isInfinite(values[i][j])) {if (values[i][j] < minValue) {minValue = values[i][j];}if (values[i][j] > maxValue) {maxValue = values[i][j];}}}}// 确定经度和纬度的最大最小值,用于缩放坐标float minLongitude = Float.MAX_VALUE;float maxLongitude = Float.MIN_VALUE;float minLatitude = Float.MAX_VALUE;float maxLatitude = Float.MIN_VALUE;for (float longitude : longitudes) {if (longitude < minLongitude) minLongitude = longitude;if (longitude > maxLongitude) maxLongitude = longitude;}for (float latitude : latitudes) {if (latitude < minLatitude) minLatitude = latitude;if (latitude > maxLatitude) maxLatitude = latitude;}// 绘制数据点for (int i = 0; i < latitudes.length; i++) {for (int j = 0; j < longitudes.length; j++) {// 缩放坐标int x = Math.round((longitudes[j] - minLongitude) / (maxLongitude - minLongitude) * (width - 1));
//                int y = Math.round((latitudes[i] - minLatitude) / (maxLatitude - minLatitude) * (height - 1));int y = Math.round(height - messageHeight - 1 - ((latitudes[i] - minLatitude) / (maxLatitude - minLatitude) * (height - messageHeight - 1)));// 剔除无效值if (values[i][j] == 1.0E35 || Double.isNaN(values[i][j]) || Double.isInfinite(values[i][j])) {// 使用一个默认值或跳过这个数据点g2d.setColor(Color.GRAY);g2d.fillRect(x, y, 2, 2);} else {// 归一化处理float value = (float) ((values[i][j] - minValue) / (maxValue - minValue));// 根据值计算颜色
//                Color color = new Color(value, 0.0f, 1.0f - value); // 从蓝到红的渐变色// 将 value 从 [0, 1] 映射到 [0, 255] 的色调值(因为色调是 0-360 度的循环,但我们可以将其转换为 0-255 的范围)// 将 value 从 [0, 1] 映射到 [0, 240] 的色调值(因为蓝色是 240 度,红色是 0 度)float hue = (float) (240.0 - value * 240.0); // 从蓝色(240)渐变到红色(0)// 你可以设置固定的饱和度和亮度值,或者根据需要进行调整float saturation = 1.0f; // 完全饱和float brightness = 1.0f; // 最大亮度// 使用 HSB 值创建颜色Color color = Color.getHSBColor(hue / 360f, saturation, brightness);g2d.setColor(color);g2d.fillOval(x, y, 2, 2); // 绘制圆形点}}}// 绘制颜色条int colorbarHeight = 50; // 颜色条的高度int colorbarY = height - colorbarHeight; // 颜色条的位置int colorbarWidth = width - 200; // 颜色条的长度与图片宽度相同// 计算每个像素代表的值,注意减1,避免除以0double valuePerPixel = (maxValue - minValue) / (colorbarWidth - 1);// 绘制颜色条g2d.setColor(Color.BLACK); // 假设背景是黑色g2d.fillRect(0 + 80, colorbarY, colorbarWidth, colorbarHeight);for (int b = 0; b < colorbarWidth; b++) {double currentValue = minValue + b * valuePerPixel;// 计算色调值从蓝色(240)渐变到红色(0)float hueValue = 240f - (float) ((currentValue - minValue) / (maxValue - minValue) * 240);// 创建颜色Color color = Color.getHSBColor(hueValue / 360f, 1.0f, 1.0f); // 使用240来归一化hue// 设置颜色并绘制像素块g2d.setColor(color);g2d.fillRect(b + 80, colorbarY, 1, colorbarHeight);}// 绘制刻度线和标签int tickSpacing = colorbarWidth / 10; // 假设我们想要5个刻度线int tickLength = 10;int labelSpacing = tickSpacing; // 假设标签之间的间隔是刻度线间隔String format = "%.2f"; // 设置值的格式,这里保留两位小数for (int x = 0; x <= colorbarWidth; x += tickSpacing) {// 绘制刻度线g2d.setColor(Color.BLACK);g2d.drawLine(x + 80, colorbarY, x + 80, colorbarY + tickLength);// 计算当前刻度对应的值double currentValue = minValue + x * valuePerPixel;// 只在特定的间隔上绘制标签if (x % labelSpacing == 0) {// 绘制标签String label = String.format(format, currentValue);FontMetrics fm = g2d.getFontMetrics();int labelX = x - fm.stringWidth(label) / 2 + 80;int labelY = colorbarY + colorbarHeight + 15; // 设置标签的y坐标g2d.setColor(Color.BLACK);g2d.setFont(new Font("Default", Font.PLAIN, 20));g2d.drawString(label, labelX, labelY - 30);}}// 绘制标签g2d.setColor(Color.BLACK);g2d.drawString("Max: " + maxValue + "        " + "Min: " + minValue, 10, colorbarY + colorbarHeight - 60);// 释放Graphics2D资源g2d.dispose();// 保存图像为TIFF或者PNG文件,修改pathName和formatName即可try {File output = new File(picturePath + pictureName + ".tiff");ImageIO.write(image, "TIFF", output);LogUtil.debug("PNG图像已成功保存到 " + output.getAbsolutePath());return output.getAbsolutePath();} catch (IOException e) {e.printStackTrace();LogUtil.error("图片生成异常" + LogUtil.getStackTraceAsString(e));return null;}}

相关文章:

JAVA读取netCdf文件并绘制热力图

读取netCdf的依赖 <dependency><groupId>ucar</groupId><artifactId>netcdfAll</artifactId><version>5.5.3</version><scope>system</scope><exclusions><exclusion><groupId>org.slf4j</groupId…...

数据结构——八大排序

一.排序的概念和其应用 1.1排序的概念 排序&#xff1a;排列或排序是将一组数据按照一定的规则或顺序重新组织的过程&#xff0c;数据既可以被组织成递增顺序&#xff08;升序&#xff09;&#xff0c;或者递减顺序&#xff08;降序&#xff09;。稳定性&#xff1a;假定在待…...

【Unity】RPG2D龙城纷争(十九)流程与UI界面(终章)

更新日期:2024年8月1日。 项目源码:第五章发布(正式开始游戏逻辑的章节) 索引 简介一、游戏流程1.初始化流程2.开始流程3.关卡流程4.关卡结束流程5.启用所有流程二、UI界面逻辑1.开始界面2.存档界面3.关卡界面DataRegion 数据显示逻辑区域RoundRegion 回合逻辑区域RoleMenu…...

C#类和结构体的区别

1、类class是引用类型&#xff0c;多个引用类型变量的值会互相影响。存储在堆&#xff08;heap&#xff09;上 2、结构体struct是值类型&#xff0c;多个值类型变量的值不会互相影响。存储在栈&#xff08;stack&#xff09;上 类结构关键字classstruct类型引用类型值类型存储…...

【RabbitMQ】RabbitMQ持久化

一、简介 RabbitMQ的持久化机制是一种确保数据在RabbitMQ服务重启或异常情况下不会丢失的重要特性。RabbitMQ的持久化主要包括三个方面的内容&#xff1a;交换器的持久化、队列的持久化、消息的持久化。 二、交换器的持久化 1、实现方式 在RabbitMQ中&#xff0c;实现交换器…...

算法刷题笔记 Kruskal算法求最小生成树(详细算法介绍,详细注释C++代码实现)

文章目录 题目描述基本思路实现代码 题目描述 给定一个n个点m条边的无向图&#xff0c;图中可能存在重边和自环&#xff0c;边权可能为负数。求最小生成树的树边权重之和&#xff0c;如果最小生成树不存在则输出impossible。 最小生成树的概念&#xff1a;给定一张边带权的无向…...

5年经验的软件测试人员,碰到这样的面试题居然会心虚......

我们这边最近的面试机会比较多&#xff0c;但是根据他们的反馈&#xff0c;结束后大部分都没音信了&#xff0c;因为现在企业面试问的非常多&#xff0c;范围非常广&#xff0c;而且开放性的问题很多&#xff0c;很多人即便面试前刷了成百上千道面试题&#xff0c;也很难碰到一…...

C#进阶-轻量级ORM框架Dapper的使用教程与原理详解

本文详细介绍了Dapper在C#中的使用方法&#xff0c;包括Dapper的基本概念、与其他持久层框架的比较、基本语法和高级语法的使用&#xff0c;并通过实例讲解了如何在项目中集成和使用Dapper。Dapper以其高效的性能和简洁的API受到开发者的青睐&#xff0c;适用于各种数据库操作需…...

Windows图形界面(GUI)-MFC-C/C++ - 编辑框(Edit Control) - CEdit

公开视频 -> 链接点击跳转公开课程博客首页 -> ​​​链接点击跳转博客主页 目录 编辑框(Edit Control) - CEdit 基本概念 成员函数 示例代码 编辑框(Edit Control) - CEdit 基本概念 编辑框&#xff08;Edit Control&#xff09;是一个允许用户输入和编辑文本的窗…...

网络安全防御【IPsec VPN搭建】

目录 一、实验拓扑图 二、实验要求 三、实验思路 四、实验步骤&#xff1a; 修改双机热备的为主备模式&#xff1a; 2、配置交换机LSW6新增的配置&#xff1a; 3、防火墙&#xff08;FW4&#xff09;做相关的基础配置&#xff1a; 4、搭建IPsec VPN通道 &#xff08;1…...

java环境配置与tomcat的配置

1、java环境配置 一、JDK下载 访问Oracle官网&#xff1a; 前往Oracle官网&#xff08;Oracle | Cloud Applications and Cloud Platform&#xff09;&#xff0c;在首页的顶部菜单中选择“Resources” > “Downloads” > “Java” > “JDK”。注意&#xff1a;Orac…...

OD C卷 - 来自异国的客人/幸运数字

来自异国的客人/幸运数字&#xff08;100&#xff09; 输入描述&#xff1a; 输入k,n,m k表示物品价值&#xff08;十进制&#xff09; k>0 n表示幸运数字, n > 0 m表示异国采用的进制&#xff1b;m > 1 n < m 输出描述&#xff1a; 输出幸运数字的个数&#xff0…...

C++ | 动态内存管理 new、delete (用法、底层)详解

目录 简单回顾C语言动态内存管理 new、delete的用法 内置类型 new delete 自定义类型 new、delete底层讲解&#xff08;重要&#xff09; operator new 与 operator delete 定位 new 结语 简单回顾C语言动态内存管理 在C语言的学习阶段 我们接触到了三个能在堆上开辟…...

【C语言】结构体内存布局解析——字节对齐

&#x1f984;个人主页:小米里的大麦-CSDN博客 &#x1f38f;所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html &#x1f381;代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录 一、引言 二、什么是字节对齐&…...

模型表达方式

目录 一、模型表达概述 二、模型精确表达 2.1 几何表示 (Geometrical Representation) 三、模型非精确表达 3.1 网格表示 (Mesh Representation) 3.2 体素表示 (Voxel Representation) 一、模型表达概述 模型的表达方式多种多样,选择适合的表达方式取决于具体应用场景和…...

校园课程助手【4】-使用Elasticsearch实现课程检索

本节将介绍本项目的查询模块&#xff0c;使用Elasticsearch又不是查询接口&#xff0c;具体流程如图所示&#xff08;如果不了解Elasticsearch可以使用sql语句进行查询&#xff09;&#xff1a; 这里是两种方法的异同点&#xff1a; Mysql&#xff1a;擅长事务类型操作&#…...

经典运维面试题

1、Linux常见的日志文件都有哪些&#xff0c;各自的用途&#xff1f;日志轮询配置文件在哪里&#xff1f;欢迎界面配置文件在哪里&#xff1f; /var/log/messages #内核及公共消息日志/var/log/cron #计划任务日志/var/log/dmesg #系统引导日志/var/log/malilog #邮件系…...

别再盲目推广了!Xinstall助你开启App线下推广新篇章

在这个数字化飞速发展的时代&#xff0c;App已经成为我们生活中不可或缺的一部分。然而&#xff0c;App市场的竞争也日益激烈&#xff0c;如何让你的App在众多竞争者中脱颖而出&#xff0c;成为每个推广者必须面对的问题。今天&#xff0c;就让我们一起探讨一下App线下推广的痛…...

大厂linux面试题攻略五之数据库管理

一、数据库管理-MySQL语句 0.MySQL基本语句&#xff1a; 1.SQL语句-增 创建xxx用户&#xff1a; mysql>create user xxx % indentified by 123456; xxx表示用户名 %b表示该用户用来连接数据库的方式&#xff08;远程或本地连接&#xff09; indentified by 123456设置密码…...

【pytorch】模型集成

在集成学习中&#xff0c;我们会训练多个模型&#xff08;通常称为「弱学习器」&#xff09;解决相同的问题&#xff0c;并将它们结合起来以获得更好的结果。最重要的假设是&#xff1a;当弱模型被正确组合时&#xff0c;我们可以得到更精确和/或更鲁棒的模型。 常用的模型集成…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

Spring AI 入门:Java 开发者的生成式 AI 实践之路

一、Spring AI 简介 在人工智能技术快速迭代的今天&#xff0c;Spring AI 作为 Spring 生态系统的新生力量&#xff0c;正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务&#xff08;如 OpenAI、Anthropic&#xff09;的无缝对接&…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...