GEE ui界面实现:用户自画多边形, 按面积比例在多边形中自动生成样点,导出多边形和样点shp,以及删除上一组多边形和样点(有视频效果展示)
零、背景
这几天在选样点,发现GEE有强大的ui功能,于是应用在我的工作上。
下述代码实现了几个功能:
①用户可以自己勾勒多边形,随后程序会按面积比例在多边形中自动生成样点,同时根据改多边形的区域生成区域平均月NDVI曲线;可以实现选取多个多边形。
②设置【Export】ui按钮,将已选的多边形和生成的样点以shp文件形式导出。
③如果对刚才画的多边形不满意,点击【Delete】ui按钮,即可将最近画的一个多边形,以及其上生成的样点删除。
一、录了个小视频,先来感受一下效果吧!
用户自画多边形, 按面积比例在多边形中自动生成样点,导出多边形
二、代码
GEE链接:https://code.earthengine.google.com/31d8edcd71f7b5d27201b88fc46c1e05
/*----------- --------------Sample
------------- --------------*/
// 创建地图
var map1 = ui.Map().setOptions('Hybrid').setZoom(4);
var map2 = ui.Map().setOptions('Hybrid').setZoom(4);// map1 监听 map2 的缩放级别变化;map2 监听 map1 的缩放级别变
map1.onChangeZoom(function(zoom){zoom = parseInt(zoom); // 转换为整数类型map2.setZoom(zoom);
});map2.onChangeZoom(function(zoom){zoom = parseInt(zoom);map1.setZoom(zoom);
});// 当在一个地图上平移时,其他两个地图会同步平移。
var linker = ui.Map.Linker([map1, map2], 'change-center');// 添加图层到地图面板
map1.centerObject(aoi,8);map1.addLayer(lucc_img.clip(aoi), luccVis, year+'_Land Cover Map');//lucc_img可替换为自己的可视化数据// 获取MODIS影像集合
var modisCollection = ee.ImageCollection('MODIS/061/MOD13Q1').filterBounds(aoi).filterDate(year+'-01-01', year+'-12-31'); // 修正日期范围// 创建时间序列面板
var chartPanel = ui.Panel({style: {width: '34%'}
});// 创建一个空的 FeatureCollection 来存储样本polygon
var polygonsCollection = ee.FeatureCollection([]);
// 创建一个空的 FeatureCollection 来存储样本points
var pointsCollection = ee.FeatureCollection([]);
var numPoints; // 全局变量// 创建region 的NDVI时间序列图表
var plotNDVI = function(geometry, title) {// 选择NDVI波段并将值乘以0.0001var adjustedModisCollection = modisCollection.map(function(image) {return image.reproject('EPSG:4326').select('NDVI').multiply(0.0001).copyProperties(image, ['system:time_start']);});// ee.Reducer.mean() 计算该区域内像素值的平均值var timeSeries = ui.Chart.image.series({imageCollection: adjustedModisCollection,region: geometry,reducer: ee.Reducer.mean(),scale: 250,xProperty: 'system:time_start'}).setOptions({title: title,vAxis: {title: 'NDVI'},hAxis: {title: 'Date'},lineWidth: 1,pointSize: 3});chartPanel.clear();chartPanel.add(timeSeries);
};// 导出函数
function exportPolygons_points() {// 检查 FeatureCollection 是否包含元素if (polygonsCollection.size().getInfo() > 0) {// 导出 FeatureCollection 到 Google Drive 为 SHP 格式Export.table.toDrive({collection: polygonsCollection,description: 'Exported_Polygons',fileFormat: 'SHP' // 指定文件格式为 SHP});print('Exporting polygons to Google Drive as SHP...');} else {print('No polygons to export.');}if (pointsCollection.size().getInfo() > 0) {// 导出 FeatureCollection 到 Google Drive 为 SHP 格式Export.table.toDrive({collection: pointsCollection,description: 'Exported_Points',fileFormat: 'SHP' // 指定文件格式为 SHP});print('Exporting points to Google Drive as SHP...');
} else {print('No points to export.');
}
}
// 创建导出按钮
var exportPolygons_points_Button = ui.Button({label: 'Export Polygons/points',onClick: exportPolygons_points
});
// 将导出按钮添加到 map2
map2.add(exportPolygons_points_Button);// Function to add drawing tools to the map
function addDrawingTools(map, mapTitle) {var drawingTools = map.drawingTools();drawingTools.addLayer([], 'geometry');drawingTools.setShape('polygon');drawingTools.draw();// Draw a polygonfunction onClickToDrawPoint(){var polygon = drawingTools.layers().get(0).getEeObject(); // Get the point drawn by the userdrawingTools.layers().reset(); // Clear the drawing toolsvar areaInMeters = polygon.area();print('areaInMeters',areaInMeters);// Create a feature with the coordinates as propertiesvar polygon_feature = ee.Feature(polygon);// Add the new point to the points collectionpolygonsCollection = polygonsCollection.merge(ee.FeatureCollection([polygon_feature])); // Merge the feature into the collection//print('polygonsCollection',polygonsCollection)// Calculate the number of random points based on the areanumPoints = areaInMeters.divide(1572500).ceil(); // Area / 1572500 (in square meters)不加var 即更新全局变量 numPoints,而不是定义局部变量print('numPoints', numPoints);// Generate random points within the polygonvar randomPoints = ee.FeatureCollection.randomPoints(polygon_feature.geometry(), numPoints);//print('randomPoints',randomPoints);pointsCollection = pointsCollection.merge(ee.FeatureCollection(randomPoints)); // Merge the feature into the collection//print('pointsCollection',pointsCollection)// Update the map with the new points collectionmap1.layers().set(4, ui.Map.Layer(polygonsCollection, {color: 'FF0000'}, 'Sample Polygons'));map2.layers().set(0, ui.Map.Layer(polygonsCollection, {color: 'FF0000'}, 'Sample Polygons'));map1.layers().set(5, ui.Map.Layer(pointsCollection, {color: '000000'}, 'Sample Points'));map2.layers().set(1, ui.Map.Layer(pointsCollection, {color: '000000'}, 'Sample Points'));// Redraw the NDVI chart (or any other chart you're displaying)plotNDVI(polygon_feature, mapTitle);drawingTools.draw();}drawingTools.onDraw(onClickToDrawPoint); // Enable drawing tools
}// Add drawing tools and delete button
addDrawingTools(map1, 'Click map 1 and add polygons!');
addDrawingTools(map2, 'Click map 2 and add polygons!');
addDeleteButton(); // Add the delete button to the UI// Function to add a delete button to remove the last drawn Polygon/Points
function addDeleteButton() {// Create the delete buttonvar deleteButton = ui.Button({label: 'Delete Last Polygon/Points',onClick: function() {// Delete last polygonif (polygonsCollection.size().getInfo() > 0) {// Get the index of the last featurevar lastPolygon = polygonsCollection.toList(polygonsCollection.size()).get(-1); // Get the last polygon// Remove the last polygon by filtering it outpolygonsCollection = polygonsCollection.filter(ee.Filter.neq('system:index', ee.Feature(lastPolygon).get('system:index')));print('Last polygon deleted');} else {print('No polygon to delete'); // Print if no polygon exists}// Delete last pointsif (pointsCollection.size().getInfo() > 0) {// Calculate the size of the collectionvar collectionSize = pointsCollection.size();// Convert FeatureCollection to listvar pointsList = pointsCollection.toList(collectionSize);//var n = numPoints // assuming `numPoints` is defined elsewhere//print('numPoints2',numPoints)// Slice the list to exclude the last `n` pointsvar slicedPointsList = pointsList.slice(0, ee.Number(collectionSize).subtract(numPoints)); // Slice to remove last `numPoints` points// Convert the sliced list back to a FeatureCollectionpointsCollection = ee.FeatureCollection(slicedPointsList);// Update the map with the new polygon/points collectionmap1.layers().set(4, ui.Map.Layer(polygonsCollection, {color: 'FF0000'}, 'Sample Polygons'));map2.layers().set(0, ui.Map.Layer(polygonsCollection, {color: 'FF0000'}, 'Sample Polygons'));map1.layers().set(5, ui.Map.Layer(pointsCollection, {color: '000000'}, 'Sample Points'));map2.layers().set(1, ui.Map.Layer(pointsCollection, {color: '000000'}, 'Sample Points'));print('Last ' + numPoints.getInfo() + ' points deleted');} else {print('No points to delete.');}}});// Add the delete button to map2map2.add(deleteButton);
}// 创建水平分割面板(宽度为整个用户界面的66%),其中 map1 和 map2 分别位于左侧和右侧
var split1 = ui.Panel(ui.SplitPanel({firstPanel: map1,secondPanel: map2,orientation: 'horizontal',wipe: false,
}), null, {width: '66%', height:'100%'});// 创建水平分割面板(宽度为整个用户界面的34%),其中 chartPanel 位于map1和map2的右侧
var split2 = ui.Panel(ui.SplitPanel({firstPanel: split1,secondPanel: chartPanel,orientation: 'horizontal',wipe: false,
}), null, {width: '100%', height: '100%'});map2.setControlVisibility(false);//设置 map2 地图的控制面板(如缩放、平移、图层选择等控制元素)不显示
ui.root.clear(); // 清空当前用户界面上的所有内容
ui.root.insert(0, split2); // 将新的布局 split2 插入到用户界面的根容器中,位置索引为 0(即第一个位置)
完结撒花!
相关文章:
GEE ui界面实现:用户自画多边形, 按面积比例在多边形中自动生成样点,导出多边形和样点shp,以及删除上一组多边形和样点(有视频效果展示)
零、背景 这几天在选样点,发现GEE有强大的ui功能,于是应用在我的工作上。 下述代码实现了几个功能: ①用户可以自己勾勒多边形,随后程序会按面积比例在多边形中自动生成样点,同时根据改多边形的区域生成区域平均月N…...
React diff算法和Vue diff算法的主要区别
React和Vue都是流行的前端框架,它们各自实现了diff算法来优化虚拟DOM的更新过程。以下是React diff算法和Vue diff算法的主要区别: 1. diff策略 React diff算法: React的diff算法主要采用了同层级比较的策略,即它不会跨层级比较节…...
WSL 2 中 FastReport 与 FastCube 的设置方法与优化策略
软件开发人员长期以来一直在思考这个问题:“我们如何才能直接在 Windows 中运行 Linux 应用程序,而无需使用单独的虚拟机?” WSL 技术为这个问题提供了一个可能的答案。WSL 的历史始于 2016 年。当时,其实现涉及使用 Windows 内核…...
《线性代数》学习笔记
列向量无关 上个星期继续学线性代数,一个矩阵,如何判断它是的列向量有几个是线性无关呢?其实有好几个方法。第一个就是一个一个判断。 先选定一个,然后看下这两个,怎么看呢?如果两个列向量线性相关&#…...
Redis三种集群模式:主从模式、哨兵模式和Cluster模式
目录标题 1、背景及介绍2、 Redis 主从复制2.1、主从复制特点2.2、Redis主从复制原理2.3 PSYNC 工作原理2.3.1、启动或重连判断:2.3.2、第一次同步处理:2.3.3、断线重连处理:2.3.4、主节点响应2.3.5、全量同步触发条件:2.3.6、复制…...
CDH大数据平台部署
二、CDH简介 全称Cloudera’s Distribution Including Apache Hadoop。 hadoop的版本 (Apache、CDH、Hotonworks版本) 在公司中一般使用cdh多一些(收费的)、也有公司使用阿里云大数据平台、微软的大数据平台。 国内也有一些平台:星环大数…...
7.4、实验四:RIPv2 认证和触发式更新
源文件 一、引言:为什么要认证和采用触发式更新? 1. RIP v2 认证 RIP(Routing Information Protocol)版本 2 添加了认证功能,以提高网络的安全性。认证的作用主要包括以下几点: 防止路由欺骗 RIP v1 是不…...
【一步步开发AI运动小程序】二十一、如果将AI运动项目配置持久化到后端?
**说明:**本文所涉及的AI运动识别、计时、计数能力,都是基于云智「Ai运动识别引擎」实现。云智「Ai运动识别」插件识别引擎,可以为您的小程序或Uni APP赋于原生、本地、广覆盖、高性能的人体识别、姿态识别、10余种常见的运动计时、计数识别及…...
LED和QLED的区别
文章目录 1. 基础背光技术2. 量子点技术的引入3. 色彩表现4. 亮度和对比度5. 能效6. 寿命7. 价格总结 LED和 QLED都是基于液晶显示(LCD)技术的电视类型,但它们在显示技术、色彩表现和亮度方面有一些关键区别。以下是两者的详细区别ÿ…...
2024 年Postman 如何安装汉化中文版?
2024 年 Postman 的汉化中文版安装教程...
转化古老的Eclipse项目为使用gradle构建
很多古老的Java项目,是使用Eclipse作为IDE开发的。 那么,使用其它IDE的开发者,如何快速地进入这种古老项目的开发呢?或者说,一个Eclipse构建的古老项目,能不能转化成一个IDE无关的项目,进而所有…...
openGauss常见问题与故障处理(二)
2.网络故障定位手段 2.1 网络故障定位手段--常见网络故障引发的异常 在数据库正常工作的情况下,网络层对上层用户是透明的,但数据库在长期运行时,可能会由于各种原因导致出现网络异常或错误。 常见的因网络故障引发的异常有: 1>…...
Mysql 8迁移到达梦DM8遇到的报错
在实战迁移时,遇到两个报错。 一、列[tag]长度超出定义 在mysql中,tag字段的长度是varchar(20),在迁移到DM8后,这个长度不够用了。怎么解决? 在迁移过程中,“指定对象”时,选择转换。 在“列映…...
Android HandlerThread 基础
HandlerThread **一、HandlerThread的基本概念和用途**1. **目的**2. **与普通线程的区别** **二、HandlerThread的使用步骤**1. **创建HandlerThread对象并启动线程**2. **创建Handler并关联到HandlerThread的消息队列**3. **发送消息到HandlerThread的消息队列** **三、Handl…...
【智能算法应用】人工水母搜索算法求解二维路径规划问题
摘要 本文基于人工水母搜索算法(Jellyfish Search Algorithm, JSA),对二维路径规划问题进行了研究。JSA作为一种新兴的群体智能优化算法,模仿了水母在海洋中觅食和迁移的行为,以求解非线性、复杂的优化问题。实验结果…...
【Altium】原理图如何利用参数管理器批量修改元器件属性
【更多软件使用问题请点击亿道电子官方网站】 1、 文档目标 解决在使用AD设计原理图的时候,使用参数管理器批量修改元器件的属性。 2、 问题场景 客户在使用ad时,想大批量修改元器件的属性,类似于Cadence中,批量修改Manufactur…...
基于Spring Boot与Redis的令牌主动失效机制实现
目录 前言1. 项目结构和依赖配置1.1 项目依赖配置1.2 Redis连接配置 2. 令牌主动失效机制的实现流程2.1 登录成功后将令牌存储到Redis中2.2 使用拦截器验证令牌2.3 用户修改密码后删除旧令牌 3. Redis的配置与测试4. 可能的扩展与优化结语 前言 在现代Web系统中,用…...
深度学习之循环神经网络(RNN)
1 为什么需要RNN? 时间序列数据是指在不同时间点上收集到的数据,这类数据反映了某一事物、现象等随时间的变化状态或程度。一般的神经网络,在训练数据足够、算法模型优越的情况下,给定特定的x,就能得到期望y。其一…...
Autosar CP Network Management模块规范导读
Network Management模块的主要功能 网络管理适配:作为通信管理器和总线特定网络管理模块之间的适配层,实现不同总线网络管理功能的统一接口,确保系统中各种网络的协同工作。协调功能 网络协调关闭:使用协调算法协调多个网络的关闭,确保它们在合适的时间同步进入睡眠模式,…...
Xshell 7 偏好设置
1 Xshell7 工具——更改用户数据文件夹 就是此电脑目录下的文档 该目录下的7 Xshell下的 applog ColorScheme Files 配色方案文件目录 HighlightSet Files 突出显示集目录 Logs 日志 QuickButton Files 快速命令集 Scripts 脚本文件 Sessions 会话文件 会话文件目录就…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
java调用dll出现unsatisfiedLinkError以及JNA和JNI的区别
UnsatisfiedLinkError 在对接硬件设备中,我们会遇到使用 java 调用 dll文件 的情况,此时大概率出现UnsatisfiedLinkError链接错误,原因可能有如下几种 类名错误包名错误方法名参数错误使用 JNI 协议调用,结果 dll 未实现 JNI 协…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing
Muffin 论文 现有方法 CRADLE 和 LEMON,依赖模型推理阶段输出进行差分测试,但在训练阶段是不可行的,因为训练阶段直到最后才有固定输出,中间过程是不断变化的。API 库覆盖低,因为各个 API 都是在各种具体场景下使用。…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...
