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

avatar
作者
筋斗云
阅读量:0

读取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,避免除以0         double 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;         }     } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!