ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

vega-geo 地理数据变换实战指南:从投影、GeoJSON 到密度等值线完整解析

vega-geo 地理数据变换实战指南:从投影、GeoJSON 到密度等值线完整解析 vega-geo 地理数据变换实战指南从投影、GeoJSON 到密度等值线完整解析【免费下载链接】vegaA visualization grammar.项目地址: https://gitcode.com/gh_mirrors/ve/vega导读vega-geo是 Vega 可视化语法vega 项目中负责地理数据处理的核心包为 Vega 数据流提供一组地理变换transform涵盖制图投影projection、GeoJSON 数据加工、经纬度投影为像素坐标、经纬网graticule生成以及基于二维核密度估计KDE的等值线isocontour与热力图heatmap可视化。阅读完本文你将掌握vega-geo全部 8 个公开变换与 1 个内部变换的用途、参数、实现原理并能用真实仓库中的示例规格如 contour-plot.vg.json、world-map.vg.json快速搭建地图与密度可视化。vega-geo 包概览为 Vega 数据流提供的地理变换集合vega-geopackages/vega-geo/README.md的定位是 Geographic data transforms for Vega dataflows。它不直接渲染图形而是作为 Vega 数据流dataflow中的变换算子把地理数据加工成下游 mark 可以直接消费的形式如 SVG path 字符串、shape 实例、GeoJSON 几何、Canvas 位图等。从包的入口文件 packages/vega-geo/index.js 可以看到它导出 10 个变换变换类型一句话用途contour公开变换已废弃基于核密度估计生成等值线功能已被kde2disocontour取代geojson公开变换把经纬度点或 GeoJSON 要素合并为单个 FeatureCollectiongeopath公开变换把 GeoJSON 要素映射为 SVG path 字符串geopoint公开变换把 (longitude, latitude) 投影为 (x, y) 像素坐标geoshape公开变换为数据项附加一个 shape 绘制实例延迟到渲染期执行投影graticule公开变换生成经纬网 GeoJSON 参考网格heatmap公开变换把栅格数据渲染为 Canvas 位图isocontour公开变换基于栅格数据生成等值线 GeoJSONkde2d公开变换对点数据执行二维核密度估计输出栅格矩阵projection内部变换维护制图投影实例供其他地理变换引用其中projection在 README 中被明确标注为internal transform即普通用户不会直接在数据流中书写它而是通过 Vega 规格顶层的projections声明来配置详见下文。从 packages/vega-geo/package.json 可以看到该包的依赖关系这直接反映了它的实现基石d3-geo提供各类投影构造器、geoPath与geoGraticuled3-array/d3-color分别用于极值计算与热力图像素颜色解析vega-dataflow提供Transform基类与脉冲pulse机制vega-projection提供投影注册表与getProjectionPathvega-canvas用于热力图离屏 Canvas 位图创建vega-statistics提供密度估计相关统计工具。Projection 内部变换一切地图变换的地基投影类型注册表Projection变换packages/vega-geo/src/Projection.js负责维护一个制图投影实例。它的核心逻辑是根据type参数从vega-projection包的注册表中取到对应构造器创建投影并把规格中出现的投影属性逐一设置到该实例上。投影注册表位于 packages/vega-projection/src/projections.jsVega 内置的投影类型全部来自d3-geo外加d3-geo-projection的mollweidealbers、albersUsa、azimuthalEqualArea、azimuthalEquidistant、conicConformal、conicEqualArea、conicEquidistant、equalEarth、equirectangular、gnomonic、identity、mercator、mollweide、naturalEarth1、orthographic、stereographic、transverseMercator。从源码看类型名是大小写不敏感的(type || mercator).toLowerCase()默认为mercator若传入未注册的类型会抛出Unrecognized projection type错误。每个创建的投影都会被附上type属性并预绑定一个geoPath().projection(p)的路径生成器p.path——这正是GeoPath/GeoShape变换通过getProjectionPath(proj)见 packages/vega-projection/src/projections.js直接取用的对象。投影属性直接透传 d3-geoprojectionProperties数组packages/vega-projection/src/projections.js定义了 Vega 透传给投影实例的标准属性覆盖 d3-geo 常规属性与 d3-geo-projection 扩展属性常规clipAngle、clipExtent、scale、translate、center、rotate、parallels、precision、reflectX、reflectY扩展coefficient、distance、fraction、lobes、parallel、radius、ratio、spacing、tilt。这些属性在 docs/docs/projections.md 中有完整说明关键几点scale默认值因投影而异且不同投影之间的 scale 数值不可直接比较translate默认[480, 250]把 (0°, 0°) 置于 960×500 区域中心rotate两或三个元素[λ, φ, γ]依次对应 yaw、pitch、rollpointRadius绘制 GeoJSONPoint/MultiPoint时的默认点半径像素默认 4.5precision自适应重采样的 Douglas–Peucker 阈值默认 √0.5 ≈ 0.70710fit/extent/size让投影自动适配给定 GeoJSON 数据见下节。fit 自动适配与 collectGeoJSONProjection变换还支持fit参数——给定 GeoJSON 数据后自动计算translate和scale使数据正好落入指定的extent或size像素区域packages/vega-geo/src/Projection.js 中的fit()函数extent存在则用fitExtent否则用fitSize。fit的输入会被collectGeoJSON()归一化接受单个 Feature/FeatureCollection也接受数组数组中的FeatureCollection会被展开裸几何对象会被包装成Feature最终合并为一个FeatureCollection。这一能力有测试直接覆盖——packages/vega-geo/test/projection-test.js 中验证了orthographic投影在size: [500, 500]且fit传入经纬网与Sphere时scale()变为 250、translate落在 (250, 250)并验证了fit输入包含null数据时依然稳健。fit与geojson变换的搭配是常见用法先用geojson变换把散落的经纬度点合并成 GeoJSON再通过信号把结果喂给投影的fit实现让地图自动缩放到数据范围。GeoJSON 变换把点与要素合并为 FeatureCollectiongeojson变换packages/vega-geo/src/GeoJSON.js把经纬度点数组或既有 GeoJSON 要素整合进一个FeatureCollection输出作为该变换的 value可通过signal绑定为信号值。它最典型的用途就是给投影的fit参数供数。参数定义见 docs/docs/transforms/geojson.md属性类型说明fieldsField[]分别包含经度、纬度值的两个字段geojsonField包含 GeoJSON Feature 对象的字段当fields与geojson均未指定时默认使用恒等函数把输入数据对象本身当作 GeoJSON Feature从源码实现packages/vega-geo/src/GeoJSON.js可以看到处理细节若提供fields遍历数据时会对每个点做数值校验(x x) x排除 NaN/字符串把有效的[lon, lat]点收集进points最后追加一个MultiPoint要素到特征数组若提供geojson字段则把每个 tuple 取出的对象作为独立要素压入数组。最终输出{type: FeatureCollection, features: ...}。官方用法示例docs/docs/transforms/geojson.md把经纬度字段合并并通过signal绑定{ type: geojson, fields: [longitude, latitude], signal: geodata }随后在投影声明中引用projections: [ { name: proj, type: mercator, fit: {signal: geodata} } ]GeoPath 与 GeoShape两种 GeoJSON 渲染策略GeoPath直接产出 SVG path 字符串geopath变换packages/vega-geo/src/GeoPath.js把 GeoJSON 要素映射为SVG path 字符串适用于pathmark。它依赖 d3-geo 的geoPath完成投影与路径生成。参数docs/docs/transforms/geopath.md属性类型默认说明projectionString—投影名不指定则不对 GeoJSON 做投影fieldField恒等存放 GeoJSON 数据的字段不指定则把整个数据对象当作 GeoJSONpointRadiusNumber|Expr—绘制Point/MultiPoint时的默认半径像素支持表达式按要素属性动态设定asStringpath输出字段名用法{ type: geopath, projection: projection }源码实现要点变换会缓存this.value中的 path 生成器当参数变化_.modified()时重建路径并reflow全部数据否则仅处理新增/修改的 tuple。pointRadius在遍历前后会被临时设置并恢复initPath保证多轮处理互不干扰。输出写入t[as]并声明modifies元数据。GeoShape延迟到渲染期的 shape 实例geoshape变换packages/vega-geo/src/GeoShape.js与geopath功能类似但不立即生成 SVG 字符串而是为每个数据项附加一个形状生成器shape instance渲染时再发出绘制命令。由于投影被延迟到渲染阶段在 Canvas 渲染的动态地图场景下通常性能更好。它专用于shapemark。参数docs/docs/transforms/geoshape.md与geopath几乎一致默认输出字段为shape属性类型默认说明projectionString—投影名不指定则不做投影fieldFielddatum存放 GeoJSON 数据的字段pointRadiusNumber|Expr—Point/MultiPoint默认半径asStringshape输出字段名源码中shapeGenerator()packages/vega-geo/src/GeoShape.js返回的 shape 函数还带context方法把渲染上下文透传给底层geoPath这正是 Canvas 直接绘制的基础。其metadata同时声明了modifies与nomod。如何选择按官方文档docs/docs/transforms/geopath.md、docs/docs/transforms/geoshape.md的说明需要立即拿到 SVG path 字符串如静态导出、SVG 渲染用geopathCanvas 动态地图优先geoshape。world-map.vg.json 就是一个典型世界地图与国家边界都使用geoshapeshapemark经纬网同样如此。GeoPoint 变换经纬度点到像素坐标geopoint变换packages/vega-geo/src/GeoPoint.js把 (longitude, latitude) 对投影为 (x, y) 像素坐标适合把散点式地理位置放到 symbol 等 mark 上。参数docs/docs/transforms/geopoint.md属性类型必填默认说明projectionString✔—投影名fieldsField[]✔—依次为经度、纬度字段asString[]—[x, y]输出字段名用法{ type: geopoint, projection: myprojection, fields: [lon, lat] }实现要点packages/vega-geo/src/GeoPoint.js调用proj([lon(t), lat(t)])若投影返回结果则写入t[x]/t[y]否则置为undefined——这一分支保证了超出投影范围如裁剪圈外的点不会产生无效坐标。geopoint.vg.jsondocs/docs/transforms/geopoint.vg.json展示了它与albersUsa投影配合把美国州府经纬度lon/lat字段投影为x/y并绘制 symbol 的完整流程。Graticule 变换生成经纬网参考网格graticule变换packages/vega-geo/src/Graticule.js生成地图经纬网一组均匀的经线meridians与纬线parallels用于展示投影变形。它内部直接使用 d3-geo 的geoGraticule()生成器输出一个包含单个 GeoJSON 对象的新数据流可交给geopath/geoshape绘制。默认网格±80° 纬度之间每 10° 一条经纬线极地区域经线每 90° 一条。参数docs/docs/transforms/graticule.md属性类型默认说明extentMajorArray[]—主要经纬网的边界两元素坐标数组extentMinorArray[]—次要经纬网的边界extentArray[]—同时设置 major 与 minor 边界stepMajorNumber[][90, 360]主要经纬网步长度stepMinorNumber[][10, 10]次要经纬网步长度stepNumber[]—同时设置 major 与 minor 步长precisionNumber2.5经纬网精度度用法{type: graticule, stepMinor: [15, 15]}源码实现packages/vega-geo/src/Graticule.js非常直白遍历参数对象凡是对应geoGraticule生成器上存在同名函数如extent、step、precision就调用设置然后执行gen()得到新的 GeoJSON用replace/ingest更新数据流中的唯一数据对象。密度可视化管线KDE2D → Isocontour / Heatmap从 Vega 5.8 起vega-geo提供了一套点数据 → 密度栅格 → 等值线/热力图的完整管线官方文档docs/docs/transforms/kde2d.md、docs/docs/transforms/isocontour.md、docs/docs/transforms/heatmap.md统一用 contour-plot 示例 演示。这套管线尤其适合海量 2D 点数据的可缩放表达。KDE2D二维核密度估计kde2d变换packages/vega-geo/src/KDE2D.js对输入点数据执行二维核密度估计输出一个或多个栅格矩阵{width, height, values, scale, translate, ...}供isocontour/heatmap消费。参数属性类型必填默认说明sizeNumber[]✔—密度估计的空间范围[width, height]像素xField✔—x 坐标字段yField✔—y 坐标字段weightField——数据点权重不指定则每个点权重为 1groupbyField[]——分组字段不指定则全部数据作为一组cellSizeNumber—4空间近似粒度默认 4 意味着宽高各缩减 2 倍设为 1 则输出栅格与size完全一致bandwidthNumber[]—自动KDE 核带宽像素两元素数组分别指定 x/y 带宽单元素同时作用于两轴小于 0 或未指定时自动确定countsBoolean—falsefalse输出概率估计true输出平滑计数asString—grid输出栅格字段名源码要点packages/vega-geo/src/KDE2D.jspartition()按groupby字段把数据切成若干组组内附带dims记录分组键值输出时回填到 tuple 上每组独立执行density2D()估计。当输入未变化且参数未修改时直接StopPropagation短路避免无谓重算。Isocontour从栅格到等值线 GeoJSONisocontour变换packages/vega-geo/src/Isocontour.js以一个或多个数值栅格为输入生成等值线isolineGeoJSON 几何流可用geoshape/geopath绘制。每条等值线是常数值的等值面边界。参数docs/docs/transforms/isocontour.md属性类型默认说明fieldField恒等存放栅格数据的字段不指定则数据对象本身视为栅格thresholdsNumber[]—显式等值线阈值数组一旦指定levels/nice/resolve/zero均被忽略levelsNumber—期望的等间距等值线数量有thresholds时忽略niceBooleanfalse是否把阈值对齐到友好整数值可能使实际条数偏离levelsresolveStringindependent多栅格阈值求解方式independent每个栅格单独计算shared所有栅格共用一套阈值zeroBooleantrue阈值是否包含 0 作为基线smoothBooleantrue是否用线性插值平滑等值线多边形密度估计场景下忽略scaleNumber|Number[]—输出坐标缩放可传[sx, sy]用于匹配坐标空间translateNumber[]—输出坐标平移[dx, dy]asStringcontour输出字段名设为null则直接输出几何对象源码实现packages/vega-geo/src/Isocontour.js值得展开每个输入栅格通过contour.size([w, h])(grid.values, thresholds)生成 GeoJSON 等值线随后transformPaths()依据栅格自带的scale/translate或显式参数对坐标做仿射变换——x (x - x1) * sx tx并在sx * sy 0坐标翻转时反转环的缠绕方向以维持几何正确性最后用rederive()把源数据属性复制到输出 tuple保证下游可以按分组字段着色。resolve: shared时阈值基于所有栅格最大值的全局统计计算。Heatmap把栅格渲染为 Canvas 位图heatmap变换packages/vega-geo/src/Heatmap.js把输入数值栅格渲染为 Canvas 位图bitmap输出可用imagemark 绘制。位图尺寸与栅格一致实际显示尺寸由 image mark 的 width/height 决定。参数docs/docs/transforms/heatmap.md属性类型默认说明fieldField恒等存放栅格数据的字段colorColor|Expr#888像素颜色表达式可读取$x、$y、$value、$max字段opacityNumber|Expr$value / $max像素不透明度表达式同样可读取四个$字段resolveStringindependent$max求解方式每个栅格独立计算或全局共享一个最大值asStringimage输出 Canvas 位图的字段名源码实现packages/vega-geo/src/Heatmap.js很巧妙为每个像素构造一个代理数据对象{$x, $y, $value, $max}颜色/不透明度函数若不依赖单个像素通过accessorFields检测是否引用$x/$y/$value/$max则只计算一次并用constant()缓存从而大幅优化逐像素开销最终通过vega-canvas创建离屏画布、逐像素写入 RGBApix[k3] ~~(255 * opacity(obj))。官方示例一密度热力图docs/docs/transforms/heatmap.md{ type: kde2d, x: x_value, y: y_value, size: [{signal: width}, {signal: height}], as: grid }, { type: heatmap, field: grid, color: steelblue, opacity: {expr: datum.$value / datum.$max} }官方示例二数学函数热力图不依赖输入栅格直接用表达式逐像素填色{ signals: [ {name: scale, value: 0.05} ], scales: [ { name: color, type: linear, domain: [-1, 1], range: {scheme: spectral} } ], data: [ { name: heatmap, values: [{width: 150, height: 100}], transform: [ { type: heatmap, color: { expr: scale(color, sin(scale * (datum.$x datum.$y)) * sin(scale * (datum.$x - datum.$y))) }, opacity: 1 } ] } ] }Contour已被取代的旧变换contour变换packages/vega-geo/src/Contour.js在 README 中即被标注为deprecated自 Vega 5.8 起未来主版本可能移除。它同时提供了 d3-contour 中contours与densityContour的能力要么直接对values数组width×height 数值网格算等值线要么对输入点数据做核密度估计后生成等值线。官方推荐迁移方案改用更灵活的kde2disocontour或kde2dheatmap组合。参数表docs/docs/transforms/contour.md如下仅供理解遗留规格属性类型必填说明sizeNumber[]✔等值线计算区域[width, height]提供values时为输入数据尺寸做密度估计时为输出视图像素尺寸valuesNumber[]—直接给定数值网格不指定则对输入点数据做密度估计x/yField—密度估计的像素坐标字段weightField—数据点权重字段cellSizeNumber—密度计算单元大小bandwidthNumber—KDE 带宽smoothBooleantrue是否线性插值平滑thresholdsNumber[]—显式阈值数组指定后忽略count/nicecountNumber—期望等值线条数niceBooleanfalse阈值是否对齐友好数值从源码可见packages/vega-geo/src/Contour.js它实际上是借用了KDE2D.js的params与Isocontour.js的transform坐标修正逻辑内部结构完全可以被新管线替代。端到端实战contour-plot 示例拆解仓库自带的 docs/examples/contour-plot.vg.json 把上述密度管线串成了一个完整可运行的 Vega 规格数据来自 docs/data/cars.json。整个流程分四步数据过滤剔除Horsepower或Miles_per_Gallon为空的行密度估计kde2d按Origin产地分组把经scale(x, ...)/scale(y, ...)换算后的像素坐标作为 x/ysize取视图宽高信号bandwidth与counts由交互控件驱动等值线isocontour读取grid字段resolve跟随信号在independent/shared间切换生成 3 层等值线渲染三层 mark 各司其职——symbol画散点imagemark 叠加heatmap生成的密度底色颜色取自Origin的序数色标pathmark 用geopath绘制等值线轮廓。对应的标记/变换组合验证了本文所述的全部要点heatmap输出喂给imageisocontour输出喂给geopath而geopath在这里未指定投影field: datum.contour的等值线坐标已是像素空间无需再投影。地图场景则可参考 docs/examples/world-map.vg.json通过信号绑定投影type、scale、rotate、center、translate配合graticule变换生成的经纬网与geoshape绘制的国家边界实现了可交互切换投影类型的世界地图——这也与 packages/vega-geo/test/projection-test.js 中验证的投影适配逻辑互相印证。源码地图与扩展指引如果你要在 Vega 数据流中二次开发或调试以下文件值得优先阅读变换入口与导出packages/vega-geo/index.js每个变换的Definition都声明了类型元数据type、metadata、params这是 Vega 解析器校验规格参数的依据分布在 packages/vega-geo/src/ 各文件工具函数packages/vega-geo/src/util/contours.js、packages/vega-geo/src/util/density2D.js、packages/vega-geo/src/util/quantize.jsGeoJSON 类型常量packages/vega-geo/src/constants.js投影注册与属性透传packages/vega-projection/src/projections.js测试用例packages/vega-geo/test/projection-test.js 与 packages/vega-geo/test/geojson-test.js。扩展自定义投影也很简单vega-projection提供了projection(name, constructor)注册接口见 packages/vega-projection/src/projections.js注册后即可在规格的projections中直接引用vega-projection-extended包则一次性注册 d3-geo-projection 的全部扩展投影。更完整的投影类型与属性清单见 docs/docs/projections.md。小结vega-geo用一套小而精的变换集合覆盖了 Vega 地理可视化的全部基础能力projection维护投影实例并支持fit自动适配geojson为fit聚合数据geopath/geoshape/geopoint分别面向 SVG 路径、Canvas shape 与散点三种渲染需求graticule提供地图参考网格kde2d、isocontour、heatmap组成现代的密度等值线与热力图管线而旧有的contour已进入废弃状态。理解这些变换的参数语义与底层实现大多直接构建在 d3-geo 之上你就能在 Vega 规格中组合出从世界地图到密度等高线的各类地理可视化。【免费下载链接】vegaA visualization grammar.项目地址: https://gitcode.com/gh_mirrors/ve/vega创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表