跳转至
Apache Sedona 1.9.0 已正式发布,新增 Spark 4.1 支持、proj4sedona 坐标系转换、Bing Tile 函数等众多特性!

Scala/Java

本页介绍如何使用 SedonaViz 可视化空间数据。示例代码使用 Scala 编写,但同样适用于 Java

SedonaViz 通过对 Sedona 处理大规模空间数据的能力进行扩展,原生支持通用的地图制图设计。它可以可视化空间 RDD 与空间查询,并以并行方式渲染超高分辨率图像。

SedonaViz 提供了 Map Visualization SQL,使用户能更灵活地设计美观的地图可视化效果,包括散点图与热力图。同时也提供 SedonaViz RDD API。

Note

SedonaViz 的 SQL/DataFrame API 全部说明请参阅 SedonaViz API

为什么需要可扩展的地图可视化

数据可视化让用户能够对数据进行总结、分析与推理。要在多个缩放级别上保证细致而准确的地理空间地图可视化,需要极高分辨率的地图。Google Maps、MapBox、ArcGIS 等传统方案受计算资源限制,对大规模地理空间数据生成地图需要花费大量时间。在大空间数据场景下,这类工具往往直接崩溃或长时间无法完成。

SedonaViz 把地图可视化流程的主要步骤(如像素化、聚合、渲染)封装为一组可大规模并行的 GeoViz 算子,用户可以自由组合任意自定义样式。

可视化 SpatialRDD

本教程主要介绍 SQL/DataFrame API。

配置依赖

  1. 阅读 Sedona Maven Central 坐标
  2. 添加 Apache Spark coreApache SparkSQL、Sedona-core、Sedona-SQL、Sedona-Viz 依赖

创建 Sedona 配置

在程序开头使用以下代码创建 Sedona 配置。如果您已经有了由 Wherobots / AWS EMR / Databricks 创建的 SparkSession(通常名为 spark),可跳过此步骤直接使用 spark

Sedona >= 1.4.1=

val config = SedonaContext.builder()
        .config("spark.kryo.registrator", classOf[SedonaVizKryoRegistrator].getName) // org.apache.sedona.viz.core.Serde.SedonaVizKryoRegistrator
        .master("local[*]") // 集群模式下请删除此行
        .appName("Sedona Viz") // 改成合适的名字
        .getOrCreate()

Sedona <1.4.1

下面这种方式自 Sedona 1.4.1 起已弃用,请改用上面的方式。

var sparkSession = SparkSession.builder()
.master("local[*]") // 集群模式下请删除此行
.appName("Sedona Viz") // 改成合适的名字
// 启用 Sedona 自定义 Kryo 序列化器
.config("spark.serializer", classOf[KryoSerializer].getName) // org.apache.spark.serializer.KryoSerializer
.config("spark.kryo.registrator", classOf[SedonaVizKryoRegistrator].getName) // org.apache.sedona.viz.core.Serde.SedonaVizKryoRegistrator
.getOrCreate()

初始化 SedonaContext

在创建 Sedona 配置之后加上以下代码。如果您已经有了由 Wherobots / AWS EMR / Databricks 创建的 SparkSession(通常名为 spark),请改为调用 SedonaContext.create(spark)

Sedona >= 1.4.1=

val sedona = SedonaContext.create(config)
SedonaVizRegistrator.registerAll(sedona)

Sedona <1.4.1

下面这种方式自 Sedona 1.4.1 起已弃用,请改用上面的方式创建 SedonaContext。

SedonaSQLRegistrator.registerAll(sparkSession)
SedonaVizRegistrator.registerAll(sparkSession)

也可以通过在 spark-submitspark-shell 中传入 --conf spark.sql.extensions=org.apache.sedona.viz.sql.SedonaVizExtensions,org.apache.sedona.sql.SedonaSqlExtensions 来一并注册。

创建空间 DataFrame

假设有如下 DataFrame:

+----------+---------+
|       _c0|      _c1|
+----------+---------+
|-88.331492|32.324142|
|-88.175933|32.360763|
|-88.388954|32.357073|
|-88.221102| 32.35078|

首先需要构造一列几何类型的列:

CREATE OR REPLACE TEMP VIEW pointtable AS
SELECT ST_Point(cast(pointtable._c0 as Decimal(24,20)),cast(pointtable._c1 as Decimal(24,20))) as shape
FROM pointtable

Sedona 提供了多种方式加载各种空间数据格式,详见 编写空间 DataFrame 应用

生成单张图像

大多数情况下,您只想从空间数据中得到一张图像。

像素化空间对象

要在地图图像上显示空间对象,先要把它们转换为像素。

首先计算该列的空间边界:

CREATE OR REPLACE TEMP VIEW boundtable AS
SELECT ST_Envelope_Aggr(shape) as bound FROM pointtable

然后用 ST_Pixelize 将其转换为像素。

下面这段代码适用于 Sedona v1.0.1 之前。ST_Pixelize 继承自 Generator,因此可以直接展开数组而无需 explode 函数。

CREATE OR REPLACE TEMP VIEW pixels AS
SELECT pixel, shape FROM pointtable
LATERAL VIEW ST_Pixelize(ST_Transform(shape, 'epsg:4326','epsg:3857'), 256, 256, (SELECT ST_Transform(bound, 'epsg:4326','epsg:3857') FROM boundtable)) AS pixel

下面这段代码适用于 Sedona v1.0.1 及之后。ST_Pixelize 返回像素数组,需要使用 explode 展开:

CREATE OR REPLACE TEMP VIEW pixels AS
SELECT pixel, shape FROM pointtable
LATERAL VIEW explode(ST_Pixelize(ST_Transform(shape, 'epsg:4326','epsg:3857'), 256, 256, (SELECT ST_Transform(bound, 'epsg:4326','epsg:3857') FROM boundtable))) AS pixel

执行完本教程末尾的 ST_Render 后,将得到 256*256 分辨率的图像。

Warning

强烈建议先用 ST_Transform 将坐标转换到适合可视化的坐标系(如 epsg:3857),否则地图可能出现变形。

聚合像素

许多对象可能被像素化到同一个像素位置。需要按空间聚合或按温度、湿度等空间观测值进行聚合:

CREATE OR REPLACE TEMP VIEW pixelaggregates AS
SELECT pixel, count(*) as weight
FROM pixels
GROUP BY pixel

weight 表示空间聚合或空间观测的程度,后续会决定该像素的颜色。

给像素上色

运行以下命令为像素根据 weight 上色:

CREATE OR REPLACE TEMP VIEW pixelaggregates AS
SELECT pixel, ST_Colorize(weight, (SELECT max(weight) FROM pixelaggregates)) as color
FROM pixelaggregates

详细 API 说明请参阅 ST_Colorize

渲染图像

使用 ST_Render 把所有像素绘制到一张图像上:

CREATE OR REPLACE TEMP VIEW images AS
SELECT ST_Render(pixel, color) AS image, (SELECT ST_AsText(bound) FROM boundtable) AS boundary
FROM pixelaggregates

该 DataFrame 中将包含一列 Image 类型的列,且只有一张图像。

将图像保存到磁盘

从上面的 DataFrame 中取出图像:

var image = sedona.table("images").take(1)(0)(0).asInstanceOf[ImageSerializableWrapper].getImage

使用 Sedona Viz 的 ImageGenerator 把图像保存到磁盘:

var imageGenerator = new ImageGenerator
imageGenerator.SaveRasterImageAsLocalFile(image, System.getProperty("user.dir")+"/target/points", ImageType.PNG)

生成地图瓦片

如果您是地图相关从业者,可能需要为不同缩放级别生成地图瓦片,最终构建出地图瓦片图层。

像素化与像素聚合

请先用与单张图像生成相同的命令完成像素化与像素聚合。在 ST_Pixelize 中需要指定较高的分辨率,例如 1000*1000。注意:每个维度都应能被 2^zoom-level 整除。

计算 tile name

使用以下命令为每个像素计算 tile name:

CREATE OR REPLACE TEMP VIEW pixelaggregates AS
SELECT pixel, weight, ST_TileName(pixel, 3) AS pid
FROM pixelaggregates

其中 3 表示这些地图瓦片的缩放级别。

像素上色

使用与单张图像生成相同的命令进行上色。

渲染地图瓦片

把像素按 tile 分组,然后并行渲染各个瓦片图像:

CREATE OR REPLACE TEMP VIEW images AS
SELECT ST_Render(pixel, color, 3) AS image
FROM pixelaggregates
GROUP BY pid

3 是这些地图瓦片的缩放级别。

将地图瓦片保存到磁盘

可以沿用单张图像生成中的命令,将所有地图瓦片逐一取出并保存。