当前位置: 首页 > 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;}}
http://www.lryc.cn/news/413988.html

相关文章:

  • 数据结构——八大排序
  • 【Unity】RPG2D龙城纷争(十九)流程与UI界面(终章)
  • C#类和结构体的区别
  • 【RabbitMQ】RabbitMQ持久化
  • 算法刷题笔记 Kruskal算法求最小生成树(详细算法介绍,详细注释C++代码实现)
  • 5年经验的软件测试人员,碰到这样的面试题居然会心虚......
  • C#进阶-轻量级ORM框架Dapper的使用教程与原理详解
  • Windows图形界面(GUI)-MFC-C/C++ - 编辑框(Edit Control) - CEdit
  • 网络安全防御【IPsec VPN搭建】
  • java环境配置与tomcat的配置
  • OD C卷 - 来自异国的客人/幸运数字
  • C++ | 动态内存管理 new、delete (用法、底层)详解
  • 【C语言】结构体内存布局解析——字节对齐
  • 模型表达方式
  • 校园课程助手【4】-使用Elasticsearch实现课程检索
  • 经典运维面试题
  • 别再盲目推广了!Xinstall助你开启App线下推广新篇章
  • 大厂linux面试题攻略五之数据库管理
  • 【pytorch】模型集成
  • 初识集合和数据结构
  • cocos creator 3.x中动态加载 resources 文件夹下的图片时提示找不到
  • 第九十八周周报
  • 程序员找工作之数据结构面试题总结分析
  • 设置provider解决maven找不到JUnit 5测试样例
  • php反序列化靶机serial实战
  • 类型推断技术及仓颉语言实践
  • 职场生存秘籍:16条黄金法则
  • Flask 介绍
  • JAVA基础知识点3 (String 和 StringBuffer 以及 StringBuilder 的特点以及区别)
  • 2024年8月AI内容生成技术的现状与未来:从文生文到跨模态交互的全景分析