本页介绍如何使用 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 算子,用户可以自由组合任意自定义样式。
本教程主要介绍 SQL/DataFrame API。
在程序开头使用以下代码创建 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()
在创建 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-submit 或 spark-shell 中传入 --conf spark.sql.extensions=org.apache.sedona.viz.sql.SedonaVizExtensions,org.apache.sedona.sql.SedonaSqlExtensions 来一并注册。
假设有如下 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:
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 是这些地图瓦片的缩放级别。
可以沿用单张图像生成中的命令,将所有地图瓦片逐一取出并保存。